Skip to content

Commit

Permalink
sike, this is the last one
Browse files Browse the repository at this point in the history
  • Loading branch information
kasenbackup committed Aug 4, 2024
1 parent cd5ace2 commit ea06b50
Show file tree
Hide file tree
Showing 15 changed files with 18,192 additions and 18,192 deletions.
220 changes: 110 additions & 110 deletions dev_scripts/followers/extract_sprites.py
Original file line number Diff line number Diff line change
@@ -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)
100 changes: 50 additions & 50 deletions dev_scripts/followers/follower_emotions.py
Original file line number Diff line number Diff line change
@@ -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)
Loading

0 comments on commit ea06b50

Please sign in to comment.