Class: Doom::Wad::SpriteManager

Inherits:
Object
  • Object
show all
Defined in:
lib/doom/wad/sprite.rb

Constant Summary collapse

THING_SPRITES =

Map thing types to sprite prefixes

{
  # Ammo
  2007 => 'CLIP', # Clip
  2048 => 'AMMO', # Box of ammo
  2008 => 'SHEL', # Shells
  2049 => 'SBOX', # Box of shells
  2010 => 'ROCK', # Rocket
  2046 => 'BROK', # Box of rockets
  2047 => 'CELL', # Cell charge
  17 => 'CELP',   # Cell pack

  # Weapons
  2001 => 'SHOT', # Shotgun
  2002 => 'MGUN', # Chaingun
  2003 => 'LAUN', # Rocket launcher
  2004 => 'PLAS', # Plasma rifle
  2006 => 'BFUG', # BFG 9000
  2005 => 'CSAW', # Chainsaw

  # Health/Armor
  2011 => 'STIM', # Stimpack
  2012 => 'MEDI', # Medikit
  2014 => 'BON1', # Health bonus
  2015 => 'BON2', # Armor bonus
  2018 => 'ARM1', # Green armor
  2019 => 'ARM2', # Blue armor

  # Keys
  5 => 'BKEY',    # Blue keycard
  6 => 'YKEY',    # Yellow keycard
  13 => 'RKEY',   # Red keycard
  40 => 'BSKU',   # Blue skull
  39 => 'YSKU',   # Yellow skull
  38 => 'RSKU',   # Red skull

  # Decorations
  2028 => 'COLU', # Light column
  30 => 'COL1',   # Tall green pillar
  31 => 'COL2',   # Short green pillar
  32 => 'COL3',   # Tall red pillar
  33 => 'COL4',   # Short red pillar
  34 => 'CAND',   # Candle
  44 => 'TBLU',   # Tall blue torch
  45 => 'TGRN',   # Tall green torch
  46 => 'TRED',   # Tall red torch
  48 => 'ELEC',   # Tall tech column
  35 => 'CBRA',   # Candelabra

  # Dead bodies / gore decorations
  10 => 'PLAY',   # Bloody mess
  12 => 'PLAY',   # Bloody mess 2
  15 => 'PLAY',   # Dead player
  24 => 'POL5',   # Pool of blood and flesh

  # Barrels
  2035 => 'BAR1', # Exploding barrel

  # Monsters
  3004 => 'POSS', # Zombieman
  9 => 'SPOS',    # Shotgun guy
  3001 => 'TROO', # Imp
  3002 => 'SARG', # Demon
  58 => 'SARG',   # Spectre (same as Demon)
  3003 => 'BOSS', # Baron of Hell
  3005 => 'HEAD', # Cacodemon
  3006 => 'SKUL', # Lost soul
  7 => 'SPID',    # Spider Mastermind
  16 => 'CYBR',   # Cyberdemon
}.freeze
THING_DEFAULT_FRAME =

Things that use a specific frame instead of ‘A’ From DOOM info.h mobjinfo spawnstate: MT_MISC10 (type 10) -> S_PLAY_XDIE9 = PLAY W (gibbed mess) MT_MISC12 (type 12) -> S_PLAY_DIE7 = PLAY N (dead body) MT_MISC15 (type 15) -> S_PLAY_DIE7 = PLAY N (dead body)

{
  10 => 'W',   # Bloody mess (gibbed)
  12 => 'N',   # Bloody mess 2 (dead body flat)
  15 => 'N',   # Dead player (dead body flat)
}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(wad) ⇒ SpriteManager

Returns a new instance of SpriteManager.



156
157
158
159
160
161
162
163
164
165
# File 'lib/doom/wad/sprite.rb', line 156

def initialize(wad)
  @wad = wad
  @cache = {}
  @rotation_cache = {}

  # Build sprite lump index: maps "PREFIXframe_rotation" -> [lump_name, mirrored?]
  # Handles combined lumps like SPOSA2A8 (rotation 2 normal, rotation 8 mirrored)
  @sprite_index = {}
  build_sprite_index
end

Instance Method Details

#[](thing_type) ⇒ Object

Get default sprite (rotation 0 or 1)



168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/doom/wad/sprite.rb', line 168

def [](thing_type)
  return @cache[thing_type] if @cache.key?(thing_type)

  prefix = THING_SPRITES[thing_type]
  return nil unless prefix

  frame = THING_DEFAULT_FRAME[thing_type] || 'A'
  sprite = load_sprite_frame(prefix, frame, 0) ||
           load_sprite_frame(prefix, frame, 1)

  @cache[thing_type] = sprite
  sprite
end

#get_frame(thing_type, frame_letter, viewer_angle, thing_angle) ⇒ Object

Get a specific frame (for death animations, etc.)



212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/doom/wad/sprite.rb', line 212

def get_frame(thing_type, frame_letter, viewer_angle, thing_angle)
  prefix = THING_SPRITES[thing_type]
  return nil unless prefix

  # Death frames typically use rotation 0 (same from all angles)
  sprite = load_sprite_frame(prefix, frame_letter, 0)
  return sprite if sprite

  # Try with calculated rotation (same formula as get_rotated)
  angle_diff = viewer_angle - (thing_angle * Math::PI / 180.0) + Math::PI
  angle_diff = angle_diff % (2 * Math::PI)
  angle_diff += 2 * Math::PI if angle_diff < 0
  rotation = ((angle_diff + Math::PI / 8) / (Math::PI / 4)).to_i % 8 + 1

  load_sprite_frame(prefix, frame_letter, rotation)
end

#get_frame_by_prefix(prefix, frame_letter) ⇒ Object

Get a frame by explicit prefix (for barrel explosions where prefix differs from thing type)



230
231
232
# File 'lib/doom/wad/sprite.rb', line 230

def get_frame_by_prefix(prefix, frame_letter)
  load_sprite_frame(prefix, frame_letter, 0)
end

#get_rotated(thing_type, viewer_angle, thing_angle) ⇒ Object

Get sprite for specific rotation (1-8, or 0 for all angles) viewer_angle: angle from viewer to sprite in radians thing_angle: thing’s facing angle in degrees



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/doom/wad/sprite.rb', line 190

def get_rotated(thing_type, viewer_angle, thing_angle)
  prefix = THING_SPRITES[thing_type]
  return nil unless prefix

  frame = THING_DEFAULT_FRAME[thing_type] || 'A'

  # Check for rotation 0 (all angles) sprite first
  sprite = load_sprite_frame(prefix, frame, 0)
  return sprite if sprite

  # Calculate rotation frame (1-8)
  # DOOM: rot = (R_PointToAngle(thing) - thing->angle + ANG45/2*9) >> 29
  # Rotation 1=front (viewer faces monster's front), 5=back
  angle_diff = viewer_angle - (thing_angle * Math::PI / 180.0) + Math::PI
  angle_diff = angle_diff % (2 * Math::PI)
  angle_diff += 2 * Math::PI if angle_diff < 0
  rotation = ((angle_diff + Math::PI / 8) / (Math::PI / 4)).to_i % 8 + 1

  load_sprite_frame(prefix, frame, rotation) || @cache[thing_type]
end

#prefix_for(thing_type) ⇒ Object

Get sprite prefix for a thing type



183
184
185
# File 'lib/doom/wad/sprite.rb', line 183

def prefix_for(thing_type)
  THING_SPRITES[thing_type]
end