diff --git a/worlds/ladx/ItemIconGuessing.py b/worlds/ladx/ItemIconGuessing.py new file mode 100644 index 000000000000..e3d2ad7b8295 --- /dev/null +++ b/worlds/ladx/ItemIconGuessing.py @@ -0,0 +1,531 @@ +BLOCKED_ASSOCIATIONS = [ + # MAX_ARROWS_UPGRADE, MAX_BOMBS_UPGRADE, MAX_POWDER_UPGRADE + # arrows and bombs will be matched to arrow and bomb respectively through pluralization + "ARROWS", + "BOMBS", + "MAX", + "UPGRADE", + + "TAIL", # TAIL_KEY + "ANGLER", # ANGLER_KEY + "FACE", # FACE_KEY + "BIRD", # BIRD_KEY + "SLIME", # SLIME_KEY + "NIGHTMARE",# NIGHTMARE_KEY + + "BLUE", # BLUE_TUNIC + "RED", # RED_TUNIC + + "TRADING", # TRADING_ITEM_* + "ITEM", # TRADING_ITEM_* + + "BAD", # BAD_HEART_CONTAINER + "GOLD", # GOLD_LEAF + "MAGIC", # MAGIC_POWDER, MAGIC_ROD + "MESSAGE", # MESSAGE (Master Stalfos' Message) + "PEGASUS", # PEGASUS_BOOTS + "PIECE", # HEART_PIECE, PIECE_OF_POWER + "POWER", # POWER_BRACELET, PIECE_OF_POWER + "SINGLE", # SINGLE_ARROW + "STONE", # STONE_BEAK + + "BEAK1", + "BEAK2", + "BEAK3", + "BEAK4", + "BEAK5", + "BEAK6", + "BEAK7", + "BEAK8", + + "COMPASS1", + "COMPASS2", + "COMPASS3", + "COMPASS4", + "COMPASS5", + "COMPASS6", + "COMPASS7", + "COMPASS8", + + "MAP1", + "MAP2", + "MAP3", + "MAP4", + "MAP5", + "MAP6", + "MAP7", + "MAP8", +] + +# Single word synonyms for Link's Awakening items, for generic matching. +SYNONYMS = { + # POWER_BRACELET + 'ANKLET': 'POWER_BRACELET', + 'ARMLET': 'POWER_BRACELET', + 'BAND': 'POWER_BRACELET', + 'BANGLE': 'POWER_BRACELET', + 'BRACER': 'POWER_BRACELET', + 'CARRY': 'POWER_BRACELET', + 'CIRCLET': 'POWER_BRACELET', + 'CROISSANT': 'POWER_BRACELET', + 'GAUNTLET': 'POWER_BRACELET', + 'GLOVE': 'POWER_BRACELET', + 'RING': 'POWER_BRACELET', + 'STRENGTH': 'POWER_BRACELET', + + # SHIELD + 'AEGIS': 'SHIELD', + 'BUCKLER': 'SHIELD', + 'SHLD': 'SHIELD', + + # BOW + 'BALLISTA': 'BOW', + + # HOOKSHOT + 'GRAPPLE': 'HOOKSHOT', + 'GRAPPLING': 'HOOKSHOT', + 'ROPE': 'HOOKSHOT', + + # MAGIC_ROD + 'BEAM': 'MAGIC_ROD', + 'CANE': 'MAGIC_ROD', + 'STAFF': 'MAGIC_ROD', + 'WAND': 'MAGIC_ROD', + + # PEGASUS_BOOTS + 'BOOT': 'PEGASUS_BOOTS', + 'GREAVES': 'PEGASUS_BOOTS', + 'RUN': 'PEGASUS_BOOTS', + 'SHOE': 'PEGASUS_BOOTS', + 'SPEED': 'PEGASUS_BOOTS', + + # OCARINA + 'FLUTE': 'OCARINA', + 'RECORDER': 'OCARINA', + + # FEATHER + 'JUMP': 'FEATHER', + 'PLUME': 'FEATHER', + 'WING': 'FEATHER', + + # SHOVEL + 'DIG': 'SHOVEL', + + # MAGIC_POWDER + 'BAG': 'MAGIC_POWDER', + 'CASE': 'MAGIC_POWDER', + 'DUST': 'MAGIC_POWDER', + 'POUCH': 'MAGIC_POWDER', + 'SACK': 'MAGIC_POWDER', + + # BOMB + 'BLAST': 'BOMB', + 'BOMBCHU': 'BOMB', + 'FIRECRACKER': 'BOMB', + 'TNT': 'BOMB', + + # SWORD + 'BLADE': 'SWORD', + 'CUT': 'SWORD', + 'DAGGER': 'SWORD', + 'DIRK': 'SWORD', + 'EDGE': 'SWORD', + 'EPEE': 'SWORD', + 'EXCALIBUR': 'SWORD', + 'FALCHION': 'SWORD', + 'KATANA': 'SWORD', + 'KNIFE': 'SWORD', + 'MACHETE': 'SWORD', + 'MASAMUNE': 'SWORD', + 'MURASAME': 'SWORD', + 'SABER': 'SWORD', + 'SABRE': 'SWORD', + 'SCIMITAR': 'SWORD', + 'SLASH': 'SWORD', + + # FLIPPERS + 'FLIPPER': 'FLIPPERS', + 'SWIM': 'FLIPPERS', + + # MEDICINE + 'BOTTLE': 'MEDICINE', + 'FLASK': 'MEDICINE', + 'LEMONADE': 'MEDICINE', + 'POTION': 'MEDICINE', + 'TEA': 'MEDICINE', + + # TAIL_KEY + + # ANGLER_KEY + + # FACE_KEY + + # BIRD_KEY + + # SLIME_KEY + + # GOLD_LEAF + 'HERB': 'GOLD_LEAF', + + # RUPEES_20 + 'COIN': 'RUPEES_20', + 'MONEY': 'RUPEES_20', + 'RUPEE': 'RUPEES_20', + + # RUPEES_50 + + # RUPEES_100 + + # RUPEES_200 + + # RUPEES_500 + 'GEM': 'RUPEES_500', + 'JEWEL': 'RUPEES_500', + + # SEASHELL + 'CARAPACE': 'SEASHELL', + 'CONCH': 'SEASHELL', + 'SHELL': 'SEASHELL', + + # MESSAGE (master stalfos message) + 'NOTHING': 'MESSAGE', + 'TRAP': 'MESSAGE', + + # BOOMERANG + 'BOOMER': 'BOOMERANG', + + # HEART_PIECE + + # BOWWOW + 'BEAST': 'BOWWOW', + 'PET': 'BOWWOW', + + # ARROWS_10 + + # SINGLE_ARROW + 'MISSILE': 'SINGLE_ARROW', + 'QUIVER': 'SINGLE_ARROW', + + # ROOSTER + 'BIRD': 'ROOSTER', + 'CHICKEN': 'ROOSTER', + 'CUCCO': 'ROOSTER', + 'FLY': 'ROOSTER', + 'GRIFFIN': 'ROOSTER', + 'GRYPHON': 'ROOSTER', + + # MAX_POWDER_UPGRADE + + # MAX_BOMBS_UPGRADE + + # MAX_ARROWS_UPGRADE + + # RED_TUNIC + + # BLUE_TUNIC + 'ARMOR': 'BLUE_TUNIC', + 'MAIL': 'BLUE_TUNIC', + 'SUIT': 'BLUE_TUNIC', + + # HEART_CONTAINER + 'TANK': 'HEART_CONTAINER', + + # TOADSTOOL + 'FUNGAL': 'TOADSTOOL', + 'FUNGUS': 'TOADSTOOL', + 'MUSHROOM': 'TOADSTOOL', + 'SHROOM': 'TOADSTOOL', + + # GUARDIAN_ACORN + 'NUT': 'GUARDIAN_ACORN', + 'SEED': 'GUARDIAN_ACORN', + + # KEY + 'DOOR': 'KEY', + 'GATE': 'KEY', + 'KEY': 'KEY', # Without this, foreign keys show up as nightmare keys + 'LOCK': 'KEY', + 'PANEL': 'KEY', + 'UNLOCK': 'KEY', + + # NIGHTMARE_KEY + + # MAP + + # COMPASS + + # STONE_BEAK + 'FOSSIL': 'STONE_BEAK', + 'RELIC': 'STONE_BEAK', + + # SONG1 + 'BOLERO': 'SONG1', + 'LULLABY': 'SONG1', + 'MELODY': 'SONG1', + 'MINUET': 'SONG1', + 'NOCTURNE': 'SONG1', + 'PRELUDE': 'SONG1', + 'REQUIEM': 'SONG1', + 'SERENADE': 'SONG1', + 'SONG': 'SONG1', + + # SONG2 + 'FISH': 'SONG2', + 'SURF': 'SONG2', + + # SONG3 + 'FROG': 'SONG3', + + # INSTRUMENT1 + 'CELLO': 'INSTRUMENT1', + 'GUITAR': 'INSTRUMENT1', + 'LUTE': 'INSTRUMENT1', + 'VIOLIN': 'INSTRUMENT1', + + # INSTRUMENT2 + 'HORN': 'INSTRUMENT2', + + # INSTRUMENT3 + 'BELL': 'INSTRUMENT3', + 'CHIME': 'INSTRUMENT3', + + # INSTRUMENT4 + 'HARP': 'INSTRUMENT4', + 'KANTELE': 'INSTRUMENT4', + + # INSTRUMENT5 + 'MARIMBA': 'INSTRUMENT5', + 'XYLOPHONE': 'INSTRUMENT5', + + # INSTRUMENT6 (triangle) + + # INSTRUMENT7 + 'KEYBOARD': 'INSTRUMENT7', + 'ORGAN': 'INSTRUMENT7', + 'PIANO': 'INSTRUMENT7', + + # INSTRUMENT8 + 'DRUM': 'INSTRUMENT8', + + # TRADING_ITEM_YOSHI_DOLL + 'DINOSAUR': 'TRADING_ITEM_YOSHI_DOLL', + 'DRAGON': 'TRADING_ITEM_YOSHI_DOLL', + 'TOY': 'TRADING_ITEM_YOSHI_DOLL', + + # TRADING_ITEM_RIBBON + 'HAIRBAND': 'TRADING_ITEM_RIBBON', + 'HAIRPIN': 'TRADING_ITEM_RIBBON', + + # TRADING_ITEM_DOG_FOOD + 'CAN': 'TRADING_ITEM_DOG_FOOD', + + # TRADING_ITEM_BANANAS + 'BANANA': 'TRADING_ITEM_BANANAS', + + # TRADING_ITEM_STICK + 'BRANCH': 'TRADING_ITEM_STICK', + 'TWIG': 'TRADING_ITEM_STICK', + + # TRADING_ITEM_HONEYCOMB + 'BEEHIVE': 'TRADING_ITEM_HONEYCOMB', + 'HIVE': 'TRADING_ITEM_HONEYCOMB', + 'HONEY': 'TRADING_ITEM_HONEYCOMB', + + # TRADING_ITEM_PINEAPPLE + 'FOOD': 'TRADING_ITEM_PINEAPPLE', + 'FRUIT': 'TRADING_ITEM_PINEAPPLE', + 'GOURD': 'TRADING_ITEM_PINEAPPLE', + + # TRADING_ITEM_HIBISCUS + 'FLOWER': 'TRADING_ITEM_HIBISCUS', + 'PETAL': 'TRADING_ITEM_HIBISCUS', + + # TRADING_ITEM_LETTER + 'CARD': 'TRADING_ITEM_LETTER', + 'MESSAGE': 'TRADING_ITEM_LETTER', + + # TRADING_ITEM_BROOM + 'SWEEP': 'TRADING_ITEM_BROOM', + + # TRADING_ITEM_FISHING_HOOK + 'CLAW': 'TRADING_ITEM_FISHING_HOOK', + + # TRADING_ITEM_NECKLACE + 'AMULET': 'TRADING_ITEM_NECKLACE', + 'BEADS': 'TRADING_ITEM_NECKLACE', + 'PEARLS': 'TRADING_ITEM_NECKLACE', + 'PENDANT': 'TRADING_ITEM_NECKLACE', + 'ROSARY': 'TRADING_ITEM_NECKLACE', + + # TRADING_ITEM_SCALE + + # TRADING_ITEM_MAGNIFYING_GLASS + 'FINDER': 'TRADING_ITEM_MAGNIFYING_GLASS', + 'LENS': 'TRADING_ITEM_MAGNIFYING_GLASS', + 'MIRROR': 'TRADING_ITEM_MAGNIFYING_GLASS', + 'SCOPE': 'TRADING_ITEM_MAGNIFYING_GLASS', + 'XRAY': 'TRADING_ITEM_MAGNIFYING_GLASS', + + # PIECE_OF_POWER + 'TRIANGLE': 'PIECE_OF_POWER', + 'POWER': 'PIECE_OF_POWER', + 'TRIFORCE': 'PIECE_OF_POWER', +} + +# For generic multi-word matches. +PHRASES = { + 'BIG KEY': 'NIGHTMARE_KEY', + 'BOSS KEY': 'NIGHTMARE_KEY', + 'HEART PIECE': 'HEART_PIECE', + 'PIECE OF HEART': 'HEART_PIECE', +} + +# All following will only be used to match items for the specific game. +# Item names will be uppercased when comparing. +# Can be multi-word. +GAME_SPECIFIC_PHRASES = { + 'Final Fantasy': { + 'OXYALE': 'MEDICINE', + 'VORPAL': 'SWORD', + 'XCALBER': 'SWORD', + }, + + 'The Legend of Zelda': { + 'WATER OF LIFE': 'MEDICINE', + }, + + 'The Legend of Zelda - Oracle of Seasons': { + 'RARE PEACH STONE': 'HEART_PIECE', + }, + + 'Noita': { + 'ALL-SEEING EYE': 'TRADING_ITEM_MAGNIFYING_GLASS', # lets you find secrets + }, + + 'Ocarina of Time': { + 'COJIRO': 'ROOSTER', + }, + + 'SMZ3': { + 'BIGKEY': 'NIGHTMARE_KEY', + 'BYRNA': 'MAGIC_ROD', + 'HEARTPIECE': 'HEART_PIECE', + 'POWERBOMB': 'BOMB', + 'SOMARIA': 'MAGIC_ROD', + 'SUPER': 'SINGLE_ARROW', + }, + + 'Sonic Adventure 2 Battle': { + 'CHAOS EMERALD': 'PIECE_OF_POWER', + }, + + 'Super Mario 64': { + 'POWER STAR': 'PIECE_OF_POWER', + }, + + 'Super Mario World': { + 'P-BALLOON': 'FEATHER', + }, + + 'Super Metroid': { + 'POWER BOMB': 'BOMB', + }, + + 'The Witness': { + 'BONK': 'BOMB', + 'BUNKER LASER': 'INSTRUMENT4', + 'DESERT LASER': 'INSTRUMENT5', + 'JUNGLE LASER': 'INSTRUMENT4', + 'KEEP LASER': 'INSTRUMENT7', + 'MONASTERY LASER': 'INSTRUMENT1', + 'POWER SURGE': 'BOMB', + 'PUZZLE SKIP': 'GOLD_LEAF', + 'QUARRY LASER': 'INSTRUMENT8', + 'SHADOWS LASER': 'INSTRUMENT1', + 'SHORTCUTS': 'KEY', + 'SLOWNESS': 'BOMB', + 'SWAMP LASER': 'INSTRUMENT2', + 'SYMMETRY LASER': 'INSTRUMENT6', + 'TOWN LASER': 'INSTRUMENT3', + 'TREEHOUSE LASER': 'INSTRUMENT2', + 'WATER PUMPS': 'KEY', + }, + + 'TUNIC': { + "AURA'S GEM": 'SHIELD', # card that enhances the shield + 'DUSTY': 'TRADING_ITEM_BROOM', # a broom + 'HERO RELIC - HP': 'TRADING_ITEM_HIBISCUS', + 'HERO RELIC - MP': 'TOADSTOOL', + 'HERO RELIC - SP': 'FEATHER', + 'HP BERRY': 'GUARDIAN_ACORN', + 'HP OFFERING': 'TRADING_ITEM_HIBISCUS', # a flower + 'LUCKY CUP': 'HEART_CONTAINER', # card with a heart on it + 'INVERTED ASH': 'MEDICINE', # card with a potion on it + 'MAGIC ORB': 'HOOKSHOT', + 'MP BERRY': 'GUARDIAN_ACORN', + 'MP OFFERING': 'TOADSTOOL', # a mushroom + 'QUESTAGON': 'PIECE_OF_POWER', # triforce piece equivalent + 'SP OFFERING': 'FEATHER', # a feather + 'SPRING FALLS': 'TRADING_ITEM_HIBISCUS', # a flower + }, + + 'FNaFW': { + 'Freddy': 'TRADING_ITEM_YOSHI_DOLL', # all of these are animatronics, aka dolls. + 'Bonnie': 'TRADING_ITEM_YOSHI_DOLL', + 'Chica': 'TRADING_ITEM_YOSHI_DOLL', + 'Foxy': 'TRADING_ITEM_YOSHI_DOLL', + 'Toy Bonnie': 'TRADING_ITEM_YOSHI_DOLL', + 'Toy Chica': 'TRADING_ITEM_YOSHI_DOLL', + 'Toy Freddy': 'TRADING_ITEM_YOSHI_DOLL', + 'Mangle': 'TRADING_ITEM_YOSHI_DOLL', + 'Balloon Boy': 'TRADING_ITEM_YOSHI_DOLL', + 'JJ': 'TRADING_ITEM_YOSHI_DOLL', + 'Phantom Freddy': 'TRADING_ITEM_YOSHI_DOLL', + 'Phantom BB': 'TRADING_ITEM_YOSHI_DOLL', + 'Phantom Chica': 'TRADING_ITEM_YOSHI_DOLL', + 'Phantom Mangle': 'TRADING_ITEM_YOSHI_DOLL', + 'Withered Foxy': 'TRADING_ITEM_YOSHI_DOLL', + 'Phantom Foxy': 'TRADING_ITEM_YOSHI_DOLL', + 'Withered Chica': 'TRADING_ITEM_YOSHI_DOLL', + 'Withered Freddy': 'TRADING_ITEM_YOSHI_DOLL', + 'Withered Bonnie': 'TRADING_ITEM_YOSHI_DOLL', + 'Shadow Freddy': 'TRADING_ITEM_YOSHI_DOLL', + 'Marionette': 'TRADING_ITEM_YOSHI_DOLL', + 'Phantom Marionette': 'TRADING_ITEM_YOSHI_DOLL', + 'Golden Freddy': 'TRADING_ITEM_YOSHI_DOLL', + 'Paperpals': 'TRADING_ITEM_YOSHI_DOLL', + 'Nightmare Freddy': 'TRADING_ITEM_YOSHI_DOLL', + 'Nightmare Bonnie': 'TRADING_ITEM_YOSHI_DOLL', + 'Nightmare Chica': 'TRADING_ITEM_YOSHI_DOLL', + 'Nightmare Foxy': 'TRADING_ITEM_YOSHI_DOLL', + 'Endo 01': 'TRADING_ITEM_YOSHI_DOLL', + 'Endo 02': 'TRADING_ITEM_YOSHI_DOLL', + 'Plushtrap': 'TRADING_ITEM_YOSHI_DOLL', + 'Endoplush': 'TRADING_ITEM_YOSHI_DOLL', + 'Springtrap': 'TRADING_ITEM_YOSHI_DOLL', + 'RWQFSFASXC': 'TRADING_ITEM_YOSHI_DOLL', + 'Crying Child': 'TRADING_ITEM_YOSHI_DOLL', + 'Funtime Foxy': 'TRADING_ITEM_YOSHI_DOLL', + 'Nightmare Fredbear': 'TRADING_ITEM_YOSHI_DOLL', + 'Nightmare': 'TRADING_ITEM_YOSHI_DOLL', + 'Fredbear': 'TRADING_ITEM_YOSHI_DOLL', + 'Spring Bonnie': 'TRADING_ITEM_YOSHI_DOLL', + 'Jack-O-Chica': 'TRADING_ITEM_YOSHI_DOLL', + 'Nightmare BB': 'TRADING_ITEM_YOSHI_DOLL', + 'Coffee': 'TRADING_ITEM_YOSHI_DOLL', + 'Jack-O-Bonnie': 'TRADING_ITEM_YOSHI_DOLL', + 'Purpleguy': 'TRADING_ITEM_YOSHI_DOLL', + 'Nightmarionne': 'TRADING_ITEM_YOSHI_DOLL', + 'Mr. Chipper': 'TRADING_ITEM_YOSHI_DOLL', + 'Animdude': 'TRADING_ITEM_YOSHI_DOLL', + 'Progressive Endoskeleton': 'BLUE_TUNIC', # basically armor you wear to give you more defense + '25 Tokens': 'RUPEES_20', # money + '50 Tokens': 'RUPEES_50', + '100 Tokens': 'RUPEES_100', + '250 Tokens': 'RUPEES_200', + '500 Tokens': 'RUPEES_500', + '1000 Tokens': 'RUPEES_500', + '2500 Tokens': 'RUPEES_500', + '5000 Tokens': 'RUPEES_500', + }, +} diff --git a/worlds/ladx/Items.py b/worlds/ladx/Items.py index 2a64c59394e6..32d466373cae 100644 --- a/worlds/ladx/Items.py +++ b/worlds/ladx/Items.py @@ -98,6 +98,7 @@ class ItemName: HEART_CONTAINER = "Heart Container" BAD_HEART_CONTAINER = "Bad Heart Container" TOADSTOOL = "Toadstool" + GUARDIAN_ACORN = "Guardian Acorn" KEY = "Key" KEY1 = "Small Key (Tail Cave)" KEY2 = "Small Key (Bottle Grotto)" @@ -173,6 +174,7 @@ class ItemName: TRADING_ITEM_NECKLACE = "Necklace" TRADING_ITEM_SCALE = "Scale" TRADING_ITEM_MAGNIFYING_GLASS = "Magnifying Glass" + PIECE_OF_POWER = "Piece Of Power" trade_item_prog = ItemClassification.progression @@ -219,6 +221,7 @@ class ItemName: ItemData(ItemName.HEART_CONTAINER, "HEART_CONTAINER", ItemClassification.useful), #ItemData(ItemName.BAD_HEART_CONTAINER, "BAD_HEART_CONTAINER", ItemClassification.trap), ItemData(ItemName.TOADSTOOL, "TOADSTOOL", ItemClassification.progression), + ItemData(ItemName.GUARDIAN_ACORN, "GUARDIAN_ACORN", ItemClassification.filler), DungeonItemData(ItemName.KEY, "KEY", ItemClassification.progression), DungeonItemData(ItemName.KEY1, "KEY1", ItemClassification.progression), DungeonItemData(ItemName.KEY2, "KEY2", ItemClassification.progression), @@ -293,7 +296,8 @@ class ItemName: TradeItemData(ItemName.TRADING_ITEM_FISHING_HOOK, "TRADING_ITEM_FISHING_HOOK", trade_item_prog, "Grandma (Animal Village)"), TradeItemData(ItemName.TRADING_ITEM_NECKLACE, "TRADING_ITEM_NECKLACE", trade_item_prog, "Fisher (Martha's Bay)"), TradeItemData(ItemName.TRADING_ITEM_SCALE, "TRADING_ITEM_SCALE", trade_item_prog, "Mermaid (Martha's Bay)"), - TradeItemData(ItemName.TRADING_ITEM_MAGNIFYING_GLASS, "TRADING_ITEM_MAGNIFYING_GLASS", trade_item_prog, "Mermaid Statue (Martha's Bay)") + TradeItemData(ItemName.TRADING_ITEM_MAGNIFYING_GLASS, "TRADING_ITEM_MAGNIFYING_GLASS", trade_item_prog, "Mermaid Statue (Martha's Bay)"), + ItemData(ItemName.PIECE_OF_POWER, "PIECE_OF_POWER", ItemClassification.filler), ] ladxr_item_to_la_item_name = { diff --git a/worlds/ladx/LADXR/locations/constants.py b/worlds/ladx/LADXR/locations/constants.py index a0489febc316..bcf22711bb7b 100644 --- a/worlds/ladx/LADXR/locations/constants.py +++ b/worlds/ladx/LADXR/locations/constants.py @@ -87,6 +87,8 @@ TOADSTOOL: 0x50, + GUARDIAN_ACORN: 0x51, + HEART_PIECE: 0x80, BOWWOW: 0x81, ARROWS_10: 0x82, @@ -128,4 +130,6 @@ TRADING_ITEM_NECKLACE: 0xA2, TRADING_ITEM_SCALE: 0xA3, TRADING_ITEM_MAGNIFYING_GLASS: 0xA4, + + PIECE_OF_POWER: 0xA5, } diff --git a/worlds/ladx/LADXR/locations/items.py b/worlds/ladx/LADXR/locations/items.py index 1ecc331f8580..56cc52232355 100644 --- a/worlds/ladx/LADXR/locations/items.py +++ b/worlds/ladx/LADXR/locations/items.py @@ -44,6 +44,8 @@ TOADSTOOL = "TOADSTOOL" +GUARDIAN_ACORN = "GUARDIAN_ACORN" + KEY = "KEY" KEY1 = "KEY1" KEY2 = "KEY2" @@ -124,3 +126,5 @@ TRADING_ITEM_NECKLACE = "TRADING_ITEM_NECKLACE" TRADING_ITEM_SCALE = "TRADING_ITEM_SCALE" TRADING_ITEM_MAGNIFYING_GLASS = "TRADING_ITEM_MAGNIFYING_GLASS" + +PIECE_OF_POWER = "PIECE_OF_POWER" \ No newline at end of file diff --git a/worlds/ladx/LADXR/patches/bank3e.asm/chest.asm b/worlds/ladx/LADXR/patches/bank3e.asm/chest.asm index 57771c17b3ca..de237c86293b 100644 --- a/worlds/ladx/LADXR/patches/bank3e.asm/chest.asm +++ b/worlds/ladx/LADXR/patches/bank3e.asm/chest.asm @@ -835,6 +835,7 @@ ItemSpriteTable: db $46, $1C ; NIGHTMARE_KEY8 db $46, $1C ; NIGHTMARE_KEY9 db $4C, $1C ; Toadstool + db $AE, $14 ; Guardian Acorn LargeItemSpriteTable: db $AC, $02, $AC, $22 ; heart piece @@ -874,6 +875,7 @@ LargeItemSpriteTable: db $D8, $0D, $DA, $0D ; TradeItem12 db $DC, $0D, $DE, $0D ; TradeItem13 db $E0, $0D, $E2, $0D ; TradeItem14 + db $14, $42, $14, $62 ; Piece Of Power ItemMessageTable: db $90, $3D, $89, $93, $94, $95, $96, $97, $98, $99, $9A, $9B, $9C, $9D, $D9, $A2 @@ -888,7 +890,7 @@ ItemMessageTable: ; $80 db $4F, $C8, $CA, $CB, $E2, $E3, $E4, $CC, $CD, $2A, $2B, $C9, $C9, $C9, $C9, $C9 db $C9, $C9, $C9, $C9, $C9, $C9, $B8, $44, $C9, $C9, $C9, $C9, $C9, $C9, $C9, $C9 - db $C9, $C9, $C9, $C9, $9D + db $C9, $C9, $C9, $C9, $9D, $C9 RenderDroppedKey: ;TODO: See EntityInitKeyDropPoint for a few special cases to unload. diff --git a/worlds/ladx/LADXR/patches/bank3e.asm/itemnames.asm b/worlds/ladx/LADXR/patches/bank3e.asm/itemnames.asm index 0c1bc9d699e4..c57ce2f81ccd 100644 --- a/worlds/ladx/LADXR/patches/bank3e.asm/itemnames.asm +++ b/worlds/ladx/LADXR/patches/bank3e.asm/itemnames.asm @@ -170,7 +170,7 @@ ItemNamePointers: dw ItemNameNightmareKey8 dw ItemNameNightmareKey9 dw ItemNameToadstool - dw ItemNameNone ; 0x51 + dw ItemNameGuardianAcorn dw ItemNameNone ; 0x52 dw ItemNameNone ; 0x53 dw ItemNameNone ; 0x54 @@ -254,6 +254,7 @@ ItemNamePointers: dw ItemTradeQuest12 dw ItemTradeQuest13 dw ItemTradeQuest14 + dw ItemPieceOfPower ItemNameNone: db m"NONE", $ff @@ -418,6 +419,8 @@ ItemNameNightmareKey9: db m"Got the {NIGHTMARE_KEY9}", $ff ItemNameToadstool: db m"Got the {TOADSTOOL}", $ff +ItemNameGuardianAcorn: + db m"Got a Guardian Acorn", $ff ItemNameHeartPiece: db m"Got the {HEART_PIECE}", $ff @@ -496,5 +499,8 @@ ItemTradeQuest13: db m"You've got the Scale", $ff ItemTradeQuest14: db m"You've got the Magnifying Lens", $ff + +ItemPieceOfPower: + db m"You've got a Piece of Power", $ff MultiNamePointers: \ No newline at end of file diff --git a/worlds/ladx/LADXR/patches/droppedKey.py b/worlds/ladx/LADXR/patches/droppedKey.py index d24b8b76c7a9..7853712a114a 100644 --- a/worlds/ladx/LADXR/patches/droppedKey.py +++ b/worlds/ladx/LADXR/patches/droppedKey.py @@ -24,14 +24,10 @@ def fixDroppedKey(rom): ld a, $06 ; giveItemMultiworld rst 8 - ldh a, [$F1] ; Load active sprite variant to see if this is just a normal small key - cp $1A - jr z, isAKey - - ;Show message (if not a key) + ;Show message ld a, $0A ; showMessageMultiworld rst 8 -isAKey: + ret """)) rom.patch(0x03, 0x24B7, "3E", "3E") # sanity check diff --git a/worlds/ladx/Options.py b/worlds/ladx/Options.py index 9414a7e3c89b..17052659157f 100644 --- a/worlds/ladx/Options.py +++ b/worlds/ladx/Options.py @@ -505,6 +505,19 @@ class InGameHints(DefaultOnToggle): display_name = "In-game Hints" + +class ForeignItemIcons(Choice): + """ + Choose how to display foreign items. + [Guess By Name] Foreign items can look like any Link's Awakening item. + [Indicate Progression] Foreign items are either a Piece of Power (progression) or Guardian Acorn (non-progression). + """ + display_name = "Foreign Item Icons" + option_guess_by_name = 0 + option_indicate_progression = 1 + default = option_guess_by_name + + ladx_option_groups = [ OptionGroup("Goal Options", [ Goal, @@ -537,6 +550,7 @@ class InGameHints(DefaultOnToggle): LinkPalette, Palette, TextShuffle, + ForeignItemIcons, APTitleScreen, GfxMod, Music, @@ -571,6 +585,7 @@ class LinksAwakeningOptions(PerGameCommonOptions): gfxmod: GfxMod palette: Palette text_shuffle: TextShuffle + foreign_item_icons: ForeignItemIcons shuffle_nightmare_keys: ShuffleNightmareKeys shuffle_small_keys: ShuffleSmallKeys shuffle_maps: ShuffleMaps diff --git a/worlds/ladx/__init__.py b/worlds/ladx/__init__.py index 7499aca8c404..8496d4cf49e3 100644 --- a/worlds/ladx/__init__.py +++ b/worlds/ladx/__init__.py @@ -4,6 +4,7 @@ import pkgutil import tempfile import typing +import re import bsdiff4 @@ -12,6 +13,7 @@ from Fill import fill_restrictive from worlds.AutoWorld import WebWorld, World from .Common import * +from . import ItemIconGuessing from .Items import (DungeonItemData, DungeonItemType, ItemName, LinksAwakeningItem, TradeItemData, ladxr_item_to_la_item_name, links_awakening_items, links_awakening_items_by_name, links_awakening_item_name_groups) @@ -380,66 +382,36 @@ def priority(item): name_cache = {} # Tries to associate an icon from another game with an icon we have - def guess_icon_for_other_world(self, other): + def guess_icon_for_other_world(self, foreign_item): if not self.name_cache: - forbidden = [ - "TRADING", - "ITEM", - "BAD", - "SINGLE", - "UPGRADE", - "BLUE", - "RED", - "NOTHING", - "MESSAGE", - ] for item in ladxr_item_to_la_item_name.keys(): self.name_cache[item] = item splits = item.split("_") - self.name_cache["".join(splits)] = item - if 'RUPEES' in splits: - self.name_cache["".join(reversed(splits))] = item - for word in item.split("_"): - if word not in forbidden and not word.isnumeric(): + if word not in ItemIconGuessing.BLOCKED_ASSOCIATIONS and not word.isnumeric(): self.name_cache[word] = item - others = { - 'KEY': 'KEY', - 'COMPASS': 'COMPASS', - 'BIGKEY': 'NIGHTMARE_KEY', - 'MAP': 'MAP', - 'FLUTE': 'OCARINA', - 'SONG': 'OCARINA', - 'MUSHROOM': 'TOADSTOOL', - 'GLOVE': 'POWER_BRACELET', - 'BOOT': 'PEGASUS_BOOTS', - 'SHOE': 'PEGASUS_BOOTS', - 'SHOES': 'PEGASUS_BOOTS', - 'SANCTUARYHEARTCONTAINER': 'HEART_CONTAINER', - 'BOSSHEARTCONTAINER': 'HEART_CONTAINER', - 'HEARTCONTAINER': 'HEART_CONTAINER', - 'ENERGYTANK': 'HEART_CONTAINER', - 'MISSILE': 'SINGLE_ARROW', - 'BOMBS': 'BOMB', - 'BLUEBOOMERANG': 'BOOMERANG', - 'MAGICMIRROR': 'TRADING_ITEM_MAGNIFYING_GLASS', - 'MIRROR': 'TRADING_ITEM_MAGNIFYING_GLASS', - 'MESSAGE': 'TRADING_ITEM_LETTER', - # TODO: Also use AP item name - } - for name in others.values(): + for name in ItemIconGuessing.SYNONYMS.values(): assert name in self.name_cache, name assert name in CHEST_ITEMS, name - self.name_cache.update(others) - - - uppered = other.upper() - if "BIG KEY" in uppered: - return 'NIGHTMARE_KEY' - possibles = other.upper().split(" ") - rejoined = "".join(possibles) - if rejoined in self.name_cache: - return self.name_cache[rejoined] + self.name_cache.update(ItemIconGuessing.SYNONYMS) + pluralizations = {k + "S": v for k, v in self.name_cache.items()} + self.name_cache = pluralizations | self.name_cache + + uppered = foreign_item.name.upper() + foreign_game = self.multiworld.game[foreign_item.player] + phrases = ItemIconGuessing.PHRASES.copy() + if foreign_game in ItemIconGuessing.GAME_SPECIFIC_PHRASES: + phrases.update(ItemIconGuessing.GAME_SPECIFIC_PHRASES[foreign_game]) + + for phrase, icon in phrases.items(): + if phrase in uppered: + return icon + # pattern for breaking down camelCase, also separates out digits + pattern = re.compile(r"(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|(?<=[a-zA-Z])(?=\d)") + possibles = pattern.sub(' ', foreign_item.name).upper() + for ch in "[]()_": + possibles = possibles.replace(ch, " ") + possibles = possibles.split() for name in possibles: if name in self.name_cache: return self.name_cache[name] @@ -465,8 +437,15 @@ def generate_output(self, output_directory: str): # If the item name contains "sword", use a sword icon, etc # Otherwise, use a cute letter as the icon + elif self.options.foreign_item_icons == 'guess_by_name': + loc.ladxr_item.item = self.guess_icon_for_other_world(loc.item) + loc.ladxr_item.custom_item_name = loc.item.name + else: - loc.ladxr_item.item = self.guess_icon_for_other_world(loc.item.name) + if loc.item.advancement: + loc.ladxr_item.item = 'PIECE_OF_POWER' + else: + loc.ladxr_item.item = 'GUARDIAN_ACORN' loc.ladxr_item.custom_item_name = loc.item.name if loc.item: