summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoryenatch <yenatch@gmail.com>2013-12-20 00:43:30 -0500
committeryenatch <yenatch@gmail.com>2013-12-21 00:37:35 -0500
commitefe0b717ef21acde2d30fc7de580547738ca67d6 (patch)
tree524c63520cc852d4244a899ec08d5e39b517cec8
parent973a78167b104479bb6c8c4c528ae914106b1b53 (diff)
parentf0aaf3cd568c485af40690ce0f18a6cd456ed02e (diff)
Merge remote-tracking branch 'kanzure/master' into battle-animations
Conflicts: pokemontools/wram.py
-rw-r--r--pokemontools/labels.py26
-rw-r--r--pokemontools/map_editor.py17
-rw-r--r--pokemontools/preprocessor.py10
-rw-r--r--pokemontools/scan_includes.py36
-rw-r--r--pokemontools/sym.py33
-rw-r--r--pokemontools/vba/path.py57
-rw-r--r--pokemontools/wram.py43
7 files changed, 158 insertions, 64 deletions
diff --git a/pokemontools/labels.py b/pokemontools/labels.py
index 96e34b9..87e9990 100644
--- a/pokemontools/labels.py
+++ b/pokemontools/labels.py
@@ -8,33 +8,39 @@ import json
import logging
import pointers
+import sym
class Labels(object):
"""
Store all labels.
"""
- filename = "labels.json"
- def __init__(self, config):
+ def __init__(self, config, filename="pokecrystal.map"):
"""
Setup the instance.
"""
self.config = config
- self.path = os.path.join(self.config.path, Labels.filename)
+ self.filename = filename
+ self.path = os.path.join(self.config.path, self.filename)
def initialize(self):
"""
Handle anything requiring file-loading and such.
"""
+ # Look for a mapfile if it's not given
if not os.path.exists(self.path):
- logging.info(
- "Running crystal.scan_for_predefined_labels to create \"{0}\". Trying.."
- .format(Labels.filename)
- )
- import crystal
- crystal.scan_for_predefined_labels()
+ self.filename = find_mapfile_in_dir(self.config.path)
+ if self.filename == None:
+ raise Exception, "Couldn't find any mapfiles. Run rgblink -m to create a mapfile."
+ self.path = os.path.join(self.config.path, self.filename)
- self.labels = json.read(open(self.path, "r").read())
+ self.labels = sym.read_mapfile(self.path)
+
+def find_mapfile_in_dir(path):
+ for filename in os.listdir(path):
+ if os.path.splitext(filename)[1] == '.map':
+ return filename
+ return None
def remove_quoted_text(line):
"""get rid of content inside quotes
diff --git a/pokemontools/map_editor.py b/pokemontools/map_editor.py
index c30fcd8..43042cb 100644
--- a/pokemontools/map_editor.py
+++ b/pokemontools/map_editor.py
@@ -128,6 +128,7 @@ def get_constants(config=config):
name, value = [s.strip() for s in line.split(' EQU ')]
constants[name] = eval(value.split(';')[0].replace('$','0x').replace('%','0b'))
config.constants = constants
+ return constants
class Application(Frame):
def __init__(self, master=None, config=config):
@@ -149,10 +150,10 @@ class Application(Frame):
self.picker_frame = Frame(self)
self.picker_frame.grid(row=1, column=1)
- self.new = Button(self.button_frame)
- self.new["text"] = "New"
- self.new["command"] = self.new_map
- self.new.grid(row=0, column=0, padx=2)
+ self.button_new = Button(self.button_frame)
+ self.button_new["text"] = "New"
+ self.button_new["command"] = self.new_map
+ self.button_new.grid(row=0, column=0, padx=2)
self.open = Button(self.button_frame)
self.open["text"] = "Open"
@@ -683,14 +684,6 @@ def macro_values(line, macro):
values = values[1:]
return values
-def db_value(line):
- macro = 'db'
- return macro_values(line, macro)
-
-def db_values(line):
- macro = 'db'
- return macro_values(line, macro)
-
def asm_at_label(asm, label):
label_def = label + ':'
lines = asm.split('\n')
diff --git a/pokemontools/preprocessor.py b/pokemontools/preprocessor.py
index 5ac7724..e7de46d 100644
--- a/pokemontools/preprocessor.py
+++ b/pokemontools/preprocessor.py
@@ -483,22 +483,18 @@ class Preprocessor(object):
for l in lines:
self.read_line(l)
- self.update_globals()
-
def update_globals(self):
"""
Add any labels not already in globals.asm.
"""
- # TODO: pokered needs to be fixed
- try:
- globes = open(os.path.join(self.config.path, 'globals.asm'), 'r+')
+ path = os.path.join(self.config.path, 'globals.asm')
+ if os.path.exists(path):
+ globes = open(path, 'r+')
lines = globes.readlines()
for globe in self.globes:
line = 'GLOBAL ' + globe + '\n'
if line not in lines:
globes.write(line)
- except Exception as exception:
- pass # don't care if it's not there...
def read_line(self, l):
"""
diff --git a/pokemontools/scan_includes.py b/pokemontools/scan_includes.py
new file mode 100644
index 0000000..7f34e92
--- /dev/null
+++ b/pokemontools/scan_includes.py
@@ -0,0 +1,36 @@
+# coding: utf-8
+
+"""
+Recursively scan an asm file for rgbasm INCLUDEs and INCBINs.
+Used to generate dependencies for each rgbasm object.
+"""
+
+import os
+import sys
+
+import configuration
+conf = configuration.Config()
+
+def recursive_scan(filename, includes = []):
+ if (filename[-4:] == '.asm' or filename[-3] == '.tx') and os.path.exists(filename):
+ lines = open(filename).readlines()
+ for line in lines:
+ for directive in ('INCLUDE', 'INCBIN'):
+ if directive in line:
+ line = line[:line.find(';')]
+ if directive in line:
+ include = line.split('"')[1]
+ if include not in includes:
+ includes += [include]
+ includes = recursive_scan(os.path.join(conf.path, include), includes)
+ break
+ return includes
+
+if __name__ == '__main__':
+ filenames = sys.argv[1:]
+ dependencies = []
+ for filename in filenames:
+ dependencies += recursive_scan(os.path.join(conf.path, filename))
+ dependencies = list(set(dependencies))
+ sys.stdout.write(' '.join(dependencies))
+
diff --git a/pokemontools/sym.py b/pokemontools/sym.py
index ebd8532..b1e755f 100644
--- a/pokemontools/sym.py
+++ b/pokemontools/sym.py
@@ -4,7 +4,7 @@ import os
import sys
import json
-def make_sym_from_json(filename = '../pokecrystal.sym', j = 'labels.json'):
+def make_sym_from_json(filename = 'pokecrystal.sym', j = 'labels.json'):
output = ''
labels = json.load(open(j))
for label in labels:
@@ -12,13 +12,13 @@ def make_sym_from_json(filename = '../pokecrystal.sym', j = 'labels.json'):
with open(filename, 'w') as sym:
sym.write(output)
-def make_json_from_mapfile(filename='labels.json', mapfile='../pokecrystal.map'):
+def make_json_from_mapfile(filename='labels.json', mapfile='pokecrystal.map'):
output = []
labels = filter_wram_addresses(read_mapfile(mapfile))
with open(filename, 'w') as out:
out.write(json.dumps(labels))
-def read_mapfile(filename='../pokecrystal.map'):
+def read_mapfile(filename='pokecrystal.map'):
"""
Scrape label addresses from an rgbds mapfile.
"""
@@ -29,9 +29,15 @@ def read_mapfile(filename='../pokecrystal.map'):
lines = mapfile.readlines()
for line in lines:
- # bank #
- if 'Bank #' in line:
- cur_bank = int(line.lstrip('Bank #').strip(';\n').strip(' (HOME)'))
+ if line[0].strip(): # section type def
+ section_type = line.split(' ')[0]
+ if section_type == 'Bank': # ROM
+ cur_bank = int(line.split(' ')[1].split(':')[0][1:])
+ elif section_type in ['WRAM0', 'HRAM']:
+ cur_bank = 0
+ elif section_type in ['WRAM, VRAM']:
+ cur_bank = int(line.split(' ')[2].split(':')[0][1:])
+ cur_bank = int(line.split(' ')[2].split(':')[0][1:])
# label definition
elif '=' in line:
@@ -39,21 +45,10 @@ def read_mapfile(filename='../pokecrystal.map'):
address = int(address.lstrip().replace('$', '0x'), 16)
label = label.strip()
- # rgbds doesn't support ram banks yet
bank = cur_bank
offset = address
-
- ranges = [
- 0x8000 <= address < 0xa000,
- 0xa000 <= address < 0xc000,
- 0xc000 <= address < 0xd000,
- 0xd000 <= address < 0xe000,
- ]
-
- if any(ranges):
- bank = 0
- else:
- offset += (bank * 0x4000 - 0x4000) if bank > 0 else 0
+ if address < 0x8000 and bank: # ROM
+ offset += (bank - 1) * 0x4000
labels += [{
'label': label,
diff --git a/pokemontools/vba/path.py b/pokemontools/vba/path.py
index 7596b86..2e50d1b 100644
--- a/pokemontools/vba/path.py
+++ b/pokemontools/vba/path.py
@@ -9,8 +9,14 @@ path finding implementation
import pokemontools.configuration
config = pokemontools.configuration.Config()
+import pokemontools.crystal
import pokemontools.map_gfx
+from PIL import (
+ Image,
+ ImageDraw,
+)
+
PENALTIES = {
# The minimum cost for a step must be greater than zero or else the path
# finding implementation might take the player through elaborate routes
@@ -541,7 +547,7 @@ class Map(object):
map.
"""
- def __init__(self, cry, height, width, map_group_id, map_id, config=config):
+ def __init__(self, cry, parsed_map, height, width, map_group_id, map_id, config=config):
"""
:param cry: pokemon crystal emulation interface
:type cry: crystal
@@ -552,11 +558,11 @@ class Map(object):
self.threat_zones = set()
self.obstacles = set()
- self.height = height
- self.width = width
-
+ self.parsed_map = parsed_map
self.map_group_id = map_group_id
self.map_id = map_id
+ self.height = height
+ self.width = width
def travel_to(self, destination_location):
"""
@@ -591,8 +597,17 @@ class Map(object):
palettes = pokemontools.map_gfx.read_palettes(self.config)
map_image = pokemontools.map_gfx.draw_map(self.map_group_id, self.map_id, palettes, show_sprites=True, config=self.config)
- # TODO: draw the given path on the map_image image object
- raise NotImplementedError
+ for coordinates in path:
+ y = coordinates[0]
+ x = coordinates[1]
+
+ some_image = Image.new("RGBA", (32, 32))
+ draw = ImageDraw.Draw(some_image, "RGBA")
+ draw.rectangle([(0, 0), (32, 32)], fill=(0, 0, 0, 127))
+
+ target = [(x * 4, y * 4), ((x + 32) * 4, (y + 32) * 4)]
+
+ map_image.paste(some_image, target, mask=some_image)
return map_image
@@ -611,19 +626,39 @@ class PathPlanner(object):
Runs the path planner and returns a list of positions making up the
path.
"""
- raise NotImplementedError
+ return [(0, 0), (1, 0), (1, 1), (1, 2), (1, 3)]
-def broken_main():
+def plan_and_draw_path_on(map_group_id=1, map_id=1, initial_location=(0, 0), final_location=(2, 2), config=config):
"""
An attempt at an entry point. This hasn't been sufficiently considered yet.
"""
- current_map = Map.from_wram(cry)
+ initial_location = (0, 0)
+ final_location = (2, 2)
+ map_group_id = 1
+ map_id = 1
+
+ pokemontools.crystal.cachably_parse_rom()
+ pokemontools.map_gfx.add_pokecrystal_paths_to_configuration(config)
- # make a graph based on the map
+ # get the map based on data from the rom
+ parsed_map = pokemontools.crystal.map_names[map_group_id][map_id]["header_new"]
+
+ # convert this map into a different structure
+ current_map = Map(cry=None, parsed_map=parsed_map, height=parsed_map.height.byte, width=parsed_map.width.byte, map_group_id=map_group_id, map_id=map_id, config=config)
+
+ # make a graph based on the map data
nodes = create_graph(current_map)
- planner = PathPlanner(current_map, (0, 0), (5, 5))
+ # make an instance of the planner implementation
+ planner = PathPlanner(current_map, initial_location, final_location)
+
+ # Make that planner do its planning based on the current configuration. The
+ # planner should be callable in the future and still have
+ # previously-calculated state, like cached pre-computed routes or
+ # something.
path = planner.plan()
+ # show the path on the map
drawn = current_map.draw_path(path)
+
return drawn
diff --git a/pokemontools/wram.py b/pokemontools/wram.py
index d34737e..1029c8e 100644
--- a/pokemontools/wram.py
+++ b/pokemontools/wram.py
@@ -23,6 +23,9 @@ def make_wram_labels(wram_sections):
wram_labels[label['address']] += [label['label']]
return wram_labels
+def bracket_value(string, i=0):
+ return string.split('[')[1 + i*2].split(']')[0]
+
def read_bss_sections(bss):
sections = []
section = {
@@ -35,10 +38,40 @@ def read_bss_sections(bss):
if 'SECTION' in line:
if section: sections.append(section) # last section
- address = eval(rgbasm_to_py(line[line.find('[')+1:line.find(']')]))
+ comment_index = line.find(';')
+ line, comment = line[:comment_index].lstrip(), line[comment_index:]
+
+ if 'SECTION' == line[:7]:
+ if section: # previous
+ sections += [section]
+
+ section_def = line.split(',')
+ name = section_def[0].split('"')[1]
+ type_ = section_def[1].strip()
+ if len(section_def) > 2:
+ bank = bracket_value(section_def[2])
+ else:
+ bank = None
+
+ if '[' in type_:
+ address = int(rgbasm_to_py(bracket_value(type_)), 16)
+ else:
+ types = {
+ 'VRAM': 0x8000,
+ 'SRAM': 0xa000,
+ 'WRAM0': 0xc000,
+ 'WRAMX': 0xd000,
+ 'HRAM': 0xff80,
+ }
+ if address == None or bank != section['bank'] or section['type'] != type_:
+ if type_ in types.keys():
+ address = types[type_]
+ # else: keep going from this address
+
section = {
- 'name': line.split('"')[1],
- #'type': line.split(',')[1].split('[')[0].strip(),
+ 'name': name,
+ 'type': type_,
+ 'bank': bank,
'start': address,
'labels': [],
}
@@ -54,7 +87,7 @@ def read_bss_sections(bss):
}]
elif line[:3] == 'ds ':
- length = eval(rgbasm_to_py(line[3:line.find(';')]))
+ length = eval(rgbasm_to_py(line[3:]))
address += length
# adjacent labels use the same space
for label in section['labels'][::-1]:
@@ -66,7 +99,7 @@ def read_bss_sections(bss):
elif 'EQU' in line:
# some space is defined using constants
name, value = line.split('EQU')
- name, value = name.strip(), rgbasm_to_py(value)
+ name, value = name.strip(), value.strip().replace('$','0x').replace('%','0b')
globals()[name] = eval(value)
sections.append(section)