From 76e0c18786a0a250ed21b380996b7367e8ab8452 Mon Sep 17 00:00:00 2001 From: jamesbrq Date: Tue, 23 Jul 2024 16:01:31 -0400 Subject: [PATCH] pre-v1.5.0 --- worlds/gl/GauntletLegendsClient.py | 13 +++++-- worlds/gl/Options.py | 13 ------- worlds/gl/Regions.py | 10 ++--- worlds/gl/Rom.py | 60 +++++++++++++++++------------- worlds/gl/__init__.py | 9 ++--- 5 files changed, 52 insertions(+), 53 deletions(-) diff --git a/worlds/gl/GauntletLegendsClient.py b/worlds/gl/GauntletLegendsClient.py index 7467d3f82b77..07732f5da65f 100644 --- a/worlds/gl/GauntletLegendsClient.py +++ b/worlds/gl/GauntletLegendsClient.py @@ -164,6 +164,13 @@ def _cmd_deathlink_toggle(self): self.ctx.deathlink_enabled = not self.ctx.deathlink_enabled logger.info(f"Deathlink {'Enabled.' if self.ctx.deathlink_enabled else 'Disabled.'}") + def _cmd_players(self, value: int): + """Set number of local players""" + if type(value) is not int: + logger.info(f"Invalid Parameters. Usage: /players [number]") + self.ctx.players = min(value, 4) + logger.info(f"Players set to {min(value, 4)}.") + class GauntletLegendsContext(CommonContext): command_processor = GauntletLegendsCommandProcessor @@ -491,7 +498,6 @@ def on_package(self, cmd: str, args: dict): self.glslotdata = args["slot_data"] if self.socket.status(): self.retro_connected = True - self.players = self.glslotdata["players"] self.deathlink_enabled = self.glslotdata["death_link"] else: raise Exception("Retroarch not detected. Please open you patched ROM in Retroarch.") @@ -575,11 +581,11 @@ async def scale(self): level = [0x1, 0xF] players = await self.active_players() player_level = await self.player_level() - max_value: int = self.glslotdata["max"] + max_value: int = max(self.glslotdata["max"], self.players) scale_value = min(max(((player_level - difficulty_convert[level[1]]) // 5), 0), 3) if self.glslotdata["instant_max"] == 1: scale_value = max_value - mountain_value = min(player_level // 10, 3) + # mountain_value = min(player_level // 10, 3) await self.socket.write( message_format(WRITE, f"0x{format(PLAYER_COUNT, 'x')} 0x{format(min(players + scale_value, max_value), 'x')}"), ) @@ -799,6 +805,7 @@ async def _patch_and_run_game(patch_file: str): # Checks location status inside of levels async def gl_sync_task(ctx: GauntletLegendsContext): logger.info("Starting N64 connector...") + logger.info("Use /players to set the number of people playing locally. This is required for the client to function.") while not ctx.exit_event.is_set(): if ctx.retro_connected: cc_str: str = f"gl_cc_T{ctx.team}_P{ctx.slot}" diff --git a/worlds/gl/Options.py b/worlds/gl/Options.py index c41240f553b9..6e1068ac1a1b 100644 --- a/worlds/gl/Options.py +++ b/worlds/gl/Options.py @@ -3,18 +3,6 @@ from Options import Choice, PerGameCommonOptions, StartInventoryPool, Toggle, Range -class PlayerCount(Range): - """ - Select how many players will be playing this world locally. - If 3 players will be active then change this to 3, etc. - """ - - display_name = "Local Players" - range_start = 1 - range_end = 4 - default = 1 - - class ChestBarrels(Choice): """ Choose how you want Chests and Barrels to be randomized. @@ -213,7 +201,6 @@ class UnlockCharacterFour(Choice): @dataclass class GLOptions(PerGameCommonOptions): start_inventory_from_pool: StartInventoryPool - local_players: PlayerCount chests_barrels: ChestBarrels obelisks: Obelisks mirror_shards: MirrorShards diff --git a/worlds/gl/Regions.py b/worlds/gl/Regions.py index eec603f92dc6..647ced17cd44 100644 --- a/worlds/gl/Regions.py +++ b/worlds/gl/Regions.py @@ -104,7 +104,7 @@ def connect_regions(world: "GauntletLegendsWorld"): connect( world, names, - "Valley of Fire", + "Menu", "Castle Courtyard", lambda state: state.has("Mountain Obelisk 1", world.player) and state.has("Mountain Obelisk 2", world.player) @@ -117,7 +117,7 @@ def connect_regions(world: "GauntletLegendsWorld"): connect( world, names, - "Valley of Fire", + "Menu", "Poisonous Fields", lambda state: state.has("Castle Obelisk 1", world.player) and state.has("Castle Obelisk 2", world.player), @@ -129,7 +129,7 @@ def connect_regions(world: "GauntletLegendsWorld"): connect( world, names, - "Valley of Fire", + "Menu", "Arctic Docks", lambda state: state.has("Town Obelisk 1", world.player) and state.has("Town Obelisk 2", world.player), @@ -141,7 +141,7 @@ def connect_regions(world: "GauntletLegendsWorld"): connect( world, names, - "Valley of Fire", + "Menu", "Desecrated Temple", lambda state: state.has("Dragon Mirror Shard", world.player) and state.has("Chimera Mirror Shard", world.player) @@ -154,7 +154,7 @@ def connect_regions(world: "GauntletLegendsWorld"): connect( world, names, - "Valley of Fire", + "Menu", "Gates of the Underworld", lambda state: state.has("Runestone 1", world.player) and state.has("Runestone 2", world.player) diff --git a/worlds/gl/Rom.py b/worlds/gl/Rom.py index 9f201a8a85ca..7832e2ccb4fb 100644 --- a/worlds/gl/Rom.py +++ b/worlds/gl/Rom.py @@ -53,8 +53,9 @@ class LevelData: objects: List[bytearray] chests: List[bytearray] end: bytes - obelisk = 0 - item = 0 + obelisk_items: int = 0 + obelisk_chests: int = 0 + item: int = 0 def __init__(self): self.items = [] @@ -136,15 +137,15 @@ def patch_items(caller: APProcedurePatch, rom: bytes): if "Chest" in location_name or ( "Barrel" in location_name and "Barrel of Gold" not in location_name ): - data.chests[j - (len(data.items) + data.obelisk)][12] = 0x27 - data.chests[j - (len(data.items) + data.obelisk)][13] = 0x4 + data.chests[j - (len(data.items) + data.obelisk_items + data.obelisk_chests)][12] = 0x27 + data.chests[j - (len(data.items) + data.obelisk_items + data.obelisk_chests)][13] = 0x4 else: - data.items[j - data.obelisk][6] = 0x27 - data.items[j - data.obelisk][7] = 0x4 + data.items[j - data.obelisk_items][6] = 0x27 + data.items[j - data.obelisk_items][7] = 0x4 else: if "Obelisk" in items_by_id[item[0]].item_name: data.objects += [ - bytearray(data.items[j - data.obelisk][0:6]) + bytearray(data.items[j - data.obelisk_items][0:6]) + bytearray( [ 0x0, @@ -168,17 +169,19 @@ def patch_items(caller: APProcedurePatch, rom: bytes): ], ), ] - del data.items[j - data.obelisk] - data.obelisk += 1 + if chest_barrel(location_name): + del data.chests[j - (len(data.items) + data.obelisk_items + data.obelisk_chests)] + data.obelisk_chests += 1 + else: + del data.items[j - data.obelisk_items] + data.obelisk_items += 1 else: - if "Chest" in location_name or ( - "Barrel" in location_name and "Barrel of Gold" not in location_name - ): - data.chests[j - (len(data.items) + data.obelisk)][12] = item_dict[item[0]][0] - data.chests[j - (len(data.items) + data.obelisk)][13] = item_dict[item[0]][1] + if chest_barrel(location_name): + data.chests[j - (len(data.items) + data.obelisk_items + data.obelisk_chests)][12] = item_dict[item[0]][0] + data.chests[j - (len(data.items) + data.obelisk_items + data.obelisk_chests)][13] = item_dict[item[0]][1] else: - data.items[j - data.obelisk][6] = item_dict[item[0]][0] - data.items[j - data.obelisk][7] = item_dict[item[0]][1] + data.items[j - data.obelisk_items][6] = item_dict[item[0]][0] + data.items[j - data.obelisk_items][7] = item_dict[item[0]][1] uncompressed = level_data_reformat(data) compressed = zenc(uncompressed) stream.seek(level_header[i] + 4, 0) @@ -290,16 +293,16 @@ def get_level_data(stream: io.BytesIO, size: int) -> (io.BytesIO, LevelData): # Format is header, items, spawners, objects, barrels/chests, then traps. def level_data_reformat(data: LevelData) -> bytes: stream = io.BytesIO() - obelisk_offset = 24 * (data.obelisk - data.item) + obelisk_offset = 24 * (data.obelisk_items - data.item) stream.write(int.to_bytes(0x5C, 4, "big")) - stream.write(int.to_bytes(data.spawner_addr + (12 * (data.item - data.obelisk)), 4, "big")) - stream.write(int.to_bytes(data.spawner_addr + (12 * (data.item - data.obelisk)), 4, "big")) - stream.write(int.to_bytes(data.obj_addr + (12 * (data.item - data.obelisk)), 4, "big")) - stream.write(int.to_bytes(data.end_addr + ((12 * (data.item - data.obelisk)) + obelisk_offset), 4, "big")) - stream.write(int.to_bytes(data.portal_addr + ((12 * (data.item - data.obelisk)) + obelisk_offset), 4, "big")) - stream.write(int.to_bytes(data.chest_addr + ((12 * (data.item - data.obelisk)) + obelisk_offset), 4, "big")) - stream.write(int.to_bytes(data.end_addr2 + ((12 * (data.item - data.obelisk)) + obelisk_offset), 4, "big")) - stream.write(int.to_bytes(data.end_addr3 + ((12 * (data.item - data.obelisk)) + obelisk_offset), 4, "big")) + stream.write(int.to_bytes(data.spawner_addr + (12 * (data.item - data.obelisk_items)), 4, "big")) + stream.write(int.to_bytes(data.spawner_addr + (12 * (data.item - data.obelisk_items)), 4, "big")) + stream.write(int.to_bytes(data.obj_addr + (12 * (data.item - data.obelisk_items)), 4, "big")) + stream.write(int.to_bytes(data.end_addr + ((12 * (data.item - data.obelisk_items)) + obelisk_offset - (data.obelisk_chests * 16)), 4, "big")) + stream.write(int.to_bytes(data.portal_addr + ((12 * (data.item - data.obelisk_items)) + obelisk_offset - (data.obelisk_chests * 16)), 4, "big")) + stream.write(int.to_bytes(data.chest_addr + ((12 * (data.item - data.obelisk_items)) + obelisk_offset), 4, "big")) + stream.write(int.to_bytes(data.end_addr2 + ((12 * (data.item - data.obelisk_items)) + obelisk_offset - (data.obelisk_chests * 16)), 4, "big")) + stream.write(int.to_bytes(data.end_addr3 + ((12 * (data.item - data.obelisk_items)) + obelisk_offset - (data.obelisk_chests * 16)), 4, "big")) stream.seek(1, 1) stream.write(bytes([len(data.items)])) stream.write(bytes([0x0, 0x0, 0x0])) @@ -307,8 +310,13 @@ def level_data_reformat(data: LevelData) -> bytes: stream.write(bytes([0x0])) stream.write(bytes([len(data.objects)])) data.stream.seek(stream.tell()) - stream.write(data.stream.read(48)) + temp = bytearray(data.stream.read(48)) + temp[7] = len(data.chests) + stream.write(temp) for item in data.items + data.spawners + data.objects + data.chests: stream.write(bytes(item)) stream.write(data.end) return stream.getvalue() + +def chest_barrel(name: str): + return ("Chest" in name or ("Barrel" in name and "Barrel of Gold" not in name)) diff --git a/worlds/gl/__init__.py b/worlds/gl/__init__.py index a14b05eaf6a8..33ea5bd0e9e3 100644 --- a/worlds/gl/__init__.py +++ b/worlds/gl/__init__.py @@ -78,9 +78,6 @@ class GauntletLegendsWorld(World): disabled_locations: typing.List[LocationData] - def generate_early(self) -> None: - self.options.max_difficulty_value = max(self.options.max_difficulty_value.value, self.options.local_players.value) - def create_regions(self) -> None: self.disabled_locations = [] if self.options.chests_barrels == 0: @@ -152,7 +149,6 @@ def fill_slot_data(self) -> dict: ] return { "player": self.player, - "players": self.options.local_players.value, "shards": shard_values, "speed": self.options.permanent_speed.value, "keys": self.options.infinite_keys.value, @@ -228,8 +224,9 @@ def set_rules(self) -> None: "Gates of the Underworld", "Region", self.player, ) - def post_fill(self) -> None: - fast_fill(self.multiworld, self.death, self.multiworld.get_unfilled_locations(player=self.player)) + def pre_fill(self) -> None: + self.random.shuffle(self.multiworld.get_unfilled_locations(self.player)) + fast_fill(self.multiworld, self.death, self.multiworld.get_unfilled_locations(self.player)) def create_item(self, name: str) -> GLItem: item = item_table[name]