200 lines
7.3 KiB
C++
200 lines
7.3 KiB
C++
#include "GameInteractor.h"
|
|
#include <libultraship/bridge.h>
|
|
|
|
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;
|
|
}
|