diff --git a/soh/CMakeLists.txt b/soh/CMakeLists.txt index 1994a2b993e..6b4429a4215 100644 --- a/soh/CMakeLists.txt +++ b/soh/CMakeLists.txt @@ -257,6 +257,12 @@ set(Header_Files__soh__Enhancements__item_tables source_group("Header Files\\soh\\Enhancements\\item-tables" FILES ${Header_Files__soh__Enhancements__item_tables}) +set(Header_Files__soh__Enhancements__game_interactor + "soh/Enhancements/game-interactor/GameInteractor.h" + "soh/Enhancements/game-interactor/GameInteractionEffect.h" +) +source_group("Header Files\\soh\\Enhancements\\game-interactor" FILES ${Header_Files__soh__Enhancements__game_interactor}) + if (BUILD_CROWD_CONTROL) set(Header_Files__soh__Enhancements__crowd_control "soh/Enhancements/crowd-control/CrowdControl.h" @@ -411,6 +417,12 @@ set(Source_Files__soh__Enhancements__item_tables source_group("Source Files\\soh\\Enhancements\\item-tables" FILES ${Source_Files__soh__Enhancements__item_tables}) +set(Source_Files__soh__Enhancements__game_interactor + "soh/Enhancements/game-interactor/GameInteractor.cpp" + "soh/Enhancements/game-interactor/GameInteractionEffect.cpp" +) +source_group("Source Files\\soh\\Enhancements\\game-interactor" FILES ${Source_Files__soh__Enhancements__game_interactor}) + if (BUILD_CROWD_CONTROL) set(Source_Files__soh__Enhancements__crowd_control "soh/Enhancements/crowd-control/CrowdControl.cpp" @@ -1629,6 +1641,7 @@ set(ALL_FILES ${Header_Files__soh__Enhancements__randomizer__3drando} ${Header_Files__soh__Enhancements__item_tables} ${Header_Files__soh__Enhancements__custom_message} + ${Header_Files__soh__Enhancements__game_interactor} ${Header_Files__soh__Enhancements__crowd_control} ${Source_Files__soh} ${Source_Files__soh__Enhancements} @@ -1642,6 +1655,7 @@ set(ALL_FILES ${Source_Files__soh__Enhancements__randomizer__3drando__location_access} ${Source_Files__soh__Enhancements__item_tables} ${Source_Files__soh__Enhancements__custom_message} + ${Source_Files__soh__Enhancements__game_interactor} ${Source_Files__soh__Enhancements__crowd_control} ${Source_Files__src__boot} ${Source_Files__src__buffers} diff --git a/soh/soh/Enhancements/crowd-control/CrowdControl.cpp b/soh/soh/Enhancements/crowd-control/CrowdControl.cpp index 2f5b1a3accc..bbfe7185dad 100644 --- a/soh/soh/Enhancements/crowd-control/CrowdControl.cpp +++ b/soh/soh/Enhancements/crowd-control/CrowdControl.cpp @@ -142,8 +142,7 @@ void CrowdControl::ListenToServer() { // If effect is a one off run, let's execute if (!incomingEffect->timeRemaining) { - EffectResult result = - ExecuteEffect(incomingEffect->type.c_str(), incomingEffect->value, false); + EffectResult result = ExecuteEffect(incomingEffect); EmitMessage(tcpsock, incomingEffect->id, incomingEffect->timeRemaining, result); } else { // check if a conflicting event is already active @@ -160,9 +159,8 @@ void CrowdControl::ListenToServer() { } // check if effect can be executed - EffectResult result = - ExecuteEffect(incomingEffect->type.c_str(), incomingEffect->value, true); - if (result == EffectResult::Retry || result == EffectResult::Failure) { + GameInteractionEffectQueryResult result = incomingEffect->giEffect->CanBeApplied(); + if (result == GameInteractionEffectQueryResult::TemporarilyNotPossible || result == GameInteractionEffectQueryResult::NotPossibe) { EmitMessage(tcpsock, incomingEffect->id, incomingEffect->timeRemaining, result); continue; } @@ -192,13 +190,13 @@ void CrowdControl::ProcessActiveEffects() { while (it != activeEffects.end()) { Effect *effect = *it; - EffectResult result = ExecuteEffect(effect->type.c_str(), effect->value, false); + EffectResult result = ExecuteEffect(effect); if (result == EffectResult::Success) { // If time remaining has reached 0, we have finished the effect if (effect->timeRemaining <= 0) { it = activeEffects.erase(std::remove(activeEffects.begin(), activeEffects.end(), effect), activeEffects.end()); - RemoveEffect(effect->type.c_str()); + RemoveEffect(effect); delete effect; } else { @@ -247,6 +245,18 @@ void CrowdControl::EmitMessage(TCPsocket socket, uint32_t eventId, long timeRema SDLNet_TCP_Send(socket, jsonPayload.c_str(), jsonPayload.size() + 1); } +void CrowdControl::EmitMessage(TCPsocket socket, uint32_t eventId, long timeRemaining, GameInteractionEffectQueryResult status) { + nlohmann::json payload; + + payload["id"] = eventId; + payload["type"] = 0; + payload["timeRemaining"] = timeRemaining; + payload["status"] = status; + + std::string jsonPayload = payload.dump(); + SDLNet_TCP_Send(socket, jsonPayload.c_str(), jsonPayload.size() + 1); +} + CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) { nlohmann::json dataReceived = nlohmann::json::parse(payload, nullptr, false); if (dataReceived.is_discarded()) { @@ -258,218 +268,241 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) { effect->lastExecutionResult = EffectResult::Initiate; effect->id = dataReceived["id"]; auto parameters = dataReceived["parameters"]; - if (parameters.size() > 0) { - effect->value = dataReceived["parameters"][0]; - } - effect->type = dataReceived["code"].get(); - - if (effect->type == EFFECT_HIGH_GRAVITY || effect->type == EFFECT_LOW_GRAVITY) { - effect->category = "gravity"; - effect->timeRemaining = 30000; - } else if (effect->type == EFFECT_DAMAGE_MULTIPLIER || effect->type == EFFECT_DEFENSE_MULTIPLIER) { - effect->category = "defense"; - effect->timeRemaining = 30000; - } else if (effect->type == EFFECT_GIANT_LINK || effect->type == EFFECT_MINISH_LINK || - effect->type == EFFECT_INVISIBLE_LINK || effect->type == EFFECT_PAPER_LINK) { - effect->category = "link_size"; - effect->timeRemaining = 30000; - } else if (effect->type == EFFECT_FREEZE || effect->type == EFFECT_DAMAGE || effect->type == EFFECT_HEAL || - effect->type == EFFECT_KNOCKBACK || effect->type == EFFECT_ELECTROCUTE || - effect->type == EFFECT_BURN || effect->type == EFFECT_KILL) { - effect->category = "link_damage"; - } else if (effect->type == EFFECT_HOVER_BOOTS || effect->type == EFFECT_IRON_BOOTS) { - effect->category = "boots"; - effect->timeRemaining = 30000; - } else if (effect->type == EFFECT_ADD_HEART_CONTAINER || effect->type == EFFECT_REMOVE_HEART_CONTAINER) { - effect->category = "heart_container"; - } else if (effect->type == EFFECT_NO_UI) { + auto effectName = dataReceived["code"].get(); + + if (effectName == EFFECT_NO_UI) { effect->category = "ui"; effect->timeRemaining = 60000; - } else if (effect->type == EFFECT_FILL_MAGIC || effect->type == EFFECT_EMPTY_MAGIC) { - effect->category = "magic"; - } else if (effect->type == EFFECT_OHKO) { - effect->category = "ohko"; - effect->timeRemaining = 30000; - } else if (effect->type == EFFECT_PACIFIST) { - effect->category = "pacifist"; - effect->timeRemaining = 15000; - } else if (effect->type == EFFECT_RAINSTORM) { - effect->category = "weather"; - effect->timeRemaining = 30000; - } else if (effect->type == EFFECT_REVERSE_CONTROLS) { - effect->category = "controls"; - effect->timeRemaining = 60000; - } else if (effect->type == EFFECT_ADD_RUPEES || effect->type == EFFECT_REMOVE_RUPEES) { - effect->category = "rupees"; - } else if (effect->type == EFFECT_INCREASE_SPEED || effect->type == EFFECT_DECREASE_SPEED) { - effect->category = "speed"; - effect->timeRemaining = 30000; - } else if (effect->type == EFFECT_NO_Z_TARGETING) { - effect->category = "no_z"; - effect->timeRemaining = 30000; - } else if (effect->type == EFFECT_SPAWN_WALLMASTER || effect->type == EFFECT_SPAWN_ARWING || - effect->type == EFFECT_SPAWN_DARK_LINK || effect->type == EFFECT_SPAWN_STALFOS || - effect->type == EFFECT_SPAWN_WOLFOS || effect->type == EFFECT_SPAWN_FREEZARD || - effect->type == EFFECT_SPAWN_KEESE || effect->type == EFFECT_SPAWN_ICE_KEESE || - effect->type == EFFECT_SPAWN_FIRE_KEESE || effect->type == EFFECT_SPAWN_TEKTITE || - effect->type == EFFECT_SPAWN_LIKE_LIKE || effect->type == EFFECT_SPAWN_CUCCO_STORM) { - effect->category = "spawn"; + effect->giEffect = new GameInteractionEffect::NoUI(); + } else if (effectName == EFFECT_ADD_HEART_CONTAINER || effectName == EFFECT_REMOVE_HEART_CONTAINER) { + effect->category = "heart_container"; } else { effect->category = "none"; effect->timeRemaining = 0; } - return effect; -} -CrowdControl::EffectResult CrowdControl::ExecuteEffect(std::string effectId, uint32_t value, bool dryRun) { - // Don't execute effect and don't advance timer when the player is not in a proper loaded savefile - // and when they're busy dying. - if (gPlayState == NULL || gPlayState->gameOverCtx.state > 0 || gSaveContext.fileNum < 0 || gSaveContext.fileNum > 2) { - return EffectResult::Retry; - } +// +// +// if (parameters.size() > 0) { +// effect->value = dataReceived["parameters"][0]; +// } +// effect->type = dataReceived["code"].get(); +// +// if (effect->type == EFFECT_HIGH_GRAVITY || effect->type == EFFECT_LOW_GRAVITY) { +// effect->category = "gravity"; +// effect->timeRemaining = 30000; +// } else if (effect->type == EFFECT_DAMAGE_MULTIPLIER || effect->type == EFFECT_DEFENSE_MULTIPLIER) { +// effect->category = "defense"; +// effect->timeRemaining = 30000; +// } else if (effect->type == EFFECT_GIANT_LINK || effect->type == EFFECT_MINISH_LINK || +// effect->type == EFFECT_INVISIBLE_LINK || effect->type == EFFECT_PAPER_LINK) { +// effect->category = "link_size"; +// effect->timeRemaining = 30000; +// } else if (effect->type == EFFECT_FREEZE || effect->type == EFFECT_DAMAGE || effect->type == EFFECT_HEAL || +// effect->type == EFFECT_KNOCKBACK || effect->type == EFFECT_ELECTROCUTE || +// effect->type == EFFECT_BURN || effect->type == EFFECT_KILL) { +// effect->category = "link_damage"; +// } else if (effect->type == EFFECT_HOVER_BOOTS || effect->type == EFFECT_IRON_BOOTS) { +// effect->category = "boots"; +// effect->timeRemaining = 30000; +// } else if (effect->type == EFFECT_ADD_HEART_CONTAINER || effect->type == EFFECT_REMOVE_HEART_CONTAINER) { +// effect->category = "heart_container"; +// } else if (effect->type == EFFECT_NO_UI) { +// effect->category = "ui"; +// effect->timeRemaining = 60000; +// } else if (effect->type == EFFECT_FILL_MAGIC || effect->type == EFFECT_EMPTY_MAGIC) { +// effect->category = "magic"; +// } else if (effect->type == EFFECT_OHKO) { +// effect->category = "ohko"; +// effect->timeRemaining = 30000; +// } else if (effect->type == EFFECT_PACIFIST) { +// effect->category = "pacifist"; +// effect->timeRemaining = 15000; +// } else if (effect->type == EFFECT_RAINSTORM) { +// effect->category = "weather"; +// effect->timeRemaining = 30000; +// } else if (effect->type == EFFECT_REVERSE_CONTROLS) { +// effect->category = "controls"; +// effect->timeRemaining = 60000; +// } else if (effect->type == EFFECT_ADD_RUPEES || effect->type == EFFECT_REMOVE_RUPEES) { +// effect->category = "rupees"; +// } else if (effect->type == EFFECT_INCREASE_SPEED || effect->type == EFFECT_DECREASE_SPEED) { +// effect->category = "speed"; +// effect->timeRemaining = 30000; +// } else if (effect->type == EFFECT_NO_Z_TARGETING) { +// effect->category = "no_z"; +// effect->timeRemaining = 30000; +// } else if (effect->type == EFFECT_SPAWN_WALLMASTER || effect->type == EFFECT_SPAWN_ARWING || +// effect->type == EFFECT_SPAWN_DARK_LINK || effect->type == EFFECT_SPAWN_STALFOS || +// effect->type == EFFECT_SPAWN_WOLFOS || effect->type == EFFECT_SPAWN_FREEZARD || +// effect->type == EFFECT_SPAWN_KEESE || effect->type == EFFECT_SPAWN_ICE_KEESE || +// effect->type == EFFECT_SPAWN_FIRE_KEESE || effect->type == EFFECT_SPAWN_TEKTITE || +// effect->type == EFFECT_SPAWN_LIKE_LIKE || effect->type == EFFECT_SPAWN_CUCCO_STORM) { +// effect->category = "spawn"; +// } else { +// effect->category = "none"; +// effect->timeRemaining = 0; +// } - Player* player = GET_PLAYER(gPlayState); - - if (player != NULL) { - if (effectId == EFFECT_ADD_HEART_CONTAINER) { - if (gSaveContext.healthCapacity >= 0x140) { - return EffectResult::Failure; - } - - if (dryRun == 0) CMD_EXECUTE(EFFECT_ADD_HEART_CONTAINER); - return EffectResult::Success; - } else if (effectId == EFFECT_REMOVE_HEART_CONTAINER) { - if ((gSaveContext.healthCapacity - 0x10) <= 0) { - return EffectResult::Failure; - } - - if (dryRun == 0) CMD_EXECUTE(EFFECT_REMOVE_HEART_CONTAINER); - return EffectResult::Success; - } else if (effectId == EFFECT_FILL_MAGIC) { - if (!gSaveContext.isMagicAcquired) { - return EffectResult::Failure; - } - - if (gSaveContext.magic >= (gSaveContext.isDoubleMagicAcquired + 1) + 0x30) { - return EffectResult::Failure; - } - - if (dryRun == 0) CMD_EXECUTE(EFFECT_FILL_MAGIC); - return EffectResult::Success; - } else if (effectId == EFFECT_EMPTY_MAGIC) { - if (!gSaveContext.isMagicAcquired || gSaveContext.magic <= 0) { - return EffectResult::Failure; - } - - if (dryRun == 0) CMD_EXECUTE(EFFECT_EMPTY_MAGIC); - return EffectResult::Success; - } else if (effectId == EFFECT_ADD_RUPEES) { - if (dryRun == 0) CMD_EXECUTE(fmt::format("update_rupees {}", value)); - return EffectResult::Success; - } else if (effectId == EFFECT_REMOVE_RUPEES) { - if (gSaveContext.rupees - value < 0) { - return EffectResult::Failure; - } - - if (dryRun == 0) CMD_EXECUTE(fmt::format("update_rupees -{}", value)); - return EffectResult::Success; - } - } - - if (player != NULL && !Player_InBlockingCsMode(gPlayState, player) && gPlayState->pauseCtx.state == 0 - && gPlayState->msgCtx.msgMode == 0) { - if (effectId == EFFECT_HIGH_GRAVITY) { - if (dryRun == 0) CMD_EXECUTE("gravity 2"); - return EffectResult::Success; - } else if (effectId == EFFECT_LOW_GRAVITY) { - if (dryRun == 0) CMD_EXECUTE("gravity 0"); - return EffectResult::Success; - } else if (effectId == EFFECT_KILL - || effectId == EFFECT_FREEZE - || effectId == EFFECT_BURN - || effectId == EFFECT_ELECTROCUTE - || effectId == EFFECT_SPAWN_CUCCO_STORM - ) { - if (PlayerGrounded(player)) { - if (dryRun == 0) CMD_EXECUTE(fmt::format("{}", effectId)); - return EffectResult::Success; - } - return EffectResult::Failure; - } else if (effectId == EFFECT_HEAL - || effectId == EFFECT_KNOCKBACK - ) { - if (dryRun == 0) CMD_EXECUTE(fmt::format("{} {}", effectId, value)); - return EffectResult::Success; - } else if (effectId == EFFECT_GIANT_LINK - || effectId == EFFECT_MINISH_LINK - || effectId == EFFECT_NO_UI - || effectId == EFFECT_INVISIBLE_LINK - || effectId == EFFECT_PAPER_LINK - || effectId == EFFECT_NO_Z_TARGETING - || effectId == EFFECT_OHKO - || effectId == EFFECT_PACIFIST - || effectId == EFFECT_RAINSTORM - ) { - if (dryRun == 0) CMD_EXECUTE(fmt::format("{} 1", effectId)); - return EffectResult::Success; - } else if (effectId == EFFECT_REVERSE_CONTROLS) { - if (dryRun == 0) CMD_EXECUTE("reverse_controls 1"); - return EffectResult::Success; - } else if (effectId == EFFECT_IRON_BOOTS) { - if (dryRun == 0) CMD_EXECUTE("boots iron"); - return EffectResult::Success; - } else if (effectId == EFFECT_HOVER_BOOTS) { - if (dryRun == 0) CMD_EXECUTE("boots hover"); - return EffectResult::Success; - } else if (effectId == "give_dekushield") { - if (dryRun == 0) CMD_EXECUTE("givedekushield"); - return EffectResult::Success; - } else if (effectId == EFFECT_SPAWN_WALLMASTER - || effectId == EFFECT_SPAWN_ARWING - || effectId == EFFECT_SPAWN_DARK_LINK - || effectId == EFFECT_SPAWN_STALFOS - || effectId == EFFECT_SPAWN_WOLFOS - || effectId == EFFECT_SPAWN_FREEZARD - || effectId == EFFECT_SPAWN_KEESE - || effectId == EFFECT_SPAWN_ICE_KEESE - || effectId == EFFECT_SPAWN_FIRE_KEESE - || effectId == EFFECT_SPAWN_TEKTITE - || effectId == EFFECT_SPAWN_LIKE_LIKE - ) { - if (dryRun == 0) { - if (CrowdControl::SpawnEnemy(effectId)) { - return EffectResult::Success; - } else { - return EffectResult::Failure; - } - } - return EffectResult::Success; - } else if (effectId == EFFECT_INCREASE_SPEED) { - if (dryRun == 0) CMD_EXECUTE("speed_modifier 2"); - return EffectResult::Success; - } else if (effectId == EFFECT_DECREASE_SPEED) { - if (dryRun == 0) CMD_EXECUTE("speed_modifier -2"); - return EffectResult::Success; - } else if (effectId == EFFECT_DAMAGE_MULTIPLIER) { - if (dryRun == 0) CMD_EXECUTE(fmt::format("defense_modifier -{}", value)); - return EffectResult::Success; - } else if (effectId == EFFECT_DEFENSE_MULTIPLIER) { - if (dryRun == 0) CMD_EXECUTE(fmt::format("defense_modifier {}", value)); - return EffectResult::Success; - } else if (effectId == EFFECT_DAMAGE) { - if ((gSaveContext.health - (16 * value)) <= 0) { - return EffectResult::Failure; - } - - if (dryRun == 0) CMD_EXECUTE(fmt::format("{} {}", effectId, value)); - return EffectResult::Success; - } - } + return effect; +} - return EffectResult::Retry; +CrowdControl::EffectResult CrowdControl::ExecuteEffect(Effect *effect) { + return CrowdControl::EffectResult::Retry; } +//CrowdControl::EffectResult CrowdControl::ExecuteEffect(std::string effectId, uint32_t value, bool dryRun) { +// // Don't execute effect and don't advance timer when the player is not in a proper loaded savefile +// // and when they're busy dying. +// if (gPlayState == NULL || gPlayState->gameOverCtx.state > 0 || gSaveContext.fileNum < 0 || gSaveContext.fileNum > 2) { +// return EffectResult::Retry; +// } +// +// Player* player = GET_PLAYER(gPlayState); +// +// if (player != NULL) { +// if (effectId == EFFECT_ADD_HEART_CONTAINER) { +// if (gSaveContext.healthCapacity >= 0x140) { +// return EffectResult::Failure; +// } +// +// if (dryRun == 0) CMD_EXECUTE(EFFECT_ADD_HEART_CONTAINER); +// return EffectResult::Success; +// } else if (effectId == EFFECT_REMOVE_HEART_CONTAINER) { +// if ((gSaveContext.healthCapacity - 0x10) <= 0) { +// return EffectResult::Failure; +// } +// +// if (dryRun == 0) CMD_EXECUTE(EFFECT_REMOVE_HEART_CONTAINER); +// return EffectResult::Success; +// } else if (effectId == EFFECT_FILL_MAGIC) { +// if (!gSaveContext.isMagicAcquired) { +// return EffectResult::Failure; +// } +// +// if (gSaveContext.magic >= (gSaveContext.isDoubleMagicAcquired + 1) + 0x30) { +// return EffectResult::Failure; +// } +// +// if (dryRun == 0) CMD_EXECUTE(EFFECT_FILL_MAGIC); +// return EffectResult::Success; +// } else if (effectId == EFFECT_EMPTY_MAGIC) { +// if (!gSaveContext.isMagicAcquired || gSaveContext.magic <= 0) { +// return EffectResult::Failure; +// } +// +// if (dryRun == 0) CMD_EXECUTE(EFFECT_EMPTY_MAGIC); +// return EffectResult::Success; +// } else if (effectId == EFFECT_ADD_RUPEES) { +// if (dryRun == 0) CMD_EXECUTE(fmt::format("update_rupees {}", value)); +// return EffectResult::Success; +// } else if (effectId == EFFECT_REMOVE_RUPEES) { +// if (gSaveContext.rupees - value < 0) { +// return EffectResult::Failure; +// } +// +// if (dryRun == 0) CMD_EXECUTE(fmt::format("update_rupees -{}", value)); +// return EffectResult::Success; +// } +// } +// +// if (player != NULL && !Player_InBlockingCsMode(gPlayState, player) && gPlayState->pauseCtx.state == 0 +// && gPlayState->msgCtx.msgMode == 0) { +// if (effectId == EFFECT_NO_UI) { +// if (dryRun == 0) { +// GameInteractor::Instance->ApplyEffect(<#GameInteractionEffect effect#>) +// } +// } else if (effectId == EFFECT_HIGH_GRAVITY) { +// if (dryRun == 0) CMD_EXECUTE("gravity 2"); +// return EffectResult::Success; +// } else if (effectId == EFFECT_LOW_GRAVITY) { +// if (dryRun == 0) CMD_EXECUTE("gravity 0"); +// return EffectResult::Success; +// } else if (effectId == EFFECT_KILL +// || effectId == EFFECT_FREEZE +// || effectId == EFFECT_BURN +// || effectId == EFFECT_ELECTROCUTE +// || effectId == EFFECT_SPAWN_CUCCO_STORM +// ) { +// if (PlayerGrounded(player)) { +// if (dryRun == 0) CMD_EXECUTE(fmt::format("{}", effectId)); +// return EffectResult::Success; +// } +// return EffectResult::Failure; +// } else if (effectId == EFFECT_HEAL +// || effectId == EFFECT_KNOCKBACK +// ) { +// if (dryRun == 0) CMD_EXECUTE(fmt::format("{} {}", effectId, value)); +// return EffectResult::Success; +// } else if (effectId == EFFECT_GIANT_LINK +// || effectId == EFFECT_MINISH_LINK +// || effectId == EFFECT_INVISIBLE_LINK +// || effectId == EFFECT_PAPER_LINK +// || effectId == EFFECT_NO_Z_TARGETING +// || effectId == EFFECT_OHKO +// || effectId == EFFECT_PACIFIST +// || effectId == EFFECT_RAINSTORM +// ) { +// if (dryRun == 0) CMD_EXECUTE(fmt::format("{} 1", effectId)); +// return EffectResult::Success; +// } else if (effectId == EFFECT_REVERSE_CONTROLS) { +// if (dryRun == 0) CMD_EXECUTE("reverse_controls 1"); +// return EffectResult::Success; +// } else if (effectId == EFFECT_IRON_BOOTS) { +// if (dryRun == 0) CMD_EXECUTE("boots iron"); +// return EffectResult::Success; +// } else if (effectId == EFFECT_HOVER_BOOTS) { +// if (dryRun == 0) CMD_EXECUTE("boots hover"); +// return EffectResult::Success; +// } else if (effectId == "give_dekushield") { +// if (dryRun == 0) CMD_EXECUTE("givedekushield"); +// return EffectResult::Success; +// } else if (effectId == EFFECT_SPAWN_WALLMASTER +// || effectId == EFFECT_SPAWN_ARWING +// || effectId == EFFECT_SPAWN_DARK_LINK +// || effectId == EFFECT_SPAWN_STALFOS +// || effectId == EFFECT_SPAWN_WOLFOS +// || effectId == EFFECT_SPAWN_FREEZARD +// || effectId == EFFECT_SPAWN_KEESE +// || effectId == EFFECT_SPAWN_ICE_KEESE +// || effectId == EFFECT_SPAWN_FIRE_KEESE +// || effectId == EFFECT_SPAWN_TEKTITE +// || effectId == EFFECT_SPAWN_LIKE_LIKE +// ) { +// if (dryRun == 0) { +// if (CrowdControl::SpawnEnemy(effectId)) { +// return EffectResult::Success; +// } else { +// return EffectResult::Failure; +// } +// } +// return EffectResult::Success; +// } else if (effectId == EFFECT_INCREASE_SPEED) { +// if (dryRun == 0) CMD_EXECUTE("speed_modifier 2"); +// return EffectResult::Success; +// } else if (effectId == EFFECT_DECREASE_SPEED) { +// if (dryRun == 0) CMD_EXECUTE("speed_modifier -2"); +// return EffectResult::Success; +// } else if (effectId == EFFECT_DAMAGE_MULTIPLIER) { +// if (dryRun == 0) CMD_EXECUTE(fmt::format("defense_modifier -{}", value)); +// return EffectResult::Success; +// } else if (effectId == EFFECT_DEFENSE_MULTIPLIER) { +// if (dryRun == 0) CMD_EXECUTE(fmt::format("defense_modifier {}", value)); +// return EffectResult::Success; +// } else if (effectId == EFFECT_DAMAGE) { +// if ((gSaveContext.health - (16 * value)) <= 0) { +// return EffectResult::Failure; +// } +// +// if (dryRun == 0) CMD_EXECUTE(fmt::format("{} {}", effectId, value)); +// return EffectResult::Success; +// } +// } +// +// return EffectResult::Retry; +//} + bool CrowdControl::SpawnEnemy(std::string effectId) { Player* player = GET_PLAYER(gPlayState); @@ -540,46 +573,50 @@ bool CrowdControl::SpawnEnemy(std::string effectId) { } -void CrowdControl::RemoveEffect(std::string effectId) { - if (gPlayState == NULL) { - return; - } - - Player* player = GET_PLAYER(gPlayState); +void CrowdControl::RemoveEffect(Effect* effect) { - if (player != NULL) { - if (effectId == EFFECT_GIANT_LINK - || effectId == EFFECT_MINISH_LINK - || effectId == EFFECT_NO_UI - || effectId == EFFECT_INVISIBLE_LINK - || effectId == EFFECT_PAPER_LINK - || effectId == EFFECT_NO_Z_TARGETING - || effectId == EFFECT_OHKO - || effectId == EFFECT_PACIFIST - || effectId == EFFECT_RAINSTORM - ) { - CMD_EXECUTE(fmt::format("{} 0", effectId)); - return; - } else if (effectId == EFFECT_IRON_BOOTS || effectId == EFFECT_HOVER_BOOTS) { - CMD_EXECUTE("boots kokiri"); - return; - } else if (effectId == EFFECT_HIGH_GRAVITY || effectId == EFFECT_LOW_GRAVITY) { - CMD_EXECUTE("gravity 1"); - return; - } else if (effectId == EFFECT_REVERSE_CONTROLS) { - CMD_EXECUTE("reverse_controls 0"); - return; - } else if (effectId == EFFECT_INCREASE_SPEED - || effectId == EFFECT_DECREASE_SPEED - ) { - CMD_EXECUTE("speed_modifier 0"); - return; - } else if (effectId == EFFECT_DAMAGE_MULTIPLIER - || effectId == EFFECT_DEFENSE_MULTIPLIER - ) { - CMD_EXECUTE("defense_modifier 0"); - return; - } - } } + +//void CrowdControl::RemoveEffect(std::string effectId) { +// if (gPlayState == NULL) { +// return; +// } +// +// Player* player = GET_PLAYER(gPlayState); +// +// if (player != NULL) { +// if (effectId == EFFECT_GIANT_LINK +// || effectId == EFFECT_MINISH_LINK +// || effectId == EFFECT_NO_UI +// || effectId == EFFECT_INVISIBLE_LINK +// || effectId == EFFECT_PAPER_LINK +// || effectId == EFFECT_NO_Z_TARGETING +// || effectId == EFFECT_OHKO +// || effectId == EFFECT_PACIFIST +// || effectId == EFFECT_RAINSTORM +// ) { +// CMD_EXECUTE(fmt::format("{} 0", effectId)); +// return; +// } else if (effectId == EFFECT_IRON_BOOTS || effectId == EFFECT_HOVER_BOOTS) { +// CMD_EXECUTE("boots kokiri"); +// return; +// } else if (effectId == EFFECT_HIGH_GRAVITY || effectId == EFFECT_LOW_GRAVITY) { +// CMD_EXECUTE("gravity 1"); +// return; +// } else if (effectId == EFFECT_REVERSE_CONTROLS) { +// CMD_EXECUTE("reverse_controls 0"); +// return; +// } else if (effectId == EFFECT_INCREASE_SPEED +// || effectId == EFFECT_DECREASE_SPEED +// ) { +// CMD_EXECUTE("speed_modifier 0"); +// return; +// } else if (effectId == EFFECT_DAMAGE_MULTIPLIER +// || effectId == EFFECT_DEFENSE_MULTIPLIER +// ) { +// CMD_EXECUTE("defense_modifier 0"); +// return; +// } +// } +//} #endif diff --git a/soh/soh/Enhancements/crowd-control/CrowdControl.h b/soh/soh/Enhancements/crowd-control/CrowdControl.h index 6b1dfd4ee5d..3489f927e80 100644 --- a/soh/soh/Enhancements/crowd-control/CrowdControl.h +++ b/soh/soh/Enhancements/crowd-control/CrowdControl.h @@ -17,6 +17,8 @@ #include #include +#include "../game-interactor/GameInteractor.h" + class CrowdControl { private: enum EffectResult { @@ -61,10 +63,9 @@ class CrowdControl { typedef struct Effect { uint32_t id; - std::string type; - uint32_t value; std::string category; long timeRemaining; + GameInteractionEffectBase *giEffect; // Metadata used while executing (only for timed effects) bool isPaused; @@ -88,11 +89,13 @@ class CrowdControl { void ListenToServer(); void ProcessActiveEffects(); - void EmitMessage(TCPsocket socket, uint32_t eventId, long timeRemaining, - CrowdControl::EffectResult status); + void EmitMessage(TCPsocket socket, uint32_t eventId, long timeRemaining, EffectResult status); + void EmitMessage(TCPsocket socket, uint32_t eventId, long timeRemaining, GameInteractionEffectQueryResult status); Effect* ParseMessage(char payload[512]); - EffectResult ExecuteEffect(std::string effectId, uint32_t value, bool dryRun); - void RemoveEffect(std::string effectId); + EffectResult ExecuteEffect(Effect* effect); + void RemoveEffect(Effect* effect); +// EffectResult ExecuteEffect(std::string effectId, uint32_t value, bool dryRun); +// void RemoveEffect(std::string effectId); bool SpawnEnemy(std::string effectId); public: diff --git a/soh/soh/Enhancements/game-interactor/GameInteractionEffect.cpp b/soh/soh/Enhancements/game-interactor/GameInteractionEffect.cpp new file mode 100644 index 00000000000..87da428437f --- /dev/null +++ b/soh/soh/Enhancements/game-interactor/GameInteractionEffect.cpp @@ -0,0 +1,68 @@ +// +// GameInteractionEffect.cpp +// soh +// +// Created by David Chavez on 15.12.22. +// + +#include "GameInteractionEffect.h" +#include "GameInteractor.h" + +extern "C" { +#include +#include "variables.h" +#include "functions.h" +#include "macros.h" +extern PlayState* gPlayState; +} + +// Effect State + +uint32_t GameInteractor_NoUI; + +// AddHeartContainer + +namespace GameInteractionEffect { + GameInteractionEffectQueryResult AddHeartContainer::CanBeApplied() { + return gSaveContext.healthCapacity >= 0x140 + ? GameInteractionEffectQueryResult::NotPossibe + : GameInteractionEffectQueryResult::Possible; + } + + void AddHeartContainer::Apply() { + Health_GiveHearts(1); + } + + // RemoveHeartContainer + + GameInteractionEffectQueryResult RemoveHeartContainer::CanBeApplied() { + return ((gSaveContext.healthCapacity - 0x10) <= 0) + ? GameInteractionEffectQueryResult::NotPossibe + : GameInteractionEffectQueryResult::Possible; + } + + void RemoveHeartContainer::Apply() { + Health_RemoveHearts(1); + } + + // GiveRupees + + GameInteractionEffectQueryResult GiveRupees::CanBeApplied() { + return GameInteractionEffectQueryResult::Possible; + } + + void GiveRupees::Apply() { + Rupees_ChangeBy(amount); + } + + + // NoUIEffect + + GameInteractionEffectQueryResult NoUI::CanBeApplied() { + return GameInteractionEffectQueryResult::Possible; + } + + void NoUI::Apply() { + GameInteractor_NoUI = 1; + } +} diff --git a/soh/soh/Enhancements/game-interactor/GameInteractionEffect.h b/soh/soh/Enhancements/game-interactor/GameInteractionEffect.h new file mode 100644 index 00000000000..f70a18f815f --- /dev/null +++ b/soh/soh/Enhancements/game-interactor/GameInteractionEffect.h @@ -0,0 +1,67 @@ +// +// GameInteractionEffect.h +// soh +// +// Created by David Chavez on 15.12.22. +// + +#ifndef GameInteractionEffect_h +#define GameInteractionEffect_h + +#include + +#ifdef __cplusplus +extern "C" { +#endif +extern uint32_t GameInteractor_NoUI; +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +enum GameInteractionEffectQueryResult { + Possible = 0x00, + TemporarilyNotPossible = 0x01, + NotPossibe = 0xFF +}; + +class GameInteractionEffectBase { +public: + virtual GameInteractionEffectQueryResult CanBeApplied() = 0; + virtual void Apply() = 0; +}; + +namespace GameInteractionEffect { + class AddHeartContainer: public GameInteractionEffectBase { + GameInteractionEffectQueryResult CanBeApplied() override; + void Apply() override; + }; + + class RemoveHeartContainer: public GameInteractionEffectBase { + GameInteractionEffectQueryResult CanBeApplied() override; + void Apply() override; + }; + + class AddOrRemoveHeartContainer: public GameInteractionEffectBase { + int32_t amount; + + GameInteractionEffectQueryResult CanBeApplied() override; + void Apply() override; + }; + + class GiveRupees: public GameInteractionEffectBase { + public: + uint32_t amount; + + GameInteractionEffectQueryResult CanBeApplied() override; + void Apply() override; + }; + + class NoUI: public GameInteractionEffectBase { + GameInteractionEffectQueryResult CanBeApplied() override; + void Apply() override; + }; +} + +#endif /* __cplusplus */ +#endif /* GameInteractionEffect_h */ diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor.cpp b/soh/soh/Enhancements/game-interactor/GameInteractor.cpp new file mode 100644 index 00000000000..23ef5542a21 --- /dev/null +++ b/soh/soh/Enhancements/game-interactor/GameInteractor.cpp @@ -0,0 +1,16 @@ +// +// GameInteractor.cpp +// soh +// +// Created by David Chavez on 07.12.22. +// + +#include "GameInteractor.h" + +GameInteractionEffectQueryResult GameInteractor::CanApplyEffect(GameInteractionEffectBase effect) { + return effect.CanBeApplied(); +} + +void GameInteractor::ApplyEffect(GameInteractionEffectBase effect) { + return effect.Apply(); +} diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor.h b/soh/soh/Enhancements/game-interactor/GameInteractor.h new file mode 100644 index 00000000000..00fbeaa00c5 --- /dev/null +++ b/soh/soh/Enhancements/game-interactor/GameInteractor.h @@ -0,0 +1,27 @@ +// +// GameInteractor.h +// soh +// +// Created by David Chavez on 07.12.22. +// + +#ifndef GameInteractor_h +#define GameInteractor_h + +#include "GameInteractionEffect.h" + +#ifdef __cplusplus +class GameInteractor { +public: + static GameInteractor* Instance; + + static GameInteractionEffectQueryResult CanApplyEffect(GameInteractionEffectBase effect); + static void ApplyEffect(GameInteractionEffectBase effect); + static void RemoveEffect(); + + static bool CanSpawnEnemy(); + static void SpawnEnemy(); +}; + +#endif +#endif /* GameInteractor_h */ diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index d63aee91861..84080af97ef 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1,4 +1,4 @@ -#include "OTRGlobals.h" +#include "OTRGlobals.h" #include "OTRAudio.h" #include #include @@ -78,10 +78,13 @@ CrowdControl* CrowdControl::Instance; #endif +#include "Enhancements/game-interactor/GameInteractor.h" + OTRGlobals* OTRGlobals::Instance; SaveManager* SaveManager::Instance; CustomMessageManager* CustomMessageManager::Instance; ItemTableManager* ItemTableManager::Instance; +GameInteractor* GameInteractor::Instance; OTRGlobals::OTRGlobals() { std::vector OTRFiles; @@ -434,6 +437,7 @@ extern "C" void InitOTR() { SaveManager::Instance = new SaveManager(); CustomMessageManager::Instance = new CustomMessageManager(); ItemTableManager::Instance = new ItemTableManager(); + GameInteractor::Instance = new GameInteractor(); clearMtx = (uintptr_t)&gMtxClear; OTRMessage_Init(); diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 8295b0845fc..b4e5bf26f72 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -13,6 +13,7 @@ #endif #include "soh/Enhancements/debugconsole.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" static uint16_t _doActionTexWidth, _doActionTexHeight = -1; @@ -4962,7 +4963,7 @@ void Interface_Draw(PlayState* play) { s16 svar6; bool fullUi = !CVar_GetS32("gMinimalUI", 0) || !R_MINIMAP_DISABLED || play->pauseCtx.state != 0; - if (chaosEffectNoUI) { + if (GameInteractor_NoUI) { return; }