10 Commits

Author SHA1 Message Date
Snesrev
fbbb3f967a Add BPS support 2023-08-17 03:16:50 +02:00
Snesrev
43db8cc0f5 Move around files 2023-08-17 03:07:19 +02:00
Snesrev
a23632ae6c Seems like the wrong nl hash was used for some reason 2023-03-16 21:48:35 +01:00
DaBanana64
83714135f3 Added Nintendo Switch build target. (#235) 2023-03-16 09:45:22 +01:00
Snesrev
03bf63f40e Switch documentation/Makefile to use restool 2023-03-14 17:21:17 +01:00
Snesrev
f9982dda65 Better error messages on ROM hash mismatch 2023-03-11 15:52:51 +01:00
Snesrev
71b1c3c020 Add support for spanish, portuguese, polish, redux, dutch, swedish 2023-03-10 19:16:44 +01:00
Snesrev
aee281aa1f Add support for extracting dialogue from some more roms 2023-03-10 03:45:19 +01:00
Snesrev
95f757309c Add support for French (Fixes #234) 2023-03-10 02:53:52 +01:00
Snesrev
9dde4a7a07 Add support for german translation
First extract the german dialogue:
python restool.py --extract-dialogue -r german.sfc

Then extract resources / build the assert file:
python restool.py --extract-from-rom --languages=de
2023-03-10 01:54:38 +01:00
95 changed files with 2115 additions and 1375 deletions

View File

@@ -18,5 +18,6 @@ body:
- "Windows"
- "Linux"
- "Mac"
- "Nintendo Switch"
validations:
required: true

16
.gitignore vendored
View File

@@ -7,24 +7,24 @@
*.aps
/obj/
/bin/
/tables/overworld/*.yaml
/tables/dungeon/*.yaml
/tables/img/
/tables/old/
/tables/zelda3.sfc
/tables/zelda3.smc
/assets/overworld/*.yaml
/assets/dungeon/*.yaml
/assets/img/
/assets/old/
/zelda3.sfc
/zelda3.smc
/saves/*.sav
/saves/sram.dat
/saves/sram.bak
/zelda3
__pycache__
/*.o
/src/*.o
/*.exe
/*.out
/snes/*.o
/msu/
/tmp/
/tables/zelda3_assets.dat
/zelda3_assets.dat
/SDL2.dll
/zelda3.*.ini
/zelda3.wiki

View File

@@ -1,9 +1,9 @@
TARGET_EXEC:=zelda3
ROM:=tables/zelda3.sfc
SRCS:=$(wildcard *.c snes/*.c) third_party/gl_core/gl_core_3_1.c third_party/opus-1.3.1-stripped/opus_decoder_amalgam.c
SRCS:=$(wildcard src/*.c snes/*.c) third_party/gl_core/gl_core_3_1.c third_party/opus-1.3.1-stripped/opus_decoder_amalgam.c
OBJS:=$(SRCS:%.c=%.o)
PYTHON:=/usr/bin/env python3
CFLAGS:=$(if $(CFLAGS),$(CFLAGS),-O2 -Werror)
CFLAGS:=$(if $(CFLAGS),$(CFLAGS),-O2 -Werror) -I .
CFLAGS:=${CFLAGS} $(shell sdl2-config --cflags) -DSYSTEM_VOLUME_MIXER_AVAILABLE=0
ifeq (${OS},Windows_NT)
@@ -16,26 +16,23 @@ endif
.PHONY: all clean clean_obj clean_gen
all: $(TARGET_EXEC) tables/zelda3_assets.dat
all: $(TARGET_EXEC) zelda3_assets.dat
$(TARGET_EXEC): $(OBJS) $(RES)
$(CC) $^ -o $@ $(LDFLAGS) $(SDLFLAGS)
%.o : %.c
$(CC) -c $(CFLAGS) $< -o $@
$(RES): platform/win32/zelda3.rc
$(RES): src/platform/win32/zelda3.rc
@echo "Generating Windows resources"
@$(WINDRES) $< -O coff -o $@
tables/zelda3_assets.dat: tables/dialogue.txt
@echo "Compiling game resources"
@cd tables; $(PYTHON) compile_resources.py ../$(ROM)
tables/dialogue.txt:
zelda3_assets.dat:
@echo "Extracting game resources"
@cd tables; $(PYTHON) extract_resources.py ../$(ROM)
$(PYTHON) assets/restool.py --extract-from-rom
clean: clean_obj clean_gen
clean_obj:
@$(RM) $(OBJS) $(TARGET_EXEC)
clean_gen:
@$(RM) $(RES) tables/zelda3_assets.dat tables/*.txt tables/*.png tables/sprites/*.png tables/*.yaml
@$(RM) $(RES) zelda3_assets.dat tables/zelda3_assets.dat tables/*.txt tables/*.png tables/sprites/*.png tables/*.yaml
@rm -rf tables/__pycache__ tables/dungeon tables/img tables/overworld tables/sound

View File

@@ -49,18 +49,15 @@ Visit Wiki for more info on building the project: https://github.com/snesrev/zel
## Compiling on Windows with TCC (1mb Tiny C Compiler)
1. Download the project by clicking "Code > Download ZIP" on the github page
2. Extract the ZIP to your hard drive
3. Place the USA rom named `zelda3.sfc` in the "\tables" subfolder
4. Open the command prompt and navigate to that folder
5. Type `python extract_resources.py` and hit enter
6. Type `python compile_resources.py` and hit enter
7. Close the command prompt
8. Download [TCC](https://github.com/FitzRoyX/tinycc/releases/download/tcc_20221020/tcc_20221020.zip) and extract to the "\third_party" subfolder
9. Download [SDL2](https://github.com/libsdl-org/SDL/releases/download/release-2.26.3/SDL2-devel-2.26.3-VC.zip) and extract to the "\third_party" subfolder
10. Double-click `run_with_tcc.bat` in the main dir to create `zelda3.exe` in that same dir
11. Configure with `zelda3.ini` in the main dir
3. Place the USA rom named `zelda3.sfc` in the root directory.
4. Double-click `extract_assets.bat` in the main dir to create `zelda3_assets.dat` in that same dir
5. Download [TCC](https://github.com/FitzRoyX/tinycc/releases/download/tcc_20221020/tcc_20221020.zip) and extract to the "\third_party" subfolder
6. Download [SDL2](https://github.com/libsdl-org/SDL/releases/download/release-2.26.3/SDL2-devel-2.26.3-VC.zip) and extract to the "\third_party" subfolder
7. Double-click `run_with_tcc.bat` in the main dir to create `zelda3.exe` in that same dir
8. Configure with `zelda3.ini` in the main dir
## Compiling on Windows with Visual Studio (4.5gb IDE and compiler)
Same Steps 1-7 above<br/>
Same Steps 1-4 above<br/>
8. Double-click `Zelda3.sln`<br/>
9. Install the **Desktop development with C++** workload with the VS Installer if you don't have it already (it should prompt you to do this).<br/>
10. Change "debug" to "release" in the top dropdown<br/>
@@ -89,7 +86,7 @@ python3 -m pip install -r requirements.txt
* macOS: `brew install sdl2` (you can get homebrew [here](https://brew.sh/))
## Compiling on Linux/MacOS
1. Place your US ROM file named `zelda3.sfc` in `zelda3/tables`
1. Place your US ROM file named `zelda3.sfc` in `zelda3`
2. Compile
```sh
make
@@ -125,7 +122,7 @@ Look at the wiki at https://github.com/snesrev/zelda3/wiki for more help.
The ROM needs to be named `zelda3.sfc` and has to be from the US region with this exact SHA256 hash
`66871d66be19ad2c34c927d6b14cd8eb6fc3181965b6e517cb361f7316009cfb`
In case you're planning to move the executable to a different location, please include the file `tables/zelda3_assets.dat`.
In case you're planning to move the executable to a different location, please include the file `zelda3_assets.dat`.
## Usage and controls

View File

@@ -1,5 +1,5 @@
zelda3.sfc
dialogue.txt
dialogue*.txt
generated_*.h
linksprite.png
map32_to_map16.txt
@@ -8,4 +8,7 @@ sfx.txt
/sound
sound_ending.txt
sound_indoor.txt
sound_intro.txt
sound_intro.txt
/hud_icons.png
/font*.png

View File

@@ -9,13 +9,7 @@ import array, hashlib, struct
from util import cache
import sprite_sheets
import argparse
parser = argparse.ArgumentParser(description='Compile resources.')
parser.add_argument('rom', nargs='?', help='the rom file')
parser.add_argument('--sprites-from-png', action='store_true', help='Use the sprite images from the .PNG files')
args = parser.parse_args()
ROM = util.LoadedRom(args.rom)
import os
def flatten(xss):
return [x for xs in xss for x in xs]
@@ -41,6 +35,10 @@ def add_asset_int16(name, data):
assert name not in assets
assets[name] = ('int16', bytes(array.array('h', data)))
def add_asset_packed(name, data):
assert name not in assets
assets[name] = ('packed', pack_arrays(data))
def print_map32_to_map16():
tab = {}
for line in open('map32_to_map16.txt'):
@@ -68,20 +66,12 @@ def print_map32_to_map16():
add_asset_uint8('kMap32ToMap16_2', res[2])
add_asset_uint8('kMap32ToMap16_3', res[3])
def print_dialogue():
new_r = []
offs = []
for line in open('dialogue.txt'):
line = line.strip('\n')
def compress_dialogue(fname, lang):
lines = []
for line in open(fname, encoding='utf8').read().splitlines():
a, b = line.split(': ', 1)
index = int(a)
offs.append(len(new_r))
r = text_compression.compress_string(b)
new_r.extend(r)
add_asset_uint16('kDialogueOffs', offs)
add_asset_uint8('kDialogueText', new_r)
lines.append(b)
return text_compression.compress_strings(lines, lang)
def compress_store(r):
rr = []
@@ -95,14 +85,20 @@ def compress_store(r):
rr.append(0xff)
return rr
def pack_u32_arrays(arr):
all_offs, offs = [], len(arr) * 4
for i in range(len(arr)):
all_offs.append(offs)
# Pack arrays and determine automatically the index size
def pack_arrays(arr):
if len(arr) == 0:
return b''
all_offs, offs = [], 0
for i in range(len(arr) - 1):
offs += len(arr[i])
return b''.join([struct.pack('I', i) for i in all_offs] + arr)
all_offs.append(offs)
if offs < 65536 and len(arr) <= 8192:
return b''.join([struct.pack('H', i) for i in all_offs] + arr + [struct.pack('H', len(arr) - 1)])
else:
return b''.join([struct.pack('I', i) for i in all_offs] + arr + [struct.pack('H', 8192 + len(arr) - 1)])
def print_images():
def print_images(args):
sprsheet = sprite_sheets.load_sprite_sheets() if args.sprites_from_png else None
all = []
@@ -114,25 +110,48 @@ def print_images():
else:
decomp, comp_len = util.decomp(tables.kCompSpritePtrs[i], ROM.get_byte, False, True)
all.append(bytes(ROM.get_bytes(tables.kCompSpritePtrs[i], comp_len)))
add_asset_uint8('kSprGfx', pack_u32_arrays(all))
add_asset_packed('kSprGfx', all)
all = []
for i in range(len(tables.kCompBgPtrs)):
decomp, comp_len = util.decomp(tables.kCompBgPtrs[i], ROM.get_byte, False, True)
all.append(bytes(ROM.get_bytes(tables.kCompBgPtrs[i], comp_len)))
add_asset_uint8('kBgGfx', pack_u32_arrays(all))
add_asset_packed('kBgGfx', all)
def print_dialogue(args):
from text_compression import dialogue_filename, kLanguages
languages = ['us']
if args.languages:
for a in args.languages.split(','):
if a in languages or a not in kLanguages:
raise Exception(f'Language {a} is not valid')
name = dialogue_filename(a)
if not os.path.exists(name):
raise Exception(f'{name} not found. You need to extract it with --extract-dialogue using the ROM of that language.')
languages.append(a)
def print_misc():
all_langs, all_fonts, mappings = [], [], []
for i, lang in enumerate(languages):
dict_packed = pack_arrays(text_compression.encode_dictionary(lang))
dialogue_packed = pack_arrays(compress_dialogue(dialogue_filename(lang), lang))
all_langs.append(pack_arrays([dict_packed, dialogue_packed]))
font_data, font_width = sprite_sheets.encode_font_from_png(lang)
all_fonts.append(pack_arrays([font_data, font_width]))
flags = text_compression.uses_new_format(lang)
if i != 0: flags |= 2 # no us rom match?
mappings.append(pack_arrays([lang.encode('utf8'), bytearray([i, i, flags])]))
add_asset_packed('kDialogue', all_langs)
add_asset_packed('kDialogueFont', all_fonts)
add_asset_packed('kDialogueMap', mappings)
def print_misc(args):
add_asset_uint8('kOverworldMapGfx', ROM.get_bytes(0x18c000, 0x4000))
add_asset_uint8('kLightOverworldTilemap', ROM.get_bytes(0xac727, 4096))
add_asset_uint8('kDarkOverworldTilemap', ROM.get_bytes(0xaD727, 1024))
add_asset_uint16('kPredefinedTileData', ROM.get_words(0x9B52, 6438))
add_asset_uint16('kFontData', ROM.get_words(0xe8000, 2048))
add_asset_uint16('kMap16ToMap8', ROM.get_words(0x8f8000, 3752 * 4))
add_asset_uint8('kGeneratedWishPondItem', ROM.get_bytes(0x888450, 256))
@@ -175,14 +194,14 @@ def print_overworld():
addr = ROM.get_24(0x82F94D + i * 3)
decomp, comp_len = util.decomp(addr, ROM.get_byte, True, True)
r.append(bytes(ROM.get_bytes(addr, comp_len)))
add_asset_uint8('kOverworld_Hibytes_Comp', pack_u32_arrays(r))
add_asset_packed('kOverworld_Hibytes_Comp', r)
r = []
for i in range(160):
addr = ROM.get_24(0x82FB2D + i * 3)
decomp, comp_len = util.decomp(addr, ROM.get_byte, True, True)
r.append(bytes(ROM.get_bytes(addr, comp_len)))
add_asset_uint8('kOverworld_Lobytes_Comp', pack_u32_arrays(r))
add_asset_packed('kOverworld_Lobytes_Comp', r)
def is_area_head(i):
return i >= 128 or ROM.get_byte(0x82A5EC + (i & 63)) == (i & 63)
@@ -430,8 +449,8 @@ def print_dungeon_map():
b = ROM.get_bytes(addr, nonzero_bytes)
r2.append(bytes(b))
add_asset_uint8('kDungMap_FloorLayout', pack_u32_arrays(r))
add_asset_uint8('kDungMap_Tiles', pack_u32_arrays(r2))
add_asset_packed('kDungMap_FloorLayout', r)
add_asset_packed('kDungMap_Tiles', r2)
@cache
@@ -691,8 +710,6 @@ def print_dungeon_rooms():
add_asset_uint16('kMovableBlockDataInit', ROM.get_words(0x84f1de, 198))
add_asset_uint16('kTorchDataInit', ROM.get_words(0x84F36A, 144))
add_asset_uint16('kTorchDataJunk', ROM.get_words(0x84F48a, 48))
def print_enemy_damage_data():
decomp, comp_len = util.decomp(0x83e800, ROM.get_byte, True, True)
@@ -736,24 +753,21 @@ def print_sound_banks():
name, data = compile_music.print_song(song)
add_asset_uint8(name, data)
def print_all():
def print_all(args):
print_sound_banks()
print_dungeon_rooms()
print_enemy_damage_data()
print_link_graphics()
print_dungeon_sprites()
print_map32_to_map16()
print_dialogue()
print_images()
print_misc()
print_images(args)
print_misc(args)
print_dialogue(args)
print_dungeon_map()
print_tilemaps()
print_overworld()
print_overworld_tables()
print_all()
def write_assets_to_file(print_header = False):
key_sig = b''
all_data = []
@@ -765,12 +779,17 @@ enum {
kNumberOfAssets = %d
};
extern const uint8 *g_asset_ptrs[kNumberOfAssets];
extern uint32 g_asset_sizes[kNumberOfAssets];''' % len(assets))
extern uint32 g_asset_sizes[kNumberOfAssets];
extern MemBlk FindInAssetArray(int asset, int idx);
''' % len(assets))
for i, (k, (tp, data)) in enumerate(assets.items()):
if print_header:
print('#define %s ((%s*)g_asset_ptrs[%d])' % (k, tp, i))
print('#define %s_SIZE (g_asset_sizes[%d])' % (k, i))
if tp == 'packed':
print('#define %s(idx) FindInAssetArray(%d, idx)' % (k, i))
else:
print('#define %s ((%s*)g_asset_ptrs[%d])' % (k, tp, i))
print('#define %s_SIZE (g_asset_sizes[%d])' % (k, i))
key_sig += k.encode('utf8') + b'\0'
all_data.append(data)
@@ -790,8 +809,19 @@ extern uint32 g_asset_sizes[kNumberOfAssets];''' % len(assets))
file_data += b'\0'
file_data += v
open('zelda3_assets.dat', 'wb').write(file_data)
open('../zelda3_assets.dat', 'wb').write(file_data)
write_assets_to_file(False)
def main(args):
print_all(args)
write_assets_to_file(args.print_assets_header)
if __name__ == "__main__":
ROM = util.load_rom(sys.argv[1] if len(sys.argv) >= 2 else None)
class DefaultArgs:
sprites_from_png = False
languages = None
print_assets_header = False
main(DefaultArgs())
else:
ROM = util.ROM

View File

@@ -240,7 +240,7 @@ def print_all_overworld_areas():
print_overworld_area(i)
def print_dialogue():
text_compression.print_strings(open('dialogue.txt', 'w'), get_byte)
text_compression.print_strings(util.ROM, file = open(text_compression.dialogue_filename(util.ROM.language), 'w', encoding='utf8'))
def decode_room_objects(p):
objs = []
@@ -529,11 +529,13 @@ def print_all_text_stuff():
def main():
make_directories()
print_all_text_stuff()
extract_music.extract_sound_data(ROM)
extract_music.extract_sound_data(util.ROM)
sprite_sheets.decode_link_sprites()
sprite_sheets.decode_sprite_sheets()
ROM = util.load_rom(sys.argv[1] if len(sys.argv) >= 2 else None)
sprite_sheets.decode_hud_icons()
sprite_sheets.decode_font()
if __name__ == "__main__":
util.load_rom(sys.argv[1] if len(sys.argv) >= 2 else None)
main()
main()
#sprite_sheets.decode_sprite_sheets()

BIN
assets/palette_usage.bin Normal file

Binary file not shown.

52
assets/restool.py Normal file
View File

@@ -0,0 +1,52 @@
import argparse
import util
import sys
import os
os.chdir(os.path.dirname(__file__))
parser = argparse.ArgumentParser(description='Resource tool used to build zelda3_assets.dat', allow_abbrev=False)
parser.add_argument('-r', '--rom', nargs='?', metavar='ROM')
parser.add_argument('--extract-from-rom', '-e', action='store_true', help='Extract/overwrite things from the ROM')
optional = parser.add_argument_group('Language settings')
optional.add_argument('--extract-dialogue', action='store_true', help = 'Extract dialogue from a translated ROM')
optional.add_argument('--languages', action='store', metavar='L1,L2', help = 'Comma separated list of additional languages to build (de,fr,fr-c,en,es,pl,pt,redux,nl,sv).')
optional = parser.add_argument_group('Debug things')
optional.add_argument('--no-build', action='store_true', help="Don't actually build zelda3_assets.dat")
optional.add_argument('--print-strings', action='store_true', help="Print all dialogue strings")
optional.add_argument('--print-assets-header', action='store_true')
optional = parser.add_argument_group('Image handling')
optional.add_argument('--sprites-from-png', action='store_true', help="When compiling, load sprites from png instead of from ROM")
args = parser.parse_args()
if args.extract_dialogue:
ROM = util.load_rom(args.rom, True)
import extract_resources, sprite_sheets
sprite_sheets.decode_font()
extract_resources.print_dialogue()
sys.exit(0)
ROM = util.load_rom(args.rom)
want_compile = True
if args.extract_from_rom:
import extract_resources
extract_resources.main()
if args.print_strings:
import text_compression
text_compression.print_strings(ROM)
want_compile = False
if want_compile and not args.no_build:
import compile_resources
compile_resources.main(args)

View File

@@ -4,6 +4,8 @@ import util
from util import get_bytes, get_words, get_byte, cache
import array
import tables
import sys
override_armor_palette = None
#override_armor_palette = [0x7fff, 0x237e, 0x11b7, 0x369e, 0x14a5, 0x1ff, 0x1078, 0x599d, 0x3647, 0x3b68, 0xa4a, 0x12ef, 0x2a5c, 0x1571, 0x7a18,
# 0x7fff, 0x237e, 0x11b7, 0x369e, 0x14a5, 0x1ff, 0x1078, 0x599d, 0x6980, 0x7691, 0x26b8, 0x437f, 0x2a5c, 0x1199, 0x7a18,
@@ -25,21 +27,20 @@ def save_as_24bpp_png(dimensions, data, fname):
img.save(fname)
@cache
def decode_2bit_tileset(tileset):
def decode_2bit_tileset(tileset, height = 32, base = 0):
data = util.decomp(tables.kCompSpritePtrs[tileset], get_byte, False)
assert len(data) == 0x400
height = 32
assert len(data) == 0x400 * height // 32
dst = bytearray(128*height)
def decode_2bit(offs, toffs):
def decode_2bit(offs, toffs, base):
for y in range(8):
d0, d1 = data[offs + y * 2], data[offs + y * 2 + 1]
for x in range(8):
t = ((d0 >> x) & 1) * 1 + ((d1 >> x) & 1) * 2
dst[toffs + y * 128 + (7 - x)] = t * 255 // 3
dst[toffs + y * 128 + (7 - x)] = t + base
for i in range(16*height//8):
x = i % 16
y = i // 16
decode_2bit(i * 16, x * 8 + y * 8 * 128)
decode_2bit(i * 16, x * 8 + y * 8 * 128, base[i] if isinstance(base, tuple) else base)
return dst
def is_high_3bit_tileset(tileset):
@@ -109,6 +110,121 @@ def decode_link_sprites():
kLinkPalette = [0, 0x7fff, 0x237e, 0x11b7, 0x369e, 0x14a5, 0x1ff, 0x1078, 0x599d, 0x3647, 0x3b68, 0xa4a, 0x12ef, 0x2a5c, 0x1571, 0x7a18]
save_as_png((128, 448), decode_4bit_tileset_link(), 'linksprite.png', convert_snes_palette(kLinkPalette))
def get_hud_snes_palette():
hud_palette = get_words(0x9BD660, 64)
palette = [(31 << 10 | 31) for i in range(256)]
for i in range(16):
for j in range(1, 4):
palette[i * 16 + j] = hud_palette[i * 4 + j]
return palette
def decode_hud_icons():
class PaletteUsage:
def __init__(self):
self.data = open('palette_usage.bin', 'rb').read()
def get(self, icon):
usage = self.data[icon]
for j in range(8):
if usage & (1 << j):
return j
return 0
pu = PaletteUsage()
dst = bytearray()
for slot, image_set in enumerate([106, 107, 105]):
tbase = tuple([pu.get(slot * 128 + i) * 16 for i in range(128)])
dst += decode_2bit_tileset(image_set, height = 64, base = tbase)
save_as_png((128, 64 * 3), dst, 'hud_icons.png', convert_snes_palette(get_hud_snes_palette()[:128]))
def get_pt_remapper():
b = util.ROM.get_bytes(0x8EFC09, 121 * 3)
d = {}
for i in range(121):
ch = (i & 0xf) | (i << 1) & 0xe0
d[ch] = b[i*3+0]
d[ch|0x10] = b[i*3+1]
return d
kFontTypes = {
'us' : (0x8e8000, 256, 'font.png', (0x8ECADF, 99)),
'de' : (0xCC6E8, 256, 'font_de.png', (0x8CDECF, 112)),
'fr' : (0xCC6E8, 256, 'font_fr.png', (0x8CDEAF, 112)),
'fr-c' : (0xCD078, 256, 'font_fr_c.png', (0x8CE83F, 112)),
'en' : (0x8E8000, 256, 'font_en.png', (0x8ECAFF, 102)),
'es' : (0x8e8000, 256, 'font_es.png', (0x8ECADF, 99)),
'pl' : (0x8e8000, 256, 'font_pl.png', (0x8ECADF, 99)),
'pt' : (0x8e8000, 256, 'font_pt.png', (0x8ECADF, 121)),
'redux': (0x8e8000, 256, 'font_redux.png', (0x8ECADF, 99)),
'nl': (0x8e8000, 256, 'font_nl.png', (0x8ECADF, 99)),
'sv': (0x8e8000, 256, 'font_sv.png', (0x8ECADF, 99)),
}
def decode_font():
lang = util.ROM.language
def decomp_one_spr_2bit(data, offs, target, toffs, pitch, palette_base):
for y in range(8):
d0, d1 = data[offs + y * 2], data[offs + y * 2 + 1]
for x in range(8):
t = ((d0 >> x) & 1) * 1 + ((d1 >> x) & 1) * 2
target[toffs + y * pitch + (7 - x)] = t + palette_base
ft = kFontTypes[lang]
if lang == 'pt':
W = util.ROM.get_bytes(0x8EFC09, 121 * 3)
W = [W[i*3+2] for i in range(121)]
remapper = get_pt_remapper()
else:
W = get_bytes(*ft[3])
remapper = {}
w = 128 + 15
hi = ft[1] // 32
h = hi * 17
data = get_bytes(ft[0], ft[1] * 16)
dst = bytearray(w * h)
for i in range(ft[1]):
x, y = i % 16, i // 16
pal_base = 6 * 16
base_offs = x * 9 + (y * 8 + (y >> 1)) * w
decomp_one_spr_2bit(data, remapper.get(i, i) * 16, dst, base_offs + w, w, pal_base)
if (y & 1) == 0:
j = (y >> 1) * 16 + x
if j < len(W):
dst[base_offs + W[j] - 1] = 255
pal = convert_snes_palette(get_hud_snes_palette()[:128])
pal.extend([0] * 384)
pal[0], pal[1], pal[2] = 192, 192, 192
pal[255*3+0], pal[255*3+1], pal[255*3+2] = 128, 128, 128
save_as_png((w, h), dst, ft[2], pal)
if lang != 'pt':
assert (data, W) == encode_font_from_png(lang)
def encode_font_from_png(lang):
font_data = Image.open(kFontTypes[lang][2]).tobytes()
def encode_one_spr_2bit(data, offs, target, toffs, pitch):
for y in range(8):
d0, d1 = 0, 0
for x in range(8):
pixel = data[offs + y * pitch + 7 - x]
d0 |= (pixel & 1) << x
d1 |= ((pixel >> 1) & 1) << x
target[toffs + y * 2 + 0], target[toffs + y * 2 + 1] = d0, d1
w = 128 + 15
dst = bytearray(256 * 16)
def get_width(base_offs):
for i in range(8):
if font_data[base_offs + i] == 255:
break
return i + 1
W = bytearray()
for i in range(256):
x, y = i % 16, i // 16
base_offs = x * 9 + (y * 8 + (y >> 1)) * w
if (y & 1) == 0:
W.append(get_width(base_offs))
encode_one_spr_2bit(font_data, base_offs + w, dst, i * 16, w)
chars_per_lang = kFontTypes[lang][3][1]
return dst, W[:chars_per_lang]
# Returns the dungeon palette for the specified palette index
# 0 = lightworld, 1 = darkworld, 2 = dungeon
@cache
@@ -425,7 +541,6 @@ class MasterTilesheets:
encode_into((y * 16 + x) * 24, y * 8 * 128 + x * 8)
return result
def decode_sprite_sheets():
master_tilesheets = MasterTilesheets()
@@ -516,3 +631,10 @@ def load_sprite_sheets():
if not is_empty(src_pos):
master_tilesheets.add_verify_8x8(tileset, pal_lut, img_data, pitch, dst_pos, src_pos)
return master_tilesheets
#if __name__ == "__main__":
# ROM = util.load_rom(sys.argv[1] if len(sys.argv) >= 2 else None, True)
# decode_font()

551
assets/text_compression.py Normal file
View File

@@ -0,0 +1,551 @@
import util, sys
kTextAlphabet_US = [
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", # 0 - 15
"Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
"w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
"-", ".", ",",
# 64 - 79
"[...]", ">", "(", ")",
"[Ankh]", "[Waves]", "[Snake]", "[LinkL]", "[LinkR]",
"\"", "[Up]", "[Down]", "[Left]",
# 80 - 95
"[Right]", "'", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
"[4HeartL]", "[4HeartR]", " ", "<", "[A]", "[B]", "[X]", "[Y]",
]
kTextAlphabet_DE = [
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", # 0 - 15
"Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
"w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
# 64 - 79
"-", ".", ",", "[...]", ">", "(", ")",
"[Ankh]", "[Waves]", "[Snake]", "[LinkL]", "[LinkR]",
"\"", "[UpL]", "[UpR]", "[LeftL]",
# 80 - 95
"[LeftR]", "'", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
"[4HeartL]", "[4HeartR]", " ", "ö", "[A]", "[B]", "[X]", "[Y]", "ü",
# 96-111
"ß", ":", "[DownL]", "[DownR]", "[RightL]", "[RightR]",
"è", "é", "ê", "à", "ù", "ç", "Ä", "Ö", "Ü", "ä"
# 112-
]
kTextAlphabet_FR = [
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", # 0 - 15
"Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
"w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
# 64 - 79
"-", ".", ",", "[...]", ">", "(", ")",
"[Ankh]", "[Waves]", "[Snake]", "[LinkL]", "[LinkR]",
"\"", "[UpL]", "[UpR]", "[LeftL]",
# 80 - 95
"[LeftR]", "'", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
"[4HeartL]", "[4HeartR]", " ", "ö", "[A]", "[B]", "[X]", "[Y]", "ü",
# 96-111
"ô", ":", "[DownL]", "[DownR]", "[RightL]", "[RightR]",
"è", "é", "ê", "à", "ù", "ç", "â", "û", "î", "ä"
# 112-
]
kText_CommandLengths_US = [1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, ]
kText_CommandNames_US = [
"NextPic", "Choose", "Item", "Name", "Window", "Number",
"Position","ScrollSpd", "Selchg", "Unused_Crash", "Choose3",
"Choose2", "Scroll", "1", "2", "3", "Color",
"Wait", "Sound", "Speed", "Unused_Mark", "Unused_Mark2", "Unused_Clear",
"Waitkey"
]
kTextDictionary_US = [
' ', ' ', ' ', "'s ", 'and ',
'are ', 'all ', 'ain', 'and', 'at ',
'ast', 'an', 'at', 'ble', 'ba',
'be', 'bo', 'can ', 'che', 'com',
'ck', 'des', 'di', 'do', 'en ',
'er ', 'ear', 'ent', 'ed ', 'en',
'er', 'ev', 'for', 'fro', 'give ',
'get', 'go', 'have', 'has', 'her',
'hi', 'ha', 'ight ', 'ing ', 'in',
'is', 'it', 'just', 'know', 'ly ',
'la', 'lo', 'man', 'ma', 'me',
'mu', "n't ", 'non', 'not', 'open',
'ound', 'out ', 'of', 'on', 'or',
'per', 'ple', 'pow', 'pro', 're ',
're', 'some', 'se', 'sh', 'so',
'st', 'ter ', 'thin', 'ter', 'tha',
'the', 'thi', 'to', 'tr', 'up',
'ver', 'with', 'wa', 'we', 'wh',
'wi', 'you', 'Her', 'Tha', 'The',
'Thi', 'You',
]
kText_CommandLengths_EU = [1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2]
kText_CommandNames_EU = [
"Selchg", "Choose3", "Choose2", "Scroll", "1", "2", "3",
"Color", "Wait", "Sound", "Speed", "Mark", "Mark2",
"Clear", "Waitkey", "EndMessage", "NextPic", "Choose",
"Item", "Name", "Window", "Number", "Position", "ScrollSpd",
]
kTextDictionary_DE = [
' ', ' ', ' ', '-Knopf', ' ich ',
' Sch', ' Ver', ' zu ', ' es ', 'aber',
'alle', 'auch', 'ang', 'aus', 'auf',
'an', 'bist', 'bin', 'bei', 'der ',
'die ', 'das ', 'den ', 'dem ', 'daß',
'der', 'die', 'das', 'den', 'da',
'etwas', 'ein ', 'ein', 'en ', 'er ',
'es ', 'en', 'er', 'es', 'ei',
'für', 'fe', 'habe', 'hier', 'hast',
'her', 'ich ', 'icht', 'ich', 'ist',
'ie ', 'im', 'ie', 'kannst ', 'kannst',
'kommen', 'kann ', 'll', 'mich', 'mein',
'mit', 'mal', 'mir', 'nicht ', 'nicht',
'nen', 'nn', 'och ', 'och', 'or',
'schon', 'sich', 'sein', 'sch', 'sie',
'st', 'tte', 'te ', 'te', 'und ',
'und', 'ung', 'um', 'von', 'ver',
'vor', 'wird', 'zu ', 'Amulett', 'Aber',
'Deine', 'Dich ', 'Dir ', 'Dir', 'Der',
'Die', 'Das', 'Du ', 'Du', 'Da',
'Ein', 'Hyrule', 'Hier', 'Ich ', 'Master-Schwert',
'Mach', 'Rubine', 'Sch', 'Sie', 'Ver',
'Weisen', 'Zelda',
]
kTextDictionary_FR = [
' ', ' de ', ' la ', ' le ', ' ! ',
' d', ' p', ' t', ' !', ", c'est moi, Sahasrahla",
', ', 'ais ', 'as ', 'an', 'ai',
'a ', 'che', 'ce', 'ch', 'dans ',
'des ', 'de ', 'de', 'est ', 'ent',
'en ', 'er ', 'es ', 'en', 'es',
'et', 'eu', 'e,', 'e ', 'ique',
'ien', 'is ', 'ie', 'in', 'ir',
'is', 'i ', 'les ', 'la ', 'le ',
'le', 'll', 'maintenant', 'magique', 'ment',
'mon', 'mai', 'me', 'ne ', 'onne',
'oir', 'our', 'ouv', 'oi', 'on',
'ou', 'or', 'pouvoir', 'pour', 'peux',
'pas', 'que ', 'qu', 'rubis', 're ',
'ra', 're', 'r ', 'sorcier', 's l',
's d', 'se', 'so', 's ', 'tro',
'te ', 'tu ', 'te', 't ', 'un',
'ur', 'u ', 'ver', 'Ah ! Ah ! Ah !', "C'est",
'Ganon', 'Maintenant', 'Merci', 'Monde', 'Perle de Lune',
'Tu as trouvé ', 'Ténèbres', 'Tu peux', 'Tu ',
]
# Uses the original format
def org_encoder(cmd, param):
if cmd not in kText_CommandNames_US:
raise Exception(f'Invalid cmd {cmd}')
cmd_index = kText_CommandNames_US.index(cmd)
if kText_CommandLengths_US[cmd_index] != (1 if param == None else 2):
raise Exception(f'Invalid cmd params {cmd} {param}')
if param == None:
return [cmd_index + 0x67]
return [cmd_index + 0x67, int(param)]
kCmdInfo = {
"Scroll" : (0x80, ),
"Waitkey" : (0x81, ),
"1" : (0x82, ),
"2" : (0x83, ),
"3" : (0x84, ),
"Name" : (0x85, ),
"Wait" : (0x87, {i:i+0x00 for i in range(16)}),
"Color" : (0x87, {i:i+0x10 for i in range(16)}),
"Number" : (0x87, {i:i+0x20 for i in range(16)}),
"Speed" : (0x87, {i:i+0x30 for i in range(16)}),
"Sound" : (0x87, {45 : 0x40, 64 : None}), # pt uses 64 for some reason
"Choose" : (0x87, 0x80),
"Choose2" : (0x87, 0x81),
"Choose3" : (0x87, 0x82),
"Selchg" : (0x87, 0x83),
"Item" : (0x87, 0x84),
"NextPic" : (0x87, 0x85),
"Window" : (0x87, {0 : None, 2 : 0x86}),
"Position" : (0x87, {0: 0x87, 1: 0x88}),
"ScrollSpd" : (0, {0 : None}),
}
# Uses another format where there's more bytes left for characters
def new_encoder(cmd, param):
if cmd not in kCmdInfo:
raise Exception(f'Invalid cmd {cmd}')
info = kCmdInfo[cmd]
if len(info) <= 1 or isinstance(info[1], int):
if param != None:
raise Exception(f'Invalid cmd params {cmd} {param}')
return info
else:
if param == None or param not in info[1]:
raise Exception(f'Invalid cmd params {cmd} {param}')
r = info[1][param]
return (info[0], r) if r != None else ()
kEncoders = {'org' : org_encoder, 'new' : new_encoder}
class LangUS:
alphabet = kTextAlphabet_US
dictionary = kTextDictionary_US
command_lengths = kText_CommandLengths_US
command_names = kText_CommandNames_US
rom_addrs = [0x9c8000, 0x8edf40]
COMMAND_START = 0x67
SWITCH_BANK = 0x80
FINISH = 0xff
DICT_BASE_ENC, DICT_BASE_DEC = 0x88, 0x88
ESCAPE_CHARACTER = None
encoder = 'org'
class LangEN(LangUS):
alphabet = kTextAlphabet_DE
dictionary = kTextDictionary_US
rom_addrs = [0x9c8000, 0x8edf60]
class LangES(LangUS):
alphabet = [
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", # 0 - 15
"Q", "R", "S", "T", "U", "V", "W", "é", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
"ó", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
"[Waves]", ".", ",",
# 64 - 79
"[...]", ">", "(", ")",
"ñ", "ú", "á", "[LinkL]", "[LinkR]", "\"", "[Up]", "[Down]", "[Left]",
# 80 - 95
"[Right]", "í", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
"[Ankh]", "[4HeartR]", " ", "[Snake]", "[A]", "[B]", "[X]", "[Y]", "[I]",
"¡", "¿", "Ñ"
]
# "[Ankh]", "[Waves]", "[Snake]"
dictionary = [
' ', ' ', ' ', ' en', ' la ', ' el ', ' de ', 'ien', 'tra', ' de',
'te ', 'ar', 'a ', 'ada', 'es', 'as', 'o ', ' con', 'ero', 'ado',
'e ', 'que', 'en', 'al', 'os ', 'ora', 'nte', ' al', 'lo ', 'or',
'os', 'er', 'aci', 'res', ' que ', ' es', 'el', 'los ', 'tar', ' se',
', ', 'ro', ' de l', ' est', 're', 'on', 'an', 'pued', ' del', 'ás ',
'la', 'ti', 'la ', 'Es', 'to', 'ta', 'para', 'uer', 'ier', ' un ',
' por', 'oder', 'da', 'in', 'cu', ' ha', 'per', 'ano', ' ve', 'cer',
'lo', ' no ', 'ic', 'ra', 'ab', 'ir', ' una', 'undo', 'es ', 'as ',
'con', 'a, ', 'te', ' m', 'gu', ' tu', 'ando', ' p', 'de', 'le',
'ol', 'o, ', 'ten', 'lle', ' a ', 'aba', 'com',
]
rom_addrs = [0x9c8000, 0x8edf40]
class LangNL(LangUS):
alphabet = [
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", # 0 - 15
"Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
"w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
"-", ".", ",", "[...]", ">", "(", ")", "[Ankh]",
"[Waves]", "[Snake]", "[LinkL]", "[LinkR]", "\"", "[Up]", "[Down]", "[Left]",
# 80 - 95
"[Right]", "'", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
"[4HeartL]", "[4HeartR]", " ", "<", "[A]", "[B]", "[X]", "[Y]",
]
dictionary = [
' ', ' ', ' ', "'s ", 'and ', 'are ', 'all ', 'ain', 'and', 'at ',
'ast', 'an', 'at', 'ble', 'ba', 'be', 'bo', 'can ', 'che', 'com',
'ck', 'des', 'di', 'do', 'en ', 'er ', 'ear', 'ent', 'ed ', 'en',
'er', 'ev', 'for', 'fro', 'give ', 'get', 'go', 'have', 'has', 'her',
'hi', 'ha', 'ight ', 'ing ', 'in', 'is', 'it', 'just', 'know', 'ly ',
'la', 'lo', 'man', 'ma', 'me', 'mu', "n't ", 'non', 'not', 'open',
'ound', 'out ', 'of', 'on', 'or', 'per', 'ple', 'pow', 'pro', 're ',
're', 'some', 'se', 'sh', 'so', 'st', 'ter ', 'thin', 'ter', 'tha',
'the', 'thi', 'to', 'tr', 'up', 'ver', 'with', 'wa', 'we', 'wh',
'wi', 'you', 'Her', 'Tha', 'The', 'Thi', 'You',
]
rom_addrs = [0x9c8000, 0x8edf40]
class LangSV(LangUS):
alphabet = [
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "Ö", "P", # 0 - 15
"Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
"w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
"å", ".", ",", "ä", ">", "(", ")","ö",
"Å", "Ä", "[LinkL]", "[LinkR]", "\"", "[Up]", "[Down]", "[Left]",
# 80 - 95
"[Right]", "'", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
"[4HeartL]", "[4HeartR]", " ", "<", "[Ankh]", "[Waves]", "[Snake]", "-", "[I]",
"[i]", "", " ",
]
dictionary = [
' ', ' ', ' ', 'Du ', 'till', 'vill', 'bara', 'det', 'den', 'och',
'en ', 'r ', 'n ', 'ett', 'en', ' d', 'a ', 'Hjäl', 'har', 'ter',
't ', 'var', ' s', 'de', 'kan', 'med', 'som', 'för', 'att', 'ar',
' h', 'er', 'jag', 'dig', 'öppna', 'mig', 'är', 'inte', 'hit', '',
'an', 'e ', 'rupie', '0kej', ' m', 'et', ', ', 'gång', 'måst', 'ten',
' f', 'u ', 'men', 'te', 'tt', 'ka', 'vara', 'ken', '0m ', 'från',
'myck', 'någo', 'in', ' k', ' i', 'vil', 'bar', 'ond', 'För', 'Jag',
'ra', 'tack', 'll', 'g ', 'ta', 'om', 'anna', 'alla', 'en,', 'ber',
'hem', 'han', 'st', 'ig', ' t', 'tro', 'kraf', 'ör', ' v', 'ag',
'', 'får', 'sin', 'mme', 'mma', 'en ', 'tat',
]
rom_addrs = [0x9c8000, 0x8edf40]
class LangPL(LangUS):
alphabet = [
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", # 0 - 15
"Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
"w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
"-", ".", ",", "ć", "[Right]", "(", ")", "[Ankh]",
"[Waves]", "[Snake]", "[LinkL]", "[LinkR]","\"", "[Up]", "[Down]", "ę",
"ł", "ń", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
"ą", "[4HeartR]", " ", "[Left]", "ó", "ś", "ż", "ź", "Ł",
"Ś", "Ż", "Ź",
] #
dictionary = ['Trój', '...', 'ść', 'Nie', ' nie', ' się', 'może', ' że', 'and', 'at ',
' ty', 'an', 'at', 'kus', 'ba', 'be', 'bo', 'chce', 'che', 'ki ',
'za', 'des', 'di', 'do', 'en ', 'er ', 'sz ', 'ent', 'ed ', 'en',
'er', ' w', 'moc', 'zię', 'przez', 'ale', 'go', 'dzie', 'has', 'rze',
'hi', 'ha', 'który', 'aby ', 'in', 'is', 'it', 'twoj', 'Może', 'łeś',
'la', 'lo', 'czn', 'ma', 'me', 'mu', 'szcz', 'ska', 'śli', 'przy',
'znaj', 'iecz', 'of', 'on', 'or', ' ', 'ple', 'pow', 'pro', 're ',
're', 'mnie', 'se', ' z', 'so', 'st', 'któr', ' jak', 'ksz', 'sze',
'coś', ' je', 'to', 'tr', 'up', 'kie', 'praw', 'wa', 'we', 'mi',
'wi', 'szy', 'chc', 'pra', 'cie', ' i ', 'esz',
]
rom_addrs = [0x9c8000, 0x8edf40]
class LangPT(LangUS):
alphabet = [
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", # 0 - 15
"Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
"w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
"-", ".", ",", "[...]", ">", "(", ")", "[Ankh]",
"[Waves]", "[Snake]", "[LinkL]", "[LinkR]", "\"", "[Up]", "[Down]", "[Left]",
# 80 - 95
"[Right]", "'", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
"[4HeartL]", "[4HeartR]", " ", "<", "[A]", "[B]", "[X]", "[Y]", "[I]",
"¡", "[!]", "Á", "À", "Â", "Ã", "É", "Ê", "Í", "Ó", "Ô", "Õ", "Ú", "á", "à", "â",
"ã", "é", "ê", "í", "ó", "ô", "õ", "ú", "ç",
]
dictionary = [
' ', ' ', ' ', ' ', 'o ', 'a ', 'e ', '..', 'de', 'ar',
's ', 'ra', ' d', 'es', 'ocê ', 'do', ' a', ' p', 'er', ' e',
'que', 'r ', 'os', 'te', ', ', 'as', 'or', 'm ', 'en', ' o',
'nt', 're', ' s', 'co', 'da', 'se', 'st', ' c', ' m', 'em',
'ma', 'ta', ' n', 'ad', 'on', 'al', 'ro', 'an', 'u ', 'nd',
' um', 'pa', 'ca', 'el', ' f', 'to', 'in', ' t', 'ou', 'ei',
'ss', 'ir', 'no', 'ri', 'tr', 'me', 'la', 'ia', 'le', 've',
'is', 'sa', 'eu', 'pe', 'a.', 'na', 'so', 'mo', 'ga', 'o.',
'á ', 'lo', 'ha', 'pr', 'ua', ' l', '! ', 'ui', 'am', 'ti',
'io', 'gu', 'i ', 'di', 'nh', ' i', 'id',
]
ESCAPE_CHARACTER = 0x62
rom_addrs = [0x9c8000, 0x8edf40]
encoder = 'new'
def __init__(self):
assert len(self.alphabet) == 121
class LangEU:
command_lengths = kText_CommandLengths_EU
command_names = kText_CommandNames_EU
COMMAND_START = 0x70
SWITCH_BANK = 0x88
FINISH = 0x8f
DICT_BASE_ENC, DICT_BASE_DEC = 0x88, 0x90
ESCAPE_CHARACTER = None
encoder = 'new'
class LangDE(LangEU):
alphabet = kTextAlphabet_DE
dictionary = kTextDictionary_DE
rom_addrs = [0x9c8000, 0x8CEB00]
class LangFR(LangEU):
alphabet = kTextAlphabet_FR
dictionary = kTextDictionary_FR
rom_addrs = [0x9c8000, 0x8CE800]
class LangFR_C(LangEU):
alphabet = kTextAlphabet_FR
dictionary = kTextDictionary_FR
rom_addrs = [0x9c8000, 0x8CF150]
kLanguages = {
'us' : LangUS(),
'de' : LangDE(),
'fr' : LangFR(),
'fr-c' : LangFR_C(),
'en' : LangEN(),
'es' : LangES(),
'pl' : LangPL(),
'pt' : LangPT(),
'redux' : LangUS(),
'nl' : LangNL(),
'sv' : LangSV(),
}
def dialogue_filename(s):
if s == 'us': return 'dialogue.txt'
return f"dialogue_{s.replace('-', '_')}.txt"
def uses_new_format(lang):
return kLanguages[lang].encoder == 'new'
dict_expansion = []
def decode_strings_generic(get_byte, lang):
info = kLanguages[lang]
p, rom_idx = info.rom_addrs[0], 1
result = []
while True:
s, srcdata = '', []
while True:
c = get_byte(p)
srcdata.append(c)
l = info.command_lengths[c - info.COMMAND_START] if c >= info.COMMAND_START and c < info.SWITCH_BANK else 1
p += l
if c == 0x7f: # EndMessage
break
if c < info.COMMAND_START:
if c == info.ESCAPE_CHARACTER:
c = get_byte(p); p += 1
srcdata.append(c)
s += info.alphabet[c]
elif c < info.SWITCH_BANK:
if l == 2:
srcdata.append(get_byte(p - 1))
s += '[%s %.2d]' % (info.command_names[c - info.COMMAND_START], get_byte(p - 1))
else:
s += '[%s]' % info.command_names[c - info.COMMAND_START]
elif c == info.FINISH:
return result # done
elif c == info.SWITCH_BANK:
p = info.rom_addrs[rom_idx]; rom_idx += 1
s, srcdata = '', []
elif c < info.SWITCH_BANK + 8:
if lang != 'pt':
assert 0
else:
s += info.dictionary[c - info.DICT_BASE_DEC]
dict_expansion.append(len(info.dictionary[c - info.DICT_BASE_DEC]))
result.append((s, srcdata))
if len(result) >= 397 and lang == 'pt':
return result
# print(len(result), s)
# if len(result) == 89:
# print(s)
# sys.exit(0)
def print_strings(rom, file = None):
texts = decode_strings_generic(rom.get_byte, rom.language)
if len(texts) == 396:
extra_str = "[Speed 00]0- [Number 00]. 1- [Number 01][2]2- [Number 02]. 3- [Number 03]"
texts = texts[:4] + [(extra_str, None)] + texts[4:]
for i, s in enumerate(texts):
print('%s: %s' % (i + 1, s[0]), file = file)
def encode_greedy_from_dict(s, i, rev, a2i, info):
a = s[i:]
if r := rev.get(a[0]):
for k, v in r.items():
if a.startswith(k):
return [v + info.DICT_BASE_ENC], len(k)
if a[0] == '[':
cmd, param = a[1:a.index(']')], None
cmdlen = len(cmd)
if r := a2i.get(a[:cmdlen+2]):
return [r], cmdlen+2
if ' ' in cmd:
cmd, param = cmd.split(' ', 1)
param = int(param)
return kEncoders[info.encoder](cmd, param), cmdlen + 2
else:
return [a2i[a[0]]], 1
print('substr %s not found' % a)
assert 0
def compress_strings(xs, lang = 'us'):
info = kLanguages[lang]
rev = {}
for a,b in enumerate(info.dictionary):
rev.setdefault(b[0], {})[b] = a
#rev = {b:a for a,b in enumerate(info.dictionary)}
a2i = {e:i for i,e in enumerate(info.alphabet)}
def compress_string(s):
i = 0
r = bytearray()
while i < len(s):
what, num = encode_greedy_from_dict(s, i, rev, a2i, info)
r.extend(what)
i += num
return r
return [compress_string(x) for x in xs]
def verify(get_byte):
for i, (decoded, original) in enumerate(decode_strings_generic(get_byte, 'us')):
c = compress_strings([decoded])[0]
if c != original:
print('String %s not match: %s, %s' % (decoded, c, original))
break
else:
pass
def encode_dictionary(lang = 'us'):
info = kLanguages[lang]
rev = {b:a for a,b in enumerate(info.alphabet)}
return [bytearray(rev[c] for c in line) for line in info.dictionary]
if __name__ == "__main__":
ROM = util.load_rom(sys.argv[1] if len(sys.argv) >= 2 else None, True)
decoded = decode_strings_generic(ROM.get_byte, 'de')
print('Total bytes: %d' % sum(len(a[1]) for a in decoded))
print('Dict tokens: %d' % len(dict_expansion))
print('Dict save: %d' % (sum(dict_expansion) - len(dict_expansion)))
print('US size ', len(kTextDictionary_US))
print('DE size ', len(kTextDictionary_DE))
texts = [a[0] for a in decoded]
# Pal seems to have one string too little
if len(texts) == 396:
extra_str = "[Speed 00]0- [Number 00]. 1- [Number 01][2]2- [Number 02]. 3- [Number 03]"
texts = texts[:4] + [extra_str] + texts[4:]
#for i, s in enumerate(texts):
# print('%s: %s' % (i + 1, s), file = None)
#encode_dictionary()
compr = compress_strings(texts, 'de')
print(f'Compressed size (excl eof): {sum(len(a) for a in compr)}')

View File

@@ -10,12 +10,27 @@ def cache(user_function):
# Both are common SNES rom extensions. For Zelda3 (NA), they are equivalent files.
COMMON_ROM_NAMES = ['zelda3.sfc', 'zelda3.smc']
DEFAULT_ROM_DIRECTORY = os.path.dirname(__file__)
ZELDA3_SHA256 = '66871d66be19ad2c34c927d6b14cd8eb6fc3181965b6e517cb361f7316009cfb'
DEFAULT_ROM_DIRECTORY = os.path.join(os.path.dirname(__file__), '..')
def load_rom(filename):
ZELDA3_SHA1_US = '6D4F10A8B10E10DBE624CB23CF03B88BB8252973'
ZELDA3_SHA1 = {
ZELDA3_SHA1_US : ('us', 'Legend of Zelda, The - A Link to the Past (USA)'),
'2E62494967FB0AFDF5DA1635607F9641DF7C6559' : ('de', 'Legend of Zelda, The - A Link to the Past (Germany)'),
'229364A1B92A05167CD38609B1AA98F7041987CC' : ('fr', 'Legend of Zelda, The - A Link to the Past (France)'),
'C1C6C7F76FFF936C534FF11F87A54162FC0AA100' : ('fr-c', 'Legend of Zelda, The - A Link to the Past (Canada)'),
'7C073A222569B9B8E8CA5FCB5DFEC3B5E31DA895' : ('en', 'Legend of Zelda, The - A Link to the Past (Europe)'),
'461FCBD700D1332009C0E85A7A136E2A8E4B111E' : ('es', 'Spanish - https://www.romhacking.net/translations/2195/'),
'3C4D605EEFDA1D76F101965138F238476655B11D' : ('pl', 'Polish - https://www.romhacking.net/translations/5760/'),
'D0D09ED41F9C373FE6AFDCCAFBF0DA8C88D3D90D' : ('pt', 'Portuguese - https://www.romhacking.net/translations/6530/'),
'B2A07A59E64C498BC1B2F28728F9BF4014C8D582' : ('redux', 'English Redux - https://www.romhacking.net/translations/6657/'),
'9325C22EB0A2A1F0017157C8B620BC3A605CEDE1' : ('redux', 'English Redux - https://www.romhacking.net/hacks/2594/'),
'FA8ADFDBA2697C9A54D583A1284A22AC764C7637' : ('nl', 'Dutch - https://www.romhacking.net/translations/1124/'),
'43CD3438469B2C3FE879EA2F410B3EF3CB3F1CA4' : ('sv', 'Swedish - https://www.romhacking.net/translations/982/'),
}
def load_rom(filename, support_multilanguage = False):
global ROM
ROM = LoadedRom(filename)
ROM = LoadedRom(filename, support_multilanguage)
return ROM
def get_byte(addr):
@@ -44,12 +59,32 @@ def get_word(addr):
class LoadedRom:
def __init__(self, path = None):
def __init__(self, path = None, support_multilanguage = False):
rom_path = self.__get_rom_path(path)
self.ROM = open(rom_path, 'rb').read()
hash = hashlib.sha256(self.ROM).hexdigest()
if hash != ZELDA3_SHA256:
raise Exception(f"ROM with hash {hash} not supported. Expected {ZELDA3_SHA256}. Please verify your ROM is the NA 1.0 version.");
# Remove the SMC header?
if (len(self.ROM) & 0xfffff) == 0x200:
self.ROM = self.ROM[0x200:]
hash = hashlib.sha1(self.ROM).hexdigest().upper()
entry = ZELDA3_SHA1.get(hash)
self.language = entry[0] if entry != None else None
# Workaround for swedish rom with broken size
if self.language == 'sv' and len(self.ROM) == 0x10083b:
self.ROM = self.ROM[0x200:]
if support_multilanguage:
if self.language == None:
msg = f"\n\nROM with hash {hash} not supported.\n\nYou need one of the following ROMs to extract the resources:\n"
for k, v in ZELDA3_SHA1.items():
msg += '%5s: %s: %s\n' % (v[0], k, v[1])
raise Exception(msg)
print('Identified ROM as: %s - "%s"' % entry)
else:
if self.language != 'us':
raise Exception(f"\n\nROM with hash {hash} not supported.\n\nExpected {ZELDA3_SHA1_US}.\nPlease verify your ROM is \"Legend of Zelda, The - A Link to the Past (USA)\"");
def get_byte(self, ea):
assert (ea & 0x8000)

25
extract_assets.bat Normal file
View File

@@ -0,0 +1,25 @@
@echo off
2>nul (del zelda3_assets.dat)
python assets/restool.py --extract-from-rom
IF NOT ERRORLEVEL 0 goto ERROR
IF NOT EXIST "zelda3_assets.dat" (
ECHO ERROR: The python program didn't generate zelda3_assets.dat successfully.
goto ERROR
) ELSE (
REM
)
goto DONE
:ERROR
ECHO:
ECHO ERROR: Asset extraction failed!
pause
EXIT /B 1
:DONE
echo Complete!
pause

117
other/make_text_dict.py Normal file
View File

@@ -0,0 +1,117 @@
import array
memos = {}
memoslist = []
def memo(s):
m = memos.get(s)
if m == None:
m = len(memoslist)
memos[s] = m
memoslist.append(s)
return m
def tos(s): return "".join(memoslist[c] for c in s)
lines = []
for line in open('dialogue.txt', 'r').read().splitlines():
line = line.split(': ')[1]
r = array.array('H')
i = 0
while i < len(line):
if line[i] == '[':
j = line.index(']', i + 1)
r.append(memo(line[i:j+1]))
i = j + 1
else:
r.append(memo(line[i]))
i += 1
#print(repr(line))
#print(r)
lines.append(list(r))
import collections
def find_all_ngrams(lines, N, cost):
ctr = collections.Counter()
for line in lines:
for i in range(len(line) - N + 1):
if line[i] != line[i+1]:
ctr[tuple(line[i:i+N])] += 1
r = list((b, a) for a, b in ctr.items() if b >= 2)
if len(r) == 0:
return None, 0
b, a = max(r)
return a, (N - cost) * b - N - 2 # 2 is the overhead of the dict
def find_best_ngram(cost):
best_score=0
for i in range(2, 32):
text, score = find_all_ngrams(lines, i, cost)
if score > best_score:
best_score = score
best_text = text
return best_score, best_text
def update_ngrams(lines, replace_from, replace_to):
for line in lines:
for i in range(len(line) - len(replace_from) + 1):
if tuple(line[i:i+len(replace_from)]) == replace_from:
line[i:i+len(replace_from)] = replace_to
total_gain = 0
original_tokens = sum(len(line) for line in lines)
kTextDictionary_US = [
' ', ' ', ' ', "'s ", 'and ',
'are ', 'all ', 'ain', 'and', 'at ',
'ast', 'an', 'at', 'ble', 'ba',
'be', 'bo', 'can ', 'che', 'com',
'ck', 'des', 'di', 'do', 'en ',
'er ', 'ear', 'ent', 'ed ', 'en',
'er', 'ev', 'for', 'fro', 'give ',
'get', 'go', 'have', 'has', 'her',
'hi', 'ha', 'ight ', 'ing ', 'in',
'is', 'it', 'just', 'know', 'ly ',
'la', 'lo', 'man', 'ma', 'me',
'mu', "n't ", 'non', 'not', 'open',
'ound', 'out ', 'of', 'on', 'or',
'per', 'ple', 'pow', 'pro', 're ',
're', 'some', 'se', 'sh', 'so',
'st', 'ter ', 'thin', 'ter', 'tha',
'the', 'thi', 'to', 'tr', 'up',
'ver', 'with', 'wa', 'we', 'wh',
'wi', 'you', 'Her', 'Tha', 'The',
'Thi', 'You',
]
dictionary = []
for i in range(111+256):
best_score, best_text = find_best_ngram(1 if i < 111 else 2)
if best_score == 0:
break
total_gain += best_score
print(f'Removed best bigram "{tos(best_text)}" with gain {best_score}, total gain {total_gain} / {original_tokens}')
dictionary.append(best_text)
update_ngrams(lines, best_text, [memo('{%s}' % tos(best_text))])
#print('kTextDictionary_NEW = [')
#for i, d in enumerate(dictionary):
# repl = tos(d).replace('{', '').replace('}', '')
# print(f'{repr(repl)},')
#print(']')
for i, a in enumerate(lines):
print(i, tos(a))

View File

@@ -25,9 +25,9 @@ IF NOT EXIST "%SDL2%\lib\x64\SDL2.dll" (
REM
)
IF NOT EXIST "tables\zelda3_assets.dat" (
IF NOT EXIST "zelda3_assets.dat" (
ECHO:
ECHO ERROR: tables\zelda3_assets.dat was not found.
ECHO ERROR: zelda3_assets.dat was not found.
ECHO You need to extract assets from the ROM first, or get this file from a friend. Please see README.md
ECHO:
PAUSE
@@ -38,7 +38,7 @@ IF NOT EXIST "tables\zelda3_assets.dat" (
echo Building with TCC...
third_party\tcc\tcc.exe -ozelda3.exe -DCOMPILER_TCC=1 -DSTBI_NO_SIMD=1 -DHAVE_STDINT_H=1 -D_HAVE_STDINT_H=1 -DSYSTEM_VOLUME_MIXER_AVAILABLE=0 -I%SDL2%/include -L%SDL2%/lib/x64 -lSDL2 *.c snes/*.c third_party/gl_core/gl_core_3_1.c third_party/opus-1.3.1-stripped/opus_decoder_amalgam.c
third_party\tcc\tcc.exe -ozelda3.exe -DCOMPILER_TCC=1 -DSTBI_NO_SIMD=1 -DHAVE_STDINT_H=1 -D_HAVE_STDINT_H=1 -DSYSTEM_VOLUME_MIXER_AVAILABLE=0 -I%SDL2%/include -L%SDL2%/lib/x64 -lSDL2 -I. src/*.c snes/*.c third_party/gl_core/gl_core_3_1.c third_party/opus-1.3.1-stripped/opus_decoder_amalgam.c
IF ERRORLEVEL 1 goto GETOUT
copy %SDL2%\lib\x64\SDL2.dll .

View File

@@ -6,7 +6,7 @@
#include <stddef.h>
#include <assert.h>
#include "ppu.h"
#include "../types.h"
#include "src/types.h"
static const uint8 kSpriteSizes[8][2] = {
{8, 16}, {8, 32}, {8, 64}, {16, 32},

View File

@@ -7,10 +7,10 @@
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "saveload.h"
#include "snes/saveload.h"
typedef struct Ppu Ppu;
#include "../types.h"
#include "src/types.h"
typedef struct BgLayer {
uint16_t hScroll;

View File

@@ -1,339 +1,332 @@
#pragma once
#include "types.h"
enum {
kNumberOfAssets = 165
};
extern const uint8 *g_asset_ptrs[kNumberOfAssets];
extern uint32 g_asset_sizes[kNumberOfAssets];
#define kSoundBank_intro ((uint8*)g_asset_ptrs[0])
#define kSoundBank_intro_SIZE (g_asset_sizes[0])
#define kSoundBank_indoor ((uint8*)g_asset_ptrs[1])
#define kSoundBank_indoor_SIZE (g_asset_sizes[1])
#define kSoundBank_ending ((uint8*)g_asset_ptrs[2])
#define kSoundBank_ending_SIZE (g_asset_sizes[2])
#define kDungeonRoom ((uint8*)g_asset_ptrs[3])
#define kDungeonRoom_SIZE (g_asset_sizes[3])
#define kDungeonRoomOffs ((uint16*)g_asset_ptrs[4])
#define kDungeonRoomOffs_SIZE (g_asset_sizes[4])
#define kDungeonRoomDoorOffs ((uint16*)g_asset_ptrs[5])
#define kDungeonRoomDoorOffs_SIZE (g_asset_sizes[5])
#define kDungeonRoomHeaders ((uint8*)g_asset_ptrs[6])
#define kDungeonRoomHeaders_SIZE (g_asset_sizes[6])
#define kDungeonRoomHeadersOffs ((uint16*)g_asset_ptrs[7])
#define kDungeonRoomHeadersOffs_SIZE (g_asset_sizes[7])
#define kDungeonRoomChests ((uint8*)g_asset_ptrs[8])
#define kDungeonRoomChests_SIZE (g_asset_sizes[8])
#define kDungeonRoomTeleMsg ((uint16*)g_asset_ptrs[9])
#define kDungeonRoomTeleMsg_SIZE (g_asset_sizes[9])
#define kDungeonPitsHurtPlayer ((uint16*)g_asset_ptrs[10])
#define kDungeonPitsHurtPlayer_SIZE (g_asset_sizes[10])
#define kEntranceData_rooms ((uint16*)g_asset_ptrs[11])
#define kEntranceData_rooms_SIZE (g_asset_sizes[11])
#define kEntranceData_relativeCoords ((uint8*)g_asset_ptrs[12])
#define kEntranceData_relativeCoords_SIZE (g_asset_sizes[12])
#define kEntranceData_scrollX ((uint16*)g_asset_ptrs[13])
#define kEntranceData_scrollX_SIZE (g_asset_sizes[13])
#define kEntranceData_scrollY ((uint16*)g_asset_ptrs[14])
#define kEntranceData_scrollY_SIZE (g_asset_sizes[14])
#define kEntranceData_playerX ((uint16*)g_asset_ptrs[15])
#define kEntranceData_playerX_SIZE (g_asset_sizes[15])
#define kEntranceData_playerY ((uint16*)g_asset_ptrs[16])
#define kEntranceData_playerY_SIZE (g_asset_sizes[16])
#define kEntranceData_cameraX ((uint16*)g_asset_ptrs[17])
#define kEntranceData_cameraX_SIZE (g_asset_sizes[17])
#define kEntranceData_cameraY ((uint16*)g_asset_ptrs[18])
#define kEntranceData_cameraY_SIZE (g_asset_sizes[18])
#define kEntranceData_blockset ((uint8*)g_asset_ptrs[19])
#define kEntranceData_blockset_SIZE (g_asset_sizes[19])
#define kEntranceData_floor ((int8*)g_asset_ptrs[20])
#define kEntranceData_floor_SIZE (g_asset_sizes[20])
#define kEntranceData_palace ((int8*)g_asset_ptrs[21])
#define kEntranceData_palace_SIZE (g_asset_sizes[21])
#define kEntranceData_doorwayOrientation ((uint8*)g_asset_ptrs[22])
#define kEntranceData_doorwayOrientation_SIZE (g_asset_sizes[22])
#define kEntranceData_startingBg ((uint8*)g_asset_ptrs[23])
#define kEntranceData_startingBg_SIZE (g_asset_sizes[23])
#define kEntranceData_quadrant1 ((uint8*)g_asset_ptrs[24])
#define kEntranceData_quadrant1_SIZE (g_asset_sizes[24])
#define kEntranceData_quadrant2 ((uint8*)g_asset_ptrs[25])
#define kEntranceData_quadrant2_SIZE (g_asset_sizes[25])
#define kEntranceData_doorSettings ((uint16*)g_asset_ptrs[26])
#define kEntranceData_doorSettings_SIZE (g_asset_sizes[26])
#define kEntranceData_musicTrack ((uint8*)g_asset_ptrs[27])
#define kEntranceData_musicTrack_SIZE (g_asset_sizes[27])
#define kStartingPoint_rooms ((uint16*)g_asset_ptrs[28])
#define kStartingPoint_rooms_SIZE (g_asset_sizes[28])
#define kStartingPoint_relativeCoords ((uint8*)g_asset_ptrs[29])
#define kStartingPoint_relativeCoords_SIZE (g_asset_sizes[29])
#define kStartingPoint_scrollX ((uint16*)g_asset_ptrs[30])
#define kStartingPoint_scrollX_SIZE (g_asset_sizes[30])
#define kStartingPoint_scrollY ((uint16*)g_asset_ptrs[31])
#define kStartingPoint_scrollY_SIZE (g_asset_sizes[31])
#define kStartingPoint_playerX ((uint16*)g_asset_ptrs[32])
#define kStartingPoint_playerX_SIZE (g_asset_sizes[32])
#define kStartingPoint_playerY ((uint16*)g_asset_ptrs[33])
#define kStartingPoint_playerY_SIZE (g_asset_sizes[33])
#define kStartingPoint_cameraX ((uint16*)g_asset_ptrs[34])
#define kStartingPoint_cameraX_SIZE (g_asset_sizes[34])
#define kStartingPoint_cameraY ((uint16*)g_asset_ptrs[35])
#define kStartingPoint_cameraY_SIZE (g_asset_sizes[35])
#define kStartingPoint_blockset ((uint8*)g_asset_ptrs[36])
#define kStartingPoint_blockset_SIZE (g_asset_sizes[36])
#define kStartingPoint_floor ((int8*)g_asset_ptrs[37])
#define kStartingPoint_floor_SIZE (g_asset_sizes[37])
#define kStartingPoint_palace ((int8*)g_asset_ptrs[38])
#define kStartingPoint_palace_SIZE (g_asset_sizes[38])
#define kStartingPoint_doorwayOrientation ((uint8*)g_asset_ptrs[39])
#define kStartingPoint_doorwayOrientation_SIZE (g_asset_sizes[39])
#define kStartingPoint_startingBg ((uint8*)g_asset_ptrs[40])
#define kStartingPoint_startingBg_SIZE (g_asset_sizes[40])
#define kStartingPoint_quadrant1 ((uint8*)g_asset_ptrs[41])
#define kStartingPoint_quadrant1_SIZE (g_asset_sizes[41])
#define kStartingPoint_quadrant2 ((uint8*)g_asset_ptrs[42])
#define kStartingPoint_quadrant2_SIZE (g_asset_sizes[42])
#define kStartingPoint_doorSettings ((uint16*)g_asset_ptrs[43])
#define kStartingPoint_doorSettings_SIZE (g_asset_sizes[43])
#define kStartingPoint_entrance ((uint8*)g_asset_ptrs[44])
#define kStartingPoint_entrance_SIZE (g_asset_sizes[44])
#define kStartingPoint_musicTrack ((uint8*)g_asset_ptrs[45])
#define kStartingPoint_musicTrack_SIZE (g_asset_sizes[45])
#define kDungeonRoomDefault ((uint8*)g_asset_ptrs[46])
#define kDungeonRoomDefault_SIZE (g_asset_sizes[46])
#define kDungeonRoomDefaultOffs ((uint16*)g_asset_ptrs[47])
#define kDungeonRoomDefaultOffs_SIZE (g_asset_sizes[47])
#define kDungeonRoomOverlay ((uint8*)g_asset_ptrs[48])
#define kDungeonRoomOverlay_SIZE (g_asset_sizes[48])
#define kDungeonRoomOverlayOffs ((uint16*)g_asset_ptrs[49])
#define kDungeonRoomOverlayOffs_SIZE (g_asset_sizes[49])
#define kDungeonSecrets ((uint8*)g_asset_ptrs[50])
#define kDungeonSecrets_SIZE (g_asset_sizes[50])
#define kDungAttrsForTile_Offs ((uint16*)g_asset_ptrs[51])
#define kDungAttrsForTile_Offs_SIZE (g_asset_sizes[51])
#define kDungAttrsForTile ((uint8*)g_asset_ptrs[52])
#define kDungAttrsForTile_SIZE (g_asset_sizes[52])
#define kMovableBlockDataInit ((uint16*)g_asset_ptrs[53])
#define kMovableBlockDataInit_SIZE (g_asset_sizes[53])
#define kTorchDataInit ((uint16*)g_asset_ptrs[54])
#define kTorchDataInit_SIZE (g_asset_sizes[54])
#define kTorchDataJunk ((uint16*)g_asset_ptrs[55])
#define kTorchDataJunk_SIZE (g_asset_sizes[55])
#define kEnemyDamageData ((uint8*)g_asset_ptrs[56])
#define kEnemyDamageData_SIZE (g_asset_sizes[56])
#define kLinkGraphics ((uint8*)g_asset_ptrs[57])
#define kLinkGraphics_SIZE (g_asset_sizes[57])
#define kDungeonSprites ((uint8*)g_asset_ptrs[58])
#define kDungeonSprites_SIZE (g_asset_sizes[58])
#define kDungeonSpriteOffs ((uint16*)g_asset_ptrs[59])
#define kDungeonSpriteOffs_SIZE (g_asset_sizes[59])
#define kMap32ToMap16_0 ((uint8*)g_asset_ptrs[60])
#define kMap32ToMap16_0_SIZE (g_asset_sizes[60])
#define kMap32ToMap16_1 ((uint8*)g_asset_ptrs[61])
#define kMap32ToMap16_1_SIZE (g_asset_sizes[61])
#define kMap32ToMap16_2 ((uint8*)g_asset_ptrs[62])
#define kMap32ToMap16_2_SIZE (g_asset_sizes[62])
#define kMap32ToMap16_3 ((uint8*)g_asset_ptrs[63])
#define kMap32ToMap16_3_SIZE (g_asset_sizes[63])
#define kDialogueOffs ((uint16*)g_asset_ptrs[64])
#define kDialogueOffs_SIZE (g_asset_sizes[64])
#define kDialogueText ((uint8*)g_asset_ptrs[65])
#define kDialogueText_SIZE (g_asset_sizes[65])
#define kSprGfx ((uint8*)g_asset_ptrs[66])
#define kSprGfx_SIZE (g_asset_sizes[66])
#define kBgGfx ((uint8*)g_asset_ptrs[67])
#define kBgGfx_SIZE (g_asset_sizes[67])
#define kOverworldMapGfx ((uint8*)g_asset_ptrs[68])
#define kOverworldMapGfx_SIZE (g_asset_sizes[68])
#define kLightOverworldTilemap ((uint8*)g_asset_ptrs[69])
#define kLightOverworldTilemap_SIZE (g_asset_sizes[69])
#define kDarkOverworldTilemap ((uint8*)g_asset_ptrs[70])
#define kDarkOverworldTilemap_SIZE (g_asset_sizes[70])
#define kPredefinedTileData ((uint16*)g_asset_ptrs[71])
#define kPredefinedTileData_SIZE (g_asset_sizes[71])
#define kFontData ((uint16*)g_asset_ptrs[72])
#define kFontData_SIZE (g_asset_sizes[72])
#define kMap16ToMap8 ((uint16*)g_asset_ptrs[73])
#define kMap16ToMap8_SIZE (g_asset_sizes[73])
#define kGeneratedWishPondItem ((uint8*)g_asset_ptrs[74])
#define kGeneratedWishPondItem_SIZE (g_asset_sizes[74])
#define kGeneratedBombosArr ((uint8*)g_asset_ptrs[75])
#define kGeneratedBombosArr_SIZE (g_asset_sizes[75])
#define kGeneratedEndSequence15 ((uint8*)g_asset_ptrs[76])
#define kGeneratedEndSequence15_SIZE (g_asset_sizes[76])
#define kEnding_Credits_Text ((uint8*)g_asset_ptrs[77])
#define kEnding_Credits_Text_SIZE (g_asset_sizes[77])
#define kEnding_Credits_Offs ((uint16*)g_asset_ptrs[78])
#define kEnding_Credits_Offs_SIZE (g_asset_sizes[78])
#define kEnding_MapData ((uint16*)g_asset_ptrs[79])
#define kEnding_MapData_SIZE (g_asset_sizes[79])
#define kEnding0_Offs ((uint16*)g_asset_ptrs[80])
#define kEnding0_Offs_SIZE (g_asset_sizes[80])
#define kEnding0_Data ((uint8*)g_asset_ptrs[81])
#define kEnding0_Data_SIZE (g_asset_sizes[81])
#define kPalette_DungBgMain ((uint16*)g_asset_ptrs[82])
#define kPalette_DungBgMain_SIZE (g_asset_sizes[82])
#define kPalette_MainSpr ((uint16*)g_asset_ptrs[83])
#define kPalette_MainSpr_SIZE (g_asset_sizes[83])
#define kPalette_ArmorAndGloves ((uint16*)g_asset_ptrs[84])
#define kPalette_ArmorAndGloves_SIZE (g_asset_sizes[84])
#define kPalette_Sword ((uint16*)g_asset_ptrs[85])
#define kPalette_Sword_SIZE (g_asset_sizes[85])
#define kPalette_Shield ((uint16*)g_asset_ptrs[86])
#define kPalette_Shield_SIZE (g_asset_sizes[86])
#define kPalette_SpriteAux3 ((uint16*)g_asset_ptrs[87])
#define kPalette_SpriteAux3_SIZE (g_asset_sizes[87])
#define kPalette_MiscSprite_Indoors ((uint16*)g_asset_ptrs[88])
#define kPalette_MiscSprite_Indoors_SIZE (g_asset_sizes[88])
#define kPalette_SpriteAux1 ((uint16*)g_asset_ptrs[89])
#define kPalette_SpriteAux1_SIZE (g_asset_sizes[89])
#define kPalette_OverworldBgMain ((uint16*)g_asset_ptrs[90])
#define kPalette_OverworldBgMain_SIZE (g_asset_sizes[90])
#define kPalette_OverworldBgAux12 ((uint16*)g_asset_ptrs[91])
#define kPalette_OverworldBgAux12_SIZE (g_asset_sizes[91])
#define kPalette_OverworldBgAux3 ((uint16*)g_asset_ptrs[92])
#define kPalette_OverworldBgAux3_SIZE (g_asset_sizes[92])
#define kPalette_PalaceMapBg ((uint16*)g_asset_ptrs[93])
#define kPalette_PalaceMapBg_SIZE (g_asset_sizes[93])
#define kPalette_PalaceMapSpr ((uint16*)g_asset_ptrs[94])
#define kPalette_PalaceMapSpr_SIZE (g_asset_sizes[94])
#define kHudPalData ((uint16*)g_asset_ptrs[95])
#define kHudPalData_SIZE (g_asset_sizes[95])
#define kOverworldMapPaletteData ((uint16*)g_asset_ptrs[96])
#define kOverworldMapPaletteData_SIZE (g_asset_sizes[96])
#define kDungMap_FloorLayout ((uint8*)g_asset_ptrs[97])
#define kDungMap_FloorLayout_SIZE (g_asset_sizes[97])
#define kDungMap_Tiles ((uint8*)g_asset_ptrs[98])
#define kDungMap_Tiles_SIZE (g_asset_sizes[98])
#define kBgTilemap_0 ((uint8*)g_asset_ptrs[99])
#define kBgTilemap_0_SIZE (g_asset_sizes[99])
#define kBgTilemap_1 ((uint8*)g_asset_ptrs[100])
#define kBgTilemap_1_SIZE (g_asset_sizes[100])
#define kBgTilemap_2 ((uint8*)g_asset_ptrs[101])
#define kBgTilemap_2_SIZE (g_asset_sizes[101])
#define kBgTilemap_3 ((uint8*)g_asset_ptrs[102])
#define kBgTilemap_3_SIZE (g_asset_sizes[102])
#define kBgTilemap_4 ((uint8*)g_asset_ptrs[103])
#define kBgTilemap_4_SIZE (g_asset_sizes[103])
#define kBgTilemap_5 ((uint8*)g_asset_ptrs[104])
#define kBgTilemap_5_SIZE (g_asset_sizes[104])
#define kOverworld_Hibytes_Comp ((uint8*)g_asset_ptrs[105])
#define kOverworld_Hibytes_Comp_SIZE (g_asset_sizes[105])
#define kOverworld_Lobytes_Comp ((uint8*)g_asset_ptrs[106])
#define kOverworld_Lobytes_Comp_SIZE (g_asset_sizes[106])
#define kOverworldMapIsSmall ((uint8*)g_asset_ptrs[107])
#define kOverworldMapIsSmall_SIZE (g_asset_sizes[107])
#define kOverworldAuxTileThemeIndexes ((uint8*)g_asset_ptrs[108])
#define kOverworldAuxTileThemeIndexes_SIZE (g_asset_sizes[108])
#define kOverworldBgPalettes ((uint8*)g_asset_ptrs[109])
#define kOverworldBgPalettes_SIZE (g_asset_sizes[109])
#define kOverworld_SignText ((uint16*)g_asset_ptrs[110])
#define kOverworld_SignText_SIZE (g_asset_sizes[110])
#define kOwMusicSets ((uint8*)g_asset_ptrs[111])
#define kOwMusicSets_SIZE (g_asset_sizes[111])
#define kOwMusicSets2 ((uint8*)g_asset_ptrs[112])
#define kOwMusicSets2_SIZE (g_asset_sizes[112])
#define kBirdTravel_ScreenIndex ((uint16*)g_asset_ptrs[113])
#define kBirdTravel_ScreenIndex_SIZE (g_asset_sizes[113])
#define kBirdTravel_Map16LoadSrcOff ((uint16*)g_asset_ptrs[114])
#define kBirdTravel_Map16LoadSrcOff_SIZE (g_asset_sizes[114])
#define kBirdTravel_ScrollX ((uint16*)g_asset_ptrs[115])
#define kBirdTravel_ScrollX_SIZE (g_asset_sizes[115])
#define kBirdTravel_ScrollY ((uint16*)g_asset_ptrs[116])
#define kBirdTravel_ScrollY_SIZE (g_asset_sizes[116])
#define kBirdTravel_LinkXCoord ((uint16*)g_asset_ptrs[117])
#define kBirdTravel_LinkXCoord_SIZE (g_asset_sizes[117])
#define kBirdTravel_LinkYCoord ((uint16*)g_asset_ptrs[118])
#define kBirdTravel_LinkYCoord_SIZE (g_asset_sizes[118])
#define kBirdTravel_CameraXScroll ((uint16*)g_asset_ptrs[119])
#define kBirdTravel_CameraXScroll_SIZE (g_asset_sizes[119])
#define kBirdTravel_CameraYScroll ((uint16*)g_asset_ptrs[120])
#define kBirdTravel_CameraYScroll_SIZE (g_asset_sizes[120])
#define kBirdTravel_Unk1 ((int8*)g_asset_ptrs[121])
#define kBirdTravel_Unk1_SIZE (g_asset_sizes[121])
#define kBirdTravel_Unk3 ((int8*)g_asset_ptrs[122])
#define kBirdTravel_Unk3_SIZE (g_asset_sizes[122])
#define kWhirlpoolAreas ((uint16*)g_asset_ptrs[123])
#define kWhirlpoolAreas_SIZE (g_asset_sizes[123])
#define kOverworld_Entrance_Area ((uint16*)g_asset_ptrs[124])
#define kOverworld_Entrance_Area_SIZE (g_asset_sizes[124])
#define kOverworld_Entrance_Pos ((uint16*)g_asset_ptrs[125])
#define kOverworld_Entrance_Pos_SIZE (g_asset_sizes[125])
#define kOverworld_Entrance_Id ((uint8*)g_asset_ptrs[126])
#define kOverworld_Entrance_Id_SIZE (g_asset_sizes[126])
#define kFallHole_Area ((uint16*)g_asset_ptrs[127])
#define kFallHole_Area_SIZE (g_asset_sizes[127])
#define kFallHole_Pos ((uint16*)g_asset_ptrs[128])
#define kFallHole_Pos_SIZE (g_asset_sizes[128])
#define kFallHole_Entrances ((uint8*)g_asset_ptrs[129])
#define kFallHole_Entrances_SIZE (g_asset_sizes[129])
#define kExitData_ScreenIndex ((uint8*)g_asset_ptrs[130])
#define kExitData_ScreenIndex_SIZE (g_asset_sizes[130])
#define kExitDataRooms ((uint16*)g_asset_ptrs[131])
#define kExitDataRooms_SIZE (g_asset_sizes[131])
#define kExitData_Map16LoadSrcOff ((uint16*)g_asset_ptrs[132])
#define kExitData_Map16LoadSrcOff_SIZE (g_asset_sizes[132])
#define kExitData_ScrollX ((uint16*)g_asset_ptrs[133])
#define kExitData_ScrollX_SIZE (g_asset_sizes[133])
#define kExitData_ScrollY ((uint16*)g_asset_ptrs[134])
#define kExitData_ScrollY_SIZE (g_asset_sizes[134])
#define kExitData_XCoord ((uint16*)g_asset_ptrs[135])
#define kExitData_XCoord_SIZE (g_asset_sizes[135])
#define kExitData_YCoord ((uint16*)g_asset_ptrs[136])
#define kExitData_YCoord_SIZE (g_asset_sizes[136])
#define kExitData_CameraXScroll ((uint16*)g_asset_ptrs[137])
#define kExitData_CameraXScroll_SIZE (g_asset_sizes[137])
#define kExitData_CameraYScroll ((uint16*)g_asset_ptrs[138])
#define kExitData_CameraYScroll_SIZE (g_asset_sizes[138])
#define kExitData_NormalDoor ((uint16*)g_asset_ptrs[139])
#define kExitData_NormalDoor_SIZE (g_asset_sizes[139])
#define kExitData_FancyDoor ((uint16*)g_asset_ptrs[140])
#define kExitData_FancyDoor_SIZE (g_asset_sizes[140])
#define kExitData_Unk1 ((int8*)g_asset_ptrs[141])
#define kExitData_Unk1_SIZE (g_asset_sizes[141])
#define kExitData_Unk3 ((int8*)g_asset_ptrs[142])
#define kExitData_Unk3_SIZE (g_asset_sizes[142])
#define kSpExit_Top ((uint16*)g_asset_ptrs[143])
#define kSpExit_Top_SIZE (g_asset_sizes[143])
#define kSpExit_Bottom ((uint16*)g_asset_ptrs[144])
#define kSpExit_Bottom_SIZE (g_asset_sizes[144])
#define kSpExit_Left ((uint16*)g_asset_ptrs[145])
#define kSpExit_Left_SIZE (g_asset_sizes[145])
#define kSpExit_Right ((uint16*)g_asset_ptrs[146])
#define kSpExit_Right_SIZE (g_asset_sizes[146])
#define kSpExit_Tab4 ((int16*)g_asset_ptrs[147])
#define kSpExit_Tab4_SIZE (g_asset_sizes[147])
#define kSpExit_Tab5 ((int16*)g_asset_ptrs[148])
#define kSpExit_Tab5_SIZE (g_asset_sizes[148])
#define kSpExit_Tab6 ((int16*)g_asset_ptrs[149])
#define kSpExit_Tab6_SIZE (g_asset_sizes[149])
#define kSpExit_Tab7 ((int16*)g_asset_ptrs[150])
#define kSpExit_Tab7_SIZE (g_asset_sizes[150])
#define kSpExit_LeftEdgeOfMap ((uint16*)g_asset_ptrs[151])
#define kSpExit_LeftEdgeOfMap_SIZE (g_asset_sizes[151])
#define kSpExit_Dir ((uint8*)g_asset_ptrs[152])
#define kSpExit_Dir_SIZE (g_asset_sizes[152])
#define kSpExit_SprGfx ((uint8*)g_asset_ptrs[153])
#define kSpExit_SprGfx_SIZE (g_asset_sizes[153])
#define kSpExit_AuxGfx ((uint8*)g_asset_ptrs[154])
#define kSpExit_AuxGfx_SIZE (g_asset_sizes[154])
#define kSpExit_PalBg ((uint8*)g_asset_ptrs[155])
#define kSpExit_PalBg_SIZE (g_asset_sizes[155])
#define kSpExit_PalSpr ((uint8*)g_asset_ptrs[156])
#define kSpExit_PalSpr_SIZE (g_asset_sizes[156])
#define kOverworldSecrets_Offs ((uint16*)g_asset_ptrs[157])
#define kOverworldSecrets_Offs_SIZE (g_asset_sizes[157])
#define kOverworldSecrets ((uint8*)g_asset_ptrs[158])
#define kOverworldSecrets_SIZE (g_asset_sizes[158])
#define kOverworldSpriteOffs ((uint16*)g_asset_ptrs[159])
#define kOverworldSpriteOffs_SIZE (g_asset_sizes[159])
#define kOverworldSprites ((uint8*)g_asset_ptrs[160])
#define kOverworldSprites_SIZE (g_asset_sizes[160])
#define kOverworldSpriteGfx ((uint8*)g_asset_ptrs[161])
#define kOverworldSpriteGfx_SIZE (g_asset_sizes[161])
#define kOverworldSpritePalettes ((uint8*)g_asset_ptrs[162])
#define kOverworldSpritePalettes_SIZE (g_asset_sizes[162])
#define kMap8DataToTileAttr ((uint8*)g_asset_ptrs[163])
#define kMap8DataToTileAttr_SIZE (g_asset_sizes[163])
#define kSomeTileAttr ((uint8*)g_asset_ptrs[164])
#define kSomeTileAttr_SIZE (g_asset_sizes[164])
#define kAssets_Sig 90, 101, 108, 100, 97, 51, 95, 118, 48, 32, 32, 32, 32, 32, 10, 0, 140, 60, 238, 107, 183, 109, 113, 156, 115, 98, 147, 236, 79, 160, 95, 71, 26, 185, 82, 158, 43, 82, 22, 60, 62, 92, 250, 152, 23, 230, 97, 235
#pragma once
#include "types.h"
enum {
kNumberOfAssets = 165
};
extern const uint8 *g_asset_ptrs[kNumberOfAssets];
extern uint32 g_asset_sizes[kNumberOfAssets];
extern MemBlk FindInAssetArray(int asset, int idx);
#define kSoundBank_intro ((uint8*)g_asset_ptrs[0])
#define kSoundBank_intro_SIZE (g_asset_sizes[0])
#define kSoundBank_indoor ((uint8*)g_asset_ptrs[1])
#define kSoundBank_indoor_SIZE (g_asset_sizes[1])
#define kSoundBank_ending ((uint8*)g_asset_ptrs[2])
#define kSoundBank_ending_SIZE (g_asset_sizes[2])
#define kDungeonRoom ((uint8*)g_asset_ptrs[3])
#define kDungeonRoom_SIZE (g_asset_sizes[3])
#define kDungeonRoomOffs ((uint16*)g_asset_ptrs[4])
#define kDungeonRoomOffs_SIZE (g_asset_sizes[4])
#define kDungeonRoomDoorOffs ((uint16*)g_asset_ptrs[5])
#define kDungeonRoomDoorOffs_SIZE (g_asset_sizes[5])
#define kDungeonRoomHeaders ((uint8*)g_asset_ptrs[6])
#define kDungeonRoomHeaders_SIZE (g_asset_sizes[6])
#define kDungeonRoomHeadersOffs ((uint16*)g_asset_ptrs[7])
#define kDungeonRoomHeadersOffs_SIZE (g_asset_sizes[7])
#define kDungeonRoomChests ((uint8*)g_asset_ptrs[8])
#define kDungeonRoomChests_SIZE (g_asset_sizes[8])
#define kDungeonRoomTeleMsg ((uint16*)g_asset_ptrs[9])
#define kDungeonRoomTeleMsg_SIZE (g_asset_sizes[9])
#define kDungeonPitsHurtPlayer ((uint16*)g_asset_ptrs[10])
#define kDungeonPitsHurtPlayer_SIZE (g_asset_sizes[10])
#define kEntranceData_rooms ((uint16*)g_asset_ptrs[11])
#define kEntranceData_rooms_SIZE (g_asset_sizes[11])
#define kEntranceData_relativeCoords ((uint8*)g_asset_ptrs[12])
#define kEntranceData_relativeCoords_SIZE (g_asset_sizes[12])
#define kEntranceData_scrollX ((uint16*)g_asset_ptrs[13])
#define kEntranceData_scrollX_SIZE (g_asset_sizes[13])
#define kEntranceData_scrollY ((uint16*)g_asset_ptrs[14])
#define kEntranceData_scrollY_SIZE (g_asset_sizes[14])
#define kEntranceData_playerX ((uint16*)g_asset_ptrs[15])
#define kEntranceData_playerX_SIZE (g_asset_sizes[15])
#define kEntranceData_playerY ((uint16*)g_asset_ptrs[16])
#define kEntranceData_playerY_SIZE (g_asset_sizes[16])
#define kEntranceData_cameraX ((uint16*)g_asset_ptrs[17])
#define kEntranceData_cameraX_SIZE (g_asset_sizes[17])
#define kEntranceData_cameraY ((uint16*)g_asset_ptrs[18])
#define kEntranceData_cameraY_SIZE (g_asset_sizes[18])
#define kEntranceData_blockset ((uint8*)g_asset_ptrs[19])
#define kEntranceData_blockset_SIZE (g_asset_sizes[19])
#define kEntranceData_floor ((int8*)g_asset_ptrs[20])
#define kEntranceData_floor_SIZE (g_asset_sizes[20])
#define kEntranceData_palace ((int8*)g_asset_ptrs[21])
#define kEntranceData_palace_SIZE (g_asset_sizes[21])
#define kEntranceData_doorwayOrientation ((uint8*)g_asset_ptrs[22])
#define kEntranceData_doorwayOrientation_SIZE (g_asset_sizes[22])
#define kEntranceData_startingBg ((uint8*)g_asset_ptrs[23])
#define kEntranceData_startingBg_SIZE (g_asset_sizes[23])
#define kEntranceData_quadrant1 ((uint8*)g_asset_ptrs[24])
#define kEntranceData_quadrant1_SIZE (g_asset_sizes[24])
#define kEntranceData_quadrant2 ((uint8*)g_asset_ptrs[25])
#define kEntranceData_quadrant2_SIZE (g_asset_sizes[25])
#define kEntranceData_doorSettings ((uint16*)g_asset_ptrs[26])
#define kEntranceData_doorSettings_SIZE (g_asset_sizes[26])
#define kEntranceData_musicTrack ((uint8*)g_asset_ptrs[27])
#define kEntranceData_musicTrack_SIZE (g_asset_sizes[27])
#define kStartingPoint_rooms ((uint16*)g_asset_ptrs[28])
#define kStartingPoint_rooms_SIZE (g_asset_sizes[28])
#define kStartingPoint_relativeCoords ((uint8*)g_asset_ptrs[29])
#define kStartingPoint_relativeCoords_SIZE (g_asset_sizes[29])
#define kStartingPoint_scrollX ((uint16*)g_asset_ptrs[30])
#define kStartingPoint_scrollX_SIZE (g_asset_sizes[30])
#define kStartingPoint_scrollY ((uint16*)g_asset_ptrs[31])
#define kStartingPoint_scrollY_SIZE (g_asset_sizes[31])
#define kStartingPoint_playerX ((uint16*)g_asset_ptrs[32])
#define kStartingPoint_playerX_SIZE (g_asset_sizes[32])
#define kStartingPoint_playerY ((uint16*)g_asset_ptrs[33])
#define kStartingPoint_playerY_SIZE (g_asset_sizes[33])
#define kStartingPoint_cameraX ((uint16*)g_asset_ptrs[34])
#define kStartingPoint_cameraX_SIZE (g_asset_sizes[34])
#define kStartingPoint_cameraY ((uint16*)g_asset_ptrs[35])
#define kStartingPoint_cameraY_SIZE (g_asset_sizes[35])
#define kStartingPoint_blockset ((uint8*)g_asset_ptrs[36])
#define kStartingPoint_blockset_SIZE (g_asset_sizes[36])
#define kStartingPoint_floor ((int8*)g_asset_ptrs[37])
#define kStartingPoint_floor_SIZE (g_asset_sizes[37])
#define kStartingPoint_palace ((int8*)g_asset_ptrs[38])
#define kStartingPoint_palace_SIZE (g_asset_sizes[38])
#define kStartingPoint_doorwayOrientation ((uint8*)g_asset_ptrs[39])
#define kStartingPoint_doorwayOrientation_SIZE (g_asset_sizes[39])
#define kStartingPoint_startingBg ((uint8*)g_asset_ptrs[40])
#define kStartingPoint_startingBg_SIZE (g_asset_sizes[40])
#define kStartingPoint_quadrant1 ((uint8*)g_asset_ptrs[41])
#define kStartingPoint_quadrant1_SIZE (g_asset_sizes[41])
#define kStartingPoint_quadrant2 ((uint8*)g_asset_ptrs[42])
#define kStartingPoint_quadrant2_SIZE (g_asset_sizes[42])
#define kStartingPoint_doorSettings ((uint16*)g_asset_ptrs[43])
#define kStartingPoint_doorSettings_SIZE (g_asset_sizes[43])
#define kStartingPoint_entrance ((uint8*)g_asset_ptrs[44])
#define kStartingPoint_entrance_SIZE (g_asset_sizes[44])
#define kStartingPoint_musicTrack ((uint8*)g_asset_ptrs[45])
#define kStartingPoint_musicTrack_SIZE (g_asset_sizes[45])
#define kDungeonRoomDefault ((uint8*)g_asset_ptrs[46])
#define kDungeonRoomDefault_SIZE (g_asset_sizes[46])
#define kDungeonRoomDefaultOffs ((uint16*)g_asset_ptrs[47])
#define kDungeonRoomDefaultOffs_SIZE (g_asset_sizes[47])
#define kDungeonRoomOverlay ((uint8*)g_asset_ptrs[48])
#define kDungeonRoomOverlay_SIZE (g_asset_sizes[48])
#define kDungeonRoomOverlayOffs ((uint16*)g_asset_ptrs[49])
#define kDungeonRoomOverlayOffs_SIZE (g_asset_sizes[49])
#define kDungeonSecrets ((uint8*)g_asset_ptrs[50])
#define kDungeonSecrets_SIZE (g_asset_sizes[50])
#define kDungAttrsForTile_Offs ((uint16*)g_asset_ptrs[51])
#define kDungAttrsForTile_Offs_SIZE (g_asset_sizes[51])
#define kDungAttrsForTile ((uint8*)g_asset_ptrs[52])
#define kDungAttrsForTile_SIZE (g_asset_sizes[52])
#define kMovableBlockDataInit ((uint16*)g_asset_ptrs[53])
#define kMovableBlockDataInit_SIZE (g_asset_sizes[53])
#define kTorchDataInit ((uint16*)g_asset_ptrs[54])
#define kTorchDataInit_SIZE (g_asset_sizes[54])
#define kTorchDataJunk ((uint16*)g_asset_ptrs[55])
#define kTorchDataJunk_SIZE (g_asset_sizes[55])
#define kEnemyDamageData ((uint8*)g_asset_ptrs[56])
#define kEnemyDamageData_SIZE (g_asset_sizes[56])
#define kLinkGraphics ((uint8*)g_asset_ptrs[57])
#define kLinkGraphics_SIZE (g_asset_sizes[57])
#define kDungeonSprites ((uint8*)g_asset_ptrs[58])
#define kDungeonSprites_SIZE (g_asset_sizes[58])
#define kDungeonSpriteOffs ((uint16*)g_asset_ptrs[59])
#define kDungeonSpriteOffs_SIZE (g_asset_sizes[59])
#define kMap32ToMap16_0 ((uint8*)g_asset_ptrs[60])
#define kMap32ToMap16_0_SIZE (g_asset_sizes[60])
#define kMap32ToMap16_1 ((uint8*)g_asset_ptrs[61])
#define kMap32ToMap16_1_SIZE (g_asset_sizes[61])
#define kMap32ToMap16_2 ((uint8*)g_asset_ptrs[62])
#define kMap32ToMap16_2_SIZE (g_asset_sizes[62])
#define kMap32ToMap16_3 ((uint8*)g_asset_ptrs[63])
#define kMap32ToMap16_3_SIZE (g_asset_sizes[63])
#define kSprGfx(idx) FindInAssetArray(64, idx)
#define kBgGfx(idx) FindInAssetArray(65, idx)
#define kOverworldMapGfx ((uint8*)g_asset_ptrs[66])
#define kOverworldMapGfx_SIZE (g_asset_sizes[66])
#define kLightOverworldTilemap ((uint8*)g_asset_ptrs[67])
#define kLightOverworldTilemap_SIZE (g_asset_sizes[67])
#define kDarkOverworldTilemap ((uint8*)g_asset_ptrs[68])
#define kDarkOverworldTilemap_SIZE (g_asset_sizes[68])
#define kPredefinedTileData ((uint16*)g_asset_ptrs[69])
#define kPredefinedTileData_SIZE (g_asset_sizes[69])
#define kMap16ToMap8 ((uint16*)g_asset_ptrs[70])
#define kMap16ToMap8_SIZE (g_asset_sizes[70])
#define kGeneratedWishPondItem ((uint8*)g_asset_ptrs[71])
#define kGeneratedWishPondItem_SIZE (g_asset_sizes[71])
#define kGeneratedBombosArr ((uint8*)g_asset_ptrs[72])
#define kGeneratedBombosArr_SIZE (g_asset_sizes[72])
#define kGeneratedEndSequence15 ((uint8*)g_asset_ptrs[73])
#define kGeneratedEndSequence15_SIZE (g_asset_sizes[73])
#define kEnding_Credits_Text ((uint8*)g_asset_ptrs[74])
#define kEnding_Credits_Text_SIZE (g_asset_sizes[74])
#define kEnding_Credits_Offs ((uint16*)g_asset_ptrs[75])
#define kEnding_Credits_Offs_SIZE (g_asset_sizes[75])
#define kEnding_MapData ((uint16*)g_asset_ptrs[76])
#define kEnding_MapData_SIZE (g_asset_sizes[76])
#define kEnding0_Offs ((uint16*)g_asset_ptrs[77])
#define kEnding0_Offs_SIZE (g_asset_sizes[77])
#define kEnding0_Data ((uint8*)g_asset_ptrs[78])
#define kEnding0_Data_SIZE (g_asset_sizes[78])
#define kPalette_DungBgMain ((uint16*)g_asset_ptrs[79])
#define kPalette_DungBgMain_SIZE (g_asset_sizes[79])
#define kPalette_MainSpr ((uint16*)g_asset_ptrs[80])
#define kPalette_MainSpr_SIZE (g_asset_sizes[80])
#define kPalette_ArmorAndGloves ((uint16*)g_asset_ptrs[81])
#define kPalette_ArmorAndGloves_SIZE (g_asset_sizes[81])
#define kPalette_Sword ((uint16*)g_asset_ptrs[82])
#define kPalette_Sword_SIZE (g_asset_sizes[82])
#define kPalette_Shield ((uint16*)g_asset_ptrs[83])
#define kPalette_Shield_SIZE (g_asset_sizes[83])
#define kPalette_SpriteAux3 ((uint16*)g_asset_ptrs[84])
#define kPalette_SpriteAux3_SIZE (g_asset_sizes[84])
#define kPalette_MiscSprite_Indoors ((uint16*)g_asset_ptrs[85])
#define kPalette_MiscSprite_Indoors_SIZE (g_asset_sizes[85])
#define kPalette_SpriteAux1 ((uint16*)g_asset_ptrs[86])
#define kPalette_SpriteAux1_SIZE (g_asset_sizes[86])
#define kPalette_OverworldBgMain ((uint16*)g_asset_ptrs[87])
#define kPalette_OverworldBgMain_SIZE (g_asset_sizes[87])
#define kPalette_OverworldBgAux12 ((uint16*)g_asset_ptrs[88])
#define kPalette_OverworldBgAux12_SIZE (g_asset_sizes[88])
#define kPalette_OverworldBgAux3 ((uint16*)g_asset_ptrs[89])
#define kPalette_OverworldBgAux3_SIZE (g_asset_sizes[89])
#define kPalette_PalaceMapBg ((uint16*)g_asset_ptrs[90])
#define kPalette_PalaceMapBg_SIZE (g_asset_sizes[90])
#define kPalette_PalaceMapSpr ((uint16*)g_asset_ptrs[91])
#define kPalette_PalaceMapSpr_SIZE (g_asset_sizes[91])
#define kHudPalData ((uint16*)g_asset_ptrs[92])
#define kHudPalData_SIZE (g_asset_sizes[92])
#define kOverworldMapPaletteData ((uint16*)g_asset_ptrs[93])
#define kOverworldMapPaletteData_SIZE (g_asset_sizes[93])
#define kDialogue(idx) FindInAssetArray(94, idx)
#define kDialogueFont(idx) FindInAssetArray(95, idx)
#define kDialogueMap(idx) FindInAssetArray(96, idx)
#define kDungMap_FloorLayout(idx) FindInAssetArray(97, idx)
#define kDungMap_Tiles(idx) FindInAssetArray(98, idx)
#define kBgTilemap_0 ((uint8*)g_asset_ptrs[99])
#define kBgTilemap_0_SIZE (g_asset_sizes[99])
#define kBgTilemap_1 ((uint8*)g_asset_ptrs[100])
#define kBgTilemap_1_SIZE (g_asset_sizes[100])
#define kBgTilemap_2 ((uint8*)g_asset_ptrs[101])
#define kBgTilemap_2_SIZE (g_asset_sizes[101])
#define kBgTilemap_3 ((uint8*)g_asset_ptrs[102])
#define kBgTilemap_3_SIZE (g_asset_sizes[102])
#define kBgTilemap_4 ((uint8*)g_asset_ptrs[103])
#define kBgTilemap_4_SIZE (g_asset_sizes[103])
#define kBgTilemap_5 ((uint8*)g_asset_ptrs[104])
#define kBgTilemap_5_SIZE (g_asset_sizes[104])
#define kOverworld_Hibytes_Comp(idx) FindInAssetArray(105, idx)
#define kOverworld_Lobytes_Comp(idx) FindInAssetArray(106, idx)
#define kOverworldMapIsSmall ((uint8*)g_asset_ptrs[107])
#define kOverworldMapIsSmall_SIZE (g_asset_sizes[107])
#define kOverworldAuxTileThemeIndexes ((uint8*)g_asset_ptrs[108])
#define kOverworldAuxTileThemeIndexes_SIZE (g_asset_sizes[108])
#define kOverworldBgPalettes ((uint8*)g_asset_ptrs[109])
#define kOverworldBgPalettes_SIZE (g_asset_sizes[109])
#define kOverworld_SignText ((uint16*)g_asset_ptrs[110])
#define kOverworld_SignText_SIZE (g_asset_sizes[110])
#define kOwMusicSets ((uint8*)g_asset_ptrs[111])
#define kOwMusicSets_SIZE (g_asset_sizes[111])
#define kOwMusicSets2 ((uint8*)g_asset_ptrs[112])
#define kOwMusicSets2_SIZE (g_asset_sizes[112])
#define kBirdTravel_ScreenIndex ((uint16*)g_asset_ptrs[113])
#define kBirdTravel_ScreenIndex_SIZE (g_asset_sizes[113])
#define kBirdTravel_Map16LoadSrcOff ((uint16*)g_asset_ptrs[114])
#define kBirdTravel_Map16LoadSrcOff_SIZE (g_asset_sizes[114])
#define kBirdTravel_ScrollX ((uint16*)g_asset_ptrs[115])
#define kBirdTravel_ScrollX_SIZE (g_asset_sizes[115])
#define kBirdTravel_ScrollY ((uint16*)g_asset_ptrs[116])
#define kBirdTravel_ScrollY_SIZE (g_asset_sizes[116])
#define kBirdTravel_LinkXCoord ((uint16*)g_asset_ptrs[117])
#define kBirdTravel_LinkXCoord_SIZE (g_asset_sizes[117])
#define kBirdTravel_LinkYCoord ((uint16*)g_asset_ptrs[118])
#define kBirdTravel_LinkYCoord_SIZE (g_asset_sizes[118])
#define kBirdTravel_CameraXScroll ((uint16*)g_asset_ptrs[119])
#define kBirdTravel_CameraXScroll_SIZE (g_asset_sizes[119])
#define kBirdTravel_CameraYScroll ((uint16*)g_asset_ptrs[120])
#define kBirdTravel_CameraYScroll_SIZE (g_asset_sizes[120])
#define kBirdTravel_Unk1 ((int8*)g_asset_ptrs[121])
#define kBirdTravel_Unk1_SIZE (g_asset_sizes[121])
#define kBirdTravel_Unk3 ((int8*)g_asset_ptrs[122])
#define kBirdTravel_Unk3_SIZE (g_asset_sizes[122])
#define kWhirlpoolAreas ((uint16*)g_asset_ptrs[123])
#define kWhirlpoolAreas_SIZE (g_asset_sizes[123])
#define kOverworld_Entrance_Area ((uint16*)g_asset_ptrs[124])
#define kOverworld_Entrance_Area_SIZE (g_asset_sizes[124])
#define kOverworld_Entrance_Pos ((uint16*)g_asset_ptrs[125])
#define kOverworld_Entrance_Pos_SIZE (g_asset_sizes[125])
#define kOverworld_Entrance_Id ((uint8*)g_asset_ptrs[126])
#define kOverworld_Entrance_Id_SIZE (g_asset_sizes[126])
#define kFallHole_Area ((uint16*)g_asset_ptrs[127])
#define kFallHole_Area_SIZE (g_asset_sizes[127])
#define kFallHole_Pos ((uint16*)g_asset_ptrs[128])
#define kFallHole_Pos_SIZE (g_asset_sizes[128])
#define kFallHole_Entrances ((uint8*)g_asset_ptrs[129])
#define kFallHole_Entrances_SIZE (g_asset_sizes[129])
#define kExitData_ScreenIndex ((uint8*)g_asset_ptrs[130])
#define kExitData_ScreenIndex_SIZE (g_asset_sizes[130])
#define kExitDataRooms ((uint16*)g_asset_ptrs[131])
#define kExitDataRooms_SIZE (g_asset_sizes[131])
#define kExitData_Map16LoadSrcOff ((uint16*)g_asset_ptrs[132])
#define kExitData_Map16LoadSrcOff_SIZE (g_asset_sizes[132])
#define kExitData_ScrollX ((uint16*)g_asset_ptrs[133])
#define kExitData_ScrollX_SIZE (g_asset_sizes[133])
#define kExitData_ScrollY ((uint16*)g_asset_ptrs[134])
#define kExitData_ScrollY_SIZE (g_asset_sizes[134])
#define kExitData_XCoord ((uint16*)g_asset_ptrs[135])
#define kExitData_XCoord_SIZE (g_asset_sizes[135])
#define kExitData_YCoord ((uint16*)g_asset_ptrs[136])
#define kExitData_YCoord_SIZE (g_asset_sizes[136])
#define kExitData_CameraXScroll ((uint16*)g_asset_ptrs[137])
#define kExitData_CameraXScroll_SIZE (g_asset_sizes[137])
#define kExitData_CameraYScroll ((uint16*)g_asset_ptrs[138])
#define kExitData_CameraYScroll_SIZE (g_asset_sizes[138])
#define kExitData_NormalDoor ((uint16*)g_asset_ptrs[139])
#define kExitData_NormalDoor_SIZE (g_asset_sizes[139])
#define kExitData_FancyDoor ((uint16*)g_asset_ptrs[140])
#define kExitData_FancyDoor_SIZE (g_asset_sizes[140])
#define kExitData_Unk1 ((int8*)g_asset_ptrs[141])
#define kExitData_Unk1_SIZE (g_asset_sizes[141])
#define kExitData_Unk3 ((int8*)g_asset_ptrs[142])
#define kExitData_Unk3_SIZE (g_asset_sizes[142])
#define kSpExit_Top ((uint16*)g_asset_ptrs[143])
#define kSpExit_Top_SIZE (g_asset_sizes[143])
#define kSpExit_Bottom ((uint16*)g_asset_ptrs[144])
#define kSpExit_Bottom_SIZE (g_asset_sizes[144])
#define kSpExit_Left ((uint16*)g_asset_ptrs[145])
#define kSpExit_Left_SIZE (g_asset_sizes[145])
#define kSpExit_Right ((uint16*)g_asset_ptrs[146])
#define kSpExit_Right_SIZE (g_asset_sizes[146])
#define kSpExit_Tab4 ((int16*)g_asset_ptrs[147])
#define kSpExit_Tab4_SIZE (g_asset_sizes[147])
#define kSpExit_Tab5 ((int16*)g_asset_ptrs[148])
#define kSpExit_Tab5_SIZE (g_asset_sizes[148])
#define kSpExit_Tab6 ((int16*)g_asset_ptrs[149])
#define kSpExit_Tab6_SIZE (g_asset_sizes[149])
#define kSpExit_Tab7 ((int16*)g_asset_ptrs[150])
#define kSpExit_Tab7_SIZE (g_asset_sizes[150])
#define kSpExit_LeftEdgeOfMap ((uint16*)g_asset_ptrs[151])
#define kSpExit_LeftEdgeOfMap_SIZE (g_asset_sizes[151])
#define kSpExit_Dir ((uint8*)g_asset_ptrs[152])
#define kSpExit_Dir_SIZE (g_asset_sizes[152])
#define kSpExit_SprGfx ((uint8*)g_asset_ptrs[153])
#define kSpExit_SprGfx_SIZE (g_asset_sizes[153])
#define kSpExit_AuxGfx ((uint8*)g_asset_ptrs[154])
#define kSpExit_AuxGfx_SIZE (g_asset_sizes[154])
#define kSpExit_PalBg ((uint8*)g_asset_ptrs[155])
#define kSpExit_PalBg_SIZE (g_asset_sizes[155])
#define kSpExit_PalSpr ((uint8*)g_asset_ptrs[156])
#define kSpExit_PalSpr_SIZE (g_asset_sizes[156])
#define kOverworldSecrets_Offs ((uint16*)g_asset_ptrs[157])
#define kOverworldSecrets_Offs_SIZE (g_asset_sizes[157])
#define kOverworldSecrets ((uint8*)g_asset_ptrs[158])
#define kOverworldSecrets_SIZE (g_asset_sizes[158])
#define kOverworldSpriteOffs ((uint16*)g_asset_ptrs[159])
#define kOverworldSpriteOffs_SIZE (g_asset_sizes[159])
#define kOverworldSprites ((uint8*)g_asset_ptrs[160])
#define kOverworldSprites_SIZE (g_asset_sizes[160])
#define kOverworldSpriteGfx ((uint8*)g_asset_ptrs[161])
#define kOverworldSpriteGfx_SIZE (g_asset_sizes[161])
#define kOverworldSpritePalettes ((uint8*)g_asset_ptrs[162])
#define kOverworldSpritePalettes_SIZE (g_asset_sizes[162])
#define kMap8DataToTileAttr ((uint8*)g_asset_ptrs[163])
#define kMap8DataToTileAttr_SIZE (g_asset_sizes[163])
#define kSomeTileAttr ((uint8*)g_asset_ptrs[164])
#define kSomeTileAttr_SIZE (g_asset_sizes[164])
#define kAssets_Sig 90, 101, 108, 100, 97, 51, 95, 118, 48, 32, 32, 32, 32, 32, 10, 0, 27, 174, 233, 45, 74, 174, 252, 50, 49, 27, 153, 197, 27, 43, 216, 197, 132, 101, 173, 169, 36, 108, 15, 155, 176, 169, 57, 131, 174, 101, 51, 207

View File

@@ -442,6 +442,9 @@ static bool HandleIniConfig(int section, const char *key, char *value) {
return ParseBool(value, &g_config.display_perf_title);
} else if (StringEqualsNoCase(key, "DisableFrameDelay")) {
return ParseBool(value, &g_config.disable_frame_delay);
} else if (StringEqualsNoCase(key, "Language")) {
g_config.language = value;
return true;
}
} else if (section == 4) {
if (StringEqualsNoCase(key, "ItemSwitchLR")) {

View File

@@ -73,6 +73,7 @@ typedef struct Config {
char *memory_buffer;
const char *shader;
const char *msu_path;
const char *language;
} Config;
enum {

View File

View File

View File

@@ -325,7 +325,7 @@ static const int8 kGraphicsLoadSp6[20] = {
static const uint8 kMirrorWarp_LoadNext_NmiLoad[15] = {0, 14, 15, 16, 17, 0, 0, 0, 0, 0, 0, 18, 19, 20, 0};
static const uint8 *GetCompSpritePtr(int i) {
return kSprGfx + *(uint32 *)(kSprGfx + i * 4);
return kSprGfx(i).ptr;
}
void ApplyPaletteFilter_bounce() {
@@ -932,7 +932,7 @@ void Graphics_LoadChrHalfSlot() { // 80e3fa
}
void TransferFontToVRAM() { // 80e556
memcpy(&g_zenv.vram[0x7000], kFontData, 0x800 * sizeof(uint16));
memcpy(&g_zenv.vram[0x7000], FindIndexInMemblk(kDialogueFont(0), 0).ptr, 0x800 * sizeof(uint16));
}
void Do3To4High(uint16 *vram_ptr, const uint8 *decomp_addr) { // 80e5af
@@ -991,17 +991,17 @@ void LoadCommonSprites() { // 80e6b7
int Decomp_spr(uint8 *dst, int gfx) { // 80e772
if (gfx < 12)
gfx = 12; // ensure it wont decode bad sheets.
MemBlk blk = kSprGfx(gfx);
const uint8 *sprite_data = GetCompSpritePtr(gfx);
// If the size is not 0x600 then it's compressed
if (gfx >= 103 || (((uint32 *)kSprGfx)[gfx + 1] - ((uint32 *)kSprGfx)[gfx]) != 0x600)
return Decompress(dst, sprite_data);
memcpy(dst, sprite_data, 0x600);
if (gfx >= 103 || blk.size != 0x600)
return Decompress(dst, blk.ptr);
memcpy(dst, blk.ptr, 0x600);
return 0x600;
}
int Decomp_bg(uint8 *dst, int gfx) { // 80e78f
const uint8 *p = kBgGfx + *(uint32 *)(kBgGfx + gfx * 4);
return Decompress(dst, p);
return Decompress(dst, kBgGfx(gfx).ptr);
}
int Decompress(uint8 *dst, const uint8 *src) { // 80e79e

View File

@@ -304,6 +304,7 @@ int main(int argc, char** argv) {
g_config.extend_y * kPpuRenderFlags_Height240 |
g_config.no_sprite_limits * kPpuRenderFlags_NoSpriteLimits;
ZeldaEnableMsu(g_config.enable_msu);
ZeldaSetLanguage(g_config.language);
if (g_config.fullscreen == 1)
g_win_flags ^= SDL_WINDOW_FULLSCREEN_DESKTOP;
@@ -809,10 +810,20 @@ uint32 g_asset_sizes[kNumberOfAssets];
static void LoadAssets() {
size_t length = 0;
uint8 *data = ReadWholeFile("tables/zelda3_assets.dat", &length);
if (!data)
data = ReadWholeFile("zelda3_assets.dat", &length);
if (!data) Die("Failed to read zelda3_assets.dat. Please see the README for information about how you get this file.");
uint8 *data = ReadWholeFile("zelda3_assets.dat", &length);
if (!data) {
size_t bps_length, bps_src_length;
uint8 *bps, *bps_src;
bps = ReadWholeFile("zelda3_assets.bps", &bps_length);
if (!bps)
Die("Failed to read zelda3_assets.dat. Please see the README for information about how you get this file.");
bps_src = ReadWholeFile("zelda3.sfc", &bps_src_length);
if (!bps_src)
Die("Missing file: zelda3.sfc");
data = ApplyBps(bps_src, bps_src_length, bps, bps_length, &length);
if (!data)
Die("Unable to apply zelda3_assets.bps. Please make sure you got the right version of 'zelda3.sfc'");
}
static const char kAssetsSig[] = { kAssets_Sig };
@@ -865,3 +876,7 @@ static void SwitchDirectory() {
pos--;
}
}
MemBlk FindInAssetArray(int asset, int idx) {
return FindIndexInMemblk((MemBlk) { g_asset_ptrs[asset], g_asset_sizes[asset] }, idx);
}

View File

@@ -101,108 +101,6 @@ static PlayerHandlerFunc *const kDungMapSubmodules[] = {
};
static const uint16 kText_Positions[2] = {0x6125, 0x6244};
static const uint16 kSrmOffsets[4] = {0, 0x500, 0xa00, 0xf00};
static const uint8 kTextDictionary[] = {
0x59, 0x59, 0x59, 0x59,
0x59, 0x59, 0x59,
0x59, 0x59,
0x51, 0x2c, 0x59,
0x1a, 0x27, 0x1d, 0x59,
0x1a, 0x2b, 0x1e, 0x59,
0x1a, 0x25, 0x25, 0x59,
0x1a, 0x22, 0x27,
0x1a, 0x27, 0x1d,
0x1a, 0x2d, 0x59,
0x1a, 0x2c, 0x2d,
0x1a, 0x27,
0x1a, 0x2d,
0x1b, 0x25, 0x1e,
0x1b, 0x1a,
0x1b, 0x1e,
0x1b, 0x28,
0x1c, 0x1a, 0x27, 0x59,
0x1c, 0x21, 0x1e,
0x1c, 0x28, 0x26,
0x1c, 0x24,
0x1d, 0x1e, 0x2c,
0x1d, 0x22,
0x1d, 0x28,
0x1e, 0x27, 0x59,
0x1e, 0x2b, 0x59,
0x1e, 0x1a, 0x2b,
0x1e, 0x27, 0x2d,
0x1e, 0x1d, 0x59,
0x1e, 0x27,
0x1e, 0x2b,
0x1e, 0x2f,
0x1f, 0x28, 0x2b,
0x1f, 0x2b, 0x28,
0x20, 0x22, 0x2f, 0x1e, 0x59,
0x20, 0x1e, 0x2d,
0x20, 0x28,
0x21, 0x1a, 0x2f, 0x1e,
0x21, 0x1a, 0x2c,
0x21, 0x1e, 0x2b,
0x21, 0x22,
0x21, 0x1a,
0x22, 0x20, 0x21, 0x2d, 0x59,
0x22, 0x27, 0x20, 0x59,
0x22, 0x27,
0x22, 0x2c,
0x22, 0x2d,
0x23, 0x2e, 0x2c, 0x2d,
0x24, 0x27, 0x28, 0x30,
0x25, 0x32, 0x59,
0x25, 0x1a,
0x25, 0x28,
0x26, 0x1a, 0x27,
0x26, 0x1a,
0x26, 0x1e,
0x26, 0x2e,
0x27, 0x51, 0x2d, 0x59,
0x27, 0x28, 0x27,
0x27, 0x28, 0x2d,
0x28, 0x29, 0x1e, 0x27,
0x28, 0x2e, 0x27, 0x1d,
0x28, 0x2e, 0x2d, 0x59,
0x28, 0x1f,
0x28, 0x27,
0x28, 0x2b,
0x29, 0x1e, 0x2b,
0x29, 0x25, 0x1e,
0x29, 0x28, 0x30,
0x29, 0x2b, 0x28,
0x2b, 0x1e, 0x59,
0x2b, 0x1e,
0x2c, 0x28, 0x26, 0x1e,
0x2c, 0x1e,
0x2c, 0x21,
0x2c, 0x28,
0x2c, 0x2d,
0x2d, 0x1e, 0x2b, 0x59,
0x2d, 0x21, 0x22, 0x27,
0x2d, 0x1e, 0x2b,
0x2d, 0x21, 0x1a,
0x2d, 0x21, 0x1e,
0x2d, 0x21, 0x22,
0x2d, 0x28,
0x2d, 0x2b,
0x2e, 0x29,
0x2f, 0x1e, 0x2b,
0x30, 0x22, 0x2d, 0x21,
0x30, 0x1a,
0x30, 0x1e,
0x30, 0x21,
0x30, 0x22,
0x32, 0x28, 0x2e,
0x7, 0x1e, 0x2b,
0x13, 0x21, 0x1a,
0x13, 0x21, 0x1e,
0x13, 0x21, 0x22,
0x18, 0x28, 0x2e,
};
static const uint16 kTextDictionary_Idx[] = {
0, 4, 7, 9, 12, 16, 20, 24, 27, 30, 33, 36, 38, 40, 43, 45, 47, 49, 53, 56, 59, 61, 64, 66, 68, 71, 74, 77, 80, 83, 85, 87, 89, 92, 95, 100, 103, 105, 109, 112, 115, 117, 119, 124, 128, 130, 132, 134, 138, 142, 145, 147, 149, 152, 154, 156, 158, 162, 165, 168, 172, 176, 180, 182, 184, 186, 189, 192, 195, 198, 201, 203, 207, 209, 211, 213, 215, 219, 223, 226, 229, 232, 235, 237, 239, 241, 244, 248, 250, 252, 254, 256, 259, 262, 265, 268, 271, 274
};
static const int8 kText_InitializationData[32] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0x39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1c, 4, 0, 0, 0, 0, 0};
static const uint16 kText_BorderTiles[9] = {0x28f3, 0x28f4, 0x68f3, 0x28c8, 0x387f, 0x68c8, 0xa8f3, 0xa8f4, 0xe8f3};
static const uint8 kText_CommandLengths[25] = {
@@ -212,16 +110,7 @@ static const uint8 kText_CommandLengths[25] = {
static const uint8 kVWF_RenderCharacter_setMasks[8] = {0x80, 0x40, 0x20, 0x10, 8, 4, 2, 1};
static const uint16 kVWF_RenderCharacter_renderPos[3] = {0, 0x2a0, 0x540};
static const uint16 kVWF_RenderCharacter_linePositions[3] = {0, 0x40, 0x80};
static const uint8 kVWF_RenderCharacter_widths[99] = {
6, 6, 6, 6, 6, 6, 6, 6, 3, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 7, 6, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6,
6, 6, 3, 5, 6, 3, 7, 6, 6, 6, 6, 5, 6, 6, 6, 7, 7, 7, 7, 6, 6, 4, 6, 6, 6, 6, 6, 6, 6, 6, 3, 7,
6, 4, 4, 6, 8, 6, 6, 6, 6, 6, 8, 8, 8, 7, 7, 7, 7, 4, 8, 8, 8, 8, 8, 8, 8, 4, 8, 8, 8, 8, 8, 8,
8, 8, 4,
};
static const uint16 kVWF_RowPositions[3] = {0, 2, 4};
static const uint16 kVWF_LinePositions[3] = {0, 40, 80};
static const uint16 kVWF_Command7B[4] = {0x24b8, 0x24ba, 0x24bc, 0x24be};
static const uint16 kVWF_Command7C[8] = {0x24b8, 0x24ba, 0x24bc, 0x24be, 0x24b8, 0x24ba, 0x24bc, 0x24be};
static const uint16 kText_WaitDurations[16] = {31, 63, 94, 125, 156, 188, 219, 250, 281, 313, 344, 375, 406, 438, 469, 500};
static PlayerHandlerFunc *const kText_Render[] = {
&RenderText_Draw_Border,
@@ -336,11 +225,11 @@ static PlayerHandlerFunc *const kModule_Death[16] = {
static const uint8 kLocationMenuStartPos[3] = {0, 1, 6};
static void RunInterface();
const uint8 *GetDungmapFloorLayout() {
return kDungMap_FloorLayout + *(uint32 *)(kDungMap_FloorLayout + (cur_palace_index_x2 >> 1) * 4);
return kDungMap_FloorLayout(cur_palace_index_x2 >> 1).ptr;
}
uint8 GetOtherDungmapInfo(int count) {
const uint8 *p = kDungMap_Tiles + *(uint32 *)(kDungMap_Tiles + (cur_palace_index_x2 >> 1) * 4);
const uint8 *p = kDungMap_Tiles(cur_palace_index_x2 >> 1).ptr;
return p[count];
}
@@ -351,10 +240,6 @@ void DungMap_4() {
overworld_map_state--;
}
const uint8 *GetCurrentTextPtr() {
return kDialogueText + kDialogueOffs[dialogue_message_index];
}
void Module_Messaging_6() {
assert(0);
}
@@ -2259,8 +2144,7 @@ void Text_Initialize_initModuleStateLoop() { // 8ec493
RenderText_SetDefaultWindowPosition();
text_tilemap_cur = 0x3980;
Text_LoadCharacterBuffer();
RenderText_Draw_EmptyBuffer();
dialogue_msg_dst_offs = 0;
memset(messaging_buf, 0, 0x7e0);
nmi_subroutine_index = 2;
nmi_disable_core_updates = 2;
}
@@ -2272,58 +2156,159 @@ void Text_InitVwfState() { // 8ec4c9
vwf_line_ptr = 0;
}
void Text_LoadCharacterBuffer() { // 8ec4e2
const uint8 *src = GetCurrentTextPtr(), *src_org = src;
uint8 *dst = messaging_text_buffer;
dst[0] = dst[1] = 0x7f;
dialogue_msg_dst_offs = 0;
dialogue_msg_src_offs = 0;
for (;;) {
uint8 c = *src++;
if (!(c & 0x80)) {
switch (c) {
case 0x67 + 3: dst = Text_WritePlayerName(dst); break;
case 0x67 + 4: // RenderText_ExtendedCommand_SetWindowType
text_render_state = *src++;
break;
case 0x67 + 5: { // Text_WritePreloadedNumber
uint8 t = *src++;
uint8 v = byte_7E1CF2[t >> 1];
*dst++ = 0x34 + ((t & 1) ? v >> 4 : v & 0xf);
break;
}
case 0x67 + 6:
text_msgbox_topleft = kText_Positions[*src++];
break;
case 0x67 + 16:
text_tilemap_cur = ((0x387F & 0xe300) | 0x180) | (*src++ << 10) & 0x3c00;
break;
case 0x67 + 7:
case 0x67 + 17:
case 0x67 + 18:
case 0x67 + 19:
*dst++ = c;
*dst++ = *src++;
break;
case 0x7f:
dialogue_msg_dst_offs = dst - messaging_text_buffer;
dialogue_msg_src_offs = src - src_org - 1;
*dst = 0x7f;
return; // done
default:
*dst++ = c;
break;
}
} else {
// dictionary
c -= 0x88;
int idx = kTextDictionary_Idx[c], num = kTextDictionary_Idx[c + 1] - idx;
memcpy(dst, &kTextDictionary[idx], num);
dst += num;
enum {
kTextCommandStart_US = 0x67,
kTextDictBase = 0x88,
kTextCmd_NextPic = 0,
kTextCmd_Choose = 1,
kTextCmd_Item = 2,
kTextCmd_Name = 3,
kTextCmd_Window = 4, // Only used with 2
kTextCmd_Number = 5,
kTextCmd_Position = 6,
kTextCmd_ScrollSpd = 7,
kTextCmd_Selchg = 8,
kTextCmd_Choose3 = 10,
kTextCmd_Choose2 = 11,
kTextCmd_Scroll = 12,
kTextCmd_1 = 13,
kTextCmd_2 = 14,
kTextCmd_3 = 15,
kTextCmd_Color = 16,
kTextCmd_Wait = 17,
kTextCmd_Sound = 18,
kTextCmd_Speed = 19,
kTextCmd_Mark = 20, // Unused
kTextCmd_Mark2 = 21, // Unused
kTextCmd_Clear = 22, // Unused
kTextCmd_Waitkey = 23,
kTextCmd_EndMessage = 24,
kTextCmd_IsLetter = 25, // Pseudo cmd
};
enum {
kTextCmd_EU_Scroll = 0x80, // frequency 875
kTextCmd_EU_Waitkey = 0x81, // frequency 362
kTextCmd_EU_1 = 0x82, // frequency 25
kTextCmd_EU_2 = 0x83, // frequency 496
kTextCmd_EU_3 = 0x84, // frequency 347
kTextCmd_EU_Name = 0x85, // frequency 64
kTextCmd_EU_Rest = 0x87,
};
#define TEXTCMD_MULTIBYTE(a) ((a) & 1)
#define TEXTCMD_CMD(a) (((a) >> 1) & 0x1f)
#define TEXTCMD_PARAM(a) ((a) >> 6)
#define TEXTCMD_MK(c, x, m) ((c) << 6 | (x) << 1 | (m))
uint32 Text_DecodeCmd(uint8 a, const uint8 *src) {
if ((g_zenv.dialogue_flags & 1) == 0) {
// US encoding
if (a < kTextCommandStart_US)
return TEXTCMD_MK(a, kTextCmd_IsLetter, 0);
if (a >= 0x80)
return TEXTCMD_MK(26, kTextCmd_IsLetter, 0); // could happen when loading snapshots
assert(a < 0x80);
static const uint8 kText_CommandLengths_US[] = { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
if (kText_CommandLengths_US[a - kTextCommandStart_US])
return TEXTCMD_MK(*src, a - kTextCommandStart_US, 1);
else
return TEXTCMD_MK(0, a - kTextCommandStart_US, 0);
} else {
// EU encoding
if (a < 0x7f)
return TEXTCMD_MK(a, kTextCmd_IsLetter, 0);
static const uint8 kSoundLut[] = {45};
static const uint8 kReturns_Simple[] = {
TEXTCMD_MK(0, kTextCmd_EndMessage, 0),
TEXTCMD_MK(0, kTextCmd_Scroll, 0),
TEXTCMD_MK(0, kTextCmd_Waitkey, 0),
TEXTCMD_MK(0, kTextCmd_1, 0),
TEXTCMD_MK(0, kTextCmd_2, 0),
TEXTCMD_MK(0, kTextCmd_3, 0),
TEXTCMD_MK(0, kTextCmd_Name, 0),
TEXTCMD_MK(0, kTextCmd_Name, 0), // Unused
};
if (a < kTextCmd_EU_Rest)
return kReturns_Simple[a - 0x7f];
a = *src;
switch (a >> 4) {
case 0: return TEXTCMD_MK(a & 0xF, kTextCmd_Wait, 1);
case 1: return TEXTCMD_MK(a & 0xF, kTextCmd_Color, 1);
case 2: return TEXTCMD_MK(a & 0xF, kTextCmd_Number, 1);
case 3: return TEXTCMD_MK(a & 0xF, kTextCmd_Speed, 1);
case 4: return TEXTCMD_MK(kSoundLut[a & 0xF], kTextCmd_Sound, 1);
case 8: {
static const uint8 kReturns_Ext[] = {
TEXTCMD_MK(0, kTextCmd_Choose, 1),
TEXTCMD_MK(0, kTextCmd_Choose2, 1),
TEXTCMD_MK(0, kTextCmd_Choose3, 1),
TEXTCMD_MK(0, kTextCmd_Selchg, 1),
TEXTCMD_MK(0, kTextCmd_Item, 1),
TEXTCMD_MK(0, kTextCmd_NextPic, 1),
TEXTCMD_MK(2, kTextCmd_Window, 1),
TEXTCMD_MK(0, kTextCmd_Position, 1),
TEXTCMD_MK(1, kTextCmd_Position, 1),
};
return kReturns_Ext[a - 0x80];
}
default:
assert(0);
return TEXTCMD_MK(26, kTextCmd_IsLetter, 0);
}
}
}
// Perform initial parsing of the string, expanding words, processing some commands, etc.
void Text_LoadCharacterBuffer() { // 8ec4e2
MemBlk dictionary = FindIndexInMemblk(g_zenv.dialogue_blk, 0);
MemBlk dialogue = FindIndexInMemblk(g_zenv.dialogue_blk, 1);
MemBlk text_str = FindIndexInMemblk(dialogue, dialogue_message_index);
const uint8 *src = text_str.ptr, *src_end = src + text_str.size, *src_org = src;
uint8 *dst = messaging_text_buffer;
while (src < src_end) {
uint8 c = *src++;
if (c >= kTextDictBase) {
MemBlk blk = FindIndexInMemblk(dictionary, c - kTextDictBase);
memcpy(dst, blk.ptr, blk.size);
dst += blk.size;
continue;
}
// Decode the next byte or multibyte character (in case we support that in the future)
// This is dependent on the current language cause US / PAL encode commands differently
uint32 cmd = Text_DecodeCmd(c, src);
switch (TEXTCMD_CMD(cmd)) {
case kTextCmd_Name: dst = Text_WritePlayerName(dst); break;
case kTextCmd_Window: // RenderText_ExtendedCommand_SetWindowType
text_render_state = TEXTCMD_PARAM(cmd);
break;
case kTextCmd_Number: { // Text_WritePreloadedNumber
uint8 t = TEXTCMD_PARAM(cmd);
uint8 v = dialogue_number[t >> 1];
*dst++ = 0x34 + ((t & 1) ? v >> 4 : v & 0xf);
break;
}
case kTextCmd_Position:
text_msgbox_topleft = kText_Positions[TEXTCMD_PARAM(cmd)];
break;
case kTextCmd_Color:
text_tilemap_cur = ((0x387F & 0xe300) | 0x180) | (TEXTCMD_PARAM(cmd) << 10) & 0x3c00;
break;
default:
// This combination is handled when rendering instead of here
*dst++ = c;
if (TEXTCMD_MULTIBYTE(cmd))
*dst++ = *src;
break;
}
src += TEXTCMD_MULTIBYTE(cmd);
}
*dst = 0x7f;
dialogue_msg_read_pos = 0;
}
uint8 *Text_WritePlayerName(uint8 *p) { // 8ec5b3
uint8 slot = srm_var1;
int offs = ((slot>>1) - 1) * 0x500;
@@ -2396,133 +2381,103 @@ void RenderText_Draw_CharacterTilemap() { // 8ec97d
}
void RenderText_Draw_MessageCharacters() { // 8ec984
restart:
if (dialogue_msg_src_offs >= 99) {
dialogue_msg_src_offs = 0;
text_next_position = 0;
} else if (dialogue_msg_src_offs >= 59 && dialogue_msg_src_offs < 80) {
dialogue_msg_src_offs = 0x50;
text_next_position = 0;
} else if (dialogue_msg_src_offs >= 19 && dialogue_msg_src_offs < 40) {
dialogue_msg_src_offs = 0x28;
text_next_position = 0;
}
if ((dialogue_msg_src_offs == 18 || dialogue_msg_src_offs == 58 || dialogue_msg_src_offs == 98) && (text_next_position & 7) >= 6) {
dialogue_msg_src_offs++;
goto restart;
}
int t = (messaging_text_buffer[dialogue_msg_dst_offs] & 0x7f) - 0x66;
if (t < 0)
t = 0;
switch (t) {
case 0: // RenderText_Draw_RenderCharacter
switch (vwf_line_mode < 2 ? vwf_line_mode : 2) {
case 0: // RenderText_Draw_RenderCharacter_All
RenderText_Draw_RenderCharacter_All();
break;
case 1: // VWF_RenderSingle
VWF_RenderSingle();
break;
default:
vwf_line_mode--;
RESTART:;
uint32 cmd = Text_DecodeCmd(messaging_text_buffer[dialogue_msg_read_pos],
&messaging_text_buffer[dialogue_msg_read_pos + 1]);
switch (TEXTCMD_CMD(cmd)) {
case kTextCmd_IsLetter:
if (vwf_line_speed_cur >= 2) {
vwf_line_speed_cur--;
break;
}
VWF_RenderSingle(TEXTCMD_PARAM(cmd));
dialogue_msg_read_pos += 1 + TEXTCMD_MULTIBYTE(cmd);
if (vwf_line_speed_cur == 0)
goto RESTART;
break;
case 1: // RenderText_Draw_NextImage
case kTextCmd_NextPic: // RenderText_Draw_NextImage
if (main_module_index == 20) {
PaletteFilterHistory();
if (!BYTE(palette_filter_countdown))
dialogue_msg_dst_offs++;
goto COMMAND_DONE;
} else {
dialogue_msg_dst_offs++;
goto COMMAND_DONE;
}
break;
case 2: // RenderText_Draw_Choose2LowOr3
case kTextCmd_Choose: // RenderText_Draw_Choose2LowOr3
RenderText_Draw_Choose2LowOr3();
break;
case 3: // RenderText_Draw_ChooseItem
case kTextCmd_Item: // RenderText_Draw_ChooseItem
RenderText_Draw_ChooseItem();
break;
case 4: //
case 5: //
case 6: //
case 7: //
case 8: // RenderText_Draw_Ignore
byte_7E1CEA = messaging_text_buffer[dialogue_msg_dst_offs + 1];
dialogue_msg_dst_offs += 2;
break;
case 9: // RenderText_Draw_Choose2HiOr3
RenderText_Draw_Choose2HiOr3();
break;
case 10: //
case kTextCmd_Name:
case kTextCmd_Window:
case kTextCmd_Number:
case kTextCmd_Position:
case kTextCmd_Color:
// These get handled in Text_LoadCharacterBuffer
assert(0);
break;
case 11: // RenderText_Draw_Choose3
// These are unused
case kTextCmd_Mark:
case kTextCmd_Mark2:
case kTextCmd_Clear:
assert(0);
break;
case kTextCmd_ScrollSpd:
dialogue_scroll_speed = TEXTCMD_PARAM(cmd);
goto COMMAND_DONE;
case kTextCmd_Selchg: // RenderText_Draw_Choose2HiOr3
RenderText_Draw_Choose2HiOr3();
break;
case kTextCmd_Choose3: // RenderText_Draw_Choose3
RenderText_Draw_Choose3();
break;
case 12: // RenderText_Draw_Choose1Or2
case kTextCmd_Choose2: // RenderText_Draw_Choose1Or2
RenderText_Draw_Choose1Or2();
break;
case 13: // RenderText_Draw_Scroll
RenderText_Draw_Scroll();
case kTextCmd_Scroll: // RenderText_Draw_Scroll
if (RenderText_Draw_Scroll())
goto COMMAND_DONE;
break;
case 14: //
case 15: //
case 16: // VWF_SetLine
dialogue_msg_src_offs = kVWF_LinePositions[(t + 2) & 3];
vwf_curline = kVWF_RowPositions[(t + 2) & 3];
case kTextCmd_1: //
case kTextCmd_2: //
case kTextCmd_3: // VWF_SetLine
vwf_curline = kVWF_RowPositions[TEXTCMD_CMD(cmd) - kTextCmd_1];
vwf_flag_next_line = 1;
dialogue_msg_dst_offs++;
text_next_position = 0;
break;
case 17: // RenderText_Draw_SetColor
byte_7E1CDC &= ~0x1c;
byte_7E1CDC |= (messaging_text_buffer[dialogue_msg_dst_offs + 1] & 7) << 2;
dialogue_msg_dst_offs += 2;
break;
case 18: // RenderText_Draw_Wait
switch (joypad1L_last & 0x80 ? 1 : text_wait_countdown >= 2 ? 2 : text_wait_countdown) {
goto COMMAND_DONE;
case kTextCmd_Wait: // RenderText_Draw_Wait
switch (joypad1L_last & 0x80 ? 1 : text_wait_countdown) {
case 0:
text_wait_countdown = kText_WaitDurations[messaging_text_buffer[dialogue_msg_dst_offs + 1] & 0xf] - 1;
text_wait_countdown = kText_WaitDurations[TEXTCMD_PARAM(cmd)] - 1;
break;
case 1:
dialogue_msg_dst_offs += 2;
BYTE(text_wait_countdown) = 0;
break;
case 2:
goto COMMAND_DONE;
default:
text_wait_countdown--;
break;
}
break;
case 19: // RenderText_Draw_PlaySfx
sound_effect_2 = messaging_text_buffer[dialogue_msg_dst_offs + 1];
dialogue_msg_dst_offs += 2;
break;
case 20: // RenderText_Draw_SetSpeed
vwf_line_speed = vwf_line_mode = messaging_text_buffer[dialogue_msg_dst_offs + 1];
dialogue_msg_dst_offs += 2;
break;
case 21: // RenderText_Draw_Command7B
RenderText_Draw_Command7B();
break;
case 22: // RenderText_Draw_ABunchOfSpaces
RenderText_Draw_ABunchOfSpaces();
break;
case 23: // RenderText_Draw_EmptyBuffer
RenderText_Draw_EmptyBuffer();
break;
case 24: // RenderText_Draw_PauseForInput
case kTextCmd_Sound: // RenderText_Draw_PlaySfx
sound_effect_2 = TEXTCMD_PARAM(cmd);
goto COMMAND_DONE;
case kTextCmd_Speed: // RenderText_Draw_SetSpeed
vwf_line_speed = vwf_line_speed_cur = TEXTCMD_PARAM(cmd);
goto COMMAND_DONE;
case kTextCmd_Waitkey: // RenderText_Draw_PauseForInput
if (text_wait_countdown2 != 0) {
if (--text_wait_countdown2 == 1)
sound_effect_2 = 36;
} else {
if ((filtered_joypad_H | filtered_joypad_L) & 0xc0) {
dialogue_msg_dst_offs++;
text_wait_countdown2 = 28;
goto COMMAND_DONE;
}
}
break;
case 25: // RenderText_Draw_Terminate
case kTextCmd_EndMessage: // RenderText_Draw_Terminate
if (text_wait_countdown2 != 0) {
if (--text_wait_countdown2 == 1)
sound_effect_2 = 36;
@@ -2534,6 +2489,9 @@ restart:
}
break;
}
if (0) COMMAND_DONE: {
dialogue_msg_read_pos += 1 + TEXTCMD_MULTIBYTE(cmd);
}
nmi_subroutine_index = 2;
nmi_disable_core_updates = 2;
}
@@ -2551,35 +2509,27 @@ void RenderText_Draw_Finish() { // 8eca35
main_module_index = saved_module_for_menu;
}
void RenderText_Draw_RenderCharacter_All() { // 8eca99
VWF_RenderSingle();
if (dialogue_msg_src_offs != 19 && dialogue_msg_src_offs != 59 && dialogue_msg_src_offs != 99)
RenderText_Draw_MessageCharacters();
}
void VWF_RenderSingle() { // 8ecab8
uint8 t = messaging_text_buffer[dialogue_msg_dst_offs];
if (t != 0x59)
void VWF_RenderSingle(int c) { // 8ecab8
if (c != 0x59)
sound_effect_2 = 12;
VWF_RenderCharacter();
vwf_line_mode = vwf_line_speed;
}
vwf_line_speed_cur = vwf_line_speed;
void VWF_RenderCharacter() { // 8ecb5e
if (vwf_flag_next_line) {
vwf_line_ptr = kVWF_RenderCharacter_renderPos[vwf_curline>>1];
vwf_var1 = kVWF_RenderCharacter_linePositions[vwf_curline>>1];
vwf_flag_next_line = 0;
}
uint8 c = messaging_text_buffer[dialogue_msg_dst_offs];
uint8 width = kVWF_RenderCharacter_widths[c];
const uint8 *kFontData = FindIndexInMemblk(g_zenv.dialogue_font_blk, 0).ptr;
uint8 width = FindIndexInMemblk(g_zenv.dialogue_font_blk, 1).ptr[c];
assert(width <= 8);
int i = vwf_var1++;
uint8 arrval = vwf_arr[i];
vwf_arr[i + 1] = arrval + width;
uint16 r10 = (c & 0x70) * 2 + (c & 0xf);
uint16 r0 = arrval * 2;
const uint16 *const kTextBits = kFontData;
const uint16 *src2 = kTextBits + r10 * 8;
const uint16 *src2 = (uint16*)(kFontData + r10 * 16);
uint8 *mbuf = (uint8 *)messaging_buf;
for (int i = 0; i != 16; i += 2) {
uint16 r4 = *src2++;
@@ -2604,7 +2554,7 @@ void VWF_RenderCharacter() { // 8ecb5e
WORD(mbuf[x + 0]) = r4;
}
uint16 r8 = vwf_line_ptr + 0x150;
const uint16 *src3 = kTextBits + (r10 + 16) * 8;
const uint16 *src3 = (uint16*)(kFontData + (r10 + 16) * 16);
for (int i = 0; i != 16; i += 2) {
uint16 r4 = *src3++;
int y = r8 + r0;
@@ -2627,7 +2577,6 @@ void VWF_RenderCharacter() { // 8ecb5e
if (r4 != 0)
WORD(mbuf[x + 0]) = r4;
}
dialogue_msg_dst_offs++;
}
void RenderText_Draw_Choose2LowOr3() { // 8ecd1a
@@ -2645,8 +2594,6 @@ void RenderText_Draw_Choose2LowOr3() { // 8ecd1a
sound_effect_2 = 32;
dialogue_message_index = t + 1;
Text_LoadCharacterBuffer();
text_next_position = 0;
dialogue_msg_dst_offs = 0;
Text_InitVwfState();
}
}
@@ -2719,8 +2666,6 @@ void RenderText_Draw_Choose2HiOr3() { // 8ece83
sound_effect_2 = 32;
dialogue_message_index = t + 11;
Text_LoadCharacterBuffer();
text_next_position = 0;
dialogue_msg_dst_offs = 0;
Text_InitVwfState();
}
}
@@ -2743,8 +2688,6 @@ void RenderText_Draw_Choose3() { // 8ecef7
sound_effect_2 = 32;
dialogue_message_index = choice + 6;
Text_LoadCharacterBuffer();
text_next_position = 0;
dialogue_msg_dst_offs = 0;
Text_InitVwfState();
}
}
@@ -2765,14 +2708,12 @@ void RenderText_Draw_Choose1Or2() { // 8ecf72
sound_effect_2 = 32;
dialogue_message_index = t + 9;
Text_LoadCharacterBuffer();
text_next_position = 0;
dialogue_msg_dst_offs = 0;
Text_InitVwfState();
}
}
void RenderText_Draw_Scroll() { // 8ecfe2
uint8 r2 = byte_7E1CEA;
bool RenderText_Draw_Scroll() { // 8ecfe2
uint8 r2 = dialogue_scroll_speed;
do {
for (int i = 0; i < 0x7e0; i += 16) {
uint16 *p = (uint16 *)((uint8 *)messaging_buf + i);
@@ -2790,43 +2731,12 @@ void RenderText_Draw_Scroll() { // 8ecfe2
p[i] = 0;
if ((++byte_7E1CDF & 0xf) == 0) {
dialogue_msg_dst_offs++;
dialogue_msg_src_offs = 80;
vwf_curline = 4;
vwf_flag_next_line = 1;
text_next_position = 0;
break;
return true;
}
} while (r2--);
}
void RenderText_Draw_Command7B() { // 8ed18d
int i = (messaging_text_buffer[dialogue_msg_dst_offs + 1] & 0x7f);
int j = dialogue_msg_src_offs;
WORD(g_ram[0x2D8 + j]) = kVWF_Command7B[i * 2 + 0];
WORD(g_ram[0x300 + j]) = kVWF_Command7B[i * 2 + 1];
dialogue_msg_src_offs = j + 2;
dialogue_msg_dst_offs += 2;
RenderText_Draw_MessageCharacters();
}
void RenderText_Draw_ABunchOfSpaces() { // 8ed1bd
int i = (messaging_text_buffer[dialogue_msg_dst_offs + 1] & 0x7f);
int j = dialogue_msg_src_offs;
WORD(g_ram[0x2D8 + j]) = kVWF_Command7C[i * 4 + 0];
WORD(g_ram[0x300 + j]) = kVWF_Command7C[i * 4 + 1];
WORD(g_ram[0x2DA + j]) = kVWF_Command7C[i * 4 + 2];
WORD(g_ram[0x302 + j]) = kVWF_Command7C[i * 4 + 3];
dialogue_msg_src_offs = j + 4;
dialogue_msg_dst_offs += 2;
RenderText_Draw_MessageCharacters();
}
void RenderText_Draw_EmptyBuffer() { // 8ed1f9
memset(messaging_buf, 0, 0x7e0);
dialogue_msg_src_offs = 0;
dialogue_msg_dst_offs++;
text_next_position = 0;
return false;
}
void RenderText_SetDefaultWindowPosition() { // 8ed280
@@ -2875,28 +2785,19 @@ void RenderText_Refresh() { // 8ed307
nmi_load_bg_from_vram = 1;
}
void Text_GenerateMessagePointers() { // 8ed3eb
const uint8 *src = kDialogueText;
// This is not actually used. Only for ram compat.
MemBlk dialogue = FindIndexInMemblk(g_zenv.dialogue_blk, 1);
uint32 p = 0x1c8000;
uint8 *dst = kTextDialoguePointers;
for (int i = 0;; i++) {
for (int i = 0; i < 398; i++) {
if (i == 359)
p = 0xedf40;
WORD(dst[0]) = p;
dst[2] = p >> 16;
dst += 3;
if (i == 397)
break;
for (;;) {
int j = *src;
int len = (j >= 0x67 && j < 0x80) ? kText_CommandLengths[j - 0x67] : 1;
src += len;
p += len;
if (j == 0x7f)
break;
}
p += (uint32)FindIndexInMemblk(dialogue, i).size + 1;
}
}

View File

@@ -4,7 +4,6 @@
const uint8 *GetDungmapFloorLayout();
uint8 GetOtherDungmapInfo(int count);
void DungMap_4();
const uint8 *GetCurrentTextPtr();
void Module_Messaging_6();
void OverworldMap_SetupHdma();
const uint8 *GetLightOverworldTilemap();
@@ -108,9 +107,7 @@ void RenderText_Draw_BorderIncremental();
void RenderText_Draw_CharacterTilemap();
void RenderText_Draw_MessageCharacters();
void RenderText_Draw_Finish();
void RenderText_Draw_RenderCharacter_All();
void VWF_RenderSingle();
void VWF_RenderCharacter();
void RenderText_Draw_Choose2LowOr3();
void RenderText_Draw_ChooseItem();
void RenderText_FindYItem_Previous();
@@ -119,10 +116,7 @@ void RenderText_DrawSelectedYItem();
void RenderText_Draw_Choose2HiOr3();
void RenderText_Draw_Choose3();
void RenderText_Draw_Choose1Or2();
void RenderText_Draw_Scroll();
void RenderText_Draw_Command7B();
void RenderText_Draw_ABunchOfSpaces();
void RenderText_Draw_EmptyBuffer();
bool RenderText_Draw_Scroll();
void RenderText_SetDefaultWindowPosition();
void RenderText_DrawBorderInitialize();
uint16 *RenderText_DrawBorderRow(uint16 *d, int y);

View File

View File

View File

View File

View File

@@ -2449,11 +2449,11 @@ void Overworld_DecompressAndDrawAllQuadrants() { // 82f54a
}
static const uint8 *GetOverworldHibytes(int i) {
return kOverworld_Hibytes_Comp + *(uint32 *)(kOverworld_Hibytes_Comp + i * 4);
return kOverworld_Hibytes_Comp(i).ptr;
}
static const uint8 *GetOverworldLobytes(int i) {
return kOverworld_Lobytes_Comp + *(uint32 *)(kOverworld_Lobytes_Comp + i * 4);
return kOverworld_Lobytes_Comp(i).ptr;
}

View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

Before

Width:  |  Height:  |  Size: 228 KiB

After

Width:  |  Height:  |  Size: 228 KiB

View File

@@ -27,7 +27,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
1 TEXTINCLUDE
BEGIN
"platform\\win32\\resource.h\0"
"src\\platform\\win32\\resource.h\0"
END
2 TEXTINCLUDE
@@ -52,7 +52,7 @@ END
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1 ICON "platform\\win32\\triforce.ico"
IDI_ICON1 ICON "src\\platform\\win32\\triforce.ico"
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////

View File

View File

View File

@@ -1058,8 +1058,8 @@ void FortuneTeller_LightOrDarkWorld(int k, bool dark_world) {
if (!dark_world)
sprite_graphics[k] = 0;
j = kFortuneTeller_Prices[sprite_A[k]>>1];
byte_7E1CF2[0] = (j / 10) | (j % 10)<< 4 ;
byte_7E1CF2[1] = 0;
dialogue_number[0] = (j / 10) | (j % 10)<< 4 ;
dialogue_number[1] = 0;
Sprite_ShowMessageUnconditional(0xf4);
sprite_ai_state[k]++;
break;
@@ -11396,7 +11396,7 @@ void Sprite_HappinessPond(int k) { // 86c44c
if (choice_in_multiselect_box == 0) {
int i = (link_bomb_upgrades | link_arrow_upgrades) != 0;
sprite_graphics[k] = i * 2;
WORD(byte_7E1CF2[0]) = WORD(kHappinessPondCostHex[i * 2]);
WORD(dialogue_number[0]) = WORD(kHappinessPondCostHex[i * 2]);
Sprite_ShowMessageUnconditional(0x14e);
sprite_ai_state[k] = 2;
flag_is_link_immobilized = 1;
@@ -11409,7 +11409,7 @@ show_later_msg:
break;
case 2: {
int i = sprite_graphics[k] + choice_in_multiselect_box;
byte_7E1CF2[1] = kHappinessPondCostHex[i];
dialogue_number[1] = kHappinessPondCostHex[i];
if (link_rupees_goal < kHappinessPondCost[i]) {
goto show_later_msg;
} else {
@@ -11430,7 +11430,7 @@ show_later_msg:
sprite_ai_state[k] = 5;
return;
}
byte_7E1CF2[0] = (link_rupees_in_pond / 10) * 16 + (link_rupees_in_pond % 10);
dialogue_number[0] = (link_rupees_in_pond / 10) * 16 + (link_rupees_in_pond % 10);
sprite_ai_state[k] = 4;
break;
}
@@ -11481,7 +11481,7 @@ show_later_msg:
int i = link_bomb_upgrades + 1;
if (i != 8) {
link_bomb_upgrades = i;
byte_7E1CF2[0] = link_bomb_filler = kMaxBombsForLevelHex[i];
dialogue_number[0] = link_bomb_filler = kMaxBombsForLevelHex[i];
Sprite_ShowMessageUnconditional(0x96);
} else {
link_rupees_goal += 100;
@@ -11518,7 +11518,7 @@ show_later_msg:
int i = link_arrow_upgrades + 1;
if (i != 8) {
link_arrow_upgrades = i;
byte_7E1CF2[0] = link_arrow_filler = kMaxArrowsForLevelHex[i];
dialogue_number[0] = link_arrow_filler = kMaxArrowsForLevelHex[i];
Sprite_ShowMessageUnconditional(0x97);
} else {
link_rupees_goal += 100;
@@ -12947,8 +12947,8 @@ void Sprite_MazeGameGuy(int k) { // 8dcbf2
t %= 60;
int c = t / 10;
t %= 10;
byte_7E1CF2[0] = t | c << 4;
byte_7E1CF2[1] = b | a << 4;
dialogue_number[0] = t | c << 4;
dialogue_number[1] = b | a << 4;
t = Sprite_ShowMessageOnContact(k, 0xcb);
if (t & 0x100) {
sprite_D[k] = sprite_head_dir[k] = (uint8)t;

View File

@@ -92,6 +92,12 @@ typedef struct OamEnt {
uint8 x, y, charnum, flags;
} OamEnt;
typedef struct MemBlk {
const uint8 *ptr;
size_t size;
} MemBlk;
MemBlk FindIndexInMemblk(MemBlk data, size_t i);
void NORETURN Die(const char *error);
#endif // ZELDA3_TYPES_H_

View File

@@ -170,3 +170,111 @@ void ByteArray_AppendByte(ByteArray *arr, uint8 v) {
ByteArray_Resize(arr, arr->size + 1);
arr->data[arr->size - 1] = v;
}
// Automatically selects between 16 or 32 bit indexes. Can hold up to 8192 elements in 16-bit mode.
MemBlk FindIndexInMemblk(MemBlk data, size_t i) {
if (data.size < 2)
return (MemBlk) { 0, 0 };
size_t end = data.size - 2, left_off, right_off;
size_t mx = *(uint16 *)(data.ptr + end);
if (mx < 8192) {
if (i > mx || mx * 2 > end)
return (MemBlk) { 0, 0 };
left_off = ((i == 0) ? mx * 2 : mx * 2 + *(uint16 *)(data.ptr + i * 2 - 2));
right_off = (i == mx) ? end : mx * 2 + *(uint16 *)(data.ptr + i * 2);
} else {
mx -= 8192;
if (i > mx || mx * 4 > end)
return (MemBlk) { 0, 0 };
left_off = ((i == 0) ? mx * 4 : mx * 4 + *(uint32 *)(data.ptr + i * 4 - 4));
right_off = (i == mx) ? end : mx * 4 + *(uint32 *)(data.ptr + i * 4);
}
if (left_off > right_off || right_off > end)
return (MemBlk) { 0, 0 };
return (MemBlk) { data.ptr + left_off, right_off - left_off };
}
static uint64 BpsDecodeInt(const uint8 **src) {
uint64 data = 0, shift = 1;
while(true) {
uint8 x = *(*src)++;
data += (x & 0x7f) * shift;
if(x & 0x80) break;
shift <<= 7;
data += shift;
}
return data;
}
#define CRC32_POLYNOMIAL 0xEDB88320
static uint32 crc32(const void *data, size_t length) {
uint32 crc = 0xFFFFFFFF;
const uint8 *byteData = (const uint8 *)data;
for (size_t i = 0; i < length; i++) {
crc ^= byteData[i];
for (int j = 0; j < 8; j++)
crc = (crc >> 1) ^ ((crc & 1) * CRC32_POLYNOMIAL);
}
return crc ^ 0xFFFFFFFF;
}
uint8 *ApplyBps(const uint8 *src, size_t src_size_in,
const uint8 *bps, size_t bps_size, size_t *length_out) {
const uint8 *bps_end = bps + bps_size - 12;
if (memcmp(bps, "BPS1", 4))
return NULL;
if (crc32(src, src_size_in) != *(uint32 *)(bps_end))
return NULL;
if (crc32(bps, bps_size - 4) != *(uint32 *)(bps_end + 8))
return NULL;
bps += 4;
uint32 src_size = BpsDecodeInt(&bps);
uint32 dst_size = BpsDecodeInt(&bps);
uint32 meta_size = BpsDecodeInt(&bps);
uint32 outputOffset = 0;
uint32 sourceRelativeOffset = 0;
uint32 targetRelativeOffset = 0;
if (src_size != src_size_in)
return NULL;
*length_out = dst_size;
uint8 *dst = malloc(dst_size);
if (!dst)
return NULL;
while (bps < bps_end) {
uint32 cmd = BpsDecodeInt(&bps);
uint32 length = (cmd >> 2) + 1;
switch (cmd & 3) {
case 0:
while(length--) {
dst[outputOffset] = src[outputOffset];
outputOffset++;
}
break;
case 1:
while (length--)
dst[outputOffset++] = *bps++;
break;
case 2:
cmd = BpsDecodeInt(&bps);
sourceRelativeOffset += (cmd & 1 ? -1 : +1) * (cmd >> 1);
while (length--)
dst[outputOffset++] = src[sourceRelativeOffset++];
break;
default:
cmd = BpsDecodeInt(&bps);
targetRelativeOffset += (cmd & 1 ? -1 : +1) * (cmd >> 1);
while(length--)
dst[outputOffset++] = dst[targetRelativeOffset++];
break;
}
}
if (dst_size != outputOffset)
return NULL;
if (crc32(dst, dst_size) != *(uint32 *)(bps_end + 4))
return NULL;
return dst;
}

View File

@@ -35,5 +35,7 @@ const char *SkipPrefix(const char *big, const char *little);
void StrSet(char **rv, const char *s);
char *StrFmt(const char *fmt, ...);
char *ReplaceFilenameWithNewPath(const char *old_path, const char *new_path);
uint8 *ApplyBps(const uint8 *src, size_t src_size_in,
const uint8 *bps, size_t bps_size, size_t *length_out);
#endif // ZELDA3_UTIL_H_

View File

@@ -814,12 +814,12 @@
#define text_msgbox_topleft_copy (*(uint16*)(g_ram+0x1CD0))
#define text_msgbox_topleft (*(uint16*)(g_ram+0x1CD2))
#define text_render_state (*(uint8*)(g_ram+0x1CD4))
#define vwf_line_mode (*(uint8*)(g_ram+0x1CD5))
#define vwf_line_speed_cur (*(uint8*)(g_ram+0x1CD5))
#define vwf_line_speed (*(uint8*)(g_ram+0x1CD6))
#define text_incremental_state (*(uint8*)(g_ram+0x1CD7))
#define messaging_module (*(uint8*)(g_ram+0x1CD8))
#define dialogue_msg_dst_offs (*(uint16*)(g_ram+0x1CD9))
#define byte_7E1CDC (*(uint8*)(g_ram+0x1CDC))
#define dialogue_msg_read_pos (*(uint16*)(g_ram+0x1CD9))
#define dialogue_text_color (*(uint8*)(g_ram+0x1CDC))
#define dialogue_msg_src_offs (*(uint16*)(g_ram+0x1CDD))
#define byte_7E1CDF (*(uint8*)(g_ram+0x1CDF))
#define text_wait_countdown (*(uint16*)(g_ram+0x1CE0))
@@ -827,9 +827,11 @@
#define text_next_position (*(uint8*)(g_ram+0x1CE6))
#define choice_in_multiselect_box (*(uint8*)(g_ram+0x1CE8))
#define text_wait_countdown2 (*(uint8*)(g_ram+0x1CE9))
#define byte_7E1CEA (*(uint8*)(g_ram+0x1CEA))
// This seems never nonzero
#define dialogue_scroll_speed (*(uint8*)(g_ram+0x1CEA))
#define dialogue_message_index (*(uint16*)(g_ram+0x1CF0))
#define byte_7E1CF2 ((uint8*)(g_ram+0x1CF2))
#define dialogue_number ((uint8*)(g_ram+0x1CF2))
#define choice_in_multiselect_box_bak (*(uint8*)(g_ram+0x1CF4))
#define alt_sprite_state ((uint8*)(g_ram+0x1D00))
#define alt_sprite_type ((uint8*)(g_ram+0x1D10))

View File

@@ -113,6 +113,8 @@ static void VerifySnapshotsEq(Snapshot *b, Snapshot *a, Snapshot *prev) {
memcpy(a->ram + 0x1db20, b->ram + 0x1db20, 64 * 2); // msu
a->ram[0x654] = b->ram[0x654]; // msu_volume
memcpy(a->ram + 0x1CDD, b->ram + 0x1CDD, 2); // dialogue_msg_src_offs
if (memcmp(b->ram, a->ram, 0x20000)) {
fprintf(stderr, "@%d: Memory compare failed (mine != theirs, prev):\n", frame_counter);
int j = 0;

View File

@@ -10,7 +10,7 @@
#include "spc_player.h"
#include "util.h"
#include "audio.h"
#include "assets.h"
ZeldaEnv g_zenv;
uint8 g_ram[131072];
@@ -739,7 +739,7 @@ bool ZeldaRunFrame(int inputs) {
EmuSyncMemoryRegion(&g_ram[kRam_CrystalRotateCounter], 1);
}
if (g_emu_runframe == NULL || enhanced_features0 != 0) {
if (g_emu_runframe == NULL || enhanced_features0 != 0 || g_zenv.dialogue_flags) {
// can't compare against real impl when running with extra features.
ZeldaRunFrameInternal(inputs, run_what);
} else {
@@ -751,7 +751,28 @@ bool ZeldaRunFrame(int inputs) {
return is_replay;
}
void ZeldaSetLanguage(const char *language) {
static const uint8 kDefaultConf[3] = { 0, 0, 0 };
MemBlk found = { kDefaultConf, 3 };
if (language) {
size_t n = strlen(language);
for (int i = 0; ; i++) {
MemBlk mb = kDialogueMap(i);
if (mb.ptr == 0) {
fprintf(stderr, "Unable to find language '%s'\n", language);
break;
}
MemBlk name = FindIndexInMemblk(mb, 0);
if (name.size == n && !memcmp(name.ptr, language, n)) {
found = FindIndexInMemblk(mb, 1);
break;
}
}
}
g_zenv.dialogue_blk = kDialogue(found.ptr[0]);
g_zenv.dialogue_font_blk = kDialogueFont(found.ptr[1]);
g_zenv.dialogue_flags = found.ptr[2];
}
static const char *const kReferenceSaves[] = {

View File

@@ -21,6 +21,10 @@ typedef struct ZeldaEnv {
struct Ppu *ppu;
struct SpcPlayer *player;
struct Dma *dma;
MemBlk dialogue_blk;
MemBlk dialogue_font_blk;
uint8 dialogue_flags;
} ZeldaEnv;
extern ZeldaEnv g_zenv;
extern int frame_ctr_dbg;
@@ -50,7 +54,7 @@ void ZeldaApuLock();
void ZeldaApuUnlock();
bool ZeldaIsPlayingMusicTrack(uint8 track);
uint8 ZeldaGetEntranceMusicTrack(int track);
void ZeldaSetLanguage(const char *language);
void PatchCommand(char cmd);
// Things for state management

View File

@@ -1,255 +0,0 @@
kTextAlphabet = [
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
"n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
# codes 0x3E and up
"!", "?", "-", ".", ",",
# codes 0x43 and up
"[...]", ">", "(", ")",
# codes 0x47 and up
"[Ankh]", "[Waves]", "[Snake]", "[LinkL]", "[LinkR]",
"\"", "[Up]", "[Down]", "[Left]", "[Right]", "'",
# codes 0x52 and up
"[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]",
"[3HeartR]", "[4HeartL]", "[4HeartR]",
" ", "<", "[A]", "[B]", "[X]", "[Y]",
]
kText_CommandLengths = [1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, ]
kText_CommandNames = [
"NextPic",
"Choose",
"Item",
"Name",
"Window",
"Number",
"Position",
"ScrollSpd",
"Selchg",
"Crash",
"Choose3",
"Choose2",
"Scroll",
"1",
"2",
"3",
"Color",
"Wait",
"Sound",
"Speed",
"Mark",
"Mark2",
"Clear",
"Waitkey",
"EndMessage"
]
kTextDictionary = [ 0x59, 0x59, 0x59, 0x59,
0x59, 0x59, 0x59,
0x59, 0x59,
0x51, 0x2c, 0x59,
0x1a, 0x27, 0x1d, 0x59,
0x1a, 0x2b, 0x1e, 0x59,
0x1a, 0x25, 0x25, 0x59,
0x1a, 0x22, 0x27,
0x1a, 0x27, 0x1d,
0x1a, 0x2d, 0x59,
0x1a, 0x2c, 0x2d,
0x1a, 0x27,
0x1a, 0x2d,
0x1b, 0x25, 0x1e,
0x1b, 0x1a,
0x1b, 0x1e,
0x1b, 0x28,
0x1c, 0x1a, 0x27, 0x59,
0x1c, 0x21, 0x1e,
0x1c, 0x28, 0x26,
0x1c, 0x24,
0x1d, 0x1e, 0x2c,
0x1d, 0x22,
0x1d, 0x28,
0x1e, 0x27, 0x59,
0x1e, 0x2b, 0x59,
0x1e, 0x1a, 0x2b,
0x1e, 0x27, 0x2d,
0x1e, 0x1d, 0x59,
0x1e, 0x27,
0x1e, 0x2b,
0x1e, 0x2f,
0x1f, 0x28, 0x2b,
0x1f, 0x2b, 0x28,
0x20, 0x22, 0x2f, 0x1e, 0x59,
0x20, 0x1e, 0x2d,
0x20, 0x28,
0x21, 0x1a, 0x2f, 0x1e,
0x21, 0x1a, 0x2c,
0x21, 0x1e, 0x2b,
0x21, 0x22,
0x21, 0x1a,
0x22, 0x20, 0x21, 0x2d, 0x59,
0x22, 0x27, 0x20, 0x59,
0x22, 0x27,
0x22, 0x2c,
0x22, 0x2d,
0x23, 0x2e, 0x2c, 0x2d,
0x24, 0x27, 0x28, 0x30,
0x25, 0x32, 0x59,
0x25, 0x1a,
0x25, 0x28,
0x26, 0x1a, 0x27,
0x26, 0x1a,
0x26, 0x1e,
0x26, 0x2e,
0x27, 0x51, 0x2d, 0x59,
0x27, 0x28, 0x27,
0x27, 0x28, 0x2d,
0x28, 0x29, 0x1e, 0x27,
0x28, 0x2e, 0x27, 0x1d,
0x28, 0x2e, 0x2d, 0x59,
0x28, 0x1f,
0x28, 0x27,
0x28, 0x2b,
0x29, 0x1e, 0x2b,
0x29, 0x25, 0x1e,
0x29, 0x28, 0x30,
0x29, 0x2b, 0x28,
0x2b, 0x1e, 0x59,
0x2b, 0x1e,
0x2c, 0x28, 0x26, 0x1e,
0x2c, 0x1e,
0x2c, 0x21,
0x2c, 0x28,
0x2c, 0x2d,
0x2d, 0x1e, 0x2b, 0x59,
0x2d, 0x21, 0x22, 0x27,
0x2d, 0x1e, 0x2b,
0x2d, 0x21, 0x1a,
0x2d, 0x21, 0x1e,
0x2d, 0x21, 0x22,
0x2d, 0x28,
0x2d, 0x2b,
0x2e, 0x29,
0x2f, 0x1e, 0x2b,
0x30, 0x22, 0x2d, 0x21,
0x30, 0x1a,
0x30, 0x1e,
0x30, 0x21,
0x30, 0x22,
0x32, 0x28, 0x2e,
0x7, 0x1e, 0x2b,
0x13, 0x21, 0x1a,
0x13, 0x21, 0x1e,
0x13, 0x21, 0x22,
0x18, 0x28, 0x2e,
]
kTextDictionary_Idx = [
0, 4, 7, 9, 12, 16, 20, 24, 27, 30, 33, 36, 38, 40, 43, 45, 47, 49, 53, 56, 59, 61, 64, 66, 68, 71, 74, 77, 80, 83, 85, 87, 89, 92, 95, 100, 103, 105, 109, 112, 115, 117, 119, 124, 128, 130, 132, 134, 138, 142, 145, 147, 149, 152, 154, 156, 158, 162, 165, 168, 172, 176, 180, 182, 184, 186, 189, 192, 195, 198, 201, 203, 207, 209, 211, 213, 215, 219, 223, 226, 229, 232, 235, 237, 239, 241, 244, 248, 250, 252, 254, 256, 259, 262, 265, 268, 271, 274
]
def make_dict():
r, rinv = {}, {}
for i in range(len(kTextDictionary_Idx) - 1):
ln = kTextDictionary_Idx[i + 1] - kTextDictionary_Idx[i]
idx = kTextDictionary_Idx[i]
s = "".join(kTextAlphabet[kTextDictionary[idx+i]] for i in range(ln))
r[i] = s
rinv[s] = i
return r, rinv
kTextDictionary_Ascii, kTextDictionary_AsciiBack = make_dict()
def decode_strings(get_byte):
p = 0x9c8000
result = []
while True:
org_p = p
#print('0x%x' % p)
s = ''
srcdata = []
while True:
c = get_byte(p)
srcdata.append(c)
l = kText_CommandLengths[c - 0x67] if c >= 0x67 and c < 0x80 else 1
p += l
if c == 0x7f:
break
if c < 0x67:
s += kTextAlphabet[c]
elif c < 0x80:
if l == 2:
srcdata.append(get_byte(p-1))
s += '[%s %.2d]' % (kText_CommandNames[c - 0x67], get_byte(p-1))
else:
s += '[%s]' % kText_CommandNames[c - 0x67]
elif c == 0x80:
p = 0x8edf40
s = None
break
elif c > 0x80 and c < 0x88:
assert 0
elif c == 0xff:
return result
else:
s += kTextDictionary_Ascii[c - 0x88]
if s != None:
result.append((s, srcdata))
def print_strings(f, get_byte):
for i, s in enumerate(decode_strings(get_byte)):
print('%s: %s' % (i + 1, s[0]), file = f)
def find_string_char_at(s, i):
a = s[i:]
for k, v in kTextDictionary_AsciiBack.items():
if a.startswith(k):
return [v + 0x88], len(k)
for i, s in enumerate(kTextAlphabet):
if a.startswith(s):
return [i], len(s)
if a.startswith('['):
cmd = a[1:a.index(']')]
if cmd in kText_CommandNames:
i = kText_CommandNames.index(cmd)
return [i + 0x67], len(cmd) + 2
for i, s in enumerate(kText_CommandNames):
if kText_CommandLengths[i] == 2 and cmd.startswith(s):
e = cmd[len(s):].strip()
return [i + 0x67, int(e)], len(cmd) + 2
print('substr %s not found' % a)
assert 0
def compress_string(s):
# find the greedy best match
i = 0
r = []
while i < len(s):
what, num = find_string_char_at(s, i)
r.extend(what)
i += num
r.append(0x7f)
return r
def verify(get_byte):
for i, (decoded, original) in enumerate(decode_strings(get_byte)):
c = compress_string(decoded)
if c != original:
print('String %s not match: %s, %s' % (decoded, c, original))
break
else:
pass

View File

@@ -1,4 +1,3 @@
/tcc/
/SDL2-2.24.0/
/SDL2-2.24.1/
/SDL2-2.*/
/gl_core/*.o

View File

@@ -15,6 +15,12 @@ ExtendedAspectRatio = 4:3
# display is set to exactly 60hz)
DisableFrameDelay = 0
# Set which language to use. Note. In order to use other languages you need to create
# the assets file appropriately.
# python restool.py --extract-dialogue -r german.sfc
# python restool.py --languages=de
# Language = de
[Graphics]
# Window size ( Auto or WidthxHeight )
WindowSize = Auto

View File

@@ -126,12 +126,14 @@
<LanguageStandard_C>stdc11</LanguageStandard_C>
<DisableSpecificWarnings>4244;4018;4996</DisableSpecificWarnings>
<TreatWarningAsError>true</TreatWarningAsError>
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalOptions>/PDBALTPATH:%_PDB% %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -143,6 +145,7 @@
<LanguageStandard_C>stdc11</LanguageStandard_C>
<DisableSpecificWarnings>4244;4018;4996</DisableSpecificWarnings>
<TreatWarningAsError>true</TreatWarningAsError>
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
@@ -151,6 +154,7 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalOptions>/PDBALTPATH:%_PDB% %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDeploy|Win32'">
@@ -162,6 +166,7 @@
<LanguageStandard_C>stdc11</LanguageStandard_C>
<DisableSpecificWarnings>4244;4018;4996</DisableSpecificWarnings>
<TreatWarningAsError>true</TreatWarningAsError>
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
@@ -171,6 +176,7 @@
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<AdditionalOptions>/PDBALTPATH:%_PDB% %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -181,9 +187,11 @@
<DisableSpecificWarnings>4244;4018;4996</DisableSpecificWarnings>
<TreatWarningAsError>true</TreatWarningAsError>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalOptions>/PDBALTPATH:%_PDB% %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -193,9 +201,12 @@
<DisableSpecificWarnings>4244;4018;4996</DisableSpecificWarnings>
<TreatWarningAsError>true</TreatWarningAsError>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalOptions>/PDBALTPATH:%_PDB% %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDeploy|x64'">
@@ -205,38 +216,36 @@
<DisableSpecificWarnings>4244;4018;4996</DisableSpecificWarnings>
<TreatWarningAsError>true</TreatWarningAsError>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<AdditionalOptions>/PDBALTPATH:%_PDB% %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="ancilla.c" />
<ClCompile Include="attract.c" />
<ClCompile Include="config.c" />
<ClCompile Include="dungeon.c" />
<ClCompile Include="ending.c" />
<ClCompile Include="glsl_shader.c" />
<ClCompile Include="hud.c" />
<ClCompile Include="load_gfx.c" />
<ClCompile Include="main.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Disabled</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='ReleaseDeploy|x64'">Disabled</Optimization>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
</ClCompile>
<ClCompile Include="messaging.c" />
<ClCompile Include="misc.c" />
<ClCompile Include="audio.c" />
<ClCompile Include="nmi.c" />
<ClCompile Include="overlord.c" />
<ClCompile Include="overworld.c" />
<ClCompile Include="platform\win32\volume_control.c" />
<ClCompile Include="player.c" />
<ClCompile Include="player_oam.c" />
<ClCompile Include="poly.c" />
<ClCompile Include="select_file.c" />
<ClCompile Include="opengl.c" />
<ClCompile Include="src\ancilla.c" />
<ClCompile Include="src\attract.c" />
<ClCompile Include="src\config.c" />
<ClCompile Include="src\dungeon.c" />
<ClCompile Include="src\ending.c" />
<ClCompile Include="src\glsl_shader.c" />
<ClCompile Include="src\hud.c" />
<ClCompile Include="src\load_gfx.c" />
<ClCompile Include="src\main.c" />
<ClCompile Include="src\messaging.c" />
<ClCompile Include="src\misc.c" />
<ClCompile Include="src\audio.c" />
<ClCompile Include="src\nmi.c" />
<ClCompile Include="src\overlord.c" />
<ClCompile Include="src\overworld.c" />
<ClCompile Include="src\platform\win32\volume_control.c" />
<ClCompile Include="src\player.c" />
<ClCompile Include="src\player_oam.c" />
<ClCompile Include="src\poly.c" />
<ClCompile Include="src\select_file.c" />
<ClCompile Include="src\opengl.c" />
<ClCompile Include="snes\apu.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
@@ -276,13 +285,10 @@
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
</ClCompile>
<ClCompile Include="snes\tracing.c" />
<ClCompile Include="spc_player.c" />
<ClCompile Include="sprite.c" />
<ClCompile Include="sprite_main.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='ReleaseDeploy|x64'">MaxSpeed</Optimization>
</ClCompile>
<ClCompile Include="tagalong.c" />
<ClCompile Include="src\spc_player.c" />
<ClCompile Include="src\sprite.c" />
<ClCompile Include="src\sprite_main.c" />
<ClCompile Include="src\tagalong.c" />
<ClCompile Include="third_party\gl_core\gl_core_3_1.c" />
<ClCompile Include="third_party\opus-1.3.1-stripped\bands.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
@@ -429,34 +435,34 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDeploy|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="tile_detect.c" />
<ClCompile Include="util.c" />
<ClCompile Include="zelda_cpu_infra.c" />
<ClCompile Include="zelda_rtl.c" />
<ClCompile Include="src\tile_detect.c" />
<ClCompile Include="src\util.c" />
<ClCompile Include="src\zelda_cpu_infra.c" />
<ClCompile Include="src\zelda_rtl.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="ancilla.h" />
<ClInclude Include="assets.h" />
<ClInclude Include="attract.h" />
<ClInclude Include="config.h" />
<ClInclude Include="dungeon.h" />
<ClInclude Include="ending.h" />
<ClInclude Include="features.h" />
<ClInclude Include="glsl_shader.h" />
<ClInclude Include="hud.h" />
<ClInclude Include="load_gfx.h" />
<ClInclude Include="messaging.h" />
<ClInclude Include="misc.h" />
<ClInclude Include="audio.h" />
<ClInclude Include="nmi.h" />
<ClInclude Include="overlord.h" />
<ClInclude Include="overworld.h" />
<ClInclude Include="platform\win32\volume_control.h" />
<ClInclude Include="player.h" />
<ClInclude Include="player_oam.h" />
<ClInclude Include="poly.h" />
<ClInclude Include="platform\win32\resource.h" />
<ClInclude Include="select_file.h" />
<ClInclude Include="src\ancilla.h" />
<ClInclude Include="src\assets.h" />
<ClInclude Include="src\attract.h" />
<ClInclude Include="src\config.h" />
<ClInclude Include="src\dungeon.h" />
<ClInclude Include="src\ending.h" />
<ClInclude Include="src\features.h" />
<ClInclude Include="src\glsl_shader.h" />
<ClInclude Include="src\hud.h" />
<ClInclude Include="src\load_gfx.h" />
<ClInclude Include="src\messaging.h" />
<ClInclude Include="src\misc.h" />
<ClInclude Include="src\audio.h" />
<ClInclude Include="src\nmi.h" />
<ClInclude Include="src\overlord.h" />
<ClInclude Include="src\overworld.h" />
<ClInclude Include="src\platform\win32\volume_control.h" />
<ClInclude Include="src\player.h" />
<ClInclude Include="src\player_oam.h" />
<ClInclude Include="src\poly.h" />
<ClInclude Include="src\platform\win32\resource.h" />
<ClInclude Include="src\select_file.h" />
<ClInclude Include="snes\apu.h" />
<ClInclude Include="snes\cart.h" />
<ClInclude Include="snes\cpu.h" />
@@ -470,10 +476,10 @@
<ClInclude Include="snes\snes_regs.h" />
<ClInclude Include="snes\spc.h" />
<ClInclude Include="snes\tracing.h" />
<ClInclude Include="spc_player.h" />
<ClInclude Include="sprite.h" />
<ClInclude Include="sprite_main.h" />
<ClInclude Include="tagalong.h" />
<ClInclude Include="src\spc_player.h" />
<ClInclude Include="src\sprite.h" />
<ClInclude Include="src\sprite_main.h" />
<ClInclude Include="src\tagalong.h" />
<ClInclude Include="third_party\gl_core\gl_core_3_1.h" />
<ClInclude Include="third_party\opus-1.3.1-stripped\arch.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
@@ -731,22 +737,22 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDeploy|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="tile_detect.h" />
<ClInclude Include="types.h" />
<ClInclude Include="util.h" />
<ClInclude Include="variables.h" />
<ClInclude Include="zelda_cpu_infra.h" />
<ClInclude Include="zelda_rtl.h" />
<ClInclude Include="src\tile_detect.h" />
<ClInclude Include="src\types.h" />
<ClInclude Include="src\util.h" />
<ClInclude Include="src\variables.h" />
<ClInclude Include="src\zelda_cpu_infra.h" />
<ClInclude Include="src\zelda_rtl.h" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="platform\win32\zelda3.rc" />
<ResourceCompile Include="src\platform\win32\zelda3.rc" />
</ItemGroup>
<ItemGroup>
<Image Include="platform\win32\triforce.ico" />
<Image Include="platform\linux\triforce.png" />
<Image Include="src\platform\win32\triforce.ico" />
<Image Include="src\platform\linux\triforce.png" />
</ItemGroup>
<ItemGroup>
<Content Include="LICENSE.txt">

View File

@@ -31,132 +31,12 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="snes\apu.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\cart.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\cpu.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\dma.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\dsp.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\input.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\ppu.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\snes.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\snes_other.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\spc.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="zelda_rtl.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="hud.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="dungeon.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="nmi.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="player_oam.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="load_gfx.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="messaging.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="overworld.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="sprite.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="sprite_main.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="tagalong.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="overlord.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="poly.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="ancilla.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="ending.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="attract.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="select_file.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="spc_player.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="player.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="tile_detect.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="misc.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="zelda_cpu_infra.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="config.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="platform\win32\volume_control.c">
<Filter>Platform</Filter>
</ClCompile>
<ClCompile Include="main.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="snes\tracing.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="opengl.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="glsl_shader.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="util.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="third_party\gl_core\gl_core_3_1.c">
<Filter>third_party</Filter>
</ClCompile>
<ClCompile Include="third_party\opus-1.3.1-stripped\opus_decoder_amalgam.c">
<Filter>third_party\Opus</Filter>
</ClCompile>
<ClCompile Include="audio.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="third_party\opus-1.3.1-stripped\bands.c">
<Filter>third_party\Opus</Filter>
</ClCompile>
@@ -211,8 +91,39 @@
<ClCompile Include="third_party\opus-1.3.1-stripped\x86\x86cpu.c">
<Filter>third_party\Opus</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClCompile Include="snes\apu.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\cart.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\cpu.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\dma.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\dsp.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\input.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\ppu.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\snes.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\snes_other.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\spc.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\tracing.c">
<Filter>Snes</Filter>
</ClCompile>
<ClInclude Include="snes\apu.h">
<Filter>Snes</Filter>
</ClInclude>
@@ -243,114 +154,107 @@
<ClInclude Include="snes\spc.h">
<Filter>Snes</Filter>
</ClInclude>
<ClInclude Include="zelda_rtl.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="hud.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="dungeon.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="nmi.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="load_gfx.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="overworld.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="variables.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="sprite.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="tagalong.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="overlord.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="poly.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="ancilla.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="ending.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="select_file.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="tile_detect.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="types.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="player.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="misc.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="player_oam.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="messaging.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="attract.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="zelda_cpu_infra.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="spc_player.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="sprite_main.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="snes\dsp_regs.h">
<Filter>Snes</Filter>
</ClInclude>
<ClInclude Include="platform\win32\resource.h">
<Filter>Resource Files</Filter>
</ClInclude>
<ClInclude Include="config.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="snes\snes_regs.h">
<Filter>Snes</Filter>
</ClInclude>
<ClInclude Include="platform\win32\volume_control.h">
<Filter>Platform</Filter>
</ClInclude>
<ClInclude Include="assets.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="features.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="snes\tracing.h">
<Filter>Snes</Filter>
</ClInclude>
<ClInclude Include="glsl_shader.h">
<ClCompile Include="src\ancilla.c">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="util.h">
</ClCompile>
<ClCompile Include="src\dungeon.c">
<Filter>Zelda</Filter>
</ClInclude>
</ClCompile>
<ClCompile Include="src\ending.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\glsl_shader.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\hud.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\load_gfx.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\main.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\messaging.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\misc.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\opengl.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\nmi.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\overworld.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\overlord.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\player.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\player_oam.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\poly.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\select_file.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\spc_player.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\sprite.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\sprite_main.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\tagalong.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\tile_detect.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\util.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\platform\win32\volume_control.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\zelda_cpu_infra.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\zelda_rtl.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\attract.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\audio.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="src\config.c">
<Filter>Zelda</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="third_party\gl_core\gl_core_3_1.h">
<Filter>third_party</Filter>
</ClInclude>
<ClInclude Include="audio.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="third_party\opus-1.3.1-stripped\_kiss_fft_guts.h">
<Filter>third_party\Opus</Filter>
</ClInclude>
@@ -447,23 +351,111 @@
<ClInclude Include="third_party\opus-1.3.1-stripped\x86\x86cpu.h">
<Filter>third_party\Opus</Filter>
</ClInclude>
<ClInclude Include="src\ancilla.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\assets.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\attract.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\audio.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\config.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\dungeon.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\ending.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\features.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\glsl_shader.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\hud.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\load_gfx.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\messaging.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\misc.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\nmi.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\overlord.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\overworld.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\player.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\player_oam.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\poly.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\platform\win32\resource.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\select_file.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\spc_player.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\sprite.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\sprite_main.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\tagalong.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\tile_detect.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\types.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\util.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\variables.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\platform\win32\volume_control.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\zelda_cpu_infra.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="src\zelda_rtl.h">
<Filter>Zelda</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Image Include="platform\win32\triforce.ico">
<Filter>Resource Files</Filter>
<Image Include="src\platform\win32\triforce.ico">
<Filter>Zelda</Filter>
</Image>
<Image Include="platform\linux\triforce.png">
<Filter>Resource Files</Filter>
<Image Include="src\platform\linux\triforce.png">
<Filter>Zelda</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="platform\win32\zelda3.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<Text Include="LICENSE.txt">
<Filter>Deploy</Filter>
@@ -481,6 +473,9 @@
<None Include="tables\zelda3_assets.dat">
<Filter>Deploy\tables</Filter>
</None>
<None Include="packages.config">
<Filter>Zelda</Filter>
</None>
</ItemGroup>
<ItemGroup>
<None Include="saves\ref\Chapter 1 - Zelda's Rescue.sav">
@@ -523,4 +518,9 @@
<Filter>Deploy\saverefs</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="src\platform\win32\zelda3.rc">
<Filter>Zelda</Filter>
</ResourceCompile>
</ItemGroup>
</Project>