Class: Lich::Gemstone::Injured

Inherits:
Gemstone::CharacterStatus
  • Object
show all
Defined in:
documented/gemstone/injured.rb

Overview

Represents the status of an injured character in the game.

See Also:

Constant Summary collapse

BODY_PART_GROUPS =
{
  eyes: %i[leftEye rightEye],
  arms: %i[leftArm rightArm],
  hands: %i[leftHand rightHand],
  legs: %i[leftLeg rightLeg],
  feet: %i[leftFoot rightFoot],
  head_and_nerves: %i[head nsys]
}.freeze

Class Method Summary collapse

Class Method Details

.able_to_cast?Boolean

Checks if the character is able to cast spells based on their injury status.

Returns:

  • (Boolean)

    true if the character can cast spells



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
130
131
132
133
# File 'documented/gemstone/injured.rb', line 99

def able_to_cast?
  fix_injury_mode("both")

  # Fetch cached or fresh injury data
  wounds, scars = get_injury_data

  # Rank 3 critical injuries prevent casting (Sigil cannot bypass)
  return false if injuries_at_rank?(3, wounds, scars, :head, :nsys, *BODY_PART_GROUPS[:eyes])

  # Check for rank 3 in arms/hands (worst of arm vs hand per side)
  left_arm = effective_injury_from_hashes(:leftArm, wounds, scars)
  left_hand = effective_injury_from_hashes(:leftHand, wounds, scars)
  right_arm = effective_injury_from_hashes(:rightArm, wounds, scars)
  right_hand = effective_injury_from_hashes(:rightHand, wounds, scars)

  left_side = [left_arm, left_hand].max
  right_side = [right_arm, right_hand].max

  return false if left_side == 3 || right_side == 3

  # Sigil of Determination bypasses rank 2 or lower injuries
  return true if bypasses_injuries?

  # Head or nerve injuries > rank 1 prevent casting
  return false if injuries_at_or_above_rank?(2, wounds, scars, *BODY_PART_GROUPS[:head_and_nerves])

  # Cumulative injuries >= 3 prevent casting
  eyes_total = BODY_PART_GROUPS[:eyes].sum { |part| effective_injury_from_hashes(part, wounds, scars) }
  return false if eyes_total >= 3

  arms_total = left_side + right_side
  return false if arms_total >= 3

  true
end

.able_to_search?Boolean

Checks if the character is able to search based on their injury status.

Returns:

  • (Boolean)

    true if the character can search



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'documented/gemstone/injured.rb', line 157

def able_to_search?
  fix_injury_mode("both")

  wounds, scars = get_injury_data

  # Rank 3 critical injuries prevent searching (Sigil cannot bypass)
  return false if injuries_at_rank?(3, wounds, scars, :head, :nsys, *BODY_PART_GROUPS[:eyes])

  # Sigil of Determination bypasses rank 2 or lower injuries
  return true if bypasses_injuries?

  # Rank 2+ head or nerve injury prevents searching
  return false if injuries_at_or_above_rank?(2, wounds, scars, *BODY_PART_GROUPS[:head_and_nerves])

  true
end

.able_to_sneak?Boolean

Checks if the character is able to sneak based on their injury status.

Returns:

  • (Boolean)

    true if the character can sneak



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'documented/gemstone/injured.rb', line 137

def able_to_sneak?
  fix_injury_mode("both")

  wounds, scars = get_injury_data

  # Rank 3 leg/foot injuries always prevent sneaking, but these are NOT critical
  # (Sigil cannot bypass, but they're not in the critical list for other actions)
  return false if injuries_at_rank?(3, wounds, scars, *BODY_PART_GROUPS[:legs], *BODY_PART_GROUPS[:feet])

  # Sigil of Determination bypasses rank 2 or lower injuries
  return true if bypasses_injuries?

  # Any leg or foot injury > rank 1 prevents sneaking
  return false if injuries_at_or_above_rank?(2, wounds, scars, *BODY_PART_GROUPS[:legs], *BODY_PART_GROUPS[:feet])

  true
end

.able_to_use_ranged?Boolean

Checks if the character is able to use ranged weapons based on their injury status.

Returns:

  • (Boolean)

    true if the character can use ranged weapons



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'documented/gemstone/injured.rb', line 176

def able_to_use_ranged?
  fix_injury_mode("both")

  wounds, scars = get_injury_data

  # Rank 3 critical injuries prevent ranged weapon use (Sigil cannot bypass)
  return false if injuries_at_rank?(3, wounds, scars, :head, :nsys, *BODY_PART_GROUPS[:eyes], *BODY_PART_GROUPS[:arms], *BODY_PART_GROUPS[:hands])

  # Sigil of Determination bypasses rank 2 or lower injuries
  return true if bypasses_injuries?

  # Any single arm or hand injury >= rank 2 prevents ranged weapon use
  return false if injuries_at_or_above_rank?(2, wounds, scars, *BODY_PART_GROUPS[:arms], *BODY_PART_GROUPS[:hands], :nsys)

  true
end

.bypasses_injuries?Boolean

Determines if the character can bypass injuries based on active effects.

Returns:

  • (Boolean)

    true if the character can bypass injuries



93
94
95
# File 'documented/gemstone/injured.rb', line 93

def bypasses_injuries?
  Effects::Buffs.active?("Sigil of Determination")
end

.effective_injury_from_hashes(body_part, wounds_hash, scars_hash) ⇒ Integer

Calculates the effective injury from wounds and scars for a given body part.

Parameters:

  • body_part (Symbol)

    the body part to check (e.g., :leftArm)

  • wounds_hash (Hash)

    a hash mapping body parts to wound counts

  • scars_hash (Hash)

    a hash mapping body parts to scar counts

Returns:

  • (Integer)

    the effective injury value



59
60
61
62
63
64
65
# File 'documented/gemstone/injured.rb', line 59

def effective_injury_from_hashes(body_part, wounds_hash, scars_hash)
  scar = scars_hash[body_part.to_s] || 0
  wound = wounds_hash[body_part.to_s] || 0
  effective_scar = (scar == 1) ? 0 : scar

  [wound, effective_scar].max
end

.get_injury_data[Array<Wound>, Array<Scar>]

Retrieves injury data, utilizing caching for efficiency.

Returns:

  • ([Array<Wound>, Array<Scar>])

    cached wounds and scars data



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'documented/gemstone/injured.rb', line 26

def get_injury_data
  current_key = XMLData.injuries

  # Fast path: return cached data if key hasn't changed
  if @injury_cache_key == current_key && @wounds_cache && @scars_cache
    return [@wounds_cache, @scars_cache]
  end

  # Slow path: fetch new data with mutex protection
  @cache_mutex.synchronize do
    # Double-check after acquiring lock (another thread may have updated)
    if @injury_cache_key == current_key && @wounds_cache && @scars_cache
      return [@wounds_cache, @scars_cache]
    end

    # Fetch fresh data
    wounds = Wounds.all_wounds
    scars = Scars.all_scars

    # Update cache
    @wounds_cache = wounds
    @scars_cache = scars
    @injury_cache_key = current_key

    [wounds, scars]
  end
end

.injuries_at_or_above_rank?(rank, wounds_hash, scars_hash, *parts) ⇒ Boolean

Checks if there are injuries at or above a specific rank for the given body parts.

Parameters:

  • rank (Integer)

    the minimum injury rank to check

  • wounds_hash (Hash)

    a hash mapping body parts to wound counts

  • scars_hash (Hash)

    a hash mapping body parts to scar counts

  • parts (Array<Symbol>)

    the body parts to check

Returns:

  • (Boolean)

    true if any specified body part has an injury at or above the given rank



85
86
87
88
89
# File 'documented/gemstone/injured.rb', line 85

def injuries_at_or_above_rank?(rank, wounds_hash, scars_hash, *parts)
  parts.flatten.any? do |part|
    effective_injury_from_hashes(part, wounds_hash, scars_hash) >= rank
  end
end

.injuries_at_rank?(rank, wounds_hash, scars_hash, *parts) ⇒ Boolean

Checks if there are injuries at a specific rank for the given body parts.

Parameters:

  • rank (Integer)

    the injury rank to check

  • wounds_hash (Hash)

    a hash mapping body parts to wound counts

  • scars_hash (Hash)

    a hash mapping body parts to scar counts

  • parts (Array<Symbol>)

    the body parts to check

Returns:

  • (Boolean)

    true if any specified body part has an injury at the given rank



73
74
75
76
77
# File 'documented/gemstone/injured.rb', line 73

def injuries_at_rank?(rank, wounds_hash, scars_hash, *parts)
  parts.flatten.any? do |part|
    effective_injury_from_hashes(part, wounds_hash, scars_hash) == rank
  end
end