diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS index b0f36024..7db1dc27 100644 --- a/docs/CODEOWNERS +++ b/docs/CODEOWNERS @@ -16,6 +16,9 @@ # A Link to the Past /worlds/alttp/ @Berserker66 +# Aquaria +/worlds/aquaria/ @tioui + # ArchipIDLE /worlds/archipidle/ @LegendaryLinux diff --git a/worlds/aquaria/Items.py b/worlds/aquaria/Items.py new file mode 100644 index 00000000..72334846 --- /dev/null +++ b/worlds/aquaria/Items.py @@ -0,0 +1,210 @@ +""" +Author: Louis M +Date: Fri, 15 Mar 2024 18:41:40 +0000 +Description: Manage items in the Aquaria game multiworld randomizer +""" + +from typing import Optional +from enum import Enum +from BaseClasses import Item, ItemClassification + +class ItemType(Enum): + """ + Used to indicate to the multi-world if an item is usefull or not + """ + NORMAL = 0 + PROGRESSION = 1 + JUNK = 2 + +class ItemGroup(Enum): + """ + Used to group items + """ + COLLECTIBLE = 0 + INGREDIENT = 1 + RECIPE = 2 + HEALTH = 3 + UTILITY = 4 + SONG = 5 + TURTLE = 6 + +class AquariaItem(Item): + """ + A single item in the Aquaria game. + """ + game: str = "Aquaria" + """The name of the game""" + + def __init__(self, name: str, classification: ItemClassification, + code: Optional[int], player: int): + """ + Initialisation of the Item + :param name: The name of the item + :param classification: If the item is usefull or not + :param code: The ID of the item (if None, it is an event) + :param player: The ID of the player in the multiworld + """ + super().__init__(name, classification, code, player) + +class ItemData: + """ + Data of an item. + """ + id:int + count:int + type:ItemType + group:ItemGroup + + def __init__(self, id:int, count:int, type:ItemType, group:ItemGroup): + """ + Initialisation of the item data + @param id: The item ID + @param count: the number of items in the pool + @param type: the importance type of the item + @param group: the usage of the item in the game + """ + self.id = id + self.count = count + self.type = type + self.group = group + +"""Information data for every (not event) item.""" +item_table = { + # name: ID, Nb, Item Type, Item Group + "Anemone": ItemData(698000, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_anemone + "Arnassi statue": ItemData(698001, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_arnassi_statue + "Big seed": ItemData(698002, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_big_seed + "Glowing seed": ItemData(698003, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_bio_seed + "Black pearl": ItemData(698004, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_blackpearl + "Baby blaster": ItemData(698005, 1, ItemType.NORMAL, ItemGroup.UTILITY), # collectible_blaster + "Crab armor": ItemData(698006, 1, ItemType.NORMAL, ItemGroup.UTILITY), # collectible_crab_costume + "Baby dumbo": ItemData(698007, 1, ItemType.PROGRESSION, ItemGroup.UTILITY), # collectible_dumbo + "Tooth": ItemData(698008, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_energy_boss + "Energy statue": ItemData(698009, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_energy_statue + "Krotite armor": ItemData(698010, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_energy_temple + "Golden starfish": ItemData(698011, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_gold_star + "Golden gear": ItemData(698012, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_golden_gear + "Jelly beacon": ItemData(698013, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_jelly_beacon + "Jelly costume": ItemData(698014, 1, ItemType.NORMAL, ItemGroup.UTILITY), # collectible_jelly_costume + "Jelly plant": ItemData(698015, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_jelly_plant + "Mithalas doll": ItemData(698016, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_mithala_doll + "Mithalan dress": ItemData(698017, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_mithalan_costume + "Mithalas banner": ItemData(698018, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_mithalas_banner + "Mithalas pot": ItemData(698019, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_mithalas_pot + "Mutant costume": ItemData(698020, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_mutant_costume + "Baby nautilus": ItemData(698021, 1, ItemType.NORMAL, ItemGroup.UTILITY), # collectible_nautilus + "Baby piranha": ItemData(698022, 1, ItemType.NORMAL, ItemGroup.UTILITY), # collectible_piranha + "Arnassi Armor": ItemData(698023, 1, ItemType.NORMAL, ItemGroup.UTILITY), # collectible_seahorse_costume + "Seed bag": ItemData(698024, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_seed_bag + "King's Skull": ItemData(698025, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_skull + "Song plant spore": ItemData(698026, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_spore_seed + "Stone head": ItemData(698027, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_stone_head + "Sun key": ItemData(698028, 1, ItemType.NORMAL, ItemGroup.COLLECTIBLE), # collectible_sun_key + "Girl costume": ItemData(698029, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_teen_costume + "Odd container": ItemData(698030, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_treasure_chest + "Trident": ItemData(698031, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_trident_head + "Turtle egg": ItemData(698032, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_turtle_egg + "Jelly egg": ItemData(698033, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_upsidedown_seed + "Urchin costume": ItemData(698034, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_urchin_costume + "Baby walker": ItemData(698035, 1, ItemType.JUNK, ItemGroup.COLLECTIBLE), # collectible_walker + "Vedha's Cure-All-All": ItemData(698036, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_Vedha'sCure-All + "Zuuna's perogi": ItemData(698037, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_Zuuna'sperogi + "Arcane poultice": ItemData(698038, 7, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_arcanepoultice + "Berry ice cream": ItemData(698039, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_berryicecream + "Buttery sea loaf": ItemData(698040, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_butterysealoaf + "Cold borscht": ItemData(698041, 2, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_coldborscht + "Cold soup": ItemData(698042, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_coldsoup + "Crab cake": ItemData(698043, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_crabcake + "Divine soup": ItemData(698044, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_divinesoup + "Dumbo ice cream": ItemData(698045, 3, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_dumboicecream + "Fish oil": ItemData(698046, 2, ItemType.NORMAL, ItemGroup.INGREDIENT), # ingredient_fishoil + "Glowing egg": ItemData(698047, 1, ItemType.NORMAL, ItemGroup.INGREDIENT), # ingredient_glowingegg + "Hand roll": ItemData(698048, 5, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_handroll + "Healing poultice": ItemData(698049, 4, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_healingpoultice + "Hearty soup": ItemData(698050, 5, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_heartysoup + "Hot borscht": ItemData(698051, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_hotborscht + "Hot soup": ItemData(698052, 3, ItemType.PROGRESSION, ItemGroup.RECIPE), # ingredient_hotsoup + "Ice cream": ItemData(698053, 2, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_icecream + "Leadership roll": ItemData(698054, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_leadershiproll + "Leaf poultice": ItemData(698055, 5, ItemType.PROGRESSION, ItemGroup.RECIPE), # ingredient_leafpoultice + "Leeching poultice": ItemData(698056, 4, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_leechingpoultice + "Legendary cake": ItemData(698057, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_legendarycake + "Loaf of life": ItemData(698058, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_loafoflife + "Long life soup": ItemData(698059, 2, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_longlifesoup + "Magic soup": ItemData(698060, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_magicsoup + "Mushroom x 2": ItemData(698061, 1, ItemType.NORMAL, ItemGroup.INGREDIENT), # ingredient_mushroom + "Perogi": ItemData(698062, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_perogi + "Plant leaf": ItemData(698063, 3, ItemType.NORMAL, ItemGroup.INGREDIENT), # ingredient_plantleaf + "Plump perogi": ItemData(698064, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_plumpperogi + "Poison loaf": ItemData(698065, 1, ItemType.JUNK, ItemGroup.RECIPE), # ingredient_poisonloaf + "Poison soup": ItemData(698066, 1, ItemType.JUNK, ItemGroup.RECIPE), # ingredient_poisonsoup + "Rainbow mushroom": ItemData(698067, 4, ItemType.NORMAL, ItemGroup.INGREDIENT), # ingredient_rainbowmushroom + "Rainbow soup": ItemData(698068, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_rainbowsoup + "Red berry": ItemData(698069, 1, ItemType.NORMAL, ItemGroup.INGREDIENT), # ingredient_redberry + "Red bulb x 2": ItemData(698070, 3, ItemType.NORMAL, ItemGroup.INGREDIENT), # ingredient_redbulb + "Rotten cake": ItemData(698071, 1, ItemType.JUNK, ItemGroup.RECIPE), # ingredient_rottencake + "Rotten loaf x 8": ItemData(698072, 1, ItemType.JUNK, ItemGroup.RECIPE), # ingredient_rottenloaf + "Rotten meat": ItemData(698073, 5, ItemType.JUNK, ItemGroup.INGREDIENT), # ingredient_rottenmeat + "Royal soup": ItemData(698074, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_royalsoup + "Sea cake": ItemData(698075, 4, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_seacake + "Sea loaf": ItemData(698076, 1, ItemType.JUNK, ItemGroup.RECIPE), # ingredient_sealoaf + "Shark fin soup": ItemData(698077, 2, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_sharkfinsoup + "Sight poultice": ItemData(698078, 2, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_sightpoultice + "Small bone x 2": ItemData(698079, 1, ItemType.NORMAL, ItemGroup.INGREDIENT), # ingredient_smallbone + "Small egg": ItemData(698080, 1, ItemType.NORMAL, ItemGroup.INGREDIENT), # ingredient_smallegg + "Small tentacle x 2": ItemData(698081, 1, ItemType.NORMAL, ItemGroup.INGREDIENT), # ingredient_smalltentacle + "Special bulb": ItemData(698082, 5, ItemType.NORMAL, ItemGroup.INGREDIENT), # ingredient_specialbulb + "Special cake": ItemData(698083, 2, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_specialcake + "Spicy meat x 2": ItemData(698084, 3, ItemType.NORMAL, ItemGroup.INGREDIENT), # ingredient_spicymeat + "Spicy roll": ItemData(698085, 11, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_spicyroll + "Spicy soup": ItemData(698086, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_spicysoup + "Spider roll": ItemData(698087, 2, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_spiderroll + "Swamp cake": ItemData(698088, 3, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_swampcake + "Tasty cake": ItemData(698089, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_tastycake + "Tasty roll": ItemData(698090, 2, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_tastyroll + "Tough cake": ItemData(698091, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_toughcake + "Turtle soup": ItemData(698092, 2, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_turtlesoup + "Vedha sea crisp": ItemData(698093, 2, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_vedhaseacrisp + "Veggie cake": ItemData(698094, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_veggiecake + "Veggie ice cream": ItemData(698095, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_veggieicecream + "Veggie soup": ItemData(698096, 2, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_veggiesoup + "Volcano roll": ItemData(698097, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_volcanoroll + "Health upgrade": ItemData(698098, 5, ItemType.NORMAL, ItemGroup.HEALTH), # upgrade_health_? + "Wok": ItemData(698099, 1, ItemType.NORMAL, ItemGroup.UTILITY), # upgrade_wok + "Eel oil x 2": ItemData(698100, 1, ItemType.NORMAL, ItemGroup.INGREDIENT), # ingredient_eeloil + "Fish meat x 2": ItemData(698101, 1, ItemType.NORMAL, ItemGroup.INGREDIENT), # ingredient_fishmeat + "Fish oil x 3": ItemData(698102, 1, ItemType.NORMAL, ItemGroup.INGREDIENT), # ingredient_fishoil + "Glowing egg x 2": ItemData(698103, 1, ItemType.NORMAL, ItemGroup.INGREDIENT), # ingredient_glowingegg + "Healing poultice x 2": ItemData(698104, 2, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_healingpoultice + "Hot soup x 2": ItemData(698105, 1, ItemType.PROGRESSION, ItemGroup.RECIPE), # ingredient_hotsoup + "Leadership roll x 2": ItemData(698106, 1, ItemType.NORMAL, ItemGroup.RECIPE), # ingredient_leadershiproll + "Leaf poultice x 3": ItemData(698107, 2, ItemType.PROGRESSION, ItemGroup.RECIPE), # ingredient_leafpoultice + "Plant leaf x 2": ItemData(698108, 2, ItemType.NORMAL, ItemGroup.INGREDIENT), # ingredient_plantleaf + "Plant leaf x 3": ItemData(698109, 4, ItemType.NORMAL, ItemGroup.INGREDIENT), # ingredient_plantleaf + "Rotten meat x 2": ItemData(698110, 1, ItemType.JUNK, ItemGroup.INGREDIENT), # ingredient_rottenmeat + "Rotten meat x 8": ItemData(698111, 1, ItemType.JUNK, ItemGroup.INGREDIENT), # ingredient_rottenmeat + "Sea loaf x 2": ItemData(698112, 1, ItemType.JUNK, ItemGroup.RECIPE), # ingredient_sealoaf + "Small bone x 3": ItemData(698113, 3, ItemType.NORMAL, ItemGroup.INGREDIENT), # ingredient_smallbone + "Small egg x 2": ItemData(698114, 1, ItemType.NORMAL, ItemGroup.INGREDIENT), # ingredient_smallegg + "Li and Li song": ItemData(698115, 1, ItemType.PROGRESSION, ItemGroup.SONG), # song_li + "Shield song": ItemData(698116, 1, ItemType.NORMAL, ItemGroup.SONG), # song_shield + "Beast form": ItemData(698117, 1, ItemType.PROGRESSION, ItemGroup.SONG), # song_beast + "Sun form": ItemData(698118, 1, ItemType.PROGRESSION, ItemGroup.SONG), # song_sun + "Nature form": ItemData(698119, 1, ItemType.PROGRESSION, ItemGroup.SONG), # song_nature + "Energy form": ItemData(698120, 1, ItemType.PROGRESSION, ItemGroup.SONG), # song_energy + "Bind song": ItemData(698121, 1, ItemType.PROGRESSION, ItemGroup.SONG), # song_bind + "Fish form": ItemData(698122, 1, ItemType.PROGRESSION, ItemGroup.SONG), # song_fish + "Spirit form": ItemData(698123, 1, ItemType.PROGRESSION, ItemGroup.SONG), # song_spirit + "Dual form": ItemData(698124, 1, ItemType.PROGRESSION, ItemGroup.SONG), # song_dual + "Transturtle Veil top left": ItemData(698125, 1, ItemType.PROGRESSION, ItemGroup.TURTLE), # transport_veil01 + "Transturtle Veil top right": ItemData(698126, 1, ItemType.PROGRESSION, ItemGroup.TURTLE), # transport_veil02 + "Transturtle Open Water top right": ItemData(698127, 1, ItemType.PROGRESSION, + ItemGroup.TURTLE), # transport_openwater03 + "Transturtle Forest bottom left": ItemData(698128, 1, ItemType.PROGRESSION, ItemGroup.TURTLE), # transport_forest04 + "Transturtle Home water": ItemData(698129, 1, ItemType.NORMAL, ItemGroup.TURTLE), # transport_mainarea + "Transturtle Abyss right": ItemData(698130, 1, ItemType.PROGRESSION, ItemGroup.TURTLE), # transport_abyss03 + "Transturtle Final Boss": ItemData(698131, 1, ItemType.PROGRESSION, ItemGroup.TURTLE), # transport_finalboss + "Transturtle Simon says": ItemData(698132, 1, ItemType.PROGRESSION, ItemGroup.TURTLE), # transport_forest05 + "Transturtle Arnassi ruins": ItemData(698133, 1, ItemType.PROGRESSION, ItemGroup.TURTLE), # transport_seahorse +} + diff --git a/worlds/aquaria/Locations.py b/worlds/aquaria/Locations.py new file mode 100644 index 00000000..824b98a3 --- /dev/null +++ b/worlds/aquaria/Locations.py @@ -0,0 +1,574 @@ +""" +Author: Louis M +Date: Fri, 15 Mar 2024 18:41:40 +0000 +Description: Manage locations in the Aquaria game multiworld randomizer +""" + +from BaseClasses import Location + + +class AquariaLocation(Location): + """ + A location in the game. + """ + game: str = "Aquaria" + """The name of the game""" + + def __init__(self, player: int, name="", code=None, parent=None) -> None: + """ + Initialisation of the object + :param player: the ID of the player + :param name: the name of the location + :param code: the ID (or address) of the location (Event if None) + :param parent: the Region that this location belongs to + """ + super(AquariaLocation, self).__init__(player, name, code, parent) + self.event = code is None + + +class AquariaLocations: + + locations_verse_cave_r = { + "Verse cave, bulb in the skeleton room": 698107, + "Verse cave, bulb in the path left of the skeleton room": 698108, + "Verse cave right area, Big Seed": 698175, + } + + locations_verse_cave_l = { + "Verse cave, the Naija hint about here shield ability": 698200, + "Verse cave left area, bulb in the center part": 698021, + "Verse cave left area, bulb in the right part": 698022, + "Verse cave left area, bulb under the rock at the end of the path": 698023, + } + + locations_home_water = { + "Home water, bulb below the grouper fish": 698058, + "Home water, bulb in the path bellow Nautilus Prime": 698059, + "Home water, bulb in the little room above the grouper fish": 698060, + "Home water, bulb in the end of the left path from the verse cave": 698061, + "Home water, bulb in the top left path": 698062, + "Home water, bulb in the bottom left room": 698063, + "Home water, bulb close to the Naija's home": 698064, + "Home water, bulb under the rock in the left path from the verse cave": 698065, + } + + locations_home_water_nautilus = { + "Home water, Nautilus Egg": 698194, + } + + locations_home_water_transturtle = { + "Home water, Transturtle": 698213, + } + + locations_naija_home = { + "Naija's home, bulb after the energy door": 698119, + "Naija's home, bulb under the rock at the right of the main path": 698120, + } + + locations_song_cave = { + "Song cave, Erulian spirit": 698206, + "Song cave, bulb in the top left part": 698071, + "Song cave, bulb in the big anemone room": 698072, + "Song cave, bulb in the path to the singing statues": 698073, + "Song cave, bulb under the rock in the path to the singing statues": 698074, + "Song cave, bulb under the rock close to the song door": 698075, + "Song cave, Verse egg": 698160, + "Song cave, Jelly beacon": 698178, + "Song cave, Anemone seed": 698162, + } + + locations_energy_temple_1 = { + "Energy temple first area, beating the energy statue": 698205, + "Energy temple first area, bulb in the bottom room blocked by a rock": 698027, + } + + locations_energy_temple_idol = { + "Energy temple first area, Energy Idol": 698170, + } + + locations_energy_temple_2 = { + "Energy temple second area, bulb under the rock": 698028, + } + + locations_energy_temple_altar = { + "Energy temple bottom entrance, Krotite armor": 698163, + } + + locations_energy_temple_3 = { + "Energy temple third area, bulb in the bottom path": 698029, + } + + locations_energy_temple_boss = { + "Energy temple boss area, Fallen god tooth": 698169, + } + + locations_energy_temple_blaster_room = { + "Energy temple blaster room, Blaster egg": 698195, + } + + locations_openwater_tl = { + "Open water top left area, bulb under the rock in the right path": 698001, + "Open water top left area, bulb under the rock in the left path": 698002, + "Open water top left area, bulb to the right of the save cristal": 698003, + } + + locations_openwater_tr = { + "Open water top right area, bulb in the small path before Mithalas": 698004, + "Open water top right area, bulb in the path from the left entrance": 698005, + "Open water top right area, bulb in the clearing close to the bottom exit": 698006, + "Open water top right area, bulb in the big clearing close to the save cristal": 698007, + "Open water top right area, bulb in the big clearing to the top exit": 698008, + "Open water top right area, first urn in the Mithalas exit": 698148, + "Open water top right area, second urn in the Mithalas exit": 698149, + "Open water top right area, third urn in the Mithalas exit": 698150, + } + locations_openwater_tr_turtle = { + "Open water top right area, bulb in the turtle room": 698009, + "Open water top right area, Transturtle": 698211, + } + + locations_openwater_bl = { + "Open water bottom left area, bulb behind the chomper fish": 698011, + "Open water bottom left area, bulb inside the downest fish pass": 698010, + } + + locations_skeleton_path = { + "Open water skeleton path, bulb close to the right exit": 698012, + "Open water skeleton path, bulb behind the chomper fish": 698013, + } + + locations_skeleton_path_sc = { + "Open water skeleton path, King skull": 698177, + } + + locations_arnassi = { + "Arnassi Ruins, bulb in the right part": 698014, + "Arnassi Ruins, bulb in the left part": 698015, + "Arnassi Ruins, bulb in the center part": 698016, + "Arnassi ruins, Song plant spore on the top of the ruins": 698179, + "Arnassi ruins, Arnassi Armor": 698191, + } + + locations_arnassi_path = { + "Arnassi Ruins, Arnassi statue": 698164, + "Arnassi Ruins, Transturtle": 698217, + } + + locations_arnassi_crab_boss = { + "Arnassi ruins, Crab armor": 698187, + } + + locations_simon = { + "Kelp forest, beating Simon says": 698156, + "Simon says area, Transturtle": 698216, + } + + locations_mithalas_city = { + "Mithalas city, first bulb in the left city part": 698030, + "Mithalas city, second bulb in the left city part": 698035, + "Mithalas city, bulb in the right part": 698031, + "Mithalas city, bulb at the top of the city": 698033, + "Mithalas city, first bulb in a broken home": 698034, + "Mithalas city, second bulb in a broken home": 698041, + "Mithalas city, bulb in the bottom left part": 698037, + "Mithalas city, first bulb in one of the homes": 698038, + "Mithalas city, second bulb in one of the homes": 698039, + "Mithalas city, first urn in one of the homes": 698123, + "Mithalas city, second urn in one of the homes": 698124, + "Mithalas city, first urn in the city reserve": 698125, + "Mithalas city, second urn in the city reserve": 698126, + "Mithalas city, third urn in the city reserve": 698127, + } + + locations_mithalas_city_top_path = { + "Mithalas city, first bulb at the end of the top path": 698032, + "Mithalas city, second bulb at the end of the top path": 698040, + "Mithalas city, bulb in the top path": 698036, + "Mithalas city, Mithalas pot": 698174, + "Mithalas city, urn in the cathedral flower tube entrance": 698128, + } + + locations_mithalas_city_fishpass = { + "Mithalas city, Doll": 698173, + "Mithalas city, urn inside a home fish pass": 698129, + } + + locations_cathedral_l = { + "Mithalas city castle, bulb in the flesh hole": 698042, + "Mithalas city castle, Blue banner": 698165, + "Mithalas city castle, urn in the bedroom": 698130, + "Mithalas city castle, first urn of the single lamp path": 698131, + "Mithalas city castle, second urn of the single lamp path": 698132, + "Mithalas city castle, urn in the bottom room": 698133, + "Mithalas city castle, first urn on the entrance path": 698134, + "Mithalas city castle, second urn on the entrance path": 698135, + } + + locations_cathedral_l_tube = { + "Mithalas castle, beating the priests": 698208, + } + + locations_cathedral_l_sc = { + "Mithalas city castle, Trident head": 698183, + } + + locations_cathedral_r = { + "Mithalas cathedral, first urn in the top right room": 698136, + "Mithalas cathedral, second urn in the top right room": 698137, + "Mithalas cathedral, third urn in the top right room": 698138, + "Mithalas cathedral, urn in the flesh room with fleas": 698139, + "Mithalas cathedral, first urn in the bottom right path": 698140, + "Mithalas cathedral, second urn in the bottom right path": 698141, + "Mithalas cathedral, urn behind the flesh vein": 698142, + "Mithalas cathedral, urn in the top left eyes boss room": 698143, + "Mithalas cathedral, first urn in the path behind the flesh vein": 698144, + "Mithalas cathedral, second urn in the path behind the flesh vein": 698145, + "Mithalas cathedral, third urn in the path behind the flesh vein": 698146, + "Mithalas cathedral, one of the urns in the top right room": 698147, + "Mithalas cathedral, Mithalan Dress": 698189, + "Mithalas cathedral right area, urn bellow the left entrance": 698198, + } + + locations_cathedral_underground = { + "Cathedral underground, bulb in the center part": 698113, + "Cathedral underground, first bulb in the top left part": 698114, + "Cathedral underground, second bulb in the top left part": 698115, + "Cathedral underground, third bulb in the top left part": 698116, + "Cathedral underground, bulb close to the save cristal": 698117, + "Cathedral underground, bulb in the bottom right path": 698118, + } + + locations_cathedral_boss = { + "Cathedral boss area, beating Mithalan God": 698202, + } + + locations_forest_tl = { + "Kelp Forest top left area, bulb in the bottom left clearing": 698044, + "Kelp Forest top left area, bulb in the path down from the top left clearing": 698045, + "Kelp Forest top left area, bulb in the top left clearing": 698046, + "Kelp Forest top left, Jelly Egg": 698185, + } + + locations_forest_tl_fp = { + "Kelp Forest top left area, bulb close to the Verse egg": 698047, + "Kelp forest top left area, Verse egg": 698158, + } + + locations_forest_tr = { + "Kelp Forest top right area, bulb under the rock in the right path": 698048, + "Kelp Forest top right area, bulb at the left of the center clearing": 698049, + "Kelp Forest top right area, bulb in the left path's big room": 698051, + "Kelp Forest top right area, bulb in the left path's small room": 698052, + "Kelp Forest top right area, bulb at the top of the center clearing": 698053, + "Kelp forest top right area, Black pearl": 698167, + } + + locations_forest_tr_fp = { + "Kelp Forest top right area, bulb in the top fish pass": 698050, + } + + locations_forest_bl = { + "Kelp Forest bottom left area, bulb close to the spirit crystals": 698054, + "Kelp forest bottom left area, Walker baby": 698186, + "Kelp Forest bottom left area, Transturtle": 698212, + } + + locations_forest_br = { + "Kelp forest bottom right area, Odd Container": 698168, + } + + locations_forest_boss = { + "Kelp forest boss area, beating Drunian God": 698204, + } + + locations_forest_boss_entrance = { + "Kelp Forest boss room, bulb at the bottom of the area": 698055, + } + + locations_forest_fish_cave = { + "Kelp Forest bottom left area, Fish cave puzzle": 698207, + } + + locations_forest_sprite_cave = { + "Kelp Forest sprite cave, bulb inside the fish pass": 698056, + } + + locations_forest_sprite_cave_tube = { + "Kelp Forest sprite cave, bulb in the second room": 698057, + "Kelp Forest Sprite Cave, Seed bag": 698176, + } + + locations_mermog_cave = { + "Mermog cave, bulb in the left part of the cave": 698121, + } + + locations_mermog_boss = { + "Mermog cave, Piranha Egg": 698197, + } + + locations_veil_tl = { + "The veil top left area, In the Li cave": 698199, + "The veil top left area, bulb under the rock in the top right path": 698078, + "The veil top left area, bulb hidden behind the blocking rock": 698076, + "The veil top left area, Transturtle": 698209, + } + + locations_veil_tl_fp = { + "The veil top left area, bulb inside the fish pass": 698077, + } + + locations_turtle_cave = { + "Turtle cave, Turtle Egg": 698184, + } + + locations_turtle_cave_bubble = { + "Turtle cave, bulb in bubble cliff": 698000, + "Turtle cave, Urchin costume": 698193, + } + + locations_veil_tr_r = { + "The veil top right area, bulb in the middle of the wall jump cliff": 698079, + "The veil top right area, golden starfish at the bottom right of the bottom path": 698180, + } + + locations_veil_tr_l = { + "The veil top right area, bulb in the top of the water fall": 698080, + "The veil top right area, Transturtle": 698210, + } + + locations_veil_bl = { + "The veil bottom area, bulb in the left path": 698082, + } + + locations_veil_b_sc = { + "The veil bottom area, bulb in the spirit path": 698081, + } + + locations_veil_bl_fp = { + "The veil bottom area, Verse egg": 698157, + } + + locations_veil_br = { + "The veil bottom area, Stone Head": 698181, + } + + locations_octo_cave_t = { + "Octopus cave, Dumbo Egg": 698196, + } + + locations_octo_cave_b = { + "Octopus cave, bulb in the path below the octopus cave path": 698122, + } + + locations_sun_temple_l = { + "Sun temple, bulb in the top left part": 698094, + "Sun temple, bulb in the top right part": 698095, + "Sun temple, bulb at the top of the high dark room": 698096, + "Sun temple, Golden Gear": 698171, + } + + locations_sun_temple_r = { + "Sun temple, first bulb of the temple": 698091, + "Sun temple, bulb on the left part": 698092, + "Sun temple, bulb in the hidden room of the right part": 698093, + "Sun temple, Sun key": 698182, + } + + locations_sun_temple_boss_path = { + "Sun Worm path, first path bulb": 698017, + "Sun Worm path, second path bulb": 698018, + "Sun Worm path, first cliff bulb": 698019, + "Sun Worm path, second cliff bulb": 698020, + } + + locations_sun_temple_boss = { + "Sun temple boss area, beating Sun God": 698203, + } + + locations_abyss_l = { + "Abyss left area, bulb in hidden path room": 698024, + "Abyss left area, bulb in the right part": 698025, + "Abyss left area, Glowing seed": 698166, + "Abyss left area, Glowing Plant": 698172, + } + + locations_abyss_lb = { + "Abyss left area, bulb in the bottom fish pass": 698026, + } + + locations_abyss_r = { + "Abyss right area, bulb behind the rock in the whale room": 698109, + "Abyss right area, bulb in the middle path": 698110, + "Abyss right area, bulb behind the rock in the middle path": 698111, + "Abyss right area, bulb in the left green room": 698112, + "Abyss right area, Transturtle": 698214, + } + + locations_ice_cave = { + "Ice cave, bulb in the room to the right": 698083, + "Ice cave, First bulbs in the top exit room": 698084, + "Ice cave, Second bulbs in the top exit room": 698085, + "Ice cave, third bulbs in the top exit room": 698086, + "Ice cave, bulb in the left room": 698087, + } + + locations_bubble_cave = { + "Bubble cave, bulb in the left cave wall": 698089, + "Bubble cave, bulb in the right cave wall (behind the ice cristal)": 698090, + } + + locations_bubble_cave_boss = { + "Bubble cave, Verse egg": 698161, + } + + locations_king_jellyfish_cave = { + "King Jellyfish cave, bulb in the right path from King Jelly": 698088, + "King Jellyfish cave, Jellyfish Costume": 698188, + } + + locations_whale = { + "The whale, Verse egg": 698159, + } + + locations_sunken_city_r = { + "Sunken city right area, crate close to the save cristal": 698154, + "Sunken city right area, crate in the left bottom room": 698155, + } + + locations_sunken_city_l = { + "Sunken city left area, crate in the little pipe room": 698151, + "Sunken city left area, crate close to the save cristal": 698152, + "Sunken city left area, crate before the bedroom": 698153, + } + + locations_sunken_city_l_bedroom = { + "Sunken city left area, Girl Costume": 698192, + } + + locations_sunken_city_boss = { + "Sunken city, bulb on the top of the boss area (boiler room)": 698043, + } + + locations_body_c = { + "The body center area, breaking li cage": 698201, + "The body main area, bulb on the main path blocking tube": 698097, + } + + locations_body_l = { + "The body left area, first bulb in the top face room": 698066, + "The body left area, second bulb in the top face room": 698069, + "The body left area, bulb bellow the water stream": 698067, + "The body left area, bulb in the top path to the top face room": 698068, + "The body left area, bulb in the bottom face room": 698070, + } + + locations_body_rt = { + "The body right area, bulb in the top face room": 698100, + } + + locations_body_rb = { + "The body right area, bulb in the top path to the bottom face room": 698098, + "The body right area, bulb in the bottom face room": 698099, + } + + locations_body_b = { + "The body bottom area, bulb in the Jelly Zap room": 698101, + "The body bottom area, bulb in the nautilus room": 698102, + "The body bottom area, Mutant Costume": 698190, + } + + locations_final_boss_tube = { + "Final boss area, first bulb in the turtle room": 698103, + "Final boss area, second bulbs in the turtle room": 698104, + "Final boss area, third bulbs in the turtle room": 698105, + "Final boss area, Transturtle": 698215, + } + + locations_final_boss = { + "Final boss area, bulb in the boss third form room": 698106, + } + + +location_table = { + **AquariaLocations.locations_openwater_tl, + **AquariaLocations.locations_openwater_tr, + **AquariaLocations.locations_openwater_tr_turtle, + **AquariaLocations.locations_openwater_bl, + **AquariaLocations.locations_skeleton_path, + **AquariaLocations.locations_skeleton_path_sc, + **AquariaLocations.locations_arnassi, + **AquariaLocations.locations_arnassi_path, + **AquariaLocations.locations_arnassi_crab_boss, + **AquariaLocations.locations_sun_temple_l, + **AquariaLocations.locations_sun_temple_r, + **AquariaLocations.locations_sun_temple_boss_path, + **AquariaLocations.locations_sun_temple_boss, + **AquariaLocations.locations_verse_cave_r, + **AquariaLocations.locations_verse_cave_l, + **AquariaLocations.locations_abyss_l, + **AquariaLocations.locations_abyss_lb, + **AquariaLocations.locations_abyss_r, + **AquariaLocations.locations_energy_temple_1, + **AquariaLocations.locations_energy_temple_2, + **AquariaLocations.locations_energy_temple_3, + **AquariaLocations.locations_energy_temple_boss, + **AquariaLocations.locations_energy_temple_blaster_room, + **AquariaLocations.locations_energy_temple_altar, + **AquariaLocations.locations_energy_temple_idol, + **AquariaLocations.locations_mithalas_city, + **AquariaLocations.locations_mithalas_city_top_path, + **AquariaLocations.locations_mithalas_city_fishpass, + **AquariaLocations.locations_cathedral_l, + **AquariaLocations.locations_cathedral_l_tube, + **AquariaLocations.locations_cathedral_l_sc, + **AquariaLocations.locations_cathedral_r, + **AquariaLocations.locations_cathedral_underground, + **AquariaLocations.locations_cathedral_boss, + **AquariaLocations.locations_forest_tl, + **AquariaLocations.locations_forest_tl_fp, + **AquariaLocations.locations_forest_tr, + **AquariaLocations.locations_forest_tr_fp, + **AquariaLocations.locations_forest_bl, + **AquariaLocations.locations_forest_br, + **AquariaLocations.locations_forest_boss, + **AquariaLocations.locations_forest_boss_entrance, + **AquariaLocations.locations_forest_sprite_cave, + **AquariaLocations.locations_forest_sprite_cave_tube, + **AquariaLocations.locations_forest_fish_cave, + **AquariaLocations.locations_home_water, + **AquariaLocations.locations_home_water_transturtle, + **AquariaLocations.locations_home_water_nautilus, + **AquariaLocations.locations_body_l, + **AquariaLocations.locations_body_rt, + **AquariaLocations.locations_body_rb, + **AquariaLocations.locations_body_c, + **AquariaLocations.locations_body_b, + **AquariaLocations.locations_final_boss_tube, + **AquariaLocations.locations_final_boss, + **AquariaLocations.locations_song_cave, + **AquariaLocations.locations_veil_tl, + **AquariaLocations.locations_veil_tl_fp, + **AquariaLocations.locations_turtle_cave, + **AquariaLocations.locations_turtle_cave_bubble, + **AquariaLocations.locations_veil_tr_r, + **AquariaLocations.locations_veil_tr_l, + **AquariaLocations.locations_veil_bl, + **AquariaLocations.locations_veil_b_sc, + **AquariaLocations.locations_veil_bl_fp, + **AquariaLocations.locations_veil_br, + **AquariaLocations.locations_ice_cave, + **AquariaLocations.locations_king_jellyfish_cave, + **AquariaLocations.locations_bubble_cave, + **AquariaLocations.locations_bubble_cave_boss, + **AquariaLocations.locations_naija_home, + **AquariaLocations.locations_mermog_cave, + **AquariaLocations.locations_mermog_boss, + **AquariaLocations.locations_octo_cave_t, + **AquariaLocations.locations_octo_cave_b, + **AquariaLocations.locations_sunken_city_l, + **AquariaLocations.locations_sunken_city_r, + **AquariaLocations.locations_sunken_city_boss, + **AquariaLocations.locations_sunken_city_l_bedroom, + **AquariaLocations.locations_simon, + **AquariaLocations.locations_whale, +} diff --git a/worlds/aquaria/Options.py b/worlds/aquaria/Options.py new file mode 100644 index 00000000..5c4936e4 --- /dev/null +++ b/worlds/aquaria/Options.py @@ -0,0 +1,145 @@ +""" +Author: Louis M +Date: Fri, 15 Mar 2024 18:41:40 +0000 +Description: Manage options in the Aquaria game multiworld randomizer +""" + +from dataclasses import dataclass +from Options import Toggle, Choice, Range, DeathLink, PerGameCommonOptions, DefaultOnToggle, StartInventoryPool + + +class IngredientRandomizer(Choice): + """ + Randomize Ingredients. Select if the simple ingredients (that does not have + a recipe) should be randomized. If 'common_ingredients' is selected, the + randomization will exclude the "Red Bulb", "Special Bulb" and "Rukh Egg". + """ + display_name = "Randomize Ingredients" + option_off = 0 + option_common_ingredients = 1 + option_all_ingredients = 2 + default = 0 + + +class DishRandomizer(Toggle): + """Randomize the drop of Dishes (Ingredients with recipe).""" + display_name = "Dish Randomizer" + + +class TurtleRandomizer(Choice): + """Randomize the transportation turtle.""" + display_name = "Turtle Randomizer" + option_no_turtle_randomization = 0 + option_randomize_all_turtle = 1 + option_randomize_turtle_other_than_the_final_one = 2 + default = 2 + + +class EarlyEnergyForm(DefaultOnToggle): + """ + Force the Energy Form to be in a location before leaving the areas around the Home Water. + """ + display_name = "Early Energy Form" + + +class AquarianTranslation(Toggle): + """Translate to English the Aquarian scripture in the game.""" + display_name = "Translate Aquarian" + + +class BigBossesToBeat(Range): + """ + A number of big bosses to beat before having access to the creator (the final boss). The big bosses are + "Fallen God", "Mithalan God", "Drunian God", "Sun God" and "The Golem". + """ + display_name = "Big bosses to beat" + range_start = 0 + range_end = 5 + default = 0 + + +class MiniBossesToBeat(Range): + """ + A number of Minibosses to beat before having access to the creator (the final boss). Mini bosses are + "Nautilus Prime", "Blaster Peg Prime", "Mergog", "Mithalan priests", "Octopus Prime", "Crabbius Maximus", + "Mantis Shrimp Prime" and "King Jellyfish God Prime". Note that the Energy statue and Simon says are not + mini bosses. + """ + display_name = "Mini bosses to beat" + range_start = 0 + range_end = 8 + default = 0 + + +class Objective(Choice): + """ + The game objective can be only to kill the creator or to kill the creator + and having obtained the three every secret memories + """ + display_name = "Objective" + option_kill_the_creator = 0 + option_obtain_secrets_and_kill_the_creator = 1 + default = 0 + +class SkipFirstVision(Toggle): + """ + The first vision in the game; where Naija transform to Energy Form and get fload by enemy; is quite cool but + can be quite long when you already know what is going on. This option can be used to skip this vision. + """ + display_name = "Skip first Naija's vision" + +class NoProgressionHardOrHiddenLocation(Toggle): + """ + Make sure that there is no progression items at hard to get or hard to find locations. + Those locations that will be very High location (that need beast form, soup and skill to get), every + location in the bubble cave, locations that need you to cross a false wall without any indication, Arnassi + race, bosses and mini-bosses. Usefull for those that want a casual run. + """ + display_name = "No progression in hard or hidden locations" + +class LightNeededToGetToDarkPlaces(DefaultOnToggle): + """ + Make sure that the sun form or the dumbo pet can be aquired before getting to dark places. Be aware that navigating + in dark place without light is extremely difficult. + """ + display_name = "Light needed to get to dark places" + +class BindSongNeededToGetUnderRockBulb(Toggle): + """ + Make sure that the bind song can be aquired before having to obtain sing bulb under rocks. + """ + display_name = "Bind song needed to get sing bulbs under rocks" + + +class UnconfineHomeWater(Choice): + """ + Open the way out of Home water area so that Naija can go to open water and beyond without the bind song. + """ + display_name = "Unconfine Home Water Area" + option_off = 0 + option_via_energy_door = 1 + option_via_transturtle = 2 + option_via_both = 3 + default = 0 + + +@dataclass +class AquariaOptions(PerGameCommonOptions): + """ + Every option in the Aquaria randomizer + """ + start_inventory_from_pool: StartInventoryPool + objective: Objective + mini_bosses_to_beat: MiniBossesToBeat + big_bosses_to_beat: BigBossesToBeat + turtle_randomizer: TurtleRandomizer + early_energy_form: EarlyEnergyForm + light_needed_to_get_to_dark_places: LightNeededToGetToDarkPlaces + bind_song_needed_to_get_under_rock_bulb: BindSongNeededToGetUnderRockBulb + unconfine_home_water: UnconfineHomeWater + no_progression_hard_or_hidden_locations: NoProgressionHardOrHiddenLocation + ingredient_randomizer: IngredientRandomizer + dish_randomizer: DishRandomizer + aquarian_translation: AquarianTranslation + skip_first_vision: SkipFirstVision + death_link: DeathLink diff --git a/worlds/aquaria/Regions.py b/worlds/aquaria/Regions.py new file mode 100755 index 00000000..d16ef9f3 --- /dev/null +++ b/worlds/aquaria/Regions.py @@ -0,0 +1,1401 @@ +""" +Author: Louis M +Date: Fri, 15 Mar 2024 18:41:40 +0000 +Description: Used to manage Regions in the Aquaria game multiworld randomizer +""" + +from typing import Dict, Optional +from BaseClasses import MultiWorld, Region, Entrance, ItemClassification, LocationProgressType, CollectionState +from .Items import AquariaItem +from .Locations import AquariaLocations, AquariaLocation +from .Options import AquariaOptions +from worlds.generic.Rules import add_rule, set_rule + + +# Every condition to connect regions + +def _has_hot_soup(state:CollectionState, player: int) -> bool: + """`player` in `state` has the hotsoup item""" + return state.has("Hot soup", player) + + +def _has_tongue_cleared(state:CollectionState, player: int) -> bool: + """`player` in `state` has the Body tongue cleared item""" + return state.has("Body tongue cleared", player) + + +def _has_sun_crystal(state:CollectionState, player: int) -> bool: + """`player` in `state` has the Sun crystal item""" + return state.has("Has sun crystal", player) and _has_bind_song(state, player) + + +def _has_li(state:CollectionState, player: int) -> bool: + """`player` in `state` has Li in its team""" + return state.has("Li and Li song", player) + + +def _has_damaging_item(state:CollectionState, player: int) -> bool: + """`player` in `state` has the shield song item""" + return state.has_any({"Energy form", "Nature form", "Beast form", "Li and Li song", "Baby nautilus", + "Baby piranha", "Baby blaster"}, player) + + +def _has_shield_song(state:CollectionState, player: int) -> bool: + """`player` in `state` has the shield song item""" + return state.has("Shield song", player) + + +def _has_bind_song(state:CollectionState, player: int) -> bool: + """`player` in `state` has the bind song item""" + return state.has("Bind song", player) + + +def _has_energy_form(state:CollectionState, player: int) -> bool: + """`player` in `state` has the energy form item""" + return state.has("Energy form", player) + + +def _has_beast_form(state:CollectionState, player: int) -> bool: + """`player` in `state` has the beast form item""" + return state.has("Beast form", player) + + +def _has_nature_form(state:CollectionState, player: int) -> bool: + """`player` in `state` has the nature form item""" + return state.has("Nature form", player) + + +def _has_sun_form(state:CollectionState, player: int) -> bool: + """`player` in `state` has the sun form item""" + return state.has("Sun form", player) + + +def _has_light(state:CollectionState, player: int) -> bool: + """`player` in `state` has the light item""" + return state.has("Baby dumbo", player) or _has_sun_form(state, player) + + +def _has_dual_form(state:CollectionState, player: int) -> bool: + """`player` in `state` has the dual form item""" + return _has_li(state, player) and state.has("Dual form", player) + + +def _has_fish_form(state:CollectionState, player: int) -> bool: + """`player` in `state` has the fish form item""" + return state.has("Fish form", player) + + +def _has_spirit_form(state:CollectionState, player: int) -> bool: + """`player` in `state` has the spirit form item""" + return state.has("Spirit form", player) + + +def _has_big_bosses(state:CollectionState, player: int) -> bool: + """`player` in `state` has beated every big bosses""" + return state.has_all({"Fallen God beated", "Mithalan God beated", "Drunian God beated", + "Sun God beated", "The Golem beated"}, player) + + +def _has_mini_bosses(state:CollectionState, player: int) -> bool: + """`player` in `state` has beated every big bosses""" + return state.has_all({"Nautilus Prime beated", "Blaster Peg Prime beated", "Mergog beated", + "Mithalan priests beated", "Octopus Prime beated", "Crabbius Maximus beated", + "Mantis Shrimp Prime beated", "King Jellyfish God Prime beated"}, player) + + +def _has_secrets(state:CollectionState, player: int) -> bool: + return state.has_all({"First secret obtained", "Second secret obtained", "Third secret obtained"},player) + + +class AquariaRegions: + """ + Class used to create regions of the Aquaria game + """ + menu: Region + verse_cave_r: Region + verse_cave_l: Region + home_water: Region + home_water_nautilus: Region + home_water_transturtle: Region + naija_home: Region + song_cave: Region + energy_temple_1: Region + energy_temple_2: Region + energy_temple_3: Region + energy_temple_boss: Region + energy_temple_idol: Region + energy_temple_blaster_room: Region + energy_temple_altar: Region + openwater_tl: Region + openwater_tr: Region + openwater_tr_turtle: Region + openwater_bl: Region + openwater_br: Region + skeleton_path: Region + skeleton_path_sc: Region + arnassi: Region + arnassi_path: Region + arnassi_crab_boss: Region + simon: Region + mithalas_city: Region + mithalas_city_top_path: Region + mithalas_city_fishpass: Region + cathedral_l: Region + cathedral_l_tube: Region + cathedral_l_sc: Region + cathedral_r: Region + cathedral_underground: Region + cathedral_boss_l: Region + cathedral_boss_r: Region + forest_tl: Region + forest_tl_fp: Region + forest_tr: Region + forest_tr_fp: Region + forest_bl: Region + forest_br: Region + forest_boss: Region + forest_boss_entrance: Region + forest_sprite_cave: Region + forest_sprite_cave_tube: Region + mermog_cave: Region + mermog_boss: Region + forest_fish_cave: Region + veil_tl: Region + veil_tl_fp: Region + veil_tr_l: Region + veil_tr_r: Region + veil_bl: Region + veil_b_sc: Region + veil_bl_fp: Region + veil_br: Region + octo_cave_t: Region + octo_cave_b: Region + turtle_cave: Region + turtle_cave_bubble: Region + sun_temple_l: Region + sun_temple_r: Region + sun_temple_boss_path: Region + sun_temple_boss: Region + abyss_l: Region + abyss_lb: Region + abyss_r: Region + ice_cave: Region + bubble_cave: Region + bubble_cave_boss: Region + king_jellyfish_cave: Region + whale: Region + first_secret: Region + sunken_city_l: Region + sunken_city_r: Region + sunken_city_boss: Region + sunken_city_l_bedroom: Region + body_c: Region + body_l: Region + body_rt: Region + body_rb: Region + body_b: Region + final_boss_loby: Region + final_boss_tube: Region + final_boss: Region + final_boss_end: Region + """ + Every Region of the game + """ + + multiworld: MultiWorld + """ + The Current Multiworld game. + """ + + player: int + """ + The ID of the player + """ + + def __add_region(self, hint: str, + locations: Optional[Dict[str, Optional[int]]]) -> Region: + """ + Create a new Region, add it to the `world` regions and return it. + Be aware that this function have a side effect on ``world`.`regions` + """ + region: Region = Region(hint, self.player, self.multiworld, hint) + if locations is not None: + region.add_locations(locations, AquariaLocation) + return region + + + + def __create_home_water_area(self) -> None: + """ + Create the `verse_cave`, `home_water` and `song_cave*` regions + """ + self.menu = self.__add_region("Menu", None) + self.verse_cave_r = self.__add_region("Verse Cave right area", + AquariaLocations.locations_verse_cave_r) + self.verse_cave_l = self.__add_region("Verse Cave left area", + AquariaLocations.locations_verse_cave_l) + self.home_water = self.__add_region("Home Water", AquariaLocations.locations_home_water) + self.home_water_nautilus = self.__add_region("Home Water, Nautilus nest", + AquariaLocations.locations_home_water_nautilus) + self.home_water_transturtle = self.__add_region("Home Water, turtle room", + AquariaLocations.locations_home_water_transturtle) + self.naija_home = self.__add_region("Naija's home", AquariaLocations.locations_naija_home) + self.song_cave = self.__add_region("Song cave", AquariaLocations.locations_song_cave) + + def __create_energy_temple(self) -> None: + """ + Create the `energy_temple_*` regions + """ + self.energy_temple_1 = self.__add_region("Energy temple first area", + AquariaLocations.locations_energy_temple_1) + self.energy_temple_2 = self.__add_region("Energy temple second area", + AquariaLocations.locations_energy_temple_2) + self.energy_temple_3 = self.__add_region("Energy temple third area", + AquariaLocations.locations_energy_temple_3) + self.energy_temple_altar = self.__add_region("Energy temple bottom entrance", + AquariaLocations.locations_energy_temple_altar) + self.energy_temple_boss = self.__add_region("Energy temple fallen God room", + AquariaLocations.locations_energy_temple_boss) + self.energy_temple_idol = self.__add_region("Energy temple Idol room", + AquariaLocations.locations_energy_temple_idol) + self.energy_temple_blaster_room = self.__add_region("Energy temple blaster room", + AquariaLocations.locations_energy_temple_blaster_room) + + def __create_openwater(self) -> None: + """ + Create the `openwater_*`, `skeleton_path`, `arnassi*` and `simon` + regions + """ + self.openwater_tl = self.__add_region("Open water top left area", + AquariaLocations.locations_openwater_tl) + self.openwater_tr = self.__add_region("Open water top right area", + AquariaLocations.locations_openwater_tr) + self.openwater_tr_turtle = self.__add_region("Open water top right area, turtle room", + AquariaLocations.locations_openwater_tr_turtle) + self.openwater_bl = self.__add_region("Open water bottom left area", + AquariaLocations.locations_openwater_bl) + self.openwater_br = self.__add_region("Open water bottom right area", None) + self.skeleton_path = self.__add_region("Open water skeleton path", + AquariaLocations.locations_skeleton_path) + self.skeleton_path_sc = self.__add_region("Open water skeleton path spirit cristal", + AquariaLocations.locations_skeleton_path_sc) + self.arnassi = self.__add_region("Arnassi Ruins", AquariaLocations.locations_arnassi) + self.arnassi_path = self.__add_region("Arnassi Ruins, back entrance path", + AquariaLocations.locations_arnassi_path) + self.arnassi_crab_boss = self.__add_region("Arnassi Ruins, Crabbius Maximus lair", + AquariaLocations.locations_arnassi_crab_boss) + + def __create_mithalas(self) -> None: + """ + Create the `mithalas_city*` and `cathedral_*` regions + """ + self.mithalas_city = self.__add_region("Mithalas city", + AquariaLocations.locations_mithalas_city) + self.mithalas_city_fishpass = self.__add_region("Mithalas city fish pass", + AquariaLocations.locations_mithalas_city_fishpass) + self.mithalas_city_top_path = self.__add_region("Mithalas city top path", + AquariaLocations.locations_mithalas_city_top_path) + self.cathedral_l = self.__add_region("Mithalas castle", AquariaLocations.locations_cathedral_l) + self.cathedral_l_tube = self.__add_region("Mithalas castle, plant tube entrance", + AquariaLocations.locations_cathedral_l_tube) + self.cathedral_l_sc = self.__add_region("Mithalas castle spirit cristal", + AquariaLocations.locations_cathedral_l_sc) + self.cathedral_r = self.__add_region("Mithalas Cathedral", + AquariaLocations.locations_cathedral_r) + self.cathedral_underground = self.__add_region("Mithalas Cathedral underground area", + AquariaLocations.locations_cathedral_underground) + self.cathedral_boss_r = self.__add_region("Mithalas Cathedral, Mithalan God room", + AquariaLocations.locations_cathedral_boss) + self.cathedral_boss_l = self.__add_region("Mithalas Cathedral, after Mithalan God room", None) + + def __create_forest(self) -> None: + """ + Create the `forest_*` dans `mermog_cave` regions + """ + self.forest_tl = self.__add_region("Kelp forest top left area", + AquariaLocations.locations_forest_tl) + self.forest_tl_fp = self.__add_region("Kelp forest top left area fish pass", + AquariaLocations.locations_forest_tl_fp) + self.forest_tr = self.__add_region("Kelp forest top right area", + AquariaLocations.locations_forest_tr) + self.forest_tr_fp = self.__add_region("Kelp forest top right area fish pass", + AquariaLocations.locations_forest_tr_fp) + self.forest_bl = self.__add_region("Kelp forest bottom left area", + AquariaLocations.locations_forest_bl) + self.forest_br = self.__add_region("Kelp forest bottom right area", + AquariaLocations.locations_forest_br) + self.forest_sprite_cave = self.__add_region("Kelp forest spirit cave", + AquariaLocations.locations_forest_sprite_cave) + self.forest_sprite_cave_tube = self.__add_region("Kelp forest spirit cave after the plant tube", + AquariaLocations.locations_forest_sprite_cave_tube) + self.forest_boss = self.__add_region("Kelp forest Drunian God room", + AquariaLocations.locations_forest_boss) + self.forest_boss_entrance = self.__add_region("Kelp forest Drunian God room entrance", + AquariaLocations.locations_forest_boss_entrance) + self.mermog_cave = self.__add_region("Kelp forest Mermog cave", + AquariaLocations.locations_mermog_cave) + self.mermog_boss = self.__add_region("Kelp forest Mermog cave boss", + AquariaLocations.locations_mermog_boss) + self.forest_fish_cave = self.__add_region("Kelp forest fish cave", + AquariaLocations.locations_forest_fish_cave) + self.simon = self.__add_region("Kelp forest, Simon's room", AquariaLocations.locations_simon) + + def __create_veil(self) -> None: + """ + Create the `veil_*`, `octo_cave` and `turtle_cave` regions + """ + self.veil_tl = self.__add_region("The veil top left area", AquariaLocations.locations_veil_tl) + self.veil_tl_fp = self.__add_region("The veil top left area fish pass", + AquariaLocations.locations_veil_tl_fp) + self.turtle_cave = self.__add_region("The veil top left area, turtle cave", + AquariaLocations.locations_turtle_cave) + self.turtle_cave_bubble = self.__add_region("The veil top left area, turtle cave bubble cliff", + AquariaLocations.locations_turtle_cave_bubble) + self.veil_tr_l = self.__add_region("The veil top right area, left of temple", + AquariaLocations.locations_veil_tr_l) + self.veil_tr_r = self.__add_region("The veil top right area, right of temple", + AquariaLocations.locations_veil_tr_r) + self.octo_cave_t = self.__add_region("Octopus cave top entrance", + AquariaLocations.locations_octo_cave_t) + self.octo_cave_b = self.__add_region("Octopus cave bottom entrance", + AquariaLocations.locations_octo_cave_b) + self.veil_bl = self.__add_region("The veil bottom left area", + AquariaLocations.locations_veil_bl) + self.veil_b_sc = self.__add_region("The veil bottom spirit cristal area", + AquariaLocations.locations_veil_b_sc) + self.veil_bl_fp = self.__add_region("The veil bottom left area, in the sunken ship", + AquariaLocations.locations_veil_bl_fp) + self.veil_br = self.__add_region("The veil bottom right area", + AquariaLocations.locations_veil_br) + + def __create_sun_temple(self) -> None: + """ + Create the `sun_temple*` regions + """ + self.sun_temple_l = self.__add_region("Sun temple left area", + AquariaLocations.locations_sun_temple_l) + self.sun_temple_r = self.__add_region("Sun temple right area", + AquariaLocations.locations_sun_temple_r) + self.sun_temple_boss_path = self.__add_region("Sun temple before boss area", + AquariaLocations.locations_sun_temple_boss_path) + self.sun_temple_boss = self.__add_region("Sun temple boss area", + AquariaLocations.locations_sun_temple_boss) + + def __create_abyss(self) -> None: + """ + Create the `abyss_*`, `ice_cave`, `king_jellyfish_cave` and `whale` + regions + """ + self.abyss_l = self.__add_region("Abyss left area", + AquariaLocations.locations_abyss_l) + self.abyss_lb = self.__add_region("Abyss left bottom area", AquariaLocations.locations_abyss_lb) + self.abyss_r = self.__add_region("Abyss right area", AquariaLocations.locations_abyss_r) + self.ice_cave = self.__add_region("Ice cave", AquariaLocations.locations_ice_cave) + self.bubble_cave = self.__add_region("Bubble cave", AquariaLocations.locations_bubble_cave) + self.bubble_cave_boss = self.__add_region("Bubble cave boss area", AquariaLocations.locations_bubble_cave_boss) + self.king_jellyfish_cave = self.__add_region("Abyss left area, King jellyfish cave", + AquariaLocations.locations_king_jellyfish_cave) + self.whale = self.__add_region("Inside the whale", AquariaLocations.locations_whale) + self.first_secret = self.__add_region("First secret area", None) + + def __create_sunken_city(self) -> None: + """ + Create the `sunken_city_*` regions + """ + self.sunken_city_l = self.__add_region("Sunken city left area", + AquariaLocations.locations_sunken_city_l) + self.sunken_city_l_bedroom = self.__add_region("Sunken city left area, bedroom", + AquariaLocations.locations_sunken_city_l_bedroom) + self.sunken_city_r = self.__add_region("Sunken city right area", + AquariaLocations.locations_sunken_city_r) + self.sunken_city_boss = self.__add_region("Sunken city boss area", + AquariaLocations.locations_sunken_city_boss) + + def __create_body(self) -> None: + """ + Create the `body_*` and `final_boss* regions + """ + self.body_c = self.__add_region("The body center area", + AquariaLocations.locations_body_c) + self.body_l = self.__add_region("The body left area", + AquariaLocations.locations_body_l) + self.body_rt = self.__add_region("The body right area, top path", + AquariaLocations.locations_body_rt) + self.body_rb = self.__add_region("The body right area, bottom path", + AquariaLocations.locations_body_rb) + self.body_b = self.__add_region("The body bottom area", + AquariaLocations.locations_body_b) + self.final_boss_loby = self.__add_region("The body, before final boss", None) + self.final_boss_tube = self.__add_region("The body, final boss area turtle room", + AquariaLocations.locations_final_boss_tube) + self.final_boss = self.__add_region("The body, final boss", + AquariaLocations.locations_final_boss) + self.final_boss_end = self.__add_region("The body, final boss area", None) + + def __connect_one_way_regions(self, source_name: str, destination_name: str, + source_region: Region, + destination_region: Region, rule=None) -> None: + """ + Connect from the `source_region` to the `destination_region` + """ + entrance = Entrance(source_region.player, source_name + " to " + destination_name, source_region) + source_region.exits.append(entrance) + entrance.connect(destination_region) + if rule is not None: + set_rule(entrance, rule) + + def __connect_regions(self, source_name: str, destination_name: str, + source_region: Region, + destination_region: Region, rule=None) -> None: + """ + Connect the `source_region` and the `destination_region` (two-way) + """ + self.__connect_one_way_regions(source_name, destination_name, source_region, destination_region, rule) + self.__connect_one_way_regions(destination_name, source_name, destination_region, source_region, rule) + + def __connect_home_water_regions(self) -> None: + """ + Connect entrances of the different regions around `home_water` + """ + self.__connect_regions("Menu", "Verse cave right area", + self.menu, self.verse_cave_r) + self.__connect_regions("Verse cave left area", "Verse cave right area", + self.verse_cave_l, self.verse_cave_r) + self.__connect_regions("Verse cave", "Home water", self.verse_cave_l, self.home_water) + self.__connect_regions("Home Water", "Haija's home", self.home_water, self.naija_home) + self.__connect_regions("Home Water", "Song cave", self.home_water, self.song_cave) + self.__connect_regions("Home Water", "Home water, nautilus nest", + self.home_water, self.home_water_nautilus, + lambda state: _has_energy_form(state, self.player) and _has_bind_song(state, self.player)) + self.__connect_regions("Home Water", "Home water transturtle room", + self.home_water, self.home_water_transturtle) + self.__connect_regions("Home Water", "Energy temple first area", + self.home_water, self.energy_temple_1, + lambda state: _has_bind_song(state, self.player)) + self.__connect_regions("Home Water", "Energy temple_altar", + self.home_water, self.energy_temple_altar, + lambda state: _has_energy_form(state, self.player) and + _has_bind_song(state, self.player)) + self.__connect_regions("Energy temple first area", "Energy temple second area", + self.energy_temple_1, self.energy_temple_2, + lambda state: _has_energy_form(state, self.player)) + self.__connect_regions("Energy temple first area", "Energy temple idol room", + self.energy_temple_1, self.energy_temple_idol, + lambda state: _has_fish_form(state, self.player)) + self.__connect_regions("Energy temple idol room", "Energy temple boss area", + self.energy_temple_idol, self.energy_temple_boss, + lambda state: _has_energy_form(state, self.player)) + self.__connect_one_way_regions("Energy temple first area", "Energy temple boss area", + self.energy_temple_1, self.energy_temple_boss, + lambda state: _has_beast_form(state, self.player) and + _has_energy_form(state, self.player)) + self.__connect_one_way_regions("Energy temple boss area", "Energy temple first area", + self.energy_temple_boss, self.energy_temple_1, + lambda state: _has_energy_form(state, self.player)) + self.__connect_regions("Energy temple second area", "Energy temple third area", + self.energy_temple_2, self.energy_temple_3, + lambda state: _has_bind_song(state, self.player) and + _has_energy_form(state, self.player)) + self.__connect_regions("Energy temple boss area", "Energy temple blaster room", + self.energy_temple_boss, self.energy_temple_blaster_room, + lambda state: _has_nature_form(state, self.player) and + _has_bind_song(state, self.player) and + _has_energy_form(state, self.player)) + self.__connect_regions("Energy temple first area", "Energy temple blaster room", + self.energy_temple_1, self.energy_temple_blaster_room, + lambda state: _has_nature_form(state, self.player) and + _has_bind_song(state, self.player) and + _has_energy_form(state, self.player) and + _has_beast_form(state, self.player)) + self.__connect_regions("Home Water", "Open water top left area", + self.home_water, self.openwater_tl) + + def __connect_open_water_regions(self) -> None: + """ + Connect entrances of the different regions around open water + """ + self.__connect_regions("Open water top left area", "Open water top right area", + self.openwater_tl, self.openwater_tr) + self.__connect_regions("Open water top left area", "Open water bottom left area", + self.openwater_tl, self.openwater_bl) + self.__connect_regions("Open water top left area", "forest bottom right area", + self.openwater_tl, self.forest_br) + self.__connect_regions("Open water top right area", "Open water top right area, turtle room", + self.openwater_tr, self.openwater_tr_turtle, + lambda state: _has_beast_form(state, self.player)) + self.__connect_regions("Open water top right area", "Open water bottom right area", + self.openwater_tr, self.openwater_br) + self.__connect_regions("Open water top right area", "Mithalas city", + self.openwater_tr, self.mithalas_city) + self.__connect_regions("Open water top right area", "Veil bottom left area", + self.openwater_tr, self.veil_bl) + self.__connect_one_way_regions("Open water top right area", "Veil bottom right", + self.openwater_tr, self.veil_br, + lambda state: _has_beast_form(state, self.player)) + self.__connect_one_way_regions("Veil bottom right", "Open water top right area", + self.veil_br, self.openwater_tr, + lambda state: _has_beast_form(state, self.player)) + self.__connect_regions("Open water bottom left area", "Open water bottom right area", + self.openwater_bl, self.openwater_br) + self.__connect_regions("Open water bottom left area", "Skeleton path", + self.openwater_bl, self.skeleton_path) + self.__connect_regions("Abyss left area", "Open water bottom left area", + self.abyss_l, self.openwater_bl) + self.__connect_regions("Skeleton path", "skeleton_path_sc", + self.skeleton_path, self.skeleton_path_sc, + lambda state: _has_spirit_form(state, self.player)) + self.__connect_regions("Abyss right area", "Open water bottom right area", + self.abyss_r, self.openwater_br) + self.__connect_one_way_regions("Open water bottom right area", "Arnassi", + self.openwater_br, self.arnassi, + lambda state: _has_beast_form(state, self.player)) + self.__connect_one_way_regions("Arnassi", "Open water bottom right area", + self.arnassi, self.openwater_br) + self.__connect_regions("Arnassi", "Arnassi path", + self.arnassi, self.arnassi_path) + self.__connect_one_way_regions("Arnassi path", "Arnassi crab boss area", + self.arnassi_path, self.arnassi_crab_boss, + lambda state: _has_beast_form(state, self.player) and + _has_energy_form(state, self.player)) + self.__connect_one_way_regions("Arnassi crab boss area", "Arnassi path", + self.arnassi_crab_boss, self.arnassi_path) + + def __connect_mithalas_regions(self) -> None: + """ + Connect entrances of the different regions around Mithalas + """ + self.__connect_one_way_regions("Mithalas city", "Mithalas city top path", + self.mithalas_city, self.mithalas_city_top_path, + lambda state: _has_beast_form(state, self.player)) + self.__connect_one_way_regions("Mithalas city_top_path", "Mithalas city", + self.mithalas_city_top_path, self.mithalas_city) + self.__connect_regions("Mithalas city", "Mithalas city home with fishpass", + self.mithalas_city, self.mithalas_city_fishpass, + lambda state: _has_fish_form(state, self.player)) + self.__connect_regions("Mithalas city", "Mithalas castle", + self.mithalas_city, self.cathedral_l, + lambda state: _has_fish_form(state, self.player)) + self.__connect_one_way_regions("Mithalas city top path", "Mithalas castle, flower tube", + self.mithalas_city_top_path, + self.cathedral_l_tube, + lambda state: _has_nature_form(state, self.player) and + _has_energy_form(state, self.player)) + self.__connect_one_way_regions("Mithalas castle, flower tube area", "Mithalas city top path", + self.cathedral_l_tube, + self.mithalas_city_top_path, + lambda state: _has_beast_form(state, self.player) and + _has_nature_form(state, self.player)) + self.__connect_one_way_regions("Mithalas castle flower tube area", "Mithalas castle, spirit crystals", + self.cathedral_l_tube, self.cathedral_l_sc, + lambda state: _has_spirit_form(state, self.player)) + self.__connect_one_way_regions("Mithalas castle_flower tube area", "Mithalas castle", + self.cathedral_l_tube, self.cathedral_l, + lambda state: _has_spirit_form(state, self.player)) + self.__connect_regions("Mithalas castle", "Mithalas castle, spirit crystals", + self.cathedral_l, self.cathedral_l_sc, + lambda state: _has_spirit_form(state, self.player)) + self.__connect_regions("Mithalas castle", "Cathedral boss left area", + self.cathedral_l, self.cathedral_boss_l, + lambda state: _has_beast_form(state, self.player) and + _has_energy_form(state, self.player) and + _has_bind_song(state, self.player)) + self.__connect_regions("Mithalas castle", "Cathedral underground", + self.cathedral_l, self.cathedral_underground, + lambda state: _has_beast_form(state, self.player) and + _has_bind_song(state, self.player)) + self.__connect_regions("Mithalas castle", "Cathedral right area", + self.cathedral_l, self.cathedral_r, + lambda state: _has_bind_song(state, self.player) and + _has_energy_form(state, self.player)) + self.__connect_regions("Cathedral right area", "Cathedral underground", + self.cathedral_r, self.cathedral_underground, + lambda state: _has_energy_form(state, self.player)) + self.__connect_one_way_regions("Cathedral underground", "Cathedral boss left area", + self.cathedral_underground, self.cathedral_boss_r, + lambda state: _has_energy_form(state, self.player) and + _has_bind_song(state, self.player)) + self.__connect_one_way_regions("Cathedral boss left area", "Cathedral underground", + self.cathedral_boss_r, self.cathedral_underground, + lambda state: _has_beast_form(state, self.player)) + self.__connect_regions("Cathedral boss right area", "Cathedral boss left area", + self.cathedral_boss_r, self.cathedral_boss_l, + lambda state: _has_bind_song(state, self.player) and + _has_energy_form(state, self.player)) + + def __connect_forest_regions(self) -> None: + """ + Connect entrances of the different regions around the Kelp Forest + """ + self.__connect_regions("Forest bottom right", "Veil bottom left area", + self.forest_br, self.veil_bl) + self.__connect_regions("Forest bottom right", "Forest bottom left area", + self.forest_br, self.forest_bl) + self.__connect_regions("Forest bottom right", "Forest top right area", + self.forest_br, self.forest_tr) + self.__connect_regions("Forest bottom left area", "Forest fish cave", + self.forest_bl, self.forest_fish_cave) + self.__connect_regions("Forest bottom left area", "Forest top left area", + self.forest_bl, self.forest_tl) + self.__connect_regions("Forest bottom left area", "Forest boss entrance", + self.forest_bl, self.forest_boss_entrance, + lambda state: _has_nature_form(state, self.player)) + self.__connect_regions("Forest top left area", "Forest top left area, fish pass", + self.forest_tl, self.forest_tl_fp, + lambda state: _has_nature_form(state, self.player) and + _has_bind_song(state, self.player) and + _has_energy_form(state, self.player) and + _has_fish_form(state, self.player)) + self.__connect_regions("Forest top left area", "Forest top right area", + self.forest_tl, self.forest_tr) + self.__connect_regions("Forest top left area", "Forest boss entrance", + self.forest_tl, self.forest_boss_entrance) + self.__connect_regions("Forest boss area", "Forest boss entrance", + self.forest_boss, self.forest_boss_entrance, + lambda state: _has_energy_form(state, self.player)) + self.__connect_regions("Forest top right area", "Forest top right area fish pass", + self.forest_tr, self.forest_tr_fp, + lambda state: _has_fish_form(state, self.player)) + self.__connect_regions("Forest top right area", "Forest sprite cave", + self.forest_tr, self.forest_sprite_cave) + self.__connect_regions("Forest sprite cave", "Forest sprite cave flower tube", + self.forest_sprite_cave, self.forest_sprite_cave_tube, + lambda state: _has_nature_form(state, self.player)) + self.__connect_regions("Forest top right area", "Mermog cave", + self.forest_tr_fp, self.mermog_cave) + self.__connect_regions("Fermog cave", "Fermog boss", + self.mermog_cave, self.mermog_boss, + lambda state: _has_beast_form(state, self.player) and + _has_energy_form(state, self.player)) + + def __connect_veil_regions(self) -> None: + """ + Connect entrances of the different regions around The Veil + """ + self.__connect_regions("Veil bottom left area", "Veil bottom left area, fish pass", + self.veil_bl, self.veil_bl_fp, + lambda state: _has_fish_form(state, self.player) and + _has_bind_song(state, self.player) and + _has_damaging_item(state, self.player)) + self.__connect_regions("Veil bottom left area", "Veil bottom area spirit crystals path", + self.veil_bl, self.veil_b_sc, + lambda state: _has_spirit_form(state, self.player)) + self.__connect_regions("Veil bottom area spirit crystals path", "Veil bottom right", + self.veil_b_sc, self.veil_br, + lambda state: _has_spirit_form(state, self.player)) + self.__connect_regions("Veil bottom right", "Veil top left area", + self.veil_br, self.veil_tl, + lambda state: _has_beast_form(state, self.player)) + self.__connect_regions("Veil top left area", "Veil_top left area, fish pass", + self.veil_tl, self.veil_tl_fp, + lambda state: _has_fish_form(state, self.player)) + self.__connect_regions("Veil top left area", "Veil right of sun temple", + self.veil_tl, self.veil_tr_r) + self.__connect_regions("Veil top left area", "Turtle cave", + self.veil_tl, self.turtle_cave) + self.__connect_regions("Turtle cave", "Turtle cave bubble cliff", + self.turtle_cave, self.turtle_cave_bubble, + lambda state: _has_beast_form(state, self.player)) + self.__connect_regions("Veil right of sun temple", "Sun temple right area", + self.veil_tr_r, self.sun_temple_r) + self.__connect_regions("Sun temple right area", "Sun temple left area", + self.sun_temple_r, self.sun_temple_l, + lambda state: _has_bind_song(state, self.player)) + self.__connect_regions("Sun temple left area", "Veil left of sun temple", + self.sun_temple_l, self.veil_tr_l) + self.__connect_regions("Sun temple left area", "Sun temple before boss area", + self.sun_temple_l, self.sun_temple_boss_path) + self.__connect_regions("Sun temple before boss area", "Sun temple boss area", + self.sun_temple_boss_path, self.sun_temple_boss, + lambda state: _has_energy_form(state, self.player)) + self.__connect_one_way_regions("Sun temple boss area", "Veil left of sun temple", + self.sun_temple_boss, self.veil_tr_l) + self.__connect_regions("Veil left of sun temple", "Octo cave top path", + self.veil_tr_l, self.octo_cave_t, + lambda state: _has_fish_form(state, self.player) and + _has_sun_form(state, self.player) and + _has_beast_form(state, self.player) and + _has_energy_form(state, self.player)) + self.__connect_regions("Veil left of sun temple", "Octo cave bottom path", + self.veil_tr_l, self.octo_cave_b, + lambda state: _has_fish_form(state, self.player)) + + def __connect_abyss_regions(self) -> None: + """ + Connect entrances of the different regions around The Abyss + """ + self.__connect_regions("Abyss left area", "Abyss bottom of left area", + self.abyss_l, self.abyss_lb, + lambda state: _has_nature_form(state, self.player)) + self.__connect_regions("Abyss left bottom area", "Sunken city right area", + self.abyss_lb, self.sunken_city_r, + lambda state: _has_li(state, self.player)) + self.__connect_one_way_regions("Abyss left bottom area", "Body center area", + self.abyss_lb, self.body_c, + lambda state: _has_tongue_cleared(state, self.player)) + self.__connect_one_way_regions("Body center area", "Abyss left bottom area", + self.body_c, self.abyss_lb) + self.__connect_regions("Abyss left area", "King jellyfish cave", + self.abyss_l, self.king_jellyfish_cave, + lambda state: _has_energy_form(state, self.player) and + _has_beast_form(state, self.player)) + self.__connect_regions("Abyss left area", "Abyss right area", + self.abyss_l, self.abyss_r) + self.__connect_regions("Abyss right area", "Inside the whale", + self.abyss_r, self.whale, + lambda state: _has_spirit_form(state, self.player) and + _has_sun_form(state, self.player)) + self.__connect_regions("Abyss right area", "First secret area", + self.abyss_r, self.first_secret, + lambda state: _has_spirit_form(state, self.player) and + _has_sun_form(state, self.player) and + _has_bind_song(state, self.player) and + _has_energy_form(state, self.player)) + self.__connect_regions("Abyss right area", "Ice cave", + self.abyss_r, self.ice_cave, + lambda state: _has_spirit_form(state, self.player)) + self.__connect_regions("Abyss right area", "Bubble cave", + self.ice_cave, self.bubble_cave, + lambda state: _has_beast_form(state, self.player)) + self.__connect_regions("Bubble cave boss area", "Bubble cave", + self.bubble_cave, self.bubble_cave_boss, + lambda state: _has_nature_form(state, self.player) and _has_bind_song(state, self.player) + ) + + def __connect_sunken_city_regions(self) -> None: + """ + Connect entrances of the different regions around The Sunken City + """ + self.__connect_regions("Sunken city right area", "Sunken city left area", + self.sunken_city_r, self.sunken_city_l) + self.__connect_regions("Sunken city left area", "Sunken city bedroom", + self.sunken_city_l, self.sunken_city_l_bedroom, + lambda state: _has_spirit_form(state, self.player)) + self.__connect_regions("Sunken city left area", "Sunken city boss area", + self.sunken_city_l, self.sunken_city_boss, + lambda state: _has_beast_form(state, self.player) and + _has_energy_form(state, self.player) and + _has_bind_song(state, self.player)) + + def __connect_body_regions(self) -> None: + """ + Connect entrances of the different regions around The body + """ + self.__connect_regions("Body center area", "Body left area", + self.body_c, self.body_l) + self.__connect_regions("Body center area", "Body right area top path", + self.body_c, self.body_rt) + self.__connect_regions("Body center area", "Body right area bottom path", + self.body_c, self.body_rb) + self.__connect_regions("Body center area", "Body bottom area", + self.body_c, self.body_b, + lambda state: _has_dual_form(state, self.player)) + self.__connect_regions("Body bottom area", "Final boss area", + self.body_b, self.final_boss_loby, + lambda state: _has_dual_form(state, self.player)) + self.__connect_regions("Before Final boss", "Final boss tube", + self.final_boss_loby, self.final_boss_tube, + lambda state: _has_nature_form(state, self.player)) + self.__connect_one_way_regions("Before Final boss", "Final boss", + self.final_boss_loby, self.final_boss, + lambda state: _has_energy_form(state, self.player) and + _has_dual_form(state, self.player) and + _has_sun_form(state, self.player) and + _has_bind_song(state, self.player)) + self.__connect_one_way_regions("final boss third form area", "final boss end", + self.final_boss, self.final_boss_end) + + def __connect_transturtle(self, item_source: str, item_target: str, region_source: Region, region_target: Region, + rule=None) -> None: + """Connect a single transturtle to another one""" + if item_source != item_target: + if rule is None: + self.__connect_one_way_regions(item_source, item_target, region_source, region_target, + lambda state: state.has(item_target, self.player)) + else: + self.__connect_one_way_regions(item_source, item_target, region_source, region_target, rule) + + def __connect_arnassi_path_transturtle(self, item_source: str, item_target: str, region_source: Region, + region_target: Region) -> None: + """Connect the Arnassi ruins transturtle to another one""" + self.__connect_one_way_regions(item_source, item_target, region_source, region_target, + lambda state: state.has(item_target, self.player) and + _has_fish_form(state, self.player)) + + def _connect_transturtle_to_other(self, item: str, region: Region) -> None: + """Connect a single transturtle to all others""" + self.__connect_transturtle(item, "Transturtle Veil top left", region, self.veil_tl) + self.__connect_transturtle(item, "Transturtle Veil top right", region, self.veil_tr_l) + self.__connect_transturtle(item, "Transturtle Open Water top right", region, self.openwater_tr_turtle) + self.__connect_transturtle(item, "Transturtle Forest bottom left", region, self.forest_bl) + self.__connect_transturtle(item, "Transturtle Home water", region, self.home_water_transturtle) + self.__connect_transturtle(item, "Transturtle Abyss right", region, self.abyss_r) + self.__connect_transturtle(item, "Transturtle Final Boss", region, self.final_boss_tube) + self.__connect_transturtle(item, "Transturtle Simon says", region, self.simon) + self.__connect_transturtle(item, "Transturtle Arnassi ruins", region, self.arnassi_path, + lambda state: state.has("Transturtle Arnassi ruins", self.player) and + _has_fish_form(state, self.player)) + + def _connect_arnassi_path_transturtle_to_other(self, item: str, region: Region) -> None: + """Connect the Arnassi ruins transturtle to all others""" + self.__connect_arnassi_path_transturtle(item, "Transturtle Veil top left", region, self.veil_tl) + self.__connect_arnassi_path_transturtle(item, "Transturtle Veil top right", region, self.veil_tr_l) + self.__connect_arnassi_path_transturtle(item, "Transturtle Open Water top right", region, + self.openwater_tr_turtle) + self.__connect_arnassi_path_transturtle(item, "Transturtle Forest bottom left", region, self.forest_bl) + self.__connect_arnassi_path_transturtle(item, "Transturtle Home water", region, self.home_water_transturtle) + self.__connect_arnassi_path_transturtle(item, "Transturtle Abyss right", region, self.abyss_r) + self.__connect_arnassi_path_transturtle(item, "Transturtle Final Boss", region, self.final_boss_tube) + self.__connect_arnassi_path_transturtle(item, "Transturtle Simon says", region, self.simon) + + def __connect_transturtles(self) -> None: + """Connect every transturtle with others""" + self._connect_transturtle_to_other("Transturtle Veil top left", self.veil_tl) + self._connect_transturtle_to_other("Transturtle Veil top right", self.veil_tr_l) + self._connect_transturtle_to_other("Transturtle Open Water top right", self.openwater_tr_turtle) + self._connect_transturtle_to_other("Transturtle Forest bottom left", self.forest_bl) + self._connect_transturtle_to_other("Transturtle Home water", self.home_water_transturtle) + self._connect_transturtle_to_other("Transturtle Abyss right", self.abyss_r) + self._connect_transturtle_to_other("Transturtle Final Boss", self.final_boss_tube) + self._connect_transturtle_to_other("Transturtle Simon says", self.simon) + self._connect_arnassi_path_transturtle_to_other("Transturtle Arnassi ruins", self.arnassi_path) + + def connect_regions(self) -> None: + """ + Connect every region (entrances and exits) + """ + self.__connect_home_water_regions() + self.__connect_open_water_regions() + self.__connect_mithalas_regions() + self.__connect_forest_regions() + self.__connect_veil_regions() + self.__connect_abyss_regions() + self.__connect_sunken_city_regions() + self.__connect_body_regions() + self.__connect_transturtles() + + def __add_event_location(self, region: Region, name: str, event_name: str) -> None: + """ + Add an event to the `region` with the name `name` and the item + `event_name` + """ + location: AquariaLocation = AquariaLocation( + self.player, name, None, region + ) + region.locations.append(location) + location.place_locked_item(AquariaItem(event_name, + ItemClassification.progression, + None, + self.player)) + + def __add_event_big_bosses(self) -> None: + """ + Add every bit bosses (other than the creator) events to the `world` + """ + self.__add_event_location(self.energy_temple_boss, + "Beating Fallen God", + "Fallen God beated") + self.__add_event_location(self.cathedral_boss_r, + "Beating Mithalan God", + "Mithalan God beated") + self.__add_event_location(self.forest_boss, + "Beating Drunian God", + "Drunian God beated") + self.__add_event_location(self.sun_temple_boss, + "Beating Sun God", + "Sun God beated") + self.__add_event_location(self.sunken_city_boss, + "Beating the Golem", + "The Golem beated") + + def __add_event_mini_bosses(self) -> None: + """ + Add every mini bosses (excluding Energy statue and Simon says) + events to the `world` + """ + self.__add_event_location(self.home_water_nautilus, + "Beating Nautilus Prime", + "Nautilus Prime beated") + self.__add_event_location(self.energy_temple_blaster_room, + "Beating Blaster Peg Prime", + "Blaster Peg Prime beated") + self.__add_event_location(self.mermog_boss, + "Beating Mergog", + "Mergog beated") + self.__add_event_location(self.cathedral_l_tube, + "Beating Mithalan priests", + "Mithalan priests beated") + self.__add_event_location(self.octo_cave_t, + "Beating Octopus Prime", + "Octopus Prime beated") + self.__add_event_location(self.arnassi_crab_boss, + "Beating Crabbius Maximus", + "Crabbius Maximus beated") + self.__add_event_location(self.bubble_cave_boss, + "Beating Mantis Shrimp Prime", + "Mantis Shrimp Prime beated") + self.__add_event_location(self.king_jellyfish_cave, + "Beating King Jellyfish God Prime", + "King Jellyfish God Prime beated") + + def __add_event_secrets(self) -> None: + """ + Add secrets events to the `world` + """ + self.__add_event_location(self.first_secret, # Doit ajouter une région pour le "first secret" + "First secret", + "First secret obtained") + self.__add_event_location(self.mithalas_city, + "Second secret", + "Second secret obtained") + self.__add_event_location(self.sun_temple_l, + "Third secret", + "Third secret obtained") + + def add_event_locations(self) -> None: + """ + Add every event (locations and items) to the `world` + """ + self.__add_event_mini_bosses() + self.__add_event_big_bosses() + self.__add_event_secrets() + self.__add_event_location(self.sunken_city_boss, + "Sunken City cleared", + "Body tongue cleared") + self.__add_event_location(self.sun_temple_r, + "Sun Crystal", + "Has sun crystal") + self.__add_event_location(self.final_boss_end, "Objective complete", + "Victory") + + def __adjusting_urns_rules(self) -> None: + """Since Urns need to be broken, add a damaging item to rules""" + add_rule(self.multiworld.get_location("Open water top right area, first urn in the Mithalas exit", self.player), + lambda state: _has_damaging_item(state, self.player)) + add_rule(self.multiworld.get_location("Open water top right area, second urn in the Mithalas exit", self.player), + lambda state: _has_damaging_item(state, self.player)) + add_rule(self.multiworld.get_location("Open water top right area, third urn in the Mithalas exit", self.player), + lambda state: _has_damaging_item(state, self.player)) + add_rule(self.multiworld.get_location("Mithalas city, first urn in one of the homes", self.player), + lambda state: _has_damaging_item(state, self.player)) + add_rule(self.multiworld.get_location("Mithalas city, second urn in one of the homes", self.player), + lambda state: _has_damaging_item(state, self.player)) + add_rule(self.multiworld.get_location("Mithalas city, first urn in the city reserve", self.player), + lambda state: _has_damaging_item(state, self.player)) + add_rule(self.multiworld.get_location("Mithalas city, second urn in the city reserve", self.player), + lambda state: _has_damaging_item(state, self.player)) + add_rule(self.multiworld.get_location("Mithalas city, third urn in the city reserve", self.player), + lambda state: _has_damaging_item(state, self.player)) + add_rule(self.multiworld.get_location("Mithalas city, urn in the cathedral flower tube entrance", self.player), + lambda state: _has_damaging_item(state, self.player)) + add_rule(self.multiworld.get_location("Mithalas city castle, urn in the bedroom", self.player), + lambda state: _has_damaging_item(state, self.player)) + add_rule(self.multiworld.get_location("Mithalas city castle, first urn of the single lamp path", self.player), + lambda state: _has_damaging_item(state, self.player)) + add_rule(self.multiworld.get_location("Mithalas city castle, second urn of the single lamp path", self.player), + lambda state: _has_damaging_item(state, self.player)) + add_rule(self.multiworld.get_location("Mithalas city castle, urn in the bottom room", self.player), + lambda state: _has_damaging_item(state, self.player)) + add_rule(self.multiworld.get_location("Mithalas city castle, first urn on the entrance path", self.player), + lambda state: _has_damaging_item(state, self.player)) + add_rule(self.multiworld.get_location("Mithalas city castle, second urn on the entrance path", self.player), + lambda state: _has_damaging_item(state, self.player)) + add_rule(self.multiworld.get_location("Mithalas city, urn inside a home fish pass", self.player), + lambda state: _has_damaging_item(state, self.player)) + + def __adjusting_crates_rules(self) -> None: + """Since Crate need to be broken, add a damaging item to rules""" + add_rule(self.multiworld.get_location("Sunken city right area, crate close to the save cristal", self.player), + lambda state: _has_damaging_item(state, self.player)) + add_rule(self.multiworld.get_location("Sunken city right area, crate in the left bottom room", self.player), + lambda state: _has_damaging_item(state, self.player)) + add_rule(self.multiworld.get_location("Sunken city left area, crate in the little pipe room", self.player), + lambda state: _has_damaging_item(state, self.player)) + add_rule(self.multiworld.get_location("Sunken city left area, crate close to the save cristal", self.player), + lambda state: _has_damaging_item(state, self.player)) + add_rule(self.multiworld.get_location("Sunken city left area, crate before the bedroom", self.player), + lambda state: _has_damaging_item(state, self.player)) + + def __adjusting_soup_rules(self) -> None: + """ + Modify rules for location that need soup + """ + add_rule(self.multiworld.get_location("Turtle cave, Urchin costume", self.player), + lambda state: _has_hot_soup(state, self.player) and _has_beast_form(state, self.player)) + add_rule(self.multiworld.get_location("Sun Worm path, first cliff bulb", self.player), + lambda state: _has_hot_soup(state, self.player) and _has_beast_form(state, self.player)) + add_rule(self.multiworld.get_location("Sun Worm path, second cliff bulb", self.player), + lambda state: _has_hot_soup(state, self.player) and _has_beast_form(state, self.player)) + add_rule(self.multiworld.get_location("The veil top right area, bulb in the top of the water fall", self.player), + lambda state: _has_hot_soup(state, self.player) and _has_beast_form(state, self.player)) + + def __adjusting_under_rock_location(self) -> None: + """ + Modify rules implying bind song needed for bulb under rocks + """ + add_rule(self.multiworld.get_location("Home water, bulb under the rock in the left path from the verse cave", + self.player), lambda state: _has_bind_song(state, self.player)) + add_rule(self.multiworld.get_location("Verse cave left area, bulb under the rock at the end of the path", + self.player), lambda state: _has_bind_song(state, self.player)) + add_rule(self.multiworld.get_location("Naija's home, bulb under the rock at the right of the main path", + self.player), lambda state: _has_bind_song(state, self.player)) + add_rule(self.multiworld.get_location("Song cave, bulb under the rock in the path to the singing statues", + self.player), lambda state: _has_bind_song(state, self.player)) + add_rule(self.multiworld.get_location("Song cave, bulb under the rock close to the song door", + self.player), lambda state: _has_bind_song(state, self.player)) + add_rule(self.multiworld.get_location("Energy temple second area, bulb under the rock", + self.player), lambda state: _has_bind_song(state, self.player)) + add_rule(self.multiworld.get_location("Open water top left area, bulb under the rock in the right path", + self.player), lambda state: _has_bind_song(state, self.player)) + add_rule(self.multiworld.get_location("Open water top left area, bulb under the rock in the left path", + self.player), lambda state: _has_bind_song(state, self.player)) + add_rule(self.multiworld.get_location("Kelp Forest top right area, bulb under the rock in the right path", + self.player), lambda state: _has_bind_song(state, self.player)) + add_rule(self.multiworld.get_location("The veil top left area, bulb under the rock in the top right path", + self.player), lambda state: _has_bind_song(state, self.player)) + add_rule(self.multiworld.get_location("Abyss right area, bulb behind the rock in the whale room", + self.player), lambda state: _has_bind_song(state, self.player)) + add_rule(self.multiworld.get_location("Abyss right area, bulb in the middle path", + self.player), lambda state: _has_bind_song(state, self.player)) + add_rule(self.multiworld.get_location("The veil top left area, bulb under the rock in the top right path", + self.player), lambda state: _has_bind_song(state, self.player)) + + def __adjusting_light_in_dark_place_rules(self) -> None: + add_rule(self.multiworld.get_location("Kelp forest top right area, Black pearl", self.player), + lambda state: _has_light(state, self.player)) + add_rule(self.multiworld.get_location("Kelp forest bottom right area, Odd Container", self.player), + lambda state: _has_light(state, self.player)) + add_rule(self.multiworld.get_entrance("Transturtle Veil top left to Transturtle Abyss right", self.player), + lambda state: _has_light(state, self.player)) + add_rule(self.multiworld.get_entrance("Transturtle Open Water top right to Transturtle Abyss right", self.player), + lambda state: _has_light(state, self.player)) + add_rule(self.multiworld.get_entrance("Transturtle Veil top right to Transturtle Abyss right", self.player), + lambda state: _has_light(state, self.player)) + add_rule(self.multiworld.get_entrance("Transturtle Forest bottom left to Transturtle Abyss right", self.player), + lambda state: _has_light(state, self.player)) + add_rule(self.multiworld.get_entrance("Transturtle Home water to Transturtle Abyss right", self.player), + lambda state: _has_light(state, self.player)) + add_rule(self.multiworld.get_entrance("Transturtle Final Boss to Transturtle Abyss right", self.player), + lambda state: _has_light(state, self.player)) + add_rule(self.multiworld.get_entrance("Transturtle Simon says to Transturtle Abyss right", self.player), + lambda state: _has_light(state, self.player)) + add_rule(self.multiworld.get_entrance("Transturtle Arnassi ruins to Transturtle Abyss right", self.player), + lambda state: _has_light(state, self.player)) + add_rule(self.multiworld.get_entrance("Body center area to Abyss left bottom area", self.player), + lambda state: _has_light(state, self.player)) + add_rule(self.multiworld.get_entrance("Veil left of sun temple to Octo cave top path", self.player), + lambda state: _has_light(state, self.player)) + add_rule(self.multiworld.get_entrance("Open water bottom right area to Abyss right area", self.player), + lambda state: _has_light(state, self.player)) + add_rule(self.multiworld.get_entrance("Open water bottom left area to Abyss left area", self.player), + lambda state: _has_light(state, self.player)) + add_rule(self.multiworld.get_entrance("Sun temple left area to Sun temple right area", self.player), + lambda state: _has_light(state, self.player) or _has_sun_crystal(state, self.player)) + add_rule(self.multiworld.get_entrance("Sun temple right area to Sun temple left area", self.player), + lambda state: _has_light(state, self.player) or _has_sun_crystal(state, self.player)) + add_rule(self.multiworld.get_entrance("Veil left of sun temple to Sun temple left area", self.player), + lambda state: _has_light(state, self.player) or _has_sun_crystal(state, self.player)) + + + + def __adjusting_manual_rules(self) -> None: + add_rule(self.multiworld.get_location("Mithalas cathedral, Mithalan Dress", self.player), + lambda state: _has_beast_form(state, self.player)) + add_rule(self.multiworld.get_location("Open water bottom left area, bulb inside the downest fish pass", self.player), + lambda state: _has_fish_form(state, self.player)) + add_rule(self.multiworld.get_location("Kelp forest bottom left area, Walker baby", self.player), + lambda state: _has_spirit_form(state, self.player)) + add_rule(self.multiworld.get_location("The veil top left area, bulb hidden behind the blocking rock", self.player), + lambda state: _has_bind_song(state, self.player)) + add_rule(self.multiworld.get_location("Turtle cave, Turtle Egg", self.player), + lambda state: _has_bind_song(state, self.player)) + add_rule(self.multiworld.get_location("Abyss left area, bulb in the bottom fish pass", self.player), + lambda state: _has_fish_form(state, self.player)) + add_rule(self.multiworld.get_location("Song cave, Anemone seed", self.player), + lambda state: _has_nature_form(state, self.player)) + add_rule(self.multiworld.get_location("Song cave, Verse egg", self.player), + lambda state: _has_bind_song(state, self.player)) + add_rule(self.multiworld.get_location("Verse cave right area, Big Seed", self.player), + lambda state: _has_bind_song(state, self.player)) + add_rule(self.multiworld.get_location("Arnassi ruins, Song plant spore on the top of the ruins", self.player), + lambda state: _has_beast_form(state, self.player)) + add_rule(self.multiworld.get_location("Energy temple first area, bulb in the bottom room blocked by a rock", + self.player), lambda state: _has_energy_form(state, self.player)) + add_rule(self.multiworld.get_location("Home water, bulb in the bottom left room", self.player), + lambda state: _has_bind_song(state, self.player)) + add_rule(self.multiworld.get_location("Home water, bulb in the path bellow Nautilus Prime", self.player), + lambda state: _has_bind_song(state, self.player)) + add_rule(self.multiworld.get_location("Naija's home, bulb after the energy door", self.player), + lambda state: _has_energy_form(state, self.player)) + add_rule(self.multiworld.get_location("Abyss right area, bulb behind the rock in the whale room", self.player), + lambda state: _has_spirit_form(state, self.player) and + _has_sun_form(state, self.player)) + add_rule(self.multiworld.get_location("Arnassi ruins, Arnassi Armor", self.player), + lambda state: _has_fish_form(state, self.player) and + _has_spirit_form(state, self.player)) + + + + + def __no_progression_hard_or_hidden_location(self) -> None: + self.multiworld.get_location("Energy temple boss area, Fallen god tooth", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("Cathedral boss area, beating Mithalan God", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("Kelp forest boss area, beating Drunian God", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("Sun temple boss area, beating Sun God", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("Sunken city, bulb on the top of the boss area (boiler room)", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("Home water, Nautilus Egg", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("Energy temple blaster room, Blaster egg", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("Mithalas castle, beating the priests", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("Mermog cave, Piranha Egg", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("Octopus cave, Dumbo Egg", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("King Jellyfish cave, bulb in the right path from King Jelly", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("King Jellyfish cave, Jellyfish Costume", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("Final boss area, bulb in the boss third form room", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("Sun Worm path, first cliff bulb", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("Sun Worm path, second cliff bulb", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("The veil top right area, bulb in the top of the water fall", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("Bubble cave, bulb in the left cave wall", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("Bubble cave, bulb in the right cave wall (behind the ice cristal)", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("Bubble cave, Verse egg", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("Kelp Forest bottom left area, bulb close to the spirit crystals", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("Kelp forest bottom left area, Walker baby", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("Sun temple, Sun key", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("The body bottom area, Mutant Costume", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("Sun temple, bulb in the hidden room of the right part", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + self.multiworld.get_location("Arnassi ruins, Arnassi Armor", + self.player).item_rule =\ + lambda item: item.classification != ItemClassification.progression + + def adjusting_rules(self, options: AquariaOptions) -> None: + """ + Modify rules for single location or optional rules + """ + self.__adjusting_urns_rules() + self.__adjusting_crates_rules() + self.__adjusting_soup_rules() + self.__adjusting_manual_rules() + if options.light_needed_to_get_to_dark_places: + self.__adjusting_light_in_dark_place_rules() + if options.bind_song_needed_to_get_under_rock_bulb: + self.__adjusting_under_rock_location() + + if options.mini_bosses_to_beat.value > 0: + add_rule(self.multiworld.get_entrance("Before Final boss to Final boss", self.player), + lambda state: _has_mini_bosses(state, self.player)) + if options.big_bosses_to_beat.value > 0: + add_rule(self.multiworld.get_entrance("Before Final boss to Final boss", self.player), + lambda state: _has_big_bosses(state, self.player)) + if options.objective.value == 1: + add_rule(self.multiworld.get_entrance("Before Final boss to Final boss", self.player), + lambda state: _has_secrets(state, self.player)) + if options.unconfine_home_water.value in [0, 1]: + add_rule(self.multiworld.get_entrance("Home Water to Home water transturtle room", self.player), + lambda state: _has_bind_song(state, self.player)) + if options.unconfine_home_water.value in [0, 2]: + add_rule(self.multiworld.get_entrance("Home Water to Open water top left area", self.player), + lambda state: _has_bind_song(state, self.player) and _has_energy_form(state, self.player)) + if options.early_energy_form: + add_rule(self.multiworld.get_entrance("Home Water to Home water transturtle room", self.player), + lambda state: _has_energy_form(state, self.player)) + if options.early_energy_form: + add_rule(self.multiworld.get_entrance("Home Water to Open water top left area", self.player), + lambda state: _has_energy_form(state, self.player)) + + if options.no_progression_hard_or_hidden_locations: + self.__no_progression_hard_or_hidden_location() + + def __add_home_water_regions_to_world(self) -> None: + """ + Add every region around home water to the `world` + """ + self.multiworld.regions.append(self.menu) + self.multiworld.regions.append(self.verse_cave_r) + self.multiworld.regions.append(self.verse_cave_l) + self.multiworld.regions.append(self.home_water) + self.multiworld.regions.append(self.home_water_nautilus) + self.multiworld.regions.append(self.home_water_transturtle) + self.multiworld.regions.append(self.naija_home) + self.multiworld.regions.append(self.song_cave) + self.multiworld.regions.append(self.energy_temple_1) + self.multiworld.regions.append(self.energy_temple_2) + self.multiworld.regions.append(self.energy_temple_3) + self.multiworld.regions.append(self.energy_temple_boss) + self.multiworld.regions.append(self.energy_temple_blaster_room) + self.multiworld.regions.append(self.energy_temple_altar) + + def __add_open_water_regions_to_world(self) -> None: + """ + Add every region around open water to the `world` + """ + self.multiworld.regions.append(self.openwater_tl) + self.multiworld.regions.append(self.openwater_tr) + self.multiworld.regions.append(self.openwater_tr_turtle) + self.multiworld.regions.append(self.openwater_bl) + self.multiworld.regions.append(self.openwater_br) + self.multiworld.regions.append(self.skeleton_path) + self.multiworld.regions.append(self.skeleton_path_sc) + self.multiworld.regions.append(self.arnassi) + self.multiworld.regions.append(self.arnassi_path) + self.multiworld.regions.append(self.arnassi_crab_boss) + self.multiworld.regions.append(self.simon) + + def __add_mithalas_regions_to_world(self) -> None: + """ + Add every region around Mithalas to the `world` + """ + self.multiworld.regions.append(self.mithalas_city) + self.multiworld.regions.append(self.mithalas_city_top_path) + self.multiworld.regions.append(self.mithalas_city_fishpass) + self.multiworld.regions.append(self.cathedral_l) + self.multiworld.regions.append(self.cathedral_l_tube) + self.multiworld.regions.append(self.cathedral_l_sc) + self.multiworld.regions.append(self.cathedral_r) + self.multiworld.regions.append(self.cathedral_underground) + self.multiworld.regions.append(self.cathedral_boss_l) + self.multiworld.regions.append(self.cathedral_boss_r) + + def __add_forest_regions_to_world(self) -> None: + """ + Add every region around the kelp forest to the `world` + """ + self.multiworld.regions.append(self.forest_tl) + self.multiworld.regions.append(self.forest_tl_fp) + self.multiworld.regions.append(self.forest_tr) + self.multiworld.regions.append(self.forest_tr_fp) + self.multiworld.regions.append(self.forest_bl) + self.multiworld.regions.append(self.forest_br) + self.multiworld.regions.append(self.forest_boss) + self.multiworld.regions.append(self.forest_boss_entrance) + self.multiworld.regions.append(self.forest_sprite_cave) + self.multiworld.regions.append(self.forest_sprite_cave_tube) + self.multiworld.regions.append(self.mermog_cave) + self.multiworld.regions.append(self.mermog_boss) + self.multiworld.regions.append(self.forest_fish_cave) + + def __add_veil_regions_to_world(self) -> None: + """ + Add every region around the Veil to the `world` + """ + self.multiworld.regions.append(self.veil_tl) + self.multiworld.regions.append(self.veil_tl_fp) + self.multiworld.regions.append(self.veil_tr_l) + self.multiworld.regions.append(self.veil_tr_r) + self.multiworld.regions.append(self.veil_bl) + self.multiworld.regions.append(self.veil_b_sc) + self.multiworld.regions.append(self.veil_bl_fp) + self.multiworld.regions.append(self.veil_br) + self.multiworld.regions.append(self.octo_cave_t) + self.multiworld.regions.append(self.octo_cave_b) + self.multiworld.regions.append(self.turtle_cave) + self.multiworld.regions.append(self.turtle_cave_bubble) + self.multiworld.regions.append(self.sun_temple_l) + self.multiworld.regions.append(self.sun_temple_r) + self.multiworld.regions.append(self.sun_temple_boss_path) + self.multiworld.regions.append(self.sun_temple_boss) + + def __add_abyss_regions_to_world(self) -> None: + """ + Add every region around the Abyss to the `world` + """ + self.multiworld.regions.append(self.abyss_l) + self.multiworld.regions.append(self.abyss_lb) + self.multiworld.regions.append(self.abyss_r) + self.multiworld.regions.append(self.ice_cave) + self.multiworld.regions.append(self.bubble_cave) + self.multiworld.regions.append(self.bubble_cave_boss) + self.multiworld.regions.append(self.king_jellyfish_cave) + self.multiworld.regions.append(self.whale) + self.multiworld.regions.append(self.sunken_city_l) + self.multiworld.regions.append(self.sunken_city_r) + self.multiworld.regions.append(self.sunken_city_boss) + self.multiworld.regions.append(self.sunken_city_l_bedroom) + + def __add_body_regions_to_world(self) -> None: + """ + Add every region around the Body to the `world` + """ + self.multiworld.regions.append(self.body_c) + self.multiworld.regions.append(self.body_l) + self.multiworld.regions.append(self.body_rt) + self.multiworld.regions.append(self.body_rb) + self.multiworld.regions.append(self.body_b) + self.multiworld.regions.append(self.final_boss_loby) + self.multiworld.regions.append(self.final_boss_tube) + self.multiworld.regions.append(self.final_boss) + self.multiworld.regions.append(self.final_boss_end) + + def add_regions_to_world(self) -> None: + """ + Add every region to the `world` + """ + self.__add_home_water_regions_to_world() + self.__add_open_water_regions_to_world() + self.__add_mithalas_regions_to_world() + self.__add_forest_regions_to_world() + self.__add_veil_regions_to_world() + self.__add_abyss_regions_to_world() + self.__add_body_regions_to_world() + + def __init__(self, multiworld: MultiWorld, player: int): + """ + Initialisation of the regions + """ + self.multiworld = multiworld + self.player = player + self.__create_home_water_area() + self.__create_energy_temple() + self.__create_openwater() + self.__create_mithalas() + self.__create_forest() + self.__create_veil() + self.__create_sun_temple() + self.__create_abyss() + self.__create_sunken_city() + self.__create_body() diff --git a/worlds/aquaria/__init__.py b/worlds/aquaria/__init__.py new file mode 100644 index 00000000..e87e8c8b --- /dev/null +++ b/worlds/aquaria/__init__.py @@ -0,0 +1,218 @@ +""" +Author: Louis M +Date: Fri, 15 Mar 2024 18:41:40 +0000 +Description: Main module for Aquaria game multiworld randomizer +""" + +from typing import List, Dict, ClassVar, Any +from ..AutoWorld import World, WebWorld +from BaseClasses import Tutorial, MultiWorld, ItemClassification +from .Items import item_table, AquariaItem, ItemType, ItemGroup +from .Locations import location_table +from .Options import AquariaOptions +from .Regions import AquariaRegions + + +class AquariaWeb(WebWorld): + """ + Class used to generate the Aquaria Game Web pages (setup, tutorial, etc.) + """ + theme = "ocean" + + bug_report_page = "https://github.com/tioui/Aquaria_Randomizer/issues" + + setup = Tutorial( + "Multiworld Setup Guide", + "A guide to setting up Aquaria for MultiWorld.", + "English", + "setup_en.md", + "setup/en", + ["Tioui"] + ) + + setup_fr = Tutorial( + "Guide de configuration Multimonde", + "Un guide pour configurer Aquaria MultiWorld", + "Français", + "setup_fr.md", + "setup/fr", + ["Tioui"] + ) + + tutorials = [setup, setup_fr] + + +class AquariaWorld(World): + """ + Aquaria is a side-scrolling action-adventure game. It follows Naija, an + aquatic humanoid woman, as she explores the underwater world of Aquaria. + Along her journey, she learns about the history of the world she inhabits + as well as her own past. The gameplay focuses on a combination of swimming, + singing, and combat, through which Naija can interact with the world. Her + songs can move items, affect plants and animals, and change her physical + appearance into other forms that have different abilities, like firing + projectiles at hostile creatures, or passing through barriers inaccessible + to her in her natural form. + From: https://en.wikipedia.org/wiki/Aquaria_(video_game) + """ + + game: str = "Aquaria" + "The name of the game" + + topology_present = True + "show path to required location checks in spoiler" + + web: WebWorld = AquariaWeb() + "The web page generation informations" + + item_name_to_id: ClassVar[Dict[str, int]] =\ + {name: data.id for name, data in item_table.items()} + "The name and associated ID of each item of the world" + + item_name_groups = { + "Damage": {"Energy form", "Nature form", "Beast form", + "Li and Li song", "Baby nautilus", "Baby piranha", + "Baby blaster"}, + "Light": {"Sun form", "Baby dumbo"} + } + """Grouping item make it easier to find them""" + + location_name_to_id = location_table + "The name and associated ID of each location of the world" + + base_id = 698000 + "The starting ID of the items and locations of the world" + + ingredients_substitution: List[int] + "Used to randomize ingredient drop" + + options_dataclass = AquariaOptions + "Used to manage world options" + + options: AquariaOptions + "Every options of the world" + + regions: AquariaRegions + "Used to manage Regions" + + exclude: List[str] + + def __init__(self, multiworld: MultiWorld, player: int): + """Initialisation of the Aquaria World""" + super(AquariaWorld, self).__init__(multiworld, player) + self.regions = AquariaRegions(multiworld, player) + self.ingredients_substitution = [] + self.exclude = [] + + def create_regions(self) -> None: + """ + Create every Region in `regions` + """ + self.regions.add_regions_to_world() + self.regions.connect_regions() + self.regions.add_event_locations() + + def create_item(self, name: str) -> AquariaItem: + """ + Create an AquariaItem using `name' as item name. + """ + result: AquariaItem + try: + data = item_table[name] + classification: ItemClassification = ItemClassification.useful + if data.type == ItemType.JUNK: + classification = ItemClassification.filler + elif data.type == ItemType.PROGRESSION: + classification = ItemClassification.progression + result = AquariaItem(name, classification, data.id, self.player) + except BaseException: + raise Exception('The item ' + name + ' is not valid.') + + return result + + def __pre_fill_item(self, item_name: str, location_name: str, precollected) -> None: + """Pre-assign an item to a location""" + if item_name not in precollected: + self.exclude.append(item_name) + data = item_table[item_name] + item = AquariaItem(item_name, ItemClassification.useful, data.id, self.player) + self.multiworld.get_location(location_name, self.player).place_locked_item(item) + + def get_filler_item_name(self): + """Getting a random ingredient item as filler""" + ingredients = [] + for name, data in item_table.items(): + if data.group == ItemGroup.INGREDIENT: + ingredients.append(name) + filler_item_name = self.random.choice(ingredients) + return filler_item_name + + def create_items(self) -> None: + """Create every item in the world""" + precollected = [item.name for item in self.multiworld.precollected_items[self.player]] + if self.options.turtle_randomizer.value > 0: + if self.options.turtle_randomizer.value == 2: + self.__pre_fill_item("Transturtle Final Boss", "Final boss area, Transturtle", precollected) + else: + self.__pre_fill_item("Transturtle Veil top left", "The veil top left area, Transturtle", precollected) + self.__pre_fill_item("Transturtle Veil top right", "The veil top right area, Transturtle", precollected) + self.__pre_fill_item("Transturtle Open Water top right", "Open water top right area, Transturtle", + precollected) + self.__pre_fill_item("Transturtle Forest bottom left", "Kelp Forest bottom left area, Transturtle", + precollected) + self.__pre_fill_item("Transturtle Home water", "Home water, Transturtle", precollected) + self.__pre_fill_item("Transturtle Abyss right", "Abyss right area, Transturtle", precollected) + self.__pre_fill_item("Transturtle Final Boss", "Final boss area, Transturtle", precollected) + # The last two are inverted because in the original game, they are special turtle that communicate directly + self.__pre_fill_item("Transturtle Simon says", "Arnassi Ruins, Transturtle", precollected) + self.__pre_fill_item("Transturtle Arnassi ruins", "Simon says area, Transturtle", precollected) + for name, data in item_table.items(): + if name in precollected: + precollected.remove(name) + self.multiworld.itempool.append(self.create_item(self.get_filler_item_name())) + else: + if name not in self.exclude: + for i in range(data.count): + item = self.create_item(name) + self.multiworld.itempool.append(item) + + def set_rules(self) -> None: + """ + Launched when the Multiworld generator is ready to generate rules + """ + + self.regions.adjusting_rules(self.options) + self.multiworld.completion_condition[self.player] = lambda \ + state: state.has("Victory", self.player) + + def generate_basic(self) -> None: + """ + Player-specific randomization that does not affect logic. + Used to fill then `ingredients_substitution` list + """ + simple_ingredients_substitution = [i for i in range(27)] + if self.options.ingredient_randomizer.value > 0: + if self.options.ingredient_randomizer.value == 1: + simple_ingredients_substitution.pop(-1) + simple_ingredients_substitution.pop(-1) + simple_ingredients_substitution.pop(-1) + self.random.shuffle(simple_ingredients_substitution) + if self.options.ingredient_randomizer.value == 1: + simple_ingredients_substitution.extend([24, 25, 26]) + dishes_substitution = [i for i in range(27, 76)] + if self.options.dish_randomizer: + self.random.shuffle(dishes_substitution) + self.ingredients_substitution.clear() + self.ingredients_substitution.extend(simple_ingredients_substitution) + self.ingredients_substitution.extend(dishes_substitution) + + def fill_slot_data(self) -> Dict[str, Any]: + return {"ingredientReplacement": self.ingredients_substitution, + "aquarianTranslate": bool(self.options.aquarian_translation.value), + "secret_needed": self.options.objective.value > 0, + "minibosses_to_kill": self.options.mini_bosses_to_beat.value, + "bigbosses_to_kill": self.options.big_bosses_to_beat.value, + "skip_first_vision": bool(self.options.skip_first_vision.value), + "unconfine_home_water_energy_door": self.options.unconfine_home_water.value in [1, 3], + "unconfine_home_water_transturtle": self.options.unconfine_home_water.value in [2, 3], + } diff --git a/worlds/aquaria/docs/en_Aquaria.md b/worlds/aquaria/docs/en_Aquaria.md new file mode 100644 index 00000000..aa095b83 --- /dev/null +++ b/worlds/aquaria/docs/en_Aquaria.md @@ -0,0 +1,64 @@ +# Aquaria + +## Game page in other languages: +* [Français](/games/Aquaria/info/fr) + +## Where is the options page? + +The player options page for this game contains all the options you need to configure and export a config file. Player +options page link: [Aquaria Player Options Page](../player-options). + +## What does randomization do to this game? +The locations in the randomizer are: + +- All sing bulbs; +- All Mithalas Urns; +- All Sunken City crates; +- Collectible treasure locations (including pet eggs and costumes); +- Beating Simon says; +- Li cave; +- Every Transportation Turtle (also called transturtle); +- Locations where you get songs, + * Erulian spirit cristal, + * Energy status mini-boss, + * Beating Mithalan God boss, + * Fish cave puzzle, + * Beating Drunian God boss, + * Beating Sun God boss, + * Breaking Li cage in the body + +Note that, unlike the vanilla game, when opening sing bulbs, Mithalas urns and Sunken City crates, +nothing will come out of them. The moment those bulbs, urns and crates are opened, the location is considered received. + +The items in the randomizer are: +- Dishes (used to learn recipes*); +- Some ingredients; +- The Wok (third plate used to cook 3 ingredients recipes everywhere); +- All collectible treasure (including pet eggs and costumes); +- Li and Li song; +- All songs (other than Li's song since it is learned when Li is obtained); +- Transportation to transturtles. + +Also, there is the option to randomize every ingredient drops (from fishes, monsters +or plants). + +*Note that, unlike in the vanilla game, the recipes for dishes (other than the Sea Loaf) +cannot be cooked (and learn) before being obtained as randomized items. Also, enemies and plants +that drop dishes that have not been learned before will drop ingredients of this dish instead. + +## What is the goal of the game? +The goal of the Aquaria game is to beat the creator. You can also add other goals like getting +secret memories, beating a number of mini-bosses and beating a number of bosses. + +## Which items can be in another player's world? +Any items specified above can be in another player's world. + +## What does another world's item look like in Aquaria? +No visuals are shown when finding locations other than collectible treasure. +For those treasures, the visual of the treasure is visually unchanged. +After collecting a location check, a message will be shown to inform the player +what has been collected, and who will receive it. + +## When the player receives an item, what happens? +When you receive an item, a message will pop up to inform you where you received +the item from, and which one it is. \ No newline at end of file diff --git a/worlds/aquaria/docs/fr_Aquaria.md b/worlds/aquaria/docs/fr_Aquaria.md new file mode 100644 index 00000000..4395b6df --- /dev/null +++ b/worlds/aquaria/docs/fr_Aquaria.md @@ -0,0 +1,65 @@ +# Aquaria + +## Où se trouve la page des options ? + +La [page des options du joueur pour ce jeu](../player-options) contient tous +les options dont vous avez besoin pour configurer et exporter le fichier. + +## Quel est l'effet de la randomisation sur ce jeu ? + +Les localisations du "Ransomizer" sont: + +- tous les bulbes musicaux; +- toutes les urnes de Mithalas; +- toutes les caisses de la cité engloutie; +- les localisations des trésors de collections (incluant les oeufs d'animaux de compagnie et les costumes); +- Battre Simom dit; +- La caverne de Li; +- Les tortues de transportation (transturtle); +- Localisation ou on obtient normalement les musiques, + * cristal de l'esprit Erulien, + * le mini-boss de la statue de l'énergie, + * battre le dieu de Mithalas, + * résoudre l'énigme de la caverne des poissons, + * battre le dieu Drunien, + * battre le dieu du soleil, + * détruire la cage de Li dans le corps, + +À noter que, contrairement au jeu original, lors de l'ouverture d'un bulbe musical, d'une urne de Mithalas ou +d'une caisse de la cité engloutie, aucun objet n'en sortira. La localisation représentée par l'objet ouvert est reçue +dès l'ouverture. + +Les objets pouvant être obtenus sont: +- les recettes (permettant d'apprendre les recettes*); +- certains ingrédients; +- le Wok (la troisième assiette permettant de cuisiner avec trois ingrédients n'importe où); +- Tous les trésors de collection (incluant les oeufs d'animal de compagnie et les costumes); +- Li et la musique de Li; +- Toutes les musiques (autre que la musique de Li puisque cette dernière est apprise en obtenant Li); +- Les localisations de transportation. + +Il y a également l'option pour mélanger les ingrédients obtenus en éliminant des monstres, des poissons ou des plantes. + +*À noter que, contrairement au jeu original, il est impossible de cuisiner une recette qui n'a pas préalablement +été apprise en obtenant un repas en tant qu'objet. À noter également que les ennemies et plantes qui +donnent un repas dont la recette n'a pas préalablement été apprise vont donner les ingrédients de cette +recette. + +## Quel est le but de Aquaria ? + +Dans Aquaria, le but est de battre le monstre final (le créateur). Il est également possible d'ajouter +des buts comme obtenir les trois souvenirs secrets, ou devoir battre une quantité de boss ou de mini-boss. + +## Quels objets peuvent se trouver dans le monde d'un autre joueur ? + +Tous les objets indiqués plus haut peuvent être obtenus à partir du monde d'un autre joueur. + +## À quoi ressemble un objet d'un autre monde dans ce jeu + +Autre que pour les trésors de collection (dont le visuel demeure inchangé), +les autres localisations n'ont aucun visuel. Lorsqu'une localisation randomisée est obtenue, +un message est affiché à l'écran pour indiquer quel objet a été trouvé et pour quel joueur. + +## Que se passe-t-il lorsque le joueur reçoit un objet ? + +Chaque fois qu'un objet est reçu, un message apparaît à l'écran pour en informer le joueur. diff --git a/worlds/aquaria/docs/setup_en.md b/worlds/aquaria/docs/setup_en.md new file mode 100644 index 00000000..435761e3 --- /dev/null +++ b/worlds/aquaria/docs/setup_en.md @@ -0,0 +1,114 @@ +# Aquaria Randomizer Setup Guide + +## Required Software + +- The original Aquaria Game (buyable from a lot of online game seller); +- The [Aquaria randomizer](https://github.com/tioui/Aquaria_Randomizer/releases) +- Optional, for sending [commands](/tutorial/Archipelago/commands/en) like `!hint`: the TextClient from [the most recent Archipelago release](https://github.com/ArchipelagoMW/Archipelago/releases) + +## Installation and execution Procedures + +### Windows + +First, you should copy the original Aquaria folder game. The randomizer will possibly modify the game so that +the original game will stop working. Copying the folder will guarantee that the original game keeps on working. +Also, in Windows, the save files are stored in the Aquaria folder. So copying the Aquaria folder for every Multiworld +game you play will make sure that every game has their own save game. + +Unzip the Aquaria randomizer release and copy all unzipped files in the Aquaria game folder. The unzipped files +are those: +- aquaria_randomizer.exe +- OpenAL32.dll +- override (directory) +- SDL2.dll +- usersettings.xml +- wrap_oal.dll +- cacert.pem + +If there is a conflict between file in the original game folder and the unzipped files, you should override +the original files with the one of the unzipped randomizer. + +Finally, to launch the randomizer, you must use the command line interface (you can open the command line interface +by writing `cmd` in the address bar of the Windows file explorer). Here is the command line to use to start the +randomizer: + +```bash +aquaria_randomizer.exe --name YourName --server theServer:thePort +``` + +or, if the room has a password: + +```bash +aquaria_randomizer.exe --name YourName --server theServer:thePort --password thePassword +``` + +### Linux when using the AppImage + +If you use the AppImage, just copy it in the Aquaria game folder. You then have to make it executable. You +can do that from command line by using + +```bash +chmod +x Aquaria_Randomizer-*.AppImage +``` + +or by using the Graphical Explorer of your system. + +To launch the randomizer, just launch in command line: + +```bash +./Aquaria_Randomizer-*.AppImage --name YourName --server theServer:thePort +``` + +or, if the room has a password: + +```bash +./Aquaria_Randomizer-*.AppImage --name YourName --server theServer:thePort --password thePassword +``` + +Note that you should not have multiple Aquaria_Randomizer AppImage file in the same folder. If this situation occurred, +the preceding commands will launch the game multiple times. + +### Linux when using the tar file + +First, you should copy the original Aquaria folder game. The randomizer will possibly modify the game so that +the original game will stop working. Copying the folder will guarantee that the original game keeps on working. + +Untar the Aquaria randomizer release and copy all extracted files in the Aquaria game folder. The extracted +files are those: +- aquaria_randomizer +- override (directory) +- usersettings.xml +- cacert.pem + +If there is a conflict between file in the original game folder and the extracted files, you should override +the original files with the one of the extracted randomizer files. + +Then, you should use your system package manager to install liblua5, libogg, libvorbis, libopenal and libsdl2. +On Debian base system (like Ubuntu), you can use the following command: + +```bash +sudo apt install liblua5.1-0-dev libogg-dev libvorbis-dev libopenal-dev libsdl2-dev +``` + +Also, if there is some `.so` files in the Aquaria original game folder (`libgcc_s.so.1`, `libopenal.so.1`, +`libSDL-1.2.so.0` and `libstdc++.so.6`), you should remove them from the Aquaria Randomizer game folder. Those are +old libraries that will not work on the recent build of the randomizer. + +To launch the randomizer, just launch in command line: + +```bash +./aquaria_randomizer --name YourName --server theServer:thePort +``` + +or, if the room has a password: + +```bash +./aquaria_randomizer --name YourName --server theServer:thePort --password thePassword +``` + +Note: If you have a permission denied error when using the command line, you can use this command line to be +sure that your executable has executable permission: + +```bash +chmod +x aquaria_randomizer +``` diff --git a/worlds/aquaria/docs/setup_fr.md b/worlds/aquaria/docs/setup_fr.md new file mode 100644 index 00000000..2c34f1e6 --- /dev/null +++ b/worlds/aquaria/docs/setup_fr.md @@ -0,0 +1,118 @@ +# Guide de configuration MultiWorld d'Aquaria + +## Logiciels nécessaires + +- Le jeu Aquaria original (trouvable sur la majorité des sites de ventes de jeux vidéo en ligne) +- Le client Randomizer d'Aquaria [Aquaria randomizer](https://github.com/tioui/Aquaria_Randomizer/releases) +- De manière optionnel, pour pouvoir envoyer des [commandes](/tutorial/Archipelago/commands/en) comme `!hint`: utilisez le client texte de [la version la plus récente d'Archipelago](https://github.com/ArchipelagoMW/Archipelago/releases) + +## Procédures d'installation et d'exécution + +### Windows + +En premier lieu, vous devriez effectuer une nouvelle copie du jeu d'Aquaria original à chaque fois que vous effectuez une +nouvelle partie. La première raison de cette copie est que le randomizer modifie des fichiers qui rendront possiblement +le jeu original non fonctionnel. La seconde raison d'effectuer cette copie est que les sauvegardes sont créées +directement dans le répertoire du jeu. Donc, la copie permet d'éviter de perdre vos sauvegardes du jeu d'origine ou +encore de charger une sauvegarde d'une ancienne partie de multiworld (ce qui pourrait avoir comme conséquence de briser +la logique du multiworld). + +Désarchiver le randomizer d'Aquaria et copier tous les fichiers de l'archive dans le répertoire du jeu d'Aquaria. Le +fichier d'archive devrait contenir les fichiers suivants: +- aquaria_randomizer.exe +- OpenAL32.dll +- override (directory) +- SDL2.dll +- usersettings.xml +- wrap_oal.dll +- cacert.pem + +S'il y a des conflits entre les fichiers de l'archive zip et les fichiers du jeu original, vous devez utiliser +les fichiers contenus dans l'archive zip. + +Finalement, pour lancer le randomizer, vous devez utiliser la ligne de commande (vous pouvez ouvrir une interface de +ligne de commande, entrez l'adresse `cmd` dans la barre d'adresse de l'explorateur de fichier de Windows). Voici +la ligne de commande à utiliser pour lancer le randomizer: + +```bash +aquaria_randomizer.exe --name VotreNom --server leServeur:LePort +``` + +ou, si vous devez entrer un mot de passe: + +```bash +aquaria_randomizer.exe --name VotreNom --server leServeur:LePort --password leMotDePasse +``` + +### Linux avec le fichier AppImage + +Si vous utilisez le fichier AppImage, copiez le fichier dans le répertoire du jeu d'Aquaria. Ensuite, assurez-vous de +le mettre exécutable. Vous pouvez mettre le fichier exécutable avec la commande suivante: + +```bash +chmod +x Aquaria_Randomizer-*.AppImage +``` + +ou bien en utilisant l'explorateur graphique de votre système. + +Pour lancer le randomizer, utiliser la commande suivante: + +```bash +./Aquaria_Randomizer-*.AppImage --name VotreNom --server LeServeur:LePort +``` + +Si vous devez entrer un mot de passe: + +```bash +./Aquaria_Randomizer-*.AppImage --name VotreNom --server LeServeur:LePort --password LeMotDePasse +``` + +À noter que vous ne devez pas avoir plusieurs fichiers AppImage différents dans le même répertoire. Si cette situation +survient, le jeu sera lancé plusieurs fois. + +### Linux avec le fichier tar + +En premier lieu, assurez-vous de faire une copie du répertoire du jeu d'origine d'Aquaria. Les fichiers contenus +dans le randomizer auront comme impact de rendre le jeu d'origine non fonctionnel. Donc, effectuer la copie du jeu +avant de déposer le randomizer à l'intérieur permet de vous assurer de garder une version du jeu d'origine fonctionnel. + +Désarchiver le fichier tar et copier tous les fichiers qu'il contient dans le répertoire du jeu d'origine d'Aquaria. Les +fichiers extraient du fichier tar devraient être les suivants: +- aquaria_randomizer +- override (directory) +- usersettings.xml +- cacert.pem + +S'il y a des conflits entre les fichiers de l'archive tar et les fichiers du jeu original, vous devez utiliser +les fichiers contenus dans l'archive tar. + +Ensuite, vous devez installer manuellement les librairies dont dépend le jeu: liblua5, libogg, libvorbis, libopenal and +libsdl2. Vous pouvez utiliser le système de "package" de votre système pour les installer. Voici un exemple avec +Debian (et Ubuntu): + +```bash +sudo apt install liblua5.1-0-dev libogg-dev libvorbis-dev libopenal-dev libsdl2-dev +``` + +Notez également que s'il y a des fichiers ".so" dans le répertoire d'Aquaria (`libgcc_s.so.1`, `libopenal.so.1`, +`libSDL-1.2.so.0` and `libstdc++.so.6`), vous devriez les retirer. Il s'agit de vieille version des librairies qui +ne sont plus fonctionnelles dans les systèmes modernes et qui pourrait empêcher le randomizer de fonctionner. + +Pour lancer le randomizer, utiliser la commande suivante: + +```bash +./aquaria_randomizer --name VotreNom --server LeServeur:LePort +``` + +Si vous devez entrer un mot de passe: + +```bash +./aquaria_randomizer --name VotreNom --server LeServeur:LePort --password LeMotDePasse +``` + +Note: Si vous avez une erreur de permission lors de l'exécution du randomizer, vous pouvez utiliser cette commande +pour vous assurer que votre fichier est exécutable: + +```bash +chmod +x aquaria_randomizer +``` diff --git a/worlds/aquaria/test/__init__.py b/worlds/aquaria/test/__init__.py new file mode 100644 index 00000000..75dfd738 --- /dev/null +++ b/worlds/aquaria/test/__init__.py @@ -0,0 +1,218 @@ +""" +Author: Louis M +Date: Thu, 18 Apr 2024 18:45:56 +0000 +Description: Base class for the Aquaria randomizer unit tests +""" + + +from test.bases import WorldTestBase + +# Every location accessible after the home water. +after_home_water_locations = [ + "Sun Crystal", + "Home water, Transturtle", + "Open water top left area, bulb under the rock in the right path", + "Open water top left area, bulb under the rock in the left path", + "Open water top left area, bulb to the right of the save cristal", + "Open water top right area, bulb in the small path before Mithalas", + "Open water top right area, bulb in the path from the left entrance", + "Open water top right area, bulb in the clearing close to the bottom exit", + "Open water top right area, bulb in the big clearing close to the save cristal", + "Open water top right area, bulb in the big clearing to the top exit", + "Open water top right area, first urn in the Mithalas exit", + "Open water top right area, second urn in the Mithalas exit", + "Open water top right area, third urn in the Mithalas exit", + "Open water top right area, bulb in the turtle room", + "Open water top right area, Transturtle", + "Open water bottom left area, bulb behind the chomper fish", + "Open water bottom left area, bulb inside the downest fish pass", + "Open water skeleton path, bulb close to the right exit", + "Open water skeleton path, bulb behind the chomper fish", + "Open water skeleton path, King skull", + "Arnassi Ruins, bulb in the right part", + "Arnassi Ruins, bulb in the left part", + "Arnassi Ruins, bulb in the center part", + "Arnassi ruins, Song plant spore on the top of the ruins", + "Arnassi ruins, Arnassi Armor", + "Arnassi Ruins, Arnassi statue", + "Arnassi Ruins, Transturtle", + "Arnassi ruins, Crab armor", + "Simon says area, Transturtle", + "Mithalas city, first bulb in the left city part", + "Mithalas city, second bulb in the left city part", + "Mithalas city, bulb in the right part", + "Mithalas city, bulb at the top of the city", + "Mithalas city, first bulb in a broken home", + "Mithalas city, second bulb in a broken home", + "Mithalas city, bulb in the bottom left part", + "Mithalas city, first bulb in one of the homes", + "Mithalas city, second bulb in one of the homes", + "Mithalas city, first urn in one of the homes", + "Mithalas city, second urn in one of the homes", + "Mithalas city, first urn in the city reserve", + "Mithalas city, second urn in the city reserve", + "Mithalas city, third urn in the city reserve", + "Mithalas city, first bulb at the end of the top path", + "Mithalas city, second bulb at the end of the top path", + "Mithalas city, bulb in the top path", + "Mithalas city, Mithalas pot", + "Mithalas city, urn in the cathedral flower tube entrance", + "Mithalas city, Doll", + "Mithalas city, urn inside a home fish pass", + "Mithalas city castle, bulb in the flesh hole", + "Mithalas city castle, Blue banner", + "Mithalas city castle, urn in the bedroom", + "Mithalas city castle, first urn of the single lamp path", + "Mithalas city castle, second urn of the single lamp path", + "Mithalas city castle, urn in the bottom room", + "Mithalas city castle, first urn on the entrance path", + "Mithalas city castle, second urn on the entrance path", + "Mithalas castle, beating the priests", + "Mithalas city castle, Trident head", + "Mithalas cathedral, first urn in the top right room", + "Mithalas cathedral, second urn in the top right room", + "Mithalas cathedral, third urn in the top right room", + "Mithalas cathedral, urn in the flesh room with fleas", + "Mithalas cathedral, first urn in the bottom right path", + "Mithalas cathedral, second urn in the bottom right path", + "Mithalas cathedral, urn behind the flesh vein", + "Mithalas cathedral, urn in the top left eyes boss room", + "Mithalas cathedral, first urn in the path behind the flesh vein", + "Mithalas cathedral, second urn in the path behind the flesh vein", + "Mithalas cathedral, third urn in the path behind the flesh vein", + "Mithalas cathedral, one of the urns in the top right room", + "Mithalas cathedral, Mithalan Dress", + "Mithalas cathedral right area, urn bellow the left entrance", + "Cathedral underground, bulb in the center part", + "Cathedral underground, first bulb in the top left part", + "Cathedral underground, second bulb in the top left part", + "Cathedral underground, third bulb in the top left part", + "Cathedral underground, bulb close to the save cristal", + "Cathedral underground, bulb in the bottom right path", + "Cathedral boss area, beating Mithalan God", + "Kelp Forest top left area, bulb in the bottom left clearing", + "Kelp Forest top left area, bulb in the path down from the top left clearing", + "Kelp Forest top left area, bulb in the top left clearing", + "Kelp Forest top left, Jelly Egg", + "Kelp Forest top left area, bulb close to the Verse egg", + "Kelp forest top left area, Verse egg", + "Kelp Forest top right area, bulb under the rock in the right path", + "Kelp Forest top right area, bulb at the left of the center clearing", + "Kelp Forest top right area, bulb in the left path's big room", + "Kelp Forest top right area, bulb in the left path's small room", + "Kelp Forest top right area, bulb at the top of the center clearing", + "Kelp forest top right area, Black pearl", + "Kelp Forest top right area, bulb in the top fish pass", + "Kelp Forest bottom left area, bulb close to the spirit crystals", + "Kelp forest bottom left area, Walker baby", + "Kelp Forest bottom left area, Transturtle", + "Kelp forest bottom right area, Odd Container", + "Kelp forest boss area, beating Drunian God", + "Kelp Forest boss room, bulb at the bottom of the area", + "Kelp Forest bottom left area, Fish cave puzzle", + "Kelp Forest sprite cave, bulb inside the fish pass", + "Kelp Forest sprite cave, bulb in the second room", + "Kelp Forest Sprite Cave, Seed bag", + "Mermog cave, bulb in the left part of the cave", + "Mermog cave, Piranha Egg", + "The veil top left area, In the Li cave", + "The veil top left area, bulb under the rock in the top right path", + "The veil top left area, bulb hidden behind the blocking rock", + "The veil top left area, Transturtle", + "The veil top left area, bulb inside the fish pass", + "Turtle cave, Turtle Egg", + "Turtle cave, bulb in bubble cliff", + "Turtle cave, Urchin costume", + "The veil top right area, bulb in the middle of the wall jump cliff", + "The veil top right area, golden starfish at the bottom right of the bottom path", + "The veil top right area, bulb in the top of the water fall", + "The veil top right area, Transturtle", + "The veil bottom area, bulb in the left path", + "The veil bottom area, bulb in the spirit path", + "The veil bottom area, Verse egg", + "The veil bottom area, Stone Head", + "Octopus cave, Dumbo Egg", + "Octopus cave, bulb in the path below the octopus cave path", + "Bubble cave, bulb in the left cave wall", + "Bubble cave, bulb in the right cave wall (behind the ice cristal)", + "Bubble cave, Verse egg", + "Sun temple, bulb in the top left part", + "Sun temple, bulb in the top right part", + "Sun temple, bulb at the top of the high dark room", + "Sun temple, Golden Gear", + "Sun temple, first bulb of the temple", + "Sun temple, bulb on the left part", + "Sun temple, bulb in the hidden room of the right part", + "Sun temple, Sun key", + "Sun Worm path, first path bulb", + "Sun Worm path, second path bulb", + "Sun Worm path, first cliff bulb", + "Sun Worm path, second cliff bulb", + "Sun temple boss area, beating Sun God", + "Abyss left area, bulb in hidden path room", + "Abyss left area, bulb in the right part", + "Abyss left area, Glowing seed", + "Abyss left area, Glowing Plant", + "Abyss left area, bulb in the bottom fish pass", + "Abyss right area, bulb behind the rock in the whale room", + "Abyss right area, bulb in the middle path", + "Abyss right area, bulb behind the rock in the middle path", + "Abyss right area, bulb in the left green room", + "Abyss right area, Transturtle", + "Ice cave, bulb in the room to the right", + "Ice cave, First bulbs in the top exit room", + "Ice cave, Second bulbs in the top exit room", + "Ice cave, third bulbs in the top exit room", + "Ice cave, bulb in the left room", + "King Jellyfish cave, bulb in the right path from King Jelly", + "King Jellyfish cave, Jellyfish Costume", + "The whale, Verse egg", + "Sunken city right area, crate close to the save cristal", + "Sunken city right area, crate in the left bottom room", + "Sunken city left area, crate in the little pipe room", + "Sunken city left area, crate close to the save cristal", + "Sunken city left area, crate before the bedroom", + "Sunken city left area, Girl Costume", + "Sunken city, bulb on the top of the boss area (boiler room)", + "The body center area, breaking li cage", + "The body main area, bulb on the main path blocking tube", + "The body left area, first bulb in the top face room", + "The body left area, second bulb in the top face room", + "The body left area, bulb bellow the water stream", + "The body left area, bulb in the top path to the top face room", + "The body left area, bulb in the bottom face room", + "The body right area, bulb in the top face room", + "The body right area, bulb in the top path to the bottom face room", + "The body right area, bulb in the bottom face room", + "The body bottom area, bulb in the Jelly Zap room", + "The body bottom area, bulb in the nautilus room", + "The body bottom area, Mutant Costume", + "Final boss area, first bulb in the turtle room", + "Final boss area, second bulbs in the turtle room", + "Final boss area, third bulbs in the turtle room", + "Final boss area, Transturtle", + "Final boss area, bulb in the boss third form room", + "Kelp forest, beating Simon says", + "Beating Fallen God", + "Beating Mithalan God", + "Beating Drunian God", + "Beating Sun God", + "Beating the Golem", + "Beating Nautilus Prime", + "Beating Blaster Peg Prime", + "Beating Mergog", + "Beating Mithalan priests", + "Beating Octopus Prime", + "Beating Crabbius Maximus", + "Beating Mantis Shrimp Prime", + "Beating King Jellyfish God Prime", + "First secret", + "Second secret", + "Third secret", + "Sunken City cleared", + "Objective complete", +] + +class AquariaTestBase(WorldTestBase): + """Base class for Aquaria unit tests""" + game = "Aquaria" diff --git a/worlds/aquaria/test/test_beast_form_access.py b/worlds/aquaria/test/test_beast_form_access.py new file mode 100644 index 00000000..a8d55515 --- /dev/null +++ b/worlds/aquaria/test/test_beast_form_access.py @@ -0,0 +1,48 @@ +""" +Author: Louis M +Date: Thu, 18 Apr 2024 18:45:56 +0000 +Description: Unit test used to test accessibility of locations with and without the beast form +""" + +from worlds.aquaria.test import AquariaTestBase + + +class BeastFormAccessTest(AquariaTestBase): + """Unit test used to test accessibility of locations with and without the beast form""" + + def test_beast_form_location(self) -> None: + """Test locations that require beast form""" + locations = [ + "Mithalas castle, beating the priests", + "Arnassi ruins, Crab armor", + "Arnassi ruins, Song plant spore on the top of the ruins", + "Mithalas city, first bulb at the end of the top path", + "Mithalas city, second bulb at the end of the top path", + "Mithalas city, bulb in the top path", + "Mithalas city, Mithalas pot", + "Mithalas city, urn in the cathedral flower tube entrance", + "Mermog cave, Piranha Egg", + "Mithalas cathedral, Mithalan Dress", + "Turtle cave, bulb in bubble cliff", + "Turtle cave, Urchin costume", + "Sun Worm path, first cliff bulb", + "Sun Worm path, second cliff bulb", + "The veil top right area, bulb in the top of the water fall", + "Bubble cave, bulb in the left cave wall", + "Bubble cave, bulb in the right cave wall (behind the ice cristal)", + "Bubble cave, Verse egg", + "Sunken city, bulb on the top of the boss area (boiler room)", + "Octopus cave, Dumbo Egg", + "Beating the Golem", + "Beating Mergog", + "Beating Crabbius Maximus", + "Beating Octopus Prime", + "Beating Mantis Shrimp Prime", + "King Jellyfish cave, Jellyfish Costume", + "King Jellyfish cave, bulb in the right path from King Jelly", + "Beating King Jellyfish God Prime", + "Beating Mithalan priests", + "Sunken City cleared" + ] + items = [["Beast form"]] + self.assertAccessDependency(locations, items) diff --git a/worlds/aquaria/test/test_bind_song_access.py b/worlds/aquaria/test/test_bind_song_access.py new file mode 100644 index 00000000..b3a5c95c --- /dev/null +++ b/worlds/aquaria/test/test_bind_song_access.py @@ -0,0 +1,36 @@ +""" +Author: Louis M +Date: Thu, 18 Apr 2024 18:45:56 +0000 +Description: Unit test used to test accessibility of locations with and without the bind song (without the location + under rock needing bind song option) +""" + +from worlds.aquaria.test import AquariaTestBase, after_home_water_locations + + +class BindSongAccessTest(AquariaTestBase): + """Unit test used to test accessibility of locations with and without the bind song""" + options = { + "bind_song_needed_to_get_under_rock_bulb": False, + } + + def test_bind_song_location(self) -> None: + """Test locations that require Bind song""" + locations = [ + "Verse cave right area, Big Seed", + "Home water, bulb in the path bellow Nautilus Prime", + "Home water, bulb in the bottom left room", + "Home water, Nautilus Egg", + "Song cave, Verse egg", + "Energy temple first area, beating the energy statue", + "Energy temple first area, bulb in the bottom room blocked by a rock", + "Energy temple first area, Energy Idol", + "Energy temple second area, bulb under the rock", + "Energy temple bottom entrance, Krotite armor", + "Energy temple third area, bulb in the bottom path", + "Energy temple boss area, Fallen god tooth", + "Energy temple blaster room, Blaster egg", + *after_home_water_locations + ] + items = [["Bind song"]] + self.assertAccessDependency(locations, items) diff --git a/worlds/aquaria/test/test_bind_song_option_access.py b/worlds/aquaria/test/test_bind_song_option_access.py new file mode 100644 index 00000000..9405b83e --- /dev/null +++ b/worlds/aquaria/test/test_bind_song_option_access.py @@ -0,0 +1,42 @@ +""" +Author: Louis M +Date: Thu, 18 Apr 2024 18:45:56 +0000 +Description: Unit test used to test accessibility of locations with and without the bind song (with the location + under rock needing bind song option) +""" + +from worlds.aquaria.test import AquariaTestBase +from worlds.aquaria.test.test_bind_song_access import after_home_water_locations + + +class BindSongOptionAccessTest(AquariaTestBase): + """Unit test used to test accessibility of locations with and without the bind song""" + options = { + "bind_song_needed_to_get_under_rock_bulb": True, + } + + def test_bind_song_location(self) -> None: + """Test locations that require Bind song with the bind song needed option activated""" + locations = [ + "Verse cave right area, Big Seed", + "Verse cave left area, bulb under the rock at the end of the path", + "Home water, bulb under the rock in the left path from the verse cave", + "Song cave, bulb under the rock close to the song door", + "Song cave, bulb under the rock in the path to the singing statues", + "Naija's home, bulb under the rock at the right of the main path", + "Home water, bulb in the path bellow Nautilus Prime", + "Home water, bulb in the bottom left room", + "Home water, Nautilus Egg", + "Song cave, Verse egg", + "Energy temple first area, beating the energy statue", + "Energy temple first area, bulb in the bottom room blocked by a rock", + "Energy temple first area, Energy Idol", + "Energy temple second area, bulb under the rock", + "Energy temple bottom entrance, Krotite armor", + "Energy temple third area, bulb in the bottom path", + "Energy temple boss area, Fallen god tooth", + "Energy temple blaster room, Blaster egg", + *after_home_water_locations + ] + items = [["Bind song"]] + self.assertAccessDependency(locations, items) diff --git a/worlds/aquaria/test/test_confined_home_water.py b/worlds/aquaria/test/test_confined_home_water.py new file mode 100644 index 00000000..f4e0e7b6 --- /dev/null +++ b/worlds/aquaria/test/test_confined_home_water.py @@ -0,0 +1,20 @@ +""" +Author: Louis M +Date: Fri, 03 May 2024 14:07:35 +0000 +Description: Unit test used to test accessibility of region with the home water confine via option +""" + +from worlds.aquaria.test import AquariaTestBase + + +class ConfinedHomeWaterAccessTest(AquariaTestBase): + """Unit test used to test accessibility of region with the unconfine home water option disabled""" + options = { + "unconfine_home_water": 0, + "early_energy_form": False + } + + def test_confine_home_water_location(self) -> None: + """Test region accessible with confined home water""" + self.assertFalse(self.can_reach_region("Open water top left area"), "Can reach Open water top left area") + self.assertFalse(self.can_reach_region("Home Water, turtle room"), "Can reach Home Water, turtle room") \ No newline at end of file diff --git a/worlds/aquaria/test/test_dual_song_access.py b/worlds/aquaria/test/test_dual_song_access.py new file mode 100644 index 00000000..14c921d7 --- /dev/null +++ b/worlds/aquaria/test/test_dual_song_access.py @@ -0,0 +1,26 @@ +""" +Author: Louis M +Date: Thu, 18 Apr 2024 18:45:56 +0000 +Description: Unit test used to test accessibility of locations with and without the dual song +""" + +from worlds.aquaria.test import AquariaTestBase + + +class LiAccessTest(AquariaTestBase): + """Unit test used to test accessibility of locations with and without the dual song""" + options = { + "turtle_randomizer": 1, + } + + def test_li_song_location(self) -> None: + """Test locations that require the dual song""" + locations = [ + "The body bottom area, bulb in the Jelly Zap room", + "The body bottom area, bulb in the nautilus room", + "The body bottom area, Mutant Costume", + "Final boss area, bulb in the boss third form room", + "Objective complete" + ] + items = [["Dual form"]] + self.assertAccessDependency(locations, items) diff --git a/worlds/aquaria/test/test_energy_form_access.py b/worlds/aquaria/test/test_energy_form_access.py new file mode 100644 index 00000000..17fb8d3b --- /dev/null +++ b/worlds/aquaria/test/test_energy_form_access.py @@ -0,0 +1,73 @@ +""" +Author: Louis M +Date: Thu, 18 Apr 2024 18:45:56 +0000 +Description: Unit test used to test accessibility of locations with and without the bind song (without the early + energy form option) +""" + +from worlds.aquaria.test import AquariaTestBase + + +class EnergyFormAccessTest(AquariaTestBase): + """Unit test used to test accessibility of locations with and without the energy form""" + options = { + "early_energy_form": False, + } + + def test_energy_form_location(self) -> None: + """Test locations that require Energy form""" + locations = [ + "Home water, Nautilus Egg", + "Naija's home, bulb after the energy door", + "Energy temple first area, bulb in the bottom room blocked by a rock", + "Energy temple second area, bulb under the rock", + "Energy temple bottom entrance, Krotite armor", + "Energy temple third area, bulb in the bottom path", + "Energy temple boss area, Fallen god tooth", + "Energy temple blaster room, Blaster egg", + "Mithalas castle, beating the priests", + "Mithalas cathedral, first urn in the top right room", + "Mithalas cathedral, second urn in the top right room", + "Mithalas cathedral, third urn in the top right room", + "Mithalas cathedral, urn in the flesh room with fleas", + "Mithalas cathedral, first urn in the bottom right path", + "Mithalas cathedral, second urn in the bottom right path", + "Mithalas cathedral, urn behind the flesh vein", + "Mithalas cathedral, urn in the top left eyes boss room", + "Mithalas cathedral, first urn in the path behind the flesh vein", + "Mithalas cathedral, second urn in the path behind the flesh vein", + "Mithalas cathedral, third urn in the path behind the flesh vein", + "Mithalas cathedral, one of the urns in the top right room", + "Mithalas cathedral, Mithalan Dress", + "Mithalas cathedral right area, urn bellow the left entrance", + "Cathedral boss area, beating Mithalan God", + "Kelp Forest top left area, bulb close to the Verse egg", + "Kelp forest top left area, Verse egg", + "Kelp forest boss area, beating Drunian God", + "Mermog cave, Piranha Egg", + "Octopus cave, Dumbo Egg", + "Sun temple boss area, beating Sun God", + "Arnassi ruins, Crab armor", + "King Jellyfish cave, bulb in the right path from King Jelly", + "King Jellyfish cave, Jellyfish Costume", + "Sunken city, bulb on the top of the boss area (boiler room)", + "Final boss area, bulb in the boss third form room", + "Beating Fallen God", + "Beating Mithalan God", + "Beating Drunian God", + "Beating Sun God", + "Beating the Golem", + "Beating Nautilus Prime", + "Beating Blaster Peg Prime", + "Beating Mergog", + "Beating Mithalan priests", + "Beating Octopus Prime", + "Beating Crabbius Maximus", + "Beating King Jellyfish God Prime", + "First secret", + "Sunken City cleared", + "Objective complete", + + ] + items = [["Energy form"]] + self.assertAccessDependency(locations, items) \ No newline at end of file diff --git a/worlds/aquaria/test/test_energy_form_access_option.py b/worlds/aquaria/test/test_energy_form_access_option.py new file mode 100644 index 00000000..4dcbce67 --- /dev/null +++ b/worlds/aquaria/test/test_energy_form_access_option.py @@ -0,0 +1,31 @@ +""" +Author: Louis M +Date: Thu, 18 Apr 2024 18:45:56 +0000 +Description: Unit test used to test accessibility of locations with and without the bind song (with the early + energy form option) +""" + +from worlds.aquaria.test import AquariaTestBase, after_home_water_locations + + +class EnergyFormAccessTest(AquariaTestBase): + """Unit test used to test accessibility of locations with and without the energy form""" + options = { + "early_energy_form": True, + } + + def test_energy_form_location(self) -> None: + """Test locations that require Energy form with early energy song enable""" + locations = [ + "Home water, Nautilus Egg", + "Naija's home, bulb after the energy door", + "Energy temple first area, bulb in the bottom room blocked by a rock", + "Energy temple second area, bulb under the rock", + "Energy temple bottom entrance, Krotite armor", + "Energy temple third area, bulb in the bottom path", + "Energy temple boss area, Fallen god tooth", + "Energy temple blaster room, Blaster egg", + *after_home_water_locations + ] + items = [["Energy form"]] + self.assertAccessDependency(locations, items) \ No newline at end of file diff --git a/worlds/aquaria/test/test_fish_form_access.py b/worlds/aquaria/test/test_fish_form_access.py new file mode 100644 index 00000000..e6c24cf0 --- /dev/null +++ b/worlds/aquaria/test/test_fish_form_access.py @@ -0,0 +1,37 @@ +""" +Author: Louis M +Date: Thu, 18 Apr 2024 18:45:56 +0000 +Description: Unit test used to test accessibility of locations with and without the fish form +""" + +from worlds.aquaria.test import AquariaTestBase + + +class FishFormAccessTest(AquariaTestBase): + """Unit test used to test accessibility of locations with and without the fish form""" + options = { + "turtle_randomizer": 1, + } + + def test_fish_form_location(self) -> None: + """Test locations that require fish form""" + locations = [ + "The veil top left area, bulb inside the fish pass", + "Mithalas city, Doll", + "Mithalas city, urn inside a home fish pass", + "Kelp Forest top right area, bulb in the top fish pass", + "The veil bottom area, Verse egg", + "Open water bottom left area, bulb inside the downest fish pass", + "Kelp Forest top left area, bulb close to the Verse egg", + "Kelp forest top left area, Verse egg", + "Mermog cave, bulb in the left part of the cave", + "Mermog cave, Piranha Egg", + "Beating Mergog", + "Octopus cave, Dumbo Egg", + "Octopus cave, bulb in the path below the octopus cave path", + "Beating Octopus Prime", + "Abyss left area, bulb in the bottom fish pass", + "Arnassi ruins, Arnassi Armor" + ] + items = [["Fish form"]] + self.assertAccessDependency(locations, items) diff --git a/worlds/aquaria/test/test_li_song_access.py b/worlds/aquaria/test/test_li_song_access.py new file mode 100644 index 00000000..74f385ab --- /dev/null +++ b/worlds/aquaria/test/test_li_song_access.py @@ -0,0 +1,45 @@ +""" +Author: Louis M +Date: Thu, 18 Apr 2024 18:45:56 +0000 +Description: Unit test used to test accessibility of locations with and without Li +""" + +from worlds.aquaria.test import AquariaTestBase + + +class LiAccessTest(AquariaTestBase): + """Unit test used to test accessibility of locations with and without Li""" + options = { + "turtle_randomizer": 1, + } + + def test_li_song_location(self) -> None: + """Test locations that require Li""" + locations = [ + "Sunken city right area, crate close to the save cristal", + "Sunken city right area, crate in the left bottom room", + "Sunken city left area, crate in the little pipe room", + "Sunken city left area, crate close to the save cristal", + "Sunken city left area, crate before the bedroom", + "Sunken city left area, Girl Costume", + "Sunken city, bulb on the top of the boss area (boiler room)", + "The body center area, breaking li cage", + "The body main area, bulb on the main path blocking tube", + "The body left area, first bulb in the top face room", + "The body left area, second bulb in the top face room", + "The body left area, bulb bellow the water stream", + "The body left area, bulb in the top path to the top face room", + "The body left area, bulb in the bottom face room", + "The body right area, bulb in the top face room", + "The body right area, bulb in the top path to the bottom face room", + "The body right area, bulb in the bottom face room", + "The body bottom area, bulb in the Jelly Zap room", + "The body bottom area, bulb in the nautilus room", + "The body bottom area, Mutant Costume", + "Final boss area, bulb in the boss third form room", + "Beating the Golem", + "Sunken City cleared", + "Objective complete" + ] + items = [["Li and Li song", "Body tongue cleared"]] + self.assertAccessDependency(locations, items) diff --git a/worlds/aquaria/test/test_light_access.py b/worlds/aquaria/test/test_light_access.py new file mode 100644 index 00000000..49414e5a --- /dev/null +++ b/worlds/aquaria/test/test_light_access.py @@ -0,0 +1,71 @@ +""" +Author: Louis M +Date: Thu, 18 Apr 2024 18:45:56 +0000 +Description: Unit test used to test accessibility of locations with and without a light (Dumbo pet or sun form) +""" + +from worlds.aquaria.test import AquariaTestBase + + +class LightAccessTest(AquariaTestBase): + """Unit test used to test accessibility of locations with and without light""" + options = { + "turtle_randomizer": 1, + "light_needed_to_get_to_dark_places": True, + } + + def test_light_location(self) -> None: + """Test locations that require light""" + locations = [ + # Since the `assertAccessDependency` sweep for events even if I tell it not to, those location cannot be + # tested. + # "Third secret", + # "Sun temple, bulb in the top left part", + # "Sun temple, bulb in the top right part", + # "Sun temple, bulb at the top of the high dark room", + # "Sun temple, Golden Gear", + # "Sun Worm path, first path bulb", + # "Sun Worm path, second path bulb", + # "Sun Worm path, first cliff bulb", + "Octopus cave, Dumbo Egg", + "Kelp forest bottom right area, Odd Container", + "Kelp forest top right area, Black pearl", + "Abyss left area, bulb in hidden path room", + "Abyss left area, bulb in the right part", + "Abyss left area, Glowing seed", + "Abyss left area, Glowing Plant", + "Abyss left area, bulb in the bottom fish pass", + "Abyss right area, bulb behind the rock in the whale room", + "Abyss right area, bulb in the middle path", + "Abyss right area, bulb behind the rock in the middle path", + "Abyss right area, bulb in the left green room", + "Abyss right area, Transturtle", + "Ice cave, bulb in the room to the right", + "Ice cave, First bulbs in the top exit room", + "Ice cave, Second bulbs in the top exit room", + "Ice cave, third bulbs in the top exit room", + "Ice cave, bulb in the left room", + "Bubble cave, bulb in the left cave wall", + "Bubble cave, bulb in the right cave wall (behind the ice cristal)", + "Bubble cave, Verse egg", + "Beating Mantis Shrimp Prime", + "King Jellyfish cave, bulb in the right path from King Jelly", + "King Jellyfish cave, Jellyfish Costume", + "Beating King Jellyfish God Prime", + "The whale, Verse egg", + "First secret", + "Sunken city right area, crate close to the save cristal", + "Sunken city right area, crate in the left bottom room", + "Sunken city left area, crate in the little pipe room", + "Sunken city left area, crate close to the save cristal", + "Sunken city left area, crate before the bedroom", + "Sunken city left area, Girl Costume", + "Sunken city, bulb on the top of the boss area (boiler room)", + "Sunken City cleared", + "Beating the Golem", + "Beating Octopus Prime", + "Final boss area, bulb in the boss third form room", + "Objective complete", + ] + items = [["Sun form", "Baby dumbo", "Has sun crystal"]] + self.assertAccessDependency(locations, items) diff --git a/worlds/aquaria/test/test_nature_form_access.py b/worlds/aquaria/test/test_nature_form_access.py new file mode 100644 index 00000000..07d4377b --- /dev/null +++ b/worlds/aquaria/test/test_nature_form_access.py @@ -0,0 +1,57 @@ +""" +Author: Louis M +Date: Thu, 18 Apr 2024 18:45:56 +0000 +Description: Unit test used to test accessibility of locations with and without the nature form +""" + +from worlds.aquaria.test import AquariaTestBase + + +class NatureFormAccessTest(AquariaTestBase): + """Unit test used to test accessibility of locations with and without the nature form""" + options = { + "turtle_randomizer": 1, + } + + def test_nature_form_location(self) -> None: + """Test locations that require nature form""" + locations = [ + "Song cave, Anemone seed", + "Energy temple blaster room, Blaster egg", + "Beating Blaster Peg Prime", + "Kelp forest top left area, Verse egg", + "Kelp Forest top left area, bulb close to the Verse egg", + "Mithalas castle, beating the priests", + "Kelp Forest sprite cave, bulb in the second room", + "Kelp Forest Sprite Cave, Seed bag", + "Beating Mithalan priests", + "Abyss left area, bulb in the bottom fish pass", + "Bubble cave, Verse egg", + "Beating Mantis Shrimp Prime", + "Sunken city right area, crate close to the save cristal", + "Sunken city right area, crate in the left bottom room", + "Sunken city left area, crate in the little pipe room", + "Sunken city left area, crate close to the save cristal", + "Sunken city left area, crate before the bedroom", + "Sunken city left area, Girl Costume", + "Sunken city, bulb on the top of the boss area (boiler room)", + "Beating the Golem", + "Sunken City cleared", + "The body center area, breaking li cage", + "The body main area, bulb on the main path blocking tube", + "The body left area, first bulb in the top face room", + "The body left area, second bulb in the top face room", + "The body left area, bulb bellow the water stream", + "The body left area, bulb in the top path to the top face room", + "The body left area, bulb in the bottom face room", + "The body right area, bulb in the top face room", + "The body right area, bulb in the top path to the bottom face room", + "The body right area, bulb in the bottom face room", + "The body bottom area, bulb in the Jelly Zap room", + "The body bottom area, bulb in the nautilus room", + "The body bottom area, Mutant Costume", + "Final boss area, bulb in the boss third form room", + "Objective complete" + ] + items = [["Nature form"]] + self.assertAccessDependency(locations, items) diff --git a/worlds/aquaria/test/test_no_progression_hard_hidden_locations.py b/worlds/aquaria/test/test_no_progression_hard_hidden_locations.py new file mode 100644 index 00000000..5876ff31 --- /dev/null +++ b/worlds/aquaria/test/test_no_progression_hard_hidden_locations.py @@ -0,0 +1,60 @@ +""" +Author: Louis M +Date: Fri, 03 May 2024 14:07:35 +0000 +Description: Unit test used to test that no progression items can be put in hard or hidden locations when option enabled +""" + +from worlds.aquaria.test import AquariaTestBase +from BaseClasses import ItemClassification + + +class UNoProgressionHardHiddenTest(AquariaTestBase): + """Unit test used to test that no progression items can be put in hard or hidden locations when option enabled""" + options = { + "no_progression_hard_or_hidden_locations": True + } + + unfillable_locations = [ + "Energy temple boss area, Fallen god tooth", + "Cathedral boss area, beating Mithalan God", + "Kelp forest boss area, beating Drunian God", + "Sun temple boss area, beating Sun God", + "Sunken city, bulb on the top of the boss area (boiler room)", + "Home water, Nautilus Egg", + "Energy temple blaster room, Blaster egg", + "Mithalas castle, beating the priests", + "Mermog cave, Piranha Egg", + "Octopus cave, Dumbo Egg", + "King Jellyfish cave, bulb in the right path from King Jelly", + "King Jellyfish cave, Jellyfish Costume", + "Final boss area, bulb in the boss third form room", + "Sun Worm path, first cliff bulb", + "Sun Worm path, second cliff bulb", + "The veil top right area, bulb in the top of the water fall", + "Bubble cave, bulb in the left cave wall", + "Bubble cave, bulb in the right cave wall (behind the ice cristal)", + "Bubble cave, Verse egg", + "Kelp Forest bottom left area, bulb close to the spirit crystals", + "Kelp forest bottom left area, Walker baby", + "Sun temple, Sun key", + "The body bottom area, Mutant Costume", + "Sun temple, bulb in the hidden room of the right part", + "Arnassi ruins, Arnassi Armor", + ] + + def test_unconfine_home_water_both_location_fillable(self) -> None: + """ + Unit test used to test that no progression items can be put in hard or hidden locations when option enabled + """ + for location in self.unfillable_locations: + for item_name in self.world.item_names: + item = self.get_item_by_name(item_name) + if item.classification == ItemClassification.progression: + self.assertFalse( + self.world.get_location(location).can_fill(self.multiworld.state, item, False), + "The location \"" + location + "\" can be filled with \"" + item_name + "\"") + else: + self.assertTrue( + self.world.get_location(location).can_fill(self.multiworld.state, item, False), + "The location \"" + location + "\" cannot be filled with \"" + item_name + "\"") + diff --git a/worlds/aquaria/test/test_progression_hard_hidden_locations.py b/worlds/aquaria/test/test_progression_hard_hidden_locations.py new file mode 100644 index 00000000..64502360 --- /dev/null +++ b/worlds/aquaria/test/test_progression_hard_hidden_locations.py @@ -0,0 +1,53 @@ +""" +Author: Louis M +Date: Fri, 03 May 2024 14:07:35 +0000 +Description: Unit test used to test that progression items can be put in hard or hidden locations when option disabled +""" + +from worlds.aquaria.test import AquariaTestBase +from BaseClasses import ItemClassification + + +class UNoProgressionHardHiddenTest(AquariaTestBase): + """Unit test used to test that no progression items can be put in hard or hidden locations when option disabled""" + options = { + "no_progression_hard_or_hidden_locations": False + } + + unfillable_locations = [ + "Energy temple boss area, Fallen god tooth", + "Cathedral boss area, beating Mithalan God", + "Kelp forest boss area, beating Drunian God", + "Sun temple boss area, beating Sun God", + "Sunken city, bulb on the top of the boss area (boiler room)", + "Home water, Nautilus Egg", + "Energy temple blaster room, Blaster egg", + "Mithalas castle, beating the priests", + "Mermog cave, Piranha Egg", + "Octopus cave, Dumbo Egg", + "King Jellyfish cave, bulb in the right path from King Jelly", + "King Jellyfish cave, Jellyfish Costume", + "Final boss area, bulb in the boss third form room", + "Sun Worm path, first cliff bulb", + "Sun Worm path, second cliff bulb", + "The veil top right area, bulb in the top of the water fall", + "Bubble cave, bulb in the left cave wall", + "Bubble cave, bulb in the right cave wall (behind the ice cristal)", + "Bubble cave, Verse egg", + "Kelp Forest bottom left area, bulb close to the spirit crystals", + "Kelp forest bottom left area, Walker baby", + "Sun temple, Sun key", + "The body bottom area, Mutant Costume", + "Sun temple, bulb in the hidden room of the right part", + "Arnassi ruins, Arnassi Armor", + ] + + def test_unconfine_home_water_both_location_fillable(self) -> None: + """Unit test used to test that progression items can be put in hard or hidden locations when option disabled""" + for location in self.unfillable_locations: + for item_name in self.world.item_names: + item = self.get_item_by_name(item_name) + self.assertTrue( + self.world.get_location(location).can_fill(self.multiworld.state, item, False), + "The location \"" + location + "\" cannot be filled with \"" + item_name + "\"") + diff --git a/worlds/aquaria/test/test_spirit_form_access.py b/worlds/aquaria/test/test_spirit_form_access.py new file mode 100644 index 00000000..4d59d90a --- /dev/null +++ b/worlds/aquaria/test/test_spirit_form_access.py @@ -0,0 +1,36 @@ +""" +Author: Louis M +Date: Thu, 18 Apr 2024 18:45:56 +0000 +Description: Unit test used to test accessibility of locations with and without the spirit form +""" + +from worlds.aquaria.test import AquariaTestBase + + +class SpiritFormAccessTest(AquariaTestBase): + """Unit test used to test accessibility of locations with and without the spirit form""" + + def test_spirit_form_location(self) -> None: + """Test locations that require spirit form""" + locations = [ + "The veil bottom area, bulb in the spirit path", + "Mithalas city castle, Trident head", + "Open water skeleton path, King skull", + "Kelp forest bottom left area, Walker baby", + "Abyss right area, bulb behind the rock in the whale room", + "The whale, Verse egg", + "Ice cave, bulb in the room to the right", + "Ice cave, First bulbs in the top exit room", + "Ice cave, Second bulbs in the top exit room", + "Ice cave, third bulbs in the top exit room", + "Ice cave, bulb in the left room", + "Bubble cave, bulb in the left cave wall", + "Bubble cave, bulb in the right cave wall (behind the ice cristal)", + "Bubble cave, Verse egg", + "Sunken city left area, Girl Costume", + "Beating Mantis Shrimp Prime", + "First secret", + "Arnassi ruins, Arnassi Armor", + ] + items = [["Spirit form"]] + self.assertAccessDependency(locations, items) diff --git a/worlds/aquaria/test/test_sun_form_access.py b/worlds/aquaria/test/test_sun_form_access.py new file mode 100644 index 00000000..159ab717 --- /dev/null +++ b/worlds/aquaria/test/test_sun_form_access.py @@ -0,0 +1,25 @@ +""" +Author: Louis M +Date: Thu, 18 Apr 2024 18:45:56 +0000 +Description: Unit test used to test accessibility of locations with and without the sun form +""" + +from worlds.aquaria.test import AquariaTestBase + + +class SunFormAccessTest(AquariaTestBase): + """Unit test used to test accessibility of locations with and without the sun form""" + + def test_sun_form_location(self) -> None: + """Test locations that require sun form""" + locations = [ + "First secret", + "The whale, Verse egg", + "Abyss right area, bulb behind the rock in the whale room", + "Octopus cave, Dumbo Egg", + "Beating Octopus Prime", + "Final boss area, bulb in the boss third form room", + "Objective complete" + ] + items = [["Sun form"]] + self.assertAccessDependency(locations, items) diff --git a/worlds/aquaria/test/test_unconfine_home_water_via_both.py b/worlds/aquaria/test/test_unconfine_home_water_via_both.py new file mode 100644 index 00000000..3af17f1b --- /dev/null +++ b/worlds/aquaria/test/test_unconfine_home_water_via_both.py @@ -0,0 +1,21 @@ +""" +Author: Louis M +Date: Fri, 03 May 2024 14:07:35 +0000 +Description: Unit test used to test accessibility of region with the unconfined home water option via transportation + turtle and energy door +""" + +from worlds.aquaria.test import AquariaTestBase + + +class UnconfineHomeWaterBothAccessTest(AquariaTestBase): + """Unit test used to test accessibility of region with the unconfine home water option enabled""" + options = { + "unconfine_home_water": 3, + "early_energy_form": False + } + + def test_unconfine_home_water_both_location(self) -> None: + """Test locations accessible with unconfined home water via energy door and transportation turtle""" + self.assertTrue(self.can_reach_region("Open water top left area"), "Cannot reach Open water top left area") + self.assertTrue(self.can_reach_region("Home Water, turtle room"), "Cannot reach Home Water, turtle room") \ No newline at end of file diff --git a/worlds/aquaria/test/test_unconfine_home_water_via_energy_door.py b/worlds/aquaria/test/test_unconfine_home_water_via_energy_door.py new file mode 100644 index 00000000..bfa82d65 --- /dev/null +++ b/worlds/aquaria/test/test_unconfine_home_water_via_energy_door.py @@ -0,0 +1,20 @@ +""" +Author: Louis M +Date: Fri, 03 May 2024 14:07:35 +0000 +Description: Unit test used to test accessibility of region with the unconfined home water option via the energy door +""" + +from worlds.aquaria.test import AquariaTestBase + + +class UnconfineHomeWaterEnergyDoorAccessTest(AquariaTestBase): + """Unit test used to test accessibility of region with the unconfine home water option enabled""" + options = { + "unconfine_home_water": 1, + "early_energy_form": False + } + + def test_unconfine_home_water_energy_door_location(self) -> None: + """Test locations accessible with unconfined home water via energy door""" + self.assertTrue(self.can_reach_region("Open water top left area"), "Cannot reach Open water top left area") + self.assertFalse(self.can_reach_region("Home Water, turtle room"), "Can reach Home Water, turtle room") \ No newline at end of file diff --git a/worlds/aquaria/test/test_unconfine_home_water_via_transturtle.py b/worlds/aquaria/test/test_unconfine_home_water_via_transturtle.py new file mode 100644 index 00000000..627a92db --- /dev/null +++ b/worlds/aquaria/test/test_unconfine_home_water_via_transturtle.py @@ -0,0 +1,20 @@ +""" +Author: Louis M +Date: Fri, 03 May 2024 14:07:35 +0000 +Description: Unit test used to test accessibility of region with the unconfined home water option via transturtle +""" + +from worlds.aquaria.test import AquariaTestBase + + +class UnconfineHomeWaterTransturtleAccessTest(AquariaTestBase): + """Unit test used to test accessibility of region with the unconfine home water option enabled""" + options = { + "unconfine_home_water": 2, + "early_energy_form": False + } + + def test_unconfine_home_water_transturtle_location(self) -> None: + """Test locations accessible with unconfined home water via transportation turtle""" + self.assertTrue(self.can_reach_region("Home Water, turtle room"), "Cannot reach Home Water, turtle room") + self.assertFalse(self.can_reach_region("Open water top left area"), "Can reach Open water top left area") \ No newline at end of file