more command classes

This commit is contained in:
Bryan Bishop 2012-03-27 02:01:04 -05:00
parent 2a22a91cbb
commit bcd9794cb5

View File

@ -3,6 +3,7 @@
import sys, os, inspect, md5, json import sys, os, inspect, md5, json
from copy import copy, deepcopy from copy import copy, deepcopy
import subprocess import subprocess
from new import classobj
#for IntervalMap #for IntervalMap
from bisect import bisect_left, bisect_right from bisect import bisect_left, bisect_right
@ -2055,100 +2056,6 @@ pksv_crystal_unknowns = [
0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
] ]
class Command():
def __init__(self, address=None):
raise Exception, "i don't think anything actually calls this?"
self.params = {}
if not is_valid_address(address):
raise Exception, "address is invalid"
self.address = address
def to_asm(self):
#start with the rgbasm macro name for this command
output = self.macro_name
#return if there are no params
if len(self.param_types.keys()) == 0: return output
#first one will have no prefixing comma
first = True
#start reading the bytes after the command byte
current_address = self.address+1
#add each param
for param in self.params:
name = param.name
#the first param shouldn't have ", " prefixed
if first: first = False
#but all other params should
else: output += ", "
#now add the asm-compatible param string
output += obj.to_asm()
current_address += obj.size
#for param_type in self.param_types:
# name = param_type["name"]
# klass = param_type["klass"]
# #create an instance of this type
# #tell it to begin parsing at this latest byte
# obj = klass(address=current_address)
# #the first param shouldn't have ", " prefixed
# if first: first = False
# #but all other params should
# else: output += ", "
# #now add the asm-compatible param string
# output += obj.to_asm()
# current_address += obj.size
return output
def parse(self):
#id, size (inclusive), param_types
#param_type = {"name": each[1], "class": each[0]}
self.params = {}
current_address = self.address+1
byte = int(rom[self.address])
if not byte == self.id:
raise Exception, "this should never happen"
i = 0
for (key, param_type) in self.param_types.items():
name = param_type["name"]
klass = param_type["class"]
#make an instance of this class, like SingleByteParam()
#or ItemLabelByte.. by making an instance, obj.parse() is called
obj = klass(address=current_address, name=name)
#save this for later
self.params[i] = obj
#increment our counters
current_address += obj.size
i += 1
return True
class GivePoke(Command):
id = 0x2D
size = 4 #minimum
param_types = {
0: {"name": "pokemon", "class": PokemonParam},
1: {"name": "level", "class": SingleByteParam},
2: {"name": "item", "class": ItemLabelByte},
3: {"name": "trainer", "class": SingleByteParam},
4: {"name": "trainer_name_pointer", "class": MultiByteParam}, #should probably use TextLabelParam
5: {"name": "pkmn_nickname", "class": MultiByteParam}, #XXX TextLabelParam ?
]
def parse(self):
self.params = {}
byte = int(rom[self.address])
if not byte == self.id:
raise Exception, "this should never happen"
current_address = self.address+1
i = 0
for (key, param_type) in self.param_types.items():
#stop executing after the 4th byte unless it == 0x1
if i == 4 and self.params[-1].byte != 1: break
name = param_type["name"]
klass = param_type["class"]
#make an instance of this class, like SingleByteParam()
#or ItemLabelByte.. by making an instance, obj.parse() is called
obj = klass(address=current_address, name=name)
#save this for later
self.params[i] = obj
#increment our counters
current_address += obj.size
i += 1
return True
class SingleByteParam(): class SingleByteParam():
"""or SingleByte(CommandParam)""" """or SingleByte(CommandParam)"""
size = 1 size = 1
@ -2158,7 +2065,7 @@ class SingleByteParam():
setattr(self, key, value) setattr(self, key, value)
#check address #check address
if not hasattr(self, "address"): if not hasattr(self, "address"):
raise Exception, "an address is a requirement") raise Exception, "an address is a requirement"
elif self.address == None: elif self.address == None:
raise Exception, "address must not be None" raise Exception, "address must not be None"
elif not is_valid_address(self.address): elif not is_valid_address(self.address):
@ -2182,7 +2089,7 @@ class ItemLabelByte(DollarSignByte):
label = find_item_label_by_id(self.byte) label = find_item_label_by_id(self.byte)
if label: return label if label: return label
elif not label: return DollarSignByte.to_asm(self) elif not label: return DollarSignByte.to_asm(self)
class DecimalByte(SingleByteParam): class DecimalParam(SingleByteParam):
should_be_decimal = True should_be_decimal = True
class MultiByteParam(): class MultiByteParam():
@ -2195,7 +2102,7 @@ class MultiByteParam():
setattr(self, key, value) setattr(self, key, value)
#check address #check address
if not hasattr(self, "address") or self.address == None: if not hasattr(self, "address") or self.address == None:
raise Exception, "an address is a requirement") raise Exception, "an address is a requirement"
elif not is_valid_address(self.address): elif not is_valid_address(self.address):
raise Exception, "address must be valid" raise Exception, "address must be valid"
#check size #check size
@ -2273,7 +2180,7 @@ def _parse_script_pointer_bytes(self):
PointerLabelParam.parse(self) PointerLabelParam.parse(self)
address = calculate_pointer_from_bytes_at(self.address, bank=self.bank) address = calculate_pointer_from_bytes_at(self.address, bank=self.bank)
self.script = parse_script_engine_script_at(address) self.script = parse_script_engine_script_at(address)
ScriptPointerLabelParam = _parse_script_pointer_bytes ScriptPointerLabelParam.parse = _parse_script_pointer_bytes
ScriptPointerLabelBeforeBank.parse = _parse_script_pointer_bytes ScriptPointerLabelBeforeBank.parse = _parse_script_pointer_bytes
ScriptPointerLabelAfterBank.parse = _parse_script_pointer_bytes ScriptPointerLabelAfterBank.parse = _parse_script_pointer_bytes
class PointerLabelToScriptPointer(PointerLabelParam): class PointerLabelToScriptPointer(PointerLabelParam):
@ -2340,15 +2247,30 @@ class PokemonParam(SingleByteParam):
if pokemon_constant: return pokemon_constant if pokemon_constant: return pokemon_constant
else: return str(self.byte) else: return str(self.byte)
class PointerParamToItemAndLetter(MultiByteParam): class PointerParamToItemAndLetter(MultiByteParam):
raise NotImplementedError, bryan_message
#[2F][2byte pointer to item no + 0x20 bytes letter text] #[2F][2byte pointer to item no + 0x20 bytes letter text]
#raise NotImplementedError, bryan_message
pass
class TrainerIdParam(SingleByteParam): class TrainerIdParam(SingleByteParam):
raise NotImplementedError, bryan_message #raise NotImplementedError, bryan_message
pass
class TrainerGroupParam(SingleByteParam): class TrainerGroupParam(SingleByteParam):
raise NotImplementedError, bryan_message #raise NotImplementedError, bryan_message
pass
SingleByteParam, HexByte, DollarSignByte, ItemLabelByte class MenuDataPointerParam(PointerLabelParam):
PointerLabelParam, PointerLabelBeforeBank, PointerLabelAfterBank #read menu data at the target site
#raise NotImplementedError, bryan_message
pass
class RawTextPointerLabelParam(PointerLabelParam):
#is this to raw text? or to a text script?
#raise NotImplementedError, bryan_message
pass
class TextPointerLabelParam(PointerLabelParam):
#definitely points to a text script
pass
class MovementPointerLabelParam(PointerLabelParam):
pass
class MapDataPointerParam(PointerLabelParam):
pass
#byte: [name, [param1 name, param1 type], [param2 name, param2 type], ...] #byte: [name, [param1 name, param1 type], [param2 name, param2 type], ...]
#0x9E: ["verbosegiveitem", ["item", ItemLabelByte], ["quantity", SingleByteParam]], #0x9E: ["verbosegiveitem", ["item", ItemLabelByte], ["quantity", SingleByteParam]],
@ -2400,7 +2322,7 @@ pksv_crystal_more = {
0x2B: ["checktime", ["time", SingleByteParam]], 0x2B: ["checktime", ["time", SingleByteParam]],
0x2C: ["checkpoke", ["pkmn", PokemonParam]], 0x2C: ["checkpoke", ["pkmn", PokemonParam]],
#0x2D: ["givepoke", ], .... see GivePoke class #0x2D: ["givepoke", ], .... see GivePoke class
0x2E: ["giveegg", ["pkmn", PokemonParam], ["level", DecimalByte]], 0x2E: ["giveegg", ["pkmn", PokemonParam], ["level", DecimalParam]],
0x2F: ["givepokeitem", ["pointer", PointerParamToItemAndLetter]], 0x2F: ["givepokeitem", ["pointer", PointerParamToItemAndLetter]],
0x30: ["checkpokeitem", ["pointer", PointerParamToItemAndLetter]], #not pksv 0x30: ["checkpokeitem", ["pointer", PointerParamToItemAndLetter]], #not pksv
0x31: ["checkbit1", ["bit_number", SingleByteParam]], 0x31: ["checkbit1", ["bit_number", SingleByteParam]],
@ -2422,94 +2344,207 @@ pksv_crystal_more = {
0x41: ["itemtotext", ["item", ItemLabelByte], ["memory", SingleByteParam]], 0x41: ["itemtotext", ["item", ItemLabelByte], ["memory", SingleByteParam]],
0x42: ["mapnametotext", ["memory", SingleByteParam]], #not pksv 0x42: ["mapnametotext", ["memory", SingleByteParam]], #not pksv
0x43: ["trainertotext", ["trainer_id", TrainerIdParam], ["trainer_group", TrainerGroupParam], ["memory", SingleByteParam]], 0x43: ["trainertotext", ["trainer_id", TrainerIdParam], ["trainer_group", TrainerGroupParam], ["memory", SingleByteParam]],
0x44: ["stringtotext", ], 0x44: ["stringtotext", ["text_pointer", RawTextPointerLabelParam], ["memory", SingleByteParam]],
0x45: ["itemnotify", ], 0x45: ["itemnotify"],
0x46: ["pocketisfull", ], 0x46: ["pocketisfull"],
0x47: ["loadfont", ], 0x47: ["loadfont"],
0x48: ["refreshscreen", ], 0x48: ["refreshscreen", ["dummy", SingleByteParam]],
0x49: ["loadmovesprites", ], 0x49: ["loadmovesprites"],
0x4B: ["3writetext", ], 0x4A: ["loadbytec1ce", ["byte", SingleByteParam]], #not pksv
0x4C: ["2writetext", ], 0x4B: ["3writetext", ["text_pointer", PointerLabelBeforeBank]],
0x4E: ["yesorno", ], 0x4C: ["2writetext", ["text_pointer", RawTextPointerLabelParam]], #XXX - is this to a text script, or raw text?
0x4F: ["loadmenudata", ], 0x4D: ["repeattext", ["byte", SingleByteParam], ["byte", SingleByteParam]], #not pksv
0x50: ["writebackup", ], 0x4E: ["yesorno"],
0x51: ["jumptextfaceplayer", ], 0x4F: ["loadmenudata", ["data", MenuDataPointerParam]],
0x53: ["jumptext", ], 0x50: ["writebackup"],
0x54: ["closetext", ], #XXX test123
0x55: ["keeptextopen", ], 0x51: ["jumptextfaceplayer", ["text_pointer", RawTextPointerLabelParam]],
0x56: ["pokepic", ], 0x53: ["jumptext", ["text_pointer", TextPointerLabelParam]],
0x57: ["pokepicyesorno", ], 0x54: ["closetext"],
0x58: ["interpretmenu", ], 0x55: ["keeptextopen"],
0x59: ["interpretmenu2", ], 0x56: ["pokepic", ["pokemon", PokemonParam]],
0x5D: ["loadpokedata", ], 0x57: ["pokepicyesorno"],
0x5E: ["loadtrainer", ], 0x58: ["interpretmenu"],
0x5F: ["startbattle", ], 0x59: ["interpretmenu2"],
0x60: ["returnafterbattle", ], #not pksv
0x61: ["catchtutorial", ], 0x5A: ["loadpikachudata"],
0x64: ["winlosstext", ], 0x5B: ["battlecheck"],
0x66: ["talkaftercancel", ], 0x5C: ["loadtrainerdata"],
0x68: ["setlasttalked", ], #back to pksv..
0x69: ["applymovement", ], 0x5D: ["loadpokedata", ["pokemon", PokemonParam], ["level", DecimalParam]],
0x6B: ["faceplayer", ], 0x5E: ["loadtrainer", ["trainer_group", TrainerGroupParam], ["trainer_id", TrainerIdParam]],
0x6C: ["faceperson", ], 0x5F: ["startbattle"],
0x6D: ["variablesprite", ], 0x60: ["returnafterbattle"],
0x6E: ["disappear", ], 0x61: ["catchtutorial", ["byte", SingleByteParam]],
0x6F: ["appear", ], #not pksv
0x70: ["follow", ], 0x62: ["trainertext", ["which_text", SingleByteParam]],
0x71: ["stopfollow", ], 0x63: ["trainerstatus", ["action", SingleByteParam]],
0x72: ["moveperson", ], #back to pksv..
0x75: ["showemote", ], 0x64: ["winlosstext", ["win_text_pointer", TextPointerLabelParam], ["loss_text_pointer", TextPointerLabelParam]],
0x76: ["spriteface", ], 0x65: ["scripttalkafter"], #not pksv
0x77: ["follownotexact", ], 0x66: ["talkaftercancel"],
0x78: ["earthquake", ], 0x67: ["istalkafterscriptexecutedafterbattle"], #not pksv
0x7A: ["changeblock", ], 0x68: ["setlasttalked", ["person", SingleByteParam]],
0x7B: ["reloadmap", ], 0x69: ["applymovement", ["person", SingleByteParam], ["data", MovementPointerLabelParam]],
0x7C: ["reloadmappart", ], 0x6A: ["applymovement2", ["data", MovementPointerLabelParam]], #not pksv
0x7D: ["writecmdqueue", ], 0x6B: ["faceplayer"],
0x7E: ["delcmdqueue", ], 0x6C: ["faceperson", ["person1", SingleByteParam], ["person2", SingleByteParam]],
0x7F: ["playmusic", ], 0x6D: ["variablesprite", ["byte", SingleByteParam], ["sprite", SingleByteParam]],
0x80: ["playrammusic", ], 0x6E: ["disappear", ["person", SingleByteParam]], #hideperson
0x81: ["musicfadeout", ], 0x6F: ["appear", ["person", SingleByteParam]], #showperson
0x82: ["playmapmusic", ], 0x70: ["follow", ["person2", SingleByteParam], ["person1", SingleByteParam]],
0x83: ["reloadmapmusic", ], 0x71: ["stopfollow"],
0x84: ["cry", ], 0x72: ["moveperson", ["person", SingleByteParam], ["x", SingleByteParam], ["y", SingleByteParam]],
0x85: ["playsound", ], 0x73: ["writepersonxy", ["person", SingleByteParam]], #not pksv
0x86: ["waitbutton", ], 0x74: ["loademote", ["bubble", SingleByteParam]],
0x87: ["warpsound", ], 0x75: ["showemote", ["bubble", SingleByteParam], ["person", SingleByteParam], ["time", SingleByteParam]],
0x88: ["specialsound", ], 0x76: ["spriteface", ["person", SingleByteParam], ["facing", SingleByteParam]],
0x89: ["passtoengine", ], 0x77: ["follownotexact", ["person2", SingleByteParam], ["person1", SingleByteParam]],
0x8A: ["newloadmap", ], 0x78: ["earthquake", ["param", SingleByteParam]],
0x8B: ["pause", ], 0x79: ["changemap", ["map_data_pointer", MapDataPointerParam]],
0x8C: ["deactivatefacing", ], 0x7A: ["changeblock", ["x", SingleByteParam], ["y", SingleByteParam], ["block", SingleByteParam]],
0x8D: ["priorityjump", ], 0x7B: ["reloadmap"],
0x8E: ["warpcheck", ], 0x7C: ["reloadmappart"],
0x8F: ["ptpriorityjump", ], 0x7D: ["writecmdqueue", ["queue_pointer", MultiByteParam]],
0x90: ["return", ], 0x7E: ["delcmdqueue", ["byte", SingleByteParam]],
0x91: ["end", ], 0x7F: ["playmusic", ["music_pointer", MultiByteParam]],
0x92: ["reloadandreturn", ], 0x80: ["playrammusic"],
0x93: ["resetfuncs", ], 0x81: ["musicfadeout", ["music", MultiByteParam], ["fadetime", SingleByteParam]],
0x94: ["pokemart", ], 0x82: ["playmapmusic"],
0x95: ["elevator", ], 0x83: ["reloadmapmusic"],
0x96: ["trade", ], 0x84: ["cry", ["cry_id", SingleByteParam], ["wtf", SingleByteParam]], #XXX maybe it should use PokemonParam
0x97: ["askforphonenumber", ], 0x85: ["playsound", ["sound_pointer", MultiByteParam]],
0x98: ["phonecall", ], 0x86: ["waitbutton"],
0x99: ["hangup", ], 0x87: ["warpsound"],
0x9A: ["describedecoration", ], 0x88: ["specialsound"],
0x9B: ["fruittree", ], 0x89: ["passtoengine", ["data_pointer", PointerLabelBeforeBank]],
0x9C: ["specialphonecall", ], 0x8A: ["newloadmap", ["which_method", SingleByteParam]],
0x9D: ["checkphonecall", ], 0x8B: ["pause", ["length", SingleByteParam]],
0x9E: ["verbosegiveitem", ], 0x8C: ["deactivatefacing", ["time", SingleByteParam]],
0xA0: ["loadwilddata", ], 0x8D: ["priorityjump", ["pointer", ScriptPointerLabelParam]],
0xA1: ["halloffame", ], 0x8E: ["warpcheck"],
0xA2: ["credits", ], 0x8F: ["ptpriorityjump", ["pointer", ScriptPointerLabelParam]],
0xA3: ["warpfacing", ], 0x90: ["return"],
0xA4: ["storetext", ], 0x91: ["end"],
0xA5: ["displaylocation", ], 0x92: ["reloadandreturn"],
0x93: ["resetfuncs"],
0x94: ["pokemart", ["dialog_id", SingleByteParam], ["mart_id", SingleByteParam]],
0x95: ["elevator", ["floor_list_pointer", PointerLabelParam]],
0x96: ["trade", ["trade_id", SingleByteParam]],
0x97: ["askforphonenumber", ["number", SingleByteParam]],
0x98: ["phonecall", ["caller_name", RawTextPointerLabelParam]],
0x99: ["hangup"],
0x9A: ["describedecoration", ["byte", SingleByteParam]],
0x9B: ["fruittree", ["tree_id", SingleByteParam]],
0x9C: ["specialphonecall", ["call_id", SingleByteParam], ["wtf", SingleByteParam]],
0x9D: ["checkphonecall"],
0x9E: ["verbosegiveitem", ["item", ItemLabelByte], ["quantity", DecimalParam]],
0xA0: ["loadwilddata", ["map_group", MapGroupParam], ["map_id", MapIdParam]],
0xA1: ["halloffame"],
0xA2: ["credits"],
0xA3: ["warpfacing", ["facing", SingleByteParam], ["map_group", MapGroupParam], ["map_id", MapIdParam], ["x", SingleByteParam], ["y", SingleByteParam]],
0xA4: ["storetext", ["pointer", PointerLabelBeforeBank], ["memory", SingleByteParam]],
0xA5: ["displaylocation", ["id", SingleByteParam]],
} }
class Command():
def __init__(self, address=None):
raise Exception, "i don't think anything actually calls this?"
self.params = {}
if not is_valid_address(address):
raise Exception, "address is invalid"
self.address = address
def to_asm(self):
#start with the rgbasm macro name for this command
output = self.macro_name
#return if there are no params
if len(self.param_types.keys()) == 0: return output
#first one will have no prefixing comma
first = True
#start reading the bytes after the command byte
current_address = self.address+1
#add each param
for param in self.params:
name = param.name
#the first param shouldn't have ", " prefixed
if first: first = False
#but all other params should
else: output += ", "
#now add the asm-compatible param string
output += obj.to_asm()
current_address += obj.size
#for param_type in self.param_types:
# name = param_type["name"]
# klass = param_type["klass"]
# #create an instance of this type
# #tell it to begin parsing at this latest byte
# obj = klass(address=current_address)
# #the first param shouldn't have ", " prefixed
# if first: first = False
# #but all other params should
# else: output += ", "
# #now add the asm-compatible param string
# output += obj.to_asm()
# current_address += obj.size
return output
def parse(self):
#id, size (inclusive), param_types
#param_type = {"name": each[1], "class": each[0]}
self.params = {}
current_address = self.address+1
byte = int(rom[self.address])
if not byte == self.id:
raise Exception, "this should never happen"
i = 0
for (key, param_type) in self.param_types.items():
name = param_type["name"]
klass = param_type["class"]
#make an instance of this class, like SingleByteParam()
#or ItemLabelByte.. by making an instance, obj.parse() is called
obj = klass(address=current_address, name=name)
#save this for later
self.params[i] = obj
#increment our counters
current_address += obj.size
i += 1
return True
class GivePoke(Command):
id = 0x2D
size = 4 #minimum
param_types = {
0: {"name": "pokemon", "class": PokemonParam},
1: {"name": "level", "class": SingleByteParam},
2: {"name": "item", "class": ItemLabelByte},
3: {"name": "trainer", "class": SingleByteParam},
4: {"name": "trainer_name_pointer", "class": MultiByteParam}, #should probably use TextLabelParam
5: {"name": "pkmn_nickname", "class": MultiByteParam}, #XXX TextLabelParam ?
}
def parse(self):
self.params = {}
byte = int(rom[self.address])
if not byte == self.id:
raise Exception, "this should never happen"
current_address = self.address+1
i = 0
for (key, param_type) in self.param_types.items():
#stop executing after the 4th byte unless it == 0x1
if i == 4 and self.params[-1].byte != 1: break
name = param_type["name"]
klass = param_type["class"]
#make an instance of this class, like SingleByteParam()
#or ItemLabelByte.. by making an instance, obj.parse() is called
obj = klass(address=current_address, name=name)
#save this for later
self.params[i] = obj
#increment our counters
current_address += obj.size
i += 1
return True
#these cause the script to end; used in create_command_classes #these cause the script to end; used in create_command_classes
pksv_crystal_more_enders = [0x03, 0x04, 0x05, 0x0C, 0x51, 0x53, pksv_crystal_more_enders = [0x03, 0x04, 0x05, 0x0C, 0x51, 0x53,
0x8D, 0x8F, 0x90, 0x91, 0x92, 0x9B] 0x8D, 0x8F, 0x90, 0x91, 0x92, 0x9B]
def create_command_classes(): def create_command_classes(debug=False):
"""creates some classes for each command byte""" """creates some classes for each command byte"""
klasses = [] klasses = []
for (byte, cmd) in pksv_crystal_more.items(): for (byte, cmd) in pksv_crystal_more.items():
@ -2521,14 +2556,17 @@ def create_command_classes():
for (i, each) in enumerate(param_types): for (i, each) in enumerate(param_types):
thing = {"name": each[0], "class": each[1]} thing = {"name": each[0], "class": each[1]}
params["param_types"][i] = thing params["param_types"][i] = thing
if debug:
print "each is: " + str(each)
print "thing[class] is: " + str(thing["class"])
params["size"] += thing["class"].size params["size"] += thing["class"].size
klass_name = cmd_name+"Command" klass_name = cmd_name+"Command"
klass = classobj(klass_name, (Command,), params) klass = classobj(klass_name, (Command,), params)
globals()[klass_name] = klass globals()[klass_name] = klass
klasses = append(klass) klasses.append(klass)
#later an individual klass will be instantiated to handle something #later an individual klass will be instantiated to handle something
return klasses return klasses
create_command_classes() command_classes = create_command_classes()
#use this to keep track of commands without pksv names #use this to keep track of commands without pksv names
pksv_no_names = {} pksv_no_names = {}