mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
Adventure: implement new game (#1531)
Adds Adventure for the Atari 2600, NTSC version. New randomizer, not based on prior works. Somewhat atypical of current AP rom patch games; The generator does not require the adventure rom, but writes some data to an .apadvn APContainer file that the client uses along with a base bsdiff patch to generate a final rom file.
This commit is contained in:
214
worlds/adventure/Locations.py
Normal file
214
worlds/adventure/Locations.py
Normal file
@@ -0,0 +1,214 @@
|
||||
from BaseClasses import Location
|
||||
|
||||
base_location_id = 118000000
|
||||
|
||||
|
||||
class AdventureLocation(Location):
|
||||
game: str = "Adventure"
|
||||
|
||||
|
||||
class WorldPosition:
|
||||
room_id: int
|
||||
room_x: int
|
||||
room_y: int
|
||||
|
||||
def __init__(self, room_id: int, room_x: int = None, room_y: int = None):
|
||||
self.room_id = room_id
|
||||
self.room_x = room_x
|
||||
self.room_y = room_y
|
||||
|
||||
def get_position(self, random):
|
||||
if self.room_x is None or self.room_y is None:
|
||||
return random.choice(standard_positions)
|
||||
else:
|
||||
return self.room_x, self.room_y
|
||||
|
||||
|
||||
class LocationData:
|
||||
def __init__(self, region, name, location_id, world_positions: [WorldPosition] = None, event=False,
|
||||
needs_bat_logic: bool = False):
|
||||
self.region: str = region
|
||||
self.name: str = name
|
||||
self.world_positions: [WorldPosition] = world_positions
|
||||
self.room_id: int = None
|
||||
self.room_x: int = None
|
||||
self.room_y: int = None
|
||||
self.location_id: int = location_id
|
||||
if location_id is None:
|
||||
self.short_location_id: int = None
|
||||
self.location_id: int = None
|
||||
else:
|
||||
self.short_location_id: int = location_id
|
||||
self.location_id: int = location_id + base_location_id
|
||||
self.event: bool = event
|
||||
if world_positions is None and not event:
|
||||
self.room_id: int = self.short_location_id
|
||||
self.needs_bat_logic: int = needs_bat_logic
|
||||
self.local_item: int = None
|
||||
|
||||
def get_position(self, random):
|
||||
if self.world_positions is None or len(self.world_positions) == 0:
|
||||
if self.room_id is None:
|
||||
return None
|
||||
self.room_x, self.room_y = random.choice(standard_positions)
|
||||
if self.room_id is None:
|
||||
selected_pos = random.choice(self.world_positions)
|
||||
self.room_id = selected_pos.room_id
|
||||
self.room_x, self.room_y = selected_pos.get_position(random)
|
||||
return self.room_x, self.room_y
|
||||
|
||||
def get_room_id(self, random):
|
||||
if self.world_positions is None or len(self.world_positions) == 0:
|
||||
return None
|
||||
if self.room_id is None:
|
||||
selected_pos = random.choice(self.world_positions)
|
||||
self.room_id = selected_pos.room_id
|
||||
self.room_x, self.room_y = selected_pos.get_position(random)
|
||||
return self.room_id
|
||||
|
||||
|
||||
standard_positions = [
|
||||
(0x80, 0x20),
|
||||
(0x20, 0x20),
|
||||
(0x20, 0x40),
|
||||
(0x20, 0x40),
|
||||
(0x30, 0x20)
|
||||
]
|
||||
|
||||
|
||||
# Gives the most difficult region the dragon can reach and get stuck in from the provided room without the
|
||||
# player unlocking something for it
|
||||
def dragon_room_to_region(room: int) -> str:
|
||||
if room <= 0x11:
|
||||
return "Overworld"
|
||||
elif room <= 0x12:
|
||||
return "YellowCastle"
|
||||
elif room <= 0x16 or room == 0x1B:
|
||||
return "BlackCastle"
|
||||
elif room <= 0x1A:
|
||||
return "WhiteCastleVault"
|
||||
elif room <= 0x1D:
|
||||
return "Overworld"
|
||||
elif room <= 0x1E:
|
||||
return "CreditsRoom"
|
||||
|
||||
|
||||
def get_random_room_in_regions(regions: [str], random) -> int:
|
||||
possible_rooms = {}
|
||||
for locname in location_table:
|
||||
if location_table[locname].region in regions:
|
||||
room = location_table[locname].get_room_id(random)
|
||||
if room is not None:
|
||||
possible_rooms[room] = location_table[locname].room_id
|
||||
return random.choice(list(possible_rooms.keys()))
|
||||
|
||||
|
||||
location_table = {
|
||||
"Blue Labyrinth 0": LocationData("Overworld", "Blue Labyrinth 0", 0x4,
|
||||
[WorldPosition(0x4, 0x83, 0x47), # exit upper right
|
||||
WorldPosition(0x4, 0x12, 0x47), # exit upper left
|
||||
WorldPosition(0x4, 0x65, 0x20), # exit bottom right
|
||||
WorldPosition(0x4, 0x2A, 0x20), # exit bottom left
|
||||
WorldPosition(0x5, 0x4B, 0x60), # T room, top
|
||||
WorldPosition(0x5, 0x28, 0x1F), # T room, bottom left
|
||||
WorldPosition(0x5, 0x70, 0x1F), # T room, bottom right
|
||||
]),
|
||||
"Blue Labyrinth 1": LocationData("Overworld", "Blue Labyrinth 1", 0x6,
|
||||
[WorldPosition(0x6, 0x8C, 0x20), # final turn bottom right
|
||||
WorldPosition(0x6, 0x03, 0x20), # final turn bottom left
|
||||
WorldPosition(0x6, 0x4B, 0x30), # final turn center
|
||||
WorldPosition(0x7, 0x4B, 0x40), # straightaway center
|
||||
WorldPosition(0x8, 0x40, 0x40), # entrance middle loop
|
||||
WorldPosition(0x8, 0x4B, 0x60), # entrance upper loop
|
||||
WorldPosition(0x8, 0x8C, 0x5E), # entrance right loop
|
||||
]),
|
||||
"Catacombs": LocationData("Overworld", "Catacombs", 0x9,
|
||||
[WorldPosition(0x9, 0x49, 0x40),
|
||||
WorldPosition(0x9, 0x4b, 0x20),
|
||||
WorldPosition(0xA),
|
||||
WorldPosition(0xA),
|
||||
WorldPosition(0xB, 0x40, 0x40),
|
||||
WorldPosition(0xB, 0x22, 0x1f),
|
||||
WorldPosition(0xB, 0x70, 0x1f)]),
|
||||
"Adjacent to Catacombs": LocationData("Overworld", "Adjacent to Catacombs", 0xC,
|
||||
[WorldPosition(0xC),
|
||||
WorldPosition(0xD)]),
|
||||
"Southwest of Catacombs": LocationData("Overworld", "Southwest of Catacombs", 0xE),
|
||||
"White Castle Gate": LocationData("Overworld", "White Castle Gate", 0xF),
|
||||
"Black Castle Gate": LocationData("Overworld", "Black Castle Gate", 0x10),
|
||||
"Yellow Castle Gate": LocationData("Overworld", "Yellow Castle Gate", 0x11),
|
||||
"Inside Yellow Castle": LocationData("YellowCastle", "Inside Yellow Castle", 0x12),
|
||||
"Dungeon0": LocationData("BlackCastle", "Dungeon0", 0x13,
|
||||
[WorldPosition(0x13),
|
||||
WorldPosition(0x14)]),
|
||||
"Dungeon Vault": LocationData("BlackCastleVault", "Dungeon Vault", 0xB5,
|
||||
[WorldPosition(0x15, 0x46, 0x1B)],
|
||||
needs_bat_logic=True),
|
||||
"Dungeon1": LocationData("BlackCastle", "Dungeon1", 0x15,
|
||||
[WorldPosition(0x15),
|
||||
WorldPosition(0x16)]),
|
||||
"RedMaze0": LocationData("WhiteCastle", "RedMaze0", 0x17,
|
||||
[WorldPosition(0x17, 0x70, 0x40), # right side third room
|
||||
WorldPosition(0x17, 0x18, 0x40), # left side third room
|
||||
WorldPosition(0x18, 0x20, 0x40),
|
||||
WorldPosition(0x18, 0x1A, 0x3F), # left side second room
|
||||
WorldPosition(0x18, 0x70, 0x3F), # right side second room
|
||||
]),
|
||||
"Red Maze Vault Entrance": LocationData("WhiteCastlePreVaultPeek", "Red Maze Vault Entrance", 0xB7,
|
||||
[WorldPosition(0x17, 0x50, 0x60)],
|
||||
needs_bat_logic=True),
|
||||
"Red Maze Vault": LocationData("WhiteCastleVault", "Red Maze Vault", 0x19,
|
||||
[WorldPosition(0x19, 0x4E, 0x35)],
|
||||
needs_bat_logic=True),
|
||||
"RedMaze1": LocationData("WhiteCastle", "RedMaze1", 0x1A), # entrance
|
||||
"Black Castle Foyer": LocationData("BlackCastle", "Black Castle Foyer", 0x1B),
|
||||
"Northeast of Catacombs": LocationData("Overworld", "Northeast of Catacombs", 0x1C),
|
||||
"Southeast of Catacombs": LocationData("Overworld", "Southeast of Catacombs", 0x1D),
|
||||
"Credits Left Side": LocationData("CreditsRoom", "Credits Left Side", 0x1E,
|
||||
[WorldPosition(0x1E, 0x25, 0x50)]),
|
||||
"Credits Right Side": LocationData("CreditsRoomFarSide", "Credits Right Side", 0xBE,
|
||||
[WorldPosition(0x1E, 0x70, 0x40)],
|
||||
needs_bat_logic=True),
|
||||
"Chalice Home": LocationData("YellowCastle", "Chalice Home", None, event=True),
|
||||
"Slay Yorgle": LocationData("Varies", "Slay Yorgle", 0xD1, event=False),
|
||||
"Slay Grundle": LocationData("Varies", "Slay Grundle", 0xD2, event=False),
|
||||
"Slay Rhindle": LocationData("Varies", "Slay Rhindle", 0xD0, event=False),
|
||||
}
|
||||
|
||||
# the old location table, for reference
|
||||
location_table_old = {
|
||||
"Blue Labyrinth 0": LocationData("Overworld", "Blue Labyrinth 0", 0x4),
|
||||
"Blue Labyrinth 1": LocationData("Overworld", "Blue Labyrinth 1", 0x5),
|
||||
"Blue Labyrinth 2": LocationData("Overworld", "Blue Labyrinth 2", 0x6),
|
||||
"Blue Labyrinth 3": LocationData("Overworld", "Blue Labyrinth 3", 0x7),
|
||||
"Blue Labyrinth 4": LocationData("Overworld", "Blue Labyrinth 4", 0x8),
|
||||
"Catacombs0": LocationData("Overworld", "Catacombs0", 0x9),
|
||||
"Catacombs1": LocationData("Overworld", "Catacombs1", 0xA),
|
||||
"Catacombs2": LocationData("Overworld", "Catacombs2", 0xB),
|
||||
"East of Catacombs": LocationData("Overworld", "East of Catacombs", 0xC),
|
||||
"West of Catacombs": LocationData("Overworld", "West of Catacombs", 0xD),
|
||||
"Southwest of Catacombs": LocationData("Overworld", "Southwest of Catacombs", 0xE),
|
||||
"White Castle Gate": LocationData("Overworld", "White Castle Gate", 0xF),
|
||||
"Black Castle Gate": LocationData("Overworld", "Black Castle Gate", 0x10),
|
||||
"Yellow Castle Gate": LocationData("Overworld", "Yellow Castle Gate", 0x11),
|
||||
"Inside Yellow Castle": LocationData("YellowCastle", "Inside Yellow Castle", 0x12),
|
||||
"Dungeon0": LocationData("BlackCastle", "Dungeon0", 0x13),
|
||||
"Dungeon1": LocationData("BlackCastle", "Dungeon1", 0x14),
|
||||
"Dungeon Vault": LocationData("BlackCastleVault", "Dungeon Vault", 0x15,
|
||||
[WorldPosition(0xB5, 0x46, 0x1B)]),
|
||||
"Dungeon2": LocationData("BlackCastle", "Dungeon2", 0x15),
|
||||
"Dungeon3": LocationData("BlackCastle", "Dungeon3", 0x16),
|
||||
"RedMaze0": LocationData("WhiteCastle", "RedMaze0", 0x17, [WorldPosition(0x17, 0x70, 0x40)]),
|
||||
"RedMaze1": LocationData("WhiteCastle", "RedMaze1", 0x18, [WorldPosition(0x18, 0x20, 0x40)]),
|
||||
"Red Maze Vault Entrance": LocationData("WhiteCastlePreVaultPeek", "Red Maze Vault Entrance",
|
||||
0x17, [WorldPosition(0xB7, 0x50, 0x60)]),
|
||||
"Red Maze Vault": LocationData("WhiteCastleVault", "Red Maze Vault", 0x19, [WorldPosition(0x19, 0x4E, 0x35)]),
|
||||
"RedMaze3": LocationData("WhiteCastle", "RedMaze3", 0x1A),
|
||||
"Black Castle Foyer": LocationData("BlackCastle", "Black Castle Foyer", 0x1B),
|
||||
"Northeast of Catacombs": LocationData("Overworld", "Northeast of Catacombs", 0x1C),
|
||||
"Southeast of Catacombs": LocationData("Overworld", "Southeast of Catacombs", 0x1D),
|
||||
"Credits Left Side": LocationData("CreditsRoom", "Credits Left Side", 0x1E, [WorldPosition(0x1E, 0x25, 0x50)]),
|
||||
"Credits Right Side": LocationData("CreditsRoomFarSide", "Credits Right Side", 0x1E,
|
||||
[WorldPosition(0xBE, 0x70, 0x40)]),
|
||||
"Chalice Home": LocationData("YellowCastle", "Chalice Home", None, event=True)
|
||||
}
|
Reference in New Issue
Block a user