From 27db236b5d1811553804ebd11ed4cc181874a86c Mon Sep 17 00:00:00 2001 From: PeachyPeach <72323920+PeachyPeachSM64@users.noreply.github.com> Date: Sat, 14 May 2022 23:28:25 +0200 Subject: [PATCH 01/13] Various bug fixes + Added is_game_paused() and more background music functions to lua (#93) Bug: DynOS models with animations cannot swap animations if they are loaded via lua (smlua_model_util_get_id and obj_set_model_extended). Fix: DynOS_Actor_GetActorGfx takes a graph node instead of a georef, and checks for DynosValidActors graph nodes if georef is NULL. Bug: The game can crash when calling obj_set_model_extended inside a HOOK_ON_OBJECT_RENDER hook. Fix: The crash happens in smlua_model_util_load_with_pool_and_cache_id due to pool being NULL. If the game can't allocate an AllocOnlyPool object, use DynOS to generate the graph node. Bug: warp_to_level and similar functions don't trigger HOOK_ON_WARP. Fix: Call HOOK_ON_WARP hooks in DynOS_Warp_UpdateWarp and DynOS_Warp_UpdateExit after level and mario initialization. Bug: The game sometimes calls HOOK_ON_OBJECT_RENDER hooks for unintended objects. Fix: Initialize hookRender field to 0 when creating an object. Bug: Actions can't apply gfx offsets to characters that have an anim offset (Waluigi, Wario) Fix: Add m->curAnimOffset to gfx.pos[1] instead of setting it to m->pos[1] + m->curAnimOffset, except during the jumbo star cutscene. --- autogen/convert_functions.py | 2 +- autogen/lua_definitions/functions.lua | 25 ++++++++++ data/dynos.c.h | 9 ++-- data/dynos.cpp.h | 2 +- data/dynos_c.cpp | 4 ++ data/dynos_mgr_actor.cpp | 26 ++++++++-- data/dynos_mgr_anim.cpp | 2 +- data/dynos_warps.cpp | 7 +++ docs/lua/functions-3.md | 72 +++++++++++++++++++++++++++ docs/lua/functions-4.md | 18 +++++++ docs/lua/functions.md | 5 ++ src/audio/external.c | 12 +++++ src/audio/external.h | 3 ++ src/game/characters.c | 6 ++- src/game/spawn_object.c | 1 + src/pc/lua/smlua_functions_autogen.c | 50 +++++++++++++++++++ src/pc/lua/smlua_hooks.h | 2 +- src/pc/lua/utils/smlua_misc_utils.c | 7 +++ src/pc/lua/utils/smlua_misc_utils.h | 2 + src/pc/lua/utils/smlua_model_utils.c | 27 +++++++--- 20 files changed, 263 insertions(+), 19 deletions(-) diff --git a/autogen/convert_functions.py b/autogen/convert_functions.py index bf0386c10..8ab1615bd 100644 --- a/autogen/convert_functions.py +++ b/autogen/convert_functions.py @@ -53,7 +53,7 @@ in_files = [ ] override_allowed_functions = { - "src/audio/external.h": [ " play_", "fade" ], + "src/audio/external.h": [ " play_", "fade", "current_background" ], "src/game/rumble_init.c": [ "queue_rumble_", "reset_rumble_timers" ], "src/pc/djui/djui_popup.h" : [ "create" ], "src/game/save_file.h": [ "save_file_get_", "save_file_set_flags", "save_file_clear_flags" ], diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua index aeebeb84b..8c283bb63 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -3688,6 +3688,26 @@ function fadeout_background_music(arg0, fadeOut) -- ... end +--- @return integer +function get_current_background_music() + -- ... +end + +--- @return integer +function get_current_background_music_max_target_volume() + -- ... +end + +--- @return integer +function get_current_background_music_target_volume() + -- ... +end + +--- @return integer +function is_current_background_music_volume_lowered() + -- ... +end + --- @return nil function play_course_clear() -- ... @@ -7376,6 +7396,11 @@ function hud_show() -- ... end +--- @return boolean +function is_game_paused() + -- ... +end + --- @param name string --- @param level integer --- @param area integer diff --git a/data/dynos.c.h b/data/dynos.c.h index 98b473531..491c7c0e9 100644 --- a/data/dynos.c.h +++ b/data/dynos.c.h @@ -9,10 +9,10 @@ void *dynos_swap_cmd(void *cmd); // -- built in -- // -void *dynos_update_cmd (void *cmd); -void dynos_update_gfx (); -void dynos_update_opt (void *pad); -s32 dynos_tex_import (void **output, void *ptr, s32 tile, void *grapi, void **hashmap, void *pool, s32 *poolpos, s32 poolsize); +void *dynos_update_cmd(void *cmd); +void dynos_update_gfx(); +void dynos_update_opt(void *pad); +s32 dynos_tex_import(void **output, void *ptr, s32 tile, void *grapi, void **hashmap, void *pool, s32 *poolpos, s32 poolsize); void dynos_gfx_swap_animations(void *ptr); // -- warps -- // @@ -33,6 +33,7 @@ void dynos_generate_packs(const char* directory); void dynos_actor_override(void** aSharedChild); void dynos_add_actor_custom(const char *filePath, const char* geoName); const void* dynos_geolayout_get(const char *name); +void *dynos_geolayout_to_graphnode(const void *geoLayout, bool keepInMemory); // -- collisions -- // void dynos_add_collision(const char *filePath, const char* collisionName); diff --git a/data/dynos.cpp.h b/data/dynos.cpp.h index a38e15a9b..05355e9f8 100644 --- a/data/dynos.cpp.h +++ b/data/dynos.cpp.h @@ -764,7 +764,7 @@ void DynOS_Pack_AddTex(PackData* aPackData, DataNode* aTexData); void DynOS_Actor_AddCustom(const SysPath &aFilename, const char *aActorName); const void *DynOS_Actor_GetLayoutFromName(const char *aActorName); -ActorGfx* DynOS_Actor_GetActorGfx(const void* aGeoref); +ActorGfx* DynOS_Actor_GetActorGfx(const GraphNode* aGraphNode); void DynOS_Actor_Valid(const void* aGeoref, ActorGfx& aActorGfx); void DynOS_Actor_Invalid(const void* aGeoref, s32 aPackIndex); void DynOS_Actor_Override(void** aSharedChild); diff --git a/data/dynos_c.cpp b/data/dynos_c.cpp index 42196c134..154013dc6 100644 --- a/data/dynos_c.cpp +++ b/data/dynos_c.cpp @@ -97,6 +97,10 @@ const void* dynos_geolayout_get(const char *name) { return DynOS_Actor_GetLayoutFromName(name); } +void *dynos_geolayout_to_graphnode(const void *geoLayout, bool keepInMemory) { + return DynOS_Geo_GetGraphNode(geoLayout, keepInMemory); +} + // -- collisions -- // void dynos_add_collision(const char *filePath, const char* collisionName) { diff --git a/data/dynos_mgr_actor.cpp b/data/dynos_mgr_actor.cpp index b4b44ac86..c1ce99880 100644 --- a/data/dynos_mgr_actor.cpp +++ b/data/dynos_mgr_actor.cpp @@ -1,4 +1,5 @@ #include +#include #include "dynos.cpp.h" extern "C" { @@ -101,11 +102,28 @@ const void *DynOS_Actor_GetLayoutFromName(const char *aActorName) { return NULL; } -ActorGfx* DynOS_Actor_GetActorGfx(const void* aGeoref) { - if (aGeoref == NULL) { return NULL; } +ActorGfx* DynOS_Actor_GetActorGfx(const GraphNode* aGraphNode) { + if (aGraphNode == NULL) { return NULL; } auto& _ValidActors = DynosValidActors(); - if (_ValidActors.count(aGeoref) == 0) { return NULL; } - return &_ValidActors[aGeoref]; + + // If georef is not NULL, check georef + if (aGraphNode->georef != NULL) { + if (_ValidActors.count(aGraphNode->georef) != 0) { + return &_ValidActors[aGraphNode->georef]; + } + return NULL; + } + + // Check graph node + auto it = std::find_if(_ValidActors.begin(), _ValidActors.end(), + [&aGraphNode](const auto& _Actor) { return _Actor.second.mGraphNode == aGraphNode; } + ); + if (it != _ValidActors.end()) { + return &it->second; + } + + // No actor found + return NULL; } void DynOS_Actor_Valid(const void* aGeoref, ActorGfx& aActorGfx) { diff --git a/data/dynos_mgr_anim.cpp b/data/dynos_mgr_anim.cpp index b65f769cc..19b42f46c 100644 --- a/data/dynos_mgr_anim.cpp +++ b/data/dynos_mgr_anim.cpp @@ -52,7 +52,7 @@ void DynOS_Anim_Swap(void *aPtr) { pDefaultAnimation = _Object->header.gfx.animInfo.curAnim; // ActorGfx data - ActorGfx* _ActorGfx = DynOS_Actor_GetActorGfx(_Object->header.gfx.sharedChild->georef); + ActorGfx* _ActorGfx = DynOS_Actor_GetActorGfx(_Object->header.gfx.sharedChild); if (!_ActorGfx) { return; } diff --git a/data/dynos_warps.cpp b/data/dynos_warps.cpp index be14ee2b9..6413cacd4 100644 --- a/data/dynos_warps.cpp +++ b/data/dynos_warps.cpp @@ -11,6 +11,7 @@ extern "C" { #include "game/sound_init.h" #include "game/object_list_processor.h" #include "game/options_menu.h" +#include "pc/lua/smlua_hooks.h" extern s8 gDialogBoxState; extern s16 gMenuMode; extern s32 gWdwWaterLevelSet; @@ -305,6 +306,9 @@ static void *DynOS_Warp_UpdateWarp(void *aCmd, bool aIsLevelInitDone) { sound_banks_enable(0, 0xFFFF); // Bowser levels sound fix } + // lua hooks + smlua_call_event_hooks(HOOK_ON_WARP); + // Reset values sDynosWarpTargetArea = -1; sDynosWarpLevelNum = -1; @@ -441,6 +445,9 @@ static void *DynOS_Warp_UpdateExit(void *aCmd, bool aIsLevelInitDone) { // Set music set_background_music(gCurrentArea->musicParam, gCurrentArea->musicParam2, 0); sDynosExitTargetWarp = NULL; + + // lua hooks + smlua_call_event_hooks(HOOK_ON_WARP); } // Phase 4 - Unlock Mario as soon as the second transition is ended diff --git a/docs/lua/functions-3.md b/docs/lua/functions-3.md index ee9e77874..b1dc37097 100644 --- a/docs/lua/functions-3.md +++ b/docs/lua/functions-3.md @@ -2378,6 +2378,78 @@
+## [get_current_background_music](#get_current_background_music) + +### Lua Example +`local integerValue = get_current_background_music()` + +### Parameters +- None + +### Returns +- `integer` + +### C Prototype +`u16 get_current_background_music(void);` + +[:arrow_up_small:](#) + +
+ +## [get_current_background_music_max_target_volume](#get_current_background_music_max_target_volume) + +### Lua Example +`local integerValue = get_current_background_music_max_target_volume()` + +### Parameters +- None + +### Returns +- `integer` + +### C Prototype +`u8 get_current_background_music_max_target_volume(void);` + +[:arrow_up_small:](#) + +
+ +## [get_current_background_music_target_volume](#get_current_background_music_target_volume) + +### Lua Example +`local integerValue = get_current_background_music_target_volume()` + +### Parameters +- None + +### Returns +- `integer` + +### C Prototype +`u8 get_current_background_music_target_volume(void);` + +[:arrow_up_small:](#) + +
+ +## [is_current_background_music_volume_lowered](#is_current_background_music_volume_lowered) + +### Lua Example +`local integerValue = is_current_background_music_volume_lowered()` + +### Parameters +- None + +### Returns +- `integer` + +### C Prototype +`u8 is_current_background_music_volume_lowered(void);` + +[:arrow_up_small:](#) + +
+ ## [play_course_clear](#play_course_clear) ### Lua Example diff --git a/docs/lua/functions-4.md b/docs/lua/functions-4.md index a3a907d1a..b83d7d860 100644 --- a/docs/lua/functions-4.md +++ b/docs/lua/functions-4.md @@ -5389,6 +5389,24 @@
+## [is_game_paused](#is_game_paused) + +### Lua Example +`local booleanValue = is_game_paused()` + +### Parameters +- None + +### Returns +- `boolean` + +### C Prototype +`bool is_game_paused(void);` + +[:arrow_up_small:](#) + +
+ ## [movtexqc_register](#movtexqc_register) ### Lua Example diff --git a/docs/lua/functions.md b/docs/lua/functions.md index 586339b39..40dd7770d 100644 --- a/docs/lua/functions.md +++ b/docs/lua/functions.md @@ -728,6 +728,10 @@ - external.h - [fade_volume_scale](functions-3.md#fade_volume_scale) - [fadeout_background_music](functions-3.md#fadeout_background_music) + - [get_current_background_music](functions-3.md#get_current_background_music) + - [get_current_background_music_max_target_volume](functions-3.md#get_current_background_music_max_target_volume) + - [get_current_background_music_target_volume](functions-3.md#get_current_background_music_target_volume) + - [is_current_background_music_volume_lowered](functions-3.md#is_current_background_music_volume_lowered) - [play_course_clear](functions-3.md#play_course_clear) - [play_dialog_sound](functions-3.md#play_dialog_sound) - [play_music](functions-3.md#play_music) @@ -1376,6 +1380,7 @@ - [hud_render_power_meter](functions-4.md#hud_render_power_meter) - [hud_set_value](functions-4.md#hud_set_value) - [hud_show](functions-4.md#hud_show) + - [is_game_paused](functions-4.md#is_game_paused) - [movtexqc_register](functions-4.md#movtexqc_register) - [play_transition](functions-4.md#play_transition) - [save_file_set_using_backup_slot](functions-4.md#save_file_set_using_backup_slot) diff --git a/src/audio/external.c b/src/audio/external.c index 1303e9940..d6f690532 100644 --- a/src/audio/external.c +++ b/src/audio/external.c @@ -2509,6 +2509,18 @@ u16 get_current_background_music(void) { return -1; } +u8 get_current_background_music_target_volume(void) { + return sBackgroundMusicTargetVolume; +} + +u8 get_current_background_music_max_target_volume(void) { + return sBackgroundMusicMaxTargetVolume; +} + +u8 is_current_background_music_volume_lowered(void) { + return sLowerBackgroundMusicVolume; +} + /** * Called from threads: thread4_sound, thread5_game_loop (EU only) */ diff --git a/src/audio/external.h b/src/audio/external.h index add25d276..3d3c3fbe6 100644 --- a/src/audio/external.h +++ b/src/audio/external.h @@ -53,6 +53,9 @@ void stop_background_music(u16 seqId); void fadeout_background_music(u16 arg0, u16 fadeOut); void drop_queued_background_music(void); u16 get_current_background_music(void); +u8 get_current_background_music_target_volume(void); +u8 get_current_background_music_max_target_volume(void); +u8 is_current_background_music_volume_lowered(void); void play_secondary_music(u8 seqId, u8 bgMusicVolume, u8 volume, u16 fadeTimer); void func_80321080(u16 fadeTimer); void func_803210D4(u16 fadeOutTime); diff --git a/src/game/characters.c b/src/game/characters.c index cad9a5624..7405e2adb 100644 --- a/src/game/characters.c +++ b/src/game/characters.c @@ -515,6 +515,10 @@ void update_character_anim_offset(struct MarioState* m) { if (m->curAnimOffset > 40) { m->curAnimOffset = 40; } if (m->curAnimOffset < -40) { m->curAnimOffset = -40; } - marioObj->header.gfx.pos[1] = m->pos[1] + m->curAnimOffset; + if (m->action == ACT_JUMBO_STAR_CUTSCENE) { + marioObj->header.gfx.pos[1] = m->pos[1] + m->curAnimOffset; + } else { + marioObj->header.gfx.pos[1] += m->curAnimOffset; + } marioObj->header.gfx.node.flags |= GRAPH_RENDER_PLAYER; } \ No newline at end of file diff --git a/src/game/spawn_object.c b/src/game/spawn_object.c index 2a86dbd19..60bce1eed 100644 --- a/src/game/spawn_object.c +++ b/src/game/spawn_object.c @@ -313,6 +313,7 @@ struct Object *allocate_object(struct ObjectNode *objList) { obj->header.gfx.throwMatrix = NULL; obj->coopFlags = 0; + obj->hookRender = 0; obj->areaTimerType = AREA_TIMER_TYPE_NONE; obj->areaTimer = 0; diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c index 9ece0bd5c..348817295 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -7438,6 +7438,42 @@ int smlua_func_fadeout_background_music(lua_State* L) { return 1; } +int smlua_func_get_current_background_music(UNUSED lua_State* L) { + if(!smlua_functions_valid_param_count(L, 0)) { return 0; } + + + lua_pushinteger(L, get_current_background_music()); + + return 1; +} + +int smlua_func_get_current_background_music_max_target_volume(UNUSED lua_State* L) { + if(!smlua_functions_valid_param_count(L, 0)) { return 0; } + + + lua_pushinteger(L, get_current_background_music_max_target_volume()); + + return 1; +} + +int smlua_func_get_current_background_music_target_volume(UNUSED lua_State* L) { + if(!smlua_functions_valid_param_count(L, 0)) { return 0; } + + + lua_pushinteger(L, get_current_background_music_target_volume()); + + return 1; +} + +int smlua_func_is_current_background_music_volume_lowered(UNUSED lua_State* L) { + if(!smlua_functions_valid_param_count(L, 0)) { return 0; } + + + lua_pushinteger(L, is_current_background_music_volume_lowered()); + + return 1; +} + int smlua_func_play_course_clear(UNUSED lua_State* L) { if(!smlua_functions_valid_param_count(L, 0)) { return 0; } @@ -15171,6 +15207,15 @@ int smlua_func_hud_show(UNUSED lua_State* L) { return 1; } +int smlua_func_is_game_paused(UNUSED lua_State* L) { + if(!smlua_functions_valid_param_count(L, 0)) { return 0; } + + + lua_pushboolean(L, is_game_paused()); + + return 1; +} + int smlua_func_movtexqc_register(lua_State* L) { if(!smlua_functions_valid_param_count(L, 4)) { return 0; } @@ -16905,6 +16950,10 @@ void smlua_bind_functions_autogen(void) { // external.h smlua_bind_function(L, "fade_volume_scale", smlua_func_fade_volume_scale); smlua_bind_function(L, "fadeout_background_music", smlua_func_fadeout_background_music); + smlua_bind_function(L, "get_current_background_music", smlua_func_get_current_background_music); + smlua_bind_function(L, "get_current_background_music_max_target_volume", smlua_func_get_current_background_music_max_target_volume); + smlua_bind_function(L, "get_current_background_music_target_volume", smlua_func_get_current_background_music_target_volume); + smlua_bind_function(L, "is_current_background_music_volume_lowered", smlua_func_is_current_background_music_volume_lowered); smlua_bind_function(L, "play_course_clear", smlua_func_play_course_clear); smlua_bind_function(L, "play_dialog_sound", smlua_func_play_dialog_sound); smlua_bind_function(L, "play_music", smlua_func_play_music); @@ -17524,6 +17573,7 @@ void smlua_bind_functions_autogen(void) { smlua_bind_function(L, "hud_render_power_meter", smlua_func_hud_render_power_meter); smlua_bind_function(L, "hud_set_value", smlua_func_hud_set_value); smlua_bind_function(L, "hud_show", smlua_func_hud_show); + smlua_bind_function(L, "is_game_paused", smlua_func_is_game_paused); smlua_bind_function(L, "movtexqc_register", smlua_func_movtexqc_register); smlua_bind_function(L, "play_transition", smlua_func_play_transition); smlua_bind_function(L, "save_file_set_using_backup_slot", smlua_func_save_file_set_using_backup_slot); diff --git a/src/pc/lua/smlua_hooks.h b/src/pc/lua/smlua_hooks.h index cbc2a4ba9..4ae109dee 100644 --- a/src/pc/lua/smlua_hooks.h +++ b/src/pc/lua/smlua_hooks.h @@ -34,7 +34,7 @@ enum LuaHookedEventType { HOOK_MAX, }; -static char* LuaHookedEventTypeName[] = { +static const char* LuaHookedEventTypeName[] = { "HOOK_UPDATE", "HOOK_MARIO_UPDATE", "HOOK_BEFORE_MARIO_UPDATE", diff --git a/src/pc/lua/utils/smlua_misc_utils.c b/src/pc/lua/utils/smlua_misc_utils.c index dc26b643b..790730938 100644 --- a/src/pc/lua/utils/smlua_misc_utils.c +++ b/src/pc/lua/utils/smlua_misc_utils.c @@ -114,6 +114,13 @@ void camera_unfreeze(void) { /// +extern s16 gMenuMode; +bool is_game_paused(void) { + return gMenuMode != -1; +} + +/// + bool warp_to_level(s32 aLevel, s32 aArea, s32 aAct) { return dynos_warp_to_level(aLevel, aArea, aAct); } diff --git a/src/pc/lua/utils/smlua_misc_utils.h b/src/pc/lua/utils/smlua_misc_utils.h index 84390c93c..326541ab7 100644 --- a/src/pc/lua/utils/smlua_misc_utils.h +++ b/src/pc/lua/utils/smlua_misc_utils.h @@ -39,6 +39,8 @@ void hud_render_power_meter(s32 health, f32 x, f32 y, f32 width, f32 height); void camera_freeze(void); void camera_unfreeze(void); +bool is_game_paused(void); + bool warp_to_level(s32 aLevel, s32 aArea, s32 aAct); bool warp_restart_level(void); bool warp_exit_level(s32 aDelay); diff --git a/src/pc/lua/utils/smlua_model_utils.c b/src/pc/lua/utils/smlua_model_utils.c index 6faf28d67..be44ef1bb 100644 --- a/src/pc/lua/utils/smlua_model_utils.c +++ b/src/pc/lua/utils/smlua_model_utils.c @@ -1,5 +1,6 @@ #include "sm64.h" #include "types.h" +#include "geo_commands.h" #include "src/game/area.h" #include "src/engine/graph_node.h" @@ -566,14 +567,28 @@ u8 smlua_model_util_load_with_pool_and_cache_id(enum ModelExtendedId extId, stru resizePool = true; } - if (info->isDisplayList) { - gLoadedGraphNodes[pickLoadedId] = (struct GraphNode *) init_graph_node_display_list(pool, NULL, info->layer, (void*)info->asset); - } else { - gLoadedGraphNodes[pickLoadedId] = process_geo_layout(pool, (void*)info->asset); + if (pool != NULL) { + if (info->isDisplayList) { + gLoadedGraphNodes[pickLoadedId] = (struct GraphNode *) init_graph_node_display_list(pool, NULL, info->layer, (void*)info->asset); + } else { + gLoadedGraphNodes[pickLoadedId] = process_geo_layout(pool, (void*)info->asset); + } + + if (resizePool) { + alloc_only_pool_resize(pool, pool->usedSpace); + } } - if (resizePool) { - alloc_only_pool_resize(pool, pool->usedSpace); + // If no pool is available, use DynOS to generate the graph node + else { + + // Turn the display list into a geo layout + if (info->isDisplayList) { + const GeoLayout displayListToGeoLayout[] = { GEO_NODE_START(), GEO_DISPLAY_LIST(info->layer, info->asset), GEO_END() }; + info->asset = memcpy(calloc(1, sizeof(displayListToGeoLayout)), displayListToGeoLayout, sizeof(displayListToGeoLayout)); + info->isDisplayList = false; + } + gLoadedGraphNodes[pickLoadedId] = dynos_geolayout_to_graphnode(info->asset, true); } // remember From 897f6712a34aced9b048f67cccdf131bdd88f335 Mon Sep 17 00:00:00 2001 From: MysterD Date: Tue, 17 May 2022 01:22:45 -0700 Subject: [PATCH 02/13] Reset hardcoded values on disconnect --- src/game/hardcoded.c | 17 +++++++++++++++-- src/game/hardcoded.h | 2 ++ src/game/rendering_graph_node.c | 18 +++++++++++------- src/pc/lua/smlua.c | 2 ++ 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/game/hardcoded.c b/src/game/hardcoded.c index 1e74a242d..091a294b1 100644 --- a/src/game/hardcoded.c +++ b/src/game/hardcoded.c @@ -37,7 +37,7 @@ // Levels // //////////// -struct LevelValues gLevelValues = { +struct LevelValues gDefaultLevelValues = { .entryLevel = LEVEL_CASTLE_GROUNDS, .exitCastleLevel = LEVEL_CASTLE, .exitCastleArea = 1, @@ -86,11 +86,13 @@ struct LevelValues gLevelValues = { }, }; +struct LevelValues gLevelValues = { 0 }; + /////////////// // Behaviors // /////////////// -struct BehaviorValues gBehaviorValues = { +struct BehaviorValues gDefaultBehaviorValues = { .KoopaBobAgility = 4.0f, .KoopaCatchupAgility = 8.0f, .KoopaThiAgility = 6.0f, @@ -218,3 +220,14 @@ struct BehaviorValues gBehaviorValues = { .PlatformLll2Trajectory = (Trajectory*) lll_seg7_trajectory_07028660, }, }; + +struct BehaviorValues gBehaviorValues = { 0 }; + + /////////////// + // functions // +/////////////// + +void hardcoded_reset_default_values(void) { + gLevelValues = gDefaultLevelValues; + gBehaviorValues = gDefaultBehaviorValues; +} diff --git a/src/game/hardcoded.h b/src/game/hardcoded.h index cca523b6b..1b8be2d80 100644 --- a/src/game/hardcoded.h +++ b/src/game/hardcoded.h @@ -195,4 +195,6 @@ struct BehaviorValues { extern struct BehaviorValues gBehaviorValues; +void hardcoded_reset_default_values(void); + #endif \ No newline at end of file diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c index a7a8c7d95..2af9cf141 100644 --- a/src/game/rendering_graph_node.c +++ b/src/game/rendering_graph_node.c @@ -378,10 +378,10 @@ static void geo_process_ortho_projection(struct GraphNodeOrthoProjection *node) if (node->node.children != NULL) { Mtx *mtx = alloc_display_list(sizeof(*mtx)); if (mtx == NULL) { return; } - f32 left = (gCurGraphNodeRoot->x - gCurGraphNodeRoot->width) / 2.0f * node->scale; - f32 right = (gCurGraphNodeRoot->x + gCurGraphNodeRoot->width) / 2.0f * node->scale; - f32 top = (gCurGraphNodeRoot->y - gCurGraphNodeRoot->height) / 2.0f * node->scale; - f32 bottom = (gCurGraphNodeRoot->y + gCurGraphNodeRoot->height) / 2.0f * node->scale; + f32 left = ((gCurGraphNodeRoot->x - gCurGraphNodeRoot->width) / 2.0f) * node->scale; + f32 right = ((gCurGraphNodeRoot->x + gCurGraphNodeRoot->width) / 2.0f) * node->scale; + f32 top = ((gCurGraphNodeRoot->y - gCurGraphNodeRoot->height) / 2.0f) * node->scale; + f32 bottom = ((gCurGraphNodeRoot->y + gCurGraphNodeRoot->height) / 2.0f) * node->scale; guOrtho(mtx, left, right, bottom, top, -2.0f, 2.0f, 1.0f); gSPPerspNormalize(gDisplayListHead++, 0xFFFF); @@ -404,10 +404,12 @@ static void geo_process_perspective(struct GraphNodePerspective *node) { Mtx *mtx = alloc_display_list(sizeof(*mtx)); if (mtx == NULL) { return; } + f32 divisor = (f32) gCurGraphNodeRoot->height; + if (divisor == 0) { divisor = 1; } #ifdef VERSION_EU - f32 aspect = ((f32) gCurGraphNodeRoot->width / (f32) gCurGraphNodeRoot->height) * 1.1f; + f32 aspect = ((f32) gCurGraphNodeRoot->width / divisor) * 1.1f; #else - f32 aspect = (f32) gCurGraphNodeRoot->width / (f32) gCurGraphNodeRoot->height; + f32 aspect = (f32) gCurGraphNodeRoot->width / divisor; #endif guPerspective(mtx, &perspNorm, not_zero(node->prevFov, gOverrideFOV), aspect, not_zero(node->near, gOverrideNear), not_zero(node->far, gOverrideFar), 1.0f); @@ -1066,7 +1068,9 @@ static s32 obj_is_in_view(struct GraphNodeObject *node, Mat4 matrix) { // Half of the fov in in-game angle units instead of degrees. s16 halfFov = (gCurGraphNodeCamFrustum->fov / 2.0f + 1.0f) * 32768.0f / 180.0f + 0.5f; - f32 hScreenEdge = -matrix[3][2] * sins(halfFov) / coss(halfFov); + f32 divisor = coss(halfFov); + if (divisor == 0) { divisor = 1; } + f32 hScreenEdge = -matrix[3][2] * sins(halfFov) / divisor; // -matrix[3][2] is the depth, which gets multiplied by tan(halfFov) to get // the amount of units between the center of the screen and the horizontal edge // given the distance from the object to the camera. diff --git a/src/pc/lua/smlua.c b/src/pc/lua/smlua.c index ed09391a5..f91e0186f 100644 --- a/src/pc/lua/smlua.c +++ b/src/pc/lua/smlua.c @@ -1,4 +1,5 @@ #include "smlua.h" +#include "game/hardcoded.h" #include "pc/mods/mods.h" #include "pc/mods/mods_utils.h" #include "pc/crash_handler.h" @@ -178,6 +179,7 @@ void smlua_update(void) { } void smlua_shutdown(void) { + hardcoded_reset_default_values(); smlua_text_utils_reset_all(); smlua_audio_utils_reset_all(); audio_custom_shutdown(); From a1ac1362580e7f31d33d710b341e0b8d9975f97a Mon Sep 17 00:00:00 2001 From: Isaac <62234577+Isaac0-dev@users.noreply.github.com> Date: Wed, 18 May 2022 09:24:56 +1000 Subject: [PATCH 03/13] change text depending on if you are client or server (#92) --- src/pc/djui/djui_panel_pause.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/pc/djui/djui_panel_pause.c b/src/pc/djui/djui_panel_pause.c index 16669434e..212905ed8 100644 --- a/src/pc/djui/djui_panel_pause.c +++ b/src/pc/djui/djui_panel_pause.c @@ -14,10 +14,17 @@ static void djui_panel_pause_quit_yes(UNUSED struct DjuiBase* caller) { } static void djui_panel_pause_quit(struct DjuiBase* caller) { - djui_panel_confirm_create(caller, - "\\#ff0800\\Q\\#1be700\\U\\#00b3ff\\I\\#ffef00\\T", - "Are you sure you want to disconnect?", - djui_panel_pause_quit_yes); + if (gNetworkType == NT_SERVER) { + djui_panel_confirm_create(caller, + "\\#ff0800\\Q\\#1be700\\U\\#00b3ff\\I\\#ffef00\\T", + "Are you sure you want to stop hosting?", + djui_panel_pause_quit_yes); + } else { + djui_panel_confirm_create(caller, + "\\#ff0800\\Q\\#1be700\\U\\#00b3ff\\I\\#ffef00\\T", + "Are you sure you want to disconnect?", + djui_panel_pause_quit_yes); + } } void djui_panel_pause_create(struct DjuiBase* caller) { @@ -48,7 +55,12 @@ void djui_panel_pause_create(struct DjuiBase* caller) { djui_base_set_size(&button2->base, 1.0f, 64); djui_interactable_hook_click(&button2->base, djui_panel_pause_resume); - struct DjuiButton* button3 = djui_button_create(&body->base, "Disconnect"); + struct DjuiButton* button3; + if (gNetworkType == NT_SERVER) { + button3 = djui_button_create(&body->base, "Stop Hosting"); + } else { + button3 = djui_button_create(&body->base, "Disconnect"); + } djui_base_set_size_type(&button3->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); djui_base_set_size(&button3->base, 1.0f, 64); djui_interactable_hook_click(&button3->base, djui_panel_pause_quit); From f63bffc64c88067756426a596a0f64526c9d3c36 Mon Sep 17 00:00:00 2001 From: mjcox244 <66311016+mjcox244@users.noreply.github.com> Date: Fri, 20 May 2022 00:33:17 +0100 Subject: [PATCH 04/13] Add Icon to windows build (#96) --- Makefile | 19 ++++++++++++++++++- res/icon.ico | Bin 0 -> 410598 bytes res/icon.rc | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 res/icon.ico create mode 100644 res/icon.rc diff --git a/Makefile b/Makefile index 44fca33d4..e41f221aa 100644 --- a/Makefile +++ b/Makefile @@ -64,6 +64,8 @@ DOCKERBUILD ?= 0 DEBUG_INFO_LEVEL ?= 2 # Enable profiling PROFILE ?= 0 +# Enable Game ICON +ICON ?= 1 # Various workarounds for weird toolchains @@ -891,6 +893,19 @@ else # endif endif +#icon +ifeq ($(WINDOWS_BUILD),1) + ifeq ($(ICON),1) + Command := mkdir $(BUILD_DIR)/res + Resp := $(shell $(call Command)) + + Command := windres -o "$(BUILD_DIR)/res/icon.o" -i res/icon.rc + Resp := $(shell $(call Command)) + + LDFLAGS += $(BUILD_DIR)/res/icon.o + endif +endif + # Coop specific libraries # Lua @@ -1093,6 +1108,8 @@ endef # Main Targets # #==============================================================================# + + ifeq ($(EXTERNAL_DATA),1) BASEPACK_PATH := $(BUILD_DIR)/$(BASEDIR)/$(BASEPACK) @@ -1545,4 +1562,4 @@ MAKEFLAGS += --no-builtin-rules -include $(DEP_FILES) -print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true \ No newline at end of file +print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true diff --git a/res/icon.ico b/res/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..a147df06c081ff6132599e52810c65596562c7b8 GIT binary patch literal 410598 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 literal 0 HcmV?d00001 diff --git a/res/icon.rc b/res/icon.rc new file mode 100644 index 000000000..7e84e50bf --- /dev/null +++ b/res/icon.rc @@ -0,0 +1 @@ +id ICON res/icon.ico \ No newline at end of file From 4fbafc27089ce2304cbb91ad309f44f899a06d50 Mon Sep 17 00:00:00 2001 From: PeachyPeach <72323920+PeachyPeachSM64@users.noreply.github.com> Date: Fri, 20 May 2022 01:40:45 +0200 Subject: [PATCH 05/13] Fixed various audio bugs; DynOS can now detect texture duplicates to decrease generated bin files size (#110) Fixed the following audio bugs: Bug: Rom-hacks sequences don't seem to be affected by volume scaling and muting Fix: Force the BGM sequences to follow the vanilla behavior: Volume can't go higher than default volume Volume is reduced to 31% when the game is paused Audio is stopped when the game is paused outside the Castle levels Bug: (Pointed out by Draco) Mario's voice clips are not replaced by the player's character's in the following instances: fall to death barrier, "here we go" in the ending cutscene, "let's a go" after selecting a star, "okey dokey" after starting the game. Fix: The first two ones now call play_character_sound(m, CHAR_SOUND_...) instead of play_sound(SOUND_MARIO_..., pos). The last two ones couldn't be fixed the same way for two reasons: First, the corresponding sounds were not referenced in the sound table, second, the sound played is always cut-off after a few frames (due to how sm64 resets the sound banks after loading a level). Added SOUND_*_LETS_A_GO and SOUND_*_OKEY_DOKEY sounds for each playable character as Bass samples. Character Bass sounds work the same way as vanilla sounds (i.e. can be played with play_character_sound), but they cannot be prematurely stopped by sm64 sound banks shenanigans. This fixes the cut-off for both the star select and the castle grounds entry, plays the sound corresponding to the player's character, and doesn't need to extend or edit the sound table. DynOS can detect texture duplicates when generating a bin or lvl file. When a duplicate is detected, the name of the original texture node is written instead of the whole PNG data, decreasing significantly the resulting file size. --- Makefile | 4 ++ autogen/lua_definitions/constants.lua | 8 ++- autogen/lua_definitions/structs.lua | 2 + data/dynos.cpp.h | 1 + data/dynos_bin_tex.cpp | 64 +++++++++++++---- docs/lua/constants.md | 4 +- docs/lua/structs.md | 2 + src/audio/effects.c | 10 +++ src/audio/external.c | 22 ++++++ src/audio/external.h | 1 + src/game/characters.c | 48 +++++++++---- src/game/characters.h | 4 ++ src/game/characters_bass_sounds.h | 99 +++++++++++++++++++++++++++ src/game/interaction.c | 2 +- src/game/mario.c | 3 +- src/game/mario_actions_cutscene.c | 2 +- src/menu/star_select.c | 4 +- src/pc/djui/djui_panel_host_message.c | 3 +- src/pc/lua/smlua_cobject_autogen.c | 4 +- src/pc/lua/smlua_constants_autogen.c | 4 +- 20 files changed, 255 insertions(+), 36 deletions(-) create mode 100644 src/game/characters_bass_sounds.h diff --git a/Makefile b/Makefile index e41f221aa..59372def6 100644 --- a/Makefile +++ b/Makefile @@ -1194,6 +1194,7 @@ ifeq ($(TARGET_N64),1) $(BUILD_DIR)/lib/rsp.o: $(BUILD_DIR)/rsp/rspboot.bin $(BUILD_DIR)/rsp/fast3d.bin $(BUILD_DIR)/rsp/audio.bin endif +$(BUILD_DIR)/src/game/characters.o: $(SOUND_SAMPLE_TABLES) $(SOUND_BIN_DIR)/sound_data.o: $(SOUND_BIN_DIR)/sound_data.ctl.inc.c $(SOUND_BIN_DIR)/sound_data.tbl.inc.c $(SOUND_BIN_DIR)/sequences.bin.inc.c $(SOUND_BIN_DIR)/bank_sets.inc.c $(BUILD_DIR)/levels/scripts.o: $(BUILD_DIR)/include/level_headers.h @@ -1321,6 +1322,9 @@ endif $(BUILD_DIR)/%.table: %.aiff $(call print,Extracting codebook:,$<,$@) $(V)$(AIFF_EXTRACT_CODEBOOK) $< >$@ + $(call print,Piping:,$<,$@.inc.c) + $(V)hexdump -v -e '1/1 "0x%X,"' $< > $@.inc.c + $(V)echo >> $@.inc.c $(BUILD_DIR)/%.aifc: $(BUILD_DIR)/%.table %.aiff $(call print,Encoding VADPCM:,$<,$@) diff --git a/autogen/lua_definitions/constants.lua b/autogen/lua_definitions/constants.lua index 0d7c729ea..b55e00227 100644 --- a/autogen/lua_definitions/constants.lua +++ b/autogen/lua_definitions/constants.lua @@ -2615,7 +2615,13 @@ CHAR_SOUND_SO_LONGA_BOWSER = 40 CHAR_SOUND_IMA_TIRED = 41 --- @type CharacterSound -CHAR_SOUND_MAX = 42 +CHAR_SOUND_LETS_A_GO = 42 + +--- @type CharacterSound +CHAR_SOUND_OKEY_DOKEY = 43 + +--- @type CharacterSound +CHAR_SOUND_MAX = 44 --- @class CharacterType diff --git a/autogen/lua_definitions/structs.lua b/autogen/lua_definitions/structs.lua index 1ae94c1a0..028c0e7e0 100644 --- a/autogen/lua_definitions/structs.lua +++ b/autogen/lua_definitions/structs.lua @@ -269,7 +269,9 @@ --- @field public soundHoohoo integer --- @field public soundHrmm integer --- @field public soundImaTired integer +--- @field public soundLetsAGo integer --- @field public soundMamaMia integer +--- @field public soundOkeyDokey integer --- @field public soundOnFire integer --- @field public soundOoof integer --- @field public soundOoof2 integer diff --git a/data/dynos.cpp.h b/data/dynos.cpp.h index 05355e9f8..7439dc397 100644 --- a/data/dynos.cpp.h +++ b/data/dynos.cpp.h @@ -11,6 +11,7 @@ extern "C" { #define FUNCTION_CODE (u32) 0x434E5546 #define POINTER_CODE (u32) 0x52544E50 #define LUA_VAR_CODE (u32) 0x5641554C +#define TEX_REF_CODE (u32) 0x52584554 #define MOD_PACK_INDEX 99 diff --git a/data/dynos_bin_tex.cpp b/data/dynos_bin_tex.cpp index 67a675d1f..9fcd09026 100644 --- a/data/dynos_bin_tex.cpp +++ b/data/dynos_bin_tex.cpp @@ -159,6 +159,22 @@ void DynOS_Tex_Write(FILE* aFile, GfxData* aGfxData, DataNode *aNode) { aNode->mName.Write(aFile); // Data + // Look for texture duplicates + // If that's the case, store the name of the texture node instead of the whole PNG data + // (Don't bother to look for duplicates if there is no data to write) + if (!aNode->mData->mPngData.Empty()) { + for (const auto& _Node : aGfxData->mTextures) { + if (_Node->mLoadIndex < aNode->mLoadIndex && // Check load order: duplicates should reference only an already loaded node + _Node->mData != NULL && // Check node data + aNode->mData->mPngData.Count() == _Node->mData->mPngData.Count() && // Check PNG data lengths + memcmp(aNode->mData->mPngData.begin(), _Node->mData->mPngData.begin(), aNode->mData->mPngData.Count()) == 0) // Check PNG data content + { + WriteBytes(aFile, TEX_REF_CODE); + _Node->mName.Write(aFile); + return; + } + } + } aNode->mData->mPngData.Write(aFile); } @@ -220,19 +236,41 @@ DataNode* DynOS_Tex_Load(FILE *aFile, GfxData *aGfxData) { // Data _Node->mData = New(); _Node->mData->mUploaded = false; - _Node->mData->mPngData.Read(aFile); - if (!_Node->mData->mPngData.Empty()) { - u8 *_RawData = stbi_load_from_memory(_Node->mData->mPngData.begin(), _Node->mData->mPngData.Count(), &_Node->mData->mRawWidth, &_Node->mData->mRawHeight, NULL, 4); - _Node->mData->mRawFormat = G_IM_FMT_RGBA; - _Node->mData->mRawSize = G_IM_SIZ_32b; - _Node->mData->mRawData = Array(_RawData, _RawData + (_Node->mData->mRawWidth * _Node->mData->mRawHeight * 4)); - free(_RawData); - } else { // Probably a palette - _Node->mData->mRawData = Array(); - _Node->mData->mRawWidth = 0; - _Node->mData->mRawHeight = 0; - _Node->mData->mRawFormat = 0; - _Node->mData->mRawSize = 0; + + // Check for the texture ref magic + s32 _FileOffset = (s32) ftell(aFile); + u32 _TexRefCode = ReadBytes(aFile); + if (_TexRefCode == TEX_REF_CODE) { + + // That's a duplicate, find the original node and copy its content + String _NodeName; _NodeName.Read(aFile); + for (const auto& _LoadedNode : aGfxData->mTextures) { + if (_LoadedNode->mName == _NodeName) { + _Node->mData->mPngData = _LoadedNode->mData->mPngData; + _Node->mData->mRawData = _LoadedNode->mData->mRawData; + _Node->mData->mRawWidth = _LoadedNode->mData->mRawWidth; + _Node->mData->mRawHeight = _LoadedNode->mData->mRawHeight; + _Node->mData->mRawFormat = _LoadedNode->mData->mRawFormat; + _Node->mData->mRawSize = _LoadedNode->mData->mRawSize; + break; + } + } + } else { + fseek(aFile, _FileOffset, SEEK_SET); + _Node->mData->mPngData.Read(aFile); + if (!_Node->mData->mPngData.Empty()) { + u8 *_RawData = stbi_load_from_memory(_Node->mData->mPngData.begin(), _Node->mData->mPngData.Count(), &_Node->mData->mRawWidth, &_Node->mData->mRawHeight, NULL, 4); + _Node->mData->mRawFormat = G_IM_FMT_RGBA; + _Node->mData->mRawSize = G_IM_SIZ_32b; + _Node->mData->mRawData = Array(_RawData, _RawData + (_Node->mData->mRawWidth * _Node->mData->mRawHeight * 4)); + free(_RawData); + } else { // Probably a palette + _Node->mData->mRawData = Array(); + _Node->mData->mRawWidth = 0; + _Node->mData->mRawHeight = 0; + _Node->mData->mRawFormat = 0; + _Node->mData->mRawSize = 0; + } } // Append diff --git a/docs/lua/constants.md b/docs/lua/constants.md index 4dda0b0ec..91ec51720 100644 --- a/docs/lua/constants.md +++ b/docs/lua/constants.md @@ -836,7 +836,9 @@ | CHAR_SOUND_SNORING3 | 39 | | CHAR_SOUND_SO_LONGA_BOWSER | 40 | | CHAR_SOUND_IMA_TIRED | 41 | -| CHAR_SOUND_MAX | 42 | +| CHAR_SOUND_LETS_A_GO | 42 | +| CHAR_SOUND_OKEY_DOKEY | 43 | +| CHAR_SOUND_MAX | 44 | ### [enum CharacterType](#CharacterType) | Identifier | Value | diff --git a/docs/lua/structs.md b/docs/lua/structs.md index ce2ac1925..46173ce09 100644 --- a/docs/lua/structs.md +++ b/docs/lua/structs.md @@ -436,7 +436,9 @@ | soundHoohoo | `integer` | read-only | | soundHrmm | `integer` | read-only | | soundImaTired | `integer` | read-only | +| soundLetsAGo | `integer` | read-only | | soundMamaMia | `integer` | read-only | +| soundOkeyDokey | `integer` | read-only | | soundOnFire | `integer` | read-only | | soundOoof | `integer` | read-only | | soundOoof2 | `integer` | read-only | diff --git a/src/audio/effects.c b/src/audio/effects.c index 801d98b51..45b67ce7f 100644 --- a/src/audio/effects.c +++ b/src/audio/effects.c @@ -63,6 +63,16 @@ static void sequence_channel_process_sound(struct SequenceChannel *seqChannel) { f32 panFromChannel; s32 i; + // Rom-hacks audio fix + // Force the BGM sequence channels to follow the BGM sequence player mute behavior + // Make the audio completely silent if MUTE_BEHAVIOR_STOP_SCRIPT or MUTE_BEHAVIOR_STOP_NOTES is set + if (seqChannel->seqPlayer == &gSequencePlayers[0]) { + seqChannel->muteBehavior = seqChannel->seqPlayer->muteBehavior; + if (seqChannel->seqPlayer->muted && (seqChannel->muteBehavior & (MUTE_BEHAVIOR_STOP_SCRIPT | MUTE_BEHAVIOR_STOP_NOTES)) != 0) { + seqChannel->seqPlayer->muteVolumeScale = 0.f; + } + } + channelVolume = seqChannel->volume * seqChannel->volumeScale * seqChannel->seqPlayer->fadeVolume * seqChannel->seqPlayer->volumeScale; if (seqChannel->seqPlayer->muted && (seqChannel->muteBehavior & MUTE_BEHAVIOR_SOFTEN) != 0) { diff --git a/src/audio/external.c b/src/audio/external.c index d6f690532..821d73129 100644 --- a/src/audio/external.c +++ b/src/audio/external.c @@ -2356,6 +2356,21 @@ void play_dialog_sound(u8 dialogID) { void set_sequence_player_volume(s32 player, f32 volume) { gSequencePlayers[player].volumeScale = volume; + + // Rom-hacks audio fix + // Custom sequences tend to ignore volume scaling and muting... + // Force the BGM sequence player to follow the Vanilla behavior: + // - Volume can't go higher than default volume + // - Volume is reduced to 31% when the game is paused + // - Audio is stopped when the game is paused outside the Castle levels + if (player == SEQ_PLAYER_LEVEL && sCurrentBackgroundMusicSeqId != 0xff) { + struct SequencePlayer *seqPlayer = &gSequencePlayers[player]; + f32 maxVolume = get_current_background_music_default_volume() / 127.f; + seqPlayer->volume = MIN(seqPlayer->volume, maxVolume); + seqPlayer->fadeVolume = MIN(seqPlayer->fadeVolume, maxVolume); + seqPlayer->muteVolumeScale = 0.31f; + seqPlayer->muteBehavior = MUTE_BEHAVIOR_SOFTEN | ((gCurrCourseNum != 0) * (MUTE_BEHAVIOR_STOP_SCRIPT | MUTE_BEHAVIOR_STOP_NOTES)); + } } /** @@ -2509,6 +2524,13 @@ u16 get_current_background_music(void) { return -1; } +u8 get_current_background_music_default_volume(void) { + if (sCurrentBackgroundMusicSeqId != 0xff) { + return sBackgroundMusicDefaultVolume[sCurrentBackgroundMusicSeqId]; + } + return 0; +} + u8 get_current_background_music_target_volume(void) { return sBackgroundMusicTargetVolume; } diff --git a/src/audio/external.h b/src/audio/external.h index 3d3c3fbe6..61f5c0320 100644 --- a/src/audio/external.h +++ b/src/audio/external.h @@ -53,6 +53,7 @@ void stop_background_music(u16 seqId); void fadeout_background_music(u16 arg0, u16 fadeOut); void drop_queued_background_music(void); u16 get_current_background_music(void); +u8 get_current_background_music_default_volume(void); u8 get_current_background_music_target_volume(void); u8 get_current_background_music_max_target_volume(void); u8 is_current_background_music_volume_lowered(void); diff --git a/src/game/characters.c b/src/game/characters.c index 7405e2adb..96025af90 100644 --- a/src/game/characters.c +++ b/src/game/characters.c @@ -10,7 +10,7 @@ #include "pc/configfile.h" #include "audio/external.h" #include "engine/graph_node.h" -#include "types.h" +#include "characters_bass_sounds.h" extern Gfx mario_cap_seg3_dl_03022F48[]; extern Gfx luigi_cap_seg3_dl_03022F48[]; @@ -87,6 +87,8 @@ struct Character gCharacters[CT_MAX] = { .soundSnoring3 = SOUND_MARIO_SNORING3, .soundSoLongaBowser = SOUND_MARIO_SO_LONGA_BOWSER, .soundImaTired = SOUND_MARIO_IMA_TIRED, + .soundLetsAGo = CHAR_BASS_SOUND(SOUND_MARIO_LETS_A_GO), + .soundOkeyDokey = CHAR_BASS_SOUND(SOUND_MARIO_OKEY_DOKEY), }, [CT_LUIGI] = { @@ -150,6 +152,8 @@ struct Character gCharacters[CT_MAX] = { .soundSnoring3 = SOUND_LUIGI_SNORING3, .soundSoLongaBowser = SOUND_LUIGI_SO_LONGA_BOWSER, .soundImaTired = SOUND_LUIGI_IMA_TIRED, + .soundLetsAGo = CHAR_BASS_SOUND(SOUND_LUIGI_LETS_A_GO), + .soundOkeyDokey = CHAR_BASS_SOUND(SOUND_LUIGI_OKEY_DOKEY), }, [CT_TOAD] = { @@ -213,6 +217,8 @@ struct Character gCharacters[CT_MAX] = { .soundSnoring3 = SOUND_MARIO_SNORING3, .soundSoLongaBowser = SOUND_MARIO_SO_LONGA_BOWSER, .soundImaTired = SOUND_MARIO_IMA_TIRED, + .soundLetsAGo = CHAR_BASS_SOUND(SOUND_MARIO_LETS_A_GO), + .soundOkeyDokey = CHAR_BASS_SOUND(SOUND_MARIO_OKEY_DOKEY), }, [CT_WALUIGI] = { @@ -279,6 +285,8 @@ struct Character gCharacters[CT_MAX] = { .soundSnoring3 = SOUND_LUIGI_SNORING3, .soundSoLongaBowser = SOUND_LUIGI_SO_LONGA_BOWSER, .soundImaTired = SOUND_LUIGI_IMA_TIRED, + .soundLetsAGo = CHAR_BASS_SOUND(SOUND_LUIGI_LETS_A_GO), + .soundOkeyDokey = CHAR_BASS_SOUND(SOUND_LUIGI_OKEY_DOKEY), }, [CT_WARIO] = { @@ -342,6 +350,8 @@ struct Character gCharacters[CT_MAX] = { .soundSnoring3 = SOUND_WARIO_SNORING3, .soundSoLongaBowser = SOUND_WARIO_SO_LONGA_BOWSER, .soundImaTired = SOUND_WARIO_IMA_TIRED, + .soundLetsAGo = CHAR_BASS_SOUND(SOUND_WARIO_LETS_A_GO), + .soundOkeyDokey = CHAR_BASS_SOUND(SOUND_WARIO_OKEY_DOKEY), }, }; @@ -450,29 +460,41 @@ static s32 get_character_sound(struct MarioState* m, enum CharacterSound charact case CHAR_SOUND_SNORING3: return character->soundSnoring3; case CHAR_SOUND_SO_LONGA_BOWSER: return character->soundSoLongaBowser; case CHAR_SOUND_IMA_TIRED: return character->soundImaTired; + case CHAR_SOUND_LETS_A_GO: return character->soundLetsAGo; + case CHAR_SOUND_OKEY_DOKEY: return character->soundOkeyDokey; default: return 0; } } +static void play_character_sound_internal(struct MarioState *m, enum CharacterSound characterSound, u32 offset, u32 flags) { + if (m != NULL && (m->flags & flags) == 0) { + s32 sound = get_character_sound(m, characterSound); + if (sound != 0) { + struct Character* character = get_character(m); + f32 *pos = (m->marioObj != NULL ? m->marioObj->header.gfx.cameraToObject : gGlobalSoundSource); + if ((u32) (sound & CHAR_BASS_MAGIC) == CHAR_BASS_MAGIC) { + CharacterBassSound *cbs = get_character_bass_sound(sound); + if (cbs != NULL) { + play_character_bass_sound(cbs, pos, character->soundFreqScale); + } + } else { + play_sound_with_freq_scale(sound + offset, pos, character->soundFreqScale); + } + } + m->flags |= flags; + } +} + void play_character_sound(struct MarioState* m, enum CharacterSound characterSound) { - s32 sound = get_character_sound(m, characterSound); - if (sound == 0) { return; } - struct Character* character = get_character(m); - play_sound_with_freq_scale(sound, m->marioObj->header.gfx.cameraToObject, character->soundFreqScale); + play_character_sound_internal(m, characterSound, 0, 0); } void play_character_sound_offset(struct MarioState* m, enum CharacterSound characterSound, u32 offset) { - s32 sound = get_character_sound(m, characterSound); - if (sound == 0) { return; } - struct Character* character = get_character(m); - play_sound_with_freq_scale(sound + offset, m->marioObj->header.gfx.cameraToObject, character->soundFreqScale); + play_character_sound_internal(m, characterSound, offset, 0); } void play_character_sound_if_no_flag(struct MarioState* m, enum CharacterSound characterSound, u32 flags) { - if ((m->flags & flags) == 0) { - play_character_sound(m, characterSound); - m->flags |= flags; - } + play_character_sound_internal(m, characterSound, 0, flags); } f32 get_character_anim_offset(struct MarioState* m) { diff --git a/src/game/characters.h b/src/game/characters.h index 05c97d631..8aaf1d5c3 100644 --- a/src/game/characters.h +++ b/src/game/characters.h @@ -81,6 +81,8 @@ struct Character { s32 soundSnoring3; s32 soundSoLongaBowser; s32 soundImaTired; + s32 soundLetsAGo; + s32 soundOkeyDokey; }; enum CharacterSound { @@ -126,6 +128,8 @@ enum CharacterSound { CHAR_SOUND_SNORING3, CHAR_SOUND_SO_LONGA_BOWSER, CHAR_SOUND_IMA_TIRED, + CHAR_SOUND_LETS_A_GO, + CHAR_SOUND_OKEY_DOKEY, CHAR_SOUND_MAX // MUST BE LAST }; diff --git a/src/game/characters_bass_sounds.h b/src/game/characters_bass_sounds.h new file mode 100644 index 000000000..a3fe191c5 --- /dev/null +++ b/src/game/characters_bass_sounds.h @@ -0,0 +1,99 @@ +#include "types.h" +#include "bass/bass.h" +#include "game/camera.h" +#undef min // Redefined in math_util.h, undef it to avoid compiler warnings +#undef max // Redefined in math_util.h, undef it to avoid compiler warnings +#include "engine/math_util.h" + +#define H01(s, i, x) (x * 65599u + (u8) s[(i) < sizeof(s) ? (i) : sizeof(s)]) +#define H04(s, i, x) H01(s, i, H01(s, i + 1, H01(s, i + 2, H01(s, i + 3, x)))) +#define H16(s, i, x) H04(s, i, H04(s, i + 4, H04(s, i + 8, H04(s, i + 12, x)))) +#define H64(s, i, x) H16(s, i, H16(s, i + 16, H16(s, i + 32, H16(s, i + 48, x)))) +#define CHAR_BASS_MAGIC 0xFF000000u +#define CHAR_BASS_SOUND_ID(name) (H64(#name "________________________________________________________________", 0, 0) & ~CHAR_BASS_MAGIC) +#define CHAR_BASS_SOUND(name) (CHAR_BASS_MAGIC | CHAR_BASS_SOUND_ID(name)) +#define CHAR_BASS_SOUND_NOT_LOADED 0xFFFFFFFFu +#define DECL_CHAR_BASS_SOUND_RAW(name, ...) static const u8 sCharacterBassSoundRaw_##name[] = +#define DECL_CHAR_BASS_SOUND(name) { CHAR_BASS_SOUND(name), (s32) sizeof(sCharacterBassSoundRaw_##name), sCharacterBassSoundRaw_##name, CHAR_BASS_SOUND_NOT_LOADED, 0.f } + +// Undef these to avoid naming issues +#undef SOUND_MARIO_LETS_A_GO +#undef SOUND_LUIGI_LETS_A_GO +#undef SOUND_WARIO_LETS_A_GO +#undef SOUND_MARIO_OKEY_DOKEY +#undef SOUND_LUIGI_OKEY_DOKEY +#undef SOUND_WARIO_OKEY_DOKEY + +///////////////// +// Bass sounds // +///////////////// + +DECL_CHAR_BASS_SOUND_RAW(SOUND_MARIO_LETS_A_GO) { +#include "sound/samples/sfx_mario/1A_mario_lets_a_go.table.inc.c" +}; + +DECL_CHAR_BASS_SOUND_RAW(SOUND_LUIGI_LETS_A_GO) { +#include "sound/samples/sfx_custom_luigi/1A.table.inc.c" +}; + +DECL_CHAR_BASS_SOUND_RAW(SOUND_WARIO_LETS_A_GO) { +#include "sound/samples/sfx_custom_wario/1A.table.inc.c" +}; + +DECL_CHAR_BASS_SOUND_RAW(SOUND_MARIO_OKEY_DOKEY) { +#include "sound/samples/sfx_mario_peach/0B_mario_okey_dokey.table.inc.c" +}; + +DECL_CHAR_BASS_SOUND_RAW(SOUND_LUIGI_OKEY_DOKEY) { +#include "sound/samples/sfx_custom_luigi_peach/0B.table.inc.c" +}; + +DECL_CHAR_BASS_SOUND_RAW(SOUND_WARIO_OKEY_DOKEY) { +#include "sound/samples/sfx_custom_wario_peach/0B.table.inc.c" +}; + +/////////////////////// +// Bass sounds table // +/////////////////////// + +typedef struct { s32 sound; s32 size; const u8 *raw; HSAMPLE sample; f32 freq; } CharacterBassSound; +static CharacterBassSound sCharacterBassSounds[] = { + DECL_CHAR_BASS_SOUND(SOUND_MARIO_LETS_A_GO), + DECL_CHAR_BASS_SOUND(SOUND_LUIGI_LETS_A_GO), + DECL_CHAR_BASS_SOUND(SOUND_WARIO_LETS_A_GO), + DECL_CHAR_BASS_SOUND(SOUND_MARIO_OKEY_DOKEY), + DECL_CHAR_BASS_SOUND(SOUND_LUIGI_OKEY_DOKEY), + DECL_CHAR_BASS_SOUND(SOUND_WARIO_OKEY_DOKEY), + { 0, 0, NULL, CHAR_BASS_SOUND_NOT_LOADED, 0.f }, +}; + +/////////////////////////// +// Bass sounds functions // +/////////////////////////// + +static CharacterBassSound *get_character_bass_sound(s32 sound) { + for (CharacterBassSound *cbs = sCharacterBassSounds; cbs->raw != NULL; cbs++) { + if (cbs->sound == sound) { + return cbs; + } + } + return NULL; +} + +static void play_character_bass_sound(CharacterBassSound *cbs, f32 *pos, f32 freqScale) { + if (cbs->sample == CHAR_BASS_SOUND_NOT_LOADED) { + cbs->sample = BASS_SampleLoad(TRUE, cbs->raw, 0, cbs->size, 32, BASS_SAMPLE_OVER_POS); + BASS_SAMPLE info; BASS_SampleGetInfo(cbs->sample, &info); + cbs->freq = info.freq; + } + DWORD handle = BASS_SampleGetChannel(cbs->sample, 0); + f32 dist = vec3f_length(pos); + f32 pan = (get_sound_pan(pos[0], pos[2]) - 0.5f) * 2.f; + f32 intensity = sound_get_level_intensity(dist); + f32 masterVolume = (f32) configMasterVolume / 127.f; + f32 sfxVolume = (f32) configSfxVolume / 127.f; + BASS_ChannelSetAttribute(handle, BASS_ATTRIB_VOL, masterVolume * sfxVolume * intensity * 0.75f); + BASS_ChannelSetAttribute(handle, BASS_ATTRIB_PAN, pan); + BASS_ChannelSetAttribute(handle, BASS_ATTRIB_FREQ, cbs->freq * freqScale); + BASS_ChannelPlay(handle, TRUE); +} diff --git a/src/game/interaction.c b/src/game/interaction.c index a8afe1753..c9c9eaec4 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -2237,7 +2237,7 @@ void check_death_barrier(struct MarioState *m) { } if (level_trigger_warp(m, WARP_OP_WARP_FLOOR) == 20 && !(m->flags & MARIO_UNKNOWN_18)) { - play_sound(SOUND_MARIO_WAAAOOOW, m->marioObj->header.gfx.cameraToObject); + play_character_sound(m, CHAR_SOUND_WAAAOOOW); } } } diff --git a/src/game/mario.c b/src/game/mario.c index 43ebb2e14..5dba7dc05 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -319,8 +319,7 @@ void play_sound_and_spawn_particles(struct MarioState *m, u32 soundBits, u32 wav return; } - if ((m->flags & MARIO_METAL_CAP) || soundBits == SOUND_ACTION_UNSTUCK_FROM_GROUND - || soundBits == SOUND_MARIO_PUNCH_HOO || soundBits == SOUND_LUIGI_PUNCH_HOO) { + if ((m->flags & MARIO_METAL_CAP) || soundBits == SOUND_ACTION_UNSTUCK_FROM_GROUND) { play_sound(soundBits, m->marioObj->header.gfx.cameraToObject); } else { play_sound(m->terrainSoundAddend + soundBits, m->marioObj->header.gfx.cameraToObject); diff --git a/src/game/mario_actions_cutscene.c b/src/game/mario_actions_cutscene.c index bed82c7a4..31b063028 100644 --- a/src/game/mario_actions_cutscene.c +++ b/src/game/mario_actions_cutscene.c @@ -2643,7 +2643,7 @@ static void end_peach_cutscene_star_dance(struct MarioState *m) { cutscene_put_cap_on(m); } if (animFrame == 88 && m->playerIndex == 0) { - play_sound(SOUND_MARIO_HERE_WE_GO, m->marioObj->header.gfx.cameraToObject); + play_character_sound(m, CHAR_SOUND_HERE_WE_GO); } if (!nonMario && animFrame >= 98) { m->marioBodyState->handState = MARIO_HAND_PEACE_SIGN; diff --git a/src/menu/star_select.c b/src/menu/star_select.c index 19f6aeb9e..34bd1453f 100644 --- a/src/menu/star_select.c +++ b/src/menu/star_select.c @@ -501,7 +501,9 @@ void star_select_finish_selection(void) { #if defined(VERSION_JP) play_sound(SOUND_MENU_STAR_SOUND, gGlobalSoundSource); #else - play_sound(SOUND_MENU_STAR_SOUND_LETS_A_GO, gGlobalSoundSource); + if (gMarioState->marioObj) vec3f_copy(gMarioState->marioObj->header.gfx.cameraToObject, gGlobalSoundSource); + play_character_sound(gMarioState, CHAR_SOUND_LETS_A_GO); + play_sound(SOUND_MENU_STAR_SOUND, gGlobalSoundSource); #endif #ifdef VERSION_SH queue_rumble_data(60, 70); diff --git a/src/pc/djui/djui_panel_host_message.c b/src/pc/djui/djui_panel_host_message.c index ff700ba96..547d0f359 100644 --- a/src/pc/djui/djui_panel_host_message.c +++ b/src/pc/djui/djui_panel_host_message.c @@ -46,7 +46,8 @@ void djui_panel_host_message_do_host(UNUSED struct DjuiBase* caller) { fake_lvl_init_from_save_file(); extern s16 gChangeLevelTransition; gChangeLevelTransition = gLevelValues.entryLevel; - play_sound(SOUND_MENU_STAR_SOUND_OKEY_DOKEY, gGlobalSoundSource); + if (gMarioState->marioObj) vec3f_copy(gMarioState->marioObj->header.gfx.cameraToObject, gGlobalSoundSource); + play_character_sound(gMarioState, CHAR_SOUND_OKEY_DOKEY); extern void play_transition(s16 transType, s16 time, u8 red, u8 green, u8 blue); play_transition(0x09, 0x14, 0x00, 0x00, 0x00); } diff --git a/src/pc/lua/smlua_cobject_autogen.c b/src/pc/lua/smlua_cobject_autogen.c index 43c71074b..03a5de2fd 100644 --- a/src/pc/lua/smlua_cobject_autogen.c +++ b/src/pc/lua/smlua_cobject_autogen.c @@ -293,7 +293,7 @@ static struct LuaObjectField sChainSegmentFields[LUA_CHAIN_SEGMENT_FIELD_COUNT] { "yaw", LVT_S16, offsetof(struct ChainSegment, yaw), false, LOT_NONE }, }; -#define LUA_CHARACTER_FIELD_COUNT 59 +#define LUA_CHARACTER_FIELD_COUNT 61 static struct LuaObjectField sCharacterFields[LUA_CHARACTER_FIELD_COUNT] = { { "animOffsetEnabled", LVT_U8, offsetof(struct Character, animOffsetEnabled), true, LOT_NONE }, { "animOffsetFeet", LVT_F32, offsetof(struct Character, animOffsetFeet), true, LOT_NONE }, @@ -329,7 +329,9 @@ static struct LuaObjectField sCharacterFields[LUA_CHARACTER_FIELD_COUNT] = { { "soundHoohoo", LVT_S32, offsetof(struct Character, soundHoohoo), true, LOT_NONE }, { "soundHrmm", LVT_S32, offsetof(struct Character, soundHrmm), true, LOT_NONE }, { "soundImaTired", LVT_S32, offsetof(struct Character, soundImaTired), true, LOT_NONE }, + { "soundLetsAGo", LVT_S32, offsetof(struct Character, soundLetsAGo), true, LOT_NONE }, { "soundMamaMia", LVT_S32, offsetof(struct Character, soundMamaMia), true, LOT_NONE }, + { "soundOkeyDokey", LVT_S32, offsetof(struct Character, soundOkeyDokey), true, LOT_NONE }, { "soundOnFire", LVT_S32, offsetof(struct Character, soundOnFire), true, LOT_NONE }, { "soundOoof", LVT_S32, offsetof(struct Character, soundOoof), true, LOT_NONE }, { "soundOoof2", LVT_S32, offsetof(struct Character, soundOoof2), true, LOT_NONE }, diff --git a/src/pc/lua/smlua_constants_autogen.c b/src/pc/lua/smlua_constants_autogen.c index 90212a695..b68a86662 100644 --- a/src/pc/lua/smlua_constants_autogen.c +++ b/src/pc/lua/smlua_constants_autogen.c @@ -1071,7 +1071,9 @@ char gSmluaConstants[] = "" "CHAR_SOUND_SNORING3 = 39\n" "CHAR_SOUND_SO_LONGA_BOWSER = 40\n" "CHAR_SOUND_IMA_TIRED = 41\n" -"CHAR_SOUND_MAX = 42\n" +"CHAR_SOUND_LETS_A_GO = 42\n" +"CHAR_SOUND_OKEY_DOKEY = 43\n" +"CHAR_SOUND_MAX = 44\n" "DIALOG_000 = 0\n" "DIALOG_001 = 1\n" "DIALOG_002 = 2\n" From 0c7ada8d2b916af8c25f530dd5e9653d7820533b Mon Sep 17 00:00:00 2001 From: Marioiscool246 Date: Thu, 19 May 2022 19:52:47 -0400 Subject: [PATCH 06/13] C-Up Player Head Rotation Fix & Particle Flags Sync Fix (#99) Local head rotation is now no longer copied to all other players C-Up mode head rotation now sends to the other players through the player packet so others can see the head move around m->particleFlags are now synced to the other players now --- src/game/interaction.c | 6 ++-- src/game/mario.c | 22 ++++++++++---- src/game/mario.h | 1 + src/game/mario_actions_airborne.c | 40 +++++++++++++------------- src/game/mario_actions_automatic.c | 4 +-- src/game/mario_actions_cutscene.c | 18 ++++++------ src/game/mario_actions_moving.c | 36 +++++++++++------------ src/game/mario_actions_object.c | 2 +- src/game/mario_actions_stationary.c | 4 +-- src/game/mario_actions_submerged.c | 12 ++++---- src/game/mario_misc.c | 6 ++-- src/game/object_list_processor.c | 5 +++- src/pc/network/packets/packet_player.c | 3 ++ 13 files changed, 89 insertions(+), 70 deletions(-) diff --git a/src/game/interaction.c b/src/game/interaction.c index c9c9eaec4..d51d99ece 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -755,7 +755,7 @@ void bounce_back_from_attack(struct MarioState *m, u32 interaction) { } if (m->playerIndex == 0) { set_camera_shake_from_hit(SHAKE_ATTACK); } - m->particleFlags |= PARTICLE_TRIANGLE; + set_mario_particle_flags(m, PARTICLE_TRIANGLE, FALSE); } if (interaction & (INT_PUNCH | INT_KICK | INT_TRIP | INT_FAST_ATTACK_OR_SHELL)) { @@ -2146,11 +2146,11 @@ void check_kick_or_punch_wall(struct MarioState *m) { mario_set_forward_vel(m, -48.0f); play_sound(SOUND_ACTION_HIT_2, m->marioObj->header.gfx.cameraToObject); - m->particleFlags |= PARTICLE_TRIANGLE; + set_mario_particle_flags(m, PARTICLE_TRIANGLE, FALSE); } else if (m->action & ACT_FLAG_AIR) { mario_set_forward_vel(m, -16.0f); play_sound(SOUND_ACTION_HIT_2, m->marioObj->header.gfx.cameraToObject); - m->particleFlags |= PARTICLE_TRIANGLE; + set_mario_particle_flags(m, PARTICLE_TRIANGLE, FALSE); } } } diff --git a/src/game/mario.c b/src/game/mario.c index 5dba7dc05..c467bd4fc 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -302,15 +302,15 @@ void adjust_sound_for_speed(struct MarioState *m) { void play_sound_and_spawn_particles(struct MarioState *m, u32 soundBits, u32 waveParticleType) { if (m->terrainSoundAddend == (SOUND_TERRAIN_WATER << 16)) { if (waveParticleType != 0) { - m->particleFlags |= PARTICLE_SHALLOW_WATER_SPLASH; + set_mario_particle_flags(m, PARTICLE_SHALLOW_WATER_SPLASH, FALSE); } else { - m->particleFlags |= PARTICLE_SHALLOW_WATER_WAVE; + set_mario_particle_flags(m, PARTICLE_SHALLOW_WATER_WAVE, FALSE); } } else { if (m->terrainSoundAddend == (SOUND_TERRAIN_SAND << 16)) { - m->particleFlags |= PARTICLE_DIRT; + set_mario_particle_flags(m, PARTICLE_DIRT, FALSE); } else if (m->terrainSoundAddend == (SOUND_TERRAIN_SNOW << 16)) { - m->particleFlags |= PARTICLE_SNOW; + set_mario_particle_flags(m, PARTICLE_SNOW, FALSE); } } @@ -1596,7 +1596,7 @@ void set_submerged_cam_preset_and_spawn_bubbles(struct MarioState *m) { // of the water with his head out, spawn bubbles. if (!(m->action & ACT_FLAG_INTANGIBLE)) { if ((m->pos[1] < (f32)(m->waterLevel - 160)) || (m->faceAngle[0] < -0x800)) { - m->particleFlags |= PARTICLE_BUBBLE; + set_mario_particle_flags(m, PARTICLE_BUBBLE, FALSE); } } } @@ -2248,3 +2248,15 @@ void init_mario_from_save_file(void) { gHudDisplay.coins = 0; gHudDisplay.wedges = 8; } + +void set_mario_particle_flags(struct MarioState* m, u32 flags, u8 clear) { + if (m->playerIndex != 0) { + return; + } + + if (clear) { + m->particleFlags &= ~flags; + } else { + m->particleFlags |= flags; + } +} \ No newline at end of file diff --git a/src/game/mario.h b/src/game/mario.h index 67aa916ac..5840e0a9d 100644 --- a/src/game/mario.h +++ b/src/game/mario.h @@ -57,5 +57,6 @@ s32 force_idle_state(struct MarioState* m); void init_single_mario(struct MarioState* m); void init_mario(void); void init_mario_from_save_file(void); +void set_mario_particle_flags(struct MarioState* m, u32 flags, u8 clear); #endif // MARIO_H diff --git a/src/game/mario_actions_airborne.c b/src/game/mario_actions_airborne.c index 685ee2fe6..9a4c8fc26 100644 --- a/src/game/mario_actions_airborne.c +++ b/src/game/mario_actions_airborne.c @@ -139,7 +139,7 @@ s32 check_fall_damage_or_get_stuck(struct MarioState *m, u32 hardFallAction) { #else play_character_sound(m, CHAR_SOUND_OOOF2); #endif - m->particleFlags |= PARTICLE_MIST_CIRCLE; + set_mario_particle_flags(m, PARTICLE_MIST_CIRCLE, FALSE); drop_and_set_mario_action(m, ACT_FEET_STUCK_IN_GROUND, 0); queue_rumble_data_mario(m, 5, 80); @@ -417,7 +417,7 @@ u32 common_air_action_step(struct MarioState *m, u32 landAction, s32 animation, // that the final quarter step detects a ledge, but you are // not able to ledge grab it. if (m->forwardVel >= 38.0f) { - m->particleFlags |= PARTICLE_VERTICAL_STAR; + set_mario_particle_flags(m, PARTICLE_VERTICAL_STAR, FALSE); set_mario_action(m, ACT_BACKWARD_AIR_KB, 0); } else { if (m->forwardVel > 8.0f) { @@ -762,7 +762,7 @@ s32 act_dive(struct MarioState *m) { #else play_character_sound(m, CHAR_SOUND_OOOF2); #endif - m->particleFlags |= PARTICLE_MIST_CIRCLE; + set_mario_particle_flags(m, PARTICLE_MIST_CIRCLE, FALSE); drop_and_set_mario_action(m, ACT_HEAD_STUCK_IN_GROUND, 0); } else if (!check_fall_damage(m, ACT_HARD_FORWARD_GROUND_KB)) { if (m->heldObj == NULL) { @@ -782,7 +782,7 @@ s32 act_dive(struct MarioState *m) { m->vel[1] = 0.0f; } - m->particleFlags |= PARTICLE_VERTICAL_STAR; + set_mario_particle_flags(m, PARTICLE_VERTICAL_STAR, FALSE); drop_and_set_mario_action(m, ACT_BACKWARD_AIR_KB, 0); break; @@ -958,12 +958,12 @@ s32 act_ground_pound(struct MarioState *m) { #else play_character_sound(m, CHAR_SOUND_OOOF2); #endif - m->particleFlags |= PARTICLE_MIST_CIRCLE; + set_mario_particle_flags(m, PARTICLE_MIST_CIRCLE, FALSE); set_mario_action(m, ACT_BUTT_STUCK_IN_GROUND, 0); } else { play_mario_heavy_landing_sound(m, SOUND_ACTION_TERRAIN_HEAVY_LANDING); if (!check_fall_damage(m, ACT_HARD_BACKWARD_GROUND_KB)) { - m->particleFlags |= PARTICLE_MIST_CIRCLE | PARTICLE_HORIZONTAL_STAR; + set_mario_particle_flags(m, (PARTICLE_MIST_CIRCLE | PARTICLE_HORIZONTAL_STAR), FALSE); set_mario_action(m, ACT_GROUND_POUND_LAND, 0); } } @@ -974,7 +974,7 @@ s32 act_ground_pound(struct MarioState *m) { m->vel[1] = 0.0f; } - m->particleFlags |= PARTICLE_VERTICAL_STAR; + set_mario_particle_flags(m, PARTICLE_VERTICAL_STAR, FALSE); set_mario_action(m, ACT_BACKWARD_AIR_KB, 0); } } @@ -992,7 +992,7 @@ s32 act_burning_jump(struct MarioState *m) { } set_mario_animation(m, m->actionArg == 0 ? MARIO_ANIM_SINGLE_JUMP : MARIO_ANIM_FIRE_LAVA_BURN); - m->particleFlags |= PARTICLE_FIRE; + set_mario_particle_flags(m, PARTICLE_FIRE, FALSE); play_sound(SOUND_MOVING_LAVA_BURN, m->marioObj->header.gfx.cameraToObject); m->marioObj->oMarioBurnTimer += 3; @@ -1020,7 +1020,7 @@ s32 act_burning_fall(struct MarioState *m) { } set_mario_animation(m, MARIO_ANIM_GENERAL_FALL); - m->particleFlags |= PARTICLE_FIRE; + set_mario_particle_flags(m, PARTICLE_FIRE, FALSE); m->marioObj->oMarioBurnTimer += 3; m->health -= 10; @@ -1085,7 +1085,7 @@ s32 act_crazy_box_bounce(struct MarioState *m) { set_mario_action(m, ACT_STOMACH_SLIDE, 0); } queue_rumble_data_mario(m, 5, 80); - m->particleFlags |= PARTICLE_MIST_CIRCLE; + set_mario_particle_flags(m, PARTICLE_MIST_CIRCLE, FALSE); break; case AIR_STEP_HIT_WALL: @@ -1334,7 +1334,7 @@ s32 act_air_hit_wall(struct MarioState *m) { m->vel[1] = 0.0f; } - m->particleFlags |= PARTICLE_VERTICAL_STAR; + set_mario_particle_flags(m, PARTICLE_VERTICAL_STAR, FALSE); return set_mario_action(m, ACT_BACKWARD_AIR_KB, 0); } else { m->wallKickTimer = 5; @@ -1465,7 +1465,7 @@ s32 act_butt_slide_air(struct MarioState *m) { if (m->vel[1] > 0.0f) { m->vel[1] = 0.0f; } - m->particleFlags |= PARTICLE_VERTICAL_STAR; + set_mario_particle_flags(m, PARTICLE_VERTICAL_STAR, FALSE); set_mario_action(m, ACT_BACKWARD_AIR_KB, 0); break; @@ -1506,7 +1506,7 @@ s32 act_hold_butt_slide_air(struct MarioState *m) { } mario_drop_held_object(m); - m->particleFlags |= PARTICLE_VERTICAL_STAR; + set_mario_particle_flags(m, PARTICLE_VERTICAL_STAR, FALSE); set_mario_action(m, ACT_BACKWARD_AIR_KB, 0); break; @@ -1566,7 +1566,7 @@ s32 act_lava_boost(struct MarioState *m) { set_mario_animation(m, MARIO_ANIM_FIRE_LAVA_BURN); if ((m->area->terrainType & TERRAIN_MASK) != TERRAIN_SNOW && !(m->flags & MARIO_METAL_CAP) && m->vel[1] > 0.0f) { - m->particleFlags |= PARTICLE_FIRE; + set_mario_particle_flags(m, PARTICLE_FIRE, FALSE); if (m->actionState == 0) { play_sound(SOUND_MOVING_LAVA_BURN, m->marioObj->header.gfx.cameraToObject); } @@ -1637,7 +1637,7 @@ s32 act_slide_kick(struct MarioState *m) { m->vel[1] = 0.0f; } - m->particleFlags |= PARTICLE_VERTICAL_STAR; + set_mario_particle_flags(m, PARTICLE_VERTICAL_STAR, FALSE); set_mario_action(m, ACT_BACKWARD_AIR_KB, 0); break; @@ -1731,7 +1731,7 @@ s32 act_shot_from_cannon(struct MarioState *m) { m->vel[1] = 0.0f; } - m->particleFlags |= PARTICLE_VERTICAL_STAR; + set_mario_particle_flags(m, PARTICLE_VERTICAL_STAR, FALSE); set_mario_action(m, ACT_BACKWARD_AIR_KB, 0); #ifndef BETTERCAMERA if (allowCameraChange) { set_camera_mode(m->area->camera, m->area->camera->defMode, 1); } @@ -1762,7 +1762,7 @@ s32 act_shot_from_cannon(struct MarioState *m) { } if (m->vel[1] > 0.0f) { - m->particleFlags |= PARTICLE_DUST; + set_mario_particle_flags(m, PARTICLE_DUST, FALSE); } reset_rumble_timers(m); @@ -1897,7 +1897,7 @@ s32 act_flying(struct MarioState *m) { : SOUND_ACTION_BONK, m->marioObj->header.gfx.cameraToObject); - m->particleFlags |= PARTICLE_VERTICAL_STAR; + set_mario_particle_flags(m, PARTICLE_VERTICAL_STAR, FALSE); set_mario_action(m, ACT_BACKWARD_AIR_KB, 0); if (m->playerIndex == 0) { @@ -1938,7 +1938,7 @@ s32 act_flying(struct MarioState *m) { } if (m->faceAngle[0] > 0x800 && m->forwardVel >= 48.0f) { - m->particleFlags |= PARTICLE_DUST; + set_mario_particle_flags(m, PARTICLE_DUST, FALSE); } if (startPitch <= 0 && m->faceAngle[0] > 0 && m->forwardVel >= 48.0f) { @@ -2170,7 +2170,7 @@ s32 act_special_triple_jump(struct MarioState *m) { set_mario_animation(m, MARIO_ANIM_GENERAL_FALL); } - m->particleFlags |= PARTICLE_SPARKLES; + set_mario_particle_flags(m, PARTICLE_SPARKLES, FALSE); return FALSE; } diff --git a/src/game/mario_actions_automatic.c b/src/game/mario_actions_automatic.c index 418f8e874..e56eb8fd5 100644 --- a/src/game/mario_actions_automatic.c +++ b/src/game/mario_actions_automatic.c @@ -44,7 +44,7 @@ void add_tree_leaf_particles(struct MarioState *m) { leafHeight = 100.0f; } if (m->pos[1] - m->floorHeight > leafHeight) { - m->particleFlags |= PARTICLE_LEAF; + set_mario_particle_flags(m, PARTICLE_LEAF, FALSE); } } } @@ -187,7 +187,7 @@ s32 act_holding_pole(struct MarioState *m) { //! The Shifting Sand Land palm tree check is done climbing up in // add_tree_leaf_particles, but not here, when climbing down. if (m->pos[1] - m->floorHeight > 100.0f) { - m->particleFlags |= PARTICLE_LEAF; + set_mario_particle_flags(m, PARTICLE_LEAF, FALSE); } } play_climbing_sounds(m, 2); diff --git a/src/game/mario_actions_cutscene.c b/src/game/mario_actions_cutscene.c index 31b063028..54cf38517 100644 --- a/src/game/mario_actions_cutscene.c +++ b/src/game/mario_actions_cutscene.c @@ -762,7 +762,7 @@ s32 act_star_dance_water(struct MarioState *m) { s32 act_fall_after_star_grab(struct MarioState *m) { if (m->pos[1] < m->waterLevel - 130) { play_sound(SOUND_ACTION_UNKNOWN430, m->marioObj->header.gfx.cameraToObject); - m->particleFlags |= PARTICLE_WATER_SPLASH; + set_mario_particle_flags(m, PARTICLE_WATER_SPLASH, FALSE); return set_mario_action(m, ACT_STAR_DANCE_WATER, m->actionArg); } if (perform_air_step(m, 1) == AIR_STEP_LANDED) { @@ -1241,7 +1241,7 @@ s32 act_exit_airborne(struct MarioState *m) { } // rotate him to face away from the entrance m->marioObj->header.gfx.angle[1] += 0x8000; - m->particleFlags |= PARTICLE_SPARKLES; + set_mario_particle_flags(m, PARTICLE_SPARKLES, FALSE); return FALSE; } @@ -1252,7 +1252,7 @@ s32 act_falling_exit_airborne(struct MarioState *m) { } // rotate Mario to face away from the entrance m->marioObj->header.gfx.angle[1] += 0x8000; - m->particleFlags |= PARTICLE_SPARKLES; + set_mario_particle_flags(m, PARTICLE_SPARKLES, FALSE); return FALSE; } @@ -1409,7 +1409,7 @@ s32 act_special_exit_airborne(struct MarioState *m) { m->actionArg = 1; } - m->particleFlags |= PARTICLE_SPARKLES; + set_mario_particle_flags(m, PARTICLE_SPARKLES, FALSE); // rotate Mario to face away from the entrance marioObj->header.gfx.angle[1] += 0x8000; // show Mario @@ -2121,7 +2121,7 @@ static s32 jumbo_star_cutscene_taking_off(struct MarioState *m) { play_character_sound(m, CHAR_SOUND_YAHOO); break; } - m->particleFlags |= PARTICLE_SPARKLES; + set_mario_particle_flags(m, PARTICLE_SPARKLES, FALSE); if (is_anim_past_end(m)) { advance_cutscene_step(m); @@ -2180,7 +2180,7 @@ static s32 jumbo_star_cutscene_flying(struct MarioState *m) { m->marioBodyState->handState = MARIO_HAND_RIGHT_OPEN; vec3f_copy(m->marioObj->header.gfx.pos, m->pos); - m->particleFlags |= PARTICLE_SPARKLES; + set_mario_particle_flags(m, PARTICLE_SPARKLES, FALSE); if (m->actionTimer++ == 500 && m->playerIndex == 0) { level_trigger_warp(m, WARP_OP_CREDITS_START); @@ -2419,7 +2419,7 @@ static void end_peach_cutscene_run_to_peach(struct MarioState *m) { play_step_sound(m, 9, 45); vec3f_copy(m->marioObj->header.gfx.pos, m->pos); - m->particleFlags |= PARTICLE_DUST; + set_mario_particle_flags(m, PARTICLE_DUST, FALSE); } // dialog 1 @@ -2858,7 +2858,7 @@ static s32 act_credits_cutscene(struct MarioState *m) { vec3f_copy(m->marioObj->header.gfx.pos, m->pos); // will copy over roll and pitch, if set vec3s_copy(m->marioObj->header.gfx.angle, m->faceAngle); - m->particleFlags |= PARTICLE_BUBBLE; + set_mario_particle_flags(m, PARTICLE_BUBBLE, FALSE); } else { set_mario_animation(m, MARIO_ANIM_FIRST_PERSON); if (m->actionTimer > 0) { @@ -3027,7 +3027,7 @@ s32 mario_execute_cutscene_action(struct MarioState *m) { } if (!cancel && (m->input & INPUT_IN_WATER)) { - m->particleFlags |= PARTICLE_IDLE_WATER_WAVE; + set_mario_particle_flags(m, PARTICLE_IDLE_WATER_WAVE, FALSE); } return cancel; diff --git a/src/game/mario_actions_moving.c b/src/game/mario_actions_moving.c index 8d4fe3d3f..032ef80d0 100644 --- a/src/game/mario_actions_moving.c +++ b/src/game/mario_actions_moving.c @@ -712,7 +712,7 @@ void push_or_sidle_wall(struct MarioState *m, Vec3f startPos) { if (m->marioObj->header.gfx.animInfo.animFrame < 20) { play_sound(SOUND_MOVING_TERRAIN_SLIDE + m->terrainSoundAddend, m->marioObj->header.gfx.cameraToObject); - m->particleFlags |= PARTICLE_DUST; + set_mario_particle_flags(m, PARTICLE_DUST, FALSE); } m->actionState = 1; @@ -836,7 +836,7 @@ s32 act_walking(struct MarioState *m) { case GROUND_STEP_NONE: anim_and_audio_for_walk(m); if (m->intendedMag - m->forwardVel > 16.0f) { - m->particleFlags |= PARTICLE_DUST; + set_mario_particle_flags(m, PARTICLE_DUST, FALSE); } break; @@ -879,7 +879,7 @@ s32 act_move_punching(struct MarioState *m) { break; case GROUND_STEP_NONE: - m->particleFlags |= PARTICLE_DUST; + set_mario_particle_flags(m, PARTICLE_DUST, FALSE); break; } @@ -934,7 +934,7 @@ s32 act_hold_walking(struct MarioState *m) { anim_and_audio_for_hold_walk(m); if (0.4f * m->intendedMag - m->forwardVel > 10.0f) { - m->particleFlags |= PARTICLE_DUST; + set_mario_particle_flags(m, PARTICLE_DUST, FALSE); } return FALSE; @@ -1004,7 +1004,7 @@ s32 act_turning_around(struct MarioState *m) { break; case GROUND_STEP_NONE: - m->particleFlags |= PARTICLE_DUST; + set_mario_particle_flags(m, PARTICLE_DUST, FALSE); break; } @@ -1069,7 +1069,7 @@ s32 act_braking(struct MarioState *m) { break; case GROUND_STEP_NONE: - m->particleFlags |= PARTICLE_DUST; + set_mario_particle_flags(m, PARTICLE_DUST, FALSE); break; case GROUND_STEP_HIT_WALL: @@ -1131,7 +1131,7 @@ s32 act_decelerating(struct MarioState *m) { set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_LEFT); play_sound(SOUND_MOVING_TERRAIN_SLIDE + m->terrainSoundAddend, m->marioObj->header.gfx.cameraToObject); adjust_sound_for_speed(m); - m->particleFlags |= PARTICLE_DUST; + set_mario_particle_flags(m, PARTICLE_DUST, FALSE); } else { // (Speed Crash) Crashes if speed exceeds 2^17. if ((val0C = (s32)(m->forwardVel / 4.0f * 0x10000)) < 0x1000) { @@ -1197,7 +1197,7 @@ s32 act_hold_decelerating(struct MarioState *m) { set_mario_animation(m, MARIO_ANIM_IDLE_WITH_LIGHT_OBJ); play_sound(SOUND_MOVING_TERRAIN_SLIDE + m->terrainSoundAddend, m->marioObj->header.gfx.cameraToObject); adjust_sound_for_speed(m); - m->particleFlags |= PARTICLE_DUST; + set_mario_particle_flags(m, PARTICLE_DUST, FALSE); } else { //! (Speed Crash) This crashes if Mario has more speed than 2^15 speed. if ((val0C = (s32)(m->forwardVel * 0x10000)) < 0x1000) { @@ -1238,7 +1238,7 @@ s32 act_riding_shell_ground(struct MarioState *m) { mario_stop_riding_object(m); play_sound(m->flags & MARIO_METAL_CAP ? SOUND_ACTION_METAL_BONK : SOUND_ACTION_BONK, m->marioObj->header.gfx.cameraToObject); - m->particleFlags |= PARTICLE_VERTICAL_STAR; + set_mario_particle_flags(m, PARTICLE_VERTICAL_STAR, FALSE); set_mario_action(m, ACT_BACKWARD_GROUND_KB, 0); break; } @@ -1348,7 +1348,7 @@ s32 act_burning_ground(struct MarioState *m) { set_mario_anim_with_accel(m, MARIO_ANIM_RUNNING, (s32)(m->forwardVel / 2.0f * 0x10000)); play_step_sound(m, 9, 45); - m->particleFlags |= PARTICLE_FIRE; + set_mario_particle_flags(m, PARTICLE_FIRE, FALSE); play_sound(SOUND_MOVING_LAVA_BURN, m->marioObj->header.gfx.cameraToObject); m->health -= 10; @@ -1393,16 +1393,16 @@ void common_slide_action(struct MarioState *m, u32 endAction, u32 airAction, s32 case GROUND_STEP_NONE: set_mario_animation(m, animation); align_with_floor(m); - m->particleFlags |= PARTICLE_DUST; + set_mario_particle_flags(m, PARTICLE_DUST, FALSE); break; case GROUND_STEP_HIT_WALL: if (!mario_floor_is_slippery(m)) { #ifdef VERSION_JP - m->particleFlags |= PARTICLE_VERTICAL_STAR; + set_mario_particle_flags(m, PARTICLE_VERTICAL_STAR, FALSE); #else if (m->forwardVel > 16.0f) { - m->particleFlags |= PARTICLE_VERTICAL_STAR; + set_mario_particle_flags(m, PARTICLE_VERTICAL_STAR, FALSE); } #endif slide_bonk(m, ACT_GROUND_BONK, endAction); @@ -1519,13 +1519,13 @@ s32 act_slide_kick_slide(struct MarioState *m) { case GROUND_STEP_HIT_WALL: mario_bonk_reflection(m, TRUE); - m->particleFlags |= PARTICLE_VERTICAL_STAR; + set_mario_particle_flags(m, PARTICLE_VERTICAL_STAR, FALSE); set_mario_action(m, ACT_BACKWARD_GROUND_KB, 0); break; } play_sound(SOUND_MOVING_TERRAIN_SLIDE + m->terrainSoundAddend, m->marioObj->header.gfx.cameraToObject); - m->particleFlags |= PARTICLE_DUST; + set_mario_particle_flags(m, PARTICLE_DUST, FALSE); return FALSE; } @@ -1761,7 +1761,7 @@ u32 common_landing_action(struct MarioState *m, s16 animation, u32 airAction) { } if (m->forwardVel > 16.0f) { - m->particleFlags |= PARTICLE_DUST; + set_mario_particle_flags(m, PARTICLE_DUST, FALSE); } set_mario_animation(m, animation); @@ -2052,8 +2052,8 @@ s32 mario_execute_moving_action(struct MarioState *m) { } if (!cancel && (m->input & INPUT_IN_WATER)) { - m->particleFlags |= PARTICLE_WAVE_TRAIL; - m->particleFlags &= ~PARTICLE_DUST; + set_mario_particle_flags(m, PARTICLE_WAVE_TRAIL, FALSE); + set_mario_particle_flags(m, PARTICLE_DUST, TRUE); } return cancel; diff --git a/src/game/mario_actions_object.c b/src/game/mario_actions_object.c index cea697627..c45bf7ab7 100644 --- a/src/game/mario_actions_object.c +++ b/src/game/mario_actions_object.c @@ -515,7 +515,7 @@ s32 mario_execute_object_action(struct MarioState *m) { } if (!cancel && (m->input & INPUT_IN_WATER)) { - m->particleFlags |= PARTICLE_IDLE_WATER_WAVE; + set_mario_particle_flags(m, PARTICLE_IDLE_WATER_WAVE, FALSE); } return cancel; diff --git a/src/game/mario_actions_stationary.c b/src/game/mario_actions_stationary.c index c5d4813fe..701f1bc9c 100644 --- a/src/game/mario_actions_stationary.c +++ b/src/game/mario_actions_stationary.c @@ -397,7 +397,7 @@ s32 act_shivering(struct MarioState *m) { case 0: animFrame = set_mario_animation(m, MARIO_ANIM_SHIVERING_WARMING_HAND); if (animFrame == 49) { - m->particleFlags |= PARTICLE_BREATH; + set_mario_particle_flags(m, PARTICLE_BREATH, FALSE); play_character_sound(m, CHAR_SOUND_PANTING_COLD); } if (animFrame == 7 || animFrame == 81) { @@ -1178,7 +1178,7 @@ s32 mario_execute_stationary_action(struct MarioState *m) { } if (!cancel && (m->input & INPUT_IN_WATER)) { - m->particleFlags |= PARTICLE_IDLE_WATER_WAVE; + set_mario_particle_flags(m, PARTICLE_IDLE_WATER_WAVE, FALSE); } return cancel; diff --git a/src/game/mario_actions_submerged.c b/src/game/mario_actions_submerged.c index 9e48096cd..e9eaaba1b 100644 --- a/src/game/mario_actions_submerged.c +++ b/src/game/mario_actions_submerged.c @@ -45,7 +45,7 @@ void set_swimming_at_surface_particles(struct MarioState *m, u32 particleFlag) { u16 pIndex = m->playerIndex; if (atSurface) { - m->particleFlags |= particleFlag; + set_mario_particle_flags(m, particleFlag, FALSE); if (atSurface ^ sWasAtSurface[pIndex]) { play_sound(SOUND_ACTION_UNKNOWN431, m->marioObj->header.gfx.cameraToObject); } @@ -1024,7 +1024,7 @@ static s32 act_water_plunge(struct MarioState *m) { play_character_sound(m, CHAR_SOUND_HAHA_2); } - m->particleFlags |= PARTICLE_WATER_SPLASH; + set_mario_particle_flags(m, PARTICLE_WATER_SPLASH, FALSE); m->actionState = 1; if (m->prevAction & ACT_FLAG_AIR) { queue_rumble_data_mario(m, 5, 80); @@ -1076,7 +1076,7 @@ static s32 act_water_plunge(struct MarioState *m) { break; } - m->particleFlags |= PARTICLE_PLUNGE_BUBBLE; + set_mario_particle_flags(m, PARTICLE_PLUNGE_BUBBLE, FALSE); return FALSE; } @@ -1157,7 +1157,7 @@ static s32 act_caught_in_whirlpool(struct MarioState *m) { static void play_metal_water_jumping_sound(struct MarioState *m, u32 landing) { if (!(m->flags & MARIO_ACTION_SOUND_PLAYED)) { - m->particleFlags |= PARTICLE_MIST_CIRCLE; + set_mario_particle_flags(m, PARTICLE_MIST_CIRCLE, FALSE); } play_sound_if_no_flag(m, landing ? SOUND_ACTION_METAL_LAND_WATER : SOUND_ACTION_METAL_JUMP_WATER, @@ -1167,7 +1167,7 @@ static void play_metal_water_jumping_sound(struct MarioState *m, u32 landing) { static void play_metal_water_walking_sound(struct MarioState *m) { if (is_anim_past_frame(m, 10) || is_anim_past_frame(m, 49)) { play_sound(SOUND_ACTION_METAL_STEP_WATER, m->marioObj->header.gfx.cameraToObject); - m->particleFlags |= PARTICLE_DUST; + set_mario_particle_flags(m, PARTICLE_DUST, FALSE); } } @@ -1257,7 +1257,7 @@ static s32 act_metal_water_standing(struct MarioState *m) { stop_and_set_height_to_floor(m); if (m->pos[1] >= m->waterLevel - 150) { - m->particleFlags |= PARTICLE_IDLE_WATER_WAVE; + set_mario_particle_flags(m, PARTICLE_IDLE_WATER_WAVE, FALSE); } return FALSE; diff --git a/src/game/mario_misc.c b/src/game/mario_misc.c index dd06e04cc..c8d989578 100644 --- a/src/game/mario_misc.c +++ b/src/game/mario_misc.c @@ -539,9 +539,9 @@ Gfx* geo_mario_head_rotation(s32 callContext, struct GraphNode* node, Mat4* c) { if (!marioActive) { node->flags &= ~GRAPH_RENDER_ACTIVE; - } else if (camera->mode == CAMERA_MODE_C_UP) { - rotNode->rotation[0] = gPlayerCameraState->headRotation[1]; - rotNode->rotation[2] = gPlayerCameraState->headRotation[0]; + } else if (((plrIdx == 0) && (camera->mode == CAMERA_MODE_C_UP)) || ((plrIdx != 0) && (action == ACT_FIRST_PERSON))) { + rotNode->rotation[0] = gPlayerCameraState[plrIdx].headRotation[1]; + rotNode->rotation[2] = gPlayerCameraState[plrIdx].headRotation[0]; } else if (action & ACT_FLAG_WATER_OR_TEXT) { rotNode->rotation[0] = bodyState->headAngle[1]; diff --git a/src/game/object_list_processor.c b/src/game/object_list_processor.c index 390caf384..561b83b56 100644 --- a/src/game/object_list_processor.c +++ b/src/game/object_list_processor.c @@ -281,7 +281,10 @@ void bhv_mario_update(void) { vec3f_copy(gMarioState->marioBodyState->torsoPos, gMarioState->pos); } - gMarioState->particleFlags = 0; + if (stateIndex == 0) { + gMarioState->particleFlags = 0; + } + smlua_call_event_hooks_mario_param(HOOK_BEFORE_MARIO_UPDATE, gMarioState); u32 particleFlags = 0; diff --git a/src/pc/network/packets/packet_player.c b/src/pc/network/packets/packet_player.c index 916dd35e9..a120f3c73 100644 --- a/src/pc/network/packets/packet_player.c +++ b/src/pc/network/packets/packet_player.c @@ -59,6 +59,7 @@ struct PacketPlayerData { u8 squishTimer; f32 peakHeight; s16 currentRoom; + Vec3s headRotation; u8 customFlags; u8 heldSyncID; @@ -121,6 +122,7 @@ static void read_packet_data(struct PacketPlayerData* data, struct MarioState* m data->squishTimer = m->squishTimer; data->peakHeight = m->peakHeight; data->currentRoom = m->currentRoom; + memcpy(data->headRotation, gPlayerCameraState[m->playerIndex].headRotation, sizeof(s16) * 3); data->customFlags = customFlags; data->heldSyncID = heldSyncID; @@ -176,6 +178,7 @@ static void write_packet_data(struct PacketPlayerData* data, struct MarioState* m->squishTimer = data->squishTimer; m->peakHeight = data->peakHeight; m->currentRoom = data->currentRoom; + memcpy(gPlayerCameraState[m->playerIndex].headRotation, data->headRotation, sizeof(s16) * 3); *customFlags = data->customFlags; *heldSyncID = data->heldSyncID; From 68d46cdefe057b792ff792efa7c2f8c906912245 Mon Sep 17 00:00:00 2001 From: Agent X <44549182+Agent-11@users.noreply.github.com> Date: Thu, 19 May 2022 20:06:51 -0400 Subject: [PATCH 07/13] Mouse lock & freeze cam fixes and warp constants (#103) --- autogen/convert_constants.py | 1 + autogen/lua_definitions/constants.lua | 39 +++++++++++++++++++++++++++ docs/lua/constants.md | 20 ++++++++++++++ src/game/camera.c | 3 ++- src/pc/controller/controller_sdl2.c | 17 +++++++----- src/pc/djui/djui_hud_utils.c | 2 +- src/pc/lua/smlua_constants_autogen.c | 13 +++++++++ src/pc/network/network.c | 4 +++ 8 files changed, 90 insertions(+), 9 deletions(-) diff --git a/autogen/convert_constants.py b/autogen/convert_constants.py index 40256fbb3..9c7ebfa5c 100644 --- a/autogen/convert_constants.py +++ b/autogen/convert_constants.py @@ -12,6 +12,7 @@ in_files = [ "include/types.h", "include/sm64.h", "src/pc/lua/smlua_hooks.h", + "src/game/area.h", "src/game/camera.h", "include/mario_animation_ids.h", "include/sounds.h", diff --git a/autogen/lua_definitions/constants.lua b/autogen/lua_definitions/constants.lua index b55e00227..6fd180651 100644 --- a/autogen/lua_definitions/constants.lua +++ b/autogen/lua_definitions/constants.lua @@ -336,6 +336,45 @@ COURSE_COUNT = 25 --- @type integer COURSE_MIN = 1 +--- @type integer +INSTANT_WARP_INDEX_START = 0x00 + +--- @type integer +INSTANT_WARP_INDEX_STOP = 0x04 + +--- @type integer +MAX_LOADED_GRAPH_NODES = 0x100 + +--- @type integer +WARP_TRANSITION_FADE_FROM_BOWSER = 0x12 + +--- @type integer +WARP_TRANSITION_FADE_FROM_CIRCLE = 0x0A + +--- @type integer +WARP_TRANSITION_FADE_FROM_COLOR = 0x00 + +--- @type integer +WARP_TRANSITION_FADE_FROM_MARIO = 0x10 + +--- @type integer +WARP_TRANSITION_FADE_FROM_STAR = 0x08 + +--- @type integer +WARP_TRANSITION_FADE_INTO_BOWSER = 0x13 + +--- @type integer +WARP_TRANSITION_FADE_INTO_CIRCLE = 0x0B + +--- @type integer +WARP_TRANSITION_FADE_INTO_COLOR = 0x01 + +--- @type integer +WARP_TRANSITION_FADE_INTO_MARIO = 0x11 + +--- @type integer +WARP_TRANSITION_FADE_INTO_STAR = 0x09 + --- @class BehaviorId --- @type BehaviorId diff --git a/docs/lua/constants.md b/docs/lua/constants.md index 91ec51720..098e0f0b3 100644 --- a/docs/lua/constants.md +++ b/docs/lua/constants.md @@ -1,6 +1,7 @@ ## [:rewind: Lua Reference](lua.md) # Supported Constants +- [area.h](#areah) - [behavior_table.h](#behavior_tableh) - [enum BehaviorId](#enum-BehaviorId) - [camera.h](#camerah) @@ -57,6 +58,25 @@
+## [area.h](#area.h) +- INSTANT_WARP_INDEX_START +- INSTANT_WARP_INDEX_STOP +- MAX_LOADED_GRAPH_NODES +- WARP_TRANSITION_FADE_FROM_BOWSER +- WARP_TRANSITION_FADE_FROM_CIRCLE +- WARP_TRANSITION_FADE_FROM_COLOR +- WARP_TRANSITION_FADE_FROM_MARIO +- WARP_TRANSITION_FADE_FROM_STAR +- WARP_TRANSITION_FADE_INTO_BOWSER +- WARP_TRANSITION_FADE_INTO_CIRCLE +- WARP_TRANSITION_FADE_INTO_COLOR +- WARP_TRANSITION_FADE_INTO_MARIO +- WARP_TRANSITION_FADE_INTO_STAR + +[:arrow_up_small:](#) + +
+ ## [behavior_table.h](#behavior_table.h) ### [enum BehaviorId](#BehaviorId) diff --git a/src/game/camera.c b/src/game/camera.c index f968cf732..9d622068e 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -32,6 +32,7 @@ #include "pc/configfile.h" #include "pc/network/network.h" #include "pc/lua/smlua_hooks.h" +#include "pc/djui/djui.h" #define CBUTTON_MASK (U_CBUTTONS | D_CBUTTONS | L_CBUTTONS | R_CBUTTONS) @@ -3050,7 +3051,7 @@ void update_lakitu(struct Camera *c) { * Gets controller input, checks for cutscenes, handles mode changes, and moves the camera */ void update_camera(struct Camera *c) { - if (gOverrideFreezeCamera) { + if (gOverrideFreezeCamera && !gDjuiInMainMenu) { return; } UNUSED u8 unused[24]; diff --git a/src/pc/controller/controller_sdl2.c b/src/pc/controller/controller_sdl2.c index b8057b4b8..c7eb3febc 100644 --- a/src/pc/controller/controller_sdl2.c +++ b/src/pc/controller/controller_sdl2.c @@ -24,6 +24,7 @@ #include "../fs/fs.h" #include "game/level_update.h" +#include "pc/lua/utils/smlua_misc_utils.h" #include "pc/djui/djui.h" #include "pc/djui/djui_hud_utils.h" @@ -168,12 +169,14 @@ static void controller_sdl_read(OSContPad *pad) { } #ifdef BETTERCAMERA - if (newcam_mouse == 1 && sCurrPlayMode != 2) { - SDL_SetRelativeMouseMode(SDL_TRUE); - ignore_lock = TRUE; - } else { - SDL_SetRelativeMouseMode(SDL_FALSE); - ignore_lock = FALSE; + if (!gDjuiHudLockMouse) { + if (newcam_mouse == 1 && (!is_game_paused() || sCurrPlayMode != 2) && !gDjuiInMainMenu) { + SDL_SetRelativeMouseMode(SDL_TRUE); + ignore_lock = true; + } else { + SDL_SetRelativeMouseMode(SDL_FALSE); + ignore_lock = false; + } } u32 mouse = SDL_GetRelativeMouseState(&mouse_x, &mouse_y); @@ -187,7 +190,7 @@ static void controller_sdl_read(OSContPad *pad) { last_mouse = (mouse_buttons ^ mouse) & mouse; mouse_buttons = mouse; #endif - if (!ignore_lock && sCurrPlayMode != 2) { + if (!ignore_lock && (!is_game_paused() || sCurrPlayMode != 2) && !gDjuiInMainMenu) { SDL_SetRelativeMouseMode(gDjuiHudLockMouse ? SDL_TRUE : SDL_FALSE); #ifndef BETTERCAMERA diff --git a/src/pc/djui/djui_hud_utils.c b/src/pc/djui/djui_hud_utils.c index d9c1efcce..2f9916d82 100644 --- a/src/pc/djui/djui_hud_utils.c +++ b/src/pc/djui/djui_hud_utils.c @@ -22,7 +22,7 @@ static enum HudUtilsResolution sResolution = RESOLUTION_DJUI; static enum DjuiFontType sFont = FONT_NORMAL; f32 gDjuiHudUtilsZ = 0; -u8 gDjuiHudLockMouse = FALSE; +u8 gDjuiHudLockMouse = false; extern ALIGNED8 const u8 texture_hud_char_camera[]; extern ALIGNED8 const u8 texture_hud_char_lakitu[]; diff --git a/src/pc/lua/smlua_constants_autogen.c b/src/pc/lua/smlua_constants_autogen.c index b68a86662..0a3f8ec97 100644 --- a/src/pc/lua/smlua_constants_autogen.c +++ b/src/pc/lua/smlua_constants_autogen.c @@ -307,6 +307,19 @@ char gSmluaConstants[] = "" "COURSE_COUNT = 25\n" "--- @type integer\n" "COURSE_MIN = 1\n" +"MAX_LOADED_GRAPH_NODES = 0x100\n" +"INSTANT_WARP_INDEX_START = 0x00\n" +"INSTANT_WARP_INDEX_STOP = 0x04\n" +"WARP_TRANSITION_FADE_FROM_COLOR = 0x00\n" +"WARP_TRANSITION_FADE_INTO_COLOR = 0x01\n" +"WARP_TRANSITION_FADE_FROM_STAR = 0x08\n" +"WARP_TRANSITION_FADE_INTO_STAR = 0x09\n" +"WARP_TRANSITION_FADE_FROM_CIRCLE = 0x0A\n" +"WARP_TRANSITION_FADE_INTO_CIRCLE = 0x0B\n" +"WARP_TRANSITION_FADE_FROM_MARIO = 0x10\n" +"WARP_TRANSITION_FADE_INTO_MARIO = 0x11\n" +"WARP_TRANSITION_FADE_FROM_BOWSER = 0x12\n" +"WARP_TRANSITION_FADE_INTO_BOWSER = 0x13\n" "id_bhv1Up = 0\n" "id_bhv1upJumpOnApproach = 1\n" "id_bhv1upRunningAway = 2\n" diff --git a/src/pc/network/network.c b/src/pc/network/network.c index 6f83aff23..c765a5b81 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -11,11 +11,13 @@ #include "pc/configfile.h" #include "pc/cheats.h" #include "pc/djui/djui.h" +#include "pc/djui/djui_hud_utils.h" #include "pc/utils/misc.h" #include "pc/lua/smlua.h" #include "pc/mods/mods.h" #include "pc/crash_handler.h" #include "pc/debuglog.h" +#include "game/camera.h" // Mario 64 specific externs extern s16 sCurrPlayMode; @@ -460,6 +462,8 @@ void network_shutdown(bool sendLeaving, bool exiting) { // reset other stuff extern u8* gOverrideEeprom; gOverrideEeprom = NULL; + gOverrideFreezeCamera = false; + gDjuiHudLockMouse = false; dynos_mod_shutdown(); mods_clear(&gActiveMods); mods_clear(&gRemoteMods); From 672af8e2a02e5b4cf874b2658f428657d100f269 Mon Sep 17 00:00:00 2001 From: Isaac <62234577+Isaac0-dev@users.noreply.github.com> Date: Fri, 20 May 2022 10:07:58 +1000 Subject: [PATCH 08/13] Restore Mario to selected palette when returning to main menu (#105) --- src/pc/network/network.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pc/network/network.c b/src/pc/network/network.c index c765a5b81..e362b8920 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -470,6 +470,7 @@ void network_shutdown(bool sendLeaving, bool exiting) { smlua_shutdown(); extern s16 gChangeLevel; gChangeLevel = LEVEL_CASTLE_GROUNDS; + network_player_init(); extern s16 gMenuMode; gMenuMode = -1; From 21451b097487c34f65873e881836d22e2072da4f Mon Sep 17 00:00:00 2001 From: Isaac <62234577+Isaac0-dev@users.noreply.github.com> Date: Fri, 20 May 2022 10:12:39 +1000 Subject: [PATCH 09/13] Headless compile flag (#107) --- Makefile | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 59372def6..4ca1ae3c1 100644 --- a/Makefile +++ b/Makefile @@ -64,9 +64,10 @@ DOCKERBUILD ?= 0 DEBUG_INFO_LEVEL ?= 2 # Enable profiling PROFILE ?= 0 +# Compile headless +HEADLESS ?= 0 # Enable Game ICON ICON ?= 1 - # Various workarounds for weird toolchains NO_BZERO_BCOPY ?= 0 @@ -349,6 +350,13 @@ else endif endif +ifeq ($(HEADLESS),1) + $(warning Compiling headless) + RENDER_API := DUMMY + WINDOW_API := DUMMY + AUDIO_API := DUMMY + CONTROLLER_API := +endif # NON_MATCHING - whether to build a matching, identical copy of the ROM # 1 - enable some alternate, more portable code that does not produce a matching ROM From 59e26fbc864d4c90ff642d5d44d13f416df93c34 Mon Sep 17 00:00:00 2001 From: Isaac <62234577+Isaac0-dev@users.noreply.github.com> Date: Fri, 20 May 2022 10:14:23 +1000 Subject: [PATCH 10/13] Restore local Mario to mirror room (#109) --- src/game/mario_misc.c | 76 +++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/src/game/mario_misc.c b/src/game/mario_misc.c index c8d989578..c87acab87 100644 --- a/src/game/mario_misc.c +++ b/src/game/mario_misc.c @@ -743,46 +743,46 @@ Gfx* geo_switch_mario_hand_grab_pos(s32 callContext, struct GraphNode* b, Mat4* * a mirror image of the player. */ Gfx* geo_render_mirror_mario(s32 callContext, struct GraphNode* node, UNUSED Mat4* c) { - for (s32 i = 0; i < MAX_PLAYERS; i++) { - f32 mirroredX; - struct MarioState* marioState = &gMarioStates[i]; - struct Object* mario = marioState->marioObj; + struct MarioState* mariolocalState = &gMarioStates[0]; + struct Object* marioLocal = mariolocalState->marioObj; + + f32 mirroredX; + struct MarioState* marioState = &gMarioStates[0]; + struct Object* mario = marioState->marioObj; - switch (callContext) { - case GEO_CONTEXT_CREATE: - init_graph_node_object(NULL, &gMirrorMario[i], NULL, gVec3fZero, gVec3sZero, gVec3fOne); - break; - case GEO_CONTEXT_AREA_LOAD: - geo_add_child(node, &gMirrorMario[i].node); - break; - case GEO_CONTEXT_AREA_UNLOAD: - geo_remove_child_from_parent(node, &gMirrorMario[i].node); - break; - case GEO_CONTEXT_RENDER: - if (mario && (((struct GraphNode*)&mario->header.gfx)->flags & GRAPH_RENDER_ACTIVE)) { - // TODO: Is this a geo layout copy or a graph node copy? - gMirrorMario[i].sharedChild = mario->header.gfx.sharedChild; - dynos_actor_override((void*)&gMirrorMario[i].sharedChild); - gMirrorMario[i].areaIndex = mario->header.gfx.areaIndex; - vec3s_copy(gMirrorMario[i].angle, mario->header.gfx.angle); - vec3f_copy(gMirrorMario[i].pos, mario->header.gfx.pos); - vec3f_copy(gMirrorMario[i].scale, mario->header.gfx.scale); - // FIXME: why does this set unk38, an inline struct, to a ptr to another one? wrong - // GraphNode types again? - gMirrorMario[i].animInfo = *(struct AnimInfo*) & mario->header.gfx.animInfo.animID; - mirroredX = MIRROR_X - gMirrorMario[i].pos[0]; - gMirrorMario[i].pos[0] = mirroredX + MIRROR_X; - gMirrorMario[i].angle[1] = -gMirrorMario[i].angle[1]; - gMirrorMario[i].scale[0] *= -1.0f; - // TODO: enabling rendering can cause the game to crash when two players are in the mirror room - //gMirrorMario[i].node.flags |= GRAPH_RENDER_ACTIVE; - gMirrorMario[i].node.flags &= ~GRAPH_RENDER_ACTIVE; - } else { - gMirrorMario[i].node.flags &= ~GRAPH_RENDER_ACTIVE; - } - break; - } + switch (callContext) { + case GEO_CONTEXT_CREATE: + init_graph_node_object(NULL, &gMirrorMario[0], NULL, gVec3fZero, gVec3sZero, gVec3fOne); + break; + case GEO_CONTEXT_AREA_LOAD: + geo_add_child(node, &gMirrorMario[0].node); + break; + case GEO_CONTEXT_AREA_UNLOAD: + geo_remove_child_from_parent(node, &gMirrorMario[0].node); + break; + case GEO_CONTEXT_RENDER: + if (marioLocal->header.gfx.pos[0] > 1700.0f) { + // TODO: Is this a geo layout copy or a graph node copy? + gMirrorMario[0].sharedChild = mario->header.gfx.sharedChild; + dynos_actor_override((void*)&gMirrorMario[0].sharedChild); + gMirrorMario[0].areaIndex = mario->header.gfx.areaIndex; + vec3s_copy(gMirrorMario[0].angle, mario->header.gfx.angle); + vec3f_copy(gMirrorMario[0].pos, mario->header.gfx.pos); + vec3f_copy(gMirrorMario[0].scale, mario->header.gfx.scale); + // FIXME: why does this set unk38, an inline struct, to a ptr to another one? wrong + // GraphNode types again? + gMirrorMario[0].animInfo = *(struct AnimInfo*) & mario->header.gfx.animInfo.animID; + mirroredX = MIRROR_X - gMirrorMario[0].pos[0]; + gMirrorMario[0].pos[0] = mirroredX + MIRROR_X; + gMirrorMario[0].angle[1] = -gMirrorMario[0].angle[1]; + gMirrorMario[0].scale[0] *= -1.0f; + gMirrorMario[0].node.flags |= GRAPH_RENDER_ACTIVE; + } else { + gMirrorMario[0].node.flags &= ~GRAPH_RENDER_ACTIVE; + } + break; } + return NULL; } From de2300f837bbb4d71a043a2f39a483fd648f9531 Mon Sep 17 00:00:00 2001 From: MysterD Date: Thu, 19 May 2022 19:42:07 -0700 Subject: [PATCH 11/13] Fix clang/mac compile --- Makefile | 2 +- actors/number/geo.inc.c | 1 + autogen/lua_definitions/functions.lua | 19 +++++++++++-- docs/lua/functions-3.md | 40 +++++++++++++++++++++++++++ docs/lua/functions-4.md | 18 ++++++------ docs/lua/functions.md | 2 ++ src/pc/djui/djui_panel_host_message.c | 1 + src/pc/gfx/gfx_pc.c | 4 ++- src/pc/lua/smlua_functions.c | 2 ++ src/pc/lua/smlua_functions_autogen.c | 32 +++++++++++++++++++-- src/pc/lua/utils/smlua_misc_utils.c | 6 ++-- src/pc/lua/utils/smlua_misc_utils.h | 6 ++-- src/pc/utils/misc.c | 31 --------------------- 13 files changed, 110 insertions(+), 54 deletions(-) diff --git a/Makefile b/Makefile index 4ca1ae3c1..c24ecf321 100644 --- a/Makefile +++ b/Makefile @@ -678,7 +678,7 @@ else ifeq ($(COMPILER),clang) CC := clang CXX := clang++ CPP := clang++ - EXTRA_CFLAGS += -Wno-unused-function -Wno-unused-variable -Wno-unknown-warning-option -Wno-self-assign -Wno-unknown-pragmas + EXTRA_CFLAGS += -Wno-unused-function -Wno-unused-variable -Wno-unknown-warning-option -Wno-self-assign -Wno-unknown-pragmas -Wno-unused-result else ifeq ($(TARGET_WEB),1) # As in, web PC port CC := emcc CXX := emcc diff --git a/actors/number/geo.inc.c b/actors/number/geo.inc.c index 44b4135d5..3c881384e 100644 --- a/actors/number/geo.inc.c +++ b/actors/number/geo.inc.c @@ -47,6 +47,7 @@ Gfx *geo_num3_switch(s32 callContext, struct GraphNode *node, UNUSED void *conte switchCase->selectedCase = 10; } } + return NULL; } extern const Gfx dl_billboard_num3_0[]; diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua index 8c283bb63..afb08b4a3 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -3693,6 +3693,11 @@ function get_current_background_music() -- ... end +--- @return integer +function get_current_background_music_default_volume() + -- ... +end + --- @return integer function get_current_background_music_max_target_volume() -- ... @@ -4232,6 +4237,14 @@ function set_mario_animation(m, targetAnimID) -- ... end +--- @param m MarioState +--- @param flags integer +--- @param clear integer +--- @return nil +function set_mario_particle_flags(m, flags, clear) + -- ... +end + --- @param m MarioState --- @param initialVelY number --- @param multiplier number @@ -7434,19 +7447,19 @@ function set_environment_region(index, value) end --- @param far number ---- @return number +--- @return nil function set_override_far(far) -- ... end --- @param fov number ---- @return number +--- @return nil function set_override_fov(fov) -- ... end --- @param near number ---- @return number +--- @return nil function set_override_near(near) -- ... end diff --git a/docs/lua/functions-3.md b/docs/lua/functions-3.md index b1dc37097..f2742567e 100644 --- a/docs/lua/functions-3.md +++ b/docs/lua/functions-3.md @@ -2396,6 +2396,24 @@
+## [get_current_background_music_default_volume](#get_current_background_music_default_volume) + +### Lua Example +`local integerValue = get_current_background_music_default_volume()` + +### Parameters +- None + +### Returns +- `integer` + +### C Prototype +`u8 get_current_background_music_default_volume(void);` + +[:arrow_up_small:](#) + +
+ ## [get_current_background_music_max_target_volume](#get_current_background_music_max_target_volume) ### Lua Example @@ -4064,6 +4082,28 @@
+## [set_mario_particle_flags](#set_mario_particle_flags) + +### Lua Example +`set_mario_particle_flags(m, flags, clear)` + +### Parameters +| Field | Type | +| ----- | ---- | +| m | [MarioState](structs.md#MarioState) | +| flags | `integer` | +| clear | `integer` | + +### Returns +- None + +### C Prototype +`void set_mario_particle_flags(struct MarioState* m, u32 flags, u8 clear);` + +[:arrow_up_small:](#) + +
+ ## [set_mario_y_vel_based_on_fspeed](#set_mario_y_vel_based_on_fspeed) ### Lua Example diff --git a/docs/lua/functions-4.md b/docs/lua/functions-4.md index b83d7d860..09c8a99f5 100644 --- a/docs/lua/functions-4.md +++ b/docs/lua/functions-4.md @@ -5498,7 +5498,7 @@ ## [set_override_far](#set_override_far) ### Lua Example -`local numberValue = set_override_far(far)` +`set_override_far(far)` ### Parameters | Field | Type | @@ -5506,10 +5506,10 @@ | far | `number` | ### Returns -- `number` +- None ### C Prototype -`f32 set_override_far(f32 far);` +`void set_override_far(f32 far);` [:arrow_up_small:](#) @@ -5518,7 +5518,7 @@ ## [set_override_fov](#set_override_fov) ### Lua Example -`local numberValue = set_override_fov(fov)` +`set_override_fov(fov)` ### Parameters | Field | Type | @@ -5526,10 +5526,10 @@ | fov | `number` | ### Returns -- `number` +- None ### C Prototype -`f32 set_override_fov(f32 fov);` +`void set_override_fov(f32 fov);` [:arrow_up_small:](#) @@ -5538,7 +5538,7 @@ ## [set_override_near](#set_override_near) ### Lua Example -`local numberValue = set_override_near(near)` +`set_override_near(near)` ### Parameters | Field | Type | @@ -5546,10 +5546,10 @@ | near | `number` | ### Returns -- `number` +- None ### C Prototype -`f32 set_override_near(f32 near);` +`void set_override_near(f32 near);` [:arrow_up_small:](#) diff --git a/docs/lua/functions.md b/docs/lua/functions.md index 40dd7770d..3866c0efe 100644 --- a/docs/lua/functions.md +++ b/docs/lua/functions.md @@ -729,6 +729,7 @@ - [fade_volume_scale](functions-3.md#fade_volume_scale) - [fadeout_background_music](functions-3.md#fadeout_background_music) - [get_current_background_music](functions-3.md#get_current_background_music) + - [get_current_background_music_default_volume](functions-3.md#get_current_background_music_default_volume) - [get_current_background_music_max_target_volume](functions-3.md#get_current_background_music_max_target_volume) - [get_current_background_music_target_volume](functions-3.md#get_current_background_music_target_volume) - [is_current_background_music_volume_lowered](functions-3.md#is_current_background_music_volume_lowered) @@ -821,6 +822,7 @@ - [set_mario_action](functions-3.md#set_mario_action) - [set_mario_anim_with_accel](functions-3.md#set_mario_anim_with_accel) - [set_mario_animation](functions-3.md#set_mario_animation) + - [set_mario_particle_flags](functions-3.md#set_mario_particle_flags) - [set_mario_y_vel_based_on_fspeed](functions-3.md#set_mario_y_vel_based_on_fspeed) - [set_steep_jump_action](functions-3.md#set_steep_jump_action) - [set_water_plunge_action](functions-3.md#set_water_plunge_action) diff --git a/src/pc/djui/djui_panel_host_message.c b/src/pc/djui/djui_panel_host_message.c index 547d0f359..edbfc5ad4 100644 --- a/src/pc/djui/djui_panel_host_message.c +++ b/src/pc/djui/djui_panel_host_message.c @@ -7,6 +7,7 @@ #include "pc/utils/misc.h" #include "src/game/level_update.h" #include "src/game/hardcoded.h" +#include "src/engine/math_util.h" #include "audio/external.h" #include "sounds.h" diff --git a/src/pc/gfx/gfx_pc.c b/src/pc/gfx/gfx_pc.c index 32bb7f7e1..7abc8227c 100644 --- a/src/pc/gfx/gfx_pc.c +++ b/src/pc/gfx/gfx_pc.c @@ -624,14 +624,16 @@ static void import_texture(int tile) { // make sure the texture id is a printable ascii string bool texidIsPrintable = true; char* c = (char*)texid; + u16 length = 0; while (c != NULL && *c != '\0') { if (*c < 33 || *c > 126) { texidIsPrintable = false; break; } + length++; c++; } - if (texidIsPrintable) { + if (texidIsPrintable && length > 0) { char texname[SYS_MAX_PATH]; snprintf(texname, sizeof(texname), FS_TEXTUREDIR "/%s.png", texid); load_texture(texname); diff --git a/src/pc/lua/smlua_functions.c b/src/pc/lua/smlua_functions.c index c9a3f9da2..f18192d8b 100644 --- a/src/pc/lua/smlua_functions.c +++ b/src/pc/lua/smlua_functions.c @@ -178,11 +178,13 @@ int smlua_func_network_send_object(lua_State* L) { int smlua_func_network_send(lua_State* L) { if (!smlua_functions_valid_param_count(L, 2)) { return 0; } network_send_lua_custom(true); + return 1; } int smlua_func_network_send_to(lua_State* L) { if (!smlua_functions_valid_param_count(L, 3)) { return 0; } network_send_lua_custom(false); + return 1; } ////////////// diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c index 348817295..1d9360098 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -7447,6 +7447,15 @@ int smlua_func_get_current_background_music(UNUSED lua_State* L) { return 1; } +int smlua_func_get_current_background_music_default_volume(UNUSED lua_State* L) { + if(!smlua_functions_valid_param_count(L, 0)) { return 0; } + + + lua_pushinteger(L, get_current_background_music_default_volume()); + + return 1; +} + int smlua_func_get_current_background_music_max_target_volume(UNUSED lua_State* L) { if(!smlua_functions_valid_param_count(L, 0)) { return 0; } @@ -8489,6 +8498,21 @@ int smlua_func_set_mario_animation(lua_State* L) { return 1; } +int smlua_func_set_mario_particle_flags(lua_State* L) { + if(!smlua_functions_valid_param_count(L, 3)) { return 0; } + + struct MarioState* m = (struct MarioState*)smlua_to_cobject(L, 1, LOT_MARIOSTATE); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; } + u32 flags = smlua_to_integer(L, 2); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 2"); return 0; } + u8 clear = smlua_to_integer(L, 3); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 3"); return 0; } + + set_mario_particle_flags(m, flags, clear); + + return 1; +} + int smlua_func_set_mario_y_vel_based_on_fspeed(lua_State* L) { if(!smlua_functions_valid_param_count(L, 3)) { return 0; } @@ -15282,7 +15306,7 @@ int smlua_func_set_override_far(lua_State* L) { f32 far = smlua_to_number(L, 1); if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; } - lua_pushnumber(L, set_override_far(far)); + set_override_far(far); return 1; } @@ -15293,7 +15317,7 @@ int smlua_func_set_override_fov(lua_State* L) { f32 fov = smlua_to_number(L, 1); if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; } - lua_pushnumber(L, set_override_fov(fov)); + set_override_fov(fov); return 1; } @@ -15304,7 +15328,7 @@ int smlua_func_set_override_near(lua_State* L) { f32 near = smlua_to_number(L, 1); if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; } - lua_pushnumber(L, set_override_near(near)); + set_override_near(near); return 1; } @@ -16951,6 +16975,7 @@ void smlua_bind_functions_autogen(void) { smlua_bind_function(L, "fade_volume_scale", smlua_func_fade_volume_scale); smlua_bind_function(L, "fadeout_background_music", smlua_func_fadeout_background_music); smlua_bind_function(L, "get_current_background_music", smlua_func_get_current_background_music); + smlua_bind_function(L, "get_current_background_music_default_volume", smlua_func_get_current_background_music_default_volume); smlua_bind_function(L, "get_current_background_music_max_target_volume", smlua_func_get_current_background_music_max_target_volume); smlua_bind_function(L, "get_current_background_music_target_volume", smlua_func_get_current_background_music_target_volume); smlua_bind_function(L, "is_current_background_music_volume_lowered", smlua_func_is_current_background_music_volume_lowered); @@ -17037,6 +17062,7 @@ void smlua_bind_functions_autogen(void) { smlua_bind_function(L, "set_mario_action", smlua_func_set_mario_action); smlua_bind_function(L, "set_mario_anim_with_accel", smlua_func_set_mario_anim_with_accel); smlua_bind_function(L, "set_mario_animation", smlua_func_set_mario_animation); + smlua_bind_function(L, "set_mario_particle_flags", smlua_func_set_mario_particle_flags); smlua_bind_function(L, "set_mario_y_vel_based_on_fspeed", smlua_func_set_mario_y_vel_based_on_fspeed); smlua_bind_function(L, "set_steep_jump_action", smlua_func_set_steep_jump_action); smlua_bind_function(L, "set_water_plunge_action", smlua_func_set_water_plunge_action); diff --git a/src/pc/lua/utils/smlua_misc_utils.c b/src/pc/lua/utils/smlua_misc_utils.c index 790730938..2a21ef0ca 100644 --- a/src/pc/lua/utils/smlua_misc_utils.c +++ b/src/pc/lua/utils/smlua_misc_utils.c @@ -192,14 +192,14 @@ void set_environment_region(u8 index, s32 value) { } } -f32 set_override_fov(f32 fov) { +void set_override_fov(f32 fov) { gOverrideFOV = fov; } -f32 set_override_near(f32 near) { +void set_override_near(f32 near) { gOverrideNear = near; } -f32 set_override_far(f32 far) { +void set_override_far(f32 far) { gOverrideFar = far; } diff --git a/src/pc/lua/utils/smlua_misc_utils.h b/src/pc/lua/utils/smlua_misc_utils.h index 326541ab7..6a55e74d6 100644 --- a/src/pc/lua/utils/smlua_misc_utils.h +++ b/src/pc/lua/utils/smlua_misc_utils.h @@ -59,9 +59,9 @@ void movtexqc_register(const char* name, s16 level, s16 area, s16 type); f32 get_environment_region(u8 index); void set_environment_region(u8 index, s32 value); -f32 set_override_fov(f32 fov); -f32 set_override_near(f32 near); -f32 set_override_far(f32 far); +void set_override_fov(f32 fov); +void set_override_near(f32 near); +void set_override_far(f32 far); void play_transition(s16 transType, s16 time, u8 red, u8 green, u8 blue); diff --git a/src/pc/utils/misc.c b/src/pc/utils/misc.c index d09aecc16..a62874cef 100644 --- a/src/pc/utils/misc.c +++ b/src/pc/utils/misc.c @@ -129,37 +129,6 @@ static f32 asins(f32 val) { return radians_to_sm64(asin(sm64_to_radians(val))); } -void mtx_to_euler1(Mtx* mat, Vec3s rot) { - if (mat->m[1][1] == 1.0f) { - rot[0] = 0; - rot[1] = atan2(mat->m[1][3], mat->m[3][4]); - rot[2] = 0; - } else if (mat->m[1][1] == -1.0f) { - rot[0] = 0; - rot[1] = atan2(mat->m[1][3], mat->m[3][4]); - rot[2] = 0; - } else { - rot[0] = asin(mat->m[2][1]); - rot[1] = atan2(-mat->m[3][1], mat->m[1][1]); - rot[2] = atan2(-mat->m[2][3], mat->m[2][2]); - } -} -void mtx_to_euler2(Mtx* mat, Vec3s rot) { - if (mat->m[1][1] == 1.0f) { - rot[0] = 0; - rot[1] = atan2(mat->m[3][1], mat->m[4][3]); - rot[2] = 0; - } else if (mat->m[1][1] == -1.0f) { - rot[0] = 0; - rot[1] = atan2(mat->m[3][1], mat->m[4][3]); - rot[2] = 0; - } else { - rot[0] = asin(mat->m[1][2]); - rot[1] = atan2(-mat->m[1][3], mat->m[1][1]); - rot[2] = atan2(-mat->m[3][2], mat->m[2][2]); - } -} - f32 delta_interpolate_f32(f32 start, f32 end, f32 delta) { return start * (1.0f - delta) + end * delta; } From 6d6c8fc5e3e69dba9c7ed5557b016864f8df86cd Mon Sep 17 00:00:00 2001 From: Marioiscool246 Date: Fri, 20 May 2022 14:32:47 -0400 Subject: [PATCH 12/13] Particle sync fixes (#112) * Fix lingering particles when a player exits an area or disconnects --- src/game/object_list_processor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/game/object_list_processor.c b/src/game/object_list_processor.c index 561b83b56..ca0919e68 100644 --- a/src/game/object_list_processor.c +++ b/src/game/object_list_processor.c @@ -16,6 +16,7 @@ #include "object_collision.h" #include "object_helpers.h" #include "object_list_processor.h" +#include "obj_behaviors.h" #include "platform_displacement.h" #include "profiler.h" #include "spawn_object.h" @@ -281,7 +282,7 @@ void bhv_mario_update(void) { vec3f_copy(gMarioState->marioBodyState->torsoPos, gMarioState->pos); } - if (stateIndex == 0) { + if ((stateIndex == 0) || (!is_player_active(gMarioState))) { gMarioState->particleFlags = 0; } From d553d9b551087681681621334c8f539891eb2dfa Mon Sep 17 00:00:00 2001 From: Amy54Desu <69287652+Amy54Desu@users.noreply.github.com> Date: Fri, 20 May 2022 14:36:44 -0400 Subject: [PATCH 13/13] Add Act Num to Playerlist (#95) --- src/pc/djui/djui_panel_modlist.c | 2 +- src/pc/djui/djui_panel_playerlist.c | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/pc/djui/djui_panel_modlist.c b/src/pc/djui/djui_panel_modlist.c index 8d42ee6ea..5b98e6f51 100644 --- a/src/pc/djui/djui_panel_modlist.c +++ b/src/pc/djui/djui_panel_modlist.c @@ -7,7 +7,7 @@ struct DjuiThreePanel* gDjuiModList = NULL; void djui_panel_modlist_create(UNUSED struct DjuiBase* caller) { - int playerListWidth = 585; + int playerListWidth = 710; int modListWidth = 280; // delete old mod list diff --git a/src/pc/djui/djui_panel_playerlist.c b/src/pc/djui/djui_panel_playerlist.c index 7921421a6..ede0250c1 100644 --- a/src/pc/djui/djui_panel_playerlist.c +++ b/src/pc/djui/djui_panel_playerlist.c @@ -15,9 +15,16 @@ static struct DjuiImage* djuiImages[MAX_PLAYERS] = { 0 }; static struct DjuiText* djuiTextNames[MAX_PLAYERS] = { 0 }; static struct DjuiText* djuiTextDescriptions[MAX_PLAYERS] = { 0 }; static struct DjuiText* djuiTextLocations[MAX_PLAYERS] = { 0 }; +static struct DjuiText* djuiTextAct[MAX_PLAYERS] = { 0 }; static void playerlist_update_row(u8 i, struct NetworkPlayer *np) { u8 charIndex = np->overrideModelIndex; + char sActNum[7]; + if (np->currActNum != 99) { + snprintf(sActNum, 7, "# %d", np->currActNum); + } else { + snprintf(sActNum, 7, "Done"); + } if (charIndex >= CT_MAX) { charIndex = 0; } djuiImages[i]->texture = gCharacters[charIndex].hudHeadTexture.texture; @@ -36,6 +43,7 @@ static void playerlist_update_row(u8 i, struct NetworkPlayer *np) { djui_text_set_text(djuiTextDescriptions[i], np->description); djui_text_set_text(djuiTextLocations[i], get_level_name(np->currCourseNum, np->currLevelNum, np->currAreaIndex)); + djui_text_set_text(djuiTextAct[i], sActNum); } void djui_panel_playerlist_on_render_pre(UNUSED struct DjuiBase* base, UNUSED bool* skipRender) { @@ -61,7 +69,7 @@ void djui_panel_playerlist_create(UNUSED struct DjuiBase* caller) { panel->base.on_render_pre = djui_panel_playerlist_on_render_pre; djui_base_set_alignment(&panel->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER); djui_base_set_size_type(&panel->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE); - djui_base_set_size(&panel->base, 585, bodyHeight + (32 + 16) + 32 + 32); + djui_base_set_size(&panel->base, 710, bodyHeight + (32 + 16) + 32 + 32); djui_base_set_visible(&panel->base, false); struct DjuiFlowLayout* body = (struct DjuiFlowLayout*)djui_three_panel_get_body(panel); djui_flow_layout_set_margin(body, 4); @@ -91,9 +99,9 @@ void djui_panel_playerlist_create(UNUSED struct DjuiBase* caller) { struct DjuiText* t3 = djui_text_create(&row->base, ""); djui_base_set_size_type(&t3->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE); - djui_base_set_size(&t3->base, 103, 32.0f); + djui_base_set_size(&t3->base, 100, 32.0f); djui_base_set_color(&t3->base, 220, 220, 220, 255); - djui_text_set_alignment(t3, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP); + djui_text_set_alignment(t3, DJUI_HALIGN_CENTER, DJUI_VALIGN_TOP); djuiTextDescriptions[i] = t3; struct DjuiText* t4 = djui_text_create(&row->base, "location"); @@ -102,5 +110,12 @@ void djui_panel_playerlist_create(UNUSED struct DjuiBase* caller) { djui_base_set_color(&t4->base, t, t, t, 255); djui_text_set_alignment(t4, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP); djuiTextLocations[i] = t4; + + struct DjuiText* t5 = djui_text_create(&row->base, "act"); + djui_base_set_size_type(&t5->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&t5->base, 100, 32.0f); + djui_base_set_color(&t5->base, t, t, t, 255); + djui_text_set_alignment(t5, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP); + djuiTextAct[i] = t5; } }