diff --git a/soh/include/functions.h b/soh/include/functions.h index 0bea29da2..0c6ff3266 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -1059,9 +1059,12 @@ void Interface_SetDoAction(GlobalContext* globalCtx, u16 action); void Interface_SetNaviCall(GlobalContext* globalCtx, u16 naviCallState); void Interface_LoadActionLabelB(GlobalContext* globalCtx, u16 action); s32 Health_ChangeBy(GlobalContext* globalCtx, s16 healthChange); +void Health_GiveHearts(s16 hearts); +void Health_RemoveHearts(s16 hearts); void Rupees_ChangeBy(s16 rupeeChange); void Inventory_ChangeAmmo(s16 item, s16 ammoChange); void Magic_Fill(GlobalContext* globalCtx); +void Magic_Empty(); void func_800876C8(GlobalContext* globalCtx); s32 func_80087708(GlobalContext* globalCtx, s16 arg1, s16 arg2); void func_80088AA0(s16 seconds); @@ -1074,6 +1077,7 @@ f32 Path_OrientAndGetDistSq(Actor* actor, Path* path, s16 waypoint, s16* yaw); void Path_CopyLastPoint(Path* path, Vec3f* dest); void FrameAdvance_Init(FrameAdvanceContext* frameAdvCtx); s32 FrameAdvance_Update(FrameAdvanceContext* frameAdvCtx, Input* input); +u8 PlayerGrounded(Player* player); void Player_SetBootData(GlobalContext* globalCtx, Player* player); s32 Player_InBlockingCsMode(GlobalContext* globalCtx, Player* player); s32 Player_InCsMode(GlobalContext* globalCtx); @@ -1086,6 +1090,7 @@ void Player_SetModelGroup(Player* player, s32 modelGroup); void func_8008EC70(Player* player); void Player_SetEquipmentData(GlobalContext* globalCtx, Player* player); void Player_UpdateBottleHeld(GlobalContext* globalCtx, Player* player, s32 item, s32 actionParam); +void func_80837C0C(GlobalContext* globalCtx, Player* this, s32 arg2, f32 arg3, f32 arg4, s16 arg5, s32 arg6); void func_8008EDF0(Player* player); void func_8008EE08(Player* player); void func_8008EEAC(GlobalContext* globalCtx, Actor* actor); diff --git a/soh/soh/Enhancements/debugconsole.cpp b/soh/soh/Enhancements/debugconsole.cpp index daf4d0b6e..204028e41 100644 --- a/soh/soh/Enhancements/debugconsole.cpp +++ b/soh/soh/Enhancements/debugconsole.cpp @@ -31,15 +31,14 @@ extern GlobalContext* gGlobalCtx; } #include "Cvar.h" +#include "overlays/actors/ovl_En_Niw/z_en_niw.h" #define CMD_REGISTER SohImGui::BindCmd -uint32_t defenseModifier; uint32_t giantLink; uint32_t minishLink; uint32_t gravityLevel; uint32_t resetLinkScale; -uint32_t noUI; uint32_t invisibleLink; static bool ActorSpawnHandler(std::shared_ptr Console, const std::vector& args) { @@ -388,6 +387,11 @@ static bool InvisibleHandler(std::shared_ptr Console, const std:: try { invisibleLink = std::stoi(args[1], nullptr, 10) == 0 ? 0 : 1; + if (!invisibleLink) { + Player* player = GET_PLAYER(gGlobalCtx); + player->actor.shape.shadowDraw = ActorShadow_DrawFeet; + } + return CMD_SUCCESS; } catch (std::invalid_argument const& ex) { SohImGui::console->SendErrorMessage("[SOH] Invisible value must be a number."); @@ -441,7 +445,7 @@ static bool AddHeartContainerHandler(std::shared_ptr Console, con if (gSaveContext.healthCapacity >= 0x140) return CMD_FAILED; - gSaveContext.healthCapacity += 0x10; + Health_GiveHearts(1); return CMD_SUCCESS; } @@ -449,7 +453,7 @@ static bool RemoveHeartContainerHandler(std::shared_ptr Console, if ((gSaveContext.healthCapacity - 0x10) < 3) return CMD_FAILED; - gSaveContext.healthCapacity -= 0x10; + Health_RemoveHearts(1); return CMD_SUCCESS; } @@ -468,20 +472,236 @@ static bool GravityHandler(std::shared_ptr Console, const std::ve } } -// TODO: Does not yet function static bool NoUIHandler(std::shared_ptr Console, const std::vector& args) { if (args.size() != 2) { SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); return CMD_FAILED; } - try { - bool noUI = std::stoi(args[1], nullptr, 10) == 0 ? 0 : 1; + // TODO: Implement +} + +static bool FreezeHandler(std::shared_ptr Console, const std::vector& args) { + Player* player = GET_PLAYER(gGlobalCtx); + if (PlayerGrounded(player)) { + func_80837C0C(gGlobalCtx, player, 3, 0, 0, 0, 0); return CMD_SUCCESS; - } catch (std::invalid_argument const& ex) { - SohImGui::console->SendErrorMessage("[SOH] NoUI value must be a number."); + } + + return CMD_FAILED; +} + +static bool DefenseModifierHandler(std::shared_ptr Console, const std::vector& args) { + if (args.size() != 2) { + SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); return CMD_FAILED; } + + // TODO: Implement +} + +static bool DamageHandler(std::shared_ptr Console, const std::vector& args) { + if (args.size() != 2) { + SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); + return CMD_FAILED; + } + + try { + int value = std::stoi(args[1], nullptr, 10); + if (value < 0) { + SohImGui::console->SendErrorMessage("[SOH] Invalid value passed. Value must be greater than 0"); + return CMD_FAILED; + } + + Player* player = GET_PLAYER(gGlobalCtx); + + Health_ChangeBy(gGlobalCtx, -value * 0x10); + func_80837C0C(gGlobalCtx, player, 0, 0, 0, 0, 0); + player->invincibilityTimer = 28; + + return CMD_SUCCESS; + } catch (std::invalid_argument const& ex) { + SohImGui::console->SendErrorMessage("[SOH] Damage value must be a number."); + return CMD_FAILED; + } +} + +static bool HealHandler(std::shared_ptr Console, const std::vector& args) { + if (args.size() != 2) { + SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); + return CMD_FAILED; + } + + try { + int value = std::stoi(args[1], nullptr, 10); + if (value < 0) { + SohImGui::console->SendErrorMessage("[SOH] Invalid value passed. Value must be greater than 0"); + return CMD_FAILED; + } + + Health_ChangeBy(gGlobalCtx, value * 0x10); + return CMD_SUCCESS; + } catch (std::invalid_argument const& ex) { + SohImGui::console->SendErrorMessage("[SOH] Heal value must be a number."); + return CMD_FAILED; + } +} + +static bool FillMagicHandler(std::shared_ptr Console, const std::vector& args) { + Magic_Fill(gGlobalCtx); + return CMD_SUCCESS; +} + +static bool EmptyMagicHandler(std::shared_ptr Console, const std::vector& args) { + Magic_Empty(); + return CMD_SUCCESS; +} + +static bool NoZHandler(std::shared_ptr Console, const std::vector& args) { + if (args.size() != 2) { + SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); + return CMD_FAILED; + } + + // TODO: Implement +} + +static bool OneHitKOHandler(std::shared_ptr Console, const std::vector& args) { + if (args.size() != 2) { + SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); + return CMD_FAILED; + } + + // TODO: Implement +} + +static bool PacifistHandler(std::shared_ptr Console, const std::vector& args) { + if (args.size() != 2) { + SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); + return CMD_FAILED; + } + + // TODO: Implement +} + +static bool PaperLinkHandler(std::shared_ptr Console, const std::vector& args) { + if (args.size() != 2) { + SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); + return CMD_FAILED; + } + + // TODO: Implement +} + +static bool RainstormHandler(std::shared_ptr Console, const std::vector& args) { + // TODO: Implement +} + +static bool ReverseControlsHandler(std::shared_ptr Console, const std::vector& args) { + if (args.size() != 2) { + SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); + return CMD_FAILED; + } + + // TODO: Implement +} + +static bool AddRemoveRupeesHandler(std::shared_ptr Console, const std::vector& args) { + if (args.size() != 2) { + SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); + return CMD_FAILED; + } + + // TODO: Implement +} + +static bool SpeedModifierHandler(std::shared_ptr Console, const std::vector& args) { + if (args.size() != 2) { + SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); + return CMD_FAILED; + } + + // TODO: Implement +} + +const static std::map boots { + { "kokiri", PLAYER_BOOTS_KOKIRI }, + { "iron", PLAYER_BOOTS_IRON }, { "hover", PLAYER_BOOTS_HOVER }, +}; + +static bool BootsHandler(std::shared_ptr Console, const std::vector& args) { + if (args.size() != 2) { + SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); + return CMD_FAILED; + } + + const auto& it = boots.find(args[1]); + if (it == ammoItems.end()) { + SohImGui::console->SendErrorMessage("Invalid boot type. Options are 'kokiri', 'iron' and 'hover'"); + return CMD_FAILED; + } + + Player* player = GET_PLAYER(gGlobalCtx); + player->currentBoots = it->second; + Inventory_ChangeEquipment(EQUIP_BOOTS, it->second + 1); + Player_SetBootData(gGlobalCtx, player); + + return CMD_SUCCESS; +} + +static bool KnockbackHandler(std::shared_ptr Console, const std::vector& args) { + if (args.size() != 2) { + SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); + return CMD_FAILED; + } + + try { + int value = std::stoi(args[1], nullptr, 10); + if (value < 0) { + SohImGui::console->SendErrorMessage("[SOH] Invalid value passed. Value must be greater than 0"); + return CMD_FAILED; + } + + Player* player = GET_PLAYER(gGlobalCtx); + func_8002F71C(gGlobalCtx, &player->actor, value * 5, player->actor.world.rot.y + 0x8000, value * 5); + + return CMD_SUCCESS; + } catch (std::invalid_argument const& ex) { + SohImGui::console->SendErrorMessage("[SOH] Knockback value must be a number."); + return CMD_FAILED; + } +} + +static bool ElectrocuteHandler(std::shared_ptr Console, const std::vector& args) { + Player* player = GET_PLAYER(gGlobalCtx); + if (PlayerGrounded(player)) { + func_80837C0C(gGlobalCtx, player, 4, 0, 0, 0, 0); + return CMD_SUCCESS; + } + + return CMD_FAILED; +} + +static bool BurnHandler(std::shared_ptr Console, const std::vector& args) { + Player* player = GET_PLAYER(gGlobalCtx); + if (PlayerGrounded(player)) { + for (int i = 0; i < 18; i++) { + player->flameTimers[i] = Rand_S16Offset(0, 200); + } + player->isBurning = true; + func_80837C0C(gGlobalCtx, player, 0, 0, 0, 0, 0); + return 1; + } + return 0; +} + +static bool CuccoStormHandler(std::shared_ptr Console, const std::vector& args) { + Player* player = GET_PLAYER(gGlobalCtx); + EnNiw* cucco = (EnNiw*)Actor_Spawn(&gGlobalCtx->actorCtx, gGlobalCtx, ACTOR_EN_NIW, player->actor.world.pos.x, + player->actor.world.pos.y, player->actor.world.pos.z, 0, 0, 0, 0); + // TODO: Start the storm with the function below + // cucco->actionFunc = func_80AB70A0; + return CMD_SUCCESS; } #define VARTYPE_INTEGER 0 @@ -571,17 +791,33 @@ static bool GetCVarHandler(std::shared_ptr Console, const std::ve } void DebugConsole_Init(void) { + // Console + CMD_REGISTER("reset", { ResetHandler, "Resets the game." }); + + // Save States + CMD_REGISTER("save_state", { SaveStateHandler, "Save a state." }); + CMD_REGISTER("load_state", { LoadStateHandler, "Load a state." }); + CMD_REGISTER("set_slot", { StateSlotSelectHandler, "Selects a SaveState slot", { + { "Slot number", Ship::ArgumentType::NUMBER, } + }}); + + // Gameplay CMD_REGISTER("kill", { KillPlayerHandler, "Commit suicide." }); + CMD_REGISTER("map", { LoadSceneHandler, "Load up kak?" }); + CMD_REGISTER("rupee", { RuppeHandler, "Set your rupee counter.", { {"amount", Ship::ArgumentType::NUMBER } }}); + CMD_REGISTER("bItem", { BHandler, "Set an item to the B button.", { { "Item ID", Ship::ArgumentType::NUMBER } }}); + CMD_REGISTER("health", { SetPlayerHealthHandler, "Set the health of the player.", { { "health", Ship::ArgumentType::NUMBER } }}); + CMD_REGISTER("spawn", { ActorSpawnHandler, "Spawn an actor.", { { "actor_id", Ship::ArgumentType::NUMBER }, { "data", Ship::ArgumentType::NUMBER }, @@ -592,19 +828,22 @@ void DebugConsole_Init(void) { { "ry", Ship::ArgumentType::PLAYER_ROT, true }, { "rz", Ship::ArgumentType::PLAYER_ROT, true } }}); + CMD_REGISTER("pos", { SetPosHandler, "Sets the position of the player.", { { "x", Ship::ArgumentType::PLAYER_POS, true }, { "y", Ship::ArgumentType::PLAYER_POS, true }, { "z", Ship::ArgumentType::PLAYER_POS, true } }}); + CMD_REGISTER("set", { SetCVarHandler, "Sets a console variable.", { { "varName", Ship::ArgumentType::TEXT }, { "varValue", Ship::ArgumentType::TEXT } }}); + CMD_REGISTER("get", { GetCVarHandler, "Gets a console variable.", { { "varName", Ship::ArgumentType::TEXT } }}); - CMD_REGISTER("reset", { ResetHandler, "Resets the game." }); + CMD_REGISTER("ammo", { AmmoHandler, "Changes ammo of an item.", { { "item", Ship::ArgumentType::TEXT }, { "count", Ship::ArgumentType::NUMBER } @@ -619,17 +858,11 @@ void DebugConsole_Init(void) { { "slot", Ship::ArgumentType::NUMBER }, { "item id", Ship::ArgumentType::NUMBER } }}); + CMD_REGISTER("entrance", { EntranceHandler, "Sends player to the entered entrance (hex)", { { "entrance", Ship::ArgumentType::NUMBER } }}); - CMD_REGISTER("save_state", { SaveStateHandler, "Save a state." }); - CMD_REGISTER("load_state", { LoadStateHandler, "Load a state." }); - CMD_REGISTER("set_slot", { StateSlotSelectHandler, "Selects a SaveState slot", { - { "Slot number", Ship::ArgumentType::NUMBER, } - }}); - - // Console effects CMD_REGISTER("invisible", { InvisibleHandler, "Activate Link's Elvish cloak, making him appear invisible.", { { "value", Ship::ArgumentType::NUMBER } }}); @@ -650,9 +883,75 @@ void DebugConsole_Init(void) { { "value", Ship::ArgumentType::NUMBER } }}); - CMD_REGISTER("no_ui", { NoUIHandler, "Disable the UI.", { + CMD_REGISTER("no_ui", { NoUIHandler, "Disables the UI.", { { "value", Ship::ArgumentType::NUMBER } }}); + CMD_REGISTER("freeze", { FreezeHandler, "Freezes Link in place" }); + + CMD_REGISTER("defense_modifier", { DefenseModifierHandler, "Sets the defense modifier.", { + { "value", Ship::ArgumentType::NUMBER } + }}); + + CMD_REGISTER("damage", { DamageHandler, "Deal damage to Link.", { + { "value", Ship::ArgumentType::NUMBER } + }}); + + CMD_REGISTER("heal", { HealHandler, "Heals Link.", { + { "value", Ship::ArgumentType::NUMBER } + }}); + + CMD_REGISTER("fill_magic", { FillMagicHandler, "Fills magic." }); + + CMD_REGISTER("empty_magic", { EmptyMagicHandler, "Empties magic." }); + + CMD_REGISTER("no_z", { NoZHandler, "Disables Z-button presses.", { + { "value", Ship::ArgumentType::NUMBER } + }}); + + CMD_REGISTER("ohko", { OneHitKOHandler, "Activates one hit KO.", { + { "value", Ship::ArgumentType::NUMBER } + }}); + + CMD_REGISTER("pacifist", { PacifistHandler, "Activates pacifist mode.", { + { "value", Ship::ArgumentType::NUMBER } + }}); + + CMD_REGISTER("paper_link", { PaperLinkHandler, "Link but made out of paper.", { + { "value", Ship::ArgumentType::NUMBER } + }}); + + CMD_REGISTER("rainstorm", { RainstormHandler, "Activates rainstorm." }); + + CMD_REGISTER("reverse_controls", { ReverseControlsHandler, "Reverses the controls.", { + { "value", Ship::ArgumentType::NUMBER } + }}); + + CMD_REGISTER("add_rupees", { AddRemoveRupeesHandler, "Adds rupees.", { + { "value", Ship::ArgumentType::NUMBER } + }}); + + CMD_REGISTER("subtract_rupees", { AddRemoveRupeesHandler, "Subtracts rupees.", { + { "value", Ship::ArgumentType::NUMBER } + }}); + + CMD_REGISTER("speed_modifier", { SpeedModifierHandler, "Sets the speed modifier.", { + { "value", Ship::ArgumentType::NUMBER } + }}); + + CMD_REGISTER("boots", { BootsHandler, "Activates boots.", { + { "type", Ship::ArgumentType::TEXT }, + }}); + + CMD_REGISTER("knockback", { KnockbackHandler, "Knocks Link back.", { + { "value", Ship::ArgumentType::NUMBER } + }}); + + CMD_REGISTER("electrocute", { ElectrocuteHandler, "Electrocutes Link." }); + + CMD_REGISTER("burn", { BurnHandler, "Burns Link." }); + + CMD_REGISTER("cucco_storm", { CuccoStormHandler, "Activates Cucco Storm." }); + CVar_Load(); } diff --git a/soh/soh/Enhancements/debugconsole.h b/soh/soh/Enhancements/debugconsole.h index dabe171ab..9a3c3c72b 100644 --- a/soh/soh/Enhancements/debugconsole.h +++ b/soh/soh/Enhancements/debugconsole.h @@ -5,7 +5,6 @@ #ifdef __cplusplus extern "C" { #endif -extern uint32_t defenseModifier; extern uint32_t giantLink; extern uint32_t minishLink; extern uint32_t gravityLevel; diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 24211c590..daeef38a0 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -2684,6 +2684,10 @@ void Health_GiveHearts(s16 hearts) { gSaveContext.healthCapacity += hearts * 0x10; } +void Health_RemoveHearts(s16 hearts) { + gSaveContext.healthCapacity -= hearts * 0x10; +} + void Rupees_ChangeBy(s16 rupeeChange) { gSaveContext.rupeeAccumulator += rupeeChange; } @@ -2755,6 +2759,12 @@ void Magic_Fill(GlobalContext* globalCtx) { } } +// TODO: Make it stop blinking +void Magic_Empty() { + gSaveContext.unk_13F8 = 0; + gSaveContext.unk_13F0 = 1; +} + void func_800876C8(GlobalContext* globalCtx) { if ((gSaveContext.unk_13F0 != 8) && (gSaveContext.unk_13F0 != 9)) { if (gSaveContext.unk_13F0 == 10) { diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index ac5978570..02fb773df 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -1533,8 +1533,6 @@ u8 PlayerGrounded(Player* player) { return (player->actor.world.pos.y - player->actor.floorHeight) == 0; } -extern func_80AB70A0(EnNiw* this, GlobalContext* globalCtx); - void RemoveEffect(const char* effectId) { if (gGlobalCtx == NULL) { return; @@ -1551,7 +1549,7 @@ void RemoveEffect(const char* effectId) { minishLink = 0; resetLinkScale = 1; } else if (strcmp(effectId, "defense_modifier") == 0) { - defenseModifier = 0; + // defenseModifier = 0; return; } else if (strcmp(effectId, "iron_boots") == 0 || strcmp(effectId, "hover_boots") == 0) { player->currentBoots = PLAYER_BOOTS_KOKIRI; @@ -1562,7 +1560,7 @@ void RemoveEffect(const char* effectId) { gravityLevel = 1; return; } else if (strcmp(effectId, "no_ui") == 0) { - noUI = 0; + // noUI = 0; return; } else if (strcmp(effectId, "invisible") == 0) { invisibleLink = 0; @@ -1609,7 +1607,7 @@ u8 ExecuteEffect(const char* effectId, uint32_t value) { minishLink = 1; return 1; } else if (strcmp(effectId, "defense_modifier") == 0) { - defenseModifier = value; + // defenseModifier = value; return 1; } else if (strcmp(effectId, "kill") == 0) { if (PlayerGrounded(player)) { @@ -1621,7 +1619,7 @@ u8 ExecuteEffect(const char* effectId, uint32_t value) { EnNiw* cucco = (EnNiw*)Actor_Spawn(&gGlobalCtx->actorCtx, gGlobalCtx, ACTOR_EN_NIW, player->actor.world.pos.x, player->actor.world.pos.y, player->actor.world.pos.z, 0, 0, 0, 0); - cucco->actionFunc = func_80AB70A0; + // cucco->actionFunc = func_80AB70A0; return 1; } else if (strcmp(effectId, "damage") == 0) { Health_ChangeBy(gGlobalCtx, -value * 16); @@ -1670,7 +1668,7 @@ u8 ExecuteEffect(const char* effectId, uint32_t value) { Actor_Spawn(&gGlobalCtx->actorCtx, gGlobalCtx, ACTOR_EN_WALLMAS, player->actor.world.pos.x, player->actor.world.pos.y, player->actor.world.pos.z, 0, 0, 0, 0); return 1; } else if (strcmp(effectId, "no_ui") == 0) { - noUI = 1; + // noUI = 1; return 1; } else if (strcmp(effectId, "invisible") == 0) { invisibleLink = 1;