diff options
Diffstat (limited to 'mm/2s2h/Rando/ActorBehavior/ObjGrass.cpp')
| -rw-r--r-- | mm/2s2h/Rando/ActorBehavior/ObjGrass.cpp | 375 |
1 files changed, 334 insertions, 41 deletions
diff --git a/mm/2s2h/Rando/ActorBehavior/ObjGrass.cpp b/mm/2s2h/Rando/ActorBehavior/ObjGrass.cpp index 08e245124..3651e46c4 100644 --- a/mm/2s2h/Rando/ActorBehavior/ObjGrass.cpp +++ b/mm/2s2h/Rando/ActorBehavior/ObjGrass.cpp @@ -14,13 +14,21 @@ extern "C" { #include "variables.h" #include "overlays/actors/ovl_Obj_Grass/z_obj_grass.h" #include "overlays/actors/ovl_En_Kusa/z_en_kusa.h" +#include "overlays/actors/ovl_En_Kusa2/z_en_kusa2.h" #include "overlays/actors/ovl_Obj_Grass_Carry/z_obj_grass_carry.h" #include "overlays/actors/ovl_Obj_Mure2/z_obj_mure2.h" void ObjGrass_OverrideMatrixCurrent(MtxF* matrix); +void EnKusa_DrawGrass(Actor* thisx, PlayState* play); extern ObjGrass* sGrassManager; } +struct KeatonGrassRing { + RandoCheckId baseCheckId = RC_UNKNOWN; + RandoCheckId wonderItemCheckId = RC_UNKNOWN; +}; +static ObjectExtension::Register<KeatonGrassRing> keatonGrassRingRegister; + // clang-format off // For large swathes of grass that share a singular actor std::map<std::tuple<s16, u8>, std::tuple<s16, RandoCheckId>> grassObjMap = { @@ -118,6 +126,160 @@ std::map<std::tuple<s16, s16, s16>, RandoCheckId> enKusaMap = { { { SCENE_KAKUSIANA, 2, 4 }, RC_TERMINA_FIELD_GOSSIP_STONE_GROTTO_4_GRASS_05 }, { { SCENE_KAKUSIANA, 11, 0 }, RC_TERMINA_FIELD_BIO_BABA_GROTTO_GRASS_01 }, { { SCENE_KAKUSIANA, 11, 3 }, RC_TERMINA_FIELD_BIO_BABA_GROTTO_GRASS_02 }, + // Sprout grass + { { SCENE_20SICHITAI, 0, 45 }, RC_SOUTHERN_SWAMP_POISON_TOURIST_GRASS_01 }, + { { SCENE_20SICHITAI, 0, 46 }, RC_SOUTHERN_SWAMP_POISON_TOURIST_GRASS_02 }, + { { SCENE_20SICHITAI, 2, 17 }, RC_SOUTHERN_SWAMP_POISON_WOODS_GRASS_01 }, + { { SCENE_20SICHITAI, 2, 18 }, RC_SOUTHERN_SWAMP_POISON_WOODS_GRASS_02 }, + { { SCENE_20SICHITAI2, 0, 39 }, RC_SOUTHERN_SWAMP_CLEARED_TOURIST_GRASS_01 }, + { { SCENE_20SICHITAI2, 0, 40 }, RC_SOUTHERN_SWAMP_CLEARED_TOURIST_GRASS_02 }, + { { SCENE_BOTI, 0, 16 }, RC_IKANA_GRAVEYARD_LOWER_GRASS_04 }, + { { SCENE_BOTI, 0, 17 }, RC_IKANA_GRAVEYARD_LOWER_GRASS_03 }, + { { SCENE_BOTI, 0, 18 }, RC_IKANA_GRAVEYARD_LOWER_GRASS_01 }, + { { SCENE_BOTI, 0, 19 }, RC_IKANA_GRAVEYARD_LOWER_GRASS_02 }, + { { SCENE_BOTI, 0, 20 }, RC_IKANA_GRAVEYARD_LOWER_GRASS_05 }, + { { SCENE_BOTI, 0, 31 }, RC_IKANA_GRAVEYARD_LOWER_GRASS_01 }, + { { SCENE_BOTI, 0, 39 }, RC_IKANA_GRAVEYARD_LOWER_GRASS_02 }, + { { SCENE_BOTI, 0, 40 }, RC_IKANA_GRAVEYARD_LOWER_GRASS_03 }, + { { SCENE_BOTI, 0, 41 }, RC_IKANA_GRAVEYARD_LOWER_GRASS_04 }, + { { SCENE_BOTI, 0, 42 }, RC_IKANA_GRAVEYARD_LOWER_GRASS_05 }, + { { SCENE_CASTLE, 0, 32 }, RC_ANCIENT_CASTLE_OF_IKANA_COURTYARD_GRASS_01 }, + { { SCENE_CASTLE, 0, 33 }, RC_ANCIENT_CASTLE_OF_IKANA_COURTYARD_GRASS_02 }, + { { SCENE_CASTLE, 0, 34 }, RC_ANCIENT_CASTLE_OF_IKANA_COURTYARD_GRASS_03 }, + { { SCENE_CASTLE, 0, 35 }, RC_ANCIENT_CASTLE_OF_IKANA_COURTYARD_GRASS_04 }, + { { SCENE_CASTLE, 0, 36 }, RC_ANCIENT_CASTLE_OF_IKANA_COURTYARD_GRASS_05 }, + { { SCENE_CASTLE, 0, 37 }, RC_ANCIENT_CASTLE_OF_IKANA_COURTYARD_GRASS_06 }, + { { SCENE_CASTLE, 0, 38 }, RC_ANCIENT_CASTLE_OF_IKANA_COURTYARD_GRASS_07 }, + { { SCENE_CASTLE, 0, 39 }, RC_ANCIENT_CASTLE_OF_IKANA_COURTYARD_GRASS_08 }, + { { SCENE_CASTLE, 0, 40 }, RC_ANCIENT_CASTLE_OF_IKANA_COURTYARD_GRASS_09 }, + { { SCENE_CASTLE, 0, 41 }, RC_ANCIENT_CASTLE_OF_IKANA_COURTYARD_GRASS_10 }, + { { SCENE_CASTLE, 0, 42 }, RC_ANCIENT_CASTLE_OF_IKANA_COURTYARD_GRASS_11 }, + { { SCENE_CASTLE, 0, 43 }, RC_ANCIENT_CASTLE_OF_IKANA_COURTYARD_GRASS_12 }, + { { SCENE_HAKUGIN, 4, 60 }, RC_SNOWHEAD_TEMPLE_CENTRAL_ROOM_BOTTOM_GRASS_01 }, + { { SCENE_HAKUGIN, 4, 61 }, RC_SNOWHEAD_TEMPLE_CENTRAL_ROOM_BOTTOM_GRASS_02 }, + { { SCENE_HAKUGIN, 4, 62 }, RC_SNOWHEAD_TEMPLE_CENTRAL_ROOM_BOTTOM_GRASS_03 }, + { { SCENE_HAKUGIN, 4, 63 }, RC_SNOWHEAD_TEMPLE_CENTRAL_ROOM_BOTTOM_GRASS_04 }, + { { SCENE_HAKUGIN, 4, 64 }, RC_SNOWHEAD_TEMPLE_CENTRAL_ROOM_BOTTOM_GRASS_05 }, + { { SCENE_HAKUGIN, 4, 65 }, RC_SNOWHEAD_TEMPLE_CENTRAL_ROOM_BOTTOM_GRASS_06 }, + { { SCENE_HAKUGIN, 4, 66 }, RC_SNOWHEAD_TEMPLE_CENTRAL_ROOM_BOTTOM_GRASS_07 }, + { { SCENE_HAKUGIN, 4, 67 }, RC_SNOWHEAD_TEMPLE_CENTRAL_ROOM_BOTTOM_GRASS_08 }, + { { SCENE_HAKUGIN, 4, 68 }, RC_SNOWHEAD_TEMPLE_CENTRAL_ROOM_BOTTOM_GRASS_09 }, + { { SCENE_HAKUGIN, 4, 69 }, RC_SNOWHEAD_TEMPLE_CENTRAL_ROOM_BOTTOM_GRASS_10 }, + { { SCENE_IKANA, 0, 29 }, RC_IKANA_CANYON_GRASS_01 }, + { { SCENE_IKANA, 0, 30 }, RC_IKANA_CANYON_GRASS_02 }, + { { SCENE_IKANA, 0, 31 }, RC_IKANA_CANYON_GRASS_03 }, + { { SCENE_IKANA, 0, 32 }, RC_IKANA_CANYON_GRASS_04 }, + { { SCENE_IKANA, 0, 59 }, RC_IKANA_CANYON_GRASS_01 }, + { { SCENE_IKANA, 0, 60 }, RC_IKANA_CANYON_GRASS_02 }, + { { SCENE_IKANA, 0, 61 }, RC_IKANA_CANYON_GRASS_03 }, + { { SCENE_IKANA, 0, 62 }, RC_IKANA_CANYON_GRASS_04 }, + { { SCENE_INISIE_N, 0, 10 }, RC_STONE_TOWER_TEMPLE_ENTRANCE_GRASS_01 }, + { { SCENE_INISIE_N, 0, 11 }, RC_STONE_TOWER_TEMPLE_ENTRANCE_GRASS_02 }, + { { SCENE_INISIE_N, 0, 12 }, RC_STONE_TOWER_TEMPLE_ENTRANCE_GRASS_03 }, + { { SCENE_INISIE_N, 2, 18 }, RC_STONE_TOWER_TEMPLE_SWITCH_ROOM_GRASS_01 }, + { { SCENE_INISIE_N, 2, 19 }, RC_STONE_TOWER_TEMPLE_SWITCH_ROOM_GRASS_02 }, + { { SCENE_INISIE_N, 2, 20 }, RC_STONE_TOWER_TEMPLE_SWITCH_ROOM_GRASS_03 }, + { { SCENE_INISIE_N, 2, 21 }, RC_STONE_TOWER_TEMPLE_SWITCH_ROOM_GRASS_04 }, + { { SCENE_INISIE_N, 2, 22 }, RC_STONE_TOWER_TEMPLE_SWITCH_ROOM_GRASS_05 }, + { { SCENE_INISIE_N, 2, 23 }, RC_STONE_TOWER_TEMPLE_SWITCH_ROOM_GRASS_06 }, + { { SCENE_MITURIN, 0, 30 }, RC_WOODFALL_TEMPLE_PRE_BOSS_GRASS_01 }, + { { SCENE_MITURIN, 0, 31 }, RC_WOODFALL_TEMPLE_PRE_BOSS_GRASS_02 }, + { { SCENE_MITURIN, 0, 32 }, RC_WOODFALL_TEMPLE_PRE_BOSS_GRASS_03 }, + { { SCENE_MITURIN, 0, 33 }, RC_WOODFALL_TEMPLE_PRE_BOSS_GRASS_04 }, + { { SCENE_MITURIN, 0, 34 }, RC_WOODFALL_TEMPLE_PRE_BOSS_GRASS_05 }, + { { SCENE_MITURIN, 1, 30 }, RC_WOODFALL_TEMPLE_MAIN_ROOM_LOWER_GRASS_01 }, + { { SCENE_MITURIN, 1, 32 }, RC_WOODFALL_TEMPLE_MAIN_ROOM_LOWER_GRASS_02 }, + { { SCENE_MITURIN, 1, 31 }, RC_WOODFALL_TEMPLE_MAIN_ROOM_UPPER_GRASS_01 }, + { { SCENE_MITURIN, 2, 23 }, RC_WOODFALL_TEMPLE_ENTRANCE_GRASS_01 }, + { { SCENE_MITURIN, 2, 24 }, RC_WOODFALL_TEMPLE_ENTRANCE_GRASS_02 }, + { { SCENE_MITURIN, 2, 25 }, RC_WOODFALL_TEMPLE_ENTRANCE_GRASS_04 }, + { { SCENE_MITURIN, 2, 26 }, RC_WOODFALL_TEMPLE_ENTRANCE_GRASS_05 }, + { { SCENE_MITURIN, 2, 27 }, RC_WOODFALL_TEMPLE_ENTRANCE_GRASS_03 }, + { { SCENE_MITURIN, 4, 5 }, RC_WOODFALL_TEMPLE_COMPASS_ROOM_GRASS_01 }, + { { SCENE_MITURIN, 4, 6 }, RC_WOODFALL_TEMPLE_COMPASS_ROOM_GRASS_02 }, + { { SCENE_MITURIN, 4, 7 }, RC_WOODFALL_TEMPLE_COMPASS_ROOM_GRASS_03 }, + { { SCENE_MITURIN, 5, 18 }, RC_WOODFALL_TEMPLE_WATER_ROOM_GRASS_01 }, + { { SCENE_MITURIN, 5, 19 }, RC_WOODFALL_TEMPLE_WATER_ROOM_GRASS_02 }, + { { SCENE_MITURIN, 6, 6 }, RC_WOODFALL_TEMPLE_MAP_ROOM_GRASS_01 }, + { { SCENE_MITURIN, 6, 7 }, RC_WOODFALL_TEMPLE_MAP_ROOM_GRASS_02 }, + { { SCENE_MITURIN, 6, 8 }, RC_WOODFALL_TEMPLE_MAP_ROOM_GRASS_03 }, + { { SCENE_MITURIN, 6, 9 }, RC_WOODFALL_TEMPLE_MAP_ROOM_GRASS_04 }, + { { SCENE_MITURIN, 6, 10 }, RC_WOODFALL_TEMPLE_MAP_ROOM_GRASS_05 }, + { { SCENE_MITURIN, 10, 6 }, RC_WOODFALL_TEMPLE_UPPER_WALKWAY_GRASS_01 }, + { { SCENE_MITURIN, 10, 7 }, RC_WOODFALL_TEMPLE_UPPER_WALKWAY_GRASS_02 }, + { { SCENE_MITURIN, 10, 8 }, RC_WOODFALL_TEMPLE_UPPER_WALKWAY_GRASS_03 }, + { { SCENE_MITURIN, 10, 9 }, RC_WOODFALL_TEMPLE_UPPER_WALKWAY_GRASS_04 }, + { { SCENE_MITURIN, 10, 10 }, RC_WOODFALL_TEMPLE_UPPER_WALKWAY_GRASS_05 }, + { { SCENE_MITURIN, 10, 11 }, RC_WOODFALL_TEMPLE_UPPER_WALKWAY_GRASS_06 }, + { { SCENE_MITURIN, 10, 12 }, RC_WOODFALL_TEMPLE_UPPER_WALKWAY_GRASS_07 }, + { { SCENE_MITURIN, 10, 13 }, RC_WOODFALL_TEMPLE_UPPER_WALKWAY_GRASS_08 }, + { { SCENE_MITURIN, 10, 14 }, RC_WOODFALL_TEMPLE_UPPER_WALKWAY_GRASS_09 }, + { { SCENE_MITURIN, 10, 15 }, RC_WOODFALL_TEMPLE_UPPER_WALKWAY_GRASS_10 }, + { { SCENE_MITURIN, 10, 16 }, RC_WOODFALL_TEMPLE_UPPER_WALKWAY_GRASS_11 }, + { { SCENE_MITURIN_BS, 0, 10 }, RC_WOODFALL_TEMPLE_BOSS_GRASS_01 }, + { { SCENE_MITURIN_BS, 0, 11 }, RC_WOODFALL_TEMPLE_BOSS_GRASS_02 }, + { { SCENE_MITURIN_BS, 0, 12 }, RC_WOODFALL_TEMPLE_BOSS_GRASS_03 }, + { { SCENE_MITURIN_BS, 0, 13 }, RC_WOODFALL_TEMPLE_BOSS_GRASS_04 }, + { { SCENE_MITURIN_BS, 0, 14 }, RC_WOODFALL_TEMPLE_BOSS_GRASS_05 }, + { { SCENE_MITURIN_BS, 0, 15 }, RC_WOODFALL_TEMPLE_BOSS_GRASS_06 }, + { { SCENE_MITURIN_BS, 0, 16 }, RC_WOODFALL_TEMPLE_BOSS_GRASS_07 }, + { { SCENE_MITURIN_BS, 0, 17 }, RC_WOODFALL_TEMPLE_BOSS_GRASS_08 }, + { { SCENE_MITURIN_BS, 0, 18 }, RC_WOODFALL_TEMPLE_BOSS_GRASS_09 }, + { { SCENE_MITURIN_BS, 0, 19 }, RC_WOODFALL_TEMPLE_BOSS_GRASS_10 }, + { { SCENE_MITURIN_BS, 0, 20 }, RC_WOODFALL_TEMPLE_BOSS_GRASS_11 }, + { { SCENE_MITURIN_BS, 0, 21 }, RC_WOODFALL_TEMPLE_BOSS_GRASS_12 }, + { { SCENE_MITURIN_BS, 0, 22 }, RC_WOODFALL_TEMPLE_BOSS_GRASS_13 }, + { { SCENE_MITURIN_BS, 0, 23 }, RC_WOODFALL_TEMPLE_BOSS_GRASS_14 }, + { { SCENE_MITURIN_BS, 0, 24 }, RC_WOODFALL_TEMPLE_BOSS_GRASS_15 }, + { { SCENE_MITURIN_BS, 0, 25 }, RC_WOODFALL_TEMPLE_BOSS_GRASS_16 }, + { { SCENE_RANDOM, 0, 26 }, RC_SECRET_SHRINE_ENTRANCE_GRASS_01 }, + { { SCENE_RANDOM, 0, 27 }, RC_SECRET_SHRINE_ENTRANCE_GRASS_02 }, + { { SCENE_RANDOM, 0, 28 }, RC_SECRET_SHRINE_ENTRANCE_GRASS_03 }, + { { SCENE_RANDOM, 0, 29 }, RC_SECRET_SHRINE_ENTRANCE_GRASS_04 }, + { { SCENE_RANDOM, 0, 30 }, RC_SECRET_SHRINE_ENTRANCE_GRASS_05 }, + { { SCENE_RANDOM, 0, 31 }, RC_SECRET_SHRINE_ENTRANCE_GRASS_06 }, + { { SCENE_RANDOM, 2, 4 }, RC_SECRET_SHRINE_DINOLFOS_GRASS_01 }, + { { SCENE_RANDOM, 2, 5 }, RC_SECRET_SHRINE_DINOLFOS_GRASS_02 }, + { { SCENE_RANDOM, 2, 6 }, RC_SECRET_SHRINE_DINOLFOS_GRASS_03 }, + { { SCENE_RANDOM, 2, 7 }, RC_SECRET_SHRINE_DINOLFOS_GRASS_04 }, + { { SCENE_RANDOM, 3, 6 }, RC_SECRET_SHRINE_WIZZROBE_GRASS_01 }, + { { SCENE_RANDOM, 3, 7 }, RC_SECRET_SHRINE_WIZZROBE_GRASS_02 }, + { { SCENE_RANDOM, 3, 8 }, RC_SECRET_SHRINE_WIZZROBE_GRASS_03 }, + { { SCENE_RANDOM, 3, 9 }, RC_SECRET_SHRINE_WIZZROBE_GRASS_04 }, + { { SCENE_RANDOM, 3, 10 }, RC_SECRET_SHRINE_WIZZROBE_GRASS_05 }, + { { SCENE_RANDOM, 4, 5 }, RC_SECRET_SHRINE_WART_GRASS_01 }, + { { SCENE_RANDOM, 4, 6 }, RC_SECRET_SHRINE_WART_GRASS_02 }, + { { SCENE_RANDOM, 4, 7 }, RC_SECRET_SHRINE_WART_GRASS_03 }, + { { SCENE_RANDOM, 4, 8 }, RC_SECRET_SHRINE_WART_GRASS_04 }, + { { SCENE_RANDOM, 4, 9 }, RC_SECRET_SHRINE_WART_GRASS_05 }, + { { SCENE_RANDOM, 4, 10 }, RC_SECRET_SHRINE_WART_GRASS_06 }, + { { SCENE_RANDOM, 4, 11 }, RC_SECRET_SHRINE_WART_GRASS_07 }, + { { SCENE_RANDOM, 4, 12 }, RC_SECRET_SHRINE_WART_GRASS_08 }, + { { SCENE_RANDOM, 5, 2 }, RC_SECRET_SHRINE_GARO_MASTER_GRASS_01 }, + { { SCENE_RANDOM, 5, 3 }, RC_SECRET_SHRINE_GARO_MASTER_GRASS_02 }, + { { SCENE_RANDOM, 5, 4 }, RC_SECRET_SHRINE_GARO_MASTER_GRASS_03 }, + { { SCENE_RANDOM, 5, 5 }, RC_SECRET_SHRINE_GARO_MASTER_GRASS_04 }, + { { SCENE_RANDOM, 5, 6 }, RC_SECRET_SHRINE_GARO_MASTER_GRASS_05 }, + { { SCENE_RANDOM, 5, 7 }, RC_SECRET_SHRINE_GARO_MASTER_GRASS_06 }, + { { SCENE_ROMANYMAE, 0, 17 }, RC_MILK_ROAD_GRASS_01 }, + { { SCENE_ROMANYMAE, 0, 18 }, RC_MILK_ROAD_GRASS_02 }, + { { SCENE_ROMANYMAE, 0, 19 }, RC_MILK_ROAD_GRASS_03 }, + { { SCENE_20SICHITAI2, 2, 14 }, RC_SOUTHERN_SWAMP_CLEARED_WOODS_GRASS_01 }, + { { SCENE_20SICHITAI2, 2, 15 }, RC_SOUTHERN_SWAMP_CLEARED_WOODS_GRASS_02 }, + { { SCENE_REDEAD, 3, 9 }, RC_BENEATH_THE_WELL_RIGHT_FIRE_KEESE_GRASS_01 }, + { { SCENE_REDEAD, 3, 10 }, RC_BENEATH_THE_WELL_RIGHT_FIRE_KEESE_GRASS_02 }, + { { SCENE_REDEAD, 3, 11 }, RC_BENEATH_THE_WELL_RIGHT_FIRE_KEESE_GRASS_03 }, + { { SCENE_REDEAD, 3, 12 }, RC_BENEATH_THE_WELL_RIGHT_FIRE_KEESE_GRASS_04 }, + { { SCENE_REDEAD, 5, 22 }, RC_BENEATH_THE_WELL_TWO_SPIKED_BARS_GRASS_01 }, + { { SCENE_REDEAD, 5, 23 }, RC_BENEATH_THE_WELL_TWO_SPIKED_BARS_GRASS_02 }, + { { SCENE_REDEAD, 7, 19 }, RC_BENEATH_THE_WELL_FOUR_SPIKED_BARS_GRASS_01 }, + { { SCENE_REDEAD, 7, 20 }, RC_BENEATH_THE_WELL_FOUR_SPIKED_BARS_GRASS_02 }, + { { SCENE_REDEAD, 7, 21 }, RC_BENEATH_THE_WELL_FOUR_SPIKED_BARS_GRASS_03 }, + { { SCENE_REDEAD, 7, 22 }, RC_BENEATH_THE_WELL_FOUR_SPIKED_BARS_GRASS_04 }, + { { SCENE_REDEAD, 7, 23 }, RC_BENEATH_THE_WELL_FOUR_SPIKED_BARS_GRASS_05 }, + { { SCENE_REDEAD, 9, 6 }, RC_BENEATH_THE_WELL_COW_ROOM_GRASS_01 }, + { { SCENE_REDEAD, 9, 7 }, RC_BENEATH_THE_WELL_COW_ROOM_GRASS_02 }, + { { SCENE_REDEAD, 9, 8 }, RC_BENEATH_THE_WELL_COW_ROOM_GRASS_03 }, }; // For lone grass actors spawned in chest grottos @@ -145,6 +307,16 @@ std::map<std::tuple<u16, u8, s16>, RandoCheckId> objMure2GrassMap = { { { SCENE_10YUKIYAMANOMURA2, 0, 30 }, RC_MOUNTAIN_VILLAGE_SPRING_GRASS_13 }, { { SCENE_10YUKIYAMANOMURA2, 0, 31 }, RC_MOUNTAIN_VILLAGE_SPRING_GRASS_22 }, { { SCENE_BOTI, 1, 47 }, RC_IKANA_GRAVEYARD_GRASS_01 }, + { { SCENE_BOTI, 1, 7 }, RC_IKANA_GRAVEYARD_GRASS_01 }, // Night layer +}; + +// For rings of Keaton grass, mapped by their manager actor to the first RC of the ring and the RC of its bonus reward +std::map<std::tuple<s16, s16, s16>, KeatonGrassRing> keatonGrassMap = { + { { SCENE_BACKTOWN, 0, 16 }, { RC_CLOCK_TOWN_NORTH_KEATON_GRASS_01, RC_CLOCK_TOWN_NORTH_KEATON_GRASS_WONDER_ITEM } }, + { { SCENE_BACKTOWN, 0, 28 }, { RC_CLOCK_TOWN_NORTH_KEATON_GRASS_01, RC_CLOCK_TOWN_NORTH_KEATON_GRASS_WONDER_ITEM } }, + { { SCENE_ROMANYMAE, 0, 6 }, { RC_MILK_ROAD_KEATON_GRASS_01, RC_MILK_ROAD_KEATON_GRASS_WONDER_ITEM } }, + { { SCENE_10YUKIYAMANOMURA2, 0, 44 }, { RC_MOUNTAIN_VILLAGE_SPRING_KEATON_GRASS_01, RC_MOUNTAIN_VILLAGE_SPRING_KEATON_GRASS_WONDER_ITEM } }, + { { SCENE_10YUKIYAMANOMURA2, 0, 50 }, { RC_MOUNTAIN_VILLAGE_SPRING_KEATON_GRASS_01, RC_MOUNTAIN_VILLAGE_SPRING_KEATON_GRASS_WONDER_ITEM } }, }; // clang-format on @@ -165,53 +337,51 @@ void SpawnGrassDrop(Vec3f pos, RandoCheckId randoCheckId) { }); } -void EnKusaBush_RandoDraw(Actor* actor, PlayState* play) { +Gfx* GetObjGrassDList(RandoCheckId randoCheckId) { if (!CVarGetInteger("gRando.CSMC", 0)) { - Gfx_DrawDListOpa(play, (Gfx*)gRandoBushDL); - return; + return (Gfx*)gRandoBushDL; } - RandoCheckId randoCheckId = Rando::ActorBehavior::GetObjectRandoCheckId(actor); RandoItemId randoItemId = Rando::ConvertItem(RANDO_SAVE_CHECKS[randoCheckId].randoItemId, randoCheckId); RandoItemType randoItemType = Rando::StaticData::Items[randoItemId].randoItemType; switch (randoItemType) { case RITYPE_BOSS_KEY: - Gfx_DrawDListOpa(play, (Gfx*)gRandoBushBossKeyDL); + return (Gfx*)gRandoBushBossKeyDL; break; case RITYPE_HEALTH: - Gfx_DrawDListOpa(play, (Gfx*)gRandoBushHeartDL); + return (Gfx*)gRandoBushHeartDL; break; case RITYPE_LESSER: - Gfx_DrawDListOpa(play, (Gfx*)gRandoBushMinorDL); + return (Gfx*)gRandoBushMinorDL; break; case RITYPE_MAJOR: - Gfx_DrawDListOpa(play, (Gfx*)gRandoBushMajorDL); + return (Gfx*)gRandoBushMajorDL; break; case RITYPE_MASK: - Gfx_DrawDListOpa(play, (Gfx*)gRandoBushMaskDL); + return (Gfx*)gRandoBushMaskDL; break; case RITYPE_SKULLTULA_TOKEN: - Gfx_DrawDListOpa(play, (Gfx*)gRandoBushTokenDL); + return (Gfx*)gRandoBushTokenDL; break; case RITYPE_SMALL_KEY: - Gfx_DrawDListOpa(play, (Gfx*)gRandoBushSmallKeyDL); + return (Gfx*)gRandoBushSmallKeyDL; break; case RITYPE_STRAY_FAIRY: - Gfx_DrawDListOpa(play, (Gfx*)gRandoBushFairyDL); + return (Gfx*)gRandoBushFairyDL; break; case RITYPE_JUNK: - Gfx_DrawDListOpa(play, (Gfx*)gRandoBushJunkDL); + return (Gfx*)gRandoBushJunkDL; break; default: - Gfx_DrawDListOpa(play, (Gfx*)gRandoBushDL); + return (Gfx*)gRandoBushDL; break; } } -Gfx* GetObjGrassDList(RandoCheckId randoCheckId) { +Gfx* GetObjGrassXluDList(RandoCheckId randoCheckId) { if (!CVarGetInteger("gRando.CSMC", 0)) { - return (Gfx*)gRandoBushDL; + return (Gfx*)gRandoBushXluDL; } RandoItemId randoItemId = Rando::ConvertItem(RANDO_SAVE_CHECKS[randoCheckId].randoItemId, randoCheckId); @@ -219,41 +389,42 @@ Gfx* GetObjGrassDList(RandoCheckId randoCheckId) { switch (randoItemType) { case RITYPE_BOSS_KEY: - return (Gfx*)gRandoBushBossKeyDL; + return (Gfx*)gRandoBushBossKeyXluDL; break; case RITYPE_HEALTH: - return (Gfx*)gRandoBushHeartDL; + return (Gfx*)gRandoBushHeartXluDL; break; case RITYPE_LESSER: - return (Gfx*)gRandoBushMinorDL; + return (Gfx*)gRandoBushMinorXluDL; break; case RITYPE_MAJOR: - return (Gfx*)gRandoBushMajorDL; + return (Gfx*)gRandoBushMajorXluDL; break; case RITYPE_MASK: - return (Gfx*)gRandoBushMaskDL; + return (Gfx*)gRandoBushMaskXluDL; break; case RITYPE_SKULLTULA_TOKEN: - return (Gfx*)gRandoBushTokenDL; + return (Gfx*)gRandoBushTokenXluDL; break; case RITYPE_SMALL_KEY: - return (Gfx*)gRandoBushSmallKeyDL; + return (Gfx*)gRandoBushSmallKeyXluDL; break; case RITYPE_STRAY_FAIRY: - return (Gfx*)gRandoBushFairyDL; + return (Gfx*)gRandoBushFairyXluDL; break; case RITYPE_JUNK: - return (Gfx*)gRandoBushJunkDL; + return (Gfx*)gRandoBushJunkXluDL; break; default: - return (Gfx*)gRandoBushDL; + return (Gfx*)gRandoBushXluDL; break; } } -Gfx* GetObjGrassXluDList(RandoCheckId randoCheckId) { +// Cuttable grass has its own set of models, as the bush ones above are far too large to stand in for a sprout. +Gfx* GetCuttableGrassDList(RandoCheckId randoCheckId) { if (!CVarGetInteger("gRando.CSMC", 0)) { - return (Gfx*)gRandoBushXluDL; + return (Gfx*)gRandoCuttableGrassRandomDL; } RandoItemId randoItemId = Rando::ConvertItem(RANDO_SAVE_CHECKS[randoCheckId].randoItemId, randoCheckId); @@ -261,34 +432,34 @@ Gfx* GetObjGrassXluDList(RandoCheckId randoCheckId) { switch (randoItemType) { case RITYPE_BOSS_KEY: - return (Gfx*)gRandoBushBossKeyXluDL; + return (Gfx*)gRandoCuttableGrassBossKeyDL; break; case RITYPE_HEALTH: - return (Gfx*)gRandoBushHeartXluDL; + return (Gfx*)gRandoCuttableGrassHeartDL; break; case RITYPE_LESSER: - return (Gfx*)gRandoBushMinorXluDL; + return (Gfx*)gRandoCuttableGrassMinorDL; break; case RITYPE_MAJOR: - return (Gfx*)gRandoBushMajorXluDL; + return (Gfx*)gRandoCuttableGrassMajorDL; break; case RITYPE_MASK: - return (Gfx*)gRandoBushMaskXluDL; + return (Gfx*)gRandoCuttableGrassMaskDL; break; case RITYPE_SKULLTULA_TOKEN: - return (Gfx*)gRandoBushTokenXluDL; + return (Gfx*)gRandoCuttableGrassTokenDL; break; case RITYPE_SMALL_KEY: - return (Gfx*)gRandoBushSmallKeyXluDL; + return (Gfx*)gRandoCuttableGrassSmallKeyDL; break; case RITYPE_STRAY_FAIRY: - return (Gfx*)gRandoBushFairyXluDL; + return (Gfx*)gRandoCuttableGrassFairyDL; break; case RITYPE_JUNK: - return (Gfx*)gRandoBushJunkXluDL; + return (Gfx*)gRandoCuttableGrassJunkDL; break; default: - return (Gfx*)gRandoBushXluDL; + return (Gfx*)gRandoCuttableGrassRandomDL; break; } } @@ -323,6 +494,52 @@ void ObjGrass_RandoDrawXlu(ObjGrass* objGrass, ObjGrassElement* grassElem, Rando CLOSE_DISPS(gPlayState->state.gfxCtx); } +void EnKusaBush_RandoDraw(Actor* actor, PlayState* play) { + Gfx_DrawDListOpa(play, GetObjGrassDList(Rando::ActorBehavior::GetObjectRandoCheckId(actor))); +} + +void EnKusaGrass_RandoDraw(Actor* actor, PlayState* play) { + EnKusa* grass = (EnKusa*)actor; + RandoCheckId randoCheckId = Rando::ActorBehavior::GetObjectRandoCheckId(actor); + + if (RANDO_SAVE_CHECKS[randoCheckId].obtained) { + actor->draw = EnKusa_DrawGrass; + EnKusa_DrawGrass(actor, play); + return; + } + + if (grass->isCut) { + EnKusa_DrawGrass(actor, play); + return; + } + + Gfx_DrawDListOpa(play, GetCuttableGrassDList(randoCheckId)); +} + +void KeatonGrassRing_DrawWonderItemSparkle(EnKusa2* grassRingActor) { + static Vec3f sVelocity = { 0.0f, 1.2f, 0.0f }; + static Vec3f sAccel = { 0.0f, -0.05f, 0.0f }; + static Color_RGBA8 sPrimColor = { 255, 255, 255, 255 }; + static Color_RGBA8 sEnvColor = { 255, 200, 64, 255 }; + + if (gGameState->frames % 4 != 0) { + return; + } + + EnKusa2* grassBush = grassRingActor->unk_194[(s32)Rand_ZeroFloat(ARRAY_COUNT(grassRingActor->unk_194))]; + if (grassBush == nullptr) { + return; + } + + Vec3f pos = { + Rand_CenteredFloat(20.0f) + grassBush->actor.world.pos.x, + (Rand_ZeroOne() * 25.0f) + grassBush->actor.world.pos.y, + Rand_CenteredFloat(20.0f) + grassBush->actor.world.pos.z, + }; + + EffectSsKirakira_SpawnDispersed(gPlayState, &pos, &sVelocity, &sAccel, &sPrimColor, &sEnvColor, 1600, 16); +} + void Rando::ActorBehavior::InitObjGrassBehavior() { /* * Identify directly spawned actor grass by scene ID, room, and actor list index. If this is a common chest grotto, @@ -360,9 +577,40 @@ void Rando::ActorBehavior::InitObjGrassBehavior() { }); /* + * Identify the manager actor of a ring of Keaton grass by scene ID, room, and actor list index, and remember which + * RCs the ring owns. Its bushes are spawned later, and each of them claims one of those RCs as it attaches. + */ + COND_ID_HOOK(OnActorInit, ACTOR_EN_KUSA2, IS_RANDO, [](Actor* actor) { + if (ENKUSA2_GET_1(actor)) { // This is one of the ring's bushes, not the manager + return; + } + + auto it = keatonGrassMap.find({ gPlayState->sceneId, actor->room, GetActorListIndex(actor) }); + if (it == keatonGrassMap.end()) { + return; + } + + ObjectExtension::GetInstance().Set<KeatonGrassRing>(actor, KeatonGrassRing{ it->second }); + }); + + // Only a ring's manager actor is given this extension, so this skips the ring's bushes along with all other grass. + COND_ID_HOOK(OnActorUpdate, ACTOR_EN_KUSA2, IS_RANDO, [](Actor* actor) { + KeatonGrassRing* grassRing = ObjectExtension::GetInstance().Get<KeatonGrassRing>(actor); + if (grassRing == nullptr) { + return; + } + + RandoSaveCheck& randoSaveCheck = RANDO_SAVE_CHECKS[grassRing->wonderItemCheckId]; + if (randoSaveCheck.shuffled && !randoSaveCheck.obtained) { + KeatonGrassRing_DrawWonderItemSparkle((EnKusa2*)actor); + } + }); + + /* * Identify actor grass that was spawned by a spawner actor, by scene ID, room, and the spawner's actor list index. * The RCs and child grass are contiguous, so they can increment the base value to get their target RC. */ + COND_VB_SHOULD(VB_OBJ_MURE2_SET_CHILD_ROOM, IS_RANDO, { Actor* actor = va_arg(args, Actor*); ObjMure2* objMure2 = (ObjMure2*)actor; @@ -449,12 +697,42 @@ void Rando::ActorBehavior::InitObjGrassBehavior() { } }); - COND_VB_SHOULD(VB_KUSA_BUSH_DRAW_BE_OVERRIDDEN, IS_RANDO, { + COND_VB_SHOULD(VB_KUSA_DRAW_BE_OVERRIDDEN, IS_RANDO, { Actor* actor = va_arg(args, Actor*); RandoCheckId randoCheckId = GetObjectRandoCheckId(actor); if (randoCheckId != RC_UNKNOWN && !RANDO_SAVE_CHECKS[randoCheckId].obtained) { *should = false; - actor->draw = EnKusaBush_RandoDraw; + actor->draw = KUSA_GET_TYPE(actor) == ENKUSA_TYPE_BUSH ? EnKusaBush_RandoDraw : EnKusaGrass_RandoDraw; + } + }); + + /* + * A ring's bushes always spawn in the same positions, so a bush's index within the ring is enough to tie it to a + * specific RC. The RCs are contiguous, so the ring's base value can just be incremented. + */ + COND_VB_SHOULD(VB_KEATON_GRASS_ATTACH_CHILD, IS_RANDO, { + EnKusa2* grassBush = va_arg(args, EnKusa2*); + s32 i = va_arg(args, s32); + KeatonGrassRing* grassRing = ObjectExtension::GetInstance().Get<KeatonGrassRing>(grassBush->unk_1C0); + + if (grassRing == nullptr) { + return; + } + + RandoCheckId randoCheckId = static_cast<RandoCheckId>(grassRing->baseCheckId + i); + if (!RANDO_SAVE_CHECKS[randoCheckId].shuffled || RANDO_SAVE_CHECKS[randoCheckId].cycleObtained) { + return; + } + + SetObjectRandoCheckId(grassBush, randoCheckId); + }); + + COND_VB_SHOULD(VB_KEATON_GRASS_DRAW, IS_RANDO, { + EnKusa2* grassBush = va_arg(args, EnKusa2*); + RandoCheckId randoCheckId = GetObjectRandoCheckId(grassBush); + if (randoCheckId != RC_UNKNOWN && !RANDO_SAVE_CHECKS[randoCheckId].obtained) { + *should = false; + Gfx_DrawDListOpa(gPlayState, GetObjGrassDList(randoCheckId)); } }); @@ -494,7 +772,7 @@ void Rando::ActorBehavior::InitObjGrassBehavior() { COND_VB_SHOULD(VB_GRASS_DROP_COLLECTIBLE, IS_RANDO, { auto actorId = static_cast<ActorId>(va_arg(args, int32_t)); Vec3f collectiblePos = gZeroVec3f; - RandoCheckId randoCheckId; + RandoCheckId randoCheckId = RC_UNKNOWN; if (actorId == ACTOR_OBJ_GRASS) { ObjGrassElement* grassElemActor = va_arg(args, ObjGrassElement*); @@ -508,6 +786,21 @@ void Rando::ActorBehavior::InitObjGrassBehavior() { ObjGrassCarry* grassCarryActor = va_arg(args, ObjGrassCarry*); collectiblePos = grassCarryActor->actor.world.pos; randoCheckId = GetObjectRandoCheckId(grassCarryActor); + } else if (actorId == ACTOR_EN_KUSA2) { + EnKusa2* grassBush = va_arg(args, EnKusa2*); + collectiblePos = grassBush->actor.world.pos; + randoCheckId = GetObjectRandoCheckId(grassBush); + + // This bush is the one vanilla would have dropped the ring's red rupee from, so it also owes the check + // that took that reward's place. + EnKusa2* grassRingActor = grassBush->unk_1C0; + KeatonGrassRing* grassRing = ObjectExtension::GetInstance().Get<KeatonGrassRing>(grassRingActor); + if (grassRing != nullptr && grassRingActor->unk_1BC == 8 && + RANDO_SAVE_CHECKS[grassRing->wonderItemCheckId].shuffled && + !RANDO_SAVE_CHECKS[grassRing->wonderItemCheckId].cycleObtained) { + SpawnGrassDrop(collectiblePos, grassRing->wonderItemCheckId); + *should = false; + } } if (randoCheckId == RC_UNKNOWN) { |
