mirror of
https://gitlab.com/xCrystal/pokecrystal-board.git
synced 2024-11-16 11:27:33 -08:00
152 lines
4.7 KiB
Python
152 lines
4.7 KiB
Python
|
# -*- encoding: utf-8 -*-
|
||
|
"""
|
||
|
Dump out asm for scripting things in bank $25. This script will modify main.asm
|
||
|
and insert all scripting commands.
|
||
|
"""
|
||
|
|
||
|
import crystal
|
||
|
from gbz80disasm import output_bank_opcodes
|
||
|
|
||
|
rom = crystal.load_rom()
|
||
|
roml = [ord(x) for x in rom]
|
||
|
|
||
|
script_command_table_address = 0x96cb1
|
||
|
script_command_count = 170
|
||
|
|
||
|
# a list of addresses for each script command
|
||
|
command_pointers = [crystal.calculate_pointer_from_bytes_at(script_command_table_address + (id * 2), bank=0x25) for id in range(0, 170)]
|
||
|
|
||
|
# a list of hex addresses for each script command in bank $25
|
||
|
command_pointers_hex = ["$%.2x" % (x % 0x4000 + 0x4000) for x in command_pointers]
|
||
|
|
||
|
commands = {}
|
||
|
|
||
|
# force data into a more usable form
|
||
|
for command in crystal.command_classes:
|
||
|
name = "Script_" + command.macro_name
|
||
|
id = command.id
|
||
|
params = {}
|
||
|
|
||
|
for (id2, param_type) in command.param_types.items():
|
||
|
param = {
|
||
|
"name": param_type["name"],
|
||
|
"type": param_type["class"].__name__,
|
||
|
}
|
||
|
params[id2] = param
|
||
|
|
||
|
if id <= 0xa9:
|
||
|
commands[id] = {
|
||
|
"name": name,
|
||
|
"params": params,
|
||
|
"address": command_pointers[id],
|
||
|
}
|
||
|
|
||
|
avoid = [
|
||
|
0x974b0,
|
||
|
0x974be,
|
||
|
0x9754b,
|
||
|
0x97556,
|
||
|
0x97562,
|
||
|
0x9756e,
|
||
|
0x97540,
|
||
|
|
||
|
0x96f8e, # verbosegiveitem2
|
||
|
]
|
||
|
|
||
|
class DisassembledScriptCommand():
|
||
|
"""
|
||
|
Just a temporary object to store information about a script command's asm.
|
||
|
This is used by some of the infrastructure in crystal.py to automatically
|
||
|
insert asm into main.asm, rather than having someone do it manually.
|
||
|
"""
|
||
|
dependencies = None
|
||
|
|
||
|
def __init__(self, label=None, id=None, address=None, params=None):
|
||
|
self.id = id
|
||
|
self.label = crystal.Label(name=label, address=address, object=self)
|
||
|
self.address = address
|
||
|
self.params = params
|
||
|
|
||
|
max_byte_count = 0x4000
|
||
|
|
||
|
# Some of these scripts need to be truncated before insertion, because
|
||
|
# output_bank_opcodes doesn't know anything about stopping if some of
|
||
|
# the local labels are not resolved yet.
|
||
|
|
||
|
# Script_if_equal
|
||
|
if address == 0x97540:
|
||
|
max_byte_count = 86
|
||
|
|
||
|
# disassemble and laso get the last address
|
||
|
(asm, last_address, last_hl_address, last_a_address, used_3d97) = output_bank_opcodes(address, max_byte_count=max_byte_count, stop_at=command_pointers, include_last_address=False)
|
||
|
|
||
|
# remove indentation
|
||
|
asm = asm.replace("\n\t", "\n")
|
||
|
if asm[0] == "\t":
|
||
|
asm = asm[1:]
|
||
|
|
||
|
# remove the last two newlines
|
||
|
while asm[-1] == "\n":
|
||
|
asm = asm[:-1]
|
||
|
|
||
|
self.asm = asm
|
||
|
self.last_address = last_address
|
||
|
|
||
|
# make sure this gets dumped into main.asm
|
||
|
#if crystal.script_parse_table[self.address] == None and crystal.script_parse_table[self.last_address] == None:
|
||
|
crystal.script_parse_table[self.address : self.last_address] = self
|
||
|
#else:
|
||
|
# print ".. hm, something is already at " + hex(self.address) + " for " + self.label.name
|
||
|
|
||
|
def to_asm(self):
|
||
|
#output += self.label + ": ; " + hex(self.address) + "\n"
|
||
|
output = "; script command " + hex(self.id) + "\n"
|
||
|
if len(self.params) > 0:
|
||
|
output += "; parameters:\n"
|
||
|
for (id2, param) in self.params.items():
|
||
|
output += "; " + param["name"] + " (" + param["type"] + ")\n"
|
||
|
output += "\n"
|
||
|
output += self.asm
|
||
|
return output
|
||
|
|
||
|
def get_dependencies(*args, **kwargs):
|
||
|
return []
|
||
|
|
||
|
# make instances of DisassembledScriptCommand
|
||
|
for (id, command) in commands.items():
|
||
|
name = command["name"]
|
||
|
params = command["params"]
|
||
|
address = command["address"]
|
||
|
|
||
|
script_asm = DisassembledScriptCommand(label=name, id=id, address=address, params=params)
|
||
|
#print script_asm.to_asm()
|
||
|
#print crystal.to_asm(script_asm, use_asm_rules=True)
|
||
|
|
||
|
class ScriptCommandTable():
|
||
|
address = script_command_table_address
|
||
|
last_address = script_command_table_address + (2 * 170)
|
||
|
dependencies = None
|
||
|
|
||
|
def __init__(self):
|
||
|
self.label = crystal.Label(name="ScriptCommandTable", address=self.address, object=self)
|
||
|
|
||
|
# make sure this gets dumped into main.asm
|
||
|
crystal.script_parse_table[self.address : self.last_address] = self
|
||
|
|
||
|
def get_dependencies(*args, **kwargs):
|
||
|
return []
|
||
|
|
||
|
def to_asm(self):
|
||
|
output = ""
|
||
|
for (id, command) in commands.items():
|
||
|
output += "dw " + command["name"] + "; " + hex(command["address"]) + "\n"
|
||
|
if output[-1] == "\n":
|
||
|
output = output[:-1]
|
||
|
return output
|
||
|
script_command_table = ScriptCommandTable()
|
||
|
#print crystal.to_asm(script_command_table, use_asm_rules=True)
|
||
|
|
||
|
# automatic asm insertion
|
||
|
asm = crystal.Asm()
|
||
|
asm.insert_and_dump(limit=500)
|