Sabrina

A library for manipulating GBA ROMs of a popular monster collection RPG series. It is written entirely in Ruby and uses Chunky PNG, which is also a pure Ruby library. Compared to the many excellent GUI tools available, Sabrina focuses on non-interactive manipulation of ROM data.

Source code

github.com/Winterbraid/sabrina_gba

Gem

rubygems.org/gems/sabrina

Documentation

rubydoc.info/gems/sabrina/frames

Example use

Basic usage

require 'sabrina'
include Sabrina
r = Rom.new "Decap and Attack Rombase 1.5.gba"
# => MrDollSteak's Decap and Attack Rombase [MrDS]
m = Monster.new r, 36 # => 36. Clef/name redacted/
m.stats.to_json
# =>
# {
#   "36": {
#     "stats": {
#       "hp": 95,
#       "attack": 70,
#       "defense": 73,
#       "speed": 60,
#       "sp_atk": 85,
#       "sp_def": 90,
#       "type_1": "23 (Fairy)",
# /output truncated/
m.save_spritesheet
# => #<File:Decap and Attack Rombase 1.5_files/036.png (closed)>
r.close # => 0

Copy sprites between ROMs

require 'benchmark'
require 'sabrina'
include Sabrina
r1 = Rom.new 'Moemon FireRed (1.5).gba'
r2 = Rom.new 'Ruby (E).gba'
puts "Copying sprites from #{r1} to #{r2}."
b = Benchmark.measure do
  (1..414).each do |i|
    m = Monster.new r1, i
    print "#{ m.to_s.ljust(20, ' ') }\r"
    m.rom = r2
    m.write_spritesheet
  end
end
r1.close
r2.close
puts "\nTook #{b.real} seconds."

Sabrina is…

…a backend. The main purpose of the library is to be used inside other programs. That said, Ruby comes packaged with a robust interactive interpreter in the form of irb, and the classes and methods of Sabrina are intended to be human-friendly enough to easily perform many tasks from the irb prompt with even a rudimentary knowledge of Ruby.

…reasonably quick. While Ruby is not the speediest language out there, Sabrina employs internal caching to avoid certain costly operations when possible. This design particularly shines in the use case of copying data between two ROMs, where Sabrina should always be faster than a tool that relies on temporary HDD files or multiple program instances.

…extensible. ROM types should be recognized automatically, and adding support for new ROM bases is as simple as dropping a JSON file in ~/.sabrina (assuming the ROM uses a unique ID). The code is designed to allow easy addition of data abstractions, which means new features should arrive at a reasonable pace.

…mostly clean. The library itself is warning-free (any warnings produced with the -w switch come from ChunkyPNG). Adherence to the Ruby Style Guide, while not strict, is kept at what is perceived to be a reasonable level.

Sabrina is not…

…complete. Currently the Monster class provides an abstraction for dealing with monster data, and handlers exist for sprites and base stats. Adding support for other monster-related data sets such as evolutions or dex entries is a high priority, after which moves and items may be looked at.

…a user interface. It comes with no GUI or CLI in the traditional sense, and it is unlikely one will be included. However, scripts are in the works that should cover many common use cases and provide inspiration for advanced users to write their own.

…a backup manager. In accordance with the above, all write operations will be performed directly on the ROM, without waiting for a separate save command, and there is no undo feature. Therefore, it is the user’s responsibility to maintain backups of ROM files.

…a limit remover/table expander. If you need those, you should try G3HS, look for a premade expanded ROM base, or refer to a tutorial. However, Sabrina does try to make as few assumptions about limits as possible, so expanded ROMs should be supported out of the box (although custom IDs and config files might be required if table offsets have been changed).

Known issues

  • Either the Lz77 compressor or the image encoder has a problem with the monster no. 360 for some reason. Copying from another ROM still works fine (likely because it bypasses the encoding step and uses the data from the source ROM directly), but loading from PNG will result in garbled sprites for frames 3-4.

Currently missing features include:

  • Support for Sapphire and LeafGreen.

  • Support for additional data abstractions beyond sprite sheets and stats may be included depending on resources and feedback.

  • Support for moves.