diff options
59 files changed, 1787 insertions, 1692 deletions
diff --git a/pkmnasm/asmlex.py b/pkmnasm/asmlex.py index 9f61ab3..112c2bf 100644 --- a/pkmnasm/asmlex.py +++ b/pkmnasm/asmlex.py @@ -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() diff --git a/pokemontools/__init__.py b/pokemontools/__init__.py index dc4346a..e4adfb8 100644 --- a/pokemontools/__init__.py +++ b/pokemontools/__init__.py @@ -1,5 +1 @@ -import configuration as config -import crystal -import preprocessor - __version__ = "1.6.0" diff --git a/pokemontools/audio.py b/pokemontools/audio.py index 9e08113..e136545 100644 --- a/pokemontools/audio.py +++ b/pokemontools/audio.py @@ -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)] diff --git a/pokemontools/battle_animations.py b/pokemontools/battle_animations.py index ffc89e4..8cc302f 100644 --- a/pokemontools/battle_animations.py +++ b/pokemontools/battle_animations.py @@ -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)) diff --git a/pokemontools/comparator.py b/pokemontools/comparator.py index 6cc440c..225defa 100644 --- a/pokemontools/comparator.py +++ b/pokemontools/comparator.py @@ -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]) diff --git a/pokemontools/crystal.py b/pokemontools/crystal.py index 6053f1f..74763e0 100644 --- a/pokemontools/crystal.py +++ b/pokemontools/crystal.py @@ -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 - -import addresses +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 + +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. diff --git a/pokemontools/crystalparts/old_parsers.py b/pokemontools/crystalparts/old_parsers.py index 371ba45..81d79ed 100644 --- a/pokemontools/crystalparts/old_parsers.py +++ b/pokemontools/crystalparts/old_parsers.py @@ -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"? diff --git a/pokemontools/disassemble_map_scripts.py b/pokemontools/disassemble_map_scripts.py index f51fb92..28c2ec1 100644 --- a/pokemontools/disassemble_map_scripts.py +++ b/pokemontools/disassemble_map_scripts.py @@ -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] diff --git a/pokemontools/dump_gfx.py b/pokemontools/dump_gfx.py index cddb0b6..01eb069 100644 --- a/pokemontools/dump_gfx.py +++ b/pokemontools/dump_gfx.py @@ -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): diff --git a/pokemontools/gbz80disasm.py b/pokemontools/gbz80disasm.py index 50e1f48..e383db0 100644 --- a/pokemontools/gbz80disasm.py +++ b/pokemontools/gbz80disasm.py @@ -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: diff --git a/pokemontools/gfx.py b/pokemontools/gfx.py index f93553d..0050d79 100644 --- a/pokemontools/gfx.py +++ b/pokemontools/gfx.py @@ -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) diff --git a/pokemontools/graph.py b/pokemontools/graph.py index 47087e5..a639ca0 100644 --- a/pokemontools/graph.py +++ b/pokemontools/graph.py @@ -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): """ diff --git a/pokemontools/interval_map.py b/pokemontools/interval_map.py index daf22cd..fc53e69 100644 --- a/pokemontools/interval_map.py +++ b/pokemontools/interval_map.py @@ -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 diff --git a/pokemontools/labels.py b/pokemontools/labels.py index 69be4b1..f8e8ec2 100644 --- a/pokemontools/labels.py +++ b/pokemontools/labels.py @@ -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: diff --git a/pokemontools/lz.py b/pokemontools/lz.py index aef5c64..f5d90d8 100644 --- a/pokemontools/lz.py +++ b/pokemontools/lz.py @@ -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 ) diff --git a/pokemontools/map_editor.py b/pokemontools/map_editor.py index ff5323a..5abe700 100644 --- a/pokemontools/map_editor.py +++ b/pokemontools/map_editor.py @@ -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() diff --git a/pokemontools/map_gfx.py b/pokemontools/map_gfx.py index b06f0df..a70449d 100644 --- a/pokemontools/map_gfx.py +++ b/pokemontools/map_gfx.py @@ -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) diff --git a/pokemontools/old_parse_scripts.py b/pokemontools/old_parse_scripts.py index 8ed10ef..baf4f9a 100644 --- a/pokemontools/old_parse_scripts.py +++ b/pokemontools/old_parse_scripts.py @@ -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 diff --git a/pokemontools/old_text_script.py b/pokemontools/old_text_script.py index a4cfb8c..b3692fa 100644 --- a/pokemontools/old_text_script.py +++ b/pokemontools/old_text_script.py @@ -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 diff --git a/pokemontools/overworldripper.py b/pokemontools/overworldripper.py index 654f287..b2dec59 100644 --- a/pokemontools/overworldripper.py +++ b/pokemontools/overworldripper.py @@ -1,4 +1,5 @@ -import gfx +from __future__ import absolute_import +from . import gfx def rip_sprites_from_bank(bank, offset=0): """ diff --git a/pokemontools/parse_consecutive_strings.py b/pokemontools/parse_consecutive_strings.py index 4c864ba..eace2bb 100644 --- a/pokemontools/parse_consecutive_strings.py +++ b/pokemontools/parse_consecutive_strings.py @@ -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 diff --git a/pokemontools/pcm.py b/pokemontools/pcm.py index 2e936d9..3a2920b 100755 --- a/pokemontools/pcm.py +++ b/pokemontools/pcm.py @@ -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) diff --git a/pokemontools/pic.py b/pokemontools/pic.py index 34e88f5..25f2621 100644 --- a/pokemontools/pic.py +++ b/pokemontools/pic.py @@ -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(): diff --git a/pokemontools/preprocessor.py b/pokemontools/preprocessor.py index 954263a..92b42b0 100644 --- a/pokemontools/preprocessor.py +++ b/pokemontools/preprocessor.py @@ -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 diff --git a/pokemontools/redmusicdisasm.py b/pokemontools/redmusicdisasm.py index a2b8a2b..51b1901 100755 --- a/pokemontools/redmusicdisasm.py +++ b/pokemontools/redmusicdisasm.py @@ -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
\ No newline at end of file diff --git a/pokemontools/redsfxdisasm.py b/pokemontools/redsfxdisasm.py index f1cfece..63b8dd1 100755 --- a/pokemontools/redsfxdisasm.py +++ b/pokemontools/redsfxdisasm.py @@ -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
\ No newline at end of file diff --git a/pokemontools/redsfxheaders.py b/pokemontools/redsfxheaders.py index 223d82f..eff9dd0 100755 --- a/pokemontools/redsfxheaders.py +++ b/pokemontools/redsfxheaders.py @@ -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)
\ No newline at end of file diff --git a/pokemontools/romstr.py b/pokemontools/romstr.py index 69a4f2a..ed77896 100644 --- a/pokemontools/romstr.py +++ b/pokemontools/romstr.py @@ -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) diff --git a/pokemontools/scan_includes.py b/pokemontools/scan_includes.py index 53ff091..fea7002 100644 --- a/pokemontools/scan_includes.py +++ b/pokemontools/scan_includes.py @@ -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() diff --git a/pokemontools/tcgdisasm.py b/pokemontools/tcgdisasm.py index 2e9e8b3..e34d944 100755 --- a/pokemontools/tcgdisasm.py +++ b/pokemontools/tcgdisasm.py @@ -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) diff --git a/pokemontools/vba/autoplayer.py b/pokemontools/vba/autoplayer.py index af14d47..2d2e8af 100644 --- a/pokemontools/vba/autoplayer.py +++ b/pokemontools/vba/autoplayer.py @@ -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 diff --git a/pokemontools/vba/keyboard.py b/pokemontools/vba/keyboard.py index 4a07e57..a3d7611 100644 --- a/pokemontools/vba/keyboard.py +++ b/pokemontools/vba/keyboard.py @@ -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") diff --git a/pokemontools/vba/vba.py b/pokemontools/vba/vba.py index 204e102..3ec347c 100644 --- a/pokemontools/vba/vba.py +++ b/pokemontools/vba/vba.py @@ -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): """ diff --git a/pokemontools/wram.py b/pokemontools/wram.py index 8270566..a372952 100644 --- a/pokemontools/wram.py +++ b/pokemontools/wram.py @@ -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, diff --git a/redtools/analyze_incbins.py b/redtools/analyze_incbins.py index db503ff..9bddacd 100644 --- a/redtools/analyze_incbins.py +++ b/redtools/analyze_incbins.py @@ -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) diff --git a/redtools/analyze_texts.py b/redtools/analyze_texts.py index 08b8ab0..0f17a38 100644 --- a/redtools/analyze_texts.py +++ b/redtools/analyze_texts.py @@ -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 diff --git a/redtools/connection_helper.py b/redtools/connection_helper.py index c15b358..d6306ad 100644 --- a/redtools/connection_helper.py +++ b/redtools/connection_helper.py @@ -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)) diff --git a/redtools/extract_tileblocks.py b/redtools/extract_tileblocks.py index 1d01c34..a8a8182 100644 --- a/redtools/extract_tileblocks.py +++ b/redtools/extract_tileblocks.py @@ -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: diff --git a/redtools/extract_tilesets.py b/redtools/extract_tilesets.py index a0eb477..ca99606 100644 --- a/redtools/extract_tilesets.py +++ b/redtools/extract_tilesets.py @@ -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.") diff --git a/redtools/fix_labels.py b/redtools/fix_labels.py index 321a18e..13350f6 100644 --- a/redtools/fix_labels.py +++ b/redtools/fix_labels.py @@ -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() diff --git a/redtools/gbz80disasm.py b/redtools/gbz80disasm.py index 396ce5b..f6711a8 100644 --- a/redtools/gbz80disasm.py +++ b/redtools/gbz80disasm.py @@ -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]) diff --git a/redtools/generate_sys.py b/redtools/generate_sys.py index 7295703..a321cf4 100644 --- a/redtools/generate_sys.py +++ b/redtools/generate_sys.py @@ -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: diff --git a/redtools/insert_object_data.py b/redtools/insert_object_data.py index e779c10..b275078 100644 --- a/redtools/insert_object_data.py +++ b/redtools/insert_object_data.py @@ -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") diff --git a/redtools/insert_texts.py b/redtools/insert_texts.py index d5a8015..f89d2da 100644 --- a/redtools/insert_texts.py +++ b/redtools/insert_texts.py @@ -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(): diff --git a/redtools/make_map_size_constants.py b/redtools/make_map_size_constants.py index 4dfb1be..70b12c5 100644 --- a/redtools/make_map_size_constants.py +++ b/redtools/make_map_size_constants.py @@ -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)) diff --git a/redtools/map_block_dumper.py b/redtools/map_block_dumper.py index 1ffa1e6..add52d2 100644 --- a/redtools/map_block_dumper.py +++ b/redtools/map_block_dumper.py @@ -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"]) diff --git a/redtools/pretty_map_headers.py b/redtools/pretty_map_headers.py index ef26be3..2534622 100644 --- a/redtools/pretty_map_headers.py +++ b/redtools/pretty_map_headers.py @@ -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 diff --git a/redtools/pretty_text.py b/redtools/pretty_text.py index 4933dca..dd17a12 100644 --- a/redtools/pretty_text.py +++ b/redtools/pretty_text.py @@ -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") diff --git a/redtools/pretty_trainer_headers.py b/redtools/pretty_trainer_headers.py index 5bfc2be..47d68db 100644 --- a/redtools/pretty_trainer_headers.py +++ b/redtools/pretty_trainer_headers.py @@ -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() diff --git a/redtools/replace_dimensions.py b/redtools/replace_dimensions.py index fc089f7..b8bb717 100644 --- a/redtools/replace_dimensions.py +++ b/redtools/replace_dimensions.py @@ -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() diff --git a/redtools/romvisualizer.py b/redtools/romvisualizer.py index 516ac91..c294556 100644 --- a/redtools/romvisualizer.py +++ b/redtools/romvisualizer.py @@ -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") diff --git a/redtools/romviz.py b/redtools/romviz.py index 3f07d65..23661b3 100644 --- a/redtools/romviz.py +++ b/redtools/romviz.py @@ -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"] diff --git a/redtools/sprite_helper.py b/redtools/sprite_helper.py index ee7a5f4..9e4c804 100644 --- a/redtools/sprite_helper.py +++ b/redtools/sprite_helper.py @@ -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)) diff --git a/redtools/text_pointers.py b/redtools/text_pointers.py index f0f74da..84e1e79 100644 --- a/redtools/text_pointers.py +++ b/redtools/text_pointers.py @@ -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()) diff --git a/tests/bootstrapping.py b/tests/bootstrapping.py index b71c19a..a8c2402 100644 --- a/tests/bootstrapping.py +++ b/tests/bootstrapping.py @@ -2,7 +2,7 @@ Functions to bootstrap the emulator state """ -from setup_vba import ( +from tests.setup_vba import ( vba, autoplayer, ) diff --git a/tests/integration/tests.py b/tests/integration/tests.py index 79fadda..e5ca6cd 100644 --- a/tests/integration/tests.py +++ b/tests/integration/tests.py @@ -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 diff --git a/tests/test_vba.py b/tests/test_vba.py index caa1867..a5f7589 100644 --- a/tests/test_vba.py +++ b/tests/test_vba.py @@ -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) diff --git a/tests/test_vba_battle.py b/tests/test_vba_battle.py index c6debc3..5664392 100644 --- a/tests/test_vba_battle.py +++ b/tests/test_vba_battle.py @@ -4,7 +4,7 @@ Tests for the battle controller import unittest -from setup_vba import ( +from tests.setup_vba import ( vba, autoplayer, ) diff --git a/tests/tests.py b/tests/tests.py index 4c7f7a4..13b1e49 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -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" |