mirror of
https://github.com/pret/pokeyellow.git
synced 2024-11-27 12:20:21 +00:00
make extras/ a submodule
Use pokemontools v1.3.0 and use the same preprocessor as the pokecrystal project.
This commit is contained in:
parent
4d6b824969
commit
e84a5b2062
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "extras"]
|
||||
path = extras
|
||||
url = git://github.com/kanzure/pokemon-reverse-engineering-tools.git
|
11
Makefile
11
Makefile
@ -1,17 +1,16 @@
|
||||
.SUFFIXES: .asm .tx .o .gbc
|
||||
|
||||
TEXTFILES = text/oakspeech.tx text/pokedex.tx text/mapRedsHouse1F.tx \
|
||||
text/mapBluesHouse.tx text/mapPalletTown.tx
|
||||
TEXTFILES := $(shell find ./ -type f -name '*.asm')
|
||||
|
||||
all: pokered.gbc
|
||||
|
||||
pokered.o: pokered.tx main.tx constants.tx music.tx wram.tx ${TEXTFILES}
|
||||
pokered.o: pokered.tx main.tx constants.tx music.tx wram.tx ${TEXTFILES:.asm=.tx}
|
||||
rgbasm -o pokered.o pokered.tx
|
||||
|
||||
pokeblue.o: pokeblue.asm main.tx constants.tx ${TEXTFILES}
|
||||
pokeblue.o: pokeblue.tx main.tx constants.tx music.tx wram.tx ${TEXTFILES:.asm=.tx}
|
||||
rgbasm -o pokeblue.o pokeblue.asm
|
||||
|
||||
redrle: extras/redrle.c
|
||||
redrle: extras/redtools/redrle.c
|
||||
${CC} -o $@ $>
|
||||
|
||||
.asm.tx:
|
||||
@ -28,6 +27,6 @@ pokeblue.gbc: pokeblue.o
|
||||
cmp blue.gbc $@
|
||||
|
||||
clean:
|
||||
rm -f main.tx pokered.o pokered.gbc pokeblue.o pokeblue.gbc redrle ${TEXTFILES}
|
||||
rm -f pokered.o pokered.gbc pokeblue.o pokeblue.gbc redrle $(TEXTFILES:.asm=.tx)
|
||||
|
||||
more: pokered.gbc pokeblue.gbc
|
||||
|
1
extras
Submodule
1
extras
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 795cd58a70c80082003e40127241cfaefa0fae8b
|
@ -1,41 +0,0 @@
|
||||
#author: Bryan Bishop <kanzure@gmail.com>
|
||||
#date: 2011-01-04
|
||||
#purpose: insert labels into map headers
|
||||
import sys
|
||||
|
||||
asm = None
|
||||
asm_lines = []
|
||||
def load_asm():
|
||||
global asm, asm_lines
|
||||
asm = open("../pokered.asm", "r").read()
|
||||
asm_lines = asm.split("\n")
|
||||
|
||||
def find_with_start_of_line(name):
|
||||
global asm_lines
|
||||
for line in asm_lines:
|
||||
if len(line) > len(name) and ": " in line:
|
||||
if line[:len(name)] == name: return True
|
||||
return False
|
||||
|
||||
def process_lines():
|
||||
global asm, asm_lines
|
||||
for line in asm_lines:
|
||||
if not "_h:" in line: continue #skip
|
||||
index = asm_lines.index(line)
|
||||
name = line.split("_h:")[0]
|
||||
|
||||
if "Blocks" in asm_lines[index+3]: continue #skip, already done
|
||||
#if not (str(name + "Blocks:") in asm): continue #skip, no block label found
|
||||
if not find_with_start_of_line(name + "Blocks:"): continue #skip
|
||||
|
||||
orig_line = asm_lines[index+3]
|
||||
fixed_line = orig_line.split(",")
|
||||
fixed_line[0] = " dw " + name + "Blocks"
|
||||
fixed_line = ",".join(fixed_line)
|
||||
|
||||
asm_lines[index+3] = fixed_line
|
||||
|
||||
if __name__ == "__main__":
|
||||
load_asm()
|
||||
process_lines()
|
||||
sys.stdout.write("\n".join(asm_lines))
|
@ -1,502 +0,0 @@
|
||||
#author: Bryan Bishop <kanzure@gmail.com>
|
||||
#date: 2012-01-03
|
||||
#purpose: map which addresses are left
|
||||
#note: use python2.7 because of subprocess
|
||||
import sys, os
|
||||
from copy import copy, deepcopy
|
||||
import subprocess
|
||||
import json
|
||||
from extract_maps import rom, assert_rom, load_rom, calculate_pointer, load_map_pointers, read_all_map_headers, map_headers
|
||||
from pokered_dir import pokered_dir
|
||||
|
||||
try:
|
||||
from pretty_map_headers import map_header_pretty_printer, map_name_cleaner
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
#store each line of source code here
|
||||
asm = None
|
||||
|
||||
#store each incbin line separately
|
||||
incbin_lines = []
|
||||
|
||||
#storage for processed incbin lines
|
||||
processed_incbins = {}
|
||||
|
||||
def offset_to_pointer(offset):
|
||||
if type(offset) == str: offset = int(offset, base)
|
||||
return int(offset) % 0x4000 + 0x4000
|
||||
|
||||
def load_asm(filename=os.path.join(pokered_dir, "main.asm")):
|
||||
"""loads the asm source code into memory
|
||||
this also detects if the revision of the repository
|
||||
is using main.asm, common.asm or pokered.asm, which is
|
||||
useful when generating images in romvisualizer.py"""
|
||||
global asm
|
||||
# chronological order is important
|
||||
defaults = [os.path.join(pokered_dir, f) for f in ["main.asm", "common.asm", "pokered.asm"]]
|
||||
if filename in defaults:
|
||||
if not load_asm_if_one_exists_in(defaults):
|
||||
raise Exception("This shouldn't happen")
|
||||
elif os.path.exists(filename):
|
||||
asm = get_all_lines_from_file(filename)
|
||||
if asm is None:
|
||||
raise Exception("file doesn't exists (did you mean one among: {0}?)".format(", ".join(defaults)))
|
||||
return asm
|
||||
|
||||
def load_asm_if_one_exists_in(defaults):
|
||||
global asm
|
||||
for f in defaults:
|
||||
if os.path.exists(f):
|
||||
asm = get_all_lines_from_file(f)
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_all_lines_from_file(filename):
|
||||
try:
|
||||
return open(filename, "r").read().split("\n")
|
||||
except IOError as e:
|
||||
raise(e)
|
||||
|
||||
def isolate_incbins():
|
||||
"find each incbin line"
|
||||
global incbin_lines
|
||||
incbin_lines = []
|
||||
for line in asm:
|
||||
if line == "": continue
|
||||
if line.count(" ") == len(line): continue
|
||||
|
||||
#clean up whitespace at beginning of line
|
||||
while line[0] == " ":
|
||||
line = line[1:]
|
||||
|
||||
if line[0:6] == "INCBIN" and "baserom.gbc" in line:
|
||||
incbin_lines.append(line)
|
||||
return incbin_lines
|
||||
|
||||
def process_incbins():
|
||||
"parse incbin lines into memory"
|
||||
global incbins
|
||||
incbins = {} #reset
|
||||
for incbin in incbin_lines:
|
||||
processed_incbin = {}
|
||||
|
||||
line_number = asm.index(incbin)
|
||||
|
||||
partial_start = incbin[21:]
|
||||
start = partial_start.split(",")[0].replace("$", "0x")
|
||||
start = eval(start)
|
||||
start_hex = hex(start).replace("0x", "$")
|
||||
|
||||
partial_interval = incbin[21:].split(",")[1]
|
||||
partial_interval = partial_interval.replace(";", "#")
|
||||
partial_interval = partial_interval.replace("$", "0x").replace("0xx", "0x")
|
||||
interval = eval(partial_interval)
|
||||
interval_hex = hex(interval).replace("0x", "$").replace("x", "")
|
||||
|
||||
end = start + interval
|
||||
end_hex = hex(end).replace("0x", "$")
|
||||
|
||||
processed_incbin = {
|
||||
"line_number": line_number,
|
||||
"line": incbin,
|
||||
"start": start,
|
||||
"interval": interval,
|
||||
"end": end,
|
||||
}
|
||||
|
||||
#don't add this incbin if the interval is 0
|
||||
if interval != 0:
|
||||
processed_incbins[line_number] = processed_incbin
|
||||
|
||||
def find_incbin_to_replace_for(address):
|
||||
"""returns a line number for which incbin to edit
|
||||
if you were to insert bytes into main.asm"""
|
||||
if type(address) == str: address = int(address, 16)
|
||||
|
||||
for incbin_key in processed_incbins.keys():
|
||||
incbin = processed_incbins[incbin_key]
|
||||
|
||||
start = incbin["start"]
|
||||
end = incbin["end"]
|
||||
|
||||
#print "start is: " + str(start)
|
||||
#print "end is: " + str(end)
|
||||
#print "address is: " + str(type(address))
|
||||
#print "checking.... " + hex(start) + " <= " + hex(address) + " <= " + hex(end)
|
||||
|
||||
if start <= address <= end:
|
||||
return incbin_key
|
||||
return None
|
||||
|
||||
def split_incbin_line_into_three(line, start_address, byte_count):
|
||||
"""
|
||||
splits an incbin line into three pieces.
|
||||
you can replace the middle one with the new content of length bytecount
|
||||
|
||||
start_address: where you want to start inserting bytes
|
||||
byte_count: how many bytes you will be inserting
|
||||
"""
|
||||
if type(start_address) == str: start_address = int(start_address, 16)
|
||||
|
||||
original_incbin = processed_incbins[line]
|
||||
start = original_incbin["start"]
|
||||
end = original_incbin["end"]
|
||||
|
||||
#start, end1, end2 (to be printed as start, end1 - end2)
|
||||
if start_address - start > 0:
|
||||
first = (start, start_address, start)
|
||||
else:
|
||||
first = (None) #skip this one because we're not including anything
|
||||
|
||||
#this is the one you will replace with whatever content
|
||||
second = (start_address, byte_count)
|
||||
|
||||
third = (start_address + byte_count, end - (start_address + byte_count))
|
||||
|
||||
output = ""
|
||||
|
||||
if first:
|
||||
output += "INCBIN \"baserom.gbc\",$" + hex(first[0])[2:] + ",$" + hex(first[1])[2:] + " - $" + hex(first[2])[2:] + "\n"
|
||||
output += "INCBIN \"baserom.gbc\",$" + hex(second[0])[2:] + "," + str(byte_count) + "\n"
|
||||
output += "INCBIN \"baserom.gbc\",$" + hex(third[0])[2:] + ",$" + hex(third[1])[2:] #no newline
|
||||
return output
|
||||
|
||||
def generate_diff_insert(line_number, newline):
|
||||
original = "\n".join(line for line in asm)
|
||||
newfile = deepcopy(asm)
|
||||
newfile[line_number] = newline #possibly inserting multiple lines
|
||||
newfile = "\n".join(line for line in newfile)
|
||||
|
||||
original_filename = "ejroqjfoad.temp"
|
||||
newfile_filename = "fjiqefo.temp"
|
||||
|
||||
original_fh = open(original_filename, "w")
|
||||
original_fh.write(original)
|
||||
original_fh.close()
|
||||
|
||||
newfile_fh = open(newfile_filename, "w")
|
||||
newfile_fh.write(newfile)
|
||||
newfile_fh.close()
|
||||
|
||||
try:
|
||||
diffcontent = subprocess.check_output(
|
||||
"diff -u {0} {1}".format(os.path.join(pokered_dir, "main.asm"), newfile_filename),
|
||||
shell=True)
|
||||
except AttributeError, exc:
|
||||
raise exc
|
||||
except Exception, exc:
|
||||
diffcontent = exc.output
|
||||
|
||||
os.system("rm " + original_filename)
|
||||
os.system("rm " + newfile_filename)
|
||||
|
||||
return diffcontent
|
||||
|
||||
def insert_map_header_asm(map_id):
|
||||
map = map_headers[map_id]
|
||||
line_number = find_incbin_to_replace_for(map["address"])
|
||||
if line_number == None: # or map_name_cleaner(map["name"], 0) in "\n".join(line for line in asm):
|
||||
print "i think map id=" + str(map_id) + " has previously been added."
|
||||
return #this map has already been added i bet
|
||||
newlines = split_incbin_line_into_three(line_number, map["address"], 12 + (11 * len(map["connections"])))
|
||||
|
||||
map_header_asm = map_header_pretty_printer(map_headers[map_id])
|
||||
|
||||
newlines = newlines.split("\n")
|
||||
if len(newlines) == 2: index = 0
|
||||
elif len(newlines) == 3:
|
||||
index = 1
|
||||
newlines[0] += "\n" #spacing is a nice thing to have
|
||||
newlines[index] = map_header_asm
|
||||
newlines = "\n".join(line for line in newlines)
|
||||
|
||||
diff = generate_diff_insert(line_number, newlines)
|
||||
|
||||
print diff
|
||||
print "... Applying diff."
|
||||
|
||||
#write the diff to a file
|
||||
fh = open("temp.patch", "w")
|
||||
fh.write(diff)
|
||||
fh.close()
|
||||
|
||||
#apply the patch
|
||||
os.system("patch {0} temp.patch".format(os.path.join(pokered_dir, "main.asm")))
|
||||
|
||||
#remove the patch
|
||||
os.system("rm temp.patch")
|
||||
|
||||
def wrapper_insert_map_header_asm(map_id):
|
||||
"reload the asm because it has changed (probably)"
|
||||
load_asm()
|
||||
isolate_incbins()
|
||||
process_incbins()
|
||||
insert_map_header_asm(map_id)
|
||||
|
||||
def dump_all_remaining_maps():
|
||||
for map_id in map_headers:
|
||||
print "Inserting map id=" + str(map_id)
|
||||
wrapper_insert_map_header_asm(map_id)
|
||||
|
||||
def reset_incbins():
|
||||
"reset asm before inserting another diff"
|
||||
asm = None
|
||||
incbin_lines = []
|
||||
processed_incbins = {}
|
||||
load_asm()
|
||||
isolate_incbins()
|
||||
process_incbins()
|
||||
|
||||
def apply_diff(diff, try_fixing=True, do_compile=True):
|
||||
print "... Applying diff."
|
||||
|
||||
#write the diff to a file
|
||||
fh = open("temp.patch", "w")
|
||||
fh.write(diff)
|
||||
fh.close()
|
||||
|
||||
#apply the patch
|
||||
os.system("cp {0} {1}".format(
|
||||
os.path.join(pokered_dir, "main.asm"),
|
||||
os.path.join(pokered_dir, "main1.asm")))
|
||||
os.system("patch {0} {1}".format(
|
||||
os.path.join(pokered_dir, "main.asm"),
|
||||
"temp.patch"))
|
||||
|
||||
#remove the patch
|
||||
os.system("rm temp.patch")
|
||||
|
||||
#confirm it's working
|
||||
if do_compile:
|
||||
try:
|
||||
subprocess.check_call("cd {0}; make clean; LC_CTYPE=C make".format(pokered_dir), shell=True)
|
||||
return True
|
||||
except Exception, exc:
|
||||
if try_fixing:
|
||||
os.system("mv {0} {1}".format(
|
||||
os.path.join(pokered_dir, "main1.asm"),
|
||||
os.path.join(pokered_dir, "main.asm")))
|
||||
return False
|
||||
|
||||
def index(seq, f):
|
||||
"""return the index of the first item in seq
|
||||
where f(item) == True."""
|
||||
return next((i for i in xrange(len(seq)) if f(seq[i])), None)
|
||||
|
||||
def is_probably_pointer(input):
|
||||
try:
|
||||
blah = int(input, 16)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
label_errors = ""
|
||||
def get_labels_between(start_line_id, end_line_id, bank_id):
|
||||
labels = []
|
||||
#label = {
|
||||
# "line_number": 15,
|
||||
# "bank_id": 32,
|
||||
# "label": "PalletTownText1",
|
||||
# "local_pointer": "$5315",
|
||||
# "address": 0x75315,
|
||||
#}
|
||||
global label_errors
|
||||
errors = ""
|
||||
current_line_offset = 0
|
||||
|
||||
sublines = asm[start_line_id : end_line_id + 1]
|
||||
for line in sublines:
|
||||
label = {}
|
||||
line_id = start_line_id + current_line_offset
|
||||
address = None
|
||||
local_pointer = None
|
||||
|
||||
if ": ; 0x" in line:
|
||||
temp = line.split(": ; 0x")[1]
|
||||
if not " " in temp:
|
||||
address = int("0x" + temp, 16)
|
||||
else:
|
||||
temp2 = temp.split(" ")[0]
|
||||
address = int("0x" + temp2, 16)
|
||||
elif ": ; " in line:
|
||||
partial = line.split(": ; ")[1]
|
||||
if ": ; $" in line:
|
||||
temp = line.split(": ; $")[1]
|
||||
if " " in temp:
|
||||
temp = temp.split(" ")[0]
|
||||
local_pointer = "$" + temp
|
||||
elif " " in partial:
|
||||
if " to " in partial:
|
||||
temp = partial.split(" to ")[0]
|
||||
if "0x" in temp:
|
||||
address = int(temp, 16)
|
||||
elif len(temp) == 4:
|
||||
local_pointer = "$" + temp
|
||||
else:
|
||||
errors += "found \" to \" in partial on line " + str(line_id) + ", but don't know what to do (debug14)" + "\n"
|
||||
errors += "line is: " + line + "\n"
|
||||
continue
|
||||
elif partial[4] == " " and partial[5] == "(":
|
||||
temp = partial[0:4]
|
||||
address = int(temp, 16)
|
||||
elif partial[5] == " " and partial[6] == "(":
|
||||
temp = partial[0:5]
|
||||
address = int(temp, 16)
|
||||
elif len(partial[4]) == 4 or partial[4] == " ": #then it's probably a local pointer
|
||||
temp = partial[0:4]
|
||||
local_pointer = "$" + temp
|
||||
else:
|
||||
errors += "found \": ; \" and another \" \" in line " + str(line_id) + ", but don't know what to do (debug15)" + "\n"
|
||||
errors += "line is: " + line + "\n"
|
||||
continue
|
||||
else:
|
||||
if len(partial) > 3 and partial[2] == ":": #14:3BAC
|
||||
temp = partial[2].split(":")[1]
|
||||
if len(temp) == 3 or len(temp) == 4:
|
||||
local_pointer = "$" + temp
|
||||
else:
|
||||
temp = temp.split(" ")[0]
|
||||
local_pointer = "$" + temp
|
||||
elif len(partial) == 4 or (len(partial) == 3 and is_probably_pointer(partial)):
|
||||
local_pointer = "$" + partial
|
||||
else:
|
||||
errors += "found \": ; \" in line " + str(line_id) + ", but don't know what to do (debug16)" + "\n"
|
||||
errors += "line is: " + line + "\n"
|
||||
continue
|
||||
else:
|
||||
#this line doesn't have a label
|
||||
continue
|
||||
|
||||
if local_pointer != None and not is_probably_pointer(local_pointer.replace("0x", "").replace("$", "")):
|
||||
continue
|
||||
|
||||
line_label = line.split(": ;")[0]
|
||||
|
||||
if address == None and local_pointer != None:
|
||||
temp = int(local_pointer.replace("$", "0x"), 16)
|
||||
if temp < 0x4000 or bank_id == 0:
|
||||
address = temp
|
||||
else:
|
||||
address = calculate_pointer(int(local_pointer.replace("$", "0x"), 16), bank_id)
|
||||
elif local_pointer == None and address != None:
|
||||
if address < 0x4000:
|
||||
local_pointer = hex(address).replace("0x", "$")
|
||||
else:
|
||||
local_pointer = hex((address % 0x4000) + 0x4000).replace("0x", "$")
|
||||
|
||||
print line_label + " is at " + hex(address)
|
||||
|
||||
label = {
|
||||
"line_number": line_id,
|
||||
"bank_id": bank_id,
|
||||
"label": line_label,
|
||||
"local_pointer": local_pointer,
|
||||
"address": address
|
||||
}
|
||||
labels.append(label)
|
||||
|
||||
current_line_offset += 1
|
||||
label_errors += errors
|
||||
return labels
|
||||
|
||||
def scan_for_predefined_labels():
|
||||
"""looks through the asm file for labels at specific addresses,
|
||||
this relies on the label having its address after. ex:
|
||||
|
||||
ViridianCity_h: ; 0x18357 to 0x18384 (45 bytes) (bank=6) (id=1)
|
||||
PalletTownText1: ; 4F96 0x18f96
|
||||
ViridianCityText1: ; 0x19102
|
||||
|
||||
It would be more productive to use rgbasm to spit out all label
|
||||
addresses, but faster to write this script. rgbasm would be able
|
||||
to grab all label addresses better than this script..
|
||||
"""
|
||||
bank_intervals = {}
|
||||
all_labels = []
|
||||
|
||||
if asm is None:
|
||||
load_asm()
|
||||
|
||||
#figure out line numbers for each bank
|
||||
for bank_id in range(0x2d):
|
||||
abbreviation = ("%.x" % (bank_id)).upper()
|
||||
abbreviation_next = ("%.x" % (bank_id+1)).upper()
|
||||
if bank_id == 0:
|
||||
abbreviation = "0"
|
||||
abbreviation_next = "1"
|
||||
|
||||
start_line_id = index(asm, lambda line: "\"bank" + abbreviation + "\"" in line)
|
||||
|
||||
if bank_id != 0x2c:
|
||||
end_line_id = index(asm, lambda line: "\"bank" + abbreviation_next + "\"" in line)
|
||||
else:
|
||||
end_line_id = len(asm) - 1
|
||||
|
||||
print "bank" + abbreviation + " starts at " + str(start_line_id) + " to " + str(end_line_id)
|
||||
|
||||
bank_intervals[bank_id] = {
|
||||
"start": start_line_id,
|
||||
"end": end_line_id,
|
||||
}
|
||||
|
||||
for bank_id in bank_intervals.keys():
|
||||
bank_data = bank_intervals[bank_id]
|
||||
|
||||
start_line_id = bank_data["start"]
|
||||
end_line_id = bank_data["end"]
|
||||
|
||||
labels = get_labels_between(start_line_id, end_line_id, bank_id)
|
||||
#bank_intervals[bank_id]["labels"] = labels
|
||||
all_labels.extend(labels)
|
||||
|
||||
write_all_labels(all_labels)
|
||||
return all_labels
|
||||
|
||||
def write_all_labels(all_labels):
|
||||
fh = open("labels.json", "w")
|
||||
fh.write(json.dumps(all_labels))
|
||||
fh.close()
|
||||
|
||||
def analyze_intervals():
|
||||
"""find the largest baserom.gbc intervals"""
|
||||
global asm
|
||||
global processed_incbins
|
||||
if asm == None:
|
||||
load_asm()
|
||||
if processed_incbins == {}:
|
||||
isolate_incbins()
|
||||
process_incbins()
|
||||
|
||||
results = []
|
||||
ordered_keys = sorted(processed_incbins, key=lambda entry: processed_incbins[entry]["interval"])
|
||||
ordered_keys.reverse()
|
||||
for key in ordered_keys:
|
||||
results.append(processed_incbins[key])
|
||||
|
||||
return results
|
||||
|
||||
if __name__ == "__main__":
|
||||
#load map headers
|
||||
load_rom()
|
||||
load_map_pointers()
|
||||
read_all_map_headers()
|
||||
|
||||
#load incbins (mandatory)
|
||||
load_asm()
|
||||
#isolate_incbins()
|
||||
#process_incbins()
|
||||
#print processed_incbins
|
||||
|
||||
#line_number = find_incbin_to_replace_for(0x492c3)
|
||||
#newlines = split_incbin_line_into_three(line_number, 0x492c3, 12)
|
||||
#diff = generate_diff_insert(line_number, newlines)
|
||||
#print diff
|
||||
|
||||
#insert_map_header_asm(86)
|
||||
#dump_all_remaining_maps()
|
||||
|
||||
scan_for_predefined_labels()
|
||||
print "Errors:"
|
||||
print label_errors
|
||||
|
@ -1,716 +0,0 @@
|
||||
#author: Bryan Bishop <kanzure@gmail.com>
|
||||
#date: 2012-01-06
|
||||
#analyze texts, how many commands are unknown?
|
||||
import extract_maps
|
||||
import analyze_incbins #for asm
|
||||
try:
|
||||
from pretty_map_headers import map_name_cleaner, txt_bytes, spacing, constant_abbreviation_bytes
|
||||
except Exception, exc: pass
|
||||
from operator import itemgetter
|
||||
import sys
|
||||
debug = False #set to True to increase logging output
|
||||
|
||||
#how many times is each command byte called?
|
||||
totals = {}
|
||||
total_text_commands = 0
|
||||
should_be_total = 0
|
||||
|
||||
def get_text_pointer(texts_pointer, text_id):
|
||||
if type(texts_pointer) == str: texts_pointer = int(texts_pointer, 16)
|
||||
if type(text_id) == str: text_id = int(text_id)
|
||||
|
||||
byte1 = ord(extract_maps.rom[texts_pointer + ((text_id - 1) * 2)])
|
||||
byte2 = ord(extract_maps.rom[texts_pointer + ((text_id - 1) * 2) + 1])
|
||||
pointer = (byte1 + (byte2 << 8))
|
||||
|
||||
return pointer
|
||||
|
||||
def how_many_until(byte, starting):
|
||||
index = extract_maps.rom.find(byte, starting)
|
||||
return index-starting
|
||||
|
||||
def print_command_debug_info(command_byte, text_id, text_pointer, map_id):
|
||||
if debug:
|
||||
print "byte is " + str(command_byte) + " on text #" + str(text_id) + " at " + hex(text_pointer) + " on map " + str(map_id) + " (" + extract_maps.map_headers[map_id]["name"] + ")"
|
||||
|
||||
def add_command_byte_to_totals(byte):
|
||||
global totals
|
||||
if not byte in totals.keys(): totals[byte] = 1
|
||||
else: totals[byte] += 1
|
||||
|
||||
def process_00_subcommands(start_address, end_address):
|
||||
"""split this text up into multiple lines
|
||||
based on subcommands ending each line"""
|
||||
lines = {}
|
||||
subsection = extract_maps.rom[start_address:end_address+1]
|
||||
|
||||
line_count = 0
|
||||
current_line = []
|
||||
for pbyte in subsection:
|
||||
byte = ord(pbyte)
|
||||
current_line.append(byte)
|
||||
if byte == 0x4f or byte == 0x51 or byte == 0x55:
|
||||
lines[line_count] = current_line
|
||||
current_line = []
|
||||
line_count += 1
|
||||
|
||||
#don't forget the last line
|
||||
lines[line_count] = current_line
|
||||
line_count += 1
|
||||
return lines
|
||||
|
||||
def parse_text_script(text_pointer, text_id, map_id, txfar=False):
|
||||
global total_text_commands
|
||||
offset = text_pointer
|
||||
commands = {}
|
||||
command_counter = 0
|
||||
|
||||
if extract_maps.rom == None:
|
||||
extract_maps.load_rom()
|
||||
|
||||
end = False
|
||||
while not end:
|
||||
command = {}
|
||||
command_byte = ord(extract_maps.rom[offset])
|
||||
|
||||
print_command_debug_info(command_byte, text_id, text_pointer, map_id)
|
||||
if command_byte == 0:
|
||||
#read until $57, $50 or $58
|
||||
jump57 = how_many_until(chr(0x57), offset)
|
||||
jump50 = how_many_until(chr(0x50), offset)
|
||||
jump58 = how_many_until(chr(0x58), offset)
|
||||
|
||||
#whichever command comes first
|
||||
jump = min([jump57, jump50, jump58])
|
||||
|
||||
end_address = offset + jump - 1 #we want the address before $57
|
||||
|
||||
command = {"type": command_byte,
|
||||
"start_address": offset,
|
||||
"end_address": end_address,
|
||||
"size": jump,
|
||||
"lines": process_00_subcommands(offset+1, end_address),
|
||||
}
|
||||
|
||||
offset += jump
|
||||
elif command_byte == 0x17:
|
||||
#TX_FAR [pointer][bank]
|
||||
pointer_byte1 = ord(extract_maps.rom[offset+1])
|
||||
pointer_byte2 = ord(extract_maps.rom[offset+2])
|
||||
pointer_bank = ord(extract_maps.rom[offset+3])
|
||||
|
||||
pointer = (pointer_byte1 + (pointer_byte2 << 8))
|
||||
pointer = extract_maps.calculate_pointer(pointer, pointer_bank)
|
||||
|
||||
command = {"type": command_byte,
|
||||
"start_address": offset,
|
||||
"end_address": offset + 3, #last byte belonging to this command
|
||||
"pointer": pointer, #parameter
|
||||
}
|
||||
|
||||
offset += 3 + 1
|
||||
elif command_byte == 0x50 or command_byte == 0x57 or command_byte == 0x58: #end text
|
||||
command = {"type": command_byte,
|
||||
"start_address": offset,
|
||||
"end_address": offset,
|
||||
}
|
||||
|
||||
#this byte simply indicates to end the script
|
||||
end = True
|
||||
|
||||
#this byte simply indicates to end the script
|
||||
if command_byte == 0x50 and ord(extract_maps.rom[offset+1]) == 0x50: #$50$50 means end completely
|
||||
end = True
|
||||
commands[command_counter+1] = command
|
||||
|
||||
#also save the next byte, before we quit
|
||||
commands[command_counter+1]["start_address"] += 1
|
||||
commands[command_counter+1]["end_address"] += 1
|
||||
add_command_byte_to_totals(command_byte)
|
||||
elif command_byte == 0x50: #only end if we started with $0
|
||||
if len(commands.keys()) > 0:
|
||||
if commands[0]["type"] == 0x0: end = True
|
||||
elif command_byte == 0x57 or command_byte == 0x58: #end completely
|
||||
end = True
|
||||
offset += 1 #go past this 0x50
|
||||
elif command_byte == 0x1:
|
||||
#01 = text from RAM. [01][2-byte pointer]
|
||||
size = 3 #total size, including the command byte
|
||||
pointer_byte1 = ord(extract_maps.rom[offset+1])
|
||||
pointer_byte2 = ord(extract_maps.rom[offset+2])
|
||||
|
||||
command = {"type": command_byte,
|
||||
"start_address": offset+1,
|
||||
"end_address": offset+2, #last byte belonging to this command
|
||||
"pointer": [pointer_byte1, pointer_byte2], #RAM pointer
|
||||
}
|
||||
|
||||
#view near these bytes
|
||||
#subsection = extract_maps.rom[offset:offset+size+1] #peak ahead
|
||||
#for x in subsection:
|
||||
# print hex(ord(x))
|
||||
#print "--"
|
||||
|
||||
offset += 2 + 1 #go to the next byte
|
||||
|
||||
#use this to look at the surrounding bytes
|
||||
if debug:
|
||||
print "next command is: " + hex(ord(extract_maps.rom[offset])) + " ... we are at command number: " + str(command_counter) + " near " + hex(offset) + " on map_id=" + str(map_id) + " for text_id=" + str(text_id) + " and txfar(recursion)=" + str(txfar)
|
||||
elif command_byte == 0x7:
|
||||
#07 = shift texts 1 row above (2nd line becomes 1st line); address for next text = 2nd line. [07]
|
||||
size = 1
|
||||
command = {"type": command_byte,
|
||||
"start_address": offset,
|
||||
"end_address": offset,
|
||||
}
|
||||
offset += 1
|
||||
elif command_byte == 0x3:
|
||||
#03 = set new address in RAM for text. [03][2-byte RAM address]
|
||||
size = 3
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset+2}
|
||||
offset += size
|
||||
elif command_byte == 0x4: #draw box
|
||||
#04 = draw box. [04][2-Byte pointer][height Y][width X]
|
||||
size = 5 #including the command
|
||||
command = {
|
||||
"type": command_byte,
|
||||
"start_address": offset,
|
||||
"end_address": offset + size,
|
||||
"pointer_bytes": [ord(extract_maps.rom[offset+1]), ord(extract_maps.rom[offset+2])],
|
||||
"y": ord(extract_maps.rom[offset+3]),
|
||||
"x": ord(extract_maps.rom[offset+4]),
|
||||
}
|
||||
offset += size + 1
|
||||
elif command_byte == 0x5:
|
||||
#05 = write text starting at 2nd line of text-box. [05][text][ending command]
|
||||
#read until $57, $50 or $58
|
||||
jump57 = how_many_until(chr(0x57), offset)
|
||||
jump50 = how_many_until(chr(0x50), offset)
|
||||
jump58 = how_many_until(chr(0x58), offset)
|
||||
|
||||
#whichever command comes first
|
||||
jump = min([jump57, jump50, jump58])
|
||||
|
||||
end_address = offset + jump - 1 #we want the address before $57
|
||||
|
||||
command = {"type": command_byte,
|
||||
"start_address": offset,
|
||||
"end_address": end_address,
|
||||
"size": jump,
|
||||
"lines": process_00_subcommands(offset+1, end_address),
|
||||
}
|
||||
offset = end_address + 1
|
||||
elif command_byte == 0x6:
|
||||
#06 = wait for keypress A or B (put blinking arrow in textbox). [06]
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0x7:
|
||||
#07 = shift texts 1 row above (2nd line becomes 1st line); address for next text = 2nd line. [07]
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0x8:
|
||||
#08 = asm until whenever
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
end = True
|
||||
elif command_byte == 0x9:
|
||||
#09 = write hex-to-dec number from RAM to textbox [09][2-byte RAM address][byte bbbbcccc]
|
||||
# bbbb = how many bytes to read (read number is big-endian)
|
||||
# cccc = how many digits display (decimal)
|
||||
#(note: max of decimal digits is 7,i.e. max number correctly displayable is 9999999)
|
||||
ram_address_byte1 = ord(extract_maps.rom[offset+1])
|
||||
ram_address_byte2 = ord(extract_maps.rom[offset+2])
|
||||
read_byte = ord(extract_maps.rom[offset+3])
|
||||
|
||||
command = {
|
||||
"type": command_byte,
|
||||
"address": [ram_address_byte1, ram_address_byte2],
|
||||
"read_byte": read_byte, #split this up when we make a macro for this
|
||||
}
|
||||
|
||||
offset += 4
|
||||
elif command_byte == 0xB:
|
||||
#0B = sound_86 (Hiro obtains ITEM)[same as 0F]
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0xE:
|
||||
#0E = sound_91 (learnt something)
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0xF:
|
||||
#0F = sound_86 (given rare candy)[same as 0B]
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0x10:
|
||||
#10 = sound_89 (PKMN successfully caught)
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0x11:
|
||||
#11 = sound_94 (Hiro gives OAK the PARCEL)
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0x12:
|
||||
#12 = sound_9A (successfully caught)
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0x13:
|
||||
#13 = sound_98 (song heard when "new data will be added for..")
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0x14:
|
||||
#14 = MonCry (Nidorina)
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0x15:
|
||||
#14 = MonCry (Pidgeot)
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0x16:
|
||||
#14 = MonCry (Dewgong)
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0x19:
|
||||
#19 = play a 'bump' noise
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0x1F:
|
||||
#1F = play some pokemon's roar, don't know which..
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0x20:
|
||||
#20 = oddish roar?
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0x3F:
|
||||
#3F = some other roar
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0x9D:
|
||||
#9D = a roar or some other sound, four times in quick succession
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0x76:
|
||||
#76 = another roar
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0xCA:
|
||||
#CA = stop music, start this other song that i can't name
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0xF6:
|
||||
#F6 = play a 'blurp blurp' noise.. like something is increasing
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0xFA:
|
||||
#FA = change music to champion song?
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0xFE:
|
||||
#FE = another roar, kinda glitchy?
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
elif command_byte == 0xFF:
|
||||
#FF = change music to a specific song that i don't know the name of
|
||||
command = {"type": command_byte, "start_address": offset, "end_address": offset}
|
||||
offset += 1
|
||||
else:
|
||||
#if len(commands) > 0:
|
||||
# print "Unknown text command " + hex(command_byte) + " at " + hex(offset) + ", script began with " + hex(commands[0]["type"])
|
||||
if debug:
|
||||
print "Unknown text command at " + hex(offset) + " - command: " + hex(ord(extract_maps.rom[offset])) + " on map_id=" + str(map_id) + " text_id=" + str(text_id)
|
||||
|
||||
#end at the first unknown command
|
||||
end = True
|
||||
add_command_byte_to_totals(command_byte)
|
||||
|
||||
commands[command_counter] = command
|
||||
command_counter += 1
|
||||
total_text_commands += len(commands)
|
||||
return commands
|
||||
|
||||
def analyze_texts():
|
||||
global should_be_total
|
||||
|
||||
texts = {}
|
||||
for map_id in extract_maps.map_headers:
|
||||
if map_id in extract_maps.bad_maps: continue #skip
|
||||
map2 = extract_maps.map_headers[map_id]
|
||||
map2["texts"] = {}
|
||||
referenced_texts = map2["referenced_texts"]
|
||||
should_be_total += len(referenced_texts)
|
||||
texts_pointer = int(map2["texts_pointer"], 16)
|
||||
|
||||
#print "Checking texts on... map_id=" + str(map_id) + " and len(referenced_texts)=" + str(len(referenced_texts))
|
||||
for text_id in referenced_texts:
|
||||
text_pointer = get_text_pointer(texts_pointer, text_id)
|
||||
if 0x4000 <= text_pointer <= 0x7fff: #only care about bank when it's between 4000-7fff
|
||||
text_pointer = extract_maps.calculate_pointer(text_pointer, int(map2["bank"], 16))
|
||||
#print "Working on map id=" + str(map2["id"]) + " and text id=" + str(text_id)
|
||||
#print "for map_id=" + str(map_id) + " texts_pointer=" + hex(texts_pointer) + " text_id=" + str(text_id) + " the pointer=" + hex(text_pointer)
|
||||
commands = parse_text_script(text_pointer, text_id, map_id)
|
||||
|
||||
#process TX_FARs
|
||||
for command_id in commands:
|
||||
#skip commands starting with an unknown command byte
|
||||
if len(commands[command_id]) == 0: continue
|
||||
|
||||
if commands[command_id]["type"] == 0x17:
|
||||
TX_FAR = parse_text_script(commands[command_id]["pointer"], text_id, map_id, txfar=True)
|
||||
if debug:
|
||||
if len(TX_FAR.keys()) > 0:
|
||||
#print "TX_FAR object: " + str(TX_FAR)
|
||||
print "processing a TX_FAR at " + hex(commands[command_id]["pointer"]) + "... first byte is: " + str(ord(extract_maps.rom[commands[command_id]["pointer"]])) + " .. offset: " + hex(commands[command_id]["pointer"])
|
||||
##sys.exit(0)
|
||||
|
||||
commands[command_id]["TX_FAR"] = TX_FAR
|
||||
#map2["texts"][text_id][command_id]["TX_FAR"] = parse_text_script(command["pointer"], text_id, map_id)
|
||||
map2["texts"][text_id] = commands
|
||||
|
||||
texts[map_id] = map2["texts"]
|
||||
extract_maps.map_headers[map_id]["texts"] = map2["texts"]
|
||||
return texts
|
||||
|
||||
def find_missing_08s(all_texts):
|
||||
"""determines which $08s have yet to be inserted
|
||||
based on their start addresses"""
|
||||
missing_08s = 0
|
||||
for map_id in all_texts.keys():
|
||||
for text_id in all_texts[map_id].keys():
|
||||
for line_id in all_texts[map_id][text_id].keys():
|
||||
if not line_id == 0:
|
||||
current_line = all_texts[map_id][text_id][line_id]
|
||||
if "type" in current_line.keys():
|
||||
if current_line["type"] == 0x8:
|
||||
missing_08s += 1
|
||||
print "missing $08 on map_id=" + str(map_id) + " text_id=" + str(text_id) + " line_id=" + str(line_id) + " at " + hex(current_line["start_address"])
|
||||
return missing_08s
|
||||
|
||||
def text_pretty_printer_at(start_address, label="SomeLabel"):
|
||||
commands = parse_text_script(start_address, None, None)
|
||||
needs_to_begin_with_0 = True #how should this be determined?
|
||||
|
||||
#wanted_command = None
|
||||
#if needs_to_begin_with_0:
|
||||
# wanted_command = None
|
||||
# for command_id in commands:
|
||||
# command = commands[command_id]
|
||||
# if command["type"] == 0:
|
||||
# wanted_command = command_id
|
||||
#
|
||||
# if wanted_command == None:
|
||||
# raise "error: address did not start with a $0 text"
|
||||
|
||||
#start with zero please
|
||||
byte_count = 0
|
||||
|
||||
output = ""
|
||||
had_text_end_byte = False
|
||||
had_text_end_byte_57_58 = False
|
||||
had_db_last = False
|
||||
first_line = True
|
||||
for this_command in commands.keys():
|
||||
if not "lines" in commands[this_command].keys():
|
||||
command = commands[this_command]
|
||||
if not "type" in command.keys():
|
||||
print "ERROR in command: " + str(command)
|
||||
continue #dunno what to do here?
|
||||
|
||||
if command["type"] == 0x1: #TX_RAM
|
||||
if first_line:
|
||||
output = "\n"
|
||||
output += label + ": ; " + hex(start_address)
|
||||
first_line = False
|
||||
p1 = command["pointer"][0]
|
||||
p2 = command["pointer"][1]
|
||||
|
||||
#remember to account for big endian -> little endian
|
||||
output += "\n" + spacing + "TX_RAM $%.2x%.2x" %(p2, p1)
|
||||
byte_count += 3
|
||||
had_db_last = False
|
||||
elif command["type"] == 0x17: #TX_FAR
|
||||
if first_line:
|
||||
output = "\n"
|
||||
output += label + ": ; " + hex(start_address)
|
||||
first_line = False
|
||||
#p1 = command["pointer"][0]
|
||||
#p2 = command["pointer"][1]
|
||||
output += "\n" + spacing + "TX_FAR _" + label + " ; " + hex(command["pointer"])
|
||||
byte_count += 4 #$17, bank, address word
|
||||
had_db_last = False
|
||||
elif command["type"] == 0x9: #TX_RAM_HEX2DEC
|
||||
if first_line:
|
||||
output = "\n" + label + ": ; " + hex(start_address)
|
||||
first_line = False
|
||||
#address, read_byte
|
||||
output += "\n" + spacing + "TX_NUM $%.2x%.2x, $%.2x" % (command["address"][1], command["address"][0], command["read_byte"])
|
||||
had_db_last = False
|
||||
byte_count += 4
|
||||
elif command["type"] == 0x50 and not had_text_end_byte:
|
||||
#had_text_end_byte helps us avoid repeating $50s
|
||||
if first_line:
|
||||
output = "\n" + label + ": ; " + hex(start_address)
|
||||
first_line = False
|
||||
if had_db_last:
|
||||
output += ", $50"
|
||||
else:
|
||||
output += "\n" + spacing + "db $50"
|
||||
byte_count += 1
|
||||
had_db_last = True
|
||||
elif command["type"] in [0x57, 0x58] and not had_text_end_byte_57_58:
|
||||
if first_line: #shouldn't happen, really
|
||||
output = "\n" + label + ": ; " + hex(start_address)
|
||||
first_line = False
|
||||
if had_db_last:
|
||||
output += ", $%.2x" % (command["type"])
|
||||
else:
|
||||
output += "\n" + spacing + "db $%.2x" % (command["type"])
|
||||
byte_count += 1
|
||||
had_db_last = True
|
||||
elif command["type"] in [0x57, 0x58] and had_text_end_byte_57_58:
|
||||
pass #this is ok
|
||||
elif command["type"] == 0x50 and had_text_end_byte:
|
||||
pass #this is also ok
|
||||
elif command["type"] == 0x0b:
|
||||
if first_line:
|
||||
output = "\n" + label + ": ; " + hex(start_address)
|
||||
first_line = False
|
||||
if had_db_last:
|
||||
output += ", $0b"
|
||||
else:
|
||||
output += "\n" + spacing + "db $0B"
|
||||
byte_count += 1
|
||||
had_db_last = True
|
||||
elif command["type"] == 0x11:
|
||||
if first_line:
|
||||
output = "\n" + label + ": ; " + hex(start_address)
|
||||
first_line = False
|
||||
if had_db_last:
|
||||
output += ", $11"
|
||||
else:
|
||||
output += "\n" + spacing + "db $11"
|
||||
byte_count += 1
|
||||
had_db_last = True
|
||||
elif command["type"] == 0x6: #wait for keypress
|
||||
if first_line:
|
||||
output = "\n" + label + ": ; " + hex(start_address)
|
||||
first_line = False
|
||||
if had_db_last:
|
||||
output += ", $6"
|
||||
else:
|
||||
output += "\n" + spacing + "db $6"
|
||||
byte_count += 1
|
||||
had_db_last = True
|
||||
else:
|
||||
print "ERROR in command: " + hex(command["type"])
|
||||
had_db_last = False
|
||||
|
||||
#everything else is for $0s, really
|
||||
continue
|
||||
lines = commands[this_command]["lines"]
|
||||
|
||||
#reset this in case we have non-$0s later
|
||||
had_db_last = False
|
||||
|
||||
#add the ending byte to the last line- always seems $57
|
||||
#this should already be in there, but it's not because of a bug in the text parser
|
||||
lines[len(lines.keys())-1].append(commands[len(commands.keys())-1]["type"])
|
||||
|
||||
if first_line:
|
||||
output = "\n"
|
||||
output += label + ": ; " + hex(start_address) + "\n"
|
||||
first_line = False
|
||||
else:
|
||||
output += "\n"
|
||||
|
||||
first = True #first byte
|
||||
for line_id in lines:
|
||||
line = lines[line_id]
|
||||
output += spacing + "db "
|
||||
if first and needs_to_begin_with_0:
|
||||
output += "$0, "
|
||||
first = False
|
||||
byte_count += 1
|
||||
|
||||
quotes_open = False
|
||||
first_byte = True
|
||||
was_byte = False
|
||||
for byte in line:
|
||||
if byte == 0x50:
|
||||
had_text_end_byte = True #don't repeat it
|
||||
if byte in [0x58, 0x57]:
|
||||
had_text_end_byte_57_58 = True
|
||||
|
||||
if byte in txt_bytes:
|
||||
if not quotes_open and not first_byte: #start text
|
||||
output += ", \""
|
||||
quotes_open = True
|
||||
first_byte = False
|
||||
if not quotes_open and first_byte: #start text
|
||||
output += "\""
|
||||
quotes_open = True
|
||||
output += txt_bytes[byte]
|
||||
elif byte in constant_abbreviation_bytes:
|
||||
if quotes_open:
|
||||
output += "\""
|
||||
quotes_open = False
|
||||
if not first_byte:
|
||||
output += ", "
|
||||
output += constant_abbreviation_bytes[byte]
|
||||
else:
|
||||
if quotes_open:
|
||||
output += "\""
|
||||
quotes_open = False
|
||||
|
||||
#if you want the ending byte on the last line
|
||||
#if not (byte == 0x57 or byte == 0x50 or byte == 0x58):
|
||||
if not first_byte:
|
||||
output += ", "
|
||||
|
||||
output += "$" + hex(byte)[2:]
|
||||
was_byte = True
|
||||
|
||||
#add a comma unless it's the end of the line
|
||||
#if byte_count+1 != len(line):
|
||||
# output += ", "
|
||||
|
||||
first_byte = False
|
||||
byte_count += 1
|
||||
#close final quotes
|
||||
if quotes_open:
|
||||
output += "\""
|
||||
quotes_open = False
|
||||
|
||||
output += "\n"
|
||||
include_newline = "\n"
|
||||
if len(output)!=0 and output[-1] == "\n":
|
||||
include_newline = ""
|
||||
output += include_newline + "; " + hex(start_address) + " + " + str(byte_count) + " bytes = " + hex(start_address + byte_count)
|
||||
print output
|
||||
return (output, byte_count)
|
||||
|
||||
def is_label_in_asm(label):
|
||||
for line in analyze_incbins.asm:
|
||||
if label in line:
|
||||
if line[0:len(label)] == label:
|
||||
return True
|
||||
return False
|
||||
|
||||
def find_undone_texts():
|
||||
usable_table = {}
|
||||
if analyze_incbins.asm == None:
|
||||
analyze_incbins.load_asm()
|
||||
|
||||
for map_id in extract_maps.map_headers:
|
||||
#skip bad maps
|
||||
if map_id in extract_maps.bad_maps: continue
|
||||
|
||||
map2 = extract_maps.map_headers[map_id]
|
||||
name = map_name_cleaner(map2["name"], None)[:-2] + "Text"
|
||||
|
||||
for text_id in map2["referenced_texts"]:
|
||||
label = name + str(text_id)
|
||||
|
||||
if len(extract_maps.map_headers[map_id]["texts"][text_id].keys()) == 0: continue
|
||||
if len(extract_maps.map_headers[map_id]["texts"][text_id][0].keys()) == 0: continue
|
||||
|
||||
try:
|
||||
address = extract_maps.map_headers[map_id]["texts"][text_id][0]["start_address"]
|
||||
except:
|
||||
address = extract_maps.map_headers[map_id]["texts"][text_id][1]["start_address"]
|
||||
|
||||
if not is_label_in_asm(label):
|
||||
print label + " map_id=" + str(map_id) + " text_id=" + str(text_id) + " at " + hex(address) + " byte is: " + hex(ord(extract_maps.rom[address]))
|
||||
if not address in usable_table.keys():
|
||||
usable_table[address] = 1
|
||||
else:
|
||||
usable_table[address] += 1
|
||||
|
||||
print "\n\n which ones are priority?"
|
||||
sorted_results = sorted(usable_table.iteritems(), key=itemgetter(1), reverse=True)
|
||||
for result in sorted_results:
|
||||
print str(result[1]) + " times: " + hex(result[0])
|
||||
|
||||
def scan_rom_for_tx_fars(printer=True):
|
||||
"""find TX_FARs
|
||||
search only addresses that are INCBINed
|
||||
keep only TX_FARs that are valid
|
||||
|
||||
returns a list of [TX_FAR target address, TX_FAR address]"""
|
||||
rom = extract_maps.rom
|
||||
|
||||
analyze_incbins.load_asm()
|
||||
analyze_incbins.isolate_incbins()
|
||||
analyze_incbins.process_incbins()
|
||||
|
||||
possible_tx_fars = []
|
||||
possible_tx_far_targets = []
|
||||
|
||||
for incbin_line_number in analyze_incbins.processed_incbins.keys():
|
||||
incbin = analyze_incbins.processed_incbins[incbin_line_number]
|
||||
start_address = incbin["start"]
|
||||
end_address = incbin["end"]
|
||||
if incbin["interval"] == 0: continue #skip this one
|
||||
|
||||
subrom = rom[start_address:end_address]
|
||||
for address in range(start_address, end_address):
|
||||
current_byte = ord(rom[address])
|
||||
if current_byte == 0x17:
|
||||
if ord(rom[address+4]) == 0x50:
|
||||
byte1 = ord(rom[address+1])
|
||||
byte2 = ord(rom[address+2])
|
||||
address2 = byte1 + (byte2 << 8)
|
||||
if address2 > 0x3fff:
|
||||
address2 = extract_maps.calculate_pointer(address2, ord(rom[address+3]))
|
||||
#print "possible TX_FAR at " + hex(address) + " to " + hex(address2)
|
||||
|
||||
possible_tx_fars.append(address)
|
||||
possible_tx_far_targets.append([address2, address])
|
||||
|
||||
if printer:
|
||||
pre_handled = []
|
||||
#address_bundle is [TX_FAR target address, TX_FAR address]
|
||||
for address_bundle in possible_tx_far_targets:
|
||||
if address_bundle[0] in [0xa82f8, 0xa8315]:
|
||||
continue #bad
|
||||
if address_bundle[0] in pre_handled:
|
||||
continue #already did this
|
||||
|
||||
print "-------"
|
||||
print "TX_FAR is at: " + hex(address_bundle[1])
|
||||
|
||||
#let's try printing out the TX_FAR?
|
||||
text_pretty_printer_at(address_bundle[1], "blah")
|
||||
|
||||
text_pretty_printer_at(address_bundle[0], "_blah")
|
||||
print "-------"
|
||||
pre_handled.append(address_bundle[0])
|
||||
return possible_tx_far_targets
|
||||
|
||||
if __name__ == "__main__":
|
||||
extract_maps.load_rom()
|
||||
extract_maps.load_map_pointers()
|
||||
extract_maps.read_all_map_headers()
|
||||
#text_output = analyze_texts()
|
||||
#print text_output
|
||||
|
||||
#these aren't really "missing", just a certain type that was
|
||||
#known to be missed on a first pass.
|
||||
#missing_08s = find_missing_08s(text_output)
|
||||
|
||||
#print "\n\n---- stats ----\n\n"
|
||||
|
||||
#popular_text_commands = sorted(totals.iteritems(), key=itemgetter(1), reverse=True)
|
||||
#convert the first values (command byte) to hex
|
||||
#for popular_item in popular_text_commands:
|
||||
# print hex(popular_item[0]) + " was used " + str(popular_item[1]) + " times."
|
||||
#print "popular text commands: " + str(popular_text_commands)
|
||||
|
||||
#print "total text commands: " + str(total_text_commands)
|
||||
#print "total text scripts: " + str(should_be_total)
|
||||
#print "missing 08s: " + str(missing_08s)
|
||||
#print "\n\n"
|
||||
|
||||
#text_pretty_printer_at(0x800b1)
|
||||
#find_undone_texts()
|
||||
|
||||
scan_rom_for_tx_fars()
|
@ -1,104 +0,0 @@
|
||||
#author: Bryan Bishop <kanzure@gmail.com>
|
||||
#date: 2012-01-15
|
||||
#help with connection math
|
||||
import extract_maps
|
||||
from pretty_map_headers import map_constants, map_name_cleaner, offset_to_pointer
|
||||
|
||||
def print_connections(map_id, in_connection_id=None, do_output=False):
|
||||
map1 = extract_maps.map_headers[map_id]
|
||||
map1_name = map1["name"]
|
||||
connections = map1["connections"]
|
||||
output = ""
|
||||
|
||||
if in_connection_id != None:
|
||||
connections2 = {}
|
||||
connections2[in_connection_id] = connections[in_connection_id]
|
||||
connections = connections2
|
||||
|
||||
for connection_id in connections:
|
||||
connection = connections[connection_id]
|
||||
direction = connection["direction"]
|
||||
connected_pointer = int(connection["connected_map_tile_pointer"], 16)
|
||||
current_pointer = int(connection["current_map_tile_pointer"], 16)
|
||||
map2_id = connection["map_id"]
|
||||
map2 = extract_maps.map_headers[map2_id]
|
||||
map2_name = map2["name"]
|
||||
map2_cname = map_name_cleaner(map2["name"], None)[:-2]
|
||||
map2_bank = int(map2["bank"], 16)
|
||||
map2_blocks_pointer = offset_to_pointer(int(map2["map_pointer"], 16))
|
||||
map2_height = int(map2["y"], 16)
|
||||
map2_width = int(map2["x"], 16)
|
||||
|
||||
output += map1_name + " (id=" + str(map_id) + ") " + direction + " to " + map2_name + "\n"
|
||||
output += "map2 blocks pointer: " + hex(map2_blocks_pointer) + "\n"
|
||||
output += "map2 height: " + str(map2_height) + "\n"
|
||||
output += "map2 width: " + str(map2_width) + "\n"
|
||||
output += "map1 connection pointer: " + hex(connected_pointer) + "\n"
|
||||
|
||||
shift = 0
|
||||
#not sure about the calculated shift for NORTH or SOUTH
|
||||
if direction == "NORTH":
|
||||
calculated = map2_blocks_pointer + (map2_height - 3) * map2_width
|
||||
result = connected_pointer - calculated
|
||||
if result != 0:
|
||||
shift = result #seems to always be 2?
|
||||
calculated = map2_blocks_pointer + (map2_height - 3) * map2_width + shift
|
||||
output += "shift: " + str(shift) + "\n"
|
||||
formula = map2_cname + "Blocks + (" + map2_cname + "Height - 3) * " + map2_cname + "Width + " + str(shift)
|
||||
else:
|
||||
formula = map2_cname + "Blocks + (" + map2_cname + "Height - 3) * " + map2_cname + "Width"
|
||||
elif direction == "SOUTH":
|
||||
calculated = map2_blocks_pointer
|
||||
result = connected_pointer - calculated
|
||||
formula = map2_cname + "Blocks"
|
||||
if result != 0:
|
||||
shift = result
|
||||
calculated = map2_blocks_pointer + shift
|
||||
output += "shift: " + str(shift) + "\n"
|
||||
formula += " + " + str(shift)
|
||||
elif direction == "WEST":
|
||||
calculated = map2_blocks_pointer - 3 + (map2_width)
|
||||
result = connected_pointer - calculated
|
||||
formula = map2_cname + "Blocks - 3 + (" + map2_cname + "Width)"
|
||||
if result != 0:
|
||||
shift = result / map2_width
|
||||
shift += 1
|
||||
calculated = map2_blocks_pointer - 3 + (map2_width * shift)
|
||||
output += "shift: " + str(shift) + "\n"
|
||||
formula = map2_cname + "Blocks - 3 + (" + map2_cname + "Width * " + str(shift) + ")"
|
||||
elif direction == "EAST":
|
||||
calculated = map2_blocks_pointer + (map2_width)
|
||||
result = connected_pointer - calculated
|
||||
output += ".. result is: " + str(result) + "\n"
|
||||
formula = map2_cname + "Blocks + (" + map2_cname + "Width)"
|
||||
if result != 0:
|
||||
shift = result / map2_width
|
||||
shift += 1
|
||||
calculated = map2_blocks_pointer + (map2_width * shift)
|
||||
output += "shift: " + str(shift) + "\n"
|
||||
formula = map2_cname + "Blocks" + " + (" + map2_cname + "Width * " + str(shift) + ")"
|
||||
|
||||
output += "formula: " + formula + "\n"
|
||||
|
||||
result = connected_pointer - calculated
|
||||
output += "result: " + str(result) + "\n"
|
||||
|
||||
output += "\n\n"
|
||||
|
||||
if in_connection_id != None:
|
||||
return formula
|
||||
if do_output == True:
|
||||
return output
|
||||
|
||||
if __name__ == "__main__":
|
||||
extract_maps.load_rom()
|
||||
extract_maps.load_map_pointers()
|
||||
extract_maps.read_all_map_headers()
|
||||
|
||||
#trouble:
|
||||
#print_connections(13)
|
||||
#print_connections(15)
|
||||
|
||||
for map_id in extract_maps.map_headers.keys():
|
||||
if map_id not in extract_maps.bad_maps:
|
||||
print print_connections(map_id, do_output=True)
|
@ -1,702 +0,0 @@
|
||||
#author: Bryan Bishop <kanzure@gmail.com>
|
||||
#date: 2012-01-02
|
||||
#url: http://hax.iimarck.us/files/rbheaders.txt
|
||||
import json
|
||||
|
||||
#parse hex values as base 16 (see calculate_pointer)
|
||||
base = 16
|
||||
|
||||
#where to load the rom from
|
||||
rom_filename = "../baserom.gbc"
|
||||
rom = None #load the rom later
|
||||
|
||||
#map header pointers start at 0x1AE
|
||||
start_map_header_pointers = 0x1AE
|
||||
|
||||
#bank bytes for each map header start at 0xC23D
|
||||
start_map_header_pointer_banks = 0xC23D
|
||||
|
||||
#number of maps in this list
|
||||
map_count = 0xF8 #including the 0th the total is is 248 or 0xF8
|
||||
|
||||
bad_maps = [0x0b, 0x45, 0x4b, 0x4e, 0x69, 0x6a, 0x6b, 0x6d, 0x6e, 0x6f, 0x70, 0x72, 0x73, 0x74, 0x75, 0xad, 0xcc, 0xcd, 0xce, 0xe7, 0xed, 0xee, 0xf1, 0xf2, 0xf3, 0xf4]
|
||||
|
||||
maps = {
|
||||
0x00: "Pallet Town",
|
||||
0x01: "Viridian City",
|
||||
0x02: "Pewter City",
|
||||
0x03: "Cerulean City",
|
||||
0x04: "Lavender Town", #??
|
||||
0x05: "Vermilion City", #correct
|
||||
0x06: "Celadon City",
|
||||
0x07: "Fuchsia City",
|
||||
0x08: "Cinnabar Island",
|
||||
0x09: "Indigo Plateau",
|
||||
0x0A: "Saffron City",
|
||||
0x0B: "FREEZE",
|
||||
0x0C: "Route 1",
|
||||
0x0D: "Route 2",
|
||||
0x0E: "Route 3",
|
||||
0x0F: "Route 4",
|
||||
0x10: "Route 5",
|
||||
0x11: "Route 6",
|
||||
0x12: "Route 7",
|
||||
0x13: "Route 8",
|
||||
0x14: "Route 9",
|
||||
0x15: "Route 10",
|
||||
0x16: "Route 11",
|
||||
0x17: "Route 12",
|
||||
0x18: "Route 13",
|
||||
0x19: "Route 14",
|
||||
0x1A: "Route 15",
|
||||
0x1B: "Route 16",
|
||||
0x1C: "Route 17",
|
||||
0x1D: "Route 18",
|
||||
0x1E: "Route 19",
|
||||
0x1F: "Route 20",
|
||||
0x20: "Route 21",
|
||||
0x21: "Route 22",
|
||||
0x22: "Route 23",
|
||||
0x23: "Route 24",
|
||||
0x24: "Route 25",
|
||||
0x25: "Red's House 1F",
|
||||
0x26: "Red's House 2F",
|
||||
0x27: "Blue's House",
|
||||
0x28: "Oak's Lab",
|
||||
0x29: "Viridian Poke Center",
|
||||
0x2A: "Viridian Mart",
|
||||
0x2B: "School",
|
||||
0x2C: "Viridian House",
|
||||
0x2D: "Viridian Gym",
|
||||
0x2E: "Digletts Cave (Route 2)",
|
||||
0x2F: "Viridian Forest (exit)",
|
||||
0x30: "Route 2 House",
|
||||
0x31: "Route 2 Gate",
|
||||
0x32: "Viridian Forest (Entrance)",
|
||||
0x33: "Viridian Forest",
|
||||
0x34: "Museum F1",
|
||||
0x35: "Museum F2",
|
||||
0x36: "Pewter Gym",
|
||||
0x37: "Pewter House (1)",
|
||||
0x38: "Pewter Mart",
|
||||
0x39: "Pewter House (2)",
|
||||
0x3A: "Pewter Pokecenter",
|
||||
0x3B: "Mt. Moon (1)",
|
||||
0x3C: "Mt. Moon (2)",
|
||||
0x3D: "Mt. Moon (3)",
|
||||
0x3E: "Cerulean House (Trashed)",
|
||||
0x3F: "Cerulean House (2)",
|
||||
0x40: "Cerulean Pokecenter",
|
||||
0x41: "Cerulean Gym",
|
||||
0x42: "Bike Shop",
|
||||
0x43: "Cerulean Mart",
|
||||
0x44: "Mt. Moon Pokecenter",
|
||||
0x45: "COPY OF: Trashed House",
|
||||
0x46: "Route 5 Gate",
|
||||
0x47: "Underground Tunnel Entrance (Route 5)",
|
||||
0x48: "Day Care M",
|
||||
0x49: "Route 6 Gate",
|
||||
0x4A: "Underground Tunnel Entrance (Route 6)",
|
||||
0x4B: "COPY OF: Underground Tunnel Entrance (Route 6)",
|
||||
0x4C: "Route 7 Gate",
|
||||
0x4D: "Underground Path Entrance (Route 7)",
|
||||
0x4E: "COPY OF: Underground Path Entrance (Route 7)",
|
||||
0x4F: "Route 8 Gate",
|
||||
0x50: "Underground Path Entrance (Route 8)",
|
||||
0x51: "Rock Tunnel Pokecenter",
|
||||
0x52: "Rock Tunnel (1)",
|
||||
0x53: "Power Plant",
|
||||
0x54: "Route 11 Gate",
|
||||
0x55: "Digletts Cave Entrance (Route 11)",
|
||||
0x56: "Route 11 Gate (Upstairs)",
|
||||
0x57: "Route 12 Gate",
|
||||
0x58: "Bill's House",
|
||||
0x59: "Vermilion Pokecenter",
|
||||
0x5A: "Fan Club",
|
||||
0x5B: "Vermilion Mart",
|
||||
0x5C: "Vermilion Gym",
|
||||
0x5D: "Vermilion House (1)",
|
||||
0x5E: "Vermilion Dock",
|
||||
0x5F: "S.S. Anne (1)",
|
||||
0x60: "S.S. Anne (2)",
|
||||
0x61: "S.S. Anne (3)",
|
||||
0x62: "S.S. Anne (4)",
|
||||
0x63: "S.S. Anne (5)",
|
||||
0x64: "S.S. Anne (6)",
|
||||
0x65: "S.S. Anne (7)",
|
||||
0x66: "S.S. Anne (8)",
|
||||
0x67: "S.S. Anne (9)",
|
||||
0x68: "S.S. Anne (10)",
|
||||
0x69: "FREEZE",
|
||||
0x6A: "FREEZE",
|
||||
0x6B: "FREEZE",
|
||||
0x6C: "Victory Road (1)",
|
||||
0x6D: "FREEZE",
|
||||
0x6E: "FREEZE",
|
||||
0x6F: "FREEZE",
|
||||
0x70: "FREEZE",
|
||||
0x71: "Lance",
|
||||
0x72: "FREEZE",
|
||||
0x73: "FREEZE",
|
||||
0x74: "FREEZE",
|
||||
0x75: "FREEZE",
|
||||
0x76: "Hall of Fame Room",
|
||||
0x77: "Underground Path (N/S)",
|
||||
0x78: "Gary",
|
||||
0x79: "Underground Path (W/E)",
|
||||
0x7A: "Celadon Mart (1)",
|
||||
0x7B: "Celadon Mart (2)",
|
||||
0x7C: "Celadon Mart (3)",
|
||||
0x7D: "Celadon Mart (4)",
|
||||
0x7E: "Celadon Mart Roof",
|
||||
0x7F: "Celadon Mart Elevator",
|
||||
0x80: "Celadon Mansion (1)",
|
||||
0x81: "Celadon Mansion (2)",
|
||||
0x82: "Celadon Mansion (3)",
|
||||
0x83: "Celadon Mansion (4)",
|
||||
0x84: "Celadon Mansion (5)",
|
||||
0x85: "Celadon Pokecenter",
|
||||
0x86: "Celadon Gym",
|
||||
0x87: "Celadon Game Corner",
|
||||
0x88: "Celadon Mart 5",
|
||||
0x89: "Celadon Prize Room",
|
||||
0x8A: "Celadon Diner",
|
||||
0x8B: "Celadon House",
|
||||
0x8C: "Celadon Hotel",
|
||||
0x8D: "Lavender Pokecenter",
|
||||
0x8E: "Pokemon Tower (1)",
|
||||
0x8F: "Pokemon Tower (2)",
|
||||
0x90: "Pokemon Tower (3)",
|
||||
0x91: "Pokemon Tower (4)",
|
||||
0x92: "Pokemon Tower (5)",
|
||||
0x93: "Pokemon Tower (6) ",
|
||||
0x94: "Pokemon Tower (7)",
|
||||
0x95: "Lavender House (1)",
|
||||
0x96: "Lavender Mart",
|
||||
0x97: "Lavender House (2)",
|
||||
0x98: "Fuchsia Mart",
|
||||
0x99: "Fuchsia House (1)",
|
||||
0x9A: "Fuchsia Pokecenter",
|
||||
0x9B: "Fuchsia House (2)",
|
||||
0x9C: "Safari Zone Entrance",
|
||||
0x9D: "Fuchsia Gym",
|
||||
0x9E: "Fuchsia Meeting Room",
|
||||
0x9F: "Seafoam Islands (2)",
|
||||
0xA0: "Seafoam Islands (3)",
|
||||
0xA1: "Seafoam Islands (4)",
|
||||
0xA2: "Seafoam Islands (5)",
|
||||
0xA3: "Vermilion House (2)",
|
||||
0xA4: "Fuchsia House (3)",
|
||||
0xA5: "Mansion (1)",
|
||||
0xA6: "Cinnabar Gym",
|
||||
0xA7: "Lab (1)",
|
||||
0xA8: "Lab (2)",
|
||||
0xA9: "Lab (3)",
|
||||
0xAA: "Lab (4)",
|
||||
0xAB: "Cinnabar Pokecenter",
|
||||
0xAC: "Cinnabar Mart",
|
||||
0xAD: "COPY: Cinnabar Mart",
|
||||
0xAE: "Indigo Plateau Lobby",
|
||||
0xAF: "Copycat's House F1",
|
||||
0xB0: "Copycat's House F2",
|
||||
0xB1: "Fighting Dojo",
|
||||
0xB2: "Saffron Gym",
|
||||
0xB3: "Saffron House (1)",
|
||||
0xB4: "Saffron Mart",
|
||||
0xB5: "Silph Co (1)",
|
||||
0xB6: "Saffron Pokecenter",
|
||||
0xB7: "Saffron House (2)",
|
||||
0xB8: "Route 15 Gate",
|
||||
0xBA: "Route 16 Gate Map",
|
||||
0xBB: "Route 16 Gate Upstairs",
|
||||
0xBC: "Route 16 House",
|
||||
0xBD: "Route 12 House",
|
||||
0xBE: "Route 18 Gate",
|
||||
0xBF: "Route 18 Gate Header",
|
||||
0xC0: "Seafoam Islands (1)",
|
||||
0xC1: "Route 22 Gate",
|
||||
0xC2: "Victory Road (2)",
|
||||
0xC3: "Route 12 Gate Upstairs",
|
||||
0xC4: "Vermilion House (3)",
|
||||
0xC5: "Diglett's Cave",
|
||||
0xC6: "Victory Road (3)",
|
||||
0xC7: "Rocket Hideout (1)",
|
||||
0xC8: "Rocket Hideout (2)",
|
||||
0xC9: "Rocket Hideout (3)",
|
||||
0xCA: "Rocket Hideout (4) ",
|
||||
0xCB: "Rocket Hideout (Elevator)",
|
||||
0xCC: "FREEZE",
|
||||
0xCD: "FREEZE",
|
||||
0xCE: "FREEZE",
|
||||
0xCF: "Silph Co (2)",
|
||||
0xD0: "Silph Co (3)",
|
||||
0xD1: "Silph Co (4)",
|
||||
0xD2: "Silph Co (5)",
|
||||
0xD3: "Silph Co (6)",
|
||||
0xD4: "Silph Co (7)",
|
||||
0xD5: "Silph Co (8)",
|
||||
0xD6: "Mansion (2)",
|
||||
0xD7: "Mansion (3)",
|
||||
0xD8: "Mansion (4)",
|
||||
0xD9: "Safari Zone East",
|
||||
0xDA: "Safari Zone North",
|
||||
0xDB: "Safari Zone West",
|
||||
0xDC: "Safari Zone Center",
|
||||
0xDD: "Safari Zone Rest House (1)",
|
||||
0xDE: "Safari Zone Secret House",
|
||||
0xDF: "Safari Zone Rest House (2)",
|
||||
0xE0: "Safari Zone Rest House (3)",
|
||||
0xE1: "Safari Zone Rest House (4)",
|
||||
0xE2: "Unknown Dungeon (2)",
|
||||
0xE3: "Unknown Dungeon (3)",
|
||||
0xE4: "Unknown Dungeon (1)",
|
||||
0xE5: "Name Rater",
|
||||
0xE6: "Cerulean House (3)",
|
||||
0xE7: "FREEZE",
|
||||
0xE8: "Rock Tunnel (2)",
|
||||
0xE9: "Silph Co (9)",
|
||||
0xEA: "Silph Co (10)",
|
||||
0xEB: "Silph Co (11)",
|
||||
0xEC: "Silph Co (Elevator)",
|
||||
0xED: "FREEZE",
|
||||
0xEE: "FREEZE",
|
||||
0xEF: "Battle Center M",
|
||||
0xF0: "Trade Center M",
|
||||
0xF1: "FREEZE",
|
||||
0xF2: "FREEZE",
|
||||
0xF3: "FREEZE",
|
||||
0xF4: "FREEZE",
|
||||
0xF5: "Lorelei",
|
||||
0xF6: "Bruno",
|
||||
0xF7: "Agatha"
|
||||
}
|
||||
|
||||
map_pointers = {
|
||||
#0x00: {
|
||||
# "name": "Pallet Town",
|
||||
# "address": 0x182a1
|
||||
# },
|
||||
}
|
||||
|
||||
map_headers = {
|
||||
#0x00: {
|
||||
# "name": "Pallet Town",
|
||||
# "address": 0x182a1,
|
||||
# "tileset"
|
||||
# "y"
|
||||
# "x"
|
||||
# "map_pointer"
|
||||
# "texts_pointer"
|
||||
# "script_pointer"
|
||||
# "connection_byte"
|
||||
# "num_connections"
|
||||
# "connections":
|
||||
# { "0":
|
||||
# { map_id, connected_map_tile_pointer, current_map_tile_pointer, bigness, width, y, x, window_pointer }
|
||||
# },
|
||||
# "object_data_pointer"
|
||||
# },
|
||||
}
|
||||
|
||||
#haters gonna hate
|
||||
def load_rom(filename=None):
|
||||
"load the rom into a global (returns True/False)"
|
||||
global rom
|
||||
|
||||
if not filename:
|
||||
filename = rom_filename
|
||||
|
||||
try:
|
||||
rom = open(filename, "rb").read()
|
||||
return True
|
||||
except Exception, exception:
|
||||
print "error loading rom"
|
||||
return False
|
||||
|
||||
def assert_rom():
|
||||
global rom
|
||||
assert rom, "rom must be loaded, see load_rom()"
|
||||
|
||||
def calculate_pointer(short_pointer, bank):
|
||||
short_pointer = int(short_pointer)
|
||||
bank = int(bank)
|
||||
|
||||
pointer = short_pointer - 0x4000 + (bank * 0x4000)
|
||||
|
||||
#result will be an integer
|
||||
return pointer
|
||||
|
||||
def get_nth_map_header_pointer_bank_byte_address(map_id):
|
||||
"returns the address to the bank byte associated with this map pointer"
|
||||
address = start_map_header_pointer_banks + map_id
|
||||
return address
|
||||
|
||||
def get_nth_map_header_pointer_bank_byte(map_id):
|
||||
"returns the bank number for this map header"
|
||||
assert_rom()
|
||||
|
||||
address = get_nth_map_header_pointer_bank_byte_address(map_id)
|
||||
bank_byte = ord(rom[address])
|
||||
return bank_byte
|
||||
|
||||
def get_nth_map_header_pointer(map_id):
|
||||
"returns the full pointer to the map header struct for this map"
|
||||
assert_rom()
|
||||
|
||||
#figure out where the bytes for this pointer are located
|
||||
byte1_address = start_map_header_pointers + (map_id * 2)
|
||||
byte2_address = start_map_header_pointers + (map_id * 2) + 1
|
||||
|
||||
#grab the two bytes making up the partial pointer
|
||||
byte1 = ord(rom[byte1_address])
|
||||
byte2 = ord(rom[byte2_address])
|
||||
|
||||
#swap the bytes (16-bit pointers for z80 are little endian)
|
||||
temp = byte1
|
||||
byte1 = byte2
|
||||
byte2 = temp
|
||||
del temp
|
||||
|
||||
#combine these into a single pointer (0x byte1 byte2)
|
||||
partial_pointer = (byte2 + (byte1 << 8))
|
||||
#print hex(partial_pointer)
|
||||
|
||||
#get the bank id
|
||||
bank = get_nth_map_header_pointer_bank_byte(map_id)
|
||||
|
||||
#calculate the full pointer
|
||||
pointer = calculate_pointer(partial_pointer, bank)
|
||||
|
||||
#return it as an integer
|
||||
return pointer
|
||||
|
||||
def load_map_pointers():
|
||||
global maps
|
||||
global map_pointers
|
||||
|
||||
for map in maps.keys():
|
||||
pointer = get_nth_map_header_pointer(map)
|
||||
#print maps[map] + "\t\t\t" + hex(pointer)
|
||||
|
||||
entry = {
|
||||
"name": maps[map],
|
||||
"address": hex(pointer),
|
||||
"bank": hex(get_nth_map_header_pointer_bank_byte(map))
|
||||
}
|
||||
map_pointers[map] = entry
|
||||
|
||||
#print json.dumps(map_pointers)
|
||||
|
||||
def read_connection_bytes(connection_bytes, bank):
|
||||
map_id = ord(connection_bytes[0])
|
||||
|
||||
#connection strip
|
||||
connected_map_tile_pointer_byte1 = ord(connection_bytes[1])
|
||||
connected_map_tile_pointer_byte2 = ord(connection_bytes[2])
|
||||
connected_map_tile_pointer = (connected_map_tile_pointer_byte1 + (connected_map_tile_pointer_byte2 << 8))
|
||||
|
||||
#connection strip
|
||||
current_map_tile_pointer_byte1 = ord(connection_bytes[3])
|
||||
current_map_tile_pointer_byte2 = ord(connection_bytes[4])
|
||||
current_map_tile_pointer = (current_map_tile_pointer_byte1 + (current_map_tile_pointer_byte2 << 8))
|
||||
|
||||
bigness_byte = ord(connection_bytes[5])
|
||||
width_byte = ord(connection_bytes[6])
|
||||
y = ord(connection_bytes[7])
|
||||
x = ord(connection_bytes[8])
|
||||
|
||||
#window
|
||||
window_pointer_byte1 = ord(connection_bytes[9])
|
||||
window_pointer_byte2 = ord(connection_bytes[10])
|
||||
window_pointer = (window_pointer_byte1 + (window_pointer_byte2 << 8))
|
||||
|
||||
connection_data = {
|
||||
"map_id": map_id,
|
||||
"connected_map_tile_pointer": hex(connected_map_tile_pointer),
|
||||
"current_map_tile_pointer": hex(current_map_tile_pointer),
|
||||
"bigness": hex(bigness_byte),
|
||||
"width": hex(width_byte),
|
||||
"y": y,
|
||||
"x": x,
|
||||
"window_pointer": hex(window_pointer),
|
||||
}
|
||||
return connection_data
|
||||
|
||||
def read_warp_data(address, warp_count):
|
||||
warps = {}
|
||||
for warp_id in range(0, warp_count):
|
||||
offset = address + (warp_id*4) #4 bytes per warp
|
||||
warp = {}
|
||||
|
||||
warp["y"] = ord(rom[offset])
|
||||
warp["x"] = ord(rom[offset+1])
|
||||
warp["warp_to_point"] = ord(rom[offset+2])
|
||||
warp["warp_to_map_id"] = ord(rom[offset+3])
|
||||
|
||||
warps[warp_id] = warp
|
||||
return warps
|
||||
|
||||
def read_sign_data(address, sign_count):
|
||||
signs = {}
|
||||
for sign_id in range(0, sign_count):
|
||||
offset = address + (sign_id * 3)
|
||||
sign = {}
|
||||
sign["y"] = ord(rom[offset])
|
||||
sign["x"] = ord(rom[offset+1])
|
||||
sign["text_id"] = ord(rom[offset+2])
|
||||
signs[sign_id] = sign
|
||||
return signs
|
||||
|
||||
def read_warp_tos(address, warp_count):
|
||||
warp_tos = {}
|
||||
for warp_to_id in range(0, warp_count):
|
||||
offset = address + (warp_to_id * 4)
|
||||
warp_to = {}
|
||||
warp_to["event_displacement"] = [ord(rom[offset]),ord(rom[offset+1])]
|
||||
warp_to["y"] = ord(rom[offset+2])
|
||||
warp_to["x"] = ord(rom[offset+3])
|
||||
warp_tos[warp_to_id] = warp_to
|
||||
return warp_tos
|
||||
|
||||
def get_object_data(address):
|
||||
if type(address) == str: address = int(address, base)
|
||||
output = {}
|
||||
|
||||
maps_border_tile = ord(rom[address])
|
||||
|
||||
number_of_warps = ord(rom[address+1])
|
||||
if number_of_warps == 0: warps = {}
|
||||
else:
|
||||
warps = read_warp_data(address+2, number_of_warps)
|
||||
|
||||
offset = number_of_warps * 4
|
||||
address = address + 2 + offset
|
||||
|
||||
number_of_signs = ord(rom[address])
|
||||
if number_of_signs == 0: signs = {}
|
||||
else:
|
||||
signs = read_sign_data(address+1, number_of_signs)
|
||||
|
||||
offset = number_of_signs * 3
|
||||
address = address + 1 + offset
|
||||
|
||||
number_of_things = ord(rom[address])
|
||||
address = address + 1
|
||||
|
||||
things = {}
|
||||
for thing_id in range(0, number_of_things):
|
||||
thing = {}
|
||||
picture_number = ord(rom[address])
|
||||
y = ord(rom[address+1])
|
||||
x = ord(rom[address+2])
|
||||
movement1 = ord(rom[address+3])
|
||||
movement2 = ord(rom[address+4])
|
||||
text_string_number = ord(rom[address+5])
|
||||
|
||||
address += 5 + 1
|
||||
|
||||
if text_string_number & (1 << 6) != 0: #trainer
|
||||
thing["type"] = "trainer"
|
||||
thing["trainer_type"] = ord(rom[address])
|
||||
thing["pokemon_set"] = ord(rom[address+1])
|
||||
address += 2
|
||||
elif text_string_number & (1 << 7) != 0: #item
|
||||
thing["type"] = "item"
|
||||
thing["item_number"] = ord(rom[address])
|
||||
address += 1
|
||||
else: #normal person
|
||||
thing["type"] = "person"
|
||||
|
||||
thing["picture_number"] = picture_number
|
||||
thing["y"] = y
|
||||
thing["x"] = x
|
||||
thing["movement1"] = movement1
|
||||
thing["movement2"] = movement2
|
||||
thing["original_text_string_number"] = text_string_number
|
||||
thing["text_string_number"] = text_string_number & 0xF
|
||||
things[thing_id] = thing
|
||||
|
||||
warp_tos = read_warp_tos(address, number_of_warps)
|
||||
|
||||
output["maps_border_tile"] = maps_border_tile
|
||||
output["number_of_warps"] = number_of_warps
|
||||
output["warps"] = warps
|
||||
output["number_of_signs"] = number_of_signs
|
||||
output["signs"] = signs
|
||||
output["number_of_things"] = number_of_things
|
||||
output["things"] = things
|
||||
output["warp_tos"] = warp_tos
|
||||
|
||||
return output
|
||||
|
||||
def compute_object_data_size(object):
|
||||
size = 4
|
||||
size += 6 * (int(object["number_of_things"]))
|
||||
|
||||
trainer_count = 0
|
||||
item_count = 0
|
||||
for thing in object["things"]:
|
||||
thing = object["things"][thing]
|
||||
if thing["type"] == "trainer": trainer_count += 1
|
||||
elif thing["type"] == "item": item_count += 1
|
||||
|
||||
size += 2 * trainer_count
|
||||
size += item_count
|
||||
|
||||
size += 8 * object["number_of_warps"]
|
||||
size += 3 * object["number_of_signs"]
|
||||
|
||||
return size
|
||||
|
||||
def get_direction(connection_byte, connection_id):
|
||||
"""given a connection byte and a connection id, which direction is this connection?
|
||||
the 0th connection of $5 is SOUTH and the 1st connection is EAST"""
|
||||
connection_options = [0b1000, 0b0100, 0b0010, 0b0001]
|
||||
results = ["NORTH", "SOUTH", "WEST", "EAST"]
|
||||
for option in connection_options:
|
||||
if (option & connection_byte) == 0:
|
||||
results[connection_options.index(option)] = ""
|
||||
#prune results
|
||||
while "" in results:
|
||||
results.remove("")
|
||||
return results[connection_id]
|
||||
|
||||
def read_map_header(address, bank):
|
||||
address = int(address, base)
|
||||
bank = int(bank, base)
|
||||
|
||||
tileset = ord(rom[address])
|
||||
y = ord(rom[address+1])
|
||||
x = ord(rom[address+2])
|
||||
|
||||
map_pointer_byte1 = ord(rom[address+3])
|
||||
map_pointer_byte2 = ord(rom[address+4])
|
||||
partial_map_pointer = (map_pointer_byte1 + (map_pointer_byte2 << 8))
|
||||
map_pointer = calculate_pointer(partial_map_pointer, bank)
|
||||
|
||||
texts_pointer_byte1 = ord(rom[address+5])
|
||||
texts_pointer_byte2 = ord(rom[address+6])
|
||||
partial_texts_pointer = (texts_pointer_byte1 + (texts_pointer_byte2 << 8))
|
||||
texts_pointer = calculate_pointer(partial_texts_pointer, bank)
|
||||
|
||||
script_pointer_byte1 = ord(rom[address+7])
|
||||
script_pointer_byte2 = ord(rom[address+8])
|
||||
partial_script_pointer = (script_pointer_byte1 + ( script_pointer_byte2 << 8))
|
||||
script_pointer = calculate_pointer(partial_script_pointer, bank)
|
||||
|
||||
connection_byte = ord(rom[address+9]) #0xc = NORTH | SOUTH
|
||||
# <&IIMarckus> the connection byte is a bitmask allowing 0-4 connections
|
||||
# <&IIMarckus> each connection is 11 bytes
|
||||
# <&IIMarckus> or'd
|
||||
# <&IIMarckus> east = 1, west = 2, south = 4, north = 8
|
||||
# <&IIMarckus> so a connection byte of 0xc means north/south
|
||||
# <&IIMarckus> which means there are 22 more bytes, 11 for each connection
|
||||
# < kanzure> 4 | 8 = c?
|
||||
# <&IIMarckus> yes
|
||||
# <&IIMarckus> easier to see if you convert to binary
|
||||
# <&IIMarckus> 0100 | 1000 = 1100
|
||||
|
||||
num_connections = 0
|
||||
connection_value = bin(connection_byte)[2:]
|
||||
if connection_value[0] == "1": #NORTH
|
||||
num_connections += 1
|
||||
if len(connection_value) > 1 and connection_value[1] == "1": #SOUTH
|
||||
num_connections += 1
|
||||
if len(connection_value) > 2 and connection_value[2] == "1": #WEST
|
||||
num_connections += 1
|
||||
if len(connection_value) > 3 and connection_value[3] == "1": #EAST
|
||||
num_connections += 1
|
||||
|
||||
#quick test for connection data
|
||||
#connection0_stuff = rom[(address + 10):(address + 10 + 11)]
|
||||
#print "Route: " + hex(ord(connection0_stuff[0]))
|
||||
|
||||
#setup
|
||||
connections = {}
|
||||
|
||||
#go straight to object data if there are no connections
|
||||
if num_connections > 0:
|
||||
for connection in range(0, num_connections):
|
||||
base_connection_address = address + 10 + (11 * connection)
|
||||
connection_bytes = rom[base_connection_address : base_connection_address + 11]
|
||||
connection_data = read_connection_bytes(connection_bytes, bank)
|
||||
connection_data["direction"] = get_direction(connection_byte, connection)
|
||||
|
||||
connections[connection] = connection_data
|
||||
|
||||
#we might have to jump around a bit
|
||||
offset = address + 10 + (11 * num_connections)
|
||||
|
||||
#object data
|
||||
object_data_pointer_byte1 = ord(rom[offset])
|
||||
object_data_pointer_byte2 = ord(rom[offset+1])
|
||||
partial_object_data_pointer = (object_data_pointer_byte1 + (object_data_pointer_byte2 << 8))
|
||||
object_data_pointer = calculate_pointer(partial_object_data_pointer, bank)
|
||||
object_data = get_object_data(object_data_pointer)
|
||||
|
||||
texts = set()
|
||||
for thing_id in object_data["things"].keys():
|
||||
thing = object_data["things"][thing_id]
|
||||
texts.add(thing["text_string_number"])
|
||||
for sign_id in object_data["signs"].keys():
|
||||
sign = object_data["signs"][sign_id]
|
||||
texts.add(sign["text_id"])
|
||||
texts = list(texts)
|
||||
number_of_referenced_texts = len(texts)
|
||||
|
||||
map_header = {
|
||||
"tileset": hex(tileset),
|
||||
"y": hex(y),
|
||||
"x": hex(x),
|
||||
"map_pointer": hex(map_pointer),
|
||||
"texts_pointer": hex(texts_pointer),
|
||||
"number_of_referenced_texts": number_of_referenced_texts,
|
||||
"referenced_texts": texts,
|
||||
"script_pointer": hex(script_pointer),
|
||||
"connection_byte": hex(connection_byte),
|
||||
"num_connections": str(num_connections),
|
||||
"connections": connections, #NORTH, SOUTH, WEST, EAST order matters
|
||||
"object_data_pointer": hex(object_data_pointer),
|
||||
"object_data": object_data,
|
||||
}
|
||||
return map_header
|
||||
|
||||
def read_all_map_headers():
|
||||
if rom == None: load_rom()
|
||||
assert_rom()
|
||||
if len(map_pointers) == 0: load_map_pointers()
|
||||
|
||||
for map_id in map_pointers.keys():
|
||||
if map_id in bad_maps: continue
|
||||
map2 = map_pointers[map_id]
|
||||
map_header = read_map_header(map2["address"], map2["bank"])
|
||||
|
||||
map_header["id"] = map_id
|
||||
map_header["name"] = map2["name"]
|
||||
map_header["address"] = map2["address"]
|
||||
map_header["bank"] = map2["bank"]
|
||||
|
||||
map_headers[map_id] = map_header
|
||||
|
||||
return map_headers
|
||||
|
||||
if __name__ == "__main__":
|
||||
#read binary data from file
|
||||
load_rom()
|
||||
|
||||
#where are the map structs?
|
||||
load_map_pointers()
|
||||
#print json.dumps(map_pointers)
|
||||
|
||||
#experimental...
|
||||
#print json.dumps(read_map_header(map_pointers[0]["address"], map_pointers[0]["bank"]))
|
||||
|
||||
read_all_map_headers()
|
||||
#print json.dumps(map_headers)
|
||||
|
||||
#print map_headers[37]
|
||||
|
||||
for header in map_headers:
|
||||
if header in bad_maps: continue
|
||||
print "map " + str(header) + " has " + str(map_headers[header]["number_of_referenced_texts"]) + " referenced texts"
|
||||
|
@ -1,94 +0,0 @@
|
||||
#author: Bryan Bishop <kanzure@gmail.com>
|
||||
#date: 2012-01-14
|
||||
#split out blocksets into binary data files
|
||||
# There's also code here to spit out asm for each blockset,
|
||||
# but it's too many lines and will probably crash rgbasm.
|
||||
|
||||
import sys
|
||||
import extract_maps
|
||||
extract_maps.load_rom()
|
||||
spacing = " "
|
||||
|
||||
tileblocks = {
|
||||
"Tset00_Block": [0x645E0, 0x64DE0, ""],
|
||||
"Tset01_Block": [0x65270, 0x653A0, ""],
|
||||
"Tset02_Block": [0x693BF, 0x6960F, ""],
|
||||
"Tset03_Block": [0x6A9FF, 0x6B1FF, ""],
|
||||
"Tset05_Block": [0x6867F, 0x68DBF, ""],
|
||||
"Tset08_Block": [0x65980, 0x65BB0, ""],
|
||||
"Tset09_Block": [0x69BFF, 0x6A3FF, ""],
|
||||
"Tset0B_Block": [0x6FEF0, 0x70000, ""],
|
||||
"Tset0D_Block": [0x6E930, 0x6ED10, ""],
|
||||
"Tset0E_Block": [0x66BF0, 0x66D60, ""],
|
||||
"Tset0F_Block": [0x6C5C0, 0x6CCA0, ""],
|
||||
"Tset10_Block": [0x67350, 0x676F0, ""],
|
||||
"Tset13_Block": [0x66190, 0x66610, ""],
|
||||
"Tset11_Block": [0x6D0C0, 0x6D8C0, ""],
|
||||
"Tset12_Block": [0x6DEA0, 0x6E390, ""],
|
||||
"Tset14_Block": [0x6F2D0, 0x6F670, ""],
|
||||
"Tset15_Block": [0x6FB20, 0x6FD60, ""],
|
||||
"Tset16_Block": [0x6B7FF, 0x6C000, ""],
|
||||
"Tset17_Block": [0x67B50, 0x68000, ""],
|
||||
}
|
||||
|
||||
#10:02 <+sawakita> each block is composed by 4x4 tiles
|
||||
#10:03 <+sawakita> so you can see a blockset as a list of 16-bytes long arrays
|
||||
#10:07 <+sawakita> 4 bytes for each row of the block, left-to-right, top-to-down
|
||||
#10:08 <+sawakita> so first byte is top-left tile
|
||||
#10:08 <+kanzure> top-left tile byte is a tile id?
|
||||
#10:08 <+sawakita> exactly
|
||||
#10:09 <+kanzure> what does a tile id reference
|
||||
#10:10 <+sawakita> tile ID $00 is the first tile of the tileset's graphics (first 16-bytes, since gfx are 2bpp)
|
||||
|
||||
output = ""
|
||||
for tileblock_id in tileblocks.keys():
|
||||
tileblock = tileblocks[tileblock_id]
|
||||
start_address = tileblock[0]
|
||||
end_address = tileblock[1]
|
||||
block_count = (end_address - start_address) / 16
|
||||
main_data = extract_maps.rom[start_address:end_address]
|
||||
|
||||
blockset_id = int(tileblock_id[4:6], 16)
|
||||
|
||||
output = "; "
|
||||
output += tileblock_id + " - " + str(block_count) + " blocks (" + hex(start_address) + " to " + hex(end_address) + ")\n"
|
||||
#print tileblock_id + " has " + str(block_count) + " block tiles."
|
||||
for block_id in range(0, block_count):
|
||||
start_address2 = start_address + (16 * block_id)
|
||||
end_address2 = start_address + (16 * block_id) + 16
|
||||
data = extract_maps.rom[start_address2:end_address2]
|
||||
|
||||
output += spacing + "; block " + str(block_id + 1) + " on " + tileblock_id + "\n"
|
||||
|
||||
#output += spacing + spacing + "db $%.2x" % (ord(data[0]))
|
||||
#for data_bit in range(1,15):
|
||||
# output += ", $%.2x" % (ord(data[data_bit]))
|
||||
#output += ", $%.2x" % (ord(data[15]))
|
||||
#output += "\n"
|
||||
|
||||
for row_id in range(0,4):
|
||||
subdata = data[row_id * 4:row_id * 4 + 4]
|
||||
subdata2 = [ord(subdata[0]), ord(subdata[1]), ord(subdata[2]), ord(subdata[3])]
|
||||
|
||||
output += spacing + spacing + " ; row " + str(row_id + 1) + "\n"
|
||||
output += spacing + spacing + spacing + "db $%.2x, $%.2x, $%.2x, $%.2x\n" % (subdata2[0], subdata2[1], subdata2[2], subdata2[3])
|
||||
|
||||
fh = open("../gfx/blocksets/%.2x.bst" % (blockset_id), "w")
|
||||
fh.write(main_data)
|
||||
fh.close()
|
||||
|
||||
print output
|
||||
|
||||
"""
|
||||
Tset00_Block:
|
||||
; block 1
|
||||
; row 1
|
||||
db 0, 0, 0, 0
|
||||
; row 2
|
||||
db 0, 0, 0, 0
|
||||
; row 3
|
||||
db 0, 0, 0, 0
|
||||
; row 4
|
||||
db 0, 0, 0, 0
|
||||
"""
|
||||
|
@ -1,37 +0,0 @@
|
||||
#author: Bryan Bishop <kanzure@gmail.com>
|
||||
#date: 2012-01-14
|
||||
#throw tilesets into separate files
|
||||
import extract_maps
|
||||
extract_maps.load_rom()
|
||||
|
||||
locations = {
|
||||
"Tset00_GFX": [0x64000, 0x645E0, "00"],
|
||||
"Tset01_GFX": [0x64DE0, 0x65270, "01"],
|
||||
"Tset08_GFX": [0x653A0, 0x65980, "08"],
|
||||
"Tset13_GFX": [0x65BB0, 0x66190, "13"],
|
||||
"Tset0E_GFX": [0x66610, 0x66BF0, "0e"],
|
||||
"Tset10_GFX": [0x66D60, 0x67350, "10"],
|
||||
"Tset17_GFX": [0x676F0, 0x67B50, "17"],
|
||||
"Tset05_GFX": [0x6807F, 0x6867F, "05"],
|
||||
"Tset02_GFX": [0x68DBF, 0x693BF, "02"],
|
||||
"Tset09_GFX": [0x6960F, 0x69BFF, "09"],
|
||||
"Tset03_GFX": [0x6A3FF, 0x6A9FF, "03"],
|
||||
"Tset16_GFX": [0x6B1FF, 0x6B7FF, "16"],
|
||||
"Tset0F_GFX": [0x6C000, 0x6C5C0, "0f"],
|
||||
"Tset11_GFX": [0x6CCA0, 0x6D0C0, "11"],
|
||||
"Tset12_GFX": [0x6D8C0, 0x6DEA0, "12"],
|
||||
"Tset0D_GFX": [0x6E390, 0x6E930, "0d"],
|
||||
"Tset14_GFX": [0x6ED10, 0x6F2D0, "14"],
|
||||
"Tset15_GFX": [0x6F670, 0x6FB20, "15"],
|
||||
"Tset0B_GFX": [0x6FD60, 0x6FEF0, "0b"],
|
||||
}
|
||||
|
||||
for tileset_id in locations.keys():
|
||||
tileset = locations[tileset_id]
|
||||
|
||||
print "writing ../gfx/tilesets/" + tileset[2] + ".2bpp"
|
||||
fh = open("../gfx/tilesets/" + tileset[2] + ".2bpp", "w")
|
||||
fh.write(extract_maps.rom[tileset[0]:tileset[1]])
|
||||
fh.close()
|
||||
|
||||
print "Done."
|
@ -1,82 +0,0 @@
|
||||
#author: Bryan Bishop <kanzure@gmail.com>
|
||||
#date: 2012-01-27
|
||||
#fix trainer header labels to not suck so much
|
||||
import analyze_incbins
|
||||
|
||||
def replace_trainer_header_labels(debug=False):
|
||||
"""trainer header labels could be better"""
|
||||
asm = analyze_incbins.asm
|
||||
if debug: print str(type(asm))
|
||||
single_asm = "\n".join(asm)
|
||||
current_map_name = "asdjkl;"
|
||||
line_id = 0
|
||||
trainer_header_counter = 1
|
||||
|
||||
for line in asm:
|
||||
trainer_header_base = current_map_name + "TrainerHeader"
|
||||
trainer_header_name = trainer_header_base + str(trainer_header_counter)
|
||||
|
||||
#we've found a TrainerHeaders thing
|
||||
if "TrainerHeaders:" in line:
|
||||
current_map_name = line.split("TrainerHeaders")[0]
|
||||
if line[0:len(current_map_name)] == current_map_name:
|
||||
trainer_header_counter = 1
|
||||
|
||||
#replace a trainer header label
|
||||
elif "TrainerHeader_" in line and line[0:14] == "TrainerHeader_":
|
||||
temp = line.split("TrainerHeader_")[1]
|
||||
temp = temp.split(": ;")[0]
|
||||
|
||||
old_label = "TrainerHeader_" + temp
|
||||
new_label = current_map_name + "TH" + str(trainer_header_counter) #trainer_header_name
|
||||
single_asm = single_asm.replace(old_label + ":", new_label + ":")
|
||||
single_asm = single_asm.replace(old_label + "\n", new_label + "\n")
|
||||
if debug: print "old_label = " + old_label
|
||||
if debug: print "new_label = " + new_label
|
||||
|
||||
trainer_header_counter += 1
|
||||
|
||||
elif trainer_header_base in line and line[0:len(trainer_header_base)] == trainer_header_base and (line[len(trainer_header_base)+1:len(trainer_header_base)+2] == ":" or line[len(trainer_header_base)+2:len(trainer_header_base)+3] == ":"):
|
||||
if line[len(trainer_header_base)+1:len(trainer_header_base)+2] == ":":
|
||||
trainer_header_counter = int(line[len(trainer_header_base):len(trainer_header_base)+1])
|
||||
elif line[len(trainer_header_base)+2:len(trainer_header_base)+3] == ":":
|
||||
trainer_header_counter = int(line[len(trainer_header_base):len(trainer_header_base)+2])
|
||||
trainer_header_name = trainer_header_base + str(trainer_header_counter)
|
||||
|
||||
#replace a text label
|
||||
elif " TextBeforeBattle" in line and not current_map_name in line:
|
||||
old_label = line.split("dw ")[1].split(" ;")[0]
|
||||
new_label = current_map_name + "B4BattleTxt" + str(trainer_header_counter) #trainer_header_name + "BeforeBattleText"
|
||||
single_asm = single_asm.replace(old_label + ":", new_label + ":")
|
||||
single_asm = single_asm.replace(old_label + "\n", new_label + "\n")
|
||||
single_asm = single_asm.replace(old_label + " ;", new_label + " ;")
|
||||
if debug: print "old_label = " + old_label
|
||||
if debug: print "new_label = " + new_label
|
||||
#replace a text label
|
||||
elif " TextAfterBattle" in line and not current_map_name in line:
|
||||
old_label = line.split("dw ")[1].split(" ;")[0]
|
||||
new_label = current_map_name + "AfterBattleTxt" + str(trainer_header_counter) #trainer_header_name + "AfterBattleText"
|
||||
single_asm = single_asm.replace(old_label + ":", new_label + ":")
|
||||
single_asm = single_asm.replace(old_label + "\n", new_label + "\n")
|
||||
single_asm = single_asm.replace(old_label + " ;", new_label + " ;")
|
||||
if debug: print "old_label = " + old_label
|
||||
if debug: print "new_label = " + new_label
|
||||
#replace a text label
|
||||
elif " TextEndBattle" in line and not current_map_name in line:
|
||||
old_label = line.split("dw ")[1].split(" ;")[0]
|
||||
new_label = current_map_name + "EndBattleTxt" + str(trainer_header_counter) #trainer_header_name + "EndBattleText"
|
||||
single_asm = single_asm.replace(old_label + ":", new_label + ":")
|
||||
single_asm = single_asm.replace(old_label + "\n", new_label + "\n")
|
||||
single_asm = single_asm.replace(old_label + " ;", new_label + " ;")
|
||||
if debug: print "old_label = " + old_label
|
||||
if debug: print "new_label = " + new_label
|
||||
|
||||
line_id += 1
|
||||
|
||||
print single_asm
|
||||
|
||||
if __name__ == "__main__":
|
||||
analyze_incbins.load_asm()
|
||||
|
||||
replace_trainer_header_labels()
|
||||
|
@ -1,853 +0,0 @@
|
||||
#author: Bryan Bishop <kanzure@gmail.com>
|
||||
#date: 2012-01-09
|
||||
import extract_maps
|
||||
import os
|
||||
import json
|
||||
from copy import copy, deepcopy
|
||||
from pretty_map_headers import random_hash, map_name_cleaner
|
||||
from ctypes import c_int8
|
||||
import sys
|
||||
spacing = " "
|
||||
|
||||
temp_opt_table = [
|
||||
[ "ADC A", 0x8f, 0 ],
|
||||
[ "ADC B", 0x88, 0 ],
|
||||
[ "ADC C", 0x89, 0 ],
|
||||
[ "ADC D", 0x8a, 0 ],
|
||||
[ "ADC E", 0x8b, 0 ],
|
||||
[ "ADC H", 0x8c, 0 ],
|
||||
[ "ADC [HL]", 0x8e, 0 ],
|
||||
[ "ADC L", 0x8d, 0 ],
|
||||
[ "ADC x", 0xce, 1 ],
|
||||
[ "ADD A", 0x87, 0 ],
|
||||
[ "ADD B", 0x80, 0 ],
|
||||
[ "ADD C", 0x81, 0 ],
|
||||
[ "ADD D", 0x82, 0 ],
|
||||
[ "ADD E", 0x83, 0 ],
|
||||
[ "ADD H", 0x84, 0 ],
|
||||
[ "ADD [HL]", 0x86, 0 ],
|
||||
[ "ADD HL, BC", 0x9, 0 ],
|
||||
[ "ADD HL, DE", 0x19, 0 ],
|
||||
[ "ADD HL, HL", 0x29, 0 ],
|
||||
[ "ADD HL, SP", 0x39, 0 ],
|
||||
[ "ADD L", 0x85, 0 ],
|
||||
[ "ADD SP, x", 0xe8, 1 ],
|
||||
[ "ADD x", 0xc6, 1 ],
|
||||
[ "AND A", 0xa7, 0 ],
|
||||
[ "AND B", 0xa0, 0 ],
|
||||
[ "AND C", 0xa1, 0 ],
|
||||
[ "AND D", 0xa2, 0 ],
|
||||
[ "AND E", 0xa3, 0 ],
|
||||
[ "AND H", 0xa4, 0 ],
|
||||
[ "AND [HL]", 0xa6, 0 ],
|
||||
[ "AND L", 0xa5, 0 ],
|
||||
[ "AND x", 0xe6, 1 ],
|
||||
[ "BIT 0, A", 0x47cb, 3 ],
|
||||
[ "BIT 0, B", 0x40cb, 3 ],
|
||||
[ "BIT 0, C", 0x41cb, 3 ],
|
||||
[ "BIT 0, D", 0x42cb, 3 ],
|
||||
[ "BIT 0, E", 0x43cb, 3 ],
|
||||
[ "BIT 0, H", 0x44cb, 3 ],
|
||||
[ "BIT 0, [HL]", 0x46cb, 3 ],
|
||||
[ "BIT 0, L", 0x45cb, 3 ],
|
||||
[ "BIT 1, A", 0x4fcb, 3 ],
|
||||
[ "BIT 1, B", 0x48cb, 3 ],
|
||||
[ "BIT 1, C", 0x49cb, 3 ],
|
||||
[ "BIT 1, D", 0x4acb, 3 ],
|
||||
[ "BIT 1, E", 0x4bcb, 3 ],
|
||||
[ "BIT 1, H", 0x4ccb, 3 ],
|
||||
[ "BIT 1, [HL]", 0x4ecb, 3 ],
|
||||
[ "BIT 1, L", 0x4dcb, 3 ],
|
||||
[ "BIT 2, A", 0x57cb, 3 ],
|
||||
[ "BIT 2, B", 0x50cb, 3 ],
|
||||
[ "BIT 2, C", 0x51cb, 3 ],
|
||||
[ "BIT 2, D", 0x52cb, 3 ],
|
||||
[ "BIT 2, E", 0x53cb, 3 ],
|
||||
[ "BIT 2, H", 0x54cb, 3 ],
|
||||
[ "BIT 2, [HL]", 0x56cb, 3 ],
|
||||
[ "BIT 2, L", 0x55cb, 3 ],
|
||||
[ "BIT 3, A", 0x5fcb, 3 ],
|
||||
[ "BIT 3, B", 0x58cb, 3 ],
|
||||
[ "BIT 3, C", 0x59cb, 3 ],
|
||||
[ "BIT 3, D", 0x5acb, 3 ],
|
||||
[ "BIT 3, E", 0x5bcb, 3 ],
|
||||
[ "BIT 3, H", 0x5ccb, 3 ],
|
||||
[ "BIT 3, [HL]", 0x5ecb, 3 ],
|
||||
[ "BIT 3, L", 0x5dcb, 3 ],
|
||||
[ "BIT 4, A", 0x67cb, 3 ],
|
||||
[ "BIT 4, B", 0x60cb, 3 ],
|
||||
[ "BIT 4, C", 0x61cb, 3 ],
|
||||
[ "BIT 4, D", 0x62cb, 3 ],
|
||||
[ "BIT 4, E", 0x63cb, 3 ],
|
||||
[ "BIT 4, H", 0x64cb, 3 ],
|
||||
[ "BIT 4, [HL]", 0x66cb, 3 ],
|
||||
[ "BIT 4, L", 0x65cb, 3 ],
|
||||
[ "BIT 5, A", 0x6fcb, 3 ],
|
||||
[ "BIT 5, B", 0x68cb, 3 ],
|
||||
[ "BIT 5, C", 0x69cb, 3 ],
|
||||
[ "BIT 5, D", 0x6acb, 3 ],
|
||||
[ "BIT 5, E", 0x6bcb, 3 ],
|
||||
[ "BIT 5, H", 0x6ccb, 3 ],
|
||||
[ "BIT 5, [HL]", 0x6ecb, 3 ],
|
||||
[ "BIT 5, L", 0x6dcb, 3 ],
|
||||
[ "BIT 6, A", 0x77cb, 3 ],
|
||||
[ "BIT 6, B", 0x70cb, 3 ],
|
||||
[ "BIT 6, C", 0x71cb, 3 ],
|
||||
[ "BIT 6, D", 0x72cb, 3 ],
|
||||
[ "BIT 6, E", 0x73cb, 3 ],
|
||||
[ "BIT 6, H", 0x74cb, 3 ],
|
||||
[ "BIT 6, [HL]", 0x76cb, 3 ],
|
||||
[ "BIT 6, L", 0x75cb, 3 ],
|
||||
[ "BIT 7, A", 0x7fcb, 3 ],
|
||||
[ "BIT 7, B", 0x78cb, 3 ],
|
||||
[ "BIT 7, C", 0x79cb, 3 ],
|
||||
[ "BIT 7, D", 0x7acb, 3 ],
|
||||
[ "BIT 7, E", 0x7bcb, 3 ],
|
||||
[ "BIT 7, H", 0x7ccb, 3 ],
|
||||
[ "BIT 7, [HL]", 0x7ecb, 3 ],
|
||||
[ "BIT 7, L", 0x7dcb, 3 ],
|
||||
[ "CALL C, ?", 0xdc, 2 ],
|
||||
[ "CALL NC, ?", 0xd4, 2 ],
|
||||
[ "CALL NZ, ?", 0xc4, 2 ],
|
||||
[ "CALL Z, ?", 0xcc, 2 ],
|
||||
[ "CALL ?", 0xcd, 2 ],
|
||||
[ "CCF", 0x3f, 0 ],
|
||||
[ "CP A", 0xbf, 0 ],
|
||||
[ "CP B", 0xb8, 0 ],
|
||||
[ "CP C", 0xb9, 0 ],
|
||||
[ "CP D", 0xba, 0 ],
|
||||
[ "CP E", 0xbb, 0 ],
|
||||
[ "CP H", 0xbc, 0 ],
|
||||
[ "CP [HL]", 0xbe, 0 ],
|
||||
[ "CPL", 0x2f, 0 ],
|
||||
[ "CP L", 0xbd, 0 ],
|
||||
[ "CP x", 0xfe, 1 ],
|
||||
[ "DAA", 0x27, 0 ],
|
||||
[ "DEBUG", 0xed, 0 ],
|
||||
[ "DEC A", 0x3d, 0 ],
|
||||
[ "DEC B", 0x5, 0 ],
|
||||
[ "DEC BC", 0xb, 0 ],
|
||||
[ "DEC C", 0xd, 0 ],
|
||||
[ "DEC D", 0x15, 0 ],
|
||||
[ "DEC DE", 0x1b, 0 ],
|
||||
[ "DEC E", 0x1d, 0 ],
|
||||
[ "DEC H", 0x25, 0 ],
|
||||
[ "DEC HL", 0x2b, 0 ],
|
||||
[ "DEC [HL]", 0x35, 0 ],
|
||||
[ "DEC L", 0x2d, 0 ],
|
||||
[ "DEC SP", 0x3b, 0 ],
|
||||
[ "DI", 0xf3, 0 ],
|
||||
[ "EI", 0xfb, 0 ],
|
||||
[ "HALT", 0x76, 0 ],
|
||||
[ "INC A", 0x3c, 0 ],
|
||||
[ "INC B", 0x4, 0 ],
|
||||
[ "INC BC", 0x3, 0 ],
|
||||
[ "INC C", 0xc, 0 ],
|
||||
[ "INC D", 0x14, 0 ],
|
||||
[ "INC DE", 0x13, 0 ],
|
||||
[ "INC E", 0x1c, 0 ],
|
||||
[ "INC H", 0x24, 0 ],
|
||||
[ "INC HL", 0x23, 0 ],
|
||||
[ "INC [HL]", 0x34, 0 ],
|
||||
[ "INC L", 0x2c, 0 ],
|
||||
[ "INC SP", 0x33, 0 ],
|
||||
[ "JP C, ?", 0xda, 2 ],
|
||||
[ "JP HL", 0xe9, 0 ],
|
||||
[ "JP NC, ?", 0xd2, 2 ],
|
||||
[ "JP NZ, ?", 0xc2, 2 ],
|
||||
[ "JP Z, ?", 0xca, 2 ],
|
||||
[ "JP ?", 0xc3, 2 ],
|
||||
[ "JR C, x", 0x38, 1 ],
|
||||
[ "JR NC, x", 0x30, 1 ],
|
||||
[ "JR NZ, x", 0x20, 1 ],
|
||||
[ "JR Z, x", 0x28, 1 ],
|
||||
[ "JR x", 0x18, 1 ],
|
||||
[ "LD A, A", 0x7f, 0 ],
|
||||
[ "LD A, B", 0x78, 0 ],
|
||||
[ "LD A, C", 0x79, 0 ],
|
||||
[ "LD A, D", 0x7a, 0 ],
|
||||
[ "LD A, E", 0x7b, 0 ],
|
||||
[ "LD A, H", 0x7c, 0 ],
|
||||
[ "LD A, L", 0x7d, 0 ],
|
||||
[ "LD A, [$FF00+C]", 0xf2, 0 ],
|
||||
[ "LD A, [$FF00+x]", 0xf0, 1 ],
|
||||
# [ "LDH A, [x]", 0xf0, 1 ], #rgbds has trouble with this one?
|
||||
[ "LD A, [BC]", 0xa, 0 ],
|
||||
[ "LD A, [DE]", 0x1a, 0 ],
|
||||
# [ "LD A, [HL+]", 0x2a, 0 ],
|
||||
# [ "LD A, [HL-]", 0x3a, 0 ],
|
||||
[ "LD A, [HL]", 0x7e, 0 ],
|
||||
[ "LD A, [HLD]", 0x3a, 0 ],
|
||||
[ "LD A, [HLI]", 0x2a, 0 ],
|
||||
[ "LD A, [?]", 0xfa, 2 ],
|
||||
[ "LD A, x", 0x3e, 1 ],
|
||||
[ "LD B, A", 0x47, 0 ],
|
||||
[ "LD B, B", 0x40, 0 ],
|
||||
[ "LD B, C", 0x41, 0 ],
|
||||
[ "LD [BC], A", 0x2, 0 ],
|
||||
[ "LD B, D", 0x42, 0 ],
|
||||
[ "LD B, E", 0x43, 0 ],
|
||||
[ "LD B, H", 0x44, 0 ],
|
||||
[ "LD B, [HL]", 0x46, 0 ],
|
||||
[ "LD B, L", 0x45, 0 ],
|
||||
[ "LD B, x", 0x6, 1 ],
|
||||
[ "LD C, A", 0x4f, 0 ],
|
||||
[ "LD C, B", 0x48, 0 ],
|
||||
[ "LD C, C", 0x49, 0 ],
|
||||
[ "LD C, D", 0x4a, 0 ],
|
||||
[ "LD C, E", 0x4b, 0 ],
|
||||
[ "LD C, H", 0x4c, 0 ],
|
||||
[ "LD C, [HL]", 0x4e, 0 ],
|
||||
[ "LD C, L", 0x4d, 0 ],
|
||||
[ "LD C, x", 0xe, 1 ],
|
||||
[ "LD D, A", 0x57, 0 ],
|
||||
# [ "LDD A, [HL]", 0x3a, 0 ],
|
||||
[ "LD D, B", 0x50, 0 ],
|
||||
[ "LD D, C", 0x51, 0 ],
|
||||
[ "LD D, D", 0x52, 0 ],
|
||||
[ "LD D, E", 0x53, 0 ],
|
||||
[ "LD [DE], A", 0x12, 0 ],
|
||||
[ "LD D, H", 0x54, 0 ],
|
||||
[ "LD D, [HL]", 0x56, 0 ],
|
||||
# [ "LDD [HL], A", 0x32, 0 ],
|
||||
[ "LD D, L", 0x55, 0 ],
|
||||
[ "LD D, x", 0x16, 1 ],
|
||||
[ "LD E, A", 0x5f, 0 ],
|
||||
[ "LD E, B", 0x58, 0 ],
|
||||
[ "LD E, C", 0x59, 0 ],
|
||||
[ "LD E, D", 0x5a, 0 ],
|
||||
[ "LD E, E", 0x5b, 0 ],
|
||||
[ "LD E, H", 0x5c, 0 ],
|
||||
[ "LD E, [HL]", 0x5e, 0 ],
|
||||
[ "LD E, L", 0x5d, 0 ],
|
||||
[ "LD E, x", 0x1e, 1 ],
|
||||
[ "LD [$FF00+C], A", 0xe2, 0 ],
|
||||
[ "LD [$FF00+x], A", 0xe0, 1 ],
|
||||
# [ "LDH [x], A", 0xe0, 1 ],
|
||||
[ "LD H, A", 0x67, 0 ],
|
||||
[ "LD H, B", 0x60, 0 ],
|
||||
[ "LD H, C", 0x61, 0 ],
|
||||
[ "LD H, D", 0x62, 0 ],
|
||||
[ "LD H, E", 0x63, 0 ],
|
||||
[ "LD H, H", 0x64, 0 ],
|
||||
[ "LD H, [HL]", 0x66, 0 ],
|
||||
[ "LD H, L", 0x65, 0 ],
|
||||
# [ "LD [HL+], A", 0x22, 0 ],
|
||||
# [ "LD [HL-], A", 0x32, 0 ],
|
||||
[ "LD [HL], A", 0x77, 0 ],
|
||||
[ "LD [HL], B", 0x70, 0 ],
|
||||
[ "LD [HL], C", 0x71, 0 ],
|
||||
[ "LD [HL], D", 0x72, 0 ],
|
||||
[ "LD [HLD], A", 0x32, 0 ],
|
||||
[ "LD [HL], E", 0x73, 0 ],
|
||||
[ "LD [HL], H", 0x74, 0 ],
|
||||
[ "LD [HLI], A", 0x22, 0 ],
|
||||
[ "LD [HL], L", 0x75, 0 ],
|
||||
[ "LD HL, SP+x", 0xf8, 1 ],
|
||||
[ "LD [HL], x", 0x36, 1 ],
|
||||
[ "LD H, x", 0x26, 1 ],
|
||||
# [ "LDI A, [HL]", 0x2a, 0 ],
|
||||
# [ "LDI [HL], A", 0x22, 0 ],
|
||||
[ "LD L, A", 0x6f, 0 ],
|
||||
[ "LD L, B", 0x68, 0 ],
|
||||
[ "LD L, C", 0x69, 0 ],
|
||||
[ "LD L, D", 0x6a, 0 ],
|
||||
[ "LD L, E", 0x6b, 0 ],
|
||||
[ "LD L, H", 0x6c, 0 ],
|
||||
[ "LD L, [HL]", 0x6e, 0 ],
|
||||
[ "LD L, L", 0x6d, 0 ],
|
||||
[ "LD L, x", 0x2e, 1 ],
|
||||
# [ "LD PC, HL", 0xe9, 0 ], #prefer jp [hl]
|
||||
[ "LD SP, HL", 0xf9, 0 ],
|
||||
[ "LD BC, ?", 0x1, 2 ],
|
||||
[ "LD DE, ?", 0x11, 2 ],
|
||||
[ "LD HL, ?", 0x21, 2 ],
|
||||
[ "LD SP, ?", 0x31, 2 ],
|
||||
# [ "LD [?], SP", 0x8, 2 ],
|
||||
[ "LD [?], A", 0xea, 2 ],
|
||||
[ "NOP", 0x0, 0 ],
|
||||
[ "OR A", 0xb7, 0 ],
|
||||
[ "OR B", 0xb0, 0 ],
|
||||
[ "OR C", 0xb1, 0 ],
|
||||
[ "OR D", 0xb2, 0 ],
|
||||
[ "OR E", 0xb3, 0 ],
|
||||
[ "OR H", 0xb4, 0 ],
|
||||
[ "OR [HL]", 0xb6, 0 ],
|
||||
[ "OR L", 0xb5, 0 ],
|
||||
[ "OR x", 0xf6, 1 ],
|
||||
[ "POP AF", 0xf1, 0 ],
|
||||
[ "POP BC", 0xc1, 0 ],
|
||||
[ "POP DE", 0xd1, 0 ],
|
||||
[ "POP HL", 0xe1, 0 ],
|
||||
[ "PUSH AF", 0xf5, 0 ],
|
||||
[ "PUSH BC", 0xc5, 0 ],
|
||||
[ "PUSH DE", 0xd5, 0 ],
|
||||
[ "PUSH HL", 0xe5, 0 ],
|
||||
[ "RES 0, A", 0x87cb, 3 ],
|
||||
[ "RES 0, B", 0x80cb, 3 ],
|
||||
[ "RES 0, C", 0x81cb, 3 ],
|
||||
[ "RES 0, D", 0x82cb, 3 ],
|
||||
[ "RES 0, E", 0x83cb, 3 ],
|
||||
[ "RES 0, H", 0x84cb, 3 ],
|
||||
[ "RES 0, [HL]", 0x86cb, 3 ],
|
||||
[ "RES 0, L", 0x85cb, 3 ],
|
||||
[ "RES 1, A", 0x8fcb, 3 ],
|
||||
[ "RES 1, B", 0x88cb, 3 ],
|
||||
[ "RES 1, C", 0x89cb, 3 ],
|
||||
[ "RES 1, D", 0x8acb, 3 ],
|
||||
[ "RES 1, E", 0x8bcb, 3 ],
|
||||
[ "RES 1, H", 0x8ccb, 3 ],
|
||||
[ "RES 1, [HL]", 0x8ecb, 3 ],
|
||||
[ "RES 1, L", 0x8dcb, 3 ],
|
||||
[ "RES 2, A", 0x97cb, 3 ],
|
||||
[ "RES 2, B", 0x90cb, 3 ],
|
||||
[ "RES 2, C", 0x91cb, 3 ],
|
||||
[ "RES 2, D", 0x92cb, 3 ],
|
||||
[ "RES 2, E", 0x93cb, 3 ],
|
||||
[ "RES 2, H", 0x94cb, 3 ],
|
||||
[ "RES 2, [HL]", 0x96cb, 3 ],
|
||||
[ "RES 2, L", 0x95cb, 3 ],
|
||||
[ "RES 3, A", 0x9fcb, 3 ],
|
||||
[ "RES 3, B", 0x98cb, 3 ],
|
||||
[ "RES 3, C", 0x99cb, 3 ],
|
||||
[ "RES 3, D", 0x9acb, 3 ],
|
||||
[ "RES 3, E", 0x9bcb, 3 ],
|
||||
[ "RES 3, H", 0x9ccb, 3 ],
|
||||
[ "RES 3, [HL]", 0x9ecb, 3 ],
|
||||
[ "RES 3, L", 0x9dcb, 3 ],
|
||||
[ "RES 4, A", 0xa7cb, 3 ],
|
||||
[ "RES 4, B", 0xa0cb, 3 ],
|
||||
[ "RES 4, C", 0xa1cb, 3 ],
|
||||
[ "RES 4, D", 0xa2cb, 3 ],
|
||||
[ "RES 4, E", 0xa3cb, 3 ],
|
||||
[ "RES 4, H", 0xa4cb, 3 ],
|
||||
[ "RES 4, [HL]", 0xa6cb, 3 ],
|
||||
[ "RES 4, L", 0xa5cb, 3 ],
|
||||
[ "RES 5, A", 0xafcb, 3 ],
|
||||
[ "RES 5, B", 0xa8cb, 3 ],
|
||||
[ "RES 5, C", 0xa9cb, 3 ],
|
||||
[ "RES 5, D", 0xaacb, 3 ],
|
||||
[ "RES 5, E", 0xabcb, 3 ],
|
||||
[ "RES 5, H", 0xaccb, 3 ],
|
||||
[ "RES 5, [HL]", 0xaecb, 3 ],
|
||||
[ "RES 5, L", 0xadcb, 3 ],
|
||||
[ "RES 6, A", 0xb7cb, 3 ],
|
||||
[ "RES 6, B", 0xb0cb, 3 ],
|
||||
[ "RES 6, C", 0xb1cb, 3 ],
|
||||
[ "RES 6, D", 0xb2cb, 3 ],
|
||||
[ "RES 6, E", 0xb3cb, 3 ],
|
||||
[ "RES 6, H", 0xb4cb, 3 ],
|
||||
[ "RES 6, [HL]", 0xb6cb, 3 ],
|
||||
[ "RES 6, L", 0xb5cb, 3 ],
|
||||
[ "RES 7, A", 0xbfcb, 3 ],
|
||||
[ "RES 7, B", 0xb8cb, 3 ],
|
||||
[ "RES 7, C", 0xb9cb, 3 ],
|
||||
[ "RES 7, D", 0xbacb, 3 ],
|
||||
[ "RES 7, E", 0xbbcb, 3 ],
|
||||
[ "RES 7, H", 0xbccb, 3 ],
|
||||
[ "RES 7, [HL]", 0xbecb, 3 ],
|
||||
[ "RES 7, L", 0xbdcb, 3 ],
|
||||
[ "RETI", 0xd9, 0 ],
|
||||
[ "RET C", 0xd8, 0 ],
|
||||
[ "RET NC", 0xd0, 0 ],
|
||||
[ "RET NZ", 0xc0, 0 ],
|
||||
[ "RET Z", 0xc8, 0 ],
|
||||
[ "RET", 0xc9, 0 ],
|
||||
[ "RLA", 0x17, 0 ],
|
||||
[ "RL A", 0x17cb, 3 ],
|
||||
[ "RL B", 0x10cb, 3 ],
|
||||
[ "RL C", 0x11cb, 3 ],
|
||||
[ "RLCA", 0x7, 0 ],
|
||||
[ "RLC A", 0x7cb, 3 ],
|
||||
[ "RLC B", 0xcb, 3 ],
|
||||
[ "RLC C", 0x1cb, 3 ],
|
||||
[ "RLC D", 0x2cb, 3 ],
|
||||
[ "RLC E", 0x3cb, 3 ],
|
||||
[ "RLC H", 0x4cb, 3 ],
|
||||
[ "RLC [HL]", 0x6cb, 3 ],
|
||||
[ "RLC L", 0x5cb, 3 ],
|
||||
[ "RL D", 0x12cb, 3 ],
|
||||
[ "RL E", 0x13cb, 3 ],
|
||||
[ "RL H", 0x14cb, 3 ],
|
||||
[ "RL [HL]", 0x16cb, 3 ],
|
||||
[ "RL L", 0x15cb, 3 ],
|
||||
[ "RRA", 0x1f, 0 ],
|
||||
[ "RR A", 0x1fcb, 3 ],
|
||||
[ "RR B", 0x18cb, 3 ],
|
||||
[ "RR C", 0x19cb, 3 ],
|
||||
[ "RRCA", 0xf, 0 ],
|
||||
[ "RRC A", 0xfcb, 3 ],
|
||||
[ "RRC B", 0x8cb, 3 ],
|
||||
[ "RRC C", 0x9cb, 3 ],
|
||||
[ "RRC D", 0xacb, 3 ],
|
||||
[ "RRC E", 0xbcb, 3 ],
|
||||
[ "RRC H", 0xccb, 3 ],
|
||||
[ "RRC [HL]", 0xecb, 3 ],
|
||||
[ "RRC L", 0xdcb, 3 ],
|
||||
[ "RR D", 0x1acb, 3 ],
|
||||
[ "RR E", 0x1bcb, 3 ],
|
||||
[ "RR H", 0x1ccb, 3 ],
|
||||
[ "RR [HL]", 0x1ecb, 3 ],
|
||||
[ "RR L", 0x1dcb, 3 ],
|
||||
[ "RST $0", 0xc7, 0 ],
|
||||
[ "RST $10", 0xd7, 0 ],
|
||||
[ "RST $18", 0xdf, 0 ],
|
||||
[ "RST $20", 0xe7, 0 ],
|
||||
[ "RST $28", 0xef, 0 ],
|
||||
[ "RST $30", 0xf7, 0 ],
|
||||
[ "RST $38", 0xff, 0 ],
|
||||
[ "RST $8", 0xcf, 0 ],
|
||||
[ "SBC A", 0x9f, 0 ],
|
||||
[ "SBC B", 0x98, 0 ],
|
||||
[ "SBC C", 0x99, 0 ],
|
||||
[ "SBC D", 0x9a, 0 ],
|
||||
[ "SBC E", 0x9b, 0 ],
|
||||
[ "SBC H", 0x9c, 0 ],
|
||||
[ "SBC [HL]", 0x9e, 0 ],
|
||||
[ "SBC L", 0x9d, 0 ],
|
||||
[ "SBC x", 0xde, 1 ],
|
||||
[ "SCF", 0x37, 0 ],
|
||||
[ "SET 0, A", 0xc7cb, 3 ],
|
||||
[ "SET 0, B", 0xc0cb, 3 ],
|
||||
[ "SET 0, C", 0xc1cb, 3 ],
|
||||
[ "SET 0, D", 0xc2cb, 3 ],
|
||||
[ "SET 0, E", 0xc3cb, 3 ],
|
||||
[ "SET 0, H", 0xc4cb, 3 ],
|
||||
[ "SET 0, [HL]", 0xc6cb, 3 ],
|
||||
[ "SET 0, L", 0xc5cb, 3 ],
|
||||
[ "SET 1, A", 0xcfcb, 3 ],
|
||||
[ "SET 1, B", 0xc8cb, 3 ],
|
||||
[ "SET 1, C", 0xc9cb, 3 ],
|
||||
[ "SET 1, D", 0xcacb, 3 ],
|
||||
[ "SET 1, E", 0xcbcb, 3 ],
|
||||
[ "SET 1, H", 0xcccb, 3 ],
|
||||
[ "SET 1, [HL]", 0xcecb, 3 ],
|
||||
[ "SET 1, L", 0xcdcb, 3 ],
|
||||
[ "SET 2, A", 0xd7cb, 3 ],
|
||||
[ "SET 2, B", 0xd0cb, 3 ],
|
||||
[ "SET 2, C", 0xd1cb, 3 ],
|
||||
[ "SET 2, D", 0xd2cb, 3 ],
|
||||
[ "SET 2, E", 0xd3cb, 3 ],
|
||||
[ "SET 2, H", 0xd4cb, 3 ],
|
||||
[ "SET 2, [HL]", 0xd6cb, 3 ],
|
||||
[ "SET 2, L", 0xd5cb, 3 ],
|
||||
[ "SET 3, A", 0xdfcb, 3 ],
|
||||
[ "SET 3, B", 0xd8cb, 3 ],
|
||||
[ "SET 3, C", 0xd9cb, 3 ],
|
||||
[ "SET 3, D", 0xdacb, 3 ],
|
||||
[ "SET 3, E", 0xdbcb, 3 ],
|
||||
[ "SET 3, H", 0xdccb, 3 ],
|
||||
[ "SET 3, [HL]", 0xdecb, 3 ],
|
||||
[ "SET 3, L", 0xddcb, 3 ],
|
||||
[ "SET 4, A", 0xe7cb, 3 ],
|
||||
[ "SET 4, B", 0xe0cb, 3 ],
|
||||
[ "SET 4, C", 0xe1cb, 3 ],
|
||||
[ "SET 4, D", 0xe2cb, 3 ],
|
||||
[ "SET 4, E", 0xe3cb, 3 ],
|
||||
[ "SET 4, H", 0xe4cb, 3 ],
|
||||
[ "SET 4, [HL]", 0xe6cb, 3 ],
|
||||
[ "SET 4, L", 0xe5cb, 3 ],
|
||||
[ "SET 5, A", 0xefcb, 3 ],
|
||||
[ "SET 5, B", 0xe8cb, 3 ],
|
||||
[ "SET 5, C", 0xe9cb, 3 ],
|
||||
[ "SET 5, D", 0xeacb, 3 ],
|
||||
[ "SET 5, E", 0xebcb, 3 ],
|
||||
[ "SET 5, H", 0xeccb, 3 ],
|
||||
[ "SET 5, [HL]", 0xeecb, 3 ],
|
||||
[ "SET 5, L", 0xedcb, 3 ],
|
||||
[ "SET 6, A", 0xf7cb, 3 ],
|
||||
[ "SET 6, B", 0xf0cb, 3 ],
|
||||
[ "SET 6, C", 0xf1cb, 3 ],
|
||||
[ "SET 6, D", 0xf2cb, 3 ],
|
||||
[ "SET 6, E", 0xf3cb, 3 ],
|
||||
[ "SET 6, H", 0xf4cb, 3 ],
|
||||
[ "SET 6, [HL]", 0xf6cb, 3 ],
|
||||
[ "SET 6, L", 0xf5cb, 3 ],
|
||||
[ "SET 7, A", 0xffcb, 3 ],
|
||||
[ "SET 7, B", 0xf8cb, 3 ],
|
||||
[ "SET 7, C", 0xf9cb, 3 ],
|
||||
[ "SET 7, D", 0xfacb, 3 ],
|
||||
[ "SET 7, E", 0xfbcb, 3 ],
|
||||
[ "SET 7, H", 0xfccb, 3 ],
|
||||
[ "SET 7, [HL]", 0xfecb, 3 ],
|
||||
[ "SET 7, L", 0xfdcb, 3 ],
|
||||
[ "SLA A", 0x27cb, 3 ],
|
||||
[ "SLA B", 0x20cb, 3 ],
|
||||
[ "SLA C", 0x21cb, 3 ],
|
||||
[ "SLA D", 0x22cb, 3 ],
|
||||
[ "SLA E", 0x23cb, 3 ],
|
||||
[ "SLA H", 0x24cb, 3 ],
|
||||
[ "SLA [HL]", 0x26cb, 3 ],
|
||||
[ "SLA L", 0x25cb, 3 ],
|
||||
[ "SRA A", 0x2fcb, 3 ],
|
||||
[ "SRA B", 0x28cb, 3 ],
|
||||
[ "SRA C", 0x29cb, 3 ],
|
||||
[ "SRA D", 0x2acb, 3 ],
|
||||
[ "SRA E", 0x2bcb, 3 ],
|
||||
[ "SRA H", 0x2ccb, 3 ],
|
||||
[ "SRA [HL]", 0x2ecb, 3 ],
|
||||
[ "SRA L", 0x2dcb, 3 ],
|
||||
[ "SRL A", 0x3fcb, 3 ],
|
||||
[ "SRL B", 0x38cb, 3 ],
|
||||
[ "SRL C", 0x39cb, 3 ],
|
||||
[ "SRL D", 0x3acb, 3 ],
|
||||
[ "SRL E", 0x3bcb, 3 ],
|
||||
[ "SRL H", 0x3ccb, 3 ],
|
||||
[ "SRL [HL]", 0x3ecb, 3 ],
|
||||
[ "SRL L", 0x3dcb, 3 ],
|
||||
[ "STOP", 0x10, 0 ],
|
||||
[ "SUB A", 0x97, 0 ],
|
||||
[ "SUB B", 0x90, 0 ],
|
||||
[ "SUB C", 0x91, 0 ],
|
||||
[ "SUB D", 0x92, 0 ],
|
||||
[ "SUB E", 0x93, 0 ],
|
||||
[ "SUB H", 0x94, 0 ],
|
||||
[ "SUB [HL]", 0x96, 0 ],
|
||||
[ "SUB L", 0x95, 0 ],
|
||||
[ "SUB x", 0xd6, 1 ],
|
||||
[ "SWAP A", 0x37cb, 3 ],
|
||||
[ "SWAP B", 0x30cb, 3 ],
|
||||
[ "SWAP C", 0x31cb, 3 ],
|
||||
[ "SWAP D", 0x32cb, 3 ],
|
||||
[ "SWAP E", 0x33cb, 3 ],
|
||||
[ "SWAP H", 0x34cb, 3 ],
|
||||
[ "SWAP [HL]", 0x36cb, 3 ],
|
||||
[ "SWAP L", 0x35cb, 3 ],
|
||||
[ "XOR A", 0xaf, 0 ],
|
||||
[ "XOR B", 0xa8, 0 ],
|
||||
[ "XOR C", 0xa9, 0 ],
|
||||
[ "XOR D", 0xaa, 0 ],
|
||||
[ "XOR E", 0xab, 0 ],
|
||||
[ "XOR H", 0xac, 0 ],
|
||||
[ "XOR [HL]", 0xae, 0 ],
|
||||
[ "XOR L", 0xad, 0 ],
|
||||
[ "XOR x", 0xee, 1 ],
|
||||
[ "E", 0x100, -1 ],
|
||||
]
|
||||
|
||||
#find conflicts
|
||||
conflict_table = {}
|
||||
for line in temp_opt_table:
|
||||
if line[1] in conflict_table.keys():
|
||||
print "CONFLICT: " + line[0] + " ($" + hex(line[1])[2:] + ") .... " + conflict_table[line[1]]
|
||||
else:
|
||||
conflict_table[line[1]] = line[0]
|
||||
|
||||
#construct real opt_table
|
||||
opt_table = {}
|
||||
for line in temp_opt_table:
|
||||
opt_table[line[1]] = [line[0], line[2]]
|
||||
del temp_opt_table
|
||||
del line
|
||||
|
||||
end_08_scripts_with = [
|
||||
0xe9, #jp hl
|
||||
#0xc3, #jp
|
||||
##0x18, #jr
|
||||
0xc9, #ret
|
||||
###0xda, 0xe9, 0xd2, 0xc2, 0xca, 0xc3, 0x38, 0x30, 0x20, 0x28, 0x18, 0xd8, 0xd0, 0xc0, 0xc8, 0xc9
|
||||
]
|
||||
relative_jumps = [0x38, 0x30, 0x20, 0x28, 0x18, 0xc3, 0xda, 0xc2]
|
||||
relative_unconditional_jumps = [0xc3, 0x18]
|
||||
|
||||
#TODO: replace call and a pointer with call and a label
|
||||
call_commands = [0xdc, 0xd4, 0xc4, 0xcc, 0xcd]
|
||||
|
||||
|
||||
all_labels = {}
|
||||
|
||||
def load_labels(filename="labels.json"):
|
||||
global all_labels
|
||||
if os.path.exists(filename):
|
||||
all_labels = json.loads(open(filename, "r").read())
|
||||
else:
|
||||
print "You must run analyze_incbins.scan_for_predefined_labels() to create \"labels.json\". Trying..."
|
||||
import analyze_incbins
|
||||
analyze_incbins.scan_for_predefined_labels()
|
||||
load_labels()
|
||||
|
||||
def find_label(local_address, bank_id=0):
|
||||
global all_labels
|
||||
#keep an integer
|
||||
if type(local_address) == str:
|
||||
local_address1 = int(local_address.replace("$", "0x"), 16)
|
||||
else: local_address1 = local_address
|
||||
|
||||
#turn local_address into a string
|
||||
if type(local_address) == str:
|
||||
if "0x" in local_address: local_address = local_address.replace("0x", "$")
|
||||
elif not "$" in local_address: local_address = "$" + local_address
|
||||
if type(local_address) == int:
|
||||
local_address = "$%.x" % (local_address)
|
||||
local_address = local_address.upper()
|
||||
|
||||
for label_entry in all_labels:
|
||||
if label_entry["local_pointer"].upper() == local_address:
|
||||
if label_entry["bank_id"] == bank_id or (local_address1 < 0x8000 and (label_entry["bank_id"] == 0 or label_entry["bank_id"] == 1)):
|
||||
return label_entry["label"]
|
||||
return None
|
||||
|
||||
def random_asm_label():
|
||||
return ".ASM_" + random_hash()
|
||||
|
||||
def asm_label(address):
|
||||
# why using a random value when you can use the eff. address?
|
||||
return ".ASM_" + hex(address)[2:]
|
||||
|
||||
def output_bank_opcodes(original_offset, max_byte_count=0x4000):
|
||||
#fs = current_address
|
||||
#b = bank_byte
|
||||
#in = input_data -- extract_maps.rom
|
||||
#bank_size = byte_count
|
||||
#i = offset
|
||||
#ad = end_address
|
||||
#a, oa = current_byte_number
|
||||
|
||||
bank_id = 0
|
||||
if original_offset > 0x8000:
|
||||
bank_id = original_offset / 0x4000
|
||||
print "bank id is: " + str(bank_id)
|
||||
|
||||
last_hl_address = None #for when we're scanning the main map script
|
||||
last_a_address = None
|
||||
used_3d97 = False
|
||||
|
||||
rom = extract_maps.rom
|
||||
offset = original_offset
|
||||
current_byte_number = 0 #start from the beginning
|
||||
|
||||
#we don't actually have an end address, but we'll just say $4000
|
||||
end_address = original_offset + max_byte_count
|
||||
|
||||
byte_labels = {}
|
||||
|
||||
output = ""
|
||||
keep_reading = True
|
||||
while offset <= end_address and keep_reading:
|
||||
current_byte = ord(extract_maps.rom[offset])
|
||||
is_data = False
|
||||
maybe_byte = current_byte
|
||||
|
||||
#first check if this byte already has a label
|
||||
#if it does, use the label
|
||||
#if not, generate a new label
|
||||
if offset in byte_labels.keys():
|
||||
line_label = byte_labels[offset]["name"]
|
||||
byte_labels[offset]["usage"] += 1
|
||||
else:
|
||||
line_label = asm_label(offset)
|
||||
byte_labels[offset] = {}
|
||||
byte_labels[offset]["name"] = line_label
|
||||
byte_labels[offset]["usage"] = 0
|
||||
byte_labels[offset]["definition"] = True
|
||||
output += line_label.lower() + "\n" #" ; " + hex(offset) + "\n"
|
||||
|
||||
#find out if there's a two byte key like this
|
||||
temp_maybe = maybe_byte
|
||||
temp_maybe += ( ord(rom[offset+1]) << 8)
|
||||
if temp_maybe in opt_table.keys() and ord(rom[offset+1])!=0:
|
||||
opstr = opt_table[temp_maybe][0].lower()
|
||||
|
||||
if "x" in opstr:
|
||||
for x in range(0, opstr.count("x")):
|
||||
insertion = ord(rom[offset + 1])
|
||||
insertion = "$" + hex(insertion)[2:]
|
||||
|
||||
opstr = opstr[:opstr.find("x")].lower() + insertion + opstr[opstr.find("x")+1:].lower()
|
||||
|
||||
current_byte += 1
|
||||
offset += 1
|
||||
if "?" in opstr:
|
||||
for y in range(0, opstr.count("?")):
|
||||
byte1 = ord(rom[offset + 1])
|
||||
byte2 = ord(rom[offset + 2])
|
||||
|
||||
number = byte1
|
||||
number += byte2 << 8;
|
||||
|
||||
insertion = "$%.4x" % (number)
|
||||
|
||||
opstr = opstr[:opstr.find("?")].lower() + insertion + opstr[opstr.find("?")+1:].lower()
|
||||
|
||||
current_byte_number += 2
|
||||
offset += 2
|
||||
|
||||
output += spacing + opstr #+ " ; " + hex(offset)
|
||||
output += "\n"
|
||||
|
||||
current_byte_number += 2
|
||||
offset += 2
|
||||
elif maybe_byte in opt_table.keys():
|
||||
op_code = opt_table[maybe_byte]
|
||||
op_code_type = op_code[1]
|
||||
op_code_byte = maybe_byte
|
||||
|
||||
#type = -1 when it's the E op
|
||||
#if op_code_type != -1:
|
||||
if op_code_type == 0 and ord(rom[offset]) == op_code_byte:
|
||||
op_str = op_code[0].lower()
|
||||
|
||||
output += spacing + op_code[0].lower() #+ " ; " + hex(offset)
|
||||
output += "\n"
|
||||
|
||||
offset += 1
|
||||
current_byte_number += 1
|
||||
elif op_code_type == 1 and ord(rom[offset]) == op_code_byte:
|
||||
oplen = len(op_code[0])
|
||||
opstr = copy(op_code[0])
|
||||
xes = op_code[0].count("x")
|
||||
include_comment = False
|
||||
for x in range(0, xes):
|
||||
insertion = ord(rom[offset + 1])
|
||||
insertion = "$" + hex(insertion)[2:]
|
||||
|
||||
if current_byte == 0x18 or current_byte==0x20 or current_byte in relative_jumps: #jr or jr nz
|
||||
#generate a label for the byte we're jumping to
|
||||
target_address = offset + 2 + c_int8(ord(rom[offset + 1])).value
|
||||
if target_address in byte_labels.keys():
|
||||
byte_labels[target_address]["usage"] = 1 + byte_labels[target_address]["usage"]
|
||||
line_label2 = byte_labels[target_address]["name"]
|
||||
else:
|
||||
line_label2 = asm_label(target_address)
|
||||
byte_labels[target_address] = {}
|
||||
byte_labels[target_address]["name"] = line_label2
|
||||
byte_labels[target_address]["usage"] = 1
|
||||
byte_labels[target_address]["definition"] = False
|
||||
|
||||
insertion = line_label2.lower()
|
||||
include_comment = True
|
||||
elif current_byte == 0x3e:
|
||||
last_a_address = ord(rom[offset + 1])
|
||||
|
||||
opstr = opstr[:opstr.find("x")].lower() + insertion + opstr[opstr.find("x")+1:].lower()
|
||||
output += spacing + opstr
|
||||
if include_comment:
|
||||
output += " ; " + hex(offset)
|
||||
if current_byte in relative_jumps:
|
||||
output += " $" + hex(ord(rom[offset + 1]))[2:]
|
||||
output += "\n"
|
||||
|
||||
current_byte_number += 1
|
||||
offset += 1
|
||||
insertion = ""
|
||||
|
||||
current_byte_number += 1
|
||||
offset += 1
|
||||
include_comment = False
|
||||
elif op_code_type == 2 and ord(rom[offset]) == op_code_byte:
|
||||
oplen = len(op_code[0])
|
||||
opstr = copy(op_code[0])
|
||||
qes = op_code[0].count("?")
|
||||
for x in range(0, qes):
|
||||
byte1 = ord(rom[offset + 1])
|
||||
byte2 = ord(rom[offset + 2])
|
||||
|
||||
number = byte1
|
||||
number += byte2 << 8;
|
||||
|
||||
insertion = "$%.4x" % (number)
|
||||
if maybe_byte in call_commands or current_byte in relative_unconditional_jumps or current_byte in relative_jumps:
|
||||
result = find_label(insertion, bank_id)
|
||||
if result != None:
|
||||
insertion = result
|
||||
|
||||
opstr = opstr[:opstr.find("?")].lower() + insertion + opstr[opstr.find("?")+1:].lower()
|
||||
output += spacing + opstr #+ " ; " + hex(offset)
|
||||
output += "\n"
|
||||
|
||||
current_byte_number += 2
|
||||
offset += 2
|
||||
|
||||
current_byte_number += 1
|
||||
offset += 1
|
||||
|
||||
if current_byte == 0x21:
|
||||
last_hl_address = byte1 + (byte2 << 8)
|
||||
if current_byte == 0xcd:
|
||||
if number == 0x3d97: used_3d97 = True
|
||||
|
||||
#duck out if this is jp $24d7
|
||||
if current_byte == 0xc3 or current_byte in relative_unconditional_jumps:
|
||||
if current_byte == 0xc3:
|
||||
if number == 0x3d97: used_3d97 = True
|
||||
#if number == 0x24d7: #jp
|
||||
if not has_outstanding_labels(byte_labels) or all_outstanding_labels_are_reverse(byte_labels, offset):
|
||||
keep_reading = False
|
||||
is_data = False
|
||||
break
|
||||
else:
|
||||
is_data = True
|
||||
|
||||
#stop reading at a jump, relative jump or return
|
||||
if current_byte in end_08_scripts_with:
|
||||
if not has_outstanding_labels(byte_labels) and all_outstanding_labels_are_reverse(byte_labels, offset):
|
||||
keep_reading = False
|
||||
is_data = False #cleanup
|
||||
break
|
||||
else:
|
||||
is_data = False
|
||||
keep_reading = True
|
||||
else:
|
||||
is_data = False
|
||||
keep_reading = True
|
||||
else:
|
||||
# if is_data and keep_reading:
|
||||
output += spacing + "db $" + hex(ord(rom[offset]))[2:] #+ " ; " + hex(offset)
|
||||
output += "\n"
|
||||
offset += 1
|
||||
current_byte_number += 1
|
||||
#else the while loop would have spit out the opcode
|
||||
|
||||
#these two are done prior
|
||||
#offset += 1
|
||||
#current_byte_number += 1
|
||||
|
||||
#clean up unused labels
|
||||
for label_line in byte_labels.keys():
|
||||
address = label_line
|
||||
label_line = byte_labels[label_line]
|
||||
if label_line["usage"] == 0:
|
||||
output = output.replace((label_line["name"] + "\n").lower(), "")
|
||||
|
||||
#add the offset of the final location
|
||||
output += "; " + hex(offset)
|
||||
|
||||
return (output, offset, last_hl_address, last_a_address, used_3d97)
|
||||
|
||||
def has_outstanding_labels(byte_labels):
|
||||
"""
|
||||
if a label is used once, it means it has to be called or specified later
|
||||
"""
|
||||
for label_line in byte_labels.keys():
|
||||
real_line = byte_labels[label_line]
|
||||
if real_line["definition"] == False: return True
|
||||
return False
|
||||
|
||||
def all_outstanding_labels_are_reverse(byte_labels, offset):
|
||||
for label_id in byte_labels.keys():
|
||||
line = byte_labels[label_id] # label_id is also the address
|
||||
if line["definition"] == False:
|
||||
if not label_id < offset: return False
|
||||
return True
|
||||
|
||||
def text_asm_pretty_printer(label, address_of_08, include_08=True):
|
||||
"""returns (output, end_address)"""
|
||||
output = label + ": ; " + hex(address_of_08) + "\n"
|
||||
if include_08:
|
||||
output += spacing + "db $08 ; asm\n"
|
||||
results = output_bank_opcodes(address_of_08 + 1)
|
||||
else:
|
||||
results = output_bank_opcodes(address_of_08)
|
||||
output += results[0]
|
||||
end_address = results[1]
|
||||
|
||||
return (output, end_address)
|
||||
|
||||
if __name__ == "__main__":
|
||||
extract_maps.load_rom()
|
||||
extract_maps.load_map_pointers()
|
||||
extract_maps.read_all_map_headers()
|
||||
|
||||
#0x18f96 is PalletTownText1
|
||||
#0x19B5D is BluesHouseText1
|
||||
print output_bank_opcodes(int(sys.argv[1], 16))[0]
|
@ -1,8 +0,0 @@
|
||||
import json
|
||||
|
||||
import analyze_incbins
|
||||
analyze_incbins.scan_for_predefined_labels()
|
||||
|
||||
with open('../pokered.sym', 'w') as sym:
|
||||
for label in json.load(open('labels.json')):
|
||||
sym.write('{0:x}:{1} {2}\n'.format(label['bank_id'], label['local_pointer'][1:], label['label']))
|
@ -1,82 +0,0 @@
|
||||
#author: Bryan Bishop <kanzure@gmail.com>
|
||||
#date: 2012-01-05
|
||||
#insert object data into pokered.asm
|
||||
import extract_maps
|
||||
from pretty_map_headers import map_name_cleaner, object_data_pretty_printer, make_object_label_name, make_text_label, map_constants
|
||||
from analyze_incbins import asm, offset_to_pointer, find_incbin_to_replace_for, split_incbin_line_into_three, generate_diff_insert, load_asm, isolate_incbins, process_incbins
|
||||
import analyze_incbins
|
||||
import os, sys
|
||||
import subprocess
|
||||
spacing = " "
|
||||
|
||||
def insert_object(map_id):
|
||||
map = extract_maps.map_headers[map_id]
|
||||
object = map["object_data"]
|
||||
size = extract_maps.compute_object_data_size(object)
|
||||
address = int(map["object_data_pointer"], 16)
|
||||
|
||||
line_number = find_incbin_to_replace_for(address)
|
||||
if line_number == None:
|
||||
print "skipping object data for map " + str(map["id"]) + " at " + map["object_data_pointer"] + " for " + str(size) + " bytes."
|
||||
return
|
||||
|
||||
newlines = split_incbin_line_into_three(line_number, address, size)
|
||||
object_asm = object_data_pretty_printer(map_id)
|
||||
|
||||
newlines = newlines.split("\n")
|
||||
if len(newlines) == 2: index = 0 #replace the 1st line with new content
|
||||
elif len(newlines) == 3: index = 1 #replace the 2nd line with new content
|
||||
|
||||
newlines[index] = object_asm
|
||||
|
||||
if len(newlines) == 3 and newlines[2][-2:] == "$0":
|
||||
#get rid of the last incbin line if it is only including 0 bytes
|
||||
del newlines[2]
|
||||
#note that this has to be done after adding in the new asm
|
||||
newlines = "\n".join(line for line in newlines)
|
||||
|
||||
diff = generate_diff_insert(line_number, newlines)
|
||||
print diff
|
||||
|
||||
print "... Applying diff."
|
||||
|
||||
#write the diff to a file
|
||||
fh = open("temp.patch", "w")
|
||||
fh.write(diff)
|
||||
fh.close()
|
||||
|
||||
#apply the patch
|
||||
os.system("patch ../pokered.asm temp.patch")
|
||||
|
||||
#remove the patch
|
||||
os.system("rm temp.patch")
|
||||
|
||||
#confirm it's working
|
||||
subprocess.check_call("cd ../; make clean; LC_CTYPE=UTF-8 make", shell=True)
|
||||
|
||||
def insert_all_objects():
|
||||
for map_id in extract_maps.map_headers.keys():
|
||||
if map_id not in extract_maps.bad_maps:
|
||||
insert_object(map_id)
|
||||
|
||||
analyze_incbins.asm = None
|
||||
analyze_incbins.incbin_lines = []
|
||||
analyze_incbins.processed_incbins = {}
|
||||
load_asm()
|
||||
isolate_incbins()
|
||||
process_incbins()
|
||||
|
||||
if __name__ == "__main__":
|
||||
#load map headers and object data
|
||||
extract_maps.load_rom()
|
||||
extract_maps.load_map_pointers()
|
||||
extract_maps.read_all_map_headers()
|
||||
|
||||
#load incbins
|
||||
load_asm()
|
||||
isolate_incbins()
|
||||
process_incbins()
|
||||
|
||||
#insert_object(1)
|
||||
insert_all_objects()
|
||||
|
@ -1,891 +0,0 @@
|
||||
#author: Bryan Bishop <kanzure@gmail.com>
|
||||
#date: 2012-01-07, 2012-01-17, 2012-01-27
|
||||
#insert TX_FAR targets into pokered.asm
|
||||
#and other insertion tasks
|
||||
import extract_maps
|
||||
from analyze_texts import analyze_texts, text_pretty_printer_at, scan_rom_for_tx_fars
|
||||
from pretty_map_headers import map_name_cleaner, make_text_label, map_constants, find_all_tx_fars, tx_far_pretty_printer, tx_far_label_maker
|
||||
import pretty_map_headers
|
||||
from analyze_incbins import asm, offset_to_pointer, find_incbin_to_replace_for, split_incbin_line_into_three, generate_diff_insert, load_asm, isolate_incbins, process_incbins, reset_incbins, apply_diff
|
||||
import analyze_incbins
|
||||
from gbz80disasm import text_asm_pretty_printer, output_bank_opcodes, load_labels, find_label
|
||||
import os, sys
|
||||
import subprocess
|
||||
spacing = " "
|
||||
tx_fars = None
|
||||
failed_attempts = {}
|
||||
|
||||
pokemons = ["BULBASAUR", "IVYSAUR", "VENUSAUR", "CHARMANDER", "CHARMELEON", "CHARIZARD", "SQUIRTLE", "WARTORTLE", "BLASTOISE", "CATERPIE", "METAPOD", "BUTTERFREE", "WEEDLE", "KAKUNA", "BEEDRILL", "PIDGEY", "PIDGEOTTO", "PIDGEOT", "RATTATA", "RATICATE", "SPEAROW", "FEAROW", "EKANS", "ARBOK", "PIKACHU", "RAICHU", "SANDSHREW", "SANDSLASH", "NIDORANF", "NIDORINA", "NIDOQUEEN", "NIDORANM", "NIDORINO", "NIDOKING", "CLEFAIRY", "CLEFABLE", "VULPIX", "NINETALES", "JIGGLYPUFF", "WIGGLYTUFF", "ZUBAT", "GOLBAT", "ODDISH", "GLOOM", "VILEPLUME", "PARAS", "PARASECT", "VENONAT", "VENOMOTH", "DIGLETT", "DUGTRIO", "MEOWTH", "PERSIAN", "PSYDUCK", "GOLDUCK", "MANKEY", "PRIMEAPE", "GROWLITHE", "ARCANINE", "POLIWAG", "POLIWHIRL", "POLIWRATH", "ABRA", "KADABRA", "ALAKAZAM", "MACHOP", "MACHOKE", "MACHAMP", "BELLSPROUT", "WEEPINBELL", "VICTREEBEL", "TENTACOOL", "TENTACRUEL", "GEODUDE", "GRAVELER", "GOLEM", "PONYTA", "RAPIDASH", "SLOWPOKE", "SLOWBRO", "MAGNEMITE", "MAGNETON", "FARFETCH_D", "DODUO", "DODRIO", "SEEL", "DEWGONG", "GRIMER", "MUK", "SHELLDER", "CLOYSTER", "GASTLY", "HAUNTER", "GENGAR", "ONIX", "DROWZEE", "HYPNO", "KRABBY", "KINGLER", "VOLTORB", "ELECTRODE", "EXEGGCUTE", "EXEGGUTOR", "CUBONE", "MAROWAK", "HITMONLEE", "HITMONCHAN", "LICKITUNG", "KOFFING", "WEEZING", "RHYHORN", "RHYDON", "CHANSEY", "TANGELA", "KANGASKHAN", "HORSEA", "SEADRA", "GOLDEEN", "SEAKING", "STARYU", "STARMIE", "MR_MIME", "SCYTHER", "JYNX", "ELECTABUZZ", "MAGMAR", "PINSIR", "TAUROS", "MAGIKARP", "GYARADOS", "LAPRAS", "DITTO", "EEVEE", "VAPOREON", "JOLTEON", "FLAREON", "PORYGON", "OMANYTE", "OMASTAR", "KABUTO", "KABUTOPS", "AERODACTYL", "SNORLAX", "ARTICUNO", "ZAPDOS", "MOLTRES", "DRATINI", "DRAGONAIR", "DRAGONITE", "MEWTWO", "MEW"]
|
||||
|
||||
moves = [["POUND", 0x01], ["KARATE_CHOP", 0x02], ["DOUBLESLAP", 0x03], ["COMET_PUNCH", 0x04], ["MEGA_PUNCH", 0x05], ["PAY_DAY", 0x06], ["FIRE_PUNCH", 0x07], ["ICE_PUNCH", 0x08], ["THUNDERPUNCH", 0x09], ["SCRATCH", 0x0A], ["VICEGRIP", 0x0B], ["GUILLOTINE", 0x0C], ["RAZOR_WIND", 0x0D], ["SWORDS_DANCE", 0x0E], ["CUT", 0x0F], ["GUST", 0x10], ["WING_ATTACK", 0x11], ["WHIRLWIND", 0x12], ["FLY", 0x13], ["BIND", 0x14], ["SLAM", 0x15], ["VINE_WHIP", 0x16], ["STOMP", 0x17], ["DOUBLE_KICK", 0x18], ["MEGA_KICK", 0x19], ["JUMP_KICK", 0x1A], ["ROLLING_KICK", 0x1B], ["SAND_ATTACK", 0x1C], ["HEADBUTT", 0x1D], ["HORN_ATTACK", 0x1E], ["FURY_ATTACK", 0x1F], ["HORN_DRILL", 0x20], ["TACKLE", 0x21], ["BODY_SLAM", 0x22], ["WRAP", 0x23], ["TAKE_DOWN", 0x24], ["THRASH", 0x25], ["DOUBLE_EDGE", 0x26], ["TAIL_WHIP", 0x27], ["POISON_STING", 0x28], ["TWINEEDLE", 0x29], ["PIN_MISSILE", 0x2A], ["LEER", 0x2B], ["BITE", 0x2C], ["GROWL", 0x2D], ["ROAR", 0x2E], ["SING", 0x2F], ["SUPERSONIC", 0x30], ["SONICBOOM", 0x31], ["DISABLE", 0x32], ["ACID", 0x33], ["EMBER", 0x34], ["FLAMETHROWER", 0x35], ["MIST", 0x36], ["WATER_GUN", 0x37], ["HYDRO_PUMP", 0x38], ["SURF", 0x39], ["ICE_BEAM", 0x3A], ["BLIZZARD", 0x3B], ["PSYBEAM", 0x3C], ["BUBBLEBEAM", 0x3D], ["AURORA_BEAM", 0x3E], ["HYPER_BEAM", 0x3F], ["PECK", 0x40], ["DRILL_PECK", 0x41], ["SUBMISSION", 0x42], ["LOW_KICK", 0x43], ["COUNTER", 0x44], ["SEISMIC_TOSS", 0x45], ["STRENGTH", 0x46], ["ABSORB", 0x47], ["MEGA_DRAIN", 0x48], ["LEECH_SEED", 0x49], ["GROWTH", 0x4A], ["RAZOR_LEAF", 0x4B], ["SOLARBEAM", 0x4C], ["POISONPOWDER", 0x4D], ["STUN_SPORE", 0x4E], ["SLEEP_POWDER", 0x4F], ["PETAL_DANCE", 0x50], ["STRING_SHOT", 0x51], ["DRAGON_RAGE", 0x52], ["FIRE_SPIN", 0x53], ["THUNDERSHOCK", 0x54], ["THUNDERBOLT", 0x55], ["THUNDER_WAVE", 0x56], ["THUNDER", 0x57], ["ROCK_THROW", 0x58], ["EARTHQUAKE", 0x59], ["FISSURE", 0x5A], ["DIG", 0x5B], ["TOXIC", 0x5C], ["CONFUSION", 0x5D], ["PSYCHIC_M", 0x5E], ["HYPNOSIS", 0x5F], ["MEDITATE", 0x60], ["AGILITY", 0x61], ["QUICK_ATTACK", 0x62], ["RAGE", 0x63], ["TELEPORT", 0x64], ["NIGHT_SHADE", 0x65], ["MIMIC", 0x66], ["SCREECH", 0x67], ["DOUBLE_TEAM", 0x68], ["RECOVER", 0x69], ["HARDEN", 0x6A], ["MINIMIZE", 0x6B], ["SMOKESCREEN", 0x6C], ["CONFUSE_RAY", 0x6D], ["WITHDRAW", 0x6E], ["DEFENSE_CURL", 0x6F], ["BARRIER", 0x70], ["LIGHT_SCREEN", 0x71], ["HAZE", 0x72], ["REFLECT", 0x73], ["FOCUS_ENERGY", 0x74], ["BIDE", 0x75], ["METRONOME", 0x76], ["MIRROR_MOVE", 0x77], ["SELFDESTRUCT", 0x78], ["EGG_BOMB", 0x79], ["LICK", 0x7A], ["SMOG", 0x7B], ["SLUDGE", 0x7C], ["BONE_CLUB", 0x7D], ["FIRE_BLAST", 0x7E], ["WATERFALL", 0x7F], ["CLAMP", 0x80], ["SWIFT", 0x81], ["SKULL_BASH", 0x82], ["SPIKE_CANNON", 0x83], ["CONSTRICT", 0x84], ["AMNESIA", 0x85], ["KINESIS", 0x86], ["SOFTBOILED", 0x87], ["HI_JUMP_KICK", 0x88], ["GLARE", 0x89], ["DREAM_EATER", 0x8A], ["POISON_GAS", 0x8B], ["BARRAGE", 0x8C], ["LEECH_LIFE", 0x8D], ["LOVELY_KISS", 0x8E], ["SKY_ATTACK", 0x8F], ["TRANSFORM", 0x90], ["BUBBLE", 0x91], ["DIZZY_PUNCH", 0x92], ["SPORE", 0x93], ["FLASH", 0x94], ["PSYWAVE", 0x95], ["SPLASH", 0x96], ["ACID_ARMOR", 0x97], ["CRABHAMMER", 0x98], ["EXPLOSION", 0x99], ["FURY_SWIPES", 0x9A], ["BONEMERANG", 0x9B], ["REST", 0x9C], ["ROCK_SLIDE", 0x9D], ["HYPER_FANG", 0x9E], ["SHARPEN", 0x9F], ["CONVERSION", 0xA0], ["TRI_ATTACK", 0xA1], ["SUPER_FANG", 0xA2], ["SLASH", 0xA3], ["SUBSTITUTE", 0xA4], ["STRUGGLE", 0xA5]]
|
||||
|
||||
elemental_types = [
|
||||
["NORMAL", "EQU", 0x00],
|
||||
["FIGHTING", "EQU", 0x01],
|
||||
["FLYING", "EQU", 0x02],
|
||||
["POISON", "EQU", 0x03],
|
||||
["GROUND", "EQU", 0x04],
|
||||
["ROCK", "EQU", 0x05],
|
||||
["BUG", "EQU", 0x07],
|
||||
["GHOST", "EQU", 0x08],
|
||||
["FIRE", "EQU", 0x14],
|
||||
["WATER", "EQU", 0x15],
|
||||
["GRASS", "EQU", 0x16],
|
||||
["ELECTRIC", "EQU", 0x17],
|
||||
["PSYCHIC", "EQU", 0x18],
|
||||
["ICE", "EQU", 0x19],
|
||||
["DRAGON", "EQU", 0x1A]]
|
||||
|
||||
def local_reset_incbins():
|
||||
asm = None
|
||||
incbin_lines = []
|
||||
processed_incbins = {}
|
||||
analyze_incbins.asm = None
|
||||
analyze_incbins.incbin_lines = []
|
||||
analyze_incbins.processed_incbins = {}
|
||||
|
||||
#reload
|
||||
load_asm()
|
||||
isolate_incbins()
|
||||
process_incbins()
|
||||
|
||||
def find_tx_far_entry(map_id, text_id):
|
||||
for tx_far_line in tx_fars:
|
||||
if tx_far_line[0] == map_id and tx_far_line[1] == text_id:
|
||||
return tx_far_line
|
||||
|
||||
def insert_tx_far(map_id, text_id, tx_far_line=None):
|
||||
"inserts a tx_far"
|
||||
global tx_fars
|
||||
if tx_far_line == None:
|
||||
tx_far_line = find_tx_far_entry(map_id, text_id)
|
||||
text_pointer = tx_far_line[2]
|
||||
start_address = tx_far_line[3]
|
||||
tx_far_object = tx_far_line[4]
|
||||
end_address = tx_far_object[1]["end_address"] + 1 #the end byte; +1 because of a bug somewhere :(
|
||||
|
||||
line_number = find_incbin_to_replace_for(start_address)
|
||||
if line_number == None:
|
||||
print "skipping tx_far for map_id=" + str(map_id) + " text_id=" + str(text_id) + " text_pointer=" + hex(text_pointer) + " tx_far_start_address=" + hex(start_address)
|
||||
return
|
||||
|
||||
#also do a name check
|
||||
label = tx_far_label_maker(extract_maps.map_headers[map_id]["name"], text_id)
|
||||
if (label + ":") in "\n".join(analyze_incbins.asm):
|
||||
print "skipping tx_far for map_id=" + str(map_id) + " text_id=" + str(text_id) + " text_pointer=" + hex(text_pointer) + " tx_far_start_address=" + hex(start_address)
|
||||
return
|
||||
|
||||
newlines = split_incbin_line_into_three(line_number, start_address, end_address - start_address)
|
||||
tx_far_asm = tx_far_pretty_printer(tx_far_line)
|
||||
|
||||
newlines = newlines.split("\n")
|
||||
if len(newlines) == 2: index = 0 #replace the 1st line with new content
|
||||
elif len(newlines) == 3: index = 1 #replace the 2nd line with new content
|
||||
|
||||
newlines[index] = tx_far_asm
|
||||
|
||||
if len(newlines) == 3 and newlines[2][-2:] == "$0":
|
||||
#get rid of the last incbin line if it is only including 0 bytes
|
||||
del newlines[2]
|
||||
#note that this has to be done after adding in the new asm
|
||||
newlines = "\n".join(line for line in newlines)
|
||||
newlines = newlines.replace("$x", "$") #where does this keep coming from??
|
||||
|
||||
#signs are dumb; cluster the labels please
|
||||
if "\"needs fulfilled!\", $55" in newlines:
|
||||
newlines = "\n" + label + ": "
|
||||
line_number += 1
|
||||
if ("STRENGTH to move!" in newlines) or ("it the way it is." in newlines):
|
||||
newlines = "\n" + label + ": "
|
||||
line_number += 1
|
||||
if "@\"" in newlines and not "@@\"" in newlines:
|
||||
newlines = newlines.replace("@", "@@")
|
||||
|
||||
#Char52 doesn't work yet? oh well
|
||||
newlines = newlines.replace("Char52", "$52")
|
||||
|
||||
diff = generate_diff_insert(line_number, newlines)
|
||||
print "working on map_id=" + str(map_id) + " text_id=" + str(text_id)
|
||||
print diff
|
||||
apply_diff(diff)
|
||||
|
||||
def insert_all_tx_far_targets():
|
||||
for tx_far in tx_fars:
|
||||
map_id = tx_far[0]
|
||||
text_id = tx_far[1]
|
||||
#if map_id <= 185: continue #i'm just trying to get it going faster
|
||||
|
||||
insert_tx_far(map_id, text_id, tx_far_line=tx_far)
|
||||
|
||||
reset_incbins()
|
||||
analyze_incbins.reset_incbins()
|
||||
asm = None
|
||||
incbin_lines = []
|
||||
processed_incbins = {}
|
||||
analyze_incbins.asm = None
|
||||
analyze_incbins.incbin_lines = []
|
||||
analyze_incbins.processed_incbins = {}
|
||||
|
||||
load_asm()
|
||||
isolate_incbins()
|
||||
process_incbins()
|
||||
|
||||
def all_texts_are_tx_fars(map_id):
|
||||
map2 = extract_maps.map_headers[map_id]
|
||||
for text_id in map2["texts"]:
|
||||
txt = map2["texts"][text_id]
|
||||
if not "TX_FAR" in txt[0].keys(): return False
|
||||
return True
|
||||
|
||||
def texts_label_pretty_printer(map_id):
|
||||
"output a texts label for map if all texts are TX_FARs and in the asm already"
|
||||
#extract_maps.map_headers[map_id]["texts"][text_id][0]["TX_FAR"]
|
||||
#if not all_texts_are_tx_fars(map_id): return None
|
||||
map2 = extract_maps.map_headers[map_id]
|
||||
|
||||
#pointer to the list of texts
|
||||
texts_list_pointer = int(map2["texts_pointer"], 16)
|
||||
|
||||
#get the label for this texts list
|
||||
base_label = map_name_cleaner(map2["name"], None)[:-2]
|
||||
label = base_label + "Texts"
|
||||
|
||||
#make up a label for each text
|
||||
text_labels = []
|
||||
text_id = 1
|
||||
for text in map2["texts"].keys():
|
||||
text_label = base_label + "Text" + str(text_id)
|
||||
text_labels.append(text_label)
|
||||
text_id += 1
|
||||
|
||||
output = label + ": ; " + hex(texts_list_pointer)
|
||||
output += "\n"
|
||||
output += spacing + "dw "
|
||||
|
||||
first = True
|
||||
for labela in text_labels:
|
||||
if not first:
|
||||
output += ", " + labela
|
||||
else:
|
||||
output += labela
|
||||
first = False
|
||||
|
||||
return output
|
||||
|
||||
def insert_texts_label(map_id):
|
||||
#if not all_texts_are_tx_fars(map_id): return None
|
||||
map2 = extract_maps.map_headers[map_id]
|
||||
|
||||
base_label = map_name_cleaner(map2["name"], None)[:-2]
|
||||
label = base_label + "Texts"
|
||||
texts_pointer = int(map2["texts_pointer"], 16)
|
||||
|
||||
insert_asm = texts_label_pretty_printer(map_id)
|
||||
|
||||
line_number = find_incbin_to_replace_for(texts_pointer)
|
||||
if line_number == None:
|
||||
print "skipping texts label for map_id=" + str(map_id) + " texts_pointer=" + hex(texts_pointer) + " because the address is taken"
|
||||
return
|
||||
|
||||
#also do a name check
|
||||
if (label + ":") in "\n".join(analyze_incbins.asm):
|
||||
print "skipping texts label for map_id=" + str(map_id) + " texts_pointer=" + hex(texts_pointer) + " because the label is already used"
|
||||
return
|
||||
|
||||
newlines = split_incbin_line_into_three(line_number, texts_pointer, len(map2["referenced_texts"])*2 )
|
||||
|
||||
newlines = newlines.split("\n")
|
||||
if len(newlines) == 2: index = 0 #replace the 1st line with new content
|
||||
elif len(newlines) == 3: index = 1 #replace the 2nd line with new content
|
||||
|
||||
newlines[index] = insert_asm
|
||||
|
||||
if len(newlines) == 3 and newlines[2][-2:] == "$0":
|
||||
#get rid of the last incbin line if it is only including 0 bytes
|
||||
del newlines[2]
|
||||
#note that this has to be done after adding in the new asm
|
||||
newlines = "\n".join(line for line in newlines)
|
||||
newlines = newlines.replace("$x", "$")
|
||||
|
||||
diff = generate_diff_insert(line_number, newlines)
|
||||
print "working on map_id=" + str(map_id) + " texts_pointer=" + hex(texts_pointer)
|
||||
print diff
|
||||
apply_diff(diff)
|
||||
|
||||
#untested as of 2012-01-07
|
||||
def insert_all_texts_labels():
|
||||
for map_id in extract_maps.map_headers.keys():
|
||||
if map_id not in extract_maps.bad_maps:
|
||||
if len(extract_maps.map_headers[map_id]["referenced_texts"]) > 0:
|
||||
insert_texts_label(map_id)
|
||||
|
||||
reset_incbins()
|
||||
analyze_incbins.reset_incbins()
|
||||
asm = None
|
||||
incbin_lines = []
|
||||
processed_incbins = {}
|
||||
analyze_incbins.asm = None
|
||||
analyze_incbins.incbin_lines = []
|
||||
analyze_incbins.processed_incbins = {}
|
||||
|
||||
load_asm()
|
||||
isolate_incbins()
|
||||
process_incbins()
|
||||
|
||||
def txt_to_tx_far_pretty_printer(address, label, target_label, include_byte=False):
|
||||
output = "\n" + label + ": ; " + hex(address) + "\n"
|
||||
output += spacing + "TX_FAR " + target_label + "\n"
|
||||
if include_byte:
|
||||
output += spacing + "db $50\n"
|
||||
return output
|
||||
|
||||
def insert_text_label_tx_far(map_id, text_id):
|
||||
if map_id in extract_maps.bad_maps:
|
||||
print "bad map id=" + str(map_id)
|
||||
return
|
||||
map2 = extract_maps.map_headers[map_id]
|
||||
if map2["texts"][text_id] == {0: {}}: return None
|
||||
|
||||
base_label = map_name_cleaner(map2["name"], None)[:-2]
|
||||
label = base_label + "Text" + str(text_id)
|
||||
target_label = "_" + label
|
||||
start_address = map2["texts"][text_id][0]["start_address"]
|
||||
if 0x4000 <= start_address <= 0x7fff:
|
||||
start_address = extract_maps.calculate_pointer(start_address, int(map2["bank"],16))
|
||||
include_byte = False
|
||||
print map2["texts"][text_id]
|
||||
if "type" in map2["texts"][text_id][1].keys():
|
||||
if map2["texts"][text_id][1]["type"] == 0x50:
|
||||
include_byte = True
|
||||
tx_far_asm = txt_to_tx_far_pretty_printer(start_address, label, target_label, include_byte=include_byte)
|
||||
|
||||
line_number = find_incbin_to_replace_for(start_address)
|
||||
if line_number == None:
|
||||
print "skipping text label that calls TX_FAR for map_id=" + str(map_id) + " text_id=" + str(text_id) + " because the address is taken " + hex(start_address)
|
||||
return
|
||||
|
||||
#also do a name check
|
||||
if 1 < ("\n".join(analyze_incbins.asm)).count("\n" + label + ":"):
|
||||
print "skipping text label that calls TX_FAR for map_id=" + str(map_id) + " text_id" + str(text_id) + " because the label is already used (" + label + ":)"
|
||||
return
|
||||
|
||||
extra = 0
|
||||
if include_byte: extra += 1
|
||||
newlines = split_incbin_line_into_three(line_number, start_address, 4 + extra )
|
||||
|
||||
newlines = newlines.split("\n")
|
||||
if len(newlines) == 2: index = 0 #replace the 1st line with new content
|
||||
elif len(newlines) == 3: index = 1 #replace the 2nd line with new content
|
||||
|
||||
newlines[index] = tx_far_asm
|
||||
|
||||
if len(newlines) == 3 and newlines[2][-2:] == "$0":
|
||||
#get rid of the last incbin line if it is only including 0 bytes
|
||||
del newlines[2]
|
||||
#note that this has to be done after adding in the new asm
|
||||
newlines = "\n".join(line for line in newlines)
|
||||
|
||||
newlines = newlines.replace("$x", "$")
|
||||
|
||||
diff = generate_diff_insert(line_number, newlines)
|
||||
print "working on map_id=" + str(map_id) + " text_id=" + str(text_id)
|
||||
print diff
|
||||
apply_diff(diff)
|
||||
|
||||
def insert_all_text_labels():
|
||||
for map_id in extract_maps.map_headers.keys():
|
||||
if map_id <= 100: continue #skip
|
||||
if map_id not in extract_maps.bad_maps:
|
||||
for text_id in extract_maps.map_headers[map_id]["referenced_texts"]:
|
||||
insert_text_label_tx_far(map_id, text_id)
|
||||
|
||||
reset_incbins()
|
||||
analyze_incbins.reset_incbins()
|
||||
asm = None
|
||||
incbin_lines = []
|
||||
processed_incbins = {}
|
||||
analyze_incbins.asm = None
|
||||
analyze_incbins.incbin_lines = []
|
||||
analyze_incbins.processed_incbins = {}
|
||||
|
||||
load_asm()
|
||||
isolate_incbins()
|
||||
process_incbins()
|
||||
|
||||
#TODO: if line_id !=0 then don't include the label?
|
||||
def insert_08_asm(map_id, text_id, line_id=0):
|
||||
map2 = extract_maps.map_headers[map_id]
|
||||
base_label = map_name_cleaner(map2["name"], None)[:-2]
|
||||
label = base_label + "Text" + str(text_id)
|
||||
|
||||
start_address = all_texts[map_id][text_id][line_id]["start_address"]
|
||||
|
||||
(text_asm, end_address) = text_asm_pretty_printer(label, start_address)
|
||||
print "end address is: " + hex(end_address)
|
||||
|
||||
#find where to insert the assembly
|
||||
line_number = find_incbin_to_replace_for(start_address)
|
||||
if line_number == None:
|
||||
print "skipping text label for a $08 on map_id=" + str(map_id) + " text_id=" + str(text_id) + " because the address is taken"
|
||||
return
|
||||
|
||||
#also do a name check
|
||||
if 1 <= ("\n".join(analyze_incbins.asm)).count("\n" + label + ":"):
|
||||
print "skipping text label for a $08 on map_id=" + str(map_id) + " text_id=" + str(text_id) + " because the label is already taken (" + label + ":)"
|
||||
return
|
||||
|
||||
newlines = split_incbin_line_into_three(line_number, start_address, end_address - start_address )
|
||||
|
||||
newlines = newlines.split("\n")
|
||||
if len(newlines) == 2: index = 0 #replace the 1st line with new content
|
||||
elif len(newlines) == 3: index = 1 #replace the 2nd line with new content
|
||||
|
||||
newlines[index] = text_asm
|
||||
|
||||
if len(newlines) == 3 and newlines[2][-2:] == "$0":
|
||||
#get rid of the last incbin line if it is only including 0 bytes
|
||||
del newlines[2]
|
||||
#note that this has to be done after adding in the new asm
|
||||
newlines = "\n".join(line for line in newlines)
|
||||
|
||||
newlines = newlines.replace("$x", "$")
|
||||
|
||||
diff = generate_diff_insert(line_number, newlines)
|
||||
print "working on map_id=" + str(map_id) + " text_id=" + str(text_id)
|
||||
print diff
|
||||
result = apply_diff(diff)
|
||||
|
||||
if result == False:
|
||||
failed_attempts[len(failed_attempts.keys())] = {"map_id": map_id, "text_id": text_id}
|
||||
|
||||
def find_all_08s():
|
||||
all_08s = []
|
||||
for map_id in all_texts:
|
||||
for text_id in all_texts[map_id].keys():
|
||||
if 0 in all_texts[map_id][text_id].keys():
|
||||
for line_id in all_texts[map_id][text_id].keys():
|
||||
if all_texts[map_id][text_id][line_id]["type"] == 0x8:
|
||||
all_08s.append([map_id, text_id, line_id])
|
||||
return all_08s
|
||||
|
||||
def insert_all_08s():
|
||||
all_08s = find_all_08s()
|
||||
for the_08_line in all_08s:
|
||||
map_id = the_08_line[0]
|
||||
if map_id <= 86: continue #speed things up
|
||||
text_id = the_08_line[1]
|
||||
line_id = the_08_line[2]
|
||||
|
||||
print "processing map_id=" + str(map_id) + " text_id=" + str(text_id)
|
||||
insert_08_asm(map_id, text_id, line_id)
|
||||
|
||||
#reset everything
|
||||
analyze_incbins.reset_incbins()
|
||||
asm = None
|
||||
incbin_lines = []
|
||||
processed_incbins = {}
|
||||
analyze_incbins.asm = None
|
||||
analyze_incbins.incbin_lines = []
|
||||
analyze_incbins.processed_incbins = {}
|
||||
|
||||
#reload
|
||||
load_asm()
|
||||
isolate_incbins()
|
||||
process_incbins()
|
||||
|
||||
def insert_asm(start_address, label, text_asm=None, end_address=None):
|
||||
if text_asm == None and end_address == None:
|
||||
(text_asm, end_address) = text_asm_pretty_printer(label, start_address, include_08=False)
|
||||
print "end address is: " + hex(end_address)
|
||||
|
||||
#find where to insert the assembly
|
||||
line_number = find_incbin_to_replace_for(start_address)
|
||||
if line_number == None:
|
||||
print "skipping asm because the address is taken"
|
||||
return False
|
||||
|
||||
#name check
|
||||
if (label + ":") in "\n".join(analyze_incbins.asm):
|
||||
print "skipping asm because the label is taken"
|
||||
return False
|
||||
|
||||
newlines = split_incbin_line_into_three(line_number, start_address, end_address - start_address )
|
||||
|
||||
newlines = newlines.split("\n")
|
||||
if len(newlines) == 2: index = 0 #replace the 1st line with new content
|
||||
elif len(newlines) == 3: index = 1 #replace the 2nd line with new content
|
||||
|
||||
newlines[index] = text_asm
|
||||
|
||||
if len(newlines) == 3 and newlines[2][-2:] == "$0":
|
||||
#get rid of the last incbin line if it is only including 0 bytes
|
||||
del newlines[2]
|
||||
#note that this has to be done after adding in the new asm
|
||||
newlines = "\n".join(line for line in newlines)
|
||||
|
||||
newlines = newlines.replace("$x", "$")
|
||||
|
||||
diff = generate_diff_insert(line_number, newlines)
|
||||
print diff
|
||||
result = apply_diff(diff, try_fixing=True)
|
||||
return True
|
||||
|
||||
def insert_text(address, label, apply=False, try_fixing=True):
|
||||
"inserts a text script (but not $8s)"
|
||||
start_address = address
|
||||
|
||||
line_number = find_incbin_to_replace_for(start_address)
|
||||
if line_number == None:
|
||||
print "skipping text at " + hex(start_address) + " with address " + label
|
||||
return "skip"
|
||||
|
||||
#another reason to skip is if the interval is 0
|
||||
processed_incbin = analyze_incbins.processed_incbins[line_number]
|
||||
if processed_incbin["interval"] == 0:
|
||||
print "skipping text at " + hex(start_address) + " with address " + label + " because the interval is 0"
|
||||
return "skip"
|
||||
|
||||
text_asm, byte_count = text_pretty_printer_at(start_address, label)
|
||||
end_address = start_address + byte_count
|
||||
newlines = split_incbin_line_into_three(line_number, start_address, byte_count)
|
||||
|
||||
newlines = newlines.split("\n")
|
||||
if len(newlines) == 2: index = 0 #replace the 1st line with new content
|
||||
elif len(newlines) == 3: index = 1 #replace the 2nd line with new content
|
||||
|
||||
newlines[index] = text_asm
|
||||
|
||||
if len(newlines) == 3 and newlines[2][-2:] == "$0":
|
||||
#get rid of the last incbin line if it is only including 0 bytes
|
||||
del newlines[2]
|
||||
#note that this has to be done after adding in the new asm
|
||||
newlines = "\n".join(line for line in newlines)
|
||||
newlines = newlines.replace("$x", "$") #where does this keep coming from??
|
||||
|
||||
#Char52 doesn't work yet
|
||||
newlines = newlines.replace("Char52", "$52")
|
||||
|
||||
diff = generate_diff_insert(line_number, newlines)
|
||||
print diff
|
||||
if apply:
|
||||
return apply_diff(diff, try_fixing=try_fixing)
|
||||
else: #simulate a successful insertion
|
||||
return True
|
||||
|
||||
#move this into another file?
|
||||
def scan_for_map_scripts_pointer():
|
||||
for map_id in extract_maps.map_headers.keys(): #skip id=0 (Pallet Town) because the naming conventions are wonky
|
||||
map2 = extract_maps.map_headers[map_id]
|
||||
if map_id in extract_maps.bad_maps or map_id in [0, 39, 37, 38]: continue #skip
|
||||
script_pointer = int(map2["script_pointer"], 16)
|
||||
|
||||
main_asm_output, offset, last_hl_address, last_a_address, used_3d97 = output_bank_opcodes(script_pointer)
|
||||
hl_pointer = "None"
|
||||
|
||||
first_script_text = ""
|
||||
if last_hl_address != None and last_hl_address != "None" and used_3d97==True:
|
||||
if last_hl_address > 0x3fff:
|
||||
hl_pointer = extract_maps.calculate_pointer(last_hl_address, int(map2["bank"], 16))
|
||||
else:
|
||||
hl_pointer = last_hl_address
|
||||
byte1 = ord(extract_maps.rom[hl_pointer])
|
||||
byte2 = ord(extract_maps.rom[hl_pointer+1])
|
||||
address = byte1 + (byte2 << 8)
|
||||
|
||||
if address > 0x3fff:
|
||||
first_script_pointer = extract_maps.calculate_pointer(address, int(map2["bank"], 16))
|
||||
else:
|
||||
first_script_pointer = address
|
||||
|
||||
#for later output
|
||||
first_script_text = " first_script=" + hex(first_script_pointer)
|
||||
|
||||
#go ahead and insert this script pointer
|
||||
insert_asm(first_script_pointer, map_name_cleaner(map2["name"], None)[:-2] + "Script0")
|
||||
|
||||
#reset everything
|
||||
#analyze_incbins.reset_incbins()
|
||||
asm = None
|
||||
incbin_lines = []
|
||||
processed_incbins = {}
|
||||
analyze_incbins.asm = None
|
||||
analyze_incbins.incbin_lines = []
|
||||
analyze_incbins.processed_incbins = {}
|
||||
|
||||
#reload
|
||||
load_asm()
|
||||
isolate_incbins()
|
||||
process_incbins()
|
||||
|
||||
a_numbers = [0]
|
||||
last_a_id = 0
|
||||
script_pointers = [hex(first_script_pointer)]
|
||||
latest_script_pointer = first_script_pointer
|
||||
while last_a_id == (max(a_numbers)) or last_a_id==0:
|
||||
asm_output, offset, last_hl_address2, last_a_id, byte1, byte2, address = None, None, None, None, None, None, None
|
||||
asm_output, offset, last_hl_address2, last_a_id, used_3d97_2 = output_bank_opcodes(latest_script_pointer)
|
||||
|
||||
if last_a_id == (max(a_numbers) + 1):
|
||||
a_numbers.append(last_a_id)
|
||||
else:
|
||||
break
|
||||
|
||||
byte1 = ord(extract_maps.rom[hl_pointer + (2*last_a_id)])
|
||||
byte2 = ord(extract_maps.rom[hl_pointer + (2*last_a_id) + 1])
|
||||
address2 = byte1 + (byte2 << 8)
|
||||
if address2 > 0x3fff:
|
||||
latest_script_pointer = extract_maps.calculate_pointer(address2, int(map2["bank"], 16))
|
||||
else:
|
||||
latest_script_pointer = address2
|
||||
|
||||
script_pointers.append(hex(latest_script_pointer))
|
||||
#print "latest script pointer (part 1): " + hex(address2)
|
||||
#print "latest script pointer: " + hex(latest_script_pointer)
|
||||
|
||||
#go ahead and insert the asm for this script
|
||||
result = insert_asm(latest_script_pointer, map_name_cleaner(map2["name"], None)[:-2] + "Script" + str(len(script_pointers) - 1))
|
||||
|
||||
if result:
|
||||
#reset everything
|
||||
#analyze_incbins.reset_incbins()
|
||||
asm = None
|
||||
incbin_lines = []
|
||||
processed_incbins = {}
|
||||
analyze_incbins.asm = None
|
||||
analyze_incbins.incbin_lines = []
|
||||
analyze_incbins.processed_incbins = {}
|
||||
|
||||
#reload
|
||||
load_asm()
|
||||
isolate_incbins()
|
||||
process_incbins()
|
||||
|
||||
print "map_id=" + str(map_id) + " scripts are: " + str(script_pointers)
|
||||
|
||||
if last_hl_address == None: last_hl_address = "None"
|
||||
else: last_hl_address = hex(last_hl_address)
|
||||
|
||||
if hl_pointer != None and hl_pointer != "None": hl_pointer = hex(hl_pointer)
|
||||
|
||||
print "map_id=" + str(map_id) + " " + map2["name"] + " script_pointer=" + hex(script_pointer) + " script_pointers=" + hl_pointer + first_script_text
|
||||
print main_asm_output
|
||||
print "\n\n"
|
||||
|
||||
#insert asm for the main script
|
||||
result = insert_asm(script_pointer, map_name_cleaner(map2["name"], None)[:-2] + "Script")
|
||||
|
||||
if result:
|
||||
#reset everything
|
||||
#analyze_incbins.reset_incbins()
|
||||
asm = None
|
||||
incbin_lines = []
|
||||
processed_incbins = {}
|
||||
analyze_incbins.asm = None
|
||||
analyze_incbins.incbin_lines = []
|
||||
analyze_incbins.processed_incbins = {}
|
||||
|
||||
#reload
|
||||
load_asm()
|
||||
isolate_incbins()
|
||||
process_incbins()
|
||||
|
||||
#insert script pointer list asm if there's anything of value
|
||||
if hl_pointer != None and hl_pointer != "None" and used_3d97==True:
|
||||
start_address = int(hl_pointer, 16) #where to insert this list
|
||||
total_size = len(a_numbers) * 2
|
||||
|
||||
script_label = map_name_cleaner(map2["name"], None)[:-2] + "Script"
|
||||
scripts_label = script_label + "s"
|
||||
script_asm = scripts_label + ": ; " + hex(start_address) + "\n"
|
||||
script_asm += spacing + "dw"
|
||||
|
||||
first = True
|
||||
for id in a_numbers:
|
||||
if first:
|
||||
script_asm += " "
|
||||
first = False
|
||||
else:
|
||||
script_asm += ", "
|
||||
script_asm += script_label + str(id)
|
||||
script_asm += "\n" #extra newline?
|
||||
|
||||
result = insert_asm(start_address, scripts_label, text_asm=script_asm, end_address=start_address + total_size)
|
||||
if result:
|
||||
#reset everything
|
||||
#analyze_incbins.reset_incbins()
|
||||
asm = None
|
||||
incbin_lines = []
|
||||
processed_incbins = {}
|
||||
analyze_incbins.asm = None
|
||||
analyze_incbins.incbin_lines = []
|
||||
analyze_incbins.processed_incbins = {}
|
||||
|
||||
#reload
|
||||
load_asm()
|
||||
isolate_incbins()
|
||||
process_incbins()
|
||||
else:
|
||||
print "trouble inserting map script pointer list"
|
||||
print script_asm
|
||||
sys.exit(0)
|
||||
|
||||
def scan_rom_for_tx_fars_and_insert():
|
||||
"""calls analyze_texts.scan_rom_for_tx_fars()
|
||||
looks through INCBIN'd addresses from main.asm,
|
||||
finds TX_FARs that aren't included yet.
|
||||
"""
|
||||
x = 0
|
||||
address_bundles = scan_rom_for_tx_fars(printer=True)
|
||||
for address_bundle in address_bundles:
|
||||
tx_far_address = address_bundle[1]
|
||||
tx_far_target_address = address_bundle[0]
|
||||
if tx_far_address in [0xeff2]: continue #skip
|
||||
#if tx_far_address < 0x7627b: continue #because it stopped a few times for errors
|
||||
|
||||
tx_far_label = "UnnamedText_%.2x" % (tx_far_address)
|
||||
tx_far_target_label = "_" + tx_far_label
|
||||
|
||||
#let's also do a quick check if it might be in the file already
|
||||
if not (": ; " + hex(tx_far_address) in analyze_incbins.asm):
|
||||
print "inserting text at " + hex(tx_far_address)
|
||||
result = insert_text(tx_far_target_address, tx_far_target_label, apply=True)
|
||||
else:
|
||||
#we can't just pretend like it worked, because we don't know what label was used
|
||||
#so, figure out the label
|
||||
for line in analyze_incbins.asm_lines:
|
||||
if ": ; " + hex(tx_far_address) in line:
|
||||
tx_far_target_label = line.split(":")[0]
|
||||
result = "skip"
|
||||
|
||||
if result == True or result == None:
|
||||
local_reset_incbins()
|
||||
result2 = insert_text(tx_far_address, tx_far_label, apply=True)
|
||||
local_reset_incbins()
|
||||
elif result == "skip":
|
||||
print "skipping " + hex(tx_far_address)
|
||||
# result2 = insert_text(tx_far_address, tx_far_label, apply=True)
|
||||
# local_reset_incbins()
|
||||
|
||||
#just skip these for now
|
||||
#if not result or not result2:
|
||||
# sys.exit(0)
|
||||
|
||||
def get_mon_name(id):
|
||||
return pokemons[id]
|
||||
|
||||
def get_type_label(id):
|
||||
for line in elemental_types:
|
||||
if line[2] == id: return line[0]
|
||||
return None
|
||||
|
||||
def get_attack_label(id):
|
||||
for move in moves:
|
||||
if move[1] == id: return move[0]
|
||||
return "0" #no move
|
||||
|
||||
def get_pointer_target_at(address):
|
||||
rom = extract_maps.rom
|
||||
byte1 = ord(rom[address])
|
||||
byte2 = ord(rom[address+1])
|
||||
pointer = (byte1 + (byte2 << 8))
|
||||
return pointer
|
||||
|
||||
def get_frontsprite_label(id):
|
||||
return get_mon_name(id).title() + "PicFront"
|
||||
def get_backsprite_label(id):
|
||||
return get_mon_name(id).title() + "PicBack"
|
||||
|
||||
def base_data_pretty_printer(id):
|
||||
"""returns beautified asm for this pokemon
|
||||
|
||||
uses 28 bytes
|
||||
|
||||
pokedex number, base hp, base attack, base defense, base speed, base special
|
||||
type 1 (label), type 2 (label), catch rate, base experience yield
|
||||
dimensions of frontsprite (byte)
|
||||
frontsprite label pointer
|
||||
backsprite label pointer
|
||||
attacks known at level 1 (4 bytes, 4 constants)
|
||||
growth rate (byte)
|
||||
incbin - tm/hm flags (7 bytes)
|
||||
padding (0)
|
||||
"""
|
||||
output = ""
|
||||
rom = extract_maps.rom
|
||||
base_address = 0x383de + (28 * (id))
|
||||
|
||||
pokedex_number = id
|
||||
mon_name = get_mon_name(id)
|
||||
base_hp = ord(rom[base_address + 1])
|
||||
base_attack = ord(rom[base_address + 2])
|
||||
base_defense = ord(rom[base_address + 3])
|
||||
base_speed = ord(rom[base_address + 4])
|
||||
base_special = ord(rom[base_address + 5])
|
||||
|
||||
type1_id = ord(rom[base_address + 6])
|
||||
type2_id = ord(rom[base_address + 7])
|
||||
type1 = get_type_label(type1_id)
|
||||
type2 = get_type_label(type2_id)
|
||||
|
||||
catch_rate = ord(rom[base_address + 8])
|
||||
base_exp_yield = ord(rom[base_address + 9])
|
||||
frontsprite_dimensions = ord(rom[base_address + 10])
|
||||
|
||||
frontsprite = get_frontsprite_label(id)
|
||||
backsprite = get_backsprite_label(id)
|
||||
|
||||
#attacks known at level 0
|
||||
attack1 = get_attack_label(ord(rom[base_address + 15]))
|
||||
attack2 = get_attack_label(ord(rom[base_address + 16]))
|
||||
attack3 = get_attack_label(ord(rom[base_address + 17]))
|
||||
attack4 = get_attack_label(ord(rom[base_address + 18]))
|
||||
|
||||
growth_rate = ord(rom[base_address + 19])
|
||||
|
||||
incbin_start_address = base_address + 20
|
||||
incbin_end_address = base_address + 27
|
||||
|
||||
output = mon_name.title() + ("BaseStats: ; 0x%.x" % (base_address)) + "\n"
|
||||
output += spacing + "db DEX_" + mon_name.upper() + " ; pokedex id\n"
|
||||
output += spacing + ("db " + str(base_hp)) + " ; base hp\n"
|
||||
output += spacing + "db " + str(base_attack) + " ; base attack\n"
|
||||
output += spacing + "db " + str(base_defense) + " ; base defense\n"
|
||||
output += spacing + "db " + str(base_speed) + " ; base speed\n"
|
||||
output += spacing + "db " + str(base_special) + " ; base special\n\n"
|
||||
output += spacing + "db " + type1 + " ; species type 1\n"
|
||||
output += spacing + "db " + type2 + " ; species type 2\n\n"
|
||||
output += spacing + "db " + str(catch_rate) + " ; catch rate\n"
|
||||
output += spacing + "db " + str(base_exp_yield) + " ; base exp yield\n"
|
||||
output += spacing + ("db $%.2x" % (frontsprite_dimensions)) + " ; sprite dimensions\n\n"
|
||||
output += spacing + "dw " + frontsprite + "\n"
|
||||
output += spacing + "dw " + backsprite + "\n"
|
||||
output += spacing + "\n" + spacing + "; attacks known at lvl 0\n"
|
||||
output += spacing + "db " + attack1 + "\n"
|
||||
output += spacing + "db " + attack2 + "\n"
|
||||
output += spacing + "db " + attack3 + "\n"
|
||||
output += spacing + "db " + attack4 + "\n\n"
|
||||
output += spacing + "db " + str(growth_rate) + " ; growth rate\n"
|
||||
output += spacing + "\n" + spacing + "; learnset\n"
|
||||
|
||||
#learnset crap
|
||||
output += spacing + "db %" + bin(ord(rom[base_address + 20]))[2:].zfill(8) + "\n"
|
||||
output += spacing + "db %" + bin(ord(rom[base_address + 21]))[2:].zfill(8) + "\n"
|
||||
output += spacing + "db %" + bin(ord(rom[base_address + 22]))[2:].zfill(8) + "\n"
|
||||
output += spacing + "db %" + bin(ord(rom[base_address + 23]))[2:].zfill(8) + "\n"
|
||||
output += spacing + "db %" + bin(ord(rom[base_address + 24]))[2:].zfill(8) + "\n"
|
||||
output += spacing + "db %" + bin(ord(rom[base_address + 25]))[2:].zfill(8) + "\n"
|
||||
output += spacing + "db %" + bin(ord(rom[base_address + 26]))[2:].zfill(8) + "\n\n"
|
||||
|
||||
output += spacing + "db 0 ; padding\n"
|
||||
|
||||
return output
|
||||
|
||||
def insert_base_stats(id):
|
||||
insert_asm = base_data_pretty_printer(id)
|
||||
|
||||
address = 0x383de + (28 * (id))
|
||||
line_number = find_incbin_to_replace_for(address)
|
||||
label = get_mon_name(id).title() + "BaseStats"
|
||||
if line_number == None:
|
||||
print "skipping, already inserted at " + hex(address)
|
||||
return
|
||||
|
||||
#also do a name check
|
||||
if (label + ":") in "\n".join(analyze_incbins.asm):
|
||||
print "skipping " + label + " because it is already in use.."
|
||||
return
|
||||
|
||||
newlines = split_incbin_line_into_three(line_number, address, 28 )
|
||||
|
||||
newlines = newlines.split("\n")
|
||||
if len(newlines) == 2: index = 0 #replace the 1st line with new content
|
||||
elif len(newlines) == 3: index = 1 #replace the 2nd line with new content
|
||||
|
||||
newlines[index] = insert_asm
|
||||
|
||||
if len(newlines) == 3 and newlines[2][-2:] == "$0":
|
||||
#get rid of the last incbin line if it is only including 0 bytes
|
||||
del newlines[2]
|
||||
#note that this has to be done after adding in the new asm
|
||||
newlines = "\n".join(line for line in newlines)
|
||||
newlines = newlines.replace("$x", "$")
|
||||
|
||||
diff = generate_diff_insert(line_number, newlines)
|
||||
print diff
|
||||
apply_diff(diff, try_fixing=False, do_compile=False)
|
||||
|
||||
def insert_all_base_stats():
|
||||
for id in range(0, 151):
|
||||
#if id < 62: continue #skip
|
||||
insert_base_stats(id)
|
||||
|
||||
#reset everything
|
||||
reset_incbins()
|
||||
analyze_incbins.reset_incbins()
|
||||
asm = None
|
||||
incbin_lines = []
|
||||
processed_incbins = {}
|
||||
analyze_incbins.asm = None
|
||||
analyze_incbins.incbin_lines = []
|
||||
analyze_incbins.processed_incbins = {}
|
||||
|
||||
#reload
|
||||
load_asm()
|
||||
isolate_incbins()
|
||||
process_incbins()
|
||||
|
||||
if __name__ == "__main__":
|
||||
#load map headers and object data
|
||||
extract_maps.load_rom()
|
||||
extract_maps.load_map_pointers()
|
||||
extract_maps.read_all_map_headers()
|
||||
load_labels()
|
||||
#print base_data_pretty_printer(0)
|
||||
load_asm()
|
||||
isolate_incbins()
|
||||
process_incbins()
|
||||
#insert_base_stats(1)
|
||||
insert_all_base_stats()
|
||||
|
||||
#load texts (these two have different formats)
|
||||
#all_texts = pretty_map_headers.analyze_texts.analyze_texts()
|
||||
#pretty_map_headers.all_texts = all_texts
|
||||
#tx_fars = pretty_map_headers.find_all_tx_fars()
|
||||
|
||||
#load incbins
|
||||
#reset_incbins()
|
||||
|
||||
#scan_for_map_scripts_pointer()
|
||||
#scan_rom_for_tx_fars_and_insert()
|
||||
#insert_text(0xa586b, "_VermilionCityText14")
|
||||
|
||||
#insert _ViridianCityText10
|
||||
#insert_tx_far(1, 10)
|
||||
|
||||
#just me testing a pokemart sign duplicate
|
||||
#insert_tx_far(3, 14)
|
||||
|
||||
#this is the big one
|
||||
#insert_all_tx_far_targets()
|
||||
|
||||
#for map_id in extract_maps.map_headers.keys():
|
||||
# if map_id not in extract_maps.bad_maps:
|
||||
# if len(extract_maps.map_headers[map_id]["referenced_texts"]) > 0:
|
||||
# texts_label_pretty_printer(map_id)
|
||||
|
||||
#insert_texts_label(240)
|
||||
#insert_all_texts_labels()
|
||||
|
||||
#insert_text_label_tx_far(240, 1)
|
||||
#insert_all_text_labels()
|
||||
|
||||
#insert_08_asm(83, 1)
|
||||
#insert_all_08s()
|
||||
|
||||
#insert_asm(0x1da56, "NameRaterText1")
|
||||
#insert_text_label_tx_far(91, 1)
|
||||
|
||||
#insert_text(0x44276, "ViridianPokeCenterText4")
|
||||
#insert_texts_label(4)
|
||||
#insert_all_texts_labels()
|
||||
|
@ -1,37 +0,0 @@
|
||||
#author: Bryan Bishop <kanzure@gmail.com>
|
||||
#date: 2012-01-15
|
||||
#dump map height/width constants
|
||||
import extract_maps
|
||||
from pretty_map_headers import map_name_cleaner, map_constants
|
||||
|
||||
def get_map_size_constants(do_sed=False):
|
||||
output = ""
|
||||
sed_lines = ""
|
||||
for map_id in extract_maps.map_headers.keys():
|
||||
if map_id in extract_maps.bad_maps: continue #skip
|
||||
|
||||
map2 = extract_maps.map_headers[map_id]
|
||||
base_name = map_name_cleaner(map2["name"], None)[:-2]
|
||||
constant_name = map_constants[map_id]
|
||||
|
||||
height = int(map2["y"], 16)
|
||||
width = int(map2["x"], 16)
|
||||
|
||||
output += "; " + base_name + "_h map_id=" + str(map_id) + "\n"
|
||||
output += constant_name + "_HEIGHT EQU $%.2x\n" % (height)
|
||||
output += constant_name + "_WIDTH EQU $%.2x\n" % (width)
|
||||
output += "\n"
|
||||
|
||||
sed_lines += "sed -i 's/" + base_name + "Height/" + constant_name + "_HEIGHT" + "/g' main.asm" + "\n"
|
||||
sed_lines += "sed -i 's/" + base_name + "Width/" + constant_name + "_WIDTH" + "/g' main.asm" + "\n"
|
||||
|
||||
if do_sed:
|
||||
return sed_lines
|
||||
else:
|
||||
return output
|
||||
|
||||
if __name__ == "__main__":
|
||||
extract_maps.load_rom()
|
||||
extract_maps.load_map_pointers()
|
||||
extract_maps.read_all_map_headers()
|
||||
print get_map_size_constants(do_sed=True)
|
@ -1,171 +0,0 @@
|
||||
#author: Bryan Bishop <kanzure@gmail.com>
|
||||
#date: 2012-01-03
|
||||
#purpose: extract .blk files from baserom.gbc
|
||||
#note: use python2.7 because of subprocess in analyze_incbins
|
||||
import extract_maps #rom, assert_rom, load_rom, calculate_pointer, load_map_pointers, read_all_map_headers, map_headers
|
||||
from pretty_map_headers import map_name_cleaner
|
||||
from analyze_incbins import asm, offset_to_pointer, find_incbin_to_replace_for, split_incbin_line_into_three, generate_diff_insert, load_asm, isolate_incbins, process_incbins
|
||||
import analyze_incbins
|
||||
import os, sys
|
||||
import subprocess
|
||||
spacing = " "
|
||||
|
||||
used_map_pointers = []
|
||||
|
||||
def extract_map_block_data(map_id, savefile=False):
|
||||
map = extract_maps.map_headers[map_id]
|
||||
if map["name"] == "FREEZE": return #skip this one
|
||||
|
||||
blocksdata_pointer = int(map["map_pointer"], 16)
|
||||
|
||||
y = int(map["y"], 16)
|
||||
x = int(map["x"], 16)
|
||||
size = x*y
|
||||
|
||||
#fetch the data from the rom
|
||||
blocksdata = extract_maps.rom[blocksdata_pointer:blocksdata_pointer+size]
|
||||
|
||||
#clean up the filename and label (for pokered.asm)
|
||||
cleaned_name = map_name_cleaner(map["name"], None)
|
||||
label_text = cleaned_name.replace("_h", "Blocks")
|
||||
filename = cleaned_name.replace("_h", "").lower()
|
||||
full_filepath = "maps/" + filename + ".blk"
|
||||
|
||||
if savefile:
|
||||
print "Saving ../maps/" + filename + ".blk for map id=" + str(map_id)
|
||||
fh = open("../maps/" + filename + ".blk", "w")
|
||||
fh.write(blocksdata)
|
||||
fh.close()
|
||||
|
||||
def make_labels(name):
|
||||
cleaned_name = map_name_cleaner(name, None)
|
||||
label_text = cleaned_name.replace("_h", "Blocks")
|
||||
filename = cleaned_name.replace("_h", "").lower()
|
||||
full_filepath = "maps/" + filename + ".blk"
|
||||
return cleaned_name, label_text, filename, full_filepath
|
||||
|
||||
def generate_label_asm(name,size=None):
|
||||
cleaned_name, label_text, filename, full_filepath = make_labels(name)
|
||||
|
||||
output = label_text + ":"
|
||||
if size: output += " ; " + str(size) + "\n"
|
||||
else: output += "\n"
|
||||
output += spacing + "INCBIN \"" + full_filepath + "\""
|
||||
|
||||
return output
|
||||
|
||||
def insert_map_block_label(map_id):
|
||||
map = extract_maps.map_headers[map_id]
|
||||
address = int(map["map_pointer"], 16)
|
||||
y = int(map["y"], 16)
|
||||
x = int(map["x"], 16)
|
||||
size = x*y
|
||||
|
||||
print "map name: " + map["name"]
|
||||
print "map address: " + map["map_pointer"]
|
||||
|
||||
line_number = find_incbin_to_replace_for(address)
|
||||
if line_number == None:
|
||||
print "skipping map id=" + str(map_id) + " probably because it was already done."
|
||||
used_map_pointers.append(map["map_pointer"])
|
||||
return
|
||||
|
||||
newlines = split_incbin_line_into_three(line_number, address, size)
|
||||
|
||||
label_asm = generate_label_asm(map["name"], size)
|
||||
|
||||
newlines = newlines.split("\n")
|
||||
if len(newlines) == 2: index = 0 #replace the 1st line with new content
|
||||
elif len(newlines) == 3: index = 1 #replace the 2nd line with new content
|
||||
|
||||
newlines[index] = label_asm
|
||||
|
||||
if len(newlines) == 3 and newlines[2][-2:] == "$0":
|
||||
#get rid of the last incbin line if it is only including 0 bytes
|
||||
del newlines[2]
|
||||
#note that this has to be done after adding in the new asm
|
||||
newlines = "\n".join(line for line in newlines)
|
||||
|
||||
#fix a lame error from somewhere
|
||||
newlines = newlines.replace("$x", "$")
|
||||
|
||||
diff = generate_diff_insert(line_number, newlines)
|
||||
print diff
|
||||
print "... Applying diff."
|
||||
|
||||
#write the diff to a file
|
||||
fh = open("temp.patch", "w")
|
||||
fh.write(diff)
|
||||
fh.close()
|
||||
|
||||
#apply the patch
|
||||
os.system("patch ../pokered.asm temp.patch")
|
||||
|
||||
#remove the patch
|
||||
os.system("rm temp.patch")
|
||||
|
||||
#confirm it's working
|
||||
subprocess.check_call("cd ../; make clean; LC_CTYPE=UTF-8 make", shell=True)
|
||||
|
||||
def get_all_map_blockdata():
|
||||
for map in extract_maps.map_headers.keys():
|
||||
extract_map_block_data(map)
|
||||
|
||||
def insert_all_labels():
|
||||
"this is very buggy, don't use it"
|
||||
#limit = 200 #0:150
|
||||
for map in extract_maps.map_headers.keys():
|
||||
mapmap = extract_maps.map_headers[map]
|
||||
if mapmap["name"] == "FREEZE": continue #skip this one
|
||||
if "Ash's" in mapmap["name"]: continue
|
||||
if "Gary's" in mapmap["name"]: continue
|
||||
if not ("cat" in mapmap["name"]) and "copy" in mapmap["name"].lower(): continue #skip this one
|
||||
|
||||
#bill's house breaks things?
|
||||
#if mapmap["name"] == "Bill's House": continue
|
||||
if mapmap["name"] == "Viridian Forest": continue
|
||||
#if mapmap["name"] == "Cerulean Mart": continue
|
||||
if mapmap["name"] == "Virdian Forest Exit": continue
|
||||
#if "copy" in mapmap["name"].lower(): continue #skip this one too..
|
||||
|
||||
if mapmap["map_pointer"] in used_map_pointers: continue #skip for sure
|
||||
|
||||
#reset asm
|
||||
analyze_incbins.asm = None
|
||||
analyze_incbins.incbin_lines = []
|
||||
analyze_incbins.processed_incbins = {}
|
||||
|
||||
#reload asm each time
|
||||
load_asm()
|
||||
|
||||
#check if this label is already in there
|
||||
cleaned_name, label_text, filename, full_filepath = make_labels(mapmap["name"])
|
||||
if label_text in "\n".join(line for line in analyze_incbins.asm):
|
||||
print "skipping (found label text in asm already)"
|
||||
used_map_pointers.append(mapmap["map_pointer"])
|
||||
continue #skip this one
|
||||
|
||||
isolate_incbins()
|
||||
process_incbins()
|
||||
|
||||
print "XYZ|" + mapmap["name"]
|
||||
insert_map_block_label(map)
|
||||
|
||||
used_map_pointers.append(mapmap["map_pointer"])
|
||||
|
||||
if __name__ == "__main__":
|
||||
#load map headers
|
||||
extract_maps.load_rom()
|
||||
extract_maps.load_map_pointers()
|
||||
extract_maps.read_all_map_headers()
|
||||
|
||||
#load incbins
|
||||
load_asm()
|
||||
isolate_incbins()
|
||||
process_incbins()
|
||||
|
||||
#extract_map_block_data(2)
|
||||
#get_all_map_blockdata()
|
||||
|
||||
#insert_map_block_label(49)
|
||||
insert_all_labels()
|
@ -1,4 +0,0 @@
|
||||
import os
|
||||
|
||||
#main dir of repo (simply one level up than here)
|
||||
pokered_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
@ -1,755 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#author: Bryan Bishop <kanzure@gmail.com>
|
||||
#date: 2012-01-02
|
||||
#purpose: dump asm for each map header
|
||||
import json
|
||||
import extract_maps
|
||||
import sprite_helper
|
||||
import random
|
||||
import string
|
||||
import analyze_texts #hopefully not a dependency loop
|
||||
|
||||
base = 16
|
||||
spacing = " "
|
||||
all_texts = None
|
||||
|
||||
#map constants
|
||||
map_constants = [
|
||||
["PALLET_TOWN", 0x00],
|
||||
["VIRIDIAN_CITY", 0x01],
|
||||
["PEWTER_CITY", 0x02],
|
||||
["CERULEAN_CITY", 0x03],
|
||||
["LAVENDER_TOWN", 0x04],
|
||||
["VERMILION_CITY", 0x05],
|
||||
["CELADON_CITY", 0x06],
|
||||
["FUCHSIA_CITY", 0x07],
|
||||
["CINNABAR_ISLAND", 0x08],
|
||||
["INDIGO_PLATEAU", 0x09],
|
||||
["SAFFRON_CITY", 0x0A],
|
||||
["ROUTE_1", 0x0C],
|
||||
["ROUTE_2", 0x0D],
|
||||
["ROUTE_3", 0x0E],
|
||||
["ROUTE_4", 0x0F],
|
||||
["ROUTE_5", 0x10],
|
||||
["ROUTE_6", 0x11],
|
||||
["ROUTE_7", 0x12],
|
||||
["ROUTE_8", 0x13],
|
||||
["ROUTE_9", 0x14],
|
||||
["ROUTE_10", 0x15],
|
||||
["ROUTE_11", 0x16],
|
||||
["ROUTE_12", 0x17],
|
||||
["ROUTE_13", 0x18],
|
||||
["ROUTE_14", 0x19],
|
||||
["ROUTE_15", 0x1A],
|
||||
["ROUTE_16", 0x1B],
|
||||
["ROUTE_17", 0x1C],
|
||||
["ROUTE_18", 0x1D],
|
||||
["ROUTE_19", 0x1E],
|
||||
["ROUTE_20", 0x1F],
|
||||
["ROUTE_21", 0x20],
|
||||
["ROUTE_22", 0x21],
|
||||
["ROUTE_23", 0x22],
|
||||
["ROUTE_24", 0x23],
|
||||
["ROUTE_25", 0x24],
|
||||
["REDS_HOUSE_1F", 0x25],
|
||||
["REDS_HOUSE_2F", 0x26],
|
||||
["BLUES_HOUSE", 0x27],
|
||||
["OAKS_LAB", 0x28],
|
||||
["VIRIDIAN_POKECENTER", 0x29],
|
||||
["VIRIDIAN_MART", 0x2A],
|
||||
["VIRIDIAN_SCHOOL", 0x2B],
|
||||
["VIRIDIAN_HOUSE", 0x2C],
|
||||
["VIRIDIAN_GYM", 0x2D],
|
||||
["DIGLETTS_CAVE_EXIT", 0x2E],
|
||||
["VIRIDIAN_FOREST_EXIT", 0x2F],
|
||||
["ROUTE_2_HOUSE", 0x30],
|
||||
["ROUTE_2_GATE", 0x31],
|
||||
["VIRIDIAN_FOREST_ENTRANCE", 0x32],
|
||||
["VIRIDIAN_FOREST", 0x33],
|
||||
["MUSEUM_1F", 0x34],
|
||||
["MUSEUM_2F", 0x35],
|
||||
["PEWTER_GYM", 0x36],
|
||||
["PEWTER_HOUSE_1", 0x37],
|
||||
["PEWTER_MART", 0x38],
|
||||
["PEWTER_HOUSE_2", 0x39],
|
||||
["PEWTER_POKECENTER", 0x3A],
|
||||
["MT_MOON_1", 0x3B],
|
||||
["MT_MOON_2", 0x3C],
|
||||
["MT_MOON_3", 0x3D],
|
||||
["TRASHED_HOUSE", 0x3E],
|
||||
["CERULEAN_HOUSE", 0x3F],
|
||||
["CERULEAN_POKECENTER", 0x40],
|
||||
["CERULEAN_GYM", 0x41],
|
||||
["BIKE_SHOP", 0x42],
|
||||
["CERULEAN_MART", 0x43],
|
||||
["MT_MOON_POKECENTER", 0x44],
|
||||
["ROUTE_5_GATE", 0x46],
|
||||
["PATH_ENTRANCE_ROUTE_5", 0x47],
|
||||
["DAYCAREM", 0x48],
|
||||
["ROUTE_6_GATE", 0x49],
|
||||
["PATH_ENTRANCE_ROUTE_6", 0x4A],
|
||||
["ROUTE_7_GATE", 0x4C],
|
||||
["PATH_ENTRANCE_ROUTE_7", 0x4D],
|
||||
["ROUTE_8_GATE", 0x4F],
|
||||
["PATH_ENTRANCE_ROUTE_8", 0x50],
|
||||
["ROCK_TUNNEL_POKECENTER", 0x51],
|
||||
["ROCK_TUNNEL_1", 0x52],
|
||||
["POWER_PLANT", 0x53],
|
||||
["ROUTE_11_GATE_1F", 0x54],
|
||||
["DIGLETTS_CAVE_ENTRANCE", 0x55],
|
||||
["ROUTE_11_GATE_2F", 0x56],
|
||||
["ROUTE_12_GATE", 0x57],
|
||||
["BILLS_HOUSE", 0x58],
|
||||
["VERMILION_POKECENTER", 0x59],
|
||||
["POKEMON_FAN_CLUB", 0x5A],
|
||||
["VERMILION_MART", 0x5B],
|
||||
["VERMILION_GYM", 0x5C],
|
||||
["VERMILION_HOUSE_1", 0x5D],
|
||||
["VERMILION_DOCK", 0x5E],
|
||||
["SS_ANNE_1", 0x5F],
|
||||
["SS_ANNE_2", 0x60],
|
||||
["SS_ANNE_3", 0x61],
|
||||
["SS_ANNE_4", 0x62],
|
||||
["SS_ANNE_5", 0x63],
|
||||
["SS_ANNE_6", 0x64],
|
||||
["SS_ANNE_7", 0x65],
|
||||
["SS_ANNE_8", 0x66],
|
||||
["SS_ANNE_9", 0x67],
|
||||
["SS_ANNE_10", 0x68],
|
||||
["VICTORY_ROAD_1", 0x6C],
|
||||
["LANCES_ROOM", 0x71],
|
||||
["HALL_OF_FAME", 0x76],
|
||||
["UNDERGROUND_PATH_NS", 0x77],
|
||||
["CHAMPIONS_ROOM", 0x78],
|
||||
["UNDERGROUND_PATH_WE", 0x79],
|
||||
["CELADON_MART_1", 0x7A],
|
||||
["CELADON_MART_2", 0x7B],
|
||||
["CELADON_MART_3", 0x7C],
|
||||
["CELADON_MART_4", 0x7D],
|
||||
["CELADON_MART_5", 0x7E],
|
||||
["CELADON_MART_6", 0x7F],
|
||||
["CELADON_MANSION_1", 0x80],
|
||||
["CELADON_MANSION_2", 0x81],
|
||||
["CELADON_MANSION_3", 0x82],
|
||||
["CELADON_MANSION_4", 0x83],
|
||||
["CELADON_MANSION_5", 0x84],
|
||||
["CELADON_POKECENTER", 0x85],
|
||||
["CELADON_GYM", 0x86],
|
||||
["GAME_CORNER", 0x87],
|
||||
["CELADON_HOUSE", 0x88],
|
||||
["CELADONPRIZE_ROOM", 0x89],
|
||||
["CELADON_DINER", 0x8A],
|
||||
["CELADON_HOUSE_2", 0x8B],
|
||||
["CELADONHOTEL", 0x8C],
|
||||
["LAVENDER_POKECENTER", 0x8D],
|
||||
["POKEMONTOWER_1", 0x8E],
|
||||
["POKEMONTOWER_2", 0x8F],
|
||||
["POKEMONTOWER_3", 0x90],
|
||||
["POKEMONTOWER_4", 0x91],
|
||||
["POKEMONTOWER_5", 0x92],
|
||||
["POKEMONTOWER_6", 0x93],
|
||||
["POKEMONTOWER_7", 0x94],
|
||||
["LAVENDER_HOUSE_1", 0x95],
|
||||
["LAVENDER_MART", 0x96],
|
||||
["LAVENDER_HOUSE_2", 0x97],
|
||||
["FUCHSIA_MART", 0x98],
|
||||
["FUCHSIA_HOUSE_1", 0x99],
|
||||
["FUCHSIA_POKECENTER", 0x9A],
|
||||
["FUCHSIA_HOUSE_2", 0x9B],
|
||||
["SAFARIZONEENTRANCE", 0x9C],
|
||||
["FUCHSIA_GYM", 0x9D],
|
||||
["FUCHSIAMEETINGROOM", 0x9E],
|
||||
["SEAFOAM_ISLANDS_2", 0x9F],
|
||||
["SEAFOAM_ISLANDS_3", 0xA0],
|
||||
["SEAFOAM_ISLANDS_4", 0xA1],
|
||||
["SEAFOAM_ISLANDS_5", 0xA2],
|
||||
["VERMILION_HOUSE_2", 0xA3],
|
||||
["FUCHSIA_HOUSE_3", 0xA4],
|
||||
["MANSION_1", 0xA5],
|
||||
["CINNABAR_GYM", 0xA6],
|
||||
["CINNABAR_LAB_1", 0xA7],
|
||||
["CINNABAR_LAB_2", 0xA8],
|
||||
["CINNABAR_LAB_3", 0xA9],
|
||||
["CINNABAR_LAB_4", 0xAA],
|
||||
["CINNABAR_POKECENTER", 0xAB],
|
||||
["CINNABAR_MART", 0xAC],
|
||||
["INDIGO_PLATEAU_LOBBY", 0xAE],
|
||||
["COPYCATS_HOUSE_1F", 0xAF],
|
||||
["COPYCATS_HOUSE_2F", 0xB0],
|
||||
["FIGHTINGDOJO", 0xB1],
|
||||
["SAFFRON_GYM", 0xB2],
|
||||
["SAFFRON_HOUSE_1", 0xB3],
|
||||
["SAFFRON_MART", 0xB4],
|
||||
["SILPH_CO_1F", 0xB5],
|
||||
["SAFFRON_POKECENTER", 0xB6],
|
||||
["SAFFRON_HOUSE_2", 0xB7],
|
||||
["ROUTE_15_GATE", 0xB8],
|
||||
["ROUTE_16_GATE_1F", 0xBA],
|
||||
["ROUTE_16_GATE_2F", 0xBB],
|
||||
["ROUTE_16_HOUSE", 0xBC],
|
||||
["ROUTE_12_HOUSE", 0xBD],
|
||||
["ROUTE_18_GATE_1F", 0xBE],
|
||||
["ROUTE_18_GATE_2F", 0xBF],
|
||||
["SEAFOAM_ISLANDS_1", 0xC0],
|
||||
["ROUTE_22_GATE", 0xC1],
|
||||
["VICTORY_ROAD_2", 0xC2],
|
||||
["ROUTE_12_GATE_2F", 0xC3],
|
||||
["VERMILION_HOUSE_3", 0xC4],
|
||||
["DIGLETTS_CAVE", 0xC5],
|
||||
["VICTORY_ROAD_3", 0xC6],
|
||||
["ROCKET_HIDEOUT_1", 0xC7],
|
||||
["ROCKET_HIDEOUT_2", 0xC8],
|
||||
["ROCKET_HIDEOUT_3", 0xC9],
|
||||
["ROCKET_HIDEOUT_4", 0xCA],
|
||||
["ROCKET_HIDEOUT_ELEVATOR", 0xCB],
|
||||
["SILPH_CO_2F", 0xCF],
|
||||
["SILPH_CO_3F", 0xD0],
|
||||
["SILPH_CO_4F", 0xD1],
|
||||
["SILPH_CO_5F", 0xD2],
|
||||
["SILPH_CO_6F", 0xD3],
|
||||
["SILPH_CO_7F", 0xD4],
|
||||
["SILPH_CO_8F", 0xD5],
|
||||
["MANSION_2", 0xD6],
|
||||
["MANSION_3", 0xD7],
|
||||
["MANSION_4", 0xD8],
|
||||
["SAFARI_ZONE_EAST", 0xD9],
|
||||
["SAFARI_ZONE_NORTH", 0xDA],
|
||||
["SAFARI_ZONE_WEST", 0xDB],
|
||||
["SAFARI_ZONE_CENTER", 0xDC],
|
||||
["SAFARI_ZONE_REST_HOUSE_1", 0xDD],
|
||||
["SAFARI_ZONE_SECRET_HOUSE", 0xDE],
|
||||
["SAFARI_ZONE_REST_HOUSE_2", 0xDF],
|
||||
["SAFARI_ZONE_REST_HOUSE_3", 0xE0],
|
||||
["SAFARI_ZONE_REST_HOUSE_4", 0xE1],
|
||||
["UNKNOWN_DUNGEON_2", 0xE2],
|
||||
["UNKNOWN_DUNGEON_3", 0xE3],
|
||||
["UNKNOWN_DUNGEON_1", 0xE4],
|
||||
["NAME_RATERS_HOUSE", 0xE5],
|
||||
["CERULEAN_HOUSE_3", 0xE6],
|
||||
["ROCK_TUNNEL_2", 0xE8],
|
||||
["SILPH_CO_9F", 0xE9],
|
||||
["SILPH_CO_10F", 0xEA],
|
||||
["SILPH_CO_11F", 0xEB],
|
||||
["SILPH_CO_ELEVATOR", 0xEC],
|
||||
["BATTLE_CENTER", 0xEF],
|
||||
["TRADE_CENTER", 0xF0],
|
||||
["LORELEIS_ROOM", 0xF5],
|
||||
["BRUNOS_ROOM", 0xF6],
|
||||
["AGATHAS_ROOM", 0xF7],
|
||||
["BEACH_HOUSE", 0xF8]]
|
||||
|
||||
#i prefer a different data structure
|
||||
temp = {}
|
||||
for constant in map_constants:
|
||||
value = constant[1]
|
||||
name = constant[0]
|
||||
temp[value] = name
|
||||
map_constants = temp
|
||||
del temp
|
||||
|
||||
#these appear outside of quotes
|
||||
constant_abbreviation_bytes = {
|
||||
}
|
||||
|
||||
#these appear in quotes
|
||||
char_conversion = [
|
||||
(" ", 0x7F),
|
||||
("A", 0x80),
|
||||
("B", 0x81),
|
||||
("C", 0x82),
|
||||
("D", 0x83),
|
||||
("E", 0x84),
|
||||
("F", 0x85),
|
||||
("G", 0x86),
|
||||
("H", 0x87),
|
||||
("I", 0x88),
|
||||
("J", 0x89),
|
||||
("K", 0x8A),
|
||||
("L", 0x8B),
|
||||
("M", 0x8C),
|
||||
("N", 0x8D),
|
||||
("O", 0x8E),
|
||||
("P", 0x8F),
|
||||
("Q", 0x90),
|
||||
("R", 0x91),
|
||||
("S", 0x92),
|
||||
("T", 0x93),
|
||||
("U", 0x94),
|
||||
("V", 0x95),
|
||||
("W", 0x96),
|
||||
("X", 0x97),
|
||||
("Y", 0x98),
|
||||
("Z", 0x99),
|
||||
("(", 0x9A),
|
||||
(")", 0x9B),
|
||||
(":", 0x9C),
|
||||
(";", 0x9D),
|
||||
("[", 0x9E),
|
||||
("]", 0x9F),
|
||||
("a", 0xA0),
|
||||
("b", 0xA1),
|
||||
("c", 0xA2),
|
||||
("d", 0xA3),
|
||||
("e", 0xA4),
|
||||
("f", 0xA5),
|
||||
("g", 0xA6),
|
||||
("h", 0xA7),
|
||||
("i", 0xA8),
|
||||
("j", 0xA9),
|
||||
("k", 0xAA),
|
||||
("l", 0xAB),
|
||||
("m", 0xAC),
|
||||
("n", 0xAD),
|
||||
("o", 0xAE),
|
||||
("p", 0xAF),
|
||||
("q", 0xB0),
|
||||
("r", 0xB1),
|
||||
("s", 0xB2),
|
||||
("t", 0xB3),
|
||||
("u", 0xB4),
|
||||
("v", 0xB5),
|
||||
("w", 0xB6),
|
||||
("x", 0xB7),
|
||||
("y", 0xB8),
|
||||
("z", 0xB9),
|
||||
("é", 0xBA),
|
||||
("'d", 0xBB),
|
||||
("'l", 0xBC),
|
||||
("'s", 0xBD),
|
||||
("'t", 0xBE),
|
||||
("'v", 0xBF),
|
||||
("'", 0xE0),
|
||||
("-", 0xE3),
|
||||
("'r", 0xE4),
|
||||
("'m", 0xE5),
|
||||
("?", 0xE6),
|
||||
("!", 0xE7),
|
||||
(".", 0xE8),
|
||||
("♂", 0xEF),
|
||||
#("¥", 0xF0),
|
||||
("/", 0xF3),
|
||||
(",", 0xF4),
|
||||
("♀", 0xF5),
|
||||
("0", 0xF6),
|
||||
("1", 0xF7),
|
||||
("2", 0xF8),
|
||||
("3", 0xF9),
|
||||
("4", 0xFA),
|
||||
("5", 0xFB),
|
||||
("6", 0xFC),
|
||||
("7", 0xFD),
|
||||
("8", 0xFE),
|
||||
("9", 0xFF)]
|
||||
#these appear in quotes
|
||||
txt_bytes = {
|
||||
0x50: "@",
|
||||
0x54: "#",
|
||||
0x75: "…",
|
||||
}
|
||||
for item in char_conversion:
|
||||
txt_bytes[item[1]] = item[0]
|
||||
del char_conversion
|
||||
|
||||
#this was originally for renaming freeze maps for a unique name
|
||||
def random_hash():
|
||||
available_chars = string.hexdigits[:16]
|
||||
return ''.join(
|
||||
random.choice(available_chars)
|
||||
for dummy in xrange(5))
|
||||
|
||||
def offset_to_pointer(offset):
|
||||
if type(offset) == str: offset = int(offset, base)
|
||||
return int(offset) % 0x4000 + 0x4000
|
||||
|
||||
def map_name_cleaner(name, id):
|
||||
"names have to be acceptable asm labels"
|
||||
|
||||
#duck out early
|
||||
if name == "FREEZE":
|
||||
#name += "_" + random_hash() + "_h"
|
||||
name += "_" + str(id) + "_h"
|
||||
return name
|
||||
|
||||
#the long haul
|
||||
name = name.replace(":", "")
|
||||
name = name.replace("(", "")
|
||||
name = name.replace(")", "")
|
||||
name = name.replace("'", "")
|
||||
name = name.replace("/", "") #N/S -> NS, W/E -> WE
|
||||
name = name.replace(".", "") #S.S. -> SS, Mt. -> Mt
|
||||
name = name.replace(" ", "") #or '_' ??
|
||||
name = name + "_h"
|
||||
|
||||
return name
|
||||
|
||||
def write_connections(north, south, west, east):
|
||||
#north 0, south 1, west 2, east 3
|
||||
if north and south and west and east: return "NORTH | SOUTH | WEST | EAST"
|
||||
if north and south and west and not east: return "NORTH | SOUTH | WEST"
|
||||
if north and south and not west and east: return "NORTH | SOUTH | EAST"
|
||||
if north and not south and west and east: return "NORTH | WEST | EAST"
|
||||
if not north and south and west and east: return "SOUTH | WEST | EAST"
|
||||
if north and south and not west and not east: return "NORTH | SOUTH"
|
||||
if not north and not south and west and east: return "WEST | EAST"
|
||||
if not north and south and west and not east: return "SOUTH | WEST"
|
||||
if not north and south and not west and east: return "SOUTH | EAST"
|
||||
if north and not south and west and not east: return "NORTH | WEST"
|
||||
if north and not south and not west and east: return "NORTH | EAST"
|
||||
raise Exception, "unpredicted outcome on write_connections"
|
||||
|
||||
#TODO: make this elegant
|
||||
def connection_line(byte):
|
||||
if type(byte) == str:
|
||||
byte = int(byte, base)
|
||||
|
||||
connections = 0
|
||||
north, south, west, east = False, False, False, False
|
||||
|
||||
temp = bin(byte)[2:]
|
||||
|
||||
if len(temp) == 1:
|
||||
if temp[0] == "1": #EAST
|
||||
east = True
|
||||
elif len(temp) == 2:
|
||||
if temp[0] == "1": #WEST
|
||||
west = True
|
||||
if temp[1] == "1": #EAST
|
||||
east = True
|
||||
elif len(temp) == 3:
|
||||
if temp[0] == "1": #SOUTH
|
||||
south = True
|
||||
if temp[1] == "1": #WEST
|
||||
west = True
|
||||
if temp[2] == "1": #EAST
|
||||
east = True
|
||||
elif len(temp) == 4:
|
||||
if temp[0] == "1": #NORTH
|
||||
north = True
|
||||
if temp[1] == "1": #SOUTH
|
||||
south = True
|
||||
if temp[2] == "1": #WEST
|
||||
west = True
|
||||
if temp[3] == "1": #EAST
|
||||
east = True
|
||||
|
||||
if north: connections += 1
|
||||
if south: connections += 1
|
||||
if west: connections += 1
|
||||
if east: connections += 1
|
||||
|
||||
#i don't have time to optimize this
|
||||
if connections == 0:
|
||||
return "$00"
|
||||
if connections == 1:
|
||||
if north: return "NORTH"
|
||||
if south: return "SOUTH"
|
||||
if west: return "WEST"
|
||||
if east: return "EAST"
|
||||
if connections >= 2:
|
||||
return write_connections(north, south, west, east)
|
||||
|
||||
def connection_pretty_printer(connections):
|
||||
#map_id, connected_map_tile_pointer, current_map_tile_pointer, bigness, width, y, x, window_pointer
|
||||
output = ""
|
||||
|
||||
for connection in connections.keys():
|
||||
connection = connections[connection]
|
||||
map_id = hex(connection["map_id"])[2:].zfill(2)
|
||||
connected_map_tile_pointer = connection["connected_map_tile_pointer"][2:]
|
||||
current_map_tile_pointer = connection["current_map_tile_pointer"][2:]
|
||||
bigness = hex(int(connection["bigness"], base))[2:].zfill(2)
|
||||
width = hex(int(connection["width"], base))[2:].zfill(2)
|
||||
y = hex(connection["y"])[2:].zfill(2)
|
||||
x = hex(connection["x"])[2:].zfill(2)
|
||||
window_pointer = connection["window_pointer"][2:]
|
||||
|
||||
output += spacing + "db $" + map_id + " ; some map\n"
|
||||
output += spacing + "dw $" + connected_map_tile_pointer + ", $" + current_map_tile_pointer + " ; pointers (connected, current) (strip)\n"
|
||||
output += spacing + "db $" + bigness + ", $" + width + " ; bigness, width\n"
|
||||
output += spacing + "db $" + y + ", $" + x + " ; alignments (y, x)\n"
|
||||
output += spacing + "dw $" + window_pointer + " ; window\n\n"
|
||||
|
||||
return output
|
||||
|
||||
def map_header_pretty_printer(map_header):
|
||||
address = map_header["address"]
|
||||
bank = map_header["bank"]
|
||||
id = map_header["id"]
|
||||
|
||||
name = map_header["name"]
|
||||
asm_name = map_name_cleaner(name, id)
|
||||
if name == "FREEZE": return "" #skip freeze maps
|
||||
|
||||
tileset = map_header["tileset"][2:]
|
||||
y = int(map_header["y"], base)
|
||||
x = int(map_header["x"], base)
|
||||
map_pointer = map_header["map_pointer"]
|
||||
texts_pointer = map_header["texts_pointer"]
|
||||
script_pointer = map_header["script_pointer"]
|
||||
connection_byte = map_header["connection_byte"]
|
||||
connections = map_header["connections"]
|
||||
object_data_pointer = map_header["object_data_pointer"]
|
||||
|
||||
byte_size = 12 + (11 * len(connections.keys()))
|
||||
|
||||
map_pointer = hex(offset_to_pointer(map_pointer))[2:]
|
||||
texts_pointer = hex(offset_to_pointer(texts_pointer))[2:]
|
||||
script_pointer = hex(offset_to_pointer(script_pointer))[2:]
|
||||
object_data_pointer = hex(offset_to_pointer(object_data_pointer))[2:]
|
||||
|
||||
#formatting: hex(y)[2:].zill(2) or "%02x" % (y,)
|
||||
|
||||
output = asm_name + ": ; " + address + " to " + hex(int(address, base) + byte_size) + " (" + str(byte_size) + " bytes) (id=" + str(id) + ")\n"
|
||||
output += spacing + "db $" + str(tileset).zfill(2) + " ; tileset\n"
|
||||
output += spacing + "db $" + hex(y)[2:].zfill(2) + ", $" + hex(x)[2:].zfill(2) + " ; dimensions (y, x)\n"
|
||||
output += spacing + "dw $" + map_pointer + ", $" + texts_pointer + ", $" + script_pointer + " ; blocks, texts, scripts\n"
|
||||
output += spacing + "db " + connection_line(connection_byte) + " ; connections\n\n"
|
||||
|
||||
if len(connections) > 0:
|
||||
output += spacing + "; connections data\n\n"
|
||||
output += connection_pretty_printer(connections)
|
||||
output += spacing + "; end connection data\n\n"
|
||||
|
||||
#TODO: print out label for object_data_pointer if it's already in the file
|
||||
output += spacing + "dw $" + object_data_pointer + " ; objects\n"
|
||||
|
||||
return output
|
||||
|
||||
def make_object_label_name(name):
|
||||
"""make a label for the asm file
|
||||
like: PalletTownObject"""
|
||||
name = map_name_cleaner(name, None)
|
||||
return name.replace("_h", "") + "Object"
|
||||
|
||||
def make_text_label(map_name, id):
|
||||
"""using standard object labels
|
||||
for instance, PalletTownText3"""
|
||||
label = map_name_cleaner(map_name, None)[:-2] + "Text" + str(id)
|
||||
return label
|
||||
|
||||
def object_data_pretty_printer(map_id):
|
||||
map = extract_maps.map_headers[map_id]
|
||||
output = ""
|
||||
|
||||
label_name = make_object_label_name(map["name"])
|
||||
object_data_pointer = map["object_data_pointer"]
|
||||
object = map["object_data"]
|
||||
size = extract_maps.compute_object_data_size(object)
|
||||
|
||||
output += label_name + ": ; " + object_data_pointer + " (size=" + str(size) + ")\n"
|
||||
output += spacing + "db $" + hex(object["maps_border_tile"])[2:] + " ; border tile\n"
|
||||
output += "\n"
|
||||
output += spacing + "db $" + hex(int(object["number_of_warps"]))[2:] + " ; warps\n"
|
||||
|
||||
#warps
|
||||
for warp_id in object["warps"]:
|
||||
warp = object["warps"][warp_id]
|
||||
y = warp["y"]
|
||||
x = warp["x"]
|
||||
warp_to_point = warp["warp_to_point"]
|
||||
warp_to_map_id = warp["warp_to_map_id"]
|
||||
|
||||
try:
|
||||
warp_to_map_constant = map_constants[warp_to_map_id]
|
||||
except Exception, exc:
|
||||
warp_to_map_constant = "$" + hex(warp_to_map_id)[2:]
|
||||
|
||||
output += spacing + "db $" + hex(int(y))[2:] + ", $" + hex(int(x))[2:] + ", $" + hex(int(warp_to_point))[2:] + ", " + warp_to_map_constant + "\n"
|
||||
|
||||
output += "\n"
|
||||
output += spacing + "db $" + hex(int(object["number_of_signs"]))[2:] + " ; signs\n"
|
||||
|
||||
#signs
|
||||
for sign_id in object["signs"]:
|
||||
sign = object["signs"][sign_id]
|
||||
y = sign["y"]
|
||||
x = sign["x"]
|
||||
text_id = sign["text_id"]
|
||||
|
||||
output += spacing + "db $" + hex(int(y))[2:] + ", $" + hex(int(x))[2:] + ", $" + hex(int(text_id))[2:] + " ; " + make_text_label(map["name"], text_id) + "\n"
|
||||
|
||||
output += "\n"
|
||||
output += spacing + "db $" + hex(int(object["number_of_things"]))[2:] + " ; people\n"
|
||||
|
||||
#people
|
||||
for thing_id in object["things"]:
|
||||
thing = object["things"][thing_id]
|
||||
|
||||
ending = ""
|
||||
if thing["type"] == "item":
|
||||
ending = ", $" + hex(int(thing["item_number"]))[2:] + " ; item\n"
|
||||
elif thing["type"] == "trainer":
|
||||
ending = ", $" + hex(int(thing["trainer_type"]))[2:] + ", $" + hex(int(thing["pokemon_set"]))[2:] + " ; trainer\n"
|
||||
else:
|
||||
ending = " ; person\n"
|
||||
|
||||
picture_number = hex(int(thing["picture_number"]))[2:]
|
||||
y = hex(int(thing["y"]) - 4)[2:]
|
||||
x = hex(int(thing["x"]) - 4)[2:]
|
||||
movement1 = hex(int(thing["movement1"]))[2:]
|
||||
movement2 = hex(int(thing["movement2"]))[2:]
|
||||
text_id = hex(int(thing["original_text_string_number"]))[2:]
|
||||
|
||||
output += spacing + "db " + sprite_helper.sprites[thing["picture_number"]] + ", $" + y + " + 4, $" + x + " + 4, $" + movement1 + ", $" + movement2 + ", $" + text_id + ending
|
||||
|
||||
output += "\n"
|
||||
|
||||
if object["number_of_warps"] > 0:
|
||||
output += spacing + "; warp-to\n"
|
||||
|
||||
for warp_to_id in object["warp_tos"]:
|
||||
warp_to = object["warp_tos"][warp_to_id]
|
||||
map_width = map["x"]
|
||||
warp_to_y = hex(int(warp_to["y"]))[2:]
|
||||
warp_to_x = hex(int(warp_to["x"]))[2:]
|
||||
|
||||
try:
|
||||
previous_location = map_constants[object["warps"][warp_to_id]["warp_to_map_id"]]
|
||||
comment = " ; " + previous_location
|
||||
except Exception, exc:
|
||||
comment = ""
|
||||
|
||||
output += spacing + "EVENT_DISP $" + map_width[2:] + ", $" + warp_to_y + ", $" + warp_to_x + comment + "\n"
|
||||
#output += spacing + "dw $" + hex(int(warp_to["event_displacement"][1]))[2:] + hex(int(warp_to["event_displacement"][0]))[2:] + "\n"
|
||||
#output += spacing + "db $" + hex(int(warp_to["y"]))[2:] + ", $" + hex(int(warp_to["x"]))[2:] + "\n"
|
||||
#output += "\n"
|
||||
|
||||
output += "\n"
|
||||
|
||||
while output[-1] == "\n":
|
||||
output = output[:-1]
|
||||
|
||||
output += "\n"
|
||||
return output
|
||||
|
||||
def find_all_tx_fars():
|
||||
global all_texts
|
||||
tx_fars = [] #[map_id, text_id, text_pointer, tx_far_pointer, TX_FAR]
|
||||
for map_id in all_texts:
|
||||
map2 = all_texts[map_id]
|
||||
for text_id in map2.keys():
|
||||
text = map2[text_id]
|
||||
for command_id in text.keys():
|
||||
command = text[command_id]
|
||||
if "TX_FAR" in command.keys():
|
||||
TX_FAR = command["TX_FAR"]
|
||||
if TX_FAR[0]["type"] == 0x0:
|
||||
tx_fars.append([map_id, text_id, analyze_texts.get_text_pointer(int(extract_maps.map_headers[map_id]["texts_pointer"], 16), text_id), command["pointer"], TX_FAR])
|
||||
return tx_fars
|
||||
|
||||
def tx_far_label_maker(map_name, text_id):
|
||||
label = "_" + map_name_cleaner(map_name, None)[:-2] + "Text" + str(text_id)
|
||||
return label
|
||||
|
||||
def tx_far_pretty_printer(tx_far):
|
||||
"pretty output for a tx_far"
|
||||
map_id = tx_far[0]
|
||||
map2 = extract_maps.map_headers[map_id]
|
||||
text_id = tx_far[1]
|
||||
text_pointer = tx_far[2]
|
||||
tx_far_start_address = tx_far[3]
|
||||
text_far = tx_far[4]
|
||||
lines = text_far[0]["lines"]
|
||||
label = tx_far_label_maker(map2["name"], text_id)
|
||||
|
||||
#add the ending byte on the next line
|
||||
#lines[len(lines.keys())+1] = [text_far[1]["type"]]
|
||||
|
||||
#add the ending byte to the last line- always seems $57
|
||||
lines[len(lines.keys())-1].append(text_far[1]["type"])
|
||||
|
||||
output = "\n"
|
||||
output += label + ": ; " + hex(tx_far_start_address) + "\n"
|
||||
first = True
|
||||
for line_id in lines:
|
||||
line = lines[line_id]
|
||||
output += spacing + "db "
|
||||
if first:
|
||||
output += "$0, "
|
||||
first = False
|
||||
|
||||
quotes_open = False
|
||||
first_byte = True
|
||||
was_byte = False
|
||||
byte_count = 0
|
||||
for byte in line:
|
||||
if byte in txt_bytes:
|
||||
if not quotes_open and not first_byte: #start text
|
||||
output += ", \""
|
||||
quotes_open = True
|
||||
first_byte = False
|
||||
if not quotes_open and first_byte: #start text
|
||||
output += "\""
|
||||
quotes_open = True
|
||||
output += txt_bytes[byte]
|
||||
elif byte in constant_abbreviation_bytes:
|
||||
if quotes_open:
|
||||
output += "\""
|
||||
quotes_open = False
|
||||
if not first_byte:
|
||||
output += ", "
|
||||
output += constant_abbreviation_bytes[byte]
|
||||
else:
|
||||
if quotes_open:
|
||||
output += "\""
|
||||
quotes_open = False
|
||||
|
||||
#if you want the ending byte on the last line
|
||||
#if not (byte == 0x57 or byte == 0x50 or byte == 0x58):
|
||||
if not first_byte:
|
||||
output += ", "
|
||||
|
||||
output += "$" + hex(byte)[2:]
|
||||
was_byte = True
|
||||
|
||||
#add a comma unless it's the end of the line
|
||||
#if byte_count+1 != len(line):
|
||||
# output += ", "
|
||||
|
||||
first_byte = False
|
||||
byte_count += 1
|
||||
#close final quotes
|
||||
if quotes_open:
|
||||
output += "\""
|
||||
quotes_open = False
|
||||
|
||||
output += "\n"
|
||||
|
||||
#output += "\n"
|
||||
return output
|
||||
|
||||
def print_all_headers():
|
||||
maps = []
|
||||
for map in extract_maps.map_headers:
|
||||
maps.append(extract_maps.map_headers[map])
|
||||
|
||||
maps = sorted(maps, key=lambda map: int(map["address"], base))
|
||||
|
||||
for map in maps:
|
||||
output = map_header_pretty_printer(map)
|
||||
if output != "": print output
|
||||
|
||||
if __name__ == "__main__":
|
||||
#read binary data from file
|
||||
extract_maps.load_rom()
|
||||
|
||||
#where are the map structs?
|
||||
extract_maps.load_map_pointers()
|
||||
|
||||
#load map headers into memory
|
||||
extract_maps.read_all_map_headers()
|
||||
|
||||
#load texts
|
||||
all_texts = analyze_texts.analyze_texts()
|
||||
|
||||
#print them out
|
||||
#print_all_headers()
|
||||
|
||||
#print out only the object data for pallet town (map 0)
|
||||
#print object_data_pretty_printer(0)
|
||||
|
||||
#prepare to pretty print tx_fars
|
||||
#first you must load all_texts
|
||||
#tx_fars = find_all_tx_fars()
|
||||
#for entry in tx_fars:
|
||||
# print tx_far_pretty_printer(entry)
|
@ -1,21 +0,0 @@
|
||||
#author: Bryan Bishop <kanzure@gmail.com>
|
||||
#date: 2012-01-16
|
||||
from optparse import OptionParser
|
||||
from analyze_texts import text_pretty_printer_at
|
||||
|
||||
def main():
|
||||
usage = "usage: %prog address label"
|
||||
parser = OptionParser(usage)
|
||||
(options, args) = parser.parse_args()
|
||||
if len(args) == 1:
|
||||
print "usage: python pretty_text.py address label"
|
||||
args.append("UnnamedText_" + (args[0].replace("0x", "")))
|
||||
elif len(args) != 2:
|
||||
parser.error("we need both an address and a label")
|
||||
address = int(args[0], 16)
|
||||
label = args[1]
|
||||
|
||||
text_pretty_printer_at(address, label)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -1,126 +0,0 @@
|
||||
#author: Bryan Bishop <kanzure@gmail.com>
|
||||
#date: 2012-01-24
|
||||
from optparse import OptionParser
|
||||
from gbz80disasm import load_labels, find_label
|
||||
from extract_maps import calculate_pointer
|
||||
import sys
|
||||
spacing = "\t"
|
||||
rom = None
|
||||
|
||||
def pretty_print_trainer_header(address, label=None):
|
||||
"""make pretty text for a trainer header"""
|
||||
global rom
|
||||
output = ""
|
||||
bank_id = 0
|
||||
if address > 0x4000:
|
||||
bank_id = address / 0x4000
|
||||
|
||||
#convert address to an integer if necessary
|
||||
if type(address) == str:
|
||||
if "$" in address: address = address.replace("$", "0x")
|
||||
address = int(address, 16)
|
||||
|
||||
#label this section of asm
|
||||
if label == None:
|
||||
output += "TrainerHeader_" + hex(address)[2:] + ": ; 0x" + hex(address)[2:] + "\n"
|
||||
else:
|
||||
output += label + ": ; 0x" + hex(address)[2:] + "\n"
|
||||
|
||||
#flag's bit
|
||||
output += spacing + "db $" + hex(ord(rom[address]))[2:] + " ; flag's bit\n"
|
||||
|
||||
#trainer's view range
|
||||
view_range = ord(rom[address+1]) >> 4
|
||||
output += spacing + "db ($" + hex(view_range)[2:] + " << 4) ; trainer's view range\n"
|
||||
|
||||
#flag's byte
|
||||
pointer_byte1 = ord(rom[address+2])
|
||||
pointer_byte2 = ord(rom[address+3])
|
||||
partial_pointer = (pointer_byte1 + (pointer_byte2 << 8))
|
||||
partial_pointer = "$%.2x" % partial_pointer
|
||||
output += spacing + "dw " + partial_pointer + " ; flag's byte\n"
|
||||
|
||||
#TextBeforeBattle
|
||||
pointer_byte1 = ord(rom[address+4])
|
||||
pointer_byte2 = ord(rom[address+5])
|
||||
partial_pointer = (pointer_byte1 + (pointer_byte2 << 8))
|
||||
label = find_label(partial_pointer, bank_id)
|
||||
if label == None:
|
||||
print "label not found for (TextBeforeBattle) " + hex(calculate_pointer(partial_pointer, bank_id))
|
||||
print ""
|
||||
label = "$" + hex(partial_pointer)[2:]
|
||||
#sys.exit(0)
|
||||
|
||||
output += spacing + "dw " + label + " ; " + hex(partial_pointer) + " TextBeforeBattle\n"
|
||||
|
||||
#TextAfterBattle
|
||||
pointer_byte1 = ord(rom[address+6])
|
||||
pointer_byte2 = ord(rom[address+7])
|
||||
partial_pointer = (pointer_byte1 + (pointer_byte2 << 8))
|
||||
label = find_label(partial_pointer, bank_id)
|
||||
if label == None:
|
||||
print "label not found for (TextAfterBattle) " + hex(calculate_pointer(partial_pointer, bank_id))
|
||||
print ""
|
||||
label = "$" + hex(partial_pointer)[2:]
|
||||
#sys.exit(0)
|
||||
|
||||
output += spacing + "dw " + label + " ; " + hex(partial_pointer) + " TextAfterBattle\n"
|
||||
|
||||
#TextEndBattle
|
||||
pointer_byte1 = ord(rom[address+8])
|
||||
pointer_byte2 = ord(rom[address+9])
|
||||
partial_pointer = (pointer_byte1 + (pointer_byte2 << 8))
|
||||
label = find_label(partial_pointer, bank_id)
|
||||
if label == None:
|
||||
print "label not found for (TextEndBattle) " + hex(calculate_pointer(partial_pointer, bank_id))
|
||||
print ""
|
||||
label = "$" + hex(partial_pointer)[2:]
|
||||
#sys.exit(0)
|
||||
|
||||
output += spacing + "dw " + label + " ; " + hex(partial_pointer) + " TextEndBattle\n"
|
||||
|
||||
#TextEndBattle
|
||||
pointer_byte1 = ord(rom[address+10])
|
||||
pointer_byte2 = ord(rom[address+11])
|
||||
partial_pointer = (pointer_byte1 + (pointer_byte2 << 8))
|
||||
label = find_label(partial_pointer, bank_id)
|
||||
if label == None:
|
||||
print "label not found for (TextEndBattle) " + hex(calculate_pointer(partial_pointer, bank_id))
|
||||
print ""
|
||||
label = "$" + hex(partial_pointer)[2:]
|
||||
#sys.exit(0)
|
||||
|
||||
output += spacing + "dw " + label + " ; " + hex(partial_pointer) + " TextEndBattle\n"
|
||||
|
||||
output += "; " + hex(address+12) + "\n"
|
||||
|
||||
return output
|
||||
|
||||
def all_trainer_headers_at(address):
|
||||
i = 0
|
||||
while ord(rom[address + (i*12)]) != 0xff:
|
||||
print pretty_print_trainer_header(address + (i*12))
|
||||
i += 1
|
||||
|
||||
def main():
|
||||
load_labels()
|
||||
|
||||
usage = "usage: %prog address"
|
||||
parser = OptionParser(usage)
|
||||
(options, args) = parser.parse_args()
|
||||
if len(args) == 1:
|
||||
print "usage: python pretty_trainer_headers.py address label\n"
|
||||
args.append("TrainerHeader_" + (args[0].replace("0x", "")))
|
||||
elif len(args) != 2:
|
||||
parser.error("we need both an address and a label")
|
||||
address = int(args[0], 16)
|
||||
label = args[1]
|
||||
|
||||
global rom
|
||||
rom = open("../baserom.gbc", "r").read()
|
||||
|
||||
#print pretty_print_trainer_header(address, label)
|
||||
print all_trainer_headers_at(address)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
128
extras/redrle.c
128
extras/redrle.c
@ -1,128 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2011 IIMarckus <iimarckus@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program compresses or decompresses the Town Map tilemap
|
||||
* from Pokémon Red, Blue, and Yellow.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
fprintf(stderr, "Usage: redrle [-d] infile outfile\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
FILE *infile, *outfile;
|
||||
bool d = false; /* compress or decompress flag */
|
||||
|
||||
if (argc < 3 || argc > 4)
|
||||
usage();
|
||||
|
||||
if (strcmp(argv[1], "-d") == 0) {
|
||||
if (argc != 4)
|
||||
usage();
|
||||
d = true;
|
||||
}
|
||||
|
||||
infile = fopen(argv[argc - 2], "rb");
|
||||
if (infile == NULL) {
|
||||
fprintf(stderr, "Error opening file '%s': ", argv[argc - 2]);
|
||||
perror(NULL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
outfile = fopen(argv[argc - 1], "wb");
|
||||
if (outfile == NULL) {
|
||||
fprintf(stderr, "Error opening file '%s': ", argv[argc - 1]);
|
||||
perror(NULL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (d) { /* decompress */
|
||||
for (;;) {
|
||||
int i, count;
|
||||
int byte = fgetc(infile);
|
||||
if (byte == 0)
|
||||
break;
|
||||
count = byte & 0xF;
|
||||
byte >>= 4;
|
||||
|
||||
if (feof(infile)) {
|
||||
fprintf(stderr, "Decompress error: reached "
|
||||
"end of file without finding terminating "
|
||||
"null byte.\n");
|
||||
exit(1);
|
||||
}
|
||||
for (i = 0; i < count;
|
||||
++i)
|
||||
fputc(byte, outfile);
|
||||
}
|
||||
} else { /* compress */
|
||||
int byte, count = 0, lastbyte = 0;
|
||||
for (;;) {
|
||||
byte = fgetc(infile);
|
||||
|
||||
if (feof(infile)) {
|
||||
while (count > 0xF) {
|
||||
count -= 0xF;
|
||||
fputc(lastbyte << 4 | 0xF, outfile);
|
||||
}
|
||||
if (count != 0) {
|
||||
fputc(lastbyte << 4 | count, outfile);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (byte > 0xF) {
|
||||
fprintf(stderr, "Compress error: read a byte "
|
||||
"greater than 0xF.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (byte == lastbyte)
|
||||
++count;
|
||||
else {
|
||||
while (count > 0xF) {
|
||||
count -= 0xF;
|
||||
fputc(lastbyte << 4 | 0xF, outfile);
|
||||
}
|
||||
if (count != 0) {
|
||||
fputc(lastbyte << 4 | count, outfile);
|
||||
count = 0;
|
||||
}
|
||||
|
||||
lastbyte = byte;
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
fputc(0, outfile); /* Terminating 0x00 */
|
||||
}
|
||||
|
||||
fclose(infile);
|
||||
fclose(outfile);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,245 +0,0 @@
|
||||
#author: Bryan Bishop <kanzure@gmail.com>
|
||||
#date: 2012-01-15
|
||||
#replace dimensions with constants
|
||||
import sys #for non-newline-terminated output :/
|
||||
from add_map_labels_to_map_headers import find_with_start_of_line
|
||||
from pretty_map_headers import map_name_cleaner, spacing, offset_to_pointer, map_constants
|
||||
from connection_helper import print_connections
|
||||
from ctypes import c_int8
|
||||
|
||||
# X/Y_Movement_Of_Connection
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
#
|
||||
# A X movement is how many map blocks there are to the left of one of your north/south connections.
|
||||
# A Y movement is how many map blocks there are above your west/east connection.
|
||||
|
||||
#===============================================================================
|
||||
# #4-#5 : Current Map Position
|
||||
#===============================================================================
|
||||
#
|
||||
# This points to the part of the current map (further up in RAM)
|
||||
# that the connection strips upperleft block is placed on the current map.
|
||||
#
|
||||
# ____________________
|
||||
# Connection |
|
||||
# Direction | Formula
|
||||
# ___________|_______
|
||||
#
|
||||
# North: C6EB + X_Movement_of_Connection Strip
|
||||
#
|
||||
# South: C6EB + (Height of Map + 3) * (Width of Map + 6) +
|
||||
# X_Movement_of_Connection Strip
|
||||
#
|
||||
# West: C6E8 + (Width of Map + 6) * (Y_Movement_of_"Connection Strip" + 3)
|
||||
#
|
||||
# East: C6E5 + (Width of Map + 6) * (Y_Movement_of_"Connection Strip" + 4)
|
||||
|
||||
asm = None
|
||||
asm_lines = None
|
||||
def load_asm():
|
||||
global asm, asm_lines
|
||||
asm = open("../main.asm", "r").read()
|
||||
asm_lines = asm.split("\n")
|
||||
|
||||
def get_xy_movement_of_connection_strip(map_id, connection_id):
|
||||
map1 = extract_maps.map_headers[map_id]
|
||||
connections = map1["connections"]
|
||||
connection = connections[connection_id]
|
||||
direction = connection["direction"]
|
||||
current_map_location = int(connection["current_map_tile_pointer"], 16)
|
||||
|
||||
map2 = extract_maps.map_headers[connection["map_id"]]
|
||||
map2_height = int(map2["y"], 16)
|
||||
map2_width = int(map2["x"], 16)
|
||||
|
||||
y_mov = None
|
||||
#if direction == "WEST":
|
||||
# y_mov = ((current_map_location - 0xC6E8) / (map2_width + 6)) - 3
|
||||
#elif direction == "EAST":
|
||||
# y_mov = ((current_map_location - 0xC6E5) / (map2_width + 6)) - 4
|
||||
if direction in ["WEST", "EAST"]:
|
||||
y_mov = c_int8(connection["y"]).value / -2
|
||||
|
||||
x_mov = None
|
||||
#if direction == "NORTH":
|
||||
# x_mov = current_map_location - 0xC6EB
|
||||
#elif direction == "SOUTH":
|
||||
# x_mov = current_map_location - 0xC6EB - ((map2_height + 3) * (map2_width + 6))
|
||||
if direction in ["NORTH", "SOUTH"]:
|
||||
x_mov = c_int8(connection["x"]).value / -2
|
||||
|
||||
return {"y_mov": y_mov, "x_mov": x_mov}
|
||||
|
||||
def find_line_starting_with(value):
|
||||
global asm_lines
|
||||
id = 0
|
||||
for line in asm_lines:
|
||||
if len(line) < len(value): continue
|
||||
if line[:len(value)] == value:
|
||||
return asm_lines.index(line)
|
||||
id += 1
|
||||
return False #not found
|
||||
|
||||
def current_map_position_formula(map_id, connection_id):
|
||||
map1_id = map_id
|
||||
map1 = extract_maps.map_headers[map_id]
|
||||
connections = map1["connections"]
|
||||
connection = connections[connection_id]
|
||||
map1_height = int(map1["y"], 16)
|
||||
map1_width = int(map1["x"], 16)
|
||||
map1_name = map1["name"]
|
||||
map1_name = map_name_cleaner(map1_name, None)[:-2]
|
||||
|
||||
direction = connection["direction"]
|
||||
current_map_location = int(connection["current_map_tile_pointer"], 16)
|
||||
|
||||
map2_id = connection["map_id"]
|
||||
map2 = extract_maps.map_headers[map2_id]
|
||||
map2_name = map2["name"]
|
||||
map2_name = map_name_cleaner(map2_name, None)[:-2]
|
||||
map2_height = int(map2["y"], 16)
|
||||
map2_width = int(map2["x"], 16)
|
||||
|
||||
y_mov = None
|
||||
if direction == "WEST":
|
||||
y_mov = ((current_map_location - 0xC6E8) / (map1_width + 6)) - 3
|
||||
elif direction == "EAST":
|
||||
y_mov = ((current_map_location - 0xC6E5) / (map1_width + 6)) - 4
|
||||
|
||||
x_mov = None
|
||||
if direction == "NORTH":
|
||||
x_mov = current_map_location - 0xC6EB
|
||||
elif direction == "SOUTH":
|
||||
x_mov = current_map_location - 0xC6EB - ((map1_height + 3) * (map1_width + 6))
|
||||
|
||||
formula = ""
|
||||
if direction == "NORTH":
|
||||
formula = "$C6EB + " + str(x_mov)
|
||||
elif direction == "SOUTH":
|
||||
formula = "$C6EB + (" + map1_name + "Height + 3) * (" + map1_name + "Width + 6) + " + str(x_mov)
|
||||
elif direction == "WEST":
|
||||
formula = "$C6E8 + (" + map1_name + "Width + 6) * (" + str(y_mov) + " + 3)"
|
||||
elif direction == "EAST":
|
||||
formula = "$C6E5 + (" + map1_name + "Width + 6) * (" + str(y_mov) + " + 4)"
|
||||
|
||||
return formula
|
||||
|
||||
def replace_values():
|
||||
global asm_lines #0-15 ok
|
||||
for map_id in [3]: #extract_maps.map_headers.keys():
|
||||
if map_id in extract_maps.bad_maps: continue #skip
|
||||
if map_id == 12: continue #skip Route 1
|
||||
|
||||
map1 = extract_maps.map_headers[map_id]
|
||||
label_name = map_name_cleaner(map1["name"], None)
|
||||
clean_name = label_name[:-2]
|
||||
|
||||
line_number = find_line_starting_with(label_name)
|
||||
if line_number == False: continue #skip, not found
|
||||
|
||||
#replace dimensions if necessary
|
||||
if "dimensions" in asm_lines[line_number + 2] and "$" in asm_lines[line_number + 2] and not "\t" in asm_lines[line_number+2]:
|
||||
asm_lines[line_number + 2] = spacing + "db " + clean_name + "Height, " + clean_name + "Width ; dimensions (y, x)"
|
||||
|
||||
#skip the rest of this if there are no connections
|
||||
if len(map1["connections"]) == 0: continue
|
||||
if not "; connections data" in asm_lines[line_number + 6]: continue
|
||||
|
||||
connection_offset = line_number + 8
|
||||
|
||||
for connection_id in map1["connections"]:
|
||||
connection = map1["connections"][connection_id]
|
||||
direction = connection["direction"]
|
||||
map2_id = connection["map_id"]
|
||||
map2 = extract_maps.map_headers[map2_id]
|
||||
map2_name = map_name_cleaner(map2["name"], None)[:-2]
|
||||
map2_height = int(map2["y"], 16)
|
||||
map2_width = int(map2["x"], 16)
|
||||
|
||||
movements = get_xy_movement_of_connection_strip(map_id, connection_id)
|
||||
y_mov = movements["y_mov"]
|
||||
x_mov = movements["x_mov"]
|
||||
|
||||
#replace the first two pointers
|
||||
if " dw " in asm_lines[connection_offset + 1]:
|
||||
formula = print_connections(map_id, in_connection_id=connection_id)
|
||||
formula2 = current_map_position_formula(map_id, connection_id)
|
||||
|
||||
temp_line = asm_lines[connection_offset + 1]
|
||||
temp_line = spacing + "dw " + formula + " ; connection strip location\n" #connection strip location
|
||||
temp_line += spacing + "dw " + formula2 + " ; current map position" #current map position
|
||||
|
||||
asm_lines[connection_offset + 1] = temp_line
|
||||
|
||||
#bigness, width
|
||||
if "bigness, width" in asm_lines[connection_offset + 2]:
|
||||
temp_line = spacing + "db "
|
||||
|
||||
if int(connection["bigness"],16) == map2_width:
|
||||
temp_line += map2_name + "Width"
|
||||
elif int(connection["bigness"],16) == map2_height:
|
||||
temp_line += map2_name + "Height"
|
||||
else: #dunno wtf to do
|
||||
temp_line += "$" + hex(int(connection["bigness"],16))[2:]
|
||||
#if direction in ["NORTH", "SOUTH"]:
|
||||
# temp_line += map2_name + "Width"
|
||||
#elif direction in ["WEST", "EAST"]:
|
||||
# temp_line += map2_name + "Height"
|
||||
|
||||
temp_line += ", " + map2_name + "Width"
|
||||
|
||||
temp_line += " ; bigness, width"
|
||||
asm_lines[connection_offset + 2] = temp_line
|
||||
|
||||
#alignments (y, x)
|
||||
if "alignments (y, x)" in asm_lines[connection_offset + 3]:
|
||||
temp_line = spacing + "db "
|
||||
|
||||
if direction == "NORTH":
|
||||
temp_line += "(" + map2_name + "Height * 2) - 1"
|
||||
elif direction == "SOUTH":
|
||||
temp_line += "0"
|
||||
elif direction in ["WEST", "EAST"]:
|
||||
#TODO: this might be y_mov/4 ??
|
||||
temp_line += "(" + str(y_mov) + " * -2)"
|
||||
|
||||
temp_line += ", "
|
||||
|
||||
#Relative X-Position of player after entering connected map.
|
||||
if direction in ["NORTH", "SOUTH"]:
|
||||
temp_line += "(" + str(x_mov) + " * -2)"
|
||||
elif direction == "WEST":
|
||||
temp_line += "(" + map2_name + "Width * 2) - 1"
|
||||
elif direction == "EAST":
|
||||
temp_line += "0"
|
||||
|
||||
temp_line += " ; alignments (y, x)"
|
||||
asm_lines[connection_offset + 3] = temp_line
|
||||
|
||||
#window
|
||||
if "; window" in asm_lines[connection_offset + 4]:
|
||||
temp_line = spacing + "dw "
|
||||
|
||||
if direction == "NORTH":
|
||||
temp_line += "$C6E9 + " + map2_name + "Height * (" + map2_name + "Width + 6)"
|
||||
elif direction in ["SOUTH", "EAST"]:
|
||||
temp_line += "$C6EF + " + map2_name + "Width"
|
||||
elif direction == "WEST":
|
||||
temp_line += "$C6EE + 2 * " + map2_name + "Width"
|
||||
|
||||
temp_line += " ; window"
|
||||
asm_lines[connection_offset + 4] = temp_line
|
||||
|
||||
#jump to the next connection
|
||||
connection_offset += 6
|
||||
|
||||
if __name__ == "__main__":
|
||||
import extract_maps
|
||||
extract_maps.load_rom()
|
||||
extract_maps.load_map_pointers()
|
||||
extract_maps.read_all_map_headers()
|
||||
|
||||
load_asm()
|
||||
replace_values()
|
||||
sys.stdout.write("\n".join(asm_lines))
|
||||
|
@ -1,28 +0,0 @@
|
||||
#author: Bryan Bishop <kanzure@gmail.com>
|
||||
#date: 2012-01-13
|
||||
import os
|
||||
|
||||
changeset_numbers = range(1145, 1149)
|
||||
|
||||
def take_snapshot_image(changeset_number):
|
||||
"turn main.asm into an image at a certain version"
|
||||
|
||||
print "reverting main.asm to r" + str(changeset_number)
|
||||
|
||||
#revert the file (it used to be common.asm)
|
||||
os.system("rm ../main.asm; rm ../common.asm; rm ../pokered.asm")
|
||||
os.system("hg revert ../main.asm -r" + str(changeset_number))
|
||||
os.system("hg revert ../common.asm -r" + str(changeset_number))
|
||||
os.system("hg revert ../pokered.asm -r" + str(changeset_number))
|
||||
|
||||
print "generating the image.."
|
||||
|
||||
#draw the image
|
||||
os.system("python romviz.py")
|
||||
|
||||
#move the file
|
||||
os.system("mv test.png versions/" + str(changeset_number) + ".png")
|
||||
|
||||
for changeset_number in changeset_numbers:
|
||||
take_snapshot_image(changeset_number)
|
||||
|
@ -1,40 +0,0 @@
|
||||
#author: Bryan Bishop <kanzure@gmail.com>
|
||||
#date: 2012-01-10
|
||||
#show me an image
|
||||
import Image
|
||||
from math import floor
|
||||
import extract_maps
|
||||
import analyze_incbins
|
||||
|
||||
print "loading rom.."
|
||||
extract_maps.load_rom()
|
||||
#extract_maps.load_map_pointers()
|
||||
#extract_maps.read_all_map_headers()
|
||||
|
||||
print "analyzing incbins.."
|
||||
analyze_incbins.load_asm()
|
||||
analyze_incbins.isolate_incbins()
|
||||
analyze_incbins.process_incbins()
|
||||
|
||||
width = 1024
|
||||
height = 1024
|
||||
|
||||
im = Image.new("P", (width, height), 0)
|
||||
|
||||
im.putpalette([
|
||||
0, 0, 0,
|
||||
126, 30, 156,
|
||||
])
|
||||
|
||||
print "drawing incbins..."
|
||||
for incbin_key in analyze_incbins.processed_incbins:
|
||||
incbin = analyze_incbins.processed_incbins[incbin_key]
|
||||
start = incbin["start"]
|
||||
end = incbin["end"]
|
||||
|
||||
for pos in range(start, end+1):
|
||||
widthx = int(pos % width)
|
||||
heighty = int(floor(pos / height))
|
||||
im.putpixel((widthx, heighty), 1)
|
||||
|
||||
im.save("test.png")
|
@ -1,402 +0,0 @@
|
||||
import extract_maps
|
||||
spacing = "\t"
|
||||
|
||||
#provided by sawakita
|
||||
#these were originally used for making the initial_icon_constants
|
||||
#but the label names in constants.asm have since been edited
|
||||
initial_icon_constants = {
|
||||
0x01: ["Hiro", ""],
|
||||
0x02: ["Rival", ""],
|
||||
0x03: ["Oak", ""],
|
||||
0x04: ["blonde boy", ""],
|
||||
0x05: ["machoke/slowbro OW", "machoke slowbro"],
|
||||
0x06: ["blonde(horse-tail-hair) girl", "blonde ponytail girl"],
|
||||
0x07: ["black-hair boy 1", "black hair boy 1"],
|
||||
0x08: ["little kid (F)", "little girl"],
|
||||
0x09: ["bird", ""],
|
||||
0x0A: ["fat bald man", "fat bald guy"],
|
||||
0x0B: ["monk", ""],
|
||||
0x0C: ["black-hair boy 2/Brock", "black hair boy 2"],
|
||||
0x0D: ["girl", ""],
|
||||
0x0E: ["hiker/angry man", "hiker"],
|
||||
0x0F: ["foulard woman", "foulard woman"],
|
||||
0x10: ["rich(black-hat) man", "gentleman"],
|
||||
0x11: ["sister", ""],
|
||||
0x12: ["motorbiker", "biker"],
|
||||
0x13: ["sailor", ""],
|
||||
0x14: ["cook", ""],
|
||||
0x15: ["sun-glasses guy (bike seller)", "sunglasses guy"],
|
||||
0x16: ["mr. fuji", ""],
|
||||
0x17: ["giovanni", ""],
|
||||
0x18: ["rocket guy", "rocket grunt"],
|
||||
0x19: ["medium", ""],
|
||||
0x1A: ["waiter", ""],
|
||||
0x1B: ["erika", ""],
|
||||
0x1C: ["mother (geisha)", "mom geisha"],
|
||||
0x1D: ["brunette girl", ""],
|
||||
0x1E: ["lance", ""],
|
||||
0x1F: ["oak's aide/scientist", "oak scientist aide"],
|
||||
0x20: ["oak's aide", "oak aide"],
|
||||
0x21: ["punk", ""],
|
||||
0x22: ["swimmer", ""],
|
||||
0x23: ["white player", ""],
|
||||
0x24: ["gym helper", ""],
|
||||
0x25: ["old (wo)man", "old person"],
|
||||
0x26: ["mart guy", ""],
|
||||
0x27: ["fisher", ""],
|
||||
0x28: ["old woman/medium?", "old medium woman"],
|
||||
0x29: ["nurse", ""],
|
||||
0x2A: ["cable-club woman", "cable club woman"],
|
||||
0x2B: ["Mr. Masterball?", "mr masterball"],
|
||||
0x2C: ["person that gives Lapras", "lapras giver"],
|
||||
0x2D: ["semi-bald fat guy", "balding fat guy"],
|
||||
0x2E: ["black hat white beard man ", ""],
|
||||
0x2F: ["fat man", ""],
|
||||
0x30: ["dojo guy", ""],
|
||||
0x31: ["guard (cop?)", "guard cop"],
|
||||
0x32: ["cop (guard)", "cop guard"],
|
||||
0x33: ["mom", ""],
|
||||
0x34: ["semi-bald man", "balding guy"],
|
||||
0x35: ["young girl", ""],
|
||||
0x36: ["gameboy kid", ""],
|
||||
0x37: ["gameboy kid copy", ""],
|
||||
0x38: ["clefairy-like", "clefairylike"],
|
||||
0x39: ["Agatha", ""],
|
||||
0x3A: ["Bruno", ""],
|
||||
0x3B: ["Lorelei", ""],
|
||||
0x3C: ["seel", ""],
|
||||
0x3D: ["ball", ""],
|
||||
0x3E: ["omanyte", ""],
|
||||
0x3F: ["boulder", ""],
|
||||
0x40: ["paper sheet", ""],
|
||||
0x41: ["book/map/dex", ""],
|
||||
0x42: ["clipboard", ""],
|
||||
0x43: ["snorlax", ""],
|
||||
0x44: ["old amber copy", ""],
|
||||
0x45: ["old amber", ""],
|
||||
0x46: ["lying old man unused 1", ""],
|
||||
0x47: ["lying old man unused 2", ""],
|
||||
0x48: ["lying old man", ""],
|
||||
}
|
||||
|
||||
#somewhat more recent sprite labels
|
||||
sprite_constants = {
|
||||
0x01: "SPRITE_RED",
|
||||
0x02: "SPRITE_BLUE",
|
||||
0x03: "SPRITE_OAK",
|
||||
0x04: "SPRITE_BUG_CATCHER",
|
||||
0x05: "SPRITE_SLOWBRO",
|
||||
0x06: "SPRITE_LASS",
|
||||
0x07: "SPRITE_BLACK_HAIR_BOY_1",
|
||||
0x08: "SPRITE_LITTLE_GIRL",
|
||||
0x09: "SPRITE_BIRD",
|
||||
0x0a: "SPRITE_FAT_BALD_GUY",
|
||||
0x0b: "SPRITE_GAMBLER",
|
||||
0x0c: "SPRITE_BLACK_HAIR_BOY_2",
|
||||
0x0d: "SPRITE_GIRL",
|
||||
0x0e: "SPRITE_HIKER",
|
||||
0x0f: "SPRITE_FOULARD_WOMAN",
|
||||
0x10: "SPRITE_GENTLEMAN",
|
||||
0x11: "SPRITE_DAISY",
|
||||
0x12: "SPRITE_BIKER",
|
||||
0x13: "SPRITE_SAILOR",
|
||||
0x14: "SPRITE_COOK",
|
||||
0x15: "SPRITE_BIKE_SHOP_GUY",
|
||||
0x16: "SPRITE_MR_FUJI",
|
||||
0x17: "SPRITE_GIOVANNI",
|
||||
0x18: "SPRITE_ROCKET",
|
||||
0x19: "SPRITE_MEDIUM",
|
||||
0x1a: "SPRITE_WAITER",
|
||||
0x1b: "SPRITE_ERIKA",
|
||||
0x1c: "SPRITE_MOM_GEISHA",
|
||||
0x1d: "SPRITE_BRUNETTE_GIRL",
|
||||
0x1e: "SPRITE_LANCE",
|
||||
0x1f: "SPRITE_OAK_SCIENTIST_AIDE",
|
||||
0x20: "SPRITE_OAK_AIDE",
|
||||
0x21: "SPRITE_ROCKER",
|
||||
0x22: "SPRITE_SWIMMER",
|
||||
0x23: "SPRITE_WHITE_PLAYER",
|
||||
0x24: "SPRITE_GYM_HELPER",
|
||||
0x25: "SPRITE_OLD_PERSON",
|
||||
0x26: "SPRITE_MART_GUY",
|
||||
0x27: "SPRITE_FISHER",
|
||||
0x28: "SPRITE_OLD_MEDIUM_WOMAN",
|
||||
0x29: "SPRITE_NURSE",
|
||||
0x2a: "SPRITE_CABLE_CLUB_WOMAN",
|
||||
0x2b: "SPRITE_MR_MASTERBALL",
|
||||
0x2c: "SPRITE_LAPRAS_GIVER",
|
||||
0x2d: "SPRITE_WARDEN",
|
||||
0x2e: "SPRITE_SS_CAPTAIN",
|
||||
0x2f: "SPRITE_FISHER2",
|
||||
0x30: "SPRITE_BLACKBELT",
|
||||
0x31: "SPRITE_GUARD",
|
||||
0x32: "SPRITE_____NOT____USED____",
|
||||
0x33: "SPRITE_MOM",
|
||||
0x34: "SPRITE_BALDING_GUY",
|
||||
0x35: "SPRITE_YOUNG_BOY",
|
||||
0x36: "SPRITE_GAMEBOY_KID",
|
||||
0x37: "SPRITE_GAMEBOY_KID_COPY",
|
||||
0x38: "SPRITE_CLEFAIRY",
|
||||
0x39: "SPRITE_AGATHA",
|
||||
0x3a: "SPRITE_BRUNO",
|
||||
0x3b: "SPRITE_LORELEI",
|
||||
0x3c: "SPRITE_SEEL",
|
||||
0x3d: "SPRITE_BALL",
|
||||
0x3e: "SPRITE_OMANYTE",
|
||||
0x3f: "SPRITE_BOULDER",
|
||||
0x40: "SPRITE_PAPER_SHEET",
|
||||
0x41: "SPRITE_BOOK_MAP_DEX",
|
||||
0x42: "SPRITE_CLIPBOARD",
|
||||
0x43: "SPRITE_SNORLAX",
|
||||
0x44: "SPRITE_OLD_AMBER_COPY",
|
||||
0x45: "SPRITE_OLD_AMBER",
|
||||
0x46: "SPRITE_LYING_OLD_MAN_UNUSED_1",
|
||||
0x47: "SPRITE_LYING_OLD_MAN_UNUSED_2",
|
||||
0x48: "SPRITE_LYING_OLD_MAN",
|
||||
}
|
||||
dont_use = [0x32, 0x44, 0x46, 0x47, 0x37]
|
||||
#sprites after 0x23 have only one image
|
||||
#SPRITE_BIKE_SHOP_GUY only has 1
|
||||
|
||||
icons = {}
|
||||
unique_icons = set()
|
||||
todo_sprites = {}
|
||||
sprites = {}
|
||||
|
||||
def load_icons():
|
||||
for map_id in map_headers:
|
||||
if map_id in [0x0b, 0x45, 0x4b, 0x4e, 0x69, 0x6a, 0x6b, 0x6d, 0x6e, 0x6f, 0x70, 0x72, 0x73, 0x74, 0x75, 0xad, 0xcc, 0xcd, 0xce, 0xe7, 0xed, 0xee, 0xf1, 0xf2, 0xf3, 0xf4]: continue #skip
|
||||
map = map_headers[map_id]
|
||||
for thing_id in map["object_data"]["things"]:
|
||||
thing = map["object_data"]["things"][thing_id]
|
||||
pic = thing["picture_number"]
|
||||
unique_icons.add(pic)
|
||||
|
||||
if not icons.has_key(pic): icons[pic] = []
|
||||
|
||||
alerter = None
|
||||
if int(thing["y"])-4 > int(map["y"], 16)*2: alerter = True
|
||||
if int(thing["x"])-4 > int(map["x"], 16)*2: alerter = True
|
||||
|
||||
icons[pic].append((map["name"] + " (id=" + str(map["id"]) + ")", thing["y"], thing["x"], alerter))
|
||||
|
||||
def print_appearances():
|
||||
"""print appearances of each icon
|
||||
see: http://diyhpl.us/~bryan/irc/pokered/sprite_appearances.txt
|
||||
"""
|
||||
output = ""
|
||||
for icon_id in icons:
|
||||
icon = icons[icon_id]
|
||||
|
||||
possible_name = ""
|
||||
if icon_id in initial_icon_constants.keys():
|
||||
possible_name = " (sawakita suggests: " + initial_icon_constants[icon_id][0] + ")"
|
||||
|
||||
output += "sprite " + hex(icon_id) + possible_name + ":\n"
|
||||
for appearance in icon:
|
||||
if appearance[3] != None: outside_alert = " !! OUTSIDE BOUNDS"
|
||||
else: outside_alert = ""
|
||||
output += spacing + ".. in " + appearance[0] + " at (" + str(appearance[1]) + ", " + str(appearance[2]) + ")" + outside_alert + "\n"
|
||||
output += "\n"
|
||||
|
||||
print output
|
||||
|
||||
def insert_todo_sprites():
|
||||
load_icons()
|
||||
counter = 1
|
||||
for icon in unique_icons:
|
||||
if icon not in initial_icon_constants:
|
||||
todo_sprites[icon] = counter
|
||||
initial_icon_constants[icon] = None
|
||||
counter += 1
|
||||
|
||||
def sprite_name_cleaner(badname):
|
||||
output = "SPRITE_" + badname
|
||||
output = output.replace(" ", "_")
|
||||
output = output.replace("/", "_")
|
||||
output = output.replace(".", "")
|
||||
|
||||
output = output.upper()
|
||||
|
||||
while output[-1] == "_":
|
||||
output = output[:-1]
|
||||
return output
|
||||
|
||||
def sprite_namer():
|
||||
"makes up better constant names for each sprite"
|
||||
insert_todo_sprites()
|
||||
|
||||
for sprite_id in initial_icon_constants:
|
||||
suggestions = initial_icon_constants[sprite_id]
|
||||
if suggestions == None:
|
||||
sprites[sprite_id] = "SPRITE_TODO_" + str(todo_sprites[sprite_id])
|
||||
continue #next please
|
||||
|
||||
original = suggestions[0]
|
||||
if suggestions[1] != "": original = suggestions[1]
|
||||
|
||||
result = sprite_name_cleaner(original)
|
||||
sprites[sprite_id] = result
|
||||
|
||||
def sprite_printer():
|
||||
"""prints out a list of sprite constants to put into constants.asm
|
||||
it's deprecated- use the names from the current file instead."""
|
||||
for key in sprites:
|
||||
line_length = len(sprites[key]) + len(" EQU $") + 2
|
||||
|
||||
if line_length < 40:
|
||||
extra = (40 - line_length) * " "
|
||||
else: extra = ""
|
||||
|
||||
value = hex(key)[2:]
|
||||
if len(value) == 1: value = "0" + value
|
||||
|
||||
print sprites[key] + extra + " EQU $" + value
|
||||
|
||||
def parse_sprite_sheet_pointer_table():
|
||||
"""parses the bytes making up the pointer table
|
||||
first two bytes are the pointer
|
||||
third byte is the number of bytes (1 * 4 tiles * 16 bytes each, or 3 * 4 tiles * 16 bytes per tile)
|
||||
1 = 1 pose
|
||||
3 = 3 poses, possibly 6 immediately after
|
||||
$C0 or $40
|
||||
fourth byte is the rom bank
|
||||
|
||||
so a quick estimation is that, if it has 3, and there's no other pointer that points to the one after the 3rd & next 3, then assume those next 3 are the 4th, 5th and 6th
|
||||
"""
|
||||
rom = extract_maps.rom
|
||||
ptable_address = 0x17b27 #5:7b27
|
||||
ptable_pointers = []
|
||||
ptable_sheet_data = {}
|
||||
|
||||
#load up pointers please
|
||||
for sprite_id in sprite_constants.keys():
|
||||
pointer_offset = 0x17b27 + ((sprite_id -1) * 4)
|
||||
pointer_byte1 = ord(rom[pointer_offset])
|
||||
pointer_byte2 = ord(rom[pointer_offset+1])
|
||||
partial_pointer = (pointer_byte1 + (pointer_byte2 << 8))
|
||||
bank = ord(rom[pointer_offset+3])
|
||||
pointer = extract_maps.calculate_pointer(partial_pointer, bank)
|
||||
ptable_pointers.append(pointer)
|
||||
|
||||
#72 sprite pointers, we're not using id=$32
|
||||
for sprite_id in sprite_constants.keys():
|
||||
sprite_name = sprite_constants[sprite_id]
|
||||
|
||||
#some basic information about this sprite first
|
||||
data_entry = {"sprite_id": sprite_id, "sprite_name": sprite_name}
|
||||
|
||||
#calculate where it is in the 0x17b27 pointer table
|
||||
pointer_offset = 0x17b27 + ((sprite_id -1) * 4)
|
||||
data_entry["sprite_ptr_table_entry_address"] = pointer_offset
|
||||
|
||||
#actual sprite pointer
|
||||
pointer_byte1 = ord(rom[pointer_offset])
|
||||
pointer_byte2 = ord(rom[pointer_offset+1])
|
||||
partial_pointer = (pointer_byte1 + (pointer_byte2 << 8))
|
||||
bank = ord(rom[pointer_offset+3])
|
||||
pointer = extract_maps.calculate_pointer(partial_pointer, bank)
|
||||
data_entry["pointer"] = pointer
|
||||
data_entry["bank"] = bank
|
||||
|
||||
byte_count = ord(rom[pointer_offset+2])
|
||||
data_entry["byte_count"] = byte_count
|
||||
|
||||
has_more_text = ""
|
||||
data_entry["poses"] = 1
|
||||
if byte_count == 0xc0: #has at least 3 poses
|
||||
setter1, setter2, setter3 = False, False, False
|
||||
data_entry["poses"] = 3
|
||||
#let's check if there's possibly more
|
||||
if not ((byte_count + pointer) in ptable_pointers): #yep, probably (#4)
|
||||
data_entry["poses"] += 1
|
||||
data_entry["byte_count"] += 64
|
||||
setter1 = True
|
||||
if setter1 and not ((byte_count + pointer + 64) in ptable_pointers): #has another (#5)
|
||||
data_entry["poses"] += 1
|
||||
data_entry["byte_count"] += 64
|
||||
setter2 = True
|
||||
if setter2 and not ((byte_count + pointer + 64 + 64) in ptable_pointers): #has a #6
|
||||
data_entry["poses"] += 1
|
||||
data_entry["byte_count"] += 64
|
||||
setter3 = True
|
||||
|
||||
print ("$%.2x " % (sprite_id)) + sprite_name + " has $%.2x bytes" % (byte_count) + " pointing to 0x%.x" % (pointer) + " bank is $%.2x" % (bank) + " with pose_count=" + str(data_entry["poses"])
|
||||
|
||||
ptable_sheet_data[sprite_id] = data_entry
|
||||
return ptable_sheet_data
|
||||
|
||||
def pretty_print_sheet_incbins(ptable_sheet_data):
|
||||
"""make things look less awful"""
|
||||
output = ""
|
||||
used_addresses = []
|
||||
|
||||
for sheet_id in ptable_sheet_data:
|
||||
sheet_data = ptable_sheet_data[sheet_id]
|
||||
name = sheet_data["sprite_name"].split("SPRITE_")[1].lower().title()
|
||||
clean_name = name.replace("_", "")
|
||||
address = sheet_data["pointer"]
|
||||
byte_count = sheet_data["byte_count"]
|
||||
|
||||
#if not (0x10000 <= address <= 0x12e7f): continue #skip
|
||||
#if not (0x14180 <= address <= 0x17840): continue #skip
|
||||
if address in used_addresses: continue #skip
|
||||
used_addresses.append(address)
|
||||
|
||||
output += clean_name + "Sprite: ; 0x%.x" % (address) + "\n"
|
||||
#output += spacing + "INCBIN \"baserom.gbc\",$%.x,$%.x - $%.x" % (address, address + byte_count, address) + "\n"
|
||||
output += spacing + "INCBIN \"gfx/sprites/" + name.lower() + ".2bpp\" ; was $%.x" % (address) + "\n"
|
||||
|
||||
filename = "../gfx/sprites/" + name.lower() + ".2bpp"
|
||||
#fh = open(filename, "w")
|
||||
#fh.write(extract_maps.rom[address : address + byte_count])
|
||||
#fh.close()
|
||||
|
||||
return output
|
||||
|
||||
def pretty_print_sheet_data(ptable_sheet_data):
|
||||
"""make the pointer table not suck so much"""
|
||||
output = "SpriteSheetPointerTable: ; 0x17b27\n"
|
||||
used_addresses = []
|
||||
|
||||
for sheet_id in ptable_sheet_data:
|
||||
sheet_data = ptable_sheet_data[sheet_id]
|
||||
address = sheet_data["pointer"]
|
||||
checker = False
|
||||
for x in used_addresses:
|
||||
if not checker and x[0] == address:
|
||||
checker = True
|
||||
clean_name = x[1]
|
||||
|
||||
if not checker:
|
||||
name = sheet_data["sprite_name"].split("SPRITE_")[1].lower().title()
|
||||
clean_name = name.replace("_", "")
|
||||
clean_name += "Sprite"
|
||||
|
||||
byte_count = sheet_data["byte_count"]
|
||||
if byte_count > 0x40:
|
||||
byte_count = 0xc0
|
||||
|
||||
output += "\n\t; " + sprite_constants[sheet_data["sprite_id"]] + "\n"
|
||||
output += spacing + "dw " + clean_name + "\n"
|
||||
output += spacing + "db $%.2x ; byte count\n" % (byte_count)
|
||||
output += spacing + "db BANK(" + clean_name + ")\n"
|
||||
|
||||
used_addresses.append((address, clean_name))
|
||||
|
||||
output += "; 0x17c47"
|
||||
return output
|
||||
|
||||
if __name__ == "__main__":
|
||||
extract_maps.load_rom()
|
||||
#extract_maps.load_map_pointers()
|
||||
#extract_maps.read_all_map_headers()
|
||||
|
||||
#sprite_namer()
|
||||
#load_icons()
|
||||
#print_appearances()
|
||||
#sprite_printer()
|
||||
|
||||
ptable_sheet_data = parse_sprite_sheet_pointer_table()
|
||||
print pretty_print_sheet_incbins(ptable_sheet_data)
|
||||
print pretty_print_sheet_data(ptable_sheet_data)
|
@ -1,55 +0,0 @@
|
||||
#author: Bryan Bishop <kanzure@gmail.com>
|
||||
#date: 2012-01-03
|
||||
#utilities for working with text pointers
|
||||
import extract_maps #rom, assert_rom, load_rom, calculate_pointer, load_map_pointers, read_all_map_headers, map_headers
|
||||
from pretty_map_headers import map_name_cleaner
|
||||
#import analyze_incbins #asm, offset_to_pointer, find_incbin_to_replace_for, split_incbin_line_into_three, generate_diff_insert, load_asm, isolate_incbins, process_incbins
|
||||
spacing = " "
|
||||
|
||||
def test_first_text_pointer_bytes(range=20): #30 for viridian city, 34 for cerulean city, 36 for celadon, 48 for fuchsia city, 50 for safron
|
||||
"""
|
||||
does the first text pointer byte always point to (end address of text pointer list) + 1?
|
||||
|
||||
range determines how far is acceptable.
|
||||
r=15 means 30 text pointers
|
||||
"""
|
||||
|
||||
for map_id in extract_maps.map_headers:
|
||||
map = extract_maps.map_headers[map_id]
|
||||
bank = int(map["bank"],16)
|
||||
text_list_pointer = int(map["texts_pointer"], 16)
|
||||
|
||||
bad_names = ["FREEZE", "COPY: Cinnibar Mart", "COPY OF: Underground Tunnel Entrance (Route 6)", "COPY OF: Trashed House", "COPY OF: Underground Path Entrance (Route 7)"]
|
||||
if map["name"] in bad_names: continue
|
||||
|
||||
#extract the bytes making up the first text pointer
|
||||
pointer_byte1 = ord(extract_maps.rom[text_list_pointer])
|
||||
pointer_byte2 = ord(extract_maps.rom[text_list_pointer+1])
|
||||
|
||||
#swap the bytes
|
||||
temp = pointer_byte1
|
||||
pointer_byte1 = pointer_byte2
|
||||
pointer_byte2 = temp
|
||||
del temp
|
||||
|
||||
#combine these into a single pointer
|
||||
partial_pointer = (pointer_byte2 + (pointer_byte1 << 8))
|
||||
|
||||
#get the full pointer
|
||||
first_text_pointer = extract_maps.calculate_pointer(partial_pointer, bank)
|
||||
|
||||
#if (first_text_pointer <= (text_list_pointer+range)):
|
||||
print "map " + map["name"] + " (" + str(map["id"]) + ")"
|
||||
print spacing + "text_pointer (list) = " + hex(text_list_pointer)
|
||||
print spacing + "first_text_pointer (first text) = " + hex(first_text_pointer)
|
||||
print spacing + "difference = " + str(first_text_pointer - text_list_pointer)
|
||||
#return False
|
||||
|
||||
return True
|
||||
|
||||
if __name__ == "__main__":
|
||||
extract_maps.load_rom()
|
||||
extract_maps.load_map_pointers()
|
||||
extract_maps.read_all_map_headers()
|
||||
|
||||
print test_first_text_pointer_bytes()
|
@ -1,4 +1,4 @@
|
||||
_RED EQU 0
|
||||
_BLUE EQU 1
|
||||
INCLUDE "wram.asm"
|
||||
INCLUDE "main.tx"
|
||||
INCLUDE "main.asm"
|
||||
|
@ -1,4 +1,4 @@
|
||||
_RED EQU 1
|
||||
_BLUE EQU 0
|
||||
INCLUDE "wram.asm"
|
||||
INCLUDE "main.tx"
|
||||
INCLUDE "main.asm"
|
||||
|
82
textpre.py
82
textpre.py
@ -1,5 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import extras.pokemontools.preprocessor as preprocessor
|
||||
|
||||
import sys
|
||||
|
||||
chars = {
|
||||
@ -254,81 +256,11 @@ chars = {
|
||||
"6": 0xFC,
|
||||
"7": 0xFD,
|
||||
"8": 0xFE,
|
||||
"9": 0xFF
|
||||
|
||||
"9": 0xFF,
|
||||
}
|
||||
|
||||
for l in sys.stdin:
|
||||
preprocessor.chars = chars
|
||||
|
||||
# strip comments
|
||||
line = l.partition(";")
|
||||
i = 0
|
||||
asm = ""
|
||||
while i < len(line) and l[0] != ";":
|
||||
asm = asm + line[i]
|
||||
i = i + 1
|
||||
|
||||
# skip asm with no quotes
|
||||
if "\"" not in asm:
|
||||
sys.stdout.write(l)
|
||||
continue
|
||||
|
||||
# split by quotes
|
||||
asms = asm.split("\"")
|
||||
|
||||
# skip asm that actually does use ASCII in quotes
|
||||
lowasm = asms[0].lower()
|
||||
if "section" in lowasm \
|
||||
or "include" in lowasm \
|
||||
or "incbin" in lowasm:
|
||||
sys.stdout.write(l)
|
||||
continue
|
||||
|
||||
even = False
|
||||
i = 0
|
||||
for token in asms:
|
||||
i = i + 1
|
||||
if even:
|
||||
# token is a string to convert to byte values
|
||||
|
||||
while len(token):
|
||||
# read a single UTF-8 codepoint
|
||||
char = token[0]
|
||||
if ord(char) >= 0xFC:
|
||||
char = char + token[1:6]
|
||||
token = token[6:]
|
||||
elif ord(char) >= 0xF8:
|
||||
char = char + token[1:5]
|
||||
token = token[5:]
|
||||
elif ord(char) >= 0xF0:
|
||||
char = char + token[1:4]
|
||||
token = token[4:]
|
||||
elif ord(char) >= 0xE0:
|
||||
char = char + token[1:3]
|
||||
token = token[3:]
|
||||
elif ord(char) >= 0xC0:
|
||||
char = char + token[1:2]
|
||||
token = token[2:]
|
||||
else:
|
||||
token = token[1:]
|
||||
|
||||
# certain apostrophe-letter pairs are only a single byte
|
||||
if char == "'" and \
|
||||
(token[0] == "d" or \
|
||||
token[0] == "l" or \
|
||||
token[0] == "m" or \
|
||||
token[0] == "r" or \
|
||||
token[0] == "s" or \
|
||||
token[0] == "t" or \
|
||||
token[0] == "v"):
|
||||
char = char + token[0]
|
||||
token = token[1:]
|
||||
|
||||
sys.stdout.write("${0:02X}".format(chars[char]))
|
||||
|
||||
if len(token):
|
||||
sys.stdout.write(", ")
|
||||
|
||||
else:
|
||||
sys.stdout.write(token)
|
||||
even = not even
|
||||
macros = []
|
||||
macro_table = preprocessor.make_macro_table(macros)
|
||||
preprocessor.preprocess(macro_table)
|
||||
|
Loading…
Reference in New Issue
Block a user