From 6fb82588c55beb0a42cf9acbef568ceb72872451 Mon Sep 17 00:00:00 2001 From: Silvris <58583688+Silvris@users.noreply.github.com> Date: Wed, 21 Feb 2024 01:08:00 -0600 Subject: [PATCH] world cleanup --- worlds/kdl3/Client.py | 6 +-- worlds/kdl3/ClientAddrs.py | 2 +- worlds/kdl3/Compression.py | 18 ++++---- worlds/kdl3/Options.py | 4 +- worlds/kdl3/Regions.py | 8 ++-- worlds/kdl3/Rom.py | 90 +++++++++++++++++++------------------- worlds/kdl3/Room.py | 3 +- worlds/kdl3/__init__.py | 7 +-- 8 files changed, 67 insertions(+), 71 deletions(-) diff --git a/worlds/kdl3/Client.py b/worlds/kdl3/Client.py index 63a6e82b4d38..9603a8b5687c 100644 --- a/worlds/kdl3/Client.py +++ b/worlds/kdl3/Client.py @@ -239,10 +239,10 @@ async def pick_gift_recipient(self, ctx, gift): # only send to ourselves if no one else will take it most_applicable_slot = int(slot) # print(most_applicable, most_applicable_slot) - UUID = uuid.uuid4().hex + item_uuid = uuid.uuid4().hex item = { **gift_base, - "ID": UUID, + "ID": item_uuid, "Sender": ctx.player_names[ctx.slot], "Receiver": ctx.player_names[most_applicable_slot], "SenderTeam": ctx.team, @@ -251,7 +251,7 @@ async def pick_gift_recipient(self, ctx, gift): } # print(item) await update_object(ctx, f"Giftbox;{ctx.team};{most_applicable_slot}", { - UUID: item, + item_uuid: item, }) async def game_watcher(self, ctx) -> None: diff --git a/worlds/kdl3/ClientAddrs.py b/worlds/kdl3/ClientAddrs.py index af5fd8b33a8c..1f5475741b3b 100644 --- a/worlds/kdl3/ClientAddrs.py +++ b/worlds/kdl3/ClientAddrs.py @@ -813,4 +813,4 @@ 0x7706fd: 1831, 0x7706fe: 1832, 0x7706ff: 1858, -} \ No newline at end of file +} diff --git a/worlds/kdl3/Compression.py b/worlds/kdl3/Compression.py index 04dc2c1d697d..ec5461fbec75 100644 --- a/worlds/kdl3/Compression.py +++ b/worlds/kdl3/Compression.py @@ -5,23 +5,23 @@ def hal_decompress(comp: bytes) -> bytes: """ inpos = 0 - input = 0 + inval = 0 output = bytearray() - while input != 0xFF: + while inval != 0xFF: remaining = 65536 - inpos if remaining < 1: return bytes() - input = comp[inpos] + inval = comp[inpos] inpos += 1 - if input == 0xFF: + if inval == 0xFF: break - if (input & 0xE0) == 0xE0: - command = (input >> 2) & 0x07 - length = (((input & 0x03) << 8) | comp[inpos]) + 1 + if (inval & 0xE0) == 0xE0: + command = (inval >> 2) & 0x07 + length = (((inval & 0x03) << 8) | comp[inpos]) + 1 inpos += 1 else: - command = input >> 5 - length = (input & 0x1F) + 1 + command = inval >> 5 + length = (inval & 0x1F) + 1 if (command == 2 and ((len(output) + 2*length) > 65536)) or (len(output) + length) > 65536: return bytes() if command == 0: diff --git a/worlds/kdl3/Options.py b/worlds/kdl3/Options.py index cae8eea1ac3f..3f66dfaa29ff 100644 --- a/worlds/kdl3/Options.py +++ b/worlds/kdl3/Options.py @@ -1,9 +1,8 @@ import random from dataclasses import dataclass -from Options import Option, DeathLink, Choice, Toggle, OptionDict, Range, PlandoBosses, DefaultOnToggle, \ +from Options import DeathLink, Choice, Toggle, OptionDict, Range, PlandoBosses, DefaultOnToggle, \ PerGameCommonOptions -import typing from .Names import LocationName @@ -399,6 +398,7 @@ class Gifting(Toggle): """ display_name = "Gifting" + @dataclass class KDL3Options(PerGameCommonOptions): death_link: DeathLink diff --git a/worlds/kdl3/Regions.py b/worlds/kdl3/Regions.py index ea46b06c4908..a2d0e66186dd 100644 --- a/worlds/kdl3/Regions.py +++ b/worlds/kdl3/Regions.py @@ -1,4 +1,4 @@ -import json +import orjson import os import typing from pkgutil import get_data @@ -22,6 +22,7 @@ } first_stage_blacklist = { + # We want to confirm that the first stage can be completed without any items 0x77000B, # 2-5 needs Kine 0x770011, # 3-5 needs Cutter 0x77001C, # 5-4 needs Burning @@ -38,7 +39,7 @@ def generate_valid_level(level, stage, possible_stages, slot_random): def generate_rooms(world: "KDL3World", door_shuffle: bool, level_regions: typing.Dict[int, Region]): level_names = {LocationName.level_names[level]: level for level in LocationName.level_names} - room_data = json.loads(get_data(__name__, os.path.join("data", "Rooms.json"))) + room_data = orjson.loads(get_data(__name__, os.path.join("data", "Rooms.json"))) rooms: typing.Dict[str, KDL3Room] = dict() for room_entry in room_data: room = KDL3Room(room_entry["name"], world.player, world.multiworld, None, room_entry["level"], @@ -48,7 +49,8 @@ def generate_rooms(world: "KDL3World", door_shuffle: bool, level_regions: typing room.add_locations({location: world.location_name_to_id[location] if location in world.location_name_to_id else None for location in room_entry["locations"] if (not any([x in location for x in ["1-Up", "Maxim"]]) or - world.options.consumables.value) and (not "Star" in location or world.options.starsanity.value)}, + world.options.consumables.value) and ("Star" not in location + or world.options.starsanity.value)}, KDL3Location) rooms[room.name] = room for location in room.locations: diff --git a/worlds/kdl3/Rom.py b/worlds/kdl3/Rom.py index 991f264f1cdb..5a846ab8be5e 100644 --- a/worlds/kdl3/Rom.py +++ b/worlds/kdl3/Rom.py @@ -1,15 +1,13 @@ import typing from pkgutil import get_data -from random import Random import Utils -from typing import Optional, Dict, List, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING import hashlib import os import struct import settings -from BaseClasses import MultiWorld from worlds.Files import APDeltaPatch from .Aesthetics import get_palette_bytes, kirby_target_palettes, get_kirby_palette, gooey_target_palettes, \ get_gooey_palette @@ -335,7 +333,7 @@ def write_heart_star_sprites(rom: RomData): rom.write_bytes(0x3F0EBF, [0x00, 0xD0, 0x39]) -def write_consumable_sprites(rom: RomData, consumables, stars): +def write_consumable_sprites(rom: RomData, consumables: bool, stars: bool): compressed = rom.read_bytes(consumable_address, consumable_size) decompressed = hal_decompress(compressed) patched = bytearray(decompressed) @@ -385,9 +383,7 @@ def patch(self, target: str): rom.write_to_file(target) -def patch_rom(world: "KDL3World", multiworld: MultiWorld, player: int, rom: RomData, heart_stars_required: int, - boss_requirements: Dict[int, int], shuffled_levels: Dict[int, List[int]], bb_boss_enabled: List[bool], - copy_abilities: Dict[str, str], slot_random: Random): +def patch_rom(world: "KDL3World", rom: RomData): rom.apply_patch(get_data(__name__, os.path.join("data", "kdl3_basepatch.bsdiff4"))) tiles = get_data(__name__, os.path.join("data", "APPauseIcons.dat")) rom.write_bytes(0x3F000, tiles) @@ -417,12 +413,12 @@ def patch_rom(world: "KDL3World", multiworld: MultiWorld, player: int, rom: RomD if world.options.music_shuffle > 0: if world.options.music_shuffle == 1: shuffled_music = music_choices.copy() - slot_random.shuffle(shuffled_music) + world.random.shuffle(shuffled_music) music_map = dict(zip(music_choices, shuffled_music)) # Avoid putting star twinkle in the pool - music_map[5] = slot_random.choice(music_choices) + music_map[5] = world.random.choice(music_choices) # Heart Star music doesn't work on regular stages - music_map[8] = slot_random.choice(music_choices) + music_map[8] = world.random.choice(music_choices) for room in rooms: room.music = music_map[room.music] for room in room_pointers: @@ -439,17 +435,17 @@ def patch_rom(world: "KDL3World", multiworld: MultiWorld, player: int, rom: RomD rom.write_byte(0x4A38D, music_map[0x1D]) elif world.options.music_shuffle == 2: for room in rooms: - room.music = slot_random.choice(music_choices) + room.music = world.random.choice(music_choices) for room in room_pointers: - rom.write_byte(room + 2, slot_random.choice(music_choices)) + rom.write_byte(room + 2, world.random.choice(music_choices)) for i in range(5): # level themes - rom.write_byte(0x133F2 + i, slot_random.choice(music_choices)) + rom.write_byte(0x133F2 + i, world.random.choice(music_choices)) # Zero - rom.write_byte(0x9AE79, slot_random.choice(music_choices)) + rom.write_byte(0x9AE79, world.random.choice(music_choices)) # Heart Star success and fail - rom.write_byte(0x4A388, slot_random.choice(music_choices)) - rom.write_byte(0x4A38D, slot_random.choice(music_choices)) + rom.write_byte(0x4A388, world.random.choice(music_choices)) + rom.write_byte(0x4A38D, world.random.choice(music_choices)) for room in rooms: room.patch(rom) @@ -469,9 +465,10 @@ def patch_rom(world: "KDL3World", multiworld: MultiWorld, player: int, rom: RomD rom.write_bytes(0x2C8217, [0xFF, 0x1E, ]) # boss requirements - rom.write_bytes(0x3D000, struct.pack("HHHHH", boss_requirements[0], boss_requirements[1], boss_requirements[2], - boss_requirements[3], boss_requirements[4])) - rom.write_bytes(0x3D00A, struct.pack("H", heart_stars_required if world.options.goal_speed == 1 else 0xFFFF)) + rom.write_bytes(0x3D000, struct.pack("HHHHH", world.boss_requirements[0], world.boss_requirements[1], + world.boss_requirements[2], world.boss_requirements[3], + world.boss_requirements[4])) + rom.write_bytes(0x3D00A, struct.pack("H", world.required_heart_stars if world.options.goal_speed == 1 else 0xFFFF)) rom.write_byte(0x3D00C, world.options.goal_speed.value) rom.write_byte(0x3D00E, world.options.open_world.value) rom.write_byte(0x3D010, world.options.death_link.value) @@ -484,59 +481,60 @@ def patch_rom(world: "KDL3World", multiworld: MultiWorld, player: int, rom: RomD rom.write_byte(0x3D01E, world.options.strict_bosses.value) # don't write gifting for solo game, since there's no one to send anything to - for level in shuffled_levels: - for i in range(len(shuffled_levels[level])): + for level in world.player_levels: + for i in range(len(world.player_levels[level])): rom.write_bytes(0x3F002E + ((level - 1) * 14) + (i * 2), - struct.pack("H", level_pointers[shuffled_levels[level][i]])) + struct.pack("H", level_pointers[world.player_levels[level][i]])) rom.write_bytes(0x3D020 + (level - 1) * 14 + (i * 2), - struct.pack("H", shuffled_levels[level][i] & 0x00FFFF)) + struct.pack("H", world.player_levels[level][i] & 0x00FFFF)) if (i == 0) or (i > 0 and i % 6 != 0): rom.write_bytes(0x3D080 + (level - 1) * 12 + (i * 2), - struct.pack("H", (shuffled_levels[level][i] & 0x00FFFF) % 6)) + struct.pack("H", (world.player_levels[level][i] & 0x00FFFF) % 6)) for i in range(6): - if bb_boss_enabled[i]: + if world.boss_butch_bosses[i]: rom.write_bytes(0x3F0000 + (level_pointers[0x770200 + i]), struct.pack("I", bb_bosses[0x770200 + i])) # copy ability shuffle if world.options.copy_ability_randomization.value > 0: - for enemy in copy_abilities: + for enemy in world.copy_abilities: if enemy in miniboss_remap: rom.write_bytes(0xB417E + (miniboss_remap[enemy] << 1), - struct.pack("H", ability_remap[copy_abilities[enemy]])) + struct.pack("H", ability_remap[world.copy_abilities[enemy]])) else: rom.write_bytes(0xB3CAC + (enemy_remap[enemy] << 1), - struct.pack("H", ability_remap[copy_abilities[enemy]])) + struct.pack("H", ability_remap[world.copy_abilities[enemy]])) # following only needs done on non-door rando # incredibly lucky this follows the same order (including 5E == star block) - rom.write_byte(0x2F77EA, 0x5E + (ability_remap[copy_abilities["Sparky"]] << 1)) - rom.write_byte(0x2F7811, 0x5E + (ability_remap[copy_abilities["Sparky"]] << 1)) - rom.write_byte(0x2F9BC4, 0x5E + (ability_remap[copy_abilities["Blocky"]] << 1)) - rom.write_byte(0x2F9BEB, 0x5E + (ability_remap[copy_abilities["Blocky"]] << 1)) - rom.write_byte(0x2FAC06, 0x5E + (ability_remap[copy_abilities["Jumper Shoot"]] << 1)) - rom.write_byte(0x2FAC2D, 0x5E + (ability_remap[copy_abilities["Jumper Shoot"]] << 1)) - rom.write_byte(0x2F9E7B, 0x5E + (ability_remap[copy_abilities["Yuki"]] << 1)) - rom.write_byte(0x2F9EA2, 0x5E + (ability_remap[copy_abilities["Yuki"]] << 1)) - rom.write_byte(0x2FA951, 0x5E + (ability_remap[copy_abilities["Sir Kibble"]] << 1)) - rom.write_byte(0x2FA978, 0x5E + (ability_remap[copy_abilities["Sir Kibble"]] << 1)) - rom.write_byte(0x2FA132, 0x5E + (ability_remap[copy_abilities["Haboki"]] << 1)) - rom.write_byte(0x2FA159, 0x5E + (ability_remap[copy_abilities["Haboki"]] << 1)) - rom.write_byte(0x2FA3E8, 0x5E + (ability_remap[copy_abilities["Boboo"]] << 1)) - rom.write_byte(0x2FA40F, 0x5E + (ability_remap[copy_abilities["Boboo"]] << 1)) - rom.write_byte(0x2F90E2, 0x5E + (ability_remap[copy_abilities["Captain Stitch"]] << 1)) - rom.write_byte(0x2F9109, 0x5E + (ability_remap[copy_abilities["Captain Stitch"]] << 1)) + rom.write_byte(0x2F77EA, 0x5E + (ability_remap[world.copy_abilities["Sparky"]] << 1)) + rom.write_byte(0x2F7811, 0x5E + (ability_remap[world.copy_abilities["Sparky"]] << 1)) + rom.write_byte(0x2F9BC4, 0x5E + (ability_remap[world.copy_abilities["Blocky"]] << 1)) + rom.write_byte(0x2F9BEB, 0x5E + (ability_remap[world.copy_abilities["Blocky"]] << 1)) + rom.write_byte(0x2FAC06, 0x5E + (ability_remap[world.copy_abilities["Jumper Shoot"]] << 1)) + rom.write_byte(0x2FAC2D, 0x5E + (ability_remap[world.copy_abilities["Jumper Shoot"]] << 1)) + rom.write_byte(0x2F9E7B, 0x5E + (ability_remap[world.copy_abilities["Yuki"]] << 1)) + rom.write_byte(0x2F9EA2, 0x5E + (ability_remap[world.copy_abilities["Yuki"]] << 1)) + rom.write_byte(0x2FA951, 0x5E + (ability_remap[world.copy_abilities["Sir Kibble"]] << 1)) + rom.write_byte(0x2FA978, 0x5E + (ability_remap[world.copy_abilities["Sir Kibble"]] << 1)) + rom.write_byte(0x2FA132, 0x5E + (ability_remap[world.copy_abilities["Haboki"]] << 1)) + rom.write_byte(0x2FA159, 0x5E + (ability_remap[world.copy_abilities["Haboki"]] << 1)) + rom.write_byte(0x2FA3E8, 0x5E + (ability_remap[world.copy_abilities["Boboo"]] << 1)) + rom.write_byte(0x2FA40F, 0x5E + (ability_remap[world.copy_abilities["Boboo"]] << 1)) + rom.write_byte(0x2F90E2, 0x5E + (ability_remap[world.copy_abilities["Captain Stitch"]] << 1)) + rom.write_byte(0x2F9109, 0x5E + (ability_remap[world.copy_abilities["Captain Stitch"]] << 1)) if world.options.copy_ability_randomization == 2: for enemy in enemy_remap: # we just won't include it for minibosses - rom.write_bytes(0xB3E40 + (enemy_remap[enemy] << 1), struct.pack("h", slot_random.randint(-1, 2))) + rom.write_bytes(0xB3E40 + (enemy_remap[enemy] << 1), struct.pack("h", world.random.randint(-1, 2))) # write jumping goal rom.write_bytes(0x94F8, struct.pack("H", world.options.jumping_target)) rom.write_bytes(0x944E, struct.pack("H", world.options.jumping_target)) from Utils import __version__ - rom.name = bytearray(f'KDL3{__version__.replace(".", "")[0:3]}_{player}_{multiworld.seed:11}\0', 'utf8')[:21] + rom.name = bytearray( + f'KDL3{__version__.replace(".", "")[0:3]}_{world.player}_{world.multiworld.seed:11}\0', 'utf8')[:21] rom.name.extend([0] * (21 - len(rom.name))) rom.write_bytes(0x3C000, rom.name) rom.write_byte(0x3C020, world.options.game_language.value) diff --git a/worlds/kdl3/Room.py b/worlds/kdl3/Room.py index 43ffe675d3a8..256955b924ab 100644 --- a/worlds/kdl3/Room.py +++ b/worlds/kdl3/Room.py @@ -80,7 +80,8 @@ def patch(self, rom: "RomData"): self.entity_load.append([2, 22]) if load_len < len(self.entity_load): rom.write_bytes(self.pointer + 88 + (load_len * 2), bytes(self.entity_load[load_len])) - rom.write_bytes(self.pointer + 104 + (load_len * 2), bytes(struct.pack("H", self.consumable_pointer))) + rom.write_bytes(self.pointer + 104 + (load_len * 2), + bytes(struct.pack("H", self.consumable_pointer))) if is_progression: if [1, 22] in self.entity_load: vtype = 1 diff --git a/worlds/kdl3/__init__.py b/worlds/kdl3/__init__.py index ad3120e29d33..9e717e744f61 100644 --- a/worlds/kdl3/__init__.py +++ b/worlds/kdl3/__init__.py @@ -268,12 +268,7 @@ def generate_output(self, output_directory: str): player = self.player rom = RomData(get_base_rom_path()) - patch_rom(self, self.multiworld, self.player, rom, self.required_heart_stars, - self.boss_requirements, - self.player_levels, - self.boss_butch_bosses, - self.copy_abilities, - self.random) + patch_rom(self, rom) rom_path = os.path.join(output_directory, f"{self.multiworld.get_out_file_name_base(self.player)}.sfc") rom.write_to_file(rom_path)