Module: Lich::Gemstone::Combat::Definitions::Outcomes
- Defined in:
- documented/gemstone/combat/defs/outcomes.rb
Overview
Classifies attack-outcome lines - the line that says how a swing, bolt, or maneuver resolved (miss, hit, evade, block, parry, warded, intercepted, resisted, ...). One outcome type per line; an attack event may accumulate several outcomes (multi-strike attacks).
Defined Under Namespace
Classes: OutcomeDef
Constant Summary collapse
- OUTCOME_DEFS =
All outcome definitions, in match-priority order (parse is first-match-wins, so more specific categories precede the broad :evade/:block pools).
[ OutcomeDef.new(:miss, [ /A clean miss./, /A close miss./, /Nowhere close./, /(?<attacker>.+?)'s#{MK_POST} swing goes wide./, /The (?:arrow|bolt) streaks off into the distance./, /Though (?<target>.+?) is caught unaware, you manage to completely miss your strike./, /You make a grab for (?<target>.+?) but miss, leaving yourself open./, /You stumble slightly as you leap from hiding, revealing yourself in the process./, /You move towards (?<target>.+?) to finish your kill, but .+? thwarts your attempt./, /The shadowy barb strikes harmlessly at the ground near (?<target>[^.]+)./, /A falling arrow flashes past (?<target>.+?) and shatters against the (?:ground|floor)./, /An incoming arrow just misses (?<target>[^!]+)./, /An arrow falls to the (?:ground|floor), narrowly missing (?<target>[^!]+)./, /(?<target>.+?) moves at the last moment to avoid an incoming arrow./, /The spray of arrows leaves (?<target>.+?) unscathed and undeterred./, /The .+? vine#{MK_POST} (?:lashes out at|grabs at) (?<target>.+?),? (?:but is unable to grasp|unable to find a purchase)/, /Your strike misses its mark./, /(?<attacker>.+?) whacks your legs to no effect./, /You whack (?<target>.+?'s)#{MK_POST} legs futilely./, /You end up missing entirely, leaving you slightl?y off balance./, /(?<target>.+?) avoids your bash./, /(?<target>.+?) is unaffected by your futile bash./, /Your (?<weapon>.+?) flies wide, narrowly missing (?<target>[^!]+)./, /The net flies past you and collapses into a useless heap./, /(?<attacker>.+?) stumbles behind you like a top out of control./, /The enormous hand attempts to grab you, but you manage to avoid it at the last moment./ ].freeze), OutcomeDef.new(:hit, [ /(?:A|Good) hit!/, # Nature's Fury per-target hit lines (round-13 sweep: 52/52 # follow the natures_fury initiation + Warding failed! in # the same chunk, damage always follows). The adjective is # terrain flavor (hard/snowy/cold/hot/mist-covered...). # Outcome, not attack def - the "surroundings advance" # initiation already owns the event; these just confirm # the strike landed. /(?<target>.+?) is struck by a sharp piece of \S+(?: \S+)? debris!/, /One of the large, pointed slivers of \S+(?: \S+)? debris hits (?<target>[^!]+)!/, # 1106 Bone Shatter result rider (owner evidence 2026-09-05: # sits between "Warding failed!" and the "battered for N" # damage; severity grades by endroll - mild/moderate/severe # observed). Initiation + damage were already claimed; # this closes the 6.2k-line rider family. /(?<target>.+?) shudders with \w+ convulsions as pearlescent ripples envelop #{MK_PRE}(?:his|her|its|your)#{MK_POST} body\./ ].freeze), OutcomeDef.new(:warded, [/Warded off!/].freeze), OutcomeDef.new(:ward_failed, [/Warding failed!/].freeze), # INTERCEPTS - the attack is nullified BEFORE it resolves, by a # barrier/shield/ward standing between attacker and defender. # Categorically NOT :block or :evade: nothing was blocked or # dodged, and no defensive skill was exercised - it is as if the # attack never happened. Kept separate so hit-rate and # block-rate statistics stay honest (an intercept must not count # against a creature's evasion or a character's block rate). # # Ordered BEFORE :evade/:block so these claim their lines first # (parse is first-match-wins). OutcomeDef.new(:intercept, [ # 250 Thorn Barrier / thorny barrier /The thorny barrier surrounding (?<target>.+?) blocks your .+?!/, /The thorny barrier surrounding you blocks the attack from (?<attacker>[^!]+)!/, /The thorny barrier surrounding (?<target>.+?) blocks the attack from .+?!/, # 319 Soul Ward (owner-corrected 2026-09-04; the 319 wiki # page carries this wording verbatim - 430 is Elemental # Barrier and was a misattribution) /The evanescent shield shrouding (?<target>.+?) flares to life and absorbs the (?:oncoming blow|essence of the spell, dissipating it harmlessly)\./, /The evanescent shield shrouding you flares to life and absorbs the (?:oncoming blow|essence of the spell, dissipating it harmlessly)\./, # 606 Bark Skin /The layer of bark on you hardens and absorbs the attack!/, /The layer of bark on (?<target>.+?) hardens and absorbs the attack!/, # stone barrier /A heavy barrier of stone momentarily forms around (?<target>.+?) and blocks the attack!/, # full spell-deflect barrier - replaces the roll line entirely /A complex pattern of .+? energy flashes briefly into existence between .+? and (?<target>.+?), deflecting the assault entirely\./, /(?<attacker>.+?)'s#{MK_POST} spell is deflected by your barrier in a flash of \w+ light!/, %r{Your spell is deflected by (?:<pushBold/>)?the (?<target>.+?)'s#{MK_POST} barrier in a flash of \w+ light!}, # mirror image - the image takes the hit, not the character /A mirror image of (?:you|.+?) shimmers into view, gaining substance just long enough to intercept the attack!/, ].freeze), OutcomeDef.new(:evade, [ /By amazing chance, (?<target>.+?) evades the .+?!/, /Lying flat on .+? back, (?<target>.+?) leans to one side and dodges the .+?!/, /Nearly insensible, (?<target>.+?) desperately evades the .+?!/, /Rolling hurriedly, (?<target>.+?) blocks the .+? with .+?!/, /Stupefied, (?<target>.+?) evades the .+? by blind luck!/, /Unable to focus clearly, (?<target>.+?) blindly evades the .+?!/, /(?<target>.+?) barely dodges the .+?!/, /(?<target>.+?) dodges just in the nick of time!/, /(?<target>.+?) dodges out of the way!/, /(?<target>.+?) evades the .+? by a hair!/, /(?<target>.+?) evades the .+? by inches!/, /(?<target>.+?) evades the .+? with ease!/, /(?<target>.+?) flails on the ground but manages to barely dodge the .+?!/, /(?<target>.+?) gracefully avoids the .+?!/, /(?<target>.+?) moves at the last moment to evade the .+?!/, /(?<target>.+?) rolls to one side and evades the .+?!/, /(?<target>.+?) skillfully dodges the .+?!/, /(?<target>.+?) stumbles dazedly, somehow managing to evade the .+?!/, /(?<target>.+?) outmaneuvers the attack and completely avoids it!/, /You outmaneuver the attack and completely avoid it!/, /(?<target>.+?) dodges an incoming arrow!/, /Sensing your attack coming, (?<target>.+?) leaps to safety as you move to attack (?:him|her|it), leaving you out of position!/, /Unable to focus clearly, you blindly evade the attack!/, /You barely dodge the attack!/, /Unfortunately, your aim is off and your attack goes wide!/, /You evade the (?:attack|missile|bolt) by inches!/, /You evade the (?:attack|missile|bolt) by a hair!/, /You evade the (?:attack|missile|bolt) with ease!/, /You evade the attack with incredible finesse!/, /You dodge just in the nick of time!/, /You dodge out of the way!/, /By amazing chance, you evade the .+?!/, /You move at the last moment to evade the .+?!/, /You gracefully avoid the .+?!/, /You skillfully dodge the .+?!/, /With blinding speed, (?:you|(?<target>.+?)) dodges? the .+?!/, /You move slightly, letting the attack pass harmlessly by!/, /You move quickly avoiding the magic!/, /You manage to jump out of the way!/, /Staggering like a punch-drunk brawler, you dodge the .+?!/, /Sensing an impending attack, you manage to roll hard to the side/, /Stupefied, you evade the .+? by blind luck!/, /You manage to dodge (?<attacker>.+?)'s#{MK_POST} blow!/, /(?<attacker>.+?) attempts to bearhug (?<target>.+?), but .+? to evade #{MK_PRE}(?:his|her|its)#{MK_POST} grasp!/, /You dodge the .+? with barely a hair's breadth to spare!/, /You manage to dodge .+?(?:, and it passes harmlessly by| in the nick of time)!/, /You dodge the .+? by a hair!/, /Bobbing and weaving, you dodge the .+?!/, /(?<target>.+?) deftly avoids the stroke\./, # 1712 Ethereal Censer per-target dodge - pairs with the # :ethereal_censer "becomes enveloped" initiation (round-11/12 # coverage channel: 13,713 lines across 12 creatures) /(?<target>.+?) avoids the incense smoke!/ ].freeze), OutcomeDef.new(:block, [ /Amazingly, (?<target>.+?) manages to block the .+? with .+?!/, /At the last moment, (?<target>.+?) blocks the .+? with .+?!/, /Fumbling aimlessly, (?<target>.+?) manages to deflect the .+? with .+?!/, /In the nick of time, (?<target>.+?) interposes .+? between .+? and the .+?!/, /Lying flat on .+? back, (?<target>.+?) barely deflects the .+? with .+?!/, /Nearly insensible, (?<target>.+?) desperately blocks the .+? with .+?!/, /Nearly insensible, (?<target>.+?) wildly blocks the .+? with .+?!/, /Reeling and staggering, (?<target>.+?) barely blocks the .+? with .+?!/, /Stupefied, (?<target>.+?) blocks the .+? by blind luck!/, /You harmlessly deflect the charge!/, /Unable to focus clearly, (?<target>.+?) blindly blocks the .+?!/, /With extreme effort, (?<target>.+?) blocks the .+? with .+?!/, /With no room to spare, (?<target>.+?) blocks the .+? with .+?!/, /(?<target>.+?) awkwardly scrambles along the ground to avoid the .+?!/, /(?<target>.+?) awkwardly scrambles to the right and blocks the .+?!/, /(?<target>.+?) barely manages to block the .+? with .+?!/, /(?<target>.+?) easily blocks the .+? with .+?!/, /(?<target>.+?) flails on the ground but manages to block the .+? with .+?!/, /(?<target>.+?) interposes .+? between .+? and the .+?!/, /(?<target>.+?) manages to block the .+? with .+?!/, /(?<target>.+?) rolls to one side and deflects the .+? with .+?!/, /(?<target>.+?) skillfully blocks the .+? with .+?!/, /(?<target>.+?) skillfully interposes .+? between .+? and the .+?!/, /(?<target>.+?) stumbles dazedly, but (?:manages to )?blocks? the .+? with .+?!/, /(?<target>.+?) deflects your (?<weapon>.+?) with #{MK_PRE}(?:his|her|its)#{MK_POST} .+?!/, /(?<target>.+?) stumbles dazedly, somehow managing to block the .+? with .+?!/, /(?<target>.+?) tumbles to the side and deflects the .+? with .+?!/, /(?<target>.+?) harmlessly deflects the charge!/, /You gauge the attack and expertly deflect it with your .+?!/, /At the last moment, you block the missile with your .+?!/, /In the nick of time, you interpose your .+? between yourself and the (?:missile|blow)!/, /Though dazed, you easily deflect the .+? with your .+?!/, /Although completely oblivious, you instinctively block the .+? with your .+?!/, /You skillfully block the missile with your .+?!/, /(?:With no room to spare|With blinding speed|With extreme effort|Amazingly), you(?: manage to)? block the .+? with your .+?!/, /At the last moment, you block the (?:attack|missile|bolt|blow) with your .+?!/, /You (?:easily|skillfully) block the (?:attack|missile|bolt|blow) with your .+?!/, /You barely manage to block the .+? with your .+?!/, /With incredible finesse, you deflect the .+? with your .+?!/, /You block the (?:attack|missile|bolt|blow) with your .+?!/, /You manage to deflect (?<attacker>.+?)'s#{MK_POST} blow in the nick of time!/ # (spell-deflect-by-barrier lines live in :intercept, which wins # first-match; keeping copies here would be dead and would also # contradict :intercept's design note that these are NOT :block) ].freeze), OutcomeDef.new(:parry, [ /Amazingly, (?<target>.+?) manages to parry the .+? with .+?!/, /At the last moment, (?<target>.+?) parries the .+? with .+?!/, /Using the bone plates surrounding .+? forearms, (?<target>.+?) parries your .+?!/, /With extreme effort, (?<target>.+?) beats back the .+? with .+?!/, /With no room to spare, (?<target>.+?) manages to parry the .+? with .+?!/, /(?<target>.+?) barely manages to fend off the .+? with .+?!/, /(?<target>.+?) flails on the ground but manages to parry the .+? with .+?!/, /(?<target>.+?) rolls to one side and parries the .+? with .+?!/, /With no room to spare, you manage to parry the blow with your .+?!/, /Using the bone plates surrounding your forearms, you parry the attack!/, /(?<target>.+?) manages to fend off (?:your|(?<attacker>.+?)'s#{MK_POST}) attack!/, /At the last moment, you parry the .+? with your .+?!/, /Amazingly, you manage to parry the .+? with your .+?!/, /You barely manage to fend off the .+? with your .+?!/, /With extreme effort, you beat back the .+? with your .+?!/, /You gauge the attack and expertly parry it with your .+?!/ ].freeze), OutcomeDef.new(:resisted, [ /(?<target>.+?) shrugs off some of the damage!/, /(?<target>.+?)'s#{MK_POST} exterior hardens for a moment and softens the attack!/, /(?<target>.+?) aura absorbs some of the damage!/, /(?<target>.+?) manages to block some of the (?:elemental )?damage with #{MK_PRE}(?:his|her|its)#{MK_POST} .+?!/, /(?<armor>.+?) partially deflects the onslaught of the \w+ attack\./, /Your body resists the \w+ damage and lessens the severity of the attack!/ ].freeze), # Immunity: the spell simply has no effect - no CS/TD roll is # printed at all (e.g. 501 Sleep vs a troll wraith, forge # capture), so this line is the ONLY thing that settles the # cast event. Distinct from :warded (a roll happened and failed). OutcomeDef.new(:unaffected, [ /(?<target>.+?) does not seem to be affected\./, # AoE sweep no-effect lines (round-12 tracker candidates). # The fused "buffeted ..., but is unaffected" form MUST sit # before the bare form: the lazy target capture of the bare # pattern would otherwise swallow "... waves, but" into the # target text. # "A giant warg is buffeted by the formless black waves, # but is unaffected." (~2.0k lines, ewave/sphere family) /(?<target>.+?) is buffeted by the .+?, but is unaffected\./, # "A tattooed gigas berserker is unaffected." (~2.2k lines) /(?<target>.+?) is unaffected\./, # Elemental no-effect on immune creatures - per-target line of # our elemental AoEs/flares (round-11/12 status candidate list: # plasma 5,983x/4, electricity 5,571x/5, cold 4,479x/7, # heat 1,094x/4, impact 34,531x/4 from the 2026-09-03 # full-corpus sweep; only observed elements listed). Owner # note 2026-09-04: many of these are likely TEMPORARY # immunities a creature gains after taking damage of that # type, not permanent traits - so consumers should treat # the outcome as per-attack fact, not a creature attribute. /(?<target>.+?) is unharmed by the (?:plasma|electricity|cold|heat|impact)!/, # holy-luminescence AoE no-effect (full-corpus sweep 2026-09-03: # 1,239 lines across 50+ creatures) /(?<target>.+?) endures the luminescence and is unscathed!/, # magic-avoid special defense (triton brawler): follows the # gesture with NO roll printed, so like the troll-wraith # immunity above it is the ONLY line that settles the cast # (exchange evidence 2026-09-03; 21.7k lines) /(?<target>.+?)'s#{MK_POST} face goes blank for a moment before returning to normal, as #{MK_PRE}(?:he|she|it)#{MK_POST} successfully avoids the effects of the magical attack!/ ].freeze), # Attacking a corpse: the attack never happens - no roll, # no roundtime, no attack def (owner ruling 2026-09-05). # Pure information for the player; claimed so 2k lines # across 22 creatures stop reading as unmatched. OutcomeDef.new(:already_dead, [/(?<target>.+?) is quite dead already\./].freeze), OutcomeDef.new(:fumble, [/d100 == 1 FUMBLE!/].freeze), OutcomeDef.new(:hindrance, [/\[Spell Hindrance for (?<armor>.+?) is (?<hindrance_amount>\d+)% with current Armor Use skill, d100= (?<roll>\d+)\]/].freeze), OutcomeDef.new(:confused, [/Something confusing enters your mind at the worst possible moment, and the distraction disrupts your .+?!/].freeze) ].freeze
- OUTCOME_LOOKUP =
Flattened [pattern, type] pairs in definition order, used for first-match-wins scanning.
OUTCOME_DEFS.flat_map { |d| d.patterns.map { |rx| [rx, d.type] } }.freeze
Class Method Summary collapse
-
.parse(line) ⇒ Symbol?
Classifies a single game line as an attack outcome.
Class Method Details
.parse(line) ⇒ Symbol?
Classifies a single game line as an attack outcome.
311 312 313 314 315 316 |
# File 'documented/gemstone/combat/defs/outcomes.rb', line 311 def self.parse(line) return nil unless GATE.match?(line) || ALWAYS_SCAN.any? { |rx| rx.match?(line) } OUTCOME_LOOKUP.each { |rx, type| return type if rx.match?(line) } nil end |