mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2024-11-22 01:12:19 -05:00
VBify (#4255)
* Convert ocarina buttons & skip scarecrow song to VB * Move most of boss rush & rupee/key counters to VB * Move BossRush_HandleCompleteBoss to VB * Convert boss timestamps to VB * Move being able to open doors to VB * Convert Entrance_OverrideWeatherState to VB * Move boss souls to hook_handlers.cpp * Update hook_handlers.cpp * Move infinite upgrades to hook_handlers.cpp * Move skeleton key to hook_handlers.cpp * Move swim and child wallet to hook_handlers.cpp * Move ganons boss key to hook_handlers.cpp * Move triforce hunt to hook_handlers.cpp * Move randomizer sheik spawn to hook_handlers.cpp * Update BossRush.h * Convert spoiling items to VB * Move load game stuff to hook_handlers.cpp * Move warp song handling to hook_handlers.cpp * Convert being able to play bowling to VB * Move shooting gallery man handling to hook_handlers.cpp * Move spirit temple silver block removal to hook_handlers.cpp * Fix build * Move last beehive stuff to hook_handlers.cpp * Fix build * Add VB_CLOSE_PAUSE_MENU * Add VB_BE_ABLE_TO_SAVE * Add VB_RENDER_YES_ON_CONTINUE_PROMPT * Add VB_SPAWN_BLUE_WARP * Add VB_BLUE_WARP_ADULT_WARP_OUT * Add VB_BG_BREAKWALL_BREAK * Convert Saria stuff to VB * Remove now unused check * Add VB_GANON_HEAL_BEFORE_FIGHT * Update hook_handlers.cpp * Fix blue warp offsets * Fixes from review * Improve documentation * Update BossRush.cpp * Fix my stupidity * Fix #4327 * Update hook_handlers.cpp * Fix blue warps * Use ultralib types & clean header * Replace options amount macro with BR_OPTIONS_MAX * Remove unused includes * Remove accidental line doubling * Tweaks to boss rush (#6) * Update GameInteractor_HookTable.h --------- Co-authored-by: Garrett Cox <garrettjcox@gmail.com>
This commit is contained in:
parent
7450cee0b2
commit
2822dfc3f3
@ -276,7 +276,7 @@ typedef struct {
|
||||
/* */ u16 pendingSaleMod;
|
||||
/* */ uint8_t questId;
|
||||
/* */ uint32_t isBossRushPaused;
|
||||
/* */ uint8_t bossRushOptions[BOSSRUSH_OPTIONS_AMOUNT];
|
||||
/* */ uint8_t bossRushOptions[BR_OPTIONS_MAX];
|
||||
/* */ u8 pendingIceTrapCount;
|
||||
/* */ SohStats sohStats;
|
||||
/* */ FaroresWindData backupFW;
|
||||
|
@ -1,19 +1,33 @@
|
||||
#include "BossRush.h"
|
||||
#include "soh/OTRGlobals.h"
|
||||
#include "functions.h"
|
||||
#include "macros.h"
|
||||
#include "variables.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
extern "C" {
|
||||
#include "functions.h"
|
||||
#include "macros.h"
|
||||
#include "variables.h"
|
||||
#include "src/overlays/actors/ovl_Boss_Goma/z_boss_goma.h"
|
||||
#include "src/overlays/actors/ovl_Boss_Mo/z_boss_mo.h"
|
||||
#include "src/overlays/actors/ovl_Door_Warp1/z_door_warp1.h"
|
||||
extern PlayState* gPlayState;
|
||||
|
||||
Gfx* KaleidoScope_QuadTextureIA8(Gfx* gfx, void* texture, s16 width, s16 height, u16 point);
|
||||
#include "textures/icon_item_nes_static/icon_item_nes_static.h"
|
||||
#include "textures/icon_item_ger_static/icon_item_ger_static.h"
|
||||
#include "textures/icon_item_fra_static/icon_item_fra_static.h"
|
||||
}
|
||||
|
||||
typedef struct BossRushSetting {
|
||||
std::array<std::string, LANGUAGE_MAX> name;
|
||||
std::vector<std::array<std::string, LANGUAGE_MAX>> choices;
|
||||
} BossRushSetting;
|
||||
|
||||
BossRushSetting BossRushOptions[BOSSRUSH_OPTIONS_AMOUNT] = {
|
||||
BossRushSetting BossRushOptions[BR_OPTIONS_MAX] = {
|
||||
{
|
||||
{ "BOSSES:", "BOSSE:", "BOSS:" },
|
||||
{
|
||||
@ -112,15 +126,15 @@ BossRushSetting BossRushOptions[BOSSRUSH_OPTIONS_AMOUNT] = {
|
||||
}
|
||||
};
|
||||
|
||||
const char* BossRush_GetSettingName(uint8_t optionIndex, uint8_t language) {
|
||||
const char* BossRush_GetSettingName(u8 optionIndex, u8 language) {
|
||||
return BossRushOptions[optionIndex].name[language].c_str();
|
||||
}
|
||||
|
||||
const char* BossRush_GetSettingChoiceName(uint8_t optionIndex, uint8_t choiceIndex, uint8_t language) {
|
||||
const char* BossRush_GetSettingChoiceName(u8 optionIndex, u8 choiceIndex, u8 language) {
|
||||
return BossRushOptions[optionIndex].choices[choiceIndex][language].c_str();
|
||||
}
|
||||
|
||||
uint8_t BossRush_GetSettingOptionsAmount(uint8_t optionIndex) {
|
||||
u8 BossRush_GetSettingOptionsAmount(u8 optionIndex) {
|
||||
return BossRushOptions[optionIndex].choices.size();
|
||||
}
|
||||
|
||||
@ -168,8 +182,44 @@ void BossRush_SpawnBlueWarps(PlayState* play) {
|
||||
}
|
||||
}
|
||||
|
||||
void BossRush_HandleBlueWarp(PlayState* play, f32 warpPosX, f32 warpPosZ) {
|
||||
void BossRush_SetEquipment(u8 linkAge) {
|
||||
std::array<u8, 8> brButtonItems;
|
||||
std::array<u8, 7> brCButtonSlots;
|
||||
|
||||
// Set Child Equipment.
|
||||
if (linkAge == LINK_AGE_CHILD) {
|
||||
brButtonItems = {
|
||||
ITEM_SWORD_KOKIRI, ITEM_STICK, ITEM_NUT, ITEM_BOMB, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE
|
||||
};
|
||||
|
||||
brCButtonSlots = { SLOT_STICK, SLOT_NUT, SLOT_BOMB, SLOT_NONE, SLOT_NONE, SLOT_NONE, SLOT_NONE };
|
||||
|
||||
Inventory_ChangeEquipment(EQUIP_TYPE_SWORD, EQUIP_VALUE_SWORD_KOKIRI);
|
||||
Inventory_ChangeEquipment(EQUIP_TYPE_SHIELD, EQUIP_VALUE_SHIELD_DEKU);
|
||||
// Set Adult equipment.
|
||||
} else {
|
||||
brButtonItems = { ITEM_SWORD_MASTER, ITEM_BOW, ITEM_HAMMER, ITEM_BOMB,
|
||||
ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE };
|
||||
|
||||
brCButtonSlots = { SLOT_BOW, SLOT_HAMMER, SLOT_BOMB, SLOT_NONE, SLOT_NONE, SLOT_NONE, SLOT_NONE };
|
||||
|
||||
Inventory_ChangeEquipment(EQUIP_TYPE_SWORD, EQUIP_VALUE_SWORD_MASTER);
|
||||
Inventory_ChangeEquipment(EQUIP_TYPE_SHIELD, EQUIP_VALUE_SHIELD_MIRROR);
|
||||
Inventory_ChangeEquipment(EQUIP_TYPE_TUNIC, EQUIP_VALUE_TUNIC_GORON);
|
||||
}
|
||||
|
||||
// Button Items
|
||||
for (int button = 0; button < ARRAY_COUNT(gSaveContext.equips.buttonItems); button++) {
|
||||
gSaveContext.equips.buttonItems[button] = brButtonItems[button];
|
||||
}
|
||||
|
||||
// C buttons
|
||||
for (int button = 0; button < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); button++) {
|
||||
gSaveContext.equips.cButtonSlots[button] = brCButtonSlots[button];
|
||||
}
|
||||
}
|
||||
|
||||
void BossRush_HandleBlueWarp(PlayState* play, f32 warpPosX, f32 warpPosZ) {
|
||||
// If warping from Chamber of Sages, choose the correct boss room to teleport to.
|
||||
if (play->sceneNum == SCENE_CHAMBER_OF_THE_SAGES) {
|
||||
// Gohma & Phantom Ganon
|
||||
@ -202,10 +252,13 @@ void BossRush_HandleBlueWarp(PlayState* play, f32 warpPosX, f32 warpPosZ) {
|
||||
// Ganondork
|
||||
} else if (warpPosX == -199 && warpPosZ == 0) {
|
||||
play->nextEntranceIndex = ENTR_GANONDORF_BOSS_0;
|
||||
} else {
|
||||
SPDLOG_ERROR("[BossRush]: Unknown blue warp in chamber of sages at position ({}, {}). Warping back to chamber of sages.", warpPosX, warpPosZ);
|
||||
play->nextEntranceIndex = ENTR_CHAMBER_OF_THE_SAGES_0;
|
||||
}
|
||||
// If coming from a boss room, teleport back to Chamber of Sages and set flag.
|
||||
} else {
|
||||
play->nextEntranceIndex = SCENE_HAIRAL_NIWA2;
|
||||
play->nextEntranceIndex = ENTR_CHAMBER_OF_THE_SAGES_0;
|
||||
|
||||
if (CheckDungeonCount() == 3) {
|
||||
play->linkAgeOnLoad = LINK_AGE_ADULT;
|
||||
@ -223,6 +276,10 @@ void BossRush_HandleBlueWarp(PlayState* play, f32 warpPosX, f32 warpPosZ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
play->transitionTrigger = TRANS_TRIGGER_START;
|
||||
play->transitionType = TRANS_TYPE_FADE_WHITE;
|
||||
gSaveContext.nextTransitionType = TRANS_TYPE_FADE_WHITE_SLOW;
|
||||
}
|
||||
|
||||
void BossRush_HandleBlueWarpHeal(PlayState* play) {
|
||||
@ -235,10 +292,6 @@ void BossRush_HandleBlueWarpHeal(PlayState* play) {
|
||||
}
|
||||
|
||||
void BossRush_HandleCompleteBoss(PlayState* play) {
|
||||
if (!IS_BOSS_RUSH) {
|
||||
return;
|
||||
}
|
||||
|
||||
gSaveContext.isBossRushPaused = 1;
|
||||
switch (play->sceneNum) {
|
||||
case SCENE_DEKU_TREE_BOSS:
|
||||
@ -308,7 +361,7 @@ void BossRush_InitSave() {
|
||||
}
|
||||
|
||||
// Set health
|
||||
uint16_t health = 16;
|
||||
u16 health = 16;
|
||||
switch (gSaveContext.bossRushOptions[BR_OPTIONS_HEARTS]) {
|
||||
case BR_CHOICE_HEARTS_7:
|
||||
health *= 7;
|
||||
@ -418,7 +471,7 @@ void BossRush_InitSave() {
|
||||
}
|
||||
|
||||
// Upgrades
|
||||
uint8_t upgradeLevel = 1;
|
||||
u8 upgradeLevel = 1;
|
||||
if (gSaveContext.bossRushOptions[BR_OPTIONS_AMMO] == BR_CHOICE_AMMO_MAXED) {
|
||||
upgradeLevel = 3;
|
||||
}
|
||||
@ -450,40 +503,209 @@ void BossRush_InitSave() {
|
||||
}
|
||||
}
|
||||
|
||||
void BossRush_SetEquipment(uint8_t linkAge) {
|
||||
|
||||
std::array<u8, 8> brButtonItems;
|
||||
std::array<u8, 7> brCButtonSlots;
|
||||
|
||||
// Set Child Equipment.
|
||||
if (linkAge == LINK_AGE_CHILD) {
|
||||
brButtonItems = {
|
||||
ITEM_SWORD_KOKIRI, ITEM_STICK, ITEM_NUT, ITEM_BOMB, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE
|
||||
static void* sSavePromptNoChoiceTexs[] = {
|
||||
(void*)gPauseNoENGTex,
|
||||
(void*)gPauseNoGERTex,
|
||||
(void*)gPauseNoFRATex
|
||||
};
|
||||
|
||||
brCButtonSlots = { SLOT_STICK, SLOT_NUT, SLOT_BOMB, SLOT_NONE, SLOT_NONE, SLOT_NONE, SLOT_NONE };
|
||||
void BossRush_OnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, void* optionalArg) {
|
||||
switch (id) {
|
||||
// Allow not healing before ganon
|
||||
case VB_GANON_HEAL_BEFORE_FIGHT: {
|
||||
if (gSaveContext.bossRushOptions[BR_OPTIONS_HEAL] == BR_CHOICE_HEAL_NEVER) {
|
||||
*should = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Replace the blue warp transitions with ones that lead back to the chamber of sages
|
||||
case VB_BLUE_WARP_APPLY_ENTRANCE_AND_CUTSCENE: {
|
||||
DoorWarp1* blueWarp = static_cast<DoorWarp1*>(optionalArg);
|
||||
BossRush_HandleBlueWarp(gPlayState, blueWarp->actor.world.pos.x, blueWarp->actor.world.pos.z);
|
||||
*should = false;
|
||||
break;
|
||||
}
|
||||
// Spawn clean blue warps (no ruto, adult animation, etc)
|
||||
case VB_SPAWN_BLUE_WARP: {
|
||||
switch (gPlayState->sceneNum) {
|
||||
case SCENE_DEKU_TREE_BOSS: {
|
||||
BossGoma* bossGoma = static_cast<BossGoma*>(optionalArg);
|
||||
static Vec3f roomCenter = { -150.0f, 0.0f, -350.0f };
|
||||
Vec3f childPos = roomCenter;
|
||||
|
||||
Inventory_ChangeEquipment(EQUIP_TYPE_SWORD, EQUIP_VALUE_SWORD_KOKIRI);
|
||||
Inventory_ChangeEquipment(EQUIP_TYPE_SHIELD, EQUIP_VALUE_SHIELD_DEKU);
|
||||
// Set Adult equipment.
|
||||
for (s32 i = 0; i < 10000; i++) {
|
||||
if ((fabsf(childPos.x - GET_PLAYER(gPlayState)->actor.world.pos.x) < 100.0f &&
|
||||
fabsf(childPos.z - GET_PLAYER(gPlayState)->actor.world.pos.z) < 100.0f) ||
|
||||
(fabsf(childPos.x - bossGoma->actor.world.pos.x) < 150.0f &&
|
||||
fabsf(childPos.z - bossGoma->actor.world.pos.z) < 150.0f)) {
|
||||
childPos.x = Rand_CenteredFloat(400.0f) + -150.0f;
|
||||
childPos.z = Rand_CenteredFloat(400.0f) + -350.0f;
|
||||
} else {
|
||||
brButtonItems = { ITEM_SWORD_MASTER, ITEM_BOW, ITEM_HAMMER, ITEM_BOMB,
|
||||
ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE };
|
||||
|
||||
brCButtonSlots = { SLOT_BOW, SLOT_HAMMER, SLOT_BOMB, SLOT_NONE, SLOT_NONE, SLOT_NONE, SLOT_NONE };
|
||||
|
||||
Inventory_ChangeEquipment(EQUIP_TYPE_SWORD, EQUIP_VALUE_SWORD_MASTER);
|
||||
Inventory_ChangeEquipment(EQUIP_TYPE_SHIELD, EQUIP_VALUE_SHIELD_MIRROR);
|
||||
Inventory_ChangeEquipment(EQUIP_TYPE_TUNIC, EQUIP_VALUE_TUNIC_GORON);
|
||||
}
|
||||
|
||||
// Button Items
|
||||
for (int button = 0; button < ARRAY_COUNT(gSaveContext.equips.buttonItems); button++) {
|
||||
gSaveContext.equips.buttonItems[button] = brButtonItems[button];
|
||||
}
|
||||
|
||||
// C buttons
|
||||
for (int button = 0; button < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); button++) {
|
||||
gSaveContext.equips.cButtonSlots[button] = brCButtonSlots[button];
|
||||
break;
|
||||
}
|
||||
}
|
||||
Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_DOOR_WARP1, childPos.x, bossGoma->actor.world.pos.y, childPos.z, 0, 0, 0, WARP_DUNGEON_ADULT, false);
|
||||
break;
|
||||
}
|
||||
case SCENE_DODONGOS_CAVERN_BOSS: {
|
||||
Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_DOOR_WARP1, -890.0f, -1523.76f, -3304.0f, 0, 0, 0, WARP_DUNGEON_ADULT, false);
|
||||
break;
|
||||
}
|
||||
case SCENE_JABU_JABU_BOSS: {
|
||||
static Vec3f sWarpPos[] = {
|
||||
{ 10.0f, 0.0f, 30.0f },
|
||||
{ 260.0f, 0.0f, -470.0f },
|
||||
{ -240.0f, 0.0f, -470.0f },
|
||||
};
|
||||
|
||||
s32 sp7C = 2;
|
||||
for (s32 i = 2; i > 0; i -= 1) {
|
||||
if (Math_Vec3f_DistXYZ(&sWarpPos[i], &GET_PLAYER(gPlayState)->actor.world.pos) <
|
||||
Math_Vec3f_DistXYZ(&sWarpPos[i - 1], &GET_PLAYER(gPlayState)->actor.world.pos)) {
|
||||
sp7C = i - 1;
|
||||
}
|
||||
}
|
||||
|
||||
Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_DOOR_WARP1, sWarpPos[sp7C].x, sWarpPos[sp7C].y, sWarpPos[sp7C].z, 0, 0, 0, WARP_DUNGEON_ADULT, false);
|
||||
break;
|
||||
}
|
||||
case SCENE_FOREST_TEMPLE_BOSS: {
|
||||
Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_DOOR_WARP1, 14.0f, -33.0f, -3315.0f, 0, 0, 0, WARP_DUNGEON_ADULT, true);
|
||||
break;
|
||||
}
|
||||
case SCENE_FIRE_TEMPLE_BOSS: {
|
||||
Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_DOOR_WARP1, 0.0f, 100.0f, 0.0f, 0, 0, 0, WARP_DUNGEON_ADULT, true);
|
||||
break;
|
||||
}
|
||||
case SCENE_WATER_TEMPLE_BOSS: {
|
||||
BossMo* bossMo = static_cast<BossMo*>(optionalArg);
|
||||
Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_DOOR_WARP1, bossMo->actor.world.pos.x, -280.0f, bossMo->actor.world.pos.z, 0, 0, 0, WARP_DUNGEON_ADULT, true);
|
||||
break;
|
||||
}
|
||||
case SCENE_SPIRIT_TEMPLE_BOSS: {
|
||||
Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_DOOR_WARP1, 600.0f, 230.0f, 0.0f, 0, 0, 0, WARP_DUNGEON_ADULT, true);
|
||||
break;
|
||||
}
|
||||
case SCENE_SHADOW_TEMPLE_BOSS: {
|
||||
Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_DOOR_WARP1, -50.0f, 0.0f, 400.0f, 0, 0, 0, WARP_DUNGEON_ADULT, true);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
SPDLOG_WARN("[BossRush]: Blue warp spawned in unhandled scene, ignoring");
|
||||
return;
|
||||
}
|
||||
}
|
||||
*should = false;
|
||||
break;
|
||||
}
|
||||
// Skip past the "Save?" window when pressing B while paused and instead close the menu.
|
||||
case VB_CLOSE_PAUSE_MENU: {
|
||||
if (CHECK_BTN_ALL(gPlayState->state.input[0].press.button, BTN_B)) {
|
||||
*should = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Show "No" twice because the player can't continue.
|
||||
case VB_RENDER_YES_ON_CONTINUE_PROMPT: {
|
||||
Gfx** disp = static_cast<Gfx**>(optionalArg);
|
||||
*disp = KaleidoScope_QuadTextureIA8(*disp, sSavePromptNoChoiceTexs[gSaveContext.language], 48, 16, 12);
|
||||
*should = false;
|
||||
break;
|
||||
}
|
||||
// Break the dodongo breakable floor immediately so the player can jump in the hole immediately.
|
||||
case VB_BG_BREAKWALL_BREAK: {
|
||||
*should = true;
|
||||
break;
|
||||
}
|
||||
// Skip past the "Save?" window when dying and go to the "Continue?" screen immediately.
|
||||
case VB_TRANSITION_TO_SAVE_SCREEN_ON_DEATH: {
|
||||
PauseContext* pauseCtx = static_cast<PauseContext*>(optionalArg);
|
||||
pauseCtx->state = 0xF;
|
||||
*should = false;
|
||||
break;
|
||||
}
|
||||
// Prevent saving
|
||||
case VB_BE_ABLE_TO_SAVE:
|
||||
// Disable doors so the player can't leave the boss rooms backwards.
|
||||
case VB_BE_ABLE_TO_OPEN_DOORS:
|
||||
// There's no heart containers in boss rush
|
||||
case VB_SPAWN_HEART_CONTAINER:
|
||||
// Rupees are useless in boss rush
|
||||
case VB_RENDER_RUPEE_COUNTER: {
|
||||
*should = false;
|
||||
break;
|
||||
}
|
||||
// Prevent warning spam
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BossRush_OnActorInitHandler(void* actorRef) {
|
||||
Actor* actor = static_cast<Actor*>(actorRef);
|
||||
|
||||
if (actor->id == ACTOR_DEMO_SA && gPlayState->sceneNum == SCENE_CHAMBER_OF_THE_SAGES) {
|
||||
BossRush_SpawnBlueWarps(gPlayState);
|
||||
Actor_Kill(actor);
|
||||
GET_PLAYER(gPlayState)->actor.world.rot.y = GET_PLAYER(gPlayState)->actor.shape.rot.y = 27306;
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove chests, mainly for the chest in King Dodongo's boss room.
|
||||
// Remove bushes, used in Gohma's arena.
|
||||
// Remove pots, used in Barinade's and Ganondorf's arenas.
|
||||
if (actor->id == ACTOR_EN_KUSA || actor->id == ACTOR_OBJ_TSUBO || actor->id == ACTOR_EN_BOX) {
|
||||
Actor_Kill(actor);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void BossRush_OnSceneInitHandler(s16 sceneNum) {
|
||||
// Unpause the timer when the scene loaded isn't the Chamber of Sages.
|
||||
if (sceneNum != SCENE_CHAMBER_OF_THE_SAGES) {
|
||||
gSaveContext.isBossRushPaused = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void BossRush_OnBossDefeatHandler(void* refActor) {
|
||||
BossRush_HandleCompleteBoss(gPlayState);
|
||||
}
|
||||
|
||||
void BossRush_OnBlueWarpUpdate(void* actor) {
|
||||
DoorWarp1* blueWarp = static_cast<DoorWarp1*>(actor);
|
||||
|
||||
if (blueWarp->warpTimer > 160) {
|
||||
BossRush_HandleBlueWarp(gPlayState, blueWarp->actor.world.pos.x, blueWarp->actor.world.pos.z);
|
||||
}
|
||||
}
|
||||
|
||||
void BossRush_RegisterHooks() {
|
||||
static u32 onVanillaBehaviorHook = 0;
|
||||
static u32 onSceneInitHook = 0;
|
||||
static u32 onActorInitHook = 0;
|
||||
static u32 onBossDefeatHook = 0;
|
||||
static u32 onActorUpdate = 0;
|
||||
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnLoadGame>([](int32_t fileNum) {
|
||||
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnVanillaBehavior>(onVanillaBehaviorHook);
|
||||
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnSceneInit>(onSceneInitHook);
|
||||
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnActorInit>(onActorInitHook);
|
||||
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnBossDefeat>(onBossDefeatHook);
|
||||
GameInteractor::Instance->UnregisterGameHookForID<GameInteractor::OnActorUpdate>(onActorUpdate);
|
||||
|
||||
onVanillaBehaviorHook = 0;
|
||||
onSceneInitHook = 0;
|
||||
onActorInitHook = 0;
|
||||
onBossDefeatHook = 0;
|
||||
onActorUpdate = 0;
|
||||
|
||||
if (!IS_BOSS_RUSH) return;
|
||||
|
||||
onVanillaBehaviorHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnVanillaBehavior>(BossRush_OnVanillaBehaviorHandler);
|
||||
onSceneInitHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>(BossRush_OnSceneInitHandler);
|
||||
onActorInitHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorInit>(BossRush_OnActorInitHandler);
|
||||
onBossDefeatHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnBossDefeat>(BossRush_OnBossDefeatHandler);
|
||||
onActorUpdate = GameInteractor::Instance->RegisterGameHookForID<GameInteractor::OnActorUpdate>(ACTOR_DOOR_WARP1, BossRush_OnBlueWarpUpdate);
|
||||
});
|
||||
}
|
@ -1,20 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "BossRushTypes.h"
|
||||
#include "variables.h"
|
||||
#include "z64.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void BossRush_SpawnBlueWarps(PlayState* play);
|
||||
void BossRush_HandleBlueWarp(PlayState* play, f32 warpPosX, f32 warpPosZ);
|
||||
void BossRush_HandleBlueWarpHeal(PlayState* play);
|
||||
void BossRush_InitSave();
|
||||
void BossRush_SetEquipment(uint8_t linkAge);
|
||||
void BossRush_HandleCompleteBoss(PlayState* play);
|
||||
const char* BossRush_GetSettingName(uint8_t optionIndex, uint8_t language);
|
||||
const char* BossRush_GetSettingChoiceName(uint8_t optionIndex, uint8_t choiceIndex, uint8_t language);
|
||||
uint8_t BossRush_GetSettingOptionsAmount(uint8_t optionIndex);
|
||||
const char* BossRush_GetSettingName(u8 optionIndex, u8 language);
|
||||
const char* BossRush_GetSettingChoiceName(u8 optionIndex, u8 choiceIndex, u8 language);
|
||||
u8 BossRush_GetSettingOptionsAmount(u8 optionIndex);
|
||||
void BossRush_RegisterHooks();
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#define BOSSRUSH_OPTIONS_AMOUNT 12
|
||||
#define BOSSRUSH_MAX_OPTIONS_ON_SCREEN 6
|
||||
|
||||
typedef enum {
|
||||
@ -15,7 +14,8 @@ typedef enum {
|
||||
BR_OPTIONS_LONGSHOT,
|
||||
BR_OPTIONS_HOVERBOOTS,
|
||||
BR_OPTIONS_BUNNYHOOD,
|
||||
BR_OPTIONS_TIMER
|
||||
BR_OPTIONS_TIMER,
|
||||
BR_OPTIONS_MAX,
|
||||
} BossRushOptionEnums;
|
||||
|
||||
typedef enum {
|
||||
|
@ -247,6 +247,46 @@ typedef enum {
|
||||
```
|
||||
*/
|
||||
VB_DRAW_AMMO_COUNT,
|
||||
// Vanilla condition: true
|
||||
VB_HAVE_OCARINA_NOTE_D4,
|
||||
// Vanilla condition: true
|
||||
VB_HAVE_OCARINA_NOTE_D5,
|
||||
// Vanilla condition: true
|
||||
VB_HAVE_OCARINA_NOTE_F4,
|
||||
// Vanilla condition: true
|
||||
VB_HAVE_OCARINA_NOTE_B4,
|
||||
// Vanilla condition: true
|
||||
VB_HAVE_OCARINA_NOTE_A4,
|
||||
// Vanilla condition: false
|
||||
VB_SKIP_SCARECROWS_SONG,
|
||||
// Vanilla condition: true
|
||||
VB_RENDER_RUPEE_COUNTER,
|
||||
// Vanilla condition: true
|
||||
VB_RENDER_KEY_COUNTER,
|
||||
// Vanilla condition: true
|
||||
VB_SPAWN_HEART_CONTAINER,
|
||||
// Vanilla condition: true
|
||||
VB_BE_ABLE_TO_OPEN_DOORS,
|
||||
// Vanilla condition: true
|
||||
VB_REVERT_SPOILING_ITEMS,
|
||||
// Vanilla condition: Flags_GetEventChkInf(EVENTCHKINF_USED_DODONGOS_CAVERN_BLUE_WARP) || BREG(2)
|
||||
VB_BE_ABLE_TO_PLAY_BOMBCHU_BOWLING,
|
||||
// Vanilla condition: true
|
||||
VB_BE_ABLE_TO_SAVE,
|
||||
// Vanilla condition: true
|
||||
VB_TRANSITION_TO_SAVE_SCREEN_ON_DEATH,
|
||||
// Vanilla condition: true
|
||||
VB_RENDER_YES_ON_CONTINUE_PROMPT,
|
||||
// Vanilla condition: CHECK_BTN_ALL(input->press.button, BTN_START)
|
||||
VB_CLOSE_PAUSE_MENU,
|
||||
// Vanilla condition: true
|
||||
VB_SPAWN_BLUE_WARP,
|
||||
// Vanilla condition: this->warpTimer > sWarpTimerTarget && gSaveContext.nextCutsceneIndex == 0xFFEF
|
||||
VB_BLUE_WARP_APPLY_ENTRANCE_AND_CUTSCENE,
|
||||
// Vanilla condition: this->collider.base.acFlags & 2
|
||||
VB_BG_BREAKWALL_BREAK,
|
||||
// Vanilla condition: true
|
||||
VB_GANON_HEAL_BEFORE_FIGHT,
|
||||
VB_FREEZE_LINK_FOR_BLOCK_THROW,
|
||||
VB_MOVE_THROWN_ACTOR,
|
||||
|
||||
|
@ -24,6 +24,7 @@ DEFINE_HOOK(OnActorInit, (void* actor));
|
||||
DEFINE_HOOK(OnActorUpdate, (void* actor));
|
||||
DEFINE_HOOK(OnActorKill, (void* actor));
|
||||
DEFINE_HOOK(OnEnemyDefeat, (void* actor));
|
||||
DEFINE_HOOK(OnBossDefeat, (void* actor));
|
||||
DEFINE_HOOK(OnPlayerBonk, ());
|
||||
DEFINE_HOOK(OnPlayDestroy, ());
|
||||
DEFINE_HOOK(OnPlayDrawEnd, ());
|
||||
|
@ -100,6 +100,13 @@ void GameInteractor_ExecuteOnEnemyDefeat(void* actor) {
|
||||
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnEnemyDefeat>(actor);
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteOnBossDefeat(void* actor) {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnBossDefeat>(actor);
|
||||
GameInteractor::Instance->ExecuteHooksForID<GameInteractor::OnBossDefeat>(((Actor*)actor)->id, actor);
|
||||
GameInteractor::Instance->ExecuteHooksForPtr<GameInteractor::OnBossDefeat>((uintptr_t)actor, actor);
|
||||
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnBossDefeat>(actor);
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteOnPlayerBonk() {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnPlayerBonk>();
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ void GameInteractor_ExecuteOnActorInit(void* actor);
|
||||
void GameInteractor_ExecuteOnActorUpdate(void* actor);
|
||||
void GameInteractor_ExecuteOnActorKill(void* actor);
|
||||
void GameInteractor_ExecuteOnEnemyDefeat(void* actor);
|
||||
void GameInteractor_ExecuteOnBossDefeat(void* actor);
|
||||
void GameInteractor_ExecuteOnPlayerBonk();
|
||||
void GameInteractor_ExecuteOnOcarinaSongAction();
|
||||
void GameInteractor_ExecuteOnShopSlotChangeHooks(uint8_t cursorIndex, int16_t price);
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include "game-interactor/GameInteractor.h"
|
||||
#include "tts/tts.h"
|
||||
#include "soh/OTRGlobals.h"
|
||||
#include "soh/Enhancements/boss-rush/BossRushTypes.h"
|
||||
#include "soh/Enhancements/boss-rush/BossRush.h"
|
||||
#include "soh/Enhancements/enhancementTypes.h"
|
||||
#include "soh/Enhancements/randomizer/3drando/random.hpp"
|
||||
#include "soh/Enhancements/cosmetics/authenticGfxPatches.h"
|
||||
@ -784,48 +784,6 @@ void RegisterResetNaviTimer() {
|
||||
});
|
||||
}
|
||||
|
||||
f32 triforcePieceScale;
|
||||
|
||||
void RegisterTriforceHunt() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnPlayerUpdate>([]() {
|
||||
if (!GameInteractor::IsGameplayPaused() &&
|
||||
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT)) {
|
||||
|
||||
// Warp to credits
|
||||
if (GameInteractor::State::TriforceHuntCreditsWarpActive) {
|
||||
gPlayState->nextEntranceIndex = ENTR_CHAMBER_OF_THE_SAGES_0;
|
||||
gSaveContext.nextCutsceneIndex = 0xFFF2;
|
||||
gPlayState->transitionTrigger = TRANS_TRIGGER_START;
|
||||
gPlayState->transitionType = TRANS_TYPE_FADE_WHITE;
|
||||
GameInteractor::State::TriforceHuntCreditsWarpActive = 0;
|
||||
}
|
||||
|
||||
// Reset Triforce Piece scale for GI animation. Triforce Hunt allows for multiple triforce models,
|
||||
// and cycles through them based on the amount of triforce pieces collected. It takes a little while
|
||||
// for the count to increase during the GI animation, so the model is entirely hidden until that piece
|
||||
// has been added. That scale has to be reset after the textbox is closed, and this is the best way
|
||||
// to ensure it's done at that point in time specifically.
|
||||
if (GameInteractor::State::TriforceHuntPieceGiven) {
|
||||
triforcePieceScale = 0.0f;
|
||||
GameInteractor::State::TriforceHuntPieceGiven = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterGrantGanonsBossKey() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnPlayerUpdate>([]() {
|
||||
// Triforce Hunt needs the check if the player isn't being teleported to the credits scene.
|
||||
if (!GameInteractor::IsGameplayPaused() && IS_RANDO &&
|
||||
Flags_GetRandomizerInf(RAND_INF_GRANT_GANONS_BOSSKEY) && gPlayState->transitionTrigger != TRANS_TRIGGER_START &&
|
||||
(1 << 0 & gSaveContext.inventory.dungeonItems[SCENE_GANONS_TOWER]) == 0) {
|
||||
GetItemEntry getItemEntry =
|
||||
ItemTableManager::Instance->RetrieveItemEntry(MOD_RANDOMIZER, RG_GANONS_CASTLE_BOSS_KEY);
|
||||
GiveItemEntryWithoutActor(gPlayState, getItemEntry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//this map is used for enemies that can be uniquely identified by their id
|
||||
//and that are always counted
|
||||
//enemies that can't be uniquely identified by their id
|
||||
@ -873,7 +831,7 @@ static std::unordered_map<u16, u16> uniqueEnemyIdToStatCount = {
|
||||
|
||||
void RegisterEnemyDefeatCounts() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnEnemyDefeat>([](void* refActor) {
|
||||
Actor* actor = (Actor*)refActor;
|
||||
Actor* actor = static_cast<Actor*>(refActor);
|
||||
if (uniqueEnemyIdToStatCount.contains(actor->id)) {
|
||||
gSaveContext.sohStats.count[uniqueEnemyIdToStatCount[actor->id]]++;
|
||||
} else {
|
||||
@ -1017,6 +975,45 @@ void RegisterEnemyDefeatCounts() {
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterBossDefeatTimestamps() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnBossDefeat>([](void* refActor) {
|
||||
Actor* actor = static_cast<Actor*>(refActor);
|
||||
switch (actor->id) {
|
||||
case ACTOR_BOSS_DODONGO:
|
||||
gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_KING_DODONGO] = GAMEPLAYSTAT_TOTAL_TIME;
|
||||
break;
|
||||
case ACTOR_BOSS_FD2:
|
||||
gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_VOLVAGIA] = GAMEPLAYSTAT_TOTAL_TIME;
|
||||
break;
|
||||
case ACTOR_BOSS_GANON:
|
||||
gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_GANONDORF] = GAMEPLAYSTAT_TOTAL_TIME;
|
||||
break;
|
||||
case ACTOR_BOSS_GANON2:
|
||||
gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_GANON] = GAMEPLAYSTAT_TOTAL_TIME;
|
||||
gSaveContext.sohStats.gameComplete = true;
|
||||
break;
|
||||
case ACTOR_BOSS_GANONDROF:
|
||||
gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_PHANTOM_GANON] = GAMEPLAYSTAT_TOTAL_TIME;
|
||||
break;
|
||||
case ACTOR_BOSS_GOMA:
|
||||
gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_GOHMA] = GAMEPLAYSTAT_TOTAL_TIME;
|
||||
break;
|
||||
case ACTOR_BOSS_MO:
|
||||
gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_MORPHA] = GAMEPLAYSTAT_TOTAL_TIME;
|
||||
break;
|
||||
case ACTOR_BOSS_SST:
|
||||
gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_BONGO_BONGO] = GAMEPLAYSTAT_TOTAL_TIME;
|
||||
break;
|
||||
case ACTOR_BOSS_TW:
|
||||
gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_TWINROVA] = GAMEPLAYSTAT_TOTAL_TIME;
|
||||
break;
|
||||
case ACTOR_BOSS_VA:
|
||||
gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_BARINADE] = GAMEPLAYSTAT_TOTAL_TIME;
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
ADD_ICE_TRAP,
|
||||
ADD_BURN_TRAP,
|
||||
@ -1165,83 +1162,6 @@ void RegisterAltTrapTypes() {
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterRandomizerSheikSpawn() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneSpawnActors>([]() {
|
||||
if (!gPlayState) return;
|
||||
if (!IS_RANDO || !LINK_IS_ADULT || !OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHEIK_LA_HINT)) return;
|
||||
switch (gPlayState->sceneNum) {
|
||||
case SCENE_TEMPLE_OF_TIME:
|
||||
if (gPlayState->roomCtx.curRoom.num == 1) {
|
||||
Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_EN_XC, -104, -40, 2382, 0, 0x8000, 0, SHEIK_TYPE_RANDO, false);
|
||||
}
|
||||
break;
|
||||
case SCENE_INSIDE_GANONS_CASTLE:
|
||||
if (gPlayState->roomCtx.curRoom.num == 1){
|
||||
Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_EN_XC, 101, 150, 137, 0, 0, 0, SHEIK_TYPE_RANDO, false);
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//Boss souls require an additional item (represented by a RAND_INF) to spawn a boss in a particular lair
|
||||
void RegisterBossSouls() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorInit>([](void* actor) {
|
||||
if (!gPlayState) return;
|
||||
if (!IS_RANDO || !(OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_BOSS_SOULS))) return;
|
||||
RandomizerInf rand_inf = RAND_INF_MAX;
|
||||
Actor* actual = (Actor*)actor;
|
||||
switch (gPlayState->sceneNum){
|
||||
case SCENE_DEKU_TREE_BOSS:
|
||||
rand_inf = RAND_INF_GOHMA_SOUL;
|
||||
break;
|
||||
case SCENE_DODONGOS_CAVERN_BOSS:
|
||||
rand_inf = RAND_INF_KING_DODONGO_SOUL;
|
||||
break;
|
||||
case SCENE_JABU_JABU_BOSS:
|
||||
rand_inf = RAND_INF_BARINADE_SOUL;
|
||||
break;
|
||||
case SCENE_FOREST_TEMPLE_BOSS:
|
||||
rand_inf = RAND_INF_PHANTOM_GANON_SOUL;
|
||||
break;
|
||||
case SCENE_FIRE_TEMPLE_BOSS:
|
||||
rand_inf = RAND_INF_VOLVAGIA_SOUL;
|
||||
break;
|
||||
case SCENE_WATER_TEMPLE_BOSS:
|
||||
rand_inf = RAND_INF_MORPHA_SOUL;
|
||||
break;
|
||||
case SCENE_SHADOW_TEMPLE_BOSS:
|
||||
rand_inf = RAND_INF_BONGO_BONGO_SOUL;
|
||||
break;
|
||||
case SCENE_SPIRIT_TEMPLE_BOSS:
|
||||
rand_inf = RAND_INF_TWINROVA_SOUL;
|
||||
break;
|
||||
case SCENE_GANONDORF_BOSS:
|
||||
case SCENE_GANON_BOSS:
|
||||
if (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_BOSS_SOULS) == RO_BOSS_SOULS_ON_PLUS_GANON) {
|
||||
rand_inf = RAND_INF_GANON_SOUL;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
//Deletes all actors in the boss category if the soul isn't found.
|
||||
//Some actors, like Dark Link, Arwings, and Zora's Sapphire...?, are in this category despite not being actual bosses,
|
||||
//so ignore any "boss" if `rand_inf` doesn't change from RAND_INF_MAX.
|
||||
if (rand_inf != RAND_INF_MAX) {
|
||||
if (!Flags_GetRandomizerInf(rand_inf) && actual->category == ACTORCAT_BOSS) {
|
||||
Actor_Delete(&gPlayState->actorCtx, actual, gPlayState);
|
||||
}
|
||||
//Special case for Phantom Ganon's horse (and fake), as they're considered "background actors",
|
||||
//but still control the boss fight flow.
|
||||
if (!Flags_GetRandomizerInf(RAND_INF_PHANTOM_GANON_SOUL) && actual->id == ACTOR_EN_FHG) {
|
||||
Actor_Delete(&gPlayState->actorCtx, actual, gPlayState);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void UpdateHurtContainerModeState(bool newState) {
|
||||
static bool hurtEnabled = false;
|
||||
if (hurtEnabled == newState) {
|
||||
@ -1460,131 +1380,6 @@ void RegisterPauseMenuHooks() {
|
||||
});
|
||||
}
|
||||
|
||||
//from z_player.c
|
||||
typedef struct {
|
||||
/* 0x00 */ Vec3f pos;
|
||||
/* 0x0C */ s16 yaw;
|
||||
} SpecialRespawnInfo; // size = 0x10
|
||||
|
||||
//special respawns used when voided out without swim to prevent infinite loops
|
||||
std::map<s32, SpecialRespawnInfo> swimSpecialRespawnInfo = {
|
||||
{
|
||||
ENTR_ZORAS_RIVER_3,//hf to zr in water
|
||||
{ { -1455.443, -20, 1384.826 }, 28761 }
|
||||
},
|
||||
{
|
||||
ENTR_HYRULE_FIELD_14,//zr to hf in water
|
||||
{ { 5830.209, -92.16, 3925.911 }, -20025 }
|
||||
},
|
||||
{
|
||||
ENTR_LOST_WOODS_7,//zr to lw
|
||||
{ { 1978.718, -36.908, -855 }, -16384 }
|
||||
},
|
||||
{
|
||||
ENTR_ZORAS_RIVER_4,//lw to zr
|
||||
{ { 4082.366, 860.442, -1018.949 }, -32768 }
|
||||
},
|
||||
{
|
||||
ENTR_LAKE_HYLIA_1,//gv to lh
|
||||
{ { -3276.416, -1033, 2908.421 }, 11228 }
|
||||
},
|
||||
{
|
||||
ENTR_WATER_TEMPLE_0,//lh to water temple
|
||||
{ { -182, 780, 759.5 }, -32768 }
|
||||
},
|
||||
{
|
||||
ENTR_LAKE_HYLIA_2,//water temple to lh
|
||||
{ { -955.028, -1306.9, 6768.954 }, -32768 }
|
||||
},
|
||||
{
|
||||
ENTR_ZORAS_DOMAIN_4,//lh to zd
|
||||
{ { -109.86, 11.396, -9.933 }, -29131 }
|
||||
},
|
||||
{
|
||||
ENTR_LAKE_HYLIA_7,//zd to lh
|
||||
{ { -912, -1326.967, 3391 }, 0 }
|
||||
},
|
||||
{
|
||||
ENTR_GERUDO_VALLEY_1,//caught by gerudos as child
|
||||
{ { -424, -2051, -74 }, 16384 }
|
||||
}
|
||||
};
|
||||
|
||||
void RegisterNoSwim() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnPlayerUpdate>([]() {
|
||||
if (
|
||||
IS_RANDO &&
|
||||
(GET_PLAYER(gPlayState)->stateFlags1 & PLAYER_STATE1_IN_WATER) &&
|
||||
!Flags_GetRandomizerInf(RAND_INF_CAN_SWIM) &&
|
||||
CUR_EQUIP_VALUE(EQUIP_TYPE_BOOTS) != EQUIP_VALUE_BOOTS_IRON
|
||||
) {
|
||||
//if you void out in water temple without swim you get instantly kicked out to prevent softlocks
|
||||
if (gPlayState->sceneNum == SCENE_WATER_TEMPLE) {
|
||||
GameInteractor::RawAction::TeleportPlayer(Entrance_OverrideNextIndex(ENTR_LAKE_HYLIA_2));//lake hylia from water temple
|
||||
return;
|
||||
}
|
||||
|
||||
if (swimSpecialRespawnInfo.find(gSaveContext.entranceIndex) != swimSpecialRespawnInfo.end()) {
|
||||
SpecialRespawnInfo* respawnInfo = &swimSpecialRespawnInfo.at(gSaveContext.entranceIndex);
|
||||
|
||||
Play_SetupRespawnPoint(gPlayState, RESPAWN_MODE_DOWN, 0xDFF);
|
||||
gSaveContext.respawn[RESPAWN_MODE_DOWN].pos = respawnInfo->pos;
|
||||
gSaveContext.respawn[RESPAWN_MODE_DOWN].yaw = respawnInfo->yaw;
|
||||
}
|
||||
|
||||
Play_TriggerVoidOut(gPlayState);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterNoWallet() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
if (IS_RANDO && !Flags_GetRandomizerInf(RAND_INF_HAS_WALLET)) {
|
||||
gSaveContext.rupees = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterInfiniteUpgrades() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
if (!IS_RANDO) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_QUIVER)) {
|
||||
AMMO(ITEM_BOW) = CUR_CAPACITY(UPG_QUIVER);
|
||||
}
|
||||
|
||||
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_BOMB_BAG)) {
|
||||
AMMO(ITEM_BOMB) = CUR_CAPACITY(UPG_BOMB_BAG);
|
||||
}
|
||||
|
||||
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_BULLET_BAG)) {
|
||||
AMMO(ITEM_SLINGSHOT) = CUR_CAPACITY(UPG_BULLET_BAG);
|
||||
}
|
||||
|
||||
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_STICK_UPGRADE)) {
|
||||
AMMO(ITEM_STICK) = CUR_CAPACITY(UPG_STICKS);
|
||||
}
|
||||
|
||||
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_NUT_UPGRADE)) {
|
||||
AMMO(ITEM_NUT) = CUR_CAPACITY(UPG_NUTS);
|
||||
}
|
||||
|
||||
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_MAGIC_METER)) {
|
||||
gSaveContext.magic = gSaveContext.magicCapacity;
|
||||
}
|
||||
|
||||
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_BOMBCHUS)) {
|
||||
AMMO(ITEM_BOMBCHU) = 50;
|
||||
}
|
||||
|
||||
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_MONEY)) {
|
||||
gSaveContext.rupees = CUR_CAPACITY(UPG_WALLET);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey);
|
||||
|
||||
void PatchCompasses() {
|
||||
@ -1605,30 +1400,8 @@ void RegisterRandomizerCompasses() {
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" void func_8099485C(DoorGerudo* gerudoDoor, PlayState* play);
|
||||
|
||||
void RegisterSkeletonKey() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorUpdate>([](void* refActor) {
|
||||
if (Flags_GetRandomizerInf(RAND_INF_HAS_SKELETON_KEY)) {
|
||||
Actor* actor = static_cast<Actor*>(refActor);
|
||||
if (actor->id == ACTOR_EN_DOOR) {
|
||||
EnDoor* door = (EnDoor*)actor;
|
||||
door->lockTimer = 0;
|
||||
} else if (actor->id == ACTOR_DOOR_SHUTTER) {
|
||||
DoorShutter* shutterDoor = (DoorShutter*)actor;
|
||||
if (shutterDoor->doorType == SHUTTER_KEY_LOCKED) {
|
||||
shutterDoor->unk_16E = 0;
|
||||
}
|
||||
} else if (actor->id == ACTOR_DOOR_GERUDO) {
|
||||
DoorGerudo* gerudoDoor = (DoorGerudo*)actor;
|
||||
gerudoDoor->actionFunc = func_8099485C;
|
||||
gerudoDoor->dyna.actor.world.pos.y = gerudoDoor->dyna.actor.home.pos.y + 200.0f;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void InitMods() {
|
||||
BossRush_RegisterHooks();
|
||||
RandomizerRegisterHooks();
|
||||
TimeSaverRegisterHooks();
|
||||
CheatsRegisterHooks();
|
||||
@ -1658,24 +1431,17 @@ void InitMods() {
|
||||
RegisterMenuPathFix();
|
||||
RegisterMirrorModeHandler();
|
||||
RegisterResetNaviTimer();
|
||||
RegisterTriforceHunt();
|
||||
RegisterGrantGanonsBossKey();
|
||||
RegisterEnemyDefeatCounts();
|
||||
RegisterBossDefeatTimestamps();
|
||||
RegisterAltTrapTypes();
|
||||
RegisterRandomizerSheikSpawn();
|
||||
RegisterBossSouls();
|
||||
RegisterRandomizedEnemySizes();
|
||||
RegisterOpenAllHours();
|
||||
RegisterToTMedallions();
|
||||
RegisterNoSwim();
|
||||
RegisterNoWallet();
|
||||
RegisterInfiniteUpgrades();
|
||||
RegisterRandomizerCompasses();
|
||||
NameTag_RegisterHooks();
|
||||
RegisterFloorSwitchesHook();
|
||||
RegisterPatchHandHandler();
|
||||
RegisterHurtContainerModeHandler();
|
||||
RegisterPauseMenuHooks();
|
||||
RegisterSkeletonKey();
|
||||
RandoKaleido_RegisterHooks();
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "soh/OTRGlobals.h"
|
||||
#include "soh/Enhancements/enhancementTypes.h"
|
||||
#include "soh/Enhancements/custom-message/CustomMessageTypes.h"
|
||||
#include "soh/Enhancements/item-tables/ItemTableManager.h"
|
||||
#include "soh/Enhancements/randomizer/randomizerTypes.h"
|
||||
#include "soh/Enhancements/randomizer/dungeon.h"
|
||||
#include "soh/Enhancements/randomizer/fishsanity.h"
|
||||
@ -35,6 +36,10 @@ extern "C" {
|
||||
#include "src/overlays/actors/ovl_Obj_Comb/z_obj_comb.h"
|
||||
#include "src/overlays/actors/ovl_En_Bom_Bowl_Pit/z_en_bom_bowl_pit.h"
|
||||
#include "src/overlays/actors/ovl_En_Ge1/z_en_ge1.h"
|
||||
#include "src/overlays/actors/ovl_En_Door/z_en_door.h"
|
||||
#include "src/overlays/actors/ovl_Door_Shutter/z_door_shutter.h"
|
||||
#include "src/overlays/actors/ovl_Door_Gerudo/z_door_gerudo.h"
|
||||
#include "src/overlays/actors/ovl_En_Xc/z_en_xc.h"
|
||||
#include "src/overlays/actors/ovl_Fishing/z_fishing.h"
|
||||
#include "adult_trade_shuffle.h"
|
||||
#include "draw.h"
|
||||
@ -1179,6 +1184,79 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, void
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VB_HAVE_OCARINA_NOTE_D4: {
|
||||
if (!Flags_GetRandomizerInf(RAND_INF_HAS_OCARINA_A)) {
|
||||
*should = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VB_HAVE_OCARINA_NOTE_D5: {
|
||||
if (!Flags_GetRandomizerInf(RAND_INF_HAS_OCARINA_C_UP)) {
|
||||
*should = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VB_HAVE_OCARINA_NOTE_F4: {
|
||||
if (!Flags_GetRandomizerInf(RAND_INF_HAS_OCARINA_C_DOWN)) {
|
||||
*should = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VB_HAVE_OCARINA_NOTE_B4: {
|
||||
if (!Flags_GetRandomizerInf(RAND_INF_HAS_OCARINA_C_LEFT)) {
|
||||
*should = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VB_HAVE_OCARINA_NOTE_A4: {
|
||||
if (!Flags_GetRandomizerInf(RAND_INF_HAS_OCARINA_C_RIGHT)) {
|
||||
*should = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VB_SKIP_SCARECROWS_SONG: {
|
||||
int ocarinaButtonCount = 0;
|
||||
for (int i = VB_HAVE_OCARINA_NOTE_D4; i <= VB_HAVE_OCARINA_NOTE_A4; i++) {
|
||||
if (GameInteractor_Should((GIVanillaBehavior)i, true, NULL)) {
|
||||
ocarinaButtonCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (ocarinaButtonCount < 2) {
|
||||
*should = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (gPlayState->msgCtx.msgMode == MSGMODE_OCARINA_PLAYING && RAND_GET_OPTION(RSK_SKIP_SCARECROWS_SONG)) {
|
||||
*should = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VB_RENDER_KEY_COUNTER: {
|
||||
if (Flags_GetRandomizerInf(RAND_INF_HAS_SKELETON_KEY)) {
|
||||
*should = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VB_RENDER_RUPEE_COUNTER: {
|
||||
if (!Flags_GetRandomizerInf(RAND_INF_HAS_WALLET) || Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_MONEY)) {
|
||||
*should = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VB_REVERT_SPOILING_ITEMS: {
|
||||
if (RAND_GET_OPTION(RSK_SHUFFLE_ADULT_TRADE)) {
|
||||
*should = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VB_BE_ABLE_TO_PLAY_BOMBCHU_BOWLING: {
|
||||
// Only check for bomb bag when bombchus aren't in logic
|
||||
// and only check for bombchus when bombchus are in logic
|
||||
*should = INV_CONTENT((RAND_GET_OPTION(RSK_BOMBCHUS_IN_LOGIC) ? ITEM_BOMBCHU : ITEM_BOMB)) != ITEM_NONE;
|
||||
break;
|
||||
}
|
||||
case VB_SHOULD_CHECK_FOR_FISHING_RECORD: {
|
||||
f32 sFishOnHandLength = *static_cast<f32*>(optionalArg);
|
||||
*should = *should || ShouldGiveFishingPrize(sFishOnHandLength);
|
||||
@ -1286,6 +1364,10 @@ void RandomizerOnSceneInitHandler(int16_t sceneNum) {
|
||||
CheckTracker::RecalculateAllAreaTotals();
|
||||
}
|
||||
|
||||
if (RAND_GET_OPTION(RSK_SHUFFLE_ENTRANCES)) {
|
||||
Entrance_OverrideWeatherState();
|
||||
}
|
||||
|
||||
// LACs & Prelude checks
|
||||
static uint32_t updateHook = 0;
|
||||
|
||||
@ -1577,6 +1659,291 @@ void RandomizerOnActorInitHandler(void* actorRef) {
|
||||
) {
|
||||
Actor_Kill(actor);
|
||||
}
|
||||
|
||||
if (RAND_GET_OPTION(RSK_SHUFFLE_BOSS_SOULS)) {
|
||||
//Boss souls require an additional item (represented by a RAND_INF) to spawn a boss in a particular lair
|
||||
RandomizerInf currentBossSoulRandInf = RAND_INF_MAX;
|
||||
switch (gPlayState->sceneNum){
|
||||
case SCENE_DEKU_TREE_BOSS:
|
||||
currentBossSoulRandInf = RAND_INF_GOHMA_SOUL;
|
||||
break;
|
||||
case SCENE_DODONGOS_CAVERN_BOSS:
|
||||
currentBossSoulRandInf = RAND_INF_KING_DODONGO_SOUL;
|
||||
break;
|
||||
case SCENE_JABU_JABU_BOSS:
|
||||
currentBossSoulRandInf = RAND_INF_BARINADE_SOUL;
|
||||
break;
|
||||
case SCENE_FOREST_TEMPLE_BOSS:
|
||||
currentBossSoulRandInf = RAND_INF_PHANTOM_GANON_SOUL;
|
||||
break;
|
||||
case SCENE_FIRE_TEMPLE_BOSS:
|
||||
currentBossSoulRandInf = RAND_INF_VOLVAGIA_SOUL;
|
||||
break;
|
||||
case SCENE_WATER_TEMPLE_BOSS:
|
||||
currentBossSoulRandInf = RAND_INF_MORPHA_SOUL;
|
||||
break;
|
||||
case SCENE_SHADOW_TEMPLE_BOSS:
|
||||
currentBossSoulRandInf = RAND_INF_BONGO_BONGO_SOUL;
|
||||
break;
|
||||
case SCENE_SPIRIT_TEMPLE_BOSS:
|
||||
currentBossSoulRandInf = RAND_INF_TWINROVA_SOUL;
|
||||
break;
|
||||
case SCENE_GANONDORF_BOSS:
|
||||
case SCENE_GANON_BOSS:
|
||||
if (RAND_GET_OPTION(RSK_SHUFFLE_BOSS_SOULS) == RO_BOSS_SOULS_ON_PLUS_GANON) {
|
||||
currentBossSoulRandInf = RAND_INF_GANON_SOUL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
//Deletes all actors in the boss category if the soul isn't found.
|
||||
//Some actors, like Dark Link, Arwings, and Zora's Sapphire...?, are in this category despite not being actual bosses,
|
||||
//so ignore any "boss" if `currentBossSoulRandInf` doesn't change from RAND_INF_MAX.
|
||||
if (currentBossSoulRandInf != RAND_INF_MAX) {
|
||||
if (!Flags_GetRandomizerInf(currentBossSoulRandInf) && actor->category == ACTORCAT_BOSS) {
|
||||
Actor_Delete(&gPlayState->actorCtx, actor, gPlayState);
|
||||
}
|
||||
//Special case for Phantom Ganon's horse (and fake), as they're considered "background actors",
|
||||
//but still control the boss fight flow.
|
||||
if (!Flags_GetRandomizerInf(RAND_INF_PHANTOM_GANON_SOUL) && actor->id == ACTOR_EN_FHG) {
|
||||
Actor_Delete(&gPlayState->actorCtx, actor, gPlayState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// In MQ Spirit, remove the large silver block in the hole as child so the chest in the silver block hallway
|
||||
// can be guaranteed accessible
|
||||
if (
|
||||
actor->id == ACTOR_OBJ_OSHIHIKI &&
|
||||
LINK_IS_CHILD &&
|
||||
IsGameMasterQuest() &&
|
||||
gPlayState->sceneNum == SCENE_SPIRIT_TEMPLE && actor->room == 6 && // Spirit Temple silver block hallway
|
||||
actor->params == 0x9C7 // Silver block that is marked as in the hole
|
||||
) {
|
||||
Actor_Kill(actor);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
// If child is in the adult shooting gallery or adult in the child shooting gallery, then despawn the shooting gallery man
|
||||
actor->id == ACTOR_EN_SYATEKI_MAN &&
|
||||
RAND_GET_OPTION(RSK_SHUFFLE_INTERIOR_ENTRANCES) &&
|
||||
(
|
||||
(LINK_IS_CHILD && Entrance_SceneAndSpawnAre(SCENE_SHOOTING_GALLERY, 0x00)) || //Kakariko Village -> Adult Shooting Gallery, index 003B in the entrance table
|
||||
(LINK_IS_ADULT && Entrance_SceneAndSpawnAre(SCENE_SHOOTING_GALLERY, 0x01)) //Market -> Child Shooting Gallery, index 016D in the entrance table
|
||||
)
|
||||
) {
|
||||
Actor_Kill(actor);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void RandomizerOnGameFrameUpdateHandler() {
|
||||
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_QUIVER)) {
|
||||
AMMO(ITEM_BOW) = CUR_CAPACITY(UPG_QUIVER);
|
||||
}
|
||||
|
||||
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_BOMB_BAG)) {
|
||||
AMMO(ITEM_BOMB) = CUR_CAPACITY(UPG_BOMB_BAG);
|
||||
}
|
||||
|
||||
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_BULLET_BAG)) {
|
||||
AMMO(ITEM_SLINGSHOT) = CUR_CAPACITY(UPG_BULLET_BAG);
|
||||
}
|
||||
|
||||
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_STICK_UPGRADE)) {
|
||||
AMMO(ITEM_STICK) = CUR_CAPACITY(UPG_STICKS);
|
||||
}
|
||||
|
||||
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_NUT_UPGRADE)) {
|
||||
AMMO(ITEM_NUT) = CUR_CAPACITY(UPG_NUTS);
|
||||
}
|
||||
|
||||
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_MAGIC_METER)) {
|
||||
gSaveContext.magic = gSaveContext.magicCapacity;
|
||||
}
|
||||
|
||||
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_BOMBCHUS)) {
|
||||
AMMO(ITEM_BOMBCHU) = 50;
|
||||
}
|
||||
|
||||
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_MONEY)) {
|
||||
gSaveContext.rupees = CUR_CAPACITY(UPG_WALLET);
|
||||
}
|
||||
|
||||
if (!Flags_GetRandomizerInf(RAND_INF_HAS_WALLET)) {
|
||||
gSaveContext.rupees = 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void func_8099485C(DoorGerudo* gerudoDoor, PlayState* play);
|
||||
|
||||
void RandomizerOnActorUpdateHandler(void* refActor) {
|
||||
Actor* actor = static_cast<Actor*>(refActor);
|
||||
|
||||
if (Flags_GetRandomizerInf(RAND_INF_HAS_SKELETON_KEY)) {
|
||||
if (actor->id == ACTOR_EN_DOOR) {
|
||||
EnDoor* door = reinterpret_cast<EnDoor*>(actor);
|
||||
door->lockTimer = 0;
|
||||
} else if (actor->id == ACTOR_DOOR_SHUTTER) {
|
||||
DoorShutter* shutterDoor = reinterpret_cast<DoorShutter*>(actor);
|
||||
if (shutterDoor->doorType == SHUTTER_KEY_LOCKED) {
|
||||
shutterDoor->unk_16E = 0;
|
||||
}
|
||||
} else if (actor->id == ACTOR_DOOR_GERUDO) {
|
||||
DoorGerudo* gerudoDoor = (DoorGerudo*)actor;
|
||||
gerudoDoor->actionFunc = func_8099485C;
|
||||
gerudoDoor->dyna.actor.world.pos.y = gerudoDoor->dyna.actor.home.pos.y + 200.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// In ER, override the warp song locations. Also removes the warp song cutscene
|
||||
if (RAND_GET_OPTION(RSK_SHUFFLE_ENTRANCES) && actor->id == ACTOR_DEMO_KANKYO && actor->params == 0x000F) { // Warp Song particles
|
||||
Entrance_SetWarpSongEntrance();
|
||||
}
|
||||
|
||||
if (actor->id == ACTOR_OBJ_COMB) {
|
||||
ObjComb* combActor = reinterpret_cast<ObjComb*>(actor);
|
||||
combActor->actor.shape.rot.x = Math_SinS(combActor->unk_1B2) * CLAMP_MIN(combActor->unk_1B0, 0) + combActor->actor.home.rot.x;
|
||||
}
|
||||
}
|
||||
|
||||
//from z_player.c
|
||||
typedef struct {
|
||||
/* 0x00 */ Vec3f pos;
|
||||
/* 0x0C */ s16 yaw;
|
||||
} SpecialRespawnInfo; // size = 0x10
|
||||
|
||||
//special respawns used when voided out without swim to prevent infinite loops
|
||||
std::map<s32, SpecialRespawnInfo> swimSpecialRespawnInfo = {
|
||||
{
|
||||
ENTR_ZORAS_RIVER_3,//hf to zr in water
|
||||
{ { -1455.443, -20, 1384.826 }, 28761 }
|
||||
},
|
||||
{
|
||||
ENTR_HYRULE_FIELD_14,//zr to hf in water
|
||||
{ { 5730.209, -20, 3725.911 }, -20025 }
|
||||
},
|
||||
{
|
||||
ENTR_LOST_WOODS_7,//zr to lw
|
||||
{ { 1978.718, -36.908, -855 }, -16384 }
|
||||
},
|
||||
{
|
||||
ENTR_ZORAS_RIVER_4,//lw to zr
|
||||
{ { 4082.366, 860.442, -1018.949 }, -32768 }
|
||||
},
|
||||
{
|
||||
ENTR_LAKE_HYLIA_1,//gv to lh
|
||||
{ { -3276.416, -1033, 2908.421 }, 11228 }
|
||||
},
|
||||
{
|
||||
ENTR_WATER_TEMPLE_0,//lh to water temple
|
||||
{ { -182, 780, 759.5 }, -32768 }
|
||||
},
|
||||
{
|
||||
ENTR_LAKE_HYLIA_2,//water temple to lh
|
||||
{ { -955.028, -1306.9, 6768.954 }, -32768 }
|
||||
},
|
||||
{
|
||||
ENTR_ZORAS_DOMAIN_4,//lh to zd
|
||||
{ { -109.86, 11.396, -9.933 }, -29131 }
|
||||
},
|
||||
{
|
||||
ENTR_LAKE_HYLIA_7,//zd to lh
|
||||
{ { -912, -1326.967, 3391 }, 0 }
|
||||
},
|
||||
{
|
||||
ENTR_GERUDO_VALLEY_1,//caught by gerudos as child
|
||||
{ { -424, -2051, -74 }, 16384 }
|
||||
},
|
||||
{
|
||||
ENTR_HYRULE_FIELD_7,//mk to hf (can be a problem when it then turns night)
|
||||
{ { 0, 0, 1100 }, 0 }
|
||||
},
|
||||
{
|
||||
ENTR_ZORAS_FOUNTAIN_0,//jabu blue warp to zf
|
||||
{ { -1580, 150, 1670 }, 8000 }
|
||||
},
|
||||
};
|
||||
|
||||
f32 triforcePieceScale;
|
||||
|
||||
void RandomizerOnPlayerUpdateHandler() {
|
||||
if (
|
||||
(GET_PLAYER(gPlayState)->stateFlags1 & PLAYER_STATE1_IN_WATER) &&
|
||||
!Flags_GetRandomizerInf(RAND_INF_CAN_SWIM) &&
|
||||
CUR_EQUIP_VALUE(EQUIP_TYPE_BOOTS) != EQUIP_VALUE_BOOTS_IRON
|
||||
) {
|
||||
//if you void out in water temple without swim you get instantly kicked out to prevent softlocks
|
||||
if (gPlayState->sceneNum == SCENE_WATER_TEMPLE) {
|
||||
GameInteractor::RawAction::TeleportPlayer(Entrance_OverrideNextIndex(ENTR_LAKE_HYLIA_2));//lake hylia from water temple
|
||||
} else {
|
||||
if (swimSpecialRespawnInfo.find(gSaveContext.entranceIndex) != swimSpecialRespawnInfo.end()) {
|
||||
SpecialRespawnInfo* respawnInfo = &swimSpecialRespawnInfo.at(gSaveContext.entranceIndex);
|
||||
|
||||
Play_SetupRespawnPoint(gPlayState, RESPAWN_MODE_DOWN, 0xDFF);
|
||||
gSaveContext.respawn[RESPAWN_MODE_DOWN].pos = respawnInfo->pos;
|
||||
gSaveContext.respawn[RESPAWN_MODE_DOWN].yaw = respawnInfo->yaw;
|
||||
}
|
||||
|
||||
Play_TriggerVoidOut(gPlayState);
|
||||
}
|
||||
}
|
||||
|
||||
// Triforce Hunt needs the check if the player isn't being teleported to the credits scene.
|
||||
if (
|
||||
!GameInteractor::IsGameplayPaused() &&
|
||||
Flags_GetRandomizerInf(RAND_INF_GRANT_GANONS_BOSSKEY) &&
|
||||
gPlayState->transitionTrigger != TRANS_TRIGGER_START &&
|
||||
(1 << 0 & gSaveContext.inventory.dungeonItems[SCENE_GANONS_TOWER]) == 0
|
||||
) {
|
||||
GiveItemEntryWithoutActor(gPlayState, ItemTableManager::Instance->RetrieveItemEntry(MOD_RANDOMIZER, RG_GANONS_CASTLE_BOSS_KEY));
|
||||
}
|
||||
|
||||
if (
|
||||
!GameInteractor::IsGameplayPaused() &&
|
||||
RAND_GET_OPTION(RSK_TRIFORCE_HUNT)
|
||||
) {
|
||||
// Warp to credits
|
||||
if (GameInteractor::State::TriforceHuntCreditsWarpActive) {
|
||||
gPlayState->nextEntranceIndex = ENTR_CHAMBER_OF_THE_SAGES_0;
|
||||
gSaveContext.nextCutsceneIndex = 0xFFF2;
|
||||
gPlayState->transitionTrigger = TRANS_TRIGGER_START;
|
||||
gPlayState->transitionType = TRANS_TYPE_FADE_WHITE;
|
||||
GameInteractor::State::TriforceHuntCreditsWarpActive = 0;
|
||||
}
|
||||
|
||||
// Reset Triforce Piece scale for GI animation. Triforce Hunt allows for multiple triforce models,
|
||||
// and cycles through them based on the amount of triforce pieces collected. It takes a little while
|
||||
// for the count to increase during the GI animation, so the model is entirely hidden until that piece
|
||||
// has been added. That scale has to be reset after the textbox is closed, and this is the best way
|
||||
// to ensure it's done at that point in time specifically.
|
||||
if (GameInteractor::State::TriforceHuntPieceGiven) {
|
||||
triforcePieceScale = 0.0f;
|
||||
GameInteractor::State::TriforceHuntPieceGiven = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RandomizerOnSceneSpawnActorsHandler() {
|
||||
if (LINK_IS_ADULT && RAND_GET_OPTION(RSK_SHEIK_LA_HINT)) {
|
||||
switch (gPlayState->sceneNum) {
|
||||
case SCENE_TEMPLE_OF_TIME:
|
||||
if (gPlayState->roomCtx.curRoom.num == 1) {
|
||||
Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_EN_XC, -104, -40, 2382, 0, 0x8000, 0, SHEIK_TYPE_RANDO, false);
|
||||
}
|
||||
break;
|
||||
case SCENE_INSIDE_GANONS_CASTLE:
|
||||
if (gPlayState->roomCtx.curRoom.num == 1) {
|
||||
Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_EN_XC, 101, 150, 137, 0, 0, 0, SHEIK_TYPE_RANDO, false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RandomizerRegisterHooks() {
|
||||
@ -1588,6 +1955,10 @@ void RandomizerRegisterHooks() {
|
||||
static uint32_t onVanillaBehaviorHook = 0;
|
||||
static uint32_t onSceneInitHook = 0;
|
||||
static uint32_t onActorInitHook = 0;
|
||||
static uint32_t onActorUpdateHook = 0;
|
||||
static uint32_t onPlayerUpdateHook = 0;
|
||||
static uint32_t onGameFrameUpdateHook = 0;
|
||||
static uint32_t onSceneSpawnActorsHook = 0;
|
||||
|
||||
static uint32_t fishsanityOnActorInitHook = 0;
|
||||
static uint32_t fishsanityOnFlagSetHook = 0;
|
||||
@ -1608,6 +1979,10 @@ void RandomizerRegisterHooks() {
|
||||
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnVanillaBehavior>(onVanillaBehaviorHook);
|
||||
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnSceneInit>(onSceneInitHook);
|
||||
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnActorInit>(onActorInitHook);
|
||||
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnActorUpdate>(onActorUpdateHook);
|
||||
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnPlayerUpdate>(onPlayerUpdateHook);
|
||||
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnGameFrameUpdate>(onGameFrameUpdateHook);
|
||||
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnSceneSpawnActors>(onSceneSpawnActorsHook);
|
||||
|
||||
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnActorInit>(fishsanityOnActorInitHook);
|
||||
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnFlagSet>(fishsanityOnFlagSetHook);
|
||||
@ -1623,6 +1998,10 @@ void RandomizerRegisterHooks() {
|
||||
onVanillaBehaviorHook = 0;
|
||||
onSceneInitHook = 0;
|
||||
onActorInitHook = 0;
|
||||
onActorUpdateHook = 0;
|
||||
onPlayerUpdateHook = 0;
|
||||
onGameFrameUpdateHook = 0;
|
||||
onSceneSpawnActorsHook = 0;
|
||||
|
||||
fishsanityOnActorInitHook = 0;
|
||||
fishsanityOnFlagSetHook = 0;
|
||||
@ -1632,6 +2011,14 @@ void RandomizerRegisterHooks() {
|
||||
|
||||
if (!IS_RANDO) return;
|
||||
|
||||
// Setup the modified entrance table and entrance shuffle table for rando
|
||||
Entrance_Init();
|
||||
|
||||
// Handle randomized spawn positions after the save context has been setup from load
|
||||
if (RAND_GET_OPTION(RSK_SHUFFLE_ENTRANCES)) {
|
||||
Entrance_SetSavewarpEntrance();
|
||||
}
|
||||
|
||||
onFlagSetHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnFlagSet>(RandomizerOnFlagSetHandler);
|
||||
onSceneFlagSetHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneFlagSet>(RandomizerOnSceneFlagSetHandler);
|
||||
onPlayerUpdateForRCQueueHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnPlayerUpdate>(RandomizerOnPlayerUpdateForRCQueueHandler);
|
||||
@ -1640,15 +2027,19 @@ void RandomizerRegisterHooks() {
|
||||
onVanillaBehaviorHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnVanillaBehavior>(RandomizerOnVanillaBehaviorHandler);
|
||||
onSceneInitHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>(RandomizerOnSceneInitHandler);
|
||||
onActorInitHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorInit>(RandomizerOnActorInitHandler);
|
||||
onActorUpdateHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorUpdate>(RandomizerOnActorUpdateHandler);
|
||||
onPlayerUpdateHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnPlayerUpdate>(RandomizerOnPlayerUpdateHandler);
|
||||
onGameFrameUpdateHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>(RandomizerOnGameFrameUpdateHandler);
|
||||
onSceneSpawnActorsHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneSpawnActors>(RandomizerOnSceneSpawnActorsHandler);
|
||||
|
||||
if (RAND_GET_OPTION(RSK_FISHSANITY) != RO_FISHSANITY_OFF) {
|
||||
OTRGlobals::Instance->gRandoContext->GetFishsanity()->InitializeFromSave();
|
||||
|
||||
fishsanityOnActorInitHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorInit>(Rando::Fishsanity::OnActorInitHandler);
|
||||
fishsanityOnActorInitHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnFlagSet>(Rando::Fishsanity::OnFlagSetHandler);
|
||||
fishsanityOnActorInitHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorUpdate>(Rando::Fishsanity::OnActorUpdateHandler);
|
||||
fishsanityOnActorInitHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>(Rando::Fishsanity::OnSceneInitHandler);
|
||||
fishsanityOnActorInitHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnVanillaBehavior>(Rando::Fishsanity::OnVanillaBehaviorHandler);
|
||||
fishsanityOnFlagSetHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnFlagSet>(Rando::Fishsanity::OnFlagSetHandler);
|
||||
fishsanityOnActorUpdateHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorUpdate>(Rando::Fishsanity::OnActorUpdateHandler);
|
||||
fishsanityOnSceneInitHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>(Rando::Fishsanity::OnSceneInitHandler);
|
||||
fishsanityOnVanillaBehaviorHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnVanillaBehavior>(Rando::Fishsanity::OnVanillaBehaviorHandler);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -650,6 +650,12 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, void*
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VB_SKIP_SCARECROWS_SONG: {
|
||||
if (gPlayState->msgCtx.msgMode == MSGMODE_OCARINA_PLAYING && CVarGetInteger(CVAR_ENHANCEMENT("InstantScarecrow"), 0) && gSaveContext.scarecrowSpawnSongSet) {
|
||||
*should = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "functions.h"
|
||||
#include "macros.h"
|
||||
#include <variables.h>
|
||||
#include "soh/Enhancements/boss-rush/BossRush.h"
|
||||
#include <libultraship/libultraship.h>
|
||||
#include "SohGui.hpp"
|
||||
|
||||
|
@ -77,10 +77,6 @@ void OTRPlay_InitScene(PlayState* play, s32 spawn) {
|
||||
gSaveContext.worldMapArea = 0;
|
||||
OTRScene_ExecuteCommands(play, (SOH::Scene*)play->sceneSegment);
|
||||
Play_InitEnvironment(play, play->skyboxId);
|
||||
// Unpause the timer for Boss Rush when the scene loaded isn't the Chamber of Sages.
|
||||
if (IS_BOSS_RUSH && play->sceneNum != SCENE_CHAMBER_OF_THE_SAGES) {
|
||||
gSaveContext.isBossRushPaused = 0;
|
||||
}
|
||||
/* auto data = static_cast<LUS::Vertex*>(Ship::Context::GetInstance()
|
||||
->GetResourceManager()
|
||||
->ResourceLoad("object_link_child\\object_link_childVtx_01FE08")
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include <libultraship/libultra.h>
|
||||
#include "global.h"
|
||||
#include "soh/Enhancements/audio/AudioEditor.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
// TODO: can these macros be shared between files? code_800F9280 seems to use
|
||||
// versions without any casts...
|
||||
@ -1626,23 +1628,23 @@ void func_800ED458(s32 arg0) {
|
||||
}
|
||||
|
||||
Audio_OcaUpdateBtnMap(customControls, dpad, rStick);
|
||||
if (D_8016BA18 & sOcarinaD4BtnMap && (!IS_RANDO || Flags_GetRandomizerInf(RAND_INF_HAS_OCARINA_A))) {
|
||||
if (D_8016BA18 & sOcarinaD4BtnMap && GameInteractor_Should(VB_HAVE_OCARINA_NOTE_D4, true, NULL)) {
|
||||
osSyncPrintf("Presss NA_KEY_D4 %08x\n", sOcarinaD4BtnMap);
|
||||
sCurOcarinaBtnVal = 2;
|
||||
sCurOcarinaBtnIdx = 0;
|
||||
} else if (D_8016BA18 & sOcarinaF4BtnMap && (!IS_RANDO || Flags_GetRandomizerInf(RAND_INF_HAS_OCARINA_C_DOWN))) {
|
||||
} else if (D_8016BA18 & sOcarinaF4BtnMap && GameInteractor_Should(VB_HAVE_OCARINA_NOTE_F4, true, NULL)) {
|
||||
osSyncPrintf("Presss NA_KEY_F4 %08x\n", sOcarinaF4BtnMap);
|
||||
sCurOcarinaBtnVal = 5;
|
||||
sCurOcarinaBtnIdx = 1;
|
||||
} else if (D_8016BA18 & sOcarinaA4BtnMap && (!IS_RANDO || Flags_GetRandomizerInf(RAND_INF_HAS_OCARINA_C_RIGHT))) {
|
||||
} else if (D_8016BA18 & sOcarinaA4BtnMap && GameInteractor_Should(VB_HAVE_OCARINA_NOTE_A4, true, NULL)) {
|
||||
osSyncPrintf("Presss NA_KEY_A4 %08x\n", sOcarinaA4BtnMap);
|
||||
sCurOcarinaBtnVal = 9;
|
||||
sCurOcarinaBtnIdx = 2;
|
||||
} else if (D_8016BA18 & sOcarinaB4BtnMap && (!IS_RANDO || Flags_GetRandomizerInf(RAND_INF_HAS_OCARINA_C_LEFT))) {
|
||||
} else if (D_8016BA18 & sOcarinaB4BtnMap && GameInteractor_Should(VB_HAVE_OCARINA_NOTE_B4, true, NULL)) {
|
||||
osSyncPrintf("Presss NA_KEY_B4 %08x\n", sOcarinaA4BtnMap);
|
||||
sCurOcarinaBtnVal = 0xB;
|
||||
sCurOcarinaBtnIdx = 3;
|
||||
} else if (D_8016BA18 & sOcarinaD5BtnMap && (!IS_RANDO || Flags_GetRandomizerInf(RAND_INF_HAS_OCARINA_C_UP))) {
|
||||
} else if (D_8016BA18 & sOcarinaD5BtnMap && GameInteractor_Should(VB_HAVE_OCARINA_NOTE_D5, true, NULL)) {
|
||||
osSyncPrintf("Presss NA_KEY_D5 %08x\n", sOcarinaD5BtnMap);
|
||||
sCurOcarinaBtnVal = 0xE;
|
||||
sCurOcarinaBtnIdx = 4;
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "global.h"
|
||||
#include "vt.h"
|
||||
#include <assert.h>
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
s32 func_8006CFC0(s32 scene) {
|
||||
s32 validScenes[] = { SCENE_HYRULE_FIELD, SCENE_LAKE_HYLIA, SCENE_GERUDO_VALLEY, SCENE_GERUDOS_FORTRESS, SCENE_LON_LON_RANCH };
|
||||
@ -75,9 +77,9 @@ void func_8006D0EC(PlayState* play, Player* player) {
|
||||
} else if ((play->sceneNum == gSaveContext.horseData.scene) &&
|
||||
(((Flags_GetEventChkInf(EVENTCHKINF_EPONA_OBTAINED) != 0) && (!IS_RANDO ||
|
||||
(IS_RANDO && CHECK_QUEST_ITEM(QUEST_SONG_EPONA) &&
|
||||
Flags_GetRandomizerInf(RAND_INF_HAS_OCARINA_C_UP) &&
|
||||
Flags_GetRandomizerInf(RAND_INF_HAS_OCARINA_C_LEFT) &&
|
||||
Flags_GetRandomizerInf(RAND_INF_HAS_OCARINA_C_RIGHT) &&
|
||||
GameInteractor_Should(VB_HAVE_OCARINA_NOTE_D5, true, NULL) &&
|
||||
GameInteractor_Should(VB_HAVE_OCARINA_NOTE_B4, true, NULL) &&
|
||||
GameInteractor_Should(VB_HAVE_OCARINA_NOTE_A4, true, NULL) &&
|
||||
(INV_CONTENT(ITEM_OCARINA_FAIRY) != ITEM_NONE)))) || DREG(1) != 0)) {
|
||||
// "Set by existence of horse %d %d %d"
|
||||
osSyncPrintf("馬存在によるセット %d %d %d\n", gSaveContext.horseData.scene, Flags_GetEventChkInf(EVENTCHKINF_EPONA_OBTAINED),
|
||||
|
@ -5372,8 +5372,7 @@ void Interface_Draw(PlayState* play) {
|
||||
if (fullUi) {
|
||||
s16 PosX_RC;
|
||||
s16 PosY_RC;
|
||||
//when not having a wallet (or infinite money) in rando, don't calculate the ruppe icon
|
||||
if (!IS_RANDO || (Flags_GetRandomizerInf(RAND_INF_HAS_WALLET) && !Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_MONEY))) {
|
||||
if (GameInteractor_Should(VB_RENDER_RUPEE_COUNTER, true, NULL)) {
|
||||
// Rupee Icon
|
||||
if (CVarGetInteger(CVAR_ENHANCEMENT("DynamicWalletIcon"), 0)) {
|
||||
switch (CUR_UPG_VALUE(UPG_WALLET)) {
|
||||
@ -5444,14 +5443,10 @@ void Interface_Draw(PlayState* play) {
|
||||
PosX_RC = PosX_RC_ori;
|
||||
}
|
||||
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, rColor.r, rColor.g, rColor.b, interfaceCtx->magicAlpha);
|
||||
// Draw Rupee icon. Hide in Boss Rush.
|
||||
if (!IS_BOSS_RUSH) {
|
||||
OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, gRupeeCounterIconTex, 16, 16, PosX_RC, PosY_RC, 16, 16, 1 << 10, 1 << 10);
|
||||
}
|
||||
}
|
||||
|
||||
//when having the skeleton key in rando, don't render the small key counter
|
||||
if (!Flags_GetRandomizerInf(RAND_INF_HAS_SKELETON_KEY)) {
|
||||
if (GameInteractor_Should(VB_RENDER_KEY_COUNTER, true, NULL)) {
|
||||
switch (play->sceneNum) {
|
||||
case SCENE_FOREST_TEMPLE:
|
||||
case SCENE_FIRE_TEMPLE:
|
||||
@ -5467,7 +5462,6 @@ void Interface_Draw(PlayState* play) {
|
||||
case SCENE_GANONS_TOWER_COLLAPSE_INTERIOR:
|
||||
case SCENE_INSIDE_GANONS_CASTLE_COLLAPSE:
|
||||
case SCENE_TREASURE_BOX_SHOP:
|
||||
|
||||
if (gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] >= 0) {
|
||||
s16 X_Margins_SKC;
|
||||
s16 Y_Margins_SKC;
|
||||
@ -5533,6 +5527,7 @@ void Interface_Draw(PlayState* play) {
|
||||
}
|
||||
}
|
||||
|
||||
if (GameInteractor_Should(VB_RENDER_RUPEE_COUNTER, true, NULL)) {
|
||||
// Rupee Counter
|
||||
gDPPipeSync(OVERLAY_DISP++);
|
||||
|
||||
@ -5567,15 +5562,12 @@ void Interface_Draw(PlayState* play) {
|
||||
svar2 = rupeeDigitsFirst[CUR_UPG_VALUE(UPG_WALLET)];
|
||||
svar5 = rupeeDigitsCount[CUR_UPG_VALUE(UPG_WALLET)];
|
||||
|
||||
// Draw Rupee Counter. Hide in Boss Rush and when not having a wallet in rando.
|
||||
if (!IS_BOSS_RUSH && (!IS_RANDO || Flags_GetRandomizerInf(RAND_INF_HAS_WALLET))) {
|
||||
for (svar1 = 0, svar3 = 16; svar1 < svar5; svar1++, svar2++, svar3 += 8) {
|
||||
OVERLAY_DISP = Gfx_TextureI8(OVERLAY_DISP, ((u8*)digitTextures[interfaceCtx->counterDigits[svar2]]),
|
||||
8, 16, PosX_RC + svar3, PosY_RC, 8, 16, 1 << 10, 1 << 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Make sure item counts have black backgrounds
|
||||
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 0, 0, 0, interfaceCtx->magicAlpha);
|
||||
gDPSetEnvColor(OVERLAY_DISP++, 0, 0, 0, 0);
|
||||
|
@ -1804,10 +1804,6 @@ void* Play_LoadFile(PlayState* play, RomFile* file) {
|
||||
}
|
||||
|
||||
void Play_InitEnvironment(PlayState* play, s16 skyboxId) {
|
||||
// For entrance rando, ensure the correct weather state and sky mode is applied
|
||||
if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) {
|
||||
Entrance_OverrideWeatherState();
|
||||
}
|
||||
Skybox_Init(&play->state, &play->skyboxCtx, skyboxId);
|
||||
Environment_Init(play, &play->envCtx, 0);
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
#include "vt.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
#include "soh/Enhancements/randomizer/randomizer_entrance.h"
|
||||
#include "soh/Enhancements/randomizer/savefile.h"
|
||||
|
||||
@ -198,7 +200,7 @@ void Sram_OpenSave() {
|
||||
}
|
||||
}
|
||||
|
||||
if (!(IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE))) {
|
||||
if (GameInteractor_Should(VB_REVERT_SPOILING_ITEMS, true, NULL)) {
|
||||
for (i = 0; i < ARRAY_COUNT(gSpoilingItems); i++) {
|
||||
if (INV_CONTENT(ITEM_TRADE_ADULT) == gSpoilingItems[i]) {
|
||||
INV_CONTENT(gSpoilingItemReverts[i]) = gSpoilingItemReverts[i];
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "scenes/dungeons/ddan/ddan_scene.h"
|
||||
#include "objects/object_bwall/object_bwall.h"
|
||||
#include "objects/object_kingdodongo/object_kingdodongo.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
#define FLAGS ACTOR_FLAG_UPDATE_WHILE_CULLED
|
||||
@ -275,8 +276,7 @@ void BgBreakwall_Wait(BgBreakwall* this, PlayState* play) {
|
||||
}
|
||||
}
|
||||
|
||||
// Break the floor immediately in Boss Rush so the player can jump in the hole immediately.
|
||||
if (this->collider.base.acFlags & 2 || blueFireArrowHit || IS_BOSS_RUSH) {
|
||||
if (GameInteractor_Should(VB_BG_BREAKWALL_BREAK, this->collider.base.acFlags & 2 || blueFireArrowHit, NULL)) {
|
||||
Vec3f effectPos;
|
||||
s32 wallType = ((this->dyna.actor.params >> 13) & 3) & 0xFF;
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include "overlays/actors/ovl_Door_Warp1/z_door_warp1.h"
|
||||
#include "scenes/dungeons/ddan_boss/ddan_boss_room_1.h"
|
||||
#include "soh/frame_interpolation.h"
|
||||
#include "soh/Enhancements/boss-rush/BossRush.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
#include <stdlib.h> // malloc
|
||||
@ -341,8 +340,10 @@ void BossDodongo_Init(Actor* thisx, PlayState* play) {
|
||||
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_DOOR_WARP1, -890.0f, -1523.76f,
|
||||
-3304.0f, 0, 0, 0, WARP_DUNGEON_CHILD);
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_BG_BREAKWALL, -890.0f, -1523.76f, -3304.0f, 0, 0, 0, 0x6000, true);
|
||||
if (GameInteractor_Should(VB_SPAWN_HEART_CONTAINER, true, NULL)) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, -690.0f, -1523.76f, -3304.0f, 0, 0, 0, 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
this->actor.flags &= ~ACTOR_FLAG_TARGETABLE;
|
||||
|
||||
@ -1559,8 +1560,7 @@ void BossDodongo_DeathCutscene(BossDodongo* this, PlayState* play) {
|
||||
this->cameraAt.x = camera->at.x;
|
||||
this->cameraAt.y = camera->at.y;
|
||||
this->cameraAt.z = camera->at.z;
|
||||
gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_KING_DODONGO] = GAMEPLAYSTAT_TOTAL_TIME;
|
||||
BossRush_HandleCompleteBoss(play);
|
||||
GameInteractor_ExecuteOnBossDefeat(&this->actor);
|
||||
break;
|
||||
case 5:
|
||||
tempSin = Math_SinS(this->actor.shape.rot.y - 0x1388) * 150.0f;
|
||||
@ -1845,7 +1845,7 @@ void BossDodongo_DeathCutscene(BossDodongo* this, PlayState* play) {
|
||||
|
||||
if (this->unk_1DA == 820) {
|
||||
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_BOSS_CLEAR);
|
||||
if (!IS_BOSS_RUSH) {
|
||||
if (GameInteractor_Should(VB_SPAWN_HEART_CONTAINER, true, NULL)) {
|
||||
Actor_Spawn(
|
||||
&play->actorCtx, play, ACTOR_ITEM_B_HEART,
|
||||
Math_SinS(this->actor.shape.rot.y) * -50.0f + this->actor.world.pos.x, this->actor.world.pos.y,
|
||||
@ -1864,10 +1864,8 @@ void BossDodongo_DeathCutscene(BossDodongo* this, PlayState* play) {
|
||||
Play_ChangeCameraStatus(play, MAIN_CAM, CAM_STAT_ACTIVE);
|
||||
func_80064534(play, &play->csCtx);
|
||||
Player_SetCsActionWithHaltedActors(play, &this->actor, 7);
|
||||
if (!IS_BOSS_RUSH) {
|
||||
if (GameInteractor_Should(VB_SPAWN_BLUE_WARP, true, this)) {
|
||||
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_DOOR_WARP1, -890.0f, -1523.76f, -3304.0f, 0, 0, 0, WARP_DUNGEON_CHILD);
|
||||
} else {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_DOOR_WARP1, -890.0f, -1523.76f, -3304.0f, 0, 0, 0, WARP_DUNGEON_ADULT, false);
|
||||
}
|
||||
this->skelAnime.playSpeed = 0.0f;
|
||||
Flags_SetClear(play, play->roomCtx.curRoom.num);
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "objects/gameplay_keep/gameplay_keep.h"
|
||||
|
||||
#include "soh/frame_interpolation.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
#define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_HOSTILE | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_DRAW_WHILE_CULLED)
|
||||
|
||||
@ -227,7 +229,9 @@ void BossFd_Init(Actor* thisx, PlayState* play) {
|
||||
Actor_Kill(&this->actor);
|
||||
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_DOOR_WARP1, 0.0f, 100.0f, 0.0f, 0, 0, 0,
|
||||
WARP_DUNGEON_ADULT);
|
||||
if (GameInteractor_Should(VB_SPAWN_HEART_CONTAINER, true, NULL)) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, 0.0f, 100.0f, 200.0f, 0, 0, 0, 0, true);
|
||||
}
|
||||
} else {
|
||||
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_BOSS_FD2, this->actor.world.pos.x,
|
||||
this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, this->introState);
|
||||
@ -913,7 +917,7 @@ void BossFd_Fly(BossFd* this, PlayState* play) {
|
||||
this->actionFunc = BossFd_Wait;
|
||||
this->actor.world.pos.y -= 1000.0f;
|
||||
}
|
||||
if (this->timers[0] == 7 && !IS_BOSS_RUSH) {
|
||||
if (GameInteractor_Should(VB_SPAWN_HEART_CONTAINER, this->timers[0] == 7, NULL)) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, this->actor.world.pos.x,
|
||||
this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, 0, true);
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "overlays/actors/ovl_Door_Warp1/z_door_warp1.h"
|
||||
#include "vt.h"
|
||||
#include "soh/frame_interpolation.h"
|
||||
#include "soh/Enhancements/boss-rush/BossRush.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
#define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_HOSTILE | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_DRAW_WHILE_CULLED)
|
||||
|
||||
@ -789,12 +789,9 @@ void BossFd2_Death(BossFd2* this, PlayState* play) {
|
||||
this->deathCamera = 0;
|
||||
func_80064534(play, &play->csCtx);
|
||||
Player_SetCsActionWithHaltedActors(play, &this->actor, 7);
|
||||
if (!IS_BOSS_RUSH) {
|
||||
if (GameInteractor_Should(VB_SPAWN_BLUE_WARP, true, this)) {
|
||||
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_DOOR_WARP1, 0.0f, 100.0f, 0.0f, 0, 0,
|
||||
0, WARP_DUNGEON_ADULT);
|
||||
} else {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_DOOR_WARP1, 0.0f, 100.0f, 0.0f, 0, 0, 0,
|
||||
WARP_DUNGEON_ADULT, true);
|
||||
}
|
||||
Flags_SetClear(play, play->roomCtx.curRoom.num);
|
||||
}
|
||||
@ -899,8 +896,7 @@ void BossFd2_CollisionCheck(BossFd2* this, PlayState* play) {
|
||||
Audio_QueueSeqCmd(0x1 << 28 | SEQ_PLAYER_BGM_MAIN << 24 | 0x100FF);
|
||||
Audio_PlayActorSound2(&this->actor, NA_SE_EN_VALVAISA_DEAD);
|
||||
Enemy_StartFinishingBlow(play, &this->actor);
|
||||
gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_VOLVAGIA] = GAMEPLAYSTAT_TOTAL_TIME;
|
||||
BossRush_HandleCompleteBoss(play);
|
||||
GameInteractor_ExecuteOnBossDefeat(&this->actor);
|
||||
} else if (damage) {
|
||||
BossFd2_SetupDamaged(this, play);
|
||||
this->work[FD2_DAMAGE_FLASH_TIMER] = 10;
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "assets/scenes/dungeons/ganon_boss/ganon_boss_scene.h"
|
||||
|
||||
#include "soh/frame_interpolation.h"
|
||||
#include "soh/Enhancements/boss-rush/BossRush.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@ -581,7 +581,7 @@ void BossGanon_IntroCutscene(BossGanon* this, PlayState* play) {
|
||||
BossGanon_SetIntroCsCamera(this, 11);
|
||||
this->unk_198 = 2;
|
||||
this->timers[2] = 110;
|
||||
if (!(IS_BOSS_RUSH && gSaveContext.bossRushOptions[BR_OPTIONS_HEAL] == BR_CHOICE_HEAL_NEVER)) {
|
||||
if (GameInteractor_Should(VB_GANON_HEAL_BEFORE_FIGHT, true, NULL)) {
|
||||
gSaveContext.healthAccumulator = 0x140;
|
||||
}
|
||||
Audio_QueueSeqCmd(NA_BGM_STOP);
|
||||
@ -2806,8 +2806,7 @@ void BossGanon_UpdateDamage(BossGanon* this, PlayState* play) {
|
||||
func_80078914(&sZeroVec, NA_SE_EN_LAST_DAMAGE);
|
||||
Audio_QueueSeqCmd(0x100100FF);
|
||||
this->screenFlashTimer = 4;
|
||||
gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_GANONDORF] = GAMEPLAYSTAT_TOTAL_TIME;
|
||||
BossRush_HandleCompleteBoss(play);
|
||||
GameInteractor_ExecuteOnBossDefeat(&this->actor);
|
||||
} else {
|
||||
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_DAMAGE2);
|
||||
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_CUTBODY);
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "objects/object_ganon_anime3/object_ganon_anime3.h"
|
||||
#include "objects/object_geff/object_geff.h"
|
||||
#include "soh/frame_interpolation.h"
|
||||
#include "soh/Enhancements/boss-rush/BossRush.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@ -1688,9 +1688,7 @@ void func_8090120C(BossGanon2* this, PlayState* play) {
|
||||
if ((ABS(temp_a0_2) < 0x2000) && (sqrtf(SQ(temp_f14) + SQ(temp_f12)) < 70.0f) &&
|
||||
(player->meleeWeaponState != 0) && (player->heldItemAction == PLAYER_IA_SWORD_MASTER)) {
|
||||
func_80064520(play, &play->csCtx);
|
||||
gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_GANON] = GAMEPLAYSTAT_TOTAL_TIME;
|
||||
BossRush_HandleCompleteBoss(play);
|
||||
gSaveContext.sohStats.gameComplete = true;
|
||||
GameInteractor_ExecuteOnBossDefeat(&this->actor);
|
||||
this->unk_39E = Play_CreateSubCamera(play);
|
||||
Play_ChangeCameraStatus(play, MAIN_CAM, CAM_STAT_WAIT);
|
||||
Play_ChangeCameraStatus(play, this->unk_39E, CAM_STAT_ACTIVE);
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "overlays/effects/ovl_Effect_Ss_Fhg_Flash/z_eff_ss_fhg_flash.h"
|
||||
#include "overlays/effects/ovl_Effect_Ss_Hahen/z_eff_ss_hahen.h"
|
||||
#include "overlays/actors/ovl_Door_Warp1/z_door_warp1.h"
|
||||
#include "soh/Enhancements/boss-rush/BossRush.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
#define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_HOSTILE | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_DRAW_WHILE_CULLED)
|
||||
@ -234,10 +233,14 @@ void BossGanondrof_Init(Actor* thisx, PlayState* play) {
|
||||
this->actor.flags &= ~ACTOR_FLAG_TARGETABLE;
|
||||
if (Flags_GetClear(play, play->roomCtx.curRoom.num)) {
|
||||
Actor_Kill(&this->actor);
|
||||
if (GameInteractor_Should(VB_SPAWN_BLUE_WARP, true, this)) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_DOOR_WARP1, GND_BOSSROOM_CENTER_X, GND_BOSSROOM_CENTER_Y,
|
||||
GND_BOSSROOM_CENTER_Z, 0, 0, 0, WARP_DUNGEON_ADULT, true);
|
||||
}
|
||||
if (GameInteractor_Should(VB_SPAWN_HEART_CONTAINER, true, NULL)) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, 200.0f + GND_BOSSROOM_CENTER_X,
|
||||
GND_BOSSROOM_CENTER_Y, GND_BOSSROOM_CENTER_Z, 0, 0, 0, 0, true);
|
||||
}
|
||||
} else {
|
||||
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_EN_FHG, this->actor.world.pos.x,
|
||||
this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, this->actor.params);
|
||||
@ -1059,9 +1062,11 @@ void BossGanondrof_Death(BossGanondrof* this, PlayState* play) {
|
||||
bodyDecayLevel = 10;
|
||||
if (this->timers[0] == 150) {
|
||||
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_BOSS_CLEAR);
|
||||
if (GameInteractor_Should(VB_SPAWN_BLUE_WARP, true, this)) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_DOOR_WARP1, GND_BOSSROOM_CENTER_X, GND_BOSSROOM_CENTER_Y,
|
||||
GND_BOSSROOM_CENTER_Z, 0, 0, 0, WARP_DUNGEON_ADULT, true);
|
||||
}
|
||||
}
|
||||
|
||||
Math_ApproachZeroF(&this->cameraEye.y, 0.05f, 1.0f); // GND_BOSSROOM_CENTER_Y + 33.0f
|
||||
Math_ApproachF(&this->cameraEye.z, GND_BOSSROOM_CENTER_Z + 170.0f, 0.05f, 2.0f);
|
||||
@ -1076,7 +1081,7 @@ void BossGanondrof_Death(BossGanondrof* this, PlayState* play) {
|
||||
this->deathCamera = 0;
|
||||
func_80064534(play, &play->csCtx);
|
||||
Player_SetCsActionWithHaltedActors(play, &this->actor, 7);
|
||||
if (!IS_BOSS_RUSH) {
|
||||
if (GameInteractor_Should(VB_SPAWN_HEART_CONTAINER, true, NULL)) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, GND_BOSSROOM_CENTER_X, GND_BOSSROOM_CENTER_Y,
|
||||
GND_BOSSROOM_CENTER_Z + 200.0f, 0, 0, 0, 0, true);
|
||||
}
|
||||
@ -1219,8 +1224,7 @@ void BossGanondrof_CollisionCheck(BossGanondrof* this, PlayState* play) {
|
||||
if ((s8)this->actor.colChkInfo.health <= 0) {
|
||||
BossGanondrof_SetupDeath(this, play);
|
||||
Enemy_StartFinishingBlow(play, &this->actor);
|
||||
gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_PHANTOM_GANON] = GAMEPLAYSTAT_TOTAL_TIME;
|
||||
BossRush_HandleCompleteBoss(play);
|
||||
GameInteractor_ExecuteOnBossDefeat(&this->actor);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,8 @@
|
||||
#include "overlays/actors/ovl_En_Goma/z_en_goma.h"
|
||||
#include "overlays/actors/ovl_Door_Shutter/z_door_shutter.h"
|
||||
#include "overlays/actors/ovl_Door_Warp1/z_door_warp1.h"
|
||||
#include "soh/Enhancements/boss-rush/BossRush.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
#define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_HOSTILE | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_DRAW_WHILE_CULLED)
|
||||
|
||||
@ -339,10 +340,14 @@ void BossGoma_Init(Actor* thisx, PlayState* play) {
|
||||
|
||||
if (Flags_GetClear(play, play->roomCtx.curRoom.num)) {
|
||||
Actor_Kill(&this->actor);
|
||||
if (GameInteractor_Should(VB_SPAWN_BLUE_WARP, true, this)) {
|
||||
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_DOOR_WARP1, 0.0f, -640.0f, 0.0f, 0, 0,
|
||||
0, WARP_DUNGEON_CHILD);
|
||||
}
|
||||
if (GameInteractor_Should(VB_SPAWN_HEART_CONTAINER, true, NULL)) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, 141.0f, -640.0f, -84.0f, 0, 0, 0, 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < ARRAY_COUNT(sClearPixelTex16); i++) {
|
||||
sClearPixelTex16[i] = 0;
|
||||
@ -1118,7 +1123,7 @@ void BossGoma_Defeated(BossGoma* this, PlayState* play) {
|
||||
this->timer = 70;
|
||||
this->decayingProgress = 0;
|
||||
this->subCameraFollowSpeed = 0.0f;
|
||||
if (!IS_BOSS_RUSH) {
|
||||
if (GameInteractor_Should(VB_SPAWN_HEART_CONTAINER, true, NULL)) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, this->actor.world.pos.x,
|
||||
this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, 0, true);
|
||||
}
|
||||
@ -1152,12 +1157,9 @@ void BossGoma_Defeated(BossGoma* this, PlayState* play) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!IS_BOSS_RUSH) {
|
||||
if (GameInteractor_Should(VB_SPAWN_BLUE_WARP, true, this)) {
|
||||
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_DOOR_WARP1, childPos.x,
|
||||
this->actor.world.pos.y, childPos.z, 0, 0, 0, WARP_DUNGEON_CHILD);
|
||||
} else {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_DOOR_WARP1, childPos.x, this->actor.world.pos.y,
|
||||
childPos.z, 0, 0, 0, WARP_DUNGEON_ADULT, false);
|
||||
}
|
||||
Flags_SetClear(play, play->roomCtx.curRoom.num);
|
||||
}
|
||||
@ -1841,8 +1843,7 @@ void BossGoma_UpdateHit(BossGoma* this, PlayState* play) {
|
||||
} else {
|
||||
BossGoma_SetupDefeated(this, play);
|
||||
Enemy_StartFinishingBlow(play, &this->actor);
|
||||
gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_GOHMA] = GAMEPLAYSTAT_TOTAL_TIME;
|
||||
BossRush_HandleCompleteBoss(play);
|
||||
GameInteractor_ExecuteOnBossDefeat(&this->actor);
|
||||
}
|
||||
|
||||
this->invincibilityFrames = 10;
|
||||
|
@ -12,7 +12,8 @@
|
||||
#include "vt.h"
|
||||
|
||||
#include "soh/frame_interpolation.h"
|
||||
#include "soh/Enhancements/boss-rush/BossRush.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@ -370,9 +371,13 @@ void BossMo_Init(Actor* thisx, PlayState* play2) {
|
||||
Collider_SetCylinder(play, &this->coreCollider, &this->actor, &sCylinderInit);
|
||||
if (Flags_GetClear(play, play->roomCtx.curRoom.num)) {
|
||||
Actor_Kill(&this->actor);
|
||||
if (GameInteractor_Should(VB_SPAWN_BLUE_WARP, true, this)) {
|
||||
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_DOOR_WARP1, 0.0f, -280.0f, 0.0f, 0,
|
||||
0, 0, WARP_DUNGEON_ADULT);
|
||||
}
|
||||
if (GameInteractor_Should(VB_SPAWN_HEART_CONTAINER, true, NULL)) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, -200.0f, -280.0f, 0.0f, 0, 0, 0, 0, true);
|
||||
}
|
||||
play->roomCtx.unk_74[0] = 0xFF;
|
||||
MO_WATER_LEVEL(play) = -500;
|
||||
return;
|
||||
@ -1116,16 +1121,17 @@ void BossMo_Tentacle(BossMo* this, PlayState* play) {
|
||||
BossMo_SpawnDroplet(MO_FX_DROPLET, (BossMoEffect*)play->specialEffects, &spD4, &spE0,
|
||||
((300 - indS1) * .0015f) + 0.13f);
|
||||
}
|
||||
if (!IS_BOSS_RUSH) {
|
||||
if (GameInteractor_Should(VB_SPAWN_BLUE_WARP, true, this)) {
|
||||
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_DOOR_WARP1,
|
||||
this->actor.world.pos.x, -280.0f, this->actor.world.pos.z, 0, 0, 0,
|
||||
WARP_DUNGEON_ADULT);
|
||||
}
|
||||
|
||||
if (GameInteractor_Should(VB_SPAWN_HEART_CONTAINER, true, NULL)) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, this->actor.world.pos.x + 200.0f,
|
||||
-280.0f, this->actor.world.pos.z, 0, 0, 0, 0, true);
|
||||
} else {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_DOOR_WARP1, this->actor.world.pos.x, -280.0f,
|
||||
this->actor.world.pos.z, 0, 0, 0, WARP_DUNGEON_ADULT, true);
|
||||
}
|
||||
|
||||
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_BOSS_CLEAR);
|
||||
Flags_SetClear(play, play->roomCtx.curRoom.num);
|
||||
}
|
||||
@ -1793,8 +1799,7 @@ void BossMo_CoreCollisionCheck(BossMo* this, PlayState* play) {
|
||||
if (((sMorphaTent1->csCamera == 0) && (sMorphaTent2 == NULL)) ||
|
||||
((sMorphaTent1->csCamera == 0) && (sMorphaTent2 != NULL) && (sMorphaTent2->csCamera == 0))) {
|
||||
Enemy_StartFinishingBlow(play, &this->actor);
|
||||
gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_MORPHA] = GAMEPLAYSTAT_TOTAL_TIME;
|
||||
BossRush_HandleCompleteBoss(play);
|
||||
GameInteractor_ExecuteOnBossDefeat(&this->actor);
|
||||
Audio_QueueSeqCmd(0x1 << 28 | SEQ_PLAYER_BGM_MAIN << 24 | 0x100FF);
|
||||
this->csState = MO_DEATH_START;
|
||||
sMorphaTent1->drawActor = false;
|
||||
|
@ -11,7 +11,8 @@
|
||||
#include "overlays/actors/ovl_Bg_Sst_Floor/z_bg_sst_floor.h"
|
||||
#include "overlays/actors/ovl_Door_Warp1/z_door_warp1.h"
|
||||
#include "soh/frame_interpolation.h"
|
||||
#include "soh/Enhancements/boss-rush/BossRush.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
#define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_HOSTILE | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_DRAW_WHILE_CULLED | ACTOR_FLAG_DRAGGED_BY_HOOKSHOT)
|
||||
|
||||
@ -293,10 +294,14 @@ void BossSst_Init(Actor* thisx, PlayState* play2) {
|
||||
this->actor.home.pos = this->actor.world.pos;
|
||||
this->actor.shape.rot.y = 0;
|
||||
if (Flags_GetClear(play, play->roomCtx.curRoom.num)) {
|
||||
if (GameInteractor_Should(VB_SPAWN_BLUE_WARP, true, this)) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_DOOR_WARP1, ROOM_CENTER_X, ROOM_CENTER_Y,
|
||||
ROOM_CENTER_Z + 400.0f, 0, 0, 0, WARP_DUNGEON_ADULT, true);
|
||||
}
|
||||
if (GameInteractor_Should(VB_SPAWN_HEART_CONTAINER, true, NULL)) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, ROOM_CENTER_X, ROOM_CENTER_Y,
|
||||
ROOM_CENTER_Z - 200.0f, 0, 0, 0, 0, true);
|
||||
}
|
||||
Actor_Kill(&this->actor);
|
||||
} else {
|
||||
sHands[LEFT] =
|
||||
@ -1202,9 +1207,11 @@ void BossSst_HeadFinish(BossSst* this, PlayState* play) {
|
||||
Flags_SetClear(play, play->roomCtx.curRoom.num);
|
||||
}
|
||||
} else if (this->effects[0].alpha == 0) {
|
||||
if (GameInteractor_Should(VB_SPAWN_BLUE_WARP, true, this)) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_DOOR_WARP1, ROOM_CENTER_X, ROOM_CENTER_Y, ROOM_CENTER_Z, 0, 0, 0,
|
||||
WARP_DUNGEON_ADULT, true);
|
||||
if (!IS_BOSS_RUSH) {
|
||||
}
|
||||
if (GameInteractor_Should(VB_SPAWN_HEART_CONTAINER, true, NULL)) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART,
|
||||
(Math_SinS(this->actor.shape.rot.y) * 200.0f) + ROOM_CENTER_X, ROOM_CENTER_Y,
|
||||
Math_CosS(this->actor.shape.rot.y) * 200.0f + ROOM_CENTER_Z, 0, 0, 0, 0, true);
|
||||
@ -2563,8 +2570,7 @@ void BossSst_HeadCollisionCheck(BossSst* this, PlayState* play) {
|
||||
if (Actor_ApplyDamage(&this->actor) == 0) {
|
||||
Enemy_StartFinishingBlow(play, &this->actor);
|
||||
BossSst_HeadSetupDeath(this, play);
|
||||
gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_BONGO_BONGO] = GAMEPLAYSTAT_TOTAL_TIME;
|
||||
BossRush_HandleCompleteBoss(play);
|
||||
GameInteractor_ExecuteOnBossDefeat(&this->actor);
|
||||
} else {
|
||||
BossSst_HeadSetupDamage(this);
|
||||
}
|
||||
|
@ -4,7 +4,8 @@
|
||||
#include "objects/object_tw/object_tw.h"
|
||||
#include "overlays/actors/ovl_Door_Warp1/z_door_warp1.h"
|
||||
#include "soh/frame_interpolation.h"
|
||||
#include "soh/Enhancements/boss-rush/BossRush.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@ -535,9 +536,14 @@ void BossTw_Init(Actor* thisx, PlayState* play2) {
|
||||
if (Flags_GetClear(play, play->roomCtx.curRoom.num)) {
|
||||
// twinrova has been defeated.
|
||||
Actor_Kill(&this->actor);
|
||||
if (GameInteractor_Should(VB_SPAWN_BLUE_WARP, true, this)) {
|
||||
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_DOOR_WARP1, 600.0f, 230.0f, 0.0f, 0,
|
||||
0, 0, WARP_DUNGEON_ADULT);
|
||||
}
|
||||
|
||||
if (GameInteractor_Should(VB_SPAWN_HEART_CONTAINER, true, NULL)) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, -600.0f, 230.0f, 0.0f, 0, 0, 0, 0, true);
|
||||
}
|
||||
} else {
|
||||
sKotakePtr = (BossTw*)Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_BOSS_TW,
|
||||
this->actor.world.pos.x, this->actor.world.pos.y,
|
||||
@ -2795,14 +2801,15 @@ void BossTw_TwinrovaDeathCS(BossTw* this, PlayState* play) {
|
||||
func_80064534(play, &play->csCtx);
|
||||
Player_SetCsActionWithHaltedActors(play, &this->actor, 7);
|
||||
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_BOSS_CLEAR);
|
||||
if (!IS_BOSS_RUSH) {
|
||||
if (GameInteractor_Should(VB_SPAWN_BLUE_WARP, true, this)) {
|
||||
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_DOOR_WARP1, 600.0f, 230.0f, 0.0f, 0,
|
||||
0, 0, WARP_DUNGEON_ADULT);
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, -600.0f, 230.f, 0.0f, 0, 0, 0, 0, true);
|
||||
} else {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_DOOR_WARP1, 600.0f, 230.0f, 0.0f, 0, 0, 0,
|
||||
WARP_DUNGEON_ADULT, true);
|
||||
}
|
||||
|
||||
if (GameInteractor_Should(VB_SPAWN_HEART_CONTAINER, true, NULL)) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, -600.0f, 230.f, 0.0f, 0, 0, 0, 0, true);
|
||||
}
|
||||
|
||||
this->actor.world.pos.y = -2000.0f;
|
||||
this->workf[UNK_F18] = 0.0f;
|
||||
sKoumePtr->visible = sKotakePtr->visible = false;
|
||||
@ -5289,8 +5296,7 @@ void BossTw_TwinrovaDamage(BossTw* this, PlayState* play, u8 damage) {
|
||||
BossTw_TwinrovaSetupDeathCS(this, play);
|
||||
Enemy_StartFinishingBlow(play, &this->actor);
|
||||
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_YOUNG_DEAD);
|
||||
gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_TWINROVA] = GAMEPLAYSTAT_TOTAL_TIME;
|
||||
BossRush_HandleCompleteBoss(play);
|
||||
GameInteractor_ExecuteOnBossDefeat(&this->actor);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,8 @@
|
||||
#include "overlays/actors/ovl_Door_Warp1/z_door_warp1.h"
|
||||
|
||||
#include "soh/frame_interpolation.h"
|
||||
#include "soh/Enhancements/boss-rush/BossRush.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
#define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_HOSTILE | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_DRAW_WHILE_CULLED)
|
||||
|
||||
@ -641,11 +642,16 @@ void BossVa_Init(Actor* thisx, PlayState* play2) {
|
||||
if (Flags_GetEventChkInf(EVENTCHKINF_USED_JABU_JABUS_BELLY_BLUE_WARP)) {
|
||||
warpId = ACTOR_DOOR_WARP1;
|
||||
}
|
||||
if (GameInteractor_Should(VB_SPAWN_BLUE_WARP, true, this)) {
|
||||
Actor_Spawn(&play->actorCtx, play, warpId, this->actor.world.pos.x, this->actor.world.pos.y,
|
||||
this->actor.world.pos.z, 0, 0, 0,
|
||||
0, true); //! params could be WARP_DUNGEON_CHILD however this can also spawn Ru1
|
||||
}
|
||||
|
||||
if (GameInteractor_Should(VB_SPAWN_HEART_CONTAINER, true, NULL)) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, this->actor.world.pos.x + 160.0f,
|
||||
this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, 0, true);
|
||||
}
|
||||
sDoorState = 100;
|
||||
Actor_Kill(&this->actor);
|
||||
} else {
|
||||
@ -1401,8 +1407,7 @@ void BossVa_BodyPhase4(BossVa* this, PlayState* play) {
|
||||
if (sFightPhase >= PHASE_DEATH) {
|
||||
BossVa_SetupBodyDeath(this, play);
|
||||
Enemy_StartFinishingBlow(play, &this->actor);
|
||||
gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_BARINADE] = GAMEPLAYSTAT_TOTAL_TIME;
|
||||
BossRush_HandleCompleteBoss(play);
|
||||
GameInteractor_ExecuteOnBossDefeat(&this->actor);
|
||||
return;
|
||||
}
|
||||
this->actor.speedXZ = -10.0f;
|
||||
@ -1657,7 +1662,7 @@ void BossVa_BodyDeath(BossVa* this, PlayState* play) {
|
||||
Player_SetCsActionWithHaltedActors(play, &this->actor, 7);
|
||||
sCsState++;
|
||||
|
||||
if (!IS_BOSS_RUSH) {
|
||||
if (GameInteractor_Should(VB_SPAWN_HEART_CONTAINER, true, NULL)) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, this->actor.world.pos.x,
|
||||
this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, 0, true);
|
||||
}
|
||||
@ -1669,12 +1674,9 @@ void BossVa_BodyDeath(BossVa* this, PlayState* play) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!IS_BOSS_RUSH) {
|
||||
if (GameInteractor_Should(VB_SPAWN_BLUE_WARP, true, this)) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_EN_RU1, sWarpPos[sp7C].x, sWarpPos[sp7C].y,
|
||||
sWarpPos[sp7C].z, 0, 0, 0, 0, true);
|
||||
} else {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_DOOR_WARP1, sWarpPos[sp7C].x, sWarpPos[sp7C].y,
|
||||
sWarpPos[sp7C].z, 0, 0, 0, WARP_DUNGEON_ADULT, false);
|
||||
}
|
||||
}
|
||||
case DEATH_FINISH:
|
||||
|
@ -426,12 +426,6 @@ void DemoKankyo_KillDoorOfTimeCollision(DemoKankyo* this, PlayState* play) {
|
||||
void DemoKankyo_Update(Actor* thisx, PlayState* play) {
|
||||
DemoKankyo* this = (DemoKankyo*)thisx;
|
||||
this->actionFunc(this, play);
|
||||
|
||||
// In ER, override the warp song locations. Also removes the warp song cutscene
|
||||
if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES) &&
|
||||
thisx->params == 0x000F) { // Warp Song particles
|
||||
Entrance_SetWarpSongEntrance();
|
||||
}
|
||||
}
|
||||
|
||||
void DemoKankyo_Draw(Actor* thisx, PlayState* play) {
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include "overlays/actors/ovl_En_Elf/z_en_elf.h"
|
||||
#include "overlays/actors/ovl_Door_Warp1/z_door_warp1.h"
|
||||
#include "objects/object_sa/object_sa.h"
|
||||
#include "soh/Enhancements/boss-rush/BossRush.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
#include "vt.h"
|
||||
@ -257,7 +256,6 @@ void func_8098E960(DemoSa* this, PlayState* play) {
|
||||
|
||||
if ((gSaveContext.chamberCutsceneNum == 0) && (gSaveContext.sceneSetupIndex < 4)) {
|
||||
player = GET_PLAYER(play);
|
||||
if (!IS_BOSS_RUSH) {
|
||||
this->action = 1;
|
||||
play->csCtx.segment = D_8099010C;
|
||||
gSaveContext.cutsceneTrigger = 2;
|
||||
@ -265,13 +263,6 @@ void func_8098E960(DemoSa* this, PlayState* play) {
|
||||
Item_Give(play, ITEM_MEDALLION_FOREST);
|
||||
}
|
||||
player->actor.world.rot.y = player->actor.shape.rot.y = this->actor.world.rot.y + 0x8000;
|
||||
} else {
|
||||
this->action = 1;
|
||||
if (gSaveContext.linkAge == LINK_AGE_CHILD) {
|
||||
player->actor.world.rot.y = player->actor.shape.rot.y = -5461 + 0x8000;
|
||||
}
|
||||
BossRush_SpawnBlueWarps(play);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -749,9 +749,7 @@ void DoorWarp1_AdultWarpOut(DoorWarp1* this, PlayState* play) {
|
||||
this->warpTimer++;
|
||||
|
||||
if (this->warpTimer > sWarpTimerTarget && gSaveContext.nextCutsceneIndex == 0xFFEF) {
|
||||
if (IS_BOSS_RUSH) {
|
||||
BossRush_HandleBlueWarp(play, this->actor.world.pos.x, this->actor.world.pos.z);
|
||||
} else if (play->sceneNum == SCENE_FOREST_TEMPLE_BOSS) {
|
||||
if (play->sceneNum == SCENE_FOREST_TEMPLE_BOSS) {
|
||||
if (GameInteractor_Should(VB_PLAY_BLUE_WARP_CS, !Flags_GetEventChkInf(EVENTCHKINF_USED_FOREST_TEMPLE_BLUE_WARP), EVENTCHKINF_USED_FOREST_TEMPLE_BLUE_WARP)) {
|
||||
Flags_SetEventChkInf(EVENTCHKINF_USED_FOREST_TEMPLE_BLUE_WARP);
|
||||
if (GameInteractor_Should(VB_GIVE_ITEM_FROM_BLUE_WARP, true, ITEM_MEDALLION_FOREST)) {
|
||||
|
@ -3,6 +3,8 @@
|
||||
#include "overlays/actors/ovl_En_Syateki_Niw/z_en_syateki_niw.h"
|
||||
#include "overlays/actors/ovl_En_Ex_Item/z_en_ex_item.h"
|
||||
#include "objects/object_bg/object_bg.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
#define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_DRAW_WHILE_CULLED | ACTOR_FLAG_NO_LOCKON)
|
||||
|
||||
@ -141,27 +143,12 @@ void EnBomBowMan_BlinkAwake(EnBomBowlMan* this, PlayState* play) {
|
||||
if (frameCount == 30.0f) {
|
||||
this->dialogState = TEXT_STATE_EVENT;
|
||||
|
||||
// Check for beaten Dodongo's Cavern if Rando is disabled
|
||||
if (!IS_RANDO) {
|
||||
if ((Flags_GetEventChkInf(EVENTCHKINF_USED_DODONGOS_CAVERN_BLUE_WARP)) || BREG(2)) {
|
||||
if (GameInteractor_Should(VB_BE_ABLE_TO_PLAY_BOMBCHU_BOWLING, (Flags_GetEventChkInf(EVENTCHKINF_USED_DODONGOS_CAVERN_BLUE_WARP)) || BREG(2), NULL)) {
|
||||
this->actor.textId = 0xBF;
|
||||
} else {
|
||||
this->actor.textId = 0x7058;
|
||||
}
|
||||
}
|
||||
|
||||
// In randomizer, only check for bomb bag when bombchus aren't in logic
|
||||
// and only check for bombchus when bombchus are in logic
|
||||
if (IS_RANDO) {
|
||||
u8 bombchusInLogic = Randomizer_GetSettingValue(RSK_BOMBCHUS_IN_LOGIC);
|
||||
if ((!bombchusInLogic && INV_CONTENT(ITEM_BOMB) == ITEM_NONE) ||
|
||||
(bombchusInLogic && INV_CONTENT(ITEM_BOMBCHU) == ITEM_NONE)) {
|
||||
this->actor.textId = 0x7058;
|
||||
} else {
|
||||
this->actor.textId = 0xBF;
|
||||
}
|
||||
}
|
||||
}
|
||||
Message_ContinueTextbox(play, this->actor.textId);
|
||||
|
||||
if ((this->eyeTextureIndex == 0) && (this->eyeMode == CHU_GIRL_EYES_BLINK_RAPIDLY) && (this->blinkTimer == 0)) {
|
||||
|
@ -207,11 +207,6 @@ void EnBox_Init(Actor* thisx, PlayState* play2) {
|
||||
if (play->sceneNum == SCENE_FOREST_TEMPLE && this->dyna.actor.params == 10222) {
|
||||
this->movementFlags = ENBOX_MOVE_IMMOBILE;
|
||||
}
|
||||
|
||||
// Delete chests in Boss Rush. Mainly for the chest in King Dodongo's boss room.
|
||||
if (IS_BOSS_RUSH) {
|
||||
EnBox_SetupAction(this, EnBox_Destroy);
|
||||
}
|
||||
}
|
||||
|
||||
void EnBox_Destroy(Actor* thisx, PlayState* play) {
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include "z_en_kakasi2.h"
|
||||
#include "vt.h"
|
||||
#include "objects/object_ka/object_ka.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
#define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_DRAW_WHILE_CULLED | ACTOR_FLAG_NO_FREEZE_OCARINA | ACTOR_FLAG_NO_LOCKON)
|
||||
|
||||
@ -117,20 +119,7 @@ void func_80A90264(EnKakasi2* this, PlayState* play) {
|
||||
|
||||
this->unk_194++;
|
||||
|
||||
int ocarinaButtonCount = 0;
|
||||
for (int i = RAND_INF_HAS_OCARINA_A; i <= RAND_INF_HAS_OCARINA_C_DOWN; i++) {
|
||||
if (Flags_GetRandomizerInf(i)) {
|
||||
ocarinaButtonCount++;
|
||||
}
|
||||
}
|
||||
|
||||
bool hasTwoOcarinaButtons = !IS_RANDO || ocarinaButtonCount >= 2;
|
||||
|
||||
bool skipScarecrow = hasTwoOcarinaButtons && play->msgCtx.msgMode == MSGMODE_OCARINA_PLAYING &&
|
||||
((CVarGetInteger(CVAR_ENHANCEMENT("InstantScarecrow"), 0) && gSaveContext.scarecrowSpawnSongSet) ||
|
||||
(IS_RANDO && Randomizer_GetSettingValue(RSK_SKIP_SCARECROWS_SONG)));
|
||||
|
||||
if ((BREG(1) != 0) || skipScarecrow && (this->actor.xzDistToPlayer < this->maxSpawnDistance.x) &&
|
||||
if ((BREG(1) != 0) || GameInteractor_Should(VB_SKIP_SCARECROWS_SONG, false, NULL) && (this->actor.xzDistToPlayer < this->maxSpawnDistance.x) &&
|
||||
(fabsf(player->actor.world.pos.y - this->actor.world.pos.y) < this->maxSpawnDistance.y)) {
|
||||
this->actor.draw = func_80A90948;
|
||||
Collider_InitCylinder(play, &this->collider);
|
||||
|
@ -277,11 +277,6 @@ void EnKusa_Destroy(Actor* thisx, PlayState* play2) {
|
||||
}
|
||||
|
||||
void EnKusa_SetupWaitObject(EnKusa* this) {
|
||||
// Kill bushes in Boss Rush. Used in Gohma's arena.
|
||||
if (IS_BOSS_RUSH) {
|
||||
Actor_Kill(this);
|
||||
}
|
||||
|
||||
EnKusa_SetupAction(this, EnKusa_WaitObject);
|
||||
}
|
||||
|
||||
|
@ -157,15 +157,6 @@ void EnSyatekiMan_Init(Actor* thisx, PlayState* play) {
|
||||
s32 pad;
|
||||
EnSyatekiMan* this = (EnSyatekiMan*)thisx;
|
||||
|
||||
if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_INTERIOR_ENTRANCES)) {
|
||||
// If child is in the adult shooting gallery or adult in the child shooting gallery, then despawn the shooting gallery man
|
||||
if ((LINK_IS_CHILD && Entrance_SceneAndSpawnAre(SCENE_SHOOTING_GALLERY, 0x00)) || //Kakariko Village -> Adult Shooting Gallery, index 003B in the entrance table
|
||||
(LINK_IS_ADULT && Entrance_SceneAndSpawnAre(SCENE_SHOOTING_GALLERY, 0x01))) { //Market -> Child Shooting Gallery, index 016D in the entrance table
|
||||
Actor_Kill(thisx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
osSyncPrintf("\n\n");
|
||||
// "Old man appeared!! Muhohohohohohohon"
|
||||
osSyncPrintf(VT_FGCOL(GREEN) "☆☆☆☆☆ 親父登場!!むほほほほほほほーん ☆☆☆☆☆ \n" VT_RST);
|
||||
|
@ -200,12 +200,7 @@ void ObjComb_Update(Actor* thisx, PlayState* play) {
|
||||
|
||||
this->unk_1B2 += 0x2EE0;
|
||||
this->actionFunc(this, play);
|
||||
s16 wiggleOffset = this->unk_1B0;
|
||||
|
||||
if (IS_RANDO && this->unk_1B0 < 0) {
|
||||
wiggleOffset = 0;
|
||||
}
|
||||
this->actor.shape.rot.x = Math_SinS(this->unk_1B2) * wiggleOffset + this->actor.home.rot.x;
|
||||
this->actor.shape.rot.x = Math_SinS(this->unk_1B2) * this->unk_1B0 + this->actor.home.rot.x;
|
||||
}
|
||||
|
||||
void ObjComb_Draw(Actor* thisx, PlayState* play) {
|
||||
|
@ -273,15 +273,6 @@ void ObjOshihiki_Init(Actor* thisx, PlayState* play2) {
|
||||
PlayState* play = play2;
|
||||
ObjOshihiki* this = (ObjOshihiki*)thisx;
|
||||
|
||||
// In MQ Spirit, remove the large silver block in the hole as child so the chest in the silver block hallway
|
||||
// can be guaranteed accessible
|
||||
if (IS_RANDO && LINK_IS_CHILD && ResourceMgr_IsGameMasterQuest() &&
|
||||
play->sceneNum == SCENE_SPIRIT_TEMPLE && thisx->room == 6 && // Spirit Temple silver block hallway
|
||||
thisx->params == 0x9C7) { // Silver block that is marked as in the hole
|
||||
Actor_Kill(thisx);
|
||||
return;
|
||||
}
|
||||
|
||||
ObjOshihiki_CheckType(this, play);
|
||||
|
||||
if ((((this->dyna.actor.params >> 8) & 0xFF) >= 0) && (((this->dyna.actor.params >> 8) & 0xFF) <= 0x3F)) {
|
||||
|
@ -221,11 +221,6 @@ void ObjTsubo_WaterBreak(ObjTsubo* this, PlayState* play) {
|
||||
}
|
||||
|
||||
void ObjTsubo_SetupWaitForObject(ObjTsubo* this) {
|
||||
// Remove pots in Boss Rush. Present in Barinade's and Ganondorf's arenas.
|
||||
if (IS_BOSS_RUSH) {
|
||||
Actor_Kill(this);
|
||||
}
|
||||
|
||||
this->actionFunc = ObjTsubo_WaitForObject;
|
||||
}
|
||||
|
||||
|
@ -4843,8 +4843,7 @@ s32 Player_ActionChange_1(Player* this, PlayState* play) {
|
||||
if ((this->doorType != PLAYER_DOORTYPE_NONE) &&
|
||||
(!(this->stateFlags1 & PLAYER_STATE1_ITEM_OVER_HEAD) ||
|
||||
((this->heldActor != NULL) && (this->heldActor->id == ACTOR_EN_RU1)))) {
|
||||
// Disable doors in Boss Rush so the player can't leave the boss rooms backwards.
|
||||
if ((CHECK_BTN_ALL(sControlInput->press.button, BTN_A) || (Player_Action_8084F9A0 == this->actionFunc)) && !IS_BOSS_RUSH) {
|
||||
if ((CHECK_BTN_ALL(sControlInput->press.button, BTN_A) || (Player_Action_8084F9A0 == this->actionFunc)) && GameInteractor_Should(VB_BE_ABLE_TO_OPEN_DOORS, true, NULL)) {
|
||||
doorActor = this->doorActor;
|
||||
|
||||
if (this->doorType <= PLAYER_DOORTYPE_AJAR) {
|
||||
|
@ -1388,7 +1388,7 @@ void FileChoose_UpdateBossRushMenu(GameState* thisx) {
|
||||
// Move down
|
||||
if (this->stickRelY < -30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DDOWN))) {
|
||||
// When selecting past the last option, cycle back to the first option.
|
||||
if ((this->bossRushIndex + 1) > BOSSRUSH_OPTIONS_AMOUNT - 1) {
|
||||
if ((this->bossRushIndex + 1) > BR_OPTIONS_MAX - 1) {
|
||||
this->bossRushIndex = 0;
|
||||
this->bossRushOffset = 0;
|
||||
} else {
|
||||
@ -1401,7 +1401,7 @@ void FileChoose_UpdateBossRushMenu(GameState* thisx) {
|
||||
} else if (this->stickRelY > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DUP))) {
|
||||
// When selecting past the first option, cycle back to the last option and offset the list to view it properly.
|
||||
if ((this->bossRushIndex - 1) < 0) {
|
||||
this->bossRushIndex = BOSSRUSH_OPTIONS_AMOUNT - 1;
|
||||
this->bossRushIndex = BR_OPTIONS_MAX - 1;
|
||||
this->bossRushOffset = this->bossRushIndex - BOSSRUSH_MAX_OPTIONS_ON_SCREEN + 1;
|
||||
} else {
|
||||
// When first visible option is selected when moving up, offset the list up by one.
|
||||
@ -2306,7 +2306,7 @@ void FileChoose_DrawWindowContents(GameState* thisx) {
|
||||
(arrowUpY + 8) << 2, G_TX_RENDERTILE, 0, 0, (1 << 11), (1 << 11));
|
||||
}
|
||||
// Arrow down
|
||||
if (BOSSRUSH_OPTIONS_AMOUNT - listOffset > BOSSRUSH_MAX_OPTIONS_ON_SCREEN) {
|
||||
if (BR_OPTIONS_MAX - listOffset > BOSSRUSH_MAX_OPTIONS_ON_SCREEN) {
|
||||
uint16_t arrowDownX = 140;
|
||||
uint16_t arrowDownY = 181 + (this->bossRushArrowOffset / 10);
|
||||
gDPLoadTextureBlock(POLY_OPA_DISP++, gArrowDownTex, G_IM_FMT_IA,
|
||||
@ -3045,16 +3045,6 @@ void FileChoose_LoadGame(GameState* thisx) {
|
||||
|
||||
gSaveContext.naviTimer = 0;
|
||||
|
||||
if (IS_RANDO) {
|
||||
// Setup the modified entrance table and entrance shuffle table for rando
|
||||
Entrance_Init();
|
||||
|
||||
// Handle randomized spawn positions after the save context has been setup from load
|
||||
if (Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) {
|
||||
Entrance_SetSavewarpEntrance();
|
||||
}
|
||||
}
|
||||
|
||||
GameInteractor_ExecuteOnLoadGame(gSaveContext.fileNum);
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
#include "textures/parameter_static/parameter_static.h"
|
||||
#include "textures/icon_item_static/icon_item_static.h"
|
||||
#include "soh/Enhancements/cosmetics/cosmeticsTypes.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
extern const char* digitTextures[];
|
||||
|
||||
@ -12,7 +14,7 @@ void KaleidoScope_DrawQuestStatus(PlayState* play, GraphicsContext* gfxCtx) {
|
||||
} else if (CVarGetInteger(CVAR_COSMETIC("DefaultColorScheme"), COLORSCHEME_N64) == COLORSCHEME_GAMECUBE) {
|
||||
aButtonColor = (Color_RGB8){ 80, 255, 150 };
|
||||
}
|
||||
if (IS_RANDO && !Flags_GetRandomizerInf(RAND_INF_HAS_OCARINA_A)) {
|
||||
if (!GameInteractor_Should(VB_HAVE_OCARINA_NOTE_D4, true, NULL)) {
|
||||
aButtonColor = (Color_RGB8){ 191, 191, 191 };
|
||||
}
|
||||
|
||||
@ -24,7 +26,7 @@ void KaleidoScope_DrawQuestStatus(PlayState* play, GraphicsContext* gfxCtx) {
|
||||
if (CVarGetInteger(CVAR_COSMETIC("HUD.CUpButton.Changed"), 0)) {
|
||||
cUpButtonColor = CVarGetColor24(CVAR_COSMETIC("HUD.CUpButton.Value"), cUpButtonColor);
|
||||
}
|
||||
if (IS_RANDO && !Flags_GetRandomizerInf(RAND_INF_HAS_OCARINA_C_UP)) {
|
||||
if (!GameInteractor_Should(VB_HAVE_OCARINA_NOTE_D5, true, NULL)) {
|
||||
cUpButtonColor = (Color_RGB8){ 191, 191, 191 };
|
||||
}
|
||||
|
||||
@ -32,7 +34,7 @@ void KaleidoScope_DrawQuestStatus(PlayState* play, GraphicsContext* gfxCtx) {
|
||||
if (CVarGetInteger(CVAR_COSMETIC("HUD.CDownButton.Changed"), 0)) {
|
||||
cDownButtonColor = CVarGetColor24(CVAR_COSMETIC("HUD.CDownButton.Value"), cDownButtonColor);
|
||||
}
|
||||
if (IS_RANDO && !Flags_GetRandomizerInf(RAND_INF_HAS_OCARINA_C_DOWN)) {
|
||||
if (!GameInteractor_Should(VB_HAVE_OCARINA_NOTE_F4, true, NULL)) {
|
||||
cDownButtonColor = (Color_RGB8){ 191, 191, 191 };
|
||||
}
|
||||
|
||||
@ -40,7 +42,7 @@ void KaleidoScope_DrawQuestStatus(PlayState* play, GraphicsContext* gfxCtx) {
|
||||
if (CVarGetInteger(CVAR_COSMETIC("HUD.CLeftButton.Changed"), 0)) {
|
||||
cLeftButtonColor = CVarGetColor24(CVAR_COSMETIC("HUD.CLeftButton.Value"), cLeftButtonColor);
|
||||
}
|
||||
if (IS_RANDO && !Flags_GetRandomizerInf(RAND_INF_HAS_OCARINA_C_LEFT)) {
|
||||
if (!GameInteractor_Should(VB_HAVE_OCARINA_NOTE_B4, true, NULL)) {
|
||||
cLeftButtonColor = (Color_RGB8){ 191, 191, 191 };
|
||||
}
|
||||
|
||||
@ -48,7 +50,7 @@ void KaleidoScope_DrawQuestStatus(PlayState* play, GraphicsContext* gfxCtx) {
|
||||
if (CVarGetInteger(CVAR_COSMETIC("HUD.CRightButton.Changed"), 0)) {
|
||||
cRightButtonColor = CVarGetColor24(CVAR_COSMETIC("HUD.CRightButton.Value"), cRightButtonColor);
|
||||
}
|
||||
if (IS_RANDO && !Flags_GetRandomizerInf(RAND_INF_HAS_OCARINA_C_RIGHT)) {
|
||||
if (!GameInteractor_Should(VB_HAVE_OCARINA_NOTE_A4, true, NULL)) {
|
||||
cRightButtonColor = (Color_RGB8){ 191, 191, 191 };
|
||||
}
|
||||
|
||||
|
@ -1650,13 +1650,9 @@ void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) {
|
||||
gDPSetCombineMode(POLY_KAL_DISP++, G_CC_MODULATEIA, G_CC_MODULATEIA);
|
||||
gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha);
|
||||
|
||||
if (!IS_BOSS_RUSH) {
|
||||
if (GameInteractor_Should(VB_RENDER_YES_ON_CONTINUE_PROMPT, true, &POLY_KAL_DISP)) {
|
||||
POLY_KAL_DISP = KaleidoScope_QuadTextureIA8(
|
||||
POLY_KAL_DISP, sPromptChoiceTexs[gSaveContext.language][0], 48, 16, 12);
|
||||
} else {
|
||||
// Show "No" twice in Boss Rush because the player can't save within it.
|
||||
POLY_KAL_DISP = KaleidoScope_QuadTextureIA8(
|
||||
POLY_KAL_DISP, sPromptChoiceTexs[gSaveContext.language][1], 48, 16, 12);
|
||||
}
|
||||
|
||||
POLY_KAL_DISP =
|
||||
@ -4002,9 +3998,7 @@ void KaleidoScope_Update(PlayState* play)
|
||||
case 6:
|
||||
switch (pauseCtx->unk_1E4) {
|
||||
case 0:
|
||||
// Boss Rush skips past the "Save?" window when pressing B while paused.
|
||||
if (CHECK_BTN_ALL(input->press.button, BTN_START) ||
|
||||
(CHECK_BTN_ALL(input->press.button, BTN_B) && IS_BOSS_RUSH)) {
|
||||
if (GameInteractor_Should(VB_CLOSE_PAUSE_MENU, CHECK_BTN_ALL(input->press.button, BTN_START), NULL)) {
|
||||
if (CVarGetInteger(CVAR_CHEAT("EasyPauseBuffer"), 0) || CVarGetInteger(CVAR_CHEAT("EasyInputBuffer"), 0)) {
|
||||
// Easy pause buffer is 13 frames, 12 for kaledio to end, and one more to advance a single frame
|
||||
CVarSetInteger(CVAR_GENERAL("CheatEasyPauseBufferTimer"), 13);
|
||||
@ -4391,10 +4385,8 @@ void KaleidoScope_Update(PlayState* play)
|
||||
VREG(88) = 66;
|
||||
WREG(2) = 0;
|
||||
pauseCtx->alpha = 255;
|
||||
if (!IS_BOSS_RUSH) {
|
||||
if (GameInteractor_Should(VB_TRANSITION_TO_SAVE_SCREEN_ON_DEATH, true, pauseCtx)) {
|
||||
pauseCtx->state = 0xE;
|
||||
} else {
|
||||
pauseCtx->state = 0xF;
|
||||
}
|
||||
gSaveContext.deaths++;
|
||||
if (gSaveContext.deaths > 999) {
|
||||
@ -4439,7 +4431,7 @@ void KaleidoScope_Update(PlayState* play)
|
||||
|
||||
case 0x10:
|
||||
if (CHECK_BTN_ALL(input->press.button, BTN_A) || CHECK_BTN_ALL(input->press.button, BTN_START)) {
|
||||
if (pauseCtx->promptChoice == 0 && !IS_BOSS_RUSH) {
|
||||
if (pauseCtx->promptChoice == 0 && GameInteractor_Should(VB_BE_ABLE_TO_SAVE, true, NULL)) {
|
||||
Audio_PlaySoundGeneral(NA_SE_SY_PIECE_OF_HEART, &D_801333D4, 4, &D_801333E0, &D_801333E0,
|
||||
&D_801333E8);
|
||||
Play_SaveSceneFlags(play);
|
||||
@ -4512,7 +4504,7 @@ void KaleidoScope_Update(PlayState* play)
|
||||
R_PAUSE_MENU_MODE = 0;
|
||||
func_800981B8(&play->objectCtx);
|
||||
func_800418D0(&play->colCtx, play);
|
||||
if (pauseCtx->promptChoice == 0 && !IS_BOSS_RUSH) {
|
||||
if (pauseCtx->promptChoice == 0 && GameInteractor_Should(VB_BE_ABLE_TO_SAVE, true, NULL)) {
|
||||
Play_TriggerRespawn(play);
|
||||
gSaveContext.respawnFlag = -2;
|
||||
// In ER, handle death warp to last entrance from grottos
|
||||
|
Loading…
Reference in New Issue
Block a user