Merge pull request #103 from eevee/py3

Python 3 compatibility, sort of, maybe
This commit is contained in:
yenatch 2017-02-13 18:09:31 -05:00 committed by GitHub
commit 979c98a7c0
59 changed files with 1786 additions and 1691 deletions

View File

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
import ply.lex as lex
import sys, os
@ -466,7 +467,7 @@ class Lexer(object):
''' Prints an error msg.
'''
#print '%s:%i %s' % (FILENAME, self.lex.lineno, str)
print '%s:%s %s' % (FILENAME, "?", str)
print('%s:%s %s' % (FILENAME, "?", str))
def error(self, str):
@ -490,5 +491,5 @@ if __name__ == '__main__':
tmp.input(open(sys.argv[1]).read())
tok = tmp.token()
while tok:
print tok
print(tok)
tok = tmp.token()

View File

@ -1,5 +1 @@
import configuration as config
import crystal
import preprocessor
__version__ = "1.6.0"

View File

@ -1,17 +1,18 @@
# coding: utf-8
from __future__ import absolute_import
import os
from math import ceil
from song_names import song_names
from sfx_names import sfx_names
from cry_names import cry_names
from .song_names import song_names
from .sfx_names import sfx_names
from .cry_names import cry_names
from gbz80disasm import get_global_address, get_local_address
from labels import line_has_label
from crystal import music_classes as sound_classes
from crystal import (
from .gbz80disasm import get_global_address, get_local_address
from .labels import line_has_label
from .crystal import music_classes as sound_classes
from .crystal import (
Command,
SingleByteParam,
MultiByteParam,
@ -22,7 +23,7 @@ from crystal import (
rom = load_rom()
rom = bytearray(rom)
import configuration
from . import configuration
conf = configuration.Config()
@ -299,7 +300,7 @@ class Channel:
self.address / 0x4000 != self.start_address / 0x4000
) and not done:
done = True
raise Exception, self.label + ': reached the end of the bank without finishing!'
raise Exception(self.label + ': reached the end of the bank without finishing!')
self.output += [(self.address, '; %x\n' % self.address, self.address)]

View File

@ -1,12 +1,14 @@
# coding: utf-8
from __future__ import print_function
from __future__ import absolute_import
import os
from new import classobj
import configuration
from . import configuration
conf = configuration.Config()
from crystal import (
from .crystal import (
SingleByteParam,
PointerLabelParam,
DecimalParam,
@ -15,11 +17,11 @@ from crystal import (
load_rom
)
from gbz80disasm import get_local_address, get_global_address
from audio import sort_asms
from .gbz80disasm import get_local_address, get_global_address
from .audio import sort_asms
from wram import read_constants
from .wram import read_constants
rom = bytearray(load_rom())
@ -42,7 +44,7 @@ anims = read_constants(os.path.join(conf.path, 'constants/animation_constants.as
objs = { k: v for k, v in anims.items() if 'ANIM_OBJ' in v }
bgs = { k: v for k, v in anims.items() if 'ANIM_BG' in v }
anims = { k: v.replace('ANIM_','') for k, v in anims.items() }
from move_constants import moves
from .move_constants import moves
anims.update(moves)
class AnimObjParam(SingleByteParam):
@ -320,5 +322,5 @@ def asm_list_to_text(asms):
if __name__ == '__main__':
asms = dump_battle_anims()
print asm_list_to_text(asms)
print(asm_list_to_text(asms))

View File

@ -2,8 +2,10 @@
"""
Find shared functions between red/crystal.
"""
from __future__ import print_function
from __future__ import absolute_import
from crystal import (
from .crystal import (
get_label_from_line,
get_address_from_line_comment,
AsmSection,
@ -11,7 +13,7 @@ from crystal import (
direct_load_asm,
)
from romstr import (
from .romstr import (
RomStr,
AsmList,
)
@ -53,7 +55,7 @@ class Address(int):
instance = int.__new__(cls, int(x, base=16), *args, **kwargs)
else:
msg = "Address.__new__ doesn't know how to parse this string"
raise Exception, msg
raise Exception(msg)
else:
instance = int.__new__(cls, x, *args, **kwargs)
@ -157,7 +159,7 @@ class BinaryBlob(object):
found_blobs.append(self)
if self.debug:
print self.label + ": found " + str(len(self.locations)) + " matches."
print(self.label + ": found " + str(len(self.locations)) + " matches.")
def find_by_first_bytes(self):
"""
@ -181,7 +183,7 @@ class BinaryBlob(object):
found_blobs.append(self)
if self.debug:
print self.label + ": found " + str(len(self.locations)) + " matches."
print(self.label + ": found " + str(len(self.locations)) + " matches.")
pokecrystal_rom_path = "../baserom.gbc"
pokecrystal_src_path = "../main.asm"
@ -214,14 +216,14 @@ def scan_red_asm(bank_stop=3, debug=True):
for line in redsrc:
if debug and show_lines:
print "processing a line from red: " + line
print("processing a line from red: " + line)
if line[0:7] == "SECTION":
thing = AsmSection(line)
current_bank = thing.bank_id
if debug:
print "scan_red_asm: switching to bank " + str(current_bank)
print("scan_red_asm: switching to bank " + str(current_bank))
elif line[0:6] != "INCBIN":
if ":" in line and not ";XXX:" in line and not " ; XXX:" in line:
@ -240,7 +242,7 @@ def scan_red_asm(bank_stop=3, debug=True):
line_number=line_number)
if debug:
print "Created a new blob: " + str(blob) + " from line: " + str(latest_line)
print("Created a new blob: " + str(blob) + " from line: " + str(latest_line))
latest_label = current_label
latest_start_address = current_start_address
@ -250,18 +252,18 @@ def scan_red_asm(bank_stop=3, debug=True):
if current_bank == bank_stop:
if debug:
print "scan_red_asm: stopping because current_bank >= " + \
str(bank_stop) + " (bank_stop)"
print("scan_red_asm: stopping because current_bank >= " + \
str(bank_stop) + " (bank_stop)")
break
scan_red_asm(bank_stop=3)
print "================================"
print("================================")
for blob in found_blobs:
print blob
print(blob)
print "Found " + str(len(found_blobs)) + " possibly copied functions."
print("Found " + str(len(found_blobs)) + " possibly copied functions.")
print [hex(x) for x in found_blobs[10].locations]
print([hex(x) for x in found_blobs[10].locations])

View File

@ -2,16 +2,15 @@
"""
utilities to help disassemble pokémon crystal
"""
from __future__ import print_function
from __future__ import absolute_import
import os
import sys
import inspect
import hashlib
import json
from copy import copy, deepcopy
import subprocess
from new import classobj
import random
import logging
# for capwords
@ -47,27 +46,27 @@ texts = []
# this doesn't do anything but is still used in TextScript
constant_abbreviation_bytes = {}
import helpers
import chars
import labels
import pksv
import romstr
import pointers
import interval_map
import trainers
import move_constants
import pokemon_constants
import item_constants
import wram
import exceptions
from . import helpers
from . import chars
from . import labels
from . import pksv
from . import romstr
from . import pointers
from . import interval_map
from . import trainers
from . import move_constants
from . import pokemon_constants
from . import item_constants
from . import wram
from . import exceptions
import addresses
from . import addresses
is_valid_address = addresses.is_valid_address
import old_text_script
from . import old_text_script
OldTextScript = old_text_script
import configuration
from . import configuration
conf = configuration.Config()
data_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "data/pokecrystal/")
@ -75,8 +74,8 @@ conf.wram = os.path.join(data_path, "wram.asm")
conf.gbhw = os.path.join(data_path, "gbhw.asm")
conf.hram = os.path.join(data_path, "hram.asm")
from map_names import map_names
from song_names import song_names
from .map_names import map_names
from .song_names import song_names
# ---- script_parse_table explanation ----
# This is an IntervalMap that keeps track of previously parsed scripts, texts
@ -239,7 +238,7 @@ def command_debug_information(command_byte=None, map_group=None, map_id=None, ad
return info1
all_texts = []
class TextScript:
class TextScript(object):
"""
A text is a sequence of bytes (and sometimes commands). It's not the same
thing as a Script. The bytes are translated into characters based on the
@ -435,7 +434,7 @@ def find_text_addresses():
useful for testing parse_text_engine_script_at"""
return TextScript.find_addresses()
class EncodedText:
class EncodedText(object):
"""a sequence of bytes that, when decoded, represent readable text
based on the chars table from preprocessor.py and other places"""
base_label = "UnknownRawText_"
@ -1263,7 +1262,7 @@ class MovementPointerLabelParam(PointerLabelParam):
class MapDataPointerParam(PointerLabelParam):
pass
class Command:
class Command(object):
"""
Note: when dumping to asm, anything in script_parse_table that directly
inherits Command should not be .to_asm()'d.
@ -1453,14 +1452,14 @@ event_flags = None
def read_event_flags():
global event_flags
constants = wram.read_constants(os.path.join(conf.path, 'constants.asm'))
event_flags = dict(filter(lambda (key, value): value.startswith('EVENT_'), constants.items()))
event_flags = dict(filter(lambda key_value: key_value[1].startswith('EVENT_'), constants.items()))
return event_flags
engine_flags = None
def read_engine_flags():
global engine_flags
constants = wram.read_constants(os.path.join(conf.path, 'constants.asm'))
engine_flags = dict(filter(lambda (key, value): value.startswith('ENGINE_'), constants.items()))
engine_flags = dict(filter(lambda key_value1: key_value1[1].startswith('ENGINE_'), constants.items()))
return engine_flags
class EventFlagParam(MultiByteParam):
@ -1611,7 +1610,7 @@ def create_movement_commands(debug=False):
klass_name = cmd_name+"Command"
params["id"] = copy(byte)
params["macro_name"] = cmd_name
klass = classobj(copy(klass_name), (MovementCommand,), deepcopy(params))
klass = type(copy(klass_name), (MovementCommand,), deepcopy(params))
globals()[klass_name] = klass
movement_command_classes2.append(klass)
@ -1621,7 +1620,7 @@ def create_movement_commands(debug=False):
del klass_name
else:
klass_name = cmd_name+"Command"
klass = classobj(klass_name, (MovementCommand,), params)
klass = type(klass_name, (MovementCommand,), params)
globals()[klass_name] = klass
movement_command_classes2.append(klass)
# later an individual klass will be instantiated to handle something
@ -1630,7 +1629,7 @@ def create_movement_commands(debug=False):
movement_command_classes = create_movement_commands()
all_movements = []
class ApplyMovementData:
class ApplyMovementData(object):
base_label = "MovementData_"
def __init__(self, address, map_group=None, map_id=None, debug=False, label=None, force=False):
@ -1763,9 +1762,9 @@ class ApplyMovementData:
def print_all_movements():
for each in all_movements:
print each.to_asm()
print "------------------"
print "done"
print(each.to_asm())
print("------------------")
print("done")
class TextCommand(Command):
# an individual text command will not end it
@ -2431,7 +2430,7 @@ def create_command_classes(debug=False):
logging.debug("each is {0} and thing[class] is {1}".format(each, thing["class"]))
params["size"] += thing["class"].size
klass_name = cmd_name+"Command"
klass = classobj(klass_name, (Command,), params)
klass = type(klass_name, (Command,), params)
globals()[klass_name] = klass
klasses.append(klass)
# later an individual klass will be instantiated to handle something
@ -2439,7 +2438,7 @@ def create_command_classes(debug=False):
command_classes = create_command_classes()
class BigEndianParam:
class BigEndianParam(object):
"""big-endian word"""
size = 2
should_be_decimal = False
@ -2548,7 +2547,7 @@ def create_music_command_classes(debug=False):
logging.debug("each is {0} and thing[class] is {1}".format(each, thing["class"]))
params["size"] += thing["class"].size
klass_name = cmd_name+"Command"
klass = classobj(klass_name, (Command,), params)
klass = type(klass_name, (Command,), params)
globals()[klass_name] = klass
if klass.macro_name == "notetype":
klass.allowed_lengths = [1, 2]
@ -2808,7 +2807,7 @@ def create_effect_command_classes(debug=False):
logging.debug("each is {0} and thing[class] is {1}".format(each, thing["class"]))
params["size"] += thing["class"].size
klass_name = cmd_name+"Command"
klass = classobj(klass_name, (Command,), params)
klass = type(klass_name, (Command,), params)
globals()[klass_name] = klass
klasses.append(klass)
# later an individual klass will be instantiated to handle something
@ -2854,9 +2853,9 @@ def pretty_print_pksv_no_names():
for (command_byte, addresses) in pksv_no_names.items():
if command_byte in pksv.pksv_crystal_unknowns:
continue
print hex(command_byte) + " appearing in these scripts: "
print(hex(command_byte) + " appearing in these scripts: ")
for address in addresses:
print " " + hex(address)
print(" " + hex(address))
recursive_scripts = set([])
def rec_parse_script_engine_script_at(address, origin=None, debug=True):
@ -2891,7 +2890,7 @@ stop_points = [0x1aafa2,
0x9f58f, # battle tower
0x9f62f, # battle tower
]
class Script:
class Script(object):
base_label = "UnknownScript_"
def __init__(self, *args, **kwargs):
self.address = None
@ -3086,7 +3085,7 @@ class Script:
def old_parse(self, *args, **kwargs):
"""included from old_parse_scripts"""
import old_parse_scripts
from . import old_parse_scripts
Script.old_parse = old_parse_scripts.old_parse
def parse_script_engine_script_at(address, map_group=None, map_id=None, force=False, debug=True, origin=True):
@ -3469,7 +3468,7 @@ class TrainerFragmentParam(PointerLabelParam):
return deps
trainer_group_table = None
class TrainerGroupTable:
class TrainerGroupTable(object):
"""
A list of pointers.
@ -3524,7 +3523,7 @@ class TrainerGroupTable:
output = "".join([str("dw "+get_label_for(header.address)+"\n") for header in self.headers])
return output
class TrainerGroupHeader:
class TrainerGroupHeader(object):
"""
A trainer group header is a repeating list of individual trainer headers.
@ -3617,7 +3616,7 @@ class TrainerGroupHeader:
output = "\n\n".join(["; "+header.make_constant_name()+" ("+str(header.trainer_id)+") at "+hex(header.address)+"\n"+header.to_asm() for header in self.individual_trainer_headers])
return output
class TrainerHeader:
class TrainerHeader(object):
"""
<Trainer Name> <0x50> <Data type> <Pokémon Data>+ <0xFF>
@ -3722,7 +3721,7 @@ class TrainerHeader:
output += "\n; last_address="+hex(self.last_address)+" size="+str(self.size)
return output
class TrainerPartyMonParser:
class TrainerPartyMonParser(object):
"""
Just a generic trainer party mon parser.
Don't use this directly. Only use the child classes.
@ -4251,8 +4250,8 @@ class PeopleEvent(Command):
lower_bits = color_function_byte & 0xF
higher_bits = color_function_byte >> 4
is_regular_script = lower_bits == 00
is_give_item = lower_bits == 01
is_trainer = lower_bits == 02
is_give_item = lower_bits == 0o1
is_trainer = lower_bits == 0o2
current_address += obj.size
self.size += obj.size
i += 1
@ -4326,9 +4325,9 @@ def old_parse_people_event_bytes(some_bytes, address=None, map_group=None, map_i
is_regular_script = lower_bits == 00
# pointer points to script
is_give_item = lower_bits == 01
is_give_item = lower_bits == 0o1
# pointer points to [Item no.][Amount]
is_trainer = lower_bits == 02
is_trainer = lower_bits == 0o2
# pointer points to trainer header
# goldmap called these next two bytes "text_block" and "text_bank"?
@ -4412,7 +4411,7 @@ def old_parse_people_event_bytes(some_bytes, address=None, map_group=None, map_i
return people_events
class SignpostRemoteBase:
class SignpostRemoteBase(object):
def __init__(self, address, bank=None, map_group=None, map_id=None, signpost=None, debug=False, label=None):
self.address = address
self.last_address = address + self.size
@ -4851,7 +4850,7 @@ class TimeOfDayParam(DecimalParam):
return DecimalParam.to_asm(self)
class MapHeader:
class MapHeader(object):
base_label = "MapHeader_"
def __init__(self, address, map_group=None, map_id=None, debug=True, label=None, bank=0x25):
@ -4937,7 +4936,7 @@ def get_direction(connection_byte, connection_id):
return results[connection_id]
class SecondMapHeader:
class SecondMapHeader(object):
base_label = "SecondMapHeader_"
def __init__(self, address, map_group=None, map_id=None, debug=True, bank=None, label=None):
@ -5079,7 +5078,7 @@ wrong_easts = []
wrong_souths = []
wrong_wests = []
class Connection:
class Connection(object):
size = 12
def __init__(self, address, direction=None, map_group=None, map_id=None, debug=True, smh=None):
@ -5743,7 +5742,7 @@ def parse_second_map_header_at(address, map_group=None, map_id=None, debug=True)
all_second_map_headers.append(smh)
return smh
class MapBlockData:
class MapBlockData(object):
base_label = "MapBlockData_"
maps_path = os.path.realpath(os.path.join(conf.path, "maps"))
@ -5789,7 +5788,7 @@ class MapBlockData:
return "INCBIN \"maps/"+self.map_name+".blk\""
class MapEventHeader:
class MapEventHeader(object):
base_label = "MapEventHeader_"
def __init__(self, address, map_group=None, map_id=None, debug=True, bank=None, label=None):
@ -5928,7 +5927,7 @@ def parse_map_event_header_at(address, map_group=None, map_id=None, debug=True,
all_map_event_headers.append(ev)
return ev
class MapScriptHeader:
class MapScriptHeader(object):
"""parses a script header
This structure allows the game to have e.g. one-time only events on a map
@ -6121,7 +6120,7 @@ def parse_all_map_headers(map_names, all_map_headers=None, _parse_map_header_at=
"""
if _parse_map_header_at == None:
_parse_map_header_at = parse_map_header_at
if not map_names[1].has_key("offset"):
if "offset" not in map_names[1]:
raise Exception("dunno what to do - map_names should have groups with pre-calculated offsets by now")
for (group_id, group_data) in map_names.items():
offset = group_data["offset"]
@ -6140,7 +6139,7 @@ def parse_all_map_headers(map_names, all_map_headers=None, _parse_map_header_at=
new_parsed_map = _parse_map_header_at(map_header_offset, map_group=group_id, map_id=map_id, all_map_headers=all_map_headers, rom=rom, debug=debug)
map_names[group_id][map_id]["header_new"] = new_parsed_map
class PokedexEntryPointerTable:
class PokedexEntryPointerTable(object):
"""
A list of pointers.
"""
@ -6190,7 +6189,7 @@ class PokedexEntryPointerTable:
output = "".join([str("dw "+get_label_for(entry.address)+"\n") for entry in self.entries])
return output
class PokedexEntry:
class PokedexEntry(object):
def __init__(self, address, pokemon_id):
self.address = address
self.dependencies = None
@ -6244,7 +6243,7 @@ for map_group_id in map_names.keys():
# skip if we maybe already have the 'offset' label set in this map group
if map_id == "offset": continue
# skip if we provided a pre-set value for the map's label
if map_group[map_id].has_key("label"): continue
if "label" in map_group[map_id]: continue
# convience alias
map_data = map_group[map_id]
# clean up the map name to be an asm label
@ -6306,7 +6305,7 @@ def get_dependencies_for(some_object, recompute=False, global_dependencies=set()
else:
some_object.get_dependencies(recompute=recompute, global_dependencies=global_dependencies)
return global_dependencies
except RuntimeError, e:
except RuntimeError as e:
# 1552, 1291, 2075, 1552, 1291...
errorargs = {
@ -6532,15 +6531,14 @@ def apply_diff(diff, try_fixing=True, do_compile=True):
try:
subprocess.check_call("cd " + conf.path + "; make clean; make", shell=True)
return True
except Exception, exc:
except Exception as exc:
if try_fixing:
os.system("mv " + os.path.join(conf.path, "main1.asm") + " " + os.path.join(conf.path, "main.asm"))
return False
import crystalparts.asmline
AsmLine = crystalparts.asmline.AsmLine
from .crystalparts.asmline import AsmLine
class Incbin:
class Incbin(object):
def __init__(self, line, bank=None, debug=False):
self.line = line
self.bank = bank
@ -6559,7 +6557,7 @@ class Incbin:
logging.debug("Incbin.parse start is {0}".format(start))
try:
start = eval(start)
except Exception, e:
except Exception as e:
logging.debug("start is {0}".format(start))
raise Exception("problem with evaluating interval range: " + str(e))
@ -6627,7 +6625,7 @@ class Incbin:
return incbins
class AsmSection:
class AsmSection(object):
def __init__(self, line):
self.bank_id = None
self.line = line
@ -6669,7 +6667,7 @@ def load_asm2(filename=None, force=False):
new_asm = Asm(filename=filename)
return new_asm
class Asm:
class Asm(object):
"""controls the overall asm output"""
def __init__(self, filename=None, debug=True):
if filename == None:
@ -7133,7 +7131,7 @@ def get_label_for(address, _all_labels=None, _script_parse_table=None):
# at least until the two approaches are merged in the code base.
all_new_labels = []
class Label:
class Label(object):
"""
Every object in script_parse_table is given a label.

View File

@ -274,9 +274,9 @@ def old_parse_people_event_bytes(some_bytes, address=None, map_group=None, map_i
is_regular_script = lower_bits == 00
# pointer points to script
is_give_item = lower_bits == 01
is_give_item = lower_bits == 0o1
# pointer points to [Item no.][Amount]
is_trainer = lower_bits == 02
is_trainer = lower_bits == 0o2
# pointer points to trainer header
# goldmap called these next two bytes "text_block" and "text_bank"?

View File

@ -3,9 +3,10 @@
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
import crystal
import gbz80disasm
from . import crystal
from . import gbz80disasm
rom = crystal.load_rom()
roml = [ord(x) for x in rom]

View File

@ -1,7 +1,9 @@
from gfx import *
from pokemon_constants import pokemon_constants
import trainers
import romstr
from __future__ import print_function
from __future__ import absolute_import
from .gfx import *
from .pokemon_constants import pokemon_constants
from . import trainers
from . import romstr
def load_rom(filename=config.rom_path):
rom = romstr.RomStr.load(filename=filename)
@ -357,7 +359,7 @@ def dump_pic_animations(addresses={'bitmasks': 'BitmasksPointers', 'frames': 'Fr
tiles = (x for x in frame[1])
for j, bit in enumerate(bitmask):
if bit:
tmap[(i + 1) * length + j] = tiles.next()
tmap[(i + 1) * length + j] = next(tiles)
filename = os.path.join(directory, 'front.{0}x{0}.2bpp.lz'.format(size))
tiles = get_tiles(Decompressed(open(filename).read()).output)
@ -495,7 +497,7 @@ def dump_trainer_pals():
to_file('../'+dir+filename, pal_data)
spacing = ' ' * (12 - len(name))
print name+'Palette:'+spacing+' INCBIN"'+dir+filename+'"'
print(name+'Palette:'+spacing+' INCBIN"'+dir+filename+'"')
def get_uncompressed_gfx(start, num_tiles, filename):

View File

@ -2,13 +2,15 @@
"""
GBC disassembler
"""
from __future__ import print_function
from __future__ import absolute_import
import os
import argparse
from ctypes import c_int8
import configuration
from wram import read_constants
from . import configuration
from .wram import read_constants
z80_table = [
('nop', 0), # 00
@ -392,20 +394,20 @@ def load_symbols(path):
label = symbol['label']
if 0x0000 <= address < 0x8000:
if not sym.has_key(bank):
if bank not in sym:
sym[bank] = {}
sym[bank][address] = label
reverse_sym[label] = get_global_address(address, bank)
elif 0xa000 <= address < 0xc000:
if not sram_sym.has_key(bank):
if bank not in sram_sym:
sram_sym[bank] = {}
sram_sym[bank][address] = label
elif address < 0xe000:
if not wram_sym.has_key(bank):
if bank not in wram_sym:
wram_sym[bank] = {}
wram_sym[bank][address] = label
@ -575,7 +577,7 @@ class Disassembler(object):
stop_offset = (bank_id + 1) * 0x4000 - 1
if debug:
print "bank id is: " + str(bank_id)
print("bank id is: " + str(bank_id))
rom = self.rom
@ -904,7 +906,7 @@ if __name__ == "__main__":
# suppress output if quiet flag is set
if not args.quiet:
print output
print(output)
# only write to the output file if the no write flag is unset
if not args.no_write:

View File

@ -1,23 +1,25 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import sys
import png
from . import png
from math import sqrt, floor, ceil
import argparse
import operator
import configuration
from . import configuration
config = configuration.Config()
from lz import Compressed, Decompressed
from .lz import Compressed, Decompressed
def split(list_, interval):
"""
Split a list by length.
"""
for i in xrange(0, len(list_), interval):
for i in range(0, len(list_), interval):
j = min(i + interval, len(list_))
yield list_[i:j]
@ -69,7 +71,7 @@ def transpose(tiles, width=None):
"""
if width == None:
width = int(sqrt(len(tiles))) # assume square image
tiles = sorted(enumerate(tiles), key= lambda (i, tile): i % width)
tiles = sorted(enumerate(tiles), key= lambda i_tile: i_tile[0] % width)
return [tile for i, tile in tiles]
def transpose_tiles(image, width=None):
@ -135,7 +137,7 @@ def condense_tiles_to_map(tiles, pic=0):
# Leave the first frame intact for pics.
new_tiles = tiles[:pic]
tilemap = range(pic)
tilemap = list(range(pic))
for i, tile in enumerate(tiles[pic:]):
if tile not in new_tiles:
@ -175,14 +177,13 @@ def to_file(filename, data):
"""
Apparently open(filename, 'wb').write(bytearray(data)) won't work.
"""
file = open(filename, 'wb')
for byte in data:
file.write('%c' % byte)
file.close()
with open(filename, 'wb') as f:
f.write((bytearray(data)))
def decompress_file(filein, fileout=None):
image = bytearray(open(filein).read())
with open(filein, 'rb') as f:
image = bytearray(f.read())
de = Decompressed(image)
if fileout == None:
@ -191,7 +192,8 @@ def decompress_file(filein, fileout=None):
def compress_file(filein, fileout=None):
image = bytearray(open(filein).read())
with open(filein, 'rb') as f:
image = bytearray(f.read())
lz = Compressed(image)
if fileout == None:
@ -208,7 +210,8 @@ def bin_to_rgb(word):
return (red, green, blue)
def convert_binary_pal_to_text_by_filename(filename):
pal = bytearray(open(filename).read())
with open(filename, 'rb') as f:
pal = bytearray(f.read())
return convert_binary_pal_to_text(pal)
def convert_binary_pal_to_text(pal):
@ -247,7 +250,7 @@ def flatten(planar):
bottom = bottom
top = top
strip = []
for i in xrange(7,-1,-1):
for i in range(7,-1,-1):
color = (
(bottom >> i & 1) +
(top *2 >> i & 2)
@ -262,14 +265,14 @@ def to_lines(image, width):
"""
tile_width = 8
tile_height = 8
num_columns = width / tile_width
height = len(image) / width
num_columns = width // tile_width
height = len(image) // width
lines = []
for cur_line in xrange(height):
tile_row = cur_line / tile_height
for cur_line in range(height):
tile_row = cur_line // tile_height
line = []
for column in xrange(num_columns):
for column in range(num_columns):
anchor = (
num_columns * tile_row * tile_width * tile_height +
column * tile_width * tile_height +
@ -290,7 +293,7 @@ def dmg2rgb(word):
value >>= 5
word = shift(word)
# distribution is less even w/ << 3
red, green, blue = [int(color * 8.25) for color in [word.next() for _ in xrange(3)]]
red, green, blue = [int(color * 8.25) for color in [next(word) for _ in range(3)]]
alpha = 255
return (red, green, blue, alpha)
@ -299,9 +302,9 @@ def rgb_to_dmg(color):
"""
For PNGs.
"""
word = (color['r'] / 8)
word += (color['g'] / 8) << 5
word += (color['b'] / 8) << 10
word = (color['r'] // 8)
word += (color['g'] // 8) << 5
word += (color['b'] // 8) << 10
return word
@ -332,7 +335,7 @@ def png_to_rgb(palette):
"""
output = ''
for color in palette:
r, g, b = [color[c] / 8 for c in 'rgb']
r, g, b = [color[c] // 8 for c in 'rgb']
output += '\tRGB ' + ', '.join(['%.2d' % hue for hue in (r, g, b)])
output += '\n'
return output
@ -431,7 +434,7 @@ def convert_2bpp_to_png(image, **kwargs):
# Width must be specified to interleave.
if interleave and width:
image = interleave_tiles(image, width / 8)
image = interleave_tiles(image, width // 8)
# Pad the image by a given number of tiles if asked.
image += pad_color * 0x10 * tile_padding
@ -446,34 +449,34 @@ def convert_2bpp_to_png(image, **kwargs):
trailing = len(image) % pic_length
pic = []
for i in xrange(0, len(image) - trailing, pic_length):
for i in range(0, len(image) - trailing, pic_length):
pic += transpose_tiles(image[i:i+pic_length], h)
image = bytearray(pic) + image[len(image) - trailing:]
# Pad out trailing lines.
image += pad_color * 0x10 * ((w - (len(image) / 0x10) % h) % w)
image += pad_color * 0x10 * ((w - (len(image) // 0x10) % h) % w)
def px_length(img):
return len(img) * 4
def tile_length(img):
return len(img) * 4 / (8*8)
return len(img) * 4 // (8*8)
if width and height:
tile_width = width / 8
tile_width = width // 8
more_tile_padding = (tile_width - (tile_length(image) % tile_width or tile_width))
image += pad_color * 0x10 * more_tile_padding
elif width and not height:
tile_width = width / 8
tile_width = width // 8
more_tile_padding = (tile_width - (tile_length(image) % tile_width or tile_width))
image += pad_color * 0x10 * more_tile_padding
height = px_length(image) / width
height = px_length(image) // width
elif height and not width:
tile_height = height / 8
tile_height = height // 8
more_tile_padding = (tile_height - (tile_length(image) % tile_height or tile_height))
image += pad_color * 0x10 * more_tile_padding
width = px_length(image) / height
width = px_length(image) // height
# at least one dimension should be given
if width * height != px_length(image):
@ -481,15 +484,15 @@ def convert_2bpp_to_png(image, **kwargs):
matches = []
# Height need not be divisible by 8, but width must.
# See pokered gfx/minimize_pic.1bpp.
for w in range(8, px_length(image) / 2 + 1, 8):
h = px_length(image) / w
for w in range(8, px_length(image) // 2 + 1, 8):
h = px_length(image) // w
if w * h == px_length(image):
matches += [(w, h)]
# go for the most square image
if len(matches):
width, height = sorted(matches, key= lambda (w, h): (h % 8 != 0, w + h))[0] # favor height
width, height = sorted(matches, key= lambda w_h: (w_h[1] % 8 != 0, w_h[0] + w_h[1]))[0] # favor height
else:
raise Exception, 'Image can\'t be divided into tiles (%d px)!' % (px_length(image))
raise Exception('Image can\'t be divided into tiles (%d px)!' % (px_length(image)))
# convert tiles to lines
lines = to_lines(flatten(image), width)
@ -520,7 +523,7 @@ def get_pic_animation(tmap, w, h):
base = frames.pop(0)
bitmasks = []
for i in xrange(len(frames)):
for i in range(len(frames)):
frame_text += '\tdw .frame{}\n'.format(i + 1)
for i, frame in enumerate(frames):
@ -530,7 +533,7 @@ def get_pic_animation(tmap, w, h):
which_bitmask = bitmasks.index(bitmask)
mask = iter(bitmask)
masked_frame = filter(lambda _: mask.next(), frame)
masked_frame = filter(lambda _: next(mask), frame)
frame_text += '.frame{}\n'.format(i + 1)
frame_text += '\tdb ${:02x} ; bitmask\n'.format(which_bitmask)
@ -607,12 +610,12 @@ def get_image_padding(width, height, wstep=8, hstep=8):
}
if width % wstep and width >= wstep:
pad = float(width % wstep) / 2
pad = width % wstep / 2
padding['left'] = int(ceil(pad))
padding['right'] = int(floor(pad))
if height % hstep and height >= hstep:
pad = float(height % hstep) / 2
pad = height % hstep / 2
padding['top'] = int(ceil(pad))
padding['bottom'] = int(floor(pad))
@ -636,8 +639,6 @@ def png_to_2bpp(filein, **kwargs):
if type(filein) is str:
filein = open(filein, 'rb')
assert type(filein) is file
width, height, rgba, info = png.Reader(filein).asRGBA8()
# png.Reader returns flat pixel data. Nested is easier to work with
@ -646,16 +647,16 @@ def png_to_2bpp(filein, **kwargs):
palette = []
for line in rgba:
newline = []
for px in xrange(0, len(line), len_px):
for px in range(0, len(line), len_px):
color = dict(zip('rgba', line[px:px+len_px]))
if color not in palette:
if len(palette) < 4:
palette += [color]
else:
# TODO Find the nearest match
print 'WARNING: %s: Color %s truncated to' % (filein, color),
print('WARNING: %s: Color %s truncated to' % (filein, color), end=' ')
color = sorted(palette, key=lambda x: sum(x.values()))[0]
print color
print(color)
newline += [color]
image += [newline]
@ -698,15 +699,15 @@ def png_to_2bpp(filein, **kwargs):
# Graphics are stored in tiles instead of lines
tile_width = 8
tile_height = 8
num_columns = max(width, tile_width) / tile_width
num_rows = max(height, tile_height) / tile_height
num_columns = max(width, tile_width) // tile_width
num_rows = max(height, tile_height) // tile_height
image = []
for row in xrange(num_rows):
for column in xrange(num_columns):
for row in range(num_rows):
for column in range(num_columns):
# Split it up into strips to convert to planar data
for strip in xrange(min(tile_height, height)):
for strip in range(min(tile_height, height)):
anchor = (
row * num_columns * tile_width * tile_height +
column * tile_width +
@ -716,7 +717,7 @@ def png_to_2bpp(filein, **kwargs):
bottom, top = 0, 0
for bit, quad in enumerate(line):
bottom += (quad & 1) << (7 - bit)
top += (quad /2 & 1) << (7 - bit)
top += (quad // 2 & 1) << (7 - bit)
image += [bottom, top]
dim = arguments['pic_dimensions']
@ -725,20 +726,20 @@ def png_to_2bpp(filein, **kwargs):
w, h = dim
else:
# infer dimensions based on width.
w = width / tile_width
h = height / tile_height
w = width // tile_width
h = height // tile_height
if h % w == 0:
h = w
tiles = get_tiles(image)
pic_length = w * h
tile_width = width / 8
tile_width = width // 8
trailing = len(tiles) % pic_length
new_image = []
for block in xrange(len(tiles) / pic_length):
offset = (h * tile_width) * ((block * w) / tile_width) + ((block * w) % tile_width)
for block in range(len(tiles) // pic_length):
offset = (h * tile_width) * ((block * w) // tile_width) + ((block * w) % tile_width)
pic = []
for row in xrange(h):
for row in range(h):
index = offset + (row * tile_width)
pic += tiles[index:index + w]
new_image += transpose(pic, w)
@ -865,7 +866,7 @@ def convert_to_2bpp(filenames=[]):
elif extension == '.png':
export_png_to_2bpp(filename)
else:
raise Exception, "Don't know how to convert {} to 2bpp!".format(filename)
raise Exception("Don't know how to convert {} to 2bpp!".format(filename))
def convert_to_1bpp(filenames=[]):
for filename in filenames:
@ -877,7 +878,7 @@ def convert_to_1bpp(filenames=[]):
elif extension == '.png':
export_png_to_1bpp(filename)
else:
raise Exception, "Don't know how to convert {} to 1bpp!".format(filename)
raise Exception("Don't know how to convert {} to 1bpp!".format(filename))
def convert_to_png(filenames=[]):
for filename in filenames:
@ -889,7 +890,7 @@ def convert_to_png(filenames=[]):
elif extension == '.png':
pass
else:
raise Exception, "Don't know how to convert {} to png!".format(filename)
raise Exception("Don't know how to convert {} to png!".format(filename))
def compress(filenames=[]):
for filename in filenames:
@ -933,7 +934,7 @@ def main():
}.get(args.mode, None)
if method == None:
raise Exception, "Unknown conversion method!"
raise Exception("Unknown conversion method!")
method(args.filenames)

View File

@ -1,8 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from __future__ import absolute_import
import networkx as nx
from romstr import (
from .romstr import (
RomStr,
relative_jumps,
call_commands,
@ -92,7 +94,7 @@ class RomGraph(nx.DiGraph):
# check if there are any nops (probably not a function)
nops = 0
for (id, command) in func.asm_commands.items():
if command.has_key("id") and command["id"] == 0x0:
if "id" in command and command["id"] == 0x0:
nops += 1
# skip this function
@ -131,7 +133,7 @@ class RomGraph(nx.DiGraph):
Shows some text output describing which nodes point to which other
nodes.
"""
print self.edges()
print(self.edges())
def to_d3(self):
"""

View File

@ -1,7 +1,11 @@
# -*- coding: utf-8 -*-
from bisect import bisect_left, bisect_right
from itertools import izip
try:
from future_builtins import zip
except ImportError:
pass
class IntervalMap(object):
"""
@ -75,7 +79,7 @@ class IntervalMap(object):
((low_bound, high_bound), value)
these items are returned in order"""
previous_bound = None
for (b, v) in izip(self._bounds, self._items):
for (b, v) in zip(self._bounds, self._items):
if v is not None:
yield (previous_bound, b), v
previous_bound = b

View File

@ -2,13 +2,14 @@
"""
Various label/line-related functions.
"""
from __future__ import absolute_import
import os
import json
import logging
import pointers
import sym
from . import pointers
from . import sym
class Labels(object):
"""
@ -31,7 +32,7 @@ class Labels(object):
if not os.path.exists(self.path):
self.filename = find_symfile_in_dir(self.config.path)
if self.filename == None:
raise Exception, "Couldn't find any .sym files. Run rgblink -n to create a .sym file."
raise Exception("Couldn't find any .sym files. Run rgblink -n to create a .sym file.")
self.path = os.path.join(self.config.path, self.filename)
self.labels = sym.read_symfile(self.path)
@ -178,7 +179,7 @@ def get_address_from_line_comment(line, bank=None):
def line_has_label(line):
"""returns True if the line has an asm label"""
if not isinstance(line, str):
raise Exception, "can't check this type of object"
raise Exception("can't check this type of object")
line = line.rstrip(" ").lstrip(" ")
line = remove_quoted_text(line)
if ";" in line:

View File

@ -2,6 +2,7 @@
"""
Pokemon Crystal data de/compression.
"""
from __future__ import print_function
"""
A rundown of Pokemon Crystal's compression scheme:
@ -44,8 +45,8 @@ lz_end = 0xff
bit_flipped = [
sum(((byte >> i) & 1) << (7 - i) for i in xrange(8))
for byte in xrange(0x100)
sum(((byte >> i) & 1) << (7 - i) for i in range(8))
for byte in range(0x100)
]
@ -189,7 +190,7 @@ class Compressed:
)
for method in self.lookback_methods:
min_score = self.min_scores[method]
for address in xrange(self.address+1, self.address+best_score):
for address in range(self.address+1, self.address+best_score):
length, index = self.find_lookback(method, address)
if length > max(min_score, best_score):
# BUG: lookbacks can reduce themselves. This appears to be a bug in the target also.
@ -211,7 +212,7 @@ class Compressed:
def find_lookback(self, method, address=None):
"""Temporarily stubbed, because the real function doesn't run in polynomial time."""
return 0, None
return 0, None
def broken_find_lookback(self, method, address=None):
if address is None:
@ -282,7 +283,7 @@ class Compressed:
return lookback
def get_indexes(self, byte):
if not self.indexes.has_key(byte):
if byte not in self.indexes:
self.indexes[byte] = []
index = -1
while 1:
@ -315,15 +316,15 @@ class Compressed:
def do_winner(self):
winners = filter(
lambda (method, score):
score
> self.min_scores[method] + int(score > lowmax),
lambda method_score:
method_score[1]
> self.min_scores[method_score[0]] + int(method_score[1] > lowmax),
self.scores.iteritems()
)
winners.sort(
key = lambda (method, score): (
-(score - self.min_scores[method] - int(score > lowmax)),
self.preference.index(method)
key = lambda method_score1: (
-(method_score1[1] - self.min_scores[method_score1[0]] - int(method_score1[1] > lowmax)),
self.preference.index(method_score1[0])
)
)
winner, score = winners[0]
@ -368,11 +369,11 @@ class Compressed:
output += [offset / 0x100, offset % 0x100] # big endian
if self.debug:
print ' '.join(map(str, [
print(' '.join(map(str, [
cmd, length, '\t',
' '.join(map('{:02x}'.format, output)),
self.data[start_address:start_address+length] if cmd in self.lookback_methods else '',
]))
])))
self.output += output
@ -414,7 +415,7 @@ class Decompressed:
if self.lz is not None:
self.decompress()
if self.debug: print self.command_list()
if self.debug: print(self.command_list())
def command_list(self):
@ -466,7 +467,7 @@ class Decompressed:
self.direction = None
if (self.byte == lz_end):
self.next()
next(self)
break
self.cmd = (self.byte & 0b11100000) >> 5
@ -474,11 +475,11 @@ class Decompressed:
if self.cmd_name == 'long':
# 10-bit length
self.cmd = (self.byte & 0b00011100) >> 2
self.length = (self.next() & 0b00000011) * 0x100
self.length += self.next() + 1
self.length = (next(self) & 0b00000011) * 0x100
self.length += next(self) + 1
else:
# 5-bit length
self.length = (self.next() & 0b00011111) + 1
self.length = (next(self) & 0b00011111) + 1
self.__class__.__dict__[self.cmd_name](self)
@ -515,12 +516,12 @@ class Decompressed:
if self.byte >= 0x80: # negative
# negative
offset = self.next() & 0x7f
offset = next(self) & 0x7f
offset = len(self.output) - offset - 1
else:
# positive
offset = self.next() * 0x100
offset += self.next()
offset = next(self) * 0x100
offset += next(self)
self.offset = offset
@ -536,14 +537,14 @@ class Decompressed:
"""
Write one byte repeatedly.
"""
self.output += [self.next()] * self.length
self.output += [next(self)] * self.length
def alternate(self):
"""
Write alternating bytes.
"""
alts = [self.next(), self.next()]
self.output += [ alts[x & 1] for x in xrange(self.length) ]
alts = [next(self), next(self)]
self.output += [ alts[x & 1] for x in range(self.length) ]
def blank(self):
"""
@ -575,6 +576,6 @@ class Decompressed:
self.get_offset()
self.direction = direction
# Note: appends must be one at a time (this way, repeats can draw from themselves if required)
for i in xrange(self.length):
for i in range(self.length):
byte = self.output[ self.offset + i * direction ]
self.output.append( table[byte] if table else byte )

View File

@ -1,3 +1,4 @@
from __future__ import absolute_import
import os
import sys
import logging
@ -36,10 +37,10 @@ from PIL import (
ImageTk,
)
import gfx
import wram
import preprocessor
import configuration
from . import gfx
from . import wram
from . import preprocessor
from . import configuration
config = configuration.Config()

View File

@ -1,9 +1,11 @@
"""
Map-related graphic functions.
"""
from __future__ import print_function
from __future__ import absolute_import
import os
import png
from . import png
from io import BytesIO
from PIL import (
@ -11,8 +13,8 @@ from PIL import (
ImageDraw,
)
import crystal
import gfx
from . import crystal
from . import gfx
tile_width = 8
tile_height = 8
@ -285,7 +287,7 @@ def draw_map_sprites(map_header, map_image, config=config):
other_args = {}
if sprite_image_id not in sprites.keys() or sprite_image_id > 0x66:
print "sprite_image_id {} is not in sprites".format(sprite_image_id)
print("sprite_image_id {} is not in sprites".format(sprite_image_id))
sprite_image = Image.new("RGBA", (16, 16))
@ -362,7 +364,7 @@ def save_map(map_group_id, map_id, savedir, show_sprites=True, config=config):
palettes = read_palettes(config=config)
print "Drawing {}".format(map_name)
print("Drawing {}".format(map_name))
map_image = draw_map(map_group_id, map_id, palettes, show_sprites=show_sprites, config=config)
map_image.save(filepath)

View File

@ -5,21 +5,22 @@ do anything on its own.
old_parse is a part of the Script class
"""
from __future__ import print_function
def old_parse(self, *args, **kwargs):
"""parses a script-engine script; force=True if you want to re-parse
and get the debug information"""
print "Script.old_parse address="+hex(self.address)
print("Script.old_parse address="+hex(self.address))
#can't handle more than one argument
if len(args) > 1:
raise Exception, "Script.parse_script doesn't know how to handle positional arguments"
raise Exception("Script.parse_script doesn't know how to handle positional arguments")
#use the first positional argument as the address
elif len(args) == 1:
self.address = args[0]
if type(self.address) == str:
self.address = int(self.address, 16)
elif type(self.address) != int:
raise Exception, "address param is the wrong type"
raise Exception("address param is the wrong type")
#parse any keyword arguments, first make up the defaults
kwargsorig = {"map_group": None, "map_id": None, "force": False, "debug": True, "origin": False}
#let the caller override any defaults
@ -48,16 +49,16 @@ def old_parse(self, *args, **kwargs):
#don't parse these crazy things (battle tower things, some rival things, etc.)
if address in stop_points:
print "got " + hex(address) + ".. map_group=" + str(map_group) + " map_id=" + str(map_id)
print("got " + hex(address) + ".. map_group=" + str(map_group) + " map_id=" + str(map_id))
return None
#don't parse anything that looks crazy
if address < 0x4000 and address not in [0x26ef, 0x114, 0x1108]:
print "address is less than 0x4000.. address is: " + hex(address)
print("address is less than 0x4000.. address is: " + hex(address))
sys.exit()
#check if work is being repeated
if is_script_already_parsed_at(address) and not force:
raise Exception, "this script has already been parsed before, please use that instance"
raise Exception("this script has already been parsed before, please use that instance")
#use the commands from a previously-parsed Script object
#self.commands = script_parse_table[address].commands
#return True
@ -90,8 +91,8 @@ def old_parse(self, *args, **kwargs):
start_address = offset
if (len(commands.keys()) > max_cmds) and origin != False:
print "too many commands in this script? might not be a script (starting at: " +\
hex(original_start_address) + ").. called from a script at: " + hex(origin)
print("too many commands in this script? might not be a script (starting at: " +\
hex(original_start_address) + ").. called from a script at: " + hex(origin))
sys.exit()
#start checking against possible command bytes
@ -107,12 +108,12 @@ def old_parse(self, *args, **kwargs):
last_byte_address = offset + size - 1
pointer = calculate_pointer_from_bytes_at(start_address+1)
if pointer == None:
raise Exception, "pointer is None (shouldn't be None pointer on 0x0 script command"
raise Exception("pointer is None (shouldn't be None pointer on 0x0 script command")
command["pointer"] = pointer
if debug:
print "in script starting at "+hex(original_start_address)+\
print("in script starting at "+hex(original_start_address)+\
" about to parse script at "+hex(pointer)+\
" called by "+info+" byte="+hex(command_byte)
" called by "+info+" byte="+hex(command_byte))
script = rec_parse_script_engine_script_at(pointer, original_start_address, debug=debug)
command["script"] = script
elif command_byte == 0x01: #Pointer code [3b+ret]
@ -126,9 +127,9 @@ def old_parse(self, *args, **kwargs):
info = "pointer code"
pointer = calculate_pointer_from_bytes_at(start_address+1, bank=True)
if debug:
print "in script starting at "+hex(original_start_address)+\
print("in script starting at "+hex(original_start_address)+\
" about to parse script at "+hex(pointer)+\
" called by "+info+" byte="+hex(command_byte)
" called by "+info+" byte="+hex(command_byte))
script = rec_parse_script_engine_script_at(pointer, original_start_address, debug)
command["pointer"] = pointer
command["script"] = script
@ -141,9 +142,9 @@ def old_parse(self, *args, **kwargs):
size = 3
pointer = calculate_pointer_from_bytes_at(start_address+1)
if debug:
print "in script starting at "+hex(original_start_address)+\
print("in script starting at "+hex(original_start_address)+\
" about to parse script at "+hex(pointer)+\
" called by "+info+" byte="+hex(command_byte)
" called by "+info+" byte="+hex(command_byte))
script = rec_parse_script_engine_script_at(pointer, original_start_address, debug=debug)
command["pointer"] = pointer
command["script"] = script
@ -157,9 +158,9 @@ def old_parse(self, *args, **kwargs):
size = 3
pointer = calculate_pointer_from_bytes_at(start_address+1)
if debug:
print "in script starting at "+hex(original_start_address)+\
print("in script starting at "+hex(original_start_address)+\
" about to parse script at "+hex(pointer)+\
" called by "+info+" byte="+hex(command_byte)
" called by "+info+" byte="+hex(command_byte))
script = rec_parse_script_engine_script_at(pointer, original_start_address, debug=debug)
command["pointer"] = pointer
command["script"] = script
@ -173,9 +174,9 @@ def old_parse(self, *args, **kwargs):
size = 4
pointer = calculate_pointer_from_bytes_at(start_address+1, bank=True)
if debug:
print "in script starting at "+hex(original_start_address)+\
print("in script starting at "+hex(original_start_address)+\
" about to parse script at "+hex(pointer)+\
" called by "+info+" byte="+hex(command_byte)
" called by "+info+" byte="+hex(command_byte))
script = rec_parse_script_engine_script_at(pointer, original_start_address, debug=debug)
command["pointer"] = pointer
command["script"] = script
@ -191,9 +192,9 @@ def old_parse(self, *args, **kwargs):
command["target_pointer"] = calculate_pointer_from_bytes_at(command["pointer"], bank=True)
if debug:
print "in script starting at "+hex(original_start_address)+\
print("in script starting at "+hex(original_start_address)+\
" about to parse script at "+hex(command["target_pointer"])+\
" called by "+info+" byte="+hex(command_byte)
" called by "+info+" byte="+hex(command_byte))
script = rec_parse_script_engine_script_at(command["target_pointer"], original_start_address, debug=debug)
command["script"] = script
end = True #according to pksv
@ -207,9 +208,9 @@ def old_parse(self, *args, **kwargs):
command["byte"] = ord(rom[start_address+1])
pointer = calculate_pointer_from_bytes_at(start_address+2)
if debug:
print "in script starting at "+hex(original_start_address)+\
print("in script starting at "+hex(original_start_address)+\
" about to parse script at "+hex(pointer)+\
" called by "+info+" byte="+hex(command_byte)
" called by "+info+" byte="+hex(command_byte))
script = rec_parse_script_engine_script_at(pointer, original_start_address, debug=debug)
command["pointer"] = pointer
command["script"] = script
@ -223,9 +224,9 @@ def old_parse(self, *args, **kwargs):
command["byte"] = ord(rom[start_address+1])
pointer = calculate_pointer_from_bytes_at(start_address+2)
if debug:
print "in script starting at "+hex(original_start_address)+\
print("in script starting at "+hex(original_start_address)+\
" about to parse script at "+hex(pointer)+\
" called by "+info+" byte="+hex(command_byte)
" called by "+info+" byte="+hex(command_byte))
script = rec_parse_script_engine_script_at(pointer, original_start_address, debug=debug)
command["pointer"] = pointer
command["script"] = script
@ -238,9 +239,9 @@ def old_parse(self, *args, **kwargs):
size = 3
pointer = calculate_pointer_from_bytes_at(start_address+1)
if debug:
print "in script starting at "+hex(original_start_address)+\
print("in script starting at "+hex(original_start_address)+\
" about to parse script at "+hex(pointer)+\
" called by "+info+" byte="+hex(command_byte)
" called by "+info+" byte="+hex(command_byte))
script = rec_parse_script_engine_script_at(pointer, original_start_address, debug=debug)
command["pointer"] = pointer
command["script"] = script
@ -253,9 +254,9 @@ def old_parse(self, *args, **kwargs):
size = 3
pointer = calculate_pointer_from_bytes_at(start_address+1)
if debug:
print "in script starting at "+hex(original_start_address)+\
print("in script starting at "+hex(original_start_address)+\
" about to parse script at "+hex(pointer)+\
" called by "+info+" byte="+hex(command_byte)
" called by "+info+" byte="+hex(command_byte))
script = rec_parse_script_engine_script_at(pointer, original_start_address, debug=debug)
command["pointer"] = pointer
command["script"] = script
@ -269,9 +270,9 @@ def old_parse(self, *args, **kwargs):
command["byte"] = ord(rom[start_address+1])
pointer = calculate_pointer_from_bytes_at(start_address+2)
if debug:
print "in script starting at "+hex(original_start_address)+\
print("in script starting at "+hex(original_start_address)+\
" about to parse script at "+hex(pointer)+\
" called by "+info+" byte="+hex(command_byte)
" called by "+info+" byte="+hex(command_byte))
script = rec_parse_script_engine_script_at(pointer, original_start_address, debug=debug)
command["pointer"] = pointer
command["script"] = script
@ -285,9 +286,9 @@ def old_parse(self, *args, **kwargs):
command["byte"] = ord(rom[start_address+1])
pointer = calculate_pointer_from_bytes_at(start_address+2)
if debug:
print "in script starting at "+hex(original_start_address)+\
print("in script starting at "+hex(original_start_address)+\
" about to parse script at "+hex(pointer)+\
" called by "+info+" byte="+hex(command_byte)
" called by "+info+" byte="+hex(command_byte))
script = rec_parse_script_engine_script_at(pointer, original_start_address, debug=debug)
command["pointer"] = pointer
command["script"] = script
@ -1588,9 +1589,9 @@ def old_parse(self, *args, **kwargs):
size = 3
script_pointer = calculate_pointer_from_bytes_at(start_address+1, bank=False)
if debug:
print "in script starting at "+hex(original_start_address)+\
print("in script starting at "+hex(original_start_address)+\
" about to parse script at "+hex(script_pointer)+\
" called by "+info+" byte="+hex(command_byte)
" called by "+info+" byte="+hex(command_byte))
script = rec_parse_script_engine_script_at(script_pointer, original_start_address, debug=debug)
command["script_pointer"] = script_pointer
command["script"] = script
@ -1612,9 +1613,9 @@ def old_parse(self, *args, **kwargs):
size = 3
script_pointer = calculate_pointer_from_bytes_at(start_address+1, bank=False)
if debug:
print "in script starting at "+hex(original_start_address)+\
print("in script starting at "+hex(original_start_address)+\
" about to parse script at "+hex(script_pointer)+\
" called by "+info+" byte="+hex(command_byte)
" called by "+info+" byte="+hex(command_byte))
script = rec_parse_script_engine_script_at(script_pointer, original_start_address, debug=debug)
command["script_pointer"] = script_pointer
command["script"] = script
@ -1854,7 +1855,7 @@ def old_parse(self, *args, **kwargs):
size = 1
#end = True
#raise NotImplementedError, "command byte is " + hex(command_byte) + " at " + hex(offset) + " on map " + str(map_group) + "." + str(map_id)
print "dunno what this command is: " + hex(command_byte)
print("dunno what this command is: " + hex(command_byte))
long_info = clean_up_long_info(long_info)
if command_byte in pksv_crystal.keys():
@ -1867,7 +1868,7 @@ def old_parse(self, *args, **kwargs):
pksv_no_names[command_byte] = [address]
if debug:
print command_debug_information(command_byte=command_byte, map_group=map_group, map_id=map_id, address=offset, info=info, long_info=long_info, pksv_name=pksv_name)
print(command_debug_information(command_byte=command_byte, map_group=map_group, map_id=map_id, address=offset, info=info, long_info=long_info, pksv_name=pksv_name))
#store the size of the command
command["size"] = size

View File

@ -1,8 +1,9 @@
"""
An old implementation of TextScript that may not be useful anymore.
"""
from __future__ import absolute_import
import pointers
from . import pointers
class OldTextScript:
"a text is a sequence of commands different from a script-engine script"
@ -43,7 +44,7 @@ class OldTextScript:
if signpost["func"] in [0, 1, 2, 3, 4]:
# dump this into script
script = signpost["script"]
elif signpost["func"] in [05, 06]:
elif signpost["func"] in [0o5, 0o6]:
script = signpost["script"]
else: continue
# skip signposts with no bytes

View File

@ -1,4 +1,5 @@
import gfx
from __future__ import absolute_import
from . import gfx
def rip_sprites_from_bank(bank, offset=0):
"""

View File

@ -1,6 +1,8 @@
from __future__ import print_function
from __future__ import absolute_import
import sys
import crystal
from . import crystal
rom = crystal.load_rom()
@ -16,10 +18,10 @@ for i in range(count):
asm = string.to_asm()
except Exception as ex:
break
print label_prefix+str(i)+": ; "+hex(addr)
print "\t"+asm
print
print(label_prefix+str(i)+": ; "+hex(addr))
print("\t"+asm)
print()
addr = string.last_address
print "; "+hex(addr)
print("; "+hex(addr))
if ex: raise ex

View File

@ -1,5 +1,8 @@
# pcm.py
# Converts between .wav files and 1-bit pcm data. (pcm = pulse-code modulation)
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import argparse
import os
@ -72,7 +75,7 @@ def convert_to_pcm(filenames=[]):
# Pack the 1-bit samples together.
packed_samples = bytearray()
for i in xrange(0, len(clamped_samples), 8):
for i in range(0, len(clamped_samples), 8):
# Read 8 pcm values to pack one byte.
packed_value = 0
for j in range(8):
@ -103,14 +106,14 @@ def get_wav_samples(filename):
# Unpack the values based on the sample byte width.
unpacked_samples = []
for i in xrange(0, len(samples), sample_width):
for i in range(0, len(samples), sample_width):
if sample_width == 1:
fmt = 'B'
elif sample_width == 2:
fmt = 'h'
else:
# todo: support 3-byte sample width
raise Exception, "Unsupported sample width: " + str(sample_width)
raise Exception("Unsupported sample width: " + str(sample_width))
value = struct.unpack(fmt, samples[i:i + sample_width])[0]
unpacked_samples.append(value)
@ -122,7 +125,7 @@ def get_wav_samples(filename):
# Also find the average amplitude of the samples.
resampled_samples = []
total_value = 0
interval = float(sample_rate) / BASE_SAMPLE_RATE
interval = sample_rate / BASE_SAMPLE_RATE
index = 0
while index < sample_count:
sample = unpacked_samples[int(index)]
@ -131,7 +134,7 @@ def get_wav_samples(filename):
resampled_samples.append(sample)
index += interval
average_sample = float(total_value) / len(resampled_samples)
average_sample = total_value / len(resampled_samples)
return resampled_samples, average_sample
@ -148,7 +151,7 @@ def main():
}.get(args.mode, None)
if method == None:
raise Exception, "Unknown conversion method!"
raise Exception("Unknown conversion method!")
method(args.filenames)

View File

@ -3,13 +3,15 @@
"""
A library for use with compressed monster and trainer pics in pokered.
"""
from __future__ import absolute_import
from __future__ import division
import os
import sys
import argparse
from math import sqrt
from gfx import transpose_tiles
from .gfx import transpose_tiles
def bitflip(x, n):
@ -28,14 +30,14 @@ class Decompressor:
Ported to python 2.7 from the python 3 code at https://github.com/magical/pokemon-sprites-rby.
"""
table1 = [(2 << i) - 1 for i in xrange(16)]
table1 = [(2 << i) - 1 for i in range(16)]
table2 = [
[0x0, 0x1, 0x3, 0x2, 0x7, 0x6, 0x4, 0x5, 0xf, 0xe, 0xc, 0xd, 0x8, 0x9, 0xb, 0xa],
[0xf, 0xe, 0xc, 0xd, 0x8, 0x9, 0xb, 0xa, 0x0, 0x1, 0x3, 0x2, 0x7, 0x6, 0x4, 0x5], # prev ^ 0xf
[0x0, 0x8, 0xc, 0x4, 0xe, 0x6, 0x2, 0xa, 0xf, 0x7, 0x3, 0xb, 0x1, 0x9, 0xd, 0x5],
[0xf, 0x7, 0x3, 0xb, 0x1, 0x9, 0xd, 0x5, 0x0, 0x8, 0xc, 0x4, 0xe, 0x6, 0x2, 0xa], # prev ^ 0xf
]
table3 = [bitflip(i, 4) for i in xrange(16)]
table3 = [bitflip(i, 4) for i in range(16)]
tilesize = 8
@ -79,7 +81,7 @@ class Decompressor:
self._decode(rams[r1])
self._xor(rams[r1], rams[r2])
else:
raise Exception, "Invalid deinterlace mode!"
raise Exception("Invalid deinterlace mode!")
data = []
if self.planar:
@ -117,7 +119,7 @@ class Decompressor:
a = self._readint(i + 1)
n += a
for i in xrange(n):
for i in range(n):
ram.append(0)
def _read_data_chunk(self, ram, size):
@ -134,9 +136,9 @@ class Decompressor:
if mirror is None:
mirror = self.mirror
for x in xrange(self.sizex):
for x in range(self.sizex):
bit = 0
for y in xrange(self.sizey):
for y in range(self.sizey):
i = y * self.sizex + x
a = (ram[i] >> 4) & 0xf
b = ram[i] & 0xf
@ -157,7 +159,7 @@ class Decompressor:
if mirror is None:
mirror = self.mirror
for i in xrange(len(ram2)):
for i in range(len(ram2)):
if mirror:
a = (ram2[i] >> 4) & 0xf
b = ram2[i] & 0xf
@ -169,10 +171,10 @@ class Decompressor:
def _deinterlace_bitgroups(self, bits):
l = []
for y in xrange(self.sizey):
for x in xrange(self.sizex):
for y in range(self.sizey):
for x in range(self.sizex):
i = 4 * y * self.sizex + x
for j in xrange(4):
for j in range(4):
l.append(bits[i])
i += self.sizex
return l
@ -192,12 +194,12 @@ def fbitstream(f):
break
byte = ord(char)
for i in xrange(7, -1, -1):
for i in range(7, -1, -1):
yield (byte >> i) & 1
def bitstream(b):
for byte in b:
for i in xrange(7, -1, -1):
for i in range(7, -1, -1):
yield (byte >> i) & 1
def readint(bs, count):
@ -210,7 +212,7 @@ def readint(bs, count):
def bitgroups_to_bytes(bits):
l = []
for i in xrange(0, len(bits) - 3, 4):
for i in range(0, len(bits) - 3, 4):
n = ((bits[i + 0] << 6)
| (bits[i + 1] << 4)
| (bits[i + 2] << 2)
@ -230,21 +232,21 @@ class Compressor:
Adapted from stag019's C compressor.
"""
table1 = [(2 << i) - 1 for i in xrange(16)]
table1 = [(2 << i) - 1 for i in range(16)]
table2 = [
[0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4, 0xc, 0xd, 0xf, 0xe, 0xa, 0xb, 0x9, 0x8],
[0x8, 0x9, 0xb, 0xa, 0xe, 0xf, 0xd, 0xc, 0x4, 0x5, 0x7, 0x6, 0x2, 0x3, 0x1, 0x0], # reverse
]
table3 = [bitflip(i, 4) for i in xrange(16)]
table3 = [bitflip(i, 4) for i in range(16)]
def __init__(self, image, width=None, height=None):
self.image = bytearray(image)
self.size = len(self.image)
planar_tile = 8 * 8 / 4
tile_size = self.size / planar_tile
if height and not width: width = tile_size / height
elif width and not height: height = tile_size / width
planar_tile = 8 * 8 // 4
tile_size = self.size // planar_tile
if height and not width: width = tile_size // height
elif width and not height: height = tile_size // width
elif not width and not height: width = height = int(sqrt(tile_size))
self.width, self.height = width, height
@ -256,7 +258,7 @@ class Compressor:
rams = [[],[]]
datas = []
for mode in xrange(3):
for mode in range(3):
# Order is redundant for mode 0.
@ -269,16 +271,16 @@ class Compressor:
# Using order 0 instead of 1 breaks this feature.
for order in xrange(2):
for order in range(2):
if mode == 0 and order == 0:
continue
for i in xrange(2):
for i in range(2):
rams[i] = self.image[i::2]
self._interpret_compress(rams, mode, order)
datas += [(self.data[:], int(self.which_bit))]
# Pick the smallest pic, measured in bits.
datas = sorted(datas, key=lambda (data, bit): (len(data), -bit))
datas = sorted(datas, key=lambda data_bit: (len(data_bit[0]), -data_bit[1]))
self.data, self.which_bit = datas[0]
def _interpret_compress(self, rams, mode, order):
@ -299,7 +301,7 @@ class Compressor:
self._encode(rams[r1])
self._encode(rams[r2], mirror=False)
else:
raise Exception, 'invalid interlace mode!'
raise Exception('invalid interlace mode!')
self._writeint(self.height, 4)
self._writeint(self.width, 4)
@ -319,10 +321,10 @@ class Compressor:
nums = 0
bitgroups = []
for x in xrange(self.width):
for bit in xrange(0, 8, 2):
for x in range(self.width):
for bit in range(0, 8, 2):
byte = x * self.height * 8
for y in xrange(self.height * 8):
for y in range(self.height * 8):
bitgroup = (ram[byte] >> (6 - bit)) & 3
if bitgroup == 0:
if rle == 0:
@ -377,16 +379,16 @@ class Compressor:
v >>= 1
bitcount += 1
for j in xrange(bitcount):
for j in range(bitcount):
self._writebit(1)
self._writebit(0)
for j in xrange(bitcount, -1, -1):
for j in range(bitcount, -1, -1):
self._writebit((number >> j) & 1)
def _encode(self, ram, mirror=None):
a = b = 0
for i in xrange(len(ram)):
j = i / self.height
for i in range(len(ram)):
j = i // self.height
j += i % self.height * self.width * 8
if i % self.height == 0:
b = 0
@ -402,7 +404,7 @@ class Compressor:
ram[j] = (code_1 << 4) | code_2
def _xor(self, ram1, ram2):
for i in xrange(len(ram2)):
for i in range(len(ram2)):
ram2[i] ^= ram1[i]
def _writebit(self, bit):
@ -415,7 +417,7 @@ class Compressor:
def _writeint(self, num, size=None):
bits = []
if size:
for i in xrange(size):
for i in range(size):
bits += [num & 1]
num >>= 1
else:
@ -468,7 +470,7 @@ def compress_file(filename):
pic = bytearray(pic)
output_filename = os.path.splitext(filename)[0] + '.pic'
with open(output_filename, 'wb') as out:
out.write(pic)
out.write(pic)
def main():

View File

@ -2,12 +2,13 @@
"""
Basic preprocessor for both pokecrystal and pokered.
"""
from __future__ import absolute_import
import os
import sys
import exceptions
import crystal
from . import exceptions
from . import crystal
chars = {
"": 0x05,
@ -565,11 +566,11 @@ class Preprocessor(object):
if show_original_lines:
sys.stdout.write("; original_line: " + original_line)
# rgbasm can handle other macros too
# rgbasm can handle other macros too
if "is_rgbasm_macro" in dir(macro):
if macro.is_rgbasm_macro:
sys.stdout.write(original_line)
return
return
# certain macros don't need an initial byte written
# do: all scripting macros

View File

@ -1,316 +1,317 @@
import configuration
config = configuration.Config()
rom = bytearray(open(config.rom_path, "r").read())
songs = [
"PalletTown",
"Pokecenter",
"Gym",
"Cities1",
"Cities2",
"Celadon",
"Cinnabar",
"Vermilion",
"Lavender",
"SSAnne",
"MeetProfOak",
"MeetRival",
"MuseumGuy",
"SafariZone",
"PkmnHealed",
"Routes1",
"Routes2",
"Routes3",
"Routes4",
"IndigoPlateau",
"GymLeaderBattle",
"TrainerBattle",
"WildBattle",
"FinalBattle",
"DefeatedTrainer",
"DefeatedWildMon",
"DefeatedGymLeader",
"TitleScreen",
"Credits",
"HallOfFame",
"OaksLab",
"JigglypuffSong",
"BikeRiding",
"Surfing",
"GameCorner",
"IntroBattle",
"Dungeon1",
"Dungeon2",
"Dungeon3",
"CinnabarMansion",
"PokemonTower",
"SilphCo",
"MeetEvilTrainer",
"MeetFemaleTrainer",
"MeetMaleTrainer",
"UnusedSong",
]
"""
songs = [
"YellowIntro",
"SurfingPikachu",
"MeetJessieJames",
"YellowUnusedSong",
]
"""
music_commands = {
0xd0: ["notetype", {"type": "nibble"}, 2],
0xe0: ["octave", 1],
0xe8: ["toggleperfectpitch", 1],
0xea: ["vibrato", {"type": "byte"}, {"type": "nibble"}, 3],
0xeb: ["pitchbend", {"type": "byte"}, {"type": "byte"}, 3],
0xec: ["duty", {"type": "byte"}, 2],
0xed: ["tempo", {"type": "word"}, 3],
0xee: ["stereopanning", {"type": "byte"}, 2],
0xf0: ["volume", {"type": "nibble"}, 2],
0xf8: ["executemusic", 1],
0xfc: ["dutycycle", {"type": "byte"}, 2],
0xfd: ["callchannel", {"type": "label"}, 3],
0xfe: ["loopchannel", {"type": "byte"}, {"type": "label"}, 4],
0xff: ["endchannel", 1],
}
param_lengths = {
"nibble": 1,
"byte": 1,
"word": 2,
"label": 2,
}
music_notes = {
0x0: "C_",
0x1: "C#",
0x2: "D_",
0x3: "D#",
0x4: "E_",
0x5: "F_",
0x6: "F#",
0x7: "G_",
0x8: "G#",
0x9: "A_",
0xa: "A#",
0xb: "B_",
}
def printnoisechannel(songname, songfile, startingaddress, bank, output):
noise_commands = {
0xfd: ["callchannel", {"type": "label"}, 3],
0xfe: ["loopchannel", {"type": "byte"}, {"type": "label"}, 4],
0xff: ["endchannel", 1],
}
noise_instruments = {
0x01: "snare1",
0x02: "snare2",
0x03: "snare3",
0x04: "snare4",
0x05: "snare5",
0x06: "triangle1",
0x07: "triangle2",
0x08: "snare6",
0x09: "snare7",
0x0a: "snare8",
0x0b: "snare9",
0x0c: "cymbal1",
0x0d: "cymbal2",
0x0e: "cymbal3",
0x0f: "mutedsnare1",
0x10: "triangle3",
0x11: "mutedsnare2",
0x12: "mutedsnare3",
0x13: "mutedsnare4",
}
# pass 1, build a list of all addresses pointed to by calls and loops
address = startingaddress
labels = []
labelsleft= []
while 1:
byte = rom[address]
if byte < 0xc0:
command_length = 2
elif byte < 0xe0:
command_length = 1
else:
command_length = noise_commands[byte][-1]
if byte == 0xfd or byte == 0xfe:
label = rom[address + command_length - 1] * 0x100 + rom[address + command_length - 2]
labels.append(label)
if label > address % 0x4000 + 0x4000: labelsleft.append(label)
address += command_length
if len(labelsleft) == 0 and (byte == 0xfe and rom[address - command_length + 1] == 0 and rom[address - 1] * 0x100 + rom[address - 2] < address % 0x4000 + 0x4000 or byte == 0xff): break
while address % 0x4000 + 0x4000 in labelsleft: labelsleft.remove(address % 0x4000 + 0x4000)
# once the loop ends, start over from first address
if rom[address] == 0xff: address += 1
end = address
address = startingaddress
byte = rom[address]
output += "Music_{}_Ch4:: ; {:02x} ({:0x}:{:02x})\n".format(songname, address, bank, address % 0x4000 + 0x4000)
# pass 2, print commands and labels for addresses that are in labels
while address != end:
if address % 0x4000 + 0x4000 in labels and address != startingaddress:
output += "\nMusic_{}_branch_{:02x}::\n".format(songname, address)
if byte < 0xc0:
output += "\t{} {}".format(noise_instruments[rom[address + 1]], byte % 0x10 + 1)
command_length = 2
elif byte < 0xd0:
output += "\trest {}".format(byte % 0x10 + 1)
command_length = 1
elif byte < 0xe0:
output += "\tdspeed {}".format(byte % 0x10)
command_length = 1
else:
command = noise_commands[byte]
output += "\t{}".format(command[0])
command_length = 1
params = 1
# print all params for current command
while params != len(noise_commands[byte]) - 1:
param_type = noise_commands[byte][params]["type"]
address += command_length
command_length = param_lengths[param_type]
param = rom[address]
if param_type == "byte":
output += " {}".format(param)
else:
param += rom[address + 1] * 0x100 - 0x4000 + (bank * 0x4000)
if param == startingaddress: output += " Music_{}_Ch4".format(songname)
else: output += " Music_{}_branch_{:02x}".format(songname, param)
params += 1
if params != len(noise_commands[byte]) - 1: output += ","
output += "\n"
address += command_length
byte = rom[address]
output += "; {}\n".format(hex(address))
songfile.write(output)
for i, songname in enumerate(songs):
songfile = open("music/" + songname.lower() + ".asm", 'a')
if songname == "PalletTown": header = 0x822e
if songname == "GymLeaderBattle": header = 0x202be
if songname == "TitleScreen": header = 0x7c249
if songname == "YellowIntro": header = 0x7c294
if songname == "SurfingPikachu": header = 0x801cb
bank = header / 0x4000
startingaddress = rom[header + 2] * 0x100 + rom[header + 1] - 0x4000 + (0x4000 * bank)
curchannel = 1
lastchannel = (rom[header] >> 6) + 1
exception = False
if songname == "MeetRival" or songname == "Cities1":
startingaddress -= 7
exception = True
if songname == "UnusedSong":
bank = 2
startingaddress = 0xa913
lastchannel = 2
output = ''
while 1:
# pass 1, build a list of all addresses pointed to by calls and loops
address = startingaddress
labels = []
labelsleft = []
if songname == "MeetRival":
if curchannel == 1:
labels.append(0x719b)
labelsleft.append(0x719b)
labels.append(0x71a2)
labelsleft.append(0x71a2)
if curchannel == 2:
labels.append(0x721d)
labelsleft.append(0x721d)
if curchannel == 3:
labels.append(0x72b5)
labelsleft.append(0x72b5)
while 1:
byte = rom[address]
if byte < 0xd0:
command_length = 1
elif byte < 0xe0:
command_length = 2
elif byte < 0xe8:
command_length = 1
else:
command_length = music_commands[byte][-1]
if byte == 0xfd or byte == 0xfe:
label = rom[address + command_length - 1] * 0x100 + rom[address + command_length - 2]
labels.append(label)
if label > address % 0x4000 + 0x4000: labelsleft.append(label)
address += command_length
if len(labelsleft) == 0 and (exception == False or address > startingaddress + 7) and (byte == 0xfe and rom[address - command_length + 1] == 0 and rom[address - 1] * 0x100 + rom[address - 2] < address % 0x4000 + 0x4000 or byte == 0xff): break
while address % 0x4000 + 0x4000 in labelsleft: labelsleft.remove(address % 0x4000 + 0x4000)
# once the loop breaks, start over from first address
if rom[address] == 0xff: address += 1
end = address
if curchannel != lastchannel and songname != "UnusedSong": end = rom[header + 5] * 0x100 + rom[header + 4] + (0x4000 * (bank - 1))
address = startingaddress
byte = rom[address]
# if song has an alternate start to channel 1, print a label and set startingaddress to true channel start
if exception:
output += "Music_{}_branch_{:02x}::\n".format(songname, address)
startingaddress += 7
# pass 2, print commands and labels for addresses that are in labels
while address != end:
if address == startingaddress:
if exception: output += "\n"
output += "Music_{}_Ch{}:: ; {:02x} ({:0x}:{:02x})\n".format(songname, curchannel, address, bank, address % 0x4000 + 0x4000)
elif address % 0x4000 + 0x4000 in labels:
output += "\nMusic_{}_branch_{:02x}::\n".format(songname, address)
if byte < 0xc0:
output += "\t{} {}".format(music_notes[byte >> 4], byte % 0x10 + 1)
command_length = 1
elif byte < 0xd0:
output += "\trest {}".format(byte % 0x10 + 1)
command_length = 1
else:
if byte < 0xe0:
command = music_commands[0xd0]
output += "\t{} {},".format(command[0], byte % 0x10)
byte = 0xd0
elif byte < 0xe8:
command = music_commands[0xe0]
output += "\t{} {}".format(command[0], 0xe8 - byte)
byte = 0xe0
else:
command = music_commands[byte]
output += "\t{}".format(command[0])
command_length = 1
params = 1
# print all params for current command
while params != len(music_commands[byte]) - 1:
param_type = music_commands[byte][params]["type"]
address += command_length
command_length = param_lengths[param_type]
param = rom[address]
if param_type == "nibble":
output += " {}, {}".format(param >> 4, param % 0x10)
elif param_type == "byte":
output += " {}".format(param)
elif param_type == "word":
output += " {}".format(param * 0x100 + rom[address + 1])
else:
param += rom[address + 1] * 0x100 - 0x4000 + (bank * 0x4000)
if param == startingaddress: output += " Music_{}_Ch{}".format(songname, curchannel)
else: output += " Music_{}_branch_{:02x}".format(songname, param)
params += 1
if params != len(music_commands[byte]) - 1: output += ","
output += "\n"
address += command_length
byte = rom[address]
header += 3
if curchannel == lastchannel:
output += "; {}\n".format(hex(address))
songfile.write(output)
break
curchannel += 1
output += "\n\n"
startingaddress = end
exception = False
if curchannel == 4:
printnoisechannel(songname, songfile, startingaddress, bank, output)
header += 3
from __future__ import absolute_import
from . import configuration
config = configuration.Config()
rom = bytearray(open(config.rom_path, "r").read())
songs = [
"PalletTown",
"Pokecenter",
"Gym",
"Cities1",
"Cities2",
"Celadon",
"Cinnabar",
"Vermilion",
"Lavender",
"SSAnne",
"MeetProfOak",
"MeetRival",
"MuseumGuy",
"SafariZone",
"PkmnHealed",
"Routes1",
"Routes2",
"Routes3",
"Routes4",
"IndigoPlateau",
"GymLeaderBattle",
"TrainerBattle",
"WildBattle",
"FinalBattle",
"DefeatedTrainer",
"DefeatedWildMon",
"DefeatedGymLeader",
"TitleScreen",
"Credits",
"HallOfFame",
"OaksLab",
"JigglypuffSong",
"BikeRiding",
"Surfing",
"GameCorner",
"IntroBattle",
"Dungeon1",
"Dungeon2",
"Dungeon3",
"CinnabarMansion",
"PokemonTower",
"SilphCo",
"MeetEvilTrainer",
"MeetFemaleTrainer",
"MeetMaleTrainer",
"UnusedSong",
]
"""
songs = [
"YellowIntro",
"SurfingPikachu",
"MeetJessieJames",
"YellowUnusedSong",
]
"""
music_commands = {
0xd0: ["notetype", {"type": "nibble"}, 2],
0xe0: ["octave", 1],
0xe8: ["toggleperfectpitch", 1],
0xea: ["vibrato", {"type": "byte"}, {"type": "nibble"}, 3],
0xeb: ["pitchbend", {"type": "byte"}, {"type": "byte"}, 3],
0xec: ["duty", {"type": "byte"}, 2],
0xed: ["tempo", {"type": "word"}, 3],
0xee: ["stereopanning", {"type": "byte"}, 2],
0xf0: ["volume", {"type": "nibble"}, 2],
0xf8: ["executemusic", 1],
0xfc: ["dutycycle", {"type": "byte"}, 2],
0xfd: ["callchannel", {"type": "label"}, 3],
0xfe: ["loopchannel", {"type": "byte"}, {"type": "label"}, 4],
0xff: ["endchannel", 1],
}
param_lengths = {
"nibble": 1,
"byte": 1,
"word": 2,
"label": 2,
}
music_notes = {
0x0: "C_",
0x1: "C#",
0x2: "D_",
0x3: "D#",
0x4: "E_",
0x5: "F_",
0x6: "F#",
0x7: "G_",
0x8: "G#",
0x9: "A_",
0xa: "A#",
0xb: "B_",
}
def printnoisechannel(songname, songfile, startingaddress, bank, output):
noise_commands = {
0xfd: ["callchannel", {"type": "label"}, 3],
0xfe: ["loopchannel", {"type": "byte"}, {"type": "label"}, 4],
0xff: ["endchannel", 1],
}
noise_instruments = {
0x01: "snare1",
0x02: "snare2",
0x03: "snare3",
0x04: "snare4",
0x05: "snare5",
0x06: "triangle1",
0x07: "triangle2",
0x08: "snare6",
0x09: "snare7",
0x0a: "snare8",
0x0b: "snare9",
0x0c: "cymbal1",
0x0d: "cymbal2",
0x0e: "cymbal3",
0x0f: "mutedsnare1",
0x10: "triangle3",
0x11: "mutedsnare2",
0x12: "mutedsnare3",
0x13: "mutedsnare4",
}
# pass 1, build a list of all addresses pointed to by calls and loops
address = startingaddress
labels = []
labelsleft= []
while 1:
byte = rom[address]
if byte < 0xc0:
command_length = 2
elif byte < 0xe0:
command_length = 1
else:
command_length = noise_commands[byte][-1]
if byte == 0xfd or byte == 0xfe:
label = rom[address + command_length - 1] * 0x100 + rom[address + command_length - 2]
labels.append(label)
if label > address % 0x4000 + 0x4000: labelsleft.append(label)
address += command_length
if len(labelsleft) == 0 and (byte == 0xfe and rom[address - command_length + 1] == 0 and rom[address - 1] * 0x100 + rom[address - 2] < address % 0x4000 + 0x4000 or byte == 0xff): break
while address % 0x4000 + 0x4000 in labelsleft: labelsleft.remove(address % 0x4000 + 0x4000)
# once the loop ends, start over from first address
if rom[address] == 0xff: address += 1
end = address
address = startingaddress
byte = rom[address]
output += "Music_{}_Ch4:: ; {:02x} ({:0x}:{:02x})\n".format(songname, address, bank, address % 0x4000 + 0x4000)
# pass 2, print commands and labels for addresses that are in labels
while address != end:
if address % 0x4000 + 0x4000 in labels and address != startingaddress:
output += "\nMusic_{}_branch_{:02x}::\n".format(songname, address)
if byte < 0xc0:
output += "\t{} {}".format(noise_instruments[rom[address + 1]], byte % 0x10 + 1)
command_length = 2
elif byte < 0xd0:
output += "\trest {}".format(byte % 0x10 + 1)
command_length = 1
elif byte < 0xe0:
output += "\tdspeed {}".format(byte % 0x10)
command_length = 1
else:
command = noise_commands[byte]
output += "\t{}".format(command[0])
command_length = 1
params = 1
# print all params for current command
while params != len(noise_commands[byte]) - 1:
param_type = noise_commands[byte][params]["type"]
address += command_length
command_length = param_lengths[param_type]
param = rom[address]
if param_type == "byte":
output += " {}".format(param)
else:
param += rom[address + 1] * 0x100 - 0x4000 + (bank * 0x4000)
if param == startingaddress: output += " Music_{}_Ch4".format(songname)
else: output += " Music_{}_branch_{:02x}".format(songname, param)
params += 1
if params != len(noise_commands[byte]) - 1: output += ","
output += "\n"
address += command_length
byte = rom[address]
output += "; {}\n".format(hex(address))
songfile.write(output)
for i, songname in enumerate(songs):
songfile = open("music/" + songname.lower() + ".asm", 'a')
if songname == "PalletTown": header = 0x822e
if songname == "GymLeaderBattle": header = 0x202be
if songname == "TitleScreen": header = 0x7c249
if songname == "YellowIntro": header = 0x7c294
if songname == "SurfingPikachu": header = 0x801cb
bank = header / 0x4000
startingaddress = rom[header + 2] * 0x100 + rom[header + 1] - 0x4000 + (0x4000 * bank)
curchannel = 1
lastchannel = (rom[header] >> 6) + 1
exception = False
if songname == "MeetRival" or songname == "Cities1":
startingaddress -= 7
exception = True
if songname == "UnusedSong":
bank = 2
startingaddress = 0xa913
lastchannel = 2
output = ''
while 1:
# pass 1, build a list of all addresses pointed to by calls and loops
address = startingaddress
labels = []
labelsleft = []
if songname == "MeetRival":
if curchannel == 1:
labels.append(0x719b)
labelsleft.append(0x719b)
labels.append(0x71a2)
labelsleft.append(0x71a2)
if curchannel == 2:
labels.append(0x721d)
labelsleft.append(0x721d)
if curchannel == 3:
labels.append(0x72b5)
labelsleft.append(0x72b5)
while 1:
byte = rom[address]
if byte < 0xd0:
command_length = 1
elif byte < 0xe0:
command_length = 2
elif byte < 0xe8:
command_length = 1
else:
command_length = music_commands[byte][-1]
if byte == 0xfd or byte == 0xfe:
label = rom[address + command_length - 1] * 0x100 + rom[address + command_length - 2]
labels.append(label)
if label > address % 0x4000 + 0x4000: labelsleft.append(label)
address += command_length
if len(labelsleft) == 0 and (exception == False or address > startingaddress + 7) and (byte == 0xfe and rom[address - command_length + 1] == 0 and rom[address - 1] * 0x100 + rom[address - 2] < address % 0x4000 + 0x4000 or byte == 0xff): break
while address % 0x4000 + 0x4000 in labelsleft: labelsleft.remove(address % 0x4000 + 0x4000)
# once the loop breaks, start over from first address
if rom[address] == 0xff: address += 1
end = address
if curchannel != lastchannel and songname != "UnusedSong": end = rom[header + 5] * 0x100 + rom[header + 4] + (0x4000 * (bank - 1))
address = startingaddress
byte = rom[address]
# if song has an alternate start to channel 1, print a label and set startingaddress to true channel start
if exception:
output += "Music_{}_branch_{:02x}::\n".format(songname, address)
startingaddress += 7
# pass 2, print commands and labels for addresses that are in labels
while address != end:
if address == startingaddress:
if exception: output += "\n"
output += "Music_{}_Ch{}:: ; {:02x} ({:0x}:{:02x})\n".format(songname, curchannel, address, bank, address % 0x4000 + 0x4000)
elif address % 0x4000 + 0x4000 in labels:
output += "\nMusic_{}_branch_{:02x}::\n".format(songname, address)
if byte < 0xc0:
output += "\t{} {}".format(music_notes[byte >> 4], byte % 0x10 + 1)
command_length = 1
elif byte < 0xd0:
output += "\trest {}".format(byte % 0x10 + 1)
command_length = 1
else:
if byte < 0xe0:
command = music_commands[0xd0]
output += "\t{} {},".format(command[0], byte % 0x10)
byte = 0xd0
elif byte < 0xe8:
command = music_commands[0xe0]
output += "\t{} {}".format(command[0], 0xe8 - byte)
byte = 0xe0
else:
command = music_commands[byte]
output += "\t{}".format(command[0])
command_length = 1
params = 1
# print all params for current command
while params != len(music_commands[byte]) - 1:
param_type = music_commands[byte][params]["type"]
address += command_length
command_length = param_lengths[param_type]
param = rom[address]
if param_type == "nibble":
output += " {}, {}".format(param >> 4, param % 0x10)
elif param_type == "byte":
output += " {}".format(param)
elif param_type == "word":
output += " {}".format(param * 0x100 + rom[address + 1])
else:
param += rom[address + 1] * 0x100 - 0x4000 + (bank * 0x4000)
if param == startingaddress: output += " Music_{}_Ch{}".format(songname, curchannel)
else: output += " Music_{}_branch_{:02x}".format(songname, param)
params += 1
if params != len(music_commands[byte]) - 1: output += ","
output += "\n"
address += command_length
byte = rom[address]
header += 3
if curchannel == lastchannel:
output += "; {}\n".format(hex(address))
songfile.write(output)
break
curchannel += 1
output += "\n\n"
startingaddress = end
exception = False
if curchannel == 4:
printnoisechannel(songname, songfile, startingaddress, bank, output)
header += 3
break

View File

@ -1,454 +1,456 @@
import configuration
config = configuration.Config()
rom = bytearray(open(config.rom_path, "r").read())
sfx_names = [
"Snare1_2",
"Snare2_2",
"Snare3_2",
"Snare4_2",
"Snare5_2",
"Triangle1_2",
"Triangle2_2",
"Snare6_2",
"Snare7_2",
"Snare8_2",
"Snare9_2",
"Cymbal1_2",
"Cymbal2_2",
"Cymbal3_2",
"Muted_Snare1_2",
"Triangle3_2",
"Muted_Snare2_2",
"Muted_Snare3_2",
"Muted_Snare4_2",
"Cry00_2",
"Cry01_2",
"Cry02_2",
"Cry03_2",
"Cry04_2",
"Cry05_2",
"Cry06_2",
"Cry07_2",
"Cry08_2",
"Cry09_2",
"Cry0A_2",
"Cry0B_2",
"Cry0C_2",
"Cry0D_2",
"Cry0E_2",
"Cry0F_2",
"Cry10_2",
"Cry11_2",
"Cry12_2",
"Cry13_2",
"Cry14_2",
"Cry15_2",
"Cry16_2",
"Cry17_2",
"Cry18_2",
"Cry19_2",
"Cry1A_2",
"Cry1B_2",
"Cry1C_2",
"Cry1D_2",
"Cry1E_2",
"Cry1F_2",
"Cry20_2",
"Cry21_2",
"Cry22_2",
"Cry23_2",
"Cry24_2",
"Cry25_2",
"Level_Up",
"Get_Item2_2",
"Tink_2",
"Heal_HP_2",
"Heal_Ailment_2",
"Start_Menu_2",
"Press_AB_2",
"Ball_Toss",
"Ball_Poof",
"Faint_Thud",
"Run",
"Dex_Page_Added",
"Caught_Mon",
"Peck",
"Faint_Fall",
"Battle_09",
"Pound",
"Battle_0B",
"Battle_0C",
"Battle_0D",
"Battle_0E",
"Battle_0F",
"Damage",
"Not_Very_Effective",
"Battle_12",
"Battle_13",
"Battle_14",
"Vine_Whip",
"Battle_16",
"Battle_17",
"Battle_18",
"Battle_19",
"Super_Effective",
"Battle_1B",
"Battle_1C",
"Doubleslap",
"Battle_1E",
"Horn_Drill",
"Battle_20",
"Battle_21",
"Battle_22",
"Battle_23",
"Battle_24",
"Battle_25",
"Battle_26",
"Battle_27",
"Battle_28",
"Battle_29",
"Battle_2A",
"Battle_2B",
"Battle_2C",
"Psybeam",
"Battle_2E",
"Battle_2F",
"Psychic_M",
"Battle_31",
"Battle_32",
"Battle_33",
"Battle_34",
"Battle_35",
"Battle_36",
"Silph_Scope",
"Snare1_1",
"Snare2_1",
"Snare3_1",
"Snare4_1",
"Snare5_1",
"Triangle1_1",
"Triangle2_1",
"Snare6_1",
"Snare7_1",
"Snare8_1",
"Snare9_1",
"Cymbal1_1",
"Cymbal2_1",
"Cymbal3_1",
"Muted_Snare1_1",
"Triangle3_1",
"Muted_Snare2_1",
"Muted_Snare3_1",
"Muted_Snare4_1",
"Cry00_1",
"Cry01_1",
"Cry02_1",
"Cry03_1",
"Cry04_1",
"Cry05_1",
"Cry06_1",
"Cry07_1",
"Cry08_1",
"Cry09_1",
"Cry0A_1",
"Cry0B_1",
"Cry0C_1",
"Cry0D_1",
"Cry0E_1",
"Cry0F_1",
"Cry10_1",
"Cry11_1",
"Cry12_1",
"Cry13_1",
"Cry14_1",
"Cry15_1",
"Cry16_1",
"Cry17_1",
"Cry18_1",
"Cry19_1",
"Cry1A_1",
"Cry1B_1",
"Cry1C_1",
"Cry1D_1",
"Cry1E_1",
"Cry1F_1",
"Cry20_1",
"Cry21_1",
"Cry22_1",
"Cry23_1",
"Cry24_1",
"Cry25_1",
"Get_Item1_1",
"Get_Item2_1",
"Tink_1",
"Heal_HP_1",
"Heal_Ailment_1",
"Start_Menu_1",
"Press_AB_1",
"Pokedex_Rating_1",
"Get_Key_Item_1",
"Poisoned_1",
"Trade_Machine_1",
"Turn_On_PC_1",
"Turn_Off_PC_1",
"Enter_PC_1",
"Shrink_1",
"Switch_1",
"Healing_Machine_1",
"Teleport_Exit1_1",
"Teleport_Enter1_1",
"Teleport_Exit2_1",
"Ledge_1",
"Teleport_Enter2_1",
"Fly_1",
"Denied_1",
"Arrow_Tiles_1",
"Push_Boulder_1",
"SS_Anne_Horn_1",
"Withdraw_Deposit_1",
"Cut_1",
"Go_Inside_1",
"Swap_1",
"59_1",
"Purchase_1",
"Collision_1",
"Go_Outside_1",
"Save_1",
"Pokeflute",
"Safari_Zone_PA",
"Snare1_3",
"Snare2_3",
"Snare3_3",
"Snare4_3",
"Snare5_3",
"Triangle1_3",
"Triangle2_3",
"Snare6_3",
"Snare7_3",
"Snare8_3",
"Snare9_3",
"Cymbal1_3",
"Cymbal2_3",
"Cymbal3_3",
"Muted_Snare1_3",
"Triangle3_3",
"Muted_Snare2_3",
"Muted_Snare3_3",
"Muted_Snare4_3",
"Cry00_3",
"Cry01_3",
"Cry02_3",
"Cry03_3",
"Cry04_3",
"Cry05_3",
"Cry06_3",
"Cry07_3",
"Cry08_3",
"Cry09_3",
"Cry0A_3",
"Cry0B_3",
"Cry0C_3",
"Cry0D_3",
"Cry0E_3",
"Cry0F_3",
"Cry10_3",
"Cry11_3",
"Cry12_3",
"Cry13_3",
"Cry14_3",
"Cry15_3",
"Cry16_3",
"Cry17_3",
"Cry18_3",
"Cry19_3",
"Cry1A_3",
"Cry1B_3",
"Cry1C_3",
"Cry1D_3",
"Cry1E_3",
"Cry1F_3",
"Cry20_3",
"Cry21_3",
"Cry22_3",
"Cry23_3",
"Cry24_3",
"Cry25_3",
"Get_Item1_3",
"Get_Item2_3",
"Tink_3",
"Heal_HP_3",
"Heal_Ailment_3",
"Start_Menu_3",
"Press_AB_3",
"Pokedex_Rating_3",
"Get_Key_Item_3",
"Poisoned_3",
"Trade_Machine_3",
"Turn_On_PC_3",
"Turn_Off_PC_3",
"Enter_PC_3",
"Shrink_3",
"Switch_3",
"Healing_Machine_3",
"Teleport_Exit1_3",
"Teleport_Enter1_3",
"Teleport_Exit2_3",
"Ledge_3",
"Teleport_Enter2_3",
"Fly_3",
"Denied_3",
"Arrow_Tiles_3",
"Push_Boulder_3",
"SS_Anne_Horn_3",
"Withdraw_Deposit_3",
"Cut_3",
"Go_Inside_3",
"Swap_3",
"59_3",
"Purchase_3",
"Collision_3",
"Go_Outside_3",
"Save_3",
"Intro_Lunge",
"Intro_Hip",
"Intro_Hop",
"Intro_Raise",
"Intro_Crash",
"Intro_Whoosh",
"Slots_Stop_Wheel",
"Slots_Reward",
"Slots_New_Spin",
"Shooting_Star",
]
banks = {
0x02: 0x60,
0x08: 0x78,
0x1f: 0x68,
}
music_commands = {
0xd0: ["notetype", {"type": "nibble"}, 2],
0xe0: ["octave", 1],
0xe8: ["toggleperfectpitch", 1],
0xea: ["vibrato", {"type": "byte"}, {"type": "nibble"}, 3],
0xec: ["duty", {"type": "byte"}, 2],
0xed: ["tempo", {"type": "word"}, 3],
0xf0: ["volume", {"type": "nibble"}, 2],
0xf8: ["executemusic", 1],
0xfc: ["dutycycle", {"type": "byte"}, 2],
0xfe: ["loopchannel", {"type": "byte"}, {"type": "label"}, 4],
0xff: ["endchannel", 1],
}
param_lengths = {
"nibble": 1,
"byte": 1,
"word": 2,
"label": 2,
}
music_notes = {
0x0: "C_",
0x1: "C#",
0x2: "D_",
0x3: "D#",
0x4: "E_",
0x5: "F_",
0x6: "F#",
0x7: "G_",
0x8: "G#",
0x9: "A_",
0xa: "A#",
0xb: "B_",
}
sfxnum = 0
for bank in banks:
print bank
header = bank * 0x4000 + 3
for sfx in range(1,banks[bank]):
sfxname = sfx_names[sfxnum]
sfxfile = open("music/sfx/" + sfx_names[sfxnum].lower() + ".asm", 'w')
sfxname = "SFX_" + sfxname
startingaddress = rom[header + 2] * 0x100 + rom[header + 1] + (0x4000 * (bank - 1))
end = 0
curchannel = 1
lastchannel = (rom[header] >> 6) + 1
channelnumber = rom[header] % 0x10
output = ''
while 1:
address = startingaddress
if curchannel != lastchannel:
end = rom[header + 5] * 0x100 + rom[header + 4] + (0x4000 * (bank - 1))
byte = rom[address]
if byte == 0xf8 or (bank == 2 and sfx == 0x5e): executemusic = True
else: executemusic = False
output += "{}_Ch{}: ; {:02x} ({:0x}:{:02x})\n".format(sfxname, curchannel, address, bank, address % 0x4000 + 0x4000)
while 1:
if address == 0x2062a or address == 0x2063d or address == 0x20930:
output += "\n{}_branch_{:02x}:\n".format(sfxname, address)
if byte == 0x10 and not executemusic:
output += "\tunknownsfx0x{:02x} {}".format(byte, rom[address + 1])
command_length = 2
elif byte < 0x30 and not executemusic:
if channelnumber == 7:
output += "\tunknownnoise0x20 {}, {}, {}".format(byte % 0x10, rom[address + 1], rom[address + 2])
command_length = 3
else:
output += "\tunknownsfx0x20 {}, {}, {}, {}".format(byte % 0x10, rom[address + 1], rom[address + 2], rom[address + 3])
command_length = 4
elif byte < 0xc0:
output += "\t{} {}".format(music_notes[byte >> 4], byte % 0x10 + 1)
command_length = 1
elif byte < 0xd0:
output += "\trest {}".format(byte % 0x10 + 1)
command_length = 1
else:
if byte < 0xe0:
command = music_commands[0xd0]
output += "\t{} {},".format(command[0], byte % 0x10)
byte = 0xd0
elif byte < 0xe8:
command = music_commands[0xe0]
output += "\t{} {}".format(command[0], 0xe8 - byte)
byte = 0xe0
else:
command = music_commands[byte]
output += "\t{}".format(command[0])
command_length = 1
params = 1
# print all params for current command
while params != len(music_commands[byte]) - 1:
param_type = music_commands[byte][params]["type"]
address += command_length
command_length = param_lengths[param_type]
param = rom[address]
if param_type == "nibble":
output += " {}, {}".format(param >> 4, param % 0x10)
elif param_type == "byte":
output += " {}".format(param)
elif param_type == "word":
output += " {}".format(param * 0x100 + rom[address + 1])
else:
param += rom[address + 1] * 0x100 - 0x4000 + (bank * 0x4000)
if param == startingaddress: output += " {}_Ch{}".format(sfxname, curchannel)
else: output += " {}_branch_{:02x}".format(sfxname, param)
params += 1
if params != len(music_commands[byte]) - 1: output += ","
output += "\n"
address += command_length
if byte == 0xff or address == end: break
byte = rom[address]
header += 3
channelnumber = rom[header]
if curchannel == lastchannel:
# output += "; {}".format(hex(address))
sfxfile.write(output)
break
output += "\n\n"
startingaddress = address
curchannel += 1
from __future__ import print_function
from __future__ import absolute_import
from . import configuration
config = configuration.Config()
rom = bytearray(open(config.rom_path, "r").read())
sfx_names = [
"Snare1_2",
"Snare2_2",
"Snare3_2",
"Snare4_2",
"Snare5_2",
"Triangle1_2",
"Triangle2_2",
"Snare6_2",
"Snare7_2",
"Snare8_2",
"Snare9_2",
"Cymbal1_2",
"Cymbal2_2",
"Cymbal3_2",
"Muted_Snare1_2",
"Triangle3_2",
"Muted_Snare2_2",
"Muted_Snare3_2",
"Muted_Snare4_2",
"Cry00_2",
"Cry01_2",
"Cry02_2",
"Cry03_2",
"Cry04_2",
"Cry05_2",
"Cry06_2",
"Cry07_2",
"Cry08_2",
"Cry09_2",
"Cry0A_2",
"Cry0B_2",
"Cry0C_2",
"Cry0D_2",
"Cry0E_2",
"Cry0F_2",
"Cry10_2",
"Cry11_2",
"Cry12_2",
"Cry13_2",
"Cry14_2",
"Cry15_2",
"Cry16_2",
"Cry17_2",
"Cry18_2",
"Cry19_2",
"Cry1A_2",
"Cry1B_2",
"Cry1C_2",
"Cry1D_2",
"Cry1E_2",
"Cry1F_2",
"Cry20_2",
"Cry21_2",
"Cry22_2",
"Cry23_2",
"Cry24_2",
"Cry25_2",
"Level_Up",
"Get_Item2_2",
"Tink_2",
"Heal_HP_2",
"Heal_Ailment_2",
"Start_Menu_2",
"Press_AB_2",
"Ball_Toss",
"Ball_Poof",
"Faint_Thud",
"Run",
"Dex_Page_Added",
"Caught_Mon",
"Peck",
"Faint_Fall",
"Battle_09",
"Pound",
"Battle_0B",
"Battle_0C",
"Battle_0D",
"Battle_0E",
"Battle_0F",
"Damage",
"Not_Very_Effective",
"Battle_12",
"Battle_13",
"Battle_14",
"Vine_Whip",
"Battle_16",
"Battle_17",
"Battle_18",
"Battle_19",
"Super_Effective",
"Battle_1B",
"Battle_1C",
"Doubleslap",
"Battle_1E",
"Horn_Drill",
"Battle_20",
"Battle_21",
"Battle_22",
"Battle_23",
"Battle_24",
"Battle_25",
"Battle_26",
"Battle_27",
"Battle_28",
"Battle_29",
"Battle_2A",
"Battle_2B",
"Battle_2C",
"Psybeam",
"Battle_2E",
"Battle_2F",
"Psychic_M",
"Battle_31",
"Battle_32",
"Battle_33",
"Battle_34",
"Battle_35",
"Battle_36",
"Silph_Scope",
"Snare1_1",
"Snare2_1",
"Snare3_1",
"Snare4_1",
"Snare5_1",
"Triangle1_1",
"Triangle2_1",
"Snare6_1",
"Snare7_1",
"Snare8_1",
"Snare9_1",
"Cymbal1_1",
"Cymbal2_1",
"Cymbal3_1",
"Muted_Snare1_1",
"Triangle3_1",
"Muted_Snare2_1",
"Muted_Snare3_1",
"Muted_Snare4_1",
"Cry00_1",
"Cry01_1",
"Cry02_1",
"Cry03_1",
"Cry04_1",
"Cry05_1",
"Cry06_1",
"Cry07_1",
"Cry08_1",
"Cry09_1",
"Cry0A_1",
"Cry0B_1",
"Cry0C_1",
"Cry0D_1",
"Cry0E_1",
"Cry0F_1",
"Cry10_1",
"Cry11_1",
"Cry12_1",
"Cry13_1",
"Cry14_1",
"Cry15_1",
"Cry16_1",
"Cry17_1",
"Cry18_1",
"Cry19_1",
"Cry1A_1",
"Cry1B_1",
"Cry1C_1",
"Cry1D_1",
"Cry1E_1",
"Cry1F_1",
"Cry20_1",
"Cry21_1",
"Cry22_1",
"Cry23_1",
"Cry24_1",
"Cry25_1",
"Get_Item1_1",
"Get_Item2_1",
"Tink_1",
"Heal_HP_1",
"Heal_Ailment_1",
"Start_Menu_1",
"Press_AB_1",
"Pokedex_Rating_1",
"Get_Key_Item_1",
"Poisoned_1",
"Trade_Machine_1",
"Turn_On_PC_1",
"Turn_Off_PC_1",
"Enter_PC_1",
"Shrink_1",
"Switch_1",
"Healing_Machine_1",
"Teleport_Exit1_1",
"Teleport_Enter1_1",
"Teleport_Exit2_1",
"Ledge_1",
"Teleport_Enter2_1",
"Fly_1",
"Denied_1",
"Arrow_Tiles_1",
"Push_Boulder_1",
"SS_Anne_Horn_1",
"Withdraw_Deposit_1",
"Cut_1",
"Go_Inside_1",
"Swap_1",
"59_1",
"Purchase_1",
"Collision_1",
"Go_Outside_1",
"Save_1",
"Pokeflute",
"Safari_Zone_PA",
"Snare1_3",
"Snare2_3",
"Snare3_3",
"Snare4_3",
"Snare5_3",
"Triangle1_3",
"Triangle2_3",
"Snare6_3",
"Snare7_3",
"Snare8_3",
"Snare9_3",
"Cymbal1_3",
"Cymbal2_3",
"Cymbal3_3",
"Muted_Snare1_3",
"Triangle3_3",
"Muted_Snare2_3",
"Muted_Snare3_3",
"Muted_Snare4_3",
"Cry00_3",
"Cry01_3",
"Cry02_3",
"Cry03_3",
"Cry04_3",
"Cry05_3",
"Cry06_3",
"Cry07_3",
"Cry08_3",
"Cry09_3",
"Cry0A_3",
"Cry0B_3",
"Cry0C_3",
"Cry0D_3",
"Cry0E_3",
"Cry0F_3",
"Cry10_3",
"Cry11_3",
"Cry12_3",
"Cry13_3",
"Cry14_3",
"Cry15_3",
"Cry16_3",
"Cry17_3",
"Cry18_3",
"Cry19_3",
"Cry1A_3",
"Cry1B_3",
"Cry1C_3",
"Cry1D_3",
"Cry1E_3",
"Cry1F_3",
"Cry20_3",
"Cry21_3",
"Cry22_3",
"Cry23_3",
"Cry24_3",
"Cry25_3",
"Get_Item1_3",
"Get_Item2_3",
"Tink_3",
"Heal_HP_3",
"Heal_Ailment_3",
"Start_Menu_3",
"Press_AB_3",
"Pokedex_Rating_3",
"Get_Key_Item_3",
"Poisoned_3",
"Trade_Machine_3",
"Turn_On_PC_3",
"Turn_Off_PC_3",
"Enter_PC_3",
"Shrink_3",
"Switch_3",
"Healing_Machine_3",
"Teleport_Exit1_3",
"Teleport_Enter1_3",
"Teleport_Exit2_3",
"Ledge_3",
"Teleport_Enter2_3",
"Fly_3",
"Denied_3",
"Arrow_Tiles_3",
"Push_Boulder_3",
"SS_Anne_Horn_3",
"Withdraw_Deposit_3",
"Cut_3",
"Go_Inside_3",
"Swap_3",
"59_3",
"Purchase_3",
"Collision_3",
"Go_Outside_3",
"Save_3",
"Intro_Lunge",
"Intro_Hip",
"Intro_Hop",
"Intro_Raise",
"Intro_Crash",
"Intro_Whoosh",
"Slots_Stop_Wheel",
"Slots_Reward",
"Slots_New_Spin",
"Shooting_Star",
]
banks = {
0x02: 0x60,
0x08: 0x78,
0x1f: 0x68,
}
music_commands = {
0xd0: ["notetype", {"type": "nibble"}, 2],
0xe0: ["octave", 1],
0xe8: ["toggleperfectpitch", 1],
0xea: ["vibrato", {"type": "byte"}, {"type": "nibble"}, 3],
0xec: ["duty", {"type": "byte"}, 2],
0xed: ["tempo", {"type": "word"}, 3],
0xf0: ["volume", {"type": "nibble"}, 2],
0xf8: ["executemusic", 1],
0xfc: ["dutycycle", {"type": "byte"}, 2],
0xfe: ["loopchannel", {"type": "byte"}, {"type": "label"}, 4],
0xff: ["endchannel", 1],
}
param_lengths = {
"nibble": 1,
"byte": 1,
"word": 2,
"label": 2,
}
music_notes = {
0x0: "C_",
0x1: "C#",
0x2: "D_",
0x3: "D#",
0x4: "E_",
0x5: "F_",
0x6: "F#",
0x7: "G_",
0x8: "G#",
0x9: "A_",
0xa: "A#",
0xb: "B_",
}
sfxnum = 0
for bank in banks:
print(bank)
header = bank * 0x4000 + 3
for sfx in range(1,banks[bank]):
sfxname = sfx_names[sfxnum]
sfxfile = open("music/sfx/" + sfx_names[sfxnum].lower() + ".asm", 'w')
sfxname = "SFX_" + sfxname
startingaddress = rom[header + 2] * 0x100 + rom[header + 1] + (0x4000 * (bank - 1))
end = 0
curchannel = 1
lastchannel = (rom[header] >> 6) + 1
channelnumber = rom[header] % 0x10
output = ''
while 1:
address = startingaddress
if curchannel != lastchannel:
end = rom[header + 5] * 0x100 + rom[header + 4] + (0x4000 * (bank - 1))
byte = rom[address]
if byte == 0xf8 or (bank == 2 and sfx == 0x5e): executemusic = True
else: executemusic = False
output += "{}_Ch{}: ; {:02x} ({:0x}:{:02x})\n".format(sfxname, curchannel, address, bank, address % 0x4000 + 0x4000)
while 1:
if address == 0x2062a or address == 0x2063d or address == 0x20930:
output += "\n{}_branch_{:02x}:\n".format(sfxname, address)
if byte == 0x10 and not executemusic:
output += "\tunknownsfx0x{:02x} {}".format(byte, rom[address + 1])
command_length = 2
elif byte < 0x30 and not executemusic:
if channelnumber == 7:
output += "\tunknownnoise0x20 {}, {}, {}".format(byte % 0x10, rom[address + 1], rom[address + 2])
command_length = 3
else:
output += "\tunknownsfx0x20 {}, {}, {}, {}".format(byte % 0x10, rom[address + 1], rom[address + 2], rom[address + 3])
command_length = 4
elif byte < 0xc0:
output += "\t{} {}".format(music_notes[byte >> 4], byte % 0x10 + 1)
command_length = 1
elif byte < 0xd0:
output += "\trest {}".format(byte % 0x10 + 1)
command_length = 1
else:
if byte < 0xe0:
command = music_commands[0xd0]
output += "\t{} {},".format(command[0], byte % 0x10)
byte = 0xd0
elif byte < 0xe8:
command = music_commands[0xe0]
output += "\t{} {}".format(command[0], 0xe8 - byte)
byte = 0xe0
else:
command = music_commands[byte]
output += "\t{}".format(command[0])
command_length = 1
params = 1
# print all params for current command
while params != len(music_commands[byte]) - 1:
param_type = music_commands[byte][params]["type"]
address += command_length
command_length = param_lengths[param_type]
param = rom[address]
if param_type == "nibble":
output += " {}, {}".format(param >> 4, param % 0x10)
elif param_type == "byte":
output += " {}".format(param)
elif param_type == "word":
output += " {}".format(param * 0x100 + rom[address + 1])
else:
param += rom[address + 1] * 0x100 - 0x4000 + (bank * 0x4000)
if param == startingaddress: output += " {}_Ch{}".format(sfxname, curchannel)
else: output += " {}_branch_{:02x}".format(sfxname, param)
params += 1
if params != len(music_commands[byte]) - 1: output += ","
output += "\n"
address += command_length
if byte == 0xff or address == end: break
byte = rom[address]
header += 3
channelnumber = rom[header]
if curchannel == lastchannel:
# output += "; {}".format(hex(address))
sfxfile.write(output)
break
output += "\n\n"
startingaddress = address
curchannel += 1
sfxnum += 1

View File

@ -1,359 +1,360 @@
import configuration
config = configuration.Config()
rom = bytearray(open(config.rom_path, "r").read())
sfx_names = [
"Snare1_1",
"Snare2_1",
"Snare3_1",
"Snare4_1",
"Snare5_1",
"Triangle1_1",
"Triangle2_1",
"Snare6_1",
"Snare7_1",
"Snare8_1",
"Snare9_1",
"Cymbal1_1",
"Cymbal2_1",
"Cymbal3_1",
"Muted_Snare1_1",
"Triangle3_1",
"Muted_Snare2_1",
"Muted_Snare3_1",
"Muted_Snare4_1",
"Cry00_1",
"Cry01_1",
"Cry02_1",
"Cry03_1",
"Cry04_1",
"Cry05_1",
"Cry06_1",
"Cry07_1",
"Cry08_1",
"Cry09_1",
"Cry0A_1",
"Cry0B_1",
"Cry0C_1",
"Cry0D_1",
"Cry0E_1",
"Cry0F_1",
"Cry10_1",
"Cry11_1",
"Cry12_1",
"Cry13_1",
"Cry14_1",
"Cry15_1",
"Cry16_1",
"Cry17_1",
"Cry18_1",
"Cry19_1",
"Cry1A_1",
"Cry1B_1",
"Cry1C_1",
"Cry1D_1",
"Cry1E_1",
"Cry1F_1",
"Cry20_1",
"Cry21_1",
"Cry22_1",
"Cry23_1",
"Cry24_1",
"Cry25_1",
"Get_Item1_1",
"Get_Item2_1",
"Tink_1",
"Heal_HP_1",
"Heal_Ailment_1",
"Start_Menu_1",
"Press_AB_1",
"Pokedex_Rating_1",
"Get_Key_Item_1",
"Poisoned_1",
"Trade_Machine_1",
"Turn_On_PC_1",
"Turn_Off_PC_1",
"Enter_PC_1",
"Shrink_1",
"Switch_1",
"Healing_Machine_1",
"Teleport_Exit1_1",
"Teleport_Enter1_1",
"Teleport_Exit2_1",
"Ledge_1",
"Teleport_Enter2_1",
"Fly_1",
"Denied_1",
"Arrow_Tiles_1",
"Push_Boulder_1",
"SS_Anne_Horn_1",
"Withdraw_Deposit_1",
"Cut_1",
"Go_Inside_1",
"Swap_1",
"59_1",
"Purchase_1",
"Collision_1",
"Go_Outside_1",
"Save_1",
"Pokeflute",
"Safari_Zone_PA",
"Snare1_2",
"Snare2_2",
"Snare3_2",
"Snare4_2",
"Snare5_2",
"Triangle1_2",
"Triangle2_2",
"Snare6_2",
"Snare7_2",
"Snare8_2",
"Snare9_2",
"Cymbal1_2",
"Cymbal2_2",
"Cymbal3_2",
"Muted_Snare1_2",
"Triangle3_2",
"Muted_Snare2_2",
"Muted_Snare3_2",
"Muted_Snare4_2",
"Cry00_2",
"Cry01_2",
"Cry02_2",
"Cry03_2",
"Cry04_2",
"Cry05_2",
"Cry06_2",
"Cry07_2",
"Cry08_2",
"Cry09_2",
"Cry0A_2",
"Cry0B_2",
"Cry0C_2",
"Cry0D_2",
"Cry0E_2",
"Cry0F_2",
"Cry10_2",
"Cry11_2",
"Cry12_2",
"Cry13_2",
"Cry14_2",
"Cry15_2",
"Cry16_2",
"Cry17_2",
"Cry18_2",
"Cry19_2",
"Cry1A_2",
"Cry1B_2",
"Cry1C_2",
"Cry1D_2",
"Cry1E_2",
"Cry1F_2",
"Cry20_2",
"Cry21_2",
"Cry22_2",
"Cry23_2",
"Cry24_2",
"Cry25_2",
"Level_Up",
"Get_Item2_2",
"Tink_2",
"Heal_HP_2",
"Heal_Ailment_2",
"Start_Menu_2",
"Press_AB_2",
"Ball_Toss",
"Ball_Poof",
"Faint_Thud",
"Run",
"Dex_Page_Added",
"Caught_Mon",
"Peck",
"Faint_Fall",
"Battle_09",
"Pound",
"Battle_0B",
"Battle_0C",
"Battle_0D",
"Battle_0E",
"Battle_0F",
"Damage",
"Not_Very_Effective",
"Battle_12",
"Battle_13",
"Battle_14",
"Vine_Whip",
"Battle_16",
"Battle_17",
"Battle_18",
"Battle_19",
"Super_Effective",
"Battle_1B",
"Battle_1C",
"Doubleslap",
"Battle_1E",
"Horn_Drill",
"Battle_20",
"Battle_21",
"Battle_22",
"Battle_23",
"Battle_24",
"Battle_25",
"Battle_26",
"Battle_27",
"Battle_28",
"Battle_29",
"Battle_2A",
"Battle_2B",
"Battle_2C",
"Psybeam",
"Battle_2E",
"Battle_2F",
"Psychic_M",
"Battle_31",
"Battle_32",
"Battle_33",
"Battle_34",
"Battle_35",
"Battle_36",
"Silph_Scope",
"Snare1_3",
"Snare2_3",
"Snare3_3",
"Snare4_3",
"Snare5_3",
"Triangle1_3",
"Triangle2_3",
"Snare6_3",
"Snare7_3",
"Snare8_3",
"Snare9_3",
"Cymbal1_3",
"Cymbal2_3",
"Cymbal3_3",
"Muted_Snare1_3",
"Triangle3_3",
"Muted_Snare2_3",
"Muted_Snare3_3",
"Muted_Snare4_3",
"Cry00_3",
"Cry01_3",
"Cry02_3",
"Cry03_3",
"Cry04_3",
"Cry05_3",
"Cry06_3",
"Cry07_3",
"Cry08_3",
"Cry09_3",
"Cry0A_3",
"Cry0B_3",
"Cry0C_3",
"Cry0D_3",
"Cry0E_3",
"Cry0F_3",
"Cry10_3",
"Cry11_3",
"Cry12_3",
"Cry13_3",
"Cry14_3",
"Cry15_3",
"Cry16_3",
"Cry17_3",
"Cry18_3",
"Cry19_3",
"Cry1A_3",
"Cry1B_3",
"Cry1C_3",
"Cry1D_3",
"Cry1E_3",
"Cry1F_3",
"Cry20_3",
"Cry21_3",
"Cry22_3",
"Cry23_3",
"Cry24_3",
"Cry25_3",
"Get_Item1_3",
"Get_Item2_3",
"Tink_3",
"Heal_HP_3",
"Heal_Ailment_3",
"Start_Menu_3",
"Press_AB_3",
"Pokedex_Rating_3",
"Get_Key_Item_3",
"Poisoned_3",
"Trade_Machine_3",
"Turn_On_PC_3",
"Turn_Off_PC_3",
"Enter_PC_3",
"Shrink_3",
"Switch_3",
"Healing_Machine_3",
"Teleport_Exit1_3",
"Teleport_Enter1_3",
"Teleport_Exit2_3",
"Ledge_3",
"Teleport_Enter2_3",
"Fly_3",
"Denied_3",
"Arrow_Tiles_3",
"Push_Boulder_3",
"SS_Anne_Horn_3",
"Withdraw_Deposit_3",
"Cut_3",
"Go_Inside_3",
"Swap_3",
"59_3",
"Purchase_3",
"Collision_3",
"Go_Outside_3",
"Save_3",
"Intro_Lunge",
"Intro_Hip",
"Intro_Hop",
"Intro_Raise",
"Intro_Crash",
"Intro_Whoosh",
"Slots_Stop_Wheel",
"Slots_Reward",
"Slots_New_Spin",
"Shooting_Star",
]
headerlist = (
["sfxheaders02.asm", 0x8003, 0x822e],
["sfxheaders08.asm", 0x20003, 0x202be],
["sfxheaders1f.asm", 0x7c003, 0x7c249],
)
def printsfxheaders(filename, address, end, sfxnum):
file = open(filename, 'w')
bank = address / 0x4000
byte = rom[address]
sfx = 1
channel = 1
file.write("SFX_Headers_{:02x}::\n".format(bank))
file.write("\tdb $ff, $ff, $ff ; padding\n")
while address != end:
left = (byte >> 6) + 1
file.write("\nSFX_{}:: ; {:02x} ({:0x}:{:02x})\n".format(sfx_names[sfxnum], address, bank, address % 0x4000 + 0x4000))
while left != 0:
pointer = rom[address + 2] * 0x100 + rom[address + 1]
if byte >> 4 != 0: file.write(" db ( ${:0x}0 | CH{:0x} )\n".format(byte >> 4, byte % 0x10))
else: file.write("\tdb CH{:0x}\n".format(byte))
file.write("\tdw SFX_{}_Ch{}\n".format(sfx_names[sfxnum], channel))
address += 3
byte = rom[address]
channel += 1
left -= 1
channel = 1
sfx += 1
sfxnum += 1
#file.write("\n; {}".format(hex(address)))
return sfxnum
sfxnum = 0
for header in headerlist:
from __future__ import absolute_import
from . import configuration
config = configuration.Config()
rom = bytearray(open(config.rom_path, "r").read())
sfx_names = [
"Snare1_1",
"Snare2_1",
"Snare3_1",
"Snare4_1",
"Snare5_1",
"Triangle1_1",
"Triangle2_1",
"Snare6_1",
"Snare7_1",
"Snare8_1",
"Snare9_1",
"Cymbal1_1",
"Cymbal2_1",
"Cymbal3_1",
"Muted_Snare1_1",
"Triangle3_1",
"Muted_Snare2_1",
"Muted_Snare3_1",
"Muted_Snare4_1",
"Cry00_1",
"Cry01_1",
"Cry02_1",
"Cry03_1",
"Cry04_1",
"Cry05_1",
"Cry06_1",
"Cry07_1",
"Cry08_1",
"Cry09_1",
"Cry0A_1",
"Cry0B_1",
"Cry0C_1",
"Cry0D_1",
"Cry0E_1",
"Cry0F_1",
"Cry10_1",
"Cry11_1",
"Cry12_1",
"Cry13_1",
"Cry14_1",
"Cry15_1",
"Cry16_1",
"Cry17_1",
"Cry18_1",
"Cry19_1",
"Cry1A_1",
"Cry1B_1",
"Cry1C_1",
"Cry1D_1",
"Cry1E_1",
"Cry1F_1",
"Cry20_1",
"Cry21_1",
"Cry22_1",
"Cry23_1",
"Cry24_1",
"Cry25_1",
"Get_Item1_1",
"Get_Item2_1",
"Tink_1",
"Heal_HP_1",
"Heal_Ailment_1",
"Start_Menu_1",
"Press_AB_1",
"Pokedex_Rating_1",
"Get_Key_Item_1",
"Poisoned_1",
"Trade_Machine_1",
"Turn_On_PC_1",
"Turn_Off_PC_1",
"Enter_PC_1",
"Shrink_1",
"Switch_1",
"Healing_Machine_1",
"Teleport_Exit1_1",
"Teleport_Enter1_1",
"Teleport_Exit2_1",
"Ledge_1",
"Teleport_Enter2_1",
"Fly_1",
"Denied_1",
"Arrow_Tiles_1",
"Push_Boulder_1",
"SS_Anne_Horn_1",
"Withdraw_Deposit_1",
"Cut_1",
"Go_Inside_1",
"Swap_1",
"59_1",
"Purchase_1",
"Collision_1",
"Go_Outside_1",
"Save_1",
"Pokeflute",
"Safari_Zone_PA",
"Snare1_2",
"Snare2_2",
"Snare3_2",
"Snare4_2",
"Snare5_2",
"Triangle1_2",
"Triangle2_2",
"Snare6_2",
"Snare7_2",
"Snare8_2",
"Snare9_2",
"Cymbal1_2",
"Cymbal2_2",
"Cymbal3_2",
"Muted_Snare1_2",
"Triangle3_2",
"Muted_Snare2_2",
"Muted_Snare3_2",
"Muted_Snare4_2",
"Cry00_2",
"Cry01_2",
"Cry02_2",
"Cry03_2",
"Cry04_2",
"Cry05_2",
"Cry06_2",
"Cry07_2",
"Cry08_2",
"Cry09_2",
"Cry0A_2",
"Cry0B_2",
"Cry0C_2",
"Cry0D_2",
"Cry0E_2",
"Cry0F_2",
"Cry10_2",
"Cry11_2",
"Cry12_2",
"Cry13_2",
"Cry14_2",
"Cry15_2",
"Cry16_2",
"Cry17_2",
"Cry18_2",
"Cry19_2",
"Cry1A_2",
"Cry1B_2",
"Cry1C_2",
"Cry1D_2",
"Cry1E_2",
"Cry1F_2",
"Cry20_2",
"Cry21_2",
"Cry22_2",
"Cry23_2",
"Cry24_2",
"Cry25_2",
"Level_Up",
"Get_Item2_2",
"Tink_2",
"Heal_HP_2",
"Heal_Ailment_2",
"Start_Menu_2",
"Press_AB_2",
"Ball_Toss",
"Ball_Poof",
"Faint_Thud",
"Run",
"Dex_Page_Added",
"Caught_Mon",
"Peck",
"Faint_Fall",
"Battle_09",
"Pound",
"Battle_0B",
"Battle_0C",
"Battle_0D",
"Battle_0E",
"Battle_0F",
"Damage",
"Not_Very_Effective",
"Battle_12",
"Battle_13",
"Battle_14",
"Vine_Whip",
"Battle_16",
"Battle_17",
"Battle_18",
"Battle_19",
"Super_Effective",
"Battle_1B",
"Battle_1C",
"Doubleslap",
"Battle_1E",
"Horn_Drill",
"Battle_20",
"Battle_21",
"Battle_22",
"Battle_23",
"Battle_24",
"Battle_25",
"Battle_26",
"Battle_27",
"Battle_28",
"Battle_29",
"Battle_2A",
"Battle_2B",
"Battle_2C",
"Psybeam",
"Battle_2E",
"Battle_2F",
"Psychic_M",
"Battle_31",
"Battle_32",
"Battle_33",
"Battle_34",
"Battle_35",
"Battle_36",
"Silph_Scope",
"Snare1_3",
"Snare2_3",
"Snare3_3",
"Snare4_3",
"Snare5_3",
"Triangle1_3",
"Triangle2_3",
"Snare6_3",
"Snare7_3",
"Snare8_3",
"Snare9_3",
"Cymbal1_3",
"Cymbal2_3",
"Cymbal3_3",
"Muted_Snare1_3",
"Triangle3_3",
"Muted_Snare2_3",
"Muted_Snare3_3",
"Muted_Snare4_3",
"Cry00_3",
"Cry01_3",
"Cry02_3",
"Cry03_3",
"Cry04_3",
"Cry05_3",
"Cry06_3",
"Cry07_3",
"Cry08_3",
"Cry09_3",
"Cry0A_3",
"Cry0B_3",
"Cry0C_3",
"Cry0D_3",
"Cry0E_3",
"Cry0F_3",
"Cry10_3",
"Cry11_3",
"Cry12_3",
"Cry13_3",
"Cry14_3",
"Cry15_3",
"Cry16_3",
"Cry17_3",
"Cry18_3",
"Cry19_3",
"Cry1A_3",
"Cry1B_3",
"Cry1C_3",
"Cry1D_3",
"Cry1E_3",
"Cry1F_3",
"Cry20_3",
"Cry21_3",
"Cry22_3",
"Cry23_3",
"Cry24_3",
"Cry25_3",
"Get_Item1_3",
"Get_Item2_3",
"Tink_3",
"Heal_HP_3",
"Heal_Ailment_3",
"Start_Menu_3",
"Press_AB_3",
"Pokedex_Rating_3",
"Get_Key_Item_3",
"Poisoned_3",
"Trade_Machine_3",
"Turn_On_PC_3",
"Turn_Off_PC_3",
"Enter_PC_3",
"Shrink_3",
"Switch_3",
"Healing_Machine_3",
"Teleport_Exit1_3",
"Teleport_Enter1_3",
"Teleport_Exit2_3",
"Ledge_3",
"Teleport_Enter2_3",
"Fly_3",
"Denied_3",
"Arrow_Tiles_3",
"Push_Boulder_3",
"SS_Anne_Horn_3",
"Withdraw_Deposit_3",
"Cut_3",
"Go_Inside_3",
"Swap_3",
"59_3",
"Purchase_3",
"Collision_3",
"Go_Outside_3",
"Save_3",
"Intro_Lunge",
"Intro_Hip",
"Intro_Hop",
"Intro_Raise",
"Intro_Crash",
"Intro_Whoosh",
"Slots_Stop_Wheel",
"Slots_Reward",
"Slots_New_Spin",
"Shooting_Star",
]
headerlist = (
["sfxheaders02.asm", 0x8003, 0x822e],
["sfxheaders08.asm", 0x20003, 0x202be],
["sfxheaders1f.asm", 0x7c003, 0x7c249],
)
def printsfxheaders(filename, address, end, sfxnum):
file = open(filename, 'w')
bank = address / 0x4000
byte = rom[address]
sfx = 1
channel = 1
file.write("SFX_Headers_{:02x}::\n".format(bank))
file.write("\tdb $ff, $ff, $ff ; padding\n")
while address != end:
left = (byte >> 6) + 1
file.write("\nSFX_{}:: ; {:02x} ({:0x}:{:02x})\n".format(sfx_names[sfxnum], address, bank, address % 0x4000 + 0x4000))
while left != 0:
pointer = rom[address + 2] * 0x100 + rom[address + 1]
if byte >> 4 != 0: file.write(" db ( ${:0x}0 | CH{:0x} )\n".format(byte >> 4, byte % 0x10))
else: file.write("\tdb CH{:0x}\n".format(byte))
file.write("\tdw SFX_{}_Ch{}\n".format(sfx_names[sfxnum], channel))
address += 3
byte = rom[address]
channel += 1
left -= 1
channel = 1
sfx += 1
sfxnum += 1
#file.write("\n; {}".format(hex(address)))
return sfxnum
sfxnum = 0
for header in headerlist:
sfxnum = printsfxheaders(header[0], header[1], header[2], sfxnum)

View File

@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from __future__ import absolute_import
import sys
import os
import time
@ -12,7 +14,7 @@ import json
if not hasattr(json, "read"):
json.read = json.loads
from labels import (
from .labels import (
get_label_from_line,
get_address_from_line_comment,
)
@ -170,7 +172,7 @@ class RomStr(str):
start_address = address
if start_address == None:
raise Exception, "address must be given"
raise Exception("address must be given")
if debug == None:
if not hasattr(self, "debug"):
@ -180,9 +182,9 @@ class RomStr(str):
# this is probably a terrible idea.. why am i doing this?
if size != None and max_size < size:
raise Exception, "max_size must be greater than or equal to size"
raise Exception("max_size must be greater than or equal to size")
elif end_address != None and (end_address - start_address) > max_size:
raise Exception, "end_address is out of bounds"
raise Exception("end_address is out of bounds")
elif end_address != None and size != None:
if (end_address - start_address) >= size:
size = end_address - start_address
@ -216,4 +218,4 @@ class AsmList(list):
if __name__ == "__main__":
cryrom = RomStr(open("../pokecrystal.gbc", "r").read());
asm = cryrom.to_asm(sys.argv[1])
print asm
print(asm)

View File

@ -4,40 +4,48 @@
"""
Recursively scan an asm file for dependencies.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import sys
import argparse
import os.path
includes = set()
def scan_file(filename):
for line in open(filename):
if 'INC' not in line:
continue
line = line.split(';')[0]
if 'INCLUDE' in line:
include = line.split('"')[1]
if os.path.exists("src/"):
includes.add("src/" + include)
scan_file("src/" + include)
else:
includes.add(include)
scan_file(include)
elif 'INCBIN' in line:
include = line.split('"')[1]
if 'baserom.gbc' not in line and os.path.exists("src/"):
includes.add("src/" + include)
else:
includes.add(include)
with open(filename) as f:
for line in f:
if 'INC' not in line:
continue
line = line.split(';')[0]
if 'INCLUDE' in line:
include = line.split('"')[1]
if os.path.exists("src/"):
yield "src/" + include
for inc in scan_file("src/" + include):
yield inc
else:
yield include
for inc in scan_file(include):
yield inc
elif 'INCBIN' in line:
include = line.split('"')[1]
if 'baserom.gbc' not in line and os.path.exists("src/"):
yield "src/" + include
else:
yield include
def main():
ap = argparse.ArgumentParser()
ap.add_argument('filenames', nargs='*')
args = ap.parse_args()
for filename in set(args.filenames):
scan_file(filename)
sys.stdout.write(' '.join(includes))
ap = argparse.ArgumentParser()
ap.add_argument('filenames', nargs='*')
args = ap.parse_args()
includes = set()
for filename in set(args.filenames):
includes.update(scan_file(filename))
sys.stdout.write(' '.join(sorted(includes)))
if __name__ == '__main__':
main()
main()

View File

@ -2,6 +2,8 @@
"""
GBC disassembler, specialized for TCG macros
"""
from __future__ import print_function
from __future__ import absolute_import
import os
import sys
@ -10,9 +12,9 @@ from ctypes import c_int8
import random
import json
import configuration
import labels
import wram
from . import configuration
from . import labels
from . import wram
# New versions of json don't have read anymore.
if not hasattr(json, "read"):
@ -663,7 +665,7 @@ class Disassembler(object):
"""
bank_id = original_offset / 0x4000
if debug: print "bank id is: " + str(bank_id)
if debug: print("bank id is: " + str(bank_id))
last_hl_address = None #for when we're scanning the main map script
last_a_address = None
@ -995,4 +997,4 @@ if __name__ == "__main__":
else:
output = "Func_{:02x}: ; {:02x} ({:0x}:{:02x})\n".format(addr, addr, addr / 0x4000, addr % 0x4000 + 0x4000)
output += disasm.output_bank_opcodes(addr)[0]
print output
print(output)

View File

@ -2,12 +2,14 @@
"""
Programmatic speedrun of Pokémon Crystal
"""
from __future__ import print_function
from __future__ import absolute_import
import os
import pokemontools.configuration as configuration
# bring in the emulator and basic tools
import vba as _vba
from . import vba as _vba
def skippable(func):
"""
@ -394,13 +396,13 @@ class SpeedRunner(Runner):
self.cry.text_wait()
hp = self.cry.get_enemy_hp()
print "enemy hp is: " + str(hp)
print("enemy hp is: " + str(hp))
if hp == 0:
print "enemy hp is zero, exiting"
print("enemy hp is zero, exiting")
break
else:
print "enemy hp is: " + str(hp)
print("enemy hp is: " + str(hp))
attacks = attacks - 1
@ -417,7 +419,7 @@ class SpeedRunner(Runner):
# happens.
self.cry.text_wait(max_wait=30, debug=True)
print "okay, back in the overworld"
print("okay, back in the overworld")
cur_hp = ((self.cry.vba.memory[0xdd01] << 8) | self.cry.vba.memory[0xdd02])
move_pp = self.cry.vba.memory[0xdcf6] # move 1 pp

View File

@ -3,6 +3,7 @@
This file constructs a networkx.DiGraph object called graph, which can be used
to find the shortest path of keypresses on the keyboard to type a word.
"""
from __future__ import print_function
import os
import itertools
@ -44,7 +45,7 @@ def convert_nodes_to_button_press(node1, node2):
"""
Determines the button necessary to switch from node1 to node2.
"""
print "getting button press for state transition: " + node1 + " -> " + node2
print("getting button press for state transition: " + node1 + " -> " + node2)
return graph.get_edge_data(node1, node2)["key"]
def plan_typing(text, current="A"):
@ -56,7 +57,7 @@ def plan_typing(text, current="A"):
if target == current:
buttons.append("a")
else:
print "Finding the shortest path between " + current + " and " + target
print("Finding the shortest path between " + current + " and " + target)
more_buttons = shortest_path(current, target)
buttons.extend(more_buttons)
buttons.append("a")

View File

@ -2,6 +2,8 @@
"""
VBA automation
"""
from __future__ import print_function
from __future__ import absolute_import
import os
import sys
@ -18,7 +20,7 @@ from pokemontools.map_names import (
map_names,
)
import keyboard
from . import keyboard
# just use a default config for now until the globals are removed completely
import pokemontools.configuration as configuration
@ -183,9 +185,9 @@ class crystal(object):
self.vba.write_memory_at(self.registers.sp + 1, value >> 8)
self.vba.write_memory_at(self.registers.sp, value & 0xFF)
if list(self.vba.memory[self.registers.sp : self.registers.sp + 2]) != [value & 0xFF, value >> 8]:
print "desired memory values: " + str([value & 0xFF, value >> 8] )
print "actual memory values: " + str(list(self.vba.memory[self.registers.sp : self.registers.sp + 2]))
print "wrong value at " + hex(self.registers.sp) + " expected " + hex(value) + " but got " + hex(self.vba.read_memory_at(self.registers.sp))
print("desired memory values: " + str([value & 0xFF, value >> 8] ))
print("actual memory values: " + str(list(self.vba.memory[self.registers.sp : self.registers.sp + 2])))
print("wrong value at " + hex(self.registers.sp) + " expected " + hex(value) + " but got " + hex(self.vba.read_memory_at(self.registers.sp)))
def get_stack(self):
"""
@ -426,7 +428,7 @@ class crystal(object):
address = ((hi << 8) | lo)
if address in range(0xa1b, 0xa46) + range(0xaaf, 0xaf5): # 0xaef:
print "pressing, then breaking.. address is: " + str(hex(address))
print("pressing, then breaking.. address is: " + str(hex(address)))
# set CurSFX
self.vba.write_memory_at(0xc2bf, 0)
@ -436,19 +438,19 @@ class crystal(object):
# check if CurSFX is SFX_READ_TEXT_2
if self.vba.read_memory_at(0xc2bf) == 0x8:
if "CANCEL Which" in self.get_text():
print "probably the 'switch pokemon' menu"
print("probably the 'switch pokemon' menu")
return
else:
print "cursfx is set to SFX_READ_TEXT_2, looping.."
print self.get_text()
print("cursfx is set to SFX_READ_TEXT_2, looping..")
print(self.get_text())
return self.text_wait(step_size=step_size, max_wait=max_wait, debug=debug, callback=callback, sfx_limit=sfx_limit)
else:
if sfx_limit > 0:
sfx_limit = sfx_limit - 1
print "decreasing sfx_limit"
print("decreasing sfx_limit")
else:
# probably the last textbox in a sequence
print "cursfx is not set to SFX_READ_TEXT_2, so: breaking"
print("cursfx is not set to SFX_READ_TEXT_2, so: breaking")
break
else:
@ -456,19 +458,19 @@ class crystal(object):
# yes/no box or the name selection box
if address in range(0xa46, 0xaaf):
print "probably at a yes/no box.. exiting."
print("probably at a yes/no box.. exiting.")
break
# date/time box (day choice)
# 0x47ab is the one from the intro, 0x49ab is the one from mom.
elif 0x47ab in stack or 0x49ab in stack: # was any([x in stack for x in range(0x46EE, 0x47AB)])
if not self.is_in_battle():
print "probably at a date/time box ? exiting."
print("probably at a date/time box ? exiting.")
break
# "How many minutes?" selection box
elif 0x4826 in stack:
print "probably at a \"How many minutes?\" box ? exiting."
print("probably at a \"How many minutes?\" box ? exiting.")
break
self.vba.step(count=step_size)
@ -482,7 +484,7 @@ class crystal(object):
if callback != None:
result = callback()
if result == True:
print "callback returned True, exiting"
print("callback returned True, exiting")
return
# only useful when debugging. When this is left on, text that
@ -492,7 +494,7 @@ class crystal(object):
max_wait = max_wait - 1
if max_wait == 0:
print "max_wait was hit"
print("max_wait was hit")
def walk_through_walls_slow(self):
memory = self.vba.memory
@ -852,7 +854,7 @@ class crystal(object):
"""
while limit > 0:
if self.vba.read_memory_at(0xd438) != 255:
print "script is done executing"
print("script is done executing")
return
else:
self.vba.step()
@ -861,7 +863,7 @@ class crystal(object):
limit = limit - 1
if limit == 0:
print "limit ran out"
print("limit ran out")
def move(self, cmd):
"""

View File

@ -159,7 +159,7 @@ class BSSReader:
# rgbasm allows labels without :, but prefer convention
label = line[:line.find(':')]
if '\\' in label:
raise Exception, line + ' ' + label
raise Exception(line + ' ' + label)
if ';' not in label:
section_label = {
'label': label,

View File

@ -1,3 +1,5 @@
from __future__ import print_function
from __future__ import absolute_import
#author: Bryan Bishop <kanzure@gmail.com>
#date: 2012-01-03
#purpose: map which addresses are left
@ -6,11 +8,11 @@ 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
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
from .pretty_map_headers import map_header_pretty_printer, map_name_cleaner
except Exception:
pass
@ -183,9 +185,9 @@ def generate_diff_insert(line_number, newline):
diffcontent = subprocess.check_output(
"diff -u {0} {1}".format(os.path.join(pokered_dir, "main.asm"), newfile_filename),
shell=True)
except AttributeError, exc:
except AttributeError as exc:
raise exc
except Exception, exc:
except Exception as exc:
diffcontent = exc.output
os.system("rm " + original_filename)
@ -197,7 +199,7 @@ 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."
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"])))
@ -213,8 +215,8 @@ def insert_map_header_asm(map_id):
diff = generate_diff_insert(line_number, newlines)
print diff
print "... Applying diff."
print(diff)
print("... Applying diff.")
#write the diff to a file
fh = open("temp.patch", "w")
@ -236,7 +238,7 @@ def wrapper_insert_map_header_asm(map_id):
def dump_all_remaining_maps():
for map_id in map_headers:
print "Inserting map id=" + str(map_id)
print("Inserting map id=" + str(map_id))
wrapper_insert_map_header_asm(map_id)
def reset_incbins():
@ -249,7 +251,7 @@ def reset_incbins():
process_incbins()
def apply_diff(diff, try_fixing=True, do_compile=True):
print "... Applying diff."
print("... Applying diff.")
#write the diff to a file
fh = open("temp.patch", "w")
@ -272,7 +274,7 @@ def apply_diff(diff, try_fixing=True, do_compile=True):
try:
subprocess.check_call("cd {0}; make clean; LC_CTYPE=C make".format(pokered_dir), shell=True)
return True
except Exception, exc:
except Exception as exc:
if try_fixing:
os.system("mv {0} {1}".format(
os.path.join(pokered_dir, "main1.asm"),
@ -390,7 +392,7 @@ def get_labels_between(start_line_id, end_line_id, bank_id):
else:
local_pointer = hex((address % 0x4000) + 0x4000).replace("0x", "$")
print line_label + " is at " + hex(address)
print(line_label + " is at " + hex(address))
label = {
"line_number": line_id,
@ -438,7 +440,7 @@ def scan_for_predefined_labels():
else:
end_line_id = len(asm) - 1
print "bank" + abbreviation + " starts at " + str(start_line_id) + " to " + str(end_line_id)
print("bank" + abbreviation + " starts at " + str(start_line_id) + " to " + str(end_line_id))
bank_intervals[bank_id] = {
"start": start_line_id,
@ -502,6 +504,6 @@ if __name__ == "__main__":
#dump_all_remaining_maps()
scan_for_predefined_labels()
print "Errors:"
print label_errors
print("Errors:")
print(label_errors)

View File

@ -1,11 +1,13 @@
from __future__ import print_function
from __future__ import absolute_import
#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
from . import extract_maps
from . 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 .pretty_map_headers import map_name_cleaner, txt_bytes, spacing, constant_abbreviation_bytes
except Exception as exc: pass
from operator import itemgetter
import sys
debug = False #set to True to increase logging output
@ -31,7 +33,7 @@ def how_many_until(byte, 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"] + ")"
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
@ -155,7 +157,7 @@ def parse_text_script(text_pointer, text_id, map_id, txfar=False):
#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)
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
@ -317,7 +319,7 @@ def parse_text_script(text_pointer, text_id, map_id, txfar=False):
#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)
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
@ -359,7 +361,7 @@ def analyze_texts():
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"])
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
@ -382,7 +384,7 @@ def find_missing_08s(all_texts):
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"])
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"):
@ -412,7 +414,7 @@ def text_pretty_printer_at(start_address, label="SomeLabel"):
if not "lines" in commands[this_command].keys():
command = commands[this_command]
if not "type" in command.keys():
print "ERROR in command: " + str(command)
print("ERROR in command: " + str(command))
continue #dunno what to do here?
if command["type"] == 0x1: #TX_RAM
@ -501,7 +503,7 @@ def text_pretty_printer_at(start_address, label="SomeLabel"):
byte_count += 1
had_db_last = True
else:
print "ERROR in command: " + hex(command["type"])
print("ERROR in command: " + hex(command["type"]))
had_db_last = False
#everything else is for $0s, really
@ -585,7 +587,7 @@ def text_pretty_printer_at(start_address, label="SomeLabel"):
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
print(output)
return (output, byte_count)
def is_label_in_asm(label):
@ -619,16 +621,16 @@ def find_undone_texts():
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]))
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?"
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])
print(str(result[1]) + " times: " + hex(result[0]))
def scan_rom_for_tx_fars(printer=True):
"""find TX_FARs
@ -675,14 +677,14 @@ def scan_rom_for_tx_fars(printer=True):
if address_bundle[0] in pre_handled:
continue #already did this
print "-------"
print "TX_FAR is at: " + hex(address_bundle[1])
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 "-------"
print("-------")
pre_handled.append(address_bundle[0])
return possible_tx_far_targets

View File

@ -1,8 +1,10 @@
from __future__ import print_function
from __future__ import absolute_import
#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
from . 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]
@ -101,4 +103,4 @@ if __name__ == "__main__":
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)
print(print_connections(map_id, do_output=True))

View File

@ -1,3 +1,5 @@
from __future__ import print_function
from __future__ import absolute_import
#author: Bryan Bishop <kanzure@gmail.com>
#date: 2012-01-14
#split out blocksets into binary data files
@ -5,7 +7,7 @@
# but it's too many lines and will probably crash rgbasm.
import sys
import extract_maps
from . import extract_maps
extract_maps.load_rom()
spacing = " "
@ -77,7 +79,7 @@ for tileblock_id in tileblocks.keys():
fh.write(main_data)
fh.close()
print output
print(output)
"""
Tset00_Block:

View File

@ -1,7 +1,9 @@
from __future__ import print_function
from __future__ import absolute_import
#author: Bryan Bishop <kanzure@gmail.com>
#date: 2012-01-14
#throw tilesets into separate files
import extract_maps
from . import extract_maps
extract_maps.load_rom()
locations = {
@ -29,9 +31,9 @@ locations = {
for tileset_id in locations.keys():
tileset = locations[tileset_id]
print "writing ../gfx/tilesets/" + tileset[2] + ".2bpp"
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."
print("Done.")

View File

@ -1,12 +1,14 @@
from __future__ import print_function
from __future__ import absolute_import
#author: Bryan Bishop <kanzure@gmail.com>
#date: 2012-01-27
#fix trainer header labels to not suck so much
import analyze_incbins
from . 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))
if debug: print(str(type(asm)))
single_asm = "\n".join(asm)
current_map_name = "asdjkl;"
line_id = 0
@ -31,8 +33,8 @@ def replace_trainer_header_labels(debug=False):
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
if debug: print("old_label = " + old_label)
if debug: print("new_label = " + new_label)
trainer_header_counter += 1
@ -50,8 +52,8 @@ def replace_trainer_header_labels(debug=False):
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
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]
@ -59,8 +61,8 @@ def replace_trainer_header_labels(debug=False):
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
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]
@ -68,12 +70,12 @@ def replace_trainer_header_labels(debug=False):
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
if debug: print("old_label = " + old_label)
if debug: print("new_label = " + new_label)
line_id += 1
print single_asm
print(single_asm)
if __name__ == "__main__":
analyze_incbins.load_asm()

View File

@ -1,10 +1,12 @@
from __future__ import print_function
from __future__ import absolute_import
#author: Bryan Bishop <kanzure@gmail.com>
#date: 2012-01-09
import extract_maps
from . import extract_maps
import os
import json
from copy import copy, deepcopy
from pretty_map_headers import random_hash, map_name_cleaner
from .pretty_map_headers import random_hash, map_name_cleaner
from ctypes import c_int8
import sys
@ -530,7 +532,7 @@ temp_opt_table = [
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]]
print("CONFLICT: " + line[0] + " ($" + hex(line[1])[2:] + ") .... " + conflict_table[line[1]])
else:
conflict_table[line[1]] = line[0]
@ -562,8 +564,8 @@ def load_labels(filename="labels.json"):
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
print("You must run analyze_incbins.scan_for_predefined_labels() to create \"labels.json\". Trying...")
from . import analyze_incbins
analyze_incbins.scan_for_predefined_labels()
load_labels()
@ -607,7 +609,7 @@ def output_bank_opcodes(original_offset, max_byte_count=0x4000):
bank_id = 0
if original_offset > 0x8000:
bank_id = original_offset / 0x4000
print "bank id is: " + str(bank_id)
print("bank id is: " + str(bank_id))
last_hl_address = None #for when we're scanning the main map script
last_a_address = None
@ -849,4 +851,4 @@ if __name__ == "__main__":
extract_maps.load_map_pointers()
extract_maps.read_all_map_headers()
print output_bank_opcodes(int(sys.argv[1], 16))[0]
print(output_bank_opcodes(int(sys.argv[1], 16))[0])

View File

@ -1,6 +1,7 @@
from __future__ import absolute_import
import json
import analyze_incbins
from . import analyze_incbins
analyze_incbins.scan_for_predefined_labels()
with open('../pokered.sym', 'w') as sym:

View File

@ -1,10 +1,12 @@
from __future__ import print_function
from __future__ import absolute_import
#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
from . 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
from . import analyze_incbins
import os, sys
import subprocess
spacing = " "
@ -17,7 +19,7 @@ def insert_object(map_id):
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."
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)
@ -36,9 +38,9 @@ def insert_object(map_id):
newlines = "\n".join(line for line in newlines)
diff = generate_diff_insert(line_number, newlines)
print diff
print(diff)
print "... Applying diff."
print("... Applying diff.")
#write the diff to a file
fh = open("temp.patch", "w")

View File

@ -1,14 +1,16 @@
from __future__ import print_function
from __future__ import absolute_import
#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
from . 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
from . 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
from . import analyze_incbins
from .gbz80disasm import text_asm_pretty_printer, output_bank_opcodes, load_labels, find_label
import os, sys
import subprocess
spacing = " "
@ -66,13 +68,13 @@ def insert_tx_far(map_id, text_id, tx_far_line=None):
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)
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)
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)
@ -105,8 +107,8 @@ def insert_tx_far(map_id, text_id, tx_far_line=None):
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
print("working on map_id=" + str(map_id) + " text_id=" + str(text_id))
print(diff)
apply_diff(diff)
def insert_all_tx_far_targets():
@ -184,12 +186,12 @@ def insert_texts_label(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"
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"
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 )
@ -208,8 +210,8 @@ def insert_texts_label(map_id):
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
print("working on map_id=" + str(map_id) + " texts_pointer=" + hex(texts_pointer))
print(diff)
apply_diff(diff)
#untested as of 2012-01-07
@ -241,7 +243,7 @@ def txt_to_tx_far_pretty_printer(address, label, target_label, include_byte=Fals
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)
print("bad map id=" + str(map_id))
return
map2 = extract_maps.map_headers[map_id]
if map2["texts"][text_id] == {0: {}}: return None
@ -253,7 +255,7 @@ def insert_text_label_tx_far(map_id, text_id):
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]
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
@ -261,12 +263,12 @@ def insert_text_label_tx_far(map_id, text_id):
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)
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 + ":)"
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
@ -288,8 +290,8 @@ def insert_text_label_tx_far(map_id, text_id):
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
print("working on map_id=" + str(map_id) + " text_id=" + str(text_id))
print(diff)
apply_diff(diff)
def insert_all_text_labels():
@ -321,17 +323,17 @@ def insert_08_asm(map_id, text_id, line_id=0):
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)
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"
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 + ":)"
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 )
@ -351,8 +353,8 @@ def insert_08_asm(map_id, text_id, line_id=0):
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
print("working on map_id=" + str(map_id) + " text_id=" + str(text_id))
print(diff)
result = apply_diff(diff)
if result == False:
@ -376,7 +378,7 @@ def insert_all_08s():
text_id = the_08_line[1]
line_id = the_08_line[2]
print "processing map_id=" + str(map_id) + " text_id=" + str(text_id)
print("processing map_id=" + str(map_id) + " text_id=" + str(text_id))
insert_08_asm(map_id, text_id, line_id)
#reset everything
@ -396,17 +398,17 @@ def insert_all_08s():
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)
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"
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"
print("skipping asm because the label is taken")
return False
newlines = split_incbin_line_into_three(line_number, start_address, end_address - start_address )
@ -426,7 +428,7 @@ def insert_asm(start_address, label, text_asm=None, end_address=None):
newlines = newlines.replace("$x", "$")
diff = generate_diff_insert(line_number, newlines)
print diff
print(diff)
result = apply_diff(diff, try_fixing=True)
return True
@ -436,13 +438,13 @@ def insert_text(address, label, apply=False, try_fixing=True):
line_number = find_incbin_to_replace_for(start_address)
if line_number == None:
print "skipping text at " + hex(start_address) + " with address " + label
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"
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)
@ -466,7 +468,7 @@ def insert_text(address, label, apply=False, try_fixing=True):
newlines = newlines.replace("Char52", "$52")
diff = generate_diff_insert(line_number, newlines)
print diff
print(diff)
if apply:
return apply_diff(diff, try_fixing=try_fixing)
else: #simulate a successful insertion
@ -560,16 +562,16 @@ def scan_for_map_scripts_pointer():
isolate_incbins()
process_incbins()
print "map_id=" + str(map_id) + " scripts are: " + str(script_pointers)
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"
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")
@ -625,8 +627,8 @@ def scan_for_map_scripts_pointer():
isolate_incbins()
process_incbins()
else:
print "trouble inserting map script pointer list"
print script_asm
print("trouble inserting map script pointer list")
print(script_asm)
sys.exit(0)
def scan_rom_for_tx_fars_and_insert():
@ -647,7 +649,7 @@ def scan_rom_for_tx_fars_and_insert():
#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)
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
@ -662,7 +664,7 @@ def scan_rom_for_tx_fars_and_insert():
result2 = insert_text(tx_far_address, tx_far_label, apply=True)
local_reset_incbins()
elif result == "skip":
print "skipping " + hex(tx_far_address)
print("skipping " + hex(tx_far_address))
# result2 = insert_text(tx_far_address, tx_far_label, apply=True)
# local_reset_incbins()
@ -787,12 +789,12 @@ def insert_base_stats(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)
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.."
print("skipping " + label + " because it is already in use..")
return
newlines = split_incbin_line_into_three(line_number, address, 28 )
@ -811,7 +813,7 @@ def insert_base_stats(id):
newlines = newlines.replace("$x", "$")
diff = generate_diff_insert(line_number, newlines)
print diff
print(diff)
apply_diff(diff, try_fixing=False, do_compile=False)
def insert_all_base_stats():

View File

@ -1,8 +1,10 @@
from __future__ import print_function
from __future__ import absolute_import
#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
from . import extract_maps
from .pretty_map_headers import map_name_cleaner, map_constants
def get_map_size_constants(do_sed=False):
output = ""
@ -34,4 +36,4 @@ 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)
print(get_map_size_constants(do_sed=True))

View File

@ -1,11 +1,13 @@
from __future__ import print_function
from __future__ import absolute_import
#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
from . 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
from . import analyze_incbins
import os, sys
import subprocess
spacing = " "
@ -32,7 +34,7 @@ def extract_map_block_data(map_id, savefile=False):
full_filepath = "maps/" + filename + ".blk"
if savefile:
print "Saving ../maps/" + filename + ".blk for map id=" + str(map_id)
print("Saving ../maps/" + filename + ".blk for map id=" + str(map_id))
fh = open("../maps/" + filename + ".blk", "w")
fh.write(blocksdata)
fh.close()
@ -61,12 +63,12 @@ def insert_map_block_label(map_id):
x = int(map["x"], 16)
size = x*y
print "map name: " + map["name"]
print "map address: " + map["map_pointer"]
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."
print("skipping map id=" + str(map_id) + " probably because it was already done.")
used_map_pointers.append(map["map_pointer"])
return
@ -90,8 +92,8 @@ def insert_map_block_label(map_id):
newlines = newlines.replace("$x", "$")
diff = generate_diff_insert(line_number, newlines)
print diff
print "... Applying diff."
print(diff)
print("... Applying diff.")
#write the diff to a file
fh = open("temp.patch", "w")
@ -141,14 +143,14 @@ def insert_all_labels():
#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)"
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"]
print("XYZ|" + mapmap["name"])
insert_map_block_label(map)
used_map_pointers.append(mapmap["map_pointer"])

View File

@ -2,12 +2,14 @@
#author: Bryan Bishop <kanzure@gmail.com>
#date: 2012-01-02
#purpose: dump asm for each map header
from __future__ import print_function
from __future__ import absolute_import
import json
import extract_maps
import sprite_helper
from . import extract_maps
from . import sprite_helper
import random
import string
import analyze_texts #hopefully not a dependency loop
from . import analyze_texts #hopefully not a dependency loop
base = 16
spacing = " "
@ -395,7 +397,7 @@ def write_connections(north, south, west, east):
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"
raise Exception("unpredicted outcome on write_connections")
#TODO: make this elegant
def connection_line(byte):
@ -551,7 +553,7 @@ def object_data_pretty_printer(map_id):
try:
warp_to_map_constant = map_constants[warp_to_map_id]
except Exception, exc:
except Exception as 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"
@ -606,7 +608,7 @@ def object_data_pretty_printer(map_id):
try:
previous_location = map_constants[object["warps"][warp_to_id]["warp_to_map_id"]]
comment = " ; " + previous_location
except Exception, exc:
except Exception as exc:
comment = ""
output += spacing + "EVENT_DISP $" + map_width[2:] + ", $" + warp_to_y + ", $" + warp_to_x + comment + "\n"
@ -727,7 +729,7 @@ def print_all_headers():
for map in maps:
output = map_header_pretty_printer(map)
if output != "": print output
if output != "": print(output)
if __name__ == "__main__":
#read binary data from file

View File

@ -1,14 +1,16 @@
from __future__ import print_function
from __future__ import absolute_import
#author: Bryan Bishop <kanzure@gmail.com>
#date: 2012-01-16
from optparse import OptionParser
from analyze_texts import text_pretty_printer_at
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"
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")

View File

@ -1,8 +1,10 @@
from __future__ import print_function
from __future__ import absolute_import
#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
from .gbz80disasm import load_labels, find_label
from .extract_maps import calculate_pointer
import sys
spacing = "\t"
rom = None
@ -46,8 +48,8 @@ def pretty_print_trainer_header(address, label=None):
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 ""
print("label not found for (TextBeforeBattle) " + hex(calculate_pointer(partial_pointer, bank_id)))
print("")
label = "$" + hex(partial_pointer)[2:]
#sys.exit(0)
@ -59,8 +61,8 @@ def pretty_print_trainer_header(address, label=None):
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 ""
print("label not found for (TextAfterBattle) " + hex(calculate_pointer(partial_pointer, bank_id)))
print("")
label = "$" + hex(partial_pointer)[2:]
#sys.exit(0)
@ -72,8 +74,8 @@ def pretty_print_trainer_header(address, label=None):
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 ""
print("label not found for (TextEndBattle) " + hex(calculate_pointer(partial_pointer, bank_id)))
print("")
label = "$" + hex(partial_pointer)[2:]
#sys.exit(0)
@ -85,8 +87,8 @@ def pretty_print_trainer_header(address, label=None):
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 ""
print("label not found for (TextEndBattle) " + hex(calculate_pointer(partial_pointer, bank_id)))
print("")
label = "$" + hex(partial_pointer)[2:]
#sys.exit(0)
@ -99,7 +101,7 @@ def pretty_print_trainer_header(address, label=None):
def all_trainer_headers_at(address):
i = 0
while ord(rom[address + (i*12)]) != 0xff:
print pretty_print_trainer_header(address + (i*12))
print(pretty_print_trainer_header(address + (i*12)))
i += 1
def main():
@ -109,7 +111,7 @@ def main():
parser = OptionParser(usage)
(options, args) = parser.parse_args()
if len(args) == 1:
print "usage: python pretty_trainer_headers.py address label\n"
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")
@ -120,7 +122,7 @@ def main():
rom = open("../baserom.gbc", "r").read()
#print pretty_print_trainer_header(address, label)
print all_trainer_headers_at(address)
print(all_trainer_headers_at(address))
if __name__ == "__main__":
main()

View File

@ -1,10 +1,11 @@
from __future__ import absolute_import
#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 .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
@ -234,7 +235,7 @@ def replace_values():
connection_offset += 6
if __name__ == "__main__":
import extract_maps
from . import extract_maps
extract_maps.load_rom()
extract_maps.load_map_pointers()
extract_maps.read_all_map_headers()

View File

@ -1,3 +1,4 @@
from __future__ import print_function
#author: Bryan Bishop <kanzure@gmail.com>
#date: 2012-01-13
import os
@ -7,7 +8,7 @@ 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)
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")
@ -15,7 +16,7 @@ def take_snapshot_image(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.."
print("generating the image..")
#draw the image
os.system("python romviz.py")

View File

@ -1,17 +1,19 @@
from __future__ import print_function
from __future__ import absolute_import
#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
from . import extract_maps
from . import analyze_incbins
print "loading rom.."
print("loading rom..")
extract_maps.load_rom()
#extract_maps.load_map_pointers()
#extract_maps.read_all_map_headers()
print "analyzing incbins.."
print("analyzing incbins..")
analyze_incbins.load_asm()
analyze_incbins.isolate_incbins()
analyze_incbins.process_incbins()
@ -26,7 +28,7 @@ im.putpalette([
126, 30, 156,
])
print "drawing incbins..."
print("drawing incbins...")
for incbin_key in analyze_incbins.processed_incbins:
incbin = analyze_incbins.processed_incbins[incbin_key]
start = incbin["start"]

View File

@ -1,4 +1,6 @@
import extract_maps
from __future__ import print_function
from __future__ import absolute_import
from . import extract_maps
spacing = "\t"
#provided by sawakita
@ -172,7 +174,7 @@ def load_icons():
pic = thing["picture_number"]
unique_icons.add(pic)
if not icons.has_key(pic): icons[pic] = []
if pic not in icons: icons[pic] = []
alerter = None
if int(thing["y"])-4 > int(map["y"], 16)*2: alerter = True
@ -199,7 +201,7 @@ def print_appearances():
output += spacing + ".. in " + appearance[0] + " at (" + str(appearance[1]) + ", " + str(appearance[2]) + ")" + outside_alert + "\n"
output += "\n"
print output
print(output)
def insert_todo_sprites():
load_icons()
@ -251,7 +253,7 @@ def sprite_printer():
value = hex(key)[2:]
if len(value) == 1: value = "0" + value
print sprites[key] + extra + " EQU $" + value
print(sprites[key] + extra + " EQU $" + value)
def parse_sprite_sheet_pointer_table():
"""parses the bytes making up the pointer table
@ -321,7 +323,7 @@ def parse_sprite_sheet_pointer_table():
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"])
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
@ -398,5 +400,5 @@ if __name__ == "__main__":
#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)
print(pretty_print_sheet_incbins(ptable_sheet_data))
print(pretty_print_sheet_data(ptable_sheet_data))

View File

@ -1,8 +1,10 @@
from __future__ import print_function
from __future__ import absolute_import
#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
from . 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 = " "
@ -39,10 +41,10 @@ def test_first_text_pointer_bytes(range=20): #30 for viridian city, 34 for cerul
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)
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
@ -52,4 +54,4 @@ if __name__ == "__main__":
extract_maps.load_map_pointers()
extract_maps.read_all_map_headers()
print test_first_text_pointer_bytes()
print(test_first_text_pointer_bytes())

View File

@ -2,7 +2,7 @@
Functions to bootstrap the emulator state
"""
from setup_vba import (
from tests.setup_vba import (
vba,
autoplayer,
)

View File

@ -99,7 +99,11 @@ from pokemontools.crystal import (
import pokemontools.wram
import unittest
import mock
try:
import unittest.mock as mock
except ImportError:
import mock
class BasicTestCase(unittest.TestCase):
"this is where i cram all of my unit tests together"
@ -151,6 +155,9 @@ class BasicTestCase(unittest.TestCase):
rom_segment = self.rom[0x112116:0x112116+8]
self.assertEqual(rom_segment, "HTTP/1.0")
def test_rom_text_at(self):
self.assertEquals(rom_text_at(0x112116, 8), b"HTTP/1.0")
def test_rom_interval(self):
address = 0x100
interval = 10
@ -182,9 +189,6 @@ class BasicTestCase(unittest.TestCase):
addr2 = calculate_pointer_from_bytes_at(0x100, bank=True)
self.assertEqual(addr2, 0x2ec3)
def test_rom_text_at(self):
self.assertEquals(rom_text_at(0x112116, 8), "HTTP/1.0")
class TestRomStr(unittest.TestCase):
sample_text = "hello world!"
sample = None

View File

@ -1,16 +1,17 @@
"""
Tests for VBA automation tools
"""
from __future__ import print_function
import unittest
from setup_vba import (
from tests.setup_vba import (
vba,
autoplayer,
keyboard,
)
from bootstrapping import (
from tests.bootstrapping import (
bootstrap,
bootstrap_trainer_battle,
)
@ -267,13 +268,13 @@ class VbaTests(unittest.TestCase):
start_state = self.cry.vba.state
for name in names:
print "Writing name: " + name
print("Writing name: " + name)
self.cry.vba.state = start_state
sequence = self.cry.write(name)
print "sequence is: " + str(sequence)
print("sequence is: " + str(sequence))
# save this selection
self.cry.vba.press("start", hold=20)

View File

@ -4,7 +4,7 @@ Tests for the battle controller
import unittest
from setup_vba import (
from tests.setup_vba import (
vba,
autoplayer,
)

View File

@ -95,7 +95,11 @@ from pokemontools.crystal import (
)
import unittest
import mock
try:
import unittest.mock as mock
except ImportError:
import mock
class TestCram(unittest.TestCase):
"this is where i cram all of my unit tests together"