Class: Lich::Gemstone::Warcry

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

Overview

Class for managing and using Warcries in GemStone IV.

Warcries are cost-based vocal abilities that provide buffs or perform effects. This class provides:

  • Metadata for each known warcry (cost, regex, optional buff name)

  • Checks for knowledge, affordability, cooldown, and buff activity

  • Execution logic including FORCERT handling

Examples:

Using a warcry

Warcry.use("holler")

Constant Summary collapse

@@warcries =

Internal table of all warcry abilities.

Returns:

  • (Hash<String, Hash>)

    Mapping from long name to metadata, including:

    • ‘:long_name` [String]

    • ‘:short_name` [String]

    • ‘:cost` [Integer]

    • ‘:regex` [Regexp]

    • ‘:buff` [String, optional]

{
  "bertrandts_bellow" => {
    :long_name  => "bertrandts_bellow",
    :short_name => "bellow",
    :type       => :setup,
    :cost       => { stamina: 20 }, # @todo only 10 for single
    :regex      => /You glare at .+ and let out a nerve-shattering bellow!/,
  },
  "yerties_yowlp"     => {
    :long_name  => "yerties_yowlp",
    :short_name => "yowlp",
    :type       => :buff,
    :cost       => { stamina: 20 },
    :regex      => /You throw back your shoulders and let out a resounding yowlp!/,
    :buff       => "Yertie's Yowlp",
  },
  "gerrelles_growl"   => {
    :long_name  => "gerrelles_growl",
    :short_name => "growl",
    :type       => :setup,
    :cost       => { stamina: 14 }, # @todo only 7 for single
    :regex      => /Your face contorts as you unleash a guttural, deep-throated growl at .+!/,
  },
  "seanettes_shout"   => {
    :long_name  => "seanettes_shout",
    :short_name => "shout",
    :type       => :buff,
    :cost       => { stamina: 20 },
    :regex      => /You let loose an echoing shout!/,
    :buff       => 'Empowered (+20)',
  },
  "carns_cry"         => {
    :long_name  => "carns_cry",
    :short_name => "cry",
    :type       => :setup,
    :cost       => { stamina: 20 },
    :regex      => /You stare down .+ and let out an eerie, modulating cry!/,
  },
  "horlands_holler"   => {
    :long_name  => "horlands_holler",
    :short_name => "holler",
    :type       => :buff,
    :cost       => { stamina: 20 },
    :regex      => /You throw back your head and let out a thundering holler!/,
    :buff       => 'Enh. Health (+20)',
  },
}

Class Method Summary collapse

Class Method Details

.[](name) ⇒ Integer

Looks up the rank known of a warcry. In reality, warcries are not ranked, but this is a convenient way to check if a warcry is known or not that fits with the rest of the PSMS.

Examples:

Warcry["holler"] => 1 # if known
Warcry["holler"] => 0 # if not known

Parameters:

  • name (String)

    The name of the warcry

Returns:

  • (Integer)

    The rank of the warcry, or 0 if unknown



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

def Warcry.[](name)
  return PSMS.assess(name, 'Warcry')
end

.affordable?(name, forcert_count: 0) ⇒ Boolean

Determines if a warcry is affordable, and optionally tests affordability with a given number of FORCERTs having been used (including the current one).

Examples:

Warcry.affordable?("holler") => true # if enough skill and stamina
Warcry.affordable?("holler", forcert_count: 1) => false  # if not enough skill or stamina

Parameters:

  • name (String)

    The name of the warcry

  • forcert_count (Integer) (defaults to: 0)

    Optionally, the count of FORCERTs being used, including for this execution (default: 0)

Returns:

  • (Boolean)

    True if the technique can be used with available FORCERTs



122
123
124
# File 'documented/gemstone/psms/warcry.rb', line 122

def Warcry.affordable?(name, forcert_count: 0)
  return PSMS.assess(name, 'Warcry', true, forcert_count: forcert_count)
end

.available?(name, min_rank: 1, forcert_count: 0) ⇒ Boolean

Determines if a warcry is available to use right now by testing:

  • if the technique is known

  • if the technique is affordable

  • if the technique is not on cooldown

  • if the character is not overexerted

  • if the character is capable of performing the number of FORCERTs specified

blocked by overexertion

Examples:

Warcry.available?("holler") => true # if known, affordable, not on cooldown, and not overexerted

Parameters:

  • name (String)

    The name of the warcry

  • min_rank (Integer) (defaults to: 1)

    Optionally, the minimum rank to check (default: 1)

  • forcert_count (Integer) (defaults to: 0)

    Optionally, the count of FORCERTs being used (default: 0)

Returns:

  • (Boolean)

    True if the technique is known, affordable, and not on cooldown or



140
141
142
143
144
# File 'documented/gemstone/psms/warcry.rb', line 140

def Warcry.available?(name, min_rank: 1, forcert_count: 0)
  Warcry.known?(name, min_rank: min_rank) &&
    Warcry.affordable?(name, forcert_count: forcert_count) &&
    PSMS.available?(name)
end

.buff_active?(name) ⇒ Boolean

Checks whether the warcry’s buff is currently active.

Examples:

Warcry.buff_active?("holler") => true # if buff is active

Parameters:

  • name (String)

    Warcry name

Returns:

  • (Boolean)

    True if buff is already active



163
164
165
166
167
# File 'documented/gemstone/psms/warcry.rb', line 163

def Warcry.buff_active?(name)
  buff = @@warcries.fetch(PSMS.find_name(name, "Warcry")[:long_name])[:buff]
  return false if buff.nil?
  Lich::Util.normalize_lookup('Buffs', buff)
end

.buffActive?(name) ⇒ Boolean

DEPRECATED: Use #buff_active? instead. Checks whether the warcry’s buff is currently active.

Parameters:

  • name (String)

    Warcry name

Returns:

  • (Boolean)

    True if buff is already active



151
152
153
154
155
# File 'documented/gemstone/psms/warcry.rb', line 151

def Warcry.buffActive?(name)
  ### DEPRECATED ###
  Lich.deprecated("Warcry.buffActive?", "Warcry.buff_active?", caller[0], fe_log: false)
  buff_active?(name)
end

.known?(name, min_rank: 1) ⇒ Boolean

Determines if the character knows a warcry at all, and optionally if the character knows it at the specified rank. In reality, warcries are not ranked, but this is a convenient way to check if a warcry is known or not that fits with the rest of the PSMS.

Examples:

Warcry.known?("holler") => true # if any number of ranks is known

Parameters:

  • name (String)

    The name of the warcry

  • min_rank (Integer) (defaults to: 1)

    Optionally, the minimum rank to test against (default: 1, so known)

Returns:

  • (Boolean)

    True if the technique is known at or above the given rank



108
109
110
111
# File 'documented/gemstone/psms/warcry.rb', line 108

def Warcry.known?(name, min_rank: 1)
  min_rank = 1 unless min_rank >= 1 # in case a 0 or below is passed
  Warcry[name] >= min_rank
end

.regexp(name) ⇒ Regexp

Returns the “success” regex associated with a given warcry name. This regex is used to match the expected output when the technique is successfully attempted. It does not necessarily indicate that the technique was successful in its effect, or even that the technique was executed at all.

Examples:

Warcry.regexp("holler") => /As \w+ prays? over \w+(?:'s)? [\w\s]+, you sense that (?:the Arkati's|a) blessing will be granted against magical attacks\./i

Parameters:

  • name (String)

    The technique name

Returns:

  • (Regexp)

    The regex used to match technique success or effects



233
234
235
# File 'documented/gemstone/psms/warcry.rb', line 233

def Warcry.regexp(name)
  @@warcries.fetch(PSMS.find_name(name, "Warcry")[:long_name])[:regex]
end

.use(name, target = "", results_of_interest: nil, forcert_count: 0) ⇒ String?

Attempts to use a warcry, optionally on a target.

Examples:

Warcry.use("holler") # attempt to use holler on self
Warcry.use("holler", "Dissonance") # attempt to use holler on Dissonance

Parameters:

  • name (String)

    The name of the warcry

  • target (String, Integer, GameObj) (defaults to: "")

    The target of the technique (optional). If unspecified, the target is assumed to be the user.

  • results_of_interest (Regexp, nil) (defaults to: nil)

    Additional regex to capture from result (optional)

  • forcert_count (Integer) (defaults to: 0)

    Number of FORCERTs to use (default: 0)

Returns:

  • (String, nil)

    The result of the regex match, or nil if unavailable



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'documented/gemstone/psms/warcry.rb', line 179

def Warcry.use(name, target = "", results_of_interest: nil, forcert_count: 0)
  return unless Warcry.available?(name, forcert_count: forcert_count)
  return if Warcry.buff_active?(name)

  name_normalized = PSMS.name_normal(name)
  technique = @@warcries.fetch(PSMS.find_name(name_normalized, "Warcry")[:long_name])
  usage = name_normalized
  return if usage.nil?

  in_cooldown_regex = /^#{name} is still in cooldown\./i

  results_regex = Regexp.union(
    PSMS::FAILURES_REGEXES,
    /^#{name} what\?$/i,
    in_cooldown_regex,
    technique[:regex],
    /^Roundtime: [0-9]+ sec\.$/,
  )

  results_regex = Regexp.union(results_regex, results_of_interest) if results_of_interest.is_a?(Regexp)

  usage_cmd = "warcry #{usage}"
  if target.is_a?(GameObj)
    usage_cmd += " ##{target.id}"
  elsif target.is_a?(Integer)
    usage_cmd += " ##{target}"
  elsif target != ""
    usage_cmd += " #{target}"
  end

  if forcert_count > 0
    usage_cmd += " forcert"
  else # if we're using forcert, we don't want to wait for rt, but we need to otherwise
    waitrt?
    waitcastrt?
  end

  usage_result = dothistimeout(usage_cmd, 5, results_regex)
  if usage_result == "You don't seem to be able to move to do that."
    100.times { break if clear.any? { |line| line =~ /^You regain control of your senses!$/ }; sleep 0.1 }
    usage_result = dothistimeout(usage_cmd, 5, results_regex)
  end
  usage_result
end

.warcry_lookupsArray<Hash>

Returns a summary array of all warcries, including long name, short name, and cost.

Examples:

Warcry.warcry_lookups # returns an array of warcry metadata

Returns:

  • (Array<Hash>)

    Each hash has :long_name, :short_name, :cost



75
76
77
78
79
80
81
82
83
# File 'documented/gemstone/psms/warcry.rb', line 75

def self.warcry_lookups
  @@warcries.map do |long_name, psm|
    {
      long_name: long_name,
      short_name: psm[:short_name],
      cost: psm[:cost]
    }
  end
end