mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
Rogue Legacy: World folder clean up and generation improvements. (#1148)
* Minor cleanup and renaming of some files/functions. * Rename `LegacyWorld` and `LegacyWeb` to RLWorld and RLWeb. * Undo accidental change to comment. * Undo accidental change to comment. * Restructure Items.py format and combine all tables into one. * Restructure Locations.py format and combine all tables into one. * Split boss event items into separate boss entries. * Remove definitions folder. * Reformatted __init__.py for Rogue Legacy. * Allow fairy chests to be disabled. * Add working prefill logic for early vendors. * Re-introduce Early Architect setting. * Revamped rules and regions and can now generate games. * Fix normal vendors breaking everything. * Fix early vendor logic and add fairy chest logic to require Dragons or Enchantress + runes. * Fix issue with duplicate items being created. * Move event placement into __init__.py and fix duplicate Vendors. * Tweak weights and spacing. * Update documentation and include bug report link. * Fix relative link for template file. * Increase amount of chest locations in `location_table`. * Correct a refactor rename gone wrong. * Remove unused reference in imports. * Tweak mistake in boss name in place_events. * English is hard. * Tweak some lines in __init__.py to use `.settings()` method. * Add unique id tests for Rogue Legacy. IDs are mixed around, so let's try to avoid accidentally using the same identifier twice. * Fix typo in doc. * Simplify `fill_slot_data`. * Change prefix on `_place_events` to maintain convention. * Remove items that are **not** progression from rules.
This commit is contained in:
@@ -1,72 +1,125 @@
|
||||
import typing
|
||||
from typing import Dict, List, NamedTuple, Optional
|
||||
|
||||
from BaseClasses import MultiWorld, Region, RegionType, Entrance, ItemClassification
|
||||
from .Items import LegacyItem
|
||||
from .Locations import LegacyLocation, diary_location_table, location_table, base_location_table
|
||||
from .Names import LocationName, ItemName
|
||||
|
||||
prog = ItemClassification.progression
|
||||
from BaseClasses import MultiWorld, Region, RegionType, Entrance
|
||||
from .Items import RLItem
|
||||
from .Locations import RLLocation, location_table, get_locations_by_category
|
||||
|
||||
|
||||
def create_regions(world, player: int):
|
||||
class RLRegionData(NamedTuple):
|
||||
locations: Optional[List[str]]
|
||||
exits: Optional[List[str]]
|
||||
|
||||
locations: typing.List[str] = []
|
||||
|
||||
# Add required locations.
|
||||
locations += [location for location in base_location_table]
|
||||
locations += [location for location in diary_location_table]
|
||||
def create_regions(world: MultiWorld, player: int):
|
||||
regions: Dict[str, RLRegionData] = {
|
||||
"Menu": RLRegionData(None, ["Castle Hamson"]),
|
||||
"The Manor": RLRegionData([], []),
|
||||
"Castle Hamson": RLRegionData([], ["Forest Abkhazia",
|
||||
"The Maya",
|
||||
"Land of Darkness",
|
||||
"The Fountain Room",
|
||||
"The Manor"]),
|
||||
"Forest Abkhazia": RLRegionData([], []),
|
||||
"The Maya": RLRegionData([], []),
|
||||
"Land of Darkness": RLRegionData([], []),
|
||||
"The Fountain Room": RLRegionData([], None),
|
||||
}
|
||||
|
||||
# Add chests per settings.
|
||||
if world.universal_fairy_chests[player]:
|
||||
fairies = int(world.fairy_chests_per_zone[player]) * 4
|
||||
for i in range(0, fairies):
|
||||
locations += [f"Fairy Chest {i + 1}"]
|
||||
else:
|
||||
fairies = int(world.fairy_chests_per_zone[player])
|
||||
for i in range(0, fairies):
|
||||
locations += [f"{LocationName.castle} - Fairy Chest {i + 1}"]
|
||||
locations += [f"{LocationName.garden} - Fairy Chest {i + 1}"]
|
||||
locations += [f"{LocationName.tower} - Fairy Chest {i + 1}"]
|
||||
locations += [f"{LocationName.dungeon} - Fairy Chest {i + 1}"]
|
||||
# Diaries
|
||||
for diary in range(0, 25):
|
||||
region: str
|
||||
if 0 <= diary < 6:
|
||||
region = "Castle Hamson"
|
||||
elif 6 <= diary < 12:
|
||||
region = "Forest Abkhazia"
|
||||
elif 12 <= diary < 18:
|
||||
region = "The Maya"
|
||||
elif 18 <= diary < 24:
|
||||
region = "Land of Darkness"
|
||||
else:
|
||||
region = "The Fountain Room"
|
||||
|
||||
if world.universal_chests[player]:
|
||||
chests = int(world.chests_per_zone[player]) * 4
|
||||
for i in range(0, chests):
|
||||
locations += [f"Chest {i + 1}"]
|
||||
else:
|
||||
chests = int(world.chests_per_zone[player])
|
||||
for i in range(0, chests):
|
||||
locations += [f"{LocationName.castle} - Chest {i + 1}"]
|
||||
locations += [f"{LocationName.garden} - Chest {i + 1}"]
|
||||
locations += [f"{LocationName.tower} - Chest {i + 1}"]
|
||||
locations += [f"{LocationName.dungeon} - Chest {i + 1}"]
|
||||
regions[region].locations.append(f"Diary {diary + 1}")
|
||||
|
||||
# Manor & Special
|
||||
for manor in get_locations_by_category("Manor").keys():
|
||||
regions["The Manor"].locations.append(manor)
|
||||
for special in get_locations_by_category("Special").keys():
|
||||
regions["Castle Hamson"].locations.append(special)
|
||||
|
||||
# Boss Rewards
|
||||
regions["Castle Hamson"].locations.append("Castle Hamson Boss Reward")
|
||||
regions["Forest Abkhazia"].locations.append("Forest Abkhazia Boss Reward")
|
||||
regions["The Maya"].locations.append("The Maya Boss Reward")
|
||||
regions["Land of Darkness"].locations.append("Land of Darkness Boss Reward")
|
||||
|
||||
# Events
|
||||
regions["Castle Hamson"].locations.append("Castle Hamson Boss Room")
|
||||
regions["Forest Abkhazia"].locations.append("Forest Abkhazia Boss Room")
|
||||
regions["The Maya"].locations.append("The Maya Boss Room")
|
||||
regions["Land of Darkness"].locations.append("Land of Darkness Boss Room")
|
||||
regions["The Fountain Room"].locations.append("Fountain Room")
|
||||
|
||||
# Chests
|
||||
chests = int(world.chests_per_zone[player])
|
||||
for i in range(0, chests):
|
||||
if world.universal_chests[player]:
|
||||
regions["Castle Hamson"].locations.append(f"Chest {i + 1}")
|
||||
regions["Forest Abkhazia"].locations.append(f"Chest {i + 1 + chests}")
|
||||
regions["The Maya"].locations.append(f"Chest {i + 1 + (chests * 2)}")
|
||||
regions["Land of Darkness"].locations.append(f"Chest {i + 1 + (chests * 3)}")
|
||||
else:
|
||||
regions["Castle Hamson"].locations.append(f"Castle Hamson - Chest {i + 1}")
|
||||
regions["Forest Abkhazia"].locations.append(f"Forest Abkhazia - Chest {i + 1}")
|
||||
regions["The Maya"].locations.append(f"The Maya - Chest {i + 1}")
|
||||
regions["Land of Darkness"].locations.append(f"Land of Darkness - Chest {i + 1}")
|
||||
|
||||
# Fairy Chests
|
||||
chests = int(world.fairy_chests_per_zone[player])
|
||||
for i in range(0, chests):
|
||||
if world.universal_fairy_chests[player]:
|
||||
regions["Castle Hamson"].locations.append(f"Fairy Chest {i + 1}")
|
||||
regions["Forest Abkhazia"].locations.append(f"Fairy Chest {i + 1 + chests}")
|
||||
regions["The Maya"].locations.append(f"Fairy Chest {i + 1 + (chests * 2)}")
|
||||
regions["Land of Darkness"].locations.append(f"Fairy Chest {i + 1 + (chests * 3)}")
|
||||
else:
|
||||
regions["Castle Hamson"].locations.append(f"Castle Hamson - Fairy Chest {i + 1}")
|
||||
regions["Forest Abkhazia"].locations.append(f"Forest Abkhazia - Fairy Chest {i + 1}")
|
||||
regions["The Maya"].locations.append(f"The Maya - Fairy Chest {i + 1}")
|
||||
regions["Land of Darkness"].locations.append(f"Land of Darkness - Fairy Chest {i + 1}")
|
||||
|
||||
# Set up the regions correctly.
|
||||
world.regions += [
|
||||
create_region(world, player, "Menu", None, [LocationName.outside]),
|
||||
create_region(world, player, LocationName.castle, locations),
|
||||
]
|
||||
for name, data in regions.items():
|
||||
world.regions.append(create_region(world, player, name, data.locations, data.exits))
|
||||
|
||||
# Connect entrances and set up events.
|
||||
world.get_entrance(LocationName.outside, player).connect(world.get_region(LocationName.castle, player))
|
||||
world.get_location(LocationName.castle, player).place_locked_item(LegacyItem(ItemName.boss_castle, prog, None, player))
|
||||
world.get_location(LocationName.garden, player).place_locked_item(LegacyItem(ItemName.boss_forest, prog, None, player))
|
||||
world.get_location(LocationName.tower, player).place_locked_item(LegacyItem(ItemName.boss_tower, prog, None, player))
|
||||
world.get_location(LocationName.dungeon, player).place_locked_item(LegacyItem(ItemName.boss_dungeon, prog, None, player))
|
||||
world.get_location(LocationName.fountain, player).place_locked_item(LegacyItem(ItemName.boss_fountain, prog, None, player))
|
||||
world.get_entrance("Castle Hamson", player).connect(world.get_region("Castle Hamson", player))
|
||||
world.get_entrance("The Manor", player).connect(world.get_region("The Manor", player))
|
||||
world.get_entrance("Forest Abkhazia", player).connect(world.get_region("Forest Abkhazia", player))
|
||||
world.get_entrance("The Maya", player).connect(world.get_region("The Maya", player))
|
||||
world.get_entrance("Land of Darkness", player).connect(world.get_region("Land of Darkness", player))
|
||||
world.get_entrance("The Fountain Room", player).connect(world.get_region("The Fountain Room", player))
|
||||
|
||||
|
||||
def create_region(world: MultiWorld, player: int, name: str, locations=None, exits=None):
|
||||
# Shamelessly stolen from the ROR2 definition, lol
|
||||
ret = Region(name, RegionType.Generic, name, player)
|
||||
ret.world = world
|
||||
if locations:
|
||||
for location in locations:
|
||||
loc_id = location_table.get(location, 0)
|
||||
location = LegacyLocation(player, location, loc_id, ret)
|
||||
for loc_name in locations:
|
||||
loc_data = location_table.get(loc_name)
|
||||
location = RLLocation(player, loc_name, loc_data.code if loc_data else None, ret)
|
||||
|
||||
# Special rule handling for fairy chests.
|
||||
if "Fairy" in loc_name:
|
||||
location.access_rule = lambda state: state.has("Dragons", player) or (
|
||||
state.has("Enchantress", player) and (
|
||||
state.has("Vault Runes", player) or
|
||||
state.has("Sprint Runes", player) or
|
||||
state.has("Sky Runes", player)))
|
||||
ret.locations.append(location)
|
||||
if exits:
|
||||
for exit in exits:
|
||||
ret.exits.append(Entrance(player, exit, ret))
|
||||
|
||||
entrance = Entrance(player, exit, ret)
|
||||
ret.exits.append(entrance)
|
||||
return ret
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user