diff --git a/autogen/convert_functions.py b/autogen/convert_functions.py index 231eb3383..b5151e4f7 100644 --- a/autogen/convert_functions.py +++ b/autogen/convert_functions.py @@ -120,6 +120,7 @@ override_disallowed_functions = { "src/game/mario.h": [ " init_mario" ], "src/pc/djui/djui_console.h": [ " djui_console_create", "djui_console_message_create", "djui_console_message_dequeue" ], "src/pc/djui/djui_chat_message.h": [ "create_from" ], + "src/pc/djui/djui_hud_utils.h": [ "djui_hud_clear_interp_data" ], "src/game/interaction.h": [ "process_interaction", "_handle_" ], "src/game/sound_init.h": [ "_loop_", "thread4_", "set_sound_mode" ], "src/pc/network/network_utils.h": [ "network_get_player_text_color[^_]" ], diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua index 51f161f00..51d0604e1 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -3843,7 +3843,7 @@ function djui_hud_set_font(fontType) end --- @return DjuiColor ---- Gets the current DJUI HUD color +--- Gets the current DJUI HUD global color function djui_hud_get_color() -- ... end @@ -3852,16 +3852,36 @@ end --- @param g integer --- @param b integer --- @param a integer ---- Sets the current DJUI HUD color +--- Sets the current DJUI HUD global color function djui_hud_set_color(r, g, b, a) -- ... end ---- Resets the current DJUI HUD color +--- Resets the current DJUI HUD global color function djui_hud_reset_color() -- ... end +--- @return DjuiColor +--- Gets the current DJUI HUD text default color. This color is overridden by color codes +function djui_hud_get_text_color() + -- ... +end + +--- @param r integer +--- @param g integer +--- @param b integer +--- @param a integer +--- Sets the current DJUI HUD text default color. This color is overridden by color codes +function djui_hud_set_text_color(r, g, b, a) + -- ... +end + +--- Resets the current DJUI HUD text default color. This color is overridden by color codes +function djui_hud_reset_text_color() + -- ... +end + --- @return integer rotation --- @return number pivotX --- @return number pivotY @@ -9083,12 +9103,6 @@ function cur_obj_check_anim_frame_in_range(startFrame, rangeLength) -- ... end ---- @param a0 Pointer_integer ---- @return integer -function cur_obj_check_frame_prior_current_frame(a0) - -- ... -end - --- @param m MarioState --- @return integer function mario_is_in_air_action(m) diff --git a/data/dynos_bin_col.cpp b/data/dynos_bin_col.cpp index cd5a58e50..331cbb130 100644 --- a/data/dynos_bin_col.cpp +++ b/data/dynos_bin_col.cpp @@ -3,7 +3,9 @@ extern "C" { #include "include/surface_terrains.h" #include "include/level_misc_macros.h" +#include "include/special_presets.h" #include "include/special_preset_names.h" +#include "src/engine/surface_load.h" } // Free data pointers, but keep nodes and tokens intact @@ -34,12 +36,32 @@ struct CollisionValidationData { u32 vtxCount; u32 triAlloc; u32 triCount; + s16 surfaceType; u32 specialAlloc; u32 specialCount; u32 waterBoxAlloc; u32 waterBoxCount; }; +static u8 GetSpecialObjectType(u8 preset) { + for (s32 i = 0; i < ARRAY_COUNT(SpecialObjectPresets); ++i) { + if (SpecialObjectPresets[i].preset_id == preset) { + return SpecialObjectPresets[i].type; + } + } + return SPTYPE_UNKNOWN; +} + +static const char *GetCorrectSpecialObjectCommand(u8 presetType) { + switch (presetType) { + case SPTYPE_NO_YROT_OR_PARAMS: return "SPECIAL_OBJECT"; + case SPTYPE_YROT_NO_PARAMS: return "SPECIAL_OBJECT_WITH_YAW"; + case SPTYPE_PARAMS_AND_YROT: return "SPECIAL_OBJECT_WITH_YAW_AND_PARAM"; + case SPTYPE_DEF_PARAM_AND_YROT: return "SPECIAL_OBJECT_WITH_YAW"; + default: return ""; + } +} + static void ValidateColSectionChange(GfxData* aGfxData, struct CollisionValidationData& aColValData, u8 section) { if (aColValData.section == COL_SECTION_END) { PrintDataError("Found new col section after COL_END"); @@ -67,51 +89,70 @@ static void ValidateColInit(GfxData* aGfxData, struct CollisionValidationData& a ValidateColSectionChange(aGfxData, aColValData, COL_SECTION_VTX); } -static void ValidateColVertexInit(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 arg0) { +static void ValidateColVertexInit(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 vertexCount) { if (strcmp(aColValData.lastSymbol, "COL_INIT") != 0) { PrintDataError("COL_VERTEX_INIT found outside of vertex section"); } - if (arg0 < 0) { - PrintDataError("COL_VERTEX_INIT with a negative count: %d", arg0); + if (vertexCount < 0) { + PrintDataError("COL_VERTEX_INIT with a negative count: %d", vertexCount); } - aColValData.vtxAlloc = arg0; + aColValData.vtxAlloc = vertexCount; aColValData.vtxCount = 0; } -static void ValidateColVertex(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 arg0, s16 arg1, s16 arg2) { +static void ValidateColVertex(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 x, s16 y, s16 z) { if (aColValData.section != COL_SECTION_VTX) { PrintDataError("COL_VERTEX found outside of vertex section"); } aColValData.vtxCount++; } -static void ValidateColTriInit(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 arg0, s16 arg1) { - if (arg1 < 0) { - PrintDataError("COL_TRI_INIT with a negative count: %d", arg1); +static void ValidateColTriInit(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 surfaceType, s16 triangleCount) { + if (triangleCount < 0) { + PrintDataError("COL_TRI_INIT with a negative count: %d", triangleCount); } ValidateColSectionChange(aGfxData, aColValData, COL_SECTION_TRI); - aColValData.triAlloc = arg1; + aColValData.triAlloc = triangleCount; aColValData.triCount = 0; + aColValData.surfaceType = surfaceType; } -static void ValidateColTri(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 arg0, s16 arg1, s16 arg2) { +static void ValidateColTri(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 vertex0, s16 vertex1, s16 vertex2) { if (aColValData.section != COL_SECTION_TRI) { PrintDataError("COL_TRI found outside of triangle section"); } - if (arg0 < 0 || arg0 > aColValData.vtxCount) { - PrintDataError("COL_TRI used vertex outside of known range for first param: %d", arg0); + if (surface_has_force(aColValData.surfaceType)) { + PrintDataError("COL_TRI cannot be used by surface types with a force parameter: %d (use COL_TRI_SPECIAL instead)", aColValData.surfaceType); } - if (arg1 < 0 || arg1 > aColValData.vtxCount) { - PrintDataError("COL_TRI used vertex outside of known range for second param: %d", arg1); + if (vertex0 < 0 || vertex0 > aColValData.vtxCount) { + PrintDataError("COL_TRI used vertex outside of known range for first param: %d", vertex0); } - if (arg2 < 0 || arg2 > aColValData.vtxCount) { - PrintDataError("COL_TRI used vertex outside of known range for third param: %d", arg2); + if (vertex1 < 0 || vertex1 > aColValData.vtxCount) { + PrintDataError("COL_TRI used vertex outside of known range for second param: %d", vertex1); + } + if (vertex2 < 0 || vertex2 > aColValData.vtxCount) { + PrintDataError("COL_TRI used vertex outside of known range for third param: %d", vertex2); } aColValData.triCount++; } -static void ValidateColTriSpecial(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 arg0, s16 arg1, s16 arg2, s16 arg3) { - ValidateColTri(aGfxData, aColValData, arg0, arg1, arg2); +static void ValidateColTriSpecial(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 vertex0, s16 vertex1, s16 vertex2, s16 force) { + if (aColValData.section != COL_SECTION_TRI) { + PrintDataError("COL_TRI_SPECIAL found outside of triangle section"); + } + if (!surface_has_force(aColValData.surfaceType)) { + PrintDataError("COL_TRI_SPECIAL cannot be used by surface types with no force parameter: %d (use COL_TRI instead)", aColValData.surfaceType); + } + if (vertex0 < 0 || vertex0 > aColValData.vtxCount) { + PrintDataError("COL_TRI_SPECIAL used vertex outside of known range for first param: %d", vertex0); + } + if (vertex1 < 0 || vertex1 > aColValData.vtxCount) { + PrintDataError("COL_TRI_SPECIAL used vertex outside of known range for second param: %d", vertex1); + } + if (vertex2 < 0 || vertex2 > aColValData.vtxCount) { + PrintDataError("COL_TRI_SPECIAL used vertex outside of known range for third param: %d", vertex2); + } + aColValData.triCount++; } static void ValidateColStop(GfxData* aGfxData, struct CollisionValidationData& aColValData) { @@ -122,49 +163,70 @@ static void ValidateColEnd(GfxData* aGfxData, struct CollisionValidationData& aC ValidateColSectionChange(aGfxData, aColValData, COL_SECTION_END); } -static void ValidateColSpecialInit(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 arg0) { - if (arg0 < 0) { - PrintDataError("COL_SPECIAL_INIT with a negative count: %d", arg0); +static void ValidateColSpecialInit(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 specialCount) { + if (specialCount < 0) { + PrintDataError("COL_SPECIAL_INIT with a negative count: %d", specialCount); } ValidateColSectionChange(aGfxData, aColValData, COL_SECTION_SPECIAL); - aColValData.specialAlloc = arg0; + aColValData.specialAlloc = specialCount; aColValData.specialCount = 0; } -static void ValidateColWaterBoxInit(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 arg0) { - if (arg0 < 0) { - PrintDataError("COL_WATER_BOX_INIT with a negative count: %d", arg0); +static void ValidateColWaterBoxInit(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 waterBoxCount) { + if (waterBoxCount < 0) { + PrintDataError("COL_WATER_BOX_INIT with a negative count: %d", waterBoxCount); } ValidateColSectionChange(aGfxData, aColValData, COL_SECTION_WATER_BOX); - aColValData.waterBoxAlloc = arg0; + aColValData.waterBoxAlloc = waterBoxCount; aColValData.waterBoxCount = 0; } -static void ValidateColWaterBox(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 arg0, s16 arg1, s16 arg2, s16 arg3, s16 arg4, s16 arg5) { +static void ValidateColWaterBox(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 id, s16 x1, s16 z1, s16 x2, s16 z2, s16 y) { if (aColValData.section != COL_SECTION_WATER_BOX) { PrintDataError("COL_WATER_BOX found outside of water box section"); } aColValData.waterBoxCount++; } -static void ValidateColSpecialObject(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 arg0, s16 arg1, s16 arg2, s16 arg3) { +static void ValidateColSpecialObject(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 preset, s16 posX, s16 posY, s16 posZ) { if (aColValData.section != COL_SECTION_SPECIAL) { PrintDataError("SPECIAL_OBJECT found outside of special section"); } - aColValData.specialCount++; -} - -static void ValidateColSpecialObjectWithYaw(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 arg0, s16 arg1, s16 arg2, s16 arg3, s16 arg4) { - if (aColValData.section != COL_SECTION_SPECIAL) { - PrintDataError("SPECIAL_OBJECT_WITH_YAW found outside of special section"); + u8 presetType = GetSpecialObjectType(preset); + if (presetType == SPTYPE_UNKNOWN) { + PrintDataError("SPECIAL_OBJECT has invalid preset: %d", preset); + } + if (presetType != SPTYPE_NO_YROT_OR_PARAMS) { + PrintDataError("SPECIAL_OBJECT cannot be used with preset: %d (use %s instead)", preset, GetCorrectSpecialObjectCommand(presetType)); } aColValData.specialCount++; } -static void ValidateColSpecialObjectWithYawAndParam(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 arg0, s16 arg1, s16 arg2, s16 arg3, s16 arg4, s16 arg5) { +static void ValidateColSpecialObjectWithYaw(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 preset, s16 posX, s16 posY, s16 posZ, s16 yaw) { + if (aColValData.section != COL_SECTION_SPECIAL) { + PrintDataError("SPECIAL_OBJECT_WITH_YAW found outside of special section"); + } + u8 presetType = GetSpecialObjectType(preset); + if (presetType == SPTYPE_UNKNOWN) { + PrintDataError("SPECIAL_OBJECT_WITH_YAW has invalid preset: %d", preset); + } + if (presetType != SPTYPE_YROT_NO_PARAMS && presetType != SPTYPE_DEF_PARAM_AND_YROT) { + PrintDataError("SPECIAL_OBJECT_WITH_YAW cannot be used with preset: %d (use %s instead)", preset, GetCorrectSpecialObjectCommand(presetType)); + } + aColValData.specialCount++; +} + +static void ValidateColSpecialObjectWithYawAndParam(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 preset, s16 posX, s16 posY, s16 posZ, s16 yaw, s16 param) { if (aColValData.section != COL_SECTION_SPECIAL) { PrintDataError("SPECIAL_OBJECT_WITH_YAW_AND_PARAM found outside of special section"); } + u8 presetType = GetSpecialObjectType(preset); + if (presetType == SPTYPE_UNKNOWN) { + PrintDataError("SPECIAL_OBJECT_WITH_YAW_AND_PARAM has invalid preset: %d", preset); + } + if (presetType != SPTYPE_PARAMS_AND_YROT) { + PrintDataError("SPECIAL_OBJECT_WITH_YAW_AND_PARAM cannot be used with preset: %d (use %s instead)", preset, GetCorrectSpecialObjectCommand(presetType)); + } aColValData.specialCount++; } diff --git a/data/dynos_mgr_pack.cpp b/data/dynos_mgr_pack.cpp index 9bd54ad92..e60ccf410 100644 --- a/data/dynos_mgr_pack.cpp +++ b/data/dynos_mgr_pack.cpp @@ -151,7 +151,7 @@ PackData* DynOS_Pack_Add(const SysPath& aPath) { const char* displayName = aPath.c_str(); const char* ctoken = displayName; while (*ctoken != '\0') { - if (*ctoken == '/' || *ctoken == '\\') { + if (*ctoken == *PATH_SEPARATOR || *ctoken == *PATH_SEPARATOR_ALT) { if (*(ctoken + 1) != '\0') { displayName = (ctoken + 1); } diff --git a/docs/lua/functions-3.md b/docs/lua/functions-3.md index 63d90d0a6..7fc69a669 100644 --- a/docs/lua/functions-3.md +++ b/docs/lua/functions-3.md @@ -2885,7 +2885,7 @@ Sets the current DJUI HUD font ## [djui_hud_get_color](#djui_hud_get_color) ### Description -Gets the current DJUI HUD color +Gets the current DJUI HUD global color ### Lua Example `local djuiColorValue = djui_hud_get_color()` @@ -2906,7 +2906,7 @@ Gets the current DJUI HUD color ## [djui_hud_set_color](#djui_hud_set_color) ### Description -Sets the current DJUI HUD color +Sets the current DJUI HUD global color ### Lua Example `djui_hud_set_color(r, g, b, a)` @@ -2932,7 +2932,7 @@ Sets the current DJUI HUD color ## [djui_hud_reset_color](#djui_hud_reset_color) ### Description -Resets the current DJUI HUD color +Resets the current DJUI HUD global color ### Lua Example `djui_hud_reset_color()` @@ -2950,6 +2950,74 @@ Resets the current DJUI HUD color
+## [djui_hud_get_text_color](#djui_hud_get_text_color) + +### Description +Gets the current DJUI HUD text default color. This color is overridden by color codes + +### Lua Example +`local djuiColorValue = djui_hud_get_text_color()` + +### Parameters +- None + +### Returns +- [DjuiColor](structs.md#DjuiColor) + +### C Prototype +`struct DjuiColor* djui_hud_get_text_color(void);` + +[:arrow_up_small:](#) + +
+ +## [djui_hud_set_text_color](#djui_hud_set_text_color) + +### Description +Sets the current DJUI HUD text default color. This color is overridden by color codes + +### Lua Example +`djui_hud_set_text_color(r, g, b, a)` + +### Parameters +| Field | Type | +| ----- | ---- | +| r | `integer` | +| g | `integer` | +| b | `integer` | +| a | `integer` | + +### Returns +- None + +### C Prototype +`void djui_hud_set_text_color(u8 r, u8 g, u8 b, u8 a);` + +[:arrow_up_small:](#) + +
+ +## [djui_hud_reset_text_color](#djui_hud_reset_text_color) + +### Description +Resets the current DJUI HUD text default color. This color is overridden by color codes + +### Lua Example +`djui_hud_reset_text_color()` + +### Parameters +- None + +### Returns +- None + +### C Prototype +`void djui_hud_reset_text_color(void);` + +[:arrow_up_small:](#) + +
+ ## [djui_hud_get_rotation](#djui_hud_get_rotation) ### Description diff --git a/docs/lua/functions-6.md b/docs/lua/functions-6.md index a639b7db9..d45ae38a8 100644 --- a/docs/lua/functions-6.md +++ b/docs/lua/functions-6.md @@ -1615,26 +1615,6 @@ Multiplies a vector by the transpose of a matrix of the form: `| ? ? ? 0 |` `| ?
-## [cur_obj_check_frame_prior_current_frame](#cur_obj_check_frame_prior_current_frame) - -### Lua Example -`local integerValue = cur_obj_check_frame_prior_current_frame(a0)` - -### Parameters -| Field | Type | -| ----- | ---- | -| a0 | `Pointer` <`integer`> | - -### Returns -- `integer` - -### C Prototype -`s32 cur_obj_check_frame_prior_current_frame(s16 *a0);` - -[:arrow_up_small:](#) - -
- ## [mario_is_in_air_action](#mario_is_in_air_action) ### Lua Example diff --git a/docs/lua/functions.md b/docs/lua/functions.md index d3aac802f..9282199d2 100644 --- a/docs/lua/functions.md +++ b/docs/lua/functions.md @@ -765,6 +765,9 @@ - [djui_hud_get_color](functions-3.md#djui_hud_get_color) - [djui_hud_set_color](functions-3.md#djui_hud_set_color) - [djui_hud_reset_color](functions-3.md#djui_hud_reset_color) + - [djui_hud_get_text_color](functions-3.md#djui_hud_get_text_color) + - [djui_hud_set_text_color](functions-3.md#djui_hud_set_text_color) + - [djui_hud_reset_text_color](functions-3.md#djui_hud_reset_text_color) - [djui_hud_get_rotation](functions-3.md#djui_hud_get_rotation) - [djui_hud_set_rotation](functions-3.md#djui_hud_set_rotation) - [djui_hud_set_rotation_interpolated](functions-3.md#djui_hud_set_rotation_interpolated) @@ -1614,7 +1617,6 @@ - [cur_obj_check_if_at_animation_end](functions-6.md#cur_obj_check_if_at_animation_end) - [cur_obj_check_anim_frame](functions-6.md#cur_obj_check_anim_frame) - [cur_obj_check_anim_frame_in_range](functions-6.md#cur_obj_check_anim_frame_in_range) - - [cur_obj_check_frame_prior_current_frame](functions-6.md#cur_obj_check_frame_prior_current_frame) - [mario_is_in_air_action](functions-6.md#mario_is_in_air_action) - [mario_is_dive_sliding](functions-6.md#mario_is_dive_sliding) - [cur_obj_set_y_vel_and_animation](functions-6.md#cur_obj_set_y_vel_and_animation) diff --git a/lang/Czech.ini b/lang/Czech.ini index ddf7ae547..81a2e89a3 100644 --- a/lang/Czech.ini +++ b/lang/Czech.ini @@ -100,6 +100,7 @@ N64_BINDS = "N64 Ovládání" EXTRA_BINDS = "Extra Ovládání" BACKGROUND_GAMEPAD = "Ovladač v pozadí" DISABLE_GAMEPADS = "Zakažte gamepady" +EXTENDED_REPORTS = "Rozšířené zprávy" GAMEPAD = "Použít ovladač" DEADZONE = "Deadzone" RUMBLE_STRENGTH = "Síla vibrace" diff --git a/lang/Dutch.ini b/lang/Dutch.ini index a06530f8b..c4e32f77c 100644 --- a/lang/Dutch.ini +++ b/lang/Dutch.ini @@ -100,6 +100,7 @@ N64_BINDS = "N64 Toetsen" EXTRA_BINDS = "Extra Toetsen" BACKGROUND_GAMEPAD = "Achtergrond Gamepad" DISABLE_GAMEPADS = "Gamepads uitschakelen" +EXTENDED_REPORTS = "Uitgebreide rapporten" GAMEPAD = "Gamepad" DEADZONE = "Doode-zone" RUMBLE_STRENGTH = "Rommel Kracht" diff --git a/lang/English.ini b/lang/English.ini index 14ec1d462..0560d9ac2 100644 --- a/lang/English.ini +++ b/lang/English.ini @@ -100,6 +100,7 @@ N64_BINDS = "N64 Binds" EXTRA_BINDS = "Extra Binds" BACKGROUND_GAMEPAD = "Background Gamepad" DISABLE_GAMEPADS = "Disable Gamepads" +EXTENDED_REPORTS = "Extended Reports" GAMEPAD = "Gamepad" DEADZONE = "Deadzone" RUMBLE_STRENGTH = "Rumble Strength" diff --git a/lang/French.ini b/lang/French.ini index b0dfe3be2..645ed0c2a 100644 --- a/lang/French.ini +++ b/lang/French.ini @@ -100,6 +100,7 @@ N64_BINDS = "Touches N64" EXTRA_BINDS = "Touches Supplémentaires" BACKGROUND_GAMEPAD = "Manette en arrière plan" DISABLE_GAMEPADS = "Désactiver les manettes de jeu" +EXTENDED_REPORTS = "Rapports détaillés" GAMEPAD = "Manette" DEADZONE = "Zone Morte" RUMBLE_STRENGTH = "Vibrations" diff --git a/lang/German.ini b/lang/German.ini index e44e5c718..1fb8031d7 100644 --- a/lang/German.ini +++ b/lang/German.ini @@ -99,6 +99,7 @@ CONTROLS = "STEUERUNG" N64_BINDS = "N64-Einstellungen" EXTRA_BINDS = "Zusätzliche Einstellungen" BACKGROUND_GAMEPAD = "Hintergrund-Gamepad" +EXTENDED_REPORTS = "Erweiterte Berichte" DISABLE_GAMEPADS = "Gamepads deaktivieren" GAMEPAD = "Gamepad" DEADZONE = "Tote Zone" diff --git a/lang/Italian.ini b/lang/Italian.ini index e0827a2f6..dfe13d3bb 100644 --- a/lang/Italian.ini +++ b/lang/Italian.ini @@ -98,6 +98,7 @@ CONTROLS = "CONTROLLI" N64_BINDS = "Comandi N64" EXTRA_BINDS = "Comandi Extra" BACKGROUND_GAMEPAD = "Attivi in Background" +EXTENDED_REPORTS = "Rapporti estesi" DISABLE_GAMEPADS = "Disabilita i Gamepad" GAMEPAD = "Controller" DEADZONE = "Zona Morta" diff --git a/lang/Japanese.ini b/lang/Japanese.ini index a15f74b3a..05b20a216 100644 --- a/lang/Japanese.ini +++ b/lang/Japanese.ini @@ -99,6 +99,7 @@ CONTROLS = "CONTROLS" N64_BINDS = "ニンテンドウ64のボタン割り当て" EXTRA_BINDS = "追加のボタン割り当て" BACKGROUND_GAMEPAD = "バックグラウンドでのコントローラー認識" +EXTENDED_REPORTS = "拡張レポート" DISABLE_GAMEPADS = "コントローラーを無効化" GAMEPAD = "コントローラー" DEADZONE = "デッドゾーン" diff --git a/lang/Polish.ini b/lang/Polish.ini index 9781c549e..cb983027d 100644 --- a/lang/Polish.ini +++ b/lang/Polish.ini @@ -99,6 +99,7 @@ CONTROLS = "STEROWANIE" N64_BINDS = "Przypisania N64" EXTRA_BINDS = "Dodatkowe Przypisania" BACKGROUND_GAMEPAD = "Gamepad w Tle" +EXTENDED_REPORTS = "Rozszerzone raporty" DISABLE_GAMEPADS = "Wyłącz Gamepady" GAMEPAD = "Gamepad" DEADZONE = "Martwa Strefa" diff --git a/lang/Portuguese.ini b/lang/Portuguese.ini index e935499a6..d3b9e0c6b 100644 --- a/lang/Portuguese.ini +++ b/lang/Portuguese.ini @@ -99,6 +99,7 @@ CONTROLS = "CONTROLES" N64_BINDS = "N64" EXTRA_BINDS = "Outros" BACKGROUND_GAMEPAD = "Controle de fundo" +EXTENDED_REPORTS = "Relatórios detalhados" DISABLE_GAMEPADS = "Desativar controles" GAMEPAD = "Controle" DEADZONE = "Zona morta" diff --git a/lang/Russian.ini b/lang/Russian.ini index 52861a4cf..85d39ae37 100644 --- a/lang/Russian.ini +++ b/lang/Russian.ini @@ -98,6 +98,7 @@ CONTROLS = "CONTROLS" N64_BINDS = "Кнопки N64" EXTRA_BINDS = "Дополнительные кнопки" BACKGROUND_GAMEPAD = "Фоновый ввод" +EXTENDED_REPORTS = "Расширенные отчеты" DISABLE_GAMEPADS = "Отключить геймпады" GAMEPAD = "Геймпад" DEADZONE = "Mёртвая зона" diff --git a/lang/Spanish.ini b/lang/Spanish.ini index f083c8ba2..50660a637 100644 --- a/lang/Spanish.ini +++ b/lang/Spanish.ini @@ -100,6 +100,7 @@ N64_BINDS = "Botones de N64" EXTRA_BINDS = "Botones Adicionales" BACKGROUND_GAMEPAD = "Mando en segundo plano" DISABLE_GAMEPADS = "Desactivar mandos" +EXTENDED_REPORTS = "Informes ampliados" GAMEPAD = "Mando" DEADZONE = "Zona muerta" RUMBLE_STRENGTH = "Intensidad de vibración" diff --git a/src/game/area.c b/src/game/area.c index 36448abd5..c22fa22eb 100644 --- a/src/game/area.c +++ b/src/game/area.c @@ -26,6 +26,7 @@ #include "pc/network/network.h" #include "pc/lua/smlua_hooks.h" #include "pc/djui/djui.h" +#include "pc/djui/djui_hud_utils.h" #include "pc/djui/djui_panel_pause.h" #include "pc/nametags.h" #include "engine/lighting_engine.h" @@ -254,6 +255,7 @@ void clear_areas(void) { le_clear(); geo_clear_interp_data(); + djui_hud_clear_interp_data(); } void clear_area_graph_nodes(void) { @@ -313,6 +315,7 @@ void unload_area(void) { le_clear(); geo_clear_interp_data(); + djui_hud_clear_interp_data(); } void load_mario_area(void) { diff --git a/src/game/game_init.c b/src/game/game_init.c index 2e13c7e57..058cc9697 100644 --- a/src/game/game_init.c +++ b/src/game/game_init.c @@ -594,8 +594,6 @@ void thread5_game_loop(UNUSED void *arg) { play_music(SEQ_PLAYER_SFX, SEQUENCE_ARGS(0, SEQ_SOUND_PLAYER), 0); set_sound_mode(save_file_get_sound_mode()); - thread6_rumble_loop(NULL); - gGlobalTimer++; } @@ -609,6 +607,7 @@ void game_loop_one_iteration(void) { osContStartReadData(&gSIEventMesgQueue); } + thread6_rumble_loop(NULL); audio_game_loop_tick(); config_gfx_pool(); read_controller_inputs(); diff --git a/src/game/interaction.c b/src/game/interaction.c index 4304a23ae..599d6c65a 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -2445,7 +2445,7 @@ void check_death_barrier(struct MarioState *m) { smlua_call_event_hooks(HOOK_ON_DEATH, m, &allowDeath); if (!allowDeath) { return; } - if (mario_can_bubble(m)) { + if ((mario_can_bubble(m) && m->numLives > 0)) { switch (gCurrCourseNum) { case COURSE_COTMC: // (20) Cavern of the Metal Cap case COURSE_TOTWC: // (21) Tower of the Wing Cap diff --git a/src/game/level_update.c b/src/game/level_update.c index 1ad390601..76348da45 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -43,6 +43,7 @@ #include "pc/configfile.h" #include "pc/network/network.h" #include "pc/djui/djui.h" +#include "pc/djui/djui_hud_utils.h" // used for getting gMainMenuSounds #include "pc/djui/djui_panel_menu_options.h" #include "pc/lua/smlua_hooks.h" @@ -878,8 +879,7 @@ void verify_warp(struct MarioState *m, bool killMario) { return; } - m->numLives--; - if (m->numLives < 0) { + if (m->numLives <= 0) { sDelayedWarpOp = WARP_OP_GAME_OVER; } else { sSourceWarpNodeId = WARP_NODE_DEATH; @@ -934,8 +934,7 @@ s16 level_trigger_warp(struct MarioState *m, s32 warpOp) { break; case WARP_OP_DEATH: - m->numLives--; - if (m->numLives <= -1) { + if (m->numLives <= 0) { sDelayedWarpOp = WARP_OP_GAME_OVER; } sDelayedWarpTimer = 48; @@ -1766,6 +1765,7 @@ s32 update_level(void) { s32 init_level(void) { sync_objects_clear(); geo_clear_interp_data(); + djui_hud_clear_interp_data(); reset_dialog_render_state(); s32 val4 = 0; diff --git a/src/game/mario.c b/src/game/mario.c index 897bbc3fe..d929544f6 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -447,7 +447,7 @@ void mario_set_bubbled(struct MarioState* m) { gLocalBubbleCounter = 20; drop_and_set_mario_action(m, ACT_BUBBLED, 0); - if (m->numLives > -1) { + if (m->numLives > 0) { m->numLives--; } m->healCounter = 0; diff --git a/src/game/mario_actions_airborne.c b/src/game/mario_actions_airborne.c index 00b338447..6112358eb 100644 --- a/src/game/mario_actions_airborne.c +++ b/src/game/mario_actions_airborne.c @@ -1734,7 +1734,7 @@ s32 act_lava_boost(struct MarioState *m) { return FALSE; } - if (mario_can_bubble(m)) { + if ((mario_can_bubble(m) && m->numLives > 0)) { m->health = 0xFF; mario_set_bubbled(m); } else { diff --git a/src/game/mario_actions_cutscene.c b/src/game/mario_actions_cutscene.c index 9162cd84a..293079dc4 100644 --- a/src/game/mario_actions_cutscene.c +++ b/src/game/mario_actions_cutscene.c @@ -849,7 +849,7 @@ s32 common_death_handler(struct MarioState *m, s32 animation, s32 frameToDeathWa smlua_call_event_hooks(HOOK_ON_DEATH, m, &allowDeath); if (!allowDeath) { return animFrame; } - if (mario_can_bubble(m)) { + if ((mario_can_bubble(m) && m->numLives > 0)) { mario_set_bubbled(m); } else { level_trigger_warp(m, WARP_OP_DEATH); @@ -922,8 +922,7 @@ s32 act_quicksand_death(struct MarioState *m) { bool allowDeath = true; smlua_call_event_hooks(HOOK_ON_DEATH, m, &allowDeath); if (!allowDeath) { return FALSE; } - - if (mario_can_bubble(m)) { + if ((mario_can_bubble(m) && m->numLives > 0)) { mario_set_bubbled(m); } else { level_trigger_warp(m, WARP_OP_DEATH); @@ -947,7 +946,7 @@ s32 act_eaten_by_bubba(struct MarioState *m) { smlua_call_event_hooks(HOOK_ON_DEATH, m, &allowDeath); if (!allowDeath) { return FALSE; } - if (mario_can_bubble(m)) { + if ((mario_can_bubble(m) && m->numLives > 0)) { m->health = 0xFF; mario_set_bubbled(m); } else { @@ -1437,6 +1436,12 @@ s32 act_exit_land_save_dialog(struct MarioState *m) { return FALSE; } +static void lose_life_after_death_exit(struct MarioState *m) { + if (sDelayedWarpArg != WARP_ARG_EXIT_COURSE) { + m->numLives--; + } +} + s32 act_death_exit(struct MarioState *m) { if (!m) { return 0; } if (15 < m->actionTimer++ @@ -1447,6 +1452,7 @@ s32 act_death_exit(struct MarioState *m) { play_character_sound(m, CHAR_SOUND_OOOF2); #endif queue_rumble_data_mario(m, 5, 80); + lose_life_after_death_exit(m); // restore 7.75 units of health m->healCounter = 31; } @@ -1463,6 +1469,7 @@ s32 act_unused_death_exit(struct MarioState *m) { #else play_character_sound(m, CHAR_SOUND_OOOF2); #endif + lose_life_after_death_exit(m); // restore 7.75 units of health m->healCounter = 31; } @@ -1479,6 +1486,7 @@ s32 act_falling_death_exit(struct MarioState *m) { #else play_character_sound(m, CHAR_SOUND_OOOF2); #endif + lose_life_after_death_exit(m); queue_rumble_data_mario(m, 5, 80); // restore 7.75 units of health m->healCounter = 31; @@ -1526,6 +1534,7 @@ s32 act_special_death_exit(struct MarioState *m) { if (launch_mario_until_land(m, ACT_HARD_BACKWARD_GROUND_KB, CHAR_ANIM_BACKWARD_AIR_KB, -24.0f)) { queue_rumble_data_mario(m, 5, 80); + lose_life_after_death_exit(m); m->healCounter = 31; } // show Mario @@ -1829,7 +1838,7 @@ s32 act_squished(struct MarioState *m) { smlua_call_event_hooks(HOOK_ON_DEATH, m, &allowDeath); if (!allowDeath) { return FALSE; } - if (mario_can_bubble(m)) { + if ((mario_can_bubble(m) && m->numLives > 0)) { mario_set_bubbled(m); } else { level_trigger_warp(m, WARP_OP_DEATH); @@ -1880,7 +1889,7 @@ s32 act_squished(struct MarioState *m) { smlua_call_event_hooks(HOOK_ON_DEATH, m, &allowDeath); if (!allowDeath) { return FALSE; } - if (mario_can_bubble(m)) { + if ((mario_can_bubble(m) && m->numLives > 0)) { mario_set_bubbled(m); } else { // 0 units of health diff --git a/src/game/mario_actions_submerged.c b/src/game/mario_actions_submerged.c index 61f3a0e15..e4195f64c 100644 --- a/src/game/mario_actions_submerged.c +++ b/src/game/mario_actions_submerged.c @@ -1003,7 +1003,7 @@ static s32 act_drowning(struct MarioState *m) { smlua_call_event_hooks(HOOK_ON_DEATH, m, &allowDeath); if (!allowDeath) { return FALSE; } - if (mario_can_bubble(m)) { + if ((mario_can_bubble(m) && m->numLives > 0)) { mario_set_bubbled(m); } else { level_trigger_warp(m, WARP_OP_DEATH); @@ -1038,7 +1038,7 @@ static s32 act_water_death(struct MarioState *m) { smlua_call_event_hooks(HOOK_ON_DEATH, m, &allowDeath); if (!allowDeath) { return FALSE; } - if (mario_can_bubble(m)) { + if ((mario_can_bubble(m) && m->numLives > 0)) { mario_set_bubbled(m); } else { level_trigger_warp(m, WARP_OP_DEATH); @@ -1164,7 +1164,7 @@ static s32 act_caught_in_whirlpool(struct MarioState *m) { smlua_call_event_hooks(HOOK_ON_DEATH, m, &allowDeath); if (!allowDeath) { reset_rumble_timers(m); return FALSE; } - if (mario_can_bubble(m)) { + if ((mario_can_bubble(m) && m->numLives > 0)) { mario_set_bubbled(m); } else { level_trigger_warp(m, WARP_OP_DEATH); diff --git a/src/game/memory.c b/src/game/memory.c index feca24fd1..ee123c0ff 100644 --- a/src/game/memory.c +++ b/src/game/memory.c @@ -185,10 +185,42 @@ void growing_pool_free_pool(struct GrowingPool *pool) { // growing array // /////////////////// +static void growing_array_free_elements(struct GrowingArray *array) { + if (array) { + if (array->buffer) { + for (u32 i = 0; i != array->capacity; ++i) { + if (array->buffer[i]) { + array->free(array->buffer[i]); + } + } + memset(array->buffer, 0, sizeof(void *) * array->capacity); + } + array->count = 0; + } +} + struct GrowingArray *growing_array_init(struct GrowingArray *array, u32 capacity, GrowingArrayAllocFunc alloc, GrowingArrayFreeFunc free) { - growing_array_free(&array); - array = calloc(1, sizeof(struct GrowingArray)); - array->buffer = calloc(capacity, sizeof(void *)); + growing_array_free_elements(array); + + // reuse buffer if array was already allocated + if (array) { + if (!array->buffer || array->capacity != capacity) { + void **buffer = realloc(array->buffer, sizeof(void *) * capacity); + + // if realloc fails, destroy the array and create a new one + if (!buffer) { + growing_array_free(&array); + return growing_array_init(NULL, capacity, alloc, free); + } + + memset(buffer, 0, sizeof(void *) * capacity); + array->buffer = buffer; + } + } else { + array = malloc(sizeof(struct GrowingArray)); + array->buffer = calloc(capacity, sizeof(void *)); + } + array->capacity = capacity; array->count = 0; array->alloc = alloc; @@ -248,11 +280,7 @@ void growing_array_move(struct GrowingArray *array, u32 from, u32 to, u32 count) void growing_array_free(struct GrowingArray **array) { if (*array) { - for (u32 i = 0; i != (*array)->capacity; ++i) { - if ((*array)->buffer[i]) { - (*array)->free((*array)->buffer[i]); - } - } + growing_array_free_elements(*array); free((*array)->buffer); free(*array); *array = NULL; diff --git a/src/game/object_helpers.c b/src/game/object_helpers.c index f0bf4d162..ff35fe280 100644 --- a/src/game/object_helpers.c +++ b/src/game/object_helpers.c @@ -1333,21 +1333,6 @@ s32 cur_obj_check_anim_frame_in_range(s32 startFrame, s32 rangeLength) { } } -s32 cur_obj_check_frame_prior_current_frame(s16 *a0) { - if (!o) { return 0; } - s16 sp6 = o->header.gfx.animInfo.animFrame; - - while (*a0 != -1) { - if (*a0 == sp6) { - return TRUE; - } - - a0++; - } - - return FALSE; -} - s32 mario_is_in_air_action(struct MarioState* m) { if (!m) { return 0; } if (m->action & ACT_FLAG_AIR) { diff --git a/src/game/object_helpers.h b/src/game/object_helpers.h index fc65f764a..d004ecbeb 100644 --- a/src/game/object_helpers.h +++ b/src/game/object_helpers.h @@ -158,7 +158,6 @@ s32 cur_obj_check_if_near_animation_end(void); s32 cur_obj_check_if_at_animation_end(void); s32 cur_obj_check_anim_frame(s32 frame); s32 cur_obj_check_anim_frame_in_range(s32 startFrame, s32 rangeLength); -s32 cur_obj_check_frame_prior_current_frame(s16 *a0); s32 mario_is_in_air_action(struct MarioState* m); s32 mario_is_dive_sliding(struct MarioState* m); void cur_obj_set_y_vel_and_animation(f32 sp18, s32 sp1C); diff --git a/src/game/object_list_processor.c b/src/game/object_list_processor.c index 1752ae7b4..98fd6174c 100644 --- a/src/game/object_list_processor.c +++ b/src/game/object_list_processor.c @@ -25,6 +25,7 @@ #include "engine/math_util.h" #include "pc/network/network.h" #include "pc/lua/smlua.h" +#include "pc/djui/djui_hud_utils.h" /** * Flags controlling what debug info is displayed. @@ -605,6 +606,7 @@ void clear_objects(void) { clear_dynamic_surfaces(); geo_clear_interp_data(); + djui_hud_clear_interp_data(); } /** diff --git a/src/pc/configfile.c b/src/pc/configfile.c index 9278577e4..34664bb5f 100644 --- a/src/pc/configfile.c +++ b/src/pc/configfile.c @@ -127,6 +127,7 @@ unsigned int configStickDeadzone = 16; unsigned int configRumbleStrength = 50; unsigned int configGamepadNumber = 0; bool configBackgroundGamepad = true; +bool configExtendedReports = false; bool configDisableGamepads = false; bool configUseStandardKeyBindingsChat = false; bool configSmoothScrolling = false; @@ -270,6 +271,7 @@ static const struct ConfigOption options[] = { {.name = "rumble_strength", .type = CONFIG_TYPE_UINT, .uintValue = &configRumbleStrength}, {.name = "gamepad_number", .type = CONFIG_TYPE_UINT, .uintValue = &configGamepadNumber}, {.name = "background_gamepad", .type = CONFIG_TYPE_UINT, .boolValue = &configBackgroundGamepad}, + {.name = "extended_reports", .type = CONFIG_TYPE_BOOL, .boolValue = &configExtendedReports}, #ifndef HANDHELD {.name = "disable_gamepads", .type = CONFIG_TYPE_BOOL, .boolValue = &configDisableGamepads}, #endif diff --git a/src/pc/configfile.h b/src/pc/configfile.h index d537970e4..11cdbd5bc 100644 --- a/src/pc/configfile.h +++ b/src/pc/configfile.h @@ -93,6 +93,7 @@ extern unsigned int configStickDeadzone; extern unsigned int configRumbleStrength; extern unsigned int configGamepadNumber; extern bool configBackgroundGamepad; +extern bool configExtendedReports; extern bool configDisableGamepads; extern bool configUseStandardKeyBindingsChat; extern bool configSmoothScrolling; diff --git a/src/pc/controller/controller_sdl2.c b/src/pc/controller/controller_sdl2.c index 251d8a85f..6d4fc30ed 100644 --- a/src/pc/controller/controller_sdl2.c +++ b/src/pc/controller/controller_sdl2.c @@ -40,6 +40,7 @@ static SDL_GameController *sdl_cntrl = NULL; static SDL_Joystick *sdl_joystick = NULL; static SDL_Haptic *sdl_haptic = NULL; +static bool sExtendedReports = false; static bool sBackgroundGamepad = false; static u32 num_joy_binds = 0; @@ -102,6 +103,13 @@ static void controller_sdl_bind(void) { } static void controller_sdl_init(void) { + // Allows extended reports on PS4 and PS5 controllers + if (configExtendedReports) { + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); + } + sExtendedReports = configExtendedReports; + // Allows game to be controlled by gamepad when not in focus if (configBackgroundGamepad) { SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); @@ -200,6 +208,13 @@ static void controller_sdl_read(OSContPad *pad) { // remember buttons that changed from 0 to 1 last_mouse = (mouse_prev ^ mouse) & mouse; + if (configExtendedReports != sExtendedReports) { + sExtendedReports = configExtendedReports; + char* hint = sExtendedReports ? "1" : "0"; + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, hint); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, hint); + } + if (configBackgroundGamepad != sBackgroundGamepad) { sBackgroundGamepad = configBackgroundGamepad; SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, sBackgroundGamepad ? "1" : "0"); diff --git a/src/pc/crash_handler.c b/src/pc/crash_handler.c index 470f4e2e6..a493bbf39 100644 --- a/src/pc/crash_handler.c +++ b/src/pc/crash_handler.c @@ -217,12 +217,12 @@ static void crash_handler_produce_one_frame_callback(void) { if (font->textBeginDisplayList != NULL) { gSPDisplayList(gDisplayListHead++, font->textBeginDisplayList); } + gDPSetPrimColor(gDisplayListHead++, 0, 0, 255, 255, 255, 255); for (CrashHandlerText* text = sCrashHandlerText; text->s[0] != 0; ++text) { s32 x = GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(text->x * aspectScale); s32 y = SCREEN_HEIGHT - 8 - text->y * aspectScale; gDPPipeSync(gDisplayListHead++); - gDPSetEnvColor(gDisplayListHead++, text->r, text->g, text->b, 0xFF); create_dl_translation_matrix(DJUI_MTX_PUSH, x, y, 0); // translate scale diff --git a/src/pc/djui/djui.c b/src/pc/djui/djui.c index 3bd9fc8b1..43218a151 100644 --- a/src/pc/djui/djui.c +++ b/src/pc/djui/djui.c @@ -171,6 +171,7 @@ void djui_reset_hud_params(void) { djui_hud_set_rotation(0, ROTATION_PIVOT_X_LEFT, ROTATION_PIVOT_Y_TOP); djui_hud_set_text_alignment(TEXT_HALIGN_LEFT, TEXT_VALIGN_TOP); djui_hud_reset_color(); + djui_hud_reset_text_color(); djui_hud_set_filter(FILTER_NEAREST); djui_hud_reset_viewport(); djui_hud_reset_scissor(); diff --git a/src/pc/djui/djui_gfx.c b/src/pc/djui/djui_gfx.c index 4319782c3..eccfa5c95 100644 --- a/src/pc/djui/djui_gfx.c +++ b/src/pc/djui/djui_gfx.c @@ -166,7 +166,8 @@ void djui_gfx_render_texture_tile(const Texture* texture, u32 w, u32 h, u8 fmt, void djui_gfx_render_texture_font_begin() { gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING | G_CULL_BOTH); - gDPSetCombineMode(gDisplayListHead++, G_CC_FADEA, G_CC_FADEA); + gDPSetCombineMode(gDisplayListHead++, G_CC_FADEA, G_CC_MODULATERGBA_PRIM2); + gDPSetCycleType(gDisplayListHead++, G_CYC_2CYCLE); gDPSetRenderMode(gDisplayListHead++, G_RM_XLU_SURF, G_RM_XLU_SURF2); gDPSetTextureFilter(gDisplayListHead++, djui_hud_get_filter() ? G_TF_BILERP : G_TF_POINT); gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON); @@ -193,12 +194,14 @@ void djui_gfx_render_texture_font(const Texture* texture, u32 w, u32 h, u8 fmt, void djui_gfx_render_texture_font_end() { gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF); gDPSetCombineMode(gDisplayListHead++, G_CC_SHADE, G_CC_SHADE); + gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE); gSPSetGeometryMode(gDisplayListHead++, G_LIGHTING | G_CULL_BACK); } void djui_gfx_render_texture_tile_font_begin() { gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING | G_CULL_BOTH); - gDPSetCombineMode(gDisplayListHead++, G_CC_FADEA, G_CC_FADEA); + gDPSetCombineMode(gDisplayListHead++, G_CC_FADEA, G_CC_MODULATERGBA_PRIM2); + gDPSetCycleType(gDisplayListHead++, G_CYC_2CYCLE); gDPSetRenderMode(gDisplayListHead++, G_RM_XLU_SURF, G_RM_XLU_SURF2); gDPSetTextureFilter(gDisplayListHead++, G_TF_POINT); gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON); @@ -243,6 +246,7 @@ void djui_gfx_render_texture_tile_font(const Texture* texture, u32 w, u32 h, u8 void djui_gfx_render_texture_tile_font_end() { gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF); gDPSetCombineMode(gDisplayListHead++, G_CC_SHADE, G_CC_SHADE); + gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE); gSPSetGeometryMode(gDisplayListHead++, G_LIGHTING | G_CULL_BACK); } diff --git a/src/pc/djui/djui_hud_utils.c b/src/pc/djui/djui_hud_utils.c index 8ad0a5b15..2e5d675d2 100644 --- a/src/pc/djui/djui_hud_utils.c +++ b/src/pc/djui/djui_hud_utils.c @@ -35,6 +35,7 @@ struct HudUtilsState { enum HudUtilsFilter filter; enum DjuiFontType font; struct DjuiColor color; + struct DjuiColor textColor; struct { InterpFieldF32 degrees; InterpFieldF32 pivotX; @@ -51,6 +52,7 @@ static struct HudUtilsState sHudUtilsState = { .filter = FILTER_NEAREST, .font = FONT_NORMAL, .color = { 255, 255, 255, 255 }, + .textColor = { 255, 255, 255, 255 }, .rotation = { .degrees = INTERP_INIT(0), .pivotX = INTERP_INIT(ROTATION_PIVOT_X_LEFT), @@ -63,6 +65,7 @@ static struct HudUtilsState sHudUtilsState = { }; static struct DjuiColor sRefColor = { 255, 255, 255, 255 }; +static struct DjuiColor sRefTextColor = { 255, 255, 255, 255 }; f32 gDjuiHudUtilsZ = 0; bool gDjuiHudLockMouse = false; @@ -144,8 +147,6 @@ static void djui_hud_translate_positions(f32 *outX, f32 *outY, f32 *outW, f32 *o // interp // //////////// -#define MAX_INTERP_HUD 512 - enum InterpHudType { INTERP_HUD_TRANSLATION, INTERP_HUD_ROTATION, @@ -170,9 +171,16 @@ struct InterpHud { struct GrowingArray *gfx; }; -static struct InterpHud sInterpHuds[MAX_INTERP_HUD] = { 0 }; -static u16 sInterpHudCount = 0; -static u8 sColorAltered = FALSE; +static struct GrowingArray *sInterpHuds = NULL; +static u32 sInterpHudCount = 0; + +static void interp_hud_free(void *ptr) { + struct InterpHud *interp = ptr; + if (interp) { + growing_array_free(&interp->gfx); + free(interp); + } +} void patch_djui_hud_before(void) { sInterpHudCount = 0; @@ -183,8 +191,8 @@ void patch_djui_hud(f32 delta) { Gfx* savedHeadPos = gDisplayListHead; struct HudUtilsState savedState = sHudUtilsState; - for (u16 i = 0; i < sInterpHudCount; i++) { - struct InterpHud* interp = &sInterpHuds[i]; + for (u32 i = 0; i < sInterpHudCount; i++) { + struct InterpHud *interp = sInterpHuds->buffer[i]; f32 x = delta_interpolate_f32(interp->posX.prev, interp->posX.curr, delta); f32 y = delta_interpolate_f32(interp->posY.prev, interp->posY.curr, delta); @@ -260,22 +268,28 @@ void patch_djui_hud(f32 delta) { gDjuiHudUtilsZ = savedZ; } -struct InterpHud *djui_hud_create_interp() { - if (sInterpHudCount >= MAX_INTERP_HUD) { return NULL; } +static struct InterpHud *djui_hud_create_interp() { + struct InterpHud *interp = ( + sInterpHudCount < sInterpHuds->count ? + sInterpHuds->buffer[sInterpHudCount] : + growing_array_alloc(sInterpHuds, sizeof(struct InterpHud)) + ); - struct InterpHud *interp = &sInterpHuds[sInterpHudCount++]; - interp->z = gDjuiHudUtilsZ; - interp->state = sHudUtilsState; - if (!interp->gfx) { - interp->gfx = growing_array_init(NULL, 8, malloc, free); - } else { - interp->gfx->count = 0; + if (interp) { + interp->z = gDjuiHudUtilsZ; + interp->state = sHudUtilsState; + if (!interp->gfx) { + interp->gfx = growing_array_init(NULL, 8, malloc, free); + } else { + interp->gfx->count = 0; + } + sInterpHudCount++; } return interp; } -InterpHudGfx *djui_hud_create_interp_gfx(struct InterpHud *interp, enum InterpHudType type) { +static InterpHudGfx *djui_hud_create_interp_gfx(struct InterpHud *interp, enum InterpHudType type) { if (!interp) { return NULL; } InterpHudGfx *gfx = growing_array_alloc(interp->gfx, sizeof(InterpHudGfx)); @@ -284,6 +298,11 @@ InterpHudGfx *djui_hud_create_interp_gfx(struct InterpHud *interp, enum InterpHu return gfx; } +void djui_hud_clear_interp_data() { + sInterpHuds = growing_array_init(sInterpHuds, 16, malloc, interp_hud_free); + sInterpHudCount = 0; +} + //////////// // others // //////////// @@ -328,19 +347,37 @@ void djui_hud_set_color(u8 r, u8 g, u8 b, u8 a) { sHudUtilsState.color.g = g; sHudUtilsState.color.b = b; sHudUtilsState.color.a = a; - sColorAltered = TRUE; gDPSetEnvColor(gDisplayListHead++, r, g, b, a); } void djui_hud_reset_color(void) { - if (sColorAltered) { - sHudUtilsState.color.r = 255; - sHudUtilsState.color.g = 255; - sHudUtilsState.color.b = 255; - sHudUtilsState.color.a = 255; - sColorAltered = FALSE; - gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255); - } + sHudUtilsState.color.r = 255; + sHudUtilsState.color.g = 255; + sHudUtilsState.color.b = 255; + sHudUtilsState.color.a = 255; + gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255); +} + +struct DjuiColor* djui_hud_get_text_color(void) { + sRefTextColor.r = sHudUtilsState.textColor.r; + sRefTextColor.g = sHudUtilsState.textColor.g; + sRefTextColor.b = sHudUtilsState.textColor.b; + sRefTextColor.a = sHudUtilsState.textColor.a; + return &sRefTextColor; +} + +void djui_hud_set_text_color(u8 r, u8 g, u8 b, u8 a) { + sHudUtilsState.textColor.r = r; + sHudUtilsState.textColor.g = g; + sHudUtilsState.textColor.b = b; + sHudUtilsState.textColor.a = a; +} + +void djui_hud_reset_text_color(void) { + sHudUtilsState.textColor.r = 255; + sHudUtilsState.textColor.g = 255; + sHudUtilsState.textColor.b = 255; + sHudUtilsState.textColor.a = 255; } void djui_hud_get_rotation(RET s16 *rotation, RET f32 *pivotX, RET f32 *pivotY) { @@ -533,8 +570,6 @@ static void djui_hud_print_text_internal(const char* message, f32 x, f32 y, f32 if (message == NULL) { return; } gDjuiHudUtilsZ += 0.001f; - if (djui_hud_text_font_is_legacy()) { scale *= 0.5f; } - const struct DjuiFont* font = djui_hud_get_text_font(); f32 fontScale = font->defaultFontScale * scale; @@ -582,13 +617,26 @@ static void djui_hud_print_text_internal(const char* message, f32 x, f32 y, f32 f32 lineWidth = 0; f32 textHeight = font->lineHeight; + // apply text color + gDPSetPrimColor(gDisplayListHead++, 0, 0, + sHudUtilsState.textColor.r, + sHudUtilsState.textColor.g, + sHudUtilsState.textColor.b, + sHudUtilsState.textColor.a + ); + font->render_begin(); while (*c != '\0') { // check color code struct DjuiColor parsedColor; - if (djui_text_parse_color(c, end, false, &sHudUtilsState.color, &c, &parsedColor)) { - gDPSetEnvColor(gDisplayListHead++, parsedColor.r, parsedColor.g, parsedColor.b, parsedColor.a); + if (djui_text_parse_color(c, end, false, &sHudUtilsState.textColor, &c, &parsedColor)) { + gDPSetPrimColor(gDisplayListHead++, 0, 0, + parsedColor.r, + parsedColor.g, + parsedColor.b, + parsedColor.a + ); continue; } @@ -654,13 +702,22 @@ static void djui_hud_print_text_internal(const char* message, f32 x, f32 y, f32 } void djui_hud_print_text(const char* message, f32 x, f32 y, f32 scale) { + if (message == NULL) { return; } + + if (djui_hud_text_font_is_legacy()) { + scale *= 0.5f; + } + djui_hud_print_text_internal(message, x, y, scale, NULL); } void djui_hud_print_text_interpolated(const char* message, f32 prevX, f32 prevY, f32 prevScale, f32 x, f32 y, f32 scale) { if (message == NULL) { return; } - if (djui_hud_text_font_is_legacy()) { prevScale *= 0.5f; } + if (djui_hud_text_font_is_legacy()) { + scale *= 0.5f; + prevScale *= 0.5f; + } struct InterpHud *interp = djui_hud_create_interp(); if (interp) { diff --git a/src/pc/djui/djui_hud_utils.h b/src/pc/djui/djui_hud_utils.h index 353ee3511..569b18a9b 100644 --- a/src/pc/djui/djui_hud_utils.h +++ b/src/pc/djui/djui_hud_utils.h @@ -62,6 +62,8 @@ extern struct GlobalTextures gGlobalTextures; extern f32 gDjuiHudUtilsZ; extern bool gDjuiHudLockMouse; +void djui_hud_clear_interp_data(); + /* |description|Gets the current DJUI HUD resolution|descriptionEnd| */ u8 djui_hud_get_resolution(void); /* |description|Sets the current DJUI HUD resolution|descriptionEnd| */ @@ -74,12 +76,18 @@ void djui_hud_set_filter(enum HudUtilsFilter filterType); s8 djui_hud_get_font(void); /* |description|Sets the current DJUI HUD font|descriptionEnd| */ void djui_hud_set_font(s8 fontType); -/* |description|Gets the current DJUI HUD color|descriptionEnd| */ +/* |description|Gets the current DJUI HUD global color|descriptionEnd| */ struct DjuiColor* djui_hud_get_color(void); -/* |description|Sets the current DJUI HUD color|descriptionEnd| */ +/* |description|Sets the current DJUI HUD global color|descriptionEnd| */ void djui_hud_set_color(u8 r, u8 g, u8 b, u8 a); -/* |description|Resets the current DJUI HUD color|descriptionEnd| */ +/* |description|Resets the current DJUI HUD global color|descriptionEnd| */ void djui_hud_reset_color(void); +/* |description|Gets the current DJUI HUD text default color. This color is overridden by color codes|descriptionEnd| */ +struct DjuiColor* djui_hud_get_text_color(void); +/* |description|Sets the current DJUI HUD text default color. This color is overridden by color codes|descriptionEnd| */ +void djui_hud_set_text_color(u8 r, u8 g, u8 b, u8 a); +/* |description|Resets the current DJUI HUD text default color. This color is overridden by color codes|descriptionEnd| */ +void djui_hud_reset_text_color(void); /* |description|Gets the current DJUI HUD rotation|descriptionEnd| */ void djui_hud_get_rotation(RET s16 *rotation, RET f32 *pivotX, RET f32 *pivotY); /* |description|Sets the current DJUI HUD rotation|descriptionEnd| */ diff --git a/src/pc/djui/djui_inputbox.c b/src/pc/djui/djui_inputbox.c index 2b91eda0e..da9b276a2 100644 --- a/src/pc/djui/djui_inputbox.c +++ b/src/pc/djui/djui_inputbox.c @@ -577,6 +577,7 @@ static bool djui_inputbox_render(struct DjuiBase* base) { } // set color + gDPSetPrimColor(gDisplayListHead++, 0, 0, 255, 255, 255, 255); gDPSetEnvColor(gDisplayListHead++, inputbox->textColor.r, inputbox->textColor.g, inputbox->textColor.b, inputbox->textColor.a); // make selection well formed diff --git a/src/pc/djui/djui_panel_controls.c b/src/pc/djui/djui_panel_controls.c index 8088580a9..e8b39396d 100644 --- a/src/pc/djui/djui_panel_controls.c +++ b/src/pc/djui/djui_panel_controls.c @@ -43,6 +43,8 @@ void djui_panel_controls_create(struct DjuiBase* caller) { djui_checkbox_create(body, DLANG(MISC, USE_STANDARD_KEY_BINDINGS_CHAT), &configUseStandardKeyBindingsChat, NULL); #ifdef HAVE_SDL2 + djui_checkbox_create(body, DLANG(CONTROLS, EXTENDED_REPORTS), &configExtendedReports, NULL); + int numJoys = SDL_NumJoysticks(); if (numJoys == 0) { numJoys = 1; } diff --git a/src/pc/djui/djui_text.c b/src/pc/djui/djui_text.c index 773d2cb93..e26d0c259 100644 --- a/src/pc/djui/djui_text.c +++ b/src/pc/djui/djui_text.c @@ -387,8 +387,10 @@ static void djui_text_render_line(struct DjuiText* text, char* c1, char* c2, f32 for (char* c = c1; c < c2;) { struct DjuiColor parsedColor; if (djui_text_parse_color(c, c2, true, &sDjuiTextDefaultColor, &c, &parsedColor)) { - gDPSetEnvColor(gDisplayListHead++, parsedColor.r, parsedColor.g, parsedColor.b, parsedColor.a); - sDjuiTextCurrentColor = parsedColor; + sDjuiTextCurrentColor.r = parsedColor.r; + sDjuiTextCurrentColor.g = parsedColor.g; + sDjuiTextCurrentColor.b = parsedColor.b; + gDPSetEnvColor(gDisplayListHead++, sDjuiTextCurrentColor.r, sDjuiTextCurrentColor.g, sDjuiTextCurrentColor.b, sDjuiTextCurrentColor.a); continue; } @@ -457,6 +459,7 @@ static bool djui_text_render(struct DjuiBase* base) { create_dl_scale_matrix(DJUI_MTX_NOPUSH, translatedFontSize, translatedFontSize, 1.0f); // set color + gDPSetPrimColor(gDisplayListHead++, 0, 0, 255, 255, 255, 255); gDPSetEnvColor(gDisplayListHead++, base->color.r, base->color.g, base->color.b, base->color.a); sDjuiTextCurrentColor = base->color; diff --git a/src/pc/lua/smlua.c b/src/pc/lua/smlua.c index cd2502050..d8f2619c7 100644 --- a/src/pc/lua/smlua.c +++ b/src/pc/lua/smlua.c @@ -359,7 +359,7 @@ void smlua_init(void) { } // skip loading scripts in subdirectories - if (strchr(file->relativePath, '/') != NULL || strchr(file->relativePath, '\\') != NULL) { + if (strchr(file->relativePath, *PATH_SEPARATOR) != NULL || strchr(file->relativePath, *PATH_SEPARATOR_ALT) != NULL) { continue; } diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c index 4ebefa534..3eef9493d 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -12345,6 +12345,59 @@ int smlua_func_djui_hud_reset_color(UNUSED lua_State* L) { return 1; } +int smlua_func_djui_hud_get_text_color(UNUSED lua_State* L) { + if (L == NULL) { return 0; } + + int top = lua_gettop(L); + if (top != 0) { + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "djui_hud_get_text_color", 0, top); + return 0; + } + + + smlua_push_object(L, LOT_DJUICOLOR, djui_hud_get_text_color(), NULL); + + return 1; +} + +int smlua_func_djui_hud_set_text_color(lua_State* L) { + if (L == NULL) { return 0; } + + int top = lua_gettop(L); + if (top != 4) { + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "djui_hud_set_text_color", 4, top); + return 0; + } + + u8 r = smlua_to_integer(L, 1); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "djui_hud_set_text_color"); return 0; } + u8 g = smlua_to_integer(L, 2); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "djui_hud_set_text_color"); return 0; } + u8 b = smlua_to_integer(L, 3); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "djui_hud_set_text_color"); return 0; } + u8 a = smlua_to_integer(L, 4); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 4, "djui_hud_set_text_color"); return 0; } + + djui_hud_set_text_color(r, g, b, a); + + return 1; +} + +int smlua_func_djui_hud_reset_text_color(UNUSED lua_State* L) { + if (L == NULL) { return 0; } + + int top = lua_gettop(L); + if (top != 0) { + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "djui_hud_reset_text_color", 0, top); + return 0; + } + + + djui_hud_reset_text_color(); + + return 1; +} + int smlua_func_djui_hud_get_rotation(lua_State* L) { if (L == NULL) { return 0; } @@ -26885,24 +26938,6 @@ int smlua_func_cur_obj_check_anim_frame_in_range(lua_State* L) { return 1; } -int smlua_func_cur_obj_check_frame_prior_current_frame(lua_State* L) { - if (L == NULL) { return 0; } - - int top = lua_gettop(L); - if (top != 1) { - LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "cur_obj_check_frame_prior_current_frame", 1, top); - return 0; - } - - s16 * a0 = (s16 *)smlua_to_cpointer(L, 1, LVT_S16_P); - if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "cur_obj_check_frame_prior_current_frame"); return 0; } - - extern s32 cur_obj_check_frame_prior_current_frame(s16 *a0); - lua_pushinteger(L, cur_obj_check_frame_prior_current_frame(a0)); - - return 1; -} - int smlua_func_mario_is_in_air_action(lua_State* L) { if (L == NULL) { return 0; } @@ -37524,6 +37559,9 @@ void smlua_bind_functions_autogen(void) { smlua_bind_function(L, "djui_hud_get_color", smlua_func_djui_hud_get_color); smlua_bind_function(L, "djui_hud_set_color", smlua_func_djui_hud_set_color); smlua_bind_function(L, "djui_hud_reset_color", smlua_func_djui_hud_reset_color); + smlua_bind_function(L, "djui_hud_get_text_color", smlua_func_djui_hud_get_text_color); + smlua_bind_function(L, "djui_hud_set_text_color", smlua_func_djui_hud_set_text_color); + smlua_bind_function(L, "djui_hud_reset_text_color", smlua_func_djui_hud_reset_text_color); smlua_bind_function(L, "djui_hud_get_rotation", smlua_func_djui_hud_get_rotation); smlua_bind_function(L, "djui_hud_set_rotation", smlua_func_djui_hud_set_rotation); smlua_bind_function(L, "djui_hud_set_rotation_interpolated", smlua_func_djui_hud_set_rotation_interpolated); @@ -38307,7 +38345,6 @@ void smlua_bind_functions_autogen(void) { smlua_bind_function(L, "cur_obj_check_if_at_animation_end", smlua_func_cur_obj_check_if_at_animation_end); smlua_bind_function(L, "cur_obj_check_anim_frame", smlua_func_cur_obj_check_anim_frame); smlua_bind_function(L, "cur_obj_check_anim_frame_in_range", smlua_func_cur_obj_check_anim_frame_in_range); - smlua_bind_function(L, "cur_obj_check_frame_prior_current_frame", smlua_func_cur_obj_check_frame_prior_current_frame); smlua_bind_function(L, "mario_is_in_air_action", smlua_func_mario_is_in_air_action); smlua_bind_function(L, "mario_is_dive_sliding", smlua_func_mario_is_dive_sliding); smlua_bind_function(L, "cur_obj_set_y_vel_and_animation", smlua_func_cur_obj_set_y_vel_and_animation); diff --git a/src/pc/lua/smlua_require.c b/src/pc/lua/smlua_require.c index c331a0570..c99db7513 100644 --- a/src/pc/lua/smlua_require.c +++ b/src/pc/lua/smlua_require.c @@ -121,7 +121,7 @@ static int smlua_custom_require(lua_State* L) { return 0; } - if (path_ends_with(moduleName, "/") || path_ends_with(moduleName, "\\")) { + if (path_ends_with(moduleName, PATH_SEPARATOR) || path_ends_with(moduleName, PATH_SEPARATOR_ALT)) { LOG_LUA_LINE("cannot require a directory"); return 0; } diff --git a/src/pc/lua/smlua_utils.c b/src/pc/lua/smlua_utils.c index d20579133..af1685a64 100644 --- a/src/pc/lua/smlua_utils.c +++ b/src/pc/lua/smlua_utils.c @@ -849,7 +849,7 @@ void smlua_logline(void) { if (strlen(src) < SYS_MAX_PATH) { int slashCount = 0; for (const char* p = src + strlen(src); p > src; --p) { - if (*p == '/' || *p == '\\') { + if (*p == *PATH_SEPARATOR || *p == *PATH_SEPARATOR_ALT) { if (++slashCount == 2) { folderStart = p + 1; break; diff --git a/src/pc/lua/utils/smlua_misc_utils.c b/src/pc/lua/utils/smlua_misc_utils.c index 9e90a45fb..faa10c1ae 100644 --- a/src/pc/lua/utils/smlua_misc_utils.c +++ b/src/pc/lua/utils/smlua_misc_utils.c @@ -622,8 +622,8 @@ LuaTable get_mod_files(struct Mod* mod, OPTIONAL const char* subDirectory) { normalize_path(normalizedSubDir); size_t subDirLen = strlen(normalizedSubDir); - if (subDirLen > 0 && subDirLen + 1 < SYS_MAX_PATH && normalizedSubDir[subDirLen - 1] != '/') { - strcat(normalizedSubDir, "/"); + if (subDirLen > 0 && subDirLen + 1 < SYS_MAX_PATH && normalizedSubDir[subDirLen - 1] != *PATH_SEPARATOR) { + strcat(normalizedSubDir, PATH_SEPARATOR); subDirLen = strlen(normalizedSubDir); } diff --git a/src/pc/mods/mods_utils.c b/src/pc/mods/mods_utils.c index 6e8c2bcd9..e09df3089 100644 --- a/src/pc/mods/mods_utils.c +++ b/src/pc/mods/mods_utils.c @@ -144,7 +144,7 @@ bool mod_file_create_directories(struct Mod* mod, struct ModFile* modFile) { char* p = path; u16 index = 0; while (*p != '\0') { - if (*p == '/' || *p == '\\') { + if (*p == *PATH_SEPARATOR || *p == *PATH_SEPARATOR_ALT) { if (snprintf(tmpPath, index + 1, "%s", path) < 0) { } if (!fs_sys_dir_exists(tmpPath)) { fs_sys_mkdir(tmpPath); @@ -210,11 +210,9 @@ void normalize_path(char* path) { // replace slashes char* p = path; while (*p) { -#if defined(_WIN32) - if (*p == '/') { *p = '\\'; } -#else - if (*p == '\\') { *p = '/'; } -#endif + if (*p == *PATH_SEPARATOR_ALT) { + *p = *PATH_SEPARATOR; + } p++; } } @@ -227,7 +225,7 @@ char* path_basename(char* path) { char* base = path; while (*path != '\0') { if (*(path + 1) != '\0') { - if (*path == '\\' || *path == '/') { + if (*path == *PATH_SEPARATOR || *path == *PATH_SEPARATOR_ALT) { base = path + 1; } } @@ -251,7 +249,7 @@ void path_get_folder(char* path, char* outpath) { int path_depth(const char* path) { int depth = 0; for (; *path; path++) { - if (*path == '/' || *path == '\\') { + if (*path == *PATH_SEPARATOR || *path == *PATH_SEPARATOR_ALT) { depth++; } } @@ -262,7 +260,7 @@ void resolve_relative_path(const char* base, const char* path, char* output) { char combined[SYS_MAX_PATH] = ""; // If path is absolute, copy as is. Otherwise, combine base and relative path - if (path[0] == '/' || path[0] == '\\') { + if (path[0] == *PATH_SEPARATOR || path[0] == *PATH_SEPARATOR_ALT) { snprintf(combined, sizeof(combined), "%s", path); } else { snprintf(combined, sizeof(combined), "%s/%s", base, path); @@ -272,7 +270,7 @@ void resolve_relative_path(const char* base, const char* path, char* output) { int tokenCount = 0; // Tokenize path by separators - char* token = strtok(combined, "/\\"); + char* token = strtok(combined, PATH_SEPARATOR PATH_SEPARATOR_ALT); while (token && tokenCount < 64) { if (strcmp(token, "..") == 0) { // Pop last token to go up a directory @@ -283,7 +281,7 @@ void resolve_relative_path(const char* base, const char* path, char* output) { tokens[tokenCount++] = token; } - token = strtok(NULL, "/\\"); + token = strtok(NULL, PATH_SEPARATOR PATH_SEPARATOR_ALT); } output[0] = '\0'; @@ -291,7 +289,7 @@ void resolve_relative_path(const char* base, const char* path, char* output) { // Build output path from tokens for (int i = 0; i < tokenCount; i++) { if (i > 0) { - strncat(output, "/", SYS_MAX_PATH - strlen(output) - 1); + strncat(output, PATH_SEPARATOR, SYS_MAX_PATH - strlen(output) - 1); } strncat(output, tokens[i], SYS_MAX_PATH - strlen(output) - 1); } @@ -308,8 +306,8 @@ bool directory_sanity_check(struct dirent* dir, char* dirPath, char* outPath) { if (!fs_sys_filename_is_portable(dir->d_name)) { return false; } // skip anything that contains \ or / - if (strchr(dir->d_name, '/') != NULL) { return false; } - if (strchr(dir->d_name, '\\') != NULL) { return false; } + if (strchr(dir->d_name, *PATH_SEPARATOR) != NULL) { return false; } + if (strchr(dir->d_name, *PATH_SEPARATOR_ALT) != NULL) { return false; } // skip anything that starts with . if (dir->d_name[0] == '.') { return false; } diff --git a/src/pc/nametags.c b/src/pc/nametags.c index 37fe27bf8..c39a1a249 100644 --- a/src/pc/nametags.c +++ b/src/pc/nametags.c @@ -18,34 +18,26 @@ struct StateExtras { }; static struct StateExtras sStateExtras[MAX_PLAYERS]; -void name_without_hex(char* input) { - s32 i, j; - bool inSlash = false; - for (i = j = 0; input[i] != '\0'; i++) { - if (input[i] == '\\') { - inSlash = !inSlash; - } else if (!inSlash) { - input[j++] = input[i]; // it just works - } - } - - input[j] = '\0'; -} - void djui_hud_print_outlined_text_interpolated(const char* text, f32 prevX, f32 prevY, f32 prevScale, f32 x, f32 y, f32 scale, u8 r, u8 g, u8 b, u8 a, f32 outlineDarkness) { f32 offset = 1 * (scale * 2); f32 prevOffset = 1 * (prevScale * 2); + djui_hud_set_text_color(r, g, b, 255); + // render outline - djui_hud_set_color(r * outlineDarkness, g * outlineDarkness, b * outlineDarkness, a); + djui_hud_set_color(255 * outlineDarkness, 255 * outlineDarkness, 255 * outlineDarkness, a); djui_hud_print_text_interpolated(text, prevX - prevOffset, prevY, prevScale, x - offset, y, scale); djui_hud_print_text_interpolated(text, prevX + prevOffset, prevY, prevScale, x + offset, y, scale); djui_hud_print_text_interpolated(text, prevX, prevY - prevOffset, prevScale, x, y - offset, scale); djui_hud_print_text_interpolated(text, prevX, prevY + prevOffset, prevScale, x, y + offset, scale); + // render text - djui_hud_set_color(r, g, b, a); + djui_hud_set_color(255, 255, 255, a); djui_hud_print_text_interpolated(text, prevX, prevY, prevScale, x, y, scale); + + // reset colors djui_hud_set_color(255, 255, 255, 255); + djui_hud_set_text_color(255, 255, 255, 255); } void nametags_render(void) { @@ -59,7 +51,21 @@ void nametags_render(void) { djui_hud_set_resolution(RESOLUTION_N64); djui_hud_set_font(FONT_SPECIAL); - for (u8 i = gNametagsSettings.showSelfTag ? 0 : 1; i < MAX_PLAYERS; i++) { + struct NametagInfo { + Vec3f pos; + f32 scale; + char name[MAX_CONFIG_STRING]; + }; + struct NametagInfo nametags[MAX_PLAYERS] = {0}; + s32 sortedNametagIndices[MAX_PLAYERS] = {0}; + s32 numNametags = 0; + + extern bool gDjuiHudToWorldCalcViewport; + gDjuiHudToWorldCalcViewport = false; + + // sort nametags by their distance to the camera + // insertion sort is quick enough for such small array + for (s32 i = gNametagsSettings.showSelfTag ? 0 : 1; i < MAX_PLAYERS; i++) { struct MarioState* m = &gMarioStates[i]; if (!is_player_active(m)) { continue; } struct NetworkPlayer* np = &gNetworkPlayers[i]; @@ -84,8 +90,6 @@ void nametags_render(void) { vec3f_copy(pos, m->marioBodyState->headPos); pos[1] += 100; - extern bool gDjuiHudToWorldCalcViewport; - gDjuiHudToWorldCalcViewport = false; if ((i != 0 || (i == 0 && m->action != ACT_FIRST_PERSON)) && djui_hud_world_pos_to_screen_pos(pos, out)) { @@ -96,61 +100,89 @@ void nametags_render(void) { snprintf(name, MAX_CONFIG_STRING, "%s", hookedString); } else { snprintf(name, MAX_CONFIG_STRING, "%s", np->name); - name_without_hex(name); } if (!djui_hud_world_pos_to_screen_pos(pos, out)) { continue; } - u8* color = network_get_player_text_color(m->playerIndex); f32 scale = -300 / out[2] * djui_hud_get_fov_coeff(); - f32 measure = djui_hud_measure_text(name) * scale * 0.5f; - out[1] -= 16 * scale; - u8 alpha = (i == 0 ? 255 : MIN(np->fadeOpacity << 3, 255)) * clamp(FADE_SCALE - scale, 0.f, 1.f); - - struct StateExtras* e = &sStateExtras[i]; - if (!e->inited) { - vec3f_copy(e->prevPos, out); - e->prevScale = scale; - e->inited = true; + s32 j = 0; + for (; j < numNametags; ++j) { + const struct NametagInfo *nametag = &nametags[sortedNametagIndices[j]]; + if (scale < nametag->scale) { + memmove(sortedNametagIndices + j + 1, sortedNametagIndices + j, sizeof(s32) * (numNametags - j)); + break; + } } + sortedNametagIndices[j] = i; - // Apply viewport for credits - extern Vp *gViewportOverride; - extern Vp *gViewportClip; - extern Vp gViewportFullscreen; - Vp *viewport = gViewportOverride == NULL ? gViewportClip : gViewportOverride; - if (viewport) { - make_viewport_clip_rect(viewport); - gSPViewport(gDisplayListHead++, viewport); - } + struct NametagInfo *nametag = &nametags[i]; + vec3f_copy(nametag->pos, out); + nametag->scale = scale; + memcpy(nametag->name, name, sizeof(name)); - djui_hud_print_outlined_text_interpolated(name, - e->prevPos[0] - measure, e->prevPos[1], e->prevScale, - out[0] - measure, out[1], scale, - color[0], color[1], color[2], alpha, 0.25); - - if (i != 0 && gNametagsSettings.showHealth) { - djui_hud_set_color(255, 255, 255, alpha); - f32 healthScale = 90 * scale; - f32 prevHealthScale = 90 * e->prevScale; - hud_render_power_meter_interpolated(m->health, - e->prevPos[0] - (prevHealthScale * 0.5f), e->prevPos[1] - 72 * scale, prevHealthScale, prevHealthScale, - out[0] - ( healthScale * 0.5f), out[1] - 72 * scale, healthScale, healthScale - ); - } - - // Reset viewport - if (viewport) { - gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, BORDER_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT - BORDER_HEIGHT); - gSPViewport(gDisplayListHead++, &gViewportFullscreen); - } - - vec3f_copy(e->prevPos, out); - e->prevScale = scale; + numNametags++; } - gDjuiHudToWorldCalcViewport = true; + } + + gDjuiHudToWorldCalcViewport = true; + + // render nametags + for (s32 k = 0; k < numNametags; ++k) { + s32 playerIndex = sortedNametagIndices[k]; + struct NametagInfo *nametag = &nametags[playerIndex]; + struct MarioState *m = &gMarioStates[playerIndex]; + struct NetworkPlayer *np = &gNetworkPlayers[playerIndex]; + + u8* color = network_get_player_text_color(m->playerIndex); + f32 measure = djui_hud_measure_text(nametag->name) * nametag->scale * 0.5f; + nametag->pos[1] -= 16 * nametag->scale; + + u8 alpha = (playerIndex == 0 ? 255 : MIN(np->fadeOpacity << 3, 255)) * clamp(FADE_SCALE - nametag->scale, 0.f, 1.f); + + struct StateExtras* e = &sStateExtras[playerIndex]; + if (!e->inited) { + vec3f_copy(e->prevPos, nametag->pos); + e->prevScale = nametag->scale; + e->inited = true; + } + + // Apply viewport for credits + extern Vp *gViewportOverride; + extern Vp *gViewportClip; + extern Vp gViewportFullscreen; + Vp *viewport = gViewportOverride == NULL ? gViewportClip : gViewportOverride; + if (viewport) { + make_viewport_clip_rect(viewport); + gSPViewport(gDisplayListHead++, viewport); + } + + // render name + djui_hud_print_outlined_text_interpolated(nametag->name, + e->prevPos[0] - measure, e->prevPos[1], e->prevScale, + nametag->pos[0] - measure, nametag->pos[1], nametag->scale, + color[0], color[1], color[2], alpha, 0.25); + + // render power meter + if (playerIndex != 0 && gNametagsSettings.showHealth) { + djui_hud_set_color(255, 255, 255, alpha); + f32 healthScale = 90 * nametag->scale; + f32 prevHealthScale = 90 * e->prevScale; + hud_render_power_meter_interpolated(m->health, + e->prevPos[0] - (prevHealthScale * 0.5f), e->prevPos[1] - 72 * nametag->scale, prevHealthScale, prevHealthScale, + nametag->pos[0] - ( healthScale * 0.5f), nametag->pos[1] - 72 * nametag->scale, healthScale, healthScale + ); + } + + // Reset viewport + if (viewport) { + gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, BORDER_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT - BORDER_HEIGHT); + gSPViewport(gDisplayListHead++, &gViewportFullscreen); + } + + vec3f_copy(e->prevPos, nametag->pos); + e->prevScale = nametag->scale; } } diff --git a/src/pc/platform.c b/src/pc/platform.c index 185b85bd9..7daeb178e 100644 --- a/src/pc/platform.c +++ b/src/pc/platform.c @@ -56,8 +56,8 @@ const char *sys_file_extension(const char *fpath) { } const char *sys_file_name(const char *fpath) { - const char *sep1 = strrchr(fpath, '/'); - const char *sep2 = strrchr(fpath, '\\'); + const char *sep1 = strrchr(fpath, *PATH_SEPARATOR); + const char *sep2 = strrchr(fpath, *PATH_SEPARATOR_ALT); const char *sep = sep1 > sep2 ? sep1 : sep2; if (!sep) return fpath; return sep + 1; @@ -325,7 +325,7 @@ const char *sys_user_path(void) { // strip the trailing separator const unsigned int len = strlen(path); - if (path[len-1] == '/' || path[len-1] == '\\') { path[len-1] = 0; } + if (path[len-1] == *PATH_SEPARATOR || path[len-1] == *PATH_SEPARATOR_ALT) { path[len-1] = 0; } return path; } diff --git a/src/pc/platform.h b/src/pc/platform.h index c05094ad4..e043c6ab5 100644 --- a/src/pc/platform.h +++ b/src/pc/platform.h @@ -7,6 +7,14 @@ /* platform-specific functions and whatnot */ +#ifdef _WIN32 +#define PATH_SEPARATOR "\\" +#define PATH_SEPARATOR_ALT "/" +#else +#define PATH_SEPARATOR "/" +#define PATH_SEPARATOR_ALT "\\" +#endif + #define SYS_MAX_PATH 4096 // crossplatform impls of misc stuff