mirror of https://github.com/snesrev/smw.git
906 lines
34 KiB
Python
906 lines
34 KiB
Python
import sys, array, hashlib, struct, argparse, os
|
|
import util
|
|
from util import cache, get_byte, get_word, get_24, get_bytes, get_words
|
|
|
|
def flatten(xss):
|
|
return [x for xs in xss for x in xs]
|
|
|
|
def invert_dict(xs):
|
|
return {s:i for i,s in xs.items()}
|
|
|
|
assets = {}
|
|
|
|
def add_asset_uint8(name, data):
|
|
assert name not in assets
|
|
assets[name] = ('uint8', bytes(array.array('B', data)))
|
|
|
|
def add_asset_uint16(name, data):
|
|
assert name not in assets
|
|
assets[name] = ('uint16', bytes(array.array('H', data)))
|
|
|
|
def add_asset_int8(name, data):
|
|
assert name not in assets
|
|
assets[name] = ('int8', bytes(array.array('b', data)))
|
|
|
|
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 add_asset_blob(name, data):
|
|
assert name not in assets
|
|
assets[name] = ('blob', pack_blob(data))
|
|
|
|
def pack_24(v):
|
|
assert v >= 0 and v < (1 << 24)
|
|
return struct.pack('I', v)[:3]
|
|
|
|
# Pack arrays and determine automatically the index size
|
|
def pack_arrays(arr):
|
|
if len(arr) == 0:
|
|
return b''
|
|
backmap, fstmap = {}, []
|
|
all_offs, offs = [], 0
|
|
saved = 0
|
|
for i, v in enumerate(arr):
|
|
v = bytes(v)
|
|
k = backmap.get(v)
|
|
if k == None:
|
|
k = len(all_offs)
|
|
backmap[v] = k
|
|
offs += len(v)
|
|
all_offs.append(offs)
|
|
else:
|
|
saved += len(v)
|
|
fstmap.append(k)
|
|
assert len(arr) <= 4096
|
|
del all_offs[-1]
|
|
flags = len(arr) - 1
|
|
if len(all_offs) == 0 or all_offs[-1] < 65536:
|
|
r = [struct.pack('H', i) for i in all_offs] + list(backmap.keys())
|
|
flags |= 0x8000
|
|
else:
|
|
r = [struct.pack('I', i) for i in all_offs] + list(backmap.keys())
|
|
if len(backmap) != len(arr):
|
|
if len(all_offs) <= 255:
|
|
r.append(array.array('B', fstmap).tobytes())
|
|
else:
|
|
r.append(array.array('H', fstmap).tobytes())
|
|
r.append(struct.pack('H', len(all_offs)))
|
|
flags |= 0x4000
|
|
r.append(struct.pack('H', flags))
|
|
return b''.join(r)
|
|
|
|
def pack_blob(ranges):
|
|
out = []
|
|
for a, b in sorted(ranges):
|
|
if len(out) and a <= out[-1][1]:
|
|
# continue existing range
|
|
if b > out[-1][1]:
|
|
out[-1] = (out[-1][0], b)
|
|
else:
|
|
out.append((a, b))
|
|
off = 2 + len(out) * 6
|
|
a_arr, b_arr, r_arr = [], [], []
|
|
for a, b in out:
|
|
a_arr.append(pack_24(a))
|
|
b_arr.append(pack_24(off))
|
|
r_arr.append(util.get_bytes(a, b - a))
|
|
off += b - a
|
|
return struct.pack('H', len(out)) + b''.join(a_arr) + b''.join(b_arr) + b''.join(r_arr)
|
|
|
|
def get_stripe_len(ea):
|
|
ea_org = ea
|
|
while True:
|
|
b = util.get_byte(ea)
|
|
if b & 0x80:
|
|
return ea + 1 - ea_org
|
|
p1 = util.get_byte(ea + 1)
|
|
p2 = util.get_byte(ea + 2)
|
|
p3 = util.get_byte(ea + 3)
|
|
ea += 4
|
|
if p2 & 0x40:
|
|
ea += 2
|
|
else:
|
|
ll = ((p2 << 8 | p3) & 0x3fff) + 1
|
|
ea += ll
|
|
|
|
def get_rats_size(p):
|
|
if p == 0: return 0
|
|
p -= 8
|
|
if (p & 0x8000) == 0:
|
|
p -= 0x8000
|
|
assert util.get_bytes(p, 4) == b'STAR', hex(p)
|
|
return get_word(p + 4) + 1
|
|
|
|
def get_rats_bytes(p):
|
|
return get_bytes(p, get_rats_size(p))
|
|
|
|
@cache
|
|
def unpack_rle(ea):
|
|
ea_org = ea
|
|
r = bytearray()
|
|
while util.get_word(ea) != 0xffff:
|
|
x = util.get_byte(ea); ea += 1
|
|
if x & 0x80:
|
|
y = util.get_byte(ea); ea += 1
|
|
for i in range((x & 0x7f) + 1):
|
|
r.append(y)
|
|
else:
|
|
for i in range((x & 0x7f) + 1):
|
|
y = util.get_byte(ea); ea += 1
|
|
r.append(y)
|
|
return bytes(r), ea + 2 - ea_org
|
|
|
|
def unpack_rle_of_size(ea, size):
|
|
ea_org = ea
|
|
r = bytearray()
|
|
while len(r) < size:
|
|
x = util.get_byte(ea); ea += 1
|
|
if x & 0x80:
|
|
y = util.get_byte(ea); ea += 1
|
|
for i in range((x & 0x7f) + 1):
|
|
r.append(y)
|
|
else:
|
|
for i in range((x & 0x7f) + 1):
|
|
y = util.get_byte(ea); ea += 1
|
|
r.append(y)
|
|
return bytes(r), ea - ea_org
|
|
|
|
|
|
@cache
|
|
def calc_level_len(ea, dbg = False):
|
|
if dbg: print('Now decoding level at 0x%x' % ea)
|
|
ea_org = ea
|
|
ea += 5
|
|
|
|
kObjNames = {
|
|
60 : 'StoneBlock',
|
|
13 : 'CementBlock',
|
|
0x22: 'LmMap16',
|
|
}
|
|
|
|
while True:
|
|
b0 = util.get_byte(ea); ea += 1
|
|
if b0 == 0xff:
|
|
break
|
|
b1 = util.get_byte(ea); ea += 1
|
|
b2 = util.get_byte(ea); ea += 1
|
|
|
|
obj_id = (b1 >> 4) | ((b0 & 0x60) >> 1)
|
|
blocks_size_or_type = b2
|
|
|
|
if dbg:
|
|
print(' %.2X %.2X %.2X: 0x%x, 0x%x, %d: %s' % (b0, b1, b2, ea-3, obj_id, blocks_size_or_type, kObjNames.get(obj_id)))
|
|
|
|
if obj_id == 0 and blocks_size_or_type == 0:
|
|
ea += 1
|
|
elif obj_id in (0x22, 0x23): # lunar magic
|
|
ea += 1
|
|
elif obj_id in (0x24, 0x25): # lunar deprecated
|
|
ea += 0
|
|
elif obj_id in (0x27, ):
|
|
ea += 2
|
|
return ea - ea_org
|
|
|
|
LUNAR_MAGIC = get_bytes(0xFF0A0, 5) == b'Lunar'
|
|
|
|
def extra_lunar_magic_text():
|
|
return '\n\nDo the following steps:\n1) Use Lunar Magic 3.33.\n' + \
|
|
'2) Open up a level, modify something, save it.\n' + \
|
|
'3) Open up the 16x16 tile map editor, edit something, save it.\n' + \
|
|
'4) Open up the Exanim editor for some level. Edit something, save.\n'
|
|
|
|
|
|
if LUNAR_MAGIC:
|
|
s = get_bytes(0xFF0A0, 24).decode('utf8')
|
|
print('Detected %s' % s, file = sys.stderr)
|
|
if s != 'Lunar Magic Version 3.33':
|
|
raise Exception('Invalid Lunar Magic version. Expected 3.33, found "%s"\n' % s + extra_lunar_magic_text())
|
|
|
|
if get_byte(0x6F540) != 0xc9:
|
|
raise Exception('The map16 file format is incorrect. ' + extra_lunar_magic_text())
|
|
|
|
|
|
def get_comp_data(ea):
|
|
data, comp_len = util.decomp(ea, util.get_byte, return_length = True)
|
|
return util.get_bytes(ea, comp_len)
|
|
|
|
def decomp_data(ea):
|
|
data, comp_len = util.decomp(ea, util.get_byte, return_length = True)
|
|
return data
|
|
|
|
|
|
kLmFeature_LmEnabled = 1 << 0
|
|
kLmFeature_Exanim = 1 << 1
|
|
kLmFeature_SkipOverworldDecompress = 1 << 2
|
|
kLmFeature_OverworldTiles4bpp = 1 << 3
|
|
kLmFeature_Copy512colors = 1 << 4
|
|
kLmFeature_WeirdPalette = 1 << 5
|
|
kLmFeature_SkipLoadPaletteHook = 1 << 6
|
|
kLmFeature_GfxUpload = 1 << 7
|
|
kLmFeature_LoadLevel = 1 << 8
|
|
kLmFeature_4bppgfx = 1 << 9
|
|
kLmFeature_CustomTitleScreenDemo = 1 << 10
|
|
kLmFeature_CustomDisplayMessage = 1 << 11
|
|
kLmFeature_DontSetYposForIntroMarch = 1 << 12
|
|
kLmFeature_OwPalette = 1 << 13
|
|
kLmFeature_LevelNamesPatch = 1 << 14
|
|
kLmFeature_DestroyTileAnims = 1 << 15
|
|
kLmFeature_EventStuff = 1 << 16
|
|
kLmFeature_MusicRegTweak = 1 << 17
|
|
kLmFeature_TideWaterTweak = 1 << 18
|
|
kLmFeature_EnemyCollTweak = 1 << 19
|
|
kLmFeature_Ow4bppGfx = 1 << 20
|
|
kLmFeature_DontResetOwPlayersMap = 1 << 21
|
|
kLmFeature_NonStdGfxAA8D = 1 << 22
|
|
kLmFeature_TimerTweaks = 1 << 23
|
|
kLmFeature_NoDefaultSavePrompts = 1 << 24
|
|
|
|
kHack_Walljump = 1 << 0
|
|
|
|
class LmFeatures:
|
|
flags = 0
|
|
kLmLvlInfo_addr = 0
|
|
kLmLvlInfo_addr_other = 0
|
|
hacks = 0
|
|
|
|
def serialize(self):
|
|
return struct.pack('IIII', self.flags, self.kLmLvlInfo_addr, self.kLmLvlInfo_addr_other, self.hacks)
|
|
|
|
def print_all(args):
|
|
lm_feat = LmFeatures()
|
|
r = []
|
|
lo, hi, bank = util.get_bytes(0xB992, 50), util.get_bytes(0xB9c4, 50), util.get_bytes(0xB9f6, 50)
|
|
for i in range(50):
|
|
p = bank[i] << 16 | hi[i] << 8 | lo[i]
|
|
r.append(get_comp_data(p))
|
|
add_asset_packed('kGraphicsPtrs', r)
|
|
|
|
data, comp_len = util.decomp(0x80000 | util.get_word(0xB8D8), util.get_byte, return_length = True)
|
|
#print('%d: %d: %d' % (0x32, comp_len, len(data)))
|
|
add_asset_uint8('kGfx32', data)
|
|
|
|
data, comp_len = util.decomp(0x80000 | util.get_word(0xB88B), util.get_byte, return_length = True)
|
|
#print('%d: %d: %d' % (0x33, comp_len, len(data)))
|
|
add_asset_uint8('kGfx33', data)
|
|
|
|
r = [b'']
|
|
for i in range(1, 86):
|
|
p = util.get_24(0x84D0 + i * 3)
|
|
pl = get_stripe_len(p)
|
|
#if i == 1:
|
|
#print(util.get_bytes(p, 16))
|
|
r.append(util.get_bytes(p, pl))
|
|
add_asset_packed('kLoadStripeImagePtrs', r)
|
|
|
|
r = []
|
|
for i in range(45):
|
|
p = util.get_24(0x59000 + i * 3)
|
|
pl = get_stripe_len(p)
|
|
r.append(util.get_bytes(p, pl))
|
|
add_asset_packed('kLayer3ImagePtrs', r)
|
|
|
|
add_asset_uint8('kSpcCreditsMusicBank', util.get_bytes(0x3e400, 6624))
|
|
add_asset_uint8('kSpcLevelMusicBank', util.get_bytes(0xEAED6, 16899))
|
|
add_asset_uint8('kSpcEngine', util.get_bytes(0xe8000, 6321) + b'\x00\x00')
|
|
add_asset_uint8('kSpcSamples', util.get_bytes(0xf8000, 28538))
|
|
add_asset_uint8('kSpcOverworldMusicBank', util.get_bytes(0xe98b1, 5667))
|
|
|
|
add_asset_uint16('kMap16Data_OverworldLayer1', util.get_words(0x05d000, 772))
|
|
|
|
add_asset_uint16('kMap16Data', util.get_words(0xd8000, (0xA100 - 0x8000) // 2))
|
|
add_asset_uint16('kMap16Data_Castle', util.get_words(0xdbc00, 712))
|
|
add_asset_uint16('kMap16Data_Rope', util.get_words(0xdc800, 712))
|
|
add_asset_uint16('kMap16Data_Underground', util.get_words(0xdd400, 712))
|
|
add_asset_uint16('kMap16Data_GhostHouse', util.get_words(0xde300, 712))
|
|
|
|
add_asset_uint16('kGlobalPalettes_Sky', util.get_words(0x00B0A0, 16))
|
|
add_asset_uint16('kGlobalPalettes_Background', util.get_words(0x00B0B0, 96))
|
|
add_asset_uint16('kGlobalPalettes_Layer3', util.get_words(0xB170, 16))
|
|
add_asset_uint16('kGlobalPalettes_Foreground', util.get_words(0x00B190, 96))
|
|
add_asset_uint16('kGlobalPalettes_Objects', util.get_words(0x00B250, 60))
|
|
add_asset_uint16('kPlayerPalettes', util.get_words(0x00B2C8, 40))
|
|
add_asset_uint16('kGlobalPalettes_Sprites', util.get_words(0x00B318, 84))
|
|
add_asset_uint16('kGlobalPalettes_YoshiBerry', util.get_words(0x00B674, 21))
|
|
add_asset_uint16('kGlobalPalettes_Flashing', util.get_words(0x00B60C, 16))
|
|
|
|
add_asset_uint16('kGlobalPalettes_OW_Objects', util.get_words(0xB528, 42))
|
|
add_asset_uint16('kGlobalPalettes_OW_Sprites', util.get_words(0xB57C, 56))
|
|
add_asset_uint16('kGlobalPalettes_B5EC', util.get_words(0xB5EC, 16))
|
|
add_asset_uint16('kGlobalPalettes_OW_Areas', util.get_words(0xB3D8, 168))
|
|
add_asset_uint16('kGlobalPalettes_OW_AreasPassed', util.get_words(0xB732, 168))
|
|
add_asset_uint16('kGlobalPalettes_Bowser', util.get_words(0xB69E, 56))
|
|
add_asset_uint16('kGlobalPalettes_Layer3Smasher', util.get_words(0xB66C, 4))
|
|
#add_asset_uint16('', util.get_words(0x, ))
|
|
|
|
|
|
add_asset_uint8('kGameMode1B_EndingCinema_Tilemaps', util.get_bytes(0xC95C7, 1873))
|
|
add_asset_uint16('kGameMode1B_EndingCinema_RowPointers', util.get_words(0xC9D18, 202))
|
|
|
|
add_asset_uint8('kLevelInfo_05F000', util.get_bytes(0x5f000, 0x200))
|
|
add_asset_uint8('kLevelInfo_05F200', util.get_bytes(0x5f200, 0x200))
|
|
add_asset_uint8('kLevelInfo_05F400', util.get_bytes(0x5f400, 0x200))
|
|
add_asset_uint8('kLevelInfo_05F600', util.get_bytes(0x5f600, 0x200))
|
|
|
|
add_asset_uint8('kLoadLevel_DATA_05D608', util.get_bytes(0x5D608, 0x100))
|
|
|
|
add_asset_uint8('kDisplayMessage_DATA_05A5D9', util.get_bytes(0x5A5D9, 2854))
|
|
|
|
add_asset_uint8('kOverworldLightningAndRandomCloudSpawning', util.get_bytes(0x4F708, 128))
|
|
|
|
add_asset_uint16('kLevelNames', util.get_words(0x4A0FC, 256))
|
|
|
|
add_asset_uint8('kLineGuideSpeedTableData', util.get_bytes(0x7F9DB, 536))
|
|
|
|
def add_packed_levels(name, addr, num, bank = None):
|
|
r = []
|
|
for i in range(num):
|
|
try:
|
|
if bank == None:
|
|
ea = util.get_24(addr + i * 3)
|
|
else:
|
|
ea = util.get_word(addr + i * 2) | bank << 16
|
|
ln = calc_level_len(ea)
|
|
r.append(util.get_bytes(ea, ln))
|
|
except:
|
|
print('\n*** Crashed while decoding level 0x%x at 0x%x ***' % (i, ea), file = sys.stderr)
|
|
print('*** Try opening it in LM and then saving it ***', file = sys.stderr)
|
|
|
|
add_asset_packed(name, r)
|
|
|
|
add_packed_levels('kLevelData_Layer1', 0x5E000, 0x200)
|
|
add_packed_levels('kEntranceData_Layer1', 0x5d766, 6)
|
|
add_packed_levels('kChoclateIsland2_Layer1', 0x5DB08, 9, bank = 6)
|
|
add_packed_levels('kRollCallData_Layer1', 0xCAD58, 13, bank = 0xc)
|
|
|
|
|
|
def add_packed_level_bg(name, addr, num, mode = None):
|
|
r = []
|
|
fls = []
|
|
for i in range(num):
|
|
if mode == None:
|
|
ea = util.get_24(addr + i * 3)
|
|
elif mode == 'choc':
|
|
ea = util.get_word(addr + i * 2) | 0xff0000
|
|
elif mode == 'end':
|
|
ea = util.get_word(addr + i * 2) | (0xff0000 if i != 12 else 0xc0000)
|
|
else:
|
|
assert 0
|
|
|
|
fl = util.get_byte(0xEF310 + i) if num == 0x200 and LUNAR_MAGIC else 0
|
|
if (ea & 0xff0000) == 0xff0000:
|
|
ea = (ea & 0xffff) | 0xc0000
|
|
fl = ((ea & 0xffff) >= 0xE8FE) << 4 | 2
|
|
fls.append(fl)
|
|
|
|
if fl & 2:
|
|
packed, ln = unpack_rle(ea)
|
|
else:
|
|
ln = calc_level_len(ea)
|
|
|
|
r.append(util.get_bytes(ea, ln))
|
|
add_asset_packed(name, r)
|
|
add_asset_uint8(name + '_IsBg', fls)
|
|
|
|
add_packed_level_bg('kLevelData_Layer2', 0x5E600, 0x200)
|
|
add_packed_level_bg('kEntranceData_Layer2', 0x5d778, 6)
|
|
add_packed_level_bg('kChoclateIsland2_Layer2', 0x5DB2C, 9, mode = 'choc')
|
|
add_packed_level_bg('kRollCallData_Layer2', 0xCAD72, 13, mode = 'end')
|
|
add_packed_level_bg('kBufferCreditsBackgrounds_Layer2', 0xc93c1, 7, mode = 'choc')
|
|
|
|
def get_sprite_data_len(ea):
|
|
ea_org = ea
|
|
ea += 1
|
|
while util.get_byte(ea) != 0xff:
|
|
ea += 3
|
|
return ea + 1 - ea_org
|
|
|
|
def remove_trail_zero(s):
|
|
lx = len(s)
|
|
while lx and s[lx - 1] == 0:
|
|
lx -= 1
|
|
return s[:lx]
|
|
|
|
def remove_trail_empty(s):
|
|
lx = len(s)
|
|
while lx and len(s[lx - 1]) == 0:
|
|
lx -= 1
|
|
return s[:lx]
|
|
|
|
def add_sprites():
|
|
spr_ranges = []
|
|
def touch(ea):
|
|
lx = get_sprite_data_len(ea)
|
|
spr_ranges.append((ea, ea + lx))
|
|
|
|
banks = util.get_bytes(0xef100, 512) if get_byte(0x05D8F5) == 0x22 else [7] * 512
|
|
for i in range(0x200):
|
|
touch(util.get_word(0x5ec00 + i * 2) | (banks[i] << 16))
|
|
|
|
touch(0x7c3ee)
|
|
for i in range(9):
|
|
touch(util.get_word(0x5DB1A + i * 2) | 0x70000)
|
|
|
|
add_asset_blob('kLvlSprBlob', spr_ranges)
|
|
add_asset_uint8('kLmSpritePtrBankByte', banks)
|
|
|
|
add_sprites()
|
|
|
|
add_asset_uint16('kLoadLevel_SpriteDataPtrs', util.get_words(0x5EC00, 0x200))
|
|
add_asset_uint8('kFileSelectText_EraseFile', util.get_bytes(0x5B6FE, 203 + 204))
|
|
add_asset_uint8('kInitializeMode7TilemapsAndPalettes_TilemapData', util.get_bytes(0x3D9DE, 912))
|
|
|
|
def do_u16(name, addr, org_addr, org_size, bank_addr = None):
|
|
p = get_24(addr) if bank_addr == None else util.get_word(addr) | get_byte(bank_addr) << 16
|
|
sz = get_rats_size(p) // 2 if p != org_addr else org_size
|
|
add_asset_uint16(name, util.get_words(p, sz))
|
|
assert p == org_addr or LUNAR_MAGIC
|
|
return p != org_addr
|
|
|
|
def do_u8(name, addr, org_addr, org_size, bank_addr = None):
|
|
p = get_24(addr) if bank_addr == None else util.get_word(addr) | get_byte(bank_addr) << 16
|
|
sz = get_rats_size(p) if p != org_addr else org_size
|
|
add_asset_uint8(name, util.get_bytes(p, sz))
|
|
assert p == org_addr or LUNAR_MAGIC
|
|
return p != org_addr
|
|
|
|
def add_event_tile_entries():
|
|
do_u16('kLayer2EventData_TileEntries', 0x4E49F, 0x4DD8D, 742)
|
|
do_u16('kChangingLayer1OverworldTiles_Layer1TileLocation', 0x4EC8C, 0x4D85D, 112)
|
|
do_u16('kOwEventProcess01_DestroyTileAnimation_DATA_04E587', 0x4EEC9, 0x4E587, 16)
|
|
if do_u16('kCheckIfDestroyTileEventIsActive_DATA_04E5B6', 0x4E69C, 0x4E5B6, 16):
|
|
lm_feat.flags |= kLmFeature_DestroyTileAnims
|
|
do_u16('kOwEventProcess01_DestroyTileAnimation_DATA_04D93D', 0x4EDB8, 0x4D93D, 112)
|
|
|
|
do_u8('kOwEventProcess07_SilentEventsAndEndOfEvent_SilentEventTiles', 0x4E9F4, 0x4E8E4, 44)
|
|
do_u8('kOwEventProcess07_SilentEventsAndEndOfEvent_SilentEventTiles_TileLayer', 0x4EA27, 0x4E910, 44)
|
|
|
|
do_u16('kOwEventProcess07_SilentEventsAndEndOfEvent_SilentEventTiles_TileNum', 0x4EA31+1, 0x4E994, 44)
|
|
do_u16('kOwEventProcess07_SilentEventsAndEndOfEvent_SilentEventTiles_TilemapLocation', 0x4EA37+1, 0x4E93C, 44)
|
|
|
|
add_asset_uint8('kOwDestruction_TileToIdx_04E5A7', get_bytes(0x4e5a7, 5))
|
|
add_asset_uint8('kOwDestruction_TopTile_04E5AC', get_bytes(0x4e5ac, 5))
|
|
add_asset_uint8('kOwDestruction_BottomTile_04E5B1', get_bytes(0x4e5b1, 5))
|
|
do_u8('kOwDestruction_TriggerEvent_04E5D6', 0x4E67C, 0x4e5d6, 16)
|
|
|
|
add_event_tile_entries()
|
|
|
|
def add_eventstuff():
|
|
def get_words_rats(p):
|
|
return get_words(p, get_rats_size(p) // 2)
|
|
|
|
def get_u8_rats(p):
|
|
return get_bytes(p, get_rats_size(p))
|
|
|
|
r1, r2, r3, r4 = [], [], [], [],
|
|
if get_byte(0x4E9F7) == 0x22:
|
|
lm_feat.flags |= kLmFeature_EventStuff
|
|
p = get_24(0x4E9F8)
|
|
r1 = get_words_rats(get_24(p - 0x8008 + 0x8014 + 1))
|
|
r2 = get_words_rats(get_24(p - 0x8008 + 0x8029 + 1))
|
|
r3 = get_words_rats(get_24(p - 0x8008 + 0x802F + 1))
|
|
r4 = get_u8_rats(get_24(p - 0x8008 + 0x803B + 1))
|
|
add_asset_uint16('kLmEventStuff1', r1)
|
|
add_asset_uint16('kLmEventStuff2', r2)
|
|
add_asset_uint16('kLmEventStuff3', r3)
|
|
add_asset_uint8('kLmEventStuff4', r4)
|
|
|
|
|
|
add_eventstuff()
|
|
|
|
do_u8('kOverworldLayer2EventTilemap_Tiles', 0x4EAF5, 0xc8000, 3328)
|
|
|
|
p = get_word(0x4DC72) | get_byte(0x4DC79) << 16
|
|
_, sz = unpack_rle_of_size(p, 0x2000)
|
|
add_asset_uint8('kLoadOverworldLayer2AndEventsTilemaps_OverworldLayer2Tilemap', get_bytes(p, sz))
|
|
|
|
p = get_word(0x4DC8d) | get_byte(0x4DC79) << 16
|
|
_, sz = unpack_rle_of_size(p, 0x2000)
|
|
add_asset_uint8('kLoadOverworldLayer2AndEventsTilemaps_OverworldLayer2Tilemap_Prop', get_bytes(p, sz))
|
|
|
|
do_u8('kOverworldLayer2EventTilemap_Prop',
|
|
addr = 0x4DD45, org_addr = 0xC8D00, org_size = 1642, bank_addr = 0x4DD4a)
|
|
|
|
add_asset_uint8('kLoadOverworldLayer1AndEvents_DATA_0CF7DF', util.get_bytes(0xCF7DF, 0x800))
|
|
|
|
add_asset_uint8('kRom', util.ROM.ROM if args.include_rom else b'')
|
|
|
|
add_asset_uint8('kUpdateLevelName_LevelNameStrings', util.get_bytes(0x49ac5, 460))
|
|
add_asset_uint8('kGameMode25_ShowEnemyRollcallScreen_TileData', util.get_bytes(0xCAF11, 1681))
|
|
|
|
lm_pals = []
|
|
if LUNAR_MAGIC and get_24(0xef577) == 0xf58320:
|
|
for i in range(0x200):
|
|
pp = util.get_24(0xEF600 + i * 3)
|
|
lm_pals.append(util.get_bytes(pp, 0x202) if pp else b'')
|
|
add_asset_packed('kLmPalettes', lm_pals)
|
|
|
|
add_asset_uint8('kPlayerGFXRt_HeadTilePointerIndex', util.get_bytes(0xE00C, 192))
|
|
add_asset_uint8('kPlayerGFXRt_BodyTilePointerIndex', util.get_bytes(0xE0CC, 192))
|
|
|
|
add_asset_uint8('kLvlInitialFlags', util.get_bytes(0x5DDA0, 96))
|
|
add_asset_uint8('kLoadOverworldSprites_SpriteSlotData', util.get_bytes(0x4F625, 65))
|
|
add_asset_uint8('kChangingLayer1OverworldTiles_TilesThatChange', util.get_bytes(0x4DA1D, 22))
|
|
add_asset_uint8('kChangingLayer1OverworldTiles_TilesToBecome', util.get_bytes(0x4DA33, 22))
|
|
|
|
add_asset_uint8('kOverworldEventProcess01_DestroyTileAnimation_DATA_04EE7A', util.get_bytes(0x4EE7A, 48))
|
|
|
|
add_asset_uint16('kLevelTileAnimations_FrameData', util.get_words(0x5B999, 208))
|
|
|
|
add_asset_uint8('kSetPlayerPose_WalkingPoseCount', util.get_bytes(0xDC78, 4))
|
|
|
|
add_asset_uint8('kDrawLoadingLetters_TileData', util.get_bytes(0x90d1, 52))
|
|
add_asset_uint8('kDrawLoadingLetters_TileData_BottomTiles', util.get_bytes(0x9105, 52))
|
|
add_asset_uint8('kDrawLoadingLetters_TileData_TopProp', util.get_bytes(0x9139, 52))
|
|
add_asset_uint8('kDrawLoadingLetters_TileData_BottomProp', util.get_bytes(0x916A, 52))
|
|
|
|
add_asset_uint16('kOwTileAnimations_WaterTileNumbers', util.get_words(0x48000, 3))
|
|
add_asset_uint16('kOwTileAnimations_TileNumbers', util.get_words(0x48006, 64))
|
|
|
|
def add_star_pipe_warp():
|
|
if get_byte(0x48509) == 0x22:
|
|
p = get_24(0x4850a)
|
|
n = get_word(p + 0xe00f - 0xdfff) // 2
|
|
add_asset_uint16('kOwStarPipeWarp_SrcX_048431', get_words(get_24(p + 0xe016 - 0xdfff), n))
|
|
add_asset_uint16('kOwStarPipeWarp_SrcY_048467', get_words(get_24(p + 0xe026 - 0xdfff), n))
|
|
assert get_byte(0x48566) == 0x22
|
|
p = get_24(0x48567)
|
|
add_asset_uint16('kOwStarPipeWarp_DstX_04849D', get_words(get_24(p + 0xe04b - 0xe03f), n))
|
|
add_asset_uint16('kOwStarPipeWarp_DstY_0484D3', get_words(get_24(p + 0xe05d - 0xe03f), n))
|
|
else:
|
|
add_asset_uint16('kOwStarPipeWarp_SrcX_048431', get_words(0x48431, 27))
|
|
add_asset_uint16('kOwStarPipeWarp_SrcY_048467', get_words(0x48467, 27))
|
|
add_asset_uint16('kOwStarPipeWarp_DstX_04849D', get_words(0x4849d, 27))
|
|
add_asset_uint16('kOwStarPipeWarp_DstY_0484D3', get_words(0x484d3, 27))
|
|
|
|
add_star_pipe_warp()
|
|
|
|
add_asset_uint16('kOwLevelsForcedMusicChange_048D74', get_words(0x48d74, 11))
|
|
add_asset_uint8('kOwSubmapMusic_048D8A', get_bytes(0x48d8a, 7))
|
|
add_asset_uint16('kOw_KoopaKidTeleportXYPos_048E49', get_words(0x48e49, 6))
|
|
add_asset_uint8('kOwTriggerSaveTiles_048F7F', get_bytes(0x48f7f, 8))
|
|
add_asset_uint16('kOwNoAutoMoveLevels_04906C', get_words(0x4906c, 6))
|
|
add_asset_uint8('kOwHardcodedPathLevel_049078', get_bytes(0x49078, 10))
|
|
add_asset_uint16('kOwHardcodedPathChocolateIsland2_049082', get_words(0x49082, 2))
|
|
add_asset_uint8('kOwHardcodedPathTiles_049086', get_bytes(0x49086, 68))
|
|
add_asset_uint8('kOwHardcodedPathDirs_0490CA', get_bytes(0x490ca, 68))
|
|
add_asset_uint8('kOwHardcodedPathStartIndex_04910E', get_bytes(0x4910e, 10))
|
|
add_asset_uint8('kOwExitLevelTiles_049426', get_bytes(0x49426, 10))
|
|
add_asset_uint16('kUpdateLevelName_DATA_049C91', get_words(0x49c91, 31))
|
|
add_asset_uint16('kUpdateLevelName_DATA_049CCF', get_words(0x49ccf, 15))
|
|
add_asset_uint16('kUpdateLevelName_DATA_049CED', get_words(0x49ced, 13))
|
|
add_asset_uint8('kOwExitSource_049964', get_bytes(0x49964, 70))
|
|
add_asset_uint8('kOwExitDest_0499AA', get_bytes(0x499aa, 70))
|
|
add_asset_uint8('kOwExitExtra_0499F0', get_bytes(0x499f0, 28))
|
|
add_asset_uint16('kOwExitLayerPosition_049A0C', get_words(0x49a0c, 12))
|
|
add_asset_uint8('kOwUnknownTableA_From_04A03C', get_bytes(0x4a03c, 24))
|
|
add_asset_uint16('kOwUnknownTableA_Alpha_04A054', get_words(0x4a054, 24))
|
|
add_asset_uint16('kOwUnknownTableA_XY_04A084', get_words(0x4a084, 48))
|
|
add_asset_uint8('kOwUnknownTableA_Direction_04A0E4', get_bytes(0x4a0e4, 24))
|
|
add_asset_uint8('kOwDirectionAfterBeatingLevel_04D678', get_bytes(0x4d678, 113))
|
|
add_asset_uint8('kOwSubmapTileset_04DC02', get_bytes(0x4dc02, 7))
|
|
add_asset_uint16('kLayer2EventData_Ptrs_04E359', get_words(0x4e359, 121))
|
|
|
|
add_asset_uint8('kLmInitSaveData', get_bytes(0x05DDA0, 96) if get_byte(0x5dd80) != 0xff else b'')
|
|
add_asset_uint8('kInitializeSaveData_InitialOWPlayerPos', get_bytes(0x9EF0, 22))
|
|
|
|
add_asset_uint16('kOWSpr07_Smoke_DATA_04FC1E', get_words(0x4FC1E, 4))
|
|
|
|
add_asset_uint16('kLoadOverworldSprites_SubmapBooXPosOffset', get_words(0x4F666, 3))
|
|
add_asset_uint16('kLoadOverworldSprites_SubmapBooYPosOffset', get_words(0x4F66C, 3))
|
|
|
|
add_asset_uint8('kLoadLevelHeader_LevelMusicTable', get_bytes(0x584DB, 8))
|
|
|
|
# hack
|
|
add_asset_uint8('kLevelsThatTriggerCutscenes', get_bytes(0xC9A7, 8) + bytearray([get_byte(0xCA0C), get_byte(0xCA13)]))
|
|
|
|
#add_asset_uint16('', util.get_words(0x, ))
|
|
#add_asset_uint8('', util.get_bytes(0x, ))
|
|
|
|
def add_exgfx(name, addr, size):
|
|
r = []
|
|
if LUNAR_MAGIC and addr != 0xffffff:
|
|
for i in range(size):
|
|
p = util.get_24(addr + i * 3)
|
|
r.append(get_comp_data(p) if p not in (0, 0xffffff) else b'')
|
|
while len(r) and r[-1] == b'':
|
|
r.pop()
|
|
add_asset_packed(name, r)
|
|
|
|
add_exgfx('kLmExgfx', 0xFF600, 128)
|
|
add_exgfx('kLmSuperExgfx', get_24(0xFF937), 0x1000 - 0x100)
|
|
add_asset_uint8('kLmGraphicsRemapped', remove_trail_zero(util.get_bytes(0xFF200, 1024)) if LUNAR_MAGIC else b'')
|
|
|
|
def add_load_level_stuff():
|
|
lm_load_level = get_byte(0x5D9A1) == 0x22
|
|
|
|
p = get_24(0x6F624)
|
|
add_asset_uint16('kLmModifyMap16Ids', util.get_words(p, 4096) if lm_load_level and p != 0xffffff else b'')
|
|
add_asset_uint8('kLm5DE00', util.get_bytes(0x5DE00, 512) if lm_load_level else b'')
|
|
add_asset_uint8('kLm6FC00', util.get_bytes(0x6FC00, 512) if lm_load_level else b'')
|
|
add_asset_uint8('kLm6FE00', util.get_bytes(0x6FE00, 512) if lm_load_level else b'')
|
|
|
|
p = util.get_24(util.get_24(0x5D9A2) + 0x10BBDF - 0x10BB83) if lm_load_level else 0
|
|
add_asset_uint8('kLm10B8BC', util.get_bytes(p, 512) if p != 0 else b'')
|
|
add_asset_uint8('kLmLevelData3FE00', util.get_bytes(0x3FE00, 512) if lm_load_level else b'')
|
|
|
|
add_asset_uint8('kLmLevelData5DC85', util.get_bytes(get_24(0x5DC86), 512) if lm_load_level else b'')
|
|
add_asset_uint8('kLmLevelData5DC8A', util.get_bytes(get_24(0x5DC8B), 512) if lm_load_level else b'')
|
|
add_asset_uint8('kLm5FE00', util.get_bytes(get_24(0x5DC81), 512) if lm_load_level else b'')
|
|
|
|
add_asset_uint8('kLevelInfo_05F800', util.get_bytes(get_24(0xde191), 0x200) if lm_load_level else b'')
|
|
add_asset_uint8('kLevelInfo_05FA00', util.get_bytes(get_24(0xde198), 0x200) if lm_load_level else b'')
|
|
add_asset_uint8('kLevelInfo_05FC00', util.get_bytes(get_24(0xde19f), 0x200) if lm_load_level else b'')
|
|
lm_feat.flags |= kLmFeature_LoadLevel if lm_load_level else 0
|
|
|
|
add_load_level_stuff()
|
|
|
|
def add_lm_map16():
|
|
if LUNAR_MAGIC:
|
|
B = 0x06F500
|
|
half = (get_byte(0x6F54B) != 0xB0)
|
|
B -= 2 if half else 0
|
|
arr = [
|
|
get_byte(B + 0x57)<<16|(get_word(B + 0x53)+0x1000&0xFFFF),
|
|
get_byte(B + 0x60)<<16|(get_word(B + 0x5C)^0x8000),
|
|
get_byte(B + 0x6B)<<16|(get_word(B + 0x67)+1 & 0xFFFF),
|
|
get_byte(B + 0x74)<<16|(get_word(B + 0x70)+0x8001&0xFFFF),
|
|
]
|
|
if not half:
|
|
arr += [
|
|
get_byte(B + 0x98)<<16|get_word(B + 0x94),
|
|
get_byte(B + 0xA1)<<16|(get_word(B + 0x9D)+0x8000&0xFFFF),
|
|
get_byte(B + 0xAC)<<16|(get_word(B + 0xA8)+1 & 0xFFFF),
|
|
get_byte(B + 0xB5)<<16|(get_word(B + 0xB1)+0x8001&0xFFFF),
|
|
]
|
|
else:
|
|
print('Warning: Half map16', file=sys.stderr)
|
|
arr += [0, 0, 0, 0]
|
|
arr.append(get_byte(B + 0x8A)<<16|(get_word(B + 0x86)+0x1000&0xFFFF)), # TS
|
|
else:
|
|
arr = [0 for i in range(9)]
|
|
|
|
for i, p in enumerate(arr):
|
|
sz = get_rats_size(p)
|
|
add_asset_uint16('kMap16_%s' % ('TS' if i == 8 else i), get_words(p, sz // 2))
|
|
|
|
add_lm_map16()
|
|
|
|
#add_asset_uint16('kMap16Bank11', util.get_words(0x118000, 16384) if LUNAR_MAGIC else b'')
|
|
#add_asset_uint16('kMap16Bank12', util.get_words(0x128000, 12288) if LUNAR_MAGIC else b'')
|
|
|
|
def calc_one_exanim_end(p):
|
|
p_org = p
|
|
tp = util.get_byte(p)
|
|
trigger = util.get_byte(p + 1)
|
|
if tp >= 1 and tp <= 0x13:
|
|
limit = util.get_byte(p + 2)
|
|
p += 5 # type, trigger, limit, dest(w)
|
|
p += (limit + 1) * 2 * (1 if trigger==0 else 2)
|
|
return p
|
|
raise Exception('exanim type %x not supported' % tp)
|
|
|
|
def calc_exanim_size(p):
|
|
p_org = p
|
|
num = util.get_word(p)
|
|
trig = util.get_word(p + 6)
|
|
p += 8
|
|
for i in range(16):
|
|
if trig & (1 << i):
|
|
p += 2 # manual triggers
|
|
max_p = p
|
|
for i in range(num):
|
|
pd = util.get_word(p + i * 2)
|
|
max_p = max(max_p, calc_one_exanim_end(p + pd))
|
|
return max_p - p_org
|
|
|
|
# parse all level exanimation
|
|
lm_lvl_exanim = []
|
|
lm_exanim_ranges = []
|
|
if LUNAR_MAGIC and get_byte(0x0583AD) == 0x22: # call LmHook_InitExanimForLevel
|
|
LmHook_InitExanimForLevel = get_24(0x583AE)
|
|
if get_bytes(LmHook_InitExanimForLevel, 4) != b'\xe2\x30\x8b\xa2':
|
|
raise Exception('The Exanim file format is incorrect. ' + extra_lunar_magic_text())
|
|
|
|
exanim_ptr = get_24((0x10C24E - 0x10C164) + LmHook_InitExanimForLevel) # 0x10CD9C
|
|
|
|
for i in range(512):
|
|
p = util.get_24(exanim_ptr + i * 3)
|
|
lm_lvl_exanim.append(0 if (p & 0x8000) == 0 else p)
|
|
if (p & 0x8000) != 0:
|
|
sz = calc_exanim_size(p)
|
|
lm_exanim_ranges.append((p, p + sz))
|
|
lm_feat.flags |= kLmFeature_Exanim
|
|
|
|
add_asset_uint8('kLmLvlExAnim', b''.join(pack_24(a) for a in remove_trail_zero(lm_lvl_exanim)))
|
|
add_asset_blob('kLmExanimBlob', lm_exanim_ranges)
|
|
|
|
kSkipOwDecompressMap = {
|
|
b'\xea\xea\xea\xea' : kLmFeature_SkipOverworldDecompress,
|
|
b'\x22\x00\xFC\x0E' : 0, # lm
|
|
b'\x22\x28\xBA\x00' : 0, # orig
|
|
}
|
|
|
|
lm_feat.flags |= kLmFeature_LmEnabled if LUNAR_MAGIC else 0
|
|
lm_feat.flags |= kSkipOwDecompressMap[bytes(get_bytes(0xA149, 4))]
|
|
lm_feat.flags |= kLmFeature_OverworldTiles4bpp if get_byte(0x480D0) == 0x60 else 0
|
|
lm_feat.flags |= kLmFeature_Copy512colors if get_byte(0xA5E1) == 0xea else 0
|
|
lm_feat.flags |= kLmFeature_WeirdPalette if get_byte(0xAF71) == 0x22 else 0
|
|
lm_feat.flags |= kLmFeature_SkipLoadPaletteHook if get_byte(0xEF570) != 0xc2 else 0
|
|
lm_feat.flags |= kLmFeature_GfxUpload if get_bytes(0xAA6B, 4) != b'\x22\x28\xBA\x00' else 0
|
|
lm_feat.flags |= kLmFeature_4bppgfx if get_byte(0xAACE) == 0x10 else 0
|
|
lm_feat.flags |= kLmFeature_DontSetYposForIntroMarch if get_byte(0x05B15D) == 0xea else 0
|
|
lm_feat.flags |= kLmFeature_MusicRegTweak if get_byte(0x5855C) == 0x8d else 0
|
|
lm_feat.flags |= kLmFeature_TideWaterTweak if get_byte(0xa045) == 0x22 else 0
|
|
lm_feat.flags |= kLmFeature_EnemyCollTweak if get_byte(0x194B6) == 0x5c else 0
|
|
lm_feat.flags |= kLmFeature_Ow4bppGfx if get_bytes(0xA149, 4) != b'\x22\x28\xBA\x00' else 0
|
|
lm_feat.flags |= kLmFeature_DontResetOwPlayersMap if get_byte(0xa0a0) == 0xea else 0
|
|
lm_feat.flags |= kLmFeature_NonStdGfxAA8D if get_byte(0xAA8D) != 0x08 else 0
|
|
lm_feat.flags |= kLmFeature_TimerTweaks if get_byte(0x58E24) == 0x8f else 0
|
|
lm_feat.flags |= kLmFeature_NoDefaultSavePrompts if get_byte(0x3BA26) == 0 else 0
|
|
|
|
|
|
# Allows Mario to perform a wall kick by sliding along a wall and pressing the
|
|
# B button.
|
|
lm_feat.hacks |= kHack_Walljump if get_24(0xA2A1) != 0x86F122 else 0
|
|
|
|
def add_custom_ow_palette():
|
|
r = b''
|
|
if get_byte(0xAD32) == 0x22:
|
|
lm_feat.flags |= kLmFeature_OwPalette
|
|
p = get_24(0xAD33) - 0x10813F
|
|
r = get_rats_bytes(get_byte(p + 0x10815D) << 16 | get_word(p + 0x108151))
|
|
add_asset_uint8('kLmOverworldPal', r)
|
|
add_custom_ow_palette()
|
|
|
|
def add_custom_display_message():
|
|
flag = get_byte(0x5B1A3) == 0x22
|
|
lm_feat.flags |= kLmFeature_CustomDisplayMessage if flag else 0
|
|
add_asset_uint8('kLmDisplayMessage_Tab0', get_rats_bytes(get_24(0x3BC0B)) if flag else b'')
|
|
add_asset_uint16('kLmDisplayMessage_3BC7F', get_words(0x3BC7F, 8) if flag else b'')
|
|
add_asset_uint16('kLmDisplayMessage_3BE80', get_words(0x3BE80, 192) if flag else b'')
|
|
r = []
|
|
if flag:
|
|
for a in [0x3BB9A, 0x3BBA1, 0x3BBA6, 0x3BBAB, 0x3BBB0]:
|
|
assert get_byte(a) == 0xe0
|
|
r.append(get_byte(a+1))
|
|
add_asset_uint8('kLmDisplayMessage_Tab1', r)
|
|
|
|
add_custom_display_message()
|
|
|
|
def add_custom_title_screen():
|
|
lm_feat.flags |= kLmFeature_CustomTitleScreenDemo if get_byte(0x9c6f) == 0x22 else 0
|
|
r = b''
|
|
if lm_feat.flags & kLmFeature_CustomTitleScreenDemo:
|
|
p = get_24(get_24(0x9c70) + 0x10F6B0 - 0x10F68D) - 2
|
|
r = get_bytes(p, get_rats_size(p))
|
|
add_asset_uint8('kLmTitleScreenMoves', r)
|
|
|
|
add_custom_title_screen()
|
|
|
|
def add_level_names_patch():
|
|
lm_feat.flags |= kLmFeature_LevelNamesPatch if get_byte(0x48E81) == 0x22 else 0
|
|
r = b''
|
|
if lm_feat.flags & kLmFeature_LevelNamesPatch:
|
|
p = get_24(0x3BB57)
|
|
r = get_bytes(p, get_rats_size(p))
|
|
add_asset_uint8('kLmLevelNamesPatch', r)
|
|
|
|
add_level_names_patch()
|
|
|
|
# compressed layer1 and events
|
|
def add_overworld():
|
|
d = []
|
|
if get_byte(0x4d813) == 0x5c:
|
|
d = get_comp_data(get_byte(0x4d808) << 16 | get_word(0x4d803))
|
|
add_asset_uint8('kOwLayer1AndEvents', d)
|
|
|
|
d = []
|
|
if get_byte(0x4d832) == 0x5c:
|
|
d = get_comp_data(get_byte(0x4d827) << 16 | get_word(0x4d822))
|
|
add_asset_uint8('kOwLayer1AndEvents2', d)
|
|
|
|
add_overworld()
|
|
|
|
r = b''
|
|
if LUNAR_MAGIC and get_byte(0xA140) == 0x22:
|
|
lm_feat.kLmLvlInfo_addr_other = get_byte(0xFFAC2) << 16 | get_word(0xFFAB9)
|
|
lm_feat.kLmLvlInfo_addr = get_24(0xFF7FF)
|
|
r = util.get_words(lm_feat.kLmLvlInfo_addr, (512+8) * 16)
|
|
add_asset_uint16('kLmLvlInfo', r)
|
|
#add_lm_lvlinfo()
|
|
|
|
|
|
|
|
def add_custom_map16_bg():
|
|
r = []
|
|
if LUNAR_MAGIC:
|
|
for i in range(16):
|
|
p = util.get_24(0xEFD50 + i * 3)
|
|
if p:
|
|
r.append(util.get_bytes(p, 0x8000 - (p & 0x7fff)))
|
|
else:
|
|
r.append(b'')
|
|
add_asset_packed('kLmCustomMap16Bg', remove_trail_empty(r))
|
|
add_custom_map16_bg()
|
|
|
|
def add_sprite_extra_size():
|
|
r = b''
|
|
if LUNAR_MAGIC:
|
|
p = util.get_24(0xef30c)
|
|
if p != 0xffffff:
|
|
r = util.get_bytes(p, 1024)
|
|
add_asset_uint8('kLmSprExtraSize', r)
|
|
add_sprite_extra_size()
|
|
|
|
add_asset_uint8('kLmFeatures', lm_feat.serialize())
|
|
|
|
|
|
def write_assets_to_file(print_header = False):
|
|
key_sig = b''
|
|
all_data = []
|
|
if print_header:
|
|
print('''#pragma once
|
|
#include "../src/types.h"
|
|
|
|
enum {
|
|
kNumberOfAssets = %d
|
|
};
|
|
extern const uint8 *g_asset_ptrs[kNumberOfAssets];
|
|
extern uint32 g_asset_sizes[kNumberOfAssets];
|
|
extern MemBlk FindInAssetArray(int asset, int idx);
|
|
extern const uint8 *FindPtrInAsset(int asset, uint32 addr);
|
|
''' % len(assets))
|
|
|
|
for i, (k, (tp, data)) in enumerate(assets.items()):
|
|
if print_header:
|
|
if tp == 'packed':
|
|
print('#define %s(idx) FindInAssetArray(%d, idx)' % (k, i))
|
|
elif tp == 'blob':
|
|
print('#define %s(addr) FindPtrInAsset(%d, addr)' % (k, i))
|
|
else:
|
|
if tp == 'uint8':
|
|
print('#define %s g_asset_ptrs[%d]' % (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)
|
|
|
|
assets_sig = b'Smw_v0 \n\0' + hashlib.sha256(key_sig).digest()
|
|
|
|
if print_header:
|
|
print('#define kAssets_Sig %s' % ", ".join((str(a) for a in assets_sig)))
|
|
|
|
hdr = assets_sig + b'\x00' * 32 + struct.pack('II', len(all_data), len(key_sig))
|
|
|
|
encoded_sizes = array.array('I', [len(i) for i in all_data])
|
|
|
|
file_data = hdr + encoded_sizes + key_sig
|
|
|
|
for v in all_data:
|
|
while len(file_data) & 3:
|
|
file_data += b'\0'
|
|
file_data += v
|
|
|
|
open('smw_assets.dat', 'wb').write(file_data)
|
|
|
|
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:
|
|
print_assets_header = True
|
|
include_rom = True
|
|
main(DefaultArgs())
|
|
else:
|
|
ROM = util.ROM
|
|
|
|
|