Compare commits

..

25 Commits

Author SHA1 Message Date
Philip Dubé adb1e46ba9 fix bad args handling in extractor (#6501) 2026-04-14 01:00:16 +00:00
Philip Dubé 13ebc31ec7 9.2.2 Ackbar Charlie (#6494) 2026-04-13 14:12:37 +00:00
Jerom Venneker ca38dba192 Add missing Hint clarities back (#6477) 2026-04-13 03:39:30 +00:00
Philip Dubé 25eb09180d Revise Arrow Cycling (#6490)
1. simplify UI, flashing buttons are unnecessary
2. change arrow without drawing a new arrow
2026-04-12 23:03:46 +00:00
Philip Dubé d855742c2f Avoid over-allocating with texture interpolation (#6489)
Also remove interpolation with all zeroes & fix one interpolation direction
2026-04-12 18:51:04 +00:00
Philip Dubé 8513fd8800 fix cosmetic/audio randomizing options being seeded when they shouldn't be (#6481) 2026-04-12 18:25:05 +00:00
Philip Dubé 568813a2a4 Remove tooltip text referencing Let It Snow chests (#6488)
Was not preserved in chest revamp
2026-04-12 18:24:53 +00:00
Philip Dubé 7b7b799fad Make Lake Hylia water level switch in rando 10x faster (#6492)
35 seconds was an eternity
2026-04-12 18:24:14 +00:00
Philip Dubé 88099e6ebe Fix generation failure for Ganon's Castle MQ Fire Trial (#6487) 2026-04-12 13:27:06 +00:00
Pepper0ni 69ef35d258 Fix malon text and make the DMC jump unintuitive (#6479) 2026-04-10 21:45:23 +00:00
Jordan Longstaff 4122d8079e Faster bean planting (#6473) 2026-04-08 22:54:04 +00:00
Philip Dubé 40425c8c28 Fix seeded warp traps to be deterministic (#6469) 2026-04-07 16:31:41 +00:00
Chris 695c05d339 Fix cooldown behavior for crystal and light switches, water gate (#6461) 2026-04-07 01:09:07 +00:00
A Green Spoon 77f2883510 use category adj for gi (#6466) 2026-04-07 01:08:32 +00:00
Malkierian 876d512a4b Fix Skip Planting Beans crash (#6463)
Move code to set beans as planted after getting the bean pack to rando item give handler.
2026-04-07 01:07:20 +00:00
OtherBlue 978a219213 add check for market balcony camera (#6464) 2026-04-06 04:04:58 +00:00
Malkierian b6f227961b Restore sub-100% values for speed modifier slider. (#6465) 2026-04-06 03:47:17 +00:00
Chris 14b464bab2 Bean guy text formatting and rando fixes (#6444) 2026-03-30 01:33:16 +00:00
Pepper0ni efc4086c6a Some Logic fixes (#6445)
- Visible Collision added to more Skulls in Crates for consistency with similar situations
- Visible Collision added to chests in crates in MQ fire and for more ways to hit the switch in MQ fire Lizalfos maze
- Allow any jumpslash to break the pot in red ice in ice cavern with visible collision.
- Add Visible Collision as a way to get the gold skull token in the rubble in 4F Gibdo room in MQ shadow
- Turns out, while you take fall damage if you backflip onto a building from GF above jail, the floor is perfectly fine.
- Granny's shop forgot to check the price of the item being sold for wallets.
2026-03-30 01:32:31 +00:00
Pepper0ni 972ed22167 reset possible ice trap models before populating item pool (#6442) 2026-03-29 18:05:56 +00:00
Chris 5494a81eb1 Fix market sneak hook (#6440) 2026-03-29 16:46:47 +00:00
Chris ebea14f297 Fix displayed token count (#6441) 2026-03-29 16:45:48 +00:00
Chris 4729eef7c8 Make item category adjustments more consistent (#6434) 2026-03-29 07:34:59 +00:00
chartergirl64 0b3ebd584d [bug fix] Changes item tracker capacity to recognize progressive chu bag limits (#6436) 2026-03-29 07:32:40 +00:00
Chris 1be7533675 Conslidate ganon2 hooks (#6432) 2026-03-28 17:52:55 +00:00
52 changed files with 394 additions and 473 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ set(CMAKE_C_STANDARD 23 CACHE STRING "The C standard to use")
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version") set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")
project(Ship VERSION 9.2.1 LANGUAGES C CXX) project(Ship VERSION 9.2.2 LANGUAGES C CXX)
include(CMake/soh-cvars.cmake) include(CMake/soh-cvars.cmake)
include(CMake/lus-cvars.cmake) include(CMake/lus-cvars.cmake)
set(SPDLOG_LEVEL_TRACE 0) set(SPDLOG_LEVEL_TRACE 0)
+44 -125
View File
@@ -8,8 +8,7 @@ extern "C" {
#include "overlays/actors/ovl_En_Arrow/z_en_arrow.h" #include "overlays/actors/ovl_En_Arrow/z_en_arrow.h"
s32 func_808351D4(Player* thisx, PlayState* play); // Arrow nocked s32 func_808351D4(Player* thisx, PlayState* play); // Arrow nocked
s32 func_808353D8(Player* thisx, PlayState* play); // Aiming in first person void EnArrow_Init(Actor* thisx, PlayState* play);
void Player_InitItemAction(PlayState* play, Player* thisx, PlayerItemAction itemAction);
extern PlayState* gPlayState; extern PlayState* gPlayState;
} }
@@ -20,16 +19,6 @@ extern PlayState* gPlayState;
static const s16 sMagicArrowCosts[] = { 4, 4, 8 }; static const s16 sMagicArrowCosts[] = { 4, 4, 8 };
#define MINIGAME_STATUS_ACTIVE 1
static const s16 BUTTON_FLASH_DURATION = 3;
static const s16 BUTTON_FLASH_COUNT = 3;
static const s16 BUTTON_HIGHLIGHT_ALPHA = 128;
static s16 sButtonFlashTimer = 0;
static s16 sButtonFlashCount = 0;
static s16 sJustCycledFrames = 0;
static const PlayerItemAction sArrowCycleOrder[] = { static const PlayerItemAction sArrowCycleOrder[] = {
PLAYER_IA_BOW, PLAYER_IA_BOW,
PLAYER_IA_BOW_FIRE, PLAYER_IA_BOW_FIRE,
@@ -54,11 +43,11 @@ static bool HasArrowType(PlayerItemAction itemAction) {
case PLAYER_IA_BOW: case PLAYER_IA_BOW:
return true; return true;
case PLAYER_IA_BOW_FIRE: case PLAYER_IA_BOW_FIRE:
return (INV_CONTENT(ITEM_ARROW_FIRE) == ITEM_ARROW_FIRE); return INV_CONTENT(ITEM_ARROW_FIRE) == ITEM_ARROW_FIRE;
case PLAYER_IA_BOW_ICE: case PLAYER_IA_BOW_ICE:
return (INV_CONTENT(ITEM_ARROW_ICE) == ITEM_ARROW_ICE); return INV_CONTENT(ITEM_ARROW_ICE) == ITEM_ARROW_ICE;
case PLAYER_IA_BOW_LIGHT: case PLAYER_IA_BOW_LIGHT:
return (INV_CONTENT(ITEM_ARROW_LIGHT) == ITEM_ARROW_LIGHT); return INV_CONTENT(ITEM_ARROW_LIGHT) == ITEM_ARROW_LIGHT;
default: default:
return false; return false;
} }
@@ -77,15 +66,24 @@ static s32 GetBowItemForArrow(PlayerItemAction itemAction) {
} }
} }
static ArrowType GetArrowTypeForArrow(s8 itemAction) {
switch (itemAction) {
case PLAYER_IA_BOW_FIRE:
return ARROW_FIRE;
case PLAYER_IA_BOW_ICE:
return ARROW_ICE;
case PLAYER_IA_BOW_LIGHT:
return ARROW_LIGHT;
default:
return ARROW_NORMAL;
}
}
static bool CanCycleArrows() { static bool CanCycleArrows() {
Player* player = GET_PLAYER(gPlayState); Player* player = GET_PLAYER(gPlayState);
// don't allow cycling during minigames return LINK_IS_ADULT && !gSaveContext.minigameState && gPlayState->sceneNum != SCENE_SHOOTING_GALLERY &&
if (gSaveContext.minigameState == MINIGAME_STATUS_ACTIVE) { !(player->stateFlags1 & PLAYER_STATE1_ON_HORSE) && player->rideActor == NULL &&
return false;
}
return !(player->stateFlags1 & PLAYER_STATE1_ON_HORSE) && player->rideActor == NULL &&
INV_CONTENT(SLOT_BOW) == ITEM_BOW && INV_CONTENT(SLOT_BOW) == ITEM_BOW &&
(INV_CONTENT(ITEM_ARROW_FIRE) == ITEM_ARROW_FIRE || INV_CONTENT(ITEM_ARROW_ICE) == ITEM_ARROW_ICE || (INV_CONTENT(ITEM_ARROW_FIRE) == ITEM_ARROW_FIRE || INV_CONTENT(ITEM_ARROW_ICE) == ITEM_ARROW_ICE ||
INV_CONTENT(ITEM_ARROW_LIGHT) == ITEM_ARROW_LIGHT); INV_CONTENT(ITEM_ARROW_LIGHT) == ITEM_ARROW_LIGHT);
@@ -113,66 +111,6 @@ static s8 GetNextArrowType(s8 currentArrowType) {
static void UpdateButtonAlpha(s16 flashAlpha, bool isButtonBow, u16* buttonAlpha) { static void UpdateButtonAlpha(s16 flashAlpha, bool isButtonBow, u16* buttonAlpha) {
if (isButtonBow) { if (isButtonBow) {
*buttonAlpha = flashAlpha; *buttonAlpha = flashAlpha;
if (sButtonFlashTimer == 0) {
*buttonAlpha = 255;
}
}
}
static void UpdateFlashEffect(PlayState* play) {
if (sButtonFlashTimer <= 0) {
return;
}
sButtonFlashTimer--;
s16 flashAlpha = (sButtonFlashTimer % 3) ? BUTTON_HIGHLIGHT_ALPHA : 255;
if (sButtonFlashTimer == 0 && sButtonFlashCount < BUTTON_FLASH_COUNT - 1) {
sButtonFlashTimer = BUTTON_FLASH_DURATION;
sButtonFlashCount++;
}
UpdateButtonAlpha(flashAlpha,
(gSaveContext.equips.buttonItems[1] == ITEM_BOW) ||
(gSaveContext.equips.buttonItems[1] >= ITEM_BOW_ARROW_FIRE &&
gSaveContext.equips.buttonItems[1] <= ITEM_BOW_ARROW_LIGHT),
&play->interfaceCtx.cLeftAlpha);
UpdateButtonAlpha(flashAlpha,
(gSaveContext.equips.buttonItems[2] == ITEM_BOW) ||
(gSaveContext.equips.buttonItems[2] >= ITEM_BOW_ARROW_FIRE &&
gSaveContext.equips.buttonItems[2] <= ITEM_BOW_ARROW_LIGHT),
&play->interfaceCtx.cDownAlpha);
UpdateButtonAlpha(flashAlpha,
(gSaveContext.equips.buttonItems[3] == ITEM_BOW) ||
(gSaveContext.equips.buttonItems[3] >= ITEM_BOW_ARROW_FIRE &&
gSaveContext.equips.buttonItems[3] <= ITEM_BOW_ARROW_LIGHT),
&play->interfaceCtx.cRightAlpha);
if (CVarGetInteger(CVAR_ENHANCEMENT("DpadEquips"), 0)) {
UpdateButtonAlpha(flashAlpha,
(gSaveContext.equips.buttonItems[4] == ITEM_BOW) ||
(gSaveContext.equips.buttonItems[4] >= ITEM_BOW_ARROW_FIRE &&
gSaveContext.equips.buttonItems[4] <= ITEM_BOW_ARROW_LIGHT),
&play->interfaceCtx.dpadRightAlpha);
UpdateButtonAlpha(flashAlpha,
(gSaveContext.equips.buttonItems[5] == ITEM_BOW) ||
(gSaveContext.equips.buttonItems[5] >= ITEM_BOW_ARROW_FIRE &&
gSaveContext.equips.buttonItems[5] <= ITEM_BOW_ARROW_LIGHT),
&play->interfaceCtx.dpadLeftAlpha);
UpdateButtonAlpha(flashAlpha,
(gSaveContext.equips.buttonItems[6] == ITEM_BOW) ||
(gSaveContext.equips.buttonItems[6] >= ITEM_BOW_ARROW_FIRE &&
gSaveContext.equips.buttonItems[6] <= ITEM_BOW_ARROW_LIGHT),
&play->interfaceCtx.dpadDownAlpha);
UpdateButtonAlpha(flashAlpha,
(gSaveContext.equips.buttonItems[7] == ITEM_BOW) ||
(gSaveContext.equips.buttonItems[7] >= ITEM_BOW_ARROW_FIRE &&
gSaveContext.equips.buttonItems[7] <= ITEM_BOW_ARROW_LIGHT),
&play->interfaceCtx.dpadUpAlpha);
} }
} }
@@ -193,72 +131,53 @@ static void UpdateEquippedBow(PlayState* play, s8 arrowType) {
} }
gSaveContext.buttonStatus[i] = BTN_ENABLED; gSaveContext.buttonStatus[i] = BTN_ENABLED;
sButtonFlashTimer = BUTTON_FLASH_DURATION;
sButtonFlashCount = 0;
} }
} }
UpdateFlashEffect(play);
} }
static void CycleToNextArrow(PlayState* play, Player* player) { bool ArrowCycleMain() {
s8 nextArrow = GetNextArrowType(player->heldItemAction);
if (player->heldActor != NULL && player->heldActor->id == ACTOR_EN_ARROW) {
EnArrow* arrow = (EnArrow*)player->heldActor;
if (arrow->actor.child != NULL) {
Actor_Kill(arrow->actor.child);
}
Actor_Kill(&arrow->actor);
}
Player_InitItemAction(play, player, (PlayerItemAction)nextArrow);
UpdateEquippedBow(play, nextArrow);
Audio_PlaySoundGeneral(NA_SE_PL_CHANGE_ARMS, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
sJustCycledFrames = 2;
}
void ArrowCycleMain() {
if (gPlayState == nullptr || !CanCycleArrows()) { if (gPlayState == nullptr || !CanCycleArrows()) {
return; return false;
} }
if (sJustCycledFrames > 0) {
sJustCycledFrames--;
}
UpdateFlashEffect(gPlayState);
Player* player = GET_PLAYER(gPlayState); Player* player = GET_PLAYER(gPlayState);
Input* input = &gPlayState->state.input[0]; if (player->heldActor != NULL && player->heldActor->id == ACTOR_EN_ARROW) {
if (IsAimingBow(player) && CHECK_BTN_ANY(input->press.button, BTN_R)) {
if (IsHoldingMagicBow(player) && gSaveContext.magicState != MAGIC_STATE_IDLE && player->heldActor == NULL) { if (IsHoldingMagicBow(player) && gSaveContext.magicState != MAGIC_STATE_IDLE && player->heldActor == NULL) {
Audio_PlaySoundGeneral(NA_SE_SY_ERROR, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, Audio_PlaySoundGeneral(NA_SE_SY_ERROR, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
return; return true;
} }
// reset magic state to IDLE before cycling to prevent error sound // reset magic state to IDLE before cycling to prevent error sound
gSaveContext.magicState = MAGIC_STATE_IDLE; gSaveContext.magicState = MAGIC_STATE_IDLE;
CycleToNextArrow(gPlayState, player); s8 nextArrow = GetNextArrowType(player->heldItemAction);
player->heldItemAction = nextArrow;
player->itemAction = nextArrow;
Actor* arrow = player->heldActor;
if (arrow->child != NULL) {
Actor_Kill(arrow->child);
arrow->child = NULL;
}
arrow->params = GetArrowTypeForArrow(nextArrow);
EnArrow_Init(arrow, gPlayState);
UpdateEquippedBow(gPlayState, nextArrow);
return true;
} }
return false;
} }
void RegisterArrowCycle() { void RegisterArrowCycle() {
COND_ID_HOOK(OnActorUpdate, ACTOR_PLAYER, CVAR_ARROW_CYCLE_VALUE, [](void* actor) { ArrowCycleMain(); });
// suppress shield input when R is held while aiming to allow arrow cycling // suppress shield input when R is held while aiming to allow arrow cycling
COND_VB_SHOULD(VB_EXECUTE_PLAYER_ACTION_FUNC, CVAR_ARROW_CYCLE_VALUE, { COND_VB_SHOULD(VB_EXECUTE_PLAYER_ACTION_FUNC, CVAR_ARROW_CYCLE_VALUE, {
Player* player = (Player*)va_arg(args, void*); Player* player = (Player*)va_arg(args, void*);
Input* input = (Input*)va_arg(args, void*); Input* input = (Input*)va_arg(args, void*);
if ((IsAimingBow(player) || sJustCycledFrames > 0) && CHECK_BTN_ANY(input->cur.button, BTN_R)) { if (IsAimingBow(player) && CHECK_BTN_ANY(input->press.button, BTN_R)) {
input->cur.button &= ~BTN_R; if (ArrowCycleMain()) {
input->press.button &= ~BTN_R; input->cur.button &= ~BTN_R;
input->press.button &= ~BTN_R;
}
} }
}); });
@@ -270,9 +189,9 @@ void RegisterArrowCycle() {
if (gSaveContext.magic < sMagicArrowCosts[magicArrowType]) { if (gSaveContext.magic < sMagicArrowCosts[magicArrowType]) {
*arrowType = ARROW_NORMAL; *arrowType = ARROW_NORMAL;
} else {
*should = false;
} }
*should = false;
}); });
COND_VB_SHOULD(VB_EN_ARROW_MAGIC_CONSUMPTION, CVAR_ARROW_CYCLE_VALUE, { COND_VB_SHOULD(VB_EN_ARROW_MAGIC_CONSUMPTION, CVAR_ARROW_CYCLE_VALUE, {
+9 -26
View File
@@ -32,6 +32,7 @@ typedef enum {
static AltTrapType roll = ADD_TRAP_MAX; static AltTrapType roll = ADD_TRAP_MAX;
static int statusTimer = -1; static int statusTimer = -1;
static int eventTimer = -1; static int eventTimer = -1;
static EntranceIndex teleportRoll = ENTR_MAX;
const char* altTrapTypeCvars[] = { const char* altTrapTypeCvars[] = {
CVAR_ENHANCEMENT("ExtraTraps.Ice"), CVAR_ENHANCEMENT("ExtraTraps.Burn"), CVAR_ENHANCEMENT("ExtraTraps.Ice"), CVAR_ENHANCEMENT("ExtraTraps.Burn"),
@@ -41,6 +42,12 @@ const char* altTrapTypeCvars[] = {
CVAR_ENHANCEMENT("ExtraTraps.Kill"), CVAR_ENHANCEMENT("ExtraTraps.Teleport"), CVAR_ENHANCEMENT("ExtraTraps.Kill"), CVAR_ENHANCEMENT("ExtraTraps.Teleport"),
}; };
const std::array<EntranceIndex, 7> teleportDestinations = {
ENTR_LINKS_HOUSE_CHILD_SPAWN, ENTR_SACRED_FOREST_MEADOW_WARP_PAD, ENTR_DEATH_MOUNTAIN_CRATER_WARP_PAD,
ENTR_LAKE_HYLIA_WARP_PAD, ENTR_DESERT_COLOSSUS_WARP_PAD, ENTR_GRAVEYARD_WARP_PAD,
ENTR_TEMPLE_OF_TIME_WARP_PAD,
};
std::vector<AltTrapType> getEnabledAddTraps() { std::vector<AltTrapType> getEnabledAddTraps() {
std::vector<AltTrapType> enabledAddTraps; std::vector<AltTrapType> enabledAddTraps;
for (int i = 0; i < ADD_TRAP_MAX; i++) { for (int i = 0; i < ADD_TRAP_MAX; i++) {
@@ -102,6 +109,7 @@ static void RollRandomTrap(uint64_t seed) {
break; break;
case ADD_TELEPORT_TRAP: case ADD_TELEPORT_TRAP:
eventTimer = 3; eventTimer = 3;
teleportRoll = ShipUtils::RandomElement(teleportDestinations, &state);
break; break;
default: default:
break; break;
@@ -135,32 +143,7 @@ static void OnPlayerUpdate() {
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
break; break;
case ADD_TELEPORT_TRAP: { case ADD_TELEPORT_TRAP: {
int entrance; GameInteractor::RawAction::TeleportPlayer(teleportRoll);
int index = Random(0, 7);
switch (index) {
case 0:
entrance = GI_TP_DEST_SERENADE;
break;
case 1:
entrance = GI_TP_DEST_REQUIEM;
break;
case 2:
entrance = GI_TP_DEST_BOLERO;
break;
case 3:
entrance = GI_TP_DEST_MINUET;
break;
case 4:
entrance = GI_TP_DEST_NOCTURNE;
break;
case 5:
entrance = GI_TP_DEST_PRELUDE;
break;
default:
entrance = GI_TP_DEST_LINKSHOUSE;
break;
}
GameInteractor::RawAction::TeleportPlayer(entrance);
break; break;
} }
default: default:
@@ -17,10 +17,10 @@ static void RegisterBossDefeatTimestamps() {
BOSS_DEFEAT_TIMESTAMP(ACTOR_BOSS_SST, TIMESTAMP_DEFEAT_BONGO_BONGO); BOSS_DEFEAT_TIMESTAMP(ACTOR_BOSS_SST, TIMESTAMP_DEFEAT_BONGO_BONGO);
BOSS_DEFEAT_TIMESTAMP(ACTOR_BOSS_TW, TIMESTAMP_DEFEAT_TWINROVA); BOSS_DEFEAT_TIMESTAMP(ACTOR_BOSS_TW, TIMESTAMP_DEFEAT_TWINROVA);
BOSS_DEFEAT_TIMESTAMP(ACTOR_BOSS_GANON, TIMESTAMP_DEFEAT_GANONDORF); BOSS_DEFEAT_TIMESTAMP(ACTOR_BOSS_GANON, TIMESTAMP_DEFEAT_GANONDORF);
BOSS_DEFEAT_TIMESTAMP(ACTOR_BOSS_GANON2, TIMESTAMP_DEFEAT_GANON); COND_ID_HOOK(OnBossDefeat, ACTOR_BOSS_GANON2, true, [](void* refActor) {
gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_GANON] = GAMEPLAYSTAT_TOTAL_TIME;
COND_ID_HOOK(OnBossDefeat, ACTOR_BOSS_GANON2, true, gSaveContext.ship.stats.gameComplete = true;
[](void* refActor) { gSaveContext.ship.stats.gameComplete = true; }); });
} }
static RegisterShipInitFunc initFunc(RegisterBossDefeatTimestamps); static RegisterShipInitFunc initFunc(RegisterBossDefeatTimestamps);
@@ -84,7 +84,8 @@ static void DisableFixedCamera_RestoreAllCameraData() {
// Helper to check if a camera type is a fixed camera // Helper to check if a camera type is a fixed camera
static bool IsFixedCameraType(s16 type) { static bool IsFixedCameraType(s16 type) {
return type == CAM_SET_PREREND_FIXED || type == CAM_SET_PREREND_PIVOT || type == CAM_SET_PIVOT_FROM_SIDE; return type == CAM_SET_PREREND_FIXED || type == CAM_SET_PREREND_PIVOT || type == CAM_SET_PIVOT_FROM_SIDE ||
type == CAM_SET_MARKET_BALCONY;
} }
static void RegisterDisableFixedCamera() { static void RegisterDisableFixedCamera() {
+1 -1
View File
@@ -24,7 +24,7 @@ void BuildSkulltulaMessage(uint16_t* textId, bool* loadFromMessageTable) {
// Auto dismiss textbox after 0x3C (60) frames (about 3 seconds for OoT) // Auto dismiss textbox after 0x3C (60) frames (about 3 seconds for OoT)
msg = msg + "\x0E\x3C"; msg = msg + "\x0E\x3C";
} }
int16_t gsCount = gSaveContext.inventory.gsTokens + (IS_RANDO ? 1 : 0); int16_t gsCount = gSaveContext.inventory.gsTokens;
msg.Replace("[[gsCount]]", std::to_string(gsCount)); msg.Replace("[[gsCount]]", std::to_string(gsCount));
msg.AutoFormat(ITEM_SKULL_TOKEN); msg.AutoFormat(ITEM_SKULL_TOKEN);
msg.LoadIntoFont(); msg.LoadIntoFont();
@@ -2,11 +2,17 @@
extern "C" { extern "C" {
#include <variables.h> #include <variables.h>
extern PlayState* gPlayState;
} }
// RANDOTODO: Port the rest of the behavior for this enhancement here. // RANDOTODO: Port the rest of the behavior for this enhancement here.
void BuildNightGuardMessage(uint16_t* textId, bool* loadFromMessageTable) { void BuildNightGuardMessage(uint16_t* textId, bool* loadFromMessageTable) {
// Other guards should not have their text overridden
if (gPlayState->sceneNum != SCENE_MARKET_ENTRANCE_NIGHT) {
return;
}
CustomMessage msg = CustomMessage("You look bored. Wanna go out for a walk?\x1B%gYes&No%w", CustomMessage msg = CustomMessage("You look bored. Wanna go out for a walk?\x1B%gYes&No%w",
"Du siehst gelangweilt aus. Willst Du einen Spaziergang machen?\x1B%gJa&Nein%w", "Du siehst gelangweilt aus. Willst Du einen Spaziergang machen?\x1B%gJa&Nein%w",
"Tu as l'air de t'ennuyer. Tu veux aller faire un tour?\x1B%gOui&Non%w"); "Tu as l'air de t'ennuyer. Tu veux aller faire un tour?\x1B%gOui&Non%w");
@@ -1,42 +0,0 @@
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/ShipInit.hpp"
extern "C" {
#include "src/overlays/actors/ovl_Obj_Lightswitch/z_obj_lightswitch.h"
#include "src/overlays/actors/ovl_Bg_Spot06_Objects/z_bg_spot06_objects.h"
#include "src/overlays/actors/ovl_Bg_Jya_Bombchuiwa/z_bg_jya_bombchuiwa.h"
extern PlayState* gPlayState;
}
#define SKIP_MISC_INTERACTIONS_NAME CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions")
#define SKIP_MISC_INTERACTIONS_VALUE CVarGetInteger(SKIP_MISC_INTERACTIONS_NAME, IS_RANDO)
static void RegisterSkipTimerDelay() {
// Skip Water Temple gate delay
COND_ID_HOOK(OnActorUpdate, ACTOR_BG_SPOT06_OBJECTS, SKIP_MISC_INTERACTIONS_VALUE, [](void* actor) {
auto spot06 = static_cast<BgSpot06Objects*>(actor);
if (spot06->dyna.actor.params == 0) {
spot06->timer = 0;
}
});
// Skip Spirit Sun on Floor activation delay
COND_ID_HOOK(OnActorUpdate, ACTOR_BG_JYA_BOMBCHUIWA, SKIP_MISC_INTERACTIONS_VALUE, [](void* actor) {
auto jya = static_cast<BgJyaBombchuiwa*>(actor);
if (!(jya->drawFlags & 4) && jya->timer > 0 && jya->timer < 9) {
jya->timer = 9;
}
});
// Skip Spirit Sun on Floor & Sun on Block activation delay
COND_ID_HOOK(OnActorUpdate, ACTOR_OBJ_LIGHTSWITCH, SKIP_MISC_INTERACTIONS_VALUE, [](void* actor) {
if (gPlayState->sceneNum == SCENE_SPIRIT_TEMPLE &&
(gPlayState->roomCtx.curRoom.num == 4 || gPlayState->roomCtx.curRoom.num == 8)) {
auto sun = static_cast<ObjLightswitch*>(actor);
sun->toggleDelay = 0;
}
});
}
static RegisterShipInitFunc initFunc_SkipTimerDelay(RegisterSkipTimerDelay,
{ SKIP_MISC_INTERACTIONS_NAME, "IS_RANDO" });
@@ -0,0 +1,18 @@
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/ShipInit.hpp"
extern "C" {
#include "src/overlays/actors/ovl_Bg_Spot06_Objects/z_bg_spot06_objects.h"
extern SaveContext gSaveContext;
}
static void RegisterSpot06GateSkip() {
COND_VB_SHOULD(VB_BG_SPOT06_OBJECTS_GATE_SKIP,
CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.OnePoint"), IS_RANDO), {
BgSpot06Objects* actor = va_arg(args, BgSpot06Objects*);
actor->timer = 0;
*should = false;
});
}
static RegisterShipInitFunc initFunc(RegisterSpot06GateSkip, { CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.OnePoint") });
+9 -6
View File
@@ -109,19 +109,22 @@ void UpdateCurrentBGM(u16 seqKey, SeqType seqType) {
} }
} }
static uint64_t seeded_audio_state = 0;
void RandomizeGroup(SeqType type, bool manual = true) { void RandomizeGroup(SeqType type, bool manual = true) {
std::vector<u16> values; std::vector<u16> values;
uint64_t localRngState = 0;
uint64_t* shuffleState = nullptr;
if (!manual) { if (!manual) {
if (CVarGetInteger(CVAR_AUDIO("RandomizeAudioGenModes"), 0) == RANDOMIZE_ON_FILE_LOAD_SEEDED || int randomizeMode = CVarGetInteger(CVAR_AUDIO("RandomizeAudioGenModes"), 0);
CVarGetInteger(CVAR_AUDIO("RandomizeAudioGenModes"), 0) == RANDOMIZE_ON_RANDO_GEN_ONLY) { if (randomizeMode == RANDOMIZE_ON_FILE_LOAD_SEEDED || randomizeMode == RANDOMIZE_ON_RANDO_GEN_ONLY) {
uint32_t finalSeed = type + (IS_RANDO ? Rando::Context::GetInstance()->GetSeed() uint32_t finalSeed = type + (IS_RANDO ? Rando::Context::GetInstance()->GetSeed()
: static_cast<uint32_t>(gSaveContext.ship.stats.fileCreatedAt)); : static_cast<uint32_t>(gSaveContext.ship.stats.fileCreatedAt));
ShipUtils::RandInit(finalSeed, &seeded_audio_state); ShipUtils::RandInit(finalSeed, &localRngState);
shuffleState = &localRngState;
} }
// For RANDOMIZE_ON_NEW_SCENE, shuffleState remains nullptr, which uses the global RNG
} }
// An empty IncludedSequences set means that the AudioEditor window has never been drawn // An empty IncludedSequences set means that the AudioEditor window has never been drawn
@@ -141,7 +144,7 @@ void RandomizeGroup(SeqType type, bool manual = true) {
if (!values.size()) if (!values.size())
return; return;
} }
ShipUtils::Shuffle(values, &seeded_audio_state); ShipUtils::Shuffle(values, shuffleState);
for (const auto& [seqId, seqData] : AudioCollection::Instance->GetAllSequences()) { for (const auto& [seqId, seqData] : AudioCollection::Instance->GetAllSequences()) {
const std::string cvarKey = AudioCollection::Instance->GetCvarKey(seqData.sfxKey); const std::string cvarKey = AudioCollection::Instance->GetCvarKey(seqData.sfxKey);
const std::string cvarLockKey = AudioCollection::Instance->GetCvarLockKey(seqData.sfxKey); const std::string cvarLockKey = AudioCollection::Instance->GetCvarLockKey(seqData.sfxKey);
@@ -1889,11 +1889,11 @@ void DrawSillyTab() {
UIWidgets::Separator(true, true, 2.0f, 2.0f); UIWidgets::Separator(true, true, 2.0f, 2.0f);
UIWidgets::CVarCheckbox("Let It Snow", CVAR_GENERAL("LetItSnow"), UIWidgets::CVarCheckbox(
UIWidgets::CheckboxOptions() "Let It Snow", CVAR_GENERAL("LetItSnow"),
.Color(THEME_COLOR) UIWidgets::CheckboxOptions()
.Tooltip("Makes snow fall, changes chest texture colors to red and green, etc, for " .Color(THEME_COLOR)
"December holidays.\nWill reset on restart outside of December 23-25.")); .Tooltip("Makes snow fall for December holidays.\nWill reset on restart outside of December 23-25."));
UIWidgets::Separator(true, true, 2.0f, 2.0f); UIWidgets::Separator(true, true, 2.0f, 2.0f);
@@ -2104,24 +2104,28 @@ void ApplySideEffects(CosmeticOption& cosmeticOption) {
} }
} }
static uint64_t seeded_cosmetics_state = 0;
void RandomizeColor(CosmeticOption& cosmeticOption, bool manual = true) { void RandomizeColor(CosmeticOption& cosmeticOption, bool manual = true) {
ImVec4 randomColor; ImVec4 randomColor;
if (!manual && CVarGetInteger(CVAR_COSMETIC("RandomizeCosmeticsGenModes"), 0) == RANDOMIZE_ON_FILE_LOAD_SEEDED || uint64_t local_seed_state = 0;
!manual && CVarGetInteger(CVAR_COSMETIC("RandomizeCosmeticsGenModes"), 0) == RANDOMIZE_ON_RANDO_GEN_ONLY) { uint64_t* randomState = nullptr;
uint32_t finalSeed = cosmeticOption.defaultColor.r + cosmeticOption.defaultColor.g + if (!manual) {
cosmeticOption.defaultColor.b + cosmeticOption.defaultColor.a + int randomizeMode = CVarGetInteger(CVAR_COSMETIC("RandomizeCosmeticsGenModes"), 0);
(IS_RANDO ? Rando::Context::GetInstance()->GetSeed() if (randomizeMode == RANDOMIZE_ON_FILE_LOAD_SEEDED || randomizeMode == RANDOMIZE_ON_RANDO_GEN_ONLY) {
: static_cast<uint32_t>(gSaveContext.ship.stats.fileCreatedAt));
randomColor = GetRandomValue(finalSeed, &seeded_cosmetics_state); uint32_t finalSeed = cosmeticOption.defaultColor.r + cosmeticOption.defaultColor.g +
} else { cosmeticOption.defaultColor.b + cosmeticOption.defaultColor.a +
randomColor = GetRandomValue(); (IS_RANDO ? Rando::Context::GetInstance()->GetSeed()
: static_cast<uint32_t>(gSaveContext.ship.stats.fileCreatedAt));
randomState = &local_seed_state;
ShipUtils::RandInit(finalSeed, randomState);
}
// For RANDOMIZE_ON_NEW_SCENE, randomState remains nullptr, which uses the global RNG
} }
randomColor = GetRandomValue(randomState);
Color_RGBA8 newColor; Color_RGBA8 newColor;
newColor.r = static_cast<uint8_t>(randomColor.x * 255.0f); newColor.r = static_cast<uint8_t>(randomColor.x * 255.0f);
newColor.g = static_cast<uint8_t>(randomColor.y * 255.0f); newColor.g = static_cast<uint8_t>(randomColor.y * 255.0f);
@@ -52,16 +52,6 @@ typedef enum {
/* 0x08 */ GI_COLOR_BLACK, /* 0x08 */ GI_COLOR_BLACK,
} GIColors; } GIColors;
typedef enum {
/* */ GI_TP_DEST_LINKSHOUSE = ENTR_LINKS_HOUSE_CHILD_SPAWN,
/* */ GI_TP_DEST_MINUET = ENTR_SACRED_FOREST_MEADOW_WARP_PAD,
/* */ GI_TP_DEST_BOLERO = ENTR_DEATH_MOUNTAIN_CRATER_WARP_PAD,
/* */ GI_TP_DEST_SERENADE = ENTR_LAKE_HYLIA_WARP_PAD,
/* */ GI_TP_DEST_REQUIEM = ENTR_DESERT_COLOSSUS_WARP_PAD,
/* */ GI_TP_DEST_NOCTURNE = ENTR_GRAVEYARD_WARP_PAD,
/* */ GI_TP_DEST_PRELUDE = ENTR_TEMPLE_OF_TIME_WARP_PAD,
} GITeleportDestinations;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@@ -225,6 +215,9 @@ class GameInteractor {
static GameInteractionEffectQueryResult RemoveEffect(RemovableGameInteractionEffect& effect); static GameInteractionEffectQueryResult RemoveEffect(RemovableGameInteractionEffect& effect);
// Game Hooks // Game Hooks
//
// Hooks should be idempotent and execution order is not guaranteed.
// If two operations must happen in a specific order, they should be placed in the same hook.
HOOK_ID nextHookId = 1; HOOK_ID nextHookId = 1;
template <typename H> struct RegisteredGameHooks { template <typename H> struct RegisteredGameHooks {
@@ -203,6 +203,14 @@ typedef enum {
// - None // - None
VB_BG_BREAKWALL_BREAK, VB_BG_BREAKWALL_BREAK,
// #### `result`
// ```c
// this->timer > 0 && this->timer <= 100
// ```
// #### `args`
// - `*BgSpot06Objects`
VB_BG_SPOT06_OBJECTS_GATE_SKIP,
// #### `result` // #### `result`
// ```c // ```c
// gSaveContext.bgsFlag // gSaveContext.bgsFlag
@@ -1355,6 +1363,14 @@ typedef enum {
// - `*DoorShutter` // - `*DoorShutter`
VB_LOCK_BOSS_DOOR, VB_LOCK_BOSS_DOOR,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - `*EnMs`
VB_MAGIC_BEAN_SALESMAN_TAKE_MONEY,
// #### `result` // #### `result`
// ```c // ```c
// CHECK_QUEST_ITEM(QUEST_SONG_EPONA) // CHECK_QUEST_ITEM(QUEST_SONG_EPONA)
@@ -1518,6 +1534,14 @@ typedef enum {
// - `*BossGanondrof` // - `*BossGanondrof`
VB_PHANTOM_GANON_DEATH_SCENE, VB_PHANTOM_GANON_DEATH_SCENE,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - None
VB_PLAY_BEAN_PLANTING_CS,
// #### `result` // #### `result`
// ##### In `DoorWarp1_ChildWarpOut` - `SCENE_DODONGOS_CAVERN_BOSS` // ##### In `DoorWarp1_ChildWarpOut` - `SCENE_DODONGOS_CAVERN_BOSS`
// ```c // ```c
@@ -2328,12 +2328,12 @@ void StaticData::HintTable_Init() {
{QM_RED, QM_BLUE, QM_GREEN})); {QM_RED, QM_BLUE, QM_GREEN}));
hintTextTable[RHT_MALON_HINT_OBSTICLE_COURSE] = HintText(CustomMessage("How about trying the #Obstacle Course?# If you beat my time I'll let you keep my favourite #cow# Elsie and her toy #[[1]]#!^" hintTextTable[RHT_MALON_HINT_OBSTICLE_COURSE] = HintText(CustomMessage("How about trying the #Obstacle Course?# If you beat my time I'll let you keep my favourite #cow# Elsie and her toy #[[1]]#!^"
"Challenge the #Obstacle Course?#&\x1B&#Let's go&No thanks#", "Challenge the #Obstacle Course?#\x1B#Let's go&No thanks#",
/*german*/ "Warum versuchst Du Dich nicht mit Epona an dem #Hindernisparcours#?^" /*german*/ "Warum versuchst Du Dich nicht mit Epona an dem #Hindernisparcours#?^"
"Gelingt es Dir den Rekord zu brechen, bekommst Du meine #Lieblingskuh# Elsie^und ihr Lieblingsspielzeug, #[[1]]#!^" "Gelingt es Dir den Rekord zu brechen, bekommst Du meine #Lieblingskuh# Elsie^und ihr Lieblingsspielzeug, #[[1]]#!^"
"Wie sieht's aus?&Möchtest Du es versuchen?\x1B&#Ja!&Nein!#", "Wie sieht's aus?&Möchtest Du es versuchen?\x1B#Ja!&Nein!#",
/*french*/ "Que dirais-tu d'essayer le #Parcours d'Obstacles#? Si tu bats mon temps, je te donnerai ma vache préférée, Elsie, et son jouet #[[1]]#!^" /*french*/ "Que dirais-tu d'essayer le #Parcours d'Obstacles#? Si tu bats mon temps, je te donnerai ma vache préférée, Elsie, et son jouet #[[1]]#!^"
"Tenter le #Parcours d'Obstacles#?&\x1B&#Allons-y&Non merci#", "Tenter le #Parcours d'Obstacles#?\x1B#Allons-y&Non merci#",
{QM_RED, QM_BLUE, QM_GREEN, QM_RED, QM_GREEN})); {QM_RED, QM_BLUE, QM_GREEN, QM_RED, QM_GREEN}));
hintTextTable[RHT_MALON_HINT_TURNING_EVIL] = HintText(CustomMessage("@? Is that you? ^If I ran the ranch, I'd build an #Obstacle Course#, and whoever gets the best time would win a #cow#!^" hintTextTable[RHT_MALON_HINT_TURNING_EVIL] = HintText(CustomMessage("@? Is that you? ^If I ran the ranch, I'd build an #Obstacle Course#, and whoever gets the best time would win a #cow#!^"
@@ -149,6 +149,7 @@ static void PlaceItemsForType(RandomizerCheckType rctype, bool overworldActive =
void GenerateItemPool() { void GenerateItemPool() {
// RANDOTODO proper removal of items not in pool or logically relevant instead of dummy checks. // RANDOTODO proper removal of items not in pool or logically relevant instead of dummy checks.
auto ctx = Rando::Context::GetInstance(); auto ctx = Rando::Context::GetInstance();
ctx->possibleIceTrapModels.clear();
itemPool.clear(); itemPool.clear();
junkPool.clear(); junkPool.clear();
plentifulPool.clear(); plentifulPool.clear();
@@ -36,7 +36,8 @@ void BuildMerchantMessage(CustomMessage& msg, RandomizerCheck rc, bool mysteriou
itemName = CustomMessage(RAND_GET_OVERRIDE(rc).GetTrickName()); itemName = CustomMessage(RAND_GET_OVERRIDE(rc).GetTrickName());
color = "%g"; color = "%g";
} else { } else {
itemName = CustomMessage(Rando::StaticData::RetrieveItem(rgid).GetName()); const Rando::Item& item = Rando::StaticData::RetrieveItem(rgid);
itemName = item.GetHint().GetHintMessage().GetForCurrentLanguage();
} }
msg.Replace("[[color]]", color); msg.Replace("[[color]]", color);
msg.InsertNames({ itemName, CustomMessage(std::to_string(price)) }); msg.InsertNames({ itemName, CustomMessage(std::to_string(price)) });
@@ -49,9 +50,9 @@ void BuildBeanGuyMessage(uint16_t* textId, bool* loadFromMessageTable) {
"I never thought I'd say this, but I'm selling the last %rMagic Bean%w.^%y99 Rupees%w, no " "I never thought I'd say this, but I'm selling the last %rMagic Bean%w.^%y99 Rupees%w, no "
"less.\x1B%gYes&No%w", "less.\x1B%gYes&No%w",
"Ich hätte nie gedacht, daß ich das sage, aber ich verkaufe die letzte^%rWundererbse%w für %y99 " "Ich hätte nie gedacht, daß ich das sage, aber ich verkaufe die letzte^%rWundererbse%w für %y99 "
"Rubine%w.\x1B&%gJa&Nein%w", "Rubine%w.\x1B%gJa&Nein%w",
"Je te vends mon dernier %rHaricot&magique%g pour %y99 Rubis%w.\x1B&%gAcheterNe pas acheter%w"); "Je te vends mon dernier %rHaricot&magique%w pour %y99 Rubis%w.\x1B%gAcheter&Ne pas acheter%w");
msg.Format(); msg.AutoFormat();
} else if (*textId == TEXT_BEAN_SALESMAN_BUY_FOR_10) { } else if (*textId == TEXT_BEAN_SALESMAN_BUY_FOR_10) {
msg = CustomMessage("Want to buy [[color]][[1]]%w for %y[[2]] Rupees%w?\x1B%gYes&No%w", msg = CustomMessage("Want to buy [[color]][[1]]%w for %y[[2]] Rupees%w?\x1B%gYes&No%w",
"Möchten Sie [[color]][[1]]%w für %y[[2]] Rubin%w kaufen?\x1B%gJa&Nein%w", "Möchten Sie [[color]][[1]]%w für %y[[2]] Rubin%w kaufen?\x1B%gJa&Nein%w",
@@ -140,7 +140,7 @@ void BuildSkulltulaPeopleMessage(uint16_t* textId, bool* loadFromMessageTable) {
"et j'aurai quelque chose à te donner! [[color]]([[1]])%w"); "et j'aurai quelque chose à te donner! [[color]]([[1]])%w");
msg.InsertNumber(count); msg.InsertNumber(count);
msg.Replace("[[color]]", item.GetColor()); msg.Replace("[[color]]", item.GetColor());
msg.InsertNames({ item.GetName() }); msg.InsertNames({ item.GetHint().GetHintMessage().GetForCurrentLanguage() });
msg.AutoFormat(); msg.AutoFormat();
msg.LoadIntoFont(); msg.LoadIntoFont();
*loadFromMessageTable = false; *loadFromMessageTable = false;
@@ -155,12 +155,10 @@ void Build100SkullsHintMessage(uint16_t* textId, bool* loadFromMessageTable) {
/*french*/ /*french*/
"Yeaaarrgh! Je suis maudit!^Détruit encore %y100 Araignées de la Malédiction%w " "Yeaaarrgh! Je suis maudit!^Détruit encore %y100 Araignées de la Malédiction%w "
"et j'aurai quelque chose à te donner! [[color]]([[1]])%w"); "et j'aurai quelque chose à te donner! [[color]]([[1]])%w");
msg.Replace("[[color]]", Rando::StaticData::RetrieveItem( Rando::Item& item =
RAND_GET_ITEM_LOC(RC_KAK_100_GOLD_SKULLTULA_REWARD)->GetPlacedRandomizerGet()) Rando::StaticData::RetrieveItem(RAND_GET_ITEM_LOC(RC_KAK_100_GOLD_SKULLTULA_REWARD)->GetPlacedRandomizerGet());
.GetColor()); msg.Replace("[[color]]", item.GetColor());
msg.InsertNames( msg.InsertNames({ item.GetHint().GetHintMessage().GetForCurrentLanguage() });
{ Rando::StaticData::RetrieveItem(RAND_GET_ITEM_LOC(RC_KAK_100_GOLD_SKULLTULA_REWARD)->GetPlacedRandomizerGet())
.GetName() });
msg.AutoFormat(); msg.AutoFormat();
msg.LoadIntoFont(); msg.LoadIntoFont();
*loadFromMessageTable = false; *loadFromMessageTable = false;
@@ -4,6 +4,7 @@
#include <libultraship/libultra.h> #include <libultraship/libultra.h>
#include "global.h" #include "global.h"
#include "soh/ObjectExtension/ObjectExtension.h" #include "soh/ObjectExtension/ObjectExtension.h"
#include "item_category_adj.h"
extern "C" { extern "C" {
#include "variables.h" #include "variables.h"
@@ -35,24 +36,7 @@ extern "C" void ObjKibako2_RandomizerDraw(Actor* thisx, PlayState* play) {
GetItemEntry crateItem = GetItemEntry crateItem =
Rando::Context::GetInstance()->GetFinalGIEntry(crateIdentity->randomizerCheck, true, GI_NONE); Rando::Context::GetInstance()->GetFinalGIEntry(crateIdentity->randomizerCheck, true, GI_NONE);
getItemCategory = crateItem.getItemCategory; getItemCategory = Randomizer_AdjustItemCategory(crateItem);
// If they have bombchus, don't consider the bombchu item major
if (INV_CONTENT(ITEM_BOMBCHU) == ITEM_BOMBCHU &&
((crateItem.modIndex == MOD_RANDOMIZER && crateItem.getItemId == RG_PROGRESSIVE_BOMBCHU_BAG) ||
(crateItem.modIndex == MOD_NONE &&
(crateItem.getItemId == GI_BOMBCHUS_5 || crateItem.getItemId == GI_BOMBCHUS_10 ||
crateItem.getItemId == GI_BOMBCHUS_20)))) {
getItemCategory = ITEM_CATEGORY_JUNK;
// If it's a bottle and they already have one, consider the item lesser
} else if ((crateItem.modIndex == MOD_RANDOMIZER && crateItem.getItemId >= RG_BOTTLE_WITH_RED_POTION &&
crateItem.getItemId <= RG_BOTTLE_WITH_POE) ||
(crateItem.modIndex == MOD_NONE &&
(crateItem.getItemId == GI_BOTTLE || crateItem.getItemId == GI_MILK_BOTTLE))) {
if (gSaveContext.inventory.items[SLOT_BOTTLE_1] != ITEM_NONE) {
getItemCategory = ITEM_CATEGORY_LESSER;
}
}
// Change texture // Change texture
switch (getItemCategory) { switch (getItemCategory) {
@@ -102,24 +86,7 @@ extern "C" void ObjKibako_RandomizerDraw(Actor* thisx, PlayState* play) {
GetItemEntry smallCrateItem = GetItemEntry smallCrateItem =
Rando::Context::GetInstance()->GetFinalGIEntry(crateIdentity->randomizerCheck, true, GI_NONE); Rando::Context::GetInstance()->GetFinalGIEntry(crateIdentity->randomizerCheck, true, GI_NONE);
getItemCategory = smallCrateItem.getItemCategory; getItemCategory = Randomizer_AdjustItemCategory(smallCrateItem);
// If they have bombchus, don't consider the bombchu item major
if (INV_CONTENT(ITEM_BOMBCHU) == ITEM_BOMBCHU &&
((smallCrateItem.modIndex == MOD_RANDOMIZER && smallCrateItem.getItemId == RG_PROGRESSIVE_BOMBCHU_BAG) ||
(smallCrateItem.modIndex == MOD_NONE &&
(smallCrateItem.getItemId == GI_BOMBCHUS_5 || smallCrateItem.getItemId == GI_BOMBCHUS_10 ||
smallCrateItem.getItemId == GI_BOMBCHUS_20)))) {
getItemCategory = ITEM_CATEGORY_JUNK;
// If it's a bottle and they already have one, consider the item lesser
} else if ((smallCrateItem.modIndex == MOD_RANDOMIZER && smallCrateItem.getItemId >= RG_BOTTLE_WITH_RED_POTION &&
smallCrateItem.getItemId <= RG_BOTTLE_WITH_POE) ||
(smallCrateItem.modIndex == MOD_NONE &&
(smallCrateItem.getItemId == GI_BOTTLE || smallCrateItem.getItemId == GI_MILK_BOTTLE))) {
if (gSaveContext.inventory.items[SLOT_BOTTLE_1] != ITEM_NONE) {
getItemCategory = ITEM_CATEGORY_LESSER;
}
}
// Change texture // Change texture
switch (getItemCategory) { switch (getItemCategory) {
@@ -1,6 +1,7 @@
#include <soh/OTRGlobals.h> #include <soh/OTRGlobals.h>
#include "soh_assets.h" #include "soh_assets.h"
#include "static_data.h" #include "static_data.h"
#include "item_category_adj.h"
#include "soh/ObjectExtension/ObjectExtension.h" #include "soh/ObjectExtension/ObjectExtension.h"
extern "C" { extern "C" {
@@ -38,7 +39,7 @@ extern "C" void EnKusa_RandomizerDraw(Actor* thisx, PlayState* play) {
if (csmc && (!requiresStoneAgony || (requiresStoneAgony && CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY)))) { if (csmc && (!requiresStoneAgony || (requiresStoneAgony && CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY)))) {
auto itemEntry = auto itemEntry =
Rando::Context::GetInstance()->GetFinalGIEntry(grassIdentity->randomizerCheck, true, GI_NONE); Rando::Context::GetInstance()->GetFinalGIEntry(grassIdentity->randomizerCheck, true, GI_NONE);
GetItemCategory getItemCategory = itemEntry.getItemCategory; GetItemCategory getItemCategory = Randomizer_AdjustItemCategory(itemEntry);
switch (getItemCategory) { switch (getItemCategory) {
case ITEM_CATEGORY_JUNK: case ITEM_CATEGORY_JUNK:
@@ -1,6 +1,7 @@
#include "soh/OTRGlobals.h" #include "soh/OTRGlobals.h"
#include "soh_assets.h" #include "soh_assets.h"
#include "static_data.h" #include "static_data.h"
#include "item_category_adj.h"
#include "soh/ObjectExtension/ObjectExtension.h" #include "soh/ObjectExtension/ObjectExtension.h"
extern "C" { extern "C" {
@@ -28,7 +29,7 @@ extern "C" void ObjTsubo_RandomizerDraw(Actor* thisx, PlayState* play) {
if (csmc && (!requiresStoneAgony || (requiresStoneAgony && CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY)))) { if (csmc && (!requiresStoneAgony || (requiresStoneAgony && CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY)))) {
auto itemEntry = auto itemEntry =
Rando::Context::GetInstance()->GetFinalGIEntry(potIdentity->randomizerCheck, true, GI_NONE); Rando::Context::GetInstance()->GetFinalGIEntry(potIdentity->randomizerCheck, true, GI_NONE);
GetItemCategory getItemCategory = itemEntry.getItemCategory; GetItemCategory getItemCategory = Randomizer_AdjustItemCategory(itemEntry);
switch (getItemCategory) { switch (getItemCategory) {
case ITEM_CATEGORY_LESSER: case ITEM_CATEGORY_LESSER:
@@ -2,6 +2,7 @@
#include "soh_assets.h" #include "soh_assets.h"
#include "static_data.h" #include "static_data.h"
#include "soh/ObjectExtension/ObjectExtension.h" #include "soh/ObjectExtension/ObjectExtension.h"
#include "item_category_adj.h"
extern "C" { extern "C" {
#include "variables.h" #include "variables.h"
@@ -60,24 +61,7 @@ extern "C" void EnWood02_RandomizerDraw(Actor* thisx, PlayState* play) {
getItemCategory = ITEM_CATEGORY_JUNK; getItemCategory = ITEM_CATEGORY_JUNK;
} else { } else {
treeItem = Rando::Context::GetInstance()->GetFinalGIEntry(treeIdentity->randomizerCheck, true, GI_NONE); treeItem = Rando::Context::GetInstance()->GetFinalGIEntry(treeIdentity->randomizerCheck, true, GI_NONE);
getItemCategory = treeItem.getItemCategory; getItemCategory = Randomizer_AdjustItemCategory(treeItem);
// If they have bombchus, don't consider the bombchu item major
if (INV_CONTENT(ITEM_BOMBCHU) == ITEM_BOMBCHU &&
((treeItem.modIndex == MOD_RANDOMIZER && treeItem.getItemId == RG_PROGRESSIVE_BOMBCHU_BAG) ||
(treeItem.modIndex == MOD_NONE &&
(treeItem.getItemId == GI_BOMBCHUS_5 || treeItem.getItemId == GI_BOMBCHUS_10 ||
treeItem.getItemId == GI_BOMBCHUS_20)))) {
getItemCategory = ITEM_CATEGORY_JUNK;
// If it's a bottle and they already have one, consider the item lesser
} else if ((treeItem.modIndex == MOD_RANDOMIZER && treeItem.getItemId >= RG_BOTTLE_WITH_RED_POTION &&
treeItem.getItemId <= RG_BOTTLE_WITH_POE) ||
(treeItem.modIndex == MOD_NONE &&
(treeItem.getItemId == GI_BOTTLE || treeItem.getItemId == GI_MILK_BOTTLE))) {
if (gSaveContext.inventory.items[SLOT_BOTTLE_1] != ITEM_NONE) {
getItemCategory = ITEM_CATEGORY_LESSER;
}
}
} }
GraphicsContext* gfxCtx = play->state.gfxCtx; GraphicsContext* gfxCtx = play->state.gfxCtx;
+3 -7
View File
@@ -513,17 +513,13 @@ const HintText Hint::GetItemHintText(uint8_t slot, bool mysterious) const {
auto ctx = Rando::Context::GetInstance(); auto ctx = Rando::Context::GetInstance();
RandomizerCheck hintedCheck = locations[slot]; RandomizerCheck hintedCheck = locations[slot];
RandomizerGet targetRG = ctx->GetItemLocation(hintedCheck)->GetPlacedRandomizerGet(); RandomizerGet targetRG = ctx->GetItemLocation(hintedCheck)->GetPlacedRandomizerGet();
CustomMessage msg;
if (mysterious) { if (mysterious) {
return StaticData::hintTextTable[RHT_MYSTERIOUS_ITEM]; return StaticData::hintTextTable[RHT_MYSTERIOUS_ITEM];
} else if (!ctx->GetOption(RSK_HINT_CLARITY).Is(RO_HINT_CLARITY_AMBIGUOUS) && } else if (targetRG == RG_ICE_TRAP) { // RANDOTODO store in item hint instead of item
targetRG == RG_ICE_TRAP) { // RANDOTODO store in item hint instead of item return HintText(CustomMessage({ ctx->overrides[hintedCheck].GetTrickName() }));
msg = CustomMessage({ ctx->overrides[hintedCheck].GetTrickName() });
} else { } else {
msg = ctx->GetItemLocation(hintedCheck)->GetPlacedItem().GetName(); return ctx->GetItemLocation(hintedCheck)->GetPlacedItem().GetHint();
} }
msg = CustomMessage(ctx->GetItemLocation(hintedCheck)->GetPlacedItem().GetArticle()) + msg;
return HintText(msg);
} }
const HintText Hint::GetAreaHintText(uint8_t slot) const { const HintText Hint::GetAreaHintText(uint8_t slot) const {
@@ -13,6 +13,7 @@
#include "soh/SaveManager.h" #include "soh/SaveManager.h"
#include "soh/ShipInit.hpp" #include "soh/ShipInit.hpp"
#include "soh/ObjectExtension/ObjectExtension.h" #include "soh/ObjectExtension/ObjectExtension.h"
#include "item_category_adj.h"
extern "C" { extern "C" {
#include "macros.h" #include "macros.h"
@@ -370,6 +371,7 @@ void RandomizerOnPlayerUpdateForRCQueueHandler() {
GetItemID vanillaItem = (GetItemID)Rando::StaticData::RetrieveItem(vanillaRandomizerGet).GetItemID(); GetItemID vanillaItem = (GetItemID)Rando::StaticData::RetrieveItem(vanillaRandomizerGet).GetItemID();
GetItemEntry getItemEntry = GetItemEntry getItemEntry =
Rando::Context::GetInstance()->GetFinalGIEntry(rc, true, (GetItemID)vanillaRandomizerGet); Rando::Context::GetInstance()->GetFinalGIEntry(rc, true, (GetItemID)vanillaRandomizerGet);
GetItemCategory getItemCategory = Randomizer_AdjustItemCategory(getItemEntry);
if (loc->HasObtained()) { if (loc->HasObtained()) {
SPDLOG_INFO("RC {} already obtained, skipping", static_cast<uint32_t>(rc)); SPDLOG_INFO("RC {} already obtained, skipping", static_cast<uint32_t>(rc));
@@ -393,13 +395,8 @@ void RandomizerOnPlayerUpdateForRCQueueHandler() {
// crude fix to ensure map hints are readable. Ideally replace with better hint tracking. // crude fix to ensure map hints are readable. Ideally replace with better hint tracking.
!(getItemEntry.getItemId >= RG_DEKU_TREE_MAP && getItemEntry.getItemId <= RG_ICE_CAVERN_MAP && !(getItemEntry.getItemId >= RG_DEKU_TREE_MAP && getItemEntry.getItemId <= RG_ICE_CAVERN_MAP &&
getItemEntry.modIndex == MOD_RANDOMIZER) && getItemEntry.modIndex == MOD_RANDOMIZER) &&
(getItemEntry.getItemCategory == ITEM_CATEGORY_JUNK || (getItemCategory == ITEM_CATEGORY_JUNK || getItemCategory == ITEM_CATEGORY_SKULLTULA_TOKEN ||
getItemEntry.getItemCategory == ITEM_CATEGORY_SKULLTULA_TOKEN || getItemCategory == ITEM_CATEGORY_HEALTH || getItemCategory == ITEM_CATEGORY_LESSER))))) {
getItemEntry.getItemCategory == ITEM_CATEGORY_HEALTH ||
getItemEntry.getItemCategory == ITEM_CATEGORY_LESSER ||
// Treat small keys as junk if Skeleton Key is obtained.
(getItemEntry.getItemCategory == ITEM_CATEGORY_SMALL_KEY &&
Flags_GetRandomizerInf(RAND_INF_HAS_SKELETON_KEY))))))) {
Item_DropCollectible(gPlayState, &spawnPos, static_cast<int16_t>(ITEM00_SOH_GIVE_ITEM_ENTRY | 0x8000)); Item_DropCollectible(gPlayState, &spawnPos, static_cast<int16_t>(ITEM00_SOH_GIVE_ITEM_ENTRY | 0x8000));
} }
} }
@@ -446,6 +443,54 @@ void RandomizerOnItemReceiveHandler(GetItemEntry receivedItemEntry) {
randomizerQueuedItemEntry = GET_ITEM_NONE; randomizerQueuedItemEntry = GET_ITEM_NONE;
} }
if (receivedItemEntry.modIndex == MOD_RANDOMIZER && receivedItemEntry.getItemId == RG_MAGIC_BEAN_PACK) {
if (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SKIP_PLANTING_BEANS)) {
gSaveContext.sceneFlags[SCENE_DEATH_MOUNTAIN_CRATER].swch |= (1 << 3);
if (gPlayState->sceneNum == SCENE_DEATH_MOUNTAIN_CRATER) {
Flags_SetSwitch(gPlayState, 3);
}
gSaveContext.sceneFlags[SCENE_DEATH_MOUNTAIN_TRAIL].swch |= (1 << 6);
if (gPlayState->sceneNum == SCENE_DEATH_MOUNTAIN_TRAIL) {
Flags_SetSwitch(gPlayState, 6);
}
gSaveContext.sceneFlags[SCENE_DESERT_COLOSSUS].swch |= (1 << 24);
if (gPlayState->sceneNum == SCENE_DESERT_COLOSSUS) {
Flags_SetSwitch(gPlayState, 24);
}
gSaveContext.sceneFlags[SCENE_GERUDO_VALLEY].swch |= (1 << 3);
if (gPlayState->sceneNum == SCENE_GERUDO_VALLEY) {
Flags_SetSwitch(gPlayState, 3);
}
gSaveContext.sceneFlags[SCENE_GRAVEYARD].swch |= (1 << 3);
if (gPlayState->sceneNum == SCENE_GRAVEYARD) {
Flags_SetSwitch(gPlayState, 3);
}
gSaveContext.sceneFlags[SCENE_KOKIRI_FOREST].swch |= (1 << 9);
if (gPlayState->sceneNum == SCENE_KOKIRI_FOREST) {
Flags_SetSwitch(gPlayState, 9);
}
gSaveContext.sceneFlags[SCENE_LAKE_HYLIA].swch |= (1 << 1);
if (gPlayState->sceneNum == SCENE_LAKE_HYLIA) {
Flags_SetSwitch(gPlayState, 1);
}
gSaveContext.sceneFlags[SCENE_LOST_WOODS].swch |= (1 << 4) | (1 << 18);
if (gPlayState->sceneNum == SCENE_LOST_WOODS) {
Flags_SetSwitch(gPlayState, 4);
Flags_SetSwitch(gPlayState, 18);
}
gSaveContext.sceneFlags[SCENE_ZORAS_RIVER].swch |= (1 << 3);
if (gPlayState->sceneNum == SCENE_ZORAS_RIVER) {
Flags_SetSwitch(gPlayState, 3);
}
ObjBean* bean = (ObjBean*)Actor_Find(&gPlayState->actorCtx, ACTOR_OBJ_BEAN, ACTORCAT_BG);
if (bean != nullptr) {
Flags_SetSwitch(gPlayState, bean->dyna.actor.params & 0x3F);
func_80B8FE00(bean);
}
AMMO(ITEM_BEAN) = 0;
}
}
if (receivedItemEntry.modIndex == MOD_NONE && if (receivedItemEntry.modIndex == MOD_NONE &&
(receivedItemEntry.itemId == ITEM_HEART_PIECE || receivedItemEntry.itemId == ITEM_HEART_PIECE_2 || (receivedItemEntry.itemId == ITEM_HEART_PIECE || receivedItemEntry.itemId == ITEM_HEART_PIECE_2 ||
receivedItemEntry.itemId == ITEM_HEART_CONTAINER)) { receivedItemEntry.itemId == ITEM_HEART_CONTAINER)) {
@@ -980,6 +1025,15 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l
OTRGlobals::Instance->gRandoContext->GetItemLocation(RC_ZR_MAGIC_BEAN_SALESMAN)->GetPrice(); OTRGlobals::Instance->gRandoContext->GetItemLocation(RC_ZR_MAGIC_BEAN_SALESMAN)->GetPrice();
} else if (RAND_GET_OPTION(RSK_SKIP_PLANTING_BEANS)) { } else if (RAND_GET_OPTION(RSK_SKIP_PLANTING_BEANS)) {
*should = gSaveContext.rupees >= 60; *should = gSaveContext.rupees >= 60;
} else if (BEANS_BOUGHT == 9) {
*should = gSaveContext.rupees >= 99;
}
break;
}
case VB_MAGIC_BEAN_SALESMAN_TAKE_MONEY: {
if (BEANS_BOUGHT == 9) {
Rupees_ChangeBy(-99);
*should = false;
} }
break; break;
} }
@@ -0,0 +1,28 @@
#include <stdint.h>
#include "item_category_adj.h"
#include "z64item.h"
#include "variables.h"
#include "macros.h"
GetItemCategory Randomizer_AdjustItemCategory(GetItemEntry item) {
GetItemCategory category = item.getItemCategory;
// Downgrade bombchus to lesser if the player already has bombchus
if (INV_CONTENT(ITEM_BOMBCHU) == ITEM_BOMBCHU &&
((item.modIndex == MOD_RANDOMIZER && item.getItemId == RG_PROGRESSIVE_BOMBCHU_BAG) ||
(item.modIndex == MOD_NONE &&
(item.getItemId == GI_BOMBCHUS_5 || item.getItemId == GI_BOMBCHUS_10 || item.getItemId == GI_BOMBCHUS_20)))) {
category = ITEM_CATEGORY_LESSER;
}
// Downgrade bottles to lesser if the player already has a bottle
if ((item.modIndex == MOD_RANDOMIZER && item.getItemId >= RG_BOTTLE_WITH_RED_POTION &&
item.getItemId <= RG_BOTTLE_WITH_POE) ||
(item.modIndex == MOD_NONE && (item.getItemId == GI_BOTTLE || item.getItemId == GI_MILK_BOTTLE))) {
if (gSaveContext.inventory.items[SLOT_BOTTLE_1] != ITEM_NONE) {
category = ITEM_CATEGORY_LESSER;
}
}
return category;
}
@@ -0,0 +1,18 @@
#pragma once
#ifndef ITEM_CATEGORY_ADJ_H
#define ITEM_CATEGORY_ADJ_H
#include "../item-tables/ItemTableTypes.h"
#ifdef __cplusplus
extern "C" {
#endif
GetItemCategory Randomizer_AdjustItemCategory(GetItemEntry item);
#ifdef __cplusplus
}
#endif
#endif
@@ -1,7 +1,6 @@
#include "soh_assets.h" #include "soh_assets.h"
#include "static_data.h" #include "static_data.h"
#include "SeedContext.h" #include "SeedContext.h"
#include "logic.h"
#include "textures/icon_item_24_static/icon_item_24_static.h" #include "textures/icon_item_24_static/icon_item_24_static.h"
#include "textures/icon_item_static/icon_item_static.h" #include "textures/icon_item_static/icon_item_static.h"
#include "z64object.h" #include "z64object.h"
@@ -244,7 +244,7 @@ void RegionTable_Init_DekuTree() {
}, { }, {
//Locations //Locations
LOCATION(RC_DEKU_TREE_MQ_MAP_CHEST, logic->HasItem(RG_OPEN_CHEST)), LOCATION(RC_DEKU_TREE_MQ_MAP_CHEST, logic->HasItem(RG_OPEN_CHEST)),
LOCATION(RC_DEKU_TREE_MQ_GS_LOBBY, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), LOCATION(RC_DEKU_TREE_MQ_GS_LOBBY, (logic->CanBreakCrates() || ctx->GetTrickOption(RT_VISIBLE_COLLISION)) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)),
LOCATION(RC_DEKU_TREE_MQ_LOBBY_HEART, true), LOCATION(RC_DEKU_TREE_MQ_LOBBY_HEART, true),
LOCATION(RC_DEKU_TREE_MQ_2F_GRASS_1, logic->CanCutShrubs()), LOCATION(RC_DEKU_TREE_MQ_2F_GRASS_1, logic->CanCutShrubs()),
LOCATION(RC_DEKU_TREE_MQ_2F_GRASS_2, logic->CanCutShrubs()), LOCATION(RC_DEKU_TREE_MQ_2F_GRASS_2, logic->CanCutShrubs()),
@@ -725,7 +725,7 @@ void RegionTable_Init_FireTemple() {
areaTable[RR_FIRE_TEMPLE_MQ_MAZE_CRATE_CAGE] = Region("Fire Temple MQ Maze Crate Cage", SCENE_FIRE_TEMPLE, {}, { areaTable[RR_FIRE_TEMPLE_MQ_MAZE_CRATE_CAGE] = Region("Fire Temple MQ Maze Crate Cage", SCENE_FIRE_TEMPLE, {}, {
//Locations //Locations
LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST, logic->HasItem(RG_OPEN_CHEST)), LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST, logic->HasItem(RG_OPEN_CHEST) && (ctx->GetTrickOption(RT_VISIBLE_COLLISION) || logic->CanBreakCrates())),
LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_1, logic->CanBreakCrates()), LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_1, logic->CanBreakCrates()),
LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_2, logic->CanBreakCrates()), LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_2, logic->CanBreakCrates()),
LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_3, logic->CanBreakCrates()), LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_3, logic->CanBreakCrates()),
@@ -739,9 +739,8 @@ void RegionTable_Init_FireTemple() {
areaTable[RR_FIRE_TEMPLE_MQ_UPPER_LIZALFOS_MAZE] = Region("Fire Temple MQ Upper Lizalfos Maze", SCENE_FIRE_TEMPLE, {}, {}, { areaTable[RR_FIRE_TEMPLE_MQ_UPPER_LIZALFOS_MAZE] = Region("Fire Temple MQ Upper Lizalfos Maze", SCENE_FIRE_TEMPLE, {}, {}, {
//Exits //Exits
ENTRANCE(RR_FIRE_TEMPLE_MQ_LOWER_LIZALFOS_MAZE, true), ENTRANCE(RR_FIRE_TEMPLE_MQ_LOWER_LIZALFOS_MAZE, true),
//this cage is much more lenient than the lower cage as the switch is close to the front. sling, rang and bow all hit the switch easily, though might be too unintuitive for default logic ENTRANCE(RR_FIRE_TEMPLE_MQ_MAZE_BOX_CAGE, AnyAgeTime([]{return logic->CanJumpslash() || logic->HasExplosives() ||
//This shouldn't come up in most cases anyway as most methods to get here need either a melee weapon or explosives (ctx->GetTrickOption(RT_VISIBLE_COLLISION) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOOMERANG)));})),
ENTRANCE(RR_FIRE_TEMPLE_MQ_MAZE_BOX_CAGE, AnyAgeTime([]{return logic->CanJumpslash() || logic->HasExplosives();})),
ENTRANCE(RR_FIRE_TEMPLE_MQ_SHORTCUT_CLIMB, logic->HasExplosives()), ENTRANCE(RR_FIRE_TEMPLE_MQ_SHORTCUT_CLIMB, logic->HasExplosives()),
//Implies RR_FIRE_TEMPLE_MQ_LOWER_LIZALFOS_MAZE access //Implies RR_FIRE_TEMPLE_MQ_LOWER_LIZALFOS_MAZE access
ENTRANCE(RR_FIRE_TEMPLE_MQ_ABOVE_MAZE, logic->HasExplosives() && logic->CanUse(RG_MEGATON_HAMMER) && (logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_SONG_OF_TIME)))), ENTRANCE(RR_FIRE_TEMPLE_MQ_ABOVE_MAZE, logic->HasExplosives() && logic->CanUse(RG_MEGATON_HAMMER) && (logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_SONG_OF_TIME)))),
@@ -750,7 +749,7 @@ void RegionTable_Init_FireTemple() {
areaTable[RR_FIRE_TEMPLE_MQ_MAZE_BOX_CAGE] = Region("Fire Temple MQ Maze Box Cage", SCENE_FIRE_TEMPLE, {}, { areaTable[RR_FIRE_TEMPLE_MQ_MAZE_BOX_CAGE] = Region("Fire Temple MQ Maze Box Cage", SCENE_FIRE_TEMPLE, {}, {
//Locations //Locations
LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CHEST, logic->HasItem(RG_OPEN_CHEST)), LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CHEST, logic->HasItem(RG_OPEN_CHEST) && (ctx->GetTrickOption(RT_VISIBLE_COLLISION) || logic->CanBreakCrates())),
LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_1, logic->CanBreakCrates()), LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_1, logic->CanBreakCrates()),
LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_2, logic->CanBreakCrates()), LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_2, logic->CanBreakCrates()),
LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_3, logic->CanBreakCrates()), LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_3, logic->CanBreakCrates()),
@@ -461,7 +461,8 @@ void RegionTable_Init_GanonsCastle() {
areaTable[RR_GANONS_CASTLE_MQ_FIRE_TRIAL_OPEN_DOOR] = Region("Ganon's Castle MQ Fire Trial Open Door", SCENE_INSIDE_GANONS_CASTLE, {}, {}, { areaTable[RR_GANONS_CASTLE_MQ_FIRE_TRIAL_OPEN_DOOR] = Region("Ganon's Castle MQ Fire Trial Open Door", SCENE_INSIDE_GANONS_CASTLE, {}, {}, {
//Exits //Exits
ENTRANCE(RR_GANONS_CASTLE_MQ_MAIN, true) ENTRANCE(RR_GANONS_CASTLE_MQ_MAIN, true),
ENTRANCE(RR_GANONS_CASTLE_MQ_FIRE_TRIAL_FROM_OPEN, true),
}); });
areaTable[RR_GANONS_CASTLE_MQ_FIRE_TRIAL_FROM_OPEN] = Region("Ganon's Castle MQ Fire Trial From Open Door", SCENE_INSIDE_GANONS_CASTLE, { areaTable[RR_GANONS_CASTLE_MQ_FIRE_TRIAL_FROM_OPEN] = Region("Ganon's Castle MQ Fire Trial From Open Door", SCENE_INSIDE_GANONS_CASTLE, {
@@ -476,7 +477,7 @@ void RegionTable_Init_GanonsCastle() {
areaTable[RR_GANONS_CASTLE_MQ_FIRE_TRIAL_FROM_BARRED] = Region("Ganon's Castle MQ Fire Trial From Barred Door", SCENE_INSIDE_GANONS_CASTLE, {}, {}, { areaTable[RR_GANONS_CASTLE_MQ_FIRE_TRIAL_FROM_BARRED] = Region("Ganon's Castle MQ Fire Trial From Barred Door", SCENE_INSIDE_GANONS_CASTLE, {}, {}, {
//Exits //Exits
ENTRANCE(RR_GANONS_CASTLE_MQ_FIRE_TRIAL_BARRED_DOOR, true) ENTRANCE(RR_GANONS_CASTLE_MQ_FIRE_TRIAL_BARRED_DOOR, true),
}); });
areaTable[RR_GANONS_CASTLE_MQ_FIRE_TRIAL_BARRED_DOOR] = Region("Ganon's Castle MQ Fire Trial Barred Door", SCENE_INSIDE_GANONS_CASTLE, {}, {}, { areaTable[RR_GANONS_CASTLE_MQ_FIRE_TRIAL_BARRED_DOOR] = Region("Ganon's Castle MQ Fire Trial Barred Door", SCENE_INSIDE_GANONS_CASTLE, {}, {}, {
@@ -50,10 +50,9 @@ void RegionTable_Init_IceCavern() {
}, { }, {
//Locations //Locations
LOCATION(RC_ICE_CAVERN_MAP_CHEST, logic->BlueFire() && logic->HasItem(RG_OPEN_CHEST)), LOCATION(RC_ICE_CAVERN_MAP_CHEST, logic->BlueFire() && logic->HasItem(RG_OPEN_CHEST)),
// very easy to break pot through ice with most weapons // Bow extension is possible, but very precise: X = 403, Z = 2062-3, Rot = -11475, needs a setup and is its own trick
// Bow extesnion is possible, but very precise: X = 403, Z = 2062-3, Rot = -11475, needs a setup and is its own trick
LOCATION(RC_ICE_CAVERN_FROZEN_POT_1, (logic->CanBreakPots() && logic->BlueFire()) || logic->HasExplosives() || LOCATION(RC_ICE_CAVERN_FROZEN_POT_1, (logic->CanBreakPots() && logic->BlueFire()) || logic->HasExplosives() ||
(ctx->GetTrickOption(RT_VISIBLE_COLLISION) && ((logic->CanStandingShield() && logic->CanUse(RG_KOKIRI_SWORD)) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER))) || (ctx->GetTrickOption(RT_VISIBLE_COLLISION) && logic->CanJumpslash()) ||
(ctx->GetTrickOption(RT_ITEM_EXTENSION) && logic->CanUse(RG_HOOKSHOT))), (ctx->GetTrickOption(RT_ITEM_EXTENSION) && logic->CanUse(RG_HOOKSHOT))),
LOCATION(RC_ICE_CAVERN_MAP_ROOM_LEFT_HEART, true), LOCATION(RC_ICE_CAVERN_MAP_ROOM_LEFT_HEART, true),
LOCATION(RC_ICE_CAVERN_MAP_ROOM_MIDDLE_HEART, true), LOCATION(RC_ICE_CAVERN_MAP_ROOM_MIDDLE_HEART, true),
@@ -155,7 +155,7 @@ void RegionTable_Init_ShadowTemple() {
LOCATION(RC_SHADOW_TEMPLE_FALLING_SPIKES_POT_3, logic->CanUse(RG_BOOMERANG)), LOCATION(RC_SHADOW_TEMPLE_FALLING_SPIKES_POT_3, logic->CanUse(RG_BOOMERANG)),
}, { }, {
//Exits //Exits
ENTRANCE(RR_SHADOW_TEMPLE_LOWER_HUGE_PIT, true), ENTRANCE(RR_SHADOW_TEMPLE_LOWER_HUGE_PIT, !!ctx->GetTrickOption(RT_VISIBLE_COLLISION)),
ENTRANCE(RR_SHADOW_TEMPLE_STONE_UMBRELLA_UPPER, ctx->GetTrickOption(RT_SHADOW_UMBRELLA_CLIP) || (ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->TakeDamage()) || (logic->IsAdult && ((ctx->GetTrickOption(RT_SHADOW_UMBRELLA_HOVER) && logic->CanUse(RG_HOVER_BOOTS)) || logic->HasItem(RG_GORONS_BRACELET)))), ENTRANCE(RR_SHADOW_TEMPLE_STONE_UMBRELLA_UPPER, ctx->GetTrickOption(RT_SHADOW_UMBRELLA_CLIP) || (ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->TakeDamage()) || (logic->IsAdult && ((ctx->GetTrickOption(RT_SHADOW_UMBRELLA_HOVER) && logic->CanUse(RG_HOVER_BOOTS)) || logic->HasItem(RG_GORONS_BRACELET)))),
}); });
@@ -638,7 +638,8 @@ void RegionTable_Init_ShadowTemple() {
//Locations //Locations
LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_WIND_ENEMY_CHEST, logic->CanKillEnemy(RE_GIBDO) && logic->HasItem(RG_OPEN_CHEST)), LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_WIND_ENEMY_CHEST, logic->CanKillEnemy(RE_GIBDO) && logic->HasItem(RG_OPEN_CHEST)),
LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_WIND_HIDDEN_CHEST, logic->HasExplosives() && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->HasItem(RG_OPEN_CHEST)), LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_WIND_HIDDEN_CHEST, logic->HasExplosives() && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->HasItem(RG_OPEN_CHEST)),
LOCATION(RC_SHADOW_TEMPLE_MQ_GS_AFTER_WIND, logic->HasExplosives()), //The various methods for this can be a bit specific, might be worthy of it's own trick when it becomes relevant with dungeon shortcut settings.
LOCATION(RC_SHADOW_TEMPLE_MQ_GS_AFTER_WIND, logic->HasExplosives() || (ctx->GetTrickOption(RT_VISIBLE_COLLISION) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA))),
LOCATION(RC_SHADOW_TEMPLE_MQ_BEFORE_BOAT_POT_1, logic->CanBreakPots()), LOCATION(RC_SHADOW_TEMPLE_MQ_BEFORE_BOAT_POT_1, logic->CanBreakPots()),
LOCATION(RC_SHADOW_TEMPLE_MQ_BEFORE_BOAT_POT_2, logic->CanBreakPots()), LOCATION(RC_SHADOW_TEMPLE_MQ_BEFORE_BOAT_POT_2, logic->CanBreakPots()),
}, { }, {
@@ -1358,7 +1358,7 @@ void RegionTable_Init_WaterTemple() {
areaTable[RR_WATER_TEMPLE_MQ_CRATE_VORTEX_CAGE] = Region("Water Temple MQ Crate Vortex Cage", SCENE_WATER_TEMPLE, {}, { areaTable[RR_WATER_TEMPLE_MQ_CRATE_VORTEX_CAGE] = Region("Water Temple MQ Crate Vortex Cage", SCENE_WATER_TEMPLE, {}, {
//Locations //Locations
LOCATION(RC_WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA) && logic->CanBreakCrates()), LOCATION(RC_WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA) && (logic->CanBreakCrates() || ctx->GetTrickOption(RT_VISIBLE_COLLISION))),
LOCATION(RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_1, logic->CanBreakCrates()), LOCATION(RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_1, logic->CanBreakCrates()),
LOCATION(RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_2, logic->CanBreakCrates()), LOCATION(RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_2, logic->CanBreakCrates()),
LOCATION(RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_3, logic->CanBreakCrates()), LOCATION(RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_3, logic->CanBreakCrates()),
@@ -30,17 +30,17 @@ void RegionTable_Init_DeathMountainCrater() {
ENTRANCE(RR_DMC_CRACKED_WALL, (logic->FireTimer() >= 16 || logic->Hearts() >= 3)), ENTRANCE(RR_DMC_CRACKED_WALL, (logic->FireTimer() >= 16 || logic->Hearts() >= 3)),
ENTRANCE(RR_DMC_SCRUB, logic->FireTimer() >= 16 || logic->Hearts() >= 3), ENTRANCE(RR_DMC_SCRUB, logic->FireTimer() >= 16 || logic->Hearts() >= 3),
ENTRANCE(RR_DMC_BLOCKED_EXIT, ((logic->FireTimer() >= 24 || logic->Hearts() >= 5) && logic->DMCUpperToPots()) || ENTRANCE(RR_DMC_BLOCKED_EXIT, ((logic->FireTimer() >= 24 || logic->Hearts() >= 5) && logic->DMCUpperToPots()) ||
(logic->IsAdult && (logic->FireTimer() >= 56 || logic->Hearts() >= 11) && logic->ReachDistantScarecrow() && logic->TakeDamage())), (logic->IsAdult && (logic->FireTimer() >= 56 || logic->Hearts() >= 11) && logic->ReachDistantScarecrow() && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS))),
ENTRANCE(RR_DMC_POTS, ((logic->FireTimer() >= 32 || logic->Hearts() >= 6) && logic->DMCUpperToPots()) || ENTRANCE(RR_DMC_POTS, ((logic->FireTimer() >= 32 || logic->Hearts() >= 6) && logic->DMCUpperToPots()) ||
(logic->IsAdult && (logic->FireTimer() >= 48 || logic->Hearts() >= 9) && logic->ReachDistantScarecrow() && logic->TakeDamage())), (logic->IsAdult && (logic->FireTimer() >= 48 || logic->Hearts() >= 9) && logic->ReachDistantScarecrow() && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS))),
ENTRANCE(RR_DMC_POT_GROTTO_EXIT, ((logic->FireTimer() >= 32 || logic->Hearts() >= 6) && logic->DMCUpperToPots()) || ENTRANCE(RR_DMC_POT_GROTTO_EXIT, ((logic->FireTimer() >= 32 || logic->Hearts() >= 6) && logic->DMCUpperToPots()) ||
(logic->IsAdult && (logic->FireTimer() >= 48 || logic->Hearts() >= 9) && logic->ReachDistantScarecrow() && logic->TakeDamage())), (logic->IsAdult && (logic->FireTimer() >= 48 || logic->Hearts() >= 9) && logic->ReachDistantScarecrow() && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS))),
ENTRANCE(RR_DMC_CENTRAL, ((logic->FireTimer() >= 64 || logic->Hearts() >= 12) && logic->DMCUpperToPots() && logic->DMCPotsToPad()) || ENTRANCE(RR_DMC_CENTRAL, ((logic->FireTimer() >= 64 || logic->Hearts() >= 12) && logic->DMCUpperToPots() && logic->DMCPotsToPad()) ||
(logic->IsAdult && (logic->FireTimer() >= 48 || logic->Hearts() >= 9) && logic->ReachDistantScarecrow() && logic->TakeDamage())), (logic->IsAdult && (logic->FireTimer() >= 48 || logic->Hearts() >= 9) && logic->ReachDistantScarecrow() && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS))),
ENTRANCE(RR_DMC_FAR_PLATFORM, (logic->IsAdult && (logic->FireTimer() >= 72 || logic->Hearts() >= 14) && logic->DMCUpperToPots() && logic->DMCPotsToPad() && logic->ReachDistantScarecrow()) || ENTRANCE(RR_DMC_FAR_PLATFORM, (logic->IsAdult && (logic->FireTimer() >= 72 || logic->Hearts() >= 14) && logic->DMCUpperToPots() && logic->DMCPotsToPad() && logic->ReachDistantScarecrow()) ||
(logic->FireTimer() >= 24 || logic->Hearts() >= 5) && logic->TakeDamage()), (logic->FireTimer() >= 24 || logic->Hearts() >= 5) && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS)),
ENTRANCE(RR_DMC_TEMPLE_EXIT, ((logic->FireTimer() >= 72 || logic->Hearts() >= 14) && logic->DMCUpperToPots() && logic->DMCPotsToPad()) || ENTRANCE(RR_DMC_TEMPLE_EXIT, ((logic->FireTimer() >= 72 || logic->Hearts() >= 14) && logic->DMCUpperToPots() && logic->DMCPotsToPad()) ||
(logic->IsAdult && (logic->FireTimer() >= 48 || logic->Hearts() >= 9) && logic->ReachDistantScarecrow() && logic->TakeDamage())), (logic->IsAdult && (logic->FireTimer() >= 48 || logic->Hearts() >= 9) && logic->ReachDistantScarecrow() && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS))),
}); });
areaTable[RR_DMC_ROCKS_GROTTO_ENTRY] = Region("DMC Rocks Grotto Entry", SCENE_DEATH_MOUNTAIN_CRATER, { areaTable[RR_DMC_ROCKS_GROTTO_ENTRY] = Region("DMC Rocks Grotto Entry", SCENE_DEATH_MOUNTAIN_CRATER, {
@@ -56,17 +56,17 @@ void RegionTable_Init_DeathMountainCrater() {
ENTRANCE(RR_DMC_CRACKED_WALL, (logic->FireTimer() >= 16 || logic->Hearts() >= 3)), ENTRANCE(RR_DMC_CRACKED_WALL, (logic->FireTimer() >= 16 || logic->Hearts() >= 3)),
ENTRANCE(RR_DMC_SCRUB, logic->FireTimer() >= 16 || logic->Hearts() >= 3), ENTRANCE(RR_DMC_SCRUB, logic->FireTimer() >= 16 || logic->Hearts() >= 3),
ENTRANCE(RR_DMC_BLOCKED_EXIT, ((logic->FireTimer() >= 32 || logic->Hearts() >= 6) && logic->DMCUpperToPots()) || ENTRANCE(RR_DMC_BLOCKED_EXIT, ((logic->FireTimer() >= 32 || logic->Hearts() >= 6) && logic->DMCUpperToPots()) ||
(logic->IsAdult && (logic->FireTimer() >= 48 || logic->Hearts() >= 9) && logic->ReachDistantScarecrow() && logic->TakeDamage())), (logic->IsAdult && (logic->FireTimer() >= 48 || logic->Hearts() >= 9) && logic->ReachDistantScarecrow() && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS))),
ENTRANCE(RR_DMC_POTS, ((logic->FireTimer() >= 32 || logic->Hearts() >= 6) && logic->DMCUpperToPots()) || ENTRANCE(RR_DMC_POTS, ((logic->FireTimer() >= 32 || logic->Hearts() >= 6) && logic->DMCUpperToPots()) ||
(logic->IsAdult && (logic->FireTimer() >= 40 || logic->Hearts() >= 8) && logic->ReachDistantScarecrow() && logic->TakeDamage())), (logic->IsAdult && (logic->FireTimer() >= 40 || logic->Hearts() >= 8) && logic->ReachDistantScarecrow() && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS))),
ENTRANCE(RR_DMC_POT_GROTTO_EXIT, ((logic->FireTimer() >= 40 || logic->Hearts() >= 8) && logic->DMCUpperToPots()) || ENTRANCE(RR_DMC_POT_GROTTO_EXIT, ((logic->FireTimer() >= 40 || logic->Hearts() >= 8) && logic->DMCUpperToPots()) ||
(logic->IsAdult && (logic->FireTimer() >= 40 || logic->Hearts() >= 8) && logic->ReachDistantScarecrow() && logic->TakeDamage())), (logic->IsAdult && (logic->FireTimer() >= 40 || logic->Hearts() >= 8) && logic->ReachDistantScarecrow() && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS))),
ENTRANCE(RR_DMC_CENTRAL, ((logic->FireTimer() >= 64 || logic->Hearts() >= 12) && logic->DMCUpperToPots() && logic->DMCPotsToPad()) || ENTRANCE(RR_DMC_CENTRAL, ((logic->FireTimer() >= 64 || logic->Hearts() >= 12) && logic->DMCUpperToPots() && logic->DMCPotsToPad()) ||
(logic->IsAdult && (logic->FireTimer() >= 40 || logic->Hearts() >= 3) && logic->ReachDistantScarecrow() && logic->TakeDamage())), (logic->IsAdult && (logic->FireTimer() >= 40 || logic->Hearts() >= 3) && logic->ReachDistantScarecrow() && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS))),
ENTRANCE(RR_DMC_FAR_PLATFORM, (logic->IsAdult && (logic->FireTimer() >= 72 || logic->Hearts() >= 14) && logic->DMCUpperToPots() && logic->DMCPotsToPad() && logic->ReachDistantScarecrow()) || ENTRANCE(RR_DMC_FAR_PLATFORM, (logic->IsAdult && (logic->FireTimer() >= 72 || logic->Hearts() >= 14) && logic->DMCUpperToPots() && logic->DMCPotsToPad() && logic->ReachDistantScarecrow()) ||
(logic->FireTimer() >= 16 || logic->Hearts() >= 3) && logic->TakeDamage()), (logic->FireTimer() >= 16 || logic->Hearts() >= 3) && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS)),
ENTRANCE(RR_DMC_TEMPLE_EXIT, ((logic->FireTimer() >= 64 || logic->Hearts() >= 12) && logic->DMCUpperToPots() && logic->DMCPotsToPad()) || ENTRANCE(RR_DMC_TEMPLE_EXIT, ((logic->FireTimer() >= 64 || logic->Hearts() >= 12) && logic->DMCUpperToPots() && logic->DMCPotsToPad()) ||
(logic->IsAdult && (logic->FireTimer() >= 40 || logic->Hearts() >= 3) && logic->ReachDistantScarecrow() && logic->TakeDamage())), (logic->IsAdult && (logic->FireTimer() >= 40 || logic->Hearts() >= 3) && logic->ReachDistantScarecrow() && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS))),
}); });
areaTable[RR_DMC_BLOCKED_ENTRY] = Region("DMC Blocked Entry", SCENE_DEATH_MOUNTAIN_CRATER, {}, { areaTable[RR_DMC_BLOCKED_ENTRY] = Region("DMC Blocked Entry", SCENE_DEATH_MOUNTAIN_CRATER, {}, {
@@ -92,13 +92,13 @@ void RegionTable_Init_DeathMountainCrater() {
ENTRANCE(RR_DMC_POTS, logic->FireTimer() >= 8 || logic->Hearts() >= 2), ENTRANCE(RR_DMC_POTS, logic->FireTimer() >= 8 || logic->Hearts() >= 2),
ENTRANCE(RR_DMC_POT_GROTTO_EXIT, logic->FireTimer() >= 16 || logic->Hearts() >= 3), ENTRANCE(RR_DMC_POT_GROTTO_EXIT, logic->FireTimer() >= 16 || logic->Hearts() >= 3),
ENTRANCE(RR_DMC_CENTRAL, ((logic->FireTimer() >= 40 || logic->Hearts() >= 8) && logic->DMCPotsToPad()) || ENTRANCE(RR_DMC_CENTRAL, ((logic->FireTimer() >= 40 || logic->Hearts() >= 8) && logic->DMCPotsToPad()) ||
(logic->IsAdult && (logic->FireTimer() >= 48 || logic->Hearts() >= 9) && logic->ReachDistantScarecrow() && logic->TakeDamage() && logic->CanClimbLadder())), (logic->IsAdult && (logic->FireTimer() >= 48 || logic->Hearts() >= 9) && logic->ReachDistantScarecrow() && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS) && logic->CanClimbLadder())),
ENTRANCE(RR_DMC_FAR_PLATFORM, (logic->IsAdult && (logic->FireTimer() >= 48 || logic->Hearts() >= 9) && logic->DMCPotsToPad() && logic->ReachDistantScarecrow()) || ENTRANCE(RR_DMC_FAR_PLATFORM, (logic->IsAdult && (logic->FireTimer() >= 48 || logic->Hearts() >= 9) && logic->DMCPotsToPad() && logic->ReachDistantScarecrow()) ||
((logic->FireTimer() >= 32 || logic->Hearts() >= 6) && logic->TakeDamage() && logic->CanClimbLadder()) || ((logic->FireTimer() >= 32 || logic->Hearts() >= 6) && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS) && logic->CanClimbLadder()) ||
(logic->IsAdult && (logic->FireTimer() >= 48 || logic->Hearts() >= 9) && logic->DMCPotsToPad() && CanPlantBean(RR_DMC_CENTRAL, RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL)) || (logic->IsAdult && (logic->FireTimer() >= 48 || logic->Hearts() >= 9) && logic->DMCPotsToPad() && CanPlantBean(RR_DMC_CENTRAL, RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL)) ||
((logic->FireTimer() >= 32 || logic->Hearts() >= 6) && logic->TakeDamage() && ctx->GetTrickOption(RT_DMC_HOVER_BEAN_POH) && logic->CanUse(RG_HOVER_BOOTS))), ((logic->FireTimer() >= 32 || logic->Hearts() >= 6) && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS) && ctx->GetTrickOption(RT_DMC_HOVER_BEAN_POH) && logic->CanUse(RG_HOVER_BOOTS))),
ENTRANCE(RR_DMC_TEMPLE_EXIT, ((logic->FireTimer() >= 48 || logic->Hearts() >= 9) && logic->DMCPotsToPad()) || ENTRANCE(RR_DMC_TEMPLE_EXIT, ((logic->FireTimer() >= 48 || logic->Hearts() >= 9) && logic->DMCPotsToPad()) ||
(logic->IsAdult && (logic->FireTimer() >= 56 || logic->Hearts() >= 11) && logic->TakeDamage() && logic->ReachDistantScarecrow() && logic->CanClimbLadder())), (logic->IsAdult && (logic->FireTimer() >= 56 || logic->Hearts() >= 11) && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS) && logic->ReachDistantScarecrow() && logic->CanClimbLadder())),
}); });
areaTable[RR_DMC_POTS_ENTRY] = Region("DMC Pots Entry", SCENE_DEATH_MOUNTAIN_CRATER, {}, { areaTable[RR_DMC_POTS_ENTRY] = Region("DMC Pots Entry", SCENE_DEATH_MOUNTAIN_CRATER, {}, {
@@ -124,11 +124,11 @@ void RegionTable_Init_DeathMountainCrater() {
ENTRANCE(RR_DMC_POTS, true), ENTRANCE(RR_DMC_POTS, true),
ENTRANCE(RR_DMC_POT_GROTTO_EXIT, logic->FireTimer() >= 8 || logic->Hearts() >= 2), ENTRANCE(RR_DMC_POT_GROTTO_EXIT, logic->FireTimer() >= 8 || logic->Hearts() >= 2),
ENTRANCE(RR_DMC_CENTRAL, ((logic->FireTimer() >= 32 || logic->Hearts() >= 6) && logic->DMCPotsToPad()) || ENTRANCE(RR_DMC_CENTRAL, ((logic->FireTimer() >= 32 || logic->Hearts() >= 6) && logic->DMCPotsToPad()) ||
(logic->IsAdult && (logic->FireTimer() >= 56 || logic->Hearts() >= 11) && logic->TakeDamage() && logic->ReachDistantScarecrow() && logic->CanClimbLadder())), (logic->IsAdult && (logic->FireTimer() >= 56 || logic->Hearts() >= 11) && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS) && logic->ReachDistantScarecrow() && logic->CanClimbLadder())),
ENTRANCE(RR_DMC_FAR_PLATFORM, (logic->IsAdult && (logic->FireTimer() >= 40 || logic->Hearts() >= 8) && logic->DMCPotsToPad() && logic->ReachDistantScarecrow()) || ENTRANCE(RR_DMC_FAR_PLATFORM, (logic->IsAdult && (logic->FireTimer() >= 40 || logic->Hearts() >= 8) && logic->DMCPotsToPad() && logic->ReachDistantScarecrow()) ||
((logic->FireTimer() >= 32 || logic->Hearts() >= 6) && logic->TakeDamage() && logic->CanClimbLadder())), ((logic->FireTimer() >= 32 || logic->Hearts() >= 6) && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS) && logic->CanClimbLadder())),
ENTRANCE(RR_DMC_TEMPLE_EXIT, ((logic->FireTimer() >= 40 || logic->Hearts() >= 8) && logic->DMCPotsToPad()) || ENTRANCE(RR_DMC_TEMPLE_EXIT, ((logic->FireTimer() >= 40 || logic->Hearts() >= 8) && logic->DMCPotsToPad()) ||
(logic->IsAdult && (logic->FireTimer() >= 56 || logic->Hearts() >= 11) && logic->TakeDamage() && logic->ReachDistantScarecrow() && logic->CanClimbLadder())), (logic->IsAdult && (logic->FireTimer() >= 56 || logic->Hearts() >= 11) && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS) && logic->ReachDistantScarecrow() && logic->CanClimbLadder())),
}); });
areaTable[RR_DMC_POT_GROTTO_ENTRY] = Region("DMC Pot Grotto Entry", SCENE_DEATH_MOUNTAIN_CRATER, {}, { areaTable[RR_DMC_POT_GROTTO_ENTRY] = Region("DMC Pot Grotto Entry", SCENE_DEATH_MOUNTAIN_CRATER, {}, {
@@ -154,11 +154,11 @@ void RegionTable_Init_DeathMountainCrater() {
ENTRANCE(RR_DMC_POTS, logic->FireTimer() >= 8 || logic->Hearts() >= 2), ENTRANCE(RR_DMC_POTS, logic->FireTimer() >= 8 || logic->Hearts() >= 2),
ENTRANCE(RR_DMC_POT_GROTTO_EXIT, true), ENTRANCE(RR_DMC_POT_GROTTO_EXIT, true),
ENTRANCE(RR_DMC_CENTRAL, ((logic->FireTimer() >= 32 || logic->Hearts() >= 6) && logic->DMCPotsToPad()) || ENTRANCE(RR_DMC_CENTRAL, ((logic->FireTimer() >= 32 || logic->Hearts() >= 6) && logic->DMCPotsToPad()) ||
(logic->IsAdult && (logic->FireTimer() >= 56 || logic->Hearts() >= 11) && logic->TakeDamage() && logic->ReachDistantScarecrow() && logic->CanClimbLadder())), (logic->IsAdult && (logic->FireTimer() >= 56 || logic->Hearts() >= 11) && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS) && logic->ReachDistantScarecrow() && logic->CanClimbLadder())),
ENTRANCE(RR_DMC_FAR_PLATFORM, (logic->IsAdult && (logic->FireTimer() >= 40 || logic->Hearts() >= 8) && logic->DMCPotsToPad() && logic->ReachDistantScarecrow()) || ENTRANCE(RR_DMC_FAR_PLATFORM, (logic->IsAdult && (logic->FireTimer() >= 40 || logic->Hearts() >= 8) && logic->DMCPotsToPad() && logic->ReachDistantScarecrow()) ||
((logic->FireTimer() >= 40 || logic->Hearts() >= 8) && logic->TakeDamage() && logic->CanClimbLadder())), ((logic->FireTimer() >= 40 || logic->Hearts() >= 8) && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS) && logic->CanClimbLadder())),
ENTRANCE(RR_DMC_TEMPLE_EXIT, ((logic->FireTimer() >= 40 || logic->Hearts() >= 8) && logic->DMCPotsToPad()) || ENTRANCE(RR_DMC_TEMPLE_EXIT, ((logic->FireTimer() >= 40 || logic->Hearts() >= 8) && logic->DMCPotsToPad()) ||
(logic->IsAdult && (logic->FireTimer() >= 56 || logic->Hearts() >= 11) && logic->TakeDamage() && logic->ReachDistantScarecrow() && logic->CanClimbLadder())), (logic->IsAdult && (logic->FireTimer() >= 56 || logic->Hearts() >= 11) && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS) && logic->ReachDistantScarecrow() && logic->CanClimbLadder())),
}); });
areaTable[RR_DMC_PAD_ENTRY] = Region("DMC Pad Entry", SCENE_DEATH_MOUNTAIN_CRATER, {}, { areaTable[RR_DMC_PAD_ENTRY] = Region("DMC Pad Entry", SCENE_DEATH_MOUNTAIN_CRATER, {}, {
@@ -188,7 +188,7 @@ void RegionTable_Init_DeathMountainCrater() {
ENTRANCE(RR_DMC_POT_GROTTO_EXIT, (logic->FireTimer() >= 16 || logic->Hearts() >= 3) && logic->DMCPadToPots() || ENTRANCE(RR_DMC_POT_GROTTO_EXIT, (logic->FireTimer() >= 16 || logic->Hearts() >= 3) && logic->DMCPadToPots() ||
((logic->IsAdult && logic->FireTimer() >= 24 || logic->Hearts() >= 5) && CanPlantBean(RR_DMC_CENTRAL, RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL))), ((logic->IsAdult && logic->FireTimer() >= 24 || logic->Hearts() >= 5) && CanPlantBean(RR_DMC_CENTRAL, RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL))),
ENTRANCE(RR_DMC_CENTRAL, (logic->FireTimer() >= 16 || logic->Hearts() >= 3)), ENTRANCE(RR_DMC_CENTRAL, (logic->FireTimer() >= 16 || logic->Hearts() >= 3)),
ENTRANCE(RR_DMC_FAR_PLATFORM, ((logic->FireTimer() >= 56 || logic->Hearts() >= 11) && logic->TakeDamage() && logic->CanClimbLadder() && logic->DMCPadToPots()) || ENTRANCE(RR_DMC_FAR_PLATFORM, ((logic->FireTimer() >= 56 || logic->Hearts() >= 11) && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS) && logic->CanClimbLadder() && logic->DMCPadToPots()) ||
((logic->FireTimer() >= 40 || logic->Hearts() >= 8) && ctx->GetTrickOption(RT_DMC_HOVER_BEAN_POH) && logic->CanUse(RG_HOVER_BOOTS) && logic->CanUse(RG_LONGSHOT)) || ((logic->FireTimer() >= 40 || logic->Hearts() >= 8) && ctx->GetTrickOption(RT_DMC_HOVER_BEAN_POH) && logic->CanUse(RG_HOVER_BOOTS) && logic->CanUse(RG_LONGSHOT)) ||
(logic->IsAdult && (logic->FireTimer() >= 24 || logic->Hearts() >= 5) && CanPlantBean(RR_DMC_CENTRAL, RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL))|| (logic->IsAdult && (logic->FireTimer() >= 24 || logic->Hearts() >= 5) && CanPlantBean(RR_DMC_CENTRAL, RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL))||
(logic->IsAdult && (logic->FireTimer() >= 16 || logic->Hearts() >= 3) && logic->ReachDistantScarecrow())), (logic->IsAdult && (logic->FireTimer() >= 16 || logic->Hearts() >= 3) && logic->ReachDistantScarecrow())),
@@ -232,7 +232,7 @@ void RegionTable_Init_DeathMountainCrater() {
(logic->IsAdult && (logic->FireTimer() >= 56 || logic->Hearts() >= 11) && CanPlantBean(RR_DMC_CENTRAL, RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL)))), (logic->IsAdult && (logic->FireTimer() >= 56 || logic->Hearts() >= 11) && CanPlantBean(RR_DMC_CENTRAL, RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL)))),
ENTRANCE(RR_DMC_CENTRAL, logic->HasItem(RG_CLIMB) && (logic->FireTimer() >= 48 || logic->Hearts() >= 9)), ENTRANCE(RR_DMC_CENTRAL, logic->HasItem(RG_CLIMB) && (logic->FireTimer() >= 48 || logic->Hearts() >= 9)),
ENTRANCE(RR_DMC_FAR_PLATFORM, logic->HasItem(RG_CLIMB) && ENTRANCE(RR_DMC_FAR_PLATFORM, logic->HasItem(RG_CLIMB) &&
(((logic->FireTimer() >= 88 || logic->Hearts() >= 3) && logic->TakeDamage() && logic->CanClimbLadder() && logic->DMCPadToPots()) || (((logic->FireTimer() >= 88 || logic->Hearts() >= 3) && logic->TakeDamage() && ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS) && logic->CanClimbLadder() && logic->DMCPadToPots()) ||
((logic->FireTimer() >= 72 || logic->Hearts() >= 14) && ctx->GetTrickOption(RT_DMC_HOVER_BEAN_POH) && logic->CanUse(RG_HOVER_BOOTS) && logic->CanUse(RG_LONGSHOT)) || ((logic->FireTimer() >= 72 || logic->Hearts() >= 14) && ctx->GetTrickOption(RT_DMC_HOVER_BEAN_POH) && logic->CanUse(RG_HOVER_BOOTS) && logic->CanUse(RG_LONGSHOT)) ||
(logic->IsAdult && (logic->FireTimer() >= 56 || logic->Hearts() >= 11) && CanPlantBean(RR_DMC_CENTRAL, RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL))|| (logic->IsAdult && (logic->FireTimer() >= 56 || logic->Hearts() >= 11) && CanPlantBean(RR_DMC_CENTRAL, RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL))||
(logic->IsAdult && (logic->FireTimer() >= 48 || logic->Hearts() >= 9) && logic->ReachDistantScarecrow()))), (logic->IsAdult && (logic->FireTimer() >= 48 || logic->Hearts() >= 9) && logic->ReachDistantScarecrow()))),
@@ -200,9 +200,10 @@ void RegionTable_Init_GerudoFortress() {
LOCATION(RC_GF_ABOVE_JAIL_CRATE, true), LOCATION(RC_GF_ABOVE_JAIL_CRATE, true),
}, { }, {
//Exits //Exits
//you don't take fall damage if you land on the rock with the flag on for some reason
//there's a trick to reach RR_GF_LONG_ROOF //there's a trick to reach RR_GF_LONG_ROOF
ENTRANCE(RR_GF_OUTSKIRTS, ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS) || logic->TakeDamage()), //For some reason, you take fall damage if you backflip onto the fortress but not onto the sand
//It's unintuitive to avoid being caught on landing, but that sends you to the same place anyway...
ENTRANCE(RR_GF_OUTSKIRTS, true),
ENTRANCE(RR_GF_NEAR_CHEST, logic->CanUse(RG_LONGSHOT)), ENTRANCE(RR_GF_NEAR_CHEST, logic->CanUse(RG_LONGSHOT)),
ENTRANCE(RR_GF_BELOW_CHEST, logic->TakeDamage()), ENTRANCE(RR_GF_BELOW_CHEST, logic->TakeDamage()),
ENTRANCE(RR_GF_JAIL_WINDOW, logic->CanUse(RG_HOOKSHOT)), ENTRANCE(RR_GF_JAIL_WINDOW, logic->CanUse(RG_HOOKSHOT)),
@@ -243,7 +243,8 @@ void RegionTable_Init_Kakariko() {
}, { }, {
//Locations //Locations
LOCATION(RC_KAK_TRADE_ODD_MUSHROOM, logic->IsAdult && logic->CanUse(RG_ODD_MUSHROOM)), LOCATION(RC_KAK_TRADE_ODD_MUSHROOM, logic->IsAdult && logic->CanUse(RG_ODD_MUSHROOM)),
LOCATION(RC_KAK_GRANNYS_SHOP, logic->IsAdult && logic->HasItem(RG_SPEAK_HYLIAN) && (logic->CanUse(RG_ODD_MUSHROOM) || logic->TradeQuestStep(RG_ODD_MUSHROOM))), LOCATION(RC_KAK_GRANNYS_SHOP, logic->IsAdult && logic->HasItem(RG_SPEAK_HYLIAN) &&
(logic->CanUse(RG_ODD_MUSHROOM) || logic->TradeQuestStep(RG_ODD_MUSHROOM)) && GetCheckPrice() <= GetWalletCapacity()),
}, { }, {
// Exits // Exits
ENTRANCE(RR_KAK_BACKYARD, true), ENTRANCE(RR_KAK_BACKYARD, true),
@@ -3867,51 +3867,6 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) {
if (INV_CONTENT(ITEM_BEAN) == ITEM_NONE) { if (INV_CONTENT(ITEM_BEAN) == ITEM_NONE) {
INV_CONTENT(ITEM_BEAN) = ITEM_BEAN; INV_CONTENT(ITEM_BEAN) = ITEM_BEAN;
AMMO(ITEM_BEAN) = 10; AMMO(ITEM_BEAN) = 10;
if (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SKIP_PLANTING_BEANS)) {
gSaveContext.sceneFlags[SCENE_DEATH_MOUNTAIN_CRATER].swch |= (1 << 3);
if (gPlayState->sceneNum == SCENE_DEATH_MOUNTAIN_CRATER) {
Flags_SetSwitch(gPlayState, 3);
}
gSaveContext.sceneFlags[SCENE_DEATH_MOUNTAIN_TRAIL].swch |= (1 << 6);
if (gPlayState->sceneNum == SCENE_DEATH_MOUNTAIN_TRAIL) {
Flags_SetSwitch(gPlayState, 6);
}
gSaveContext.sceneFlags[SCENE_DESERT_COLOSSUS].swch |= (1 << 24);
if (gPlayState->sceneNum == SCENE_DESERT_COLOSSUS) {
Flags_SetSwitch(gPlayState, 24);
}
gSaveContext.sceneFlags[SCENE_GERUDO_VALLEY].swch |= (1 << 3);
if (gPlayState->sceneNum == SCENE_GERUDO_VALLEY) {
Flags_SetSwitch(gPlayState, 3);
}
gSaveContext.sceneFlags[SCENE_GRAVEYARD].swch |= (1 << 3);
if (gPlayState->sceneNum == SCENE_GRAVEYARD) {
Flags_SetSwitch(gPlayState, 3);
}
gSaveContext.sceneFlags[SCENE_KOKIRI_FOREST].swch |= (1 << 9);
if (gPlayState->sceneNum == SCENE_KOKIRI_FOREST) {
Flags_SetSwitch(gPlayState, 9);
}
gSaveContext.sceneFlags[SCENE_LAKE_HYLIA].swch |= (1 << 1);
if (gPlayState->sceneNum == SCENE_LAKE_HYLIA) {
Flags_SetSwitch(gPlayState, 1);
}
gSaveContext.sceneFlags[SCENE_LOST_WOODS].swch |= (1 << 4) | (1 << 18);
if (gPlayState->sceneNum == SCENE_LOST_WOODS) {
Flags_SetSwitch(gPlayState, 4);
Flags_SetSwitch(gPlayState, 18);
}
gSaveContext.sceneFlags[SCENE_ZORAS_RIVER].swch |= (1 << 3);
if (gPlayState->sceneNum == SCENE_ZORAS_RIVER) {
Flags_SetSwitch(gPlayState, 3);
}
ObjBean* bean = (ObjBean*)Actor_Find(&gPlayState->actorCtx, ACTOR_OBJ_BEAN, ACTORCAT_BG);
if (bean != nullptr) {
Flags_SetSwitch(gPlayState, bean->dyna.actor.params & 0x3F);
func_80B8FE00(bean);
}
AMMO(ITEM_BEAN) = 0;
}
} }
break; break;
case RG_DOUBLE_DEFENSE: case RG_DOUBLE_DEFENSE:
@@ -537,11 +537,24 @@ ItemTrackerNumbers GetItemCurrentAndMax(ItemTrackerItem item) {
: 500; : 500;
result.currentAmmo = gSaveContext.rupees; result.currentAmmo = gSaveContext.rupees;
break; break;
case ITEM_BOMBCHU: case ITEM_BOMBCHU: {
result.currentCapacity = INV_CONTENT(ITEM_BOMBCHU) == ITEM_BOMBCHU ? 50 : 0; auto bombchuBag = RAND_GET_OPTION(RSK_BOMBCHU_BAG);
uint8_t capacity = 0;
if (INV_CONTENT(ITEM_BOMBCHU) == ITEM_BOMBCHU) {
if (bombchuBag.Is(RO_BOMBCHU_BAG_PROGRESSIVE)) {
capacity = OTRGlobals::Instance->gRandoContext->GetBombchuCapacity();
} else {
capacity = 50;
}
}
result.currentCapacity = capacity;
result.maxCapacity = 50; result.maxCapacity = 50;
result.currentAmmo = AMMO(ITEM_BOMBCHU); result.currentAmmo = AMMO(ITEM_BOMBCHU);
break; break;
}
case ITEM_BEAN: case ITEM_BEAN:
result.currentCapacity = INV_CONTENT(ITEM_BEAN) == ITEM_BEAN ? 10 : 0; result.currentCapacity = INV_CONTENT(ITEM_BEAN) == ITEM_BEAN ? 10 : 0;
result.maxCapacity = 10; result.maxCapacity = 10;
@@ -702,7 +715,7 @@ void DrawItemCount(ItemTrackerItem item, bool hideMax) {
bool shouldDisplayAmmo = trackerNumberDisplayMode == ITEM_TRACKER_NUMBER_AMMO || bool shouldDisplayAmmo = trackerNumberDisplayMode == ITEM_TRACKER_NUMBER_AMMO ||
trackerNumberDisplayMode == ITEM_TRACKER_NUMBER_CURRENT_AMMO_ONLY || trackerNumberDisplayMode == ITEM_TRACKER_NUMBER_CURRENT_AMMO_ONLY ||
// These items have a static capacity, so display ammo instead // These items have a static capacity, so display ammo instead
item.id == ITEM_BOMBCHU || item.id == ITEM_BEAN || item.id == QUEST_SKULL_TOKEN || item.id == ITEM_BEAN || item.id == QUEST_SKULL_TOKEN ||
item.id == ITEM_HEART_CONTAINER || item.id == ITEM_HEART_PIECE; item.id == ITEM_HEART_CONTAINER || item.id == ITEM_HEART_PIECE;
bool shouldDisplayMax = !(trackerNumberDisplayMode == ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY || bool shouldDisplayMax = !(trackerNumberDisplayMode == ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY ||
@@ -24,11 +24,14 @@ extern "C" {
#include "src/overlays/actors/ovl_En_Jj/z_en_jj.h" #include "src/overlays/actors/ovl_En_Jj/z_en_jj.h"
#include "src/overlays/actors/ovl_En_Daiku/z_en_daiku.h" #include "src/overlays/actors/ovl_En_Daiku/z_en_daiku.h"
#include "src/overlays/actors/ovl_Bg_Spot02_Objects/z_bg_spot02_objects.h" #include "src/overlays/actors/ovl_Bg_Spot02_Objects/z_bg_spot02_objects.h"
#include "src/overlays/actors/ovl_Bg_Spot06_Objects/z_bg_spot06_objects.h"
#include "src/overlays/actors/ovl_Bg_Spot03_Taki/z_bg_spot03_taki.h" #include "src/overlays/actors/ovl_Bg_Spot03_Taki/z_bg_spot03_taki.h"
#include "src/overlays/actors/ovl_Bg_Hidan_Kousi/z_bg_hidan_kousi.h" #include "src/overlays/actors/ovl_Bg_Hidan_Kousi/z_bg_hidan_kousi.h"
#include "src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.h" #include "src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.h"
#include "src/overlays/actors/ovl_En_Dnt_Demo/z_en_dnt_demo.h" #include "src/overlays/actors/ovl_En_Dnt_Demo/z_en_dnt_demo.h"
#include "src/overlays/actors/ovl_En_Po_Sisters/z_en_po_sisters.h" #include "src/overlays/actors/ovl_En_Po_Sisters/z_en_po_sisters.h"
#include "src/overlays/actors/ovl_Obj_Lightswitch/z_obj_lightswitch.h"
#include "src/overlays/actors/ovl_Bg_Jya_Bombchuiwa/z_bg_jya_bombchuiwa.h"
#include <overlays/actors/ovl_Boss_Ganondrof/z_boss_ganondrof.h> #include <overlays/actors/ovl_Boss_Ganondrof/z_boss_ganondrof.h>
#include <overlays/actors/ovl_En_Ik/z_en_ik.h> #include <overlays/actors/ovl_En_Ik/z_en_ik.h>
#include <objects/object_gnd/object_gnd.h> #include <objects/object_gnd/object_gnd.h>
@@ -328,6 +331,15 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li
RateLimitedSuccessChime(); RateLimitedSuccessChime();
break; break;
} }
case ACTOR_BG_JYA_BOMBCHUIWA: {
BgJyaBombchuiwa* bombchuiwa = (BgJyaBombchuiwa*)actor;
if (!(bombchuiwa->drawFlags & 4) && bombchuiwa->timer >= 0 && bombchuiwa->timer < 9) {
bombchuiwa->timer = 9;
}
*should = false;
RateLimitedSuccessChime();
break;
}
case ACTOR_EN_GO2: { case ACTOR_EN_GO2: {
EnGo2* biggoron = (EnGo2*)actor; EnGo2* biggoron = (EnGo2*)actor;
biggoron->isAwake = true; biggoron->isAwake = true;
@@ -376,8 +388,14 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li
RateLimitedSuccessChime(); RateLimitedSuccessChime();
break; break;
} }
case ACTOR_OBJ_LIGHTSWITCH: {
ObjLightswitch* lightswitch = (ObjLightswitch*)actor;
lightswitch->toggleDelay = 0;
*should = false;
RateLimitedSuccessChime();
break;
}
case ACTOR_BG_ICE_SHUTTER: case ACTOR_BG_ICE_SHUTTER:
case ACTOR_OBJ_LIGHTSWITCH:
case ACTOR_OBJ_SYOKUDAI: case ACTOR_OBJ_SYOKUDAI:
case ACTOR_OBJ_TIMEBLOCK: case ACTOR_OBJ_TIMEBLOCK:
case ACTOR_EN_PO_SISTERS: case ACTOR_EN_PO_SISTERS:
@@ -554,6 +572,7 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li
} }
break; break;
} }
case VB_PLAY_BEAN_PLANTING_CS:
case VB_PLAY_EYEDROP_CREATION_ANIM: case VB_PLAY_EYEDROP_CREATION_ANIM:
case VB_PLAY_EYEDROPS_CS: case VB_PLAY_EYEDROPS_CS:
case VB_PLAY_DROP_FISH_FOR_JABU_CS: case VB_PLAY_DROP_FISH_FOR_JABU_CS:
@@ -5,8 +5,7 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <spdlog/fmt/fmt.h> #include <spdlog/fmt/fmt.h>
#include <regex> #include "soh/ShipInit.hpp"
#include "soh/OTRGlobals.h"
extern "C" { extern "C" {
#include <z64.h> #include <z64.h>
@@ -625,37 +624,37 @@ CrowdControl::Effect* CrowdControl::ParseMessage(nlohmann::json dataReceived) {
case kEffectTpLinksHouse: case kEffectTpLinksHouse:
effect->giEffect = std::make_unique<GameInteractionEffect::TeleportPlayer>(); effect->giEffect = std::make_unique<GameInteractionEffect::TeleportPlayer>();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect.get())->parameters[0] = dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect.get())->parameters[0] =
GI_TP_DEST_LINKSHOUSE; ENTR_LINKS_HOUSE_CHILD_SPAWN;
break; break;
case kEffectTpMinuet: case kEffectTpMinuet:
effect->giEffect = std::make_unique<GameInteractionEffect::TeleportPlayer>(); effect->giEffect = std::make_unique<GameInteractionEffect::TeleportPlayer>();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect.get())->parameters[0] = dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect.get())->parameters[0] =
GI_TP_DEST_MINUET; ENTR_SACRED_FOREST_MEADOW_WARP_PAD;
break; break;
case kEffectTpBolero: case kEffectTpBolero:
effect->giEffect = std::make_unique<GameInteractionEffect::TeleportPlayer>(); effect->giEffect = std::make_unique<GameInteractionEffect::TeleportPlayer>();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect.get())->parameters[0] = dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect.get())->parameters[0] =
GI_TP_DEST_BOLERO; ENTR_DEATH_MOUNTAIN_CRATER_WARP_PAD;
break; break;
case kEffectTpSerenade: case kEffectTpSerenade:
effect->giEffect = std::make_unique<GameInteractionEffect::TeleportPlayer>(); effect->giEffect = std::make_unique<GameInteractionEffect::TeleportPlayer>();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect.get())->parameters[0] = dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect.get())->parameters[0] =
GI_TP_DEST_SERENADE; ENTR_LAKE_HYLIA_WARP_PAD;
break; break;
case kEffectTpRequiem: case kEffectTpRequiem:
effect->giEffect = std::make_unique<GameInteractionEffect::TeleportPlayer>(); effect->giEffect = std::make_unique<GameInteractionEffect::TeleportPlayer>();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect.get())->parameters[0] = dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect.get())->parameters[0] =
GI_TP_DEST_REQUIEM; ENTR_DESERT_COLOSSUS_WARP_PAD;
break; break;
case kEffectTpNocturne: case kEffectTpNocturne:
effect->giEffect = std::make_unique<GameInteractionEffect::TeleportPlayer>(); effect->giEffect = std::make_unique<GameInteractionEffect::TeleportPlayer>();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect.get())->parameters[0] = dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect.get())->parameters[0] =
GI_TP_DEST_NOCTURNE; ENTR_GRAVEYARD_WARP_PAD;
break; break;
case kEffectTpPrelude: case kEffectTpPrelude:
effect->giEffect = std::make_unique<GameInteractionEffect::TeleportPlayer>(); effect->giEffect = std::make_unique<GameInteractionEffect::TeleportPlayer>();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect.get())->parameters[0] = dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect.get())->parameters[0] =
GI_TP_DEST_PRELUDE; ENTR_TEMPLE_OF_TIME_WARP_PAD;
break; break;
default: default:
+4 -8
View File
@@ -403,7 +403,7 @@ void OTRGlobals::RunExtract(int argc, char* argv[]) {
std::vector<std::string> args; std::vector<std::string> args;
if (argc > 1) { if (argc > 1) {
for (int i = 1; i < argc; i++) { for (int i = 1; i < argc; i++) {
args.push_back(argv[argc]); args.push_back(argv[i]);
} }
} }
Extractor extract; Extractor extract;
@@ -462,7 +462,7 @@ void OTRGlobals::RunExtract(int argc, char* argv[]) {
#elif (defined(__WIIU__) || defined(__SWITCH__)) #elif (defined(__WIIU__) || defined(__SWITCH__))
extractStep = ES_VERIFY; extractStep = ES_VERIFY;
#else #else
extractStep = ES_EXTRACT; extractStep = args.empty() ? ES_EXTRACT : ES_EXTRACT_ARGS;
#endif #endif
} else { } else {
std::string msg; std::string msg;
@@ -547,11 +547,7 @@ void OTRGlobals::RunExtract(int argc, char* argv[]) {
"OK", "", [&]() { exit(0); }); "OK", "", [&]() { exit(0); });
} else { } else {
windowsStep = WS_DONE; windowsStep = WS_DONE;
if (args.size() > 0) { extractStep = args.empty() ? ES_EXTRACT : ES_EXTRACT_ARGS;
extractStep = ES_EXTRACT_ARGS;
} else {
extractStep = ES_EXTRACT;
}
} }
continue; continue;
} }
@@ -562,7 +558,7 @@ void OTRGlobals::RunExtract(int argc, char* argv[]) {
} }
case ES_EXTRACT_ARGS: { case ES_EXTRACT_ARGS: {
#if !defined(__SWITCH__) && !defined(__WIIU__) #if !defined(__SWITCH__) && !defined(__WIIU__)
if (args.size() == 0) { if (args.empty()) {
SohGui::RegisterPopup( SohGui::RegisterPopup(
"Run Ship of Harkinian", "All files have been processed. Run SoH?", "Yes", "No", "Run Ship of Harkinian", "All files have been processed. Run SoH?", "Yes", "No",
[&]() { [&]() {
+1 -1
View File
@@ -1801,7 +1801,7 @@ void SohMenu::AddMenuEnhancements() {
.CVar(CVAR_CHEAT("SpeedModifier.DoesntChangeJump")); .CVar(CVAR_CHEAT("SpeedModifier.DoesntChangeJump"));
AddWidget(path, "Multiplier:", WIDGET_CVAR_SLIDER_FLOAT) AddWidget(path, "Multiplier:", WIDGET_CVAR_SLIDER_FLOAT)
.CVar(CVAR_CHEAT("SpeedModifier.Value")) .CVar(CVAR_CHEAT("SpeedModifier.Value"))
.Options(FloatSliderOptions().IsPercentage().Min(1.0f).Max(5.0f).DefaultValue(1.0f).ShowButtons(true).Format( .Options(FloatSliderOptions().IsPercentage().Min(0.01f).Max(5.0f).DefaultValue(1.0f).ShowButtons(true).Format(
"%.0f%%")); "%.0f%%"));
AddWidget(path, "Button Combination:", WIDGET_CVAR_BTN_SELECTOR) AddWidget(path, "Button Combination:", WIDGET_CVAR_BTN_SELECTOR)
.CVar(CVAR_CHEAT("SpeedModifier.Btn")) .CVar(CVAR_CHEAT("SpeedModifier.Btn"))
+1 -10
View File
@@ -1250,16 +1250,7 @@ bool CVarBtnSelector(const char* label, const char* cvarName, const BtnSelectorO
} }
} // namespace UIWidgets } // namespace UIWidgets
ImVec4 GetRandomValue() { ImVec4 GetRandomValue(uint64_t* state) {
ImVec4 NewColor;
NewColor.x = (float)ShipUtils::RandomDouble();
NewColor.y = (float)ShipUtils::RandomDouble();
NewColor.z = (float)ShipUtils::RandomDouble();
return NewColor;
}
ImVec4 GetRandomValue(uint32_t seed, uint64_t* state) {
ShipUtils::RandInit(seed, state);
ImVec4 NewColor; ImVec4 NewColor;
NewColor.x = (float)ShipUtils::RandomDouble(state); NewColor.x = (float)ShipUtils::RandomDouble(state);
NewColor.y = (float)ShipUtils::RandomDouble(state); NewColor.y = (float)ShipUtils::RandomDouble(state);
+1 -2
View File
@@ -1089,8 +1089,7 @@ void InsertHelpHoverText(const std::string& text);
void InsertHelpHoverText(const char* text); void InsertHelpHoverText(const char* text);
} // namespace UIWidgets } // namespace UIWidgets
ImVec4 GetRandomValue(); ImVec4 GetRandomValue(uint64_t* state = nullptr);
ImVec4 GetRandomValue(uint32_t seed, uint64_t* state = nullptr);
Color_RGBA8 RGBA8FromVec(ImVec4 vec); Color_RGBA8 RGBA8FromVec(ImVec4 vec);
ImVec4 VecFromRGBA8(Color_RGBA8 color); ImVec4 VecFromRGBA8(Color_RGBA8 color);
@@ -7,6 +7,7 @@
#include "z_bg_spot06_objects.h" #include "z_bg_spot06_objects.h"
#include "objects/object_spot06_objects/object_spot06_objects.h" #include "objects/object_spot06_objects/object_spot06_objects.h"
#include "soh/Enhancements/custom-message/CustomMessageTypes.h" #include "soh/Enhancements/custom-message/CustomMessageTypes.h"
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#define FLAGS ACTOR_FLAG_HOOKSHOT_PULLS_ACTOR #define FLAGS ACTOR_FLAG_HOOKSHOT_PULLS_ACTOR
@@ -266,7 +267,7 @@ void BgSpot06Objects_GateWaitForSwitch(BgSpot06Objects* this, PlayState* play) {
* This is where the gate waits a few frames before rising after the switch is set. * This is where the gate waits a few frames before rising after the switch is set.
*/ */
void BgSpot06Objects_GateWaitToOpen(BgSpot06Objects* this, PlayState* play) { void BgSpot06Objects_GateWaitToOpen(BgSpot06Objects* this, PlayState* play) {
if (this->timer != 0) { if (GameInteractor_Should(VB_BG_SPOT06_OBJECTS_GATE_SKIP, this->timer != 0, this)) {
this->timer--; this->timer--;
} }
@@ -604,7 +605,7 @@ void BgSpot06Objects_WaterPlaneCutsceneRise(BgSpot06Objects* this, PlayState* pl
play->roomCtx.unk_74[0] = 0; // Apply the moving under water texture to lake hylia ground play->roomCtx.unk_74[0] = 0; // Apply the moving under water texture to lake hylia ground
} }
} else { } else {
Math_SmoothStepToF(&this->lakeHyliaWaterLevel, 1.0f, 0.1f, 1.0f, 0.001f); Math_SmoothStepToF(&this->lakeHyliaWaterLevel, 1.0f, 0.1f, IS_RANDO ? 10.0f : 1.0f, 0.001f);
play->colCtx.colHeader->waterBoxes[LHWB_GERUDO_VALLEY_RIVER_LOWER].ySurface = WATER_LEVEL_RIVER_LOWERED; play->colCtx.colHeader->waterBoxes[LHWB_GERUDO_VALLEY_RIVER_LOWER].ySurface = WATER_LEVEL_RIVER_LOWERED;
play->colCtx.colHeader->waterBoxes[LHWB_MAIN_1].ySurface = this->dyna.actor.world.pos.y; play->colCtx.colHeader->waterBoxes[LHWB_MAIN_1].ySurface = this->dyna.actor.world.pos.y;
play->colCtx.colHeader->waterBoxes[LHWB_MAIN_2].ySurface = this->dyna.actor.world.pos.y; play->colCtx.colHeader->waterBoxes[LHWB_MAIN_2].ySurface = this->dyna.actor.world.pos.y;
@@ -634,7 +635,7 @@ void BgSpot06Objects_WaterPlaneCutsceneLower(BgSpot06Objects* this, PlayState* p
this->actionFunc = BgSpot06Objects_DoNothing; this->actionFunc = BgSpot06Objects_DoNothing;
} else { } else {
// Go slightly beyond -681 so the smoothing doesn't slow down too much (matches the reverse of water rise func) // Go slightly beyond -681 so the smoothing doesn't slow down too much (matches the reverse of water rise func)
Math_SmoothStepToF(&this->lakeHyliaWaterLevel, -682.0f, 0.1f, 1.0f, 0.001f); Math_SmoothStepToF(&this->lakeHyliaWaterLevel, -682.0f, 0.1f, 10.0f, 0.01f);
play->colCtx.colHeader->waterBoxes[LHWB_GERUDO_VALLEY_RIVER_LOWER].ySurface = WATER_LEVEL_RIVER_LOWERED; play->colCtx.colHeader->waterBoxes[LHWB_GERUDO_VALLEY_RIVER_LOWER].ySurface = WATER_LEVEL_RIVER_LOWERED;
play->colCtx.colHeader->waterBoxes[LHWB_GERUDO_VALLEY_RIVER_LOWER].zMin = WATER_LEVEL_RIVER_LOWER_Z - 50; play->colCtx.colHeader->waterBoxes[LHWB_GERUDO_VALLEY_RIVER_LOWER].zMin = WATER_LEVEL_RIVER_LOWER_Z - 50;
play->colCtx.colHeader->waterBoxes[LHWB_MAIN_1].ySurface = yPos; play->colCtx.colHeader->waterBoxes[LHWB_MAIN_1].ySurface = yPos;
@@ -4246,7 +4246,7 @@ void BossTw_BlastIce(BossTw* this, PlayState* play) {
Math_ApproachF(&sKotakePtr->workf[UNK_F9], 80.0f, 1.0f, 3.0f); Math_ApproachF(&sKotakePtr->workf[UNK_F9], 80.0f, 1.0f, 3.0f);
Math_ApproachF(&sKotakePtr->workf[UNK_F11], 255.0f, 1.0f, 10.0f); Math_ApproachF(&sKotakePtr->workf[UNK_F11], 255.0f, 1.0f, 10.0f);
Math_ApproachF(&sKotakePtr->workf[UNK_F12], 0.04f, 0.1f, 0.002f); Math_ApproachF(&sKotakePtr->workf[UNK_F12], 0.04f, 0.1f, 0.002f);
Math_ApproachF(&sKotakePtr->workf[UNK_F16], 70.0f, 1.0f, 5.0f); Math_ApproachF(&sKotakePtr->workf[UNK_F16], 70.0f, 1.0f, -5.0f);
if ((this->timers[0] == 70) || (this->timers[0] == 30)) { if ((this->timers[0] == 70) || (this->timers[0] == 30)) {
sKotakePtr->workf[UNK_F16] = 10.0f; sKotakePtr->workf[UNK_F16] = 10.0f;
@@ -5037,9 +5037,8 @@ void BossTw_DrawEffects(PlayState* play) {
if (sp18F == 0) { if (sp18F == 0) {
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(gTwinrovaIceSurroundingPlayerMaterialDL)); gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(gTwinrovaIceSurroundingPlayerMaterialDL));
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 195, 225, 235, 255); gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 195, 225, 235, 255);
gSPSegment( gSPSegment(POLY_XLU_DISP++, 8,
POLY_XLU_DISP++, 8, Gfx_TwoTexScroll(play->state.gfxCtx, 0, 0, 0, 0x20, 0x40, 1, 0, 0, 0x20, 0x20));
Gfx_TwoTexScrollEx(play->state.gfxCtx, 0, 0, 0, 0x20, 0x40, 1, 0, 0, 0x20, 0x20, 0, 0, 0, 0));
sp18F++; sp18F++;
BossTw_InitRand(1, 0x71AC, 0x263A); BossTw_InitRand(1, 0x71AC, 0x263A);
} }
@@ -5091,9 +5090,8 @@ void BossTw_DrawEffects(PlayState* play) {
} }
gSPSegment(POLY_XLU_DISP++, 8, gSPSegment(POLY_XLU_DISP++, 8,
Gfx_TwoTexScrollEx(play->state.gfxCtx, 0, (currentEffect->frame * 3) & 0x7F, Gfx_TwoTexScroll(play->state.gfxCtx, 0, (currentEffect->frame * 3) & 0x7F,
(-currentEffect->frame * 15) & 0xFF, 0x20, 0x40, 1, 0, 0, 0x20, 0x20, 3, -15, (-currentEffect->frame * 15) & 0xFF, 0x20, 0x40, 1, 0, 0, 0x20, 0x20));
0, 0));
Matrix_Translate(currentEffect->pos.x, currentEffect->pos.y, currentEffect->pos.z, MTXMODE_NEW); Matrix_Translate(currentEffect->pos.x, currentEffect->pos.y, currentEffect->pos.z, MTXMODE_NEW);
Matrix_ReplaceRotation(&play->billboardMtxF); Matrix_ReplaceRotation(&play->billboardMtxF);
Matrix_Scale(currentEffect->workf[EFF_SCALE], currentEffect->workf[EFF_SCALE], 1.0f, MTXMODE_APPLY); Matrix_Scale(currentEffect->workf[EFF_SCALE], currentEffect->workf[EFF_SCALE], 1.0f, MTXMODE_APPLY);
+2 -15
View File
@@ -5,6 +5,7 @@
#include "soh/OTRGlobals.h" #include "soh/OTRGlobals.h"
#include "soh/ResourceManagerHelpers.h" #include "soh/ResourceManagerHelpers.h"
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/Enhancements/randomizer/item_category_adj.h"
#define FLAGS 0 #define FLAGS 0
@@ -580,21 +581,7 @@ void EnBox_UpdateTexture(EnBox* this, PlayState* play) {
this->dyna.actor.room != 6); // Exclude treasure game chests except for the final room this->dyna.actor.room != 6); // Exclude treasure game chests except for the final room
if (!isVanilla) { if (!isVanilla) {
getItemCategory = chestItem.getItemCategory; getItemCategory = Randomizer_AdjustItemCategory(chestItem);
// If they have bombchus, don't consider the bombchu item major
if ((INV_CONTENT(ITEM_BOMBCHU) == ITEM_BOMBCHU &&
((chestItem.modIndex == MOD_RANDOMIZER && chestItem.getItemId == RG_PROGRESSIVE_BOMBCHU_BAG) ||
(chestItem.modIndex == MOD_NONE &&
(chestItem.getItemId == GI_BOMBCHUS_5 || chestItem.getItemId == GI_BOMBCHUS_10 ||
chestItem.getItemId == GI_BOMBCHUS_20)))) ||
// If it's a bottle and they already have one, consider the item lesser
((chestItem.modIndex == MOD_RANDOMIZER && chestItem.getItemId >= RG_BOTTLE_WITH_RED_POTION &&
chestItem.getItemId <= RG_BOTTLE_WITH_POE) ||
(chestItem.modIndex == MOD_NONE &&
(chestItem.getItemId == GI_BOTTLE || chestItem.getItemId == GI_MILK_BOTTLE)) &&
gSaveContext.inventory.items[SLOT_BOTTLE_1] != ITEM_NONE)) {
getItemCategory = ITEM_CATEGORY_LESSER;
}
} }
switch (this->type) { switch (this->type) {
+2 -3
View File
@@ -2,7 +2,6 @@
#include "objects/object_fz/object_fz.h" #include "objects/object_fz/object_fz.h"
#include "soh/frame_interpolation.h" #include "soh/frame_interpolation.h"
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/ObjectExtension/ActorMaximumHealth.h"
#define FLAGS \ #define FLAGS \
(ACTOR_FLAG_ATTENTION_ENABLED | ACTOR_FLAG_HOSTILE | ACTOR_FLAG_UPDATE_CULLING_DISABLED | \ (ACTOR_FLAG_ATTENTION_ENABLED | ACTOR_FLAG_HOSTILE | ACTOR_FLAG_UPDATE_CULLING_DISABLED | \
@@ -887,8 +886,8 @@ void EnFz_DrawIceSmoke(EnFz* this, PlayState* play) {
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 195, 225, 235, iceSmoke->primAlpha); gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 195, 225, 235, iceSmoke->primAlpha);
gSPSegment(POLY_XLU_DISP++, 0x08, gSPSegment(POLY_XLU_DISP++, 0x08,
Gfx_TwoTexScrollEx(play->state.gfxCtx, 0, 3 * (iceSmoke->timer + (3 * i)), Gfx_TwoTexScroll(play->state.gfxCtx, 0, 3 * (iceSmoke->timer + (3 * i)),
15 * (iceSmoke->timer + (3 * i)), 32, 64, 1, 0, 0, 32, 32, 3, 15, 0, 0)); 15 * (iceSmoke->timer + (3 * i)), 32, 64, 1, 0, 0, 32, 32));
Matrix_Translate(iceSmoke->pos.x, iceSmoke->pos.y, iceSmoke->pos.z, MTXMODE_NEW); Matrix_Translate(iceSmoke->pos.x, iceSmoke->pos.y, iceSmoke->pos.z, MTXMODE_NEW);
Matrix_ReplaceRotation(&play->billboardMtxF); Matrix_ReplaceRotation(&play->billboardMtxF);
Matrix_Scale(iceSmoke->xyScale, iceSmoke->xyScale, 1.0f, MTXMODE_APPLY); Matrix_Scale(iceSmoke->xyScale, iceSmoke->xyScale, 1.0f, MTXMODE_APPLY);
+3 -1
View File
@@ -150,7 +150,9 @@ void EnMs_Talk(EnMs* this, PlayState* play) {
void EnMs_Sell(EnMs* this, PlayState* play) { void EnMs_Sell(EnMs* this, PlayState* play) {
if (Actor_HasParent(&this->actor, play)) { if (Actor_HasParent(&this->actor, play)) {
Rupees_ChangeBy(-sPrices[BEANS_BOUGHT]); if (GameInteractor_Should(VB_MAGIC_BEAN_SALESMAN_TAKE_MONEY, true, this)) {
Rupees_ChangeBy(-sPrices[BEANS_BOUGHT]);
}
this->actor.parent = NULL; this->actor.parent = NULL;
this->actionFunc = EnMs_TalkAfterPurchase; this->actionFunc = EnMs_TalkAfterPurchase;
} else { } else {
@@ -551,7 +551,9 @@ void ObjBean_WaitForBean(ObjBean* this, PlayState* play) {
void func_80B8FE00(ObjBean* this) { void func_80B8FE00(ObjBean* this) {
this->actionFunc = func_80B8FE3C; this->actionFunc = func_80B8FE3C;
ObjBean_SetDrawMode(this, BEAN_STATE_DRAW_LEAVES); ObjBean_SetDrawMode(this, BEAN_STATE_DRAW_LEAVES);
this->timer = 60; if (GameInteractor_Should(VB_PLAY_BEAN_PLANTING_CS, true)) {
this->timer = 60;
}
} }
// Link is looking at the soft soil // Link is looking at the soft soil
@@ -256,9 +256,8 @@ void ObjSwitch_SetOn(ObjSwitch* this, PlayState* play) {
} else { } else {
OnePointCutscene_AttentionSetSfx(play, &this->dyna.actor, NA_SE_SY_TRE_BOX_APPEAR); OnePointCutscene_AttentionSetSfx(play, &this->dyna.actor, NA_SE_SY_TRE_BOX_APPEAR);
} }
this->cooldownOn = true;
} }
this->cooldownOn = true;
} }
} }
@@ -271,8 +270,8 @@ void ObjSwitch_SetOff(ObjSwitch* this, PlayState* play) {
if ((this->dyna.actor.params >> 4 & 7) == 1) { if ((this->dyna.actor.params >> 4 & 7) == 1) {
if (GameInteractor_Should(VB_PLAY_ONEPOINT_ACTOR_CS, true, this)) { if (GameInteractor_Should(VB_PLAY_ONEPOINT_ACTOR_CS, true, this)) {
OnePointCutscene_AttentionSetSfx(play, &this->dyna.actor, NA_SE_SY_TRE_BOX_APPEAR); OnePointCutscene_AttentionSetSfx(play, &this->dyna.actor, NA_SE_SY_TRE_BOX_APPEAR);
this->cooldownOn = true;
} }
this->cooldownOn = true;
} }
} }
} }
@@ -6063,7 +6063,9 @@ s32 Player_ActionHandler_13(Player* this, PlayState* play) {
Inventory_ChangeAmmo(ITEM_BEAN, -1); Inventory_ChangeAmmo(ITEM_BEAN, -1);
Player_SetupActionPreserveItemAction(play, this, Player_Action_8084279C, 0); Player_SetupActionPreserveItemAction(play, this, Player_Action_8084279C, 0);
this->stateFlags1 |= PLAYER_STATE1_IN_CUTSCENE; this->stateFlags1 |= PLAYER_STATE1_IN_CUTSCENE;
this->av2.actionVar2 = 0x50; if (GameInteractor_Should(VB_PLAY_BEAN_PLANTING_CS, true)) {
this->av2.actionVar2 = 0x50;
}
this->av1.actionVar1 = -1; this->av1.actionVar1 = -1;
} }
talkActor->flags |= ACTOR_FLAG_TALK; talkActor->flags |= ACTOR_FLAG_TALK;
@@ -122,8 +122,8 @@ void EffectSsEnIce_Draw(PlayState* play, u32 index, EffectSs* this) {
Gfx_SetupDL_25Xlu(play->state.gfxCtx); Gfx_SetupDL_25Xlu(play->state.gfxCtx);
func_8002EB44(&this->pos, &play->view.eye, &hiliteLightDir, play->state.gfxCtx); func_8002EB44(&this->pos, &play->view.eye, &hiliteLightDir, play->state.gfxCtx);
gSPSegment(POLY_XLU_DISP++, 0x08, gSPSegment(POLY_XLU_DISP++, 0x08,
Gfx_TwoTexScrollEx(play->state.gfxCtx, 0, 0, gameplayFrames & 0xFF, 0x20, 0x10, 1, 0, Gfx_TwoTexScroll(play->state.gfxCtx, 0, 0, gameplayFrames & 0xFF, 0x20, 0x10, 1, 0,
(gameplayFrames * 2) & 0xFF, 0x40, 0x20, 0, 1, 0, 2)); (gameplayFrames * 2) & 0xFF, 0x40, 0x20));
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, this->rPrimColorR, this->rPrimColorG, this->rPrimColorB, gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, this->rPrimColorR, this->rPrimColorG, this->rPrimColorB,
this->rPrimColorA); this->rPrimColorA);
gDPSetEnvColor(POLY_XLU_DISP++, this->rEnvColorR, this->rEnvColorG, this->rEnvColorB, (u32)alpha); gDPSetEnvColor(POLY_XLU_DISP++, this->rEnvColorR, this->rEnvColorG, this->rEnvColorB, (u32)alpha);