diff --git a/Makefile b/Makefile index 44fca33d4..c24ecf321 100644 --- a/Makefile +++ b/Makefile @@ -64,7 +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 @@ -347,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 @@ -668,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 @@ -891,6 +901,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 +1116,8 @@ endef # Main Targets # #==============================================================================# + + ifeq ($(EXTERNAL_DATA),1) BASEPACK_PATH := $(BUILD_DIR)/$(BASEDIR)/$(BASEPACK) @@ -1177,6 +1202,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 @@ -1304,6 +1330,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:,$<,$@) @@ -1545,4 +1574,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/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/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/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/constants.lua b/autogen/lua_definitions/constants.lua index 0d7c729ea..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 @@ -2615,7 +2654,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/functions.lua b/autogen/lua_definitions/functions.lua index aeebeb84b..afb08b4a3 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -3688,6 +3688,31 @@ function fadeout_background_music(arg0, fadeOut) -- ... end +--- @return integer +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() + -- ... +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() -- ... @@ -4212,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 @@ -7376,6 +7409,11 @@ function hud_show() -- ... end +--- @return boolean +function is_game_paused() + -- ... +end + --- @param name string --- @param level integer --- @param area integer @@ -7409,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/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.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..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 @@ -764,7 +765,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_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/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/constants.md b/docs/lua/constants.md index 4dda0b0ec..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) @@ -836,7 +856,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/functions-3.md b/docs/lua/functions-3.md index ee9e77874..f2742567e 100644 --- a/docs/lua/functions-3.md +++ b/docs/lua/functions-3.md @@ -2378,6 +2378,96 @@
+## [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_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 +`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 @@ -3992,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 a3a907d1a..09c8a99f5 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 @@ -5480,7 +5498,7 @@ ## [set_override_far](#set_override_far) ### Lua Example -`local numberValue = set_override_far(far)` +`set_override_far(far)` ### Parameters | Field | Type | @@ -5488,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:](#) @@ -5500,7 +5518,7 @@ ## [set_override_fov](#set_override_fov) ### Lua Example -`local numberValue = set_override_fov(fov)` +`set_override_fov(fov)` ### Parameters | Field | Type | @@ -5508,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:](#) @@ -5520,7 +5538,7 @@ ## [set_override_near](#set_override_near) ### Lua Example -`local numberValue = set_override_near(near)` +`set_override_near(near)` ### Parameters | Field | Type | @@ -5528,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 586339b39..3866c0efe 100644 --- a/docs/lua/functions.md +++ b/docs/lua/functions.md @@ -728,6 +728,11 @@ - 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_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) - [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) @@ -817,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) @@ -1376,6 +1382,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/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/res/icon.ico b/res/icon.ico new file mode 100644 index 000000000..a147df06c Binary files /dev/null and b/res/icon.ico differ 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 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 1303e9940..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,25 @@ 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; +} + +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..61f5c0320 100644 --- a/src/audio/external.h +++ b/src/audio/external.h @@ -53,6 +53,10 @@ 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); 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/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/game/characters.c b/src/game/characters.c index cad9a5624..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) { @@ -515,6 +537,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/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/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/interaction.c b/src/game/interaction.c index a8afe1753..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); } } } @@ -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..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); } } @@ -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); @@ -1597,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); } } } @@ -2249,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 bed82c7a4..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 @@ -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; @@ -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..c87acab87 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]; @@ -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; } diff --git a/src/game/object_list_processor.c b/src/game/object_list_processor.c index 390caf384..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,10 @@ void bhv_mario_update(void) { vec3f_copy(gMarioState->marioBodyState->torsoPos, gMarioState->pos); } - gMarioState->particleFlags = 0; + if ((stateIndex == 0) || (!is_player_active(gMarioState))) { + gMarioState->particleFlags = 0; + } + smlua_call_event_hooks_mario_param(HOOK_BEFORE_MARIO_UPDATE, gMarioState); u32 particleFlags = 0; 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/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/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/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/djui/djui_panel_host_message.c b/src/pc/djui/djui_panel_host_message.c index ff700ba96..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" @@ -46,7 +47,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/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_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); 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; } } 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.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(); 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..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" @@ -1071,7 +1084,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" 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 9ece0bd5c..1d9360098 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -7438,6 +7438,51 @@ 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_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; } + + + 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; } @@ -8453,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; } @@ -15171,6 +15231,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; } @@ -15237,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; } @@ -15248,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; } @@ -15259,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; } @@ -16905,6 +16974,11 @@ 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_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); 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); @@ -16988,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); @@ -17524,6 +17599,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..2a21ef0ca 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); } @@ -185,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 84390c93c..6a55e74d6 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); @@ -57,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/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 diff --git a/src/pc/network/network.c b/src/pc/network/network.c index 6f83aff23..e362b8920 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,12 +462,15 @@ 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); smlua_shutdown(); extern s16 gChangeLevel; gChangeLevel = LEVEL_CASTLE_GROUNDS; + network_player_init(); extern s16 gMenuMode; gMenuMode = -1; 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; 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; }