diff --git a/code/include/hid.h b/code/include/hid.h index 065e4e80..ce11b65e 100644 --- a/code/include/hid.h +++ b/code/include/hid.h @@ -116,4 +116,10 @@ typedef struct { #define CPAD_UP (1 << 30) #define CPAD_DOWN (1 << 31) +// Generic catch-all directions +#define PAD_RIGHT (BUTTON_RIGHT | CPAD_RIGHT) +#define PAD_LEFT (BUTTON_LEFT | CPAD_LEFT) +#define PAD_UP (BUTTON_UP | CPAD_UP) +#define PAD_DOWN (BUTTON_DOWN | CPAD_DOWN) + #endif // HID_H diff --git a/code/include/z3D/z3D.h b/code/include/z3D/z3D.h index b57cb3ff..1a868a5c 100644 --- a/code/include/z3D/z3D.h +++ b/code/include/z3D/z3D.h @@ -403,7 +403,7 @@ typedef struct { typedef struct { /* 0x0000 */ u8 unk_00; /* 0x0001 */ char unk_01[0x01]; - /* 0x0002 */ u8 unk_02; + /* 0x0002 */ u8 hammerQuakeFlag; /* 0x0003 */ u8 unk_03; /* 0x0004 */ char unk_04[0x04]; /* 0x0008 */ u8 total; // total number of actors loaded @@ -522,13 +522,15 @@ typedef struct GameState { /* 0x04 */ void (*main)(struct GameState*); /* 0x08 */ void (*destroy)(struct GameState*); // "cleanup" /* 0x0C */ void (*init)(struct GameState*); - // TODO + /* 0x10 */ u32 size; + /* 0x14 */ char unk_14[0xED]; + /* 0x101*/ u8 running; } GameState; +_Static_assert(sizeof(GameState) == 0x104, "GameState size"); // Global Context (ram start: 0871E840) typedef struct GlobalContext { - // /* 0x0000 */ GameState state; - /* 0x0000 */ char unk_0[0x0104]; + /* 0x0000 */ GameState state; /* 0x0104 */ s16 sceneNum; /* 0x0106 */ char unk_106[0x0012]; /* 0x0118 */ SubGlobalContext_118 sub118; @@ -573,7 +575,8 @@ typedef struct GlobalContext { /* 0x3A58 */ ObjectContext objectCtx; /* 0x43DC */ char unk_43DC[0x0854]; /* 0x4C30 */ s8 roomNum; - /* 0x4C31 */ char unk_4C31[0x0FCF]; + /* 0x4C31 */ char unk_4C31[0x0FCB]; + /* 0x5BFC */ u32 gameplayFrames; /* 0x5C00 */ u8 linkAgeOnLoad; /* 0x5C01 */ u8 unk_5C01; /* 0x5C02 */ u8 curSpawn; @@ -655,6 +658,27 @@ typedef struct TargetContext { // ... size unknown } TargetContext; +typedef struct SAModelListEntry { + SkeletonAnimationModel* saModel; + u32 unk; +} SAModelListEntry; + +typedef struct SubMainClass_180 { + /* 0x000 */ char unk_00[0x8]; + /* 0x008 */ s32 saModelsCount1; + /* 0x00C */ s32 saModelsCount2; + /* 0x010 */ char unk_10[0x10]; + /* 0x020 */ SAModelListEntry* saModelsList1; // 3D models + /* 0x024 */ SAModelListEntry* saModelsList2; // 2D billboards + /* ... size unknown*/ +} SubMainClass_180; + +typedef struct MainClass { + /* 0x000 */ char unk_00[0x180]; + /* 0x180 */ SubMainClass_180 sub180; + /* ... size unknown*/ +} MainClass; + extern GlobalContext* gGlobalContext; extern const u32 ItemSlots[]; extern const char DungeonNames[][25]; @@ -672,6 +696,7 @@ extern const char DungeonNames[][25]; #define gDrawItemTable ((DrawItemTableEntry*)0x4D88C8) #define gRestrictionFlags ((RestrictionFlags*)0x539DC4) #define PLAYER ((Player*)gGlobalContext->actorCtx.actorList[ACTORTYPE_PLAYER].first) +#define gMainClass ((MainClass*)0x5BE5B8) #define GearSlot(X) (X - ITEM_SWORD_KOKIRI) @@ -863,4 +888,15 @@ typedef void (*Animation_Change_proc)(SkelAnime* anime, s32 animation_index, f32 #define Animation_Change_addr 0x375C08 #define Animation_Change ((Animation_Change_proc)Animation_Change_addr) +typedef void (*EffectSsDeadDb_Spawn_proc)(GlobalContext* globalCtx, Vec3f* position, Vec3f* velocity, + Vec3f* acceleration, s16 scale, s16 scale_step, s16 prim_r, s16 prim_g, + s16 prim_b, s16 prim_a, s16 env_r, s16 env_g, s16 env_b, s16 unused, + s32 frame_duration, s16 play_sound); +#define EffectSsDeadDb_Spawn_addr 0x3642F4 +#define EffectSsDeadDb_Spawn ((EffectSsDeadDb_Spawn_proc)EffectSsDeadDb_Spawn_addr) + +typedef void (*SaveGame_proc)(GlobalContext* globalCtx, u8 isSaveFileCreation); +#define SaveGame_addr 0x2FDAC8 +#define SaveGame ((SaveGame_proc)SaveGame_addr) + #endif //_Z3D_H_ diff --git a/code/include/z3D/z3Dactor.h b/code/include/z3D/z3Dactor.h index 5c02c859..e89f0fbc 100644 --- a/code/include/z3D/z3Dactor.h +++ b/code/include/z3D/z3Dactor.h @@ -148,9 +148,9 @@ typedef struct { typedef struct { /* 0x00 */ Collider base; - /* 0x18 */ // ColliderInfo info; - /* 0x40 */ // Cylinderf dim; -} ColliderCylinder; // size = 0x58 + /* 0x18 */ char unk_18[0x28]; // ColliderInfo info; + /* 0x40 */ char unk_40[0x18]; // Cylinderf dim; +} ColliderCylinder; // size = 0x58 typedef struct { /* 0x00 */ Vec3s rot; // Current actor shape rotation @@ -269,7 +269,9 @@ typedef struct { /* 0x01C0 */ void* leftHandDLists; /* 0x01C4 */ void* sheathDLists; /* 0x01C8 */ void* waistDLists; - /* 0x01CC */ char unk_1CC[0x80]; + /* 0x01CC */ char unk_1CC[0x78]; + /* 0x0244 */ SkeletonAnimationModel* giModel1; + /* 0x0248 */ SkeletonAnimationModel* giModel2; /* 0x024C */ void* giDrawSpace; /* 0x0250 */ char unk_250[0x0004]; /* 0x0254 */ struct SkelAnime skelAnime; diff --git a/code/include/z3D/z3Ditem.h b/code/include/z3D/z3Ditem.h index 62aefb61..5e982b08 100644 --- a/code/include/z3D/z3Ditem.h +++ b/code/include/z3D/z3Ditem.h @@ -410,7 +410,7 @@ typedef enum { /* 0xC7 */ GI_TYCOON_WALLET, /* 0xC8 */ GI_LETTER_RUTO_2, /* 0xC9 */ GI_MAGIC_BEAN_PACK, - /* 0xCA */ GI_TRIFORCE_PIECE, // unused + /* 0xCA */ GI_TRIFORCE_PIECE, /* 0xCB */ GI_KOKIRI_EMERALD, /* 0xCC */ GI_GORON_RUBY, @@ -435,6 +435,60 @@ typedef enum { /* 0xDC */ GI_FORTRESS_KEY_RING, /* 0xDD */ GI_GANON_KEY_RING, /* 0xDE */ GI_CHEST_GAME_KEY, + + /* 0xDF */ GI_SOUL_POE, + /* 0xE0 */ GI_SOUL_OCTOROK, + /* 0xE1 */ GI_SOUL_KEESE, + /* 0xE2 */ GI_SOUL_TEKTITE, + /* 0xE3 */ GI_SOUL_LEEVER, + /* 0xE4 */ GI_SOUL_PEAHAT, + /* 0xE5 */ GI_SOUL_LIZALFOS, + /* 0xE6 */ GI_SOUL_SHABOM, + /* 0xE7 */ GI_SOUL_BIRI_BARI, + /* 0xE8 */ GI_SOUL_TAILPASARAN, + /* 0xE9 */ GI_SOUL_SKULLTULA, + /* 0xEA */ GI_SOUL_TORCH_SLUG, + /* 0xEB */ GI_SOUL_STINGER, + /* 0xEC */ GI_SOUL_MOBLIN, + /* 0xED */ GI_SOUL_ARMOS, + /* 0xEE */ GI_SOUL_DEKU_BABA, + /* 0xEF */ GI_SOUL_BUBBLE, + /* 0xF0 */ GI_SOUL_FLYING_TRAP, + /* 0xF1 */ GI_SOUL_BEAMOS, + /* 0xF2 */ GI_SOUL_WALLMASTER, + /* 0xF3 */ GI_SOUL_REDEAD_GIBDO, + /* 0xF4 */ GI_SOUL_SHELL_BLADE, + /* 0xF5 */ GI_SOUL_LIKE_LIKE, + /* 0xF6 */ GI_SOUL_TENTACLE, + /* 0xF7 */ GI_SOUL_ANUBIS, + /* 0xF8 */ GI_SOUL_SPIKE, + /* 0xF9 */ GI_SOUL_SKULL_KID, + /* 0xFA */ GI_SOUL_FREEZARD, + /* 0xFB */ GI_SOUL_DEKU_SCRUB, + /* 0xFC */ GI_SOUL_WOLFOS, + /* 0xFD */ GI_SOUL_STALCHILD, + /* 0xFE */ GI_SOUL_GUAY, + /* 0xFF */ GI_SOUL_DOOR_MIMIC, + /* 0x100 */ GI_SOUL_STALFOS, + /* 0x101 */ GI_SOUL_DARK_LINK, + /* 0x102 */ GI_SOUL_FLARE_DANCER, + /* 0x103 */ GI_SOUL_DEAD_HAND, + /* 0x104 */ GI_SOUL_GERUDO, + /* 0x105 */ GI_SOUL_GOHMA, + /* 0x106 */ GI_SOUL_DODONGO, + /* 0x107 */ GI_SOUL_BARINADE, + /* 0x108 */ GI_SOUL_PHANTOM_GANON, + /* 0x109 */ GI_SOUL_VOLVAGIA, + /* 0x10A */ GI_SOUL_MORPHA, + /* 0x10B */ GI_SOUL_BONGO_BONGO, + /* 0x10C */ GI_SOUL_TWINROVA, + /* 0x10D */ GI_SOUL_GANON, + + /* 0x10E */ GI_OCARINA_BUTTON_L, + /* 0x10F */ GI_OCARINA_BUTTON_R, + /* 0x110 */ GI_OCARINA_BUTTON_X, + /* 0x111 */ GI_OCARINA_BUTTON_Y, + /* 0x112 */ GI_OCARINA_BUTTON_A, } GetItemID; typedef enum { diff --git a/code/include/z3D/z3Dmath.h b/code/include/z3D/z3Dmath.h index 58fc0c66..0b78e67e 100644 --- a/code/include/z3D/z3Dmath.h +++ b/code/include/z3D/z3Dmath.h @@ -7,4 +7,14 @@ typedef f32 (*Math_SinS_proc)(s16 angle) __attribute__((pcs("aapcs-vfp"))); typedef f32 (*Math_CosS_proc)(s16 angle) __attribute__((pcs("aapcs-vfp"))); #define Math_CosS ((Math_CosS_proc)0x338F60) +typedef void (*Matrix_Multiply_proc)(nn_math_MTX34* dst, nn_math_MTX34* lhs, nn_math_MTX44* rhs) + __attribute__((pcs("aapcs-vfp"))); +#define Matrix_Multiply_addr 0x36C174 +#define Matrix_Multiply ((Matrix_Multiply_proc)Matrix_Multiply_addr) + +typedef void (*Matrix_UpdatePosition_proc)(nn_math_MTX34* dst, nn_math_MTX34* src, Vec3f* vec) + __attribute__((pcs("aapcs-vfp"))); +#define Matrix_UpdatePosition_addr 0x372070 +#define Matrix_UpdatePosition ((Matrix_UpdatePosition_proc)Matrix_UpdatePosition_addr) + #endif diff --git a/code/object_and_gi_usage.txt b/code/object_and_gi_usage.txt index 313437cf..cb81c6cc 100644 --- a/code/object_and_gi_usage.txt +++ b/code/object_and_gi_usage.txt @@ -12,6 +12,9 @@ The following custom objectIds are currently being used: 126: GTG Small Key 127: Ganon Small Key 128: Boss Keys +228: Enemy Souls +291: Ocarina Note Buttons +366: Triforce Piece To use a custom asset, currently: - choose an unused objectId to be repurposed for the custom item @@ -20,4 +23,5 @@ To use a custom asset, currently: - if you need to apply a custom texture to the model: - add a CMAB file with the new texture in the custom archive (romfs/zelda_gi_melody.zar) - in CustomModels_ApplyItemCMAB, add a case for the objectId + - if you need to edit the scale or position of the model, add a case in Model_Create (for overworld models) and in CustomModels_UpdateMatrix (for shop and GetItem models) - add the objectId to this txt file diff --git a/code/oot.ld b/code/oot.ld index 05847055..12eb6eab 100644 --- a/code/oot.ld +++ b/code/oot.ld @@ -48,6 +48,14 @@ SECTIONS *(.patch_ItemEtceteraModelDraw) } + .patch_FlyingPotCollision 0x11DB34 : { + *(.patch_FlyingPotCollision) + } + + .patch_DodongoAfterSwallowBomb 0x11E4B8 : { + *(.patch_DodongoAfterSwallowBomb) + } + .patch_SariasSongItemGive 0x12C84C : { *(.patch_SariasSongItemGive) } @@ -396,6 +404,10 @@ SECTIONS *(.patch_FishingSizeIgnoreAdult) } + .patch_BabyDodongoAfterSwallowBomb 0x1C42DC : { + *(.patch_BabyDodongoAfterSwallowBomb) + } + .patch_BiggoronAfterGiveItem 0x1C4E4C : { *(.patch_BiggoronAfterGiveItem) } @@ -596,6 +608,10 @@ SECTIONS *(.patch_BoleroLocation) } + .patch_FlyingTileCollision 0x26E730 : { + *(.patch_FlyingTileCollision) + } + .patch_RedBoulderExplode 0x26FE7C : { *(.patch_RedBoulderExplode) } @@ -700,6 +716,10 @@ SECTIONS *(.patch_GetCustomMessageTextOne) } + .patch_ActorDraw 0x2D6310 : { + *(.patch_ActorDraw) + } + .patch_CamUpdate 0x2D84C8 : { * (.patch_CamUpdate) } @@ -708,20 +728,12 @@ SECTIONS *(.patch_CamRoll) } - .patch_InstantTextFirstLine 0x2E049C : { - *(.patch_InstantTextFirstLine) - } - - .patch_InstantTextBoxBreak 0x2E0664 : { - *(.patch_InstantTextBoxBreak) + .patch_CheckForTextControlCode 0x2E0490 : { + * (.patch_CheckForTextControlCode) } - .patch_InstantTextRemoveOff 0x2E06C8 : { - *(.patch_InstantTextRemoveOff) - } - - .patch_SkippableText 0x2E09BC : { - *(.patch_SkippableText) + .patch_HandleTextControlCode 0x2E057C : { + * (.patch_HandleTextControlCode) } .patch_SceneInitAfterCopyScenes 0x2EAFDC : { @@ -744,6 +756,10 @@ SECTIONS *(.patch_OverrideDrawItemOne) } + .patch_OcarinaNoteButtonsDraw 0x2F9430 : { + * (.patch_OcarinaNoteButtonsDraw) + } + .patch_SaveGame 0x2FBFA8 : { *(.patch_SaveGame) } @@ -1016,6 +1032,10 @@ SECTIONS *(.patch_GerudoArcheryOne) } + .patch_ShabomAfterDamagePlayer 0x3B5060 : { + *(.patch_ShabomAfterDamagePlayer) + } + .patch_RandomGsLoc_CustomTokenSpawnOffset 0x3B94C4 : { *(.patch_RandomGsLoc_CustomTokenSpawnOffset) } @@ -1220,6 +1240,10 @@ SECTIONS *(.patch_SleepQueryCallback) } + .patch_OcarinaNoteButtonsPress 0x41AAAC : { + * (.patch_OcarinaNoteButtonsPress) + } + .patch_CurseTrapDizzyStick 0x41AB24 : { *(.patch_CurseTrapDizzyStick) } @@ -1244,8 +1268,12 @@ SECTIONS *(.patch_GearMenuEmptySlot) } - .patch_LoadGame 0x447380 : { - *(.patch_LoadGame) + .patch_BeforeLoadGame 0x447380 : { + *(.patch_BeforeLoadGame) + } + + .patch_AfterLoadGame 0x449F00 : { + *(.patch_AfterLoadGame) } .patch_DontSetMotionSetting 0x447410 : { @@ -1440,8 +1468,8 @@ SECTIONS *(.patch_AfterActorSetup_RoomChange) } - .patch_HyperActors 0x461790 : { - *(.patch_HyperActors) + .patch_ActorUpdate 0x461790 : { + *(.patch_ActorUpdate) } .patch_TitleCardUpdate 0x4618B8 : { @@ -1568,6 +1596,10 @@ SECTIONS *(.patch_HookshotRotation) } + .patch_EditDrawGetItemAfterMatrixUpdate 0x4C4D14 : { + *(.patch_EditDrawGetItemAfterMatrixUpdate) + } + .patch_EditDrawGetItemAfterModelSpawn 0x4C61A4 : { *(.patch_EditDrawGetItemAfterModelSpawn) } diff --git a/code/oot_e.ld b/code/oot_e.ld index 9aea1c48..f9da2397 100644 --- a/code/oot_e.ld +++ b/code/oot_e.ld @@ -48,6 +48,14 @@ SECTIONS *(.patch_ItemEtceteraModelDraw) } + .patch_FlyingPotCollision 0x11DB34 : { + *(.patch_FlyingPotCollision) + } + + .patch_DodongoAfterSwallowBomb 0x11E4B8 : { + *(.patch_DodongoAfterSwallowBomb) + } + .patch_SariasSongItemGive 0x12C84C : { *(.patch_SariasSongItemGive) } @@ -396,6 +404,10 @@ SECTIONS *(.patch_FishingSizeIgnoreAdult) } + .patch_BabyDodongoAfterSwallowBomb 0x1C42DC : { + *(.patch_BabyDodongoAfterSwallowBomb) + } + .patch_BiggoronAfterGiveItem 0x1C4E4C : { *(.patch_BiggoronAfterGiveItem) } @@ -596,6 +608,10 @@ SECTIONS *(.patch_BoleroLocation) } + .patch_FlyingTileCollision 0x26E730 : { + *(.patch_FlyingTileCollision) + } + .patch_RedBoulderExplode 0x26FE7C : { *(.patch_RedBoulderExplode) } @@ -700,6 +716,10 @@ SECTIONS *(.patch_GetCustomMessageTextOne) } + .patch_ActorDraw 0x2D6310 : { + *(.patch_ActorDraw) + } + .patch_CamUpdate 0x2D84C8 : { * (.patch_CamUpdate) } @@ -708,20 +728,12 @@ SECTIONS *(.patch_CamRoll) } - .patch_InstantTextFirstLine 0x2E049C : { - *(.patch_InstantTextFirstLine) - } - - .patch_InstantTextBoxBreak 0x2E0664 : { - *(.patch_InstantTextBoxBreak) + .patch_CheckForTextControlCode 0x2E0490 : { + * (.patch_CheckForTextControlCode) } - .patch_InstantTextRemoveOff 0x2E06C8 : { - *(.patch_InstantTextRemoveOff) - } - - .patch_SkippableText 0x2E09BC : { - *(.patch_SkippableText) + .patch_HandleTextControlCode 0x2E057C : { + * (.patch_HandleTextControlCode) } .patch_SceneInitAfterCopyScenes 0x2EAFDC : { @@ -744,6 +756,10 @@ SECTIONS *(.patch_OverrideDrawItemOne) } + .patch_OcarinaNoteButtonsDraw 0x2F9430 : { + * (.patch_OcarinaNoteButtonsDraw) + } + .patch_SaveGame 0x2FBFA8 : { *(.patch_SaveGame) } @@ -1016,6 +1032,10 @@ SECTIONS *(.patch_GerudoArcheryOne) } + .patch_ShabomAfterDamagePlayer 0x3B5060 : { + *(.patch_ShabomAfterDamagePlayer) + } + .patch_RandomGsLoc_CustomTokenSpawnOffset 0x3B94C4 : { *(.patch_RandomGsLoc_CustomTokenSpawnOffset) } @@ -1220,6 +1240,10 @@ SECTIONS *(.patch_SleepQueryCallback) } + .patch_OcarinaNoteButtonsPress 0x41AAD0 : { + * (.patch_OcarinaNoteButtonsPress) + } + .patch_CurseTrapDizzyStick 0x41AB48 : { *(.patch_CurseTrapDizzyStick) } @@ -1244,8 +1268,12 @@ SECTIONS *(.patch_GearMenuEmptySlot) } - .patch_LoadGame 0x4473A0 : { - *(.patch_LoadGame) + .patch_BeforeLoadGame 0x4473A0 : { + *(.patch_BeforeLoadGame) + } + + .patch_AfterLoadGame 0x449F20 : { + *(.patch_AfterLoadGame) } .patch_DontSetMotionSetting 0x447430 : { @@ -1440,8 +1468,8 @@ SECTIONS *(.patch_AfterActorSetup_RoomChange) } - .patch_HyperActors 0x4617B0 : { - *(.patch_HyperActors) + .patch_ActorUpdate 0x4617B0 : { + *(.patch_ActorUpdate) } .patch_TitleCardUpdate 0x4618D8 : { @@ -1568,6 +1596,10 @@ SECTIONS *(.patch_HookshotRotation) } + .patch_EditDrawGetItemAfterMatrixUpdate 0x4C4D14 : { + *(.patch_EditDrawGetItemAfterMatrixUpdate) + } + .patch_EditDrawGetItemAfterModelSpawn 0x4C61A4 : { *(.patch_EditDrawGetItemAfterModelSpawn) } diff --git a/code/src/actor.c b/code/src/actor.c index 970923a1..1470432f 100644 --- a/code/src/actor.c +++ b/code/src/actor.c @@ -1,5 +1,8 @@ #include "z3D/z3D.h" #include "common.h" +#include "actor.h" +#include "savefile.h" +#include "enemy_souls.h" #include "owl.h" #include "item00.h" #include "heart_container.h" @@ -55,12 +58,19 @@ #include "bean_plant.h" #include "sheik.h" #include "skulltula_people.h" +#include "red_ice.h" +#include "shabom.h" +#include "anubis.h" +#include "fishing.h" #define OBJECT_GI_KEY 170 #define OBJECT_GI_BOSSKEY 185 #define OBJECT_GI_HEARTS 189 #define OBJECT_GI_OCARINA 222 #define OBJECT_GI_OCARINA_0 270 +#define OBJECT_GI_SHOP_FAIRY 375 +#define OBJECT_GI_SOLD_OUT 328 +#define OBJECT_TRIFORCE 149 typedef void (*TitleCard_Update_proc)(GlobalContext* globalCtx, TitleCardContext* titleCtx); #ifdef Version_EUR @@ -91,6 +101,8 @@ void Actor_Init() { gActorOverlayTable[0x15].initInfo->update = EnItem00_rUpdate; gActorOverlayTable[0x15].initInfo->draw = EnItem00_rDraw; + // gActorOverlayTable[0x2D].initInfo->update = EnBubble_rUpdate; + gActorOverlayTable[0x2E].initInfo->init = DoorShutter_rInit; gActorOverlayTable[0x2E].initInfo->update = (ActorFunc)DoorShutter_rUpdate; @@ -135,6 +147,8 @@ void Actor_Init() { gActorOverlayTable[0xDC].initInfo->draw = Boss_Tw_rDraw; gActorOverlayTable[0xDC].initInfo->destroy = Boss_Tw_rDestroy; + gActorOverlayTable[0xE0].initInfo->update = EnAnubice_rUpdate; + gActorOverlayTable[0xE6].initInfo->init = BgBdanSwitch_rInit; gActorOverlayTable[0xE7].initInfo->init = EnMa1_rInit; @@ -143,6 +157,10 @@ void Actor_Init() { gActorOverlayTable[0xF1].initInfo->destroy = ItemOcarina_rDestroy; gActorOverlayTable[0xF1].initInfo->draw = ItemOcarina_rDraw; + gActorOverlayTable[0xFE].initInfo->init = Fishing_rInit; + gActorOverlayTable[0xFE].initInfo->update = Fishing_rUpdateFish; + gActorOverlayTable[0xFE].initInfo->draw = Fishing_rDrawFish; + gActorOverlayTable[0xFF].initInfo->update = ObjOshihiki_rUpdate; gActorOverlayTable[0x104].initInfo->init = BgSpot01Idomizu_rInit; @@ -253,6 +271,15 @@ void Actor_Init() { // Define object 128 to be by default the same as object 185 strncpy(gObjectTable[OBJECT_CUSTOM_BOSS_KEYS].filename, gObjectTable[OBJECT_GI_BOSSKEY].filename, 0x40); + + // Define object 228 to be by default the same as object 375 + strncpy(gObjectTable[OBJECT_CUSTOM_ENEMY_SOUL].filename, gObjectTable[OBJECT_GI_SHOP_FAIRY].filename, 0x40); + + // Define object 291 to be by default the same as object 328 + strncpy(gObjectTable[OBJECT_CUSTOM_OCARINA_BUTTON].filename, gObjectTable[OBJECT_GI_SOLD_OUT].filename, 0x40); + + // Define object 366 to be by default the same as object 149 + strncpy(gObjectTable[OBJECT_CUSTOM_TRIFORCE_PIECE].filename, gObjectTable[OBJECT_TRIFORCE].filename, 0x40); } void ActorSetup_Extra() { @@ -300,8 +327,6 @@ void HyperActors_UpdateAgain(Actor* thisx) { } void HyperActors_Main(Actor* thisx, GlobalContext* globalCtx) { - thisx->update(thisx, globalCtx); - if (!IsInGame() || thisx->update == NULL || (PLAYER != NULL && Player_InBlockingCsMode(globalCtx, PLAYER))) { return; } @@ -403,3 +428,61 @@ void HyperActors_Main(Actor* thisx, GlobalContext* globalCtx) { } } } + +void Actor_rUpdate(Actor* actor, GlobalContext* globalCtx) { + u8 tempHammerQuakeFlag = globalCtx->actorCtx.hammerQuakeFlag; + + if (!EnemySouls_CheckSoulForActor(actor)) { + globalCtx->actorCtx.hammerQuakeFlag = 0; + } + + actor->update(actor, globalCtx); + HyperActors_Main(actor, globalCtx); + + if (tempHammerQuakeFlag != 0) { + globalCtx->actorCtx.hammerQuakeFlag = tempHammerQuakeFlag; + } +} + +void Actor_rDraw(Actor* actor, GlobalContext* globalCtx) { + static Vec3f vecAcc = { 0 }; + static Vec3f vecVel = { 0 }; + + // As a temporary way to mark invulnerable enemies whose soul has not been collected yet, + // the model will not be rendered and a flame will take its place. + s32 shouldDrawSoulless = !EnemySouls_CheckSoulForActor(actor) && // soul not owned; + actor->scale.x != 0 && // if scale is 0, enemy is invisible; + actor->id != 0x11D && actor->id != 0x06B; // flying traps will appear normal. + if (shouldDrawSoulless && (PauseContext_GetState() == 0)) { + s32 velFrameIdx = (rGameplayFrames % 16); + s32 accFrameIdx = (rGameplayFrames % 4); + s32 bossMult = (actor->type == ACTORTYPE_BOSS ? 4 : 1); + vecAcc.y = 0.12f * accFrameIdx * bossMult; + vecVel.x = 0.5f * Math_SinS(0x1000 * velFrameIdx) * bossMult; + vecVel.z = 0.5f * Math_CosS(0x1000 * velFrameIdx) * bossMult; + s16 scale = 150 * bossMult; + EffectSsDeadDb_Spawn(globalCtx, &actor->focus.pos, &vecVel, &vecAcc, scale, -1, 0x6E, 0x05, 0xFF, 0xFF, 0x28, + 0x00, 0xFF, 1, 8, 0); + } + + s32 origSaModelsCount1 = gMainClass->sub180.saModelsCount1; + s32 origSaModelsCount2 = gMainClass->sub180.saModelsCount2; + + actor->draw(actor, globalCtx); + + if (shouldDrawSoulless) { + // make enemy invisible + gMainClass->sub180.saModelsCount1 = origSaModelsCount1; // 3D models + gMainClass->sub180.saModelsCount2 = origSaModelsCount2; // 2D billboards + } +} + +s32 Actor_CollisionATvsAC(Collider* at, Collider* ac) { + RedIce_CheckIceArrow(at, ac); + + if (ac->actor != 0 && !EnemySouls_CheckSoulForActor(ac->actor)) { + return 0; // ignore this collision + } + + return 1; // continue as normal +} diff --git a/code/src/actor.h b/code/src/actor.h index 21e78c16..3fed0b0d 100644 --- a/code/src/actor.h +++ b/code/src/actor.h @@ -5,5 +5,6 @@ void Actor_Init(); void ActorSetup_Extra(); +s32 Actor_CollisionATvsAC(Collider* at, Collider* ac); #endif //_ACTOR_H_ diff --git a/code/src/actors/anubis.c b/code/src/actors/anubis.c new file mode 100644 index 00000000..2a8180b8 --- /dev/null +++ b/code/src/actors/anubis.c @@ -0,0 +1,16 @@ +#include "z3D/z3D.h" +#include "anubis.h" +#include "enemy_souls.h" + +#define EnAnubice_Update ((ActorFunc)0x246E58) + +void EnAnubice_rUpdate(Actor* thisx, GlobalContext* globalCtx) { + EnAnubice* this = (EnAnubice*)thisx; + + if (!EnemySouls_CheckSoulForActor(thisx)) { + for (s32 i = 0; i < 5; i++) { + this->flameCircles[i] = 0; + } + } + EnAnubice_Update(thisx, globalCtx); +} diff --git a/code/src/actors/anubis.h b/code/src/actors/anubis.h new file mode 100644 index 00000000..86d70937 --- /dev/null +++ b/code/src/actors/anubis.h @@ -0,0 +1,16 @@ +#ifndef _ANUBIS_H_ +#define _ANUBIS_H_ + +#include "z3D/z3D.h" + +typedef struct EnAnubice { + /* 0x0000 */ Actor actor; + /* 0x01A4 */ SkelAnime skelAnime; + /* 0x0228 */ char unk_228[0x470]; + /* 0x0698 */ Actor* flameCircles[5]; + // ... +} EnAnubice; + +void EnAnubice_rUpdate(Actor* thisx, GlobalContext* globalCtx); + +#endif //_ANUBIS_H_ diff --git a/code/src/actors/dodongos.c b/code/src/actors/dodongos.c new file mode 100644 index 00000000..4bb9e24c --- /dev/null +++ b/code/src/actors/dodongos.c @@ -0,0 +1,25 @@ +#include "z3D/z3D.h" +#include "dodongos.h" +#include "enemy_souls.h" + +#define EnDodongo_Idle ((EnDodongoActionFunc)0x3E4FE8) +#define EnDodojr_JumpAttackBounce ((EnDodojrActionFunc)0x3D069C) + +s32 Dodongos_AfterSwallowBomb_Normal(EnDodongo* this) { + if (!EnemySouls_CheckSoulForActor(&this->base)) { + this->actionFunc = EnDodongo_Idle; + return 1; + } + + return 0; +} + +s32 Dodongos_AfterSwallowBomb_Baby(EnDodojr* this) { + if (!EnemySouls_CheckSoulForActor(&this->base)) { + this->counter = 3; + this->actionFunc = EnDodojr_JumpAttackBounce; + return 1; + } + + return 0; +} diff --git a/code/src/actors/dodongos.h b/code/src/actors/dodongos.h new file mode 100644 index 00000000..8e2deb06 --- /dev/null +++ b/code/src/actors/dodongos.h @@ -0,0 +1,35 @@ +#ifndef _DODONGOS_H_ +#define _DODONGOS_H_ + +#include "z3D/z3D.h" + +struct EnDodongo; +struct EnDodojr; + +typedef void (*EnDodongoActionFunc)(struct EnDodongo*, GlobalContext*); +typedef void (*EnDodojrActionFunc)(struct EnDodojr*, GlobalContext*); + +typedef struct EnDodongo { + /* 0x0000 */ Actor base; + /* 0x01A4 */ SkelAnime skelAnime; + /* 0x0228 */ char unk_228[0x750]; + /* 0x0978 */ s32 actionState; + /* 0x097C */ EnDodongoActionFunc actionFunc; + /* 0x0980 */ char unk_980[0x47C]; +} EnDodongo; // size = 0xDFC +_Static_assert(sizeof(EnDodongo) == 0xDFC, "EnDodongo size"); + +typedef struct EnDodojr { + /* 0x0000 */ Actor base; + /* 0x01A4 */ SkelAnime skelAnime; + /* 0x0228 */ char unk_228[0x270]; + /* 0x0498 */ EnDodojrActionFunc actionFunc; + /* 0x049C */ char unk_49C[0x058]; + /* 0x04F4 */ Actor* bomb; + /* 0x04F8 */ char unk_4F8[0x018]; + /* 0x0510 */ s16 counter; // Used for bouncing and flashing when dying. + /* 0x0512 */ char unk_512[0x00D]; +} EnDodojr; // size = 0x520 +_Static_assert(sizeof(EnDodojr) == 0x520, "EnDodojr size"); + +#endif //_DODONGOS_H_ diff --git a/code/src/actors/flying_traps.c b/code/src/actors/flying_traps.c new file mode 100644 index 00000000..e17d97c0 --- /dev/null +++ b/code/src/actors/flying_traps.c @@ -0,0 +1,25 @@ +#include "z3D/z3D.h" +#include "flying_traps.h" +#include "enemy_souls.h" + +#define EnYukabyun_Levitate ((EnYukabyun_ActionFunc)0x3B9E3C) +#define EnTuboTrap_WaitForProximity ((EnTuboTrap_ActionFunc)0x3E6F88) + +s32 FlyingTraps_Tile_OnImpact(EnYukabyun* this) { + if (!EnemySouls_CheckSoulForActor(&this->base)) { + this->actionFunc = EnYukabyun_Levitate; + this->waitCounter = 0; + return 0; + } + return 1; +} + +s32 FlyingTraps_Pot_OnImpact(EnTuboTrap* this) { + if (this->base.bgCheckFlags & 0x1) { // Standing on the ground + this->actionFunc = EnTuboTrap_WaitForProximity; + this->base.gravity = 0; + this->base.speedXZ = 0; + } + + return EnemySouls_CheckSoulForActor(&this->base); +} diff --git a/code/src/actors/flying_traps.h b/code/src/actors/flying_traps.h new file mode 100644 index 00000000..1e27db81 --- /dev/null +++ b/code/src/actors/flying_traps.h @@ -0,0 +1,30 @@ +#ifndef _FLYING_TRAPS_H_ +#define _FLYING_TRAPS_H_ + +#include "z3D/z3D.h" + +struct EnYukabyun; +struct EnTuboTrap; + +typedef void (*EnYukabyun_ActionFunc)(struct EnYukabyun* self, GlobalContext* globalCtx); +typedef void (*EnTuboTrap_ActionFunc)(struct EnTuboTrap* self, GlobalContext* globalCtx); + +typedef struct EnYukabyun { + /* 0x0000 */ Actor base; + /* 0x01A4 */ EnYukabyun_ActionFunc actionFunc; + /* 0x01A8 */ s16 waitCounter; + /* 0x01AA */ char unk_1AA[0x2]; + /* 0x01AC */ ColliderCylinder* collider; + /* 0x0204 */ SkeletonAnimationModel* saModel; +} EnYukabyun; + +typedef struct EnTuboTrap { + /* 0x0000 */ Actor base; + /* 0x01A4 */ EnTuboTrap_ActionFunc actionFunc; + /* 0x01A8 */ f32 targetY; + /* 0x01AC */ Vec3f originPos; + /* 0x01B8 */ ColliderCylinder* collider; + /* 0x0210 */ SkeletonAnimationModel* saModel; +} EnTuboTrap; + +#endif //_FLYING_TRAPS_H_ diff --git a/code/src/actors/red_ice.h b/code/src/actors/red_ice.h index f0cd479c..aa79a41b 100644 --- a/code/src/actors/red_ice.h +++ b/code/src/actors/red_ice.h @@ -24,4 +24,6 @@ typedef struct BgIceShelter { /* 0x0270 */ s16 alpha; } BgIceShelter; // size = 0x0204 +void RedIce_CheckIceArrow(Collider* at, Collider* ac); + #endif diff --git a/code/src/actors/shabom.c b/code/src/actors/shabom.c new file mode 100644 index 00000000..0f9bf68e --- /dev/null +++ b/code/src/actors/shabom.c @@ -0,0 +1,26 @@ +#include "z3D/z3D.h" +#include "stddef.h" +#include "shabom.h" +#include "settings.h" +#include "enemy_souls.h" + +u16 Shabom_CheckEnemySoul(void) { + return gSettingsContext.shuffleEnemySouls == OFF || EnemySouls_GetSoulFlag(SOUL_SHABOM); +} + +// This is currently useless because soulless enemies are invisible +// void EnBubble_rUpdate(Actor* thisx, GlobalContext* globalCtx) { +// EnBubble* this = (EnBubble*)thisx; + +// EnBubble_Update(thisx, globalCtx); + +// // If the Shabom explodes but its Soul has not been collected, set up its unused functions that make it regrow +// if (!EnemySouls_CheckSoulForActor(thisx) && this->base.update == NULL) { +// this->actionFunc = EnBubble_Disappear; + +// // Undo Actor_Kill +// this->base.draw = EnBubble_Draw; +// this->base.update = EnBubble_rUpdate; +// this->base.flags |= 0x1; +// } +// } diff --git a/code/src/actors/shabom.h b/code/src/actors/shabom.h new file mode 100644 index 00000000..bb5db67b --- /dev/null +++ b/code/src/actors/shabom.h @@ -0,0 +1,22 @@ +#ifndef _SHABOM_H_ +#define _SHABOM_H_ + +#include "z3D/z3D.h" + +struct EnBubble; +typedef void (*EnBubbleActionFunc)(struct EnBubble*, GlobalContext*); + +#define EnBubble_Update ((ActorFunc)0x228F24) +#define EnBubble_Draw ((ActorFunc)0X228CB4) +#define EnBubble_Disappear ((EnBubbleActionFunc)0x3B5190) + +// void EnBubble_rUpdate(Actor* thisx, GlobalContext* globalCtx); + +typedef struct EnBubble { + /* 0x0000 */ Actor base; + /* 0x01A4 */ EnBubbleActionFunc actionFunc; + /* 0x01A8 */ Collider collider; // part of ColliderJntSph colliderSphere; + /* 0x01C0 */ char unk_01C0[0x120]; +} EnBubble; + +#endif //_SHABOM_H_ diff --git a/code/src/actors/shops.c b/code/src/actors/shops.c index ef48ba25..6bd5ab99 100644 --- a/code/src/actors/shops.c +++ b/code/src/actors/shops.c @@ -37,6 +37,8 @@ s32 numShopItemsLoaded = 0; // Used to determine params. Reset this to 0 in ossa #define EnGirlA_InitializeItemAction ((EnGirlAActionFunc)0x14D5C8) +void ShopsanityItem_Draw(Actor* itemx, GlobalContext* globalCtx); + // Checks for if item is of a certain type u8 ShopsanityItem_IsBombs(u8 id) { @@ -223,6 +225,7 @@ void ShopsanityItem_InitializeItem(EnGirlA* item, GlobalContext* globalCtx) { u16 index = ShopsanityItem_GetIndex(shopItem); item->actor.textId = 0x9200 + index * 2; item->itemBuyPromptTextId = 0x9200 + index * 2 + 1; + item->actor.draw = ShopsanityItem_Draw; } } @@ -318,6 +321,16 @@ void ShopsanityItem_Init(Actor* itemx, GlobalContext* globalCtx) { } } +void ShopsanityItem_Draw(Actor* itemx, GlobalContext* globalCtx) { + ShopsanityItem* item = (ShopsanityItem*)itemx; + ItemOverride override = ItemOverride_Lookup(&item->super.actor, globalCtx->sceneNum, item->getItemId); + + u16 itemId = override.value.looksLikeItemId ? override.value.looksLikeItemId : override.value.itemId; + CustomModels_UpdateMatrix(&item->super.actor.modelMtx, ItemTable_GetItemRow(itemId)->objectId); + + EnGirlA_Draw(itemx, globalCtx); +} + void ShopsanityItem_SellOut(Actor* itemx, u16 index) { ShopsanityItem* item = (ShopsanityItem*)itemx; diff --git a/code/src/custom_models.c b/code/src/custom_models.c index f37de049..256a99b2 100644 --- a/code/src/custom_models.c +++ b/code/src/custom_models.c @@ -227,6 +227,46 @@ static void CustomModel_SetBossKeyToRGBA565(void* bossKeyCMB) { EDIT_BYTE(0x44B, 0x00); } +static void CustomModel_SetSoldOutToRGBA565(void* soldOutCMB) { + char* BASE_ = (char*)soldOutCMB; + + EDIT_BYTE(0x274, 0x5B); // ImageFormat: 0x6758 -> 0x675B +} + +static void CustomModel_EditShopFairyToEnemySoul(void* ZARBuf) { + char* caseCMB = (((char*)ZARBuf) + 0x178); + char* fairyCMB = (((char*)ZARBuf) + 0x25F8); + char* BASE_; + + BASE_ = caseCMB; + // Colors used for base and top + EDIT_BYTE(0x154, 0x00); + EDIT_BYTE(0x155, 0x00); + EDIT_BYTE(0x156, 0x00); + EDIT_BYTE(0x158, 0x10); + EDIT_BYTE(0x159, 0x00); + EDIT_BYTE(0x15A, 0xFF); + + // Color used for glass part + EDIT_BYTE(0x2B4, 0x40); + EDIT_BYTE(0x2B5, 0x00); + EDIT_BYTE(0x2B6, 0xFF); + + BASE_ = fairyCMB; + // Color used for fairy orb + EDIT_BYTE(0x13C, 0x00); + EDIT_BYTE(0x13D, 0x40); + EDIT_BYTE(0x13E, 0x00); +} + +static void CustomModel_EditTriforce(void* triforceCMB) { + char* BASE_ = (char*)triforceCMB; + + // Set number of vertices from 0x120 to 0x60 so only one triangle will be drawn. + EDIT_BYTE(0x3FC, 0x60); + EDIT_BYTE(0x3FD, 0x00); +} + void CustomModel_Update(void) { // Make sure custom_assets is loaded if (ExtendedObject_GetIndex(&gGlobalContext->objectCtx, OBJECT_CUSTOM_GENERAL_ASSETS) < 0) { @@ -266,6 +306,18 @@ void CustomModels_EditItemCMB(void* ZARBuf, u16 objectId, s8 special) { cmb = ((char*)ZARBuf) + 0x78; CustomModel_SetBossKeyToRGBA565(cmb); break; + case OBJECT_CUSTOM_OCARINA_BUTTON: + cmb = ((char*)ZARBuf) + 0xA4; + CustomModel_SetSoldOutToRGBA565(cmb); + break; + case OBJECT_CUSTOM_ENEMY_SOUL: + // This function takes the ZARBuf instead of the CMB + CustomModel_EditShopFairyToEnemySoul(ZARBuf); + break; + case OBJECT_CUSTOM_TRIFORCE_PIECE: + cmb = ((char*)ZARBuf) + 0xF0; + CustomModel_EditTriforce(cmb); + break; } } @@ -294,5 +346,34 @@ void CustomModels_ApplyItemCMAB(SkeletonAnimationModel* model, u16 objectId, s8 model->unk_0C->animMode = 0; model->unk_0C->curFrame = special; break; + case OBJECT_CUSTOM_OCARINA_BUTTON: + cmabMan = ExtendedObject_GetCMABByIndex(OBJECT_CUSTOM_GENERAL_ASSETS, TEXANIM_OCARINA_NOTE_BUTTON); + TexAnim_Spawn(model->unk_0C, cmabMan); + model->unk_0C->animSpeed = 0.0f; + model->unk_0C->animMode = 0; + model->unk_0C->curFrame = special; } } + +void CustomModels_UpdateMatrix(nn_math_MTX34* modelMtx, u16 objectId) { + f32 scale; + Vec3f posOffset; + + switch (objectId) { + case OBJECT_CUSTOM_TRIFORCE_PIECE: + scale = 0.05f; + posOffset = (Vec3f){ 0.0f, -800.0f, 0.0f }; + break; + default: + return; + } + + nn_math_MTX44 scaleMtx = { 0 }; + scaleMtx.data[0][0] = scale; + scaleMtx.data[1][1] = scale; + scaleMtx.data[2][2] = scale; + scaleMtx.data[3][3] = 1.0f; + + Matrix_Multiply(modelMtx, modelMtx, &scaleMtx); + Matrix_UpdatePosition(modelMtx, modelMtx, &posOffset); +} diff --git a/code/src/custom_models.h b/code/src/custom_models.h index 213cbd33..508247a1 100644 --- a/code/src/custom_models.h +++ b/code/src/custom_models.h @@ -7,6 +7,7 @@ void CustomModel_EditTitleScreenLogo(void* titleScreenZAR); void CustomModel_Update(void); void CustomModels_EditItemCMB(void* ZARBuf, u16 objectId, s8 special); void CustomModels_ApplyItemCMAB(SkeletonAnimationModel* model, u16 objectId, s8 special); +void CustomModels_UpdateMatrix(nn_math_MTX34* modelMtx, u16 objectId); #define OBJECT_CUSTOM_DOUBLE_DEFENSE 4 #define OBJECT_CUSTOM_CHILD_SONGS 5 @@ -22,6 +23,9 @@ void CustomModels_ApplyItemCMAB(SkeletonAnimationModel* model, u16 objectId, s8 #define OBJECT_CUSTOM_SMALL_KEY_GANON 127 #define OBJECT_CUSTOM_BOSS_KEYS 128 #define OBJECT_CUSTOM_GENERAL_ASSETS 182 +#define OBJECT_CUSTOM_ENEMY_SOUL 228 +#define OBJECT_CUSTOM_OCARINA_BUTTON 291 +#define OBJECT_CUSTOM_TRIFORCE_PIECE 366 typedef enum { TEXANIM_COPY_NINTENDO, @@ -35,6 +39,7 @@ typedef enum { TEXANIM_KEY_CHEST, TEXANIM_HEART_CHEST, TEXANIM_SKULL_CHEST, + TEXANIM_OCARINA_NOTE_BUTTON, } CustomGeneralAssetsTexAnims; typedef enum { diff --git a/code/src/enemy_souls.c b/code/src/enemy_souls.c new file mode 100644 index 00000000..e2970d8d --- /dev/null +++ b/code/src/enemy_souls.c @@ -0,0 +1,104 @@ +#define CREATE_SOULMENUNAMES +#include "enemy_souls.h" +#include "savefile.h" +#include "settings.h" + +// clang-format off +static EnemySoulId EnemySouls_GetSoulId(s16 actorId) { + switch (actorId) { + case 0x00D: return SOUL_POE; // Small Poe + case 0x175: return SOUL_POE; // Big Poe + case 0x091: return SOUL_POE; // Poe Sisters + case 0x00E: return SOUL_OCTOROK; // Octorok + case 0x0C6: return SOUL_OCTOROK; // Big Octo + case 0x013: return SOUL_KEESE; + case 0x01B: return SOUL_TEKTITE; + case 0x01C: return SOUL_LEEVER; + case 0x01D: return SOUL_PEAHAT; + case 0x025: return SOUL_LIZALFOS; + case 0x02D: return SOUL_SHABOM; + case 0x034: return SOUL_BIRI_BARI; // Biri + case 0x063: return SOUL_BIRI_BARI; // Bari + case 0x035: return SOUL_TAILPASARAN; + case 0x037: return SOUL_SKULLTULA; // Normal + case 0x095: return SOUL_SKULLTULA; // Walltula/Gold + case 0x038: return SOUL_TORCH_SLUG; + case 0x03A: return SOUL_STINGER; // Land + case 0x18C: return SOUL_STINGER; // Water + case 0x04B: return SOUL_MOBLIN; + case 0x054: return SOUL_ARMOS; + case 0x055: return SOUL_DEKU_BABA; // Normal + case 0x0C7: return SOUL_DEKU_BABA; // Withered + case 0x069: return SOUL_BUBBLE; + case 0x11D: return SOUL_FLYING_TRAP; // Flying Pot + case 0x06B: return SOUL_FLYING_TRAP; // Flying Tile + case 0x08A: return SOUL_BEAMOS; + case 0x011: return SOUL_WALLMASTER; // Wallmaster + case 0x08E: return SOUL_WALLMASTER; // Floormaster + case 0x090: return SOUL_REDEAD_GIBDO; + case 0x0C5: return SOUL_SHELL_BLADE; + case 0x0DD: return SOUL_LIKE_LIKE; + case 0x0DE: return SOUL_TENTACLE; + case 0x0E0: return SOUL_ANUBIS; + case 0x0EC: return SOUL_SPIKE; + case 0x115: return SOUL_SKULL_KID; + case 0x121: return SOUL_FREEZARD; + case 0x192: return SOUL_DEKU_SCRUB; // Normal (green) + case 0x060: return SOUL_DEKU_SCRUB; // Mad (red) + case 0x195: return SOUL_DEKU_SCRUB; // Business + case 0x1AF: return SOUL_WOLFOS; + case 0x1B0: return SOUL_STALCHILD; + case 0x1C0: return SOUL_GUAY; + case 0x1C1: return SOUL_DOOR_MIMIC; + case 0x002: return SOUL_STALFOS; + case 0x033: return SOUL_DARK_LINK; + case 0x099: return SOUL_FLARE_DANCER; // Normal + case 0x0AB: return SOUL_FLARE_DANCER; // Core + case 0x0A4: return SOUL_DEAD_HAND; // Body + case 0x0A5: return SOUL_DEAD_HAND; // Hands + case 0x186: return SOUL_GERUDO; // Purple Gerudo guards + case 0x197: return SOUL_GERUDO; // Gerudo fighters + case 0x113: return SOUL_GERUDO; // Iron Knuckles + case 0x028: return SOUL_GOHMA; // Queen Gohma + case 0x02B: return SOUL_GOHMA; // Gohma Larva/Egg + case 0x012: return SOUL_DODONGO; // Dodongo + case 0x02F: return SOUL_DODONGO; // Baby Dodongo + case 0x027: return SOUL_DODONGO; // King Dodongo + case 0x0BA: return SOUL_BARINADE; + case 0x052: return SOUL_PHANTOM_GANON; // PG + case 0x067: return SOUL_PHANTOM_GANON; // Horse + case 0x096: return SOUL_VOLVAGIA; // Flying + case 0x0A2: return SOUL_VOLVAGIA; // Hole + case 0x0C4: return SOUL_MORPHA; + case 0x0E9: return SOUL_BONGO_BONGO; + case 0x0DC: return SOUL_TWINROVA; + case 0x0E8: return SOUL_GANON; // Ganondorf + case 0x17A: return SOUL_GANON; // Ganon + } + + return SOUL_NONE; +} +// clang-format on + +u8 EnemySouls_GetSoulFlag(EnemySoulId soulId) { + if (soulId == SOUL_NONE) { + return 1; + } + return gExtSaveData.extInf[EXTINF_ENEMYSOULSFLAGS_START + (soulId >> 3)] & (1 << (soulId & 0b111)); +} + +void EnemySouls_SetSoulFlag(EnemySoulId soulId) { + if (soulId == SOUL_NONE) { + return; + } + gExtSaveData.extInf[EXTINF_ENEMYSOULSFLAGS_START + (soulId >> 3)] |= (1 << (soulId & 0b111)); +} + +u8 EnemySouls_CheckSoulForActor(Actor* actor) { + if ((gSettingsContext.shuffleEnemySouls == OFF) || (actor->id == 0x054 && actor->params == 0 /* Armos statue */)) { + return TRUE; + } + + EnemySoulId soulId = EnemySouls_GetSoulId(actor->id); + return soulId == SOUL_NONE || EnemySouls_GetSoulFlag(soulId); +} diff --git a/code/src/enemy_souls.h b/code/src/enemy_souls.h new file mode 100644 index 00000000..2450a1e4 --- /dev/null +++ b/code/src/enemy_souls.h @@ -0,0 +1,126 @@ +#ifndef _ENEMYSOULS_H_ +#define _ENEMYSOULS_H_ + +#include "../include/z3D/z3D.h" + +typedef enum EnemySoulId { + SOUL_NONE = -1, + SOUL_POE, + SOUL_OCTOROK, + SOUL_KEESE, + SOUL_TEKTITE, + SOUL_LEEVER, + SOUL_PEAHAT, + SOUL_LIZALFOS, + SOUL_SHABOM, + SOUL_BIRI_BARI, + SOUL_TAILPASARAN, + SOUL_SKULLTULA, + SOUL_TORCH_SLUG, + SOUL_STINGER, + SOUL_MOBLIN, + SOUL_ARMOS, + SOUL_DEKU_BABA, + SOUL_BUBBLE, + SOUL_FLYING_TRAP, + SOUL_BEAMOS, + SOUL_WALLMASTER, + SOUL_REDEAD_GIBDO, + SOUL_SHELL_BLADE, + SOUL_LIKE_LIKE, + SOUL_TENTACLE, + SOUL_ANUBIS, + SOUL_SPIKE, + SOUL_SKULL_KID, + SOUL_FREEZARD, + SOUL_DEKU_SCRUB, + SOUL_WOLFOS, + SOUL_STALCHILD, + SOUL_GUAY, + SOUL_DOOR_MIMIC, + SOUL_STALFOS, + SOUL_DARK_LINK, + SOUL_FLARE_DANCER, + SOUL_DEAD_HAND, + SOUL_GERUDO, + SOUL_GOHMA, + SOUL_DODONGO, + SOUL_BARINADE, + SOUL_PHANTOM_GANON, + SOUL_VOLVAGIA, + SOUL_MORPHA, + SOUL_BONGO_BONGO, + SOUL_TWINROVA, + SOUL_GANON, + SOUL_MAX, +} EnemySoulId; + +typedef struct SoulMenuInfo { + EnemySoulId soulId; + const char* name; +} SoulMenuInfo; + +extern SoulMenuInfo SoulMenuNames[SOUL_MAX]; + +// This array is used in the patch side for the enemy souls page in the in-game menu, +// and in the app side for the starting inventory options. +// So CREATE_SOULMENUNAMES should only be defined in one C file and one CPP file. +#ifdef CREATE_SOULMENUNAMES +SoulMenuInfo SoulMenuNames[SOUL_MAX] = { + // Normal enemies, ordered alphabetically + { SOUL_ANUBIS, "Anubis" }, + { SOUL_ARMOS, "Armos" }, + { SOUL_BEAMOS, "Beamos" }, + { SOUL_BIRI_BARI, "Biri, Bari" }, + { SOUL_BUBBLE, "Bubble (all)" }, + { SOUL_DARK_LINK, "Dark Link" }, + { SOUL_DEAD_HAND, "Dead Hand" }, + { SOUL_DEKU_BABA, "Deku Baba (all)" }, + { SOUL_DEKU_SCRUB, "Deku Scrub (all)" }, + { SOUL_DOOR_MIMIC, "Door Mimic" }, + { SOUL_FLARE_DANCER, "Flare Dancer" }, + { SOUL_FLYING_TRAP, "Flying Pot & Tile" }, + { SOUL_FREEZARD, "Freezard" }, + { SOUL_GERUDO, "Gerudo, Iron Knuckles" }, + { SOUL_GUAY, "Guay" }, + { SOUL_KEESE, "Keese (all)" }, + { SOUL_LEEVER, "Leever" }, + { SOUL_LIKE_LIKE, "Like Like" }, + { SOUL_LIZALFOS, "Lizalfos, Dinolfos" }, + { SOUL_MOBLIN, "Moblin, Club Moblin" }, + { SOUL_OCTOROK, "Octorok, Big Octo" }, + { SOUL_TENTACLE, "Parasitic Tentacle" }, + { SOUL_PEAHAT, "Peahat" }, + { SOUL_POE, "Poe (all)" }, + { SOUL_REDEAD_GIBDO, "Redead, Gibdo" }, + { SOUL_SHABOM, "Shabom" }, + { SOUL_SHELL_BLADE, "Shell Blade" }, + { SOUL_SKULL_KID, "Skull Kid" }, + { SOUL_SKULLTULA, "Skulltula (all)" }, + { SOUL_SPIKE, "Spike" }, + { SOUL_STALCHILD, "Stalchild" }, + { SOUL_STALFOS, "Stalfos" }, + { SOUL_STINGER, "Stinger" }, + { SOUL_TAILPASARAN, "Tailpasaran" }, + { SOUL_TEKTITE, "Tektite" }, + { SOUL_TORCH_SLUG, "Torch Slug" }, + { SOUL_WALLMASTER, "Wallmaster, Floormaster" }, + { SOUL_WOLFOS, "Wolfos (all)" }, + // Bosses + { SOUL_GOHMA, "Gohma, Gohma Larva" }, + { SOUL_DODONGO, "Dodongo (all)" }, + { SOUL_BARINADE, "Barinade" }, + { SOUL_PHANTOM_GANON, "Phantom Ganon" }, + { SOUL_VOLVAGIA, "Volvagia" }, + { SOUL_MORPHA, "Morpha" }, + { SOUL_BONGO_BONGO, "Bongo Bongo" }, + { SOUL_TWINROVA, "Twinrova" }, + { SOUL_GANON, "Ganondorf, Ganon" }, +}; +#endif + +u8 EnemySouls_GetSoulFlag(EnemySoulId soulId); +void EnemySouls_SetSoulFlag(EnemySoulId soulId); +u8 EnemySouls_CheckSoulForActor(Actor* actor); + +#endif //_ENEMYSOULS_H_ diff --git a/code/src/fishing.c b/code/src/fishing.c index 639cfd92..7be1b552 100644 --- a/code/src/fishing.c +++ b/code/src/fishing.c @@ -1,5 +1,40 @@ #include "z3D/z3D.h" +#include "fishing.h" +#include "models.h" +#include "settings.h" u32 isFishing(void) { return gSaveContext.equips.buttonItems[0] == ITEM_FISHING_POLE && gGlobalContext->sceneNum == 73; } + +static s32 rewardObtained(void) { + u8 obtainedRewardFlag = gSaveContext.linkAge == AGE_ADULT ? 0x8 : 0x4; + return gSaveContext.fishingStats.flags & obtainedRewardFlag; +} + +void Fishing_rInit(Actor* thisx, GlobalContext* globalCtx) { + u16 baseItemId = gSaveContext.linkAge == AGE_ADULT ? GI_SCALE_GOLD : GI_HEART_PIECE; + Fishing_Init(thisx, globalCtx); + if (gSettingsContext.fishingHints && thisx->params == EN_FISH_AQUARIUM && !rewardObtained()) { + Model_SpawnByActor(thisx, globalCtx, baseItemId); + } +} + +void Fishing_rUpdateFish(Actor* thisx, GlobalContext* globalCtx) { + Fishing_UpdateFish(thisx, globalCtx); + if (gSettingsContext.fishingHints && thisx->params == EN_FISH_AQUARIUM && !rewardObtained()) { + thisx->textId = 0x40AE; // custom text, overrides vanilla "pond owner" record text + } +} + +void Fishing_rDrawFish(Actor* thisx, GlobalContext* globalCtx) { + static s16 sPrizeRotation = 0x8000; // used because shape.rot.y is reset between update cycles + + if (gSettingsContext.fishingHints && thisx->params == EN_FISH_AQUARIUM && !rewardObtained()) { + sPrizeRotation += 0x100; + thisx->shape.rot.y = sPrizeRotation; + Model_DrawByActor(thisx); + } else { + Fishing_DrawFish(thisx, globalCtx); + } +} diff --git a/code/src/fishing.h b/code/src/fishing.h new file mode 100644 index 00000000..6a7aad98 --- /dev/null +++ b/code/src/fishing.h @@ -0,0 +1,16 @@ +#ifndef _FISHING_H_ +#define _FISHING_H_ + +#include "z3D/z3D.h" + +#define Fishing_Init ((ActorFunc)0x1C0AD8) +#define Fishing_UpdateFish ((ActorFunc)0x1F9ACC) +#define Fishing_DrawFish ((ActorFunc)0x1F98B4) + +#define EN_FISH_AQUARIUM 200 // param for record fish in tank. + +void Fishing_rInit(Actor* thisx, GlobalContext* globalCtx); +void Fishing_rUpdateFish(Actor* thisx, GlobalContext* globalCtx); +void Fishing_rDrawFish(Actor* thisx, GlobalContext* globalCtx); + +#endif //_FISHING_H_ diff --git a/code/src/gfx.c b/code/src/gfx.c index caa2ebdf..5ea1dff3 100644 --- a/code/src/gfx.c +++ b/code/src/gfx.c @@ -16,6 +16,7 @@ #include "input.h" #include "multiplayer.h" #include "dungeon.h" +#include "enemy_souls.h" u32 pressed; bool handledInput; @@ -24,6 +25,7 @@ static u8 GfxInit = 0; static u32 closingButton = 0; static u8 currentSphere = 0; static s16 spoilerScroll = 0; +static s16 soulsScroll = 0; static s16 allItemsScroll = 0; static s16 groupItemsScroll = 0; @@ -153,6 +155,7 @@ static char* spoilerEntranceGroupNames[] = { typedef enum { PAGE_SEEDHASH, PAGE_DUNGEONITEMS, + PAGE_ENEMYSOULS, PAGE_SPHERES, PAGE_ITEMTRACKER_ALL, PAGE_ITEMTRACKER_GROUPS, @@ -290,6 +293,11 @@ static void Gfx_DrawButtonPrompts(void) { Draw_DrawIcon(offsetX, promptY, COLOR_BUTTON_A, ICON_BUTTON_A); offsetX += buttonSpacing; Draw_DrawString(offsetX, textY, COLOR_TITLE, "Toggle Legend"); + } else if (curMenuIdx == PAGE_ENEMYSOULS) { + Draw_DrawIcon(offsetX, promptY, COLOR_WHITE, ICON_BUTTON_DPAD); + offsetX += buttonSpacing; + nextStr = "Scroll"; + Draw_DrawString(offsetX, textY, COLOR_TITLE, nextStr); } else if (curMenuIdx == PAGE_SPHERES) { Draw_DrawIcon(offsetX, promptY, COLOR_WHITE, ICON_BUTTON_DPAD); offsetX += buttonSpacing; @@ -368,6 +376,16 @@ static void Gfx_DrawSeedHash(void) { minutes, seconds); offsetY++; + if (gSettingsContext.triforceHunt) { + Draw_DrawString(10, 16 + (SPACING_Y * offsetY++), COLOR_TITLE, "Triforce Pieces:"); + u8 triforceDone = gExtSaveData.extInf[EXTINF_TRIFORCE_PIECES] >= gSettingsContext.triforcePiecesRequired; + Draw_DrawFormattedString( + 10 + (SPACING_X * 4), 16 + (SPACING_Y * offsetY++), triforceDone ? COLOR_YELLOW : COLOR_WHITE, "%d / %d", + gExtSaveData.extInf[EXTINF_TRIFORCE_PIECES], + triforceDone ? gSettingsContext.triforcePiecesTotal : gSettingsContext.triforcePiecesRequired); + offsetY++; + } + if (gSettingsContext.mp_Enabled) { Draw_DrawFormattedString(10, 16 + (SPACING_Y * offsetY++), COLOR_TITLE, "Multiplayer:"); s16 playerCount = Multiplayer_PlayerCount(); @@ -515,6 +533,23 @@ static void Gfx_DrawDungeonItems(void) { } } +static void Gfx_DrawEnemySouls(void) { + Draw_DrawString(10, 16, COLOR_TITLE, "Enemy Souls Obtained"); + + u8 startIndex = soulsScroll <= 0 ? 0 : 32; + u8 endIndex = soulsScroll <= 0 ? 32 : ARRAY_SIZE(SoulMenuNames); + + for (u8 i = startIndex; i < endIndex; i++) { + u16 posX = 10 + (((i % 32) / 16) * (SPACING_X * 25)); + u16 posY = 30 + (SPACING_Y * (i % 16)); + SoulMenuInfo info = SoulMenuNames[i]; + + Draw_DrawRect(posX, posY, 9, 9, COLOR_WHITE); + Draw_DrawRect(posX + 1, posY + 1, 7, 7, EnemySouls_GetSoulFlag(info.soulId) ? COLOR_GREEN : COLOR_BLACK); + Draw_DrawString(posX + SPACING_X * 2, posY, COLOR_WHITE, info.name); + } +} + static void Gfx_DrawSpoilerData(void) { if (gSpoilerData.SphereCount > 0) { u16 itemCount = gSpoilerData.Spheres[currentSphere].ItemCount; @@ -775,7 +810,10 @@ static void Gfx_DrawEntranceTracker(void) { static void (*menu_draw_funcs[])(void) = { // Make sure these line up with the GfxPage enum above - Gfx_DrawSeedHash, Gfx_DrawDungeonItems, Gfx_DrawSpoilerData, + Gfx_DrawSeedHash, // + Gfx_DrawDungeonItems, // + Gfx_DrawEnemySouls, // + Gfx_DrawSpoilerData, // Gfx_DrawItemTracker, // All Gfx_DrawItemTracker, // Groups Gfx_DrawEntranceTracker, // All @@ -841,6 +879,11 @@ static void Gfx_ShowMenu(void) { showingLegend = !showingLegend; handledInput = true; } + } else if (curMenuIdx == PAGE_ENEMYSOULS) { + if (pressed & (PAD_UP | PAD_DOWN | PAD_RIGHT | PAD_LEFT)) { + soulsScroll = (soulsScroll + 1) % 2; + handledInput = true; + } } else if (curMenuIdx == PAGE_SPHERES && gSpoilerData.SphereCount > 0) { // Spoiler log u16 itemCount = gSpoilerData.Spheres[currentSphere].ItemCount; @@ -1119,6 +1162,9 @@ void Gfx_Init(void) { else if (gSettingsContext.menuOpeningButton == 5) closingButton = BUTTON_B | BUTTON_LEFT; + if (!gSettingsContext.shuffleEnemySouls) { + menu_draw_funcs[PAGE_ENEMYSOULS] = NULL; + } if (!gSettingsContext.ingameSpoilers) { menu_draw_funcs[PAGE_SPHERES] = NULL; } diff --git a/code/src/hooks.s b/code/src/hooks.s index 7696f7db..daae5de5 100644 --- a/code/src/hooks.s +++ b/code/src/hooks.s @@ -146,6 +146,14 @@ hook_EditDrawDetItemAfterModelSpawn: str r0,[r6,#0x78] bx lr +.global hook_EditDrawGetItemAfterMatrixUpdate +hook_EditDrawGetItemAfterMatrixUpdate: + push {r0-r12, lr} + cpy r0,r1 @ SkeletonAnimationModel + bl ItemOverride_EditDrawGetItemAfterMatrixUpdate + pop {r0-r12, lr} + b 0x330B98 + # TODO: Text ID in game gets messed up, # Gives the "What's that?" text instead of # the text about moving the statue @@ -310,10 +318,10 @@ hook_ApplyDamageMultiplier: pop {r0-r3, r5-r12, lr} bx lr -.global hook_HyperActors -hook_HyperActors: +.global hook_ActorUpdate +hook_ActorUpdate: push {r0-r12, lr} - bl HyperActors_Main + bl Actor_rUpdate pop {r0-r12, lr} bx lr @@ -847,62 +855,6 @@ hook_GKSetDurability: pop {r0-r12, lr} b 0x376BE0 -.global hook_SkippableText -hook_SkippableText: - push {r0-r12, lr} - bl Settings_GetQuickTextOption - cmp r0,#0x1 - pop {r0-r12, lr} - beq 0x2E0ED4 - ldr r0,[r5,#0x0] - b 0x2E09C0 - -.global hook_InstantTextFirstLine -hook_InstantTextFirstLine: - cmp r9,#0x0 - bgt NoInstantText - push {r0-r12, lr} - bl Settings_GetQuickTextOption - cmp r0,#0x2 - pop {r0-r12, lr} - blt NoInstantText - push {r0-r12, lr} - ldr r0,[r5,#0x0] - ldr r1,[r0,#0x20] - cpy r0,r5 - blx r1 - strb r11,[r4,#0x24] - pop {r0-r12, lr} -NoInstantText: - cmp r10,#0xFF - bx lr - -.global hook_InstantTextBoxBreak -hook_InstantTextBoxBreak: - push {r0-r12, lr} - bl Settings_GetQuickTextOption - cmp r0,#0x2 - pop {r0-r12, lr} - blt 0x2E0EE0 - push {r0-r12, lr} - ldr r0,[r5,#0x0] - ldr r1,[r0,#0x20] - cpy r0,r5 - blx r1 - strb r11,[r4,#0x24] - pop {r0-r12, lr} - b 0x2E0EE0 - -.global hook_InstantTextRemoveOff -hook_InstantTextRemoveOff: - push {r0-r12, lr} - bl Settings_GetQuickTextOption - cmp r0,#0x2 - pop {r0-r12, lr} - bge 0x2E0ED4 - ldr r0,[r5,#0x0] - b 0x2E06CC - .global hook_TurboTextAdvance hook_TurboTextAdvance: push {r0-r12, lr} @@ -1076,11 +1028,11 @@ hook_LostWoodsBridgeMusic: pop {r0-r12, lr} bx lr -.global hook_LoadGame -hook_LoadGame: +.global hook_BeforeLoadGame +hook_BeforeLoadGame: add r0, r4, r5 push {r0-r12, lr} - bl SaveFile_LoadExtSaveData + bl SaveFile_BeforeLoadGame pop {r0-r12, lr} .if _EUR_==1 b 0x4473A4 @@ -1088,6 +1040,13 @@ hook_LoadGame: b 0x447384 .endif +.global hook_AfterLoadGame +hook_AfterLoadGame: + push {r0-r12, lr} + bl SaveFile_AfterLoadGame + pop {r0-r12, lr} + pop {r4-r6, pc} + .global hook_SaveGame hook_SaveGame: cmp r5, #0 @@ -1723,9 +1682,11 @@ hook_CollisionATvsAC: push {r0-r12,lr} cpy r0,r1 @ AT collider cpy r1,r12 @ AC collider - bl RedIce_CheckIceArrow + bl Actor_CollisionATvsAC + cmp r0,#0x1 pop {r0-r12,lr} - bx lr + bxeq lr + b 0x3192E4 .global hook_CollisionCheck_SetAll_Once hook_CollisionCheck_SetAll_Once: @@ -2058,6 +2019,105 @@ hook_RandomGsLoc_SkipSoilJingle: ldrsh r0,[r0,#0x1C] bx lr +.global hook_ActorDraw +hook_ActorDraw: + push {r0-r12, lr} + bl Actor_rDraw + pop {r0-r12, lr} + bx lr + +.global hook_FlyingPotCollision +hook_FlyingPotCollision: + strh r0,[r4,#0xBE] + push {r0-r12, lr} + cpy r0,r4 @ Actor + bl FlyingTraps_Pot_OnImpact + cmp r0,#0x1 + pop {r0-r12, lr} + bne 0x11DEE4 @ Skip collision checks and return + bx lr + +.global hook_FlyingTileCollision +hook_FlyingTileCollision: + cpy r0,r5 + push {r0-r12, lr} + cpy r0,r4 @ Actor + bl FlyingTraps_Tile_OnImpact + cmp r0,#0x1 + pop {r0-r12, lr} + addne lr,lr,#0x8 @ Skip setting actionFunc + bx lr + +.global hook_ShabomAfterDamagePlayer +hook_ShabomAfterDamagePlayer: + push {r0-r12, lr} + bl Shabom_CheckEnemySoul + cmp r0,#0x0 + pop {r0-r12, lr} + beq 0x3B511C @ Skip popping + strh r10,[r5,#0x80] + +.global hook_DodongoAfterSwallowBomb +hook_DodongoAfterSwallowBomb: + mov r1,#0xA + push {r0-r12, lr} + cpy r0,r4 @ Actor + bl Dodongos_AfterSwallowBomb_Normal + cmp r0,#0x0 + pop {r0-r12, lr} + bne 0x11E4F4 + bx lr + +.global hook_BabyDodongoAfterSwallowBomb +hook_BabyDodongoAfterSwallowBomb: + mov r3,#0x8 + push {r0-r12, lr} + cpy r0,r4 @ Actor + bl Dodongos_AfterSwallowBomb_Baby + cmp r0,#0x0 + pop {r0-r12, lr} + bne 0x1C4370 + bx lr + +.global hook_OcarinaNoteButtonsDraw +hook_OcarinaNoteButtonsDraw: + push {r0-r12, lr} + bl OcarinaNotes_MoveButtons + pop {r0-r12, lr} + mov r2,r2,lsl #0x1 @ original code + cmp r2,#0x0 @ original code + mov r3,r3,lsl #0x1 @ original code + bx lr + +.global hook_OcarinaNoteButtonsPress +hook_OcarinaNoteButtonsPress: + cpy r0,r6 + push {r1-r12, lr} + bl OcarinaNotes_HandleInputs + pop {r1-r12, lr} + bx lr + +.global hook_HandleTextControlCode +hook_HandleTextControlCode: + ldrb r0,[r6,#0x4] @ Control Code identifier + push {r0-r12, lr} + cpy r1,r5 @ Text Object + cpy r2,r3 @ Unk pointer + bl Message_HandleTextControlCode + cmp r0,#0x0 + pop {r0-r12, lr} + bxeq lr @ Not a custom control char, resume base game code + b 0x2E0ED4 @ Handled custom control char, skip base game code + +.global hook_CheckForTextControlCode +hook_CheckForTextControlCode: + push {r1-r12, lr} + cpy r2,r5 @ Text Object + cpy r3,r9 @ Char Index (loop counter) + bl Message_rCheckForControlCodes + pop {r1-r12, lr} + bx lr + @ ---------------------------------- @ ---------------------------------- diff --git a/code/src/item_effect.c b/code/src/item_effect.c index 02b5330c..d26e0c8c 100644 --- a/code/src/item_effect.c +++ b/code/src/item_effect.c @@ -6,6 +6,8 @@ #include "dungeon.h" #include "common.h" #include "actors/chest.h" +#include "enemy_souls.h" +#include "ocarina_notes.h" void ItemEffect_None(SaveContext* saveCtx, s16 arg1, s16 arg2) { } @@ -20,29 +22,6 @@ void ItemEffect_FullHeal(SaveContext* saveCtx, s16 arg1, s16 arg2) { } } -// void give_triforce_piece(SaveContext* saveCtx, s16 arg1, s16 arg2) { -// save->scene_flags[0x48].unk_00_ += 1; //Unused word in scene x48. -// set_triforce_render(); - -// // Trigger win when the target is hit -// if (save->scene_flags[0x48].unk_00_ == triforce_pieces_requied) { -// // Give GC boss key to allow beating the game again afterwards -// give_dungeon_item(save, 0x01, 10); - -// // Save Game -// save->entrance_index = z64_game.entrance_index; -// save->scene_index = z64_game.scene_index; -// commit_scene_flags(&z64_game); -// save_game(&z64_game + 0x1F74); - -// // warp to start of credits sequence -// z64_file.cutscene_next = 0xFFF8; -// z64_game.entrance_index = 0x00A0; -// z64_game.scene_load_flag = 0x14; -// z64_game.fadeout_transition = 0x01; -// } -// } - void ItemEffect_GiveTycoonWallet(SaveContext* saveCtx, s16 arg1, s16 arg2) { saveCtx->upgrades |= 3 << 12; if (gSettingsContext.startingMaxRupees) @@ -170,6 +149,22 @@ void ItemEffect_BeanPack(SaveContext* saveCtx, s16 arg1, s16 arg2) { saveCtx->ammo[SLOT_BEAN] += 10; // 10 Magic Beans } +void ItemEffect_TriforcePiece(SaveContext* saveCtx, s16 arg1, s16 arg2) { + gExtSaveData.extInf[EXTINF_TRIFORCE_PIECES]++; + if (gSettingsContext.triforceHunt && + gExtSaveData.extInf[EXTINF_TRIFORCE_PIECES] == gSettingsContext.triforcePiecesRequired) { + // Save progress + SaveGame(gGlobalContext, FALSE); + // Warp to Ganon sealing cutscene + gGlobalContext->nextEntranceIndex = 0x00A0; + gSaveContext.nextCutsceneIndex = 0xFFF8; + gEntranceTable[0x00A0].field |= 0x8000; // continue playing background music (namely get item fanfare) + gGlobalContext->fadeOutTransition = 0x2F; + gGlobalContext->sceneLoadFlag = 0x14; + PLAYER->stateFlags1 |= 1; // Loading area + } +} + // With the No Ammo Drops option on, when the player gets an ammo upgrade, // the ammo count increases by 10 instead of being set to the maximum typedef void (*Inventory_ChangeUpgrade_proc)(u32 upgrade, u32 value); @@ -433,3 +428,11 @@ void ItemEffect_ShardOfAgony(SaveContext* saveCtx, s16 arg1, s16 arg2) { } } } + +void ItemEffect_EnemySoul(SaveContext* saveCtx, s16 soulId, s16 arg2) { + EnemySouls_SetSoulFlag(soulId); +} + +void ItemEffect_OcarinaNote(SaveContext* saveCtx, s16 buttonId, s16 arg2) { + OcarinaNotes_RegisterButtonOwned(buttonId); +} diff --git a/code/src/item_effect.h b/code/src/item_effect.h index cf22d710..209399e0 100644 --- a/code/src/item_effect.h +++ b/code/src/item_effect.h @@ -23,6 +23,7 @@ void ItemEffect_GiveUpgrade(SaveContext* saveCtx, s16 arg1, s16 arg2); void ItemEffect_IceTrap(SaveContext* saveCtx, s16 arg1, s16 arg2); void ItemEffect_GiveMasterSword(SaveContext* saveCtx, s16 arg1, s16 arg2); void ItemEffect_BeanPack(SaveContext* saveCtx, s16 arg1, s16 arg2); +void ItemEffect_TriforcePiece(SaveContext* saveCtx, s16 arg1, s16 arg2); void ItemEffect_RupeeAmmo(SaveContext* saveCtx); void ItemEffect_FillWalletUpgrade(SaveContext* saveCtx, s16 arg1, s16 arg2); void ItemEffect_OpenMaskShop(SaveContext* saveCtx, s16 arg1, s16 arg2); @@ -36,4 +37,6 @@ void ItemEffect_GrannySellsPotions(SaveContext* saveCtx, s16 arg1, s16 arg2); void ItemEffect_OwnAdultTrade(SaveContext* saveCtx, s16 arg1, s16 arg2); void ItemEffect_GiveWeirdEgg(SaveContext* saveCtx, s16 arg1, s16 arg2); void ItemEffect_ShardOfAgony(SaveContext* saveCtx, s16 arg1, s16 arg2); +void ItemEffect_EnemySoul(SaveContext* saveCtx, s16 soulId, s16 arg2); +void ItemEffect_OcarinaNote(SaveContext* saveCtx, s16 buttonId, s16 arg2); #endif //_ITEM_EFFECT_H_ diff --git a/code/src/item_override.c b/code/src/item_override.c index 42e2614d..4021a8fa 100644 --- a/code/src/item_override.c +++ b/code/src/item_override.c @@ -322,7 +322,6 @@ void ItemOverride_AfterItemReceived(void) { return; } ItemOverride_AfterKeyReceived(key); - ItemOverride_Clear(); } static u32 ItemOverride_PlayerIsReadyOnLand(void) { @@ -419,6 +418,14 @@ void ItemOverride_Update(void) { } } } + + // Clear the active override once the GetItem process has finished, + // or when walking away from a chest without opening it or a collectible without collecting it. + // This will also keep the override if the player is doing a GIM-like glitch. + if (rActiveItemRow != NULL && + (PLAYER->getItemId == 0 || (PLAYER->interactRangeActor == NULL && (PLAYER->stateFlags1 & 0x400) == 0))) { + ItemOverride_Clear(); + } } void ItemOverride_GetItem(Actor* fromActor, Player* player, s8 incomingItemId) { @@ -534,6 +541,15 @@ void ItemOverride_EditDrawGetItemAfterModelSpawn(SkeletonAnimationModel* model) CustomModels_ApplyItemCMAB(model, rActiveItemObjectId, rActiveItemRow->special); } +// Called every frame while the GetItem is drawn +void ItemOverride_EditDrawGetItemAfterMatrixUpdate(SkeletonAnimationModel* model) { + if (ItemOverride_IsDrawItemVanilla()) { + return; + } + + CustomModels_UpdateMatrix(&model->mtx, rActiveItemObjectId); +} + s32 ItemOverride_GiveSariasGift(void) { u32 receivedGift = EventCheck(0xC1); if (receivedGift == 0 && @@ -597,3 +613,16 @@ s16 ItemOverride_OverrideGiDrawIdPlusOne(s16 originalDrawItemID) { return 1; // Default value that won't change the mesh. } + +void ItemOverride_PushHardcodedItem(s16 getItemId) { + ItemOverride override = { + .key = { + .type = OVR_DELAYED, // random value to have non-zero key + }, + .value = { + .itemId = getItemId, + .player = 0xFF, + } + }; + ItemOverride_PushPendingOverride(override); +} diff --git a/code/src/item_override.h b/code/src/item_override.h index 6b27ae37..075d0133 100644 --- a/code/src/item_override.h +++ b/code/src/item_override.h @@ -50,5 +50,6 @@ void ItemOverride_PushDelayedOverride(u8 flag); void ItemOverride_CheckZeldasLetter(); void ItemOverride_PushDungeonReward(u8 dungeon); void ItemOverride_CheckStartingItem(); +void ItemOverride_PushHardcodedItem(s16 getItemId); #endif //_ITEM_OVERRIDES_H_ diff --git a/code/src/item_table.c b/code/src/item_table.c index 70b14233..f3ad401c 100644 --- a/code/src/item_table.c +++ b/code/src/item_table.c @@ -1,8 +1,10 @@ #include "item_table.h" #include "item_upgrade.h" #include "item_effect.h" +#include "enemy_souls.h" #include "rHeap.h" #include "chest.h" +#include "ocarina_notes.h" #include #define ITEM_ROW(baseItemId_, chestType_, actionId_, textId_, objectId_, objectModelIdx_, cmabIndex_, \ @@ -247,7 +249,7 @@ static ItemRow rItemTable[] = { [GI_TYCOON_WALLET] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x09F7, 0x00D1, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, ItemUpgrade_None, ItemEffect_GiveTycoonWallet, 3, -1), // Tycoon's Wallet [GI_LETTER_RUTO_2] = ITEM_ROW(0x53, CHEST_MAJOR, 0x14, 0x9099, 0x010B, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, ItemUpgrade_None, ItemEffect_None, -1, -1), // Redundant Letter Bottle [GI_MAGIC_BEAN_PACK] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x0048, 0x00F3, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, ItemUpgrade_None, ItemEffect_BeanPack, -1, -1), // Magic Bean Pack -// [GI_TRIFORCE_PIECE] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9003, 0x0193, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, ItemUpgrade_None, give_triforce_piece, -1, -1), // Triforce piece + [GI_TRIFORCE_PIECE] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9003, 0x016E, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, ItemUpgrade_None, ItemEffect_TriforcePiece, -1, -1), // Triforce piece [GI_KOKIRI_EMERALD] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x0080, 0x019C, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, ItemUpgrade_None, ItemEffect_GiveStone, 0x0004, -1), // Kokiri Emerald [GI_GORON_RUBY] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x0081, 0x019D, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, ItemUpgrade_None, ItemEffect_GiveStone, 0x0008, -1), // Goron Ruby @@ -274,6 +276,60 @@ static ItemRow rItemTable[] = { [GI_CHEST_GAME_KEY] = ITEM_ROW(0x53, CHEST_SMALL_KEY, 0x41, 0x00F3, 0x00AA, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, ItemUpgrade_None, ItemEffect_GiveSmallKey, DUNGEON_TREASURE_CHEST_SHOP, -1), // Small Key (Chest Game) + [GI_SOUL_POE] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9450, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_POE, -1), // Poe Soul + [GI_SOUL_OCTOROK] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9451, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_OCTOROK, -1), // Octorok Soul + [GI_SOUL_KEESE] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9452, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_KEESE, -1), // Keese Soul + [GI_SOUL_TEKTITE] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9453, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_TEKTITE, -1), // Tektite Soul + [GI_SOUL_LEEVER] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9454, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_LEEVER, -1), // Leever Soul + [GI_SOUL_PEAHAT] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9455, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_PEAHAT, -1), // Peahat Soul + [GI_SOUL_LIZALFOS] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9456, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_LIZALFOS, -1), // Lizalfos and Dinolfos Soul + [GI_SOUL_SHABOM] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9457, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_SHABOM, -1), // Shabom Soul + [GI_SOUL_BIRI_BARI] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9458, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_BIRI_BARI, -1), // Biri and Bari Soul + [GI_SOUL_TAILPASARAN] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9459, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_TAILPASARAN, -1), // Tailpasaran Soul + [GI_SOUL_SKULLTULA] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x945A, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_SKULLTULA, -1), // Skulltula Soul + [GI_SOUL_TORCH_SLUG] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x945B, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_TORCH_SLUG, -1), // Torch Slug Soul + [GI_SOUL_STINGER] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x945C, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_STINGER, -1), // Stinger Soul + [GI_SOUL_MOBLIN] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x945D, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_MOBLIN, -1), // Moblin Soul + [GI_SOUL_ARMOS] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x945E, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_ARMOS, -1), // Armos Soul + [GI_SOUL_DEKU_BABA] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x945F, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_DEKU_BABA, -1), // Deku Baba Soul + [GI_SOUL_BUBBLE] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9460, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_BUBBLE, -1), // Bubble Soul + [GI_SOUL_FLYING_TRAP] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9461, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_FLYING_TRAP, -1), // Flying Pot & Tile Soul + [GI_SOUL_BEAMOS] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9462, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_BEAMOS, -1), // Beamos Soul + [GI_SOUL_WALLMASTER] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9463, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_WALLMASTER, -1), // Wallmaster & Floormaster Soul + [GI_SOUL_REDEAD_GIBDO] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9464, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_REDEAD_GIBDO, -1), // Redead and Gibdo Soul + [GI_SOUL_SHELL_BLADE] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9465, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_SHELL_BLADE, -1), // Shell Blade Soul + [GI_SOUL_LIKE_LIKE] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9466, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_LIKE_LIKE, -1), // Like Like Soul + [GI_SOUL_TENTACLE] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9467, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_TENTACLE, -1), // Parasitic Tentacle Soul + [GI_SOUL_ANUBIS] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9468, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_ANUBIS, -1), // Anubis Soul + [GI_SOUL_SPIKE] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9469, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_SPIKE, -1), // Spike Soul + [GI_SOUL_SKULL_KID] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x946A, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_SKULL_KID, -1), // Skull Kid Soul + [GI_SOUL_FREEZARD] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x946B, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_FREEZARD, -1), // Freezard Soul + [GI_SOUL_DEKU_SCRUB] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x946C, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_DEKU_SCRUB, -1), // Deku Scrub Soul + [GI_SOUL_WOLFOS] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x946D, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_WOLFOS, -1), // Wolfos Soul + [GI_SOUL_STALCHILD] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x946E, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_STALCHILD, -1), // Stalchild Soul + [GI_SOUL_GUAY] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x946F, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_GUAY, -1), // Guay Soul + [GI_SOUL_DOOR_MIMIC] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9470, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_DOOR_MIMIC, -1), // Door Mimic Soul + [GI_SOUL_STALFOS] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9471, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_STALFOS, -1), // Stalfos Soul + [GI_SOUL_DARK_LINK] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9472, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_DARK_LINK, -1), // Dark Link Soul + [GI_SOUL_FLARE_DANCER] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9473, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_FLARE_DANCER, -1), // Flare Dancer Soul + [GI_SOUL_DEAD_HAND] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9474, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_DEAD_HAND, -1), // Dead Hand Soul + [GI_SOUL_GERUDO] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9475, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_GERUDO, -1), // Gerudo Soul + [GI_SOUL_GOHMA] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9476, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_GOHMA, -1), // Gohma Soul + [GI_SOUL_DODONGO] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9477, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_DODONGO, -1), // Dodongo Soul + [GI_SOUL_BARINADE] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9478, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_BARINADE, -1), // Barinade Soul + [GI_SOUL_PHANTOM_GANON] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x9479, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_PHANTOM_GANON, -1), // Phantom Ganon Soul + [GI_SOUL_VOLVAGIA] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x947A, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_VOLVAGIA, -1), // Volvagia Soul + [GI_SOUL_MORPHA] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x947B, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_MORPHA, -1), // Morpha Soul + [GI_SOUL_BONGO_BONGO] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x947C, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_BONGO_BONGO, -1), // Bongo Bongo Soul + [GI_SOUL_TWINROVA] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x947D, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_TWINROVA, -1), // Twinrova Soul + [GI_SOUL_GANON] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x947E, 0x00E4, 0x00, 0xFF, 0x01, 0x00, 0xFF, ItemUpgrade_None, ItemEffect_EnemySoul, SOUL_GANON, -1), // Ganon Soul + + [GI_OCARINA_BUTTON_L] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x93F0, 0x0123, 0x00, 0xFF, 0xFF, 0xFF, 0x00, ItemUpgrade_None, ItemEffect_OcarinaNote, OCARINA_BUTTON_L, -1), // Ocarina Note Button L + [GI_OCARINA_BUTTON_R] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x93F1, 0x0123, 0x00, 0xFF, 0xFF, 0xFF, 0x01, ItemUpgrade_None, ItemEffect_OcarinaNote, OCARINA_BUTTON_R, -1), // Ocarina Note Button R + [GI_OCARINA_BUTTON_X] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x93F2, 0x0123, 0x00, 0xFF, 0xFF, 0xFF, 0x02, ItemUpgrade_None, ItemEffect_OcarinaNote, OCARINA_BUTTON_X, -1), // Ocarina Note Button X + [GI_OCARINA_BUTTON_Y] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x93F3, 0x0123, 0x00, 0xFF, 0xFF, 0xFF, 0x03, ItemUpgrade_None, ItemEffect_OcarinaNote, OCARINA_BUTTON_Y, -1), // Ocarina Note Button Y + [GI_OCARINA_BUTTON_A] = ITEM_ROW(0x53, CHEST_MAJOR, 0x41, 0x93F4, 0x0123, 0x00, 0xFF, 0xFF, 0xFF, 0x04, ItemUpgrade_None, ItemEffect_OcarinaNote, OCARINA_BUTTON_A, -1), // Ocarina Note Button A + }; // clang-format on diff --git a/code/src/main.c b/code/src/main.c index 92ada645..2aa73d9b 100644 --- a/code/src/main.c +++ b/code/src/main.c @@ -66,4 +66,8 @@ void after_GlobalContext_Update() { } Multiplayer_Sync_Update(); + + if (gGlobalContext->state.running == 0) { + Model_DestroyAll(); + } } diff --git a/code/src/message.c b/code/src/message.c index e692f04e..78f08372 100644 --- a/code/src/message.c +++ b/code/src/message.c @@ -1,6 +1,11 @@ #include "z3D/z3D.h" #include "message.h" +#include "savefile.h" +#include "settings.h" +#include "3ds/util/utf.h" +#include "lib/printf.h" #include +#include // These consts are filled in by the app volatile const u32 numCustomMessageEntries; @@ -38,3 +43,49 @@ const MessageEntry* Message_GetCustomEntry(void* param_1, u32 textId) { const char* Message_GetCustomText(void* param_1, u32 offset) { return (offset > 0x500000) ? (char*)offset : Message_GetText(param_1, offset); } + +#define MESSAGE_MAX_CUSTOM_STRING_SIZE 10 +u32 Message_HandleTextControlCode(TextControlCode ctrl, void* textObj, UnkTextControlData* data) { + static u16 utf16Str[MESSAGE_MAX_CUSTOM_STRING_SIZE] = { 0 }; + char str[MESSAGE_MAX_CUSTOM_STRING_SIZE]; + + // Make text skippable or instant depending on setting. + if ((ctrl == TEXT_CTRL_UNSKIPPABLE && gSettingsContext.quickText >= QUICKTEXT_SKIPPABLE) || + (ctrl == TEXT_CTRL_INSTANT_TEXT_OFF && gSettingsContext.quickText >= QUICKTEXT_INSTANT)) { + return 1; // Bypass control code + } + + // When a custom control code is found, copy what FUN_0040b7d8 does to insert the player name, + // but instead insert a custom string. + if (ctrl == TEXT_CTRL_TRIFORCE_PIECE_COUNT) { + snprintf_(str, MESSAGE_MAX_CUSTOM_STRING_SIZE, "%d", gExtSaveData.extInf[EXTINF_TRIFORCE_PIECES]); + utf8_to_utf16(utf16Str, (u8*)str, strlen(str)); + Message_UnkControlCodeHandler(textObj, &data); + data->unk_05 = 0; + data->stringToInsert = utf16Str; + data->stringLength = strlen(str); + return 1; + } + + return 0; // Vanilla control char, resume base game function. +} + +char* Message_rCheckForControlCodes(void* unkStruct, char* nextChars, void* textObj, u32 charIdx) { + // Set instant text when parsing the first character of the text or immediately after a box break. + if (gSettingsContext.quickText >= QUICKTEXT_INSTANT && + (charIdx == 0 || (charIdx >= 2 && nextChars[-2] == '\x7F' && nextChars[-1] == TEXT_CTRL_WAIT_FOR_INPUT))) { + Message_SetInstantText(textObj); + } + + // If the next characters are either not a control code or a vanilla one, + // use base game function. + if (nextChars[0] != '\x7F' || nextChars[1] <= TEXT_CTRL_0x2F) { + return Message_CheckForControlCodes(unkStruct, nextChars); + } + + // Store control code identifier + *(char*)(unkStruct + 4) = nextChars[1]; + // Return pointer to next char after this control code, + // assuming all custom control codes will be 2 characters long. + return nextChars + 2; +} diff --git a/code/src/message.h b/code/src/message.h index 7ec14d46..abf2db55 100644 --- a/code/src/message.h +++ b/code/src/message.h @@ -40,4 +40,77 @@ typedef struct { u32 unk_0C; } MessageFileHeader; +typedef enum TextControlCode { + /* 0x00 */ TEXT_CTRL_MESSAGE_END, + /* 0x01 */ TEXT_CTRL_WAIT_FOR_INPUT, + /* 0x02 */ TEXT_CTRL_HORIZONTAL_SPACE, + /* 0x03 */ TEXT_CTRL_GO_TO, + /* 0x04 */ TEXT_CTRL_INSTANT_TEXT_ON, + /* 0x05 */ TEXT_CTRL_INSTANT_TEXT_OFF, + /* 0x06 */ TEXT_CTRL_SHOP_MESSAGE_BOX, + /* 0x07 */ TEXT_CTRL_EVENT_TRIGGER, + /* 0x08 */ TEXT_CTRL_DELAY_FRAMES, + /* 0x09 */ TEXT_CTRL_0x9, + /* 0x0A */ TEXT_CTRL_CLOSE_AFTER, + /* 0x0B */ TEXT_CTRL_PLAYER_NAME, + /* 0x0C */ TEXT_CTRL_PLAY_OCARINA, + /* 0x0D */ TEXT_CTRL_0xD, + /* 0x0E */ TEXT_CTRL_PLAY_SFX, + /* 0x0F */ TEXT_CTRL_ITEM_OBTAINED, + /* 0x10 */ TEXT_CTRL_SET_SPEED, + /* 0x11 */ TEXT_CTRL_WRONG_SONG, + /* 0x12 */ TEXT_CTRL_MARATHON_TIME, + /* 0x13 */ TEXT_CTRL_HORSE_RACE_TIME, + /* 0x14 */ TEXT_CTRL_GERUDO_ARCHERY_POINTS, + /* 0x15 */ TEXT_CTRL_SKULLTULAS_DESTROYED, + /* 0x16 */ TEXT_CTRL_FISH_INFO, + /* 0x17 */ TEXT_CTRL_CURRENT_TIME, + /* 0x18 */ TEXT_CTRL_HIGH_SCORES, + /* 0x19 */ TEXT_CTRL_UNSKIPPABLE, + /* 0x1A */ TEXT_CTRL_TWO_WAY_CHOICE, + /* 0x1B */ TEXT_CTRL_THREE_WAY_CHOICE, + /* 0x1C */ TEXT_CTRL_NEWLINE, + /* 0x1D */ TEXT_CTRL_COLOR, + /* 0x1E */ TEXT_CTRL_CENTER_TEXT, + /* 0x1F */ TEXT_CTRL_0x1F, + /* 0x20 */ TEXT_CTRL_0x20, + /* 0x21 */ TEXT_CTRL_0x21, + /* 0x22 */ TEXT_CTRL_0x22, + /* 0x23 */ TEXT_CTRL_BOSS_CHALLENGE_RECORDS, + /* 0x24 */ TEXT_CTRL_BUTTON_ICON, + /* 0x25 */ TEXT_CTRL_CREDITS_UNK, + /* 0x26 */ TEXT_CTRL_SINGULAR_FORM_START, + /* 0x27 */ TEXT_CTRL_PLURAL_FORM_START, + /* 0x28 */ TEXT_CTRL_PLURAL_FORM_END, + /* 0x29 */ TEXT_CTRL_IF_NOT_MQ, + /* 0x2A */ TEXT_CTRL_MQ_ELSE, + /* 0x2B */ TEXT_CTRL_MQ_END, + /* 0x2C */ TEXT_CTRL_0x2C, + /* 0x2D */ TEXT_CTRL_0x2D, + /* 0x2E */ TEXT_CTRL_0x2E, + /* 0x2F */ TEXT_CTRL_0x2F, + + // The following values are custom control codes added by the randomizer + + /* 0x30 */ TEXT_CTRL_TRIFORCE_PIECE_COUNT, +} TextControlCode; + +typedef struct UnkTextControlData { + /* 0x00 */ char unk_00[0x5]; + /* 0x05 */ u8 unk_05; + /* 0x06 */ char unk_06[0x2]; + /* 0x08 */ u16* stringToInsert; + /* 0x0C */ u32 stringLength; + // ... size unknown +} UnkTextControlData; + +typedef void (*Message_UnkControlCodeHandler_proc)(void* textObj, UnkTextControlData** data); +#define Message_UnkControlCodeHandler ((Message_UnkControlCodeHandler_proc)0x306318) + +typedef char* (*Message_CheckForControlCodes_proc)(void* data, char* nextChars); +#define Message_CheckForControlCodes ((Message_CheckForControlCodes_proc)0x4C08C0) + +typedef void (*Message_SetInstantText_proc)(void* textObj); +#define Message_SetInstantText ((Message_SetInstantText_proc)0x40B608) + #endif //_MESSAGE_H_ diff --git a/code/src/models.c b/code/src/models.c index 9dc267a7..0b9ea5fa 100644 --- a/code/src/models.c +++ b/code/src/models.c @@ -26,11 +26,6 @@ typedef void (*Actor_SetModelMatrix_proc)(f32 x, f32 y, f32 z, nn_math_MTX34* mt #define Actor_SetModelMatrix_addr 0x3679D0 #define Actor_SetModelMatrix ((Actor_SetModelMatrix_proc)Actor_SetModelMatrix_addr) -typedef void (*Matrix_Multiply_proc)(nn_math_MTX34* dst, nn_math_MTX34* lhs, nn_math_MTX44* rhs) - __attribute__((pcs("aapcs-vfp"))); -#define Matrix_Multiply_addr 0x36C174 -#define Matrix_Multiply ((Matrix_Multiply_proc)Matrix_Multiply_addr) - #define LOADEDMODELS_MAX 16 Model ModelContext[LOADEDMODELS_MAX] = { 0 }; @@ -136,7 +131,7 @@ void Actor_SetModelMatrixWrapper(Actor* actor, nn_math_MTX34* mtx) { } void Model_UpdateMatrix(Model* model) { - nn_math_MTX44 scaleMtx; + nn_math_MTX44 scaleMtx = { 0 }; Actor_SetModelMatrixWrapper(model->actor, &model->saModel->mtx); if (model->saModel2 != NULL) { f32 tempRotY = model->actor->shape.rot.y; @@ -148,18 +143,16 @@ void Model_UpdateMatrix(Model* model) { model->actor->shape.rot.y = tempRotY; } - for (s32 i = 0; i < 4; ++i) { - for (s32 j = 0; j < 4; ++j) { - if (i == j) { - scaleMtx.data[i][j] = (i == 3) ? 1.0f : model->scale; - } else { - scaleMtx.data[i][j] = 0.0f; - } - } - } + scaleMtx.data[0][0] = model->scale; + scaleMtx.data[1][1] = model->scale; + scaleMtx.data[2][2] = model->scale; + scaleMtx.data[3][3] = 1.0f; + Matrix_Multiply(&model->saModel->mtx, &model->saModel->mtx, &scaleMtx); + Matrix_UpdatePosition(&model->saModel->mtx, &model->saModel->mtx, &model->posOffset); if (model->saModel2 != NULL) { Matrix_Multiply(&model->saModel2->mtx, &model->saModel2->mtx, &scaleMtx); + Matrix_UpdatePosition(&model->saModel->mtx, &model->saModel->mtx, &model->posOffset); } } @@ -247,10 +240,16 @@ void Model_Create(Model* model, GlobalContext* globalCtx) { case 0x019C: // Kokiri Emerald case 0x019D: // Goron Ruby case 0x019E: // Zora Sapphire - newModel->scale = 0.2f; + newModel->scale = 0.2f; + newModel->posOffset = (Vec3f){ 0 }; + break; + case OBJECT_CUSTOM_TRIFORCE_PIECE: + newModel->scale = 0.025f; + newModel->posOffset = (Vec3f){ 0.0f, -800.0f, 0.0f }; break; default: - newModel->scale = 0.3f; + newModel->scale = 0.3f; + newModel->posOffset = (Vec3f){ 0 }; break; } } diff --git a/code/src/models.h b/code/src/models.h index 9bdc77b5..2ca3faed 100644 --- a/code/src/models.h +++ b/code/src/models.h @@ -12,6 +12,7 @@ typedef struct { SkeletonAnimationModel* saModel; SkeletonAnimationModel* saModel2; f32 scale; + Vec3f posOffset; } Model; void Model_UpdateAll(GlobalContext* globalCtx); diff --git a/code/src/multiplayer_ghosts.c b/code/src/multiplayer_ghosts.c index 9592e678..defee568 100644 --- a/code/src/multiplayer_ghosts.c +++ b/code/src/multiplayer_ghosts.c @@ -70,13 +70,6 @@ GhostData* Multiplayer_Ghosts_GetGhostData(u16 networkID) { return NULL; } -typedef void (*EffectSsDeadDb_Spawn_proc)(GlobalContext* globalCtx, Vec3f* position, Vec3f* velocity, - Vec3f* acceleration, s16 scale, s16 scale_step, s16 prim_r, s16 prim_g, - s16 prim_b, s16 prim_a, s16 env_r, s16 env_g, s16 env_b, s16 unused, - s32 frame_duration, s16 play_sound); -#define EffectSsDeadDb_Spawn_addr 0x3642F4 -#define EffectSsDeadDb_Spawn ((EffectSsDeadDb_Spawn_proc)EffectSsDeadDb_Spawn_addr) - void Multiplayer_Ghosts_DrawAll(void) { for (size_t i = 0; i < ARRAY_SIZE(ghosts); i++) { LinkGhost* ghost = &ghosts[i]; diff --git a/code/src/ocarina_notes.c b/code/src/ocarina_notes.c new file mode 100644 index 00000000..eb762c2b --- /dev/null +++ b/code/src/ocarina_notes.c @@ -0,0 +1,83 @@ +#include "ocarina_notes.h" +#include "savefile.h" +#include "settings.h" + +s32 OcarinaNotes_IsButtonOwned(OcarinaNoteButton button) { + return (gSettingsContext.shuffleOcarinaButtons == OFF) || + (gExtSaveData.extInf[EXTINF_OCARINA_BUTTONS] & (1 << button)); +} + +void OcarinaNotes_RegisterButtonOwned(OcarinaNoteButton button) { + gExtSaveData.extInf[EXTINF_OCARINA_BUTTONS] |= (1 << button); +} + +void OcarinaNotes_MoveButtons(void* spriteStruct, Vec2f* posOffset, u32 unk, u32 spriteIndex) { + if (spriteStruct != OcarinaUIStruct) { + return; + } + + u8 shouldDraw = TRUE; + + switch (spriteIndex) { + case OCS_L_BG_L: + case OCS_L_BG_M: + case OCS_L_BG_R: + case OCS_L_BUTTON: + case OCS_L_LETTER: + case OCS_L_SHADOW_L: + case OCS_L_SHADOW_M: + case OCS_L_SHADOW_R: + shouldDraw = OcarinaNotes_IsButtonOwned(OCARINA_BUTTON_L); + break; + case OCS_R_BG_L: + case OCS_R_BG_M: + case OCS_R_BG_R: + case OCS_R_BUTTON: + case OCS_R_LETTER: + case OCS_R_SHADOW_L: + case OCS_R_SHADOW_M: + case OCS_R_SHADOW_R: + shouldDraw = OcarinaNotes_IsButtonOwned(OCARINA_BUTTON_R); + break; + case OCS_X_BG_L: + case OCS_X_BG_R: + case OCS_X_BUTTON: + case OCS_X_LETTER: + case OCS_X_SHADOW_L: + case OCS_X_SHADOW_R: + shouldDraw = OcarinaNotes_IsButtonOwned(OCARINA_BUTTON_X); + break; + case OCS_Y_BG_L: + case OCS_Y_BG_R: + case OCS_Y_BUTTON: + case OCS_Y_LETTER: + case OCS_Y_SHADOW_L: + case OCS_Y_SHADOW_R: + shouldDraw = OcarinaNotes_IsButtonOwned(OCARINA_BUTTON_Y); + break; + case OCS_A_BG_L: + case OCS_A_BG_R: + case OCS_A_BUTTON: + case OCS_A_LETTER: + case OCS_A_SHADOW_L: + case OCS_A_SHADOW_R: + shouldDraw = OcarinaNotes_IsButtonOwned(OCARINA_BUTTON_A); + break; + } + + if (shouldDraw == FALSE) { + // yeet sprite off-screen + posOffset->x += 500.0f; + posOffset->y += 500.0f; + } +} + +u32 OcarinaNotes_HandleInputs(u32 ocarinaInputs) { + static const u32 btnShifts[5] = { 7, 9, 10, 11, 8 }; // not the same offsets as the btn_t struct + u32 ownedBtnsMask = 0; + for (OcarinaNoteButton btn = 0; btn < 5; btn++) { + ownedBtnsMask |= (OcarinaNotes_IsButtonOwned(btn) << btnShifts[btn]); + } + ocarinaInputs &= ownedBtnsMask; + return ocarinaInputs; +} diff --git a/code/src/ocarina_notes.h b/code/src/ocarina_notes.h new file mode 100644 index 00000000..02cf7a3b --- /dev/null +++ b/code/src/ocarina_notes.h @@ -0,0 +1,68 @@ +#ifndef _OCARINA_NOTES_H_ +#define _OCARINA_NOTES_H_ + +#include "z3D/z3D.h" +#include "input.h" + +typedef enum OcarinaNoteButton { + OCARINA_BUTTON_L, + OCARINA_BUTTON_R, + OCARINA_BUTTON_X, + OCARINA_BUTTON_Y, + OCARINA_BUTTON_A, +} OcarinaNoteButton; + +enum OcarinaSprites { + OCS_L_BG_L = 0x3F, + OCS_L_BG_M, + OCS_L_BG_R, + OCS_L_BUTTON, + OCS_L_LETTER, + OCS_R_BG_L, + OCS_R_BG_M, + OCS_R_BG_R, + OCS_R_BUTTON, + OCS_R_LETTER, + OCS_X_BG_L, + OCS_X_BG_R, + OCS_X_BUTTON, + OCS_X_LETTER, + OCS_Y_BG_L, + OCS_Y_BG_R, + OCS_Y_BUTTON, + OCS_Y_LETTER, + OCS_A_BG_L, + OCS_A_BG_R, + OCS_A_BUTTON, + OCS_A_LETTER, + OCS_BACK_SHADOW_L, + OCS_BACK_SHADOW_M, + OCS_BACK_SHADOW_R, + OCS_SONGS_SHADOW_L, + OCS_SONGS_SHADOW_M, + OCS_SONGS_SHADOW_R, + OCS_L_SHADOW_L, + OCS_L_SHADOW_M, + OCS_L_SHADOW_R, + OCS_R_SHADOW_L, + OCS_R_SHADOW_M, + OCS_R_SHADOW_R, + OCS_X_SHADOW_L, + OCS_X_SHADOW_R, + OCS_Y_SHADOW_L, + OCS_Y_SHADOW_R, + OCS_A_SHADOW_L, + OCS_A_SHADOW_R, + OCS_YELLOW_MARKER_1, + OCS_YELLOW_MARKER_2, + OCS_YELLOW_MARKER_3, + OCS_YELLOW_MARKER_4, + OCS_YELLOW_MARKER_5, +}; // max 0x6C + +#define OcarinaUIStruct (*((void**)0x5093EC)) + +s32 OcarinaNotes_IsButtonOwned(OcarinaNoteButton button); +void OcarinaNotes_RegisterButtonOwned(OcarinaNoteButton button); + +#endif //_OCARINA_NOTES_H_ diff --git a/code/src/patches.s b/code/src/patches.s index 5ae0fed4..2015835e 100644 --- a/code/src/patches.s +++ b/code/src/patches.s @@ -71,6 +71,11 @@ EditDrawGetItemBeforeModelSpawn_patch: EditDrawGetItemAfterModelSpawn_patch: bl hook_EditDrawDetItemAfterModelSpawn +.section .patch_EditDrawGetItemAfterMatrixUpdate +.global EditDrawGetItemAfterMatrixUpdate_patch +EditDrawGetItemAfterMatrixUpdate_patch: + bl hook_EditDrawGetItemAfterMatrixUpdate + .section .patch_NoLensOfTruthNaviText nop @@ -1239,10 +1244,10 @@ SariasSongHintsOne_patch: SariasSongHintsTwo_patch: bl Hints_GetNextSariasSongHint -.section .patch_HyperActors -.global HyperActors_patch -HyperActors_patch: - bl hook_HyperActors +.section .patch_ActorUpdate +.global ActorUpdate_patch +ActorUpdate_patch: + bl hook_ActorUpdate .section .patch_TitleCardUpdate .global TitleCardUpdate_patch @@ -1335,26 +1340,6 @@ SongOfTimeJingle_patch: GKSetDurability_patch: b hook_GKSetDurability -.section .patch_SkippableText -.global SkippableText_patch -SkippableText_patch: - b hook_SkippableText - -.section .patch_InstantTextFirstLine -.global InstantTextFirstLine_patch -InstantTextFirstLine_patch: - bl hook_InstantTextFirstLine - -.section .patch_InstantTextBoxBreak -.global InstantTextBoxBreak_patch -InstantTextBoxBreak_patch: - b hook_InstantTextBoxBreak - -.section .patch_InstantTextRemoveOff -.global InstantTextRemoveOff_patch -InstantTextRemoveOff_patch: - b hook_InstantTextRemoveOff - .section .patch_TurboTextAdvance .global TurboTextAdvance_patch TurboTextAdvance_patch: @@ -1582,10 +1567,15 @@ EnteredLocation_patch: LostWoodsBridgeMusic_patch: bl hook_LostWoodsBridgeMusic -.section .patch_LoadGame -.global .LoadGame_patch -LoadGame_patch: - b hook_LoadGame +.section .patch_BeforeLoadGame +.global BeforeLoadGame_patch +BeforeLoadGame_patch: + b hook_BeforeLoadGame + +.section .patch_AfterLoadGame +.global AfterLoadGame_patch +AfterLoadGame_patch: + b hook_AfterLoadGame .section .patch_SaveGame .global .SaveGame_patch @@ -2200,6 +2190,58 @@ RandomGsLoc_BlockSpawn_Soil_patch: RandomGsLoc_SkipSoilJingle_patch: bl hook_RandomGsLoc_SkipSoilJingle +.section .patch_ActorDraw +.global ActorDraw_patch +ActorDraw_patch: + bl hook_ActorDraw + +.section .patch_FlyingPotCollision +.global FlyingPotCollision_patch +FlyingPotCollision_patch: + bl hook_FlyingPotCollision + +.section .patch_FlyingTileCollision +.global FlyingTileCollision_patch +FlyingTileCollision_patch: + bl hook_FlyingTileCollision + +.section .patch_ShabomAfterDamagePlayer +.global ShabomAfterDamagePlayer_patch +ShabomAfterDamagePlayer_patch: + bl hook_ShabomAfterDamagePlayer + +.section .patch_DodongoAfterSwallowBomb +.global DodongoAfterSwallowBomb_patch +DodongoAfterSwallowBomb_patch: + bl hook_DodongoAfterSwallowBomb + +.section .patch_BabyDodongoAfterSwallowBomb +.global BabyDodongoAfterSwallowBomb_patch +BabyDodongoAfterSwallowBomb_patch: + bl hook_BabyDodongoAfterSwallowBomb + +.section .patch_OcarinaNoteButtonsDraw +.global OcarinaNoteButtonsDraw_patch +OcarinaNoteButtonsDraw_patch: + push {lr} + bl hook_OcarinaNoteButtonsDraw + pop {lr} + +.section .patch_OcarinaNoteButtonsPress +.global OcarinaNoteButtonsPress_patch +OcarinaNoteButtonsPress_patch: + bl hook_OcarinaNoteButtonsPress + +.section .patch_HandleTextControlCode +.global HandleTextControlCode_patch +HandleTextControlCode_patch: + bl hook_HandleTextControlCode + +.section .patch_CheckForTextControlCode +.global CheckForTextControlCode_patch +CheckForTextControlCode_patch: + bl hook_CheckForTextControlCode + @ ---------------------------------- @ ---------------------------------- diff --git a/code/src/savefile.c b/code/src/savefile.c index 1b816530..afa0eed5 100644 --- a/code/src/savefile.c +++ b/code/src/savefile.c @@ -161,8 +161,8 @@ void SaveFile_Init(u32 fileBaseIndex) { gSaveContext.eventChkInf[0x0] |= 0x0010; } - SaveFile_SetStartingInventory(); SaveFile_InitExtSaveData(fileBaseIndex + gSaveContext.fileNum, 1); + SaveFile_SetStartingInventory(); // Ingame Defaults gSaveContext.zTargetingSetting = gSettingsContext.zTargeting; @@ -535,6 +535,14 @@ void SaveFile_SetStartingInventory(void) { EventSet(0x18); gSaveContext.horseData.pos.y = 0xF000; // place Epona OoB, so you can't reach her without playing the song } + + // Set owned ocarina buttons. If the shuffle option is disabled, this value will be ignored. + gExtSaveData.extInf[EXTINF_OCARINA_BUTTONS] = gSettingsContext.startingOcarinaButtons; + + // Set owned enemy souls. If the shuffle option is disabled, these values will be ignored. + for (u32 i = 0; i < sizeof(gSettingsContext.startingEnemySouls); i++) { + gExtSaveData.extInf[EXTINF_ENEMYSOULSFLAGS_START + i] = gSettingsContext.startingEnemySouls[i]; + } } // We will use the "unk" flags in DMT to represent adult trade ownership @@ -828,3 +836,17 @@ void SaveFile_LoadFileSwordless(void) { gExtSaveData.extInf[EXTINF_MASTERSWORDFLAGS] |= 2; } } + +void SaveFile_BeforeLoadGame(u32 saveNumber) { + SaveFile_LoadExtSaveData(saveNumber); +} + +void SaveFile_AfterLoadGame(void) { + // Give Ganon BK if Triforce Hunt has been completed + if (gSettingsContext.triforceHunt == ON && + gExtSaveData.extInf[EXTINF_TRIFORCE_PIECES] >= gSettingsContext.triforcePiecesRequired && + (gSaveContext.dungeonItems[DUNGEON_GANONS_TOWER] & 1) == 0) { + + ItemOverride_PushHardcodedItem(GI_GANON_BOSS_KEY); + } +} diff --git a/code/src/savefile.h b/code/src/savefile.h index 3c368185..f753a4ac 100644 --- a/code/src/savefile.h +++ b/code/src/savefile.h @@ -39,6 +39,10 @@ typedef enum { EXTINF_HASTIMETRAVELED, EXTINF_MASTERSWORDFLAGS, EXTINF_TOTALTAR_FLAGS, + EXTINF_ENEMYSOULSFLAGS_START, // 64 bits (at least one for each EnemySoulId) + EXTINF_ENEMYSOULSFLAGS_END = EXTINF_ENEMYSOULSFLAGS_START + 7, + EXTINF_OCARINA_BUTTONS, + EXTINF_TRIFORCE_PIECES, EXTINF_SIZE, } ExtInf; diff --git a/code/src/settings.h b/code/src/settings.h index eab0182a..090a1f57 100644 --- a/code/src/settings.h +++ b/code/src/settings.h @@ -231,6 +231,7 @@ typedef enum { GANONSBOSSKEY_ANY_DUNGEON, GANONSBOSSKEY_OVERWORLD, GANONSBOSSKEY_ANYWHERE, + GANONSBOSSKEY_TRIFORCE, // Unselectable option, set automatically for Triforce Hunt GANONSBOSSKEY_LACS_VANILLA, GANONSBOSSKEY_LACS_MEDALLIONS, GANONSBOSSKEY_LACS_STONES, @@ -496,6 +497,9 @@ typedef struct { u8 randomMQDungeons; u8 mqDungeonCount; u8 dungeonModesKnown[12]; // 12 dungeons which can be set Vanilla or MQ + u8 triforceHunt; + u8 triforcePiecesTotal; + u8 triforcePiecesRequired; u8 shuffleRewards; u8 linksPocketItem; @@ -514,6 +518,8 @@ typedef struct { u8 shuffleFrogSongRupees; u8 shuffleAdultTradeQuest; u8 shuffleChestMinigame; + u8 shuffleEnemySouls; + u8 shuffleOcarinaButtons; u8 mapsAndCompasses; u8 keysanity; @@ -564,6 +570,7 @@ typedef struct { u8 sheikHints; u8 dampeHint; u8 skulltulaHints; + u8 fishingHints; u8 compassesShowReward; u8 compassesShowWotH; u8 mapsShowDungeonMode; @@ -725,6 +732,9 @@ typedef struct { u32 startingEquipment; u32 startingUpgrades; + u8 startingEnemySouls[8]; + u8 startingOcarinaButtons; + u8 startingTokens; } SettingsContext; diff --git a/romfs/zelda_gi_melody.zar b/romfs/zelda_gi_melody.zar index dcdaaecb..4dbb471c 100644 Binary files a/romfs/zelda_gi_melody.zar and b/romfs/zelda_gi_melody.zar differ diff --git a/source/custom_messages.cpp b/source/custom_messages.cpp index 8434497e..729fe88f 100644 --- a/source/custom_messages.cpp +++ b/source/custom_messages.cpp @@ -1055,6 +1055,41 @@ void CreateAlwaysIncludedMessages() { rutoDialog.Replace("$", ""); // Plural marker CreateMessageFromTextObject(0x4050, 0, 2, 3, AddColorsAndFormat(rutoDialog, { itemColor })); } + + for (ItemKey soulKey = SOUL_ITEM_POE; soulKey <= SOUL_ITEM_GANON; soulKey++) { + Text soulText = Text{ "You got the #", "Vous obtenez #", "¡Has obtenido #", "Hai ottenuto l'#", "Du hast #" } + + ItemTable(soulKey).GetName() + "#!"; + + CreateMessageFromTextObject(0x9450 + soulKey - SOUL_ITEM_POE, 0, 2, 3, + AddColorsAndFormat(soulText, { QM_RED })); + } + + for (ItemKey key = OCA_BUTTON_ITEM_L; key <= OCA_BUTTON_ITEM_A; key++) { + Text text = Text{ "You got the #", "Vous obtenez #", "¡Has obtenido #", "Hai ottenuto il #", "Du hast #" } + + ItemTable(key).GetName() + "#!"; + + CreateMessageFromTextObject(0x93F0 + key - OCA_BUTTON_ITEM_L, 0, 2, 3, AddColorsAndFormat(text, { QM_RED })); + } + + // Triforce Piece + { + Text triforceMsg = + Text{ /*english*/ "You found a piece of the #Triforce#!&You have #" + TRIFORCE_PIECE_COUNT() + "#!", + /*french */ "", + /*spanish*/ "", + /*italian*/ "Hai ottenuto un frammento della #Triforza#!&Ne hai #" + TRIFORCE_PIECE_COUNT() + "#!", + /*german */ "" }; + CreateMessageFromTextObject(0x9003, 0, 2, 3, AddColorsAndFormat(triforceMsg, { QM_RED, QM_RED })); + } + + if (Settings::FishingHints) { + Text aquariumText = Text{ /*english*/ "You can have this if you catch a fish to put in the aquarium.", + /*french */ "", + /*spanish*/ "", + /*italian*/ "Puoi avere questo se catturi un pesce da mettere nell'acquario.", + /*german */ "" }; + CreateMessageFromTextObject(0x40AE, 0, 2, 3, AddColorsAndFormat(aquariumText, {})); + } } std::vector CreateBaseCompassTexts() { @@ -1357,4 +1392,7 @@ std::string MQ_ELSE() { std::string MQ_END() { return "\x7F\x2B"s; } +std::string TRIFORCE_PIECE_COUNT() { + return "\x7F\x30"s; +} } // namespace CustomMessages diff --git a/source/custom_messages.hpp b/source/custom_messages.hpp index e05ddc55..4b8cc462 100644 --- a/source/custom_messages.hpp +++ b/source/custom_messages.hpp @@ -56,4 +56,5 @@ std::string CENTER_TEXT(); std::string IF_NOT_MQ(); std::string MQ_ELSE(); std::string MQ_END(); +std::string TRIFORCE_PIECE_COUNT(); } // namespace CustomMessages diff --git a/source/descriptions.cpp b/source/descriptions.cpp index 687c3fcb..be4c76e9 100644 --- a/source/descriptions.cpp +++ b/source/descriptions.cpp @@ -342,6 +342,20 @@ string_view mqDungeonCountDesc = "Specify the number of Master Quest dung string_view setDungeonTypesDesc = "If set, you can choose specific dungeons to be\n" // "vanilla, MQ, or random"; // /*------------------------------ // +| TRIFORCE HUNT | // +------------------------------*/ // +string_view triforceHuntDesc = "Pieces of the Triforce have been scattered around\n" + "the world. Find some of them to beat the game.\n" // + "\n" // + "Game is saved on completion, and Ganon's Castle\n"// + "key is given if beating the game again is desired."; +string_view triforcePiecesTotalDesc = "Set the total number of pieces that will appear\n"// + "in the world.\n\n" // + "Hold A to scroll faster."; // +string_view triforcePiecesRequiredDesc= "Set the number of pieces required to beat the\n" // + "game.\n\n" // + "Hold A to scroll faster."; // +/*------------------------------ // | SHUFFLE DUNGEON REWARDS | // ------------------------------*/ // string_view shuffleRewardsEndOfDungeon= "Medallions and Spiritual Stones will be given as\n" @@ -531,6 +545,23 @@ string_view chestMinigameDesc = "The 5 key chests in the Treasure Chest "If you choose the \"pack\" option, you will get\n"// "all the keys at once, in a single item."; // /*------------------------------ // +| SHUFFLE ENEMY SOULS | // +------------------------------*/ // +string_view enemySoulDesc = "Enemies will be invincible and appear as a purple\n" + "flame until you find their \"soul\".\n" // + "Each enemy type will have a soul added into the\n"// + "item pool.\n\n" // + "You can exclude some enemies by adding their\n" // + "souls in the Starting Inventory.\n\n" // + "WARNING: Incompatible with Master Quest Logic."; // +/*------------------------------ // +| SHUFFLE OCARINA BUTTONS | // +------------------------------*/ // +string_view ocarinaButtonsDesc = "Enabling this locks all Ocarina inputs, and adds\n" + "5 new items to find that each unlock one of the 5\n" + "Ocarina notes.\n\n" // + "They can also be added to the Starting Inventory."; +/*------------------------------ // | MAPS AND COMPASSES | // ------------------------------*/ // string_view mapCompassStartWith = "Maps and Compasses are given to you from the\n" // @@ -819,6 +850,8 @@ string_view dampeHintDesc = "Reading Dampe's diary will reveal the l string_view skulltulaHintDesc = "Talking to a cursed House of Skulltula resident\n"// "will tell you the reward they will give you for\n"// "removing their curse."; // +string_view fishingHintsDesc = "The aquarium at the fishing pond will show what\n"// + "reward you can win as your current age."; // /*------------------------------ // | MAP AND COMPASS GIVES INFO | // ------------------------------*/ // @@ -1191,6 +1224,13 @@ string_view mirrorWorldEntranceDesc = "Different entrances to the same region string_view mirrorWorldRandomDesc = "Whether the world is mirrored may change after\n" // "every loading zone inconsistently."; // /*------------------------------ // +| SOLD OUT COSMETIC SHOP MODEL | // +------------------------------*/ // +string_view betaSoldOutDesc = "The game contains an unused model for sold out\n" // + "items in shops. It's a remade version of the N64\n" + "model, spelling \"Sold Out\" in English.\n\n" // + "This setting enables its use in shops."; // +/*------------------------------ // | SHUFFLE MUSIC | // ------------------------------*/ // string_view musicRandoDesc = "Randomize the music in the game."; // diff --git a/source/descriptions.hpp b/source/descriptions.hpp index 1c97483a..d8b1896a 100644 --- a/source/descriptions.hpp +++ b/source/descriptions.hpp @@ -112,6 +112,10 @@ extern string_view scarceHeartsDesc; extern string_view mqDungeonCountDesc; extern string_view setDungeonTypesDesc; +extern string_view triforceHuntDesc; +extern string_view triforcePiecesTotalDesc; +extern string_view triforcePiecesRequiredDesc; + extern string_view shuffleRewardsEndOfDungeon; extern string_view shuffleRewardsAnyDungeon; extern string_view shuffleRewardsOverworld; @@ -168,6 +172,10 @@ extern string_view adultTradeDesc; extern string_view chestMinigameDesc; +extern string_view enemySoulDesc; + +extern string_view ocarinaButtonsDesc; + extern string_view mapCompassStartWith; extern string_view mapCompassVanilla; extern string_view mapCompassOwnDungeon; @@ -267,6 +275,7 @@ extern string_view totAltarHintsDesc; extern string_view ganonHintsDesc; extern string_view dampeHintDesc; extern string_view skulltulaHintDesc; +extern string_view fishingHintsDesc; extern string_view compassesShowRewardsDesc; extern string_view compassesShowWotHDesc; @@ -371,6 +380,8 @@ extern string_view mirrorWorldSceneDesc; extern string_view mirrorWorldEntranceDesc; extern string_view mirrorWorldRandomDesc; +extern string_view betaSoldOutDesc; + extern string_view musicRandoDesc; extern string_view shuffleBGMDesc; extern string_view shuffleMelodiesDesc; diff --git a/source/hint_list/hint_list_item.cpp b/source/hint_list/hint_list_item.cpp index 2d902a30..442d35cf 100644 --- a/source/hint_list/hint_list_item.cpp +++ b/source/hint_list/hint_list_item.cpp @@ -1956,4 +1956,472 @@ void HintTable_Init_Item() { // Text{"An Error (Please Report This)", /*french*/"une erreur (signaler S.V.P.)", /*spanish*/"un error (repórtelo si es posible)", /*italian*/"un errore (segnalalo per favore)", /*german*/"ein Fehler (Bitte melden)"} // } // ); + + hintTable[SOUL_ITEM_POE] = HintText::Item({ + // obscure text + Text{"the Soul of all Poes", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Poo", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_OCTOROK] = HintText::Item({ + // obscure text + Text{"the Octorok Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Octorok", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_KEESE] = HintText::Item({ + // obscure text + Text{"the Keese Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Pipistrello", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_TEKTITE] = HintText::Item({ + // obscure text + Text{"the Tektite Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Tektite", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_LEEVER] = HintText::Item({ + // obscure text + Text{"the Leever Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Leever", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_PEAHAT] = HintText::Item({ + // obscure text + Text{"the Peahat Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Bulbocottero", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_LIZALFOS] = HintText::Item({ + // obscure text + Text{"the Lizalfos and Dinolfos Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Lizalfos e Dinolfos", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_SHABOM] = HintText::Item({ + // obscure text + Text{"the Shabom Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Shabom", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_BIRI_BARI] = HintText::Item({ + // obscure text + Text{"the Biri and Bari Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Cnidiri e Cnidari", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_TAILPASARAN] = HintText::Item({ + // obscure text + Text{"the Tailpasaran Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Trivolt", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_SKULLTULA] = HintText::Item({ + // obscure text + Text{"the Skulltula Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Aracnula", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_TORCH_SLUG] = HintText::Item({ + // obscure text + Text{"the Torch Slug Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Lumaca di lava", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_STINGER] = HintText::Item({ + // obscure text + Text{"the Stinger Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Trigone volante", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_MOBLIN] = HintText::Item({ + // obscure text + Text{"the Moblin Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Grublin", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_ARMOS] = HintText::Item({ + // obscure text + Text{"the Armos Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Armos", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_DEKU_BABA] = HintText::Item({ + // obscure text + Text{"the Deku Baba Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Deku Baba", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_BUBBLE] = HintText::Item({ + // obscure text + Text{"the Bubble Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Nembo", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_FLYING_TRAP] = HintText::Item({ + // obscure text + Text{"the Flying Pot & Tile Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Vaso e Piastrella volante", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_BEAMOS] = HintText::Item({ + // obscure text + Text{"the Beamos Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Laseros", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_WALLMASTER] = HintText::Item({ + // obscure text + Text{"the Wallmaster & Floormaster Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Mano Diabolica e Mano Rapace", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_REDEAD_GIBDO] = HintText::Item({ + // obscure text + Text{"the Redead and Gibdo Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Zombie e Ghibdo", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_SHELL_BLADE] = HintText::Item({ + // obscure text + Text{"the Shell Blade Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Ostrice", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_LIKE_LIKE] = HintText::Item({ + // obscure text + Text{"the Like Like Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Like Like", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_TENTACLE] = HintText::Item({ + // obscure text + Text{"the Parasitic Tentacle Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Tentacolo", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_ANUBIS] = HintText::Item({ + // obscure text + Text{"the Anubis Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Anubi", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_SPIKE] = HintText::Item({ + // obscure text + Text{"the Spike Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Riccio di Ferro", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_SKULL_KID] = HintText::Item({ + // obscure text + Text{"the Skull Kid Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Bimbo Perduto", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_FREEZARD] = HintText::Item({ + // obscure text + Text{"the Freezard Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Freezard", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_DEKU_SCRUB] = HintText::Item({ + // obscure text + Text{"the Deku Scrub Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Cespuglio Deku", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_WOLFOS] = HintText::Item({ + // obscure text + Text{"the Wolfos Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Lupo", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_STALCHILD] = HintText::Item({ + // obscure text + Text{"the Stalchild Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Stalfosso", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_GUAY] = HintText::Item({ + // obscure text + Text{"the Guay Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Corvacchia", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_DOOR_MIMIC] = HintText::Item({ + // obscure text + Text{"the Door Mimic Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Porta ingannevole", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_STALFOS] = HintText::Item({ + // obscure text + Text{"the Stalfos Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Stalfos", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_DARK_LINK] = HintText::Item({ + // obscure text + Text{"the Dark Link Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Link Oscuro", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_FLARE_DANCER] = HintText::Item({ + // obscure text + Text{"the Flare Dancer Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Fiammerino", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_DEAD_HAND] = HintText::Item({ + // obscure text + Text{"the Dead Hand Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Smaniosso", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_GERUDO] = HintText::Item({ + // obscure text + Text{"the Gerudo Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Gerudo", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_GOHMA] = HintText::Item({ + // obscure text + Text{"the Gohma Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Gohma", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_DODONGO] = HintText::Item({ + // obscure text + Text{"the Dodongo Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Dodongo", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_BARINADE] = HintText::Item({ + // obscure text + Text{"the Barinade Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Cnidade", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_PHANTOM_GANON] = HintText::Item({ + // obscure text + Text{"the Phantom Ganon Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Spettro Ganon", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_VOLVAGIA] = HintText::Item({ + // obscure text + Text{"the Volvagia Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Varubaja", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_MORPHA] = HintText::Item({ + // obscure text + Text{"the Morpha Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Morpha", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_BONGO_BONGO] = HintText::Item({ + // obscure text + Text{"the Bongo Bongo Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Bongo Bongo", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_TWINROVA] = HintText::Item({ + // obscure text + Text{"the Twinrova Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Duerova", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[SOUL_ITEM_GANON] = HintText::Item({ + // obscure text + Text{"the Ganon Soul", /*french*/"", /*spanish*/"", /*italian*/"l'anima di Ganon", /*german*/""}, + }, { + // ambiguous text + Text{"a Soul", /*french*/"", /*spanish*/"", /*italian*/"un'anima", /*german*/""}, + } + ); + + hintTable[OCA_BUTTON_ITEM_L] = HintText::Item({ + // obscure text + Text{"the Ocarina L Button", /*french*/"", /*spanish*/"", /*italian*/"il pulsante L dell'ocarina", /*german*/""}, + }, { + // ambiguous text + Text{"something to play songs", /*french*/"", /*spanish*/"", /*italian*/"qualcosa per suonare melodie", /*german*/""}, + } + ); + + hintTable[OCA_BUTTON_ITEM_R] = HintText::Item({ + // obscure text + Text{"the Ocarina R Button", /*french*/"", /*spanish*/"", /*italian*/"il pulsante R dell'ocarina", /*german*/""}, + }, { + // ambiguous text + Text{"something to play songs", /*french*/"", /*spanish*/"", /*italian*/"qualcosa per suonare melodie", /*german*/""}, + } + ); + + hintTable[OCA_BUTTON_ITEM_X] = HintText::Item({ + // obscure text + Text{"the Ocarina X Button", /*french*/"", /*spanish*/"", /*italian*/"il pulsante X dell'ocarina", /*german*/""}, + }, { + // ambiguous text + Text{"something to play songs", /*french*/"", /*spanish*/"", /*italian*/"qualcosa per suonare melodie", /*german*/""}, + } + ); + + hintTable[OCA_BUTTON_ITEM_Y] = HintText::Item({ + // obscure text + Text{"the Ocarina Y Button", /*french*/"", /*spanish*/"", /*italian*/"il pulsante Y dell'ocarina", /*german*/""}, + }, { + // ambiguous text + Text{"something to play songs", /*french*/"", /*spanish*/"", /*italian*/"qualcosa per suonare melodie", /*german*/""}, + } + ); + + hintTable[OCA_BUTTON_ITEM_A] = HintText::Item({ + // obscure text + Text{"the Ocarina A Button", /*french*/"", /*spanish*/"", /*italian*/"il pulsante A dell'ocarina", /*german*/""}, + }, { + // ambiguous text + Text{"something to play songs", /*french*/"", /*spanish*/"", /*italian*/"qualcosa per suonare melodie", /*german*/""}, + } + ); } diff --git a/source/hints.cpp b/source/hints.cpp index 8f9a336c..27b194b0 100644 --- a/source/hints.cpp +++ b/source/hints.cpp @@ -727,6 +727,9 @@ static Text BuildGanonBossKeyText() { } else if (GanonsBossKey.Is(GANONSBOSSKEY_ANYWHERE)) { ganonBossKeyText = Hint(GANON_BK_ANYWHERE_HINT).GetText(); + } else if (GanonsBossKey.Is(GANONSBOSSKEY_TRIFORCE)) { + ganonBossKeyText = Hint(GANON_BK_TRIFORCE_HINT).GetText(); + } else if (GanonsBossKey.Is(GANONSBOSSKEY_LACS_VANILLA)) { ganonBossKeyText = Hint(LACS_VANILLA_HINT).GetText(); diff --git a/source/item.hpp b/source/item.hpp index 3315132d..7299e143 100644 --- a/source/item.hpp +++ b/source/item.hpp @@ -23,7 +23,8 @@ enum ItemType { ITEMTYPE_REFILL, ITEMTYPE_SONG, ITEMTYPE_SHOP, - ITEMTYPE_DUNGEONREWARD + ITEMTYPE_DUNGEONREWARD, + ITEMTYPE_ENEMY_SOUL, }; class Item { diff --git a/source/item_list.cpp b/source/item_list.cpp index 1de7637c..88fed20c 100644 --- a/source/item_list.cpp +++ b/source/item_list.cpp @@ -96,18 +96,18 @@ void ItemTable_Init() { //Item Type itemTable[BOTTLE_WITH_BIG_POE] = Item(ITEMTYPE_ITEM, 0x93, true, &BottleWithBigPoe, BOTTLE_WITH_BIG_POE, Text{"Bottle with Big Poe", "Flacon avec une Âme", "Gran Poe en una botella", "Grande Poo in un'ampolla", "Flasche (Nachtschwärmer)"}); // Songs - itemTable[ZELDAS_LULLABY] = Item(ITEMTYPE_SONG, 0xC1, true, &ZeldasLullaby, ZELDAS_LULLABY, Text{"Zelda's Lullaby", "Berceuse de Zelda", "Nana de Zelda", "Ninna nanna di Zelda", "Zeldas Wiegenlied"}); - itemTable[EPONAS_SONG] = Item(ITEMTYPE_SONG, 0xC2, true, &EponasSong, EPONAS_SONG, Text{"Epona's Song", "Chant d'Épona", "Canción de Epona", "Canzone di Epona", "Eponas Lied"}); - itemTable[SARIAS_SONG] = Item(ITEMTYPE_SONG, 0xC3, true, &SariasSong, SARIAS_SONG, Text{"Saria's Song", "Chant de Saria", "Canción de Saria", "Canzone di Saria", "Salias Lied"}); - itemTable[SUNS_SONG] = Item(ITEMTYPE_SONG, 0xC4, true, &SunsSong, SUNS_SONG, Text{"Sun's Song", "Chant du soleil", "Canción del Sol", "Canto del sole", "Hymne der Sonne"}); - itemTable[SONG_OF_TIME] = Item(ITEMTYPE_SONG, 0xC5, true, &SongOfTime, SONG_OF_TIME, Text{"Song of Time", "Chant du temps", "Canción del tiempo", "Canzone del tempo", "Hymne der Zeit"}); - itemTable[SONG_OF_STORMS] = Item(ITEMTYPE_SONG, 0xC6, true, &SongOfStorms, SONG_OF_STORMS, Text{"Song of Storms", "Chant des tempêtes", "Canción de la tormenta", "Canzone della tempesta", "Hymne des Sturms"}); - itemTable[MINUET_OF_FOREST] = Item(ITEMTYPE_SONG, 0xBB, true, &MinuetOfForest, MINUET_OF_FOREST, Text{"Minuet of Forest", "Menuet de la forêt", "Minueto del bosque", "Minuetto della foresta", "Menuett des Waldes"}); - itemTable[BOLERO_OF_FIRE] = Item(ITEMTYPE_SONG, 0xBC, true, &BoleroOfFire, BOLERO_OF_FIRE, Text{"Bolero of Fire", "Boléro du feu", "Bolero del fuego", "Bolero del fuoco", "Bolero des Feuers"}); - itemTable[SERENADE_OF_WATER] = Item(ITEMTYPE_SONG, 0xBD, true, &SerenadeOfWater, SERENADE_OF_WATER, Text{"Serenade of Water", "Sérénade de l'eau", "Serenata del agua", "Serenata dell'acqua", "Serenade des Wassers"}); - itemTable[REQUIEM_OF_SPIRIT] = Item(ITEMTYPE_SONG, 0xBE, true, &RequiemOfSpirit, REQUIEM_OF_SPIRIT, Text{"Requiem of Spirit", "Requiem des esprits", "Réquiem del espíritu", "Requiem dello spirito", "Requiem der Geister"}); - itemTable[NOCTURNE_OF_SHADOW] = Item(ITEMTYPE_SONG, 0xBF, true, &NocturneOfShadow, NOCTURNE_OF_SHADOW, Text{"Nocturne of Shadow", "Nocturne de l'ombre", "Nocturno de la sombra", "Notturno delle ombre", "Nocturne des Schattens"}); - itemTable[PRELUDE_OF_LIGHT] = Item(ITEMTYPE_SONG, 0xC0, true, &PreludeOfLight, PRELUDE_OF_LIGHT, Text{"Prelude of Light", "Prélude de la lumière", "Preludio de la luz", "Preludio della luce", "Kantate des Lichts"}); + itemTable[ZELDAS_LULLABY] = Item(ITEMTYPE_SONG, 0xC1, true, &ZeldasLullaby_item, ZELDAS_LULLABY, Text{"Zelda's Lullaby", "Berceuse de Zelda", "Nana de Zelda", "Ninna nanna di Zelda", "Zeldas Wiegenlied"}); + itemTable[EPONAS_SONG] = Item(ITEMTYPE_SONG, 0xC2, true, &EponasSong_item, EPONAS_SONG, Text{"Epona's Song", "Chant d'Épona", "Canción de Epona", "Canzone di Epona", "Eponas Lied"}); + itemTable[SARIAS_SONG] = Item(ITEMTYPE_SONG, 0xC3, true, &SariasSong_item, SARIAS_SONG, Text{"Saria's Song", "Chant de Saria", "Canción de Saria", "Canzone di Saria", "Salias Lied"}); + itemTable[SUNS_SONG] = Item(ITEMTYPE_SONG, 0xC4, true, &SunsSong_item, SUNS_SONG, Text{"Sun's Song", "Chant du soleil", "Canción del Sol", "Canto del sole", "Hymne der Sonne"}); + itemTable[SONG_OF_TIME] = Item(ITEMTYPE_SONG, 0xC5, true, &SongOfTime_item, SONG_OF_TIME, Text{"Song of Time", "Chant du temps", "Canción del tiempo", "Canzone del tempo", "Hymne der Zeit"}); + itemTable[SONG_OF_STORMS] = Item(ITEMTYPE_SONG, 0xC6, true, &SongOfStorms_item, SONG_OF_STORMS, Text{"Song of Storms", "Chant des tempêtes", "Canción de la tormenta", "Canzone della tempesta", "Hymne des Sturms"}); + itemTable[MINUET_OF_FOREST] = Item(ITEMTYPE_SONG, 0xBB, true, &MinuetOfForest_item, MINUET_OF_FOREST, Text{"Minuet of Forest", "Menuet de la forêt", "Minueto del bosque", "Minuetto della foresta", "Menuett des Waldes"}); + itemTable[BOLERO_OF_FIRE] = Item(ITEMTYPE_SONG, 0xBC, true, &BoleroOfFire_item, BOLERO_OF_FIRE, Text{"Bolero of Fire", "Boléro du feu", "Bolero del fuego", "Bolero del fuoco", "Bolero des Feuers"}); + itemTable[SERENADE_OF_WATER] = Item(ITEMTYPE_SONG, 0xBD, true, &SerenadeOfWater_item, SERENADE_OF_WATER, Text{"Serenade of Water", "Sérénade de l'eau", "Serenata del agua", "Serenata dell'acqua", "Serenade des Wassers"}); + itemTable[REQUIEM_OF_SPIRIT] = Item(ITEMTYPE_SONG, 0xBE, true, &RequiemOfSpirit_item, REQUIEM_OF_SPIRIT, Text{"Requiem of Spirit", "Requiem des esprits", "Réquiem del espíritu", "Requiem dello spirito", "Requiem der Geister"}); + itemTable[NOCTURNE_OF_SHADOW] = Item(ITEMTYPE_SONG, 0xBF, true, &NocturneOfShadow_item, NOCTURNE_OF_SHADOW, Text{"Nocturne of Shadow", "Nocturne de l'ombre", "Nocturno de la sombra", "Notturno delle ombre", "Nocturne des Schattens"}); + itemTable[PRELUDE_OF_LIGHT] = Item(ITEMTYPE_SONG, 0xC0, true, &PreludeOfLight_item, PRELUDE_OF_LIGHT, Text{"Prelude of Light", "Prélude de la lumière", "Preludio de la luz", "Preludio della luce", "Kantate des Lichts"}); // Maps and Compasses itemTable[DEKU_TREE_MAP] = Item(ITEMTYPE_MAP, 0xA5, false, &noVariable, DEKU_TREE_MAP, Text{"Great Deku Tree Map", "Carte de l'arbre Mojo", "Mapa del Gran Árbol Deku", "Mappa del Grande Albero Deku", "Labyrinth-Karte des Deku-Baumes"}); @@ -242,6 +242,64 @@ void ItemTable_Init() { //Item Type itemTable[BUY_RED_POTION_40] = Item(ITEMTYPE_SHOP, 0x30, false, &noVariable, BOTTLE_WITH_RED_POTION, 40, Text{"Buy Red Potion [40]", "Acheter: Potion rouge [40]", "Comprar poción roja [40]", "Pozione vita in vendita [40]", "Rotes Elixier [40]"}); itemTable[BUY_RED_POTION_50] = Item(ITEMTYPE_SHOP, 0x31, false, &noVariable, BOTTLE_WITH_RED_POTION, 50, Text{"Buy Red Potion [50]", "Acheter: Potion rouge [50]", "Comprar poción roja [50]", "Pozione vita in vendita [50]", "Rotes Elixier [50]"}); + // Enemy souls + itemTable[SOUL_ITEM_POE] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_POE, true, &SoulPoe, SOUL_ITEM_POE, Text{"Poe Soul", "", "", "Anima di Poo", ""}); + itemTable[SOUL_ITEM_OCTOROK] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_OCTOROK, true, &SoulOctorok, SOUL_ITEM_OCTOROK, Text{"Octorok Soul", "", "", "Anima di Octorok", ""}); + itemTable[SOUL_ITEM_KEESE] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_KEESE, true, &SoulKeese, SOUL_ITEM_KEESE, Text{"Keese Soul", "", "", "Anima di Pipistrello", ""}); + itemTable[SOUL_ITEM_TEKTITE] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_TEKTITE, false, &noVariable, SOUL_ITEM_TEKTITE, Text{"Tektite Soul", "", "", "Anima di Tektite", ""}); + itemTable[SOUL_ITEM_LEEVER] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_LEEVER, false, &noVariable, SOUL_ITEM_LEEVER, Text{"Leever Soul", "", "", "Anima di Leever", ""}); + itemTable[SOUL_ITEM_PEAHAT] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_PEAHAT, false, &noVariable, SOUL_ITEM_PEAHAT, Text{"Peahat Soul", "", "", "Anima di Bulbocottero", ""}); + itemTable[SOUL_ITEM_LIZALFOS] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_LIZALFOS, true, &SoulLizalfosDinolfos, SOUL_ITEM_LIZALFOS, Text{"Lizalfos and Dinolfos Soul", "", "", "Anima di Lizalfos e Dinolfos", ""}); + itemTable[SOUL_ITEM_SHABOM] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_SHABOM, true, &SoulShabom, SOUL_ITEM_SHABOM, Text{"Shabom Soul", "", "", "Anima di Shabom", ""}); + itemTable[SOUL_ITEM_BIRI_BARI] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_BIRI_BARI, false, &noVariable, SOUL_ITEM_BIRI_BARI, Text{"Biri and Bari Soul", "", "", "Anima di Cnidiri e Cnidari", ""}); + itemTable[SOUL_ITEM_TAILPASARAN] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_TAILPASARAN, false, &noVariable, SOUL_ITEM_TAILPASARAN, Text{"Tailpasaran Soul", "", "", "Anima di Trivolt", ""}); + itemTable[SOUL_ITEM_SKULLTULA] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_SKULLTULA, true, &SoulSkulltula, SOUL_ITEM_SKULLTULA, Text{"Skulltula Soul", "", "", "Anima di Aracnula", ""}); + itemTable[SOUL_ITEM_TORCH_SLUG] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_TORCH_SLUG, true, &SoulTorchSlug, SOUL_ITEM_TORCH_SLUG, Text{"Torch Slug Soul", "", "", "Anima di Lumaca di lava", ""}); + itemTable[SOUL_ITEM_STINGER] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_STINGER, true, &SoulStinger, SOUL_ITEM_STINGER, Text{"Stinger Soul", "", "", "Anima di Trigone volante", ""}); + itemTable[SOUL_ITEM_MOBLIN] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_MOBLIN, true, &SoulMoblin, SOUL_ITEM_MOBLIN, Text{"Moblin Soul", "", "", "Anima di Grublin", ""}); + itemTable[SOUL_ITEM_ARMOS] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_ARMOS, true, &SoulArmos, SOUL_ITEM_ARMOS, Text{"Armos Soul", "", "", "Anima di Armos", ""}); + itemTable[SOUL_ITEM_DEKU_BABA] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_DEKU_BABA, true, &SoulDekuBaba, SOUL_ITEM_DEKU_BABA, Text{"Deku Baba Soul", "", "", "Anima di Deku Baba", ""}); + itemTable[SOUL_ITEM_BUBBLE] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_BUBBLE, true, &SoulBubble, SOUL_ITEM_BUBBLE, Text{"Bubble Soul", "", "", "Anima di Nembo", ""}); + itemTable[SOUL_ITEM_FLYING_TRAP] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_FLYING_TRAP, true, &SoulFlyingTrap, SOUL_ITEM_FLYING_TRAP, Text{"Flying Pot & Tile Soul", "", "", "Anima di Vaso e Piastrella volante", ""}); + itemTable[SOUL_ITEM_BEAMOS] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_BEAMOS, true, &SoulBeamos, SOUL_ITEM_BEAMOS, Text{"Beamos Soul", "", "", "Anima di Laseros", ""}); + itemTable[SOUL_ITEM_WALLMASTER] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_WALLMASTER, true, &SoulWallmaster, SOUL_ITEM_WALLMASTER, Text{"Wallmaster & Floormaster Soul", "", "", "Anima di Mano Diabolica e Mano Rapace", ""}); + itemTable[SOUL_ITEM_REDEAD_GIBDO] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_REDEAD_GIBDO, true, &SoulRedeadGibdo, SOUL_ITEM_REDEAD_GIBDO, Text{"Redead and Gibdo Soul", "", "", "Anima di Zombie e Ghibdo", ""}); + itemTable[SOUL_ITEM_SHELL_BLADE] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_SHELL_BLADE, true, &SoulShellBlade, SOUL_ITEM_SHELL_BLADE, Text{"Shell Blade Soul", "", "", "Anima di Ostrice", ""}); + itemTable[SOUL_ITEM_LIKE_LIKE] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_LIKE_LIKE, true, &SoulLikeLike, SOUL_ITEM_LIKE_LIKE, Text{"Like Like Soul", "", "", "Anima di Like Like", ""}); + itemTable[SOUL_ITEM_TENTACLE] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_TENTACLE, true, &SoulParasiticTentacle, SOUL_ITEM_TENTACLE, Text{"Parasitic Tentacle Soul", "", "", "Anima di Tentacolo", ""}); + itemTable[SOUL_ITEM_ANUBIS] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_ANUBIS, true, &SoulAnubis, SOUL_ITEM_ANUBIS, Text{"Anubis Soul", "", "", "Anima di Anubi", ""}); + itemTable[SOUL_ITEM_SPIKE] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_SPIKE, true, &SoulSpike, SOUL_ITEM_SPIKE, Text{"Spike Soul", "", "", "Anima di Riccio di Ferro", ""}); + itemTable[SOUL_ITEM_SKULL_KID] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_SKULL_KID, false, &noVariable, SOUL_ITEM_SKULL_KID, Text{"Skull Kid Soul", "", "", "Anima di Bimbo Perduto", ""}); + itemTable[SOUL_ITEM_FREEZARD] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_FREEZARD, true, &SoulFreezard, SOUL_ITEM_FREEZARD, Text{"Freezard Soul", "", "", "Anima di Freezard", ""}); + itemTable[SOUL_ITEM_DEKU_SCRUB] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_DEKU_SCRUB, true, &SoulDekuScrub, SOUL_ITEM_DEKU_SCRUB, Text{"Deku Scrub Soul", "", "", "Anima di Cespuglio Deku", ""}); + itemTable[SOUL_ITEM_WOLFOS] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_WOLFOS, true, &SoulWolfos, SOUL_ITEM_WOLFOS, Text{"Wolfos Soul", "", "", "Anima di Lupo", ""}); + itemTable[SOUL_ITEM_STALCHILD] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_STALCHILD, false, &noVariable, SOUL_ITEM_STALCHILD, Text{"Stalchild Soul", "", "", "Anima di Stalfosso", ""}); + itemTable[SOUL_ITEM_GUAY] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_GUAY, false, &noVariable, SOUL_ITEM_GUAY, Text{"Guay Soul", "", "", "Anima di Corvacchia", ""}); + itemTable[SOUL_ITEM_DOOR_MIMIC] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_DOOR_MIMIC, true, &SoulDoorMimic, SOUL_ITEM_DOOR_MIMIC, Text{"Door Mimic Soul", "", "", "Anima di Porta ingannevole", ""}); + itemTable[SOUL_ITEM_STALFOS] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_STALFOS, true, &SoulStalfos, SOUL_ITEM_STALFOS, Text{"Stalfos Soul", "", "", "Anima di Stalfos", ""}); + itemTable[SOUL_ITEM_DARK_LINK] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_DARK_LINK, true, &SoulDarkLink, SOUL_ITEM_DARK_LINK, Text{"Dark Link Soul", "", "", "Anima di Link Oscuro", ""}); + itemTable[SOUL_ITEM_FLARE_DANCER] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_FLARE_DANCER, true, &SoulFlareDancer, SOUL_ITEM_FLARE_DANCER, Text{"Flare Dancer Soul", "", "", "Anima di Fiammerino", ""}); + itemTable[SOUL_ITEM_DEAD_HAND] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_DEAD_HAND, true, &SoulDeadHand, SOUL_ITEM_DEAD_HAND, Text{"Dead Hand Soul", "", "", "Anima di Smaniosso", ""}); + itemTable[SOUL_ITEM_GERUDO] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_GERUDO, true, &SoulGerudo, SOUL_ITEM_GERUDO, Text{"Gerudo Soul", "", "", "Anima di Gerudo", ""}); + itemTable[SOUL_ITEM_GOHMA] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_GOHMA, true, &SoulGohma, SOUL_ITEM_GOHMA, Text{"Gohma Soul", "", "", "Anima di Gohma", ""}); + itemTable[SOUL_ITEM_DODONGO] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_DODONGO, true, &SoulDodongo, SOUL_ITEM_DODONGO, Text{"Dodongo Soul", "", "", "Anima di Dodongo", ""}); + itemTable[SOUL_ITEM_BARINADE] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_BARINADE, true, &SoulBarinade, SOUL_ITEM_BARINADE, Text{"Barinade Soul", "", "", "Anima di Cnidade", ""}); + itemTable[SOUL_ITEM_PHANTOM_GANON] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_PHANTOM_GANON,true, &SoulPhantomGanon, SOUL_ITEM_PHANTOM_GANON, Text{"Phantom Ganon Soul", "", "", "Anima di Spettro Ganon", ""}); + itemTable[SOUL_ITEM_VOLVAGIA] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_VOLVAGIA, true, &SoulVolvagia, SOUL_ITEM_VOLVAGIA, Text{"Volvagia Soul", "", "", "Anima di Varubaja", ""}); + itemTable[SOUL_ITEM_MORPHA] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_MORPHA, true, &SoulMorpha, SOUL_ITEM_MORPHA, Text{"Morpha Soul", "", "", "Anima di Morpha", ""}); + itemTable[SOUL_ITEM_BONGO_BONGO] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_BONGO_BONGO, true, &SoulBongoBongo, SOUL_ITEM_BONGO_BONGO, Text{"Bongo Bongo Soul", "", "", "Anima di Bongo Bongo", ""}); + itemTable[SOUL_ITEM_TWINROVA] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_TWINROVA, true, &SoulTwinrova, SOUL_ITEM_TWINROVA, Text{"Twinrova Soul", "", "", "Anima di Duerova", ""}); + itemTable[SOUL_ITEM_GANON] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_GANON, true, &SoulGanon, SOUL_ITEM_GANON, Text{"Ganon Soul", "", "", "Anima di Ganon", ""}); + + // Ocarina Note Buttons + itemTable[OCA_BUTTON_ITEM_L] = Item(ITEMTYPE_ITEM, GI_OCARINA_BUTTON_L, true, &OcarinaButtonL, OCA_BUTTON_ITEM_L, Text{"Ocarina L Button", "", "", "Pulsante L dell'ocarina", ""}); + itemTable[OCA_BUTTON_ITEM_R] = Item(ITEMTYPE_ITEM, GI_OCARINA_BUTTON_R, true, &OcarinaButtonR, OCA_BUTTON_ITEM_R, Text{"Ocarina R Button", "", "", "Pulsante R dell'ocarina", ""}); + itemTable[OCA_BUTTON_ITEM_X] = Item(ITEMTYPE_ITEM, GI_OCARINA_BUTTON_X, true, &OcarinaButtonX, OCA_BUTTON_ITEM_X, Text{"Ocarina X Button", "", "", "Pulsante X dell'ocarina", ""}); + itemTable[OCA_BUTTON_ITEM_Y] = Item(ITEMTYPE_ITEM, GI_OCARINA_BUTTON_Y, true, &OcarinaButtonY, OCA_BUTTON_ITEM_Y, Text{"Ocarina Y Button", "", "", "Pulsante Y dell'ocarina", ""}); + itemTable[OCA_BUTTON_ITEM_A] = Item(ITEMTYPE_ITEM, GI_OCARINA_BUTTON_A, true, &OcarinaButtonA, OCA_BUTTON_ITEM_A, Text{"Ocarina A Button", "", "", "Pulsante A dell'ocarina", ""}); + + itemTable[TRIFORCE_PIECE] = Item(ITEMTYPE_ITEM, GI_TRIFORCE_PIECE, true, &TriforcePieces, TRIFORCE_PIECE, Text{"Triforce Piece", "Fragment de la Triforce", "Fragmento de la Trifuerza", "Frammento di Triforza", "Triforce-Splitter"}); + itemTable[TRIFORCE] = Item(ITEMTYPE_EVENT, GI_RUPEE_RED_LOSE, false, &noVariable, NONE, Text{"Triforce", "Triforce", "Trifuerza", "Triforza", "Triforce"}); itemTable[HINT] = Item(ITEMTYPE_EVENT, GI_RUPEE_BLUE_LOSE, false, &noVariable, NONE, Text{"Hint", "Indice", "Pista", "Indizio", "Hinweis"}); @@ -288,4 +346,4 @@ void NewItem(const ItemKey itemKey, const Item item) { } itemTable[itemKey] = item; -} \ No newline at end of file +} diff --git a/source/item_pool.cpp b/source/item_pool.cpp index 3cb3854e..e96b7d8e 100644 --- a/source/item_pool.cpp +++ b/source/item_pool.cpp @@ -254,6 +254,22 @@ const std::array tradeItems = { EYEDROPS, CLAIM_CHECK, }; +const std::array enemySouls = { + SOUL_ITEM_POE, SOUL_ITEM_OCTOROK, SOUL_ITEM_KEESE, SOUL_ITEM_TEKTITE, SOUL_ITEM_LEEVER, + SOUL_ITEM_PEAHAT, SOUL_ITEM_LIZALFOS, SOUL_ITEM_SHABOM, SOUL_ITEM_BIRI_BARI, SOUL_ITEM_TAILPASARAN, + SOUL_ITEM_SKULLTULA, SOUL_ITEM_TORCH_SLUG, SOUL_ITEM_STINGER, SOUL_ITEM_MOBLIN, SOUL_ITEM_ARMOS, + SOUL_ITEM_DEKU_BABA, SOUL_ITEM_BUBBLE, SOUL_ITEM_FLYING_TRAP, SOUL_ITEM_BEAMOS, SOUL_ITEM_WALLMASTER, + SOUL_ITEM_REDEAD_GIBDO, SOUL_ITEM_SHELL_BLADE, SOUL_ITEM_LIKE_LIKE, SOUL_ITEM_TENTACLE, SOUL_ITEM_ANUBIS, + SOUL_ITEM_SPIKE, SOUL_ITEM_SKULL_KID, SOUL_ITEM_FREEZARD, SOUL_ITEM_DEKU_SCRUB, SOUL_ITEM_WOLFOS, + SOUL_ITEM_STALCHILD, SOUL_ITEM_GUAY, SOUL_ITEM_DOOR_MIMIC, SOUL_ITEM_STALFOS, SOUL_ITEM_DARK_LINK, + SOUL_ITEM_FLARE_DANCER, SOUL_ITEM_DEAD_HAND, SOUL_ITEM_GERUDO, SOUL_ITEM_GOHMA, SOUL_ITEM_DODONGO, + SOUL_ITEM_BARINADE, SOUL_ITEM_PHANTOM_GANON, SOUL_ITEM_VOLVAGIA, SOUL_ITEM_MORPHA, SOUL_ITEM_BONGO_BONGO, + SOUL_ITEM_TWINROVA, SOUL_ITEM_GANON, +}; + +const std::array ocarinaNoteButtons = { + OCA_BUTTON_ITEM_L, OCA_BUTTON_ITEM_R, OCA_BUTTON_ITEM_X, OCA_BUTTON_ITEM_Y, OCA_BUTTON_ITEM_A, +}; void AddItemToPool(std::vector& pool, ItemKey item, size_t count /*= 1*/) { pool.insert(pool.end(), count, item); @@ -740,6 +756,11 @@ void GenerateItemPool() { } } + if (TriforceHunt) { + AddItemToMainPool(TRIFORCE_PIECE, TriforcePiecesTotal.Value() + 1); + IceTrapModels.push_back(GI_TRIFORCE_PIECE); + } + if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) { if (ShuffleGerudoToken) { AddItemToPool(PendingJunkPool, GERUDO_TOKEN); @@ -984,7 +1005,7 @@ void GenerateItemPool() { PlaceItemInLocation(TOT_LIGHT_ARROWS_CUTSCENE, GANONS_CASTLE_BOSS_KEY); } else if (GanonsBossKey.Is(GANONSBOSSKEY_VANILLA)) { PlaceItemInLocation(GANONS_TOWER_BOSS_KEY_CHEST, GANONS_CASTLE_BOSS_KEY); - } else { + } else if (GanonsBossKey.IsNot(GANONSBOSSKEY_TRIFORCE)) { AddItemToMainPool(GANONS_CASTLE_BOSS_KEY); } @@ -1010,6 +1031,20 @@ void GenerateItemPool() { IceTrapModels.push_back(GI_SWORD_BGS); } + if (ShuffleEnemySouls) { + AddItemsToPool(ItemPool, enemySouls); + if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) { + AddItemsToPool(PendingJunkPool, enemySouls); + } + } + + if (ShuffleOcarinaButtons) { + AddItemsToPool(ItemPool, ocarinaNoteButtons); + if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) { + AddItemsToPool(PendingJunkPool, ocarinaNoteButtons); + } + } + // Replace ice traps with junk from the pending junk pool if necessary if (IceTrapValue.Is(ICETRAPS_OFF)) { ReplaceMaxItem(ICE_TRAP, 0); diff --git a/source/keys.hpp b/source/keys.hpp index 956d226e..e687046a 100644 --- a/source/keys.hpp +++ b/source/keys.hpp @@ -242,6 +242,62 @@ typedef enum { BUY_RED_POTION_40, BUY_RED_POTION_50, + // ENEMY SOULS + SOUL_ITEM_POE, + SOUL_ITEM_OCTOROK, + SOUL_ITEM_KEESE, + SOUL_ITEM_TEKTITE, + SOUL_ITEM_LEEVER, + SOUL_ITEM_PEAHAT, + SOUL_ITEM_LIZALFOS, + SOUL_ITEM_SHABOM, + SOUL_ITEM_BIRI_BARI, + SOUL_ITEM_TAILPASARAN, + SOUL_ITEM_SKULLTULA, + SOUL_ITEM_TORCH_SLUG, + SOUL_ITEM_STINGER, + SOUL_ITEM_MOBLIN, + SOUL_ITEM_ARMOS, + SOUL_ITEM_DEKU_BABA, + SOUL_ITEM_BUBBLE, + SOUL_ITEM_FLYING_TRAP, + SOUL_ITEM_BEAMOS, + SOUL_ITEM_WALLMASTER, + SOUL_ITEM_REDEAD_GIBDO, + SOUL_ITEM_SHELL_BLADE, + SOUL_ITEM_LIKE_LIKE, + SOUL_ITEM_TENTACLE, + SOUL_ITEM_ANUBIS, + SOUL_ITEM_SPIKE, + SOUL_ITEM_SKULL_KID, + SOUL_ITEM_FREEZARD, + SOUL_ITEM_DEKU_SCRUB, + SOUL_ITEM_WOLFOS, + SOUL_ITEM_STALCHILD, + SOUL_ITEM_GUAY, + SOUL_ITEM_DOOR_MIMIC, + SOUL_ITEM_STALFOS, + SOUL_ITEM_DARK_LINK, + SOUL_ITEM_FLARE_DANCER, + SOUL_ITEM_DEAD_HAND, + SOUL_ITEM_GERUDO, + SOUL_ITEM_GOHMA, + SOUL_ITEM_DODONGO, + SOUL_ITEM_BARINADE, + SOUL_ITEM_PHANTOM_GANON, + SOUL_ITEM_VOLVAGIA, + SOUL_ITEM_MORPHA, + SOUL_ITEM_BONGO_BONGO, + SOUL_ITEM_TWINROVA, + SOUL_ITEM_GANON, + + // OCARINA NOTE BUTTONS + OCA_BUTTON_ITEM_L, + OCA_BUTTON_ITEM_R, + OCA_BUTTON_ITEM_X, + OCA_BUTTON_ITEM_Y, + OCA_BUTTON_ITEM_A, + // ITEMLOCATIONS // DUNGEON REWARDS diff --git a/source/location_access.cpp b/source/location_access.cpp index 247369cf..b162cf3e 100644 --- a/source/location_access.cpp +++ b/source/location_access.cpp @@ -251,11 +251,14 @@ void AreaTable_Init() { areaTable.fill(Area("Invalid Area", "Invalid Area", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {})); // name, scene, hint text, events, locations, exits - areaTable[ROOT] = Area("Root", "", LINKS_POCKET, NO_DAY_NIGHT_CYCLE, {}, - { // Locations - LocationAccess(LINKS_POCKET, { [] { return true; } }) }, - { // Exits - Entrance(ROOT_EXITS, { [] { return true; } }) }); + areaTable[ROOT] = + Area("Root", "", LINKS_POCKET, NO_DAY_NIGHT_CYCLE, {}, + { // Locations + LocationAccess(LINKS_POCKET, { [] { return true; } }), + LocationAccess( + GANON, { [] { return TriforceHunt && TriforcePieces >= TriforcePiecesTotal.Value() + 1; } }) }, + { // Exits + Entrance(ROOT_EXITS, { [] { return true; } }) }); areaTable[ROOT_EXITS] = Area("Root Exits", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, diff --git a/source/location_access.hpp b/source/location_access.hpp index e89ae814..28d35166 100644 --- a/source/location_access.hpp +++ b/source/location_access.hpp @@ -8,6 +8,7 @@ #include "hint_list.hpp" #include "keys.hpp" #include "fill.hpp" +#include "item_location.hpp" typedef bool (*ConditionFn)(); @@ -76,6 +77,9 @@ class LocationAccess { bool GetConditionsMet() const { if (Settings::Logic.Is(LOGIC_NONE) || Settings::Logic.Is(LOGIC_VANILLA)) { return true; + } else if ((!Logic::SoulSkulltula && Location(location)->IsCategory(Category::cSkulltula)) || + (!Logic::SoulDekuScrub && Location(location)->IsCategory(Category::cDekuScrub))) { + return false; } else if (Settings::Logic.Is(LOGIC_GLITCHLESS)) { return conditions_met[0](); } else if (Settings::Logic.Is(LOGIC_GLITCHED)) { diff --git a/source/location_access/locacc_bottom_of_the_well.cpp b/source/location_access/locacc_bottom_of_the_well.cpp index 129d7624..554fa7a0 100644 --- a/source/location_access/locacc_bottom_of_the_well.cpp +++ b/source/location_access/locacc_bottom_of_the_well.cpp @@ -14,8 +14,10 @@ void AreaTable_Init_BottomOfTheWell() { "Bottom of the Well Entryway", "Bottom of the Well", BOTTOM_OF_THE_WELL, NO_DAY_NIGHT_CYCLE, {}, {}, { // Exits - Entrance(BOTTOM_OF_THE_WELL_MAIN_AREA, - { [] { return Dungeon::BottomOfTheWell.IsVanilla() && IsChild && (CanChildAttack || Nuts); } }), + Entrance(BOTTOM_OF_THE_WELL_MAIN_AREA, { [] { + return Dungeon::BottomOfTheWell.IsVanilla() && IsChild && SoulSkulltula && + (CanChildAttack || Nuts); + } }), Entrance(BOTTOM_OF_THE_WELL_MQ_PERIMETER, { [] { return Dungeon::BottomOfTheWell.IsMQ() && IsChild; }, /*Glitched*/ [] { @@ -53,7 +55,8 @@ void AreaTable_Init_BottomOfTheWell() { { [] { return (LogicLensBotw || CanUse(LENS_OF_TRUTH)) && HasExplosives; } }), LocationAccess(BOTTOM_OF_THE_WELL_FREESTANDING_KEY, { [] { return Sticks || CanUse(DINS_FIRE); } }), LocationAccess(BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST, { [] { - return CanPlay(ZeldasLullaby) && (KokiriSword || (Sticks && LogicChildDeadhand)); + return SoulDeadHand && CanPlay(ZeldasLullaby) && + (KokiriSword || (Sticks && LogicChildDeadhand)); } }), LocationAccess(BOTTOM_OF_THE_WELL_INVISIBLE_CHEST, { [] { return CanPlay(ZeldasLullaby) && (LogicLensBotw || CanUse(LENS_OF_TRUTH)); } }), diff --git a/source/location_access/locacc_deku_tree.cpp b/source/location_access/locacc_deku_tree.cpp index a8c96f54..8d91c0d2 100644 --- a/source/location_access/locacc_deku_tree.cpp +++ b/source/location_access/locacc_deku_tree.cpp @@ -28,12 +28,13 @@ void AreaTable_Init_DekuTree() { { // Events EventAccess(&DekuBabaSticks, { [] { - return DekuBabaSticks || (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(BOOMERANG)); + return DekuBabaSticks || (SoulDekuBaba && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(BOOMERANG))); } }), EventAccess(&DekuBabaNuts, { [] { - return DekuBabaNuts || (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || - CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE)); + return DekuBabaNuts || + (SoulDekuBaba && (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || + CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE))); } }), }, { @@ -46,7 +47,10 @@ void AreaTable_Init_DekuTree() { Entrance(DEKU_TREE_2F_MIDDLE_ROOM, { [] { return true; } }), Entrance(DEKU_TREE_COMPASS_ROOM, { [] { return true; } }), Entrance(DEKU_TREE_BASEMENT_LOWER, { [] { - return Here(DEKU_TREE_LOBBY, [] { return CanAdultAttack || CanChildAttack || Nuts; }); + return Here(DEKU_TREE_LOBBY, [] { + return HasFireSourceWithTorch || + (SoulSkulltula && (CanAdultAttack || CanChildAttack || Nuts)); + }); } }), Entrance(DEKU_TREE_OUTSIDE_BOSS_ROOM, { [] { return false; }, @@ -61,17 +65,19 @@ void AreaTable_Init_DekuTree() { } }), }); - areaTable[DEKU_TREE_2F_MIDDLE_ROOM] = Area( - "Deku Tree 2F Middle Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, - { - // Exits - Entrance(DEKU_TREE_LOBBY, { [] { - return Here(DEKU_TREE_2F_MIDDLE_ROOM, [] { return HasShield || CanUse(MEGATON_HAMMER); }); - } }), - Entrance(DEKU_TREE_SLINGSHOT_ROOM, { [] { - return Here(DEKU_TREE_2F_MIDDLE_ROOM, [] { return HasShield || CanUse(MEGATON_HAMMER); }); - } }), - }); + areaTable[DEKU_TREE_2F_MIDDLE_ROOM] = + Area("Deku Tree 2F Middle Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, + { + // Exits + Entrance(DEKU_TREE_LOBBY, { [] { + return Here(DEKU_TREE_2F_MIDDLE_ROOM, + [] { return SoulDekuScrub && (HasShield || CanUse(MEGATON_HAMMER)); }); + } }), + Entrance(DEKU_TREE_SLINGSHOT_ROOM, { [] { + return Here(DEKU_TREE_2F_MIDDLE_ROOM, + [] { return SoulDekuScrub && (HasShield || CanUse(MEGATON_HAMMER)); }); + } }), + }); areaTable[DEKU_TREE_SLINGSHOT_ROOM] = Area("Deku Tree Slingshot Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, @@ -96,12 +102,13 @@ void AreaTable_Init_DekuTree() { { // Events EventAccess(&DekuBabaSticks, { [] { - return DekuBabaSticks || (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(BOOMERANG)); + return DekuBabaSticks || (SoulDekuBaba && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(BOOMERANG))); } }), EventAccess(&DekuBabaNuts, { [] { - return DekuBabaNuts || (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || - CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE)); + return DekuBabaNuts || + (SoulDekuBaba && (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || + CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE))); } }), }, { @@ -123,12 +130,13 @@ void AreaTable_Init_DekuTree() { { // Events EventAccess(&DekuBabaSticks, { [] { - return DekuBabaSticks || (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(BOOMERANG)); + return DekuBabaSticks || (SoulDekuBaba && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(BOOMERANG))); } }), EventAccess(&DekuBabaNuts, { [] { - return DekuBabaNuts || (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || - CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE)); + return DekuBabaNuts || + (SoulDekuBaba && (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || + CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE))); } }), }, { @@ -175,12 +183,13 @@ void AreaTable_Init_DekuTree() { { // Events EventAccess(&DekuBabaSticks, { [] { - return DekuBabaSticks || (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || - CanUse(BIGGORON_SWORD) || CanUse(BOOMERANG)); + return DekuBabaSticks || (SoulDekuBaba && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(BOOMERANG))); } }), EventAccess(&DekuBabaNuts, { [] { - return DekuBabaNuts || (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || - CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE)); + return DekuBabaNuts || + (SoulDekuBaba && (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || + CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE))); } }), }, {}, @@ -193,49 +202,51 @@ void AreaTable_Init_DekuTree() { } }), }); - areaTable[DEKU_TREE_BASEMENT_BACK_LOBBY] = Area( - "Deku Tree Basement Back Lobby", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, - { - // Events - EventAccess(&DekuBabaSticks, { [] { - return DekuBabaSticks || - (Here(DEKU_TREE_BASEMENT_BACK_LOBBY, [] { return HasFireSourceWithTorch || CanUse(BOW); }) && - (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(BOOMERANG))); - } }), - EventAccess(&DekuBabaNuts, { [] { - return DekuBabaNuts || - (Here(DEKU_TREE_BASEMENT_BACK_LOBBY, [] { return HasFireSourceWithTorch || CanUse(BOW); }) && - (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || CanUse(MEGATON_HAMMER) || - HasExplosives || CanUse(DINS_FIRE))); - } }), - }, - {}, - { - // Exits - Entrance(DEKU_TREE_BASEMENT_TORCH_ROOM, { [] { return true; } }), - Entrance(DEKU_TREE_BASEMENT_BACK_ROOM, - { [] { - return Here(DEKU_TREE_BASEMENT_BACK_LOBBY, - [] { return HasFireSourceWithTorch || CanUse(Bow); }) && - Here(DEKU_TREE_BASEMENT_BACK_LOBBY, [] { return CanBlastOrSmash; }); - }, - /*Glitched*/ - [] { - return Here(DEKU_TREE_BASEMENT_BACK_LOBBY, - [] { return HasFireSourceWithTorch || CanUse(Bow); }) && - Here(DEKU_TREE_BASEMENT_BACK_LOBBY, [] { - return (GlitchBlueFireWall && BlueFire) || - (CanUse(STICKS) && CanTakeDamage && - CanDoGlitch(GlitchType::QPA, GlitchDifficulty::EXPERT)); - }); - } }), - Entrance(DEKU_TREE_BASEMENT_UPPER, { [] { - return Here(DEKU_TREE_BASEMENT_BACK_LOBBY, - [] { return HasFireSourceWithTorch || CanUse(Bow); }) && - IsChild; - } }), - }); + areaTable[DEKU_TREE_BASEMENT_BACK_LOBBY] = + Area("Deku Tree Basement Back Lobby", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, + { + // Events + EventAccess(&DekuBabaSticks, { [] { + return DekuBabaSticks || + (SoulDekuBaba && (Here(DEKU_TREE_BASEMENT_BACK_LOBBY, + [] { return HasFireSourceWithTorch || CanUse(BOW); }) && + (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(BOOMERANG)))); + } }), + EventAccess(&DekuBabaNuts, { [] { + return DekuBabaNuts || + (SoulDekuBaba && (Here(DEKU_TREE_BASEMENT_BACK_LOBBY, + [] { return HasFireSourceWithTorch || CanUse(BOW); }) && + (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || + CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE)))); + } }), + }, + {}, + { + // Exits + Entrance(DEKU_TREE_BASEMENT_TORCH_ROOM, { [] { return true; } }), + Entrance(DEKU_TREE_BASEMENT_BACK_ROOM, + { [] { + return Here(DEKU_TREE_BASEMENT_BACK_LOBBY, + [] { return HasFireSourceWithTorch || CanUse(Bow); }) && + Here(DEKU_TREE_BASEMENT_BACK_LOBBY, [] { return CanBlastOrSmash; }); + }, + /*Glitched*/ + [] { + return Here(DEKU_TREE_BASEMENT_BACK_LOBBY, + [] { return HasFireSourceWithTorch || CanUse(Bow); }) && + Here(DEKU_TREE_BASEMENT_BACK_LOBBY, [] { + return (GlitchBlueFireWall && BlueFire) || + (CanUse(STICKS) && CanTakeDamage && + CanDoGlitch(GlitchType::QPA, GlitchDifficulty::EXPERT)); + }); + } }), + Entrance(DEKU_TREE_BASEMENT_UPPER, { [] { + return Here(DEKU_TREE_BASEMENT_BACK_LOBBY, + [] { return HasFireSourceWithTorch || CanUse(Bow); }) && + IsChild; + } }), + }); areaTable[DEKU_TREE_BASEMENT_BACK_ROOM] = Area("Deku Tree Basement Back Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, @@ -249,12 +260,13 @@ void AreaTable_Init_DekuTree() { { // Events EventAccess(&DekuBabaSticks, { [] { - return DekuBabaSticks || (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(BOOMERANG)); + return DekuBabaSticks || (SoulDekuBaba && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(BOOMERANG))); } }), EventAccess(&DekuBabaNuts, { [] { - return DekuBabaNuts || (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || - CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE)); + return DekuBabaNuts || + (SoulDekuBaba && (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || + CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE))); } }), }, {}, @@ -274,8 +286,9 @@ void AreaTable_Init_DekuTree() { { // Exits Entrance(DEKU_TREE_BASEMENT_UPPER, { [] { return true; } }), - Entrance(DEKU_TREE_BOSS_ENTRYWAY, - { [] { return Here(DEKU_TREE_OUTSIDE_BOSS_ROOM, [] { return HasShield; }); } }), + Entrance(DEKU_TREE_BOSS_ENTRYWAY, { [] { + return Here(DEKU_TREE_OUTSIDE_BOSS_ROOM, [] { return SoulDekuScrub && HasShield; }); + } }), }); } @@ -288,12 +301,13 @@ void AreaTable_Init_DekuTree() { { // Events EventAccess(&DekuBabaSticks, { [] { - return DekuBabaSticks || (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(BOOMERANG)); + return DekuBabaSticks || (SoulDekuBaba && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(BOOMERANG))); } }), EventAccess(&DekuBabaNuts, { [] { - return DekuBabaNuts || (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || - CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE)); + return DekuBabaNuts || + (SoulDekuBaba && (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || + CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE))); } }), }, { @@ -439,13 +453,14 @@ void AreaTable_Init_DekuTree() { Area("Deku Tree Boss Room", "Deku Tree", NONE, NO_DAY_NIGHT_CYCLE, { // Events - EventAccess(&DekuTreeClear, { [] { - return DekuTreeClear || - (CanJumpslash && (Nuts || CanUse(SLINGSHOT) || CanUse(BOW) || - HookshotOrBoomerang)); - }, - /*Glitched*/ - [] { return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE); } }), + EventAccess(&DekuTreeClear, + { [] { + return DekuTreeClear || + (SoulGohma && CanJumpslash && + (Nuts || CanUse(SLINGSHOT) || CanUse(BOW) || HookshotOrBoomerang)); + }, + /*Glitched*/ + [] { return SoulGohma && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE); } }), }, { // Locations diff --git a/source/location_access/locacc_dodongos_cavern.cpp b/source/location_access/locacc_dodongos_cavern.cpp index 1f7de5ad..80c48730 100644 --- a/source/location_access/locacc_dodongos_cavern.cpp +++ b/source/location_access/locacc_dodongos_cavern.cpp @@ -124,39 +124,39 @@ void AreaTable_Init_DodongosCavern() { Entrance(DODONGOS_CAVERN_DODONGO_ROOM, { [] { return true; } }), }); - areaTable[DODONGOS_CAVERN_SE_CORRIDOR] = - Area("Dodongos Cavern SE Corridor", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, - { - // Locations - LocationAccess(DODONGOS_CAVERN_GS_SCARECROW, - { [] { - return CanUse(SCARECROW) || (IsAdult && CanUse(LONGSHOT)) || - (LogicDCScarecrowGS && (CanAdultAttack || CanChildAttack)); - }, - /*Glitched*/ - [] { - return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || - (CanUse(LONGSHOT) && - CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE)); - } }), - }, - { - // Exits - Entrance(DODONGOS_CAVERN_LOBBY, { [] { return true; } }), - Entrance(DODONGOS_CAVERN_SE_ROOM, { [] { - return Here(DODONGOS_CAVERN_SE_CORRIDOR, [] { - return CanBlastOrSmash || CanAdultAttack || - CanChildAttack || (CanTakeDamage && CanShield); - }); - }, - /*Glitched*/ - [] { - return Here(DODONGOS_CAVERN_SE_CORRIDOR, [] { - return (GlitchBlueFireWall && BlueFire); - }); - } }), - Entrance(DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS, { [] { return true; } }), - }); + areaTable[DODONGOS_CAVERN_SE_CORRIDOR] = Area( + "Dodongos Cavern SE Corridor", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, + { + // Locations + LocationAccess(DODONGOS_CAVERN_GS_SCARECROW, + { [] { + return CanUse(SCARECROW) || (IsAdult && CanUse(LONGSHOT)) || + (LogicDCScarecrowGS && (CanAdultAttack || CanChildAttack)); + }, + /*Glitched*/ + [] { + return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || + (CanUse(LONGSHOT) && + CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE)); + } }), + }, + { + // Exits + Entrance(DODONGOS_CAVERN_LOBBY, { [] { return true; } }), + Entrance(DODONGOS_CAVERN_SE_ROOM, { [] { + return Here(DODONGOS_CAVERN_SE_CORRIDOR, [] { + return CanBlastOrSmash || + (SoulDodongo && (CanAdultAttack || CanChildAttack || + (CanTakeDamage && CanShield))); + }); + }, + /*Glitched*/ + [] { + return Here(DODONGOS_CAVERN_SE_CORRIDOR, + [] { return (GlitchBlueFireWall && BlueFire); }); + } }), + Entrance(DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS, { [] { return true; } }), + }); areaTable[DODONGOS_CAVERN_SE_ROOM] = Area("Dodongos Cavern SE Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, @@ -183,18 +183,18 @@ void AreaTable_Init_DodongosCavern() { { // Exits Entrance(DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS, { [] { - return Here(DODONGOS_CAVERN_LOWER_LIZALFOS, [] { - return CanUse(BOW) || CanUse(SLINGSHOT) || CanUse(STICKS) || - CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(MEGATON_HAMMER) || HasExplosives; - }); + return SoulLizalfosDinolfos && Here(DODONGOS_CAVERN_LOWER_LIZALFOS, [] { + return CanUse(BOW) || CanUse(SLINGSHOT) || CanUse(STICKS) || + CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(MEGATON_HAMMER) || HasExplosives; + }); } }), Entrance(DODONGOS_CAVERN_DODONGO_ROOM, { [] { - return Here(DODONGOS_CAVERN_LOWER_LIZALFOS, [] { - return CanUse(BOW) || CanUse(SLINGSHOT) || CanUse(STICKS) || - CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(MEGATON_HAMMER) || HasExplosives; - }); + return SoulLizalfosDinolfos && Here(DODONGOS_CAVERN_LOWER_LIZALFOS, [] { + return CanUse(BOW) || CanUse(SLINGSHOT) || CanUse(STICKS) || + CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(MEGATON_HAMMER) || HasExplosives; + }); } }), }); @@ -369,18 +369,18 @@ void AreaTable_Init_DodongosCavern() { // Exits Entrance(DODONGOS_CAVERN_LOWER_LIZALFOS, { [] { return true; } }), Entrance(DODONGOS_CAVERN_FIRST_SLINGSHOT_ROOM, { [] { - return Here(DODONGOS_CAVERN_LOWER_LIZALFOS, [] { - return CanUse(BOW) || CanUse(SLINGSHOT) || CanUse(STICKS) || - CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(MEGATON_HAMMER) || HasExplosives; - }); + return SoulLizalfosDinolfos && Here(DODONGOS_CAVERN_LOWER_LIZALFOS, [] { + return CanUse(BOW) || CanUse(SLINGSHOT) || CanUse(STICKS) || + CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(MEGATON_HAMMER) || HasExplosives; + }); } }), Entrance(DODONGOS_CAVERN_SECOND_SLINGSHOT_ROOM, { [] { - return Here(DODONGOS_CAVERN_LOWER_LIZALFOS, [] { - return CanUse(BOW) || CanUse(SLINGSHOT) || CanUse(STICKS) || - CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(MEGATON_HAMMER) || HasExplosives; - }); + return SoulLizalfosDinolfos && Here(DODONGOS_CAVERN_LOWER_LIZALFOS, [] { + return CanUse(BOW) || CanUse(SLINGSHOT) || CanUse(STICKS) || + CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(MEGATON_HAMMER) || HasExplosives; + }); } }), }); @@ -489,8 +489,8 @@ void AreaTable_Init_DodongosCavern() { { // Events EventAccess(&DekuBabaSticks, { [] { - return DekuBabaSticks || (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || - CanUse(BIGGORON_SWORD) || CanUse(BOOMERANG)); + return DekuBabaSticks || (SoulDekuBaba && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(BOOMERANG))); } }), EventAccess(&GossipStoneFairy, { [] { return GossipStoneFairy || CanSummonGossipFairy; } }), }, @@ -605,7 +605,7 @@ void AreaTable_Init_DodongosCavern() { return DodongosCavernClear || (Here(DODONGOS_CAVERN_BOSS_ROOM, [] { return HasExplosives || (CanUse(MEGATON_HAMMER) && CanShield); }) && - (Bombs || GoronBracelet) && CanJumpslash); + SoulDodongo && (Bombs || GoronBracelet) && CanJumpslash); }, /*Glitched*/ [] { @@ -614,7 +614,7 @@ void AreaTable_Init_DodongosCavern() { return HasExplosives || (CanUse(MEGATON_HAMMER) && CanShield) || (GlitchBlueFireWall && BlueFire); }) && - (HasExplosives || GoronBracelet) && CanJumpslash; + SoulDodongo && (HasExplosives || GoronBracelet) && CanJumpslash; } }), }, { diff --git a/source/location_access/locacc_fire_temple.cpp b/source/location_access/locacc_fire_temple.cpp index 8cf94fe3..da53afe4 100644 --- a/source/location_access/locacc_fire_temple.cpp +++ b/source/location_access/locacc_fire_temple.cpp @@ -83,10 +83,10 @@ void AreaTable_Init_FireTemple() { // Exits Entrance(FIRE_TEMPLE_FIRST_ROOM, { [] { return SmallKeys(FIRE_TEMPLE, 8) || !IsKeysanity; } }), Entrance(FIRE_TEMPLE_LOOP_TILES, { [] { - return Here(FIRE_TEMPLE_LOOP_ENEMIES, [] { - return CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(MEGATON_HAMMER); - }); + return SoulKeese && SoulTorchSlug && Here(FIRE_TEMPLE_LOOP_ENEMIES, [] { + return CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(MEGATON_HAMMER); + }); } }), }); @@ -102,32 +102,34 @@ void AreaTable_Init_FireTemple() { Entrance(FIRE_TEMPLE_LOOP_FLARE_DANCER, { [] { return true; } }), }); - areaTable[FIRE_TEMPLE_LOOP_FLARE_DANCER] = - Area("Fire Temple Loop Flare Dancer", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, - { - // Locations - LocationAccess(FIRE_TEMPLE_FLARE_DANCER_CHEST, - { [] { return (HasExplosives || CanUse(MEGATON_HAMMER)) && IsAdult; }, - /*Glitched*/ - [] { - return (CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && - CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE)) || - (CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED) && - HasBombchus && CanShield && - (Slingshot || CanUse(BOW) || CanUse(HOOKSHOT))); - } }), - }, - { - // Exits - Entrance(FIRE_TEMPLE_LOOP_TILES, { [] { return true; } }), - Entrance(FIRE_TEMPLE_LOOP_HAMMER_SWITCH, { [] { - return Here(FIRE_TEMPLE_LOOP_FLARE_DANCER, [] { - return (HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(HOOKSHOT)) && - (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(SLINGSHOT) || CanUse(BOOMERANG)); - }); - } }), - }); + areaTable[FIRE_TEMPLE_LOOP_FLARE_DANCER] = Area( + "Fire Temple Loop Flare Dancer", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, + { + // Locations + LocationAccess(FIRE_TEMPLE_FLARE_DANCER_CHEST, + { [] { return SoulFlareDancer && (HasExplosives || CanUse(MEGATON_HAMMER)) && IsAdult; }, + /*Glitched*/ + [] { + return SoulFlareDancer && + ((CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && + CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE)) || + (CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED) && + HasBombchus && CanShield && + (Slingshot || CanUse(BOW) || CanUse(HOOKSHOT)))); + } }), + }, + { + // Exits + Entrance(FIRE_TEMPLE_LOOP_TILES, { [] { return true; } }), + Entrance(FIRE_TEMPLE_LOOP_HAMMER_SWITCH, { [] { + return Here(FIRE_TEMPLE_LOOP_FLARE_DANCER, [] { + return SoulFlareDancer && + (HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(HOOKSHOT)) && + (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || + CanUse(SLINGSHOT) || CanUse(BOOMERANG)); + }); + } }), + }); areaTable[FIRE_TEMPLE_LOOP_HAMMER_SWITCH] = Area("Fire Temple Loop Hammer Switch", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, @@ -551,18 +553,18 @@ void AreaTable_Init_FireTemple() { { // Exits Entrance(FIRE_TEMPLE_LATE_FIRE_MAZE, { [] { - return Here(FIRE_TEMPLE_UPPER_FLARE_DANCER, [] { - return (HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(HOOKSHOT)) && - (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(SLINGSHOT) || CanUse(BOOMERANG)); - }); + return SoulFlareDancer && Here(FIRE_TEMPLE_UPPER_FLARE_DANCER, [] { + return (HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(HOOKSHOT)) && + (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(SLINGSHOT) || CanUse(BOOMERANG)); + }); } }), Entrance(FIRE_TEMPLE_WEST_CLIMB, { [] { - return Here(FIRE_TEMPLE_UPPER_FLARE_DANCER, [] { - return (HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(HOOKSHOT)) && - (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(SLINGSHOT) || CanUse(BOOMERANG)); - }); + return SoulFlareDancer && Here(FIRE_TEMPLE_UPPER_FLARE_DANCER, [] { + return (HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(HOOKSHOT)) && + (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(SLINGSHOT) || CanUse(BOOMERANG)); + }); } }), }); @@ -775,27 +777,27 @@ void AreaTable_Init_FireTemple() { Entrance(FIRE_TEMPLE_BOSS_ROOM, { [] { return true; } }), }); - areaTable[FIRE_TEMPLE_BOSS_ROOM] = - Area("Fire Temple Boss Room", "Fire Temple", NONE, NO_DAY_NIGHT_CYCLE, - { - // Events - EventAccess(&FireTempleClear, - { [] { return FireTempleClear || (FireTimer >= 64 && CanUse(MEGATON_HAMMER)); }, - /*Glitched*/ - [] { - return FireTimer >= 48 && - ((CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE)) || - CanUse(MEGATON_HAMMER)) && - Bombs && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE); - } }), - }, - { - // Locations - LocationAccess(FIRE_TEMPLE_VOLVAGIA_HEART, { [] { return FireTempleClear; } }), - LocationAccess(VOLVAGIA, { [] { return FireTempleClear; } }), - }, - { - // Exits - Entrance(FIRE_TEMPLE_BOSS_ENTRYWAY, { [] { return false; } }), - }); + areaTable[FIRE_TEMPLE_BOSS_ROOM] = Area( + "Fire Temple Boss Room", "Fire Temple", NONE, NO_DAY_NIGHT_CYCLE, + { + // Events + EventAccess(&FireTempleClear, + { [] { return FireTempleClear || (SoulVolvagia && FireTimer >= 64 && CanUse(MEGATON_HAMMER)); }, + /*Glitched*/ + [] { + return SoulVolvagia && FireTimer >= 48 && + ((CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE)) || + CanUse(MEGATON_HAMMER)) && + Bombs && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE); + } }), + }, + { + // Locations + LocationAccess(FIRE_TEMPLE_VOLVAGIA_HEART, { [] { return FireTempleClear; } }), + LocationAccess(VOLVAGIA, { [] { return FireTempleClear; } }), + }, + { + // Exits + Entrance(FIRE_TEMPLE_BOSS_ENTRYWAY, { [] { return false; } }), + }); } diff --git a/source/location_access/locacc_forest_temple.cpp b/source/location_access/locacc_forest_temple.cpp index 34931d5d..e62b2da7 100644 --- a/source/location_access/locacc_forest_temple.cpp +++ b/source/location_access/locacc_forest_temple.cpp @@ -40,7 +40,8 @@ void AreaTable_Init_ForestTemple() { { // Exits Entrance(FOREST_TEMPLE_FIRST_ROOM, { [] { return true; } }), - Entrance(FOREST_TEMPLE_LOBBY, { [] { return CanAdultAttack || CanChildAttack || Nuts; } }), + Entrance(FOREST_TEMPLE_LOBBY, + { [] { return SoulSkulltula && (CanAdultAttack || CanChildAttack || Nuts); } }), }); areaTable[FOREST_TEMPLE_LOBBY] = Area( @@ -49,7 +50,7 @@ void AreaTable_Init_ForestTemple() { // Events EventAccess(&ForestTempleMeg, { [] { return ForestTempleMeg || - (ForestTempleJoelle && ForestTempleBeth && ForestTempleAmy && CanUse(BOW)); + (SoulPoe && ForestTempleJoelle && ForestTempleBeth && ForestTempleAmy && CanUse(BOW)); } }), }, {}, @@ -101,8 +102,8 @@ void AreaTable_Init_ForestTemple() { { // Locations LocationAccess(FOREST_TEMPLE_FIRST_STALFOS_CHEST, { [] { - return CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(MEGATON_HAMMER); + return SoulStalfos && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(MEGATON_HAMMER)); } }), }, { @@ -115,12 +116,13 @@ void AreaTable_Init_ForestTemple() { { // Events EventAccess(&DekuBabaSticks, { [] { - return DekuBabaSticks || (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(BOOMERANG)); + return DekuBabaSticks || (SoulDekuBaba && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(BOOMERANG))); } }), EventAccess(&DekuBabaNuts, { [] { - return DekuBabaNuts || (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || - CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE)); + return DekuBabaNuts || + (SoulDekuBaba && (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || + CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE))); } }), }, {}, @@ -165,12 +167,13 @@ void AreaTable_Init_ForestTemple() { { // Events EventAccess(&DekuBabaSticks, { [] { - return DekuBabaSticks || (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || - CanUse(BIGGORON_SWORD) || CanUse(BOOMERANG)); + return DekuBabaSticks || (SoulDekuBaba && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(BOOMERANG))); } }), EventAccess(&DekuBabaNuts, { [] { - return DekuBabaNuts || (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || - CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE)); + return DekuBabaNuts || + (SoulDekuBaba && (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || + CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE))); } }), }, {}, @@ -187,12 +190,13 @@ void AreaTable_Init_ForestTemple() { { // Events EventAccess(&DekuBabaSticks, { [] { - return DekuBabaSticks || (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(BOOMERANG)); + return DekuBabaSticks || (SoulDekuBaba && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(BOOMERANG))); } }), EventAccess(&DekuBabaNuts, { [] { - return DekuBabaNuts || (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || - CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE)); + return DekuBabaNuts || + (SoulDekuBaba && (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || + CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE))); } }), }, { @@ -222,12 +226,13 @@ void AreaTable_Init_ForestTemple() { { // Events EventAccess(&DekuBabaSticks, { [] { - return DekuBabaSticks || (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(BOOMERANG)); + return DekuBabaSticks || (SoulDekuBaba && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(BOOMERANG))); } }), EventAccess(&DekuBabaNuts, { [] { - return DekuBabaNuts || (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || - CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE)); + return DekuBabaNuts || + (SoulDekuBaba && (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || + CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE))); } }), }, {}, @@ -246,28 +251,28 @@ void AreaTable_Init_ForestTemple() { { // Locations LocationAccess(FOREST_TEMPLE_MAP_CHEST, { [] { - return Here(FOREST_TEMPLE_MAP_ROOM, [] { - return HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(BOW) || - ((CanJumpslash || CanUse(SLINGSHOT)) && - (Nuts || HookshotOrBoomerang || CanShield)); - }); + return SoulBubble && Here(FOREST_TEMPLE_MAP_ROOM, [] { + return HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(BOW) || + ((CanJumpslash || CanUse(SLINGSHOT)) && + (Nuts || HookshotOrBoomerang || CanShield)); + }); } }), }, { // Exits Entrance(FOREST_TEMPLE_NW_OUTDOORS_LOWER, { [] { - return Here(FOREST_TEMPLE_MAP_ROOM, [] { - return HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(BOW) || - ((CanJumpslash || CanUse(SLINGSHOT)) && - (Nuts || HookshotOrBoomerang || CanShield)); - }); + return SoulBubble && Here(FOREST_TEMPLE_MAP_ROOM, [] { + return HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(BOW) || + ((CanJumpslash || CanUse(SLINGSHOT)) && + (Nuts || HookshotOrBoomerang || CanShield)); + }); } }), Entrance(FOREST_TEMPLE_NE_OUTDOORS_UPPER, { [] { - return Here(FOREST_TEMPLE_MAP_ROOM, [] { - return HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(BOW) || - ((CanJumpslash || CanUse(SLINGSHOT)) && - (Nuts || HookshotOrBoomerang || CanShield)); - }); + return SoulBubble && Here(FOREST_TEMPLE_MAP_ROOM, [] { + return HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(BOW) || + ((CanJumpslash || CanUse(SLINGSHOT)) && + (Nuts || HookshotOrBoomerang || CanShield)); + }); } }), }); @@ -289,32 +294,34 @@ void AreaTable_Init_ForestTemple() { { // Exits Entrance(FOREST_TEMPLE_NW_OUTDOORS_UPPER, { [] { - return Here(FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST, [] { - return HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(BOW) || - ((CanJumpslash || CanUse(SLINGSHOT)) && - (Nuts || HookshotOrBoomerang || CanShield)); - }); + return SoulBubble && Here(FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST, [] { + return HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(BOW) || + ((CanJumpslash || CanUse(SLINGSHOT)) && + (Nuts || HookshotOrBoomerang || CanShield)); + }); } }), }); - areaTable[FOREST_TEMPLE_FLOORMASTER_ROOM] = Area( - "Forest Temple Floormaster Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, - { - // Locations - LocationAccess(FOREST_TEMPLE_FLOORMASTER_CHEST, { [] { return CanAdultDamage || CanChildDamage; } }), - }, - { - // Exits - Entrance(FOREST_TEMPLE_NW_OUTDOORS_UPPER, { [] { return true; } }), - }); + areaTable[FOREST_TEMPLE_FLOORMASTER_ROOM] = + Area("Forest Temple Floormaster Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, + { + // Locations + LocationAccess(FOREST_TEMPLE_FLOORMASTER_CHEST, + { [] { return SoulWallmaster && (CanAdultDamage || CanChildDamage); } }), + }, + { + // Exits + Entrance(FOREST_TEMPLE_NW_OUTDOORS_UPPER, { [] { return true; } }), + }); - areaTable[FOREST_TEMPLE_WEST_CORRIDOR] = Area( - "Forest Temple West Corridor", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, - { - // Exits - Entrance(FOREST_TEMPLE_LOBBY, { [] { return SmallKeys(FOREST_TEMPLE, 1, 5); } }), - Entrance(FOREST_TEMPLE_BLOCK_PUSH_ROOM, { [] { return CanAdultAttack || CanChildAttack || Nuts; } }), - }); + areaTable[FOREST_TEMPLE_WEST_CORRIDOR] = + Area("Forest Temple West Corridor", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, + { + // Exits + Entrance(FOREST_TEMPLE_LOBBY, { [] { return SmallKeys(FOREST_TEMPLE, 1, 5); } }), + Entrance(FOREST_TEMPLE_BLOCK_PUSH_ROOM, + { [] { return SoulSkulltula && (CanAdultAttack || CanChildAttack || Nuts); } }), + }); areaTable[FOREST_TEMPLE_BLOCK_PUSH_ROOM] = Area( "Forest Temple Block Push Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, @@ -389,40 +396,40 @@ void AreaTable_Init_ForestTemple() { Entrance(FOREST_TEMPLE_BLOCK_PUSH_ROOM, { [] { return SmallKeys(FOREST_TEMPLE, 2); } }), }); - areaTable[FOREST_TEMPLE_RED_POE_ROOM] = - Area("Forest Temple Red Poe Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, - { - // Events - EventAccess(&ForestTempleJoelle, { [] { return ForestTempleJoelle || CanUse(BOW); } }), - }, - { - // Locations - LocationAccess(FOREST_TEMPLE_RED_POE_CHEST, { [] { return ForestTempleJoelle; } }), - }, - { - // Exits - Entrance(FOREST_TEMPLE_NW_CORRIDOR_TWISTED, { [] { return SmallKeys(FOREST_TEMPLE, 3); } }), - Entrance(FOREST_TEMPLE_UPPER_STALFOS, { [] { return true; } }), - }); + areaTable[FOREST_TEMPLE_RED_POE_ROOM] = Area( + "Forest Temple Red Poe Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, + { + // Events + EventAccess(&ForestTempleJoelle, { [] { return ForestTempleJoelle || (SoulPoe && CanUse(BOW)); } }), + }, + { + // Locations + LocationAccess(FOREST_TEMPLE_RED_POE_CHEST, { [] { return ForestTempleJoelle; } }), + }, + { + // Exits + Entrance(FOREST_TEMPLE_NW_CORRIDOR_TWISTED, { [] { return SmallKeys(FOREST_TEMPLE, 3); } }), + Entrance(FOREST_TEMPLE_UPPER_STALFOS, { [] { return true; } }), + }); areaTable[FOREST_TEMPLE_UPPER_STALFOS] = Area("Forest Temple Upper Stalfos", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { // Locations LocationAccess(FOREST_TEMPLE_BOW_CHEST, { [] { - return CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(MEGATON_HAMMER); + return SoulStalfos && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(MEGATON_HAMMER)); } }), }, { // Exits Entrance(FOREST_TEMPLE_RED_POE_ROOM, { [] { - return CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(MEGATON_HAMMER); + return SoulStalfos && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(MEGATON_HAMMER)); } }), Entrance(FOREST_TEMPLE_BLUE_POE_ROOM, { [] { - return CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(MEGATON_HAMMER); + return SoulStalfos && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(MEGATON_HAMMER)); } }), }); @@ -430,7 +437,7 @@ void AreaTable_Init_ForestTemple() { Area("Forest Temple Blue Poe Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { // Events - EventAccess(&ForestTempleBeth, { [] { return ForestTempleBeth || CanUse(BOW); } }), + EventAccess(&ForestTempleBeth, { [] { return ForestTempleBeth || (SoulPoe && CanUse(BOW)); } }), }, { // Locations @@ -483,7 +490,7 @@ void AreaTable_Init_ForestTemple() { Area("Forest Temple Green Poe Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { // Events - EventAccess(&ForestTempleAmy, { [] { return ForestTempleAmy || CanUse(BOW); } }), + EventAccess(&ForestTempleAmy, { [] { return ForestTempleAmy || (SoulPoe && CanUse(BOW)); } }), }, {}, { @@ -492,13 +499,15 @@ void AreaTable_Init_ForestTemple() { Entrance(FOREST_TEMPLE_EAST_CORRIDOR, { [] { return ForestTempleAmy; } }), }); - areaTable[FOREST_TEMPLE_EAST_CORRIDOR] = Area( - "Forest Temple East Corridor", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, - { - // Exits - Entrance(FOREST_TEMPLE_LOBBY, { [] { return CanAdultAttack || CanChildAttack || Nuts; } }), - Entrance(FOREST_TEMPLE_GREEN_POE_ROOM, { [] { return CanAdultAttack || CanChildAttack || Nuts; } }), - }); + areaTable[FOREST_TEMPLE_EAST_CORRIDOR] = + Area("Forest Temple East Corridor", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, + { + // Exits + Entrance(FOREST_TEMPLE_LOBBY, + { [] { return SoulSkulltula && (CanAdultAttack || CanChildAttack || Nuts); } }), + Entrance(FOREST_TEMPLE_GREEN_POE_ROOM, + { [] { return SoulSkulltula && (CanAdultAttack || CanChildAttack || Nuts); } }), + }); areaTable[FOREST_TEMPLE_BOSS_REGION] = Area("Forest Temple Boss Region", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, @@ -614,12 +623,13 @@ void AreaTable_Init_ForestTemple() { { // Events EventAccess(&DekuBabaSticks, { [] { - return DekuBabaSticks || (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || - CanUse(BIGGORON_SWORD) || CanUse(BOOMERANG)); + return DekuBabaSticks || (SoulDekuBaba && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(BOOMERANG))); } }), EventAccess(&DekuBabaNuts, { [] { - return DekuBabaNuts || (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || - CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE)); + return DekuBabaNuts || + (SoulDekuBaba && (CanJumpslash || CanUse(SLINGSHOT) || CanUse(BOW) || + CanUse(MEGATON_HAMMER) || HasExplosives || CanUse(DINS_FIRE))); } }), }, { @@ -739,8 +749,9 @@ void AreaTable_Init_ForestTemple() { { // Events EventAccess(&ForestTempleClear, { [] { - return ForestTempleClear || ((CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)) && - (CanUse(HOOKSHOT) || CanUse(BOW) || CanUse(SLINGSHOT))); + return ForestTempleClear || + (SoulPhantomGanon && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)) && + (CanUse(HOOKSHOT) || CanUse(BOW) || CanUse(SLINGSHOT))); } }), }, { diff --git a/source/location_access/locacc_ganons_castle.cpp b/source/location_access/locacc_ganons_castle.cpp index 6d9bb053..92950c0e 100644 --- a/source/location_access/locacc_ganons_castle.cpp +++ b/source/location_access/locacc_ganons_castle.cpp @@ -77,7 +77,8 @@ void AreaTable_Init_GanonsCastle() { }, { // Locations - LocationAccess(GANONS_CASTLE_FOREST_TRIAL_CHEST, { [] { return CanAdultDamage || CanChildDamage; } }), + LocationAccess(GANONS_CASTLE_FOREST_TRIAL_CHEST, + { [] { return SoulWolfos && (CanAdultDamage || CanChildDamage); } }), }, {}); @@ -91,21 +92,22 @@ void AreaTable_Init_GanonsCastle() { }, {}, {}); - areaTable[GANONS_CASTLE_WATER_TRIAL] = Area( - "Ganon's Castle Water Trial", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, - { - // Events - EventAccess(&BlueFireAccess, { [] { return BlueFireAccess || HasBottle; } }), - EventAccess(&FairyPot, { [] { return FairyPot || BlueFire; } }), - EventAccess(&WaterTrialClear, - { [] { return BlueFire && IsAdult && CanUse(MEGATON_HAMMER) && CanUse(LIGHT_ARROWS); } }), - }, - { - // Locations - LocationAccess(GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST, { [] { return true; } }), - LocationAccess(GANONS_CASTLE_WATER_TRIAL_RIGHT_CHEST, { [] { return true; } }), - }, - {}); + areaTable[GANONS_CASTLE_WATER_TRIAL] = + Area("Ganon's Castle Water Trial", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, + { + // Events + EventAccess(&BlueFireAccess, { [] { return BlueFireAccess || HasBottle; } }), + EventAccess(&FairyPot, { [] { return FairyPot || BlueFire; } }), + EventAccess(&WaterTrialClear, { [] { + return SoulFreezard && BlueFire && IsAdult && CanUse(MEGATON_HAMMER) && CanUse(LIGHT_ARROWS); + } }), + }, + { + // Locations + LocationAccess(GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST, { [] { return true; } }), + LocationAccess(GANONS_CASTLE_WATER_TRIAL_RIGHT_CHEST, { [] { return true; } }), + }, + {}); areaTable[GANONS_CASTLE_SHADOW_TRIAL] = Area("Ganon's Castle Shadow Trial", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, @@ -114,8 +116,8 @@ void AreaTable_Init_GanonsCastle() { EventAccess(&ShadowTrialClear, { [] { return CanUse(LIGHT_ARROWS) && CanUse(MEGATON_HAMMER) && ((FireArrows && (LogicLensCastle || CanUse(LENS_OF_TRUTH))) || - (CanUse(LONGSHOT) && - (CanUse(HOVER_BOOTS) || (DinsFire && (LogicLensCastle || CanUse(LENS_OF_TRUTH)))))); + (CanUse(LONGSHOT) && ((SoulLikeLike && CanUse(HOVER_BOOTS)) || + (DinsFire && (LogicLensCastle || CanUse(LENS_OF_TRUTH)))))); } }), }, { @@ -126,7 +128,8 @@ void AreaTable_Init_GanonsCastle() { } }), LocationAccess(GANONS_CASTLE_SHADOW_TRIAL_GOLDEN_GAUNTLETS_CHEST, { [] { return CanUse(FIRE_ARROWS) || - (CanUse(LONGSHOT) && (CanUse(HOVER_BOOTS) || CanUse(DINS_FIRE))); + (CanUse(LONGSHOT) && + ((SoulLikeLike && CanUse(HOVER_BOOTS)) || CanUse(DINS_FIRE))); } }), }, {}); @@ -172,29 +175,34 @@ void AreaTable_Init_GanonsCastle() { LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_FIRST_RIGHT_CHEST, { [] { return true; } }), LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_SECOND_RIGHT_CHEST, { [] { return true; } }), LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST, { [] { return true; } }), - LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST, - { [] { return LogicLensCastle || CanUse(LENS_OF_TRUTH); } }), + LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST, { [] { + return SoulSkulltula && SoulKeese && (LogicLensCastle || CanUse(LENS_OF_TRUTH)); + } }), LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST, { [] { return CanPlay(ZeldasLullaby) && SmallKeys(GANONS_CASTLE, 1); } }), }, {}); } - areaTable[GANONS_CASTLE_TOWER] = Area( - "Ganon's Castle Tower", "Ganons Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {}, - { - // Locations - LocationAccess(GANONS_TOWER_BOSS_KEY_CHEST, - { [] { return CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD); } }), - LocationAccess(GANONDORF_HINT, { [] { - return BossKeyGanonsCastle && - (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)); - } }), - LocationAccess(GANON, { [] { - return BossKeyGanonsCastle && CanUse(LIGHT_ARROWS) && CanUse(MASTER_SWORD) && Hearts > 0; - } }), - }, - {}); + areaTable[GANONS_CASTLE_TOWER] = + Area("Ganon's Castle Tower", "Ganons Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {}, + { + // Locations + LocationAccess(GANONS_TOWER_BOSS_KEY_CHEST, { [] { + return SoulLizalfosDinolfos && SoulStalfos && + (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)); + } }), + LocationAccess(GANONDORF_HINT, { [] { + return SoulLizalfosDinolfos && SoulStalfos && SoulGerudo && BossKeyGanonsCastle && + (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)); + } }), + LocationAccess(GANON, { [] { + return SoulLizalfosDinolfos && SoulStalfos && SoulGerudo && SoulGanon && + BossKeyGanonsCastle && CanUse(LIGHT_ARROWS) && CanUse(MASTER_SWORD) && + Hearts > 0; + } }), + }, + {}); /*--------------------------- | MASTER QUEST DUNGEON | diff --git a/source/location_access/locacc_gerudo_training_grounds.cpp b/source/location_access/locacc_gerudo_training_grounds.cpp index 5d162631..b03b2fd6 100644 --- a/source/location_access/locacc_gerudo_training_grounds.cpp +++ b/source/location_access/locacc_gerudo_training_grounds.cpp @@ -33,10 +33,11 @@ void AreaTable_Init_GerudoTrainingGrounds() { LocationAccess(GERUDO_TRAINING_GROUNDS_LOBBY_RIGHT_CHEST, { [] { return CanUse(BOW) || CanUse(SLINGSHOT); } }), LocationAccess(GERUDO_TRAINING_GROUNDS_STALFOS_CHEST, { [] { - return CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD); + return SoulStalfos && + (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)); } }), LocationAccess(GERUDO_TRAINING_GROUNDS_BEAMOS_CHEST, { [] { - return HasExplosives && + return SoulBeamos && SoulLizalfosDinolfos && HasExplosives && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)); } }), }, @@ -44,14 +45,16 @@ void AreaTable_Init_GerudoTrainingGrounds() { // Exits Entrance(GERUDO_TRAINING_GROUNDS_ENTRYWAY, { [] { return true; } }), Entrance(GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_ROOM, { [] { - return (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)) && + return SoulStalfos && + (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)) && (CanUse(HOOKSHOT) || LogicGtgWithoutHookshot); } }), Entrance(GERUDO_TRAINING_GROUNDS_LAVA_ROOM, { [] { - return Here(GERUDO_TRAINING_GROUNDS_LOBBY, [] { - return (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)) && - HasExplosives; - }); + return SoulBeamos && SoulLizalfosDinolfos && Here(GERUDO_TRAINING_GROUNDS_LOBBY, [] { + return (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD)) && + HasExplosives; + }); } }), Entrance(GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE, { [] { return true; } }), }); @@ -131,8 +134,9 @@ void AreaTable_Init_GerudoTrainingGrounds() { { // Locations LocationAccess(GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_CLEAR_CHEST, { [] { - return CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || - CanUse(MEGATON_HAMMER); + return SoulKeese && SoulTorchSlug && + (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(MEGATON_HAMMER)); } }), LocationAccess(GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_SWITCH_CHEST, { [] { return CanUse(MEGATON_HAMMER) || (CanTakeDamage && LogicFlamingChests); } }), @@ -173,7 +177,8 @@ void AreaTable_Init_GerudoTrainingGrounds() { NO_DAY_NIGHT_CYCLE, {}, { // Locations - LocationAccess(GERUDO_TRAINING_GROUNDS_BEFORE_HEAVY_BLOCK_CHEST, { [] { return CanJumpslash; } }), + LocationAccess(GERUDO_TRAINING_GROUNDS_BEFORE_HEAVY_BLOCK_CHEST, + { [] { return SoulWolfos && CanJumpslash; } }), }, { // Exits @@ -193,10 +198,14 @@ void AreaTable_Init_GerudoTrainingGrounds() { NO_DAY_NIGHT_CYCLE, {}, { // Locations - LocationAccess(GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FIRST_CHEST, { [] { return CanJumpslash; } }), - LocationAccess(GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_SECOND_CHEST, { [] { return CanJumpslash; } }), - LocationAccess(GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_THIRD_CHEST, { [] { return CanJumpslash; } }), - LocationAccess(GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FOURTH_CHEST, { [] { return CanJumpslash; } }), + LocationAccess(GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FIRST_CHEST, + { [] { return SoulLikeLike && CanJumpslash; } }), + LocationAccess(GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_SECOND_CHEST, + { [] { return SoulLikeLike && CanJumpslash; } }), + LocationAccess(GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_THIRD_CHEST, + { [] { return SoulLikeLike && CanJumpslash; } }), + LocationAccess(GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FOURTH_CHEST, + { [] { return SoulLikeLike && CanJumpslash; } }), }, {}); } diff --git a/source/location_access/locacc_gerudo_valley.cpp b/source/location_access/locacc_gerudo_valley.cpp index 542fdebb..33c9b62b 100644 --- a/source/location_access/locacc_gerudo_valley.cpp +++ b/source/location_access/locacc_gerudo_valley.cpp @@ -198,27 +198,32 @@ void AreaTable_Init_GerudoValley() { (GerudoToken || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(HOVER_BOOTS) || LogicGerudoKitchen); } }), - LocationAccess(GF_NORTH_F1_CARPENTER, - { [] { return CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD); }, - /*Glitched*/ [] { return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE); } }), + LocationAccess( + GF_NORTH_F1_CARPENTER, + { [] { return SoulGerudo && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)); }, + /*Glitched*/ [] { return SoulGerudo && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE); } }), LocationAccess(GF_NORTH_F2_CARPENTER, { [] { - return (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || + return SoulGerudo && + (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)) && (GerudoToken || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(HOVER_BOOTS) || LogicGerudoKitchen); }, /*Glitched*/ [] { - return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE) && + return SoulGerudo && + CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE) && (GerudoToken || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(HOVER_BOOTS) || LogicGerudoKitchen); } }), - LocationAccess(GF_SOUTH_F1_CARPENTER, - { [] { return CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD); }, - /*Glitched*/ [] { return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE); } }), - LocationAccess(GF_SOUTH_F2_CARPENTER, - { [] { return CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD); }, - /*Glitched*/ [] { return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE); } }), + LocationAccess( + GF_SOUTH_F1_CARPENTER, + { [] { return SoulGerudo && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)); }, + /*Glitched*/ [] { return SoulGerudo && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE); } }), + LocationAccess( + GF_SOUTH_F2_CARPENTER, + { [] { return SoulGerudo && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)); }, + /*Glitched*/ [] { return SoulGerudo && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE); } }), LocationAccess(GF_GERUDO_TOKEN, { [] { return CanFinishGerudoFortress; } }), }, { diff --git a/source/location_access/locacc_hyrule_field.cpp b/source/location_access/locacc_hyrule_field.cpp index 73e0d713..37e51d29 100644 --- a/source/location_access/locacc_hyrule_field.cpp +++ b/source/location_access/locacc_hyrule_field.cpp @@ -10,7 +10,7 @@ void AreaTable_Init_HyruleField() { "Hyrule Field", "Hyrule Field", HYRULE_FIELD, DAY_NIGHT_CYCLE, { // Events - EventAccess(&BigPoeKill, { [] { return CanUse(BOW) && CanRideEpona && HasBottle; } }), + EventAccess(&BigPoeKill, { [] { return SoulPoe && CanUse(BOW) && CanRideEpona && HasBottle; } }), }, { // Locations @@ -196,7 +196,7 @@ void AreaTable_Init_HyruleField() { EventAccess(&ButterflyFairy, { [] { return ButterflyFairy || CanUse(STICKS); } }), EventAccess(&BugShrub, { [] { return BugShrub || (IsChild && CanCutShrubs); } }), EventAccess(&ChildScarecrow, - { [] { return ChildScarecrow || (IsChild && Ocarina); }, + { [] { return ChildScarecrow || (IsChild && Ocarina && (OcarinaButtonsCount >= 2)); }, /*Glitched*/ [] { return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || @@ -208,17 +208,17 @@ void AreaTable_Init_HyruleField() { CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE))) && IsChild; } }), - EventAccess(&AdultScarecrow, { [] { return AdultScarecrow || (IsAdult && Ocarina); }, - /*Glitched*/ - [] { - return (CanDoGlitch(GlitchType::OutdoorBombOI, - GlitchDifficulty::INTERMEDIATE) || - ((Bugs || Fish) && CanShield && - CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || - ((Bugs || Fish) && CanDoGlitch(GlitchType::ActionSwap, - GlitchDifficulty::NOVICE))) && - IsAdult; - } }), + EventAccess(&AdultScarecrow, + { [] { return AdultScarecrow || (IsAdult && Ocarina && (OcarinaButtonsCount >= 2)); }, + /*Glitched*/ + [] { + return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || + ((Bugs || Fish) && CanShield && + CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && + CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE))) && + IsAdult; + } }), }, { // Locations diff --git a/source/location_access/locacc_ice_cavern.cpp b/source/location_access/locacc_ice_cavern.cpp index e3cd8214..b248b1b9 100644 --- a/source/location_access/locacc_ice_cavern.cpp +++ b/source/location_access/locacc_ice_cavern.cpp @@ -29,35 +29,37 @@ void AreaTable_Init_IceCavern() { // Exits Entrance(ICE_CAVERN_ENTRYWAY, { [] { return true; } }), Entrance(ICE_CAVERN_MAIN, { [] { - return Here(ICE_CAVERN_BEGINNING, [] { - return CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || HasExplosives || - CanUse(DINS_FIRE); - }); + return SoulFreezard && Here(ICE_CAVERN_BEGINNING, [] { + return CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || HasExplosives || + CanUse(DINS_FIRE); + }); } }), }); - areaTable[ICE_CAVERN_MAIN] = Area( - "Ice Cavern", "Ice Cavern", ICE_CAVERN, NO_DAY_NIGHT_CYCLE, - { - // Events - EventAccess(&BlueFireAccess, { [] { return BlueFireAccess || (IsAdult && HasBottle); } }), - }, - { - // Locations - LocationAccess(ICE_CAVERN_MAP_CHEST, { [] { return BlueFire && IsAdult; } }), - LocationAccess(ICE_CAVERN_COMPASS_CHEST, { [] { return BlueFire; } }), - LocationAccess(ICE_CAVERN_IRON_BOOTS_CHEST, - { [] { return BlueFire && (CanJumpslash || CanUse(SLINGSHOT) || CanUse(DINS_FIRE)); } }), - LocationAccess(SHEIK_IN_ICE_CAVERN, { [] { - return BlueFire && (CanJumpslash || CanUse(SLINGSHOT) || CanUse(DINS_FIRE)) && - IsAdult; - } }), - LocationAccess(ICE_CAVERN_FREESTANDING_POH, { [] { return BlueFire; } }), - LocationAccess(ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM, { [] { return HookshotOrBoomerang; } }), - LocationAccess(ICE_CAVERN_GS_HEART_PIECE_ROOM, { [] { return BlueFire && HookshotOrBoomerang; } }), - LocationAccess(ICE_CAVERN_GS_PUSH_BLOCK_ROOM, { [] { return BlueFire && HookshotOrBoomerang; } }), - }, - {}); + areaTable[ICE_CAVERN_MAIN] = + Area("Ice Cavern", "Ice Cavern", ICE_CAVERN, NO_DAY_NIGHT_CYCLE, + { + // Events + EventAccess(&BlueFireAccess, { [] { return BlueFireAccess || (IsAdult && HasBottle); } }), + }, + { + // Locations + LocationAccess(ICE_CAVERN_MAP_CHEST, { [] { return BlueFire && IsAdult; } }), + LocationAccess(ICE_CAVERN_COMPASS_CHEST, { [] { return BlueFire; } }), + LocationAccess(ICE_CAVERN_IRON_BOOTS_CHEST, { [] { + return BlueFire && SoulWolfos && + (CanJumpslash || CanUse(SLINGSHOT) || CanUse(DINS_FIRE)); + } }), + LocationAccess(SHEIK_IN_ICE_CAVERN, { [] { + return BlueFire && SoulWolfos && + (CanJumpslash || CanUse(SLINGSHOT) || CanUse(DINS_FIRE)) && IsAdult; + } }), + LocationAccess(ICE_CAVERN_FREESTANDING_POH, { [] { return BlueFire; } }), + LocationAccess(ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM, { [] { return HookshotOrBoomerang; } }), + LocationAccess(ICE_CAVERN_GS_HEART_PIECE_ROOM, { [] { return BlueFire && HookshotOrBoomerang; } }), + LocationAccess(ICE_CAVERN_GS_PUSH_BLOCK_ROOM, { [] { return BlueFire && HookshotOrBoomerang; } }), + }, + {}); } /*--------------------------- diff --git a/source/location_access/locacc_jabujabus_belly.cpp b/source/location_access/locacc_jabujabus_belly.cpp index cdaf305c..f389c067 100644 --- a/source/location_access/locacc_jabujabus_belly.cpp +++ b/source/location_access/locacc_jabujabus_belly.cpp @@ -59,16 +59,18 @@ void AreaTable_Init_JabuJabusBelly() { } }), }); - areaTable[JABU_JABUS_BELLY_MAIN_UPPER] = Area( - "Jabu Jabus Belly Main Upper", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, - { - // Exits - Entrance(JABU_JABUS_BELLY_LIFT_MIDDLE, { [] { return true; } }), - Entrance(JABU_JABUS_BELLY_MAIN_LOWER, { [] { return true; } }), - Entrance(JABU_JABUS_BELLY_FORKED_CORRIDOR, { [] { return true; } }), - Entrance(JABU_JABUS_BELLY_BIGOCTO_ROOM, - { [] { return Here(JABU_JABUS_BELLY_GREEN_TENTACLE, [] { return CanUse(BOOMERANG); }); } }), - }); + areaTable[JABU_JABUS_BELLY_MAIN_UPPER] = + Area("Jabu Jabus Belly Main Upper", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, + { + // Exits + Entrance(JABU_JABUS_BELLY_LIFT_MIDDLE, { [] { return true; } }), + Entrance(JABU_JABUS_BELLY_MAIN_LOWER, { [] { return true; } }), + Entrance(JABU_JABUS_BELLY_FORKED_CORRIDOR, { [] { return true; } }), + Entrance(JABU_JABUS_BELLY_BIGOCTO_ROOM, { [] { + return Here(JABU_JABUS_BELLY_GREEN_TENTACLE, + [] { return SoulParasiticTentacle && CanUse(BOOMERANG); }); + } }), + }); areaTable[JABU_JABUS_BELLY_MAIN_LOWER] = Area("Jabu Jabus Belly Main Lower", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, @@ -153,26 +155,32 @@ void AreaTable_Init_JabuJabusBelly() { Entrance(JABU_JABUS_BELLY_LIFT_MIDDLE, { [] { return true; } }), }); - areaTable[JABU_JABUS_BELLY_FORKED_CORRIDOR] = Area( - "Jabu Jabus Belly Forked Corridor", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, - { - // Exits - Entrance(JABU_JABUS_BELLY_MAIN_UPPER, { [] { return true; } }), - Entrance(JABU_JABUS_BELLY_BOOMERANG_ROOM, { [] { return true; } }), - Entrance(JABU_JABUS_BELLY_MAP_ROOM, { [] { return true; } }), - Entrance(JABU_JABUS_BELLY_COMPASS_ROOM, - { [] { return Here(JABU_JABUS_BELLY_MAP_ROOM, [] { return CanUse(BOOMERANG); }); } }), - Entrance(JABU_JABUS_BELLY_BLUE_TENTACLE, - { [] { return Here(JABU_JABUS_BELLY_MAP_ROOM, [] { return CanUse(BOOMERANG); }); } }), - Entrance(JABU_JABUS_BELLY_GREEN_TENTACLE, - { [] { return Here(JABU_JABUS_BELLY_BLUE_TENTACLE, [] { return CanUse(BOOMERANG); }); } }), - }); + areaTable[JABU_JABUS_BELLY_FORKED_CORRIDOR] = + Area("Jabu Jabus Belly Forked Corridor", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, + { + // Exits + Entrance(JABU_JABUS_BELLY_MAIN_UPPER, { [] { return true; } }), + Entrance(JABU_JABUS_BELLY_BOOMERANG_ROOM, { [] { return true; } }), + Entrance(JABU_JABUS_BELLY_MAP_ROOM, { [] { return true; } }), + Entrance(JABU_JABUS_BELLY_COMPASS_ROOM, { [] { + return Here(JABU_JABUS_BELLY_MAP_ROOM, + [] { return SoulParasiticTentacle && CanUse(BOOMERANG); }); + } }), + Entrance(JABU_JABUS_BELLY_BLUE_TENTACLE, { [] { + return Here(JABU_JABUS_BELLY_MAP_ROOM, + [] { return SoulParasiticTentacle && CanUse(BOOMERANG); }); + } }), + Entrance(JABU_JABUS_BELLY_GREEN_TENTACLE, { [] { + return Here(JABU_JABUS_BELLY_BLUE_TENTACLE, + [] { return SoulParasiticTentacle && CanUse(BOOMERANG); }); + } }), + }); areaTable[JABU_JABUS_BELLY_BOOMERANG_ROOM] = Area("Jabu Jabus Belly Boomerang Room", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, { // Locations - LocationAccess(JABU_JABUS_BELLY_BOOMERANG_CHEST, { [] { return true; } }), + LocationAccess(JABU_JABUS_BELLY_BOOMERANG_CHEST, { [] { return SoulStinger; } }), }, { // Exits @@ -183,52 +191,58 @@ void AreaTable_Init_JabuJabusBelly() { Area("Jabu Jabus Belly Map Room", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, { // Locations - LocationAccess(JABU_JABUS_BELLY_MAP_CHEST, { [] { return CanUse(BOOMERANG); } }), + LocationAccess(JABU_JABUS_BELLY_MAP_CHEST, + { [] { return SoulParasiticTentacle && CanUse(BOOMERANG); } }), }, { // Exits Entrance(JABU_JABUS_BELLY_FORKED_CORRIDOR, { [] { return true; } }), }); - areaTable[JABU_JABUS_BELLY_COMPASS_ROOM] = Area( - "Jabu Jabus Belly Compass Room", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, - { - // Locations - LocationAccess(JABU_JABUS_BELLY_COMPASS_CHEST, { [] { return CanAdultAttack || CanChildAttack; } }), - }, - { - // Exits - Entrance(JABU_JABUS_BELLY_FORKED_CORRIDOR, { [] { return true; } }), - }); - - areaTable[JABU_JABUS_BELLY_BLUE_TENTACLE] = Area( - "Jabu Jabus Belly Blue Tentacle", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, - { - // Exits - Entrance(JABU_JABUS_BELLY_FORKED_CORRIDOR, - { [] { return Here(JABU_JABUS_BELLY_BLUE_TENTACLE, [] { return CanUse(BOOMERANG); }); } }), - }); + areaTable[JABU_JABUS_BELLY_COMPASS_ROOM] = + Area("Jabu Jabus Belly Compass Room", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, + { + // Locations + LocationAccess(JABU_JABUS_BELLY_COMPASS_CHEST, + { [] { return SoulShabom && (CanAdultAttack || CanChildAttack); } }), + }, + { + // Exits + Entrance(JABU_JABUS_BELLY_FORKED_CORRIDOR, { [] { return true; } }), + }); - areaTable[JABU_JABUS_BELLY_GREEN_TENTACLE] = Area( - "Jabu Jabus Belly Green Tentacle", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, - { - // Exits - Entrance(JABU_JABUS_BELLY_FORKED_CORRIDOR, - { [] { return Here(JABU_JABUS_BELLY_GREEN_TENTACLE, [] { return CanUse(BOOMERANG); }); } }), - }); + areaTable[JABU_JABUS_BELLY_BLUE_TENTACLE] = + Area("Jabu Jabus Belly Blue Tentacle", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, + { + // Exits + Entrance(JABU_JABUS_BELLY_FORKED_CORRIDOR, { [] { + return Here(JABU_JABUS_BELLY_BLUE_TENTACLE, + [] { return SoulParasiticTentacle && CanUse(BOOMERANG); }); + } }), + }); - areaTable[JABU_JABUS_BELLY_BIGOCTO_ROOM] = - Area("Jabu Jabus Belly Bigocto Room", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, + areaTable[JABU_JABUS_BELLY_GREEN_TENTACLE] = + Area("Jabu Jabus Belly Green Tentacle", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, { // Exits - Entrance(JABU_JABUS_BELLY_MAIN_LOWER, { [] { return true; } }), - Entrance(JABU_JABUS_BELLY_ABOVE_BIGOCTO, { [] { - return Here(JABU_JABUS_BELLY_BIGOCTO_ROOM, [] { - return (CanUse(BOOMERANG) || Nuts) && (CanUse(KOKIRI_SWORD) || CanUse(STICKS)); - }); + Entrance(JABU_JABUS_BELLY_FORKED_CORRIDOR, { [] { + return Here(JABU_JABUS_BELLY_GREEN_TENTACLE, + [] { return SoulParasiticTentacle && CanUse(BOOMERANG); }); } }), }); + areaTable[JABU_JABUS_BELLY_BIGOCTO_ROOM] = Area( + "Jabu Jabus Belly Bigocto Room", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, + { + // Exits + Entrance(JABU_JABUS_BELLY_MAIN_LOWER, { [] { return true; } }), + Entrance(JABU_JABUS_BELLY_ABOVE_BIGOCTO, { [] { + return SoulOctorok && Here(JABU_JABUS_BELLY_BIGOCTO_ROOM, [] { + return (CanUse(BOOMERANG) || Nuts) && (CanUse(KOKIRI_SWORD) || CanUse(STICKS)); + }); + } }), + }); + areaTable[JABU_JABUS_BELLY_ABOVE_BIGOCTO] = Area("Jabu Jabus Belly Above Bigocto", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, { @@ -376,20 +390,20 @@ void AreaTable_Init_JabuJabusBelly() { Entrance(JABU_JABUS_BELLY_BOSS_ROOM, { [] { return true; } }), }); - areaTable[JABU_JABUS_BELLY_BOSS_ROOM] = - Area("Jabu Jabus Belly Boss Room", "Jabu Jabus Belly", NONE, NO_DAY_NIGHT_CYCLE, - { - // Events - EventAccess(&JabuJabusBellyClear, - { [] { return JabuJabusBellyClear || (CanUse(BOOMERANG) && CanJumpslash); } }), - }, - { - // Locations - LocationAccess(JABU_JABUS_BELLY_BARINADE_HEART, { [] { return JabuJabusBellyClear; } }), - LocationAccess(BARINADE, { [] { return JabuJabusBellyClear; } }), - }, - { - // Exits - Entrance(JABU_JABUS_BELLY_BOSS_ENTRYWAY, { [] { return false; } }), - }); + areaTable[JABU_JABUS_BELLY_BOSS_ROOM] = Area( + "Jabu Jabus Belly Boss Room", "Jabu Jabus Belly", NONE, NO_DAY_NIGHT_CYCLE, + { + // Events + EventAccess(&JabuJabusBellyClear, + { [] { return JabuJabusBellyClear || (SoulBarinade && CanUse(BOOMERANG) && CanJumpslash); } }), + }, + { + // Locations + LocationAccess(JABU_JABUS_BELLY_BARINADE_HEART, { [] { return JabuJabusBellyClear; } }), + LocationAccess(BARINADE, { [] { return JabuJabusBellyClear; } }), + }, + { + // Exits + Entrance(JABU_JABUS_BELLY_BOSS_ENTRYWAY, { [] { return false; } }), + }); } diff --git a/source/location_access/locacc_kakariko.cpp b/source/location_access/locacc_kakariko.cpp index b813a2e4..3a0deff3 100644 --- a/source/location_access/locacc_kakariko.cpp +++ b/source/location_access/locacc_kakariko.cpp @@ -316,19 +316,20 @@ void AreaTable_Init_Kakariko() { Entrance(KAK_BACKYARD, { [] { return true; } }), }); - areaTable[KAK_REDEAD_GROTTO] = Area("Kak Redead Grotto", "Kak Redead Grotto", NONE, NO_DAY_NIGHT_CYCLE, {}, - { - // Locations - LocationAccess(KAK_REDEAD_GROTTO_CHEST, { [] { - return CanUse(STICKS) || CanUse(KOKIRI_SWORD) || - CanUse(DINS_FIRE) || CanUse(MEGATON_HAMMER) || - CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD); - } }), - }, - { - // Exits - Entrance(KAKARIKO_VILLAGE, { [] { return true; } }), - }); + areaTable[KAK_REDEAD_GROTTO] = + Area("Kak Redead Grotto", "Kak Redead Grotto", NONE, NO_DAY_NIGHT_CYCLE, {}, + { + // Locations + LocationAccess(KAK_REDEAD_GROTTO_CHEST, { [] { + return SoulRedeadGibdo && + (CanUse(STICKS) || CanUse(KOKIRI_SWORD) || CanUse(DINS_FIRE) || + CanUse(MEGATON_HAMMER) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)); + } }), + }, + { + // Exits + Entrance(KAKARIKO_VILLAGE, { [] { return true; } }), + }); areaTable[KAK_OPEN_GROTTO] = Area("Kak Open Grotto", "Kak Open Grotto", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, { @@ -442,8 +443,9 @@ void AreaTable_Init_Kakariko() { { [] { return HasFireSource; }, /*Glitched*/ [] { return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::INTERMEDIATE); } }), - LocationAccess(SONG_FROM_COMPOSERS_GRAVE, - { [] { return CanUseProjectile || CanJumpslash || CanUse(MEGATON_HAMMER); } }), + LocationAccess(SONG_FROM_COMPOSERS_GRAVE, { [] { + return SoulKeese && (CanUseProjectile || CanJumpslash || CanUse(MEGATON_HAMMER)); + } }), }, { // Exits diff --git a/source/location_access/locacc_lost_woods.cpp b/source/location_access/locacc_lost_woods.cpp index fdd87906..c02bce12 100644 --- a/source/location_access/locacc_lost_woods.cpp +++ b/source/location_access/locacc_lost_woods.cpp @@ -31,7 +31,7 @@ void AreaTable_Init_LostWoods() { Entrance(KF_KOKIRI_SHOP, { [] { return true; } }), Entrance(KF_OUTSIDE_DEKU_TREE, { [] { - return (IsAdult && (CanAdultDamage || ForestTempleClear)) || + return (IsAdult && ((SoulSkulltula && CanAdultDamage) || ForestTempleClear)) || (IsChild && (OpenForest.Is(OPENFOREST_OPEN) || ShowedMidoSwordAndShield)); }, /*Glitched*/ @@ -64,51 +64,52 @@ void AreaTable_Init_LostWoods() { } }), }); - areaTable[KF_OUTSIDE_DEKU_TREE] = - Area("KF Outside Deku Tree", "Kokiri Forest", KOKIRI_FOREST, NO_DAY_NIGHT_CYCLE, - { - // Events - EventAccess(&DekuBabaSticks, { [] { - return DekuBabaSticks || ((IsAdult && (MasterSword || BiggoronSword) && - ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF)) || - KokiriSword || Boomerang); - } }), - EventAccess(&DekuBabaNuts, { [] { - return DekuBabaNuts || ((IsAdult && (MasterSword || BiggoronSword) && - ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF)) || - KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE)); - } }), - EventAccess(&ShowedMidoSwordAndShield, - { [] { return ShowedMidoSwordAndShield || (IsChild && KokiriSword && DekuShield); } }), - }, - { - // Locations - LocationAccess(KF_DEKU_TREE_GOSSIP_STONE_LEFT, { [] { return true; } }), - LocationAccess(KF_DEKU_TREE_GOSSIP_STONE_RIGHT, { [] { return true; } }), - }, - { - // Exits - Entrance(DEKU_TREE_ENTRYWAY, - { [] { - return IsChild || (ShuffleDungeonEntrances.IsNot(SHUFFLEDUNGEONS_OFF) && - (OpenForest.Is(OPENFOREST_OPEN) || ShowedMidoSwordAndShield)); - }, - /*Glitched*/ - [] { - return CanDoGlitch(GlitchType::HammerSlide, GlitchDifficulty::INTERMEDIATE) || - CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE); - } }), - Entrance(KOKIRI_FOREST, - { [] { - return (IsAdult && (CanAdultDamage || ForestTempleClear)) || - (IsChild && (OpenForest.Is(OPENFOREST_OPEN) || ShowedMidoSwordAndShield)); - }, - /*Glitched*/ - [] { - return CanDoGlitch(GlitchType::ASlide, GlitchDifficulty::INTERMEDIATE) || - CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE); - } }), - }); + areaTable[KF_OUTSIDE_DEKU_TREE] = Area( + "KF Outside Deku Tree", "Kokiri Forest", KOKIRI_FOREST, NO_DAY_NIGHT_CYCLE, + { + // Events + EventAccess(&DekuBabaSticks, { [] { + return DekuBabaSticks || (SoulDekuBaba && ((IsAdult && (MasterSword || BiggoronSword) && + ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF)) || + KokiriSword || Boomerang)); + } }), + EventAccess(&DekuBabaNuts, { [] { + return DekuBabaNuts || + (SoulDekuBaba && ((IsAdult && (MasterSword || BiggoronSword) && + ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF)) || + KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE))); + } }), + EventAccess(&ShowedMidoSwordAndShield, + { [] { return ShowedMidoSwordAndShield || (IsChild && KokiriSword && DekuShield); } }), + }, + { + // Locations + LocationAccess(KF_DEKU_TREE_GOSSIP_STONE_LEFT, { [] { return true; } }), + LocationAccess(KF_DEKU_TREE_GOSSIP_STONE_RIGHT, { [] { return true; } }), + }, + { + // Exits + Entrance(DEKU_TREE_ENTRYWAY, + { [] { + return IsChild || (ShuffleDungeonEntrances.IsNot(SHUFFLEDUNGEONS_OFF) && + (OpenForest.Is(OPENFOREST_OPEN) || ShowedMidoSwordAndShield)); + }, + /*Glitched*/ + [] { + return CanDoGlitch(GlitchType::HammerSlide, GlitchDifficulty::INTERMEDIATE) || + CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE); + } }), + Entrance(KOKIRI_FOREST, { [] { + return (IsAdult && ((SoulSkulltula && CanAdultDamage) || ForestTempleClear)) || + (IsChild && + (OpenForest.Is(OPENFOREST_OPEN) || ShowedMidoSwordAndShield)); + }, + /*Glitched*/ + [] { + return CanDoGlitch(GlitchType::ASlide, GlitchDifficulty::INTERMEDIATE) || + CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE); + } }), + }); areaTable[KF_LINKS_HOUSE] = Area("KF Link's House", "KF Link's House", NONE, NO_DAY_NIGHT_CYCLE, {}, @@ -220,7 +221,7 @@ void AreaTable_Init_LostWoods() { LocationAccess(LW_TRADE_COJIRO, { [] { return IsAdult && Cojiro; } }), LocationAccess(LW_TRADE_ODD_POULTICE, { [] { return IsAdult && OddPoultice && Cojiro; } }), LocationAccess(LW_OCARINA_MEMORY_GAME, - { [] { return IsChild && Ocarina; }, + { [] { return IsChild && Ocarina && (OcarinaButtonsCount >= 5); }, /*Glitched*/ [] { return IsChild && @@ -370,17 +371,18 @@ void AreaTable_Init_LostWoods() { Entrance(LW_BEYOND_MIDO, { [] { return true; } }), }); - areaTable[SFM_ENTRYWAY] = - Area("SFM Entryway", "Sacred Forest Meadow", SACRED_FOREST_MEADOW, NO_DAY_NIGHT_CYCLE, {}, {}, - { - // Exits - Entrance(LW_BEYOND_MIDO, { [] { return true; } }), - Entrance(SACRED_FOREST_MEADOW, { [] { - return CanUse(SLINGSHOT) || CanUse(STICKS) || CanUse(KOKIRI_SWORD) || CanUse(DINS_FIRE) || - CanUse(MEGATON_HAMMER) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD); - } }), - Entrance(SFM_WOLFOS_GROTTO, { [] { return CanOpenBombGrotto; } }), - }); + areaTable[SFM_ENTRYWAY] = Area( + "SFM Entryway", "Sacred Forest Meadow", SACRED_FOREST_MEADOW, NO_DAY_NIGHT_CYCLE, {}, {}, + { + // Exits + Entrance(LW_BEYOND_MIDO, { [] { return true; } }), + Entrance(SACRED_FOREST_MEADOW, { [] { + return ((IsChild && SoulWolfos) || (IsAdult && SoulMoblin)) && + (CanUse(SLINGSHOT) || CanUse(STICKS) || CanUse(KOKIRI_SWORD) || CanUse(DINS_FIRE) || + CanUse(MEGATON_HAMMER) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)); + } }), + Entrance(SFM_WOLFOS_GROTTO, { [] { return CanOpenBombGrotto; } }), + }); areaTable[SACRED_FOREST_MEADOW] = Area( "Sacred Forest Meadow", "Sacred Forest Meadow", SACRED_FOREST_MEADOW, NO_DAY_NIGHT_CYCLE, @@ -428,20 +430,20 @@ void AreaTable_Init_LostWoods() { Entrance(SACRED_FOREST_MEADOW, { [] { return true; } }), }); - areaTable[SFM_WOLFOS_GROTTO] = Area("SFM Wolfos Grotto", "SFM Wolfos Grotto", NONE, NO_DAY_NIGHT_CYCLE, {}, - { - // Locations - LocationAccess(SFM_WOLFOS_GROTTO_CHEST, { [] { - return CanUse(SLINGSHOT) || CanUse(STICKS) || - CanUse(KOKIRI_SWORD) || CanUse(DINS_FIRE) || - CanUse(MEGATON_HAMMER) || CanUse(MASTER_SWORD) || - CanUse(BIGGORON_SWORD); - } }), - }, - { - // Exits - Entrance(SFM_ENTRYWAY, { [] { return true; } }), - }); + areaTable[SFM_WOLFOS_GROTTO] = + Area("SFM Wolfos Grotto", "SFM Wolfos Grotto", NONE, NO_DAY_NIGHT_CYCLE, {}, + { + // Locations + LocationAccess(SFM_WOLFOS_GROTTO_CHEST, { [] { + return SoulWolfos && (CanUse(SLINGSHOT) || CanUse(STICKS) || CanUse(KOKIRI_SWORD) || + CanUse(DINS_FIRE) || CanUse(MEGATON_HAMMER) || + CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)); + } }), + }, + { + // Exits + Entrance(SFM_ENTRYWAY, { [] { return true; } }), + }); areaTable[SFM_STORMS_GROTTO] = Area("SFM Storms Grotto", "SFM Storms Grotto", NONE, NO_DAY_NIGHT_CYCLE, {}, { diff --git a/source/location_access/locacc_shadow_temple.cpp b/source/location_access/locacc_shadow_temple.cpp index 278fcdff..251cf3b0 100644 --- a/source/location_access/locacc_shadow_temple.cpp +++ b/source/location_access/locacc_shadow_temple.cpp @@ -51,9 +51,11 @@ void AreaTable_Init_ShadowTemple() { }, { // Locations - LocationAccess(SHADOW_TEMPLE_MAP_CHEST, { [] { return CanJumpslash; } }), + LocationAccess(SHADOW_TEMPLE_MAP_CHEST, + { [] { return SoulRedeadGibdo && SoulKeese && CanJumpslash; } }), LocationAccess(SHADOW_TEMPLE_HOVER_BOOTS_CHEST, { [] { - return CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD); + return SoulDeadHand && + (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)); } }), }, { @@ -72,7 +74,7 @@ void AreaTable_Init_ShadowTemple() { }, { // Locations - LocationAccess(SHADOW_TEMPLE_COMPASS_CHEST, { [] { return CanJumpslash; } }), + LocationAccess(SHADOW_TEMPLE_COMPASS_CHEST, { [] { return SoulRedeadGibdo && CanJumpslash; } }), LocationAccess(SHADOW_TEMPLE_EARLY_SILVER_RUPEE_CHEST, { [] { return CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT); } }), LocationAccess(SHADOW_TEMPLE_GS_NEAR_SHIP, { [] { return false; }, @@ -100,15 +102,23 @@ void AreaTable_Init_ShadowTemple() { Area("Shadow Temple Huge Pit", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { // Locations - LocationAccess(SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST, { [] { return CanJumpslash; } }), - LocationAccess(SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST, { [] { return CanJumpslash; } }), + LocationAccess( + SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST, + { [] { return SoulKeese && SoulLikeLike && CanJumpslash; }, + /*Glitched*/ + [] { return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::INTERMEDIATE); } }), + LocationAccess( + SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST, + { [] { return SoulKeese && SoulLikeLike && CanJumpslash; }, + /*Glitched*/ + [] { return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::INTERMEDIATE); } }), LocationAccess(SHADOW_TEMPLE_FALLING_SPIKES_LOWER_CHEST, { [] { return true; } }), LocationAccess(SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST, { [] { return LogicShadowUmbrella || GoronBracelet; } }), LocationAccess(SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST, { [] { return LogicShadowUmbrella || GoronBracelet; } }), LocationAccess(SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST, { [] { - return SmallKeys(SHADOW_TEMPLE, 2, 3) && + return SoulRedeadGibdo && SmallKeys(SHADOW_TEMPLE, 2, 3) && (LogicLensShadowBack || CanUse(LENS_OF_TRUTH)); } }), LocationAccess(SHADOW_TEMPLE_FREESTANDING_KEY, { [] { @@ -116,7 +126,11 @@ void AreaTable_Init_ShadowTemple() { (LogicLensShadowBack || CanUse(LENS_OF_TRUTH)) && Hookshot && (Bombs || GoronBracelet || (LogicShadowFreestandingKey && HasBombchus)); } }), - LocationAccess(SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM, { [] { return CanJumpslash; } }), + LocationAccess( + SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM, + { [] { return SoulKeese && SoulLikeLike && CanJumpslash; }, + /*Glitched*/ + [] { return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::INTERMEDIATE); } }), LocationAccess(SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM, { [] { return Hookshot; } }), LocationAccess(SHADOW_TEMPLE_GS_SINGLE_GIANT_POT, { [] { return SmallKeys(SHADOW_TEMPLE, 2, 3) && @@ -136,7 +150,8 @@ void AreaTable_Init_ShadowTemple() { { // Locations LocationAccess(SHADOW_TEMPLE_WIND_HINT_CHEST, { [] { return true; } }), - LocationAccess(SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST, { [] { return CanJumpslash; } }), + LocationAccess(SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST, + { [] { return SoulFlyingTrap && SoulRedeadGibdo && CanJumpslash; } }), LocationAccess(SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST, { [] { return true; } }), LocationAccess(SHADOW_TEMPLE_GS_NEAR_SHIP, { [] { return CanJumpslash && CanUse(LONGSHOT) && SmallKeys(SHADOW_TEMPLE, 4, 5); } }), @@ -153,7 +168,8 @@ void AreaTable_Init_ShadowTemple() { // Locations LocationAccess(SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST, { [] { return CanUse(DINS_FIRE); } }), LocationAccess(SHADOW_TEMPLE_BOSS_KEY_CHEST, { [] { return CanUse(DINS_FIRE); } }), - LocationAccess(SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST, { [] { return CanJumpslash; } }), + LocationAccess(SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST, + { [] { return SoulWallmaster && CanJumpslash; } }), LocationAccess(SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT, { [] { return CanAdultAttack; } }), }, { @@ -325,7 +341,8 @@ void AreaTable_Init_ShadowTemple() { // Events EventAccess(&ShadowTempleClear, { [] { return ShadowTempleClear || - ((CanUse(LENS_OF_TRUTH) || ((Dungeon::ShadowTemple.IsVanilla() && LogicLensShadowBack) || + (SoulBongoBongo && + (CanUse(LENS_OF_TRUTH) || ((Dungeon::ShadowTemple.IsVanilla() && LogicLensShadowBack) || (Dungeon::ShadowTemple.IsMQ() && LogicLensShadowMQBack))) && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)) && (CanUse(HOOKSHOT) || CanUse(BOW) || CanUse(SLINGSHOT) || LogicShadowBongo)); diff --git a/source/location_access/locacc_spirit_temple.cpp b/source/location_access/locacc_spirit_temple.cpp index 2d447cc8..06b50100 100644 --- a/source/location_access/locacc_spirit_temple.cpp +++ b/source/location_access/locacc_spirit_temple.cpp @@ -41,18 +41,21 @@ void AreaTable_Init_SpiritTemple() { { // Locations LocationAccess(SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST, { [] { - return (Boomerang || Slingshot || (HasExplosives && LogicSpiritChildBombchu)) && + return SoulKeese && SoulArmos && + (Boomerang || Slingshot || (HasExplosives && LogicSpiritChildBombchu)) && (HasExplosives || ((Nuts || Boomerang) && (Sticks || KokiriSword || Slingshot))); } }), LocationAccess(SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST, { [] { - return (Boomerang || Slingshot || (HasExplosives && LogicSpiritChildBombchu)) && + return SoulKeese && SoulArmos && + (Boomerang || Slingshot || (HasExplosives && LogicSpiritChildBombchu)) && (HasExplosives || ((Nuts || Boomerang) && (Sticks || KokiriSword || Slingshot))) && (Sticks || CanUse(DINS_FIRE)); } }), LocationAccess(SPIRIT_TEMPLE_GS_METAL_FENCE, { [] { - return (Boomerang || Slingshot || (HasExplosives && LogicSpiritChildBombchu)) && + return SoulKeese && SoulArmos && + (Boomerang || Slingshot || (HasExplosives && LogicSpiritChildBombchu)) && (HasExplosives || ((Nuts || Boomerang) && (Sticks || KokiriSword || Slingshot))); } }), @@ -176,7 +179,8 @@ void AreaTable_Init_SpiritTemple() { }, { // Exits - Entrance(SPIRIT_TEMPLE_OUTDOOR_HANDS, { [] { return CanJumpslash || HasExplosives; } }), + Entrance(SPIRIT_TEMPLE_OUTDOOR_HANDS, + { [] { return SoulAnubis && SoulBeamos && SoulGerudo && (CanJumpslash || HasExplosives); } }), Entrance(SPIRIT_TEMPLE_BEYOND_CENTRAL_LOCKED_DOOR, { [] { return SmallKeys(SPIRIT_TEMPLE, 4) && CanUse(SILVER_GAUNTLETS); } }), Entrance(SPIRIT_TEMPLE_CHILD_CLIMB, { [] { return true; } }), @@ -213,35 +217,36 @@ void AreaTable_Init_SpiritTemple() { } }), }); - areaTable[SPIRIT_TEMPLE_BEYOND_CENTRAL_LOCKED_DOOR] = Area( - "Spirit Temple Beyond Central Locked Door", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, - { - // Locations - LocationAccess(SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST, { [] { - return (MirrorShield || (ExtraArrowEffects && CanUse(LIGHT_ARROWS))) && - HasExplosives; - } }), - LocationAccess(SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST, - { [] { return (LogicLensSpirit || CanUse(LENS_OF_TRUTH)) && HasExplosives; } }), - LocationAccess(SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST, - { [] { return (LogicLensSpirit || CanUse(LENS_OF_TRUTH)) && HasExplosives; } }), - }, - { - // Exits - Entrance(SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR, { [] { - return SmallKeys(SPIRIT_TEMPLE, 5) && - (LogicSpiritWall || CanUse(LONGSHOT) || HasBombchus || - ((Bombs || Nuts || CanUse(DINS_FIRE)) && (Bow || CanUse(HOOKSHOT) || Hammer))); - } }), - }); + areaTable[SPIRIT_TEMPLE_BEYOND_CENTRAL_LOCKED_DOOR] = + Area("Spirit Temple Beyond Central Locked Door", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, + { + // Locations + LocationAccess(SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST, { [] { + return (MirrorShield || (ExtraArrowEffects && CanUse(LIGHT_ARROWS))) && + SoulAnubis && SoulBeamos && HasExplosives; + } }), + LocationAccess(SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST, + { [] { return (LogicLensSpirit || CanUse(LENS_OF_TRUTH)) && HasExplosives; } }), + LocationAccess(SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST, + { [] { return (LogicLensSpirit || CanUse(LENS_OF_TRUTH)) && HasExplosives; } }), + }, + { + // Exits + Entrance(SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR, { [] { + return SmallKeys(SPIRIT_TEMPLE, 5) && + (LogicSpiritWall || CanUse(LONGSHOT) || + ((SoulBeamos && (HasBombchus || Bombs || Nuts || CanUse(DINS_FIRE))) && + (SoulSkulltula && (HasBombchus || Bow || CanUse(HOOKSHOT) || Hammer)))); + } }), + }); areaTable[SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR] = Area("Spirit Temple Beyond Final Locked Door", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { // Locations LocationAccess(SPIRIT_TEMPLE_BOSS_KEY_CHEST, { [] { - return CanPlay(ZeldasLullaby) && - ((CanTakeDamage && LogicFlamingChests) || (Bow && Hookshot)); + return CanPlay(ZeldasLullaby) && ((CanTakeDamage && LogicFlamingChests) || + (SoulDoorMimic && Bow && Hookshot)); } }), LocationAccess(SPIRIT_TEMPLE_TOPMOST_CHEST, { [] { return (MirrorShield || (ExtraArrowEffects && CanUse(LIGHT_ARROWS))) && @@ -477,7 +482,7 @@ void AreaTable_Init_SpiritTemple() { { // Events EventAccess(&SpiritTempleClear, { [] { - return SpiritTempleClear || (CanUse(MIRROR_SHIELD) && + return SpiritTempleClear || (SoulTwinrova && SoulGerudo && CanUse(MIRROR_SHIELD) && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD))); } }), }, diff --git a/source/location_access/locacc_water_temple.cpp b/source/location_access/locacc_water_temple.cpp index 8191c471..1534979f 100644 --- a/source/location_access/locacc_water_temple.cpp +++ b/source/location_access/locacc_water_temple.cpp @@ -176,22 +176,22 @@ void AreaTable_Init_WaterTemple() { { [] { return WaterTempleLow && (HasFireSourceWithTorch || CanUse(BOW)); } }), }); - areaTable[WATER_TEMPLE_MAP_ROOM] = - Area("Water Temple Map Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, - { - // Locations - LocationAccess(WATER_TEMPLE_MAP_CHEST, { [] { - return (MagicMeter && CanUse(KOKIRI_SWORD)) || CanUse(MASTER_SWORD) || - CanUse(BIGGORON_SWORD) || CanUse(HOOKSHOT); - } }), - }, - { - // Exits - Entrance(WATER_TEMPLE_EAST_LOWER, { [] { - return (MagicMeter && CanUse(KOKIRI_SWORD)) || CanUse(MASTER_SWORD) || - CanUse(BIGGORON_SWORD) || CanUse(HOOKSHOT); - } }), - }); + areaTable[WATER_TEMPLE_MAP_ROOM] = Area( + "Water Temple Map Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, + { + // Locations + LocationAccess(WATER_TEMPLE_MAP_CHEST, { [] { + return SoulSpike && ((MagicMeter && CanUse(KOKIRI_SWORD)) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(HOOKSHOT)); + } }), + }, + { + // Exits + Entrance(WATER_TEMPLE_EAST_LOWER, { [] { + return SoulSpike && ((MagicMeter && CanUse(KOKIRI_SWORD)) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(HOOKSHOT)); + } }), + }); areaTable[WATER_TEMPLE_CRACKED_WALL] = Area( "Water Temple Cracked Wall", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, @@ -207,22 +207,23 @@ void AreaTable_Init_WaterTemple() { Entrance(WATER_TEMPLE_EAST_LOWER, { [] { return true; } }), }); - areaTable[WATER_TEMPLE_TORCH_ROOM] = - Area("Water Temple Torch Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, - { - // Locations - LocationAccess(WATER_TEMPLE_TORCHES_CHEST, { [] { - return (MagicMeter && CanUse(KOKIRI_SWORD)) || CanUse(MASTER_SWORD) || - CanUse(BIGGORON_SWORD) || CanUse(HOOKSHOT); - } }), - }, - { - // Exits - Entrance(WATER_TEMPLE_EAST_LOWER, { [] { - return (MagicMeter && CanUse(KOKIRI_SWORD)) || CanUse(MASTER_SWORD) || - CanUse(BIGGORON_SWORD) || CanUse(HOOKSHOT); - } }), - }); + areaTable[WATER_TEMPLE_TORCH_ROOM] = Area( + "Water Temple Torch Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, + { + // Locations + LocationAccess(WATER_TEMPLE_TORCHES_CHEST, { [] { + return SoulShellBlade && + ((MagicMeter && CanUse(KOKIRI_SWORD)) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(HOOKSHOT)); + } }), + }, + { + // Exits + Entrance(WATER_TEMPLE_EAST_LOWER, { [] { + return SoulShellBlade && ((MagicMeter && CanUse(KOKIRI_SWORD)) || CanUse(MASTER_SWORD) || + CanUse(BIGGORON_SWORD) || CanUse(HOOKSHOT)); + } }), + }); areaTable[WATER_TEMPLE_NORTH_LOWER] = Area("Water Temple North Lower", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, @@ -430,8 +431,10 @@ void AreaTable_Init_WaterTemple() { "Water Temple Central Pillar Basement", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { // Locations - LocationAccess(WATER_TEMPLE_CENTRAL_PILLAR_CHEST, - { [] { return CanUse(HOOKSHOT) && CanUse(IRON_BOOTS) && WaterTimer >= 40; } }), + LocationAccess(WATER_TEMPLE_CENTRAL_PILLAR_CHEST, { [] { + return SoulSpike && SoulShellBlade && CanUse(HOOKSHOT) && CanUse(IRON_BOOTS) && + WaterTimer >= 40; + } }), }, { // Exits @@ -525,11 +528,13 @@ void AreaTable_Init_WaterTemple() { { // Exits Entrance(WATER_TEMPLE_DRAGON_PILLARS_ROOM, { [] { - return (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)) && + return SoulDarkLink && + (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)) && Hearts > 0; } }), Entrance(WATER_TEMPLE_LONGSHOT_ROOM, { [] { - return (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)) && + return SoulDarkLink && + (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)) && Hearts > 0; } }), }); @@ -701,8 +706,8 @@ void AreaTable_Init_WaterTemple() { { // Events EventAccess(&WaterTempleClear, { [] { - return WaterTempleClear || - (CanUse(HOOKSHOT) && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD))); + return WaterTempleClear || (SoulMorpha && CanUse(HOOKSHOT) && + (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD))); } }), }, { diff --git a/source/logic.cpp b/source/logic.cpp index fc2e85f8..8fbf8c25 100644 --- a/source/logic.cpp +++ b/source/logic.cpp @@ -79,6 +79,26 @@ bool EyedropsAccess = false; bool DisableTradeRevert = false; // Songs +bool ZeldasLullaby_item = false; +bool SariasSong_item = false; +bool SunsSong_item = false; +bool SongOfStorms_item = false; +bool EponasSong_item = false; +bool SongOfTime_item = false; +bool MinuetOfForest_item = false; +bool BoleroOfFire_item = false; +bool SerenadeOfWater_item = false; +bool RequiemOfSpirit_item = false; +bool NocturneOfShadow_item = false; +bool PreludeOfLight_item = false; +// Ocarina notes buttons +bool OcarinaButtonL = false; +bool OcarinaButtonR = false; +bool OcarinaButtonX = false; +bool OcarinaButtonY = false; +bool OcarinaButtonA = false; +u8 OcarinaButtonsCount = 0; +// Songs + their ocarina notes bool ZeldasLullaby = false; bool SariasSong = false; bool SunsSong = false; @@ -203,6 +223,55 @@ bool MagicRefill = false; u8 PieceOfHeart = 0; u8 HeartContainer = 0; bool DoubleDefense = false; +u8 TriforcePieces = 0; + +bool SoulPoe = false; +bool SoulOctorok = false; +bool SoulKeese = false; +bool SoulTektite = false; +bool SoulLeever = false; +bool SoulPeahat = false; +bool SoulLizalfosDinolfos = false; +bool SoulShabom = false; +bool SoulBiriBari = false; +bool SoulTailpasaran = false; +bool SoulSkulltula = false; +bool SoulTorchSlug = false; +bool SoulStinger = false; +bool SoulMoblin = false; +bool SoulArmos = false; +bool SoulDekuBaba = false; +bool SoulBubble = false; +bool SoulFlyingTrap = false; +bool SoulBeamos = false; +bool SoulWallmaster = false; +bool SoulRedeadGibdo = false; +bool SoulShellBlade = false; +bool SoulLikeLike = false; +bool SoulParasiticTentacle = false; +bool SoulAnubis = false; +bool SoulSpike = false; +bool SoulSkullKid = false; +bool SoulFreezard = false; +bool SoulDekuScrub = false; +bool SoulWolfos = false; +bool SoulStalchild = false; +bool SoulGuay = false; +bool SoulDoorMimic = false; +bool SoulStalfos = false; +bool SoulDarkLink = false; +bool SoulFlareDancer = false; +bool SoulDeadHand = false; +bool SoulGerudo = false; +bool SoulGohma = false; +bool SoulDodongo = false; +bool SoulBarinade = false; +bool SoulPhantomGanon = false; +bool SoulVolvagia = false; +bool SoulMorpha = false; +bool SoulBongoBongo = false; +bool SoulTwinrova = false; +bool SoulGanon = false; /* --- HELPERS, EVENTS, AND LOCATION ACCESS --- */ /* These are used to simplify reading the logic, but need to be updated @@ -691,6 +760,20 @@ void UpdateHelpers() { AdultsWallet = ProgressiveWallet >= 1; BiggoronSword = BiggoronSword || ProgressiveGiantKnife >= 2; + OcarinaButtonsCount = OcarinaButtonL + OcarinaButtonR + OcarinaButtonX + OcarinaButtonY + OcarinaButtonA; + ZeldasLullaby = ZeldasLullaby_item && OcarinaButtonX && OcarinaButtonA && OcarinaButtonY; + SariasSong = SariasSong_item && OcarinaButtonR && OcarinaButtonY && OcarinaButtonX; + SunsSong = SunsSong_item && OcarinaButtonY && OcarinaButtonR && OcarinaButtonA; + SongOfStorms = SongOfStorms_item && OcarinaButtonL && OcarinaButtonR && OcarinaButtonA; + EponasSong = EponasSong_item && OcarinaButtonA && OcarinaButtonX && OcarinaButtonY; + SongOfTime = SongOfTime_item && OcarinaButtonY && OcarinaButtonL && OcarinaButtonR; + MinuetOfForest = MinuetOfForest_item && OcarinaButtonL && OcarinaButtonA && OcarinaButtonX && OcarinaButtonY; + BoleroOfFire = BoleroOfFire_item && OcarinaButtonR && OcarinaButtonL && OcarinaButtonY; + SerenadeOfWater = SerenadeOfWater_item && OcarinaButtonL && OcarinaButtonR && OcarinaButtonY && OcarinaButtonX; + RequiemOfSpirit = RequiemOfSpirit_item && OcarinaButtonL && OcarinaButtonR && OcarinaButtonY; + NocturneOfShadow = NocturneOfShadow_item && OcarinaButtonX && OcarinaButtonY && OcarinaButtonL && OcarinaButtonR; + PreludeOfLight = PreludeOfLight_item && OcarinaButtonA && OcarinaButtonY && OcarinaButtonX; + ScarecrowSong = ScarecrowSong || FreeScarecrow || (ChildScarecrow && AdultScarecrow); Scarecrow = Hookshot && CanPlay(ScarecrowSong); DistantScarecrow = Longshot && CanPlay(ScarecrowSong); @@ -781,12 +864,13 @@ void UpdateHelpers() { // Gerudo Fortress CanFinishGerudoFortress = - (GerudoFortress.Is(GERUDOFORTRESS_NORMAL) && GerudoFortressKeys >= 4 && - (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)) && - (GerudoToken || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(HOVER_BOOTS) || LogicGerudoKitchen)) || - (GerudoFortress.Is(GERUDOFORTRESS_FAST) && GerudoFortressKeys >= 1 && - (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD))) || - (GerudoFortress.IsNot(GERUDOFORTRESS_NORMAL) && GerudoFortress.IsNot(GERUDOFORTRESS_FAST)); + SoulGerudo && + ((GerudoFortress.Is(GERUDOFORTRESS_NORMAL) && GerudoFortressKeys >= 4 && + (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)) && + (GerudoToken || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(HOVER_BOOTS) || LogicGerudoKitchen)) || + (GerudoFortress.Is(GERUDOFORTRESS_FAST) && GerudoFortressKeys >= 1 && + (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD))) || + (GerudoFortress.IsNot(GERUDOFORTRESS_NORMAL) && GerudoFortress.IsNot(GERUDOFORTRESS_FAST))); HasShield = CanUse(HYLIAN_SHIELD) || CanUse(DEKU_SHIELD); // Mirror shield can't reflect attacks CanShield = CanUse(MIRROR_SHIELD) || HasShield; @@ -987,6 +1071,26 @@ void LogicReset() { DisableTradeRevert = false; // Songs + ZeldasLullaby_item = false; + SariasSong_item = false; + SunsSong_item = false; + SongOfStorms_item = false; + EponasSong_item = false; + SongOfTime_item = false; + MinuetOfForest_item = false; + BoleroOfFire_item = false; + SerenadeOfWater_item = false; + RequiemOfSpirit_item = false; + NocturneOfShadow_item = false; + PreludeOfLight_item = false; + // Ocarina notes buttons + OcarinaButtonL = !ShuffleOcarinaButtons; + OcarinaButtonR = !ShuffleOcarinaButtons; + OcarinaButtonX = !ShuffleOcarinaButtons; + OcarinaButtonY = !ShuffleOcarinaButtons; + OcarinaButtonA = !ShuffleOcarinaButtons; + OcarinaButtonsCount = 0; + // Songs + their ocarina notes ZeldasLullaby = false; SariasSong = false; SunsSong = false; @@ -1109,6 +1213,55 @@ void LogicReset() { PieceOfHeart = 0; HeartContainer = 0; DoubleDefense = false; + TriforcePieces = 0; + + SoulPoe = ShuffleEnemySouls.Is(OFF); + SoulOctorok = ShuffleEnemySouls.Is(OFF); + SoulKeese = ShuffleEnemySouls.Is(OFF); + SoulTektite = ShuffleEnemySouls.Is(OFF); + SoulLeever = ShuffleEnemySouls.Is(OFF); + SoulPeahat = ShuffleEnemySouls.Is(OFF); + SoulLizalfosDinolfos = ShuffleEnemySouls.Is(OFF); + SoulShabom = ShuffleEnemySouls.Is(OFF); + SoulBiriBari = ShuffleEnemySouls.Is(OFF); + SoulTailpasaran = ShuffleEnemySouls.Is(OFF); + SoulSkulltula = ShuffleEnemySouls.Is(OFF); + SoulTorchSlug = ShuffleEnemySouls.Is(OFF); + SoulStinger = ShuffleEnemySouls.Is(OFF); + SoulMoblin = ShuffleEnemySouls.Is(OFF); + SoulArmos = ShuffleEnemySouls.Is(OFF); + SoulDekuBaba = ShuffleEnemySouls.Is(OFF); + SoulBubble = ShuffleEnemySouls.Is(OFF); + SoulFlyingTrap = ShuffleEnemySouls.Is(OFF); + SoulBeamos = ShuffleEnemySouls.Is(OFF); + SoulWallmaster = ShuffleEnemySouls.Is(OFF); + SoulRedeadGibdo = ShuffleEnemySouls.Is(OFF); + SoulShellBlade = ShuffleEnemySouls.Is(OFF); + SoulLikeLike = ShuffleEnemySouls.Is(OFF); + SoulParasiticTentacle = ShuffleEnemySouls.Is(OFF); + SoulAnubis = ShuffleEnemySouls.Is(OFF); + SoulSpike = ShuffleEnemySouls.Is(OFF); + SoulSkullKid = ShuffleEnemySouls.Is(OFF); + SoulFreezard = ShuffleEnemySouls.Is(OFF); + SoulDekuScrub = ShuffleEnemySouls.Is(OFF); + SoulWolfos = ShuffleEnemySouls.Is(OFF); + SoulStalchild = ShuffleEnemySouls.Is(OFF); + SoulGuay = ShuffleEnemySouls.Is(OFF); + SoulDoorMimic = ShuffleEnemySouls.Is(OFF); + SoulStalfos = ShuffleEnemySouls.Is(OFF); + SoulDarkLink = ShuffleEnemySouls.Is(OFF); + SoulFlareDancer = ShuffleEnemySouls.Is(OFF); + SoulDeadHand = ShuffleEnemySouls.Is(OFF); + SoulGerudo = ShuffleEnemySouls.Is(OFF); + SoulGohma = ShuffleEnemySouls.Is(OFF); + SoulDodongo = ShuffleEnemySouls.Is(OFF); + SoulBarinade = ShuffleEnemySouls.Is(OFF); + SoulPhantomGanon = ShuffleEnemySouls.Is(OFF); + SoulVolvagia = ShuffleEnemySouls.Is(OFF); + SoulMorpha = ShuffleEnemySouls.Is(OFF); + SoulBongoBongo = ShuffleEnemySouls.Is(OFF); + SoulTwinrova = ShuffleEnemySouls.Is(OFF); + SoulGanon = ShuffleEnemySouls.Is(OFF); /* --- HELPERS, EVENTS, AND LOCATION ACCESS --- */ /* These are used to simplify reading the logic, but need to be updated diff --git a/source/logic.hpp b/source/logic.hpp index b39fa449..f056cff9 100644 --- a/source/logic.hpp +++ b/source/logic.hpp @@ -74,6 +74,26 @@ extern bool EyedropsAccess; extern bool DisableTradeRevert; // Songs +extern bool ZeldasLullaby_item; +extern bool SariasSong_item; +extern bool SunsSong_item; +extern bool SongOfStorms_item; +extern bool EponasSong_item; +extern bool SongOfTime_item; +extern bool MinuetOfForest_item; +extern bool BoleroOfFire_item; +extern bool SerenadeOfWater_item; +extern bool RequiemOfSpirit_item; +extern bool NocturneOfShadow_item; +extern bool PreludeOfLight_item; +// Ocarina notes buttons +extern bool OcarinaButtonL; +extern bool OcarinaButtonR; +extern bool OcarinaButtonX; +extern bool OcarinaButtonY; +extern bool OcarinaButtonA; +extern u8 OcarinaButtonsCount; +// Songs + their ocarina notes extern bool ZeldasLullaby; extern bool SariasSong; extern bool SunsSong; @@ -197,6 +217,57 @@ extern bool MagicRefill; extern u8 PieceOfHeart; extern u8 HeartContainer; extern bool DoubleDefense; +extern u8 TriforcePieces; + +// Some souls are not currently relevant in logic. If they become such in the future, uncomment their declaration here +// and update their item in item_list.cpp to be an advancement item and use the relevant logic variable. +extern bool SoulPoe; +extern bool SoulOctorok; +extern bool SoulKeese; +// extern bool SoulTektite; +// extern bool SoulLeever; +// extern bool SoulPeahat; +extern bool SoulLizalfosDinolfos; +extern bool SoulShabom; +// extern bool SoulBiriBari; +// extern bool SoulTailpasaran; +extern bool SoulSkulltula; +extern bool SoulTorchSlug; +extern bool SoulStinger; +extern bool SoulMoblin; +extern bool SoulArmos; +extern bool SoulDekuBaba; +extern bool SoulBubble; +extern bool SoulFlyingTrap; +extern bool SoulBeamos; +extern bool SoulWallmaster; +extern bool SoulRedeadGibdo; +extern bool SoulShellBlade; +extern bool SoulLikeLike; +extern bool SoulParasiticTentacle; +extern bool SoulAnubis; +extern bool SoulSpike; +// extern bool SoulSkullKid; +extern bool SoulFreezard; +extern bool SoulDekuScrub; +extern bool SoulWolfos; +// extern bool SoulStalchild; +// extern bool SoulGuay; +extern bool SoulDoorMimic; +extern bool SoulStalfos; +extern bool SoulDarkLink; +extern bool SoulFlareDancer; +extern bool SoulDeadHand; +extern bool SoulGerudo; +extern bool SoulGohma; +extern bool SoulDodongo; +extern bool SoulBarinade; +extern bool SoulPhantomGanon; +extern bool SoulVolvagia; +extern bool SoulMorpha; +extern bool SoulBongoBongo; +extern bool SoulTwinrova; +extern bool SoulGanon; /* --- HELPERS --- */ /* These are used to simplify reading the logic, but need to be updated diff --git a/source/main.cpp b/source/main.cpp index b8cacb33..9b0d31ba 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -43,7 +43,7 @@ int main() { // send inputs off to the menu if (kDown) - MenuUpdate(kDown, updatedByHeld); + MenuUpdate(kDown, updatedByHeld, kHeld); // launch oot3d directly by holding L and R (cartridge only) if (kHeld & KEY_L && kHeld & KEY_R) { diff --git a/source/menu.cpp b/source/menu.cpp index a727708a..6a313232 100644 --- a/source/menu.cpp +++ b/source/menu.cpp @@ -164,19 +164,22 @@ void MoveCursor(u32 kDown, bool updatedByHeld) { } } - if (kDown & KEY_UP) { - currentMenu->menuIdx--; - } - if (kDown & KEY_DOWN) { - currentMenu->menuIdx++; - } + // If this is a sub-menu, loop through items until an unlocked one is reached + do { + if (kDown & KEY_UP) { + currentMenu->menuIdx--; + } + if (kDown & KEY_DOWN) { + currentMenu->menuIdx++; + } - // Bounds checking - if (currentMenu->menuIdx == max) { - currentMenu->menuIdx = 0; - } else if (currentMenu->menuIdx == 0xFFFF) { - currentMenu->menuIdx = max - 1; - } + // Bounds checking + if (currentMenu->menuIdx == max) { + currentMenu->menuIdx = 0; + } else if (currentMenu->menuIdx == 0xFFFF) { + currentMenu->menuIdx = max - 1; + } + } while (currentMenu->mode == SUB_MENU && currentMenu->itemsList->at(currentMenu->menuIdx)->IsLocked()); // Scroll Check u16 max_entries_on_screen = MAX_SUBMENUS_ON_SCREEN; @@ -202,7 +205,7 @@ void MoveCursor(u32 kDown, bool updatedByHeld) { } } -void MenuUpdate(u32 kDown, bool updatedByHeld) { +void MenuUpdate(u32 kDown, bool updatedByHeld, u32 kHeld) { consoleSelect(&bottomScreen); if (currentMenu->mode != POST_GENERATE || (kDown & KEY_B)) { // Don't clear console if ValidateSettings printed error @@ -267,7 +270,7 @@ void MenuUpdate(u32 kDown, bool updatedByHeld) { if (currentMenu->mode == MAIN_MENU) { PrintMainMenu(); } else if (currentMenu->mode == OPTION_MENU) { - UpdateOptionSubMenu(kDown); + UpdateOptionSubMenu(kDown, kHeld); PrintOptionSubMenu(); } else if (currentMenu->mode == LOAD_PREMADE_PRESET) { UpdatePremadePresetsMenu(kDown); @@ -331,17 +334,9 @@ void UpdateCustomCosmeticColors(u32 kDown) { } } -void UpdateOptionSubMenu(u32 kDown) { - if ((kDown & KEY_RIGHT) != 0) { - currentSetting->NextOptionIndex(); - } - if ((kDown & KEY_LEFT) != 0) { - currentSetting->PrevOptionIndex(); - } - - // Bounds checking - currentSetting->SanitizeSelectedOptionIndex(); - +void UpdateOptionSubMenu(u32 kDown, u32 kHeld) { + bool fastScrolling = kHeld & KEY_A; + currentSetting->ScrollOptionIndex(kDown, fastScrolling); currentSetting->SetVariable(); Settings::ForceChange(kDown, currentSetting); UpdateCustomCosmeticColors(kDown); @@ -562,14 +557,17 @@ void PrintSubMenu() { if (i >= currentMenu->itemsList->size()) break; - u8 row = 3 + i; + u8 row = 3 + i; + Menu* selectedMenu = currentMenu->itemsList->at(currentMenu->settingBound + i); // make the current menu green if (currentMenu->menuIdx == currentMenu->settingBound + i) { printf("\x1b[%d;%dH%s>", row, 2, GREEN); - printf("\x1b[%d;%dH%s%s", row, 3, currentMenu->itemsList->at(currentMenu->settingBound + i)->name.c_str(), - RESET); + printf("\x1b[%d;%dH%s%s", row, 3, selectedMenu->name.c_str(), RESET); + } else if (selectedMenu->IsLocked()) { + // Make locked menus gray. + printf("\x1b[%d;%dH%s%s%s", row, 3, DIM, selectedMenu->name.c_str(), RESET); } else { - printf("\x1b[%d;%dH%s", row, 3, currentMenu->itemsList->at(currentMenu->settingBound + i)->name.c_str()); + printf("\x1b[%d;%dH%s", row, 3, selectedMenu->name.c_str()); } } diff --git a/source/menu.hpp b/source/menu.hpp index 2c304f2d..12ab94c2 100644 --- a/source/menu.hpp +++ b/source/menu.hpp @@ -33,7 +33,7 @@ #define WHITE "\x1b[37m" void ModeChangeInit(); -void UpdateOptionSubMenu(u32 kDown); +void UpdateOptionSubMenu(u32 kDown, u32 kHeld); void UpdatePremadePresetsMenu(u32 kDown); void UpdateCustomPresetsMenu(u32 kDown); void UpdateResetToDefaultsMenu(u32 kdown); @@ -51,4 +51,4 @@ void GenerateRandomizer(); std::string GetInput(const char* hintText); extern void MenuInit(); -extern void MenuUpdate(u32 kDown, bool updatedByHeld); +extern void MenuUpdate(u32 kDown, bool updatedByHeld, u32 kHeld); diff --git a/source/patch.cpp b/source/patch.cpp index 4c7c2831..1c6c1b5f 100644 --- a/source/patch.cpp +++ b/source/patch.cpp @@ -646,6 +646,21 @@ bool WriteAllPatches() { return false; } + /*--------------------------------- + | Sold Out Cosmetic Shop Model | + ---------------------------------*/ + + const u32 SHOPITEMENTRY_SOLDOUT_CMBINDEX_ADDR = 0x525672; + char soldOutCMBIndex = 0; + + patchOffset = V_TO_P(SHOPITEMENTRY_SOLDOUT_CMBINDEX_ADDR); + patchSize = 1; + + if (Settings::BetaSoldOut && + !WritePatch(patchOffset, patchSize, &soldOutCMBIndex, code, bytesWritten, totalRW, buf)) { + return false; + } + /*------------------------- | EOF | --------------------------*/ diff --git a/source/settings.cpp b/source/settings.cpp index 754e07c0..b695800a 100644 --- a/source/settings.cpp +++ b/source/settings.cpp @@ -15,6 +15,9 @@ #include "keys.hpp" #include "gold_skulltulas.hpp" +#define CREATE_SOULMENUNAMES +#include "../code/src/enemy_souls.h" + using namespace Cosmetics; using namespace Dungeon; using namespace Trial; @@ -128,6 +131,9 @@ Option MQBotW = Option::U8 (2, "Bottom of the Well", {"Vani Option MQIceCavern = Option::U8 (2, "Ice Cavern", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc}); Option MQGTG = Option::U8 (2, "Training Grounds", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc}); Option MQCastle = Option::U8 (2, "Ganon's Castle", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc}); +Option TriforceHunt = Option::Bool("Triforce Hunt", {"Off", "On"}, {triforceHuntDesc}); +Option TriforcePiecesTotal = Option::U8 (2, "Total pieces", {NumOpts(1, 200)}, {triforcePiecesTotalDesc}, OptionCategory::Setting, 29); +Option TriforcePiecesRequired = Option::U8 (2, "Required pieces", {NumOpts(1, 100)}, {triforcePiecesRequiredDesc}, OptionCategory::Setting, 19); std::vector