diff --git a/worlds/kdl3/client.py b/worlds/kdl3/client.py index 97bf68cb..78a43239 100644 --- a/worlds/kdl3/client.py +++ b/worlds/kdl3/client.py @@ -90,7 +90,7 @@ def cmd_gift(self: "SNIClientCommandProcessor") -> None: async_start(update_object(self.ctx, f"Giftboxes;{self.ctx.team}", { f"{self.ctx.slot}": { - "IsOpen": handler.gifting, + "is_open": handler.gifting, **kdl3_gifting_options } })) @@ -175,11 +175,11 @@ class KDL3SNIClient(SNIClient): key, gift = ctx.stored_data[self.giftbox_key].popitem() await pop_object(ctx, self.giftbox_key, key) # first, special cases - traits = [trait["Trait"] for trait in gift["Traits"]] + traits = [trait["trait"] for trait in gift["traits"]] if "Candy" in traits or "Invincible" in traits: # apply invincibility candy self.item_queue.append(0x43) - elif "Tomato" in traits or "tomato" in gift["ItemName"].lower(): + elif "Tomato" in traits or "tomato" in gift["item_name"].lower(): # apply maxim tomato # only want tomatos here, no other vegetable is that good self.item_queue.append(0x42) @@ -187,7 +187,7 @@ class KDL3SNIClient(SNIClient): # Apply 1-Up self.item_queue.append(0x41) elif "Currency" in traits or "Star" in traits: - value = gift["ItemValue"] + value = gift.get("item_value", 1) if value >= 50000: self.item_queue.append(0x46) elif value >= 30000: @@ -210,8 +210,8 @@ class KDL3SNIClient(SNIClient): # check if it's tasty if any(x in traits for x in ["Consumable", "Food", "Drink", "Heal", "Health"]): # it's tasty!, use quality to decide how much to heal - quality = max((trait["Quality"] for trait in gift["Traits"] - if trait["Trait"] in ["Consumable", "Food", "Drink", "Heal", "Health"])) + quality = max((trait.get("quality", 1.0) for trait in gift["traits"] + if trait["trait"] in ["Consumable", "Food", "Drink", "Heal", "Health"])) quality = min(10, quality * 2) else: # it's not really edible, but he'll eat it anyway @@ -236,23 +236,23 @@ class KDL3SNIClient(SNIClient): for slot, info in ctx.stored_data[self.motherbox_key].items(): if int(slot) == ctx.slot and len(ctx.stored_data[self.motherbox_key]) > 1: continue - desire = len(set(info["DesiredTraits"]).intersection([trait["Trait"] for trait in gift_base["Traits"]])) + desire = len(set(info["desired_traits"]).intersection([trait["trait"] for trait in gift_base["traits"]])) if desire > most_applicable: most_applicable = desire most_applicable_slot = int(slot) - elif most_applicable_slot != ctx.slot and most_applicable == -1 and info["AcceptsAnyGift"]: + elif most_applicable_slot == ctx.slot and most_applicable == -1 and info["accepts_any_gift"]: # only send to ourselves if no one else will take it most_applicable_slot = int(slot) # print(most_applicable, most_applicable_slot) item_uuid = uuid.uuid4().hex item = { **gift_base, - "ID": item_uuid, - "Sender": ctx.player_names[ctx.slot], - "Receiver": ctx.player_names[most_applicable_slot], - "SenderTeam": ctx.team, - "ReceiverTeam": ctx.team, # for the moment - "IsRefund": False + "id": item_uuid, + "sender_slot": ctx.slot, + "receiver_slot": most_applicable_slot, + "sender_team": ctx.team, + "receiver_team": ctx.team, # for the moment + "is_refund": False } # print(item) await update_object(ctx, f"Giftbox;{ctx.team};{most_applicable_slot}", { @@ -276,8 +276,9 @@ class KDL3SNIClient(SNIClient): if not self.initialize_gifting: self.giftbox_key = f"Giftbox;{ctx.team};{ctx.slot}" self.motherbox_key = f"Giftboxes;{ctx.team}" - enable_gifting = await snes_read(ctx, KDL3_GIFTING_FLAG, 0x01) - await initialize_giftboxes(ctx, self.giftbox_key, self.motherbox_key, bool(enable_gifting[0])) + enable_gifting = await snes_read(ctx, KDL3_GIFTING_FLAG, 0x02) + await initialize_giftboxes(ctx, self.giftbox_key, self.motherbox_key, + bool(int.from_bytes(enable_gifting, "little"))) self.initialize_gifting = True # can't check debug anymore, without going and copying the value. might be important later. if not self.levels: @@ -350,19 +351,19 @@ class KDL3SNIClient(SNIClient): self.item_queue.append(item_idx | 0x80) # handle gifts here - gifting_status = await snes_read(ctx, KDL3_GIFTING_FLAG, 0x01) - if hasattr(ctx, "gifting") and ctx.gifting: - if gifting_status[0]: + gifting_status = int.from_bytes(await snes_read(ctx, KDL3_GIFTING_FLAG, 0x02), "little") + if hasattr(self, "gifting") and self.gifting: + if gifting_status: gift = await snes_read(ctx, KDL3_GIFTING_SEND, 0x01) if gift[0]: # we have a gift to send await self.pick_gift_recipient(ctx, gift[0]) snes_buffered_write(ctx, KDL3_GIFTING_SEND, bytes([0x00])) else: - snes_buffered_write(ctx, KDL3_GIFTING_FLAG, bytes([0x01])) + snes_buffered_write(ctx, KDL3_GIFTING_FLAG, bytes([0x01, 0x00])) else: - if gifting_status[0]: - snes_buffered_write(ctx, KDL3_GIFTING_FLAG, bytes([0x00])) + if gifting_status: + snes_buffered_write(ctx, KDL3_GIFTING_FLAG, bytes([0x00, 0x00])) await snes_flush_writes(ctx) diff --git a/worlds/kdl3/gifting.py b/worlds/kdl3/gifting.py index e1626091..de155148 100644 --- a/worlds/kdl3/gifting.py +++ b/worlds/kdl3/gifting.py @@ -37,157 +37,158 @@ async def initialize_giftboxes(ctx: "SNIContext", giftbox_key: str, motherbox_ke ctx.set_notify(motherbox_key, giftbox_key) await update_object(ctx, f"Giftboxes;{ctx.team}", {f"{ctx.slot}": { - "IsOpen": is_open, + "is_open": is_open, **kdl3_gifting_options }}) + await update_object(ctx, f"Giftbox;{ctx.team};{ctx.slot}", {}) ctx.client_handler.gifting = is_open kdl3_gifting_options = { - "AcceptsAnyGift": True, - "DesiredTraits": [ + "accepts_any_gift": True, + "desired_traits": [ "Consumable", "Food", "Drink", "Candy", "Tomato", "Invincible", "Life", "Heal", "Health", "Trap", "Goo", "Gel", "Slow", "Slowness", "Eject", "Removal" ], - "MinimumGiftVersion": 2, + "minimum_gift_version": 3, } kdl3_gifts = { 1: { - "ItemName": "1-Up", - "Amount": 1, - "ItemValue": 400000, - "Traits": [ + "item_name": "1-Up", + "amount": 1, + "item_value": 400000, + "traits": [ { - "Trait": "Consumable", - "Quality": 1, - "Duration": 1, + "trait": "Consumable", + "quality": 1, + "duration": 1, }, { - "Trait": "Life", - "Quality": 1, - "Duration": 1 + "trait": "Life", + "quality": 1, + "duration": 1 } ] }, 2: { - "ItemName": "Maxim Tomato", - "Amount": 1, - "ItemValue": 500000, - "Traits": [ + "item_name": "Maxim Tomato", + "amount": 1, + "item_value": 500000, + "traits": [ { - "Trait": "Consumable", - "Quality": 5, - "Duration": 1, + "trait": "Consumable", + "quality": 5, + "duration": 1, }, { - "Trait": "Heal", - "Quality": 5, - "Duration": 1, + "trait": "Heal", + "quality": 5, + "duration": 1, }, { - "Trait": "Food", - "Quality": 5, - "Duration": 1, + "trait": "Food", + "quality": 5, + "duration": 1, }, { - "Trait": "Tomato", - "Quality": 5, - "Duration": 1, + "trait": "Tomato", + "quality": 5, + "duration": 1, }, { - "Trait": "Vegetable", - "Quality": 5, - "Duration": 1, + "trait": "Vegetable", + "quality": 5, + "duration": 1, } ] }, 3: { - "ItemName": "Energy Drink", - "Amount": 1, - "ItemValue": 100000, - "Traits": [ + "item_name": "Energy Drink", + "amount": 1, + "item_value": 100000, + "traits": [ { - "Trait": "Consumable", - "Quality": 1, - "Duration": 1, + "trait": "Consumable", + "quality": 1, + "duration": 1, }, { - "Trait": "Heal", - "Quality": 1, - "Duration": 1, + "trait": "Heal", + "quality": 1, + "duration": 1, }, { - "Trait": "Drink", - "Quality": 1, - "Duration": 1, + "trait": "Drink", + "quality": 1, + "duration": 1, }, ] }, 5: { - "ItemName": "Small Star Piece", - "Amount": 1, - "ItemValue": 10000, - "Traits": [ + "item_name": "Small Star Piece", + "amount": 1, + "item_value": 10000, + "traits": [ { - "Trait": "Currency", - "Quality": 1, - "Duration": 1, + "trait": "Currency", + "quality": 1, + "duration": 1, }, { - "Trait": "Money", - "Quality": 1, - "Duration": 1, + "trait": "Money", + "quality": 1, + "duration": 1, }, { - "Trait": "Star", - "Quality": 1, - "Duration": 1 + "trait": "Star", + "quality": 1, + "duration": 1 } ] }, 6: { - "ItemName": "Medium Star Piece", - "Amount": 1, - "ItemValue": 30000, - "Traits": [ + "item_name": "Medium Star Piece", + "amount": 1, + "item_value": 30000, + "traits": [ { - "Trait": "Currency", - "Quality": 3, - "Duration": 1, + "trait": "Currency", + "quality": 3, + "duration": 1, }, { - "Trait": "Money", - "Quality": 3, - "Duration": 1, + "trait": "Money", + "quality": 3, + "duration": 1, }, { - "Trait": "Star", - "Quality": 3, - "Duration": 1 + "trait": "Star", + "quality": 3, + "duration": 1 } ] }, 7: { - "ItemName": "Large Star Piece", - "Amount": 1, - "ItemValue": 50000, - "Traits": [ + "item_name": "Large Star Piece", + "amount": 1, + "item_value": 50000, + "traits": [ { - "Trait": "Currency", - "Quality": 5, - "Duration": 1, + "trait": "Currency", + "quality": 5, + "duration": 1, }, { - "Trait": "Money", - "Quality": 5, - "Duration": 1, + "trait": "Money", + "quality": 5, + "duration": 1, }, { - "Trait": "Star", - "Quality": 5, - "Duration": 1 + "trait": "Star", + "quality": 5, + "duration": 1 } ] }, @@ -195,90 +196,90 @@ kdl3_gifts = { kdl3_trap_gifts = { 0: { - "ItemName": "Gooey Bag", - "Amount": 1, - "ItemValue": 10000, - "Traits": [ + "item_name": "Gooey Bag", + "amount": 1, + "item_value": 10000, + "traits": [ { - "Trait": "Trap", - "Quality": 1, - "Duration": 1, + "trait": "Trap", + "quality": 1, + "duration": 1, }, { - "Trait": "Goo", - "Quality": 1, - "Duration": 1, + "trait": "Goo", + "quality": 1, + "duration": 1, }, { - "Trait": "Gel", - "Quality": 1, - "Duration": 1 + "trait": "Gel", + "quality": 1, + "duration": 1 } ] }, 1: { - "ItemName": "Slowness", - "Amount": 1, - "ItemValue": 10000, - "Traits": [ + "item_name": "Slowness", + "amount": 1, + "item_value": 10000, + "traits": [ { - "Trait": "Trap", - "Quality": 1, - "Duration": 1, + "trait": "Trap", + "quality": 1, + "duration": 1, }, { - "Trait": "Slow", - "Quality": 1, - "Duration": 1, + "trait": "Slow", + "quality": 1, + "duration": 1, }, { - "Trait": "Slowness", - "Quality": 1, - "Duration": 1 + "trait": "Slowness", + "quality": 1, + "duration": 1 } ] }, 2: { - "ItemName": "Eject Ability", - "Amount": 1, - "ItemValue": 10000, - "Traits": [ + "item_name": "Eject Ability", + "amount": 1, + "item_value": 10000, + "traits": [ { - "Trait": "Trap", - "Quality": 1, - "Duration": 1, + "trait": "Trap", + "quality": 1, + "duration": 1, }, { - "Trait": "Eject", - "Quality": 1, - "Duration": 1, + "trait": "Eject", + "quality": 1, + "duration": 1, }, { - "Trait": "Removal", - "Quality": 1, - "Duration": 1 + "trait": "Removal", + "quality": 1, + "duration": 1 } ] }, 3: { - "ItemName": "Bad Meal", - "Amount": 1, - "ItemValue": 10000, - "Traits": [ + "item_name": "Bad Meal", + "amount": 1, + "item_value": 10000, + "traits": [ { - "Trait": "Trap", - "Quality": 1, - "Duration": 1, + "trait": "Trap", + "quality": 1, + "duration": 1, }, { - "Trait": "Damage", - "Quality": 1, - "Duration": 1, + "trait": "Damage", + "quality": 1, + "duration": 1, }, { - "Trait": "Food", - "Quality": 1, - "Duration": 1 + "trait": "Food", + "quality": 1, + "duration": 1 } ] }, diff --git a/worlds/kdl3/options.py b/worlds/kdl3/options.py index b9163794..77095bfe 100644 --- a/worlds/kdl3/options.py +++ b/worlds/kdl3/options.py @@ -289,7 +289,7 @@ class KirbyFlavorPreset(Choice): option_lime = 12 option_lavender = 13 option_miku = 14 - option_custom = 15 + option_custom = -1 default = 0 @classmethod @@ -297,7 +297,7 @@ class KirbyFlavorPreset(Choice): text = text.lower() if text == "random": choice_list = list(cls.name_lookup) - choice_list.remove(14) + choice_list.remove(-1) return cls(random.choice(choice_list)) return super().from_text(text) @@ -347,7 +347,7 @@ class GooeyFlavorPreset(Choice): option_orange = 11 option_lime = 12 option_lavender = 13 - option_custom = 14 + option_custom = -1 default = 0 @classmethod @@ -355,7 +355,7 @@ class GooeyFlavorPreset(Choice): text = text.lower() if text == "random": choice_list = list(cls.name_lookup) - choice_list.remove(14) + choice_list.remove(-1) return cls(random.choice(choice_list)) return super().from_text(text) diff --git a/worlds/kdl3/rom.py b/worlds/kdl3/rom.py index 741ea008..5f986bc4 100644 --- a/worlds/kdl3/rom.py +++ b/worlds/kdl3/rom.py @@ -7,7 +7,6 @@ import hashlib import os import struct -import settings from worlds.Files import APProcedurePatch, APTokenMixin, APTokenTypes, APPatchExtension from .aesthetics import get_palette_bytes, kirby_target_palettes, get_kirby_palette, gooey_target_palettes, \ get_gooey_palette @@ -475,8 +474,7 @@ def patch_rom(world: "KDL3World", patch: KDL3ProcedurePatch) -> None: patch.write_token(APTokenTypes.WRITE, 0x3D016, world.options.ow_boss_requirement.value.to_bytes(2, "little")) patch.write_token(APTokenTypes.WRITE, 0x3D018, world.options.consumables.value.to_bytes(2, "little")) patch.write_token(APTokenTypes.WRITE, 0x3D01A, world.options.starsanity.value.to_bytes(2, "little")) - patch.write_token(APTokenTypes.WRITE, 0x3D01C, world.options.gifting.value.to_bytes(2, "little") - if world.multiworld.players > 1 else bytes([0, 0])) + patch.write_token(APTokenTypes.WRITE, 0x3D01C, world.options.gifting.value.to_bytes(2, "little")) patch.write_token(APTokenTypes.WRITE, 0x3D01E, world.options.strict_bosses.value.to_bytes(2, "little")) # don't write gifting for solo game, since there's no one to send anything to @@ -594,9 +592,9 @@ def get_base_rom_bytes() -> bytes: def get_base_rom_path(file_name: str = "") -> str: - options: settings.Settings = settings.get_settings() + from . import KDL3World if not file_name: - file_name = options["kdl3_options"]["rom_file"] + file_name = KDL3World.settings.rom_file if not os.path.exists(file_name): file_name = Utils.user_path(file_name) return file_name