Class: Lich::Gemstone::CreatureTemplate

Inherits:
Object
  • Object
show all
Defined in:
documented/gemstone/creature.rb

Overview

Static creature template data (ID-less reference information)

Constant Summary collapse

BOON_ADJECTIVES =

Adjectives that appear as a prefix to some creature names in bestiary lookups. When looking up a template, boon adjectives are stripped to normalize lookups (e.g. "dashing orc" -> "orc").

Includes weather effects (blurry, ethereal), conditions (diseased, sickly), dispositions (aggressive, raging), and visual states (glowing, shimmering).

See Also:

  • BOON_REGEX
%w[
  adroit afflicted apt barbed belligerent blurry canny combative dazzling deft diseased drab
  dreary ethereal flashy flexile flickering flinty frenzied ghastly ghostly gleaming glittering
  glorious glowing grotesque hardy illustrious indistinct keen lanky luminous lustrous muculent
  nebulous oozing pestilent radiant raging ready resolute robust rune-covered shadowy shifting
  shimmering shining sickly green sinuous slimy sparkling spindly spiny stalwart steadfast stout
  tattoed tenebrous tough twinkling unflinching unyielding wavering wispy
]
BOON_REGEX =

Clean creature name by removing boon adjectives Optimized to use single compiled regex instead of 50+ sequential matches

/^(#{BOON_ADJECTIVES.join('|')})\s+/i.freeze
@@templates =
{}
@@loaded =
false

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data) ⇒ CreatureTemplate

Returns a new instance of CreatureTemplate.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'documented/gemstone/creature.rb', line 45

def initialize(data)
  @name = data[:name]
  @url = data[:url]
  @picture = data[:picture]
  @level = data[:level]&.to_i
  @family = data[:family]
  @type = data[:type]
  @undead = data[:undead]
  # Tri-state (true/false/nil) - nil means uncatalogued/unknown, not false.
  @has_blood = data[:has_blood]
  @has_bones = data[:has_bones]
  @muggable = data[:muggable]
  @otherclass = data[:otherclass] || []
  @areas = data[:areas] || []
  @bcs = data[:bcs]
  @max_hp = data[:max_hp]&.to_i || data[:hitpoints]&.to_i
  @speed = data[:speed]
  @height = data[:height].to_i
  @size = data[:size]

  atk = data[:attack_attributes] || {}
  @attack_attributes = OpenStruct.new(
    physical_attacks: atk[:physical_attacks] || [],
    bolt_spells: atk[:bolt_spells] || [],
    warding_spells: normalize_spells(atk[:warding_spells]),
    offensive_spells: normalize_spells(atk[:offensive_spells]),
    maneuvers: atk[:maneuvers] || [],
    special_abilities: (atk[:special_abilities] || []).map { |s| SpecialAbility.new(s) }
  )

  @defense_attributes = DefenseAttributes.new(data[:defense_attributes] || {})
  @treasure = Treasure.new(data[:treasure] || {})
  @messaging = Messaging.new(data[:messaging] || {})
  @special_other = data[:special_other]
  @abilities = data[:abilities] || []
  @alchemy = data[:alchemy] || []
end

Instance Attribute Details

#abilitiesObject (readonly)

Returns the value of attribute abilities.



22
23
24
# File 'documented/gemstone/creature.rb', line 22

def abilities
  @abilities
end

#alchemyObject (readonly)

Returns the value of attribute alchemy.



22
23
24
# File 'documented/gemstone/creature.rb', line 22

def alchemy
  @alchemy
end

#areasObject (readonly)

Returns the value of attribute areas.



22
23
24
# File 'documented/gemstone/creature.rb', line 22

def areas
  @areas
end

#attack_attributesObject (readonly)

Returns the value of attribute attack_attributes.



22
23
24
# File 'documented/gemstone/creature.rb', line 22

def attack_attributes
  @attack_attributes
end

#bcsObject (readonly)

Returns the value of attribute bcs.



22
23
24
# File 'documented/gemstone/creature.rb', line 22

def bcs
  @bcs
end

#defense_attributesObject (readonly)

Returns the value of attribute defense_attributes.



22
23
24
# File 'documented/gemstone/creature.rb', line 22

def defense_attributes
  @defense_attributes
end

#familyObject (readonly)

Returns the value of attribute family.



22
23
24
# File 'documented/gemstone/creature.rb', line 22

def family
  @family
end

#heightObject (readonly)

Returns the value of attribute height.



22
23
24
# File 'documented/gemstone/creature.rb', line 22

def height
  @height
end

#levelObject (readonly)

Returns the value of attribute level.



22
23
24
# File 'documented/gemstone/creature.rb', line 22

def level
  @level
end

#max_hpObject (readonly)

Returns the value of attribute max_hp.



22
23
24
# File 'documented/gemstone/creature.rb', line 22

def max_hp
  @max_hp
end

#messagingObject (readonly)

Returns the value of attribute messaging.



22
23
24
# File 'documented/gemstone/creature.rb', line 22

def messaging
  @messaging
end

#nameObject (readonly)

Returns the value of attribute name.



22
23
24
# File 'documented/gemstone/creature.rb', line 22

def name
  @name
end

#otherclassObject (readonly)

Returns the value of attribute otherclass.



22
23
24
# File 'documented/gemstone/creature.rb', line 22

def otherclass
  @otherclass
end

#pictureObject (readonly)

Returns the value of attribute picture.



22
23
24
# File 'documented/gemstone/creature.rb', line 22

def picture
  @picture
end

#sizeObject (readonly)

Returns the value of attribute size.



22
23
24
# File 'documented/gemstone/creature.rb', line 22

def size
  @size
end

#special_otherObject (readonly)

Returns the value of attribute special_other.



22
23
24
# File 'documented/gemstone/creature.rb', line 22

def special_other
  @special_other
end

#speedObject (readonly)

Returns the value of attribute speed.



22
23
24
# File 'documented/gemstone/creature.rb', line 22

def speed
  @speed
end

#treasureObject (readonly)

Returns the value of attribute treasure.



22
23
24
# File 'documented/gemstone/creature.rb', line 22

def treasure
  @treasure
end

#typeObject (readonly)

Returns the value of attribute type.



22
23
24
# File 'documented/gemstone/creature.rb', line 22

def type
  @type
end

#undeadObject (readonly)

Returns the value of attribute undead.



22
23
24
# File 'documented/gemstone/creature.rb', line 22

def undead
  @undead
end

#urlObject (readonly)

Returns the value of attribute url.



22
23
24
# File 'documented/gemstone/creature.rb', line 22

def url
  @url
end

Class Method Details

.[](name) ⇒ Object

Lookup template by name



168
169
170
171
172
173
174
175
176
177
178
179
# File 'documented/gemstone/creature.rb', line 168

def self.[](name)
  load_all unless @@loaded
  return nil unless name

  # Try exact match first
  template = @@templates[name.downcase]
  return template if template

  # Try with boon adjectives removed
  normalized_name = fix_template_name(name)
  @@templates[normalized_name]
end

.allObject

Get all loaded templates



182
183
184
185
# File 'documented/gemstone/creature.rb', line 182

def self.all
  load_all unless @@loaded
  @@templates.values.uniq
end

.fix_template_name(template_name) ⇒ String

Normalizes a creature name for template lookup by removing boon adjectives and converting to lowercase.

The lookup key is always lowercase; boon adjectives ("dashing", "ethereal", "raging", etc.) are stripped as a prefix to match how multiple in-game instances of the same creature type may differ visually but share one template.

Examples:

fix_template_name("Ethereal Orc") #=> "orc"
fix_template_name("Raging Stone Elemental") #=> "stone elemental"

Parameters:

  • template_name (String)

    the creature name from the game or template

Returns:

  • (String)

    normalized lookup key (lowercase, boon adjectives removed)



147
148
149
150
151
# File 'documented/gemstone/creature.rb', line 147

def self.fix_template_name(template_name)
  name = template_name.dup.downcase
  name.sub!(BOON_REGEX, '')
  name.strip
end

.load_all(dir = File.join(File.dirname(__FILE__), 'creatures')) ⇒ Object

Load all templates from files dir defaults to the real templates directory; overridable so tests can load an isolated fixture directory instead.



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'documented/gemstone/creature.rb', line 86

def self.load_all(dir = File.join(File.dirname(__FILE__), 'creatures'))
  return if @@loaded
  return unless File.directory?(dir)

  template_count = 0
  Dir[File.join(dir, '*.rb')].each do |path|
    next if File.basename(path) == '_creature_template.rb'

    # Filename-derived name, used only as a fallback for files that
    # don't set their own :name - the file's own value takes priority
    # so a name with characters the filename can't represent (a
    # hyphen, an apostrophe) still round-trips correctly. Both the
    # display name and the lookup key come from the same source now;
    # previously both were overwritten from the filename regardless of
    # what the file itself said, silently breaking lookup for any
    # creature whose real name a slugified filename can't represent
    # exactly (e.g. "shield-maiden" -> "shield_maiden" -> "shield maiden").
    fallback_name = File.basename(path, '.rb').tr('_', ' ')

    begin
      # Safer loading with validation
      file_content = File.read(path)
      data = load_template_data(file_content, path)
      next unless data.is_a?(Hash)

      data[:name] = fallback_name if data[:name].to_s.strip.empty?
      normalized_name = fix_template_name(data[:name])
      if @@templates.key?(normalized_name) && $creature_debug
        respond "--- warning: '#{fallback_name}' collides with an already-loaded template on lookup key '#{normalized_name}' - one will silently overwrite the other"
      end
      template = new(data)
      @@templates[normalized_name] = template
      template_count += 1
    rescue StandardError, ScriptError => e
      # ScriptError (SyntaxError's parent) isn't a StandardError, so a
      # single template file with malformed Ruby would otherwise abort
      # load_all entirely instead of just being skipped.
      respond "--- error loading template #{fallback_name}: #{e.message}" if $creature_debug
    end
  end

  @@loaded = true
  respond "--- loaded #{template_count} creature templates" if $creature_debug
end

Instance Method Details

#has_blood?Boolean?

Returns whether the bestiary template says the creature has blood.

Returns:

  • (Boolean, nil)

    true or false when catalogued; nil when unknown.



190
191
192
# File 'documented/gemstone/creature.rb', line 190

def has_blood?
  @has_blood
end

#has_bones?Boolean?

Returns whether the bestiary template says the creature has bones.

Returns:

  • (Boolean, nil)

    true or false when catalogued; nil when unknown.



197
198
199
# File 'documented/gemstone/creature.rb', line 197

def has_bones?
  @has_bones
end

#muggable?Boolean?

Returns whether the bestiary template says the creature can be mugged.

Returns:

  • (Boolean, nil)

    true or false when catalogued; nil when unknown.



204
205
206
# File 'documented/gemstone/creature.rb', line 204

def muggable?
  @muggable
end