Skip to content
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ and back to help with poking at the binary.

## HTML cards

Prebuilt version of the HTML data is available at
Prebuilt version of the HTML data is available at
https://katajakasa.fi/projects/openomf/cards/

## Installation
Expand All @@ -15,11 +15,17 @@ https://katajakasa.fi/projects/openomf/cards/
3. Activate the virtualenv, eg. `poetry shell`
4. Run! eg. `python -m omftools.cli.af_compile -h`

Or with pyenv:
1. `pyenv install 3.11.4`
2. `pyenv virtualenv 3.11.4 pyomftools-3.11`
3. `pyenv local pyomftools-3.11`
4. ...

## How to ...

### Generate the taglist.c

1. Do the installation step above
2. Make sure the tag `omftools/resources/tags.csv` is up-to-date.
3. Run `poetry run python -m omftools.cli.tags -i omftools/resources/tags.csv taglist.c`
4. Copy the generated `taglist.c` as required.
4. Copy the generated `taglist.c` as required.
621 changes: 621 additions & 0 deletions omftools/cli/dump_assets.py

Large diffs are not rendered by default.

27 changes: 23 additions & 4 deletions omftools/cli/generate_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,19 @@ def generate_pics(
for idx, photo in enumerate(pic.photos):
sprite_file = os.path.join(output_dir, f"{filename}-{idx}.png")
try:
photo.sprite.save_png(sprite_file, src_pal)
# Create a custom palette for this photo
# Start with default palette
custom_palette = Palette()

# Use the photo's own palette for indices 0x00-0x2F
for i in range(0x00, 0x30):
custom_palette.data[i] = photo.palette.data[i]

# Mask indices 0x60-0x9F with magenta
custom_palette.mask_range(0x60, 64)

# Render using the custom palette
photo.sprite.save_png(sprite_file, custom_palette)
except OMFInvalidDataException:
print(f"Skipping {sprite_file}")

Expand Down Expand Up @@ -160,15 +172,17 @@ def generate_bk(file: str, files: Filenames, output_dir: str) -> None:
filename = os.path.basename(file)
bk = BKFile.load_native(file)

# Save background using the processed palette from BKFile
bk.save_background(os.path.join(output_dir, f"{filename}-bg.png"))

pal = copy.deepcopy(bk.palettes[0].colors)
# Get the appropriate palette based on filename
processed_palette = bk.get_processed_palette(file)

for key, animation in bk.animations.items():
for idx, sprite in enumerate(animation.sprites):
sprite_file = os.path.join(output_dir, f"{filename}-{key}-{idx}.png")
try:
sprite.save_png(sprite_file, pal)
sprite.save_png(sprite_file, processed_palette)
except OMFInvalidDataException:
print(f"Skipping {sprite_file}")

Expand All @@ -182,11 +196,16 @@ def generate_af(
filename = os.path.basename(file)
af = AFFile.load_native(file)

# Use default palette for AF sprites
default_palette = Palette()
# mask off the scene colors
default_palette.mask_range(0x60, 64)

for key, animation in af.moves.items():
for idx, sprite in enumerate(animation.sprites):
sprite_file = os.path.join(output_dir, f"{filename}-{key}-{idx}.png")
try:
sprite.save_png(sprite_file, alt_pals.palettes[0])
sprite.save_png(sprite_file, default_palette, asset_type="af_sprite")
except OMFInvalidDataException:
print(f"Skipping {sprite_file}")

Expand Down
56 changes: 54 additions & 2 deletions omftools/pyshadowdive/bk.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
import typing
from validx import Dict, List, Str
import io
import os

from .protos import Entrypoint
from .bkanim import BKAnimation
from .palette_mapping import PaletteMapping
from .palette import Palette

from .utils.parser import BinaryParser
from .utils.types import EncodedImage
Expand Down Expand Up @@ -95,7 +97,10 @@ def read(self, parser: BinaryParser) -> BKFile:

# Read up all available color palettes
palette_count = parser.get_uint8()
self.palettes = [PaletteMapping().read(parser) for _ in range(palette_count)]
self.palettes = []
for _ in range(palette_count):
palette_mapping = PaletteMapping().read(parser)
self.palettes.append(palette_mapping)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unneeded change -- some remnant ?


# Get sound mappings
self.sound_table = [parser.get_uint8() for _ in range(30)]
Expand Down Expand Up @@ -140,12 +145,59 @@ def write(self, parser: BinaryParser) -> None:
parser.put_uint8(sound)

def save_background(self, filename: str) -> None:
# Apply appropriate palette processing based on the filename
palette = self.get_processed_palette(filename)

save_png(
generate_png(
self.background_image,
self.background_width,
self.background_height,
self.palettes[0].colors,
palette,
),
filename,
)

def get_processed_palette(self, filename: str) -> Palette:
"""
Get palette with appropriate processing applied based on filename.

Args:
filename: File name used to determine palette processing
"""
if not self.palettes:
return Palette() # Return default palette if no palettes are available

# Start with a copy of the first palette's colors
palette = Palette()
for i in range(256):
palette.data[i] = self.palettes[0].colors.data[i]

# Extract basename and convert to uppercase for comparison
basename = os.path.basename(filename).upper()

# MECHLAB: Reset indices 0-47 and 250-255 to default
if "MECHLAB" in basename:
palette.reset_range(0, 48) # Reset indices 0-47
palette.reset_range(250, 6) # Reset indices 250-255
# ARENA0-ARENA4, VS, MELEE: Reset indices 0-96 and 250-255 to default
elif any(
name in basename
for name in [
"ARENA0",
"ARENA1",
"ARENA2",
"ARENA3",
"ARENA4",
"VS",
"MELEE",
]
):
palette.mask_range(0, 97) # Blank out 0-96, the HAR colors
palette.reset_range(250, 6) # Reset indices 250-255
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comments about reset_range() seem to be conflicting. Does reset_range(0, 96) include the last index? Since palette.reset_range(250, 6) seems to indicate the last index is not included.


# NORTH_AM, WAR, KATUSHAI: Extended color slides
elif any(name in basename for name in ["NORTH_AM", "WAR", "KATUSHAI"]):
palette.create_extended_slides()

return palette
Loading