class Sabrina::Plugins::Stats

@todo Finish this class. This {Plugin} aids in manipulating the basic stats of any {Monster}.

@see Plugin

Constants

EGG_GROUPS

Code names for egg groups.

ENHANCES

An abstract class for dealing with further abstractions of data related to a specific, numbered monster.

See {Sabrina::Plugins} for extensions that might enhance this class with added functionality.

FEATURES

@see Plugin::FEATURES

LEVEL_CURVES

Code names for level up types.

NAMES

Where to pull descriptive names from if applicable, these can be arrays or ROM tables.

PLUGIN_NAME

@see Plugin::PLUGIN_NAME

SHORT_NAME

@see Plugin::SHORT_NAME

STRUCTURE

Describes the order in which various stats appear in the byte data. All of these will also be converted into attributes on runtime and can be modified directly.

Attributes

index[RW]

@!attribute [rw] rom

The current working ROM file.
@return [Rom]

@!attribute [rw] index

The real index of the monster.
@return [Integer]
rom[RW]

@!attribute [rw] rom

The current working ROM file.
@return [Rom]

@!attribute [rw] index

The real index of the monster.
@return [Integer]

Public Class Methods

new(monster) click to toggle source

Generates a new Stats object.

@return [Stats]

# File lib/sabrina/plugins/stats.rb, line 67
def initialize(monster)
  @monster = monster
  @rom = monster.rom
  @index = monster.index

  @stream = Bytestream.from_table(
    @rom,
    :stats_table,
    @monster.index,
    @rom.stats_length
  )

  parse_stats
end

Public Instance Methods

reread() click to toggle source

Reloads the data from a ROM, dropping any changes.

@return [self]

# File lib/sabrina/plugins/stats.rb, line 92
def reread
  parse_stats
  self
end
stream() click to toggle source

Returns a {Bytestream} object representing the stats, ready to be written to the ROM.

@return [Bytestream]

# File lib/sabrina/plugins/stats.rb, line 106
def stream
  Bytestream.from_bytes(
    unparse_stats,
    rom: @rom,
    table: :stats_table,
    index: @index
  )
end
to_h() click to toggle source

Returns a hash representation of the stats.

@return [Hash]

# File lib/sabrina/plugins/stats.rb, line 118
def to_h
  h = {}

  STRUCTURE.each do |entry|
    h[entry] = instance_variable_get('@' << entry.to_s)
  end

  { @index => { stats: h } }
end
to_hex() click to toggle source

Returns a pretty hexadecimal representation of the stats byte data.

@return [String]

# File lib/sabrina/plugins/stats.rb, line 131
def to_hex
  stream.to_hex(true)
end
to_json() click to toggle source

Returns a pretty JSON representation of the stats.

@return [String]

# File lib/sabrina/plugins/stats.rb, line 138
def to_json
  JSON.pretty_generate(to_h)
end
to_s() click to toggle source

Returns a blurb containing the base stats total.

@return [String]

# File lib/sabrina/plugins/stats.rb, line 145
def to_s
  "<Stats (#{total})>"
end
total() click to toggle source

Returns the base stats total.

@return [Integer]

# File lib/sabrina/plugins/stats.rb, line 85
def total
  @hp + @attack + @defense + @speed + @sp_atk + @sp_def
end
write() click to toggle source

Write data to the ROM.

# File lib/sabrina/plugins/stats.rb, line 98
def write
  stream.write_to_rom
end

Private Instance Methods

gender_info(i) click to toggle source

Displays readable info about the gender distribution defined by the provided gender value.

# File lib/sabrina/plugins/stats.rb, line 209
def gender_info(i)
  return 'Genderless' if i > 254
  return 'Always Female' if i == 254
  return 'Always Male' if i == 0
  "#{(100.0 * i / 255).round}% Female"
end
parse_color_flip(b) click to toggle source

Converts a byte into an array of dex color and flip.

# File lib/sabrina/plugins/stats.rb, line 242
def parse_color_flip(b)
  s = b.unpack('C').first.to_s(16).rjust(2, '0')

  [
    s[1].to_i,
    s[0] == '8' ? true : false
  ]
end
parse_evs(b) click to toggle source

Converts a word (two bytes) into a hash of EV yield data.

# File lib/sabrina/plugins/stats.rb, line 217
def parse_evs(b)
  a = b.unpack('b*').first.scan(/../).map { |x| x.reverse.to_i(2) }
  h = {}

  a.take(6).each_index do |i|
    next if a[i] < 1
    h[STRUCTURE[i]] = a[i]
  end

  h
end
parse_stats() click to toggle source

Reads stats data from the ROM.

# File lib/sabrina/plugins/stats.rb, line 152
def parse_stats
  b = @stream.to_bytes.dup

  STRUCTURE.each do |entry|
    value =
      case entry
      when :ev_yield
        parse_evs(b.slice!(0, 2))
      when :item_1, :item_2
        b.slice!(0, 2).unpack('S').first
      when :color_flip
        parse_color_flip(b.slice!(0))
      else
        b.slice!(0).unpack('C').first
      end

    pretty_value = prettify_stat(entry, value)
    instance_variable_set('@' << entry.to_s, pretty_value)
  end
end
prettify_stat(entry, value) click to toggle source

Attempts to annotate a numeric value with useful information.

# File lib/sabrina/plugins/stats.rb, line 194
def prettify_stat(entry, value)
  return "#{value} (#{gender_info(value)})" if entry == :gender

  return value unless NAMES.key?(entry) && value.is_a?(Numeric)

  zero_is_valid = [:type_1, :type_2, :level_curve]
  return value if value == 0 && !zero_is_valid.include?(entry)

  return "#{value} (#{NAMES[entry][value]})" if NAMES[entry].is_a?(Array)

  "#{value} (#{ @rom.read_string_from_table(NAMES[entry], value) })"
end
unparse_color_flip(a) click to toggle source

Converts an array of dex color and flip into a byte.

# File lib/sabrina/plugins/stats.rb, line 252
def unparse_color_flip(a)
  ((a.last ? '8' : '0') << a.first.to_s).hex.chr
end
unparse_evs(h) click to toggle source

Converts a hash of EV yield data into a word (two bytes).

# File lib/sabrina/plugins/stats.rb, line 230
def unparse_evs(h)
  a = []

  STRUCTURE.take(6).each do |stat|
    ev = h.fetch(stat, 0)
    a << ev.to_s(2).rjust(2, '0').reverse
  end

  [a.join.ljust(16, '0')].pack 'b*'
end
unparse_stats() click to toggle source

Converts stats data to a GBA-compatible byte string.

# File lib/sabrina/plugins/stats.rb, line 174
def unparse_stats
  b = ''
  STRUCTURE.each do |entry|
    val = instance_variable_get('@' << entry.to_s)
    case entry
    when :ev_yield
      b << unparse_evs(val)
    when :item_1, :item_2
      b << [val.to_i].pack('S')
    when :color_flip
      b << unparse_color_flip(val)
    else
      b << [val.to_i].pack('C')
    end
  end

  b.ljust(28, "\x00")
end