Merge pull request #19 from ExMingYan/master

bKGD Fix
This commit is contained in:
RoamerX 2025-04-09 19:45:55 +08:00 committed by GitHub
commit 30dece69da
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
58 changed files with 20599 additions and 20599 deletions

View File

@ -1,21 +1,21 @@
import glob
import re
import json
import os
import subprocess
def rename_subdirs(rootDir, old, new):
for root, dirs, files in os.walk(rootDir):
for name in files:
originalName = os.path.join(root, name)
if root.endswith(old) and os.path.isfile(originalName):
newName = originalName.replace(old + '/', new + '/')
print(originalName + " -> " + newName)
if (not os.path.isdir(root.replace(old, '') + new)):
os.mkdir(root.replace(old, '') + new)
os.rename(originalName, newName)
rename_subdirs("graphics/pokemon", '/alolan', "/alola")
rename_subdirs("graphics/pokemon", '/galarian', "/galar")
rename_subdirs("graphics/pokemon", '/hisuian', "/hisui")
rename_subdirs("graphics/pokemon", '/gigantamax', "/gmax")
import glob
import re
import json
import os
import subprocess
def rename_subdirs(rootDir, old, new):
for root, dirs, files in os.walk(rootDir):
for name in files:
originalName = os.path.join(root, name)
if root.endswith(old) and os.path.isfile(originalName):
newName = originalName.replace(old + '/', new + '/')
print(originalName + " -> " + newName)
if (not os.path.isdir(root.replace(old, '') + new)):
os.mkdir(root.replace(old, '') + new)
os.rename(originalName, newName)
rename_subdirs("graphics/pokemon", '/alolan', "/alola")
rename_subdirs("graphics/pokemon", '/galarian', "/galar")
rename_subdirs("graphics/pokemon", '/hisuian', "/hisui")
rename_subdirs("graphics/pokemon", '/gigantamax', "/gmax")

View File

@ -1,110 +1,110 @@
#!/usr/bin/env python3
""" Extract sprites from HGSS follower spritesheets. """
import os.path
import subprocess
import sys
from glob import glob
import png
SPRITESHEETS = [('gen1.png', 15, 11, 1)]
output_dir = 'sprites'
index_to_name = {}
with open('names.txt', 'r') as f:
for line in f:
index, name = line.split(' ')[:2]
name = name.strip()
index_to_name[int(index)] = name.lower()
name_to_index = {v: k for k, v in index_to_name.items()}
PKMN_GRAPHICS = os.path.join('graphics', 'pokemon')
def extract_sprites(spritesheet):
path, width, height, offset = spritesheet
for y in range(height):
for x in range(width):
if x == 3 and y == 0 or x == 10 and y == 1:
continue
output_path = os.path.join(output_dir, f'{offset:03d}.png')
subprocess.run(['convert', '-extract', f'64x128+{x*(64+1)}+{y*(128+1)}', path, output_path], check=True)
offset += 1
def stack_sprite(name, path):
joinp = os.path.join
frames = [joinp(path, 'down', name), joinp(path, 'down', 'frame2', name),
joinp(path, 'up', name), joinp(path, 'up', 'frame2', name),
joinp(path, 'left', name), joinp(path, 'left', 'frame2', name)]
output = joinp(path, name)
subprocess.run(['convert'] + frames + ['+append', output], check=True)
print(f'Stacked {output}')
def canonicalize_names():
for path in glob('overworld/**/*.png', recursive=True):
head, tail = os.path.split(path)
name, ext = os.path.splitext(tail)
try:
num = int(name)
except ValueError:
continue
new_name = f'{num:03d}'
new_path = os.path.join(head, new_name+ext)
os.rename(path, new_path)
print(path, '->', new_path)
def closest_color(c, palette):
min_d = float('inf')
best = 0
r1, g1, b1 = c
for i, (r2, g2, b2) in enumerate(palette[1:], 1):
# Color diff from https://stackoverflow.com/questions/1847092/given-an-rgb-value-what-would-be-the-best-way-to-find-the-closest-match-in-the-d
d = ((r2-r1)*0.30)**2 + ((g2-g1)*0.59)**2 + ((b2-b1)*0.11)**2
if d < min_d:
min_d = d
best = i
return best
def apply_palette(palette_file, input_file, output_file): # Apply one file's palette to another
plt = png.Reader(palette_file)
plt.read()
target_palette = tuple(c[:3] for c in plt.palette())
inp = png.Reader(input_file)
w, h, rows, _ = inp.read()
src_palette = tuple(c[:3] for c in inp.palette())
with open(output_file, 'wb') as f:
new_rows = []
for row in rows:
new_rows.append([closest_color(src_palette[c], target_palette) if c else 0 for c in row])
w = png.Writer(width=w, height=h, bitdepth=4, palette=target_palette)
w.write(f, new_rows)
def paletteify(path, output_path=None):
output_path = output_path or path
joinp = os.path.join
_, tail = os.path.split(path)
species, _ = os.path.splitext(tail)
front = png.Reader(joinp(PKMN_GRAPHICS, species, 'anim_front.png'))
front.read()
target_palette = tuple(c[:3] for c in front.palette())
r, g, b = target_palette[0]
color = f'rgb({r},{g},{b})'
# Strip alpha color
subprocess.run(['convert', path, '-background', color, '-alpha', 'remove', output_path], check=True)
apply_palette(joinp(PKMN_GRAPHICS, species, 'anim_front.png'), output_path, output_path)
# Sprites from https://veekun.com/dex/downloads
if __name__ == '__main__':
args = sys.argv[1:]
if args:
paletteify(args[0])
else:
for path in sorted(glob('overworld/*.png')):
_, tail = os.path.split(path)
name, _ = os.path.splitext(tail)
output_path = os.path.join('graphics/object_events/pics/pokemon', f'{name}.png')
try:
paletteify(path, output_path)
except Exception as e:
print(name, e.__class__.__name__, e, file=sys.stderr)
#!/usr/bin/env python3
""" Extract sprites from HGSS follower spritesheets. """
import os.path
import subprocess
import sys
from glob import glob
import png
SPRITESHEETS = [('gen1.png', 15, 11, 1)]
output_dir = 'sprites'
index_to_name = {}
with open('names.txt', 'r') as f:
for line in f:
index, name = line.split(' ')[:2]
name = name.strip()
index_to_name[int(index)] = name.lower()
name_to_index = {v: k for k, v in index_to_name.items()}
PKMN_GRAPHICS = os.path.join('graphics', 'pokemon')
def extract_sprites(spritesheet):
path, width, height, offset = spritesheet
for y in range(height):
for x in range(width):
if x == 3 and y == 0 or x == 10 and y == 1:
continue
output_path = os.path.join(output_dir, f'{offset:03d}.png')
subprocess.run(['convert', '-extract', f'64x128+{x*(64+1)}+{y*(128+1)}', path, output_path], check=True)
offset += 1
def stack_sprite(name, path):
joinp = os.path.join
frames = [joinp(path, 'down', name), joinp(path, 'down', 'frame2', name),
joinp(path, 'up', name), joinp(path, 'up', 'frame2', name),
joinp(path, 'left', name), joinp(path, 'left', 'frame2', name)]
output = joinp(path, name)
subprocess.run(['convert'] + frames + ['+append', output], check=True)
print(f'Stacked {output}')
def canonicalize_names():
for path in glob('overworld/**/*.png', recursive=True):
head, tail = os.path.split(path)
name, ext = os.path.splitext(tail)
try:
num = int(name)
except ValueError:
continue
new_name = f'{num:03d}'
new_path = os.path.join(head, new_name+ext)
os.rename(path, new_path)
print(path, '->', new_path)
def closest_color(c, palette):
min_d = float('inf')
best = 0
r1, g1, b1 = c
for i, (r2, g2, b2) in enumerate(palette[1:], 1):
# Color diff from https://stackoverflow.com/questions/1847092/given-an-rgb-value-what-would-be-the-best-way-to-find-the-closest-match-in-the-d
d = ((r2-r1)*0.30)**2 + ((g2-g1)*0.59)**2 + ((b2-b1)*0.11)**2
if d < min_d:
min_d = d
best = i
return best
def apply_palette(palette_file, input_file, output_file): # Apply one file's palette to another
plt = png.Reader(palette_file)
plt.read()
target_palette = tuple(c[:3] for c in plt.palette())
inp = png.Reader(input_file)
w, h, rows, _ = inp.read()
src_palette = tuple(c[:3] for c in inp.palette())
with open(output_file, 'wb') as f:
new_rows = []
for row in rows:
new_rows.append([closest_color(src_palette[c], target_palette) if c else 0 for c in row])
w = png.Writer(width=w, height=h, bitdepth=4, palette=target_palette)
w.write(f, new_rows)
def paletteify(path, output_path=None):
output_path = output_path or path
joinp = os.path.join
_, tail = os.path.split(path)
species, _ = os.path.splitext(tail)
front = png.Reader(joinp(PKMN_GRAPHICS, species, 'anim_front.png'))
front.read()
target_palette = tuple(c[:3] for c in front.palette())
r, g, b = target_palette[0]
color = f'rgb({r},{g},{b})'
# Strip alpha color
subprocess.run(['convert', path, '-background', color, '-alpha', 'remove', output_path], check=True)
apply_palette(joinp(PKMN_GRAPHICS, species, 'anim_front.png'), output_path, output_path)
# Sprites from https://veekun.com/dex/downloads
if __name__ == '__main__':
args = sys.argv[1:]
if args:
paletteify(args[0])
else:
for path in sorted(glob('overworld/*.png')):
_, tail = os.path.split(path)
name, _ = os.path.splitext(tail)
output_path = os.path.join('graphics/object_events/pics/pokemon', f'{name}.png')
try:
paletteify(path, output_path)
except Exception as e:
print(name, e.__class__.__name__, e, file=sys.stderr)

View File

@ -1,50 +1,50 @@
""" Processes & outputs follower emotion messages """
import sys
import re
import textwrap
blank_regex = re.compile(r'\(?_+\)?')
# Converts a series of message lines to a better format
def convert_messages(infile, outfile='emotions.txt'):
with open(infile, 'r') as f_in, open(outfile, 'w') as f_out:
for line in f_in:
line = line.rstrip('\n')
if line and line[0] == '-':
line = line[1:]
line = line.lstrip()
if not line:
continue
line = blank_regex.sub('{STR_VAR_1}', line)
if line[-1] not in ('.', '?', '!', ':'):
line += '.'
print(line)
f_out.write('\n' + line)
# Prepares a string for field-message display, performing line-wrapping, etc
# Does not add a terminator, as this is done by _("")
def prepare_string(s):
lines = textwrap.wrap(s, width=36) # Width of message window
s = lines[0]
for i, line in enumerate(lines[1:]):
ending = r'\p' if i % 2 else r'\n'
s += ending + line
return s
# Exports up to n messages in C format to outfile
def export_messages(infile, outfile, n=None, indent=0, start=0):
with open(infile, 'r') as f_in:
lines = f_in.readlines()
if n is not None:
lines = lines[:n]
with open(outfile, 'w') as f_out:
codelines = [' '*indent + f'static const u8 sCondMsg{start+i:02d}[] = _("{prepare_string(s)}");' for i, s in enumerate(lines)]
f_out.write('\n'.join(codelines))
print(f'{len(lines)} lines written')
return len(lines)
if __name__ == '__main__':
export_messages('emotions.txt', 'emotions.h', n=1, start=7)
""" Processes & outputs follower emotion messages """
import sys
import re
import textwrap
blank_regex = re.compile(r'\(?_+\)?')
# Converts a series of message lines to a better format
def convert_messages(infile, outfile='emotions.txt'):
with open(infile, 'r') as f_in, open(outfile, 'w') as f_out:
for line in f_in:
line = line.rstrip('\n')
if line and line[0] == '-':
line = line[1:]
line = line.lstrip()
if not line:
continue
line = blank_regex.sub('{STR_VAR_1}', line)
if line[-1] not in ('.', '?', '!', ':'):
line += '.'
print(line)
f_out.write('\n' + line)
# Prepares a string for field-message display, performing line-wrapping, etc
# Does not add a terminator, as this is done by _("")
def prepare_string(s):
lines = textwrap.wrap(s, width=36) # Width of message window
s = lines[0]
for i, line in enumerate(lines[1:]):
ending = r'\p' if i % 2 else r'\n'
s += ending + line
return s
# Exports up to n messages in C format to outfile
def export_messages(infile, outfile, n=None, indent=0, start=0):
with open(infile, 'r') as f_in:
lines = f_in.readlines()
if n is not None:
lines = lines[:n]
with open(outfile, 'w') as f_out:
codelines = [' '*indent + f'static const u8 sCondMsg{start+i:02d}[] = _("{prepare_string(s)}");' for i, s in enumerate(lines)]
f_out.write('\n'.join(codelines))
print(f'{len(lines)} lines written')
return len(lines)
if __name__ == '__main__':
export_messages('emotions.txt', 'emotions.h', n=1, start=7)

View File

@ -1,77 +1,77 @@
#!/usr/bin/env python3
""" Extract sprites from HGSS follower spritesheets. """
import os.path
from os.path import join as joinp
import subprocess
import sys
from glob import glob
import png
from tqdm import tqdm
import shutil
def stack_sprite(name, path):
frames = [joinp(path, 'down', name), joinp(path, 'down', 'frame2', name),
joinp(path, 'up', name), joinp(path, 'up', 'frame2', name),
joinp(path, 'left', name), joinp(path, 'left', 'frame2', name)]
output = joinp(path, name)
subprocess.run(['convert'] + frames + ['+append', output], check=True)
print(f'Stacked {output}')
def closest_color(c, palette):
min_d = float('inf')
best = 0
r1, g1, b1 = c
for i, (r2, g2, b2) in enumerate(palette[1:], 1):
# Color diff from https://stackoverflow.com/questions/1847092/given-an-rgb-value-what-would-be-the-best-way-to-find-the-closest-match-in-the-d
d = ((r2-r1)*0.30)**2 + ((g2-g1)*0.59)**2 + ((b2-b1)*0.11)**2
if d < min_d:
min_d = d
best = i
return best
def apply_palette(palette_file, input_file, output_file): # Apply one file's palette to another
plt = png.Reader(palette_file)
plt.read()
target_palette = tuple(c[:3] for c in plt.palette())
inp = png.Reader(input_file)
w, h, rows, info = inp.read()
src_palette = tuple(c[:3] for c in inp.palette())
new_rows = [[closest_color(src_palette[c][:3], target_palette) if c else 0 for c in row] for row in rows]
with open(output_file, 'wb') as f:
w = png.Writer(width=w, height=h, bitdepth=4, palette=target_palette)
w.write(f, new_rows)
# Sprites from https://veekun.com/dex/downloads
def apply_front_palettes(ow_dir, project_root=''):
mon_graphics = joinp(project_root, 'graphics', 'pokemon')
for x in os.walk(ow_dir):
current_dir = x[0]
sub_dir = current_dir[len(ow_dir) + 1:1000]
t = tqdm(sorted(glob(joinp(current_dir, '*.png'))))
spaces = 0
for path in t:
name, _ = os.path.splitext(os.path.basename(path))
name = joinp(sub_dir, name)
# old_path = joinp(project_root, 'graphics', 'object_events', 'pics', 'pokemon', f'{name}.png')
# new_path = joinp(project_root, 'graphics', 'object_events', 'pics', 'pokemon', name, 'follower.png')
# os.mkdir(joinp(project_root, 'graphics', 'object_events', 'pics', 'pokemon', name))
# shutil.move(old_path, new_path)
spaces = min(max(len(name), spaces), 10)
t.set_description(name + ' '*(spaces-len(name)))
output_path = joinp(project_root, 'graphics', 'object_events', 'pics', 'pokemon', f'{name}.png')
palette_path = joinp(mon_graphics, name, 'anim_front.png')
try:
apply_palette(palette_path, path, output_path)
except Exception as e:
palette_path = joinp(mon_graphics, name, 'front.png')
try:
apply_palette(palette_path, path, output_path)
except Exception as e2:
t.write(f'{name}: {e2.__class__.__name__}: {e2}', file=sys.stderr)
if __name__ == '__main__':
apply_front_palettes('graphics/object_events/pics/pokemon')
#!/usr/bin/env python3
""" Extract sprites from HGSS follower spritesheets. """
import os.path
from os.path import join as joinp
import subprocess
import sys
from glob import glob
import png
from tqdm import tqdm
import shutil
def stack_sprite(name, path):
frames = [joinp(path, 'down', name), joinp(path, 'down', 'frame2', name),
joinp(path, 'up', name), joinp(path, 'up', 'frame2', name),
joinp(path, 'left', name), joinp(path, 'left', 'frame2', name)]
output = joinp(path, name)
subprocess.run(['convert'] + frames + ['+append', output], check=True)
print(f'Stacked {output}')
def closest_color(c, palette):
min_d = float('inf')
best = 0
r1, g1, b1 = c
for i, (r2, g2, b2) in enumerate(palette[1:], 1):
# Color diff from https://stackoverflow.com/questions/1847092/given-an-rgb-value-what-would-be-the-best-way-to-find-the-closest-match-in-the-d
d = ((r2-r1)*0.30)**2 + ((g2-g1)*0.59)**2 + ((b2-b1)*0.11)**2
if d < min_d:
min_d = d
best = i
return best
def apply_palette(palette_file, input_file, output_file): # Apply one file's palette to another
plt = png.Reader(palette_file)
plt.read()
target_palette = tuple(c[:3] for c in plt.palette())
inp = png.Reader(input_file)
w, h, rows, info = inp.read()
src_palette = tuple(c[:3] for c in inp.palette())
new_rows = [[closest_color(src_palette[c][:3], target_palette) if c else 0 for c in row] for row in rows]
with open(output_file, 'wb') as f:
w = png.Writer(width=w, height=h, bitdepth=4, palette=target_palette)
w.write(f, new_rows)
# Sprites from https://veekun.com/dex/downloads
def apply_front_palettes(ow_dir, project_root=''):
mon_graphics = joinp(project_root, 'graphics', 'pokemon')
for x in os.walk(ow_dir):
current_dir = x[0]
sub_dir = current_dir[len(ow_dir) + 1:1000]
t = tqdm(sorted(glob(joinp(current_dir, '*.png'))))
spaces = 0
for path in t:
name, _ = os.path.splitext(os.path.basename(path))
name = joinp(sub_dir, name)
# old_path = joinp(project_root, 'graphics', 'object_events', 'pics', 'pokemon', f'{name}.png')
# new_path = joinp(project_root, 'graphics', 'object_events', 'pics', 'pokemon', name, 'follower.png')
# os.mkdir(joinp(project_root, 'graphics', 'object_events', 'pics', 'pokemon', name))
# shutil.move(old_path, new_path)
spaces = min(max(len(name), spaces), 10)
t.set_description(name + ' '*(spaces-len(name)))
output_path = joinp(project_root, 'graphics', 'object_events', 'pics', 'pokemon', f'{name}.png')
palette_path = joinp(mon_graphics, name, 'anim_front.png')
try:
apply_palette(palette_path, path, output_path)
except Exception as e:
palette_path = joinp(mon_graphics, name, 'front.png')
try:
apply_palette(palette_path, path, output_path)
except Exception as e2:
t.write(f'{name}: {e2.__class__.__name__}: {e2}', file=sys.stderr)
if __name__ == '__main__':
apply_front_palettes('graphics/object_events/pics/pokemon')

View File

@ -1,26 +1,26 @@
#!/usr/bin/python3
""" Extract a GBA-compatible palette from a PNG. """
import sys
import os.path
import png
PAL_PRELUDE = 'JASC-PAL\n0100\n'
def extract_palette(path):
r = png.Reader(path)
r.read()
root, _ = os.path.splitext(path)
out_path = root + '.pal'
with open(out_path, 'w', newline='\r\n') as f:
f.write(PAL_PRELUDE)
colors = r.palette()
if len(colors) < 16:
colors += [(0, 0, 0) for _ in range(16-len(colors))]
f.write(f'{len(colors)}\n')
for r, g, b in colors:
f.write(f'{r} {g} {b}\n')
if __name__ == '__main__':
extract_palette(*sys.argv[1:])
#!/usr/bin/python3
""" Extract a GBA-compatible palette from a PNG. """
import sys
import os.path
import png
PAL_PRELUDE = 'JASC-PAL\n0100\n'
def extract_palette(path):
r = png.Reader(path)
r.read()
root, _ = os.path.splitext(path)
out_path = root + '.pal'
with open(out_path, 'w', newline='\r\n') as f:
f.write(PAL_PRELUDE)
colors = r.palette()
if len(colors) < 16:
colors += [(0, 0, 0) for _ in range(16-len(colors))]
f.write(f'{len(colors)}\n')
for r, g, b in colors:
f.write(f'{r} {g} {b}\n')
if __name__ == '__main__':
extract_palette(*sys.argv[1:])

View File

@ -1,24 +1,24 @@
import glob
import re
import json
import os
import subprocess
# THIS IS A TEMPORARY SCRIPT MADE TO RENAME FILES WITH THE "FOLLOWER" NAME TO "OVERWORLD",
# AS THESE GRAPHICS CAN ALSO BE USED OUTSIDE THE FOLLOWER FEATURE.
#
# I'M SAVING IT HERE IN CASE IT'S NEEDED SOMEWHERE IN THE FUTURE, THOUGH TWEAKING MIGHT BE NEEDED.
# - AsparagusEduardo
def rename_files(dir, old, new):
for root, dirs, files in os.walk(dir):
for name in files:
if name.endswith(old):
originalName = os.path.join(root, name)
newName = originalName.replace(old, new)
print(originalName + " -> " + newName)
os.rename(originalName, newName)
rename_files("graphics/pokemon", 'follower.png', "overworld.png")
rename_files("graphics/pokemon", 'follow_normal.pal', "overworld_normal.pal")
rename_files("graphics/pokemon", 'follow_shiny.pal', "overworld_shiny.pal")
import glob
import re
import json
import os
import subprocess
# THIS IS A TEMPORARY SCRIPT MADE TO RENAME FILES WITH THE "FOLLOWER" NAME TO "OVERWORLD",
# AS THESE GRAPHICS CAN ALSO BE USED OUTSIDE THE FOLLOWER FEATURE.
#
# I'M SAVING IT HERE IN CASE IT'S NEEDED SOMEWHERE IN THE FUTURE, THOUGH TWEAKING MIGHT BE NEEDED.
# - AsparagusEduardo
def rename_files(dir, old, new):
for root, dirs, files in os.walk(dir):
for name in files:
if name.endswith(old):
originalName = os.path.join(root, name)
newName = originalName.replace(old, new)
print(originalName + " -> " + newName)
os.rename(originalName, newName)
rename_files("graphics/pokemon", 'follower.png', "overworld.png")
rename_files("graphics/pokemon", 'follow_normal.pal', "overworld_normal.pal")
rename_files("graphics/pokemon", 'follow_shiny.pal', "overworld_shiny.pal")

View File

@ -1,64 +1,64 @@
import glob
import re
import json
import os
import subprocess
# THIS IS A TEMPORARY SCRIPT MADE TO MOVE EXISTING FOLLOWER GRAPHICS FROM A SINGLE DIRECTORY.
# IT TAKES FOLLOWER GRAPHICS FROM a 'followers' FOLDER IN THE ROOT FOLDER AND MOVES THEM BASED ON THEIR NAME.
# EG. 'followers/bulbasaur.png' WILL BE MOVED to 'graphics/pokemon/bulbasaur/follower.png'.
#
# I'M SAVING IT HERE IN CASE IT'S NEEDED SOMEWHERE IN THE FUTURE, THOUGH TWEAKING MIGHT BE NEEDED.
# - AsparagusEduardo
def rellocate_follower_graphics():
dict_out = {}
count = 0
for pth in sorted(glob.glob('followers/*.png')):
name = pth.replace(".png", "").replace("followers/", "")
count+=1
#if (count == 2):
# break
print(name)
newname = name
newname = newname.replace("_female", "/female")
newname = newname.replace("_hisuian", "/hisuian")
newname = newname.replace("_galarian", "/galarian")
newname = newname.replace("_origin", "/origin")
newname = newname.replace("_therian", "/therian")
newname = newname.replace("_east_sea", "/east_sea")
newname = newname.replace("_crowned", "/crowned")
newname = newname.replace("arceus_", "arceus/")
newname = newname.replace("burmy_", "burmy/")
newname = newname.replace("basculin_", "basculin/")
newname = newname.replace("castform_", "castform/")
newname = newname.replace("calyrex_", "calyrex/")
newname = newname.replace("deerling_", "deerling/")
newname = newname.replace("deoxys_", "deoxys/")
newname = newname.replace("flabebe_", "flabebe/")
newname = newname.replace("floette_", "floette/")
newname = newname.replace("florges_", "florges/")
newname = newname.replace("furfrou_", "furfrou/")
newname = newname.replace("hoopa_", "hoopa/")
newname = newname.replace("lycanroc_", "lycanroc/")
newname = newname.replace("meloetta_", "meloetta/")
newname = newname.replace("necrozma_", "necrozma/")
newname = newname.replace("pichu_", "pichu/")
newname = newname.replace("rotom_", "rotom/")
newname = newname.replace("sawsbuck_", "sawsbuck/")
newname = newname.replace("toxtricity_", "toxtricity/")
newname = newname.replace("unown_", "unown/")
newname = newname.replace("ursaluna_", "ursaluna/")
newname = newname.replace("vivillon_", "vivillon/")
newname = newname.replace("wormadam_", "wormadam/")
if (os.path.exists('followers/' + newname) == False):
os.mkdir('followers/' + newname)
os.rename('followers/' + name + '.png', 'followers/' + newname + '/follower.png')
#os.popen('cp followers/' + name + '.png followers/' + name + '/follower.png')
#os.remove('followers/' + name + '.png')
#print(pth)
#subprocess.run(["tools/gbagfx/gbagfx " + name +".png " + name + "_normal.pal'" + str(count) + "'"])
rellocate_follower_graphics()
import glob
import re
import json
import os
import subprocess
# THIS IS A TEMPORARY SCRIPT MADE TO MOVE EXISTING FOLLOWER GRAPHICS FROM A SINGLE DIRECTORY.
# IT TAKES FOLLOWER GRAPHICS FROM a 'followers' FOLDER IN THE ROOT FOLDER AND MOVES THEM BASED ON THEIR NAME.
# EG. 'followers/bulbasaur.png' WILL BE MOVED to 'graphics/pokemon/bulbasaur/follower.png'.
#
# I'M SAVING IT HERE IN CASE IT'S NEEDED SOMEWHERE IN THE FUTURE, THOUGH TWEAKING MIGHT BE NEEDED.
# - AsparagusEduardo
def rellocate_follower_graphics():
dict_out = {}
count = 0
for pth in sorted(glob.glob('followers/*.png')):
name = pth.replace(".png", "").replace("followers/", "")
count+=1
#if (count == 2):
# break
print(name)
newname = name
newname = newname.replace("_female", "/female")
newname = newname.replace("_hisuian", "/hisuian")
newname = newname.replace("_galarian", "/galarian")
newname = newname.replace("_origin", "/origin")
newname = newname.replace("_therian", "/therian")
newname = newname.replace("_east_sea", "/east_sea")
newname = newname.replace("_crowned", "/crowned")
newname = newname.replace("arceus_", "arceus/")
newname = newname.replace("burmy_", "burmy/")
newname = newname.replace("basculin_", "basculin/")
newname = newname.replace("castform_", "castform/")
newname = newname.replace("calyrex_", "calyrex/")
newname = newname.replace("deerling_", "deerling/")
newname = newname.replace("deoxys_", "deoxys/")
newname = newname.replace("flabebe_", "flabebe/")
newname = newname.replace("floette_", "floette/")
newname = newname.replace("florges_", "florges/")
newname = newname.replace("furfrou_", "furfrou/")
newname = newname.replace("hoopa_", "hoopa/")
newname = newname.replace("lycanroc_", "lycanroc/")
newname = newname.replace("meloetta_", "meloetta/")
newname = newname.replace("necrozma_", "necrozma/")
newname = newname.replace("pichu_", "pichu/")
newname = newname.replace("rotom_", "rotom/")
newname = newname.replace("sawsbuck_", "sawsbuck/")
newname = newname.replace("toxtricity_", "toxtricity/")
newname = newname.replace("unown_", "unown/")
newname = newname.replace("ursaluna_", "ursaluna/")
newname = newname.replace("vivillon_", "vivillon/")
newname = newname.replace("wormadam_", "wormadam/")
if (os.path.exists('followers/' + newname) == False):
os.mkdir('followers/' + newname)
os.rename('followers/' + name + '.png', 'followers/' + newname + '/follower.png')
#os.popen('cp followers/' + name + '.png followers/' + name + '/follower.png')
#os.remove('followers/' + name + '.png')
#print(pth)
#subprocess.run(["tools/gbagfx/gbagfx " + name +".png " + name + "_normal.pal'" + str(count) + "'"])
rellocate_follower_graphics()

View File

@ -1,21 +1,21 @@
import glob
import re
import json
import os
import subprocess
# THIS IS A TEMPORARY SCRIPT MADE TO DELETE FILES WITH THE "footprint.png" NAME
# FROM THE "graphics/pokemon_old" folder, AS MOST OF THEM ALREADY EXISTED IN "graphics/pokemon".
#
# I'M SAVING IT HERE IN CASE IT'S NEEDED SOMEWHERE IN THE FUTURE, THOUGH TWEAKING MIGHT BE NEEDED.
# - AsparagusEduardo
def rename_files(dir, filename):
for root, dirs, files in os.walk(dir):
for name in files:
if name.endswith(filename):
fullName = os.path.join(root, name)
print(fullName + " deleted.")
os.remove(fullName)
rename_files("graphics/pokemon_old", 'footprint.png')
import glob
import re
import json
import os
import subprocess
# THIS IS A TEMPORARY SCRIPT MADE TO DELETE FILES WITH THE "footprint.png" NAME
# FROM THE "graphics/pokemon_old" folder, AS MOST OF THEM ALREADY EXISTED IN "graphics/pokemon".
#
# I'M SAVING IT HERE IN CASE IT'S NEEDED SOMEWHERE IN THE FUTURE, THOUGH TWEAKING MIGHT BE NEEDED.
# - AsparagusEduardo
def rename_files(dir, filename):
for root, dirs, files in os.walk(dir):
for name in files:
if name.endswith(filename):
fullName = os.path.join(root, name)
print(fullName + " deleted.")
os.remove(fullName)
rename_files("graphics/pokemon_old", 'footprint.png')

View File

@ -1,22 +1,22 @@
import glob
import re
import json
import os
import subprocess
def rename_files(dirOld, dirNew, old, new):
for root, dirs, files in os.walk(dirOld):
for name in files:
if name.endswith(old):
originalName = os.path.join(root, name)
newName = originalName.replace(old, new)
newName = newName.replace(dirOld, dirNew)
print(originalName + " -> " + newName)
os.rename(originalName, newName)
rename_files("graphics/pokemon_old", "graphics/pokemon", 'anim_front.png', "anim_front_gba.png")
rename_files("graphics/pokemon_old", "graphics/pokemon", 'normal.pal', "normal_gba.pal")
rename_files("graphics/pokemon_old", "graphics/pokemon", 'shiny.pal', "shiny_gba.pal")
rename_files("graphics/pokemon_old", "graphics/pokemon", 'back.png', "back_gba.png")
rename_files("graphics/pokemon_old", "graphics/pokemon", 'icon.png', "icon_gba.png")
rename_files("graphics/pokemon_old", "graphics/pokemon", 'footprint.png', "footprint_gba.png")
import glob
import re
import json
import os
import subprocess
def rename_files(dirOld, dirNew, old, new):
for root, dirs, files in os.walk(dirOld):
for name in files:
if name.endswith(old):
originalName = os.path.join(root, name)
newName = originalName.replace(old, new)
newName = newName.replace(dirOld, dirNew)
print(originalName + " -> " + newName)
os.rename(originalName, newName)
rename_files("graphics/pokemon_old", "graphics/pokemon", 'anim_front.png', "anim_front_gba.png")
rename_files("graphics/pokemon_old", "graphics/pokemon", 'normal.pal', "normal_gba.pal")
rename_files("graphics/pokemon_old", "graphics/pokemon", 'shiny.pal', "shiny_gba.pal")
rename_files("graphics/pokemon_old", "graphics/pokemon", 'back.png', "back_gba.png")
rename_files("graphics/pokemon_old", "graphics/pokemon", 'icon.png', "icon_gba.png")
rename_files("graphics/pokemon_old", "graphics/pokemon", 'footprint.png', "footprint_gba.png")

View File

@ -1,14 +1,14 @@
[book]
language = "en"
multilingual = false
src = "."
title = "pokeemerald-expansion"
[output.html]
git-repository-url = "https://github.com/rh-hideout/pokeemerald-expansion"
edit-url-template = "https://github.com/rh-hideout/pokeemerald-expansion/edit/master/docs/{path}"
site-url = "/pokeemerald-expansion/"
[preprocessor.fix_links]
command = "python3 fix_links.py"
after = [ "links" ]
[book]
language = "en"
multilingual = false
src = "."
title = "pokeemerald-expansion"
[output.html]
git-repository-url = "https://github.com/rh-hideout/pokeemerald-expansion"
edit-url-template = "https://github.com/rh-hideout/pokeemerald-expansion/edit/master/docs/{path}"
site-url = "/pokeemerald-expansion/"
[preprocessor.fix_links]
command = "python3 fix_links.py"
after = [ "links" ]

View File

@ -1,51 +1,51 @@
# workarounds to avoid changing current directory structure
# autolink logic based on https://github.com/zopieux/py-gfm/blob/fd7b33ed138d240d24dfb659acff7d4ce3f43745/gfm/autolink.py
import json
import sys
import re
URL_RE = re.compile(
r"(```(?s:.)+?```|`.+?`|<.+?>)|"
r"\b((?:(?i:ftp|https?)://|(?i:www)\d{0,3}[.])(?:[^\s()<>]+|"
r"\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()"
r"<>]+\)))*\)|[^\s`!()\[\]{};:" + r"'" + r'".,<>?«»“”‘’*]))'
)
PROTOCOL_RE = re.compile(r"^(?i:ftp|https?)://")
ANCHOR_RE = re.compile(r"(\]\((?:[^)#]+\.md)?#)([^)]+\))")
def handle_url(m):
code = m.group(1)
if code:
return code
href = m.group(2)
if not PROTOCOL_RE.match(href):
href = "http://%s" % href
return f'<{href}>'
def handle_anchor(m):
page = m.group(1)
anchor = m.group(2)
return page + anchor.lower()
def proc_items(items):
for item in items:
if 'Chapter' in item:
s = item['Chapter']['content']
s = s.replace('](README.md)', '](./)')
s = s.replace('](/INSTALL.md', '](INSTALL.md')
s = s.replace('](docs/', '](')
s = URL_RE.sub(handle_url, s)
item['Chapter']['content'] = ANCHOR_RE.sub(handle_anchor, s)
proc_items(item['Chapter']['sub_items'])
if __name__ == '__main__':
if len(sys.argv) > 1:
if sys.argv[1] == "supports":
sys.exit(0)
context, book = json.load(sys.stdin)
proc_items(book['sections'])
print(json.dumps(book))
# workarounds to avoid changing current directory structure
# autolink logic based on https://github.com/zopieux/py-gfm/blob/fd7b33ed138d240d24dfb659acff7d4ce3f43745/gfm/autolink.py
import json
import sys
import re
URL_RE = re.compile(
r"(```(?s:.)+?```|`.+?`|<.+?>)|"
r"\b((?:(?i:ftp|https?)://|(?i:www)\d{0,3}[.])(?:[^\s()<>]+|"
r"\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()"
r"<>]+\)))*\)|[^\s`!()\[\]{};:" + r"'" + r'".,<>?«»“”‘’*]))'
)
PROTOCOL_RE = re.compile(r"^(?i:ftp|https?)://")
ANCHOR_RE = re.compile(r"(\]\((?:[^)#]+\.md)?#)([^)]+\))")
def handle_url(m):
code = m.group(1)
if code:
return code
href = m.group(2)
if not PROTOCOL_RE.match(href):
href = "http://%s" % href
return f'<{href}>'
def handle_anchor(m):
page = m.group(1)
anchor = m.group(2)
return page + anchor.lower()
def proc_items(items):
for item in items:
if 'Chapter' in item:
s = item['Chapter']['content']
s = s.replace('](README.md)', '](./)')
s = s.replace('](/INSTALL.md', '](INSTALL.md')
s = s.replace('](docs/', '](')
s = URL_RE.sub(handle_url, s)
item['Chapter']['content'] = ANCHOR_RE.sub(handle_anchor, s)
proc_items(item['Chapter']['sub_items'])
if __name__ == '__main__':
if len(sys.argv) > 1:
if sys.argv[1] == "supports":
sys.exit(0)
context, book = json.load(sys.stdin)
proc_items(book['sections'])
print(json.dumps(book))

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1003 B

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 383 B

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 714 B

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 622 B

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 946 B

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 341 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1011 B

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 275 B

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 354 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 269 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 336 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 838 B

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -1,188 +1,188 @@
ENTRY(Start)
gNumMusicPlayers = 4;
gMaxLines = 0;
gInitialMainCB2 = CB2_InitCopyrightScreenAfterBootup;
MEMORY
{
EWRAM (rwx) : ORIGIN = 0x2000000, LENGTH = 256K
IWRAM (rwx) : ORIGIN = 0x3000000, LENGTH = 32K
ROM (rx) : ORIGIN = 0x8000000, LENGTH = 32M
}
SECTIONS {
.ewram ORIGIN(EWRAM) : AT (__ewram_lma)
ALIGN(4)
{
__ewram_start = .;
*(.ewram*)
. = ALIGN(4);
__ewram_end = .;
} > EWRAM
.ewram.sbss (NOLOAD) :
ALIGN(4)
{
src/*.o(.sbss);
} > EWRAM
.iwram ORIGIN(IWRAM) : AT (__iwram_lma)
ALIGN(4)
{
__iwram_start = .;
*(.iwram*);
. = ALIGN(4);
__iwram_end = .;
} > IWRAM
.iwram.bss (NOLOAD) :
ALIGN(4)
{
src/*.o(.bss);
data/*.o(.bss);
*libc.a:*.o(.bss*);
*libnosys.a:*.o(.bss*);
src/m4a.o(.bss.code);
src/*.o(common_data);
src/*.o(COMMON);
*libc.a:*.o(COMMON);
*libnosys.a:*.o(COMMON);
} > IWRAM
/* BEGIN ROM DATA */
.text ORIGIN(ROM) :
ALIGN(4)
{
src/rom_header.o(.text*);
src/rom_header_gf.o(.text.*);
src/rom_header_rhh.o(.text.*);
src/crt0.o(.text);
src/main.o(.text);
src/*.o(.text*);
asm/*.o(.text*);
} > ROM =0
script_data :
ALIGN(4)
{
data/*.o(script_data);
} > ROM =0
lib_text :
ALIGN(4)
{
src/libgcnmultiboot.o(.text);
src/m4a_1.o(.text);
src/m4a.o(.text);
src/agb_flash.o(.text);
src/agb_flash_1m.o(.text);
src/agb_flash_mx.o(.text);
src/siirtc.o(.text);
src/librfu_stwi.o(.text);
src/librfu_intr.o(.text);
src/librfu_rfu.o(.text);
src/librfu_sio32id.o(.text);
*libagbsyscall.a:*.o(.text*);
*libgcc.a:*.o(.text*);
*libc.a:*.o(.text*);
*libnosys.a:*.o(.text*);
src/libisagbprn.o(.text);
} > ROM =0
.rodata :
ALIGN(4)
{
src/*.o(.rodata*);
data/*.o(.rodata*);
} > ROM =0
song_data :
ALIGN(4)
{
sound/songs/*.o(.rodata);
} > ROM =0
lib_rodata :
SUBALIGN(4)
{
src/m4a.o(.rodata);
src/agb_flash.o(.rodata);
src/agb_flash_1m.o(.rodata);
src/agb_flash_mx.o(.rodata);
src/agb_flash_le.o(.rodata);
src/siirtc.o(.rodata);
src/librfu_rfu.o(.rodata);
src/librfu_sio32id.o(.rodata);
*libgcc.a:*.o(.rodata*);
*libc.a:*.o(.rodata*);
*libc.a:*.o(.data*);
src/libisagbprn.o(.rodata);
} > ROM =0
multiboot_data :
ALIGN(4)
{
data/multiboot_ereader.o(.rodata);
data/multiboot_berry_glitch_fix.o(.rodata);
data/multiboot_pokemon_colosseum.o(.rodata);
} > ROM =0
gfx_data :
ALIGN(4)
{
src/graphics.o(.rodata);
} > ROM =0
.data.iwram :
ALIGN(4)
{
__iwram_lma = .;
. = . + (__iwram_end - __iwram_start);
} > ROM = 0
.data.ewram :
ALIGN(4)
{
__ewram_lma = .;
. = . + (__ewram_end - __ewram_start);
} > ROM = 0
__rom_end = .;
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* Discard everything not specifically mentioned above. */
/DISCARD/ :
{
*(*);
}
}
ENTRY(Start)
gNumMusicPlayers = 4;
gMaxLines = 0;
gInitialMainCB2 = CB2_InitCopyrightScreenAfterBootup;
MEMORY
{
EWRAM (rwx) : ORIGIN = 0x2000000, LENGTH = 256K
IWRAM (rwx) : ORIGIN = 0x3000000, LENGTH = 32K
ROM (rx) : ORIGIN = 0x8000000, LENGTH = 32M
}
SECTIONS {
.ewram ORIGIN(EWRAM) : AT (__ewram_lma)
ALIGN(4)
{
__ewram_start = .;
*(.ewram*)
. = ALIGN(4);
__ewram_end = .;
} > EWRAM
.ewram.sbss (NOLOAD) :
ALIGN(4)
{
src/*.o(.sbss);
} > EWRAM
.iwram ORIGIN(IWRAM) : AT (__iwram_lma)
ALIGN(4)
{
__iwram_start = .;
*(.iwram*);
. = ALIGN(4);
__iwram_end = .;
} > IWRAM
.iwram.bss (NOLOAD) :
ALIGN(4)
{
src/*.o(.bss);
data/*.o(.bss);
*libc.a:*.o(.bss*);
*libnosys.a:*.o(.bss*);
src/m4a.o(.bss.code);
src/*.o(common_data);
src/*.o(COMMON);
*libc.a:*.o(COMMON);
*libnosys.a:*.o(COMMON);
} > IWRAM
/* BEGIN ROM DATA */
.text ORIGIN(ROM) :
ALIGN(4)
{
src/rom_header.o(.text*);
src/rom_header_gf.o(.text.*);
src/rom_header_rhh.o(.text.*);
src/crt0.o(.text);
src/main.o(.text);
src/*.o(.text*);
asm/*.o(.text*);
} > ROM =0
script_data :
ALIGN(4)
{
data/*.o(script_data);
} > ROM =0
lib_text :
ALIGN(4)
{
src/libgcnmultiboot.o(.text);
src/m4a_1.o(.text);
src/m4a.o(.text);
src/agb_flash.o(.text);
src/agb_flash_1m.o(.text);
src/agb_flash_mx.o(.text);
src/siirtc.o(.text);
src/librfu_stwi.o(.text);
src/librfu_intr.o(.text);
src/librfu_rfu.o(.text);
src/librfu_sio32id.o(.text);
*libagbsyscall.a:*.o(.text*);
*libgcc.a:*.o(.text*);
*libc.a:*.o(.text*);
*libnosys.a:*.o(.text*);
src/libisagbprn.o(.text);
} > ROM =0
.rodata :
ALIGN(4)
{
src/*.o(.rodata*);
data/*.o(.rodata*);
} > ROM =0
song_data :
ALIGN(4)
{
sound/songs/*.o(.rodata);
} > ROM =0
lib_rodata :
SUBALIGN(4)
{
src/m4a.o(.rodata);
src/agb_flash.o(.rodata);
src/agb_flash_1m.o(.rodata);
src/agb_flash_mx.o(.rodata);
src/agb_flash_le.o(.rodata);
src/siirtc.o(.rodata);
src/librfu_rfu.o(.rodata);
src/librfu_sio32id.o(.rodata);
*libgcc.a:*.o(.rodata*);
*libc.a:*.o(.rodata*);
*libc.a:*.o(.data*);
src/libisagbprn.o(.rodata);
} > ROM =0
multiboot_data :
ALIGN(4)
{
data/multiboot_ereader.o(.rodata);
data/multiboot_berry_glitch_fix.o(.rodata);
data/multiboot_pokemon_colosseum.o(.rodata);
} > ROM =0
gfx_data :
ALIGN(4)
{
src/graphics.o(.rodata);
} > ROM =0
.data.iwram :
ALIGN(4)
{
__iwram_lma = .;
. = . + (__iwram_end - __iwram_start);
} > ROM = 0
.data.ewram :
ALIGN(4)
{
__ewram_lma = .;
. = . + (__ewram_end - __ewram_start);
} > ROM = 0
__rom_end = .;
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* Discard everything not specifically mentioned above. */
/DISCARD/ :
{
*(*);
}
}

View File

@ -1,182 +1,182 @@
ENTRY(Start)
gNumMusicPlayers = 4;
gMaxLines = 0;
gInitialMainCB2 = CB2_TestRunner;
MEMORY
{
EWRAM (rwx) : ORIGIN = 0x2000000, LENGTH = 256K
IWRAM (rwx) : ORIGIN = 0x3000000, LENGTH = 32K
ROM (rx) : ORIGIN = 0x8000000, LENGTH = 32M
}
SECTIONS {
.ewram ORIGIN(EWRAM) : AT (__ewram_lma)
ALIGN(4)
{
__ewram_start = .;
*(.ewram*)
__ewram_end = .;
} > EWRAM
.ewram.sbss (NOLOAD) :
ALIGN(4)
{
src/*.o(.sbss);
test/*.o(.sbss);
. = ALIGN(4);
} > EWRAM
.iwram ORIGIN(IWRAM) : AT (__iwram_lma)
ALIGN(4)
{
__iwram_start = .;
*(.iwram*);
. = ALIGN(4);
__iwram_end = .;
} > IWRAM
.iwram.bss (NOLOAD) :
ALIGN(4)
{
src/*.o(.bss);
data/*.o(.bss);
test/*.o(.bss);
*libc.a:*.o(.bss*);
*libgcc.a:*.o(.bss*);
*libnosys.a:*.o(.bss*);
src/m4a.o(.bss.code);
src/*.o(common_data);
src/*.o(COMMON);
data/*.o(COMMON);
test/*.o(COMMON);
*libc.a:sbrkr.o(COMMON);
} > IWRAM
/* .persistent starts at 0x3007F00 */
/* WARNING: This is the end of the IRQ stack, if there's too
* much data it WILL be overwritten. */
. = 0x03007F00;
.iwram.persistent (NOLOAD) :
ALIGN(4)
{
test/*.o(.persistent);
} > IWRAM
/* BEGIN ROM DATA */
. = 0x8000000;
.text :
ALIGN(4)
{
src/rom_header.o(.text);
src/rom_header_gf.o(.text.*);
src/rom_header_rhh.o(.text.*);
src/*.o(.text);
} > ROM =0
script_data :
ALIGN(4)
{
data/*.o(script_data);
} > ROM =0
lib_text :
ALIGN(4)
{
*libagbsyscall.a:*.o(.text*);
*libgcc.a:*.o(.text*);
*libc.a:*.o(.text*);
*libnosys.a:*.o(.text*);
} > ROM =0
.rodata :
ALIGN(4)
{
src/*.o(.rodata*);
data/*.o(.rodata*);
} > ROM =0
song_data :
ALIGN(4)
{
sound/songs/*.o(.rodata);
} > ROM =0
lib_rodata :
SUBALIGN(4)
{
*libgcc.a:*.o(.rodata*);
*libc.a:*.o(.rodata*);
*libc.a:*.o(.data*);
src/libisagbprn.o(.rodata);
} > ROM =0
.data.iwram :
ALIGN(8)
{
__iwram_lma = .;
. = . + (__iwram_end - __iwram_start);
} > ROM = 0
.data.ewram :
ALIGN(4)
{
__ewram_lma = .;
. = . + (__ewram_end - __ewram_start);
} > ROM = 0
tests :
ALIGN(4)
{
__start_tests = .;
test/*.o(.tests);
__stop_tests = .;
test/*.o(.text);
test/*.o(.rodata*);
} > ROM =0
__rom_end = .;
dacs 0x9FFC000 :
ALIGN(4)
{
test/*.o(.dacs);
} > ROM =0
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* Discard everything not specifically mentioned above. */
/DISCARD/ :
{
*(*);
}
}
ENTRY(Start)
gNumMusicPlayers = 4;
gMaxLines = 0;
gInitialMainCB2 = CB2_TestRunner;
MEMORY
{
EWRAM (rwx) : ORIGIN = 0x2000000, LENGTH = 256K
IWRAM (rwx) : ORIGIN = 0x3000000, LENGTH = 32K
ROM (rx) : ORIGIN = 0x8000000, LENGTH = 32M
}
SECTIONS {
.ewram ORIGIN(EWRAM) : AT (__ewram_lma)
ALIGN(4)
{
__ewram_start = .;
*(.ewram*)
__ewram_end = .;
} > EWRAM
.ewram.sbss (NOLOAD) :
ALIGN(4)
{
src/*.o(.sbss);
test/*.o(.sbss);
. = ALIGN(4);
} > EWRAM
.iwram ORIGIN(IWRAM) : AT (__iwram_lma)
ALIGN(4)
{
__iwram_start = .;
*(.iwram*);
. = ALIGN(4);
__iwram_end = .;
} > IWRAM
.iwram.bss (NOLOAD) :
ALIGN(4)
{
src/*.o(.bss);
data/*.o(.bss);
test/*.o(.bss);
*libc.a:*.o(.bss*);
*libgcc.a:*.o(.bss*);
*libnosys.a:*.o(.bss*);
src/m4a.o(.bss.code);
src/*.o(common_data);
src/*.o(COMMON);
data/*.o(COMMON);
test/*.o(COMMON);
*libc.a:sbrkr.o(COMMON);
} > IWRAM
/* .persistent starts at 0x3007F00 */
/* WARNING: This is the end of the IRQ stack, if there's too
* much data it WILL be overwritten. */
. = 0x03007F00;
.iwram.persistent (NOLOAD) :
ALIGN(4)
{
test/*.o(.persistent);
} > IWRAM
/* BEGIN ROM DATA */
. = 0x8000000;
.text :
ALIGN(4)
{
src/rom_header.o(.text);
src/rom_header_gf.o(.text.*);
src/rom_header_rhh.o(.text.*);
src/*.o(.text);
} > ROM =0
script_data :
ALIGN(4)
{
data/*.o(script_data);
} > ROM =0
lib_text :
ALIGN(4)
{
*libagbsyscall.a:*.o(.text*);
*libgcc.a:*.o(.text*);
*libc.a:*.o(.text*);
*libnosys.a:*.o(.text*);
} > ROM =0
.rodata :
ALIGN(4)
{
src/*.o(.rodata*);
data/*.o(.rodata*);
} > ROM =0
song_data :
ALIGN(4)
{
sound/songs/*.o(.rodata);
} > ROM =0
lib_rodata :
SUBALIGN(4)
{
*libgcc.a:*.o(.rodata*);
*libc.a:*.o(.rodata*);
*libc.a:*.o(.data*);
src/libisagbprn.o(.rodata);
} > ROM =0
.data.iwram :
ALIGN(8)
{
__iwram_lma = .;
. = . + (__iwram_end - __iwram_start);
} > ROM = 0
.data.ewram :
ALIGN(4)
{
__ewram_lma = .;
. = . + (__ewram_end - __ewram_start);
} > ROM = 0
tests :
ALIGN(4)
{
__start_tests = .;
test/*.o(.tests);
__stop_tests = .;
test/*.o(.text);
test/*.o(.rodata*);
} > ROM =0
__rom_end = .;
dacs 0x9FFC000 :
ALIGN(4)
{
test/*.o(.dacs);
} > ROM =0
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* Discard everything not specifically mentioned above. */
/DISCARD/ :
{
*(*);
}
}

View File

@ -1,45 +1,45 @@
import glob
import re
import os
if not os.path.exists("Makefile"):
print("Please run this script from your root folder.")
quit()
# Read contest_opponents.h
for file in glob.glob('./src/data/contest_opponents.h'):
with open(file, 'r') as f:
source_content = f.read()
# Extract party info from contest_opponents.h
source_pattern = re.compile(r'(\[CONTEST_OPPONENT_.*\])\s*=\s(CONTEST_FILTER_.*)*')
source_data = {}
for match in source_pattern.findall(source_content):
if len(match) == 2:
trainer_name, contest_filter = match
source_data[trainer_name] = (contest_filter)
# Read contest_opponents.h content
for file in glob.glob('./src/data/contest_opponents.h'):
with open(file, 'r') as f:
destination_content = f.read()
# Modify contest_opponents.h content
def add_filter_data(match):
trainer_name = match.group(1)
if trainer_name in source_data:
contest_filter = source_data[trainer_name]
print(f"Updating {trainer_name}: adding {contest_filter}")
#return f'{trainer_name} = {{\n .filter = {contest_filter}'
return f'{match.group(0)}\n .filter = {contest_filter}'
else:
return match.group(0)
destination_pattern = re.compile(r'(\[CONTEST_OPPONENT_[A-Z_0-9]+\])\s*=\s*{')
modified_content = destination_pattern.sub(add_filter_data, destination_content)
# Write the modified content back to contest_opponents.h
for file in glob.glob('./src/data/contest_opponents.h'):
with open(file, 'w') as f:
f.write(modified_content)
print("contest_opponents.h has been updated")
import glob
import re
import os
if not os.path.exists("Makefile"):
print("Please run this script from your root folder.")
quit()
# Read contest_opponents.h
for file in glob.glob('./src/data/contest_opponents.h'):
with open(file, 'r') as f:
source_content = f.read()
# Extract party info from contest_opponents.h
source_pattern = re.compile(r'(\[CONTEST_OPPONENT_.*\])\s*=\s(CONTEST_FILTER_.*)*')
source_data = {}
for match in source_pattern.findall(source_content):
if len(match) == 2:
trainer_name, contest_filter = match
source_data[trainer_name] = (contest_filter)
# Read contest_opponents.h content
for file in glob.glob('./src/data/contest_opponents.h'):
with open(file, 'r') as f:
destination_content = f.read()
# Modify contest_opponents.h content
def add_filter_data(match):
trainer_name = match.group(1)
if trainer_name in source_data:
contest_filter = source_data[trainer_name]
print(f"Updating {trainer_name}: adding {contest_filter}")
#return f'{trainer_name} = {{\n .filter = {contest_filter}'
return f'{match.group(0)}\n .filter = {contest_filter}'
else:
return match.group(0)
destination_pattern = re.compile(r'(\[CONTEST_OPPONENT_[A-Z_0-9]+\])\s*=\s*{')
modified_content = destination_pattern.sub(add_filter_data, destination_content)
# Write the modified content back to contest_opponents.h
for file in glob.glob('./src/data/contest_opponents.h'):
with open(file, 'w') as f:
f.write(modified_content)
print("contest_opponents.h has been updated")

View File

@ -1,44 +1,44 @@
import glob
import re
import os
if not os.path.exists("Makefile"):
print("Please run this script from your root folder.")
quit()
# Read battle_frontier_trainer_mons.h and extract the party information
for file in glob.glob('./src/data/battle_frontier/battle_frontier_trainer_mons.h'):
with open(file, 'r') as f:
source_content = f.read()
# Extract party info from battle_frontier_trainer_mons.h
source_pattern = re.compile(r'gBattleFrontierTrainerMons_(.*)\[\]\s*=\s*\n\{\n\s*(FRONTIER.*)')
source_data = {}
for match in source_pattern.findall(source_content):
if len(match) == 2:
trainer_name, party_group = match
source_data[trainer_name] = (party_group)
# Read battle_frontier_trainers.h content
for file in glob.glob('./src/data/battle_frontier/battle_frontier_trainers.h'):
with open(file, 'r') as f:
destination_content = f.read()
# Modify battle_frontier_trainers.h content
def add_party_data(match):
trainer_name = match.group(1)
if trainer_name in source_data:
party_group = source_data[trainer_name]
print(f"Updating {trainer_name}: adding {party_group}")
return f'(const u16[]){{{party_group}}}'
else:
return match.group(0)
destination_pattern = re.compile(r'gBattleFrontierTrainerMons_(.*)')
modified_content = destination_pattern.sub(add_party_data, destination_content)
# Write the modified content back to battle_frontier_trainers.h
for file in glob.glob('./src/data/battle_frontier/battle_frontier_trainers.h'):
with open(file, 'w') as f:
f.write(modified_content)
print("battle_frontier_trainers.h has been updated")
import glob
import re
import os
if not os.path.exists("Makefile"):
print("Please run this script from your root folder.")
quit()
# Read battle_frontier_trainer_mons.h and extract the party information
for file in glob.glob('./src/data/battle_frontier/battle_frontier_trainer_mons.h'):
with open(file, 'r') as f:
source_content = f.read()
# Extract party info from battle_frontier_trainer_mons.h
source_pattern = re.compile(r'gBattleFrontierTrainerMons_(.*)\[\]\s*=\s*\n\{\n\s*(FRONTIER.*)')
source_data = {}
for match in source_pattern.findall(source_content):
if len(match) == 2:
trainer_name, party_group = match
source_data[trainer_name] = (party_group)
# Read battle_frontier_trainers.h content
for file in glob.glob('./src/data/battle_frontier/battle_frontier_trainers.h'):
with open(file, 'r') as f:
destination_content = f.read()
# Modify battle_frontier_trainers.h content
def add_party_data(match):
trainer_name = match.group(1)
if trainer_name in source_data:
party_group = source_data[trainer_name]
print(f"Updating {trainer_name}: adding {party_group}")
return f'(const u16[]){{{party_group}}}'
else:
return match.group(0)
destination_pattern = re.compile(r'gBattleFrontierTrainerMons_(.*)')
modified_content = destination_pattern.sub(add_party_data, destination_content)
# Write the modified content back to battle_frontier_trainers.h
for file in glob.glob('./src/data/battle_frontier/battle_frontier_trainers.h'):
with open(file, 'w') as f:
f.write(modified_content)
print("battle_frontier_trainers.h has been updated")

View File

@ -1,85 +1,85 @@
import glob
import re
import json
import os
if not os.path.exists("Makefile"):
print("Please run this script from your root folder.")
quit()
# scan incs
incs_to_check = glob.glob('./data/scripts/*.inc') # all .incs in the script folder
incs_to_check += glob.glob('./data/maps/*/scripts.inc') # all map scripts
pories_to_check = glob.glob('./data/scripts/*.pory') ## all .porys in the script folder
pories_to_check += glob.glob('./data/maps/*/scripts.pory') # all map scripts
array = []
array_pories = []
# make a list of which script corresponds to which item
for file in incs_to_check:
with open(file, "r") as f2:
raw = f2.read()
array += re.findall("(.*)::\n[ ]*finditem (.*)\n[ ]*end", raw)
# since this doesn't catch poryscript-generated inc files, do the same for poryscript
for file in pories_to_check:
with open(file, "r") as f2:
raw = f2.read()
array_pories += re.findall("script ([\w]*)[ \n]*\{[ \n]*finditem\((.*)\)[ \n]*\}", raw)
dict = {}
# poryscript values are prioritised because they would overwrite inc files anyway if different
for x in array_pories:
dict[x[0]] = x[1]
for x in array:
if not x[0] in dict:
dict[x[0]] = x[1]
# apply changes to inc files
for map in glob.glob('./data/maps/*/map.json'):
with open(map, "r") as f2:
data = json.load(f2)
if not 'object_events' in data:
continue
for objevent in data['object_events']:
if objevent["script"] in dict:
objevent["trainer_sight_or_berry_tree_id"] = dict[objevent["script"]]
objevent["script"] = "Common_EventScript_FindItem"
with open(map, "w") as f2:
f2.write(json.dumps(data, indent=2) + "\n")
# do another map search to find out which finditem scripts would somehow be still in use
still_in_use = []
for map in glob.glob('./data/maps/*/map.json'):
with open(map, "r") as f2:
data = json.load(f2)
if not 'object_events' in data:
continue
for objevent in data['object_events']:
if objevent["script"] in dict and not objevent["script"] in still_in_use:
still_in_use.append(objevent["script"])
for x in list(dict.keys()):
if x in still_in_use:
del dict[x]
# clean up scripts that are now no longer in use
for file in incs_to_check:
with open(file, "r") as f2:
raw = f2.read()
for unused in list(dict.keys()):
raw = re.sub("%s::\n[ ]*finditem (.*)\n[ ]*end\n*" % unused, "", raw)
with open(file, "w") as f2:
f2.write(raw)
# also clean up pory files
for file in pories_to_check:
with open(file, "r") as f2:
raw = f2.read()
for unused in list(dict.keys()):
raw = re.sub("script %s[ \n]*\{[ \n]*finditem\((.*)\)[ \n]*\}[ \n]*" % unused, "", raw)
with open(file, "w") as f2:
f2.write(raw)
print("Done!")
import glob
import re
import json
import os
if not os.path.exists("Makefile"):
print("Please run this script from your root folder.")
quit()
# scan incs
incs_to_check = glob.glob('./data/scripts/*.inc') # all .incs in the script folder
incs_to_check += glob.glob('./data/maps/*/scripts.inc') # all map scripts
pories_to_check = glob.glob('./data/scripts/*.pory') ## all .porys in the script folder
pories_to_check += glob.glob('./data/maps/*/scripts.pory') # all map scripts
array = []
array_pories = []
# make a list of which script corresponds to which item
for file in incs_to_check:
with open(file, "r") as f2:
raw = f2.read()
array += re.findall("(.*)::\n[ ]*finditem (.*)\n[ ]*end", raw)
# since this doesn't catch poryscript-generated inc files, do the same for poryscript
for file in pories_to_check:
with open(file, "r") as f2:
raw = f2.read()
array_pories += re.findall("script ([\w]*)[ \n]*\{[ \n]*finditem\((.*)\)[ \n]*\}", raw)
dict = {}
# poryscript values are prioritised because they would overwrite inc files anyway if different
for x in array_pories:
dict[x[0]] = x[1]
for x in array:
if not x[0] in dict:
dict[x[0]] = x[1]
# apply changes to inc files
for map in glob.glob('./data/maps/*/map.json'):
with open(map, "r") as f2:
data = json.load(f2)
if not 'object_events' in data:
continue
for objevent in data['object_events']:
if objevent["script"] in dict:
objevent["trainer_sight_or_berry_tree_id"] = dict[objevent["script"]]
objevent["script"] = "Common_EventScript_FindItem"
with open(map, "w") as f2:
f2.write(json.dumps(data, indent=2) + "\n")
# do another map search to find out which finditem scripts would somehow be still in use
still_in_use = []
for map in glob.glob('./data/maps/*/map.json'):
with open(map, "r") as f2:
data = json.load(f2)
if not 'object_events' in data:
continue
for objevent in data['object_events']:
if objevent["script"] in dict and not objevent["script"] in still_in_use:
still_in_use.append(objevent["script"])
for x in list(dict.keys()):
if x in still_in_use:
del dict[x]
# clean up scripts that are now no longer in use
for file in incs_to_check:
with open(file, "r") as f2:
raw = f2.read()
for unused in list(dict.keys()):
raw = re.sub("%s::\n[ ]*finditem (.*)\n[ ]*end\n*" % unused, "", raw)
with open(file, "w") as f2:
f2.write(raw)
# also clean up pory files
for file in pories_to_check:
with open(file, "r") as f2:
raw = f2.read()
for unused in list(dict.keys()):
raw = re.sub("script %s[ \n]*\{[ \n]*finditem\((.*)\)[ \n]*\}[ \n]*" % unused, "", raw)
with open(file, "w") as f2:
f2.write(raw)
print("Done!")

View File

@ -1,62 +1,62 @@
import re
def battle_frontier_mons(data):
data = re.sub(re.escape(".itemTableId = BATTLE_FRONTIER_"), ".heldItem = ", data)
data = re.sub(re.escape("FacilityMon"), "TrainerMon", data)
data = re.sub(re.escape(".evSpread = 0,"), ".ev = NULL,", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(252, 0, 0, 0, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SPEED | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 170, 170, 170, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 252, 0, 0, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SPEED,"), ".ev = TRAINER_PARTY_EVS(0, 0, 0, 252, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_DEFENSE | F_EV_SPREAD_ATTACK | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 170, 170, 0, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 170, 170, 0, 170, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_SPEED | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 0, 0, 170, 170, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_SPEED | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 0, 0, 170, 170, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 0, 170, 0, 170, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_SPEED | F_EV_SPREAD_DEFENSE,"), ".ev = TRAINER_PARTY_EVS(0, 0, 170, 170, 170, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_SPEED | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 170, 0, 170, 170, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_ATTACK | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 170, 0, 0, 170, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(252, 0, 0, 0, 252, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 252, 0, 0, 252, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_DEFENSE,"), ".ev = TRAINER_PARTY_EVS(0, 0, 252, 0, 252, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_SPEED,"), ".ev = TRAINER_PARTY_EVS(0, 0, 0, 252, 252, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SPEED | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_ATTACK | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(102, 102, 102, 102, 0, 102),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 128, 128, 0, 128, 128),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_DEFENSE,"), ".ev = TRAINER_PARTY_EVS(0, 0, 170, 0, 170, 170),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_SPEED | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_ATTACK | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(84, 84, 84, 84, 84, 84),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SPEED | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 128, 128, 128, 0, 128),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 170, 170, 0, 0, 170),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_SPEED | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(102, 0, 102, 102, 102, 102),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 170, 0, 0, 170, 170),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(128, 0, 128, 0, 128, 128),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_ATTACK | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(128, 128, 128, 0, 0, 128),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SPEED | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 0, 0, 170, 0, 170),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SPEED | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 170, 0, 170, 0, 170),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(252, 0, 0, 0, 0, 252),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SPEED | F_EV_SPREAD_DEFENSE,"), ".ev = TRAINER_PARTY_EVS(0, 0, 170, 170, 0, 170),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SPEED | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(128, 0, 128, 128, 0, 128),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 0, 0, 0, 170, 170),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 0, 170, 0, 0, 170),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_ATTACK | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 170, 0, 0, 0, 170),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 252, 0, 0, 0, 252),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SP_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 0, 0, 0, 252, 252),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_DEFENSE,"), ".ev = TRAINER_PARTY_EVS(0, 0, 252, 0, 0, 252),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_ATTACK | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(252, 252, 0, 0, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SPEED | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(252, 0, 0, 252, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SPEED | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 0, 170, 170, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SPEED | F_EV_SPREAD_ATTACK | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 170, 0, 170, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SPEED | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 252, 0, 252, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_DEFENSE | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(252, 0, 252, 0, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_DEFENSE | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 252, 252, 0, 0, 0),", data)
return data
with open('src/data/battle_frontier/battle_frontier_mons.h', 'r') as file:
data = file.read()
with open('src/data/battle_frontier/battle_frontier_mons.h', 'w') as file:
file.write(battle_frontier_mons(data))
with open('src/data/battle_frontier/battle_tent.h', 'r') as file:
data = file.read()
with open('src/data/battle_frontier/battle_tent.h', 'w') as file:
file.write(battle_frontier_mons(data))
import re
def battle_frontier_mons(data):
data = re.sub(re.escape(".itemTableId = BATTLE_FRONTIER_"), ".heldItem = ", data)
data = re.sub(re.escape("FacilityMon"), "TrainerMon", data)
data = re.sub(re.escape(".evSpread = 0,"), ".ev = NULL,", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(252, 0, 0, 0, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SPEED | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 170, 170, 170, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 252, 0, 0, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SPEED,"), ".ev = TRAINER_PARTY_EVS(0, 0, 0, 252, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_DEFENSE | F_EV_SPREAD_ATTACK | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 170, 170, 0, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 170, 170, 0, 170, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_SPEED | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 0, 0, 170, 170, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_SPEED | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 0, 0, 170, 170, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 0, 170, 0, 170, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_SPEED | F_EV_SPREAD_DEFENSE,"), ".ev = TRAINER_PARTY_EVS(0, 0, 170, 170, 170, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_SPEED | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 170, 0, 170, 170, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_ATTACK | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 170, 0, 0, 170, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(252, 0, 0, 0, 252, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 252, 0, 0, 252, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_DEFENSE,"), ".ev = TRAINER_PARTY_EVS(0, 0, 252, 0, 252, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_SPEED,"), ".ev = TRAINER_PARTY_EVS(0, 0, 0, 252, 252, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SPEED | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_ATTACK | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(102, 102, 102, 102, 0, 102),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 128, 128, 0, 128, 128),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_DEFENSE,"), ".ev = TRAINER_PARTY_EVS(0, 0, 170, 0, 170, 170),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_SPEED | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_ATTACK | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(84, 84, 84, 84, 84, 84),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SPEED | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 128, 128, 128, 0, 128),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 170, 170, 0, 0, 170),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_SPEED | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(102, 0, 102, 102, 102, 102),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 170, 0, 0, 170, 170),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(128, 0, 128, 0, 128, 128),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_ATTACK | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(128, 128, 128, 0, 0, 128),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SPEED | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 0, 0, 170, 0, 170),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SPEED | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 170, 0, 170, 0, 170),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(252, 0, 0, 0, 0, 252),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SPEED | F_EV_SPREAD_DEFENSE,"), ".ev = TRAINER_PARTY_EVS(0, 0, 170, 170, 0, 170),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SPEED | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(128, 0, 128, 128, 0, 128),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SP_ATTACK | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 0, 0, 0, 170, 170),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 0, 170, 0, 0, 170),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_ATTACK | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 170, 0, 0, 0, 170),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 252, 0, 0, 0, 252),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_SP_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 0, 0, 0, 252, 252),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SP_DEFENSE | F_EV_SPREAD_DEFENSE,"), ".ev = TRAINER_PARTY_EVS(0, 0, 252, 0, 0, 252),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_ATTACK | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(252, 252, 0, 0, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SPEED | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(252, 0, 0, 252, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SPEED | F_EV_SPREAD_DEFENSE | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 0, 170, 170, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SPEED | F_EV_SPREAD_ATTACK | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(170, 170, 0, 170, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_SPEED | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 252, 0, 252, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_DEFENSE | F_EV_SPREAD_HP,"), ".ev = TRAINER_PARTY_EVS(252, 0, 252, 0, 0, 0),", data)
data = re.sub(re.escape(".evSpread = F_EV_SPREAD_DEFENSE | F_EV_SPREAD_ATTACK,"), ".ev = TRAINER_PARTY_EVS(0, 252, 252, 0, 0, 0),", data)
return data
with open('src/data/battle_frontier/battle_frontier_mons.h', 'r') as file:
data = file.read()
with open('src/data/battle_frontier/battle_frontier_mons.h', 'w') as file:
file.write(battle_frontier_mons(data))
with open('src/data/battle_frontier/battle_tent.h', 'r') as file:
data = file.read()
with open('src/data/battle_frontier/battle_tent.h', 'w') as file:
file.write(battle_frontier_mons(data))

View File

@ -1,45 +1,45 @@
import glob
import re
import os
if not os.path.exists("Makefile"):
print("Please run this script from your root folder.")
quit()
# Read item_icon_table.h and extract the icon and palette information
for file in glob.glob('./src/data/item_icon_table.h'):
with open(file, 'r') as f:
icon_table_content = f.read()
# Extract item icon and palette data from item_icon_table.h
icon_table_pattern = re.compile(r'\[(ITEM_[A-Z_0-9]+)\]\s*=\s*\{([^,]+),\s*([^}]+)\}', re.MULTILINE)
icon_table_data = {}
for match in icon_table_pattern.findall(icon_table_content):
if len(match) == 3:
item_name, icon_pic, icon_palette = match
icon_table_data[item_name] = (icon_pic, icon_palette)
# Read items.h content
for file in glob.glob('./src/data/items.h'):
with open(file, 'r') as f:
items_content = f.read()
# Modify items.h content
def add_icon_data(match):
item_name = match.group(1)
item_content = match.group(2)
if item_name in icon_table_data:
icon_pic, icon_palette = icon_table_data[item_name]
print(f"Updating {item_name}: adding iconPic = {icon_pic}, iconPalette = {icon_palette}")
return f'[{item_name}] =\n {{{item_content} .iconPic = {icon_pic},\n .iconPalette = {icon_palette},\n }},'
else:
return match.group(0)
item_pattern = re.compile(r'\[(ITEM_[A-Z_0-9]+)\]\s*=\s*\{([\s\S]*?)\},', re.DOTALL)
modified_items_content = item_pattern.sub(add_icon_data, items_content)
# Write the modified content back to items.h
for file in glob.glob('./src/data/items.h'):
with open(file, 'w') as f:
f.write(modified_items_content)
print("items.h has been updated")
import glob
import re
import os
if not os.path.exists("Makefile"):
print("Please run this script from your root folder.")
quit()
# Read item_icon_table.h and extract the icon and palette information
for file in glob.glob('./src/data/item_icon_table.h'):
with open(file, 'r') as f:
icon_table_content = f.read()
# Extract item icon and palette data from item_icon_table.h
icon_table_pattern = re.compile(r'\[(ITEM_[A-Z_0-9]+)\]\s*=\s*\{([^,]+),\s*([^}]+)\}', re.MULTILINE)
icon_table_data = {}
for match in icon_table_pattern.findall(icon_table_content):
if len(match) == 3:
item_name, icon_pic, icon_palette = match
icon_table_data[item_name] = (icon_pic, icon_palette)
# Read items.h content
for file in glob.glob('./src/data/items.h'):
with open(file, 'r') as f:
items_content = f.read()
# Modify items.h content
def add_icon_data(match):
item_name = match.group(1)
item_content = match.group(2)
if item_name in icon_table_data:
icon_pic, icon_palette = icon_table_data[item_name]
print(f"Updating {item_name}: adding iconPic = {icon_pic}, iconPalette = {icon_palette}")
return f'[{item_name}] =\n {{{item_content} .iconPic = {icon_pic},\n .iconPalette = {icon_palette},\n }},'
else:
return match.group(0)
item_pattern = re.compile(r'\[(ITEM_[A-Z_0-9]+)\]\s*=\s*\{([\s\S]*?)\},', re.DOTALL)
modified_items_content = item_pattern.sub(add_icon_data, items_content)
# Write the modified content back to items.h
for file in glob.glob('./src/data/items.h'):
with open(file, 'w') as f:
f.write(modified_items_content)
print("items.h has been updated")

View File

@ -1,319 +1,319 @@
# If you have extra members in 'TrainerMon':
# 1. Add a regular expression which matches that member (e.g. 'shadow_definition').
# 2. Match that regular expression in 'convert' and write into 'attributes' with the key that 'trainerproc' should parse.
# 3. Add the key used in 'attributes' to 'pokemon_attribute_order'.
# 4. Update 'trainerproc.c' to parse the new key.
import re
import sys
is_blank = re.compile(r'^[ \t]*(//.*)?$')
begin_party_definition = re.compile(r'struct TrainerMon (\w+)\[\] =')
end_party_definition = re.compile(r'^};')
begin_pokemon_definition = re.compile(r'^ { *$')
end_pokemon_definition = re.compile(r'^ },? *$')
level_definition = re.compile(r'\.lvl = (\d+)')
species_definition = re.compile(r'\.species = SPECIES_(\w+)')
gender_definition = re.compile(r'\.gender = TRAINER_MON_(\w+)')
nickname_definition = re.compile(r'\.nickname = COMPOUND_STRING\("([^"]+)"\)')
item_definition = re.compile(r'\.heldItem = ITEM_(\w+)')
ball_definition = re.compile(r'\.ball = ITEM_(\w+)')
ability_definition = re.compile(r'\.ability = ABILITY_(\w+)')
friendship_definition = re.compile(r'\.friendship = (\d+)')
shiny_definition = re.compile(r'\.isShiny = (\w+)')
ivs_definition = re.compile(r'\.iv = TRAINER_PARTY_IVS\(([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+)\)')
evs_definition = re.compile(r'\.ev = TRAINER_PARTY_EVS\(([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+)\)')
moves_definition = re.compile(r'\.moves = \{([^}]+)\}')
move_definition = re.compile(r'MOVE_(\w+)')
nature_definition = re.compile(r'\.nature = NATURE_(\w+)')
# NOTE: These are just for aesthetics, the Pokemon would still compile
# without them.
species_replacements = {
"CHIEN_PAO": "Chien-Pao",
"CHI_YU": "Chi-Yu",
"HAKAMO_O": "Hakamo-o",
"HO_OH": "Ho-Oh",
"JANGMO_O": "Jangmo-o",
"KOMMO_O": "Kommo-o",
"PORYGON_Z": "Porygon-Z",
"ROTOM_": "Rotom-",
"TING_LU": "Ting-Lu",
"TYPE_NULL": "Type: Null",
"WO_CHIEN": "Wo-Chien",
"_ALOLAN": "-Alola",
"_AQUA_BREED": "-Aqua",
"_BATTLE_BOND": "-Bond",
"_BLAZE_BREED": "-Blaze",
"_CAP": "",
"_CLOAK": "",
"_COMBAT_BREED": "-Combat",
"_CROWED_SHIELD": "-Crowned",
"_CROWED_SWORD": "-Crowned",
"_DRIVE": "",
"_EAST_SEA": "-East",
"_FAMILY_OF_FOUR": "-Four",
"_FEMALE": "-F",
"_FLOWER": "",
"_GALARIAN": "-Galar",
"_GIGANTAMAX": "-Gmax",
"_HISUIAN": "-Hisui",
"_ICE_RIDER": "-Ice",
"_NOICE_FACE": "-Noice",
"_ORIGIN": "-Origin",
"_ORIGINAL_COLOR": "-Original",
"_PALDEAN": "-Paldea",
"_PLUMAGE": "",
"_POKE_BALL": "-Pokeball",
"_SHADOW_RIDER": "-Shadow",
"_STRIKE_STYLE": "-Style",
"_TOTEM": "-Totem",
"_ZEN_MODE": "-Zen",
}
pokemon_attribute_order = ['Level', 'Ability', 'IVs', 'EVs', 'Happiness', 'Shiny', 'Ball']
class Pokemon:
def __init__(self):
self.nickname = None
self.species = None
self.gender = None
self.item = None
self.nature = None
self.attributes = {}
self.attributes['IVs'] = "0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe"
self.moves = []
def convert_parties(in_path, in_h):
party_identifier = None
party = None
pokemon = None
parties = {}
for line_no, line in enumerate(in_h, 1):
try:
line = line[:-1]
if m := begin_party_definition.search(line):
if party:
raise Exception(f"unexpected start of party")
[identifier] = m.groups()
party_identifier = identifier
party = []
elif end_party_definition.search(line):
if not party:
raise Exception(f"unexpected end of party")
parties[party_identifier] = party
party = None
elif begin_pokemon_definition.search(line):
if pokemon:
raise Exception(f"unexpected start of Pokemon")
pokemon = Pokemon()
elif end_pokemon_definition.search(line):
if not pokemon:
raise Exception(f"unexpected end of Pokemon")
else:
party.append(pokemon)
pokemon = None
elif m := level_definition.search(line):
[level] = m.groups()
pokemon.attributes['Level'] = level
elif m := species_definition.search(line):
[species_] = m.groups()
for match, replacement in species_replacements.items():
species_ = species_.replace(match, replacement)
pokemon.species = species_.replace("_", " ").title()
elif m := gender_definition.search(line):
[gender_] = m.groups()
if gender_ == 'MALE':
pokemon.gender = 'M'
elif gender_ == 'FEMALE':
pokemon.gender = 'F'
else:
raise Exception(f"unknown gender: '{gender_}'")
elif m := nickname_definition.search(line):
[nickname] = m.groups()
pokemon.nickname = nickname
elif m := item_definition.search(line):
[item_] = m.groups()
pokemon.item = item_.replace("_", " ").title()
elif m := ball_definition.search(line):
[ball] = m.groups()
pokemon.attributes['Ball'] = ball.replace("_", " ").title()
elif m := ability_definition.search(line):
[ability] = m.groups()
pokemon.attributes['Ability'] = ability.replace("_", " ").title()
elif m := friendship_definition.search(line):
[friendship] = m.groups()
pokemon.attributes['Happiness'] = friendship
elif m := shiny_definition.search(line):
[shiny] = m.groups()
if shiny == 'TRUE':
pokemon.attributes['Shiny'] = 'Yes'
elif shiny == 'FALSE':
pokemon.attributes['Shiny'] = 'No'
else:
raise Exception(f"unknown isShiny: '{shiny}'")
elif m := ivs_definition.search(line):
[hp, attack, defense, speed, special_attack, special_defense] = [stat.strip() for stat in m.groups()]
stats = {"HP": hp, "Atk": attack, "Def": defense, "SpA": special_attack, "SpD": special_defense, "Spe": speed}
pokemon.attributes['IVs'] = ' / '.join(f"{value} {key}" for key, value in stats.items())
elif m := evs_definition.search(line):
[hp, attack, defense, speed, special_attack, special_defense] = [stat.strip() for stat in m.groups()]
stats = {"HP": hp, "Atk": attack, "Def": defense, "SpA": special_attack, "SpD": special_defense, "Spe": speed}
pokemon.attributes['EVs'] = ' / '.join(f"{value} {key}" for key, value in stats.items() if value != '0')
elif m := moves_definition.search(line):
[moves_] = m.groups()
pokemon.moves = [move.replace("_", " ").title() for move in move_definition.findall(moves_) if move != "NONE"]
elif m := nature_definition.search(line):
[nature_] = m.groups()
pokemon.nature = nature_.replace("_", " ").title()
elif is_blank.search(line):
pass
else:
raise Exception(f"could not parse '{line.strip()}'")
except Exception as e:
print(f"{in_path}:{line_no}: {e}")
return parties
is_trainer_skip = re.compile(r'(const struct Trainer gBattlePartners\[\] = \{)|(^ \{$)|(\.partySize =)|(\.party = NULL)|(\.mugshotEnabled = TRUE)|(\};)')
begin_trainer_definition = re.compile(r' \[(PARTNER_\w+)\] =')
end_trainer_definition = re.compile(r' }')
trainer_class_definition = re.compile(r'\.trainerClass = TRAINER_CLASS_(\w+)')
encounter_music_gender_definition = re.compile(r'\.encounterMusic_gender = (F_TRAINER_FEMALE \| )?TRAINER_ENCOUNTER_MUSIC_(\w+)')
trainer_pic_definition = re.compile(r'\.trainerPic = TRAINER_BACK_PIC_(\w+)')
trainer_name_definition = re.compile(r'\.trainerName = _\("([^"]*)"\)')
trainer_items_definition = re.compile(r'\.items = \{([^}]*)\}')
trainer_item_definition = re.compile(r'ITEM_(\w+)')
trainer_ai_flags_definition = re.compile(r'\.aiFlags = (.*)')
trainer_ai_flag_definition = re.compile(r'AI_FLAG_(\w+)')
trainer_party_definition = re.compile(r'\.party = TRAINER_PARTY\((\w+)\)')
trainer_mugshot_definition = re.compile(r'\.mugshotColor = MUGSHOT_COLOR_(\w+)')
trainer_starting_status_definition = re.compile(r'\.startingStatus = STARTING_STATUS_(\w+)')
class_fixups = {
"Rs": "RS",
}
pic_fixups = {
"Rs": "RS",
}
class Trainer:
def __init__(self, id_):
self.id = id_
self.class_ = None
self.encounter_music = None
self.gender = None
self.pic = None
self.name = None
self.items = []
self.ai_flags = None
self.mugshot = None
self.starting_status = None
self.party = None
def convert_trainers(in_path, in_h, parties, out_party):
newlines = 0
trainer = None
for line_no, line in enumerate(in_h, 1):
try:
line = line[:-1]
if m := begin_trainer_definition.search(line):
if trainer:
raise Exception(f"unexpected start of trainer")
[id_] = m.groups()
trainer = Trainer(id_)
elif m := trainer_class_definition.search(line):
[class_] = m.groups()
class_ = class_.replace("_", " ").title()
for match, replacement in class_fixups.items():
class_ = class_.replace(match, replacement)
trainer.class_ = class_
elif m := encounter_music_gender_definition.search(line):
[is_female, music] = m.groups()
trainer.gender = 'Female' if is_female else 'Male'
trainer.encounter_music = music.replace("_", " ").title()
elif m := trainer_pic_definition.search(line):
[pic] = m.groups()
pic = pic.replace("_", " ").title()
for match, replacement in pic_fixups.items():
pic = pic.replace(match, replacement)
trainer.pic = pic
elif m := trainer_name_definition.search(line):
[name] = m.groups()
trainer.name = name
elif m := trainer_items_definition.search(line):
[items] = m.groups()
trainer.items = " / ".join(item.replace("_", " ").title() for item in trainer_item_definition.findall(items) if item != "NONE")
elif m := trainer_ai_flags_definition.search(line):
[ai_flags] = m.groups()
trainer.ai_flags = " / ".join(ai_flag.replace("_", " ").title() for ai_flag in trainer_ai_flag_definition.findall(ai_flags))
elif m := trainer_mugshot_definition.search(line):
[color] = m.groups()
trainer.mugshot = color.title()
elif m := trainer_starting_status_definition.search(line):
[starting_status] = m.groups()
trainer.starting_status = starting_status.replace("_", " ").title()
elif m := trainer_party_definition.search(line):
[party] = m.groups()
trainer.party = parties[party]
elif end_trainer_definition.search(line):
if not trainer:
raise Exception(f"unexpected end of trainer")
while newlines > 0:
out_party.write(f"\n")
newlines -= 1
newlines = 1
out_party.write(f"=== {trainer.id} ===\n")
out_party.write(f"Name: {trainer.name}\n")
out_party.write(f"Class: {trainer.class_}\n")
out_party.write(f"Pic: {trainer.pic}\n")
out_party.write(f"Gender: {trainer.gender}\n")
out_party.write(f"Music: {trainer.encounter_music}\n")
if trainer.items:
out_party.write(f"Items: {trainer.items}\n")
if trainer.ai_flags:
out_party.write(f"AI: {trainer.ai_flags}\n")
if trainer.mugshot:
out_party.write(f"Mugshot: {trainer.mugshot}\n")
if trainer.starting_status:
out_party.write(f"Starting Status: {trainer.starting_status}\n")
if trainer.party:
for i, pokemon in enumerate(trainer.party):
out_party.write(f"\n")
if pokemon.nickname:
out_party.write(f"{pokemon.nickname} ({pokemon.species})")
else:
out_party.write(f"{pokemon.species}")
if pokemon.gender:
out_party.write(f" ({pokemon.gender})")
if pokemon.item and pokemon.item != 'None':
out_party.write(f" @ {pokemon.item}")
out_party.write(f"\n")
if pokemon.nature:
out_party.write(f"{pokemon.nature} Nature\n")
for key in pokemon_attribute_order:
if key in pokemon.attributes:
out_party.write(f"{key}: {pokemon.attributes[key]}\n")
for move in pokemon.moves:
out_party.write(f"- {move}\n")
trainer = None
elif is_blank.search(line) or is_trainer_skip.search(line):
pass
else:
raise Exception(f"could not parse '{line.strip()}'")
except Exception as e:
print(f"{in_path}:{line_no}: {e}")
if __name__ == '__main__':
try:
[argv0, trainers_in_path, parties_in_path, out_path] = sys.argv
except:
print(f"usage: python3 {sys.argv[0]} <trainers.h> <trainer_parties.h> <out>")
else:
with open(trainers_in_path, "r") as trainers_in_h, open(parties_in_path, "r") as parties_in_h, open(out_path, "w") as out_party:
parties = convert_parties(parties_in_path, parties_in_h)
trainers = convert_trainers(trainers_in_path, trainers_in_h, parties, out_party)
# If you have extra members in 'TrainerMon':
# 1. Add a regular expression which matches that member (e.g. 'shadow_definition').
# 2. Match that regular expression in 'convert' and write into 'attributes' with the key that 'trainerproc' should parse.
# 3. Add the key used in 'attributes' to 'pokemon_attribute_order'.
# 4. Update 'trainerproc.c' to parse the new key.
import re
import sys
is_blank = re.compile(r'^[ \t]*(//.*)?$')
begin_party_definition = re.compile(r'struct TrainerMon (\w+)\[\] =')
end_party_definition = re.compile(r'^};')
begin_pokemon_definition = re.compile(r'^ { *$')
end_pokemon_definition = re.compile(r'^ },? *$')
level_definition = re.compile(r'\.lvl = (\d+)')
species_definition = re.compile(r'\.species = SPECIES_(\w+)')
gender_definition = re.compile(r'\.gender = TRAINER_MON_(\w+)')
nickname_definition = re.compile(r'\.nickname = COMPOUND_STRING\("([^"]+)"\)')
item_definition = re.compile(r'\.heldItem = ITEM_(\w+)')
ball_definition = re.compile(r'\.ball = ITEM_(\w+)')
ability_definition = re.compile(r'\.ability = ABILITY_(\w+)')
friendship_definition = re.compile(r'\.friendship = (\d+)')
shiny_definition = re.compile(r'\.isShiny = (\w+)')
ivs_definition = re.compile(r'\.iv = TRAINER_PARTY_IVS\(([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+)\)')
evs_definition = re.compile(r'\.ev = TRAINER_PARTY_EVS\(([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+)\)')
moves_definition = re.compile(r'\.moves = \{([^}]+)\}')
move_definition = re.compile(r'MOVE_(\w+)')
nature_definition = re.compile(r'\.nature = NATURE_(\w+)')
# NOTE: These are just for aesthetics, the Pokemon would still compile
# without them.
species_replacements = {
"CHIEN_PAO": "Chien-Pao",
"CHI_YU": "Chi-Yu",
"HAKAMO_O": "Hakamo-o",
"HO_OH": "Ho-Oh",
"JANGMO_O": "Jangmo-o",
"KOMMO_O": "Kommo-o",
"PORYGON_Z": "Porygon-Z",
"ROTOM_": "Rotom-",
"TING_LU": "Ting-Lu",
"TYPE_NULL": "Type: Null",
"WO_CHIEN": "Wo-Chien",
"_ALOLAN": "-Alola",
"_AQUA_BREED": "-Aqua",
"_BATTLE_BOND": "-Bond",
"_BLAZE_BREED": "-Blaze",
"_CAP": "",
"_CLOAK": "",
"_COMBAT_BREED": "-Combat",
"_CROWED_SHIELD": "-Crowned",
"_CROWED_SWORD": "-Crowned",
"_DRIVE": "",
"_EAST_SEA": "-East",
"_FAMILY_OF_FOUR": "-Four",
"_FEMALE": "-F",
"_FLOWER": "",
"_GALARIAN": "-Galar",
"_GIGANTAMAX": "-Gmax",
"_HISUIAN": "-Hisui",
"_ICE_RIDER": "-Ice",
"_NOICE_FACE": "-Noice",
"_ORIGIN": "-Origin",
"_ORIGINAL_COLOR": "-Original",
"_PALDEAN": "-Paldea",
"_PLUMAGE": "",
"_POKE_BALL": "-Pokeball",
"_SHADOW_RIDER": "-Shadow",
"_STRIKE_STYLE": "-Style",
"_TOTEM": "-Totem",
"_ZEN_MODE": "-Zen",
}
pokemon_attribute_order = ['Level', 'Ability', 'IVs', 'EVs', 'Happiness', 'Shiny', 'Ball']
class Pokemon:
def __init__(self):
self.nickname = None
self.species = None
self.gender = None
self.item = None
self.nature = None
self.attributes = {}
self.attributes['IVs'] = "0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe"
self.moves = []
def convert_parties(in_path, in_h):
party_identifier = None
party = None
pokemon = None
parties = {}
for line_no, line in enumerate(in_h, 1):
try:
line = line[:-1]
if m := begin_party_definition.search(line):
if party:
raise Exception(f"unexpected start of party")
[identifier] = m.groups()
party_identifier = identifier
party = []
elif end_party_definition.search(line):
if not party:
raise Exception(f"unexpected end of party")
parties[party_identifier] = party
party = None
elif begin_pokemon_definition.search(line):
if pokemon:
raise Exception(f"unexpected start of Pokemon")
pokemon = Pokemon()
elif end_pokemon_definition.search(line):
if not pokemon:
raise Exception(f"unexpected end of Pokemon")
else:
party.append(pokemon)
pokemon = None
elif m := level_definition.search(line):
[level] = m.groups()
pokemon.attributes['Level'] = level
elif m := species_definition.search(line):
[species_] = m.groups()
for match, replacement in species_replacements.items():
species_ = species_.replace(match, replacement)
pokemon.species = species_.replace("_", " ").title()
elif m := gender_definition.search(line):
[gender_] = m.groups()
if gender_ == 'MALE':
pokemon.gender = 'M'
elif gender_ == 'FEMALE':
pokemon.gender = 'F'
else:
raise Exception(f"unknown gender: '{gender_}'")
elif m := nickname_definition.search(line):
[nickname] = m.groups()
pokemon.nickname = nickname
elif m := item_definition.search(line):
[item_] = m.groups()
pokemon.item = item_.replace("_", " ").title()
elif m := ball_definition.search(line):
[ball] = m.groups()
pokemon.attributes['Ball'] = ball.replace("_", " ").title()
elif m := ability_definition.search(line):
[ability] = m.groups()
pokemon.attributes['Ability'] = ability.replace("_", " ").title()
elif m := friendship_definition.search(line):
[friendship] = m.groups()
pokemon.attributes['Happiness'] = friendship
elif m := shiny_definition.search(line):
[shiny] = m.groups()
if shiny == 'TRUE':
pokemon.attributes['Shiny'] = 'Yes'
elif shiny == 'FALSE':
pokemon.attributes['Shiny'] = 'No'
else:
raise Exception(f"unknown isShiny: '{shiny}'")
elif m := ivs_definition.search(line):
[hp, attack, defense, speed, special_attack, special_defense] = [stat.strip() for stat in m.groups()]
stats = {"HP": hp, "Atk": attack, "Def": defense, "SpA": special_attack, "SpD": special_defense, "Spe": speed}
pokemon.attributes['IVs'] = ' / '.join(f"{value} {key}" for key, value in stats.items())
elif m := evs_definition.search(line):
[hp, attack, defense, speed, special_attack, special_defense] = [stat.strip() for stat in m.groups()]
stats = {"HP": hp, "Atk": attack, "Def": defense, "SpA": special_attack, "SpD": special_defense, "Spe": speed}
pokemon.attributes['EVs'] = ' / '.join(f"{value} {key}" for key, value in stats.items() if value != '0')
elif m := moves_definition.search(line):
[moves_] = m.groups()
pokemon.moves = [move.replace("_", " ").title() for move in move_definition.findall(moves_) if move != "NONE"]
elif m := nature_definition.search(line):
[nature_] = m.groups()
pokemon.nature = nature_.replace("_", " ").title()
elif is_blank.search(line):
pass
else:
raise Exception(f"could not parse '{line.strip()}'")
except Exception as e:
print(f"{in_path}:{line_no}: {e}")
return parties
is_trainer_skip = re.compile(r'(const struct Trainer gBattlePartners\[\] = \{)|(^ \{$)|(\.partySize =)|(\.party = NULL)|(\.mugshotEnabled = TRUE)|(\};)')
begin_trainer_definition = re.compile(r' \[(PARTNER_\w+)\] =')
end_trainer_definition = re.compile(r' }')
trainer_class_definition = re.compile(r'\.trainerClass = TRAINER_CLASS_(\w+)')
encounter_music_gender_definition = re.compile(r'\.encounterMusic_gender = (F_TRAINER_FEMALE \| )?TRAINER_ENCOUNTER_MUSIC_(\w+)')
trainer_pic_definition = re.compile(r'\.trainerPic = TRAINER_BACK_PIC_(\w+)')
trainer_name_definition = re.compile(r'\.trainerName = _\("([^"]*)"\)')
trainer_items_definition = re.compile(r'\.items = \{([^}]*)\}')
trainer_item_definition = re.compile(r'ITEM_(\w+)')
trainer_ai_flags_definition = re.compile(r'\.aiFlags = (.*)')
trainer_ai_flag_definition = re.compile(r'AI_FLAG_(\w+)')
trainer_party_definition = re.compile(r'\.party = TRAINER_PARTY\((\w+)\)')
trainer_mugshot_definition = re.compile(r'\.mugshotColor = MUGSHOT_COLOR_(\w+)')
trainer_starting_status_definition = re.compile(r'\.startingStatus = STARTING_STATUS_(\w+)')
class_fixups = {
"Rs": "RS",
}
pic_fixups = {
"Rs": "RS",
}
class Trainer:
def __init__(self, id_):
self.id = id_
self.class_ = None
self.encounter_music = None
self.gender = None
self.pic = None
self.name = None
self.items = []
self.ai_flags = None
self.mugshot = None
self.starting_status = None
self.party = None
def convert_trainers(in_path, in_h, parties, out_party):
newlines = 0
trainer = None
for line_no, line in enumerate(in_h, 1):
try:
line = line[:-1]
if m := begin_trainer_definition.search(line):
if trainer:
raise Exception(f"unexpected start of trainer")
[id_] = m.groups()
trainer = Trainer(id_)
elif m := trainer_class_definition.search(line):
[class_] = m.groups()
class_ = class_.replace("_", " ").title()
for match, replacement in class_fixups.items():
class_ = class_.replace(match, replacement)
trainer.class_ = class_
elif m := encounter_music_gender_definition.search(line):
[is_female, music] = m.groups()
trainer.gender = 'Female' if is_female else 'Male'
trainer.encounter_music = music.replace("_", " ").title()
elif m := trainer_pic_definition.search(line):
[pic] = m.groups()
pic = pic.replace("_", " ").title()
for match, replacement in pic_fixups.items():
pic = pic.replace(match, replacement)
trainer.pic = pic
elif m := trainer_name_definition.search(line):
[name] = m.groups()
trainer.name = name
elif m := trainer_items_definition.search(line):
[items] = m.groups()
trainer.items = " / ".join(item.replace("_", " ").title() for item in trainer_item_definition.findall(items) if item != "NONE")
elif m := trainer_ai_flags_definition.search(line):
[ai_flags] = m.groups()
trainer.ai_flags = " / ".join(ai_flag.replace("_", " ").title() for ai_flag in trainer_ai_flag_definition.findall(ai_flags))
elif m := trainer_mugshot_definition.search(line):
[color] = m.groups()
trainer.mugshot = color.title()
elif m := trainer_starting_status_definition.search(line):
[starting_status] = m.groups()
trainer.starting_status = starting_status.replace("_", " ").title()
elif m := trainer_party_definition.search(line):
[party] = m.groups()
trainer.party = parties[party]
elif end_trainer_definition.search(line):
if not trainer:
raise Exception(f"unexpected end of trainer")
while newlines > 0:
out_party.write(f"\n")
newlines -= 1
newlines = 1
out_party.write(f"=== {trainer.id} ===\n")
out_party.write(f"Name: {trainer.name}\n")
out_party.write(f"Class: {trainer.class_}\n")
out_party.write(f"Pic: {trainer.pic}\n")
out_party.write(f"Gender: {trainer.gender}\n")
out_party.write(f"Music: {trainer.encounter_music}\n")
if trainer.items:
out_party.write(f"Items: {trainer.items}\n")
if trainer.ai_flags:
out_party.write(f"AI: {trainer.ai_flags}\n")
if trainer.mugshot:
out_party.write(f"Mugshot: {trainer.mugshot}\n")
if trainer.starting_status:
out_party.write(f"Starting Status: {trainer.starting_status}\n")
if trainer.party:
for i, pokemon in enumerate(trainer.party):
out_party.write(f"\n")
if pokemon.nickname:
out_party.write(f"{pokemon.nickname} ({pokemon.species})")
else:
out_party.write(f"{pokemon.species}")
if pokemon.gender:
out_party.write(f" ({pokemon.gender})")
if pokemon.item and pokemon.item != 'None':
out_party.write(f" @ {pokemon.item}")
out_party.write(f"\n")
if pokemon.nature:
out_party.write(f"{pokemon.nature} Nature\n")
for key in pokemon_attribute_order:
if key in pokemon.attributes:
out_party.write(f"{key}: {pokemon.attributes[key]}\n")
for move in pokemon.moves:
out_party.write(f"- {move}\n")
trainer = None
elif is_blank.search(line) or is_trainer_skip.search(line):
pass
else:
raise Exception(f"could not parse '{line.strip()}'")
except Exception as e:
print(f"{in_path}:{line_no}: {e}")
if __name__ == '__main__':
try:
[argv0, trainers_in_path, parties_in_path, out_path] = sys.argv
except:
print(f"usage: python3 {sys.argv[0]} <trainers.h> <trainer_parties.h> <out>")
else:
with open(trainers_in_path, "r") as trainers_in_h, open(parties_in_path, "r") as parties_in_h, open(out_path, "w") as out_party:
parties = convert_parties(parties_in_path, parties_in_h)
trainers = convert_trainers(trainers_in_path, trainers_in_h, parties, out_party)

View File

@ -1,330 +1,330 @@
# If you have extra members in 'TrainerMon':
# 1. Add a regular expression which matches that member (e.g. 'shadow_definition').
# 2. Match that regular expression in 'convert' and write into 'attributes' with the key that 'trainerproc' should parse.
# 3. Add the key used in 'attributes' to 'pokemon_attribute_order'.
# 4. Update 'trainerproc.c' to parse the new key.
import re
import sys
is_blank = re.compile(r'^[ \t]*(//.*)?$')
begin_party_definition = re.compile(r'struct TrainerMon (\w+)\[\] =')
end_party_definition = re.compile(r'^};')
begin_pokemon_definition = re.compile(r'^ { *$')
end_pokemon_definition = re.compile(r'^ },? *$')
level_definition = re.compile(r'\.lvl = (\d+)')
species_definition = re.compile(r'\.species = SPECIES_(\w+)')
gender_definition = re.compile(r'\.gender = TRAINER_MON_(\w+)')
nickname_definition = re.compile(r'\.nickname = COMPOUND_STRING\("([^"]+)"\)')
item_definition = re.compile(r'\.heldItem = ITEM_(\w+)')
ball_definition = re.compile(r'\.ball = ITEM_(\w+)')
ability_definition = re.compile(r'\.ability = ABILITY_(\w+)')
friendship_definition = re.compile(r'\.friendship = (\d+)')
shiny_definition = re.compile(r'\.isShiny = (\w+)')
ivs_definition = re.compile(r'\.iv = TRAINER_PARTY_IVS\(([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+)\)')
evs_definition = re.compile(r'\.ev = TRAINER_PARTY_EVS\(([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+)\)')
moves_definition = re.compile(r'\.moves = \{([^}]+)\}')
move_definition = re.compile(r'MOVE_(\w+)')
nature_definition = re.compile(r'\.nature = NATURE_(\w+)')
# NOTE: These are just for aesthetics, the Pokemon would still compile
# without them.
species_replacements = {
"CHIEN_PAO": "Chien-Pao",
"CHI_YU": "Chi-Yu",
"HAKAMO_O": "Hakamo-o",
"HO_OH": "Ho-Oh",
"JANGMO_O": "Jangmo-o",
"KOMMO_O": "Kommo-o",
"PORYGON_Z": "Porygon-Z",
"ROTOM_": "Rotom-",
"TING_LU": "Ting-Lu",
"TYPE_NULL": "Type: Null",
"WO_CHIEN": "Wo-Chien",
"_ALOLAN": "-Alola",
"_AQUA_BREED": "-Aqua",
"_BATTLE_BOND": "-Bond",
"_BLAZE_BREED": "-Blaze",
"_CAP": "",
"_CLOAK": "",
"_COMBAT_BREED": "-Combat",
"_CROWED_SHIELD": "-Crowned",
"_CROWED_SWORD": "-Crowned",
"_DRIVE": "",
"_EAST_SEA": "-East",
"_FAMILY_OF_FOUR": "-Four",
"_FEMALE": "-F",
"_FLOWER": "",
"_GALARIAN": "-Galar",
"_GIGANTAMAX": "-Gmax",
"_HISUIAN": "-Hisui",
"_ICE_RIDER": "-Ice",
"_NOICE_FACE": "-Noice",
"_ORIGIN": "-Origin",
"_ORIGINAL_COLOR": "-Original",
"_PALDEAN": "-Paldea",
"_PLUMAGE": "",
"_POKE_BALL": "-Pokeball",
"_SHADOW_RIDER": "-Shadow",
"_STRIKE_STYLE": "-Style",
"_TOTEM": "-Totem",
"_ZEN_MODE": "-Zen",
}
pokemon_attribute_order = ['Level', 'Ability', 'IVs', 'EVs', 'Happiness', 'Shiny', 'Ball']
class Pokemon:
def __init__(self):
self.nickname = None
self.species = None
self.gender = None
self.item = None
self.nature = None
self.attributes = {}
self.attributes['IVs'] = "0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe"
self.moves = []
def convert_parties(in_path, in_h):
party_identifier = None
party = None
pokemon = None
parties = {}
for line_no, line in enumerate(in_h, 1):
try:
line = line[:-1]
if m := begin_party_definition.search(line):
if party:
raise Exception(f"unexpected start of party")
[identifier] = m.groups()
party_identifier = identifier
party = []
elif end_party_definition.search(line):
if not party:
raise Exception(f"unexpected end of party")
parties[party_identifier] = party
party = None
elif begin_pokemon_definition.search(line):
if pokemon:
raise Exception(f"unexpected start of Pokemon")
pokemon = Pokemon()
elif end_pokemon_definition.search(line):
if not pokemon:
raise Exception(f"unexpected end of Pokemon")
else:
party.append(pokemon)
pokemon = None
elif m := level_definition.search(line):
[level] = m.groups()
pokemon.attributes['Level'] = level
elif m := species_definition.search(line):
[species_] = m.groups()
for match, replacement in species_replacements.items():
species_ = species_.replace(match, replacement)
pokemon.species = species_.replace("_", " ").title()
elif m := gender_definition.search(line):
[gender_] = m.groups()
if gender_ == 'MALE':
pokemon.gender = 'M'
elif gender_ == 'FEMALE':
pokemon.gender = 'F'
else:
raise Exception(f"unknown gender: '{gender_}'")
elif m := nickname_definition.search(line):
[nickname] = m.groups()
pokemon.nickname = nickname
elif m := item_definition.search(line):
[item_] = m.groups()
pokemon.item = item_.replace("_", " ").title()
elif m := ball_definition.search(line):
[ball] = m.groups()
pokemon.attributes['Ball'] = ball.replace("_", " ").title()
elif m := ability_definition.search(line):
[ability] = m.groups()
pokemon.attributes['Ability'] = ability.replace("_", " ").title()
elif m := friendship_definition.search(line):
[friendship] = m.groups()
pokemon.attributes['Happiness'] = friendship
elif m := shiny_definition.search(line):
[shiny] = m.groups()
if shiny == 'TRUE':
pokemon.attributes['Shiny'] = 'Yes'
elif shiny == 'FALSE':
pokemon.attributes['Shiny'] = 'No'
else:
raise Exception(f"unknown isShiny: '{shiny}'")
elif m := ivs_definition.search(line):
[hp, attack, defense, speed, special_attack, special_defense] = [stat.strip() for stat in m.groups()]
stats = {"HP": hp, "Atk": attack, "Def": defense, "SpA": special_attack, "SpD": special_defense, "Spe": speed}
pokemon.attributes['IVs'] = ' / '.join(f"{value} {key}" for key, value in stats.items())
elif m := evs_definition.search(line):
[hp, attack, defense, speed, special_attack, special_defense] = [stat.strip() for stat in m.groups()]
stats = {"HP": hp, "Atk": attack, "Def": defense, "SpA": special_attack, "SpD": special_defense, "Spe": speed}
pokemon.attributes['EVs'] = ' / '.join(f"{value} {key}" for key, value in stats.items() if value != '0')
elif m := moves_definition.search(line):
[moves_] = m.groups()
pokemon.moves = [move.replace("_", " ").title() for move in move_definition.findall(moves_) if move != "NONE"]
elif m := nature_definition.search(line):
[nature_] = m.groups()
pokemon.nature = nature_.replace("_", " ").title()
elif is_blank.search(line):
pass
else:
raise Exception(f"could not parse '{line.strip()}'")
except Exception as e:
print(f"{in_path}:{line_no}: {e}")
return parties
is_trainer_skip = re.compile(r'(const struct Trainer gTrainers\[\] = \{)|(^ \{$)|(\.partySize =)|(\.party = NULL)|(\.mugshotEnabled = TRUE)|(\};)')
begin_trainer_definition = re.compile(r' \[(TRAINER_\w+)\] =')
end_trainer_definition = re.compile(r' }')
trainer_class_definition = re.compile(r'\.trainerClass = TRAINER_CLASS_(\w+)')
encounter_music_gender_definition = re.compile(r'\.encounterMusic_gender = (F_TRAINER_FEMALE \| )?TRAINER_ENCOUNTER_MUSIC_(\w+)')
trainer_pic_definition = re.compile(r'\.trainerPic = TRAINER_PIC_(\w+)')
trainer_name_definition = re.compile(r'\.trainerName = _\("([^"]*)"\)')
trainer_items_definition = re.compile(r'\.items = \{([^}]*)\}')
trainer_item_definition = re.compile(r'ITEM_(\w+)')
trainer_double_battle_definition = re.compile(r'\.doubleBattle = (\w+)')
trainer_ai_flags_definition = re.compile(r'\.aiFlags = (.*)')
trainer_ai_flag_definition = re.compile(r'AI_FLAG_(\w+)')
trainer_party_definition = re.compile(r'\.party = TRAINER_PARTY\((\w+)\)')
trainer_mugshot_definition = re.compile(r'\.mugshotColor = MUGSHOT_COLOR_(\w+)')
trainer_starting_status_definition = re.compile(r'\.startingStatus = STARTING_STATUS_(\w+)')
class_fixups = {
"Rs": "RS",
}
pic_fixups = {
"Rs": "RS",
}
class Trainer:
def __init__(self, id_):
self.id = id_
self.class_ = None
self.encounter_music = None
self.gender = None
self.pic = None
self.name = None
self.items = []
self.double_battle = None
self.ai_flags = None
self.mugshot = None
self.starting_status = None
self.party = None
def convert_trainers(in_path, in_h, parties, out_party):
newlines = 0
trainer = None
for line_no, line in enumerate(in_h, 1):
try:
line = line[:-1]
if m := begin_trainer_definition.search(line):
if trainer:
raise Exception(f"unexpected start of trainer")
[id_] = m.groups()
trainer = Trainer(id_)
elif m := trainer_class_definition.search(line):
[class_] = m.groups()
class_ = class_.replace("_", " ").title()
for match, replacement in class_fixups.items():
class_ = class_.replace(match, replacement)
trainer.class_ = class_
elif m := encounter_music_gender_definition.search(line):
[is_female, music] = m.groups()
trainer.gender = 'Female' if is_female else 'Male'
trainer.encounter_music = music.replace("_", " ").title()
elif m := trainer_pic_definition.search(line):
[pic] = m.groups()
pic = pic.replace("_", " ").title()
for match, replacement in pic_fixups.items():
pic = pic.replace(match, replacement)
trainer.pic = pic
elif m := trainer_name_definition.search(line):
[name] = m.groups()
trainer.name = name
elif m := trainer_items_definition.search(line):
[items] = m.groups()
trainer.items = " / ".join(item.replace("_", " ").title() for item in trainer_item_definition.findall(items) if item != "NONE")
elif m := trainer_double_battle_definition.search(line):
[double_battle] = m.groups()
if double_battle == 'TRUE':
trainer.double_battle = "Yes"
elif double_battle == 'FALSE':
trainer.double_battle = "No"
else:
raise Exception(f"unknown doubleBattle: '{double_battle}'")
elif m := trainer_ai_flags_definition.search(line):
[ai_flags] = m.groups()
trainer.ai_flags = " / ".join(ai_flag.replace("_", " ").title() for ai_flag in trainer_ai_flag_definition.findall(ai_flags))
elif m := trainer_mugshot_definition.search(line):
[color] = m.groups()
trainer.mugshot = color.title()
elif m := trainer_starting_status_definition.search(line):
[starting_status] = m.groups()
trainer.starting_status = starting_status.replace("_", " ").title()
elif m := trainer_party_definition.search(line):
[party] = m.groups()
trainer.party = parties[party]
elif end_trainer_definition.search(line):
if not trainer:
raise Exception(f"unexpected end of trainer")
while newlines > 0:
out_party.write(f"\n")
newlines -= 1
newlines = 1
out_party.write(f"=== {trainer.id} ===\n")
out_party.write(f"Name: {trainer.name}\n")
out_party.write(f"Class: {trainer.class_}\n")
out_party.write(f"Pic: {trainer.pic}\n")
out_party.write(f"Gender: {trainer.gender}\n")
out_party.write(f"Music: {trainer.encounter_music}\n")
if trainer.items:
out_party.write(f"Items: {trainer.items}\n")
out_party.write(f"Double Battle: {trainer.double_battle}\n")
if trainer.ai_flags:
out_party.write(f"AI: {trainer.ai_flags}\n")
if trainer.mugshot:
out_party.write(f"Mugshot: {trainer.mugshot}\n")
if trainer.starting_status:
out_party.write(f"Starting Status: {trainer.starting_status}\n")
if trainer.party:
for i, pokemon in enumerate(trainer.party):
out_party.write(f"\n")
if pokemon.nickname:
out_party.write(f"{pokemon.nickname} ({pokemon.species})")
else:
out_party.write(f"{pokemon.species}")
if pokemon.gender:
out_party.write(f" ({pokemon.gender})")
if pokemon.item and pokemon.item != 'None':
out_party.write(f" @ {pokemon.item}")
out_party.write(f"\n")
if pokemon.nature:
out_party.write(f"{pokemon.nature} Nature\n")
for key in pokemon_attribute_order:
if key in pokemon.attributes:
out_party.write(f"{key}: {pokemon.attributes[key]}\n")
for move in pokemon.moves:
out_party.write(f"- {move}\n")
trainer = None
elif is_blank.search(line) or is_trainer_skip.search(line):
pass
else:
raise Exception(f"could not parse '{line.strip()}'")
except Exception as e:
print(f"{in_path}:{line_no}: {e}")
if __name__ == '__main__':
try:
[argv0, trainers_in_path, parties_in_path, out_path] = sys.argv
except:
print(f"usage: python3 {sys.argv[0]} <trainers.h> <trainer_parties.h> <out>")
else:
with open(trainers_in_path, "r") as trainers_in_h, open(parties_in_path, "r") as parties_in_h, open(out_path, "w") as out_party:
parties = convert_parties(parties_in_path, parties_in_h)
trainers = convert_trainers(trainers_in_path, trainers_in_h, parties, out_party)
# If you have extra members in 'TrainerMon':
# 1. Add a regular expression which matches that member (e.g. 'shadow_definition').
# 2. Match that regular expression in 'convert' and write into 'attributes' with the key that 'trainerproc' should parse.
# 3. Add the key used in 'attributes' to 'pokemon_attribute_order'.
# 4. Update 'trainerproc.c' to parse the new key.
import re
import sys
is_blank = re.compile(r'^[ \t]*(//.*)?$')
begin_party_definition = re.compile(r'struct TrainerMon (\w+)\[\] =')
end_party_definition = re.compile(r'^};')
begin_pokemon_definition = re.compile(r'^ { *$')
end_pokemon_definition = re.compile(r'^ },? *$')
level_definition = re.compile(r'\.lvl = (\d+)')
species_definition = re.compile(r'\.species = SPECIES_(\w+)')
gender_definition = re.compile(r'\.gender = TRAINER_MON_(\w+)')
nickname_definition = re.compile(r'\.nickname = COMPOUND_STRING\("([^"]+)"\)')
item_definition = re.compile(r'\.heldItem = ITEM_(\w+)')
ball_definition = re.compile(r'\.ball = ITEM_(\w+)')
ability_definition = re.compile(r'\.ability = ABILITY_(\w+)')
friendship_definition = re.compile(r'\.friendship = (\d+)')
shiny_definition = re.compile(r'\.isShiny = (\w+)')
ivs_definition = re.compile(r'\.iv = TRAINER_PARTY_IVS\(([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+)\)')
evs_definition = re.compile(r'\.ev = TRAINER_PARTY_EVS\(([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+)\)')
moves_definition = re.compile(r'\.moves = \{([^}]+)\}')
move_definition = re.compile(r'MOVE_(\w+)')
nature_definition = re.compile(r'\.nature = NATURE_(\w+)')
# NOTE: These are just for aesthetics, the Pokemon would still compile
# without them.
species_replacements = {
"CHIEN_PAO": "Chien-Pao",
"CHI_YU": "Chi-Yu",
"HAKAMO_O": "Hakamo-o",
"HO_OH": "Ho-Oh",
"JANGMO_O": "Jangmo-o",
"KOMMO_O": "Kommo-o",
"PORYGON_Z": "Porygon-Z",
"ROTOM_": "Rotom-",
"TING_LU": "Ting-Lu",
"TYPE_NULL": "Type: Null",
"WO_CHIEN": "Wo-Chien",
"_ALOLAN": "-Alola",
"_AQUA_BREED": "-Aqua",
"_BATTLE_BOND": "-Bond",
"_BLAZE_BREED": "-Blaze",
"_CAP": "",
"_CLOAK": "",
"_COMBAT_BREED": "-Combat",
"_CROWED_SHIELD": "-Crowned",
"_CROWED_SWORD": "-Crowned",
"_DRIVE": "",
"_EAST_SEA": "-East",
"_FAMILY_OF_FOUR": "-Four",
"_FEMALE": "-F",
"_FLOWER": "",
"_GALARIAN": "-Galar",
"_GIGANTAMAX": "-Gmax",
"_HISUIAN": "-Hisui",
"_ICE_RIDER": "-Ice",
"_NOICE_FACE": "-Noice",
"_ORIGIN": "-Origin",
"_ORIGINAL_COLOR": "-Original",
"_PALDEAN": "-Paldea",
"_PLUMAGE": "",
"_POKE_BALL": "-Pokeball",
"_SHADOW_RIDER": "-Shadow",
"_STRIKE_STYLE": "-Style",
"_TOTEM": "-Totem",
"_ZEN_MODE": "-Zen",
}
pokemon_attribute_order = ['Level', 'Ability', 'IVs', 'EVs', 'Happiness', 'Shiny', 'Ball']
class Pokemon:
def __init__(self):
self.nickname = None
self.species = None
self.gender = None
self.item = None
self.nature = None
self.attributes = {}
self.attributes['IVs'] = "0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe"
self.moves = []
def convert_parties(in_path, in_h):
party_identifier = None
party = None
pokemon = None
parties = {}
for line_no, line in enumerate(in_h, 1):
try:
line = line[:-1]
if m := begin_party_definition.search(line):
if party:
raise Exception(f"unexpected start of party")
[identifier] = m.groups()
party_identifier = identifier
party = []
elif end_party_definition.search(line):
if not party:
raise Exception(f"unexpected end of party")
parties[party_identifier] = party
party = None
elif begin_pokemon_definition.search(line):
if pokemon:
raise Exception(f"unexpected start of Pokemon")
pokemon = Pokemon()
elif end_pokemon_definition.search(line):
if not pokemon:
raise Exception(f"unexpected end of Pokemon")
else:
party.append(pokemon)
pokemon = None
elif m := level_definition.search(line):
[level] = m.groups()
pokemon.attributes['Level'] = level
elif m := species_definition.search(line):
[species_] = m.groups()
for match, replacement in species_replacements.items():
species_ = species_.replace(match, replacement)
pokemon.species = species_.replace("_", " ").title()
elif m := gender_definition.search(line):
[gender_] = m.groups()
if gender_ == 'MALE':
pokemon.gender = 'M'
elif gender_ == 'FEMALE':
pokemon.gender = 'F'
else:
raise Exception(f"unknown gender: '{gender_}'")
elif m := nickname_definition.search(line):
[nickname] = m.groups()
pokemon.nickname = nickname
elif m := item_definition.search(line):
[item_] = m.groups()
pokemon.item = item_.replace("_", " ").title()
elif m := ball_definition.search(line):
[ball] = m.groups()
pokemon.attributes['Ball'] = ball.replace("_", " ").title()
elif m := ability_definition.search(line):
[ability] = m.groups()
pokemon.attributes['Ability'] = ability.replace("_", " ").title()
elif m := friendship_definition.search(line):
[friendship] = m.groups()
pokemon.attributes['Happiness'] = friendship
elif m := shiny_definition.search(line):
[shiny] = m.groups()
if shiny == 'TRUE':
pokemon.attributes['Shiny'] = 'Yes'
elif shiny == 'FALSE':
pokemon.attributes['Shiny'] = 'No'
else:
raise Exception(f"unknown isShiny: '{shiny}'")
elif m := ivs_definition.search(line):
[hp, attack, defense, speed, special_attack, special_defense] = [stat.strip() for stat in m.groups()]
stats = {"HP": hp, "Atk": attack, "Def": defense, "SpA": special_attack, "SpD": special_defense, "Spe": speed}
pokemon.attributes['IVs'] = ' / '.join(f"{value} {key}" for key, value in stats.items())
elif m := evs_definition.search(line):
[hp, attack, defense, speed, special_attack, special_defense] = [stat.strip() for stat in m.groups()]
stats = {"HP": hp, "Atk": attack, "Def": defense, "SpA": special_attack, "SpD": special_defense, "Spe": speed}
pokemon.attributes['EVs'] = ' / '.join(f"{value} {key}" for key, value in stats.items() if value != '0')
elif m := moves_definition.search(line):
[moves_] = m.groups()
pokemon.moves = [move.replace("_", " ").title() for move in move_definition.findall(moves_) if move != "NONE"]
elif m := nature_definition.search(line):
[nature_] = m.groups()
pokemon.nature = nature_.replace("_", " ").title()
elif is_blank.search(line):
pass
else:
raise Exception(f"could not parse '{line.strip()}'")
except Exception as e:
print(f"{in_path}:{line_no}: {e}")
return parties
is_trainer_skip = re.compile(r'(const struct Trainer gTrainers\[\] = \{)|(^ \{$)|(\.partySize =)|(\.party = NULL)|(\.mugshotEnabled = TRUE)|(\};)')
begin_trainer_definition = re.compile(r' \[(TRAINER_\w+)\] =')
end_trainer_definition = re.compile(r' }')
trainer_class_definition = re.compile(r'\.trainerClass = TRAINER_CLASS_(\w+)')
encounter_music_gender_definition = re.compile(r'\.encounterMusic_gender = (F_TRAINER_FEMALE \| )?TRAINER_ENCOUNTER_MUSIC_(\w+)')
trainer_pic_definition = re.compile(r'\.trainerPic = TRAINER_PIC_(\w+)')
trainer_name_definition = re.compile(r'\.trainerName = _\("([^"]*)"\)')
trainer_items_definition = re.compile(r'\.items = \{([^}]*)\}')
trainer_item_definition = re.compile(r'ITEM_(\w+)')
trainer_double_battle_definition = re.compile(r'\.doubleBattle = (\w+)')
trainer_ai_flags_definition = re.compile(r'\.aiFlags = (.*)')
trainer_ai_flag_definition = re.compile(r'AI_FLAG_(\w+)')
trainer_party_definition = re.compile(r'\.party = TRAINER_PARTY\((\w+)\)')
trainer_mugshot_definition = re.compile(r'\.mugshotColor = MUGSHOT_COLOR_(\w+)')
trainer_starting_status_definition = re.compile(r'\.startingStatus = STARTING_STATUS_(\w+)')
class_fixups = {
"Rs": "RS",
}
pic_fixups = {
"Rs": "RS",
}
class Trainer:
def __init__(self, id_):
self.id = id_
self.class_ = None
self.encounter_music = None
self.gender = None
self.pic = None
self.name = None
self.items = []
self.double_battle = None
self.ai_flags = None
self.mugshot = None
self.starting_status = None
self.party = None
def convert_trainers(in_path, in_h, parties, out_party):
newlines = 0
trainer = None
for line_no, line in enumerate(in_h, 1):
try:
line = line[:-1]
if m := begin_trainer_definition.search(line):
if trainer:
raise Exception(f"unexpected start of trainer")
[id_] = m.groups()
trainer = Trainer(id_)
elif m := trainer_class_definition.search(line):
[class_] = m.groups()
class_ = class_.replace("_", " ").title()
for match, replacement in class_fixups.items():
class_ = class_.replace(match, replacement)
trainer.class_ = class_
elif m := encounter_music_gender_definition.search(line):
[is_female, music] = m.groups()
trainer.gender = 'Female' if is_female else 'Male'
trainer.encounter_music = music.replace("_", " ").title()
elif m := trainer_pic_definition.search(line):
[pic] = m.groups()
pic = pic.replace("_", " ").title()
for match, replacement in pic_fixups.items():
pic = pic.replace(match, replacement)
trainer.pic = pic
elif m := trainer_name_definition.search(line):
[name] = m.groups()
trainer.name = name
elif m := trainer_items_definition.search(line):
[items] = m.groups()
trainer.items = " / ".join(item.replace("_", " ").title() for item in trainer_item_definition.findall(items) if item != "NONE")
elif m := trainer_double_battle_definition.search(line):
[double_battle] = m.groups()
if double_battle == 'TRUE':
trainer.double_battle = "Yes"
elif double_battle == 'FALSE':
trainer.double_battle = "No"
else:
raise Exception(f"unknown doubleBattle: '{double_battle}'")
elif m := trainer_ai_flags_definition.search(line):
[ai_flags] = m.groups()
trainer.ai_flags = " / ".join(ai_flag.replace("_", " ").title() for ai_flag in trainer_ai_flag_definition.findall(ai_flags))
elif m := trainer_mugshot_definition.search(line):
[color] = m.groups()
trainer.mugshot = color.title()
elif m := trainer_starting_status_definition.search(line):
[starting_status] = m.groups()
trainer.starting_status = starting_status.replace("_", " ").title()
elif m := trainer_party_definition.search(line):
[party] = m.groups()
trainer.party = parties[party]
elif end_trainer_definition.search(line):
if not trainer:
raise Exception(f"unexpected end of trainer")
while newlines > 0:
out_party.write(f"\n")
newlines -= 1
newlines = 1
out_party.write(f"=== {trainer.id} ===\n")
out_party.write(f"Name: {trainer.name}\n")
out_party.write(f"Class: {trainer.class_}\n")
out_party.write(f"Pic: {trainer.pic}\n")
out_party.write(f"Gender: {trainer.gender}\n")
out_party.write(f"Music: {trainer.encounter_music}\n")
if trainer.items:
out_party.write(f"Items: {trainer.items}\n")
out_party.write(f"Double Battle: {trainer.double_battle}\n")
if trainer.ai_flags:
out_party.write(f"AI: {trainer.ai_flags}\n")
if trainer.mugshot:
out_party.write(f"Mugshot: {trainer.mugshot}\n")
if trainer.starting_status:
out_party.write(f"Starting Status: {trainer.starting_status}\n")
if trainer.party:
for i, pokemon in enumerate(trainer.party):
out_party.write(f"\n")
if pokemon.nickname:
out_party.write(f"{pokemon.nickname} ({pokemon.species})")
else:
out_party.write(f"{pokemon.species}")
if pokemon.gender:
out_party.write(f" ({pokemon.gender})")
if pokemon.item and pokemon.item != 'None':
out_party.write(f" @ {pokemon.item}")
out_party.write(f"\n")
if pokemon.nature:
out_party.write(f"{pokemon.nature} Nature\n")
for key in pokemon_attribute_order:
if key in pokemon.attributes:
out_party.write(f"{key}: {pokemon.attributes[key]}\n")
for move in pokemon.moves:
out_party.write(f"- {move}\n")
trainer = None
elif is_blank.search(line) or is_trainer_skip.search(line):
pass
else:
raise Exception(f"could not parse '{line.strip()}'")
except Exception as e:
print(f"{in_path}:{line_no}: {e}")
if __name__ == '__main__':
try:
[argv0, trainers_in_path, parties_in_path, out_path] = sys.argv
except:
print(f"usage: python3 {sys.argv[0]} <trainers.h> <trainer_parties.h> <out>")
else:
with open(trainers_in_path, "r") as trainers_in_h, open(parties_in_path, "r") as parties_in_h, open(out_path, "w") as out_party:
parties = convert_parties(parties_in_path, parties_in_h)
trainers = convert_trainers(trainers_in_path, trainers_in_h, parties, out_party)

View File

@ -1,51 +1,51 @@
import re
import glob
eggMoveSpecies = []
exceptions = [ # the following exceptions are hardcoded to streamline the process. you may need to manually check what happens in case you have added forms that work similar to these below
["ShellosWestSea", "Shellos"],
["OricorioBaile", "Oricorio"]
]
# convert egg_moves.h to the new format
with open("src/data/pokemon/egg_moves.h", "r") as f:
data = f.read()
data = re.sub(r"#define(.|\n)*const u16 gEggMoves\[\] = {", "static const u16 sNoneEggMoveLearnset[] = {\n MOVE_UNAVAILABLE,\n};\n", data) # remove and replace header
data = re.sub(r"\n EGG_MOVES_TERMINATOR\n};\n\n", "", data) # remove footer
for mon in re.findall(r"egg_moves\((.*),", data):
monname = re.sub(r"_", " ", mon).title().replace(" ", "")
for x in exceptions:
if monname == x[0]:
monname = x[1]
# add it to the list for later
eggMoveSpecies.append(monname)
# regex the egg_moves.h file
data = re.sub(r" egg_moves\(" + mon + r",", "static const u16 s%sEggMoveLearnset[] = {" % monname, data)
data = re.sub(r"\),\n", ",\n MOVE_UNAVAILABLE,\n};\n", data) # add terminator to each old macro
data = re.sub(r" MOVE_", " MOVE_", data) # fix indentation
with open("src/data/pokemon/egg_moves.h", "w") as f:
f.write(data)
# update gBaseStats
for file in glob.glob('./src/data/pokemon/species_info/gen_*_families.h'):
with open(file, "r") as f:
data = f.read()
# go through all Pokemon with teachable learnsets that are also in the list, then assign egg moves to them
for mon in eggMoveSpecies:
# first do the plain replacements outside of macros
data = re.sub(r"\.teachableLearnset = s" + mon + r"sTeachableLearnset,\n", ".teachableLearnset = s%sTeachableLearnset,\n .eggMoveLearnset = s%sEggMoveLearnset,\n" % (mon, mon), data)
# check for macros (since they require \ at the end of the line and do those manually)
macrocheck = re.findall(r"\.teachableLearnset = s" + mon + r"TeachableLearnset,( *)\\\\", data)
if len(macrocheck) > 0:
data = re.sub(r"\.teachableLearnset = s" + mon + r"TeachableLearnset," + macrocheck[0] + r"\\\\", ".teachableLearnset = s%sTeachableLearnset,%s\\\\\n .eggMoveLearnset = s%sEggMoveLearnset,%s\\\\" % (mon, macrocheck[0], mon, " " * (len(macrocheck[0]) + 4)), data)
with open(file, "w") as f:
f.write(data)
import re
import glob
eggMoveSpecies = []
exceptions = [ # the following exceptions are hardcoded to streamline the process. you may need to manually check what happens in case you have added forms that work similar to these below
["ShellosWestSea", "Shellos"],
["OricorioBaile", "Oricorio"]
]
# convert egg_moves.h to the new format
with open("src/data/pokemon/egg_moves.h", "r") as f:
data = f.read()
data = re.sub(r"#define(.|\n)*const u16 gEggMoves\[\] = {", "static const u16 sNoneEggMoveLearnset[] = {\n MOVE_UNAVAILABLE,\n};\n", data) # remove and replace header
data = re.sub(r"\n EGG_MOVES_TERMINATOR\n};\n\n", "", data) # remove footer
for mon in re.findall(r"egg_moves\((.*),", data):
monname = re.sub(r"_", " ", mon).title().replace(" ", "")
for x in exceptions:
if monname == x[0]:
monname = x[1]
# add it to the list for later
eggMoveSpecies.append(monname)
# regex the egg_moves.h file
data = re.sub(r" egg_moves\(" + mon + r",", "static const u16 s%sEggMoveLearnset[] = {" % monname, data)
data = re.sub(r"\),\n", ",\n MOVE_UNAVAILABLE,\n};\n", data) # add terminator to each old macro
data = re.sub(r" MOVE_", " MOVE_", data) # fix indentation
with open("src/data/pokemon/egg_moves.h", "w") as f:
f.write(data)
# update gBaseStats
for file in glob.glob('./src/data/pokemon/species_info/gen_*_families.h'):
with open(file, "r") as f:
data = f.read()
# go through all Pokemon with teachable learnsets that are also in the list, then assign egg moves to them
for mon in eggMoveSpecies:
# first do the plain replacements outside of macros
data = re.sub(r"\.teachableLearnset = s" + mon + r"sTeachableLearnset,\n", ".teachableLearnset = s%sTeachableLearnset,\n .eggMoveLearnset = s%sEggMoveLearnset,\n" % (mon, mon), data)
# check for macros (since they require \ at the end of the line and do those manually)
macrocheck = re.findall(r"\.teachableLearnset = s" + mon + r"TeachableLearnset,( *)\\\\", data)
if len(macrocheck) > 0:
data = re.sub(r"\.teachableLearnset = s" + mon + r"TeachableLearnset," + macrocheck[0] + r"\\\\", ".teachableLearnset = s%sTeachableLearnset,%s\\\\\n .eggMoveLearnset = s%sEggMoveLearnset,%s\\\\" % (mon, macrocheck[0], mon, " " * (len(macrocheck[0]) + 4)), data)
with open(file, "w") as f:
f.write(data)

View File

@ -1,15 +1,15 @@
# 原始字符串
text = "全副武装的样子。\n即使是极巨化宝可梦的\n攻击也能轻易抵挡。"
# 按照\n分割
split_text = text.split('\n')
# 格式化输出为需要的三段,并处理最后一段不加\\n
formatted_text = [f'"{part}\\n"' for part in split_text[:-1]] # 所有除最后一段外加\\n
formatted_text.append(f'"{split_text[-1]}"') # 最后一段不加\\n
# 拼接成最终的描述
description = '\n'.join(formatted_text)
# 输出结果
print(description)
# 原始字符串
text = "全副武装的样子。\n即使是极巨化宝可梦的\n攻击也能轻易抵挡。"
# 按照\n分割
split_text = text.split('\n')
# 格式化输出为需要的三段,并处理最后一段不加\\n
formatted_text = [f'"{part}\\n"' for part in split_text[:-1]] # 所有除最后一段外加\\n
formatted_text.append(f'"{split_text[-1]}"') # 最后一段不加\\n
# 拼接成最终的描述
description = '\n'.join(formatted_text)
# 输出结果
print(description)

View File

@ -1,79 +1,79 @@
import os
import re
import pandas as pd
import os
current_folder = os.path.dirname(os.path.abspath(__file__))
def convert_description_to_multiline(description):
split_text = description.split('\\n')
# 格式化输出为需要的三段,并处理最后一段不加\\n
formatted_text = [f'"{part}\\\\n"' for part in split_text[:-1]] # 所有除最后一段外加\\n
formatted_text.append(f'"{split_text[-1]}"') # 最后一段不加\\n
# 拼接成最终的描述
description = '\n\\t\\t\\t'.join(formatted_text)
final=r'.description = COMPOUND_STRING(\n\t\t\t' + description+ '),'
return final
def query_pokemon_info(name, df):
try:
result = df.loc[name]
return {
'speciesName': result['speciesName'],
'categoryName': result['categoryName'],
'description': result['description']
}
except KeyError:
return None
def replace_species_info(content, df):
pattern = r"\[SPECIES_(\w+)\]\s*=\s*\{.*?\n\s*\},?"
matches = list(re.finditer(pattern, content, re.DOTALL))
for match in matches:
species = match.group(1)
original_block = match.group(0)
info = query_pokemon_info("SPECIES_"+species, df)
if not info:
log(f"❌ 未找到 {'SPECIES_'+species},跳过")
continue
block = original_block
# 替换 .speciesName
block = re.sub(r'\.speciesName\s*=\s*_\(.*?\),', f'.speciesName = _("{info["speciesName"]}"),', block)
# 替换 .categoryName
block = re.sub(r'\.categoryName\s*=\s*_\(.*?\),', f'.categoryName = _("{info["categoryName"]}"),', block)
# 替换 .description
block = re.sub(r'\.description\s*=\s*COMPOUND_STRING\((?:.|\n)*?\),', convert_description_to_multiline(info["description"]), block)
content = content.replace(original_block, block)
return content
def log(message):
with open(current_folder+"\log.txt", "a", encoding="utf-8") as log_file:
log_file.write(message + "\n")
print(message)
if __name__ == "__main__":
work_folder = current_folder +"\..\src\data\pokemon\species_info"
df = pd.read_excel(current_folder +r'\src\图鉴.xlsx')
df.set_index('name', inplace=True)
for filename in os.listdir(work_folder):
if re.match(r'^gen_\d+_families\.h$', filename):
file_path = os.path.join(work_folder, filename)
log(f"✅ 处理文件:{file_path}")
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
new_content = replace_species_info(content, df)
with open(file_path, "w", encoding="utf-8") as f:
f.write(new_content)
import os
import re
import pandas as pd
import os
current_folder = os.path.dirname(os.path.abspath(__file__))
def convert_description_to_multiline(description):
split_text = description.split('\\n')
# 格式化输出为需要的三段,并处理最后一段不加\\n
formatted_text = [f'"{part}\\\\n"' for part in split_text[:-1]] # 所有除最后一段外加\\n
formatted_text.append(f'"{split_text[-1]}"') # 最后一段不加\\n
# 拼接成最终的描述
description = '\n\\t\\t\\t'.join(formatted_text)
final=r'.description = COMPOUND_STRING(\n\t\t\t' + description+ '),'
return final
def query_pokemon_info(name, df):
try:
result = df.loc[name]
return {
'speciesName': result['speciesName'],
'categoryName': result['categoryName'],
'description': result['description']
}
except KeyError:
return None
def replace_species_info(content, df):
pattern = r"\[SPECIES_(\w+)\]\s*=\s*\{.*?\n\s*\},?"
matches = list(re.finditer(pattern, content, re.DOTALL))
for match in matches:
species = match.group(1)
original_block = match.group(0)
info = query_pokemon_info("SPECIES_"+species, df)
if not info:
log(f"❌ 未找到 {'SPECIES_'+species},跳过")
continue
block = original_block
# 替换 .speciesName
block = re.sub(r'\.speciesName\s*=\s*_\(.*?\),', f'.speciesName = _("{info["speciesName"]}"),', block)
# 替换 .categoryName
block = re.sub(r'\.categoryName\s*=\s*_\(.*?\),', f'.categoryName = _("{info["categoryName"]}"),', block)
# 替换 .description
block = re.sub(r'\.description\s*=\s*COMPOUND_STRING\((?:.|\n)*?\),', convert_description_to_multiline(info["description"]), block)
content = content.replace(original_block, block)
return content
def log(message):
with open(current_folder+"\log.txt", "a", encoding="utf-8") as log_file:
log_file.write(message + "\n")
print(message)
if __name__ == "__main__":
work_folder = current_folder +"\..\src\data\pokemon\species_info"
df = pd.read_excel(current_folder +r'\src\图鉴.xlsx')
df.set_index('name', inplace=True)
for filename in os.listdir(work_folder):
if re.match(r'^gen_\d+_families\.h$', filename):
file_path = os.path.join(work_folder, filename)
log(f"✅ 处理文件:{file_path}")
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
new_content = replace_species_info(content, df)
with open(file_path, "w", encoding="utf-8") as f:
f.write(new_content)

View File

@ -1,80 +1,80 @@
import os
import re
import pandas as pd
import os
current_folder = os.path.dirname(os.path.abspath(__file__))
def convert_description_to_multiline(description):
if not isinstance(description, str):
return None
# 替换中文字符为英文字符
split_text = description.split('\\n')
# 格式化输出为需要的三段,并处理最后一段不加\\n
formatted_text = [f'"{part}\\\\n"' for part in split_text[:-1]] # 所有除最后一段外加\\n
formatted_text.append(f'"{split_text[-1]}"') # 最后一段不加\\n
# 拼接成最终的描述
description = '\n\\t\\t\\t'.join(formatted_text)
final=r'.description = COMPOUND_STRING(\n\t\t\t' + description+ '),'
return final
def query_pokemon_info(name, df):
try:
result = df.loc[name]
return {
'中文名': result['中文名'],
'单独技能效果说明': result['单独技能效果说明'],
# 'description': result['description']
}
except KeyError:
return None
def replace_move_info(content, df):
pattern = r"\[MOVE_(\w+)\]\s*=\s*\{.*?\n\s*\},?"
matches = list(re.finditer(pattern, content, re.DOTALL))
for match in matches:
move = match.group(1)
original_block = match.group(0)
info = query_pokemon_info("[MOVE_"+move+"]", df)
if not info:
log(f"❌ 未找到 {'MOVE_'+move},跳过")
continue
block = original_block
# 替换 .moveName
block = re.sub(r'\.name\s*=\s*COMPOUND_STRING\(.*?\),', f'.name = COMPOUND_STRING("{info["中文名"]}"),', block)
# block = re.sub(r'\.categoryName\s*=\s*_\(.*?\),', f'.categoryName = _("{info["categoryName"]}"),', block)
try:
block = re.sub(r'\.description\s*=\s*COMPOUND_STRING\((?:.|\n)*?\),\s+#endif', convert_description_to_multiline(info["单独技能效果说明"]), block)
block = re.sub(r'\.description\s*=\s*COMPOUND_STRING\((?:.|\n)*?\),', convert_description_to_multiline(info["单独技能效果说明"]), block)
except Exception as e:
print(f"Error: {e}")
log(f"{'MOVE_'+move} 没有单独技能效果说明,跳过")
content = content.replace(original_block, block)
return content
def log(message):
with open(current_folder+"\log.txt", "a", encoding="utf-8") as log_file:
log_file.write(message + "\n")
print(message)
if __name__ == "__main__":
work_file = current_folder +"\..\src\data\moves_info.h"
df = pd.read_excel(current_folder +r'\src\技能.xlsx')
df.set_index('技能', inplace=True)
with open(work_file, "r", encoding="utf-8") as f:
content = f.read()
new_content = replace_move_info(content, df)
with open(work_file, "w", encoding="utf-8") as f:
f.write(new_content)
import os
import re
import pandas as pd
import os
current_folder = os.path.dirname(os.path.abspath(__file__))
def convert_description_to_multiline(description):
if not isinstance(description, str):
return None
# 替换中文字符为英文字符
split_text = description.split('\\n')
# 格式化输出为需要的三段,并处理最后一段不加\\n
formatted_text = [f'"{part}\\\\n"' for part in split_text[:-1]] # 所有除最后一段外加\\n
formatted_text.append(f'"{split_text[-1]}"') # 最后一段不加\\n
# 拼接成最终的描述
description = '\n\\t\\t\\t'.join(formatted_text)
final=r'.description = COMPOUND_STRING(\n\t\t\t' + description+ '),'
return final
def query_pokemon_info(name, df):
try:
result = df.loc[name]
return {
'中文名': result['中文名'],
'单独技能效果说明': result['单独技能效果说明'],
# 'description': result['description']
}
except KeyError:
return None
def replace_move_info(content, df):
pattern = r"\[MOVE_(\w+)\]\s*=\s*\{.*?\n\s*\},?"
matches = list(re.finditer(pattern, content, re.DOTALL))
for match in matches:
move = match.group(1)
original_block = match.group(0)
info = query_pokemon_info("[MOVE_"+move+"]", df)
if not info:
log(f"❌ 未找到 {'MOVE_'+move},跳过")
continue
block = original_block
# 替换 .moveName
block = re.sub(r'\.name\s*=\s*COMPOUND_STRING\(.*?\),', f'.name = COMPOUND_STRING("{info["中文名"]}"),', block)
# block = re.sub(r'\.categoryName\s*=\s*_\(.*?\),', f'.categoryName = _("{info["categoryName"]}"),', block)
try:
block = re.sub(r'\.description\s*=\s*COMPOUND_STRING\((?:.|\n)*?\),\s+#endif', convert_description_to_multiline(info["单独技能效果说明"]), block)
block = re.sub(r'\.description\s*=\s*COMPOUND_STRING\((?:.|\n)*?\),', convert_description_to_multiline(info["单独技能效果说明"]), block)
except Exception as e:
print(f"Error: {e}")
log(f"{'MOVE_'+move} 没有单独技能效果说明,跳过")
content = content.replace(original_block, block)
return content
def log(message):
with open(current_folder+"\log.txt", "a", encoding="utf-8") as log_file:
log_file.write(message + "\n")
print(message)
if __name__ == "__main__":
work_file = current_folder +"\..\src\data\moves_info.h"
df = pd.read_excel(current_folder +r'\src\技能.xlsx')
df.set_index('技能', inplace=True)
with open(work_file, "r", encoding="utf-8") as f:
content = f.read()
new_content = replace_move_info(content, df)
with open(work_file, "w", encoding="utf-8") as f:
f.write(new_content)

View File

@ -1,420 +1,420 @@
mus_abandoned_ship.mid: -E -R50 -G030 -V080
mus_abnormal_weather.mid: -E -R50 -G089 -V080
mus_aqua_magma_hideout.mid: -E -R50 -G076 -V084
mus_awaken_legend.mid: -E -R50 -G012 -V090 -P5
mus_b_arena.mid: -E -R50 -G104 -V090
mus_b_dome_lobby.mid: -E -R50 -G111 -V056
mus_b_dome.mid: -E -R50 -G111 -V090
mus_b_factory.mid: -E -R50 -G113 -V100
mus_b_frontier.mid: -E -R50 -G103 -V094
mus_b_palace.mid: -E -R50 -G108 -V105
mus_b_pike.mid: -E -R50 -G112 -V092
mus_b_pyramid_top.mid: -E -R50 -G107 -V077
mus_b_pyramid.mid: -E -R50 -G106 -V079
mus_b_tower_rs.mid: -E -R50 -G035 -V080
mus_b_tower.mid: -E -R50 -G110 -V100
mus_birch_lab.mid: -E -R50 -G033 -V080
mus_c_comm_center.mid: -E -R50 -V080
mus_c_vs_legend_beast.mid: -E -R50 -V080
mus_cable_car.mid: -E -R50 -G071 -V078
mus_caught.mid: -E -R50 -G025 -V080
mus_cave_of_origin.mid: -E -R50 -G037 -V080
mus_contest_lobby.mid: -E -R50 -G098 -V060
mus_contest_results.mid: -E -R50 -G092 -V080
mus_contest_winner.mid: -E -R50 -G085 -V100
mus_contest.mid: -E -R50 -G086 -V088
mus_credits.mid: -E -R50 -G101 -V100
mus_cycling.mid: -E -R50 -G049 -V083
mus_dewford.mid: -E -R50 -G073 -V078
mus_dummy.mid: -E -R40
mus_encounter_aqua.mid: -E -R50 -G065 -V086
mus_encounter_brendan.mid: -E -R50 -G067 -V078
mus_encounter_champion.mid: -E -R50 -G100 -V076
mus_encounter_cool.mid: -E -R50 -G063 -V086
mus_encounter_elite_four.mid: -E -R50 -G096 -V078
mus_encounter_female.mid: -E -R50 -G053 -V072
mus_encounter_girl.mid: -E -R50 -G027 -V080
mus_encounter_hiker.mid: -E -R50 -G097 -V076
mus_encounter_intense.mid: -E -R50 -G062 -V078
mus_encounter_interviewer.mid: -E -R50 -G099 -V062
mus_encounter_magma.mid: -E -R50 -G087 -V072
mus_encounter_male.mid: -E -R50 -G028 -V080
mus_encounter_may.mid: -E -R50 -G061 -V078
mus_encounter_rich.mid: -E -R50 -G043 -V094
mus_encounter_suspicious.mid: -E -R50 -G069 -V078
mus_encounter_swimmer.mid: -E -R50 -G036 -V080
mus_encounter_twins.mid: -E -R50 -G095 -V075
mus_end.mid: -E -R50 -G102 -V036
mus_ever_grande.mid: -E -R50 -G068 -V086
mus_evolution_intro.mid: -E -R50 -G026 -V080
mus_evolution.mid: -E -R50 -G026 -V080
mus_evolved.mid: -E -R50 -G012 -V090 -P5
mus_fallarbor.mid: -E -R50 -G083 -V100
mus_follow_me.mid: -E -R50 -G066 -V074
mus_fortree.mid: -E -R50 -G032 -V080
mus_game_corner.mid: -E -R50 -G072 -V072
mus_gsc_pewter.mid: -E -R50 -V080
mus_gsc_route38.mid: -E -R50 -V080
mus_gym.mid: -E -R50 -G013 -V080
mus_hall_of_fame_room.mid: -E -R50 -G093 -V080
mus_hall_of_fame.mid: -E -R50 -G082 -V078
mus_heal.mid: -E -R50 -G012 -V090 -P5
mus_help.mid: -E -R50 -G056 -V078
mus_intro_battle.mid: -E -R50 -G088 -V088
mus_intro.mid: -E -R50 -G060 -V090
mus_level_up.mid: -E -R50 -G012 -V090 -P5
mus_lilycove_museum.mid: -E -R50 -G020 -V080
mus_lilycove.mid: -E -R50 -G054 -V085
mus_link_contest_p1.mid: -E -R50 -G039 -V079
mus_link_contest_p2.mid: -E -R50 -G040 -V090
mus_link_contest_p3.mid: -E -R50 -G041 -V075
mus_link_contest_p4.mid: -E -R50 -G042 -V090
mus_littleroot_test.mid: -E -R50 -G034 -V099
mus_littleroot.mid: -E -R50 -G051 -V100
mus_move_deleted.mid: -E -R50 -G012 -V090 -P5
mus_mt_chimney.mid: -E -R50 -G052 -V078
mus_mt_pyre_exterior.mid: -E -R50 -G080 -V080
mus_mt_pyre.mid: -E -R50 -G078 -V088
mus_obtain_b_points.mid: -E -R50 -G103 -V090 -P5
mus_obtain_badge.mid: -E -R50 -G012 -V090 -P5
mus_obtain_berry.mid: -E -R50 -G012 -V090 -P5
mus_obtain_item.mid: -E -R50 -G012 -V090 -P5
mus_obtain_symbol.mid: -E -R50 -G103 -V100 -P5
mus_obtain_tmhm.mid: -E -R50 -G012 -V090 -P5
mus_oceanic_museum.mid: -E -R50 -G023 -V080
mus_oldale.mid: -E -R50 -G019 -V080
mus_petalburg_woods.mid: -E -R50 -G018 -V080
mus_petalburg.mid: -E -R50 -G015 -V080
mus_poke_center.mid: -E -R50 -G046 -V092
mus_poke_mart.mid: -E -R50 -G050 -V085
mus_rayquaza_appears.mid: -E -R50 -G109 -V090
mus_register_match_call.mid: -E -R50 -G105 -V090 -P5
mus_rg_berry_pick.mid: -E -R50 -G132 -V090
mus_rg_caught_intro.mid: -E -R50 -G179 -V094 -P5
mus_rg_caught.mid: -E -R50 -G170 -V100
mus_rg_celadon.mid: -E -R50 -G168 -V070
mus_rg_cinnabar.mid: -E -R50 -G138 -V090
mus_rg_credits.mid: -E -R50 -G149 -V090
mus_rg_cycling.mid: -E -R50 -G141 -V090
mus_rg_dex_rating.mid: -E -R50 -G175 -V070 -P5
mus_rg_encounter_boy.mid: -E -R50 -G144 -V090
mus_rg_encounter_deoxys.mid: -E -R50 -G184 -V079
mus_rg_encounter_girl.mid: -E -R50 -G143 -V051
mus_rg_encounter_gym_leader: -E -R50 -G144 -V090
mus_rg_encounter_rival.mid: -E -R50 -G174 -V079
mus_rg_encounter_rocket.mid: -E -R50 -G142 -V096
mus_rg_follow_me.mid: -E -R50 -G131 -V068
mus_rg_fuchsia.mid: -E -R50 -G167 -V090
mus_rg_game_corner.mid: -E -R50 -G132 -V090
mus_rg_game_freak.mid: -E -R50 -G181 -V075
mus_rg_gym.mid: -E -R50 -G134 -V090
mus_rg_hall_of_fame.mid: -E -R50 -G145 -V079
mus_rg_heal.mid: -E -R50 -G140 -V090
mus_rg_intro_fight.mid: -E -R50 -G136 -V090
mus_rg_jigglypuff.mid: -E -R50 -G135 -V068 -P5
mus_rg_lavender.mid: -E -R50 -G139 -V090
mus_rg_mt_moon.mid: -E -R50 -G147 -V090
mus_rg_mystery_gift.mid: -E -R50 -G183 -V100
mus_rg_net_center.mid: -E -R50 -G162 -V096
mus_rg_new_game_exit.mid: -E -R50 -G182 -V088
mus_rg_new_game_instruct.mid: -E -R50 -G182 -V085
mus_rg_new_game_intro.mid: -E -R50 -G182 -V088
mus_rg_oak_lab.mid: -E -R50 -G160 -V075
mus_rg_oak.mid: -E -R50 -G161 -V086
mus_rg_obtain_key_item.mid: -E -R50 -G178 -V077 -P5
mus_rg_pallet.mid: -E -R50 -G159 -V100
mus_rg_pewter.mid: -E -R50 -G173 -V084
mus_rg_photo.mid: -E -R50 -G180 -V100 -P5
mus_rg_poke_center.mid: -E -R50 -G162 -V096
mus_rg_poke_flute.mid: -E -R50 -G165 -V048 -P5
mus_rg_poke_jump.mid: -E -R50 -G132 -V090
mus_rg_poke_mansion.mid: -E -R50 -G148 -V090
mus_rg_poke_tower.mid: -E -R50 -G165 -V090
mus_rg_rival_exit.mid: -E -R50 -G174 -V079
mus_rg_rocket_hideout.mid: -E -R50 -G133 -V090
mus_rg_route1.mid: -E -R50 -G150 -V079
mus_rg_route3.mid: -E -R50 -G152 -V083
mus_rg_route11.mid: -E -R50 -G153 -V090
mus_rg_route24.mid: -E -R50 -G151 -V086
mus_rg_sevii_45.mid: -E -R50 -G188 -V084
mus_rg_sevii_67.mid: -E -R50 -G189 -V084
mus_rg_sevii_123.mid: -E -R50 -G173 -V084
mus_rg_sevii_cave.mid: -E -R50 -G147 -V090
mus_rg_sevii_dungeon.mid: -E -R50 -G146 -V090
mus_rg_sevii_route.mid: -E -R50 -G187 -V080
mus_rg_silph.mid: -E -R50 -G166 -V076
mus_rg_slow_pallet.mid: -E -R50 -G159 -V092
mus_rg_ss_anne.mid: -E -R50 -G163 -V090
mus_rg_surf.mid: -E -R50 -G164 -V071
mus_rg_teachy_tv_menu.mid: -E -R50 -G186 -V059
mus_rg_teachy_tv_show.mid: -E -R50 -G131 -V068
mus_rg_title.mid: -E -R50 -G137 -V090
mus_rg_trainer_tower.mid: -E -R50 -G134 -V090
mus_rg_union_room.mid: -E -R50 -G132 -V090
mus_rg_vermillion.mid: -E -R50 -G172 -V090
mus_rg_victory_gym_leader.mid: -E -R50 -G171 -V090
mus_rg_victory_road.mid: -E -R50 -G154 -V090
mus_rg_victory_trainer.mid: -E -R50 -G169 -V089
mus_rg_victory_wild.mid: -E -R50 -G170 -V090
mus_rg_viridian_forest.mid: -E -R50 -G146 -V090
mus_rg_vs_champion.mid: -E -R50 -G158 -V090
mus_rg_vs_deoxys.mid: -E -R50 -G185 -V080
mus_rg_vs_gym_leader.mid: -E -R50 -G155 -V090
mus_rg_vs_legend.mid: -E -R50 -G157 -V090
mus_rg_vs_mewtwo.mid: -E -R50 -G157 -V090
mus_rg_vs_trainer.mid: -E -R50 -G156 -V090
mus_rg_vs_wild.mid: -E -R50 -G157 -V090
mus_roulette.mid: -E -R50 -G038 -V080
mus_route101.mid: -E -R50 -G011 -V080
mus_route104.mid: -E -R50 -G047 -V097
mus_route110.mid: -E -R50 -G010 -V080
mus_route111.mid: -E -R50 -G055 -V076
mus_route113.mid: -E -R50 -G064 -V084
mus_route119.mid: -E -R50 -G048 -V096
mus_route120.mid: -E -R50 -G014 -V080
mus_route122.mid: -E -R50 -G021 -V080
mus_rustboro.mid: -E -R50 -G045 -V085
mus_safari_zone.mid: -E -R50 -G074 -V082
mus_sailing.mid: -E -R50 -G077 -V086
mus_school.mid: -E -R50 -G081 -V100
mus_sealed_chamber.mid: -E -R50 -G084 -V100
mus_slateport.mid: -E -R50 -G079 -V070
mus_slots_jackpot.mid: -E -R50 -G012 -V090 -P5
mus_slots_win.mid: -E -R50 -G012 -V090 -P5
mus_sootopolis.mid: -E -R50 -G091 -V062
mus_surf.mid: -E -R50 -G017 -V080
mus_title.mid: -E -R50 -G059 -V090
mus_too_bad.mid: -E -R50 -G012 -V090 -P5
mus_trick_house.mid: -E -R50 -G094 -V070
mus_underwater.mid: -E -R50 -G057 -V094
mus_verdanturf.mid: -E -R50 -G044 -V090
mus_victory_aqua_magma.mid: -E -R50 -G070 -V088
mus_victory_gym_leader.mid: -E -R50 -G024 -V080
mus_victory_league.mid: -E -R50 -G029 -V080
mus_victory_road.mid: -E -R50 -G075 -V076
mus_victory_trainer.mid: -E -R50 -G058 -V091
mus_victory_wild.mid: -E -R50 -G025 -V080
mus_vs_aqua_magma_leader.mid: -E -R50 -G126 -V080 -P1
mus_vs_aqua_magma.mid: -E -R50 -G118 -V080 -P1
mus_vs_champion.mid: -E -R50 -G121 -V080 -P1
mus_vs_elite_four.mid: -E -R50 -G125 -V080 -P1
mus_vs_frontier_brain.mid: -E -R50 -G115 -V090 -P1
mus_vs_gym_leader.mid: -E -R50 -G120 -V080 -P1
mus_vs_kyogre_groudon.mid: -E -R50 -G123 -V080 -P1
mus_vs_mew.mid: -E -R50 -G116 -V090
mus_vs_rayquaza.mid: -E -R50 -G114 -V080 -P1
mus_vs_regi.mid: -E -R50 -G122 -V080 -P1
mus_vs_rival.mid: -E -R50 -G124 -V080 -P1
mus_vs_trainer.mid: -E -R50 -G119 -V080 -P1
mus_vs_wild.mid: -E -R50 -G117 -V080 -P1
mus_weather_groudon.mid: -E -R50 -G090 -V050
ph_choice_blend.mid: -E -G130 -P4
ph_choice_held.mid: -E -G130 -P4
ph_choice_solo.mid: -E -G130 -P4
ph_cloth_blend.mid: -E -G130 -P4
ph_cloth_held.mid: -E -G130 -P4
ph_cloth_solo.mid: -E -G130 -P4
ph_cure_blend.mid: -E -G130 -P4
ph_cure_held.mid: -E -G130 -P4
ph_cure_solo.mid: -E -G130 -P4
ph_dress_blend.mid: -E -G130 -P4
ph_dress_held.mid: -E -G130 -P4
ph_dress_solo.mid: -E -G130 -P4
ph_face_blend.mid: -E -G130 -P4
ph_face_held.mid: -E -G130 -P4
ph_face_solo.mid: -E -G130 -P4
ph_fleece_blend.mid: -E -G130 -P4
ph_fleece_held.mid: -E -G130 -P4
ph_fleece_solo.mid: -E -G130 -P4
ph_foot_blend.mid: -E -G130 -P4
ph_foot_held.mid: -E -G130 -P4
ph_foot_solo.mid: -E -G130 -P4
ph_goat_blend.mid: -E -G130 -P4
ph_goat_held.mid: -E -G130 -P4
ph_goat_solo.mid: -E -G130 -P4
ph_goose_blend.mid: -E -G130 -P4
ph_goose_held.mid: -E -G130 -P4
ph_goose_solo.mid: -E -G130 -P4
ph_kit_blend.mid: -E -G130 -P4
ph_kit_held.mid: -E -G130 -P4
ph_kit_solo.mid: -E -G130 -P4
ph_lot_blend.mid: -E -G130 -P4
ph_lot_held.mid: -E -G130 -P4
ph_lot_solo.mid: -E -G130 -P4
ph_mouth_blend.mid: -E -G130 -P4
ph_mouth_held.mid: -E -G130 -P4
ph_mouth_solo.mid: -E -G130 -P4
ph_nurse_blend.mid: -E -G130 -P4
ph_nurse_held.mid: -E -G130 -P4
ph_nurse_solo.mid: -E -G130 -P4
ph_price_blend.mid: -E -G130 -P4
ph_price_held.mid: -E -G130 -P4
ph_price_solo.mid: -E -G130 -P4
ph_strut_blend.mid: -E -G130 -P4
ph_strut_held.mid: -E -G130 -P4
ph_strut_solo.mid: -E -G130 -P4
ph_thought_blend.mid: -E -G130 -P4
ph_thought_held.mid: -E -G130 -P4
ph_thought_solo.mid: -E -G130 -P4
ph_trap_blend.mid: -E -G130 -P4
ph_trap_held.mid: -E -G130 -P4
ph_trap_solo.mid: -E -G130 -P4
se_a.mid: -E -R50 -G128 -V095 -P4
se_applause.mid: -E -R50 -G128 -V100 -P5
se_arena_timeup1.mid: -E -R50 -G129 -P5
se_arena_timeup2.mid: -E -R50 -G129 -P5
se_ball_bounce_1.mid: -E -R50 -G128 -V100 -P4
se_ball_bounce_2.mid: -E -R50 -G128 -V100 -P4
se_ball_bounce_3.mid: -E -R50 -G128 -V100 -P4
se_ball_bounce_4.mid: -E -R50 -G128 -V100 -P4
se_ball_open.mid: -E -R50 -G127 -V100 -P5
se_ball_throw.mid: -E -R50 -G128 -V120 -P5
se_ball_trade.mid: -E -R50 -G127 -V100 -P5
se_ball_tray_ball.mid: -E -R50 -G128 -V110 -P5
se_ball_tray_enter.mid: -E -R50 -G128 -V110 -P5
se_ball_tray_exit.mid: -E -R50 -G127 -V100 -P5
se_ball.mid: -E -R50 -G127 -V070 -P4
se_balloon_blue.mid: -E -R50 -G128 -V105 -P4
se_balloon_red.mid: -E -R50 -G128 -V105 -P4
se_balloon_yellow.mid: -E -R50 -G128 -V105 -P4
se_bang.mid: -E -R50 -G128 -V110 -P4
se_berry_blender.mid: -E -R50 -G128 -V090 -P4
se_bike_bell.mid: -E -R50 -G128 -V090 -P4
se_bike_hop.mid: -E -R50 -G127 -V090 -P4
se_boo.mid: -E -R50 -G127 -V110 -P4
se_breakable_door.mid: -E -R50 -G128 -V110 -P4
se_bridge_walk.mid: -E -R50 -G128 -V095 -P4
se_card.mid: -E -R50 -G127 -V100 -P4
se_click.mid: -E -R50 -G127 -V110 -P4
se_contest_condition_lose.mid: -E -R50 -G127 -V110 -P4
se_contest_curtain_fall.mid: -E -R50 -G128 -V070 -P5
se_contest_curtain_rise.mid: -E -R50 -G128 -V070 -P5
se_contest_heart.mid: -E -R50 -G128 -V090 -P5
se_contest_icon_change.mid: -E -R50 -G128 -V110 -P5
se_contest_icon_clear.mid: -E -R50 -G128 -V090 -P5
se_contest_mons_turn.mid: -E -R50 -G128 -V090 -P5
se_contest_place.mid: -E -R50 -G127 -V110 -P4
se_dex_search.mid: -E -R50 -G127 -v100 -P5
se_ding_dong.mid: -E -R50 -G127 -V090 -P5
se_door.mid: -E -R50 -G127 -V080 -P5
se_downpour_stop.mid: -E -R50 -G128 -V100 -P2
se_downpour.mid: -E -R50 -G128 -V100 -P2
se_e.mid: -E -R50 -G128 -V120 -P4
se_effective.mid: -E -R50 -G127 -V110 -P5
se_egg_hatch.mid: -E -R50 -G128 -V120 -P5
se_elevator.mid: -E -R50 -G128 -V100 -P4
se_escalator.mid: -E -R50 -G128 -V100 -P4
se_exit.mid: -E -R50 -G127 -V120 -P5
se_exp_max.mid: -E -R50 -G128 -V094 -P5
se_exp.mid: -E -R50 -G127 -V080 -P5
se_failure.mid: -E -R50 -G127 -V120 -P4
se_faint.mid: -E -R50 -G127 -V110 -P5
se_fall.mid: -E -R50 -G128 -V110 -P4
se_field_poison.mid: -E -R50 -G127 -V110 -P5
se_flee.mid: -E -R50 -G127 -V090 -P5
se_fu_zaku.mid: -E -R50 -G127 -V120 -P4
se_glass_flute.mid: -E -R50 -G128 -V105 -P5
se_i.mid: -E -R50 -G128 -V120 -P4
se_ice_break.mid: -E -R50 -G128 -V100 -P4
se_ice_crack.mid: -E -R50 -G127 -V100 -P4
se_ice_stairs.mid: -E -R50 -G128 -V090 -P4
se_intro_blast.mid: -E -R50 -G127 -V100 -P5
se_itemfinder.mid: -E -R50 -G127 -V090 -P5
se_lavaridge_fall_warp.mid: -E -R50 -G127 -P4
se_ledge.mid: -E -R50 -G127 -V100 -P4
se_low_health.mid: -E -R50 -G127 -V100 -P3
se_m_bind.mid: -E -R50 -G128 -V100 -P4
se_m_comet_punch.mid: -E -R50 -G128 -V120 -P4
se_m_cut.mid: -E -R50 -G128 -V120 -P4
se_m_double_slap.mid: -E -R50 -G128 -V110 -P4
se_m_fire_punch.mid: -E -R50 -G128 -V110 -P4
se_m_fly.mid: -E -R50 -G128 -V110 -P4
se_m_gust.mid: -E -R50 -G128 -V110 -P4
se_m_gust2.mid: -E -R50 -G128 -V110 -P4
se_m_headbutt.mid: -E -R50 -G128 -V110 -P4
se_m_horn_attack.mid: -E -R50 -G128 -V110 -P4
se_m_jump_kick.mid: -E -R50 -G128 -V110 -P4
se_m_leer.mid: -E -R50 -G128 -V110 -P4
se_m_mega_kick.mid: -E -R50 -G128 -V090 -P4
se_m_mega_kick2.mid: -E -R50 -G128 -V110 -P4
se_m_pay_day.mid: -E -R50 -G128 -V095 -P4
se_m_razor_wind.mid: -E -R50 -G128 -V110 -P4
se_m_razor_wind2.mid: -E -R50 -G128 -V090 -P4
se_m_sand_attack.mid: -E -R50 -G128 -V110 -P4
se_m_scratch.mid: -E -R50 -G128 -V110 -P4
se_m_swords_dance.mid: -E -R50 -G128 -V100 -P4
se_m_tail_whip.mid: -E -R50 -G128 -V110 -P4
se_m_take_down.mid: -E -R50 -G128 -V105 -P4
se_m_vicegrip.mid: -E -R50 -G128 -V110 -P4
se_m_wing_attack.mid: -E -R50 -G128 -V105 -P4
se_mud_ball.mid: -E -R50 -G128 -V110 -P4
se_mugshot.mid: -E -R50 -G128 -V090 -P5
se_n.mid: -E -R50 -G128 -P4
se_not_effective.mid: -E -R50 -G127 -V110 -P5
se_note_a.mid: -E -R50 -G128 -V110 -P4
se_note_b.mid: -E -R50 -G128 -V110 -P4
se_note_c_high.mid: -E -R50 -G128 -V110 -P4
se_note_c.mid: -E -R50 -G128 -V110 -P4
se_note_d.mid: -E -R50 -G128 -V110 -P4
se_note_e.mid: -E -R50 -G128 -V110 -P4
se_note_f.mid: -E -R50 -G128 -V110 -P4
se_note_g.mid: -E -R50 -G128 -V110 -P4
se_o.mid: -E -R50 -G128 -V120 -P4
se_orb.mid: -E -R50 -G128 -V100 -P5
se_pc_login.mid: -E -R50 -G127 -V100 -P5
se_pc_off.mid: -E -R50 -G127 -V100 -P5
se_pc_on.mid: -E -R50 -G127 -V100 -P5
se_pike_curtain_close.mid: -E -R50 -G129 -P5
se_pike_curtain_open.mid: -E -R50 -G129 -P5
se_pin.mid: -E -R50 -G127 -V060 -P4
se_pokenav_call.mid: -E -R50 -G129 -V120 -P5
se_pokenav_hang_up.mid: -E -R50 -G129 -V110 -P5
se_pokenav_off.mid: -E -R50 -G127 -V100 -P5
se_pokenav_on.mid: -E -R50 -G127 -V100 -P5
se_puddle.mid: -E -R50 -G128 -V020 -P4
se_rain_stop.mid: -E -R50 -G128 -V080 -P2
se_rain.mid: -E -R50 -G128 -V080 -P2
se_repel.mid: -E -R50 -G127 -V090 -P4
se_rg_bag_cursor.mid: -E -R50 -G129 -P5
se_rg_bag_pocket.mid: -E -R50 -G129 -P5
se_rg_ball_click.mid: -E -R50 -G129 -V100 -P5
se_rg_card_flip.mid: -E -R50 -G129 -P5
se_rg_card_flipping.mid: -E -R50 -G129 -P5
se_rg_card_open.mid: -E -R50 -G129 -V112 -P5
se_rg_deoxys_move.mid: -E -R50 -G129 -V080 -P5
se_rg_door.mid: -E -R50 -G129 -V100 -P5
se_rg_help_close.mid: -E -R50 -G129 -V095 -P5
se_rg_help_error.mid: -E -R50 -G129 -V125 -P5
se_rg_help_open.mid: -E -R50 -G129 -V096 -P5
se_rg_poke_jump_failure.mid: -E -R50 -G127 -P5
se_rg_poke_jump_success.mid: -E -R50 -G128 -V110 -P5
se_rg_shop.mid: -E -R50 -G129 -V080 -P5
se_rg_ss_anne_horn.mid: -E -R50 -G129 -V096 -P5
se_rotating_gate.mid: -E -R50 -G128 -V090 -P4
se_roulette_ball.mid: -E -R50 -G128 -V110 -P2
se_roulette_ball2.mid: -E -R50 -G128 -V110 -P2
se_save.mid: -E -R50 -G128 -V080 -P5
se_select.mid: -E -R50 -G127 -V080 -P5
se_shiny.mid: -E -R50 -G128 -V095 -P5
se_ship.mid: -E -R50 -G127 -V075 -P4
se_shop.mid: -E -R50 -G127 -V090 -P5
se_sliding_door.mid: -E -R50 -G128 -V095 -P4
se_success.mid: -E -R50 -G127 -V080 -P4
se_sudowoodo_shake.mid: -E -R50 -G129 -V077 -P5
se_super_effective.mid: -E -R50 -G127 -V110 -P5
se_switch.mid: -E -R50 -G127 -V100 -P4
se_taillow_wing_flap.mid: -E -R50 -G128 -V105 -P5
se_thunder.mid: -E -R50 -G128 -V110 -P3
se_thunder2.mid: -E -R50 -G128 -V110 -P3
se_thunderstorm_stop.mid: -E -R50 -G128 -V080 -P2
se_thunderstorm.mid: -E -R50 -G128 -V080 -P2
se_truck_door.mid: -E -R50 -G128 -V110 -P4
se_truck_move.mid: -E -R50 -G128 -P4
se_truck_stop.mid: -E -R50 -G128 -P4
se_truck_unload.mid: -E -R50 -G127 -P4
se_u.mid: -E -R50 -G128 -P4
se_unlock.mid: -E -R50 -G128 -V100 -P4
se_use_item.mid: -E -R50 -G127 -V100 -P5
se_vend.mid: -E -R50 -G128 -V110 -P4
se_warp_in.mid: -E -R50 -G127 -V090 -P4
se_warp_out.mid: -E -R50 -G127 -V090 -P4
mus_abandoned_ship.mid: -E -R50 -G030 -V080
mus_abnormal_weather.mid: -E -R50 -G089 -V080
mus_aqua_magma_hideout.mid: -E -R50 -G076 -V084
mus_awaken_legend.mid: -E -R50 -G012 -V090 -P5
mus_b_arena.mid: -E -R50 -G104 -V090
mus_b_dome_lobby.mid: -E -R50 -G111 -V056
mus_b_dome.mid: -E -R50 -G111 -V090
mus_b_factory.mid: -E -R50 -G113 -V100
mus_b_frontier.mid: -E -R50 -G103 -V094
mus_b_palace.mid: -E -R50 -G108 -V105
mus_b_pike.mid: -E -R50 -G112 -V092
mus_b_pyramid_top.mid: -E -R50 -G107 -V077
mus_b_pyramid.mid: -E -R50 -G106 -V079
mus_b_tower_rs.mid: -E -R50 -G035 -V080
mus_b_tower.mid: -E -R50 -G110 -V100
mus_birch_lab.mid: -E -R50 -G033 -V080
mus_c_comm_center.mid: -E -R50 -V080
mus_c_vs_legend_beast.mid: -E -R50 -V080
mus_cable_car.mid: -E -R50 -G071 -V078
mus_caught.mid: -E -R50 -G025 -V080
mus_cave_of_origin.mid: -E -R50 -G037 -V080
mus_contest_lobby.mid: -E -R50 -G098 -V060
mus_contest_results.mid: -E -R50 -G092 -V080
mus_contest_winner.mid: -E -R50 -G085 -V100
mus_contest.mid: -E -R50 -G086 -V088
mus_credits.mid: -E -R50 -G101 -V100
mus_cycling.mid: -E -R50 -G049 -V083
mus_dewford.mid: -E -R50 -G073 -V078
mus_dummy.mid: -E -R40
mus_encounter_aqua.mid: -E -R50 -G065 -V086
mus_encounter_brendan.mid: -E -R50 -G067 -V078
mus_encounter_champion.mid: -E -R50 -G100 -V076
mus_encounter_cool.mid: -E -R50 -G063 -V086
mus_encounter_elite_four.mid: -E -R50 -G096 -V078
mus_encounter_female.mid: -E -R50 -G053 -V072
mus_encounter_girl.mid: -E -R50 -G027 -V080
mus_encounter_hiker.mid: -E -R50 -G097 -V076
mus_encounter_intense.mid: -E -R50 -G062 -V078
mus_encounter_interviewer.mid: -E -R50 -G099 -V062
mus_encounter_magma.mid: -E -R50 -G087 -V072
mus_encounter_male.mid: -E -R50 -G028 -V080
mus_encounter_may.mid: -E -R50 -G061 -V078
mus_encounter_rich.mid: -E -R50 -G043 -V094
mus_encounter_suspicious.mid: -E -R50 -G069 -V078
mus_encounter_swimmer.mid: -E -R50 -G036 -V080
mus_encounter_twins.mid: -E -R50 -G095 -V075
mus_end.mid: -E -R50 -G102 -V036
mus_ever_grande.mid: -E -R50 -G068 -V086
mus_evolution_intro.mid: -E -R50 -G026 -V080
mus_evolution.mid: -E -R50 -G026 -V080
mus_evolved.mid: -E -R50 -G012 -V090 -P5
mus_fallarbor.mid: -E -R50 -G083 -V100
mus_follow_me.mid: -E -R50 -G066 -V074
mus_fortree.mid: -E -R50 -G032 -V080
mus_game_corner.mid: -E -R50 -G072 -V072
mus_gsc_pewter.mid: -E -R50 -V080
mus_gsc_route38.mid: -E -R50 -V080
mus_gym.mid: -E -R50 -G013 -V080
mus_hall_of_fame_room.mid: -E -R50 -G093 -V080
mus_hall_of_fame.mid: -E -R50 -G082 -V078
mus_heal.mid: -E -R50 -G012 -V090 -P5
mus_help.mid: -E -R50 -G056 -V078
mus_intro_battle.mid: -E -R50 -G088 -V088
mus_intro.mid: -E -R50 -G060 -V090
mus_level_up.mid: -E -R50 -G012 -V090 -P5
mus_lilycove_museum.mid: -E -R50 -G020 -V080
mus_lilycove.mid: -E -R50 -G054 -V085
mus_link_contest_p1.mid: -E -R50 -G039 -V079
mus_link_contest_p2.mid: -E -R50 -G040 -V090
mus_link_contest_p3.mid: -E -R50 -G041 -V075
mus_link_contest_p4.mid: -E -R50 -G042 -V090
mus_littleroot_test.mid: -E -R50 -G034 -V099
mus_littleroot.mid: -E -R50 -G051 -V100
mus_move_deleted.mid: -E -R50 -G012 -V090 -P5
mus_mt_chimney.mid: -E -R50 -G052 -V078
mus_mt_pyre_exterior.mid: -E -R50 -G080 -V080
mus_mt_pyre.mid: -E -R50 -G078 -V088
mus_obtain_b_points.mid: -E -R50 -G103 -V090 -P5
mus_obtain_badge.mid: -E -R50 -G012 -V090 -P5
mus_obtain_berry.mid: -E -R50 -G012 -V090 -P5
mus_obtain_item.mid: -E -R50 -G012 -V090 -P5
mus_obtain_symbol.mid: -E -R50 -G103 -V100 -P5
mus_obtain_tmhm.mid: -E -R50 -G012 -V090 -P5
mus_oceanic_museum.mid: -E -R50 -G023 -V080
mus_oldale.mid: -E -R50 -G019 -V080
mus_petalburg_woods.mid: -E -R50 -G018 -V080
mus_petalburg.mid: -E -R50 -G015 -V080
mus_poke_center.mid: -E -R50 -G046 -V092
mus_poke_mart.mid: -E -R50 -G050 -V085
mus_rayquaza_appears.mid: -E -R50 -G109 -V090
mus_register_match_call.mid: -E -R50 -G105 -V090 -P5
mus_rg_berry_pick.mid: -E -R50 -G132 -V090
mus_rg_caught_intro.mid: -E -R50 -G179 -V094 -P5
mus_rg_caught.mid: -E -R50 -G170 -V100
mus_rg_celadon.mid: -E -R50 -G168 -V070
mus_rg_cinnabar.mid: -E -R50 -G138 -V090
mus_rg_credits.mid: -E -R50 -G149 -V090
mus_rg_cycling.mid: -E -R50 -G141 -V090
mus_rg_dex_rating.mid: -E -R50 -G175 -V070 -P5
mus_rg_encounter_boy.mid: -E -R50 -G144 -V090
mus_rg_encounter_deoxys.mid: -E -R50 -G184 -V079
mus_rg_encounter_girl.mid: -E -R50 -G143 -V051
mus_rg_encounter_gym_leader: -E -R50 -G144 -V090
mus_rg_encounter_rival.mid: -E -R50 -G174 -V079
mus_rg_encounter_rocket.mid: -E -R50 -G142 -V096
mus_rg_follow_me.mid: -E -R50 -G131 -V068
mus_rg_fuchsia.mid: -E -R50 -G167 -V090
mus_rg_game_corner.mid: -E -R50 -G132 -V090
mus_rg_game_freak.mid: -E -R50 -G181 -V075
mus_rg_gym.mid: -E -R50 -G134 -V090
mus_rg_hall_of_fame.mid: -E -R50 -G145 -V079
mus_rg_heal.mid: -E -R50 -G140 -V090
mus_rg_intro_fight.mid: -E -R50 -G136 -V090
mus_rg_jigglypuff.mid: -E -R50 -G135 -V068 -P5
mus_rg_lavender.mid: -E -R50 -G139 -V090
mus_rg_mt_moon.mid: -E -R50 -G147 -V090
mus_rg_mystery_gift.mid: -E -R50 -G183 -V100
mus_rg_net_center.mid: -E -R50 -G162 -V096
mus_rg_new_game_exit.mid: -E -R50 -G182 -V088
mus_rg_new_game_instruct.mid: -E -R50 -G182 -V085
mus_rg_new_game_intro.mid: -E -R50 -G182 -V088
mus_rg_oak_lab.mid: -E -R50 -G160 -V075
mus_rg_oak.mid: -E -R50 -G161 -V086
mus_rg_obtain_key_item.mid: -E -R50 -G178 -V077 -P5
mus_rg_pallet.mid: -E -R50 -G159 -V100
mus_rg_pewter.mid: -E -R50 -G173 -V084
mus_rg_photo.mid: -E -R50 -G180 -V100 -P5
mus_rg_poke_center.mid: -E -R50 -G162 -V096
mus_rg_poke_flute.mid: -E -R50 -G165 -V048 -P5
mus_rg_poke_jump.mid: -E -R50 -G132 -V090
mus_rg_poke_mansion.mid: -E -R50 -G148 -V090
mus_rg_poke_tower.mid: -E -R50 -G165 -V090
mus_rg_rival_exit.mid: -E -R50 -G174 -V079
mus_rg_rocket_hideout.mid: -E -R50 -G133 -V090
mus_rg_route1.mid: -E -R50 -G150 -V079
mus_rg_route3.mid: -E -R50 -G152 -V083
mus_rg_route11.mid: -E -R50 -G153 -V090
mus_rg_route24.mid: -E -R50 -G151 -V086
mus_rg_sevii_45.mid: -E -R50 -G188 -V084
mus_rg_sevii_67.mid: -E -R50 -G189 -V084
mus_rg_sevii_123.mid: -E -R50 -G173 -V084
mus_rg_sevii_cave.mid: -E -R50 -G147 -V090
mus_rg_sevii_dungeon.mid: -E -R50 -G146 -V090
mus_rg_sevii_route.mid: -E -R50 -G187 -V080
mus_rg_silph.mid: -E -R50 -G166 -V076
mus_rg_slow_pallet.mid: -E -R50 -G159 -V092
mus_rg_ss_anne.mid: -E -R50 -G163 -V090
mus_rg_surf.mid: -E -R50 -G164 -V071
mus_rg_teachy_tv_menu.mid: -E -R50 -G186 -V059
mus_rg_teachy_tv_show.mid: -E -R50 -G131 -V068
mus_rg_title.mid: -E -R50 -G137 -V090
mus_rg_trainer_tower.mid: -E -R50 -G134 -V090
mus_rg_union_room.mid: -E -R50 -G132 -V090
mus_rg_vermillion.mid: -E -R50 -G172 -V090
mus_rg_victory_gym_leader.mid: -E -R50 -G171 -V090
mus_rg_victory_road.mid: -E -R50 -G154 -V090
mus_rg_victory_trainer.mid: -E -R50 -G169 -V089
mus_rg_victory_wild.mid: -E -R50 -G170 -V090
mus_rg_viridian_forest.mid: -E -R50 -G146 -V090
mus_rg_vs_champion.mid: -E -R50 -G158 -V090
mus_rg_vs_deoxys.mid: -E -R50 -G185 -V080
mus_rg_vs_gym_leader.mid: -E -R50 -G155 -V090
mus_rg_vs_legend.mid: -E -R50 -G157 -V090
mus_rg_vs_mewtwo.mid: -E -R50 -G157 -V090
mus_rg_vs_trainer.mid: -E -R50 -G156 -V090
mus_rg_vs_wild.mid: -E -R50 -G157 -V090
mus_roulette.mid: -E -R50 -G038 -V080
mus_route101.mid: -E -R50 -G011 -V080
mus_route104.mid: -E -R50 -G047 -V097
mus_route110.mid: -E -R50 -G010 -V080
mus_route111.mid: -E -R50 -G055 -V076
mus_route113.mid: -E -R50 -G064 -V084
mus_route119.mid: -E -R50 -G048 -V096
mus_route120.mid: -E -R50 -G014 -V080
mus_route122.mid: -E -R50 -G021 -V080
mus_rustboro.mid: -E -R50 -G045 -V085
mus_safari_zone.mid: -E -R50 -G074 -V082
mus_sailing.mid: -E -R50 -G077 -V086
mus_school.mid: -E -R50 -G081 -V100
mus_sealed_chamber.mid: -E -R50 -G084 -V100
mus_slateport.mid: -E -R50 -G079 -V070
mus_slots_jackpot.mid: -E -R50 -G012 -V090 -P5
mus_slots_win.mid: -E -R50 -G012 -V090 -P5
mus_sootopolis.mid: -E -R50 -G091 -V062
mus_surf.mid: -E -R50 -G017 -V080
mus_title.mid: -E -R50 -G059 -V090
mus_too_bad.mid: -E -R50 -G012 -V090 -P5
mus_trick_house.mid: -E -R50 -G094 -V070
mus_underwater.mid: -E -R50 -G057 -V094
mus_verdanturf.mid: -E -R50 -G044 -V090
mus_victory_aqua_magma.mid: -E -R50 -G070 -V088
mus_victory_gym_leader.mid: -E -R50 -G024 -V080
mus_victory_league.mid: -E -R50 -G029 -V080
mus_victory_road.mid: -E -R50 -G075 -V076
mus_victory_trainer.mid: -E -R50 -G058 -V091
mus_victory_wild.mid: -E -R50 -G025 -V080
mus_vs_aqua_magma_leader.mid: -E -R50 -G126 -V080 -P1
mus_vs_aqua_magma.mid: -E -R50 -G118 -V080 -P1
mus_vs_champion.mid: -E -R50 -G121 -V080 -P1
mus_vs_elite_four.mid: -E -R50 -G125 -V080 -P1
mus_vs_frontier_brain.mid: -E -R50 -G115 -V090 -P1
mus_vs_gym_leader.mid: -E -R50 -G120 -V080 -P1
mus_vs_kyogre_groudon.mid: -E -R50 -G123 -V080 -P1
mus_vs_mew.mid: -E -R50 -G116 -V090
mus_vs_rayquaza.mid: -E -R50 -G114 -V080 -P1
mus_vs_regi.mid: -E -R50 -G122 -V080 -P1
mus_vs_rival.mid: -E -R50 -G124 -V080 -P1
mus_vs_trainer.mid: -E -R50 -G119 -V080 -P1
mus_vs_wild.mid: -E -R50 -G117 -V080 -P1
mus_weather_groudon.mid: -E -R50 -G090 -V050
ph_choice_blend.mid: -E -G130 -P4
ph_choice_held.mid: -E -G130 -P4
ph_choice_solo.mid: -E -G130 -P4
ph_cloth_blend.mid: -E -G130 -P4
ph_cloth_held.mid: -E -G130 -P4
ph_cloth_solo.mid: -E -G130 -P4
ph_cure_blend.mid: -E -G130 -P4
ph_cure_held.mid: -E -G130 -P4
ph_cure_solo.mid: -E -G130 -P4
ph_dress_blend.mid: -E -G130 -P4
ph_dress_held.mid: -E -G130 -P4
ph_dress_solo.mid: -E -G130 -P4
ph_face_blend.mid: -E -G130 -P4
ph_face_held.mid: -E -G130 -P4
ph_face_solo.mid: -E -G130 -P4
ph_fleece_blend.mid: -E -G130 -P4
ph_fleece_held.mid: -E -G130 -P4
ph_fleece_solo.mid: -E -G130 -P4
ph_foot_blend.mid: -E -G130 -P4
ph_foot_held.mid: -E -G130 -P4
ph_foot_solo.mid: -E -G130 -P4
ph_goat_blend.mid: -E -G130 -P4
ph_goat_held.mid: -E -G130 -P4
ph_goat_solo.mid: -E -G130 -P4
ph_goose_blend.mid: -E -G130 -P4
ph_goose_held.mid: -E -G130 -P4
ph_goose_solo.mid: -E -G130 -P4
ph_kit_blend.mid: -E -G130 -P4
ph_kit_held.mid: -E -G130 -P4
ph_kit_solo.mid: -E -G130 -P4
ph_lot_blend.mid: -E -G130 -P4
ph_lot_held.mid: -E -G130 -P4
ph_lot_solo.mid: -E -G130 -P4
ph_mouth_blend.mid: -E -G130 -P4
ph_mouth_held.mid: -E -G130 -P4
ph_mouth_solo.mid: -E -G130 -P4
ph_nurse_blend.mid: -E -G130 -P4
ph_nurse_held.mid: -E -G130 -P4
ph_nurse_solo.mid: -E -G130 -P4
ph_price_blend.mid: -E -G130 -P4
ph_price_held.mid: -E -G130 -P4
ph_price_solo.mid: -E -G130 -P4
ph_strut_blend.mid: -E -G130 -P4
ph_strut_held.mid: -E -G130 -P4
ph_strut_solo.mid: -E -G130 -P4
ph_thought_blend.mid: -E -G130 -P4
ph_thought_held.mid: -E -G130 -P4
ph_thought_solo.mid: -E -G130 -P4
ph_trap_blend.mid: -E -G130 -P4
ph_trap_held.mid: -E -G130 -P4
ph_trap_solo.mid: -E -G130 -P4
se_a.mid: -E -R50 -G128 -V095 -P4
se_applause.mid: -E -R50 -G128 -V100 -P5
se_arena_timeup1.mid: -E -R50 -G129 -P5
se_arena_timeup2.mid: -E -R50 -G129 -P5
se_ball_bounce_1.mid: -E -R50 -G128 -V100 -P4
se_ball_bounce_2.mid: -E -R50 -G128 -V100 -P4
se_ball_bounce_3.mid: -E -R50 -G128 -V100 -P4
se_ball_bounce_4.mid: -E -R50 -G128 -V100 -P4
se_ball_open.mid: -E -R50 -G127 -V100 -P5
se_ball_throw.mid: -E -R50 -G128 -V120 -P5
se_ball_trade.mid: -E -R50 -G127 -V100 -P5
se_ball_tray_ball.mid: -E -R50 -G128 -V110 -P5
se_ball_tray_enter.mid: -E -R50 -G128 -V110 -P5
se_ball_tray_exit.mid: -E -R50 -G127 -V100 -P5
se_ball.mid: -E -R50 -G127 -V070 -P4
se_balloon_blue.mid: -E -R50 -G128 -V105 -P4
se_balloon_red.mid: -E -R50 -G128 -V105 -P4
se_balloon_yellow.mid: -E -R50 -G128 -V105 -P4
se_bang.mid: -E -R50 -G128 -V110 -P4
se_berry_blender.mid: -E -R50 -G128 -V090 -P4
se_bike_bell.mid: -E -R50 -G128 -V090 -P4
se_bike_hop.mid: -E -R50 -G127 -V090 -P4
se_boo.mid: -E -R50 -G127 -V110 -P4
se_breakable_door.mid: -E -R50 -G128 -V110 -P4
se_bridge_walk.mid: -E -R50 -G128 -V095 -P4
se_card.mid: -E -R50 -G127 -V100 -P4
se_click.mid: -E -R50 -G127 -V110 -P4
se_contest_condition_lose.mid: -E -R50 -G127 -V110 -P4
se_contest_curtain_fall.mid: -E -R50 -G128 -V070 -P5
se_contest_curtain_rise.mid: -E -R50 -G128 -V070 -P5
se_contest_heart.mid: -E -R50 -G128 -V090 -P5
se_contest_icon_change.mid: -E -R50 -G128 -V110 -P5
se_contest_icon_clear.mid: -E -R50 -G128 -V090 -P5
se_contest_mons_turn.mid: -E -R50 -G128 -V090 -P5
se_contest_place.mid: -E -R50 -G127 -V110 -P4
se_dex_search.mid: -E -R50 -G127 -v100 -P5
se_ding_dong.mid: -E -R50 -G127 -V090 -P5
se_door.mid: -E -R50 -G127 -V080 -P5
se_downpour_stop.mid: -E -R50 -G128 -V100 -P2
se_downpour.mid: -E -R50 -G128 -V100 -P2
se_e.mid: -E -R50 -G128 -V120 -P4
se_effective.mid: -E -R50 -G127 -V110 -P5
se_egg_hatch.mid: -E -R50 -G128 -V120 -P5
se_elevator.mid: -E -R50 -G128 -V100 -P4
se_escalator.mid: -E -R50 -G128 -V100 -P4
se_exit.mid: -E -R50 -G127 -V120 -P5
se_exp_max.mid: -E -R50 -G128 -V094 -P5
se_exp.mid: -E -R50 -G127 -V080 -P5
se_failure.mid: -E -R50 -G127 -V120 -P4
se_faint.mid: -E -R50 -G127 -V110 -P5
se_fall.mid: -E -R50 -G128 -V110 -P4
se_field_poison.mid: -E -R50 -G127 -V110 -P5
se_flee.mid: -E -R50 -G127 -V090 -P5
se_fu_zaku.mid: -E -R50 -G127 -V120 -P4
se_glass_flute.mid: -E -R50 -G128 -V105 -P5
se_i.mid: -E -R50 -G128 -V120 -P4
se_ice_break.mid: -E -R50 -G128 -V100 -P4
se_ice_crack.mid: -E -R50 -G127 -V100 -P4
se_ice_stairs.mid: -E -R50 -G128 -V090 -P4
se_intro_blast.mid: -E -R50 -G127 -V100 -P5
se_itemfinder.mid: -E -R50 -G127 -V090 -P5
se_lavaridge_fall_warp.mid: -E -R50 -G127 -P4
se_ledge.mid: -E -R50 -G127 -V100 -P4
se_low_health.mid: -E -R50 -G127 -V100 -P3
se_m_bind.mid: -E -R50 -G128 -V100 -P4
se_m_comet_punch.mid: -E -R50 -G128 -V120 -P4
se_m_cut.mid: -E -R50 -G128 -V120 -P4
se_m_double_slap.mid: -E -R50 -G128 -V110 -P4
se_m_fire_punch.mid: -E -R50 -G128 -V110 -P4
se_m_fly.mid: -E -R50 -G128 -V110 -P4
se_m_gust.mid: -E -R50 -G128 -V110 -P4
se_m_gust2.mid: -E -R50 -G128 -V110 -P4
se_m_headbutt.mid: -E -R50 -G128 -V110 -P4
se_m_horn_attack.mid: -E -R50 -G128 -V110 -P4
se_m_jump_kick.mid: -E -R50 -G128 -V110 -P4
se_m_leer.mid: -E -R50 -G128 -V110 -P4
se_m_mega_kick.mid: -E -R50 -G128 -V090 -P4
se_m_mega_kick2.mid: -E -R50 -G128 -V110 -P4
se_m_pay_day.mid: -E -R50 -G128 -V095 -P4
se_m_razor_wind.mid: -E -R50 -G128 -V110 -P4
se_m_razor_wind2.mid: -E -R50 -G128 -V090 -P4
se_m_sand_attack.mid: -E -R50 -G128 -V110 -P4
se_m_scratch.mid: -E -R50 -G128 -V110 -P4
se_m_swords_dance.mid: -E -R50 -G128 -V100 -P4
se_m_tail_whip.mid: -E -R50 -G128 -V110 -P4
se_m_take_down.mid: -E -R50 -G128 -V105 -P4
se_m_vicegrip.mid: -E -R50 -G128 -V110 -P4
se_m_wing_attack.mid: -E -R50 -G128 -V105 -P4
se_mud_ball.mid: -E -R50 -G128 -V110 -P4
se_mugshot.mid: -E -R50 -G128 -V090 -P5
se_n.mid: -E -R50 -G128 -P4
se_not_effective.mid: -E -R50 -G127 -V110 -P5
se_note_a.mid: -E -R50 -G128 -V110 -P4
se_note_b.mid: -E -R50 -G128 -V110 -P4
se_note_c_high.mid: -E -R50 -G128 -V110 -P4
se_note_c.mid: -E -R50 -G128 -V110 -P4
se_note_d.mid: -E -R50 -G128 -V110 -P4
se_note_e.mid: -E -R50 -G128 -V110 -P4
se_note_f.mid: -E -R50 -G128 -V110 -P4
se_note_g.mid: -E -R50 -G128 -V110 -P4
se_o.mid: -E -R50 -G128 -V120 -P4
se_orb.mid: -E -R50 -G128 -V100 -P5
se_pc_login.mid: -E -R50 -G127 -V100 -P5
se_pc_off.mid: -E -R50 -G127 -V100 -P5
se_pc_on.mid: -E -R50 -G127 -V100 -P5
se_pike_curtain_close.mid: -E -R50 -G129 -P5
se_pike_curtain_open.mid: -E -R50 -G129 -P5
se_pin.mid: -E -R50 -G127 -V060 -P4
se_pokenav_call.mid: -E -R50 -G129 -V120 -P5
se_pokenav_hang_up.mid: -E -R50 -G129 -V110 -P5
se_pokenav_off.mid: -E -R50 -G127 -V100 -P5
se_pokenav_on.mid: -E -R50 -G127 -V100 -P5
se_puddle.mid: -E -R50 -G128 -V020 -P4
se_rain_stop.mid: -E -R50 -G128 -V080 -P2
se_rain.mid: -E -R50 -G128 -V080 -P2
se_repel.mid: -E -R50 -G127 -V090 -P4
se_rg_bag_cursor.mid: -E -R50 -G129 -P5
se_rg_bag_pocket.mid: -E -R50 -G129 -P5
se_rg_ball_click.mid: -E -R50 -G129 -V100 -P5
se_rg_card_flip.mid: -E -R50 -G129 -P5
se_rg_card_flipping.mid: -E -R50 -G129 -P5
se_rg_card_open.mid: -E -R50 -G129 -V112 -P5
se_rg_deoxys_move.mid: -E -R50 -G129 -V080 -P5
se_rg_door.mid: -E -R50 -G129 -V100 -P5
se_rg_help_close.mid: -E -R50 -G129 -V095 -P5
se_rg_help_error.mid: -E -R50 -G129 -V125 -P5
se_rg_help_open.mid: -E -R50 -G129 -V096 -P5
se_rg_poke_jump_failure.mid: -E -R50 -G127 -P5
se_rg_poke_jump_success.mid: -E -R50 -G128 -V110 -P5
se_rg_shop.mid: -E -R50 -G129 -V080 -P5
se_rg_ss_anne_horn.mid: -E -R50 -G129 -V096 -P5
se_rotating_gate.mid: -E -R50 -G128 -V090 -P4
se_roulette_ball.mid: -E -R50 -G128 -V110 -P2
se_roulette_ball2.mid: -E -R50 -G128 -V110 -P2
se_save.mid: -E -R50 -G128 -V080 -P5
se_select.mid: -E -R50 -G127 -V080 -P5
se_shiny.mid: -E -R50 -G128 -V095 -P5
se_ship.mid: -E -R50 -G127 -V075 -P4
se_shop.mid: -E -R50 -G127 -V090 -P5
se_sliding_door.mid: -E -R50 -G128 -V095 -P4
se_success.mid: -E -R50 -G127 -V080 -P4
se_sudowoodo_shake.mid: -E -R50 -G129 -V077 -P5
se_super_effective.mid: -E -R50 -G127 -V110 -P5
se_switch.mid: -E -R50 -G127 -V100 -P4
se_taillow_wing_flap.mid: -E -R50 -G128 -V105 -P5
se_thunder.mid: -E -R50 -G128 -V110 -P3
se_thunder2.mid: -E -R50 -G128 -V110 -P3
se_thunderstorm_stop.mid: -E -R50 -G128 -V080 -P2
se_thunderstorm.mid: -E -R50 -G128 -V080 -P2
se_truck_door.mid: -E -R50 -G128 -V110 -P4
se_truck_move.mid: -E -R50 -G128 -P4
se_truck_stop.mid: -E -R50 -G128 -P4
se_truck_unload.mid: -E -R50 -G127 -P4
se_u.mid: -E -R50 -G128 -P4
se_unlock.mid: -E -R50 -G128 -V100 -P4
se_use_item.mid: -E -R50 -G127 -V100 -P5
se_vend.mid: -E -R50 -G128 -V110 -P4
se_warp_in.mid: -E -R50 -G127 -V090 -P4
se_warp_out.mid: -E -R50 -G127 -V090 -P4

View File

@ -1,43 +1,43 @@
=== PARTNER_NONE ===
Name:
Class: Pkmn Trainer 1
Pic: Brendan
Gender: Male
Music: Male
=== PARTNER_STEVEN ===
Name: STEVEN
Class: Rival
Pic: Steven
Gender: Male
Music: Male
Metang
Brave Nature
Level: 42
IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe
EVs: 252 Atk / 252 Def / 6 SpA
- Light Screen
- Psychic
- Reflect
- Metal Claw
Skarmory
Impish Nature
Level: 43
IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe
EVs: 252 HP / 6 SpA / 252 SpD
- Toxic
- Aerial Ace
- Protect
- Steel Wing
Aggron
Adamant Nature
Level: 44
IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe
EVs: 252 Atk / 252 SpA / 6 SpD
- Thunder
- Protect
- Solar Beam
- Dragon Claw
=== PARTNER_NONE ===
Name:
Class: Pkmn Trainer 1
Pic: Brendan
Gender: Male
Music: Male
=== PARTNER_STEVEN ===
Name: STEVEN
Class: Rival
Pic: Steven
Gender: Male
Music: Male
Metang
Brave Nature
Level: 42
IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe
EVs: 252 Atk / 252 Def / 6 SpA
- Light Screen
- Psychic
- Reflect
- Metal Claw
Skarmory
Impish Nature
Level: 43
IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe
EVs: 252 HP / 6 SpA / 252 SpD
- Toxic
- Aerial Ace
- Protect
- Steel Wing
Aggron
Adamant Nature
Level: 44
IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe
EVs: 252 Atk / 252 SpA / 6 SpD
- Thunder
- Protect
- Solar Beam
- Dragon Claw

File diff suppressed because it is too large Load Diff

View File

@ -1,215 +1,215 @@
=== 0 ===
Name: Test1
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: No
Bubbles (Wobbuffet) (F) @ Assault Vest
Hasty Nature
Level: 67
Ability: Telepathy
IVs: 25 HP / 26 Atk / 27 Def / 29 SpA / 30 SpD / 28 Spe
EVs: 252 HP / 4 SpA / 252 Spe
Happiness: 42
Shiny: Yes
Ball: Master Ball
Dynamax Level: 5
- Air Slash
- Barrier
- Solar Beam
- Explosion
Wobbuffet
Level: 5
Ability: Shadow Tag
IVs: 0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe
Wynaut
Level: 5
IVs: 0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe
=== 1 ===
Name: Test2
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: No
Difficulty: Normal
Mewtwo
Level: 5
=== 2 ===
Name: Test2
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: No
Difficulty: Normal
Mewtwo
Level: 50
=== 2 ===
Name: Test2
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: No
Difficulty: Easy
Metapod
Level: 1
=== 2 ===
Name: Test2
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: No
Difficulty: Hard
Arceus
Level: 99
=== 3 ===
Name: Test3
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: No
Party Size: 1
Wynaut
Wobbuffet
Eevee
Mew
=== 4 ===
Name: Test4
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: No
Party Size: 3
Wynaut
Wobbuffet
Tags: Lead
Eevee
Tags: Ace
Mew
Oddish
Tags: Ace
Aron
Tags: Lead
=== 5 ===
Name: Test5
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: Yes
Party Size: 3
Pool Rules: Weather Doubles
Wynaut
Tags: Lead
Wobbuffet
Tags: Lead
Vulpix
Tags: Lead / Weather Setter
Bulbasaur
Tags: Lead / Weather Abuser
Torkoal
Tags: Lead / Weather Setter
Cherrim
Tags: Lead / Weather Abuser
Mew
Tags: Lead
Aron
Tags: Lead
Oddish
Eevee
=== 6 ===
Name: Test6
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: No
Party Size: 2
Pool Rules: Basic
Wynaut
Tags: Lead
Wobbuffet
Tags: Lead
Eevee
Tags: Lead
=== 7 ===
Name: Test1
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: No
Party Size: 2
Pool Rules: Basic
Pool Prune: Test
Wynaut
Wobbuffet
Tags: Lead
Eevee
=== 8 ===
Name: Test1
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: No
Party Size: 2
Pool Rules: Basic
Pool Pick Functions: Lowest
Wynaut
Tags: Ace
Wobbuffet
Eevee
Tags: Lead
=== 0 ===
Name: Test1
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: No
Bubbles (Wobbuffet) (F) @ Assault Vest
Hasty Nature
Level: 67
Ability: Telepathy
IVs: 25 HP / 26 Atk / 27 Def / 29 SpA / 30 SpD / 28 Spe
EVs: 252 HP / 4 SpA / 252 Spe
Happiness: 42
Shiny: Yes
Ball: Master Ball
Dynamax Level: 5
- Air Slash
- Barrier
- Solar Beam
- Explosion
Wobbuffet
Level: 5
Ability: Shadow Tag
IVs: 0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe
Wynaut
Level: 5
IVs: 0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe
=== 1 ===
Name: Test2
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: No
Difficulty: Normal
Mewtwo
Level: 5
=== 2 ===
Name: Test2
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: No
Difficulty: Normal
Mewtwo
Level: 50
=== 2 ===
Name: Test2
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: No
Difficulty: Easy
Metapod
Level: 1
=== 2 ===
Name: Test2
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: No
Difficulty: Hard
Arceus
Level: 99
=== 3 ===
Name: Test3
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: No
Party Size: 1
Wynaut
Wobbuffet
Eevee
Mew
=== 4 ===
Name: Test4
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: No
Party Size: 3
Wynaut
Wobbuffet
Tags: Lead
Eevee
Tags: Ace
Mew
Oddish
Tags: Ace
Aron
Tags: Lead
=== 5 ===
Name: Test5
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: Yes
Party Size: 3
Pool Rules: Weather Doubles
Wynaut
Tags: Lead
Wobbuffet
Tags: Lead
Vulpix
Tags: Lead / Weather Setter
Bulbasaur
Tags: Lead / Weather Abuser
Torkoal
Tags: Lead / Weather Setter
Cherrim
Tags: Lead / Weather Abuser
Mew
Tags: Lead
Aron
Tags: Lead
Oddish
Eevee
=== 6 ===
Name: Test6
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: No
Party Size: 2
Pool Rules: Basic
Wynaut
Tags: Lead
Wobbuffet
Tags: Lead
Eevee
Tags: Lead
=== 7 ===
Name: Test1
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: No
Party Size: 2
Pool Rules: Basic
Pool Prune: Test
Wynaut
Wobbuffet
Tags: Lead
Eevee
=== 8 ===
Name: Test1
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Double Battle: No
Party Size: 2
Pool Rules: Basic
Pool Pick Functions: Lowest
Wynaut
Tags: Ace
Wobbuffet
Eevee
Tags: Lead

View File

@ -1,20 +1,20 @@
Copyright (c) 2016 huderlem
Copyright (c) 2005, 2006 by Marco Trillo <marcotrillo@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Copyright (c) 2016 huderlem
Copyright (c) 2005, 2006 by Marco Trillo <marcotrillo@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,19 +1,19 @@
Copyright (c) 2016 YamaArashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Copyright (c) 2016 YamaArashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +1,19 @@
Copyright (c) 2015 YamaArashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Copyright (c) 2015 YamaArashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,214 +1,214 @@
import glob
import re
import json
import os
# before all else, abort if the config is off
with open("./include/config/pokemon.h", "r") as file:
learnset_config = re.findall(r"#define P_LEARNSET_HELPER_TEACHABLE *([^ ]*)", file.read())
if len(learnset_config) != 1:
quit()
if learnset_config[0] != "TRUE":
quit()
def parse_mon_name(name):
return re.sub(r'(?!^)([A-Z]+)', r'_\1', name).upper()
tm_moves = []
tutor_moves = []
# scan incs
incs_to_check = glob.glob('./data/scripts/*.inc') # all .incs in the script folder
incs_to_check += glob.glob('./data/maps/*/scripts.inc') # all map scripts
if len(incs_to_check) == 0: # disabled if no jsons present
quit()
for file in incs_to_check:
with open(file, 'r') as f2:
raw = f2.read()
if 'special ChooseMonForMoveTutor' in raw:
for x in re.findall(r'setvar VAR_0x8005, (MOVE_.*)', raw):
if not x in tutor_moves:
tutor_moves.append(x)
# scan TMs and HMs
with open("./include/constants/tms_hms.h", 'r') as file:
for x in re.findall(r'F\((.*)\)', file.read()):
if not 'MOVE_' + x in tm_moves:
tm_moves.append('MOVE_' + x)
# look up universal moves to exclude them
universal_moves = []
with open("./src/pokemon.c", "r") as file:
for x in re.findall(r"static const u16 sUniversalMoves\[\] =(.|\n)*?{((.|\n)*?)};", file.read())[0]:
x = x.replace("\n", "")
for y in x.split(","):
y = y.strip()
if y == "":
continue
universal_moves.append(y)
# get compatibility from jsons
def construct_compatibility_dict(force_custom_check):
dict_out = {}
for pth in glob.glob('./tools/learnset_helpers/porymoves_files/*.json'):
f = open(pth, 'r')
data = json.load(f)
for mon in data.keys():
if not mon in dict_out:
dict_out[mon] = []
for move in data[mon]['LevelMoves']:
if not move['Move'] in dict_out[mon]:
dict_out[mon].append(move['Move'])
#for move in data[mon]['PreEvoMoves']:
# if not move in dict_out[mon]:
# dict_out[mon].append(move)
for move in data[mon]['TMMoves']:
if not move in dict_out[mon]:
dict_out[mon].append(move)
for move in data[mon]['EggMoves']:
if not move in dict_out[mon]:
dict_out[mon].append(move)
for move in data[mon]['TutorMoves']:
if not move in dict_out[mon]:
dict_out[mon].append(move)
# if the file was not previously generated, check if there is custom data there that needs to be preserved
with open("./src/data/pokemon/teachable_learnsets.h", 'r') as file:
raw = file.read()
if not "// DO NOT MODIFY THIS FILE!" in raw and force_custom_check == True:
custom_teachable_compatibilities = {}
for entry in re.findall(r"static const u16 s(.*)TeachableLearnset\[\] = {\n((.|\n)*?)\n};", raw):
monname = parse_mon_name(entry[0])
if monname == "NONE":
continue
compatibility = entry[1].split("\n")
if not monname in custom_teachable_compatibilities:
custom_teachable_compatibilities[monname] = []
if not monname in dict_out:
# this mon is unknown, so all data needs to be preserved
for move in compatibility:
move = move.replace(",", "").strip()
if move == "" or move == "MOVE_UNAVAILABLE":
continue
custom_teachable_compatibilities[monname].append(move)
else:
# this mon is known, so check if the moves in the old teachable_learnsets.h are not in the jsons
for move in compatibility:
move = move.replace(",", "").strip()
if move == "" or move == "MOVE_UNAVAILABLE":
continue
if not move in dict_out[monname]:
custom_teachable_compatibilities[monname].append(move)
# actually store the data in custom.json
if os.path.exists("./tools/learnset_helpers/porymoves_files/custom.json"):
f2 = open("./tools/learnset_helpers/porymoves_files/custom.json", "r")
custom_json = json.load(f2)
f2.close()
else:
custom_json = {}
for x in custom_teachable_compatibilities:
if len(custom_teachable_compatibilities[x]) == 0:
continue
if not x in custom_json:
custom_json[x] = {"LevelMoves": [], "PreEvoMoves": [], "TMMoves": [], "EggMoves": [], "TutorMoves": []}
for move in custom_teachable_compatibilities[x]:
custom_json[x]["TutorMoves"].append(move)
f2 = open("./tools/learnset_helpers/porymoves_files/custom.json", "w")
f2.write(json.dumps(custom_json, indent=2))
f2.close()
print("FIRST RUN: Updated custom.json with teachable_learnsets.h's data")
# rerun the process
dict_out = construct_compatibility_dict(False)
return dict_out
compatibility_dict = construct_compatibility_dict(True)
# actually prepare the file
with open("./src/data/pokemon/teachable_learnsets.h", 'r') as file:
out = file.read()
list_of_mons = re.findall(r'static const u16 s(.*)TeachableLearnset', out)
for mon in list_of_mons:
mon_parsed = parse_mon_name(mon)
tm_learnset = []
tutor_learnset = []
if mon_parsed == "NONE" or mon_parsed == "MEW":
continue
if not mon_parsed in compatibility_dict:
print("Unable to find %s in json" % mon)
continue
for move in tm_moves:
if move in universal_moves:
continue
if move in tm_learnset:
continue
if move in compatibility_dict[mon_parsed]:
tm_learnset.append(move)
continue
for move in tutor_moves:
if move in universal_moves:
continue
if move in tutor_learnset:
continue
if move in compatibility_dict[mon_parsed]:
tutor_learnset.append(move)
continue
tm_learnset.sort()
tutor_learnset.sort()
tm_learnset += tutor_learnset
repl = "static const u16 s%sTeachableLearnset[] = {\n " % mon
if len(tm_learnset) > 0:
repl += ",\n ".join(tm_learnset) + ",\n "
repl += "MOVE_UNAVAILABLE,\n};"
newout = re.sub(r'static const u16 s%sTeachableLearnset\[\] = {[\s\S]*?};' % mon, repl, out)
if newout != out:
out = newout
print("Updated %s" % mon)
# add/update header
header = "//\n// DO NOT MODIFY THIS FILE! It is auto-generated from tools/learnset_helpers/teachable.py\n//\n\n"
longest_move_name = 0
for move in tm_moves + tutor_moves:
if len(move) > longest_move_name:
longest_move_name = len(move)
longest_move_name += 2 # + 2 for a hyphen and a space
universal_title = "Near-universal moves found in sUniversalMoves:"
tmhm_title = "TM/HM moves found in \"include/constants/tms_hms.h\":"
tutor_title = "Tutor moves found in map scripts:"
if longest_move_name < len(universal_title):
longest_move_name = len(universal_title)
if longest_move_name < len(tmhm_title):
longest_move_name = len(tmhm_title)
if longest_move_name < len(tutor_title):
longest_move_name = len(tutor_title)
def header_print(str):
global header
header += "// " + str + " " * (longest_move_name - len(str)) + " //\n"
header += "// " + longest_move_name * "*" + " //\n"
header_print(tmhm_title)
for move in tm_moves:
header_print("- " + move)
header += "// " + longest_move_name * "*" + " //\n"
header_print(tutor_title)
tutor_moves.sort() # alphabetically sort tutor moves for easier referencing
for move in tutor_moves:
header_print("- " + move)
header += "// " + longest_move_name * "*" + " //\n"
header_print(universal_title)
universal_moves.sort() # alphabetically sort near-universal moves for easier referencing
for move in universal_moves:
header_print("- " + move)
header += "// " + longest_move_name * "*" + " //\n\n"
if not "// DO NOT MODIFY THIS FILE!" in out:
out = header + out
else:
out = re.sub(r"\/\/\n\/\/ DO NOT MODIFY THIS FILE!(.|\n)*\* \/\/\n\n", header, out)
with open("./src/data/pokemon/teachable_learnsets.h", 'w') as file:
file.write(out)
import glob
import re
import json
import os
# before all else, abort if the config is off
with open("./include/config/pokemon.h", "r") as file:
learnset_config = re.findall(r"#define P_LEARNSET_HELPER_TEACHABLE *([^ ]*)", file.read())
if len(learnset_config) != 1:
quit()
if learnset_config[0] != "TRUE":
quit()
def parse_mon_name(name):
return re.sub(r'(?!^)([A-Z]+)', r'_\1', name).upper()
tm_moves = []
tutor_moves = []
# scan incs
incs_to_check = glob.glob('./data/scripts/*.inc') # all .incs in the script folder
incs_to_check += glob.glob('./data/maps/*/scripts.inc') # all map scripts
if len(incs_to_check) == 0: # disabled if no jsons present
quit()
for file in incs_to_check:
with open(file, 'r') as f2:
raw = f2.read()
if 'special ChooseMonForMoveTutor' in raw:
for x in re.findall(r'setvar VAR_0x8005, (MOVE_.*)', raw):
if not x in tutor_moves:
tutor_moves.append(x)
# scan TMs and HMs
with open("./include/constants/tms_hms.h", 'r') as file:
for x in re.findall(r'F\((.*)\)', file.read()):
if not 'MOVE_' + x in tm_moves:
tm_moves.append('MOVE_' + x)
# look up universal moves to exclude them
universal_moves = []
with open("./src/pokemon.c", "r") as file:
for x in re.findall(r"static const u16 sUniversalMoves\[\] =(.|\n)*?{((.|\n)*?)};", file.read())[0]:
x = x.replace("\n", "")
for y in x.split(","):
y = y.strip()
if y == "":
continue
universal_moves.append(y)
# get compatibility from jsons
def construct_compatibility_dict(force_custom_check):
dict_out = {}
for pth in glob.glob('./tools/learnset_helpers/porymoves_files/*.json'):
f = open(pth, 'r')
data = json.load(f)
for mon in data.keys():
if not mon in dict_out:
dict_out[mon] = []
for move in data[mon]['LevelMoves']:
if not move['Move'] in dict_out[mon]:
dict_out[mon].append(move['Move'])
#for move in data[mon]['PreEvoMoves']:
# if not move in dict_out[mon]:
# dict_out[mon].append(move)
for move in data[mon]['TMMoves']:
if not move in dict_out[mon]:
dict_out[mon].append(move)
for move in data[mon]['EggMoves']:
if not move in dict_out[mon]:
dict_out[mon].append(move)
for move in data[mon]['TutorMoves']:
if not move in dict_out[mon]:
dict_out[mon].append(move)
# if the file was not previously generated, check if there is custom data there that needs to be preserved
with open("./src/data/pokemon/teachable_learnsets.h", 'r') as file:
raw = file.read()
if not "// DO NOT MODIFY THIS FILE!" in raw and force_custom_check == True:
custom_teachable_compatibilities = {}
for entry in re.findall(r"static const u16 s(.*)TeachableLearnset\[\] = {\n((.|\n)*?)\n};", raw):
monname = parse_mon_name(entry[0])
if monname == "NONE":
continue
compatibility = entry[1].split("\n")
if not monname in custom_teachable_compatibilities:
custom_teachable_compatibilities[monname] = []
if not monname in dict_out:
# this mon is unknown, so all data needs to be preserved
for move in compatibility:
move = move.replace(",", "").strip()
if move == "" or move == "MOVE_UNAVAILABLE":
continue
custom_teachable_compatibilities[monname].append(move)
else:
# this mon is known, so check if the moves in the old teachable_learnsets.h are not in the jsons
for move in compatibility:
move = move.replace(",", "").strip()
if move == "" or move == "MOVE_UNAVAILABLE":
continue
if not move in dict_out[monname]:
custom_teachable_compatibilities[monname].append(move)
# actually store the data in custom.json
if os.path.exists("./tools/learnset_helpers/porymoves_files/custom.json"):
f2 = open("./tools/learnset_helpers/porymoves_files/custom.json", "r")
custom_json = json.load(f2)
f2.close()
else:
custom_json = {}
for x in custom_teachable_compatibilities:
if len(custom_teachable_compatibilities[x]) == 0:
continue
if not x in custom_json:
custom_json[x] = {"LevelMoves": [], "PreEvoMoves": [], "TMMoves": [], "EggMoves": [], "TutorMoves": []}
for move in custom_teachable_compatibilities[x]:
custom_json[x]["TutorMoves"].append(move)
f2 = open("./tools/learnset_helpers/porymoves_files/custom.json", "w")
f2.write(json.dumps(custom_json, indent=2))
f2.close()
print("FIRST RUN: Updated custom.json with teachable_learnsets.h's data")
# rerun the process
dict_out = construct_compatibility_dict(False)
return dict_out
compatibility_dict = construct_compatibility_dict(True)
# actually prepare the file
with open("./src/data/pokemon/teachable_learnsets.h", 'r') as file:
out = file.read()
list_of_mons = re.findall(r'static const u16 s(.*)TeachableLearnset', out)
for mon in list_of_mons:
mon_parsed = parse_mon_name(mon)
tm_learnset = []
tutor_learnset = []
if mon_parsed == "NONE" or mon_parsed == "MEW":
continue
if not mon_parsed in compatibility_dict:
print("Unable to find %s in json" % mon)
continue
for move in tm_moves:
if move in universal_moves:
continue
if move in tm_learnset:
continue
if move in compatibility_dict[mon_parsed]:
tm_learnset.append(move)
continue
for move in tutor_moves:
if move in universal_moves:
continue
if move in tutor_learnset:
continue
if move in compatibility_dict[mon_parsed]:
tutor_learnset.append(move)
continue
tm_learnset.sort()
tutor_learnset.sort()
tm_learnset += tutor_learnset
repl = "static const u16 s%sTeachableLearnset[] = {\n " % mon
if len(tm_learnset) > 0:
repl += ",\n ".join(tm_learnset) + ",\n "
repl += "MOVE_UNAVAILABLE,\n};"
newout = re.sub(r'static const u16 s%sTeachableLearnset\[\] = {[\s\S]*?};' % mon, repl, out)
if newout != out:
out = newout
print("Updated %s" % mon)
# add/update header
header = "//\n// DO NOT MODIFY THIS FILE! It is auto-generated from tools/learnset_helpers/teachable.py\n//\n\n"
longest_move_name = 0
for move in tm_moves + tutor_moves:
if len(move) > longest_move_name:
longest_move_name = len(move)
longest_move_name += 2 # + 2 for a hyphen and a space
universal_title = "Near-universal moves found in sUniversalMoves:"
tmhm_title = "TM/HM moves found in \"include/constants/tms_hms.h\":"
tutor_title = "Tutor moves found in map scripts:"
if longest_move_name < len(universal_title):
longest_move_name = len(universal_title)
if longest_move_name < len(tmhm_title):
longest_move_name = len(tmhm_title)
if longest_move_name < len(tutor_title):
longest_move_name = len(tutor_title)
def header_print(str):
global header
header += "// " + str + " " * (longest_move_name - len(str)) + " //\n"
header += "// " + longest_move_name * "*" + " //\n"
header_print(tmhm_title)
for move in tm_moves:
header_print("- " + move)
header += "// " + longest_move_name * "*" + " //\n"
header_print(tutor_title)
tutor_moves.sort() # alphabetically sort tutor moves for easier referencing
for move in tutor_moves:
header_print("- " + move)
header += "// " + longest_move_name * "*" + " //\n"
header_print(universal_title)
universal_moves.sort() # alphabetically sort near-universal moves for easier referencing
for move in universal_moves:
header_print("- " + move)
header += "// " + longest_move_name * "*" + " //\n\n"
if not "// DO NOT MODIFY THIS FILE!" in out:
out = header + out
else:
out = re.sub(r"\/\/\n\/\/ DO NOT MODIFY THIS FILE!(.|\n)*\* \/\/\n\n", header, out)
with open("./src/data/pokemon/teachable_learnsets.h", 'w') as file:
file.write(out)

View File

@ -1,19 +1,19 @@
Copyright (c) 2016 YamaArashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Copyright (c) 2016 YamaArashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,19 +1,19 @@
Copyright (c) 2016 YamaArashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Copyright (c) 2016 YamaArashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,19 +1,19 @@
Copyright (c) 2016 YamaArashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Copyright (c) 2016 YamaArashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,19 +1,19 @@
Copyright (c) 2015-2016 YamaArashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Copyright (c) 2015-2016 YamaArashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,19 +1,19 @@
Copyright (c) 2015 YamaArashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Copyright (c) 2015 YamaArashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.