LADX: Implement various upstream adjustments (#3829)
* magnifying lens changes
https://github.com/daid/LADXR/pull/156
* restore enemy visibility in mermaid statue cave
https://github.com/daid/LADXR/pull/155
* mermaid statue scale bugfix
https://github.com/daid/LADXR/pull/163
* restore vanilla map when rooster is an item
https://github.com/daid/LADXR/pull/132
* fix
* fixes to magnifying lens changes
* load marin singing even if you have marin date
4feb3099a3
* Revert "load marin singing even if you have marin date"
This reverts commit a7a546ed3f7a2b9c9bcb095984cc64319a4f7855.
* always patch tradequest
not upstream, but included in this PR because it touches the same parts of the code. https://discord.com/channels/731205301247803413/1227373762412937347
* marin date fix
* fix logic
This commit is contained in:
parent
1a5d22ca78
commit
ed721dd0c1
|
@ -153,7 +153,9 @@ def generateRom(args, world: "LinksAwakeningWorld"):
|
||||||
if world.ladxr_settings.witch:
|
if world.ladxr_settings.witch:
|
||||||
patches.witch.updateWitch(rom)
|
patches.witch.updateWitch(rom)
|
||||||
patches.softlock.fixAll(rom)
|
patches.softlock.fixAll(rom)
|
||||||
|
if not world.ladxr_settings.rooster:
|
||||||
patches.maptweaks.tweakMap(rom)
|
patches.maptweaks.tweakMap(rom)
|
||||||
|
patches.maptweaks.tweakBirdKeyRoom(rom)
|
||||||
patches.chest.fixChests(rom)
|
patches.chest.fixChests(rom)
|
||||||
patches.shop.fixShop(rom)
|
patches.shop.fixShop(rom)
|
||||||
patches.rooster.patchRooster(rom)
|
patches.rooster.patchRooster(rom)
|
||||||
|
@ -176,11 +178,7 @@ def generateRom(args, world: "LinksAwakeningWorld"):
|
||||||
patches.songs.upgradeMarin(rom)
|
patches.songs.upgradeMarin(rom)
|
||||||
patches.songs.upgradeManbo(rom)
|
patches.songs.upgradeManbo(rom)
|
||||||
patches.songs.upgradeMamu(rom)
|
patches.songs.upgradeMamu(rom)
|
||||||
if world.ladxr_settings.tradequest:
|
patches.tradeSequence.patchTradeSequence(rom, world.ladxr_settings)
|
||||||
patches.tradeSequence.patchTradeSequence(rom, world.ladxr_settings.boomerang)
|
|
||||||
else:
|
|
||||||
# Monkey bridge patch, always have the bridge there.
|
|
||||||
rom.patch(0x00, 0x333D, assembler.ASM("bit 4, e\njr Z, $05"), b"", fill_nop=True)
|
|
||||||
patches.bowwow.fixBowwow(rom, everywhere=world.ladxr_settings.bowwow != 'normal')
|
patches.bowwow.fixBowwow(rom, everywhere=world.ladxr_settings.bowwow != 'normal')
|
||||||
if world.ladxr_settings.bowwow != 'normal':
|
if world.ladxr_settings.bowwow != 'normal':
|
||||||
patches.bowwow.bowwowMapPatches(rom)
|
patches.bowwow.bowwowMapPatches(rom)
|
||||||
|
|
|
@ -1,23 +1,6 @@
|
||||||
from .droppedKey import DroppedKey
|
from .droppedKey import DroppedKey
|
||||||
from ..roomEditor import RoomEditor
|
|
||||||
from ..assembler import ASM
|
|
||||||
|
|
||||||
|
|
||||||
class BirdKey(DroppedKey):
|
class BirdKey(DroppedKey):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(0x27A)
|
super().__init__(0x27A)
|
||||||
|
|
||||||
def patch(self, rom, option, *, multiworld=None):
|
|
||||||
super().patch(rom, option, multiworld=multiworld)
|
|
||||||
|
|
||||||
re = RoomEditor(rom, self.room)
|
|
||||||
|
|
||||||
# Make the bird key accessible without the rooster
|
|
||||||
re.removeObject(1, 6)
|
|
||||||
re.removeObject(2, 6)
|
|
||||||
re.removeObject(3, 5)
|
|
||||||
re.removeObject(3, 6)
|
|
||||||
re.moveObject(1, 5, 2, 6)
|
|
||||||
re.moveObject(2, 5, 3, 6)
|
|
||||||
re.addEntity(3, 5, 0x9D)
|
|
||||||
re.store(rom)
|
|
||||||
|
|
|
@ -24,11 +24,6 @@ class BoomerangGuy(ItemInfo):
|
||||||
# But SHIELD, BOMB and MAGIC_POWDER would most likely break things.
|
# But SHIELD, BOMB and MAGIC_POWDER would most likely break things.
|
||||||
# SWORD and POWER_BRACELET would most likely introduce the lv0 shield/bracelet issue
|
# SWORD and POWER_BRACELET would most likely introduce the lv0 shield/bracelet issue
|
||||||
def patch(self, rom, option, *, multiworld=None):
|
def patch(self, rom, option, *, multiworld=None):
|
||||||
# Always have the boomerang trade guy enabled (normally you need the magnifier)
|
|
||||||
rom.patch(0x19, 0x05EC, ASM("ld a, [wTradeSequenceItem]\ncp $0E"), ASM("ld a, $0E\ncp $0E"), fill_nop=True) # show the guy
|
|
||||||
rom.patch(0x00, 0x3199, ASM("ld a, [wTradeSequenceItem]\ncp $0E"), ASM("ld a, $0E\ncp $0E"), fill_nop=True) # load the proper room layout
|
|
||||||
rom.patch(0x19, 0x05F4, ASM("ld a, [wTradeSequenceItem2]\nand a"), ASM("xor a"), fill_nop=True)
|
|
||||||
|
|
||||||
if self.setting == 'trade':
|
if self.setting == 'trade':
|
||||||
inv = INVENTORY_MAP[option]
|
inv = INVENTORY_MAP[option]
|
||||||
# Patch the check if you traded back the boomerang (so traded twice)
|
# Patch the check if you traded back the boomerang (so traded twice)
|
||||||
|
|
|
@ -61,9 +61,9 @@ class World:
|
||||||
self._addEntrance("banana_seller", sword_beach, banana_seller, r.bush)
|
self._addEntrance("banana_seller", sword_beach, banana_seller, r.bush)
|
||||||
boomerang_cave = Location("Boomerang Cave")
|
boomerang_cave = Location("Boomerang Cave")
|
||||||
if options.boomerang == 'trade':
|
if options.boomerang == 'trade':
|
||||||
Location().add(BoomerangGuy()).connect(boomerang_cave, OR(BOOMERANG, HOOKSHOT, MAGIC_ROD, PEGASUS_BOOTS, FEATHER, SHOVEL))
|
Location().add(BoomerangGuy()).connect(boomerang_cave, AND(r.shuffled_magnifier, OR(BOOMERANG, HOOKSHOT, MAGIC_ROD, PEGASUS_BOOTS, FEATHER, SHOVEL)))
|
||||||
elif options.boomerang == 'gift':
|
elif options.boomerang == 'gift':
|
||||||
Location().add(BoomerangGuy()).connect(boomerang_cave, None)
|
Location().add(BoomerangGuy()).connect(boomerang_cave, r.shuffled_magnifier)
|
||||||
self._addEntrance("boomerang_cave", sword_beach, boomerang_cave, BOMB)
|
self._addEntrance("boomerang_cave", sword_beach, boomerang_cave, BOMB)
|
||||||
self._addEntranceRequirementExit("boomerang_cave", None) # if exiting, you do not need bombs
|
self._addEntranceRequirementExit("boomerang_cave", None) # if exiting, you do not need bombs
|
||||||
|
|
||||||
|
@ -167,7 +167,9 @@ class World:
|
||||||
prairie_island_seashell = Location().add(Seashell(0x0A6)).connect(ukuku_prairie, AND(FLIPPERS, r.bush)) # next to lv3
|
prairie_island_seashell = Location().add(Seashell(0x0A6)).connect(ukuku_prairie, AND(FLIPPERS, r.bush)) # next to lv3
|
||||||
Location().add(Seashell(0x08B)).connect(ukuku_prairie, r.bush) # next to seashell house
|
Location().add(Seashell(0x08B)).connect(ukuku_prairie, r.bush) # next to seashell house
|
||||||
Location().add(Seashell(0x0A4)).connect(ukuku_prairie, PEGASUS_BOOTS) # smash into tree next to phonehouse
|
Location().add(Seashell(0x0A4)).connect(ukuku_prairie, PEGASUS_BOOTS) # smash into tree next to phonehouse
|
||||||
self._addEntrance("castle_jump_cave", ukuku_prairie, Location().add(Chest(0x1FD)), OR(AND(FEATHER, PEGASUS_BOOTS), ROOSTER)) # left of the castle, 5 holes turned into 3
|
self._addEntrance("castle_jump_cave", ukuku_prairie, Location().add(Chest(0x1FD)), ROOSTER)
|
||||||
|
if not options.rooster:
|
||||||
|
self._addEntranceRequirement("castle_jump_cave", AND(FEATHER, PEGASUS_BOOTS)) # left of the castle, 5 holes turned into 3
|
||||||
Location().add(Seashell(0x0B9)).connect(ukuku_prairie, POWER_BRACELET) # under the rock
|
Location().add(Seashell(0x0B9)).connect(ukuku_prairie, POWER_BRACELET) # under the rock
|
||||||
|
|
||||||
left_bay_area = Location()
|
left_bay_area = Location()
|
||||||
|
@ -379,7 +381,9 @@ class World:
|
||||||
self._addEntrance("rooster_house", outside_rooster_house, None, None)
|
self._addEntrance("rooster_house", outside_rooster_house, None, None)
|
||||||
bird_cave = Location()
|
bird_cave = Location()
|
||||||
bird_key = Location().add(BirdKey())
|
bird_key = Location().add(BirdKey())
|
||||||
bird_cave.connect(bird_key, OR(AND(FEATHER, COUNT(POWER_BRACELET, 2)), ROOSTER))
|
bird_cave.connect(bird_key, ROOSTER)
|
||||||
|
if not options.rooster:
|
||||||
|
bird_cave.connect(bird_key, AND(FEATHER, COUNT(POWER_BRACELET, 2))) # elephant statue added
|
||||||
if options.logic != "casual":
|
if options.logic != "casual":
|
||||||
bird_cave.connect(lower_right_taltal, None, one_way=True) # Drop in a hole at bird cave
|
bird_cave.connect(lower_right_taltal, None, one_way=True) # Drop in a hole at bird cave
|
||||||
self._addEntrance("bird_cave", outside_rooster_house, bird_cave, None)
|
self._addEntrance("bird_cave", outside_rooster_house, bird_cave, None)
|
||||||
|
@ -478,6 +482,7 @@ class World:
|
||||||
desert_lanmola.connect(desert, BOMB) # use bombs to kill lanmola
|
desert_lanmola.connect(desert, BOMB) # use bombs to kill lanmola
|
||||||
|
|
||||||
d6_connector_left.connect(d6_connector_right, AND(OR(FLIPPERS, PEGASUS_BOOTS), FEATHER)) # jump the gap in underground passage to d6 left side to skip hookshot
|
d6_connector_left.connect(d6_connector_right, AND(OR(FLIPPERS, PEGASUS_BOOTS), FEATHER)) # jump the gap in underground passage to d6 left side to skip hookshot
|
||||||
|
if not options.rooster:
|
||||||
bird_key.connect(bird_cave, COUNT(POWER_BRACELET, 2)) # corner walk past the one pit on the left side to get to the elephant statue
|
bird_key.connect(bird_cave, COUNT(POWER_BRACELET, 2)) # corner walk past the one pit on the left side to get to the elephant statue
|
||||||
fire_cave_bottom.connect(fire_cave_top, PEGASUS_BOOTS, one_way=True) # flame skip
|
fire_cave_bottom.connect(fire_cave_top, PEGASUS_BOOTS, one_way=True) # flame skip
|
||||||
|
|
||||||
|
|
|
@ -265,6 +265,7 @@ class RequirementsSettings:
|
||||||
self.rear_attack_range = OR(MAGIC_ROD, BOW) # mimic
|
self.rear_attack_range = OR(MAGIC_ROD, BOW) # mimic
|
||||||
self.fire = OR(MAGIC_POWDER, MAGIC_ROD) # torches
|
self.fire = OR(MAGIC_POWDER, MAGIC_ROD) # torches
|
||||||
self.push_hardhat = OR(SHIELD, SWORD, HOOKSHOT, BOOMERANG)
|
self.push_hardhat = OR(SHIELD, SWORD, HOOKSHOT, BOOMERANG)
|
||||||
|
self.shuffled_magnifier = TRADING_ITEM_MAGNIFYING_GLASS
|
||||||
|
|
||||||
self.boss_requirements = [
|
self.boss_requirements = [
|
||||||
SWORD, # D1 boss
|
SWORD, # D1 boss
|
||||||
|
@ -293,6 +294,8 @@ class RequirementsSettings:
|
||||||
}
|
}
|
||||||
|
|
||||||
# Adjust for options
|
# Adjust for options
|
||||||
|
if not options.tradequest:
|
||||||
|
self.shuffled_magnifier = True
|
||||||
if options.bowwow != 'normal':
|
if options.bowwow != 'normal':
|
||||||
# We cheat in bowwow mode, we pretend we have the sword, as bowwow can pretty much do all what the sword ca$ # Except for taking out bushes (and crystal pillars are removed)
|
# We cheat in bowwow mode, we pretend we have the sword, as bowwow can pretty much do all what the sword ca$ # Except for taking out bushes (and crystal pillars are removed)
|
||||||
self.bush.remove(SWORD)
|
self.bush.remove(SWORD)
|
||||||
|
|
|
@ -25,3 +25,16 @@ def addBetaRoom(rom):
|
||||||
re.store(rom)
|
re.store(rom)
|
||||||
|
|
||||||
rom.room_sprite_data_indoor[0x0FC] = rom.room_sprite_data_indoor[0x1A1]
|
rom.room_sprite_data_indoor[0x0FC] = rom.room_sprite_data_indoor[0x1A1]
|
||||||
|
|
||||||
|
|
||||||
|
def tweakBirdKeyRoom(rom):
|
||||||
|
# Make the bird key accessible without the rooster
|
||||||
|
re = RoomEditor(rom, 0x27A)
|
||||||
|
re.removeObject(1, 6)
|
||||||
|
re.removeObject(2, 6)
|
||||||
|
re.removeObject(3, 5)
|
||||||
|
re.removeObject(3, 6)
|
||||||
|
re.moveObject(1, 5, 2, 6)
|
||||||
|
re.moveObject(2, 5, 3, 6)
|
||||||
|
re.addEntity(3, 5, 0x9D)
|
||||||
|
re.store(rom)
|
||||||
|
|
|
@ -72,6 +72,10 @@ def upgradeMarin(rom):
|
||||||
rst 8
|
rst 8
|
||||||
"""), fill_nop=True)
|
"""), fill_nop=True)
|
||||||
|
|
||||||
|
# Load marin singing even if you have the marin date
|
||||||
|
rom.patch(0x03, 0x0A91, ASM("jp nz, $3F8D"), "", fill_nop=True)
|
||||||
|
rom.patch(0x05, 0x0E6E, ASM("jp nz, $7B4B"), "", fill_nop=True)
|
||||||
|
|
||||||
|
|
||||||
def upgradeManbo(rom):
|
def upgradeManbo(rom):
|
||||||
# Instead of checking if we have the song, check if we have a specific room flag set
|
# Instead of checking if we have the song, check if we have a specific room flag set
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from ..assembler import ASM
|
from ..assembler import ASM
|
||||||
|
|
||||||
|
|
||||||
def patchTradeSequence(rom, boomerang_option):
|
def patchTradeSequence(rom, settings):
|
||||||
patchTrendy(rom)
|
patchTrendy(rom)
|
||||||
patchPapahlsWife(rom)
|
patchPapahlsWife(rom)
|
||||||
patchYipYip(rom)
|
patchYipYip(rom)
|
||||||
|
@ -16,7 +16,7 @@ def patchTradeSequence(rom, boomerang_option):
|
||||||
patchMermaid(rom)
|
patchMermaid(rom)
|
||||||
patchMermaidStatue(rom)
|
patchMermaidStatue(rom)
|
||||||
patchSharedCode(rom)
|
patchSharedCode(rom)
|
||||||
patchVarious(rom, boomerang_option)
|
patchVarious(rom, settings)
|
||||||
patchInventoryMenu(rom)
|
patchInventoryMenu(rom)
|
||||||
|
|
||||||
|
|
||||||
|
@ -265,8 +265,11 @@ def patchMermaidStatue(rom):
|
||||||
and $10 ; scale
|
and $10 ; scale
|
||||||
ret z
|
ret z
|
||||||
ldh a, [$F8]
|
ldh a, [$F8]
|
||||||
and $20
|
and $20 ; ROOM_STATUS_EVENT_2
|
||||||
ret nz
|
ret nz
|
||||||
|
|
||||||
|
ld hl, wTradeSequenceItem2
|
||||||
|
res 4, [hl] ; take the trade item
|
||||||
"""), fill_nop=True)
|
"""), fill_nop=True)
|
||||||
|
|
||||||
|
|
||||||
|
@ -317,7 +320,7 @@ notSideScroll:
|
||||||
rom.patch(0x07, 0x3F7F, "00" * 7, ASM("ldh a, [$F8]\nor $20\nldh [$F8], a\nret"))
|
rom.patch(0x07, 0x3F7F, "00" * 7, ASM("ldh a, [$F8]\nor $20\nldh [$F8], a\nret"))
|
||||||
|
|
||||||
|
|
||||||
def patchVarious(rom, boomerang_option):
|
def patchVarious(rom, settings):
|
||||||
# Make the zora photo work with the magnifier
|
# Make the zora photo work with the magnifier
|
||||||
rom.patch(0x18, 0x09F3, 0x0A02, ASM("""
|
rom.patch(0x18, 0x09F3, 0x0A02, ASM("""
|
||||||
ld a, [wTradeSequenceItem2]
|
ld a, [wTradeSequenceItem2]
|
||||||
|
@ -330,22 +333,71 @@ def patchVarious(rom, boomerang_option):
|
||||||
jp z, $3F8D ; UnloadEntity
|
jp z, $3F8D ; UnloadEntity
|
||||||
"""), fill_nop=True)
|
"""), fill_nop=True)
|
||||||
# Mimic invisibility
|
# Mimic invisibility
|
||||||
rom.patch(0x18, 0x2AC8, 0x2ACE, "", fill_nop=True)
|
rom.patch(0x19, 0x2AC0, ASM("""
|
||||||
|
cp $97
|
||||||
|
jr z, mermaidStatueCave
|
||||||
|
cp $98
|
||||||
|
jr nz, visible
|
||||||
|
mermaidStatueCave:
|
||||||
|
ld a, [$DB7F]
|
||||||
|
and a
|
||||||
|
jr nz, 6
|
||||||
|
visible:
|
||||||
|
"""), ASM("""
|
||||||
|
dec a ; save one byte by only doing one cp
|
||||||
|
or $01
|
||||||
|
cp $97
|
||||||
|
jr nz, visible
|
||||||
|
mermaidStatueCave:
|
||||||
|
ld a, [wTradeSequenceItem2]
|
||||||
|
and $20 ; MAGNIFYING_GLASS
|
||||||
|
jr z, 6
|
||||||
|
visible:
|
||||||
|
"""))
|
||||||
|
# Zol invisibility
|
||||||
|
rom.patch(0x06, 0x3BE9, ASM("""
|
||||||
|
cp $97
|
||||||
|
jr z, mermaidStatueCave
|
||||||
|
cp $98
|
||||||
|
ret nz ; visible
|
||||||
|
mermaidStatueCave:
|
||||||
|
ld a, [$DB7F]
|
||||||
|
and a
|
||||||
|
ret z
|
||||||
|
"""), ASM("""
|
||||||
|
dec a ; save one byte by only doing one cp
|
||||||
|
or $01
|
||||||
|
cp $97
|
||||||
|
ret nz ; visible
|
||||||
|
mermaidStatueCave:
|
||||||
|
ld a, [wTradeSequenceItem2]
|
||||||
|
and $20 ; MAGNIFYING_GLASS
|
||||||
|
ret nz
|
||||||
|
"""))
|
||||||
# Ignore trade quest state for marin at beach
|
# Ignore trade quest state for marin at beach
|
||||||
rom.patch(0x18, 0x219E, 0x21A6, "", fill_nop=True)
|
rom.patch(0x18, 0x219E, 0x21A6, "", fill_nop=True)
|
||||||
# Shift the magnifier 8 pixels
|
# Shift the magnifier 8 pixels
|
||||||
rom.patch(0x03, 0x0F68, 0x0F6F, ASM("""
|
rom.patch(0x03, 0x0F68, 0x0F6F, ASM("""
|
||||||
ldh a, [$F6] ; map room
|
ldh a, [$F6] ; map room
|
||||||
cp $97 ; check if we are in the maginfier room
|
cp $97 ; check if we are in the magnifier room
|
||||||
jp z, $4F83
|
jp z, $4F83
|
||||||
"""), fill_nop=True)
|
"""), fill_nop=True)
|
||||||
# Something with the photographer
|
# Something with the photographer
|
||||||
rom.patch(0x36, 0x0948, 0x0950, "", fill_nop=True)
|
rom.patch(0x36, 0x0948, 0x0950, "", fill_nop=True)
|
||||||
|
|
||||||
if boomerang_option not in {'trade', 'gift'}: # Boomerang cave is not patched, so adjust it
|
# Boomerang trade guy
|
||||||
|
# if settings.boomerang not in {'trade', 'gift'} or settings.overworld in {'normal', 'nodungeons'}:
|
||||||
|
if settings.tradequest:
|
||||||
|
# Update magnifier checks
|
||||||
rom.patch(0x19, 0x05EC, ASM("ld a, [wTradeSequenceItem]\ncp $0E\njp nz, $7E61"), ASM("ld a, [wTradeSequenceItem2]\nand $20\njp z, $7E61")) # show the guy
|
rom.patch(0x19, 0x05EC, ASM("ld a, [wTradeSequenceItem]\ncp $0E\njp nz, $7E61"), ASM("ld a, [wTradeSequenceItem2]\nand $20\njp z, $7E61")) # show the guy
|
||||||
rom.patch(0x00, 0x3199, ASM("ld a, [wTradeSequenceItem]\ncp $0E\njr nz, $06"), ASM("ld a, [wTradeSequenceItem2]\nand $20\njr z, $06")) # load the proper room layout
|
rom.patch(0x00, 0x3199, ASM("ld a, [wTradeSequenceItem]\ncp $0E\njr nz, $06"), ASM("ld a, [wTradeSequenceItem2]\nand $20\njr z, $06")) # load the proper room layout
|
||||||
rom.patch(0x19, 0x05F4, 0x05FB, "", fill_nop=True)
|
else:
|
||||||
|
# Monkey bridge patch, always have the bridge there.
|
||||||
|
rom.patch(0x00, 0x333D, ASM("bit 4, e\njr Z, $05"), b"", fill_nop=True)
|
||||||
|
# Always have the boomerang trade guy enabled (magnifier not needed)
|
||||||
|
rom.patch(0x19, 0x05EC, ASM("ld a, [wTradeSequenceItem]\ncp $0E"), ASM("ld a, $0E\ncp $0E"), fill_nop=True) # show the guy
|
||||||
|
rom.patch(0x00, 0x3199, ASM("ld a, [wTradeSequenceItem]\ncp $0E"), ASM("ld a, $0E\ncp $0E"), fill_nop=True) # load the proper room layout
|
||||||
|
rom.patch(0x19, 0x05F4, ASM("ld a, [wTradeSequenceItem2]\nand a"), ASM("xor a"), fill_nop=True)
|
||||||
|
|
||||||
|
|
||||||
def patchInventoryMenu(rom):
|
def patchInventoryMenu(rom):
|
||||||
|
|
|
@ -58,7 +58,7 @@ class TextShuffle(DefaultOffToggle):
|
||||||
class Rooster(DefaultOnToggle, LADXROption):
|
class Rooster(DefaultOnToggle, LADXROption):
|
||||||
"""
|
"""
|
||||||
[On] Adds the rooster to the item pool.
|
[On] Adds the rooster to the item pool.
|
||||||
[Off] The rooster spot is still a check giving an item. But you will never find the rooster. Any rooster spot is accessible without rooster by other means.
|
[Off] The rooster spot is still a check giving an item. But you will never find the rooster. In that case, any rooster spot is accessible without rooster by other means.
|
||||||
"""
|
"""
|
||||||
display_name = "Rooster"
|
display_name = "Rooster"
|
||||||
ladxr_name = "rooster"
|
ladxr_name = "rooster"
|
||||||
|
|
Loading…
Reference in New Issue