Convert grotto entrances to standard entrance system
Grotto and Fairy Fountain Entrance Refactor
Closes #2023. Depends on #2332.
Change grottos to use the same entrance table as other scene exits. To support grottos reusing the same scene/room, alternate setups are created for each unique entrance and the entrance table is relocated and extended. With these changes, grotto entrances and exits are now valid spawn targets, and void and death warps behave consistently. This is a blocking issue for adding mixed entrance pools settings seen on Roman971's branch to main. Fairy fountain grotto fairies are also easier to randomize with setup-specific entrances instead of the same generic scene/room.
Important changes for players
Because grottos now use the same system as other entrances, voiding now consistently returns Link to the grotto exit. Previous strategies to save travel time in Death Mountain Crater using the upper grotto (and maybe other scenes) will no longer work. Previous grotto behavior is not retained as it would require maintaining two independent methods for grotto scene loading and the various item shuffle override lookups, both in the game and in the patcher.
Currently, this PR adds grotto-type entrances and exits as valid spawn and warp targets. This adds up to 66 new spawn points for spawn shuffle, depending on other settings. This is planned to be configurable before merging the feature.
To do
- [ ] Change Warp and Spawn shuffle settings to combobox with "Off, Balanced, Full" options, with the Grotto type in Full. Could also add a "Specific" option with a multiselect for full control.
- [ ] Verify logic works with the new potential exits. Add region reverse exits where needed. Do for both glitchless/advanced.
- [ ] More detailed testing.
Vanilla Hacks
- Relocate entrance table from src/code/z_scene_table.c
- Update src/code/z_demo.c checks for SCENE_TEMPLE_OF_TIME and SCENE_GANON_BOSS in Cutscene_HandleConditionalTriggers()
- Update src/code/z_play.c
- scene layer checks for SCENE_HYRULE_FIELD and SCENE_KOKIRI_FOREST in Play_Init()
- arguments to Play_SpawnScene() in Play_Init()
- patch for SCENE_GERUDO_VALLEY for playing credits on GC in Play_Init(), does it affect VC?
- set entrance transition type in Play_Init()
- "continue bgm" flag lookup in Play_Update()
- Update src/code/z_scene.c setting transition type in Scene_SetTransitionForNextEntrance()
- Update src/overlays/actors/ovl_player_actor/z_player.c title card flag lookup
- en_torch actors use new grotto entrance table for setting chest contents instead of the save context respawn data.
- Change src/overlays/actors/ovl_Door_Ana/z_door_ana.c (grotto actor)
- DoorAna_WaitOpen()
- nop all the respawn stuff
- check what the PLAYER_STATE1_31 and attentionRangeType flags do
- Player unsets BGCHECKFLAG_GROUND, seems to allow clipping effect
- Void out is handled manually in Player_Action_8084F88C() when PLAYER_STATE1_31 is set
- play->transitionTrigger = TRANS_TRIGGER_START;
- Set next entrance index using index into scene exit table, enables compatibility with ER
- DoorAna_WaitOpen()
- Remove exclusions for fairy fountain and grotto scene IDs in z_play -> Play_SetupRespawnPoint()
- z_player -> Player_HandleExitsAndVoids() remove check for ENTR_RETURN_GROTTO
- z_player -> override startMode to always use grotto start mode on respawn, not idle, if last startMode was grotto start mode
Rando Adjustments
- new grotto table keyed on entrance index, correlates scene layer and the old Door_Ana "content" parameter
- actor.c -> Actor_BuildFlag() special case for grottos to build extended flags
- get_items.c -> use grotto table for content ID instead of respawn data
- get_override_search_key()
- get_xflag_bit_offset()
- Item00_KillActorIfFlagIsSet()
- obj_comb.c -> obj_comb_drop_collectible() -> subsumed by actor.c changes
- shop.asm -> use grotto table instead of respawn data
- Deku_Check_Sold_Out
- Deku_Set_Sold_Out
- gossip_hints.asm -> gossip_hints -> use grotto table
- grotto.asm -> remove old system
- hacks.asm -> remove old system
New entrance notes
- Scene exit tables contain indexes to the entrance table.
- Scene entrance tables are (spawn point, room to load).
- Scene spawn lists have x/y/z position and rotation, plus halfword parameters.
- Scene setup is chosen based on age and time of day (0 child day, 1 child night, 2 adult day, 3 adult night).
- Special case for Kokiri Forest using the night scene to remove enemies.
- Another special case to use the night scene to raise the drawbridge in Hyrule Field after all three stones found.
- Setups linked with cutscenes are only loaded if the cutscene index is active.
- Setup count between scenes/rooms must be identical (one can be null, just need the count).
- Setup is stored in gSaveContext.sceneLayer
Generic grottos get another special case for setups. Extra entrance indexes lead to the same room/position, but are used to offset the scenelayer from 0. The extra scene setups are identical to the main one except for new exit lists. The different exit lists handle exiting to different scenes from the duplicated grottos, though it also works the same way for unique grottos as they all share the same scene. Adding more than one exit to the scene for each room would be more complicated as the data is baked into the scene collision (add new surface types -> swap out specific surface types out of thousands, not necessarily contiguous).
Grotto entrance table entries
Vanilla table in ovl_Door_Ana (shown in table index order). Grotto actor rot.x stores the exit index.
| Grotto Type | Grotto Count | Decomp ID | Value (Dec) | Value (Hex) | Entrance table value | Table start address | Table entries |
|---|---|---|---|---|---|---|---|
| Small Fairy Fountain | 5 | ENTR_FAIRYS_FOUNTAIN_0 | 877 | 0x36D | 3C 00 4183 | 0xB709A4 | 4 |
| Generic Grotto | 9 | ENTR_GROTTOS_0 | 63 | 0x3F | 3E 00 4102 | 0xB6FCEC | 4 |
| Big and Gold Skulltulas | 1 | ENTR_GROTTOS_1 | 1432 | 0x598 | 3E 01 4102 | 0xB71250 | 4 |
| 1 Scrub | 1 | ENTR_GROTTOS_2 | 1436 | 0x59C | 3E 02 4102 | 0xB71260 | 4 |
| Redeads | 1 | ENTR_GROTTOS_3 | 1440 | 0x5A0 | 3E 03 4102 | 0xB71270 | 4 |
| 3 Scrub | 4 | ENTR_GROTTOS_4 | 1444 | 0x5A4 | 3E 04 4102 | 0xB71280 | 4 |
| Webbed Cow | 1 | ENTR_GROTTOS_5 | 1448 | 0x5A8 | 3E 05 4103 | 0xB71290 | 4 |
| Octorok | 1 | ENTR_GROTTOS_6 | 1452 | 0x5AC | 3E 06 4102 | 0xB712A0 | 4 |
| Upgrade 2 Scrub | 1 | ENTR_GROTTOS_7 | 1456 | 0x5B0 | 3E 07 4102 | 0xB712B0 | 4 |
| Wolfos | 1 | ENTR_GROTTOS_8 | 1460 | 0x5B4 | 3E 08 4102 | 0xB712C0 | 4 |
| Mud Walls | 1 | ENTR_GROTTOS_9 | 1464 | 0x5B8 | 3E 09 4102 | 0xB712D0 | 4 |
| 2 Scrub | 4 | ENTR_GROTTOS_10 | 1468 | 0x5BC | 3E 0A 4102 | 0xB712E0 | 4 |
| Tektite | 1 | ENTR_GROTTOS_11 | 1472 | 0x5C0 | 3E 0B 4102 | 0xB712F0 | 4 |
| Deku Theater | 1 | ENTR_GROTTOS_12 | 1476 | 0x5C4 | 3E 0C 4102 | 0xB71300 | 4 |
| Lone Cow | 1 | ENTR_GROTTOS_13 | 1532 | 0x5FC | 3E 0D 4102 | 0xB713E0 | 4 |
New Grotto Patching Process
- If entranceindex.scene == GROTTO
- entranceindex -> scene layer table
- change layer to X
- grotto layer X has exit table edited to have exit 0 == overworld return
- scene changes
- check for and remove extraneous null entries in exit and entrance lists (exception for Kokiri Forest)
- Add child blue warp entrances for adult bosses
- for each grotto-type entrance
- use linked grotto actor scene, append forward entrance index to scene exits
- if flagged, create an entrance table index, copying the original
- record exit list entry position, save to grotto actor rot.z
- uses rot.z to look up entrance index to apply in WaitOpen
- add reverse entrance and spawn position to linked scene, recording entrance list index
- create entrance table index for reverse, using the recorded entrance list index
- create new layer for grotto scene, change exit 0 to reverse entrance index
- add entry to grotto table of forward index -> scene layer
- use linked grotto actor scene, append forward entrance index to scene exits
Testing
All testing has been done on ares v143. All testing used DMC and DMT grottos instead of every grotto. More detailed testing to be completed when I can. Checked tests are complete, unchecked are pending.
- [X] Entering a grotto goes to the right grotto, both shuffled and unshuffled.
- [X] Shuffled chests, beehives, scrubs, cows return the correct shuffled item.
- [X] Shuffled chests, beehives, scrubs, cows collection flags function correctly when re-entering (open chest, despawn actors, etc)
- [X] Gossip stones in grottos return the correct hint.
- [X] Voiding after exiting a grotto returns to the grotto exit with the hop animation
- [X] Hop animation only applies to exiting grottos, either from exit or from void.
- [X] Dying in an alternate room of a scene than the one containing the grotto exit reloads correctly. Repeat for same room.
- [X] One way entrances can target grotto entrances and exits.
- [X] Other entrances still function with the extended table, shuffled and unshuffled.
- [ ] Unshuffled scrubs give the correct item.
- [ ] End credits on VC don't crash.
- [ ] Child blue warp exits from adult boss rooms work with new entrance table without the old overrides.
- [ ] Shuffled Gold Skulltulas in grottos return the right item (should be fine as no special case in the override lookup, but still worth checking)
Videos for N64, Wii VC, and Retroarch to be provided later, if someone else doesn't get to it first.