From b014ce082b266e4fdaa3622975f6b6800d5b1fdd Mon Sep 17 00:00:00 2001 From: Trevor L <80716066+TRPG0@users.noreply.github.com> Date: Wed, 12 Oct 2022 23:51:25 -0600 Subject: [PATCH] Hylics 2: Implement new game (#1058) --- worlds/hylics2/Exits.py | 94 +++++++ worlds/hylics2/Items.py | 243 ++++++++++++++++ worlds/hylics2/Locations.py | 383 +++++++++++++++++++++++++ worlds/hylics2/Options.py | 41 +++ worlds/hylics2/Rules.py | 433 +++++++++++++++++++++++++++++ worlds/hylics2/__init__.py | 246 ++++++++++++++++ worlds/hylics2/docs/en_Hylics 2.md | 17 ++ worlds/hylics2/docs/setup_en.md | 35 +++ 8 files changed, 1492 insertions(+) create mode 100644 worlds/hylics2/Exits.py create mode 100644 worlds/hylics2/Items.py create mode 100644 worlds/hylics2/Locations.py create mode 100644 worlds/hylics2/Options.py create mode 100644 worlds/hylics2/Rules.py create mode 100644 worlds/hylics2/__init__.py create mode 100644 worlds/hylics2/docs/en_Hylics 2.md create mode 100644 worlds/hylics2/docs/setup_en.md diff --git a/worlds/hylics2/Exits.py b/worlds/hylics2/Exits.py new file mode 100644 index 00000000..99ebeba2 --- /dev/null +++ b/worlds/hylics2/Exits.py @@ -0,0 +1,94 @@ +from typing import List, Dict + + +region_exit_table: Dict[int, List[str]] = { + 0: ["New Game"], + + 1: ["To Waynehouse", + "To New Muldul", + "To Viewax", + "To TV Island", + "To Shield Facility", + "To Worm Pod", + "To Foglast", + "To Sage Labyrinth", + "To Hylemxylem"], + + 2: ["To World", + "To Afterlife",], + + 3: ["To Airship", + "To Waynehouse", + "To New Muldul", + "To Drill Castle", + "To Viewax", + "To Arcade Island", + "To TV Island", + "To Juice Ranch", + "To Shield Facility", + "To Worm Pod", + "To Foglast", + "To Sage Airship", + "To Hylemxylem"], + + 4: ["To World", + "To Afterlife", + "To New Muldul Vault"], + + 5: ["To New Muldul"], + + 6: ["To World", + "To Afterlife"], + + 7: ["To World"], + + 8: ["To World"], + + 9: ["To World", + "To Afterlife"], + + 10: ["To World"], + + 11: ["To World", + "To Afterlife", + "To Worm Pod"], + + 12: ["To Shield Facility", + "To Afterlife"], + + 13: ["To World", + "To Afterlife"], + + 14: ["To World", + "To Sage Labyrinth"], + + 15: ["To Drill Castle", + "To Afterlife"], + + 16: ["To World"], + + 17: ["To World", + "To Afterlife"] +} + + +exit_lookup_table: Dict[str, int] = { + "New Game": 2, + "To Waynehouse": 2, + "To Afterlife": 1, + "To World": 3, + "To New Muldul": 4, + "To New Muldul Vault": 5, + "To Viewax": 6, + "To Airship": 7, + "To Arcade Island": 8, + "To TV Island": 9, + "To Juice Ranch": 10, + "To Shield Facility": 11, + "To Worm Pod": 12, + "To Foglast": 13, + "To Drill Castle": 14, + "To Sage Labyrinth": 15, + "To Sage Airship": 16, + "To Hylemxylem": 17 +} \ No newline at end of file diff --git a/worlds/hylics2/Items.py b/worlds/hylics2/Items.py new file mode 100644 index 00000000..9e36b3c3 --- /dev/null +++ b/worlds/hylics2/Items.py @@ -0,0 +1,243 @@ +from BaseClasses import ItemClassification +from typing import TypedDict, Dict + + +class ItemDict(TypedDict): + classification: ItemClassification + count: int + name: str + + +item_table: Dict[int, ItemDict] = { + # Things + 200622: {'classification': ItemClassification.filler, + 'count': 1, + 'name': 'DUBIOUS BERRY'}, + 200623: {'classification': ItemClassification.filler, + 'count': 11, + 'name': 'BURRITO'}, + 200624: {'classification': ItemClassification.filler, + 'count': 1, + 'name': 'COFFEE'}, + 200625: {'classification': ItemClassification.filler, + 'count': 6, + 'name': 'SOUL SPONGE'}, + 200626: {'classification': ItemClassification.useful, + 'count': 6, + 'name': 'MUSCLE APPLIQUE'}, + 200627: {'classification': ItemClassification.filler, + 'count': 1, + 'name': 'POOLWINE'}, + 200628: {'classification': ItemClassification.filler, + 'count': 3, + 'name': 'CUPCAKE'}, + 200629: {'classification': ItemClassification.filler, + 'count': 3, + 'name': 'COOKIE'}, + 200630: {'classification': ItemClassification.progression, + 'count': 1, + 'name': 'HOUSE KEY'}, + 200631: {'classification': ItemClassification.filler, + 'count': 2, + 'name': 'MEAT'}, + 200632: {'classification': ItemClassification.progression, + 'count': 1, + 'name': 'PNEUMATOPHORE'}, + 200633: {'classification': ItemClassification.progression, + 'count': 1, + 'name': 'CAVE KEY'}, + 200634: {'classification': ItemClassification.filler, + 'count': 6, + 'name': 'JUICE'}, + 200635: {'classification': ItemClassification.progression, + 'count': 1, + 'name': 'DOCK KEY'}, + 200636: {'classification': ItemClassification.filler, + 'count': 14, + 'name': 'BANANA'}, + 200637: {'classification': ItemClassification.progression, + 'count': 3, + 'name': 'PAPER CUP'}, + 200638: {'classification': ItemClassification.progression, + 'count': 1, + 'name': 'JAIL KEY'}, + 200639: {'classification': ItemClassification.progression, + 'count': 1, + 'name': 'PADDLE'}, + 200640: {'classification': ItemClassification.progression, + 'count': 1, + 'name': 'WORM ROOM KEY'}, + 200641: {'classification': ItemClassification.progression, + 'count': 1, + 'name': 'BRIDGE KEY'}, + 200642: {'classification': ItemClassification.filler, + 'count': 2, + 'name': 'STEM CELL'}, + 200643: {'classification': ItemClassification.progression, + 'count': 1, + 'name': 'UPPER CHAMBER KEY'}, + 200644: {'classification': ItemClassification.progression, + 'count': 1, + 'name': 'VESSEL ROOM KEY'}, + 200645: {'classification': ItemClassification.filler, + 'count': 3, + 'name': 'CLOUD GERM'}, + 200646: {'classification': ItemClassification.progression, + 'count': 1, + 'name': 'SKULL BOMB'}, + 200647: {'classification': ItemClassification.progression, + 'count': 1, + 'name': 'TOWER KEY'}, + 200648: {'classification': ItemClassification.progression, + 'count': 1, + 'name': 'DEEP KEY'}, + 200649: {'classification': ItemClassification.filler, + 'count': 1, + 'name': 'MULTI-COFFEE'}, + 200650: {'classification': ItemClassification.filler, + 'count': 4, + 'name': 'MULTI-JUICE'}, + 200651: {'classification': ItemClassification.filler, + 'count': 1, + 'name': 'MULTI STEM CELL'}, + 200652: {'classification': ItemClassification.filler, + 'count': 6, + 'name': 'MULTI SOUL SPONGE'}, + #200653: {'classification': ItemClassification.filler, + # 'count': 1, + # 'name': 'ANTENNA'}, + 200654: {'classification': ItemClassification.progression, + 'count': 1, + 'name': 'UPPER HOUSE KEY'}, + 200655: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'BOTTOMLESS JUICE'}, + 200656: {'classification': ItemClassification.progression, + 'count': 3, + 'name': 'SAGE TOKEN'}, + 200657: {'classification': ItemClassification.progression, + 'count': 1, + 'name': 'CLICKER'}, + + # Garbs > Gloves + 200658: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'CURSED GLOVES'}, + 200659: {'classification': ItemClassification.useful, + 'count': 5, + 'name': 'LONG GLOVES'}, + 200660: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'BRAIN DIGITS'}, + 200661: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'MATERIEL MITTS'}, + 200662: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'PLEATHER GAGE'}, + 200663: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'PEPTIDE BODKINS'}, + 200664: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'TELESCOPIC SLEEVE'}, + 200665: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'TENDRIL HAND'}, + 200666: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'PSYCHIC KNUCKLE'}, + 200667: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'SINGLE GLOVE'}, + + # Garbs > Accessories + 200668: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'FADED PONCHO'}, + 200669: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'JUMPSUIT'}, + 200670: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'BOOTS'}, + 200671: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'CONVERTER WORM'}, + 200672: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'COFFEE CHIP'}, + 200673: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'RANCHER PONCHO'}, + 200674: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'ORGAN FORT'}, + 200675: {'classification': ItemClassification.useful, + 'count': 2, + 'name': 'LOOPED DOME'}, + 200676: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'DUCTILE HABIT'}, + 200677: {'classification': ItemClassification.useful, + 'count': 2, + 'name': 'TARP'}, + + # Bones + 200686: {'classification': ItemClassification.filler, + 'count': 1, + 'name': '100 Bones'}, + 200687: {'classification': ItemClassification.filler, + 'count': 1, + 'name': '50 Bones'} +} + + +gesture_item_table: Dict[int, ItemDict] = { + 200678: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'POROMER BLEB'}, + 200679: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'SOUL CRISPER'}, + 200680: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'TIME SIGIL'}, + 200681: {'classification': ItemClassification.progression, + 'count': 1, + 'name': 'CHARGE UP'}, + 200682: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'FATE SANDBOX'}, + 200683: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'TELEDENUDATE'}, + 200684: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'LINK MOLLUSC'}, + 200685: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'BOMBO - GENESIS'}, + 200688: {'classification': ItemClassification.useful, + 'count': 1, + 'name': 'NEMATODE INTERFACE'}, +} + + +party_item_table: Dict[int, ItemDict] = { + 200689: {'classification': ItemClassification.progression, + 'count': 1, + 'name': 'Pongorma'}, + 200690: {'classification': ItemClassification.progression, + 'count': 1, + 'name': 'Dedusmuln'}, + 200691: {'classification': ItemClassification.progression, + 'count': 1, + 'name': 'Somsnosa'} +} + +medallion_item_table: Dict[int, ItemDict] = { + 200692: {'classification': ItemClassification.filler, + 'count': 30, + 'name': '10 Bones'} +} \ No newline at end of file diff --git a/worlds/hylics2/Locations.py b/worlds/hylics2/Locations.py new file mode 100644 index 00000000..0f8bbb9b --- /dev/null +++ b/worlds/hylics2/Locations.py @@ -0,0 +1,383 @@ +from typing import Dict, TypedDict + + +class LocationDict(TypedDict, total=False): + name: str + region: int + + +location_table: Dict[int, LocationDict] = { + # Waynehouse + 200622: {'name': "Waynehouse: Toilet", + 'region': 2}, + 200623: {'name': "Waynehouse: Basement Pot 1", + 'region': 2}, + 200624: {'name': "Waynehouse: Basement Pot 2", + 'region': 2}, + 200625: {'name': "Waynehouse: Basement Pot 3", + 'region': 2}, + 200626: {'name': "Waynehouse: Sarcophagus", + 'region': 2}, + + # Afterlife + 200628: {'name': "Afterlife: Mangled Wayne", + 'region': 1}, + 200629: {'name': "Afterlife: Jar near Mangled Wayne", + 'region': 1}, + 200630: {'name': "Afterlife: Jar under Pool", + 'region': 1}, + + # New Muldul + 200632: {'name': "New Muldul: Shop Ceiling Pot 1", + 'region': 4}, + 200633: {'name': "New Muldul: Shop Ceiling Pot 2", + 'region': 4}, + 200634: {'name': "New Muldul: Flag Banana", + 'region': 4}, + 200635: {'name': "New Muldul: Pot near Vault", + 'region': 4}, + 200636: {'name': "New Muldul: Underground Pot", + 'region': 4}, + 200637: {'name': "New Muldul: Underground Chest", + 'region': 4}, + 200638: {'name': "New Muldul: Juice Trade", + 'region': 4}, + 200639: {'name': "New Muldul: Basement Suitcase", + 'region': 4}, + 200640: {'name': "New Muldul: Upper House Chest 1", + 'region': 4}, + 200641: {'name': "New Muldul: Upper House Chest 2", + 'region': 4}, + + # New Muldul Vault + 200643: {'name': "New Muldul: Talk to Pongorma", + 'region': 4}, + 200645: {'name': "New Muldul: Rescued Blerol 1", + 'region': 4}, + 200646: {'name': "New Muldul: Rescued Blerol 2", + 'region': 4}, + 200647: {'name': "New Muldul: Vault Left Chest", + 'region': 5}, + 200648: {'name': "New Muldul: Vault Right Chest", + 'region': 5}, + 200649: {'name': "New Muldul: Vault Bomb", + 'region': 5}, + + # Viewax's Edifice + 200650: {'name': "Viewax's Edifice: Fountain Banana", + 'region': 6}, + 200651: {'name': "Viewax's Edifice: Dedusmuln's Suitcase", + 'region': 6}, + 200652: {'name': "Viewax's Edifice: Dedusmuln's Campfire", + 'region': 6}, + 200653: {'name': "Viewax's Edifice: Talk to Dedusmuln", + 'region': 6}, + 200655: {'name': "Viewax's Edifice: Canopic Jar", + 'region': 6}, + 200656: {'name': "Viewax's Edifice: Cave Sarcophagus", + 'region': 6}, + 200657: {'name': "Viewax's Edifice: Shielded Key", + 'region': 6}, + 200658: {'name': "Viewax's Edifice: Tower Pot", + 'region': 6}, + 200659: {'name': "Viewax's Edifice: Tower Jar", + 'region': 6}, + 200660: {'name': "Viewax's Edifice: Tower Chest", + 'region': 6}, + 200661: {'name': "Viewax's Edifice: Sage Fridge", + 'region': 6}, + 200662: {'name': "Viewax's Edifice: Sage Item 1", + 'region': 6}, + 200663: {'name': "Viewax's Edifice: Sage Item 2", + 'region': 6}, + 200664: {'name': "Viewax's Edifice: Viewax Pot", + 'region': 6}, + 200665: {'name': "Viewax's Edifice: Defeat Viewax", + 'region': 6}, + + # Viewax Arcade Minigame + 200667: {'name': "Arcade 1: Key", + 'region': 6}, + 200668: {'name': "Arcade 1: Coin Dash", + 'region': 6}, + 200669: {'name': "Arcade 1: Burrito Alcove 1", + 'region': 6}, + 200670: {'name': "Arcade 1: Burrito Alcove 2", + 'region': 6}, + 200671: {'name': "Arcade 1: Behind Spikes Banana", + 'region': 6}, + 200672: {'name': "Arcade 1: Pyramid Banana", + 'region': 6}, + 200673: {'name': "Arcade 1: Moving Platforms Muscle Applique", + 'region': 6}, + 200674: {'name': "Arcade 1: Bed Banana", + 'region': 6}, + + # Airship + 200675: {'name': "Airship: Talk to Somsnosa", + 'region': 7}, + + # Arcade Island + 200676: {'name': "Arcade Island: Shielded Key", + 'region': 8}, + 200677: {'name': "Arcade 2: Flying Machine Banana", + 'region': 8}, + 200678: {'name': "Arcade 2: Paper Cup Detour", + 'region': 8}, + 200679: {'name': "Arcade 2: Peak Muscle Applique", + 'region': 8}, + 200680: {'name': "Arcade 2: Double Banana 1", + 'region': 8}, + 200681: {'name': "Arcade 2: Double Banana 2", + 'region': 8}, + 200682: {'name': "Arcade 2: Cave Burrito", + 'region': 8}, + + # Juice Ranch + 200684: {'name': "Juice Ranch: Juice 1", + 'region': 10}, + 200685: {'name': "Juice Ranch: Juice 2", + 'region': 10}, + 200686: {'name': "Juice Ranch: Juice 3", + 'region': 10}, + 200687: {'name': "Juice Ranch: Ledge Rancher", + 'region': 10}, + 200688: {'name': "Juice Ranch: Battle with Somsnosa", + 'region': 10}, + 200690: {'name': "Juice Ranch: Fridge", + 'region': 10}, + + # Worm Pod + 200692: {'name': "Worm Pod: Key", + 'region': 12}, + + # Foglast + 200693: {'name': "Foglast: West Sarcophagus", + 'region': 13}, + 200694: {'name': "Foglast: Underground Sarcophagus", + 'region': 13}, + 200695: {'name': "Foglast: Shielded Key", + 'region': 13}, + 200696: {'name': "Foglast: Buy Clicker", + 'region': 13}, + 200698: {'name': "Foglast: Shielded Chest", + 'region': 13}, + 200699: {'name': "Foglast: Cave Fridge", + 'region': 13}, + 200700: {'name': "Foglast: Roof Sarcophagus", + 'region': 13}, + 200701: {'name': "Foglast: Under Lair Sarcophagus 1", + 'region': 13}, + 200702: {'name': "Foglast: Under Lair Sarcophagus 2", + 'region': 13}, + 200703: {'name': "Foglast: Under Lair Sarcophagus 3", + 'region': 13}, + 200704: {'name': "Foglast: Sage Sarcophagus", + 'region': 13}, + 200705: {'name': "Foglast: Sage Item 1", + 'region': 13}, + 200706: {'name': "Foglast: Sage Item 2", + 'region': 13}, + + # Drill Castle + 200707: {'name': "Drill Castle: Ledge Banana", + 'region': 14}, + 200708: {'name': "Drill Castle: Island Banana", + 'region': 14}, + 200709: {'name': "Drill Castle: Island Pot", + 'region': 14}, + 200710: {'name': "Drill Castle: Cave Sarcophagus", + 'region': 14}, + 200711: {'name': "Drill Castle: Roof Banana", + 'region': 14}, + + # Sage Labyrinth + 200713: {'name': "Sage Labyrinth: 1F Chest Near Fountain", + 'region': 15}, + 200714: {'name': "Sage Labyrinth: 1F Hidden Sarcophagus", + 'region': 15}, + 200715: {'name': "Sage Labyrinth: 1F Four Statues Chest 1", + 'region': 15}, + 200716: {'name': "Sage Labyrinth: 1F Four Statues Chest 2", + 'region': 15}, + 200717: {'name': "Sage Labyrinth: B1 Double Chest 1", + 'region': 15}, + 200718: {'name': "Sage Labyrinth: B1 Double Chest 2", + 'region': 15}, + 200719: {'name': "Sage Labyrinth: B1 Single Chest", + 'region': 15}, + 200720: {'name': "Sage Labyrinth: B1 Enemy Chest", + 'region': 15}, + 200721: {'name': "Sage Labyrinth: B1 Hidden Sarcophagus", + 'region': 15}, + 200722: {'name': "Sage Labyrinth: B1 Hole Chest", + 'region': 15}, + 200723: {'name': "Sage Labyrinth: B2 Hidden Sarcophagus 1", + 'region': 15}, + 200724: {'name': "Sage Labyrinth: B2 Hidden Sarcophagus 2", + 'region': 15}, + 200754: {'name': "Sage Labyrinth: 2F Sarcophagus", + 'region': 15}, + 200725: {'name': "Sage Labyrinth: Motor Hunter Sarcophagus", + 'region': 15}, + 200726: {'name': "Sage Labyrinth: Sage Item 1", + 'region': 15}, + 200727: {'name': "Sage Labyrinth: Sage Item 2", + 'region': 15}, + 200728: {'name': "Sage Labyrinth: Sage Left Arm", + 'region': 15}, + 200729: {'name': "Sage Labyrinth: Sage Right Arm", + 'region': 15}, + 200730: {'name': "Sage Labyrinth: Sage Left Leg", + 'region': 15}, + 200731: {'name': "Sage Labyrinth: Sage Right Leg", + 'region': 15}, + + # Sage Airship + 200732: {'name': "Sage Airship: Bottom Level Pot", + 'region': 16}, + 200733: {'name': "Sage Airship: Flesh Pot", + 'region': 16}, + 200734: {'name': "Sage Airship: Top Jar", + 'region': 16}, + + # Hylemxylem + 200736: {'name': "Hylemxylem: Jar", + 'region': 17}, + 200737: {'name': "Hylemxylem: Lower Reservoir Key", + 'region': 17}, + 200738: {'name': "Hylemxylem: Fountain Banana", + 'region': 17}, + 200739: {'name': "Hylemxylem: East Island Banana", + 'region': 17}, + 200740: {'name': "Hylemxylem: East Island Chest", + 'region': 17}, + 200741: {'name': "Hylemxylem: Upper Chamber Banana", + 'region': 17}, + 200742: {'name': "Hylemxylem: Across Upper Reservoir Chest", + 'region': 17}, + 200743: {'name': "Hylemxylem: Drained Lower Reservoir Chest", + 'region': 17}, + 200744: {'name': "Hylemxylem: Drained Lower Reservoir Burrito 1", + 'region': 17}, + 200745: {'name': "Hylemxylem: Drained Lower Reservoir Burrito 2", + 'region': 17}, + 200746: {'name': "Hylemxylem: Lower Reservoir Hole Pot 1", + 'region': 17}, + 200747: {'name': "Hylemxylem: Lower Reservoir Hole Pot 2", + 'region': 17}, + 200748: {'name': "Hylemxylem: Lower Reservoir Hole Pot 3", + 'region': 17}, + 200749: {'name': "Hylemxylem: Lower Reservoir Hole Sarcophagus", + 'region': 17}, + 200750: {'name': "Hylemxylem: Drained Upper Reservoir Burrito 1", + 'region': 17}, + 200751: {'name': "Hylemxylem: Drained Upper Reservoir Burrito 2", + 'region': 17}, + 200752: {'name': "Hylemxylem: Drained Upper Reservoir Burrito 3", + 'region': 17}, + 200753: {'name': "Hylemxylem: Upper Reservoir Hole Key", + 'region': 17} +} + + +tv_location_table: Dict[int, LocationDict] = { + 200627: {'name': "Waynehouse: TV", + 'region': 2}, + 200631: {'name': "Afterlife: TV", + 'region': 1}, + 200642: {'name': "New Muldul: TV", + 'region': 4}, + 200666: {'name': "Viewax's Edifice: TV", + 'region': 6}, + 200683: {'name': "TV Island: TV", + 'region': 9}, + 200691: {'name': "Juice Ranch: TV", + 'region': 10}, + 200697: {'name': "Foglast: TV", + 'region': 13}, + 200712: {'name': "Drill Castle: TV", + 'region': 14}, + 200735: {'name': "Sage Airship: TV", + 'region': 16} +} + + +party_location_table: Dict[int, LocationDict] = { + 200644: {'name': "New Muldul: Pongorma Joins", + 'region': 4}, + 200654: {'name': "Viewax's Edifice: Dedusmuln Joins", + 'region': 6}, + 200689: {'name': "Juice Ranch: Somsnosa Joins", + 'region': 10} +} + + +medallion_location_table: Dict[int, LocationDict] = { + 200755: {'name': "New Muldul: Upper House Medallion", + 'region': 4}, + + 200756: {'name': "New Muldul: Vault Rear Left Medallion", + 'region': 5}, + 200757: {'name': "New Muldul: Vault Rear Right Medallion", + 'region': 5}, + 200758: {'name': "New Muldul: Vault Center Medallion", + 'region': 5}, + 200759: {'name': "New Muldul: Vault Front Left Medallion", + 'region': 5}, + 200760: {'name': "New Muldul: Vault Front Right Medallion", + 'region': 5}, + + 200761: {'name': "Viewax's Edifice: Fort Wall Medallion", + 'region': 6}, + 200762: {'name': "Viewax's Edifice: Jar Medallion", + 'region': 6}, + 200763: {'name': "Viewax's Edifice: Sage Chair Medallion", + 'region': 6}, + 200764: {'name': "Arcade 1: Lonely Medallion", + 'region': 6}, + 200765: {'name': "Arcade 1: Alcove Medallion", + 'region': 6}, + 200766: {'name': "Arcade 1: Lava Medallion", + 'region': 6}, + + 200767: {'name': "Arcade 2: Flying Machine Medallion", + 'region': 8}, + 200768: {'name': "Arcade 2: Guarded Medallion", + 'region': 8}, + 200769: {'name': "Arcade 2: Spinning Medallion", + 'region': 8}, + 200770: {'name': "Arcade 2: Hook Medallion", + 'region': 8}, + 200771: {'name': "Arcade 2: Flag Medallion", + 'region': 8}, + + 200772: {'name': "Foglast: Under Lair Medallion", + 'region': 13}, + 200773: {'name': "Foglast: Mid-Air Medallion", + 'region': 13}, + 200774: {'name': "Foglast: Top of Tower Medallion", + 'region': 13}, + + 200775: {'name': "Sage Airship: Walkway Medallion", + 'region': 16}, + 200776: {'name': "Sage Airship: Flesh Medallion", + 'region': 16}, + 200777: {'name': "Sage Airship: Top of Ship Medallion", + 'region': 16}, + 200778: {'name': "Sage Airship: Hidden Medallion 1", + 'region': 16}, + 200779: {'name': "Sage Airship: Hidden Medallion 2", + 'region': 16}, + 200780: {'name': "Sage Airship: Hidden Medallion 3", + 'region': 16}, + + 200781: {'name': "Hylemxylem: Lower Reservoir Medallion", + 'region': 17}, + 200782: {'name': "Hylemxylem: Lower Reservoir Hole Medallion", + 'region': 17}, + 200783: {'name': "Hylemxylem: Drain Switch Medallion", + 'region': 17}, + 200784: {'name': "Hylemxylem: Warpo Medallion", + 'region': 17} +} \ No newline at end of file diff --git a/worlds/hylics2/Options.py b/worlds/hylics2/Options.py new file mode 100644 index 00000000..ac57e666 --- /dev/null +++ b/worlds/hylics2/Options.py @@ -0,0 +1,41 @@ +from Options import Choice, Toggle, DefaultOnToggle, DeathLink + +class PartyShuffle(Toggle): + """Shuffles party members into the pool. + Note that enabling this can potentially increase both the difficulty and length of a run.""" + display_name = "Shuffle Party Members" + +class GestureShuffle(Choice): + """Choose where gestures will appear in the item pool.""" + display_name = "Shuffle Gestures" + option_anywhere = 0 + option_tvs_only = 1 + option_default_locations = 2 + default = 0 + +class MedallionShuffle(Toggle): + """Shuffles red medallions into the pool.""" + display_name = "Shuffle Red Medallions" + +class RandomStart(Toggle): + """Start the randomizer in 1 of 4 positions. + (Waynehouse, Viewax's Edifice, TV Island, Shield Facility)""" + display_name = "Randomize Start Location" + +class ExtraLogic(DefaultOnToggle): + """Include some extra items in logic (CHARGE UP, 1x PAPER CUP) to prevent the game from becoming too difficult.""" + display_name = "Extra Items in Logic" + +class Hylics2DeathLink(DeathLink): + """When you die, everyone dies. The reverse is also true. + Note that this also includes death by using the PERISH gesture. + Can be toggled via in-game console command "/deathlink".""" + +hylics2_options = { + "party_shuffle": PartyShuffle, + "gesture_shuffle" : GestureShuffle, + "medallion_shuffle" : MedallionShuffle, + "random_start" : RandomStart, + "extra_items_in_logic": ExtraLogic, + "death_link": Hylics2DeathLink +} \ No newline at end of file diff --git a/worlds/hylics2/Rules.py b/worlds/hylics2/Rules.py new file mode 100644 index 00000000..be38e102 --- /dev/null +++ b/worlds/hylics2/Rules.py @@ -0,0 +1,433 @@ +from worlds.generic.Rules import add_rule +from ..AutoWorld import LogicMixin + + +class Hylics2Logic(LogicMixin): + + def _hylics2_can_air_dash(self, player): + return self.has("PNEUMATOPHORE", player) + + def _hylics2_has_airship(self, player): + return self.has("DOCK KEY", player) + + def _hylics2_has_jail_key(self, player): + return self.has("JAIL KEY", player) + + def _hylics2_has_paddle(self, player): + return self.has("PADDLE", player) + + def _hylics2_has_worm_room_key(self, player): + return self.has("WORM ROOM KEY", player) + + def _hylics2_has_bridge_key(self, player): + return self.has("BRIDGE KEY", player) + + def _hylics2_has_upper_chamber_key(self, player): + return self.has("UPPER CHAMBER KEY", player) + + def _hylics2_has_vessel_room_key(self, player): + return self.has("VESSEL ROOM KEY", player) + + def _hylics2_has_house_key(self, player): + return self.has("HOUSE KEY", player) + + def _hylics2_has_cave_key(self, player): + return self.has("CAVE KEY", player) + + def _hylics2_has_skull_bomb(self, player): + return self.has("SKULL BOMB", player) + + def _hylics2_has_tower_key(self, player): + return self.has("TOWER KEY", player) + + def _hylics2_has_deep_key(self, player): + return self.has("DEEP KEY", player) + + def _hylics2_has_upper_house_key(self, player): + return self.has("UPPER HOUSE KEY", player) + + def _hylics2_has_clicker(self, player): + return self.has("CLICKER", player) + + def _hylics2_has_tokens(self, player): + return self.has("SAGE TOKEN", player, 3) + + def _hylics2_has_charge_up(self, player): + return self.has("CHARGE UP", player) + + def _hylics2_has_cup(self, player): + return self.has("PAPER CUP", player, 1) + + def _hylics2_has_1_member(self, player): + return self.has("Pongorma", player) or self.has("Dedusmuln", player) or self.has("Somsnosa", player) + + def _hylics2_has_2_members(self, player): + return (self.has("Pongorma", player) and self.has("Dedusmuln", player)) or\ + (self.has("Pongorma", player) and self.has("Somsnosa", player)) or\ + (self.has("Dedusmuln", player) and self.has("Somsnosa", player)) + + def _hylics2_has_3_members(self, player): + return self.has("Pongorma", player) and self.has("Dedusmuln", player) and self.has("Somsnosa", player) + + def _hylics2_enter_arcade2(self, player): + return self._hylics2_can_air_dash(player) and self._hylics2_has_airship(player) + + def _hylics2_enter_wormpod(self, player): + return self._hylics2_has_airship(player) and self._hylics2_has_worm_room_key(player) and\ + self._hylics2_has_paddle(player) + + def _hylics2_enter_sageship(self, player): + return self._hylics2_has_skull_bomb(player) and self._hylics2_has_airship(player) and\ + self._hylics2_has_paddle(player) + + def _hylics2_enter_foglast(self, player): + return self._hylics2_enter_wormpod(player) + + def _hylics2_enter_hylemxylem(self, player): + return self._hylics2_can_air_dash(player) and self._hylics2_enter_wormpod(player) and\ + self._hylics2_has_bridge_key(player) + + +def set_rules(hylics2world): + world = hylics2world.world + player = hylics2world.player + + # Afterlife + add_rule(world.get_location("Afterlife: TV", player), + lambda state: state._hylics2_has_cave_key(player)) + + # New Muldul + add_rule(world.get_location("New Muldul: Underground Chest", player), + lambda state: state._hylics2_can_air_dash(player)) + add_rule(world.get_location("New Muldul: TV", player), + lambda state: state._hylics2_has_house_key(player)) + add_rule(world.get_location("New Muldul: Upper House Chest 1", player), + lambda state: state._hylics2_has_upper_house_key(player)) + add_rule(world.get_location("New Muldul: Upper House Chest 2", player), + lambda state: state._hylics2_has_upper_house_key(player)) + + # New Muldul Vault + add_rule(world.get_location("New Muldul: Rescued Blerol 1", player), + lambda state: (state._hylics2_can_air_dash(player) or state._hylics2_has_airship(player)) and\ + ((state._hylics2_has_jail_key(player) and state._hylics2_has_paddle(player)) or\ + (state._hylics2_has_bridge_key(player) and state._hylics2_has_worm_room_key(player)))) + add_rule(world.get_location("New Muldul: Rescued Blerol 2", player), + lambda state: (state._hylics2_can_air_dash(player) or state._hylics2_has_airship(player)) and\ + ((state._hylics2_has_jail_key(player) and state._hylics2_has_paddle(player)) or\ + (state._hylics2_has_bridge_key(player) and state._hylics2_has_worm_room_key(player)))) + add_rule(world.get_location("New Muldul: Vault Left Chest", player), + lambda state: state._hylics2_enter_foglast(player) and state._hylics2_has_bridge_key(player)) + add_rule(world.get_location("New Muldul: Vault Right Chest", player), + lambda state: state._hylics2_enter_foglast(player) and state._hylics2_has_bridge_key(player)) + add_rule(world.get_location("New Muldul: Vault Bomb", player), + lambda state: state._hylics2_enter_foglast(player) and state._hylics2_has_bridge_key(player)) + + # Viewax's Edifice + add_rule(world.get_location("Viewax's Edifice: Canopic Jar", player), + lambda state: state._hylics2_has_paddle(player)) + add_rule(world.get_location("Viewax's Edifice: Cave Sarcophagus", player), + lambda state: state._hylics2_has_paddle(player)) + add_rule(world.get_location("Viewax's Edifice: Shielded Key", player), + lambda state: state._hylics2_has_paddle(player)) + add_rule(world.get_location("Viewax's Edifice: Shielded Key", player), + lambda state: state._hylics2_has_paddle(player)) + add_rule(world.get_location("Viewax's Edifice: Tower Pot", player), + lambda state: state._hylics2_has_paddle(player)) + add_rule(world.get_location("Viewax's Edifice: Tower Jar", player), + lambda state: state._hylics2_has_paddle(player)) + add_rule(world.get_location("Viewax's Edifice: Tower Chest", player), + lambda state: state._hylics2_has_paddle(player) and state._hylics2_has_tower_key(player)) + add_rule(world.get_location("Viewax's Edifice: Viewax Pot", player), + lambda state: state._hylics2_has_paddle(player)) + add_rule(world.get_location("Viewax's Edifice: Defeat Viewax", player), + lambda state: state._hylics2_has_paddle(player)) + add_rule(world.get_location("Viewax's Edifice: TV", player), + lambda state: state._hylics2_has_paddle(player) and state._hylics2_has_jail_key(player)) + add_rule(world.get_location("Viewax's Edifice: Sage Fridge", player), + lambda state: state._hylics2_can_air_dash(player)) + add_rule(world.get_location("Viewax's Edifice: Sage Item 1", player), + lambda state: state._hylics2_can_air_dash(player)) + add_rule(world.get_location("Viewax's Edifice: Sage Item 2", player), + lambda state: state._hylics2_can_air_dash(player)) + + # Arcade 1 + add_rule(world.get_location("Arcade 1: Key", player), + lambda state: state._hylics2_has_paddle(player)) + add_rule(world.get_location("Arcade 1: Coin Dash", player), + lambda state: state._hylics2_has_paddle(player)) + add_rule(world.get_location("Arcade 1: Burrito Alcove 1", player), + lambda state: state._hylics2_has_paddle(player)) + add_rule(world.get_location("Arcade 1: Burrito Alcove 2", player), + lambda state: state._hylics2_has_paddle(player)) + add_rule(world.get_location("Arcade 1: Behind Spikes Banana", player), + lambda state: state._hylics2_has_paddle(player)) + add_rule(world.get_location("Arcade 1: Pyramid Banana", player), + lambda state: state._hylics2_has_paddle(player)) + add_rule(world.get_location("Arcade 1: Moving Platforms Muscle Applique", player), + lambda state: state._hylics2_has_paddle(player)) + add_rule(world.get_location("Arcade 1: Bed Banana", player), + lambda state: state._hylics2_has_paddle(player)) + + # Airship + add_rule(world.get_location("Airship: Talk to Somsnosa", player), + lambda state: state._hylics2_has_worm_room_key(player)) + + # Foglast + add_rule(world.get_location("Foglast: Underground Sarcophagus", player), + lambda state: state._hylics2_can_air_dash(player)) + add_rule(world.get_location("Foglast: Shielded Key", player), + lambda state: state._hylics2_can_air_dash(player)) + add_rule(world.get_location("Foglast: TV", player), + lambda state: state._hylics2_can_air_dash(player) and state._hylics2_has_clicker(player)) + add_rule(world.get_location("Foglast: Buy Clicker", player), + lambda state: state._hylics2_can_air_dash(player)) + add_rule(world.get_location("Foglast: Shielded Chest", player), + lambda state: state._hylics2_can_air_dash(player)) + add_rule(world.get_location("Foglast: Cave Fridge", player), + lambda state: state._hylics2_can_air_dash(player)) + add_rule(world.get_location("Foglast: Roof Sarcophagus", player), + lambda state: state._hylics2_can_air_dash(player) and state._hylics2_has_bridge_key(player)) + add_rule(world.get_location("Foglast: Under Lair Sarcophagus 1", player), + lambda state: state._hylics2_can_air_dash(player) and state._hylics2_has_bridge_key(player)) + add_rule(world.get_location("Foglast: Under Lair Sarcophagus 2", player), + lambda state: state._hylics2_can_air_dash(player) and state._hylics2_has_bridge_key(player)) + add_rule(world.get_location("Foglast: Under Lair Sarcophagus 3", player), + lambda state: state._hylics2_can_air_dash(player) and state._hylics2_has_bridge_key(player)) + add_rule(world.get_location("Foglast: Sage Sarcophagus", player), + lambda state: state._hylics2_can_air_dash(player) and state._hylics2_has_bridge_key(player)) + add_rule(world.get_location("Foglast: Sage Item 1", player), + lambda state: state._hylics2_can_air_dash(player) and state._hylics2_has_bridge_key(player)) + add_rule(world.get_location("Foglast: Sage Item 2", player), + lambda state: state._hylics2_can_air_dash(player) and state._hylics2_has_bridge_key(player)) + + # Drill Castle + add_rule(world.get_location("Drill Castle: Island Banana", player), + lambda state: state._hylics2_can_air_dash(player)) + add_rule(world.get_location("Drill Castle: Island Pot", player), + lambda state: state._hylics2_can_air_dash(player)) + add_rule(world.get_location("Drill Castle: Cave Sarcophagus", player), + lambda state: state._hylics2_can_air_dash(player)) + add_rule(world.get_location("Drill Castle: TV", player), + lambda state: state._hylics2_can_air_dash(player)) + + # Sage Labyrinth + add_rule(world.get_location("Sage Labyrinth: Sage Item 1", player), + lambda state: state._hylics2_has_deep_key(player)) + add_rule(world.get_location("Sage Labyrinth: Sage Item 2", player), + lambda state: state._hylics2_has_deep_key(player)) + add_rule(world.get_location("Sage Labyrinth: Sage Left Arm", player), + lambda state: state._hylics2_has_deep_key(player)) + add_rule(world.get_location("Sage Labyrinth: Sage Right Arm", player), + lambda state: state._hylics2_has_deep_key(player)) + add_rule(world.get_location("Sage Labyrinth: Sage Left Leg", player), + lambda state: state._hylics2_has_deep_key(player)) + add_rule(world.get_location("Sage Labyrinth: Sage Right Leg", player), + lambda state: state._hylics2_has_deep_key(player)) + + # Sage Airship + add_rule(world.get_location("Sage Airship: TV", player), + lambda state: state._hylics2_has_tokens(player)) + + # Hylemxylem + add_rule(world.get_location("Hylemxylem: Upper Chamber Banana", player), + lambda state: state._hylics2_has_upper_chamber_key(player)) + add_rule(world.get_location("Hylemxylem: Across Upper Reservoir Chest", player), + lambda state: state._hylics2_has_upper_chamber_key(player)) + add_rule(world.get_location("Hylemxylem: Drained Lower Reservoir Chest", player), + lambda state: state._hylics2_has_upper_chamber_key(player)) + add_rule(world.get_location("Hylemxylem: Drained Lower Reservoir Burrito 1", player), + lambda state: state._hylics2_has_upper_chamber_key(player)) + add_rule(world.get_location("Hylemxylem: Drained Lower Reservoir Burrito 2", player), + lambda state: state._hylics2_has_upper_chamber_key(player)) + add_rule(world.get_location("Hylemxylem: Lower Reservoir Hole Pot 1", player), + lambda state: state._hylics2_has_upper_chamber_key(player)) + add_rule(world.get_location("Hylemxylem: Lower Reservoir Hole Pot 2", player), + lambda state: state._hylics2_has_upper_chamber_key(player)) + add_rule(world.get_location("Hylemxylem: Lower Reservoir Hole Pot 3", player), + lambda state: state._hylics2_has_upper_chamber_key(player)) + add_rule(world.get_location("Hylemxylem: Lower Reservoir Hole Sarcophagus", player), + lambda state: state._hylics2_has_upper_chamber_key(player)) + add_rule(world.get_location("Hylemxylem: Drained Upper Reservoir Burrito 1", player), + lambda state: state._hylics2_has_upper_chamber_key(player)) + add_rule(world.get_location("Hylemxylem: Drained Upper Reservoir Burrito 2", player), + lambda state: state._hylics2_has_upper_chamber_key(player)) + add_rule(world.get_location("Hylemxylem: Drained Upper Reservoir Burrito 3", player), + lambda state: state._hylics2_has_upper_chamber_key(player)) + add_rule(world.get_location("Hylemxylem: Upper Reservoir Hole Key", player), + lambda state: state._hylics2_has_upper_chamber_key(player)) + + # extra rules if Extra Items in Logic is enabled + if world.extra_items_in_logic[player]: + for i in world.get_region("Foglast", player).entrances: + add_rule(i, lambda state: state._hylics2_has_charge_up(player)) + for i in world.get_region("Sage Airship", player).entrances: + add_rule(i, lambda state: state._hylics2_has_charge_up(player) and state._hylics2_has_cup(player) and\ + state._hylics2_has_worm_room_key(player)) + for i in world.get_region("Hylemxylem", player).entrances: + add_rule(i, lambda state: state._hylics2_has_charge_up(player) and state._hylics2_has_cup(player)) + + add_rule(world.get_location("Sage Labyrinth: Motor Hunter Sarcophagus", player), + lambda state: state._hylics2_has_charge_up(player) and state._hylics2_has_cup(player)) + + # extra rules if Shuffle Party Members is enabled + if world.party_shuffle[player]: + for i in world.get_region("Arcade Island", player).entrances: + add_rule(i, lambda state: state._hylics2_has_3_members(player)) + for i in world.get_region("Foglast", player).entrances: + add_rule(i, lambda state: state._hylics2_has_3_members(player) or\ + (state._hylics2_has_2_members(player) and state._hylics2_has_jail_key(player))) + for i in world.get_region("Sage Airship", player).entrances: + add_rule(i, lambda state: state._hylics2_has_3_members(player)) + for i in world.get_region("Hylemxylem", player).entrances: + add_rule(i, lambda state: state._hylics2_has_3_members(player)) + + add_rule(world.get_location("Viewax's Edifice: Defeat Viewax", player), + lambda state: state._hylics2_has_2_members(player)) + add_rule(world.get_location("New Muldul: Rescued Blerol 1", player), + lambda state: state._hylics2_has_2_members(player)) + add_rule(world.get_location("New Muldul: Rescued Blerol 2", player), + lambda state: state._hylics2_has_2_members(player)) + add_rule(world.get_location("New Muldul: Vault Left Chest", player), + lambda state: state._hylics2_has_3_members(player)) + add_rule(world.get_location("New Muldul: Vault Right Chest", player), + lambda state: state._hylics2_has_3_members(player)) + add_rule(world.get_location("New Muldul: Vault Bomb", player), + lambda state: state._hylics2_has_2_members(player)) + add_rule(world.get_location("Juice Ranch: Battle with Somsnosa", player), + lambda state: state._hylics2_has_2_members(player)) + add_rule(world.get_location("Juice Ranch: Somsnosa Joins", player), + lambda state: state._hylics2_has_2_members(player)) + add_rule(world.get_location("Airship: Talk to Somsnosa", player), + lambda state: state._hylics2_has_3_members(player)) + add_rule(world.get_location("Sage Labyrinth: Motor Hunter Sarcophagus", player), + lambda state: state._hylics2_has_3_members(player)) + + # extra rules if Shuffle Red Medallions is enabled + if world.medallion_shuffle[player]: + add_rule(world.get_location("New Muldul: Upper House Medallion", player), + lambda state: state._hylics2_has_upper_house_key(player)) + add_rule(world.get_location("New Muldul: Vault Rear Left Medallion", player), + lambda state: state._hylics2_enter_foglast(player) and state._hylics2_has_bridge_key(player)) + add_rule(world.get_location("New Muldul: Vault Rear Right Medallion", player), + lambda state: state._hylics2_enter_foglast(player) and state._hylics2_has_bridge_key(player)) + add_rule(world.get_location("New Muldul: Vault Center Medallion", player), + lambda state: state._hylics2_enter_foglast(player) and state._hylics2_has_bridge_key(player)) + add_rule(world.get_location("New Muldul: Vault Front Left Medallion", player), + lambda state: state._hylics2_enter_foglast(player) and state._hylics2_has_bridge_key(player)) + add_rule(world.get_location("New Muldul: Vault Front Right Medallion", player), + lambda state: state._hylics2_enter_foglast(player) and state._hylics2_has_bridge_key(player)) + add_rule(world.get_location("Viewax's Edifice: Fort Wall Medallion", player), + lambda state: state._hylics2_has_paddle(player)) + add_rule(world.get_location("Viewax's Edifice: Jar Medallion", player), + lambda state: state._hylics2_has_paddle(player)) + add_rule(world.get_location("Viewax's Edifice: Sage Chair Medallion", player), + lambda state: state._hylics2_can_air_dash(player)) + add_rule(world.get_location("Arcade 1: Lonely Medallion", player), + lambda state: state._hylics2_has_paddle(player)) + add_rule(world.get_location("Arcade 1: Alcove Medallion", player), + lambda state: state._hylics2_has_paddle(player)) + add_rule(world.get_location("Foglast: Under Lair Medallion", player), + lambda state: state._hylics2_has_bridge_key(player)) + add_rule(world.get_location("Foglast: Mid-Air Medallion", player), + lambda state: state._hylics2_can_air_dash(player)) + add_rule(world.get_location("Foglast: Top of Tower Medallion", player), + lambda state: state._hylics2_has_paddle(player)) + add_rule(world.get_location("Hylemxylem: Lower Reservoir Hole Medallion", player), + lambda state: state._hylics2_has_upper_chamber_key(player)) + + # extra rules is Shuffle Red Medallions and Party Shuffle are enabled + if world.party_shuffle[player] and world.medallion_shuffle[player]: + add_rule(world.get_location("New Muldul: Vault Rear Left Medallion", player), + lambda state: state._hylics2_has_jail_key(player)) + add_rule(world.get_location("New Muldul: Vault Rear Right Medallion", player), + lambda state: state._hylics2_has_jail_key(player)) + add_rule(world.get_location("New Muldul: Vault Center Medallion", player), + lambda state: state._hylics2_has_jail_key(player)) + add_rule(world.get_location("New Muldul: Vault Front Left Medallion", player), + lambda state: state._hylics2_has_jail_key(player)) + add_rule(world.get_location("New Muldul: Vault Front Right Medallion", player), + lambda state: state._hylics2_has_jail_key(player)) + + # entrances + for i in world.get_region("Airship", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + for i in world.get_region("Arcade Island", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player) and state._hylics2_can_air_dash(player)) + for i in world.get_region("Worm Pod", player).entrances: + add_rule(i, lambda state: state._hylics2_enter_wormpod(player)) + for i in world.get_region("Foglast", player).entrances: + add_rule(i, lambda state: state._hylics2_enter_foglast(player)) + for i in world.get_region("Sage Labyrinth", player).entrances: + add_rule(i, lambda state: state._hylics2_has_skull_bomb(player)) + for i in world.get_region("Sage Airship", player).entrances: + add_rule(i, lambda state: state._hylics2_enter_sageship(player)) + for i in world.get_region("Hylemxylem", player).entrances: + add_rule(i, lambda state: state._hylics2_enter_hylemxylem(player)) + + # random start logic (default) + if ((not world.random_start[player]) or \ + (world.random_start[player] and hylics2world.start_location == "Waynehouse")): + # entrances + for i in world.get_region("Viewax", player).entrances: + add_rule(i, lambda state: state._hylics2_can_air_dash(player) or state._hylics2_has_airship(player)) + for i in world.get_region("TV Island", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + for i in world.get_region("Shield Facility", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + for i in world.get_region("Juice Ranch", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + + # random start logic (Viewax's Edifice) + elif (world.random_start[player] and hylics2world.start_location == "Viewax's Edifice"): + for i in world.get_region("Waynehouse", player).entrances: + add_rule(i, lambda state: state._hylics2_can_air_dash(player) or state._hylics2_has_airship(player)) + for i in world.get_region("New Muldul", player).entrances: + add_rule(i, lambda state: state._hylics2_can_air_dash(player) or state._hylics2_has_airship(player)) + for i in world.get_region("New Muldul Vault", player).entrances: + add_rule(i, lambda state: state._hylics2_can_air_dash(player) or state._hylics2_has_airship(player)) + for i in world.get_region("Drill Castle", player).entrances: + add_rule(i, lambda state: state._hylics2_can_air_dash(player) or state._hylics2_has_airship(player)) + for i in world.get_region("TV Island", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + for i in world.get_region("Shield Facility", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + for i in world.get_region("Juice Ranch", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + for i in world.get_region("Sage Labyrinth", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + + # random start logic (TV Island) + elif (world.random_start[player] and hylics2world.start_location == "TV Island"): + for i in world.get_region("Waynehouse", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + for i in world.get_region("New Muldul", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + for i in world.get_region("New Muldul Vault", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + for i in world.get_region("Drill Castle", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + for i in world.get_region("Viewax", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + for i in world.get_region("Shield Facility", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + for i in world.get_region("Juice Ranch", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + for i in world.get_region("Sage Labyrinth", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + + # random start logic (Shield Facility) + elif (world.random_start[player] and hylics2world.start_location == "Shield Facility"): + for i in world.get_region("Waynehouse", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + for i in world.get_region("New Muldul", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + for i in world.get_region("New Muldul Vault", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + for i in world.get_region("Drill Castle", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + for i in world.get_region("Viewax", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + for i in world.get_region("TV Island", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) + for i in world.get_region("Sage Labyrinth", player).entrances: + add_rule(i, lambda state: state._hylics2_has_airship(player)) \ No newline at end of file diff --git a/worlds/hylics2/__init__.py b/worlds/hylics2/__init__.py new file mode 100644 index 00000000..b429eb6a --- /dev/null +++ b/worlds/hylics2/__init__.py @@ -0,0 +1,246 @@ +import random +from typing import Dict, Any +from BaseClasses import Region, Entrance, Location, Item, Tutorial, ItemClassification, RegionType +from worlds.generic.Rules import set_rule +from ..AutoWorld import World, WebWorld +from . import Items, Locations, Options, Rules, Exits + + +class Hylics2Web(WebWorld): + theme = "ocean" + tutorials = [Tutorial( + "Multiworld Setup Guide", + "A guide to settings up the Hylics 2 randomizer connected to an Archipelago Multiworld", + "English", + "setup_en.md", + "setup/en", + ["TRPG"] + )] + + +class Hylics2World(World): + """ + Hylics 2 is a surreal and unusual RPG, with a bizarre yet unique visual style. Play as Wayne, + travel the world, and gather your allies to defeat the nefarious Gibby in his Hylemxylem! + """ + game: str = "Hylics 2" + web = Hylics2Web() + + all_items = {**Items.item_table, **Items.gesture_item_table, **Items.party_item_table, + **Items.medallion_item_table} + all_locations = {**Locations.location_table, **Locations.tv_location_table, **Locations.party_location_table, + **Locations.medallion_location_table} + + item_name_to_id = {data["name"]: item_id for item_id, data in all_items.items()} + location_name_to_id = {data["name"]: loc_id for loc_id, data in all_locations.items()} + option_definitions = Options.hylics2_options + + topology_present: bool = True + remote_items: bool = True + remote_start_inventory: bool = True + + data_version: 1 + + start_location = "Waynehouse" + + + def set_rules(self): + Rules.set_rules(self) + + + def create_item(self, name: str) -> "Hylics2Item": + item_id: int = self.item_name_to_id[name] + + return Hylics2Item(name, self.all_items[item_id]["classification"], item_id, player=self.player) + + + def add_item(self, name: str, classification: ItemClassification, code: int) -> "Item": + return Hylics2Item(name, classification, code, self.player) + + + def create_event(self, event: str): + return Hylics2Item(event, ItemClassification.progression_skip_balancing, None, self.player) + + + # set random starting location if option is enabled + def generate_early(self): + if self.world.random_start[self.player]: + i = self.world.random.randint(0, 3) + if i == 0: + self.start_location = "Waynehouse" + elif i == 1: + self.start_location = "Viewax's Edifice" + elif i == 2: + self.start_location = "TV Island" + elif i == 3: + self.start_location = "Shield Facility" + + def generate_basic(self): + # create location for beating the game and place Victory event there + loc = Location(self.player, "Defeat Gibby", None, self.world.get_region("Hylemxylem", self.player)) + loc.place_locked_item(self.create_event("Victory")) + set_rule(loc, lambda state: state._hylics2_has_upper_chamber_key(self.player) + and state._hylics2_has_vessel_room_key(self.player)) + self.world.get_region("Hylemxylem", self.player).locations.append(loc) + self.world.completion_condition[self.player] = lambda state: state.has("Victory", self.player) + + # create item pool + pool = [] + + # add regular items + for i, data in Items.item_table.items(): + if data["count"] > 0: + for j in range(data["count"]): + pool.append(self.add_item(data["name"], data["classification"], i)) + + # add party members if option is enabled + if self.world.party_shuffle[self.player]: + for i, data in Items.party_item_table.items(): + pool.append(self.add_item(data["name"], data["classification"], i)) + + # handle gesture shuffle options + if self.world.gesture_shuffle[self.player] == 2: # vanilla locations + gestures = Items.gesture_item_table + self.world.get_location("Waynehouse: TV", self.player)\ + .place_locked_item(self.add_item(gestures[200678]["name"], gestures[200678]["classification"], 200678)) + self.world.get_location("Afterlife: TV", self.player)\ + .place_locked_item(self.add_item(gestures[200683]["name"], gestures[200683]["classification"], 200683)) + self.world.get_location("New Muldul: TV", self.player)\ + .place_locked_item(self.add_item(gestures[200679]["name"], gestures[200679]["classification"], 200679)) + self.world.get_location("Viewax's Edifice: TV", self.player)\ + .place_locked_item(self.add_item(gestures[200680]["name"], gestures[200680]["classification"], 200680)) + self.world.get_location("TV Island: TV", self.player)\ + .place_locked_item(self.add_item(gestures[200681]["name"], gestures[200681]["classification"], 200681)) + self.world.get_location("Juice Ranch: TV", self.player)\ + .place_locked_item(self.add_item(gestures[200682]["name"], gestures[200682]["classification"], 200682)) + self.world.get_location("Foglast: TV", self.player)\ + .place_locked_item(self.add_item(gestures[200684]["name"], gestures[200684]["classification"], 200684)) + self.world.get_location("Drill Castle: TV", self.player)\ + .place_locked_item(self.add_item(gestures[200688]["name"], gestures[200688]["classification"], 200688)) + self.world.get_location("Sage Airship: TV", self.player)\ + .place_locked_item(self.add_item(gestures[200685]["name"], gestures[200685]["classification"], 200685)) + + elif self.world.gesture_shuffle[self.player] == 1: # TVs only + gestures = list(Items.gesture_item_table.items()) + tvs = list(Locations.tv_location_table.items()) + + # if Extra Items in Logic is enabled place CHARGE UP first and make sure it doesn't get + # placed at Sage Airship: TV + if self.world.extra_items_in_logic[self.player]: + tv = self.world.random.choice(tvs) + gest = gestures.index((200681, Items.gesture_item_table[200681])) + while tv[1]["name"] == "Sage Airship: TV": + tv = self.world.random.choice(tvs) + self.world.get_location(tv[1]["name"], self.player)\ + .place_locked_item(self.add_item(gestures[gest][1]["name"], gestures[gest][1]["classification"], + gestures[gest])) + gestures.remove(gestures[gest]) + tvs.remove(tv) + + for i in range(len(gestures)): + gest = self.world.random.choice(gestures) + tv = self.world.random.choice(tvs) + self.world.get_location(tv[1]["name"], self.player)\ + .place_locked_item(self.add_item(gest[1]["name"], gest[1]["classification"], gest[1])) + gestures.remove(gest) + tvs.remove(tv) + + else: # add gestures to pool like normal + for i, data in Items.gesture_item_table.items(): + pool.append(self.add_item(data["name"], data["classification"], i)) + + # add '10 Bones' items if medallion shuffle is enabled + if self.world.medallion_shuffle[self.player]: + for i, data in Items.medallion_item_table.items(): + for j in range(data["count"]): + pool.append(self.add_item(data["name"], data["classification"], i)) + + # add to world's pool + self.world.itempool += pool + + + def fill_slot_data(self) -> Dict[str, Any]: + slot_data: Dict[str, Any] = { + "party_shuffle": self.world.party_shuffle[self.player].value, + "medallion_shuffle": self.world.medallion_shuffle[self.player].value, + "random_start" : self.world.random_start[self.player].value, + "start_location" : self.start_location, + "death_link": self.world.death_link[self.player].value + } + return slot_data + + + def create_regions(self) -> None: + + region_table: Dict[int, Region] = { + 0: Region("Menu", RegionType.Generic, "Menu", self.player, self.world), + 1: Region("Afterlife", RegionType.Generic, "Afterlife", self.player, self.world), + 2: Region("Waynehouse", RegionType.Generic, "Waynehouse", self.player, self.world), + 3: Region("World", RegionType.Generic, "World", self.player, self.world), + 4: Region("New Muldul", RegionType.Generic, "New Muldul", self.player, self.world), + 5: Region("New Muldul Vault", RegionType.Generic, "New Muldul Vault", self.player, self.world), + 6: Region("Viewax", RegionType.Generic, "Viewax's Edifice", self.player, self.world), + 7: Region("Airship", RegionType.Generic, "Airship", self.player, self.world), + 8: Region("Arcade Island", RegionType.Generic, "Arcade Island", self.player, self.world), + 9: Region("TV Island", RegionType.Generic, "TV Island", self.player, self.world), + 10: Region("Juice Ranch", RegionType.Generic, "Juice Ranch", self.player, self.world), + 11: Region("Shield Facility", RegionType.Generic, "Shield Facility", self.player, self.world), + 12: Region("Worm Pod", RegionType.Generic, "Worm Pod", self.player, self.world), + 13: Region("Foglast", RegionType.Generic, "Foglast", self.player, self.world), + 14: Region("Drill Castle", RegionType.Generic, "Drill Castle", self.player, self.world), + 15: Region("Sage Labyrinth", RegionType.Generic, "Sage Labyrinth", self.player, self.world), + 16: Region("Sage Airship", RegionType.Generic, "Sage Airship", self.player, self.world), + 17: Region("Hylemxylem", RegionType.Generic, "Hylemxylem", self.player, self.world) + } + + # create regions from table + for i, reg in region_table.items(): + self.world.regions.append(reg) + # get all exits per region + for j, exits in Exits.region_exit_table.items(): + if j == i: + for k in exits: + # create entrance and connect it to parent and destination regions + ent = Entrance(self.player, k, reg) + reg.exits.append(ent) + if k == "New Game" and self.world.random_start[self.player]: + if self.start_location == "Waynehouse": + ent.connect(region_table[2]) + elif self.start_location == "Viewax's Edifice": + ent.connect(region_table[6]) + elif self.start_location == "TV Island": + ent.connect(region_table[9]) + elif self.start_location == "Shield Facility": + ent.connect(region_table[11]) + else: + for name, num in Exits.exit_lookup_table.items(): + if k == name: + ent.connect(region_table[num]) + + # add regular locations + for i, data in Locations.location_table.items(): + region_table[data["region"]].locations\ + .append(Hylics2Location(self.player, data["name"], i, region_table[data["region"]])) + for i, data in Locations.tv_location_table.items(): + region_table[data["region"]].locations\ + .append(Hylics2Location(self.player, data["name"], i, region_table[data["region"]])) + + # add party member locations if option is enabled + if self.world.party_shuffle[self.player]: + for i, data in Locations.party_location_table.items(): + region_table[data["region"]].locations\ + .append(Hylics2Location(self.player, data["name"], i, region_table[data["region"]])) + + # add medallion locations if option is enabled + if self.world.medallion_shuffle[self.player]: + for i, data in Locations.medallion_location_table.items(): + region_table[data["region"]].locations\ + .append(Hylics2Location(self.player, data["name"], i, region_table[data["region"]])) + + +class Hylics2Location(Location): + game: str = "Hylics 2" + + +class Hylics2Item(Item): + game: str = "Hylics 2" \ No newline at end of file diff --git a/worlds/hylics2/docs/en_Hylics 2.md b/worlds/hylics2/docs/en_Hylics 2.md new file mode 100644 index 00000000..cb201a52 --- /dev/null +++ b/worlds/hylics2/docs/en_Hylics 2.md @@ -0,0 +1,17 @@ +# Hylics 2 + +## Where is the settings page? + +The [player settings page for this game](../player-settings) contains all the options you need to configure and export a config file. + +## What does randomization do to this game? + +In Hylics 2, all unique items, equipment and skills are randomized. This includes items in chests, items that are freely standing in the world, items recieved from talking to certain characters, gestures learned from TVs, and so on. Items recieved from completing battles are not randomized, with the exception of the Jail Key recieved from defeating Viewax. + +## What Hylics 2 items can appear in other players' worlds? + +Consumable items, key items, gloves, accessories, and gestures can appear in other players' worlds. + +## What does another world's item look like in Hylics 2? + +All items retain their original appearance. You won't know if an item belongs to another player until you collect it. \ No newline at end of file diff --git a/worlds/hylics2/docs/setup_en.md b/worlds/hylics2/docs/setup_en.md new file mode 100644 index 00000000..1e1ac497 --- /dev/null +++ b/worlds/hylics2/docs/setup_en.md @@ -0,0 +1,35 @@ +# Hylics 2 Randomizer Setup Guide + +## Required Software + +- Hylics 2 from: [Steam](https://store.steampowered.com/app/1286710/Hylics_2/) or [itch.io](https://mason-lindroth.itch.io/hylics-2) +- BepInEx from: [GitHub](https://github.com/BepInEx/BepInEx/releases) +- Archipelago Mod for Hylics 2 from: [GitHub](https://github.com/TRPG0/ArchipelagoHylics2) + +## Instructions (Windows) + +1. Download and install BepInEx 5 (32-bit, version 5.4.20 or newer) to your Hylics 2 root folder. *Do not use any pre-release versions of BepInEx 6.* + +2. Start Hylics 2 once so that BepInEx can create its required configuration files. + +3. Download the latest version of ArchipelagoHylics2 from the [Releases](https://github.com/TRPG0/ArchipelagoHylics2/releases) page and extract the contents of the zip file into `BepInEx\plugins`. + +4. Start Hylics 2 again. To verify that the mod is working, begin a new game or load a save file. + +## Connecting + +To connect to an Archipelago server, open the in-game console (default key: `/`) and use the command `/connect [address:port] [name] [password]`. The port and password are both optional - if no port is provided then the default port of 38281 is used. +**Make sure that you have connected to a server at least once before attempting to check any locations.** + +## Other Commands + +There are a few additional commands that can be used while playing Hylics 2 randomizer: + +- `/disconnect` - Disconnect from an Archipelago server. +- `/popups` - Enables or disables in-game messages when an item is found or recieved. +- `/airship` - Resummons the airship at the dock above New Muldul and teleports Wayne to it, in case the player gets stuck. Player must have the DOCK KEY to use this command. +- `/respawn` - Moves Wayne back to the spawn position of the current area in case you get stuck. `/respawn home` will teleport Wayne back to his original starting position. +- `/checked [region]` - States how many locations have been checked in a given region. If no region is given, then the player's location will be used. +- `/deathlink` - Enables or disables DeathLink. +- `/help [command]` - Lists a command, it's description, and it's required arguments (if any). If no command is given, all commands will be displayed. +- `![command]` - Entering any command with an `!` at the beginning allows for remotely sending commands to the server. \ No newline at end of file