Class: Quake::Game::PlayerState

Inherits:
Object
  • Object
show all
Defined in:
lib/quake/game/player_state.rb

Overview

Tracks player game state: health, armor, ammo, weapons. Separate from physics (Physics::Player handles movement/collision).

Defined Under Namespace

Classes: FireResult

Constant Summary collapse

WEAPONS =
%i[axe shotgun super_shotgun nailgun super_nailgun
grenade_launcher rocket_launcher lightning_gun].freeze
WEAPON_MODELS =
{
  axe:              "progs/v_axe.mdl",
  shotgun:          "progs/v_shot.mdl",
  super_shotgun:    "progs/v_shot2.mdl",
  nailgun:          "progs/v_nail.mdl",
  super_nailgun:    "progs/v_nail2.mdl",
  grenade_launcher: "progs/v_rock.mdl",
  rocket_launcher:  "progs/v_rock2.mdl",
  lightning_gun:    "progs/v_light.mdl"
}.freeze
WEAPON_AMMO =

Ammo type per weapon

{
  axe:              nil,
  shotgun:          :shells,
  super_shotgun:    :shells,
  nailgun:          :nails,
  super_nailgun:    :nails,
  grenade_launcher: :rockets,
  rocket_launcher:  :rockets,
  lightning_gun:    :cells
}.freeze
POWERUP_DURATIONS =
{
  biosuit: 30.0,
  pentagram: 30.0,
  ring: 30.0,
  quad: 30.0
}.freeze
EF_DIMLIGHT =
8
EF_BLUE =
64
EF_RED =
128
POWERUP_EFFECT_BITS =
EF_DIMLIGHT | EF_BLUE | EF_RED
FL_CLIENT =
8
FL_GODMODE =
64
FL_WATERJUMP =
2048
FL_JUMPRELEASED =
4096
WEAPON_ITEM_INDEX =
{
  shotgun: 0,
  super_shotgun: 1,
  nailgun: 2,
  super_nailgun: 3,
  grenade_launcher: 4,
  rocket_launcher: 5,
  lightning_gun: 6
}.freeze
WEAPON_FIRE =

QuakeC weapons.qc/player.qc weapon fire parameters.

{
  axe: {
    cooldown: 0.5,
    ammo_type: nil,
    ammo_cost: 0,
    sound: "weapons/ax1.wav",
    range: 64.0,
    damage: 20,
    animation_frames: 1..4,
    kind: :axe
  },
  shotgun: {
    cooldown: 0.5,
    ammo_type: :shells,
    ammo_cost: 1,
    sound: "weapons/guncock.wav",
    pellets: 6,
    range: 2048.0,
    spread_x: 0.04,
    spread_y: 0.04,
    damage: 4,
    kick: :small,
    animation_frames: 1..6,
    kind: :bullets
  },
  super_shotgun: {
    cooldown: 0.7,
    ammo_type: :shells,
    ammo_cost: 2,
    sound: "weapons/shotgn2.wav",
    pellets: 14,
    range: 2048.0,
    spread_x: 0.14,
    spread_y: 0.08,
    damage: 4,
    kick: :big,
    animation_frames: 1..6,
    kind: :bullets
  },
  nailgun: {
    cooldown: 0.2,
    ammo_type: :nails,
    ammo_cost: 1,
    sound: "weapons/rocket1i.wav",
    range: 1000.0,
    damage: 9,
    kick: :small,
    animation_frames: 1..8,
    kind: :spike
  },
  super_nailgun: {
    cooldown: 0.2,
    ammo_type: :nails,
    ammo_cost: 2,
    sound: "weapons/spike2.wav",
    range: 1000.0,
    damage: 18,
    kick: :small,
    animation_frames: 1..8,
    kind: :spike
  },
  rocket_launcher: {
    cooldown: 0.8,
    ammo_type: :rockets,
    ammo_cost: 1,
    sound: "weapons/sgun1.wav",
    range: 1000.0,
    damage: 100,
    damage_variance: 20,
    radius_damage: 120,
    kick: :small,
    animation_frames: 1..6,
    kind: :rocket
  },
  lightning_gun: {
    cooldown: 0.1,
    ammo_type: :cells,
    ammo_cost: 1,
    sound: "weapons/lhit.wav",
    range: 600.0,
    damage: 30,
    kick: :small,
    animation_frames: 1..4,
    kind: :lightning
  },
  grenade_launcher: {
    cooldown: 0.6,
    ammo_type: :rockets,
    ammo_cost: 1,
    sound: "weapons/grenade.wav",
    damage: 120,
    radius_damage: 120,
    kick: :small,
    animation_frames: 1..6,
    kind: :grenade
  }
}.freeze
MAX_HEALTH =

Max ammo capacities (from Quake defs.qc)

100
MAX_MEGA_HEALTH =
250
MAX_ARMOR =
200
MAX_SHELLS =
100
MAX_NAILS =
200
MAX_ROCKETS =
100
MAX_CELLS =
100
DEAD_NO =
0
DEAD_DYING =
1
DEAD_DEAD =
2
DEAD_RESPAWNABLE =
3
DEFAULT_VIEW_OFFSET =
Math::Vec3.new(0.0, 0.0, 22.0)
DEATH_VIEW_OFFSET =
Math::Vec3.new(0.0, 0.0, -8.0)
GIB_VIEW_OFFSET =
Math::Vec3.new(0.0, 0.0, 8.0)
ARMOR_SAVE =
{
  0 => 0.0,
  1 => 0.3,
  2 => 0.6,
  3 => 0.8,
  0.0 => 0.0,
  0.3 => 0.3,
  0.6 => 0.6,
  0.8 => 0.8
}.freeze
AMMO_CAPS =
{
  shells: MAX_SHELLS, nails: MAX_NAILS,
  rockets: MAX_ROCKETS, cells: MAX_CELLS
}.freeze
WEAPON_PICKUP_RANK =

QuakeC items.qc RankForWeapon: lower ranks are preferred on pickup.

{
  lightning_gun: 1,
  rocket_launcher: 2,
  super_nailgun: 3,
  grenade_launcher: 4,
  super_shotgun: 5,
  nailgun: 6
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializePlayerState

Returns a new instance of PlayerState.



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/quake/game/player_state.rb', line 172

def initialize
  @health = 100
  @armor = 0
  @armor_type = 0 # 0=none, 1=green(30%), 2=yellow(60%), 3=red(80%)
  @current_weapon = :shotgun
  @weapons_owned = Set.new([:axe, :shotgun])
  @keys_owned = Set.new
  @serverflags = 0
  @flags = FL_CLIENT
  @ammo = { shells: 25, nails: 0, rockets: 0, cells: 0 }
  @powerup_finished = {}
  @powerup_warning_time = {}
  @weapon_gettime = {}
  @megahealth_rot_time = nil
  @effects = 0
  @deathtype = ""
  @deadflag = DEAD_NO
  @view_offset = DEFAULT_VIEW_OFFSET
  @weapon_model = nil
  @face_anim_time = 0.0
  @frags = 0
  @show_hostile = 0.0
  @b_switch = 8
  @w_switch = 8
  @centerprint = nil
end

Instance Attribute Details

#ammoObject (readonly)

Returns the value of attribute ammo.



169
170
171
# File 'lib/quake/game/player_state.rb', line 169

def ammo
  @ammo
end

#armorObject

Returns the value of attribute armor.



166
167
168
# File 'lib/quake/game/player_state.rb', line 166

def armor
  @armor
end

#armor_typeObject

Returns the value of attribute armor_type.



166
167
168
# File 'lib/quake/game/player_state.rb', line 166

def armor_type
  @armor_type
end

#b_switchObject

Returns the value of attribute b_switch.



166
167
168
# File 'lib/quake/game/player_state.rb', line 166

def b_switch
  @b_switch
end

#centerprintObject

Returns the value of attribute centerprint.



166
167
168
# File 'lib/quake/game/player_state.rb', line 166

def centerprint
  @centerprint
end

#current_weaponObject

Returns the value of attribute current_weapon.



166
167
168
# File 'lib/quake/game/player_state.rb', line 166

def current_weapon
  @current_weapon
end

#deadflagObject

Returns the value of attribute deadflag.



166
167
168
# File 'lib/quake/game/player_state.rb', line 166

def deadflag
  @deadflag
end

#deathtypeObject

Returns the value of attribute deathtype.



166
167
168
# File 'lib/quake/game/player_state.rb', line 166

def deathtype
  @deathtype
end

#effectsObject (readonly)

Returns the value of attribute effects.



169
170
171
# File 'lib/quake/game/player_state.rb', line 169

def effects
  @effects
end

#face_anim_timeObject

Returns the value of attribute face_anim_time.



166
167
168
# File 'lib/quake/game/player_state.rb', line 166

def face_anim_time
  @face_anim_time
end

#flagsObject

Returns the value of attribute flags.



166
167
168
# File 'lib/quake/game/player_state.rb', line 166

def flags
  @flags
end

#fragsObject

Returns the value of attribute frags.



166
167
168
# File 'lib/quake/game/player_state.rb', line 166

def frags
  @frags
end

#healthObject

Returns the value of attribute health.



166
167
168
# File 'lib/quake/game/player_state.rb', line 166

def health
  @health
end

#keys_ownedObject (readonly)

Returns the value of attribute keys_owned.



169
170
171
# File 'lib/quake/game/player_state.rb', line 169

def keys_owned
  @keys_owned
end

#megahealth_rot_timeObject (readonly)

Returns the value of attribute megahealth_rot_time.



169
170
171
# File 'lib/quake/game/player_state.rb', line 169

def megahealth_rot_time
  @megahealth_rot_time
end

#powerup_finishedObject (readonly)

Returns the value of attribute powerup_finished.



169
170
171
# File 'lib/quake/game/player_state.rb', line 169

def powerup_finished
  @powerup_finished
end

#powerup_warning_timeObject (readonly)

Returns the value of attribute powerup_warning_time.



169
170
171
# File 'lib/quake/game/player_state.rb', line 169

def powerup_warning_time
  @powerup_warning_time
end

#serverflagsObject (readonly)

Returns the value of attribute serverflags.



169
170
171
# File 'lib/quake/game/player_state.rb', line 169

def serverflags
  @serverflags
end

#show_hostileObject

Returns the value of attribute show_hostile.



166
167
168
# File 'lib/quake/game/player_state.rb', line 166

def show_hostile
  @show_hostile
end

#view_offsetObject

Returns the value of attribute view_offset.



166
167
168
# File 'lib/quake/game/player_state.rb', line 166

def view_offset
  @view_offset
end

#w_switchObject

Returns the value of attribute w_switch.



166
167
168
# File 'lib/quake/game/player_state.rb', line 166

def w_switch
  @w_switch
end

#weapon_gettimeObject (readonly)

Returns the value of attribute weapon_gettime.



169
170
171
# File 'lib/quake/game/player_state.rb', line 169

def weapon_gettime
  @weapon_gettime
end

#weapon_modelObject

Returns the value of attribute weapon_model.



166
167
168
# File 'lib/quake/game/player_state.rb', line 166

def weapon_model
  @weapon_model
end

#weapons_ownedObject (readonly)

Returns the value of attribute weapons_owned.



169
170
171
# File 'lib/quake/game/player_state.rb', line 169

def weapons_owned
  @weapons_owned
end

Instance Method Details

#add_ammo(type, amount, auto_switch: false, water_level: 0) ⇒ Object

Add ammo, returns true if picked up



570
571
572
573
574
575
576
577
578
579
580
581
# File 'lib/quake/game/player_state.rb', line 570

def add_ammo(type, amount, auto_switch: false, water_level: 0)
  return false unless alive?

  cap = AMMO_CAPS[type]
  return false unless cap
  return false if @ammo[type] >= cap

  old_best = best_weapon(water_level: water_level) if auto_switch
  @ammo[type] = [@ammo[type] + amount, cap].min
  @current_weapon = best_weapon(water_level: water_level) if auto_switch && @current_weapon == old_best
  true
end

#add_armor(points, type) ⇒ Object

Add armor, returns true if picked up



391
392
393
394
395
396
397
398
399
400
401
402
403
# File 'lib/quake/game/player_state.rb', line 391

def add_armor(points, type)
  return false unless alive?

  # QuakeC armor_touch compares armortype * armorvalue against
  # incoming type * value, where armortype is the save fraction.
  current_protection = ARMOR_SAVE.fetch(@armor_type, 0.0) * @armor
  incoming_protection = ARMOR_SAVE.fetch(type, 0.0) * points
  return false if current_protection >= incoming_protection

  @armor = [points, MAX_ARMOR].min
  @armor_type = type
  true
end

#add_backpack(ammo:, weapon: nil, water_level: 0, game_time: nil, b_switch: nil) ⇒ Object



583
584
585
586
587
588
589
590
591
592
593
594
595
596
# File 'lib/quake/game/player_state.rb', line 583

def add_backpack(ammo:, weapon: nil, water_level: 0, game_time: nil, b_switch: nil)
  return false unless alive?

  ammo.each do |type, amount|
    add_ammo(type, amount) if amount.positive?
  end

  if weapon
    current = @current_weapon
    give_weapon(weapon, game_time: game_time)
    @current_weapon = current unless backpack_weapon_switch_allowed?(weapon, water_level, b_switch)
  end
  true
end

#add_health(amount, mega: false, game_time: nil) ⇒ Object

Add health, returns true if picked up



365
366
367
368
369
370
371
372
373
374
# File 'lib/quake/game/player_state.rb', line 365

def add_health(amount, mega: false, game_time: nil)
  max = mega ? MAX_MEGA_HEALTH : MAX_HEALTH
  return false if @health <= 0
  return false if @health >= max

  amount = amount.to_f.ceil
  @health = [@health + amount, max].min
  @megahealth_rot_time = game_time.to_f + 5.0 if mega && game_time
  true
end

#add_key(key) ⇒ Object



414
415
416
417
418
419
420
# File 'lib/quake/game/player_state.rb', line 414

def add_key(key)
  return false unless alive?
  return false if @keys_owned.include?(key)

  @keys_owned.add(key)
  true
end

#add_powerup(powerup, game_time:, finish_time: nil) ⇒ Object



405
406
407
408
409
410
411
412
# File 'lib/quake/game/player_state.rb', line 405

def add_powerup(powerup, game_time:, finish_time: nil)
  return false unless alive?

  duration = POWERUP_DURATIONS.fetch(powerup)
  @powerup_finished[powerup] = finish_time&.to_f || game_time.to_f + duration
  @powerup_warning_time[powerup] = 1.0
  true
end

#add_sigil(flags) ⇒ Object



430
431
432
433
434
435
436
# File 'lib/quake/game/player_state.rb', line 430

def add_sigil(flags)
  return false unless alive?

  sigil_flags = flags.to_i & 15
  @serverflags |= sigil_flags
  true
end

#advance_serverflags_commandObject



438
439
440
# File 'lib/quake/game/player_state.rb', line 438

def advance_serverflags_command
  @serverflags = (@serverflags * 2) + 1
end

#alive?Boolean

Returns:

  • (Boolean)


258
259
260
# File 'lib/quake/game/player_state.rb', line 258

def alive?
  @health > 0
end

#apply_changelevel_parmsObject



484
485
486
487
488
489
490
491
492
493
494
495
# File 'lib/quake/game/player_state.rb', line 484

def apply_changelevel_parms
  if @health <= 0
    reset_to_new_parms
    return
  end

  @keys_owned.clear
  clear_temporary_powerups
  @megahealth_rot_time = nil
  @health = [[@health, 50].max, 100].min
  @ammo[:shells] = 25 if @ammo[:shells] < 25
end

#backpack_weapon_switch_allowed?(weapon, water_level, b_switch) ⇒ Boolean

Returns:

  • (Boolean)


598
599
600
601
602
603
604
# File 'lib/quake/game/player_state.rb', line 598

def backpack_weapon_switch_allowed?(weapon, water_level, b_switch)
  return false if weapon == :lightning_gun && water_level.positive?

  switch_limit = b_switch.to_i
  switch_limit = 8 if switch_limit.zero?
  weapon_code(weapon) <= switch_limit
end

#best_weapon(water_level: 0) ⇒ Object



304
305
306
307
308
309
310
311
312
# File 'lib/quake/game/player_state.rb', line 304

def best_weapon(water_level: 0)
  return :lightning_gun if water_level <= 1 && @weapons_owned.include?(:lightning_gun) && @ammo[:cells] >= 1
  return :super_nailgun if @weapons_owned.include?(:super_nailgun) && @ammo[:nails] >= 2
  return :super_shotgun if @weapons_owned.include?(:super_shotgun) && @ammo[:shells] >= 2
  return :nailgun if @weapons_owned.include?(:nailgun) && @ammo[:nails] >= 1
  return :shotgun if @weapons_owned.include?(:shotgun) && @ammo[:shells] >= 1

  :axe
end

#can_fire_current_weapon?Boolean

Returns:

  • (Boolean)


266
267
268
269
270
271
272
# File 'lib/quake/game/player_state.rb', line 266

def can_fire_current_weapon?
  _weapon, fire = effective_fire_definition
  return false unless fire

  ammo_type = fire[:ammo_type]
  ammo_type.nil? || @ammo[ammo_type] >= fire[:ammo_cost]
end

#classnameObject



262
263
264
# File 'lib/quake/game/player_state.rb', line 262

def classname
  "player"
end

#clear_powerups_on_deathObject



480
481
482
# File 'lib/quake/game/player_state.rb', line 480

def clear_powerups_on_death
  clear_temporary_powerups
end

#clear_temporary_powerupsObject



521
522
523
524
525
# File 'lib/quake/game/player_state.rb', line 521

def clear_temporary_powerups
  @powerup_finished.clear
  @powerup_warning_time.clear
  @effects &= ~POWERUP_EFFECT_BITS
end

#consume_key(key) ⇒ Object



426
427
428
# File 'lib/quake/game/player_state.rb', line 426

def consume_key(key)
  @keys_owned.delete?(key)
end

#current_ammo_countObject



203
204
205
206
# File 'lib/quake/game/player_state.rb', line 203

def current_ammo_count
  type = current_ammo_type
  type ? @ammo[type] : nil # nil = infinite (axe)
end

#current_ammo_typeObject



199
200
201
# File 'lib/quake/game/player_state.rb', line 199

def current_ammo_type
  WEAPON_AMMO[@current_weapon]
end

#current_weapon_cooldownObject



318
319
320
# File 'lib/quake/game/player_state.rb', line 318

def current_weapon_cooldown
  WEAPON_FIRE.dig(@current_weapon, :cooldown) || 0.0
end

#current_weapon_modelObject



208
209
210
211
212
# File 'lib/quake/game/player_state.rb', line 208

def current_weapon_model
  return @weapon_model unless @weapon_model.nil?

  WEAPON_MODELS[@current_weapon]
end

#effective_fire_definitionObject



547
548
549
550
551
552
553
554
555
556
557
# File 'lib/quake/game/player_state.rb', line 547

def effective_fire_definition
  if @current_weapon == :super_shotgun && @ammo[:shells] == 1
    return [:shotgun, WEAPON_FIRE[:shotgun]]
  end

  if @current_weapon == :super_nailgun && @ammo[:nails] == 1
    return [:nailgun, WEAPON_FIRE[:nailgun]]
  end

  [@current_weapon, WEAPON_FIRE[@current_weapon]]
end

#fire_current_weapon(water_level: 0, deathmatch: 0) ⇒ Object



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# File 'lib/quake/game/player_state.rb', line 274

def fire_current_weapon(water_level: 0, deathmatch: 0)
  weapon, fire = effective_fire_definition
  return nil unless fire
  unless can_fire_current_weapon?
    @current_weapon = best_weapon(water_level: water_level)
    return nil
  end

  ammo_type = fire[:ammo_type]
  @ammo[ammo_type] -= fire[:ammo_cost] if ammo_type && deathmatch.to_i != 4

  damage = fire[:damage]
  damage = 75 if weapon == :axe && deathmatch.to_i > 3

  FireResult.new(
    weapon: weapon,
    sound: fire[:sound],
    pellets: fire[:pellets],
    range: fire[:range],
    spread_x: fire[:spread_x],
    spread_y: fire[:spread_y],
    damage: damage,
    damage_variance: fire[:damage_variance],
    radius_damage: fire[:radius_damage],
    kick: fire[:kick],
    animation_frames: fire[:animation_frames],
    kind: fire[:kind]
  )
end

#give_weapon(weapon, ammo_type: nil, ammo_amount: 0, water_level: 0, game_time: nil, w_switch: nil) ⇒ Object

Give weapon, returns true if Quake weapon_touch accepts the pickup.



619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
# File 'lib/quake/game/player_state.rb', line 619

def give_weapon(weapon, ammo_type: nil, ammo_amount: 0, water_level: 0, game_time: nil, w_switch: nil)
  return false unless alive?

  had_weapon = @weapons_owned.include?(weapon)
  @weapons_owned.add(weapon)
  record_weapon_gettime(weapon, game_time) unless had_weapon

  add_ammo(ammo_type, ammo_amount) if ammo_type && ammo_amount > 0

  if weapon_pickup_rank(weapon) < weapon_pickup_rank(@current_weapon) &&
     weapon_switch_allowed?(weapon, water_level, w_switch)
    @current_weapon = weapon
  end
  true
end

#handle_impulse_command(impulse) ⇒ Object



245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/quake/game/player_state.rb', line 245

def handle_impulse_command(impulse)
  command = impulse.to_i
  if (1..WEAPONS.size).cover?(command)
    select_weapon(command)
  elsif command == 10
    next_weapon
  elsif command == 11
    advance_serverflags_command
  elsif command == 12
    prev_weapon
  end
end

#has_key?(key) ⇒ Boolean

Returns:

  • (Boolean)


422
423
424
# File 'lib/quake/game/player_state.rb', line 422

def has_key?(key)
  @keys_owned.include?(key)
end

#invulnerable_to_damage?(game_time:) ⇒ Boolean

Returns:

  • (Boolean)


451
452
453
454
# File 'lib/quake/game/player_state.rb', line 451

def invulnerable_to_damage?(game_time:)
  finished = @powerup_finished[:pentagram]
  finished && finished >= game_time.to_f
end

#next_weaponObject

Cycle to next owned weapon (mousewheel or number keys)



215
216
217
218
219
220
221
222
223
224
# File 'lib/quake/game/player_state.rb', line 215

def next_weapon
  idx = WEAPONS.index(@current_weapon) || 0
  WEAPONS.size.times do
    idx = (idx + 1) % WEAPONS.size
    if selectable_weapon?(WEAPONS[idx])
      @current_weapon = WEAPONS[idx]
      return
    end
  end
end

#powerup_active?(powerup, game_time:) ⇒ Boolean

Returns:

  • (Boolean)


442
443
444
# File 'lib/quake/game/player_state.rb', line 442

def powerup_active?(powerup, game_time:)
  (@powerup_finished[powerup] || 0.0) > game_time.to_f
end

#powerup_item_active?(powerup, game_time:) ⇒ Boolean

Returns:

  • (Boolean)


446
447
448
449
# File 'lib/quake/game/player_state.rb', line 446

def powerup_item_active?(powerup, game_time:)
  finished = @powerup_finished[powerup]
  finished && finished >= game_time.to_f
end

#prev_weaponObject



226
227
228
229
230
231
232
233
234
235
# File 'lib/quake/game/player_state.rb', line 226

def prev_weapon
  idx = WEAPONS.index(@current_weapon) || 0
  WEAPONS.size.times do
    idx = (idx - 1) % WEAPONS.size
    if selectable_weapon?(WEAPONS[idx])
      @current_weapon = WEAPONS[idx]
      return
    end
  end
end

#record_weapon_gettime(weapon, game_time) ⇒ Object



647
648
649
650
651
652
# File 'lib/quake/game/player_state.rb', line 647

def record_weapon_gettime(weapon, game_time)
  index = WEAPON_ITEM_INDEX[weapon]
  return unless index && game_time

  @weapon_gettime[index] = game_time.to_f
end

#reset_spawn_runtime_fieldsObject



497
498
499
500
501
502
503
504
505
506
507
# File 'lib/quake/game/player_state.rb', line 497

def reset_spawn_runtime_fields
  @flags = FL_CLIENT
  @deathtype = ""
  @deadflag = DEAD_NO
  @view_offset = DEFAULT_VIEW_OFFSET
  @weapon_model = nil
  @face_anim_time = 0.0
  @show_hostile = 0.0
  @weapon_gettime.clear
  clear_temporary_powerups
end

#reset_to_new_parmsObject



509
510
511
512
513
514
515
516
517
518
519
# File 'lib/quake/game/player_state.rb', line 509

def reset_to_new_parms
  @health = 100
  @armor = 0
  @armor_type = 0
  @current_weapon = :shotgun
  @weapons_owned = Set.new([:axe, :shotgun])
  @keys_owned.clear
  reset_spawn_runtime_fields
  @ammo = { shells: 25, nails: 0, rockets: 0, cells: 0 }
  @megahealth_rot_time = nil
end

#select_weapon(slot) ⇒ Object

Select weapon by slot number (1-8)



238
239
240
241
242
243
# File 'lib/quake/game/player_state.rb', line 238

def select_weapon(slot)
  return unless (1..WEAPONS.size).cover?(slot)

  weapon = WEAPONS[slot - 1]
  @current_weapon = weapon if selectable_weapon?(weapon)
end

#selectable_weapon?(weapon) ⇒ Boolean

Returns:

  • (Boolean)


559
560
561
562
563
564
565
566
567
# File 'lib/quake/game/player_state.rb', line 559

def selectable_weapon?(weapon)
  return false unless @weapons_owned.include?(weapon)

  fire = WEAPON_FIRE[weapon]
  return false unless fire

  ammo_type = fire[:ammo_type]
  ammo_type.nil? || @ammo[ammo_type] >= fire[:ammo_cost]
end

#switch_to_best_weapon(water_level: 0) ⇒ Object



314
315
316
# File 'lib/quake/game/player_state.rb', line 314

def switch_to_best_weapon(water_level: 0)
  @current_weapon = best_weapon(water_level: water_level)
end

#take_damage(amount, game_time: nil) ⇒ Object



527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
# File 'lib/quake/game/player_state.rb', line 527

def take_damage(amount, game_time: nil)
  amount = amount.to_f
  save = (ARMOR_SAVE.fetch(@armor_type, 0.0) * amount).ceil
  if save >= @armor
    save = @armor
    @armor_type = 0
  end

  @armor -= save
  return { take: 0, save: save } if (@flags & FL_GODMODE) != 0
  if game_time && invulnerable_to_damage?(game_time: game_time)
    return { take: 0, save: save }
  end

  take = (amount - save).ceil
  @health -= take
  @health = -99 if @health < -99
  { take: take, save: save }
end

#update_megahealth(game_time) ⇒ Object



376
377
378
379
380
381
382
383
384
385
386
387
388
# File 'lib/quake/game/player_state.rb', line 376

def update_megahealth(game_time)
  return unless @megahealth_rot_time
  if @health <= MAX_HEALTH
    @megahealth_rot_time = nil
    return
  end
  return if game_time < @megahealth_rot_time

  ticks = ((game_time - @megahealth_rot_time).floor + 1).to_i
  @health = [@health - ticks, MAX_HEALTH].max
  @megahealth_rot_time += ticks
  @megahealth_rot_time = nil if @health <= MAX_HEALTH
end

#update_powerup_effects(game_time) ⇒ Object



466
467
468
469
470
471
472
473
474
475
476
477
478
# File 'lib/quake/game/player_state.rb', line 466

def update_powerup_effects(game_time)
  @effects &= ~POWERUP_EFFECT_BITS

  if powerup_active?(:pentagram, game_time: game_time)
    @effects |= EF_DIMLIGHT
    @effects |= EF_RED
  end

  if powerup_active?(:quad, game_time: game_time)
    @effects |= EF_DIMLIGHT
    @effects |= EF_BLUE
  end
end

#update_powerups(game_time) ⇒ Object



456
457
458
459
460
461
462
463
464
# File 'lib/quake/game/player_state.rb', line 456

def update_powerups(game_time)
  now = game_time.to_f
  update_powerup_effects(now)
  @powerup_finished.delete_if do |powerup, finished|
    expired = finished < now
    @powerup_warning_time.delete(powerup) if expired
    expired
  end
end

#weapon_code(weapon) ⇒ Object



606
607
608
609
610
611
612
613
614
615
616
# File 'lib/quake/game/player_state.rb', line 606

def weapon_code(weapon)
  case weapon
  when :super_shotgun then 3
  when :nailgun then 4
  when :super_nailgun then 5
  when :grenade_launcher then 6
  when :rocket_launcher then 7
  when :lightning_gun then 8
  else 1
  end
end

#weapon_pickup_rank(weapon) ⇒ Object



643
644
645
# File 'lib/quake/game/player_state.rb', line 643

def weapon_pickup_rank(weapon)
  WEAPON_PICKUP_RANK.fetch(weapon, 7)
end

#weapon_switch_allowed?(weapon, water_level, w_switch) ⇒ Boolean

Returns:

  • (Boolean)


635
636
637
638
639
640
641
# File 'lib/quake/game/player_state.rb', line 635

def weapon_switch_allowed?(weapon, water_level, w_switch)
  return false if weapon == :lightning_gun && water_level.positive?

  switch_limit = w_switch.to_i
  switch_limit = 8 if switch_limit.zero?
  weapon_code(weapon) <= switch_limit
end