mirror of
https://github.com/snesrev/zelda3.git
synced 2025-07-23 12:23:04 +02:00
542 lines
19 KiB
Python
542 lines
19 KiB
Python
from ast import literal_eval as make_tuple
|
|
import sys
|
|
import text_compression
|
|
import util
|
|
from util import get_bytes, get_words, get_byte, get_word, get_int8, get_int16, cache
|
|
import tables
|
|
import yaml
|
|
import extract_music
|
|
import os
|
|
import sprite_sheets
|
|
|
|
def print_map32_to_map16(f):
|
|
for i in range(2218):
|
|
def getit(ea):
|
|
ov = [get_byte(ea + j) for j in range(6)]
|
|
res=[0]*4
|
|
res[0] = ov[0] | (ov[4] >> 4) << 8
|
|
res[1] = ov[1] | (ov[4] & 0xf) << 8
|
|
res[2] = ov[2] | (ov[5] >> 4) << 8
|
|
res[3] = ov[3] | (ov[5] & 0xf) << 8
|
|
return res
|
|
t0 = getit(0x838000 + i * 6)
|
|
t1 = getit(0x83b400 + i * 6)
|
|
t2 = getit(0x848000 + i * 6)
|
|
t3 = getit(0x84b400 + i * 6)
|
|
for j in range(4):
|
|
print('%5d: %4d, %4d, %4d, %4d' % (i * 4 + j, t0[j], t1[j], t2[j], t3[j]), file = f)
|
|
|
|
@cache
|
|
def get_exit_datas():
|
|
r = {}
|
|
for i in range(79):
|
|
room = get_word(0x82dd8a + i * 2)
|
|
screen_index = get_byte(0x82DE28 + i)
|
|
load_offs = get_word(0x82DE77 + i * 2)
|
|
scroll_y = get_word(0x82DF15 + i * 2)
|
|
scroll_x = get_word(0x82DFB3 + i * 2)
|
|
pos_y = get_word(0x82E051 + i * 2)
|
|
pos_x = get_word(0x82E0EF + i * 2)
|
|
camera_y = get_word(0x82E18D + i * 2)
|
|
camera_x = get_word(0x82E22B + i * 2)
|
|
unk1 = get_int8(0x82E2C9 + i)
|
|
unk3 = get_int8(0x82E318 + i)
|
|
ndoor = get_word(0x82E367 + i * 2)
|
|
fdoor = get_word(0x82E405 + i * 2)
|
|
base_x = (screen_index & 7) << 9
|
|
base_y = (screen_index & 56) << 6
|
|
y = {
|
|
'index' : i,
|
|
'room' : room,
|
|
'xy' : [pos_x - base_x, pos_y - base_y],
|
|
'scroll_xy' : [scroll_x - base_x, scroll_y - base_y],
|
|
'camera_xy' : [camera_x - base_x, camera_y - base_y],
|
|
}
|
|
y['load_xy'] = [((load_offs >> 1) - (y['scroll_xy'][0] >> 4)) & 0x3f, (load_offs >> 7) - (y['scroll_xy'][1] >> 4) & 0x3f]
|
|
y['unk'] = [unk1, unk3]
|
|
def get_special_exit_info(room_index):
|
|
return {
|
|
'dir' : get_byte(0x82E801 + room_index - 0x180) >> 1,
|
|
'spr_gfx' : get_byte(0x82E811 + room_index - 0x180),
|
|
'aux_gfx' : get_byte(0x82E821 + room_index - 0x180),
|
|
'pal_bg' : get_byte(0x82E831 + room_index - 0x180),
|
|
'pal_spr' : get_byte(0x82E841 + room_index - 0x180),
|
|
'top' : get_word(0x82e6e1 + (room_index - 0x180) * 2),
|
|
'bottom' : get_word(0x82e701 + (room_index - 0x180) * 2),
|
|
'left' : get_word(0x82e721 + (room_index - 0x180) * 2),
|
|
'right' : get_word(0x82e741 + (room_index - 0x180) * 2),
|
|
'left_edge_of_map' : get_word(0x82E7E1 + (room_index - 0x180) * 2),
|
|
'unk4' : get_int16(0x82e761 + (room_index - 0x180) * 2),
|
|
'unk6' : get_int16(0x82e781 + (room_index - 0x180) * 2),
|
|
'unk5' : get_int16(0x82e7a1 + (room_index - 0x180) * 2),
|
|
'unk7' : get_int16(0x82e7c1 + (room_index - 0x180) * 2),
|
|
}
|
|
|
|
if room >= 0x180 and room < 0x190:
|
|
y['special_exit'] = get_special_exit_info(room)
|
|
|
|
if ndoor != 0:
|
|
assert fdoor == 0
|
|
y['door'] = ['bombable' if ndoor & 0x8000 else 'wooden', (ndoor & 0x7e) >> 1, (ndoor & 0x3f80) >> 7]
|
|
if fdoor != 0:
|
|
y['door'] = ['palace' if fdoor & 0x8000 else 'sanctuary', (fdoor & 0x7e) >> 1, (fdoor & 0x3f80) >> 7]
|
|
r.setdefault(screen_index, []).append(y)
|
|
return r
|
|
|
|
def get_loadoffs(c, d):
|
|
x, y = c[0] >> 4, c[1] >> 4
|
|
x += d[0]
|
|
y += d[1]
|
|
return (y&0x3f) << 7 | (x&0x3f) << 1
|
|
|
|
@cache
|
|
def get_ow_travel_infos():
|
|
r = {}
|
|
for i in range(17):
|
|
screen_index = get_word(0x82EAE5 + i * 2)
|
|
load_offs = get_word(0x82EB07 + i * 2)
|
|
scroll_y = get_word(0x82EB29 + i * 2)
|
|
scroll_x = get_word(0x82EB4B + i * 2)
|
|
pos_y = get_word(0x82EB6D + i * 2)
|
|
pos_x = get_word(0x82EB8F + i * 2)
|
|
camera_y = get_word(0x82EBB1 + i * 2)
|
|
camera_x = get_word(0x82EBD3 + i * 2)
|
|
unk1 = get_int8(0x82EBF5 + i * 2)
|
|
unk3 = get_int8(0x82EC17 + i * 2)
|
|
base_x = (screen_index & 7) << 9
|
|
base_y = (screen_index & 56) << 6
|
|
y = {}
|
|
if i < 9:
|
|
y['bird_travel_id'] = i
|
|
else:
|
|
y['whirlpool_src_area'] = get_word(0x82ECF8 + (i - 9) * 2)
|
|
y['xy'] = [pos_x - base_x, pos_y - base_y]
|
|
y['scroll_xy'] = [scroll_x - base_x, scroll_y - base_y]
|
|
y['camera_xy'] = [camera_x - base_x, camera_y - base_y]
|
|
y['load_xy'] = [((load_offs >> 1) - (y['scroll_xy'][0] >> 4)) & 0x3f, (load_offs >> 7) - (y['scroll_xy'][1] >> 4) & 0x3f]
|
|
|
|
t0 = get_loadoffs(y['scroll_xy'], y['load_xy'])
|
|
assert t0 == load_offs, (t0 & 0x7f, load_offs & 0x7f)
|
|
|
|
y['unk'] = [unk1, unk3]
|
|
r.setdefault(screen_index, []).append(y)
|
|
return r
|
|
|
|
@cache
|
|
def get_ow_entrance_info():
|
|
r = {}
|
|
for i in range(129):
|
|
area = get_word(0x9BB96F + i * 2)
|
|
pos = get_word(0x9BBA71 + i * 2)
|
|
entrance_id = get_byte(0x9BBB73 + i)
|
|
r.setdefault(area, []).append({'index' : i, 'x' : (pos >> 1) & 0x3f, 'y' : (pos >> 7) & 0x3f, 'entrance_id' : entrance_id})
|
|
return r
|
|
|
|
@cache
|
|
def get_hole_infos():
|
|
r = {}
|
|
for i in range(19):
|
|
pos = get_word(0x9BB800 + i * 2) + 0x400
|
|
area = get_word(0x9BB826 + i * 2)
|
|
entrance_id = get_byte(0x9BB84C + i)
|
|
r.setdefault(area, []).append({'x' : (pos >> 1) & 0x3f, 'y' : (pos >> 7) & 0x3f, 'entrance_id' : entrance_id})
|
|
return r
|
|
|
|
def print_overworld_area(overworld_area):
|
|
is_small = get_bytes(0x82F88D, 192)
|
|
y = {}
|
|
|
|
def get_music(ambient):
|
|
def fn(x):
|
|
if ambient:
|
|
return tables.kAmbientSoundName[x >> 4]
|
|
else:
|
|
return tables.kMusicNames[x & 0xf]
|
|
if overworld_area < 64:
|
|
return {
|
|
'beginning' : fn(get_byte(0x82C303 + overworld_area)),
|
|
'zelda' : fn(get_byte(0x82C303 + overworld_area + 64)),
|
|
'sword' : fn(get_byte(0x82C303 + overworld_area + 128)),
|
|
'agahnim' : fn(get_byte(0x82C303 + overworld_area + 192)),
|
|
}
|
|
else:
|
|
assert overworld_area < 64 + 96
|
|
return {'agahnim' : fn(get_byte(0x82C403 + overworld_area - 64)) }
|
|
|
|
def get_items():
|
|
if overworld_area >= 128: return []
|
|
ea = 0x9b0000 | get_word(0x9BC2F9 + overworld_area * 2)
|
|
xs = []
|
|
while get_word(ea) != 0xffff:
|
|
pos = get_word(ea)
|
|
assert pos%2==0
|
|
x, y = pos//2%64, pos//2//64
|
|
xs.append([x, y, tables.kSecretNames[get_byte(ea+2)]])
|
|
ea += 3
|
|
return xs
|
|
|
|
header = {
|
|
'name' : tables.kAreaNames[overworld_area],
|
|
'size' : 'small' if is_small[overworld_area] else 'big',
|
|
'gfx' : get_byte(0x80FC9C + overworld_area) if overworld_area < 128 else -1,
|
|
'palette' : get_byte(0x80FD1C + overworld_area) if overworld_area < 136 else -1,
|
|
'sign_text' : get_word(0x87F51D + overworld_area * 2) if overworld_area < 128 else -1,
|
|
'music' : get_music(False),
|
|
'ambient' : get_music(True),
|
|
}
|
|
|
|
y['Header'] = header
|
|
y['Travel'] = get_ow_travel_infos().get(overworld_area, [])
|
|
y['Entrances'] = get_ow_entrance_info().get(overworld_area, [])
|
|
hole_infos = get_hole_infos()
|
|
if overworld_area in hole_infos:
|
|
y['Holes'] = hole_infos[overworld_area]
|
|
y['Exits'] = get_exit_datas().get(overworld_area, [])
|
|
y['Items'] = get_items()
|
|
|
|
def decode_sprites(base_addr):
|
|
r = []
|
|
ea = 0x890000 + get_word(base_addr + overworld_area * 2)
|
|
while get_byte(ea) != 0xff:
|
|
y, x, w = get_byte(ea), get_byte(ea+1), get_byte(ea+2)
|
|
r.append([x, y, tables.kSpriteNames[w]])
|
|
ea += 3
|
|
return r
|
|
|
|
def get_info(stage):
|
|
if overworld_area >= 128: return {}
|
|
if overworld_area >= 64: stage = 3
|
|
return {
|
|
'gfx' : get_byte(0x80FA41 + (overworld_area & 63) + stage * 64),
|
|
'palette' : get_byte(0x80FB41 + (overworld_area & 63) + stage * 64),
|
|
}
|
|
if overworld_area < 64:
|
|
y['Sprites.Beginning'] = {
|
|
'info' : get_info(0),
|
|
'sprites' : decode_sprites(0x89C881)
|
|
}
|
|
y['Sprites.FirstPart'] = {
|
|
'info' : get_info(1),
|
|
'sprites' : decode_sprites(0x89C901)
|
|
}
|
|
y['Sprites.SecondPart'] = {
|
|
'info' : get_info(2),
|
|
'sprites' : decode_sprites(0x89CA21)
|
|
}
|
|
elif overworld_area < 144:
|
|
y['Sprites'] = {
|
|
'info' : get_info(2),
|
|
'sprites' : decode_sprites(0x89CA21)
|
|
}
|
|
|
|
s = yaml.dump(y, default_flow_style=None, sort_keys=False)
|
|
open('overworld/overworld-%d.yaml' % overworld_area, 'w').write(s)
|
|
|
|
def print_all_overworld_areas():
|
|
area_heads = get_bytes(0x82A5EC, 64)
|
|
|
|
for i in range(160):
|
|
if i >= 128 or area_heads[i&63] == (i&63):
|
|
print_overworld_area(i)
|
|
|
|
def print_dialogue():
|
|
text_compression.print_strings(util.ROM, file = open(text_compression.dialogue_filename(util.ROM.language), 'w', encoding='utf8'))
|
|
|
|
def decode_room_objects(p):
|
|
objs = []
|
|
j = 0
|
|
while True:
|
|
p0, p1, p2 = get_byte(p), get_byte(p+1), get_byte(p+2)
|
|
A = p0 | p1 << 8
|
|
if A == 0xffff:
|
|
return p + 2, objs, None
|
|
if A == 0xfff0:
|
|
p += 2
|
|
break
|
|
if (A & 0xfc) != 0xfc:
|
|
index = p2
|
|
Dst = (p1 >> 2) << 7
|
|
Dst |= (p0 & 0xfc) >> 1
|
|
X = (Dst >> 1) & 0x3f
|
|
Y = (Dst >> 7) & 0x3f
|
|
W = p0 & 3
|
|
H = p1 & 3
|
|
if index < 0xf8:
|
|
objs.append({'x' : X, 'y' : Y, 's' : '%d*%d' % (W, H), 'n': tables.kType0Names[index]})
|
|
else:
|
|
index2 = (index & 7) << 4 | H << 2 | W
|
|
objs.append({'x' : X, 'y' : Y, 'n': tables.kType1Names[index2]})
|
|
else:
|
|
# subtype 2: 111111xx xxxxyyyy yyiiiiii
|
|
X = ((p0 << 4 | p1 >> 4) & 0x3f)
|
|
Y = (p1 << 2 | p2 >> 6) & 0x3f
|
|
index = p2 & 0x3f
|
|
objs.append({'x' : X, 'y' : Y, 'n' : tables.kType2Names[index]})
|
|
p += 3
|
|
j += 1
|
|
|
|
doors = []
|
|
while True:
|
|
A = get_byte(p) | get_byte(p+1) << 8
|
|
if A == 0xffff:
|
|
return p + 2, objs, doors
|
|
doors.append({'type':get_byte(p + 1), 'pos' : get_byte(p) >> 4, 'dir' : A & 3})
|
|
p += 2
|
|
|
|
@cache
|
|
def get_chest_info():
|
|
ea = 0x81e96e
|
|
all = {}
|
|
for i in range(504//3):
|
|
room = get_word(ea + i * 3)
|
|
data = get_byte(ea + i * 3 + 2)
|
|
all.setdefault(room & 0x7fff, []).append((data, (room & 0x8000) != 0))
|
|
return all
|
|
|
|
def _get_entrance_info_one(i, set):
|
|
def get_exit_door(i):
|
|
x = get_word((0x82D724, 0x82DC32)[set] + i * 2)
|
|
if x == 0:
|
|
return ['none']
|
|
if x == 0xffff:
|
|
return ['none_0xffff']
|
|
return ['bombable' if x & 0x8000 else 'wooden', (x & 0x7e) >> 1, (x & 0x3f80) >> 7]
|
|
kQuadrantNames = { 0 : 'upper_left', 2 : 'lower_left', 16 : 'upper_right', 18 : 'lower_right' }
|
|
room = get_word((0x82C813, 0x82DB6E )[set] + i * 2)
|
|
def get_se(se_base_addr, xy, quds):
|
|
base_x = (room & 0xf) * 2
|
|
base_y = (room >> 4) * 2
|
|
ym = (xy[1] & 0x100) >> 8
|
|
xm = (xy[0] & 0x100) >> 8
|
|
#if room == 259: ym = 1 # possibly related to none_0xffff
|
|
hu = get_byte(se_base_addr + i * 8 + 0) - base_y - ym
|
|
fu = get_byte(se_base_addr + i * 8 + 1) - base_y
|
|
hd = get_byte(se_base_addr + i * 8 + 2) - base_y - ym
|
|
fd = get_byte(se_base_addr + i * 8 + 3) - base_y - 1
|
|
#assert fu == 0 and fd == 0 and hd == 0 and fd == 0, (room, fu, fd, hd, fd)
|
|
qqq = xm if room >= 242 and quds[0] == 'single_x' else 0
|
|
hl = get_byte(se_base_addr + i * 8 + 4) - base_x - xm
|
|
fl = get_byte(se_base_addr + i * 8 + 5) - base_x - qqq
|
|
hr = get_byte(se_base_addr + i * 8 + 6) - base_x - xm
|
|
fr = get_byte(se_base_addr + i * 8 + 7) - base_x - 1 - qqq
|
|
return [hu, fu, hd, fd, hl, fl, hr, fr]#
|
|
|
|
player_x = get_word((0x82D063, 0x82DBDE)[set] + i * 2) - ((room & 0x00f) << 9)
|
|
player_y = get_word((0x82CF59, 0x82DBD0)[set] + i * 2) - ((room & 0x1f0) << 5)
|
|
|
|
y = {
|
|
('entrance_index' if set == 0 else 'starting_point_index'): i,
|
|
'name' : tables.kEntranceNames[i] if set == 0 else 'Starting Location %d' % i,
|
|
'scroll_xy' : [
|
|
get_word((0x82CD45, 0x82DBB4)[set] + i * 2) - ((room & 0x00f) << 9),
|
|
get_word((0x82CE4F, 0x82DBC2)[set] + i * 2) - ((room & 0x1f0) << 5),
|
|
],
|
|
'player_xy' : [ player_x, player_y ],
|
|
'camera_xy' : [
|
|
get_word((0x82D277, 0x82DBFA)[set] + i * 2),
|
|
get_word((0x82D16D, 0x82DBEC)[set] + i * 2),
|
|
],
|
|
'blockset' : get_byte((0x82D381, 0x82DC08)[set] + i),
|
|
'music' : tables.kMusicNames[get_byte((0x82D82E, 0x82DC4E)[set] + i)],
|
|
'palace' : tables.kPalaceNames[(get_int8((0x82D48B, 0x82DC16)[set] + i) + 2) >> 1],
|
|
'doorway_orientation' : get_int8(0x82D510 + i) if set == 0 else 0,
|
|
'plane' : get_byte((0x82D595, 0x82DC1D)[set] + i) & 0xf,
|
|
'ladder_level' : get_byte((0x82D595, 0x82DC1D)[set] + i) >> 4,
|
|
'quadrants' : [
|
|
'double_x' if (get_byte((0x82D61a, 0x82DC24)[set] + i) & 0x20) != 0 else 'single_x',
|
|
'double_y' if (get_byte((0x82D61a, 0x82DC24)[set] + i) & 0x2) else 'single_y',
|
|
kQuadrantNames[get_byte((0x82D69F, 0x82DC2B)[set] + i)]
|
|
],
|
|
'floor' : get_int8((0x82D406, 0x82DC0F)[set] + i),
|
|
}
|
|
|
|
se = get_se((0x82C91D, 0x82DB7C)[set], y['player_xy'], y['quadrants'])
|
|
if se != [0, 0, 0, 0, 0, 0, 0, 0]:
|
|
y['repair_scroll_bounds'] = se
|
|
y['house_exit_door'] = get_exit_door(i)
|
|
|
|
# quadrant_byte = (2 if player_y & 0x100 else 0) + (16 if player_x & 0x100 else 0)
|
|
# if get_byte((0x82D69F, 0x82DC2B)[set] + i) != quadrant_byte:
|
|
# print('Room %d has incorrect quadrant byte' % room, y['quadrants'])
|
|
if set:
|
|
y['associated_entrance_index'] = get_word(0x82DC40 + i * 2)
|
|
return room, y
|
|
|
|
@cache
|
|
def get_entrance_info(set):
|
|
r = {}
|
|
for i in range(133 if set == 0 else 7):
|
|
room, y = _get_entrance_info_one(i, set)
|
|
r.setdefault(room, []).append(y)
|
|
return r
|
|
|
|
@cache
|
|
def pits_hurt_player():
|
|
return set(get_word(0x80990C + i * 2) for i in range(57))
|
|
|
|
def print_room(room_index):
|
|
p = 0x1f8000 + room_index * 3
|
|
room_addr = get_byte(p) | get_byte(p+1) << 8 | get_byte(p+2) << 16
|
|
p = 0x40000 | get_word(0x4f502 + room_index * 2)
|
|
if p == 0x4FFEF:
|
|
p = 0x82EDC5 # just some place with zeros
|
|
floor, layout = get_byte(room_addr), get_byte(room_addr + 1)
|
|
|
|
flags = get_byte(p + 0)
|
|
p7, p8 = get_byte(p + 7), get_byte(p + 8)
|
|
|
|
ea = 0x890000 + get_word(0x89D62E + room_index * 2)
|
|
sort_sprites_setting = get_byte(ea)
|
|
|
|
header = {
|
|
'floor1': floor & 0xf,
|
|
'floor2' : floor >> 4,
|
|
'layout': layout >> 2,
|
|
'start_quadrant' : layout & 3,
|
|
'bg2' : tables.kBg2[flags >> 5],
|
|
'collision' : tables.kCollisionNames[flags >> 2 & 7],
|
|
'lights_out' : flags & 1,
|
|
'palette' : get_byte(p + 1),
|
|
'blockset' : get_byte(p + 2),
|
|
'enemyblk' : get_byte(p + 3),
|
|
'effect' : tables.kEffectNames[get_byte(p + 4)],
|
|
'tag0' : tables.kTagNames[get_byte(p + 5)],
|
|
'tag1' : tables.kTagNames[get_byte(p + 6)],
|
|
'hole0_dest' : [get_byte(p+9), p7 & 3],
|
|
'stair0_dest' : [get_byte(p+10), p7 >> 2 & 3],
|
|
'stair1_dest' : [get_byte(p+11), p7 >> 4 & 3],
|
|
'stair2_dest' : [get_byte(p+12), p7 >> 6 & 3],
|
|
'stair3_dest' : [get_byte(p+13),p8 & 3],
|
|
'tele_msg' : get_word(0x87F61D+room_index*2),
|
|
'sort_sprites' : sort_sprites_setting,
|
|
'pits_hurt_player' : room_index in pits_hurt_player()
|
|
}
|
|
|
|
def get_sprites():
|
|
ea = 0x890000 + get_word(0x89D62E + room_index * 2)
|
|
ea += 1
|
|
r = []
|
|
while get_byte(ea) != 0xff:
|
|
y, x, type = get_byte(ea), get_byte(ea+1), get_byte(ea+2)
|
|
if type == 0xe4:
|
|
if y == 0xfe or y == 0xfd:
|
|
r[-1].append('drop_key' if y == 0xfe else 'drop_big_key')
|
|
ea += 3
|
|
continue
|
|
elif x >= 0xe0:
|
|
floor = y >> 7
|
|
r.append([x & 0x1f, y & 0x1f, 'lower' if floor else 'upper', tables.kSpriteNames[type + 0x100]])
|
|
ea += 3
|
|
continue
|
|
subtype = (x >> 5) | ((y >> 5) & 3) << 3
|
|
floor = y >> 7
|
|
name = tables.kSpriteNames[type]
|
|
if subtype != 0:
|
|
i = name.index('-')
|
|
name = name[:i] + ('.%d' % subtype) + name[i:]
|
|
r.append([x & 0x1f, y & 0x1f, 'lower' if floor else 'upper', name])
|
|
ea += 3
|
|
return r
|
|
|
|
def get_secrets():
|
|
ea = 0x810000 | get_word(0x81db69 + room_index * 2)
|
|
xs = []
|
|
while get_word(ea) != 0xffff:
|
|
pos = get_word(ea)
|
|
assert pos%2==0
|
|
x, y = pos//2%64, pos//2//64
|
|
xs.append([x, y, tables.kSecretNames[get_byte(ea+2)]])
|
|
ea += 3
|
|
return xs
|
|
|
|
def get_chests():
|
|
r = []
|
|
for data, big in get_chest_info().get(room_index, []):
|
|
if big:
|
|
r.append('%d!' % data)
|
|
else:
|
|
r.append(data)
|
|
return r
|
|
|
|
sprites = get_sprites()
|
|
secrets = get_secrets()
|
|
|
|
data = {'Header' : header, 'Sprites' : sprites, 'Secrets' : secrets, 'Chests' : get_chests()}
|
|
data['Entrances'] = get_entrance_info(0).get(room_index, [])
|
|
if room_index in get_entrance_info(1):
|
|
data['StartingPoints'] = get_entrance_info(1)[room_index]
|
|
|
|
p = room_addr + 2
|
|
p, objs, doors = decode_room_objects(p)
|
|
data['Layer1'] = objs
|
|
if doors: data['Layer1.doors'] = doors
|
|
|
|
p, objs, doors = decode_room_objects(p)
|
|
data['Layer2'] = objs
|
|
if doors: data['Layer2.doors'] = doors
|
|
|
|
p, objs, doors = decode_room_objects(p)
|
|
data['Layer3'] = objs
|
|
if doors: data['Layer3.doors'] = doors
|
|
|
|
return yaml.dump(data, default_flow_style=None, sort_keys=False)
|
|
|
|
def print_all_dungeon_rooms():
|
|
for i in range(320):
|
|
s = print_room(i)
|
|
open( 'dungeon/dungeon-%d.yaml' % i, 'w').write(s)
|
|
|
|
def print_default_rooms():
|
|
def print_default_room(idx):
|
|
p = 0x84EF2F + idx * 3
|
|
room_addr = get_byte(p) | get_byte(p+1) << 8 | get_byte(p+2) << 16
|
|
p, objs, doors = decode_room_objects(room_addr)
|
|
assert doors == None
|
|
return objs
|
|
default_rooms = {}
|
|
for i in range(8):
|
|
default_rooms['Default%d' % i] = print_default_room(i)
|
|
s = yaml.dump(default_rooms, default_flow_style=None, sort_keys=False)
|
|
open('dungeon/default_rooms.yaml', 'w').write(s)
|
|
|
|
def print_overlay_rooms():
|
|
def print_overlay_room(idx):
|
|
p = 0x84ECC0 + idx * 3
|
|
room_addr = get_byte(p) | get_byte(p+1) << 8 | get_byte(p+2) << 16
|
|
p, objs, doors = decode_room_objects(room_addr)
|
|
assert doors == None
|
|
return objs
|
|
default_rooms = {}
|
|
for i in range(19):
|
|
default_rooms['Overlay%d' % i] = print_overlay_room(i)
|
|
s = yaml.dump(default_rooms, default_flow_style=None, sort_keys=False)
|
|
open('dungeon/overlay_rooms.yaml', 'w').write(s)
|
|
|
|
def make_directories():
|
|
os.makedirs('img', exist_ok=True)
|
|
os.makedirs('overworld', exist_ok=True)
|
|
os.makedirs('dungeon', exist_ok=True)
|
|
os.makedirs('sound', exist_ok=True)
|
|
|
|
def print_all_text_stuff():
|
|
print_all_overworld_areas()
|
|
print_all_dungeon_rooms()
|
|
print_overlay_rooms()
|
|
print_default_rooms()
|
|
print_dialogue()
|
|
print_map32_to_map16(open('map32_to_map16.txt', 'w'))
|
|
|
|
def main():
|
|
make_directories()
|
|
print_all_text_stuff()
|
|
extract_music.extract_sound_data(util.ROM)
|
|
sprite_sheets.decode_link_sprites()
|
|
sprite_sheets.decode_sprite_sheets()
|
|
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()
|
|
|