summaryrefslogtreecommitdiff
path: root/pokemontools/disassemble_map_scripts.py
blob: f51fb926c717f16f204275dc6f775bcc0bbe93da (plain)
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
# -*- 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
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)