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

Dynamic singleton methods are created for each warcry by long and short name.

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



91
92
93
# File 'documented/gemstone/psms/warcry.rb', line 91

def self.[](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



120
121
122
# File 'documented/gemstone/psms/warcry.rb', line 120

def self.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
and not silenced or cutthroat

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



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

def self.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) &&
    !Status.cutthroat? &&
    !Status.silenced?
end

.buff_active?(name) ⇒ Boolean

Checks whether the warcry's buff is currently active.

Parameters:

  • name (String) —

    Warcry name

Returns:

  • (Boolean) —

    True if buff is already active



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

def self.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



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

def self.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



106
107
108
109
# File 'documented/gemstone/psms/warcry.rb', line 106

def self.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



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

def self.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



178
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
# File 'documented/gemstone/psms/warcry.rb', line 178

def self.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_lookups ⇒ Array<Hash>

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

Returns:

  • (Array<Hash>) —

    Each hash has :long_name, :short_name, :cost



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

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