Skip to content

Commit

Permalink
LADX: Implement remake style warp selection (#1587)
Browse files Browse the repository at this point in the history
  • Loading branch information
zig-for authored Oct 1, 2023
1 parent d5d630d commit e08deff
Show file tree
Hide file tree
Showing 3 changed files with 234 additions and 11 deletions.
23 changes: 14 additions & 9 deletions worlds/ladx/LADXR/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@
from . import hints

from .patches import bank34
from .utils import formatText
from ..Options import TrendyGame, Palette
from .roomEditor import RoomEditor, Object
from .patches.aesthetics import rgb_to_bin, bin_to_rgb

from .locations.keyLocation import KeyLocation
Expand Down Expand Up @@ -134,7 +137,7 @@ def generateRom(args, settings, ap_settings, auth, seed_name, logic, rnd=None, m
patches.core.fixWrongWarp(rom)
patches.core.alwaysAllowSecretBook(rom)
patches.core.injectMainLoop(rom)

from ..Options import ShuffleSmallKeys, ShuffleNightmareKeys

if ap_settings["shuffle_small_keys"] != ShuffleSmallKeys.option_original_dungeon or ap_settings["shuffle_nightmare_keys"] != ShuffleNightmareKeys.option_original_dungeon:
Expand Down Expand Up @@ -239,7 +242,7 @@ def generateRom(args, settings, ap_settings, auth, seed_name, logic, rnd=None, m
patches.core.quickswap(rom, 1)
elif settings.quickswap == 'b':
patches.core.quickswap(rom, 0)

world_setup = logic.world_setup

JUNK_HINT = 0.33
Expand All @@ -263,7 +266,7 @@ def gen_hint():
name = "Your"
else:
name = f"{multiworld.player_name[location.item.player]}'s"

if isinstance(location, LinksAwakeningLocation):
location_name = location.ladxr_item.metadata.name
else:
Expand Down Expand Up @@ -323,7 +326,7 @@ def gen_hint():

# TODO: if 0 or 4, 5, remove inaccurate conveyor tiles

from .roomEditor import RoomEditor, Object

room_editor = RoomEditor(rom, 0x2A0)

if ap_settings["trendy_game"] == TrendyGame.option_easy:
Expand Down Expand Up @@ -352,12 +355,12 @@ def gen_hint():
}
def speed():
return rnd.randint(*speeds[ap_settings["trendy_game"]])
rom.banks[0x4][0x76A0-0x4000] = 0xFF - speed()
rom.banks[0x4][0x76A0-0x4000] = 0xFF - speed()
rom.banks[0x4][0x76A2-0x4000] = speed()
rom.banks[0x4][0x76A6-0x4000] = speed()
rom.banks[0x4][0x76A8-0x4000] = 0xFF - speed()
if int(ap_settings["trendy_game"]) >= TrendyGame.option_hardest:
rom.banks[0x4][0x76A1-0x4000] = 0xFF - speed()
rom.banks[0x4][0x76A1-0x4000] = 0xFF - speed()
rom.banks[0x4][0x76A3-0x4000] = speed()
rom.banks[0x4][0x76A5-0x4000] = speed()
rom.banks[0x4][0x76A7-0x4000] = 0xFF - speed()
Expand All @@ -374,12 +377,14 @@ def speed():
[0x0f, 0x38, 0x0f],
[0x30, 0x62, 0x30],
[0x8b, 0xac, 0x0f],
[0x9b, 0xbc, 0x0f],
[0x9b, 0xbc, 0x0f],
]
for color in gb_colors:
for channel in range(3):
color[channel] = color[channel] * 31 // 0xbc


if ap_settings["warp_improvements"]:
patches.core.addWarpImprovements(rom, ap_settings["additional_warp_points"])

palette = ap_settings["palette"]
if palette != Palette.option_normal:
Expand Down Expand Up @@ -410,7 +415,7 @@ def clamp(x, min, max):
for address in range(start, end, 2):
packed = (rom.banks[bank][address + 1] << 8) | rom.banks[bank][address]
r,g,b = bin_to_rgb(packed)

# 1 bit
if palette == Palette.option_1bit:
r &= 0b10000
Expand Down
205 changes: 204 additions & 1 deletion worlds/ladx/LADXR/patches/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,9 @@ def warpHome(rom):
""" % (type, map, room, x, y)), fill_nop=True)

# Patch the RAM clear not to delete our custom dialog when we screen transition
# This is kind of horrible as it relies on bank 1 being loaded, lol
rom.patch(0x01, 0x042C, "C629", "6B7E")
rom.patch(0x01, 0x3E6B, 0x3FFF, ASM("""
rom.patch(0x01, 0x3E6B, 0x3E7B, ASM("""
ld bc, $A0
call $29DC
ld bc, $1200
Expand Down Expand Up @@ -537,3 +538,205 @@ def addFrameCounter(rom, check_count):
gfx_low = "\n".join([line.split(" ")[n] for line in tile_graphics.split("\n")[8:]])
rom.banks[0x38][0x1400+n*0x20:0x1410+n*0x20] = utils.createTileData(gfx_high)
rom.banks[0x38][0x1410+n*0x20:0x1420+n*0x20] = utils.createTileData(gfx_low)

def addWarpImprovements(rom, extra_warps):
# Patch in a warp icon
tile = utils.createTileData( \
"""11111111
10000000
10200320
10323200
10033300
10023230
10230020
10000000""", key="0231")
MINIMAP_BASE = 0x3800

# This is replacing a junk tile never used on the minimap
rom.banks[0x2C][MINIMAP_BASE + len(tile) * 0x65 : MINIMAP_BASE + len(tile) * 0x66] = tile

# Allow using ENTITY_WARP for finding which map sections are warps
# Interesting - 3CA0 should be free, but something has pushed all the code forward a byte
rom.patch(0x02, 0x3CA1, None, ASM("""
ld e, $0F
ld d, $00
warp_search_loop:
; Warp search loop
ld hl, $C3A0
add hl, de ; $5FE1: $19
ld a, [hl] ; $5FE2: $7E
cp $61 ; ENTITY_WARP
jr nz, search_continue ; if it's not a warp, check the next one
ld hl, $C280
add hl, de
ld a, [hl]
and a
jr z, search_continue ; if this is despawned, check the next one
found:
jp $511B ; found
search_continue:
dec e
ld a, e
cp $FF
jr nz, warp_search_loop
not_found:
jp $512B
"""))

# Insert redirect to above code
rom.patch(0x02, 0x1109, ASM("""
ldh a, [$F6]
cp 1
"""), ASM("""
jp $7CA1
nop
"""))
# Leaves some extra bytes behind, if we need more space in 0x02

# On warp hole, open map instead
rom.patch(0x19, 0x1DB9, None, ASM("""
ld a, 7 ; Set GAMEPLAY_MAP
ld [$DB95], a
ld a, 0 ; reset subtype
ld [$DB96], a
ld a, 1 ; Set flag for using teleport
ld [$FFDD], a
ret
"""), fill_nop=True)

# Patch over some instructions that decided if we are in debug mode holding some
# buttons with instead checking for FFDD (why FFDD? It appears to be never used anywhere, so we repurpose it for "is in teleport mode")
rom.banks[0x01][0x17B8] = 0xDD
rom.banks[0x01][0x17B9] = 0xFF
rom.banks[0x01][0x17FD] = 0xDD
rom.banks[0x01][0x17FE] = 0xFF

# If in warp mode, don't allow manual exit
rom.patch(0x01, 0x1800, "20021E60", ASM("jp nz, $5818"), fill_nop=True)

# Allow warp with just B
rom.banks[0x01][0x17C0] = 0x20

# Allow cursor to move over black squares
# This allows warping to undiscovered areas - a fine cheat, but needs a check for wOverworldRoomStatus in the warp code
CHEAT_WARP_ANYWHERE = False
if CHEAT_WARP_ANYWHERE:
rom.patch(0x01, 0x1AE8, None, ASM("jp $5AF5"))

# This disables the arrows around the selection bubble
#rom.patch(0x01, 0x1B6F, None, ASM("ret"), fill_nop=True)

# Fix lag when moving the cursor
# One option - just disable the delay code
#rom.patch(0x01, 0x1A76, 0x1A76+3, ASM("xor a"), fill_nop=True)
#rom.banks[0x01][0x1A7C] = 0
# Another option - just remove the animation
rom.banks[0x01][0x1B20] = 0
rom.banks[0x01][0x1B3B] = 0

# Patch the icon for all teleports
all_warps = [0x01, 0x95, 0x2C, 0xEC]


if extra_warps:
# mamu
all_warps.append(0x45)
# Tweak the flute location
rom.banks[0x14][0x0E95] += 0x10
rom.banks[0x14][0x0EA3] += 0x01

mamu_pond = RoomEditor(rom, 0x45)
# Remove some tall grass so we can add a warp instead
mamu_pond.changeObject(1, 6, 0xE8)
mamu_pond.moveObject(1, 6, 3, 5)
mamu_pond.addEntity(3, 5, 0x61)

mamu_pond.store(rom)

# eagle
all_warps.append(0x0F)
room = RoomEditor(rom, 0x0F)
# Move one cliff edge and change it into a pit
room.changeObject(7, 6, 0xE8)
room.moveObject(7, 6, 6, 4)

# Add the warp
room.addEntity(6, 4, 0x61)
# move the two corners
room.moveObject(6, 7, 7, 7)
room.moveObject(6, 6, 7, 6)
for object in room.objects:
# Extend the lower wall
if ((object.x == 0 and object.y == 7)
# Extend the lower floor
or (object.x == 0 and object.y == 6)):
room.overlay[object.x + object.count + object.y * 10] = object.type_id
object.count += 1
room.store(rom)

for warp in all_warps:
# Set icon
rom.banks[0x20][0x168B + warp] = 0x55
# Set text
if not rom.banks[0x01][0x1959 + warp]:
rom.banks[0x01][0x1959 + warp] = 0x42
# Set palette
# rom.banks[0x20][0x178B + 0x95] = 0x1

# Setup [?!] icon on map and associated text
rom.banks[0x01][0x1909 + 0x42] = 0x2B
rom.texts[0x02B] = utils.formatText('Warp')

# call warp function (why not just jmp?!)
rom.patch(0x01, 0x17C3, None, ASM("""
call $7E7B
ret
"""))

# Build a switch statement by hand
warp_jump = "".join(f"cp ${hex(warp)[2:]}\njr z, success\n" for warp in all_warps)

rom.patch(0x01, 0x3E7B, None, ASM(f"""
TeleportHandler:
ld a, [$DBB4] ; Load the current selected tile
; TODO: check if actually revealed so we can have free movement
; Check cursor against different tiles to see if we are selecting a warp
{warp_jump}
jr exit
success:
ld a, $0B
ld [$DB95], a ; Gameplay type
xor a
ld [$D401], a ; wWarp0MapCategory
ldh [$DD], a ; unset teleport flag(!!!)
ld [$D402], a ; wWarp0Map
ld a, [$DBB4] ; wDBB4
ld [$D403], a ; wWarp0Room
ld a, $68
ld [$D404], a ; wWarp0DestinationX
ldh [$98], a ; LinkPositionY
ld [$D475], a
ld a, $70
ld [$D405], a ; wWarp0DestinationY
ldh [$99], a ; LinkPositionX
ld a, $66
ld [$D416], a ; wWarp0PositionTileIndex
ld a, $07
ld [$DB96], a ; wGameplaySubtype
ldh a, [$A2]
ld [$DBC8], a
call $0C83 ; ApplyMapFadeOutTransition
xor a ; $5DF3: $AF
ld [$C167], a ; $5DF4: $EA $67 $C1
exit:
ret
"""))

17 changes: 16 additions & 1 deletion worlds/ladx/Options.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,20 @@ class Palette(Choice):
option_greyscale = 3
option_pink = 4
option_inverted = 5


class WarpImprovements(DefaultOffToggle):
"""
[On] Adds remake style warp screen to the game. Choose your warp destination on the map after jumping in a portal and press B to select.
[Off] No change
"""

class AdditionalWarpPoints(DefaultOffToggle):
"""
[On] (requires warp improvements) Adds a warp point at Crazy Tracy's house (the Mambo teleport spot) and Eagle's Tower
[Off] No change
"""


links_awakening_options: typing.Dict[str, typing.Type[Option]] = {
'logic': Logic,
# 'heartpiece': DefaultOnToggle, # description='Includes heart pieces in the item pool'),
Expand All @@ -400,6 +413,8 @@ class Palette(Choice):
# 'bowwow': Bowwow,
# 'overworld': Overworld,
'link_palette': LinkPalette,
'warp_improvements': WarpImprovements,
'additional_warp_points': AdditionalWarpPoints,
'trendy_game': TrendyGame,
'gfxmod': GfxMod,
'palette': Palette,
Expand Down

0 comments on commit e08deff

Please sign in to comment.