Files
Archipelago/worlds/gl/Regions.py
T
jamesbrq f110a7efbc Gauntlet Legends: Implement New Game (#3499)
* Update GauntletLegendsClient.py

* Continuation of obelisk update

* APPP Implementation Groundwork.

* Continuation of APPP Implementation

* Create Pain.asm

* ROM verification modified since crc32 hash can no longer be calculated.

* Initial upload of barrel/chest locations.

* Finished adding and naming all chests/barrels.

* Continued locations.

* Added new yaml options

* Work on mirror shards

* Python 3.8 compatibility

* Finalized location names. Fixed lambda bug.

* v1.0

* Removed excess Docs and Changed item counts.

* Update Archipelago Unittests.run.xml

* Started working on Docs.

* Updated item arrays for client

* Fix client bugs

* Flake8 fixes + Yaml fix

* Update speed boots

* v1.1

* Update GauntletLegendsClient.py

* Update GauntletLegendsClient.py

* Update GauntletLegendsClient.py

* Update GauntletLegendsClient.py

* v1.0.4

* Initial Ruff format

* Formatting part-2

* More formatting + Doc changes

* Updated Docs

* Move client to root

* Update Client Name

* Make Imports Relative

* Add new yaml options + rename obelisks

* v1.1 Initial Upload

* v1.1.0 + some additions

* Client Update

* Client Updates

* pre-v1.1.1

* Update GauntletLegendsClient.py

* pre-1.2

* 1.2.0

* v1.2.1

* Client fixes

* v1.3.0

* v1.4.0

* v1.4.1

* Merged Changes

* Experimental

* pre-v1.5.0

* Changes

* v1.5.0

* Update GauntletLegendsClient.py

* Death Update

* pre v1.5.1

* Obelisk rule changes

* pre-v1.5.1

* Update GauntletLegendsClient.py

* v1.5.1

* v1.5.1

* Update GauntletLegendsClient.py

* Small fix

* Update GauntletLegendsClient.py

* v1.5.2

* pre-v1.6.0

* pre-v1.6.0

* v1.6.0

* Update

* Update GauntletLegendsClient.py

* Test

* pre-v1.6.0

* Client Updtaes

* Update GauntletLegendsClient.py

* Update GauntletLegendsClient.py

* Update GauntletLegendsClient.py

* Update Rom.py

* Update GauntletLegendsClient.py

* Update Rom.py

* Added Logging on stage enter

* v1.6.2

* v1.6.2

* Update Rom.py

* Update GauntletLegendsClient.py

* v1.6.3

* Small Update

* Update GauntletLegendsClient.py

* Update GauntletLegendsClient.py

* Update GauntletLegendsClient.py

* Changes ready for review

* Update Rom.py

* Remove root client

* Update inno_setup.iss

* Update client

* Initial Review Refactor

* Update Arrays.py

* Review refactor

* Update __init__.py

* Small tweaks after test generations

* Update GauntletLegendsClient.py

* Implement new check_locations() function

* Add name for Skorn to level_names Dict

* Fix for #4671

* Update __init__.py

* Adjust item frequency + Place 50% of filler as local

* Oops I modified the itempool after create_items teehee

* Update __init__.py

* Check MD5 hash before patching ROM

* Update __init__.py

* Fix get_filler_item_name()

* Update MD5 check to built in method in FilePath

* Update Rom.py

* Update worlds/gl/Rom.py

Co-authored-by: qwint <qwint.42@gmail.com>

* WIP Generation fixes

* v1.7.1

* Update Archipelago Unittests.run.xml

* 0.7.2

* Update GauntletLegendsClient.py

* Review Edits

* Update World description

* Fuzz fixes

* Update GauntletLegendsClient.py

* Make static data immutable

* Update option comparisons since no longer a Choice

* Update worlds/gl/Rom.py

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

* Update __init__.py

* Initial Update commit

* Progress

* Remove un-used import + Add manifest

* Add missing docstring for client command

* Progress

* pre-v2.0.0-BETA

* Updates

* Progress

* Working Generations

* Working IN-Game

* v2.0.0-BETA

* Create archipelago.json

* v2.0.1

* v2.0.1 FINAL

* pre v2.0.2

* Delete report.json

* Cleanup

* pre v2.0.2

* v2.0.2

* PR Ready

* Update Items.py

* Delete fuzz.py

* Update Items.py

* Update GauntletLegendsClient.py

* Fix scouting disabled locations

* Client Updates

* v2.0.3

* Increment World Version

* Docstring + slot_data updates

* Option name update + Remove redundant option

* Code Cleanup

* Trenches is level 24

* Frequencies

* More cleanup and removal of stale code. MISSING BASEPATCH

* v2.1.0

* Minor enemy changes

* Small fix

* Update Rom.py

* v2.1.1

* Small fixes

* Update basepatch.bsdiff4

* Update GauntletLegendsClient.py

* Socket error clarity

* Delete settings.local.json

* Update GauntletLegendsClient.py

* v2.1.2 fixes

* Boss portal fix

* Small client fix + Item Frequencies

* Update archipelago.json

* Fix for games playing with max difficulty lower than 4 not sending locations

* Update archipelago.json

* v2.1.5

* Fix for Chimera's lair mirror shard

* Update archipelago.json

* Mod Re-Base + Queue limits + Item Receiving fixes

* Options cleanup and newlines for some files

* Include v2.x features in docs

* Make sure players has at least 1 item

* v2.1.6

* Update archipelago.json

* Review Edits + Client Tweaks

---------

Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2026-07-11 19:26:27 +02:00

138 lines
7.5 KiB
Python

import typing
from typing import Optional, Callable
from BaseClasses import Region
from .Data import excluded_levels
from .Locations import GLLocation, LocationData, get_locations_by_tags
if typing.TYPE_CHECKING:
from . import GauntletLegendsWorld
def create_regions(world: "GauntletLegendsWorld"):
world.multiworld.regions.append(Region("Menu", world.player, world.multiworld))
regions_dict = get_regions_dict()
for name, locations in regions_dict.items():
if name not in [level for region, levels in excluded_levels.items() if region in world.excluded_regions for level in levels]:
create_region(world, name, locations)
else:
world.disabled_locations.update([loc.name for loc in locations if loc.name not in world.disabled_locations])
def get_regions_dict() -> dict[str, list[LocationData]]:
"""
Returns a dictionary mapping region names to their corresponding location data lists.
"""
return {
"Valley of Fire": get_locations_by_tags("valley_of_fire"),
"Dagger Peak": get_locations_by_tags("dagger_peak"),
"Cliffs of Desolation": get_locations_by_tags("cliffs_of_desolation"),
"Lost Cave": get_locations_by_tags("lost_cave"),
"Volcanic Caverns": get_locations_by_tags("volcanic_cavern"),
"Dragon's Lair": get_locations_by_tags("dragons_lair"),
"Castle Courtyard": get_locations_by_tags("castle_courtyard"),
"Dungeon of Torment": get_locations_by_tags("dungeon_of_torment"),
"Tower Armory": get_locations_by_tags("tower_armory"),
"Castle Treasury": get_locations_by_tags("castle_treasury"),
"Chimera's Keep": get_locations_by_tags("chimeras_keep"),
"Poisoned Fields": get_locations_by_tags("poisoned_fields"),
"Haunted Cemetery": get_locations_by_tags("haunted_cemetery"),
"Venomous Spire": get_locations_by_tags("venomous_spire"),
"Toxic Air Ship": get_locations_by_tags("toxic_air_ship"),
"Vat of the Plague Fiend": get_locations_by_tags("plague_fiend"),
"Arctic Docks": get_locations_by_tags("arctic_docks"),
"Frozen Camp": get_locations_by_tags("frozen_camp"),
"Crystal Mine": get_locations_by_tags("crystal_mine"),
"Erupting Fissure": get_locations_by_tags("erupting_fissure"),
"Yeti's Cavern": get_locations_by_tags("yeti"),
"Desecrated Temple": get_locations_by_tags("desecrated_temple"),
"Altar of Skorne": get_locations_by_tags("altar_of_skorne"),
"Battle Trenches": get_locations_by_tags("battle_trenches"),
"Fortified Towers": get_locations_by_tags("fortified_towers"),
"Infernal Fortress": get_locations_by_tags("infernal_fortress"),
"Gates of the Underworld": get_locations_by_tags("gates_of_the_underworld")
}
def connect_regions(world: "GauntletLegendsWorld"):
names: dict[str, int] = {}
connect(world, names, "Menu", "Valley of Fire")
connect(world, names, "Menu", "Dagger Peak", _portal_helper("Portal to Dagger Peak", world))
connect(world, names, "Menu", "Cliffs of Desolation", _portal_helper("Portal to Cliffs of Desolation", world))
connect(world, names, "Menu", "Lost Cave", _portal_helper("Portal to Lost Cave", world))
connect(world, names, "Menu", "Volcanic Caverns", _portal_helper("Portal to Volcanic Caverns", world))
connect(world, names, "Menu", "Dragon's Lair", _portal_helper("Portal to Dragon's Lair", world))
connect(world, names, "Menu", "Castle Courtyard",
lambda state: state.has("Valley of Fire Obelisk", world.player)
and state.has("Dagger Peak Obelisk", world.player)
and state.has("Cliffs of Desolation Obelisk", world.player)
)
connect(world, names, "Castle Courtyard", "Dungeon of Torment", _portal_helper("Portal to Dungeon of Torment", world))
connect(world, names, "Castle Courtyard", "Tower Armory", _portal_helper("Portal to Tower Armory", world))
connect(world, names, "Castle Courtyard", "Castle Treasury", _portal_helper("Portal to Castle Treasury", world))
connect(world, names, "Castle Courtyard", "Chimera's Keep", _portal_helper("Portal to Chimera's Keep", world))
connect(world, names, "Menu", "Poisoned Fields",
lambda state: state.has("Castle Courtyard Obelisk", world.player)
and state.has("Dungeon of Torment Obelisk", world.player)
)
connect(world, names, "Poisoned Fields", "Haunted Cemetery", _portal_helper("Portal to Haunted Cemetery", world))
connect(world, names, "Poisoned Fields", "Venomous Spire", _portal_helper("Portal to Venomous Spire", world))
connect(world, names, "Poisoned Fields", "Toxic Air Ship", _portal_helper("Portal to Toxic Air Ship", world))
connect(world, names, "Toxic Air Ship", "Vat of the Plague Fiend", _portal_helper("Portal to Vat of the Plague Fiend", world))
connect(world, names, "Menu", "Arctic Docks",
lambda state: state.has("Poisoned Fields Obelisk", world.player)
and state.has("Haunted Cemetery Obelisk", world.player)
)
connect(world, names, "Arctic Docks", "Frozen Camp", _portal_helper("Portal to Frozen Camp", world))
connect(world, names, "Arctic Docks", "Crystal Mine", _portal_helper("Portal to Crystal Mine", world))
connect(world, names, "Arctic Docks", "Erupting Fissure", _portal_helper("Portal to Erupting Fissure", world))
connect(world, names, "Erupting Fissure", "Yeti's Cavern", _portal_helper("Portal to Yeti's Cavern", world))
connect(world, names, "Menu", "Desecrated Temple",
lambda state: state.has("Dragon Mirror Shard", world.player)
and state.has("Chimera Mirror Shard", world.player)
and state.has("Plague Fiend Mirror Shard", world.player)
and state.has("Yeti Mirror Shard", world.player)
)
connect(world, names, "Desecrated Temple", "Altar of Skorne")
connect(world, names, "Desecrated Temple", "Battle Trenches")
connect(world, names, "Desecrated Temple", "Fortified Towers", _portal_helper("Portal to Fortified Towers", world))
connect(world, names, "Desecrated Temple", "Infernal Fortress", _portal_helper("Portal to Infernal Fortress", world))
connect(world, names, "Menu", "Gates of the Underworld",
lambda state: state.has("stones", world.player, 13)
)
def _portal_helper(item: str, world: "GauntletLegendsWorld") -> Callable | None:
if world.options.portals.value:
return lambda state: state.has(item, world.player)
return None
def create_region(world: "GauntletLegendsWorld", name: str, locations: list[LocationData]):
reg = Region(name, world.player, world.multiworld)
reg.add_locations({loc.name: loc.id for loc in locations if loc.name not in world.disabled_locations}, GLLocation)
world.multiworld.regions.append(reg)
def connect(world: "GauntletLegendsWorld",
used_names: dict[str, int],
source: str,
target: str,
rule: Optional[Callable] = None,
):
excluded_levels_ = [level for region, levels in excluded_levels.items() if region in world.excluded_regions for level in levels]
if source in excluded_levels_ or target in excluded_levels_:
return
source_region = world.multiworld.get_region(source, world.player)
target_region = world.multiworld.get_region(target, world.player)
if target not in used_names:
used_names[target] = 1
name = target
else:
used_names[target] += 1
name = target + (" " * used_names[target])
source_region.connect(target_region, name, rule)