#include "GameInteractor.h" #include extern "C" { #include "variables.h" #include "macros.h" #include "functions.h" extern PlayState* gPlayState; } #include "overlays/actors/ovl_En_Niw/z_en_niw.h" void GameInteractor::RawAction::AddOrRemoveHealthContainers(int16_t amount) { gSaveContext.healthCapacity += amount * 0x10; } void GameInteractor::RawAction::AddOrRemoveMagic(int8_t amount) { // Full single magic = 48 // Full double magic = 96 int8_t currentMagicCapacity = (gSaveContext.isDoubleMagicAcquired + 1) * 48; if (gSaveContext.isMagicAcquired) { gSaveContext.prevMagicState = gSaveContext.magicState; if (amount > 0) { if (gSaveContext.magic + amount > currentMagicCapacity) { gSaveContext.magicFillTarget = currentMagicCapacity; } else { gSaveContext.magicFillTarget = gSaveContext.magic + amount; } gSaveContext.magicState = MAGIC_STATE_FILL; } else if (amount < 0) { if (gSaveContext.magic + amount < 0) { gSaveContext.magic = 0; } else { gSaveContext.magic += amount; } } } } void GameInteractor::RawAction::HealOrDamagePlayer(int16_t hearts) { if (hearts > 0) { Health_ChangeBy(gPlayState, hearts * 0x10); } else if (hearts < 0) { Player* player = GET_PLAYER(gPlayState); Health_ChangeBy(gPlayState, hearts * 0x10); func_80837C0C(gPlayState, player, 0, 0, 0, 0, 0); player->invincibilityTimer = 28; } } void GameInteractor::RawAction::SetPlayerHealth(int16_t hearts) { gSaveContext.health = hearts * 0x10; } void GameInteractor::RawAction::SetLinkInvisibility(bool active) { GameInteractor::State::InvisibleLinkActive = active; if (!active) { Player* player = GET_PLAYER(gPlayState); player->actor.shape.shadowDraw = ActorShadow_DrawFeet; } } void GameInteractor::RawAction::SetWeatherStorm(bool active) { if (active) { gPlayState->envCtx.unk_F2[0] = 20; // rain intensity target gPlayState->envCtx.gloomySkyMode = 1; // start gloomy sky if ((gWeatherMode != 0) || gPlayState->envCtx.unk_17 != 0) { gPlayState->envCtx.unk_DE = 1; } gPlayState->envCtx.lightningMode = LIGHTNING_MODE_ON; Environment_PlayStormNatureAmbience(gPlayState); } else { gPlayState->envCtx.unk_F2[0] = 0; if (gPlayState->csCtx.state == CS_STATE_IDLE) { Environment_StopStormNatureAmbience(gPlayState); } else if (func_800FA0B4(SEQ_PLAYER_BGM_MAIN) == NA_BGM_NATURE_AMBIENCE) { Audio_SetNatureAmbienceChannelIO(NATURE_CHANNEL_LIGHTNING, CHANNEL_IO_PORT_1, 0); Audio_SetNatureAmbienceChannelIO(NATURE_CHANNEL_RAIN, CHANNEL_IO_PORT_1, 0); } osSyncPrintf("\n\n\nE_wether_flg=[%d]", gWeatherMode); osSyncPrintf("\nrain_evt_trg=[%d]\n\n", gPlayState->envCtx.gloomySkyMode); if (gWeatherMode == 0 && (gPlayState->envCtx.gloomySkyMode == 1)) { gPlayState->envCtx.gloomySkyMode = 2; // end gloomy sky } else { gPlayState->envCtx.gloomySkyMode = 0; gPlayState->envCtx.unk_DE = 0; } gPlayState->envCtx.lightningMode = LIGHTNING_MODE_LAST; } } void GameInteractor::RawAction::ForceEquipBoots(int8_t boots) { Player* player = GET_PLAYER(gPlayState); player->currentBoots = boots; Inventory_ChangeEquipment(EQUIP_BOOTS, boots + 1); Player_SetBootData(gPlayState, player); } void GameInteractor::RawAction::FreezePlayer() { gSaveContext.pendingIceTrapCount++; } void GameInteractor::RawAction::BurnPlayer() { Player* player = GET_PLAYER(gPlayState); for (int i = 0; i < 18; i++) { player->flameTimers[i] = Rand_S16Offset(0, 200); } player->isBurning = true; func_80837C0C(gPlayState, player, 0, 0, 0, 0, 0); } void GameInteractor::RawAction::ElectrocutePlayer() { Player* player = GET_PLAYER(gPlayState); func_80837C0C(gPlayState, player, 4, 0, 0, 0, 0); } void GameInteractor::RawAction::KnockbackPlayer(float strength) { Player* player = GET_PLAYER(gPlayState); func_8002F71C(gPlayState, &player->actor, strength * 5, player->actor.world.rot.y + 0x8000, strength * 5); } void GameInteractor::RawAction::GiveDekuShield() { // Give Deku Shield to the player, and automatically equip it when they're child and have no shield currently equiped. Player* player = GET_PLAYER(gPlayState); Item_Give(gPlayState, ITEM_SHIELD_DEKU); if (LINK_IS_CHILD && player->currentShield == PLAYER_SHIELD_NONE) { player->currentShield = PLAYER_SHIELD_DEKU; Inventory_ChangeEquipment(EQUIP_SHIELD, PLAYER_SHIELD_DEKU); } } void GameInteractor::RawAction::SpawnCuccoStorm() { Player* player = GET_PLAYER(gPlayState); EnNiw* cucco = (EnNiw*)Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_EN_NIW, player->actor.world.pos.x, player->actor.world.pos.y + 2200, player->actor.world.pos.z, 0, 0, 0, 0, 0); cucco->actionFunc = func_80AB70A0_nocutscene; } void GameInteractor::RawAction::ForceInterfaceUpdate() { gSaveContext.unk_13E8 = 50; Interface_Update(gPlayState); } GameInteractionEffectQueryResult GameInteractor::RawAction::SpawnEnemyWithOffset(uint32_t enemyId, int32_t enemyParams) { if (!GameInteractor::CanSpawnEnemy()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } Player* player = GET_PLAYER(gPlayState); float posXOffset = 0; float posYOffset = 0; float posZOffset = 0; if (enemyId == ACTOR_EN_WALLMAS) { } else if (enemyId == ACTOR_EN_CLEAR_TAG) { // Don't allow Arwings in certain areas because they cause issues. // Locations: King dodongo room, Morpha room, Twinrova room, Ganondorf room, Fishing pond, Ganon's room // TODO: Swap this to disabling the option in CC options menu instead. if (gPlayState->sceneNum == SCENE_DDAN_BOSS || gPlayState->sceneNum == SCENE_MIZUSIN_BS || gPlayState->sceneNum == SCENE_JYASINBOSS || gPlayState->sceneNum == SCENE_GANON_BOSS || gPlayState->sceneNum == SCENE_TURIBORI || gPlayState->sceneNum == SCENE_GANON_DEMO) { return GameInteractionEffectQueryResult::NotPossible; } posYOffset = 100; } else if (enemyId == ACTOR_EN_TORCH2) { posXOffset = 75; posYOffset = 50; } else if (enemyId == ACTOR_EN_TEST) { posXOffset = 75; posYOffset = 50; } else if (enemyId == ACTOR_EN_WF) { posXOffset = 75; posYOffset = 50; } else if (enemyId == ACTOR_EN_FZ) { posXOffset = 75; posYOffset = 50; } else if (enemyId == ACTOR_EN_FIREFLY) { posXOffset = 75; posYOffset = 50; } else if (enemyId == ACTOR_EN_TITE) { posXOffset = 75; posYOffset = 50; } else if (enemyId == ACTOR_EN_RR) { posXOffset = 75; posYOffset = 50; } if (Actor_Spawn(&gPlayState->actorCtx, gPlayState, enemyId, player->actor.world.pos.x + posXOffset, player->actor.world.pos.y + posYOffset, player->actor.world.pos.z + posZOffset, 0, 0, 0, enemyParams, 0) != NULL) { return GameInteractionEffectQueryResult::Possible; } return GameInteractionEffectQueryResult::TemporarilyNotPossible; }