From 76e99ffe1919280ef307102cfda7eaf3cce89f9b Mon Sep 17 00:00:00 2001 From: aMannus Date: Sun, 12 Mar 2023 08:10:03 +0100 Subject: [PATCH] Feature - Bonk damage under difficulty options (#2584) --- .../game-interactor/GameInteractor.h | 1 + .../game-interactor/GameInteractor_Hooks.cpp | 4 ++ .../game-interactor/GameInteractor_Hooks.h | 1 + soh/soh/Enhancements/mods.cpp | 51 +++++++++++++++++-- soh/soh/Enhancements/presets.h | 1 + soh/soh/GameMenuBar.cpp | 14 +++++ .../actors/ovl_player_actor/z_player.c | 1 + 7 files changed, 70 insertions(+), 3 deletions(-) diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor.h b/soh/soh/Enhancements/game-interactor/GameInteractor.h index f60063dbd..927e59f23 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor.h @@ -91,6 +91,7 @@ public: DEFINE_HOOK(OnSaleEnd, void(GetItemEntry itemEntry)); DEFINE_HOOK(OnSceneInit, void(int16_t sceneNum)); DEFINE_HOOK(OnPlayerUpdate, void()); + DEFINE_HOOK(OnPlayerBonk, void()); DEFINE_HOOK(OnSaveFile, void(int32_t fileNum)); DEFINE_HOOK(OnLoadFile, void(int32_t fileNum)); diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp index f1daa659a..9b830563b 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp @@ -30,6 +30,10 @@ void GameInteractor_ExecuteOnPlayerUpdate() { GameInteractor::Instance->ExecuteHooks(); } +void GameInteractor_ExecuteOnPlayerBonk() { + GameInteractor::Instance->ExecuteHooks(); +} + // MARK: - Save Files void GameInteractor_ExecuteOnSaveFile(int32_t fileNum) { diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h index 51d8ecce4..3a6373eff 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h @@ -8,6 +8,7 @@ extern "C" void GameInteractor_ExecuteOnItemReceiveHooks(GetItemEntry itemEntry) extern "C" void GameInteractor_ExecuteOnSaleEndHooks(GetItemEntry itemEntry); extern "C" void GameInteractor_ExecuteOnSceneInit(int16_t sceneNum); extern "C" void GameInteractor_ExecuteOnPlayerUpdate(); +extern "C" void GameInteractor_ExecuteOnPlayerBonk(); // MARK: - Save Files extern "C" void GameInteractor_ExecuteOnSaveFile(int32_t fileNum); diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp index 16d72539b..95023dcf3 100644 --- a/soh/soh/Enhancements/mods.cpp +++ b/soh/soh/Enhancements/mods.cpp @@ -7,11 +7,9 @@ extern "C" { #include #include "macros.h" #include "variables.h" +#include "functions.h" extern SaveContext gSaveContext; extern PlayState* gPlayState; -extern void Play_PerformSave(PlayState* play); -extern s32 Health_ChangeBy(PlayState* play, s16 healthChange); -extern void Rupees_ChangeBy(s16 rupeeChange); } void RegisterInfiniteMoney() { @@ -266,6 +264,52 @@ void RegisterRupeeDash() { }); } +void RegisterBonkDamage() { + GameInteractor::Instance->RegisterGameHook([]() { + uint8_t bonkOption = CVarGetInteger("gBonkDamageMul", 0); + uint16_t bonkDamage = 0; + switch (bonkOption) { + // Quarter heart + case 1: + bonkDamage = 4; + break; + // Half a heart + case 2: + bonkDamage = 8; + break; + // Full heart + case 3: + bonkDamage = 16; + break; + // 2 hearts + case 4: + bonkDamage = 32; + break; + // 4 hearts + case 5: + bonkDamage = 64; + break; + // 8 hearts + case 6: + bonkDamage = 128; + break; + case 0: + case 7: + default: + break; + } + // OHKO + if (bonkOption == 7) { + gSaveContext.health = 0; + } else if (bonkDamage) { + Health_ChangeBy(gPlayState, -bonkDamage); + // Set invincibility to make Link flash red as a visual damage indicator. + Player* player = GET_PLAYER(gPlayState); + player->invincibilityTimer = 28; + } + }); +} + void InitMods() { RegisterTTS(); RegisterInfiniteMoney(); @@ -280,4 +324,5 @@ void InitMods() { RegisterSwitchAge(); RegisterRupeeDash(); RegisterAutoSave(); + RegisterBonkDamage(); } diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index dd5369d18..da89029a0 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -82,6 +82,7 @@ const std::vector enhancementsCvars = { "gDamageMul", "gFallDamageMul", "gVoidDamageMul", + "gBonkDamageMul", "gNoRandomDrops", "gNoHeartDrops", "gBombchuDrops", diff --git a/soh/soh/GameMenuBar.cpp b/soh/soh/GameMenuBar.cpp index e98e28659..a22ba5ee0 100644 --- a/soh/soh/GameMenuBar.cpp +++ b/soh/soh/GameMenuBar.cpp @@ -73,6 +73,17 @@ namespace GameMenuBar { "Hexaquinquagintiducentuple (256x)" }; + const char* bonkDamageValues[8] = { + "No Damage", + "0.25 Heart", + "0.5 Heart", + "1 Heart", + "2 Hearts", + "4 Hearts", + "8 Hearts", + "OHKO" + }; + // MARK: - Helpers std::string GetWindowButtonText(const char* text, bool menuOpen) { @@ -477,6 +488,9 @@ namespace GameMenuBar { 32x: Can survive void damage with max health and double defense\n\ 64x: Cannot survive void damage" ); + UIWidgets::PaddedText("Bonk Damage Multiplier", true, false); + UIWidgets::EnhancementCombobox("gBonkDamageMul", bonkDamageValues, 8, 0); + UIWidgets::Tooltip("Modifies damage taken after bonking."); UIWidgets::PaddedEnhancementCheckbox("Spawn with full health", "gFullHealthSpawn", true, false); UIWidgets::Tooltip("Respawn with full health instead of 3 Hearts"); UIWidgets::PaddedEnhancementCheckbox("No Random Drops", "gNoRandomDrops", true, false); diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index 5a4cc4f53..7c56b7f6c 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -8679,6 +8679,7 @@ void func_80844708(Player* this, PlayState* play) { func_80832698(this, NA_SE_VO_LI_CLIMB_END); this->unk_850 = 1; gSaveContext.sohStats.count[COUNT_BONKS]++; + GameInteractor_ExecuteOnPlayerBonk(); return; } }