LADX: AP egg title screen (#1683)
This commit is contained in:
parent
b02b329181
commit
70ff19ac8c
|
@ -2,6 +2,7 @@ import binascii
|
||||||
import importlib.util
|
import importlib.util
|
||||||
import importlib.machinery
|
import importlib.machinery
|
||||||
import os
|
import os
|
||||||
|
import pkgutil
|
||||||
|
|
||||||
from .romTables import ROMWithTables
|
from .romTables import ROMWithTables
|
||||||
from . import assembler
|
from . import assembler
|
||||||
|
@ -61,7 +62,12 @@ from ..Options import TrendyGame, Palette, MusicChangeCondition
|
||||||
|
|
||||||
# Function to generate a final rom, this patches the rom with all required patches
|
# Function to generate a final rom, this patches the rom with all required patches
|
||||||
def generateRom(args, settings, ap_settings, auth, seed_name, logic, rnd=None, multiworld=None, player_name=None, player_names=[], player_id = 0):
|
def generateRom(args, settings, ap_settings, auth, seed_name, logic, rnd=None, multiworld=None, player_name=None, player_names=[], player_id = 0):
|
||||||
rom = ROMWithTables(args.input_filename)
|
rom_patches = []
|
||||||
|
|
||||||
|
if ap_settings["ap_title_screen"]:
|
||||||
|
rom_patches.append(pkgutil.get_data(__name__, "patches/title_screen.bdiff4"))
|
||||||
|
|
||||||
|
rom = ROMWithTables(args.input_filename, rom_patches)
|
||||||
rom.player_names = player_names
|
rom.player_names = player_names
|
||||||
pymods = []
|
pymods = []
|
||||||
if args.pymod:
|
if args.pymod:
|
||||||
|
@ -271,6 +277,8 @@ def generateRom(args, settings, ap_settings, auth, seed_name, logic, rnd=None, m
|
||||||
|
|
||||||
patches.core.warpHome(rom) # Needs to be done after setting the start location.
|
patches.core.warpHome(rom) # Needs to be done after setting the start location.
|
||||||
patches.titleScreen.setRomInfo(rom, auth, seed_name, settings, player_name, player_id)
|
patches.titleScreen.setRomInfo(rom, auth, seed_name, settings, player_name, player_id)
|
||||||
|
if ap_settings["ap_title_screen"]:
|
||||||
|
patches.titleScreen.setTitleGraphics(rom)
|
||||||
patches.endscreen.updateEndScreen(rom)
|
patches.endscreen.updateEndScreen(rom)
|
||||||
patches.aesthetics.updateSpriteData(rom)
|
patches.aesthetics.updateSpriteData(rom)
|
||||||
if args.doubletrouble:
|
if args.doubletrouble:
|
||||||
|
@ -363,15 +371,7 @@ def generateRom(args, settings, ap_settings, auth, seed_name, logic, rnd=None, m
|
||||||
if x > max:
|
if x > max:
|
||||||
return max
|
return max
|
||||||
return x
|
return x
|
||||||
def bin_to_rgb(word):
|
from patches.aesthetics import rgb_to_bin, bin_to_rgb
|
||||||
red = word & 0b11111
|
|
||||||
word >>= 5
|
|
||||||
green = word & 0b11111
|
|
||||||
word >>= 5
|
|
||||||
blue = word & 0b11111
|
|
||||||
return (red, green, blue)
|
|
||||||
def rgb_to_bin(r, g, b):
|
|
||||||
return (b << 10) | (g << 5) | r
|
|
||||||
|
|
||||||
for address in range(start, end, 2):
|
for address in range(start, end, 2):
|
||||||
packed = (rom.banks[bank][address + 1] << 8) | rom.banks[bank][address]
|
packed = (rom.banks[bank][address + 1] << 8) | rom.banks[bank][address]
|
||||||
|
|
|
@ -434,3 +434,15 @@ noChange:
|
||||||
rom.room_sprite_data_overworld[room_nr] = data
|
rom.room_sprite_data_overworld[room_nr] = data
|
||||||
else:
|
else:
|
||||||
rom.room_sprite_data_indoor[room_nr - 0x100] = data
|
rom.room_sprite_data_indoor[room_nr - 0x100] = data
|
||||||
|
|
||||||
|
|
||||||
|
def bin_to_rgb(word):
|
||||||
|
red = word & 0b11111
|
||||||
|
word >>= 5
|
||||||
|
green = word & 0b11111
|
||||||
|
word >>= 5
|
||||||
|
blue = word & 0b11111
|
||||||
|
return (red, green, blue)
|
||||||
|
|
||||||
|
def rgb_to_bin(r, g, b):
|
||||||
|
return (b << 10) | (g << 5) | r
|
||||||
|
|
|
@ -136,4 +136,4 @@ loadLoop2:
|
||||||
addr = 0x1000
|
addr = 0x1000
|
||||||
data = pkgutil.get_data(__name__, "nyan.bin")
|
data = pkgutil.get_data(__name__, "nyan.bin")
|
||||||
rom.banks[0x3F][addr : addr + len(data)] = data
|
rom.banks[0x3F][addr : addr + len(data)] = data
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
from ..backgroundEditor import BackgroundEditor
|
from ..backgroundEditor import BackgroundEditor
|
||||||
import subprocess
|
from .aesthetics import rgb_to_bin, bin_to_rgb, prepatch
|
||||||
import binascii
|
import copy
|
||||||
|
import pkgutil
|
||||||
|
|
||||||
CHAR_MAP = {'z': 0x3E, '-': 0x3F, '.': 0x39, ':': 0x42, '?': 0x3C, '!': 0x3D}
|
CHAR_MAP = {'z': 0x3E, '-': 0x3F, '.': 0x39, ':': 0x42, '?': 0x3C, '!': 0x3D}
|
||||||
|
|
||||||
|
|
||||||
def _encode(s):
|
def _encode(s):
|
||||||
result = bytearray()
|
result = bytearray()
|
||||||
for char in s:
|
for char in s:
|
||||||
|
@ -82,3 +80,68 @@ def setRomInfo(rom, seed, seed_name, settings, player_name, player_id):
|
||||||
ba.tiles[0x9820 + n] = 0x08 | pal
|
ba.tiles[0x9820 + n] = 0x08 | pal
|
||||||
be.store(rom)
|
be.store(rom)
|
||||||
ba.store(rom)
|
ba.store(rom)
|
||||||
|
|
||||||
|
def setTitleGraphics(rom):
|
||||||
|
BASE = 0x9800
|
||||||
|
ROW_SIZE = 0x20
|
||||||
|
|
||||||
|
be = BackgroundEditor(rom, 0x11, attributes=True)
|
||||||
|
for tile in be.tiles:
|
||||||
|
if be.tiles[tile] == 7:
|
||||||
|
be.tiles[tile] = 3
|
||||||
|
|
||||||
|
be.tiles[BASE + 10 * ROW_SIZE + 8] = 7
|
||||||
|
be.tiles[BASE + 10 * ROW_SIZE + 10] = 2
|
||||||
|
be.tiles[BASE + 10 * ROW_SIZE + 11] = 5
|
||||||
|
be.tiles[BASE + 11 * ROW_SIZE + 10] = 6
|
||||||
|
be.tiles[BASE + 11 * ROW_SIZE + 11] = 6
|
||||||
|
be.tiles[BASE + 12 * ROW_SIZE + 11] = 6
|
||||||
|
be.tiles[BASE + 11 * ROW_SIZE + 9] = 1
|
||||||
|
be.tiles[BASE + 12 * ROW_SIZE + 9] = 1
|
||||||
|
be.tiles[BASE + 12 * ROW_SIZE + 10] = 1
|
||||||
|
be.tiles[BASE + 13 * ROW_SIZE + 9] = 1
|
||||||
|
be.tiles[BASE + 13 * ROW_SIZE + 10] = 1
|
||||||
|
|
||||||
|
be.store(rom)
|
||||||
|
|
||||||
|
SKIP_INTRO = True
|
||||||
|
if SKIP_INTRO:
|
||||||
|
# Skip intro as it's causing problems
|
||||||
|
rom.banks[1][0x2F5B : 0x2F5B + 3] = [0xC3, 0x39, 0x6E]
|
||||||
|
# Disable initial music
|
||||||
|
rom.banks[1][0x2F03 : 0x2F03 + 5] = [0] * 5
|
||||||
|
# Disable music fade on reset
|
||||||
|
rom.banks[1][0x3436 : 0x3436 + 3] = [0] * 3
|
||||||
|
|
||||||
|
|
||||||
|
# Set egg palette
|
||||||
|
BASE = 0x3DEE
|
||||||
|
palettes = []
|
||||||
|
BANK = 0x21
|
||||||
|
for i in range(8):
|
||||||
|
palette = []
|
||||||
|
for c in range(4):
|
||||||
|
address = BASE + i * 8 + c * 2
|
||||||
|
packed = (rom.banks[BANK][address + 1] << 8) | rom.banks[BANK][address]
|
||||||
|
r,g,b = bin_to_rgb(packed)
|
||||||
|
palette.append([r, g, b])
|
||||||
|
palettes.append(palette)
|
||||||
|
|
||||||
|
for i in [1, 2, 5, 6, 7]:
|
||||||
|
palettes[i] = copy.copy(palettes[3])
|
||||||
|
|
||||||
|
def to_5_bit(r, g, b):
|
||||||
|
return [r >> 3, g >> 3, b >> 3]
|
||||||
|
|
||||||
|
palettes[1][3] = to_5_bit(0xFF, 0x80, 145)
|
||||||
|
palettes[2][2] = to_5_bit(119, 198, 155)
|
||||||
|
palettes[5][3] = to_5_bit(119, 198, 155)
|
||||||
|
palettes[6][3] = to_5_bit(192, 139, 215)
|
||||||
|
palettes[7][3] = to_5_bit(229, 196, 139)
|
||||||
|
|
||||||
|
for i in range(8):
|
||||||
|
for c in range(4):
|
||||||
|
address = BASE + i * 8 + c * 2
|
||||||
|
packed = rgb_to_bin(*palettes[i][c])
|
||||||
|
rom.banks[BANK][address] = packed & 0xFF
|
||||||
|
rom.banks[BANK][address + 1] = packed >> 8
|
||||||
|
|
Binary file not shown.
|
@ -1,3 +1,4 @@
|
||||||
|
import bsdiff4
|
||||||
import binascii
|
import binascii
|
||||||
import Utils
|
import Utils
|
||||||
|
|
||||||
|
@ -6,9 +7,13 @@ h2b = binascii.unhexlify
|
||||||
|
|
||||||
|
|
||||||
class ROM:
|
class ROM:
|
||||||
def __init__(self, filename):
|
def __init__(self, filename, patches=None):
|
||||||
data = open(Utils.user_path(filename), "rb").read()
|
data = open(Utils.user_path(filename), "rb").read()
|
||||||
#assert len(data) == 1024 * 1024
|
|
||||||
|
if patches:
|
||||||
|
for patch in patches:
|
||||||
|
data = bsdiff4.patch(data, patch)
|
||||||
|
|
||||||
self.banks = []
|
self.banks = []
|
||||||
for n in range(0x40):
|
for n in range(0x40):
|
||||||
self.banks.append(bytearray(data[n*0x4000:(n+1)*0x4000]))
|
self.banks.append(bytearray(data[n*0x4000:(n+1)*0x4000]))
|
||||||
|
|
|
@ -180,8 +180,8 @@ class IndoorRoomSpriteData(PointerTable):
|
||||||
|
|
||||||
|
|
||||||
class ROMWithTables(ROM):
|
class ROMWithTables(ROM):
|
||||||
def __init__(self, filename):
|
def __init__(self, filename, patches=None):
|
||||||
super().__init__(filename)
|
super().__init__(filename, patches)
|
||||||
|
|
||||||
# Ability to patch any text in the game with different text
|
# Ability to patch any text in the game with different text
|
||||||
self.texts = Texts(self)
|
self.texts = Texts(self)
|
||||||
|
|
|
@ -79,6 +79,12 @@ class DungeonShuffle(DefaultOffToggle, LADXROption):
|
||||||
"""
|
"""
|
||||||
ladxr_name = "dungeonshuffle"
|
ladxr_name = "dungeonshuffle"
|
||||||
|
|
||||||
|
class APTitleScreen(DefaultOnToggle):
|
||||||
|
"""
|
||||||
|
Enables AP specific title screen and disables the intro cutscene
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class BossShuffle(Choice):
|
class BossShuffle(Choice):
|
||||||
none = 0
|
none = 0
|
||||||
shuffle = 1
|
shuffle = 1
|
||||||
|
@ -396,5 +402,6 @@ links_awakening_options: typing.Dict[str, typing.Type[Option]] = {
|
||||||
'shuffle_compasses': ShuffleCompasses,
|
'shuffle_compasses': ShuffleCompasses,
|
||||||
'shuffle_stone_beaks': ShuffleStoneBeaks,
|
'shuffle_stone_beaks': ShuffleStoneBeaks,
|
||||||
'music_change_condition': MusicChangeCondition,
|
'music_change_condition': MusicChangeCondition,
|
||||||
'nag_messages': NagMessages
|
'nag_messages': NagMessages,
|
||||||
|
'ap_title_screen': APTitleScreen,
|
||||||
}
|
}
|
||||||
|
|
|
@ -381,16 +381,14 @@ class LinksAwakeningWorld(World):
|
||||||
# Kind of kludge, make it possible for the location to differentiate between local and remote items
|
# Kind of kludge, make it possible for the location to differentiate between local and remote items
|
||||||
loc.ladxr_item.location_owner = self.player
|
loc.ladxr_item.location_owner = self.player
|
||||||
|
|
||||||
rom_path = "Legend of Zelda, The - Link's Awakening DX (USA, Europe) (SGB Enhanced).gbc"
|
rom_name = "Legend of Zelda, The - Link's Awakening DX (USA, Europe) (SGB Enhanced).gbc"
|
||||||
out_name = f"AP-{self.multiworld.seed_name}-P{self.player}-{self.multiworld.player_name[self.player]}.gbc"
|
out_name = f"AP-{self.multiworld.seed_name}-P{self.player}-{self.multiworld.player_name[self.player]}.gbc"
|
||||||
out_file = os.path.join(output_directory, out_name)
|
out_path = os.path.join(output_directory, f"{self.multiworld.get_out_file_name_base(self.player)}.gbc")
|
||||||
|
|
||||||
rompath = os.path.join(output_directory, f"{self.multiworld.get_out_file_name_base(self.player)}.gbc")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
parser = get_parser()
|
parser = get_parser()
|
||||||
args = parser.parse_args([rom_path, "-o", out_name, "--dump"])
|
args = parser.parse_args([rom_name, "-o", out_name, "--dump"])
|
||||||
|
|
||||||
name_for_rom = self.multiworld.player_name[self.player]
|
name_for_rom = self.multiworld.player_name[self.player]
|
||||||
|
|
||||||
|
@ -408,14 +406,15 @@ class LinksAwakeningWorld(World):
|
||||||
player_names=all_names,
|
player_names=all_names,
|
||||||
player_id = self.player)
|
player_id = self.player)
|
||||||
|
|
||||||
handle = open(rompath, "wb")
|
handle = open(out_path, "wb")
|
||||||
rom.save(handle, name="LADXR")
|
rom.save(handle, name="LADXR")
|
||||||
|
|
||||||
handle.close()
|
handle.close()
|
||||||
patch = LADXDeltaPatch(os.path.splitext(rompath)[0]+LADXDeltaPatch.patch_file_ending, player=self.player,
|
patch = LADXDeltaPatch(os.path.splitext(out_path)[0]+LADXDeltaPatch.patch_file_ending, player=self.player,
|
||||||
player_name=self.multiworld.player_name[self.player], patched_path=rompath)
|
player_name=self.multiworld.player_name[self.player], patched_path=out_path)
|
||||||
patch.write()
|
patch.write()
|
||||||
if not DEVELOPER_MODE:
|
if not DEVELOPER_MODE:
|
||||||
os.unlink(rompath)
|
os.unlink(out_path)
|
||||||
|
|
||||||
def generate_multi_key(self):
|
def generate_multi_key(self):
|
||||||
return bytearray(self.multiworld.random.getrandbits(8) for _ in range(10)) + self.player.to_bytes(2, 'big')
|
return bytearray(self.multiworld.random.getrandbits(8) for _ in range(10)) + self.player.to_bytes(2, 'big')
|
||||||
|
|
|
@ -42,7 +42,7 @@ This randomizer is based on (forked from) the wonderful work daid did on LADXR -
|
||||||
|
|
||||||
The autotracker code for communication with magpie tracker is directly copied from kbranch's repo - https://github.com/kbranch/Magpie/tree/master/autotracking
|
The autotracker code for communication with magpie tracker is directly copied from kbranch's repo - https://github.com/kbranch/Magpie/tree/master/autotracking
|
||||||
|
|
||||||
### Sprites
|
### Graphics
|
||||||
|
|
||||||
The following sprite sheets have been included with permission of their respective authors:
|
The following sprite sheets have been included with permission of their respective authors:
|
||||||
|
|
||||||
|
@ -56,6 +56,8 @@ The following sprite sheets have been included with permission of their respecti
|
||||||
* Richard
|
* Richard
|
||||||
* Tarin
|
* Tarin
|
||||||
|
|
||||||
|
Title screen graphics by toomanyteeth✨ (https://instagram.com/toomanyyyteeth)
|
||||||
|
|
||||||
## Some tips from LADXR...
|
## Some tips from LADXR...
|
||||||
|
|
||||||
<h3>Locations</h3>
|
<h3>Locations</h3>
|
||||||
|
|
Loading…
Reference in New Issue