1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
# -*- encoding: utf-8 -*-
"""
Dump out asm for scripting things in bank $25. This script will modify main.asm
and insert all scripting commands.
"""
from __future__ import absolute_import
from . import crystal
from . import gbz80disasm
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) = gbz80disasm.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)
|