1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
#include "ActorBehavior.h"
#include "2s2h/Enhancements/Cutscenes/StoryCutscenes/SkipGiantsChamber.h"
#include <libultraship/bridge/consolevariablebridge.h>
extern "C" {
#include "overlays/actors/ovl_Door_Warp1/z_door_warp1.h"
#include "overlays/actors/ovl_Dm_Hina/z_dm_hina.h"
void func_808B9524(DoorWarp1* doorWarp1, PlayState* play);
}
void Rando::ActorBehavior::InitDoorWarp1VBehavior() {
/*
* This actor normally checks for the boss remains flags for multiple things (spawning the item, warping animation,
* whether to go to the Giants' Chamber). In rando, use rando checks instead
*/
COND_VB_SHOULD(VB_SPAWN_BOSS_REMAINS, IS_RANDO, {
s32* ret = va_arg(args, s32*);
if ((gPlayState->sceneId == SCENE_MITURIN_BS) &&
!RANDO_SAVE_CHECKS[RC_WOODFALL_TEMPLE_BOSS_WARP].cycleObtained) {
// Odolwa's Lair
*ret = 1;
} else if ((gPlayState->sceneId == SCENE_HAKUGIN_BS) &&
!RANDO_SAVE_CHECKS[RC_SNOWHEAD_TEMPLE_BOSS_WARP].cycleObtained) {
// Goht's Lair
*ret = 2;
} else if ((gPlayState->sceneId == SCENE_SEA_BS) &&
!RANDO_SAVE_CHECKS[RC_GREAT_BAY_TEMPLE_BOSS_WARP].cycleObtained) {
// Gyorg's Lair
*ret = 3;
} else if ((gPlayState->sceneId == SCENE_INISIE_BS) &&
!RANDO_SAVE_CHECKS[RC_STONE_TOWER_TEMPLE_INVERTED_BOSS_WARP].cycleObtained) {
// Twinmold's Lair
*ret = 4;
}
*should = false;
});
/*
* This should only be reached if the check has not already been activated. On repeats, there is no item, and the
* crystal warp animation plays out instead.
*/
COND_VB_SHOULD(VB_GIVE_ITEM_FROM_OFFER, IS_RANDO, {
GetItemId* item = va_arg(args, GetItemId*);
Actor* actor = va_arg(args, Actor*);
DoorWarp1* doorWarp1 = (DoorWarp1*)actor;
Player* player = GET_PLAYER(gPlayState);
if (actor->id == ACTOR_DOOR_WARP1) {
RandoCheckId checkId;
switch (gPlayState->sceneId) {
case SCENE_MITURIN_BS: // Odolwa's Lair
checkId = RC_WOODFALL_TEMPLE_BOSS_WARP;
break;
case SCENE_HAKUGIN_BS: // Goht's Lair
checkId = RC_SNOWHEAD_TEMPLE_BOSS_WARP;
break;
case SCENE_SEA_BS: // Gyorg's Lair
checkId = RC_GREAT_BAY_TEMPLE_BOSS_WARP;
break;
case SCENE_INISIE_BS: // Twinmold's Lair
checkId = RC_STONE_TOWER_TEMPLE_INVERTED_BOSS_WARP;
break;
}
RANDO_SAVE_CHECKS[checkId].eligible = !RANDO_SAVE_CHECKS[checkId].cycleObtained;
// Transform back to human Link and warp away without waiting for a textbox to close as normal
Player_SetCsActionWithHaltedActors(gPlayState, &doorWarp1->dyna.actor, PLAYER_CSACTION_9);
player->unk_3A0.x = doorWarp1->dyna.actor.world.pos.x;
player->unk_3A0.z = doorWarp1->dyna.actor.world.pos.z;
doorWarp1->unk_1CA = 1;
doorWarp1->actionFunc = func_808B9524;
// Now that we have reached this boss remains check, stop drawing it.
if (doorWarp1->unk_1A0 != nullptr) {
((DmHina*)doorWarp1->unk_1A0)->isDrawn = false;
}
HandleGiantsCutsceneSkip();
*should = false;
}
});
/*
* Changes the requirements to activate the boss room warp pad shortcut to check for boss room blue warp used
*/
COND_VB_SHOULD(VB_ACTIVATE_BOSS_WARP_PAD, IS_RANDO, {
Actor* actor = va_arg(args, Actor*);
RandoCheckId checkId = RC_UNKNOWN;
switch (DOORWARP1_GET_FF(actor)) {
case ENDOORWARP1_FF_2:
checkId = RC_WOODFALL_TEMPLE_BOSS_WARP;
break;
case ENDOORWARP1_FF_3:
checkId = RC_SNOWHEAD_TEMPLE_BOSS_WARP;
break;
case ENDOORWARP1_FF_4:
checkId = RC_GREAT_BAY_TEMPLE_BOSS_WARP;
break;
case ENDOORWARP1_FF_5:
checkId = RC_STONE_TOWER_TEMPLE_INVERTED_BOSS_WARP;
break;
}
*should = RANDO_SAVE_CHECKS[checkId].obtained;
});
}
|