summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoryenatch <yenatch@gmail.com>2017-02-13 18:09:31 -0500
committerGitHub <noreply@github.com>2017-02-13 18:09:31 -0500
commit979c98a7c0f67ad6b9685b2d532c66a1f76ffb22 (patch)
treec67cc7b8500aac4e400d4e8bfdbef57a57b63eb1
parent74c620d01ad59bfb09cf4111ace549b925fcb9ab (diff)
parent766dea11bd63dee939db2b47198410e6c6e0fc7e (diff)
Merge pull request #103 from eevee/py3
Python 3 compatibility, sort of, maybe
-rw-r--r--pkmnasm/asmlex.py5
-rw-r--r--pokemontools/__init__.py4
-rw-r--r--pokemontools/audio.py19
-rw-r--r--pokemontools/battle_animations.py16
-rw-r--r--pokemontools/comparator.py30
-rw-r--r--pokemontools/crystal.py136
-rw-r--r--pokemontools/crystalparts/old_parsers.py4
-rw-r--r--pokemontools/disassemble_map_scripts.py5
-rw-r--r--pokemontools/dump_gfx.py14
-rw-r--r--pokemontools/gbz80disasm.py16
-rw-r--r--pokemontools/gfx.py127
-rw-r--r--pokemontools/graph.py8
-rw-r--r--pokemontools/interval_map.py8
-rw-r--r--pokemontools/labels.py9
-rw-r--r--pokemontools/lz.py51
-rw-r--r--pokemontools/map_editor.py9
-rw-r--r--pokemontools/map_gfx.py12
-rw-r--r--pokemontools/old_parse_scripts.py79
-rw-r--r--pokemontools/old_text_script.py5
-rw-r--r--pokemontools/overworldripper.py3
-rw-r--r--pokemontools/parse_consecutive_strings.py12
-rwxr-xr-xpokemontools/pcm.py15
-rw-r--r--pokemontools/pic.py72
-rw-r--r--pokemontools/preprocessor.py9
-rwxr-xr-xpokemontools/redmusicdisasm.py631
-rwxr-xr-xpokemontools/redsfxdisasm.py908
-rwxr-xr-xpokemontools/redsfxheaders.py717
-rw-r--r--pokemontools/romstr.py12
-rw-r--r--pokemontools/scan_includes.py60
-rwxr-xr-xpokemontools/tcgdisasm.py12
-rw-r--r--pokemontools/vba/autoplayer.py12
-rw-r--r--pokemontools/vba/keyboard.py5
-rw-r--r--pokemontools/vba/vba.py36
-rw-r--r--pokemontools/wram.py2
-rw-r--r--redtools/analyze_incbins.py32
-rw-r--r--redtools/analyze_texts.py38
-rw-r--r--redtools/connection_helper.py8
-rw-r--r--redtools/extract_tileblocks.py6
-rw-r--r--redtools/extract_tilesets.py8
-rw-r--r--redtools/fix_labels.py24
-rw-r--r--redtools/gbz80disasm.py16
-rw-r--r--redtools/generate_sys.py3
-rw-r--r--redtools/insert_object_data.py16
-rw-r--r--redtools/insert_texts.py92
-rw-r--r--redtools/make_map_size_constants.py8
-rw-r--r--redtools/map_block_dumper.py26
-rw-r--r--redtools/pretty_map_headers.py16
-rw-r--r--redtools/pretty_text.py6
-rw-r--r--redtools/pretty_trainer_headers.py28
-rw-r--r--redtools/replace_dimensions.py9
-rw-r--r--redtools/romvisualizer.py5
-rw-r--r--redtools/romviz.py12
-rw-r--r--redtools/sprite_helper.py16
-rw-r--r--redtools/text_pointers.py16
-rw-r--r--tests/bootstrapping.py2
-rw-r--r--tests/integration/tests.py12
-rw-r--r--tests/test_vba.py9
-rw-r--r--tests/test_vba_battle.py2
-rw-r--r--tests/tests.py6
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"