RO Renewal Math Core — Scenarios
Every scenario in core/scenarios/smoke.json. Pages marked computable render the actual library output; others show the fixture and wait for their phase to land.
- SC-001autoAttackcomputableBaseline auto-attack: Novice with Knife vs PoringSmoke test for the simplest possible physical damage path. No skill, no buffs, no cards, no element advantage. If this is wrong, everything is wrong.physicalDamageelementTablesoftDEFweaponSizeMultiplier
- SC-002skillcomputableBash Lv10: Swordsman vs PoringTests skill multiplier on physical damage path. Bash Lv10 multiplier is 400% (100 + 30*10). Verifies the skill formula evaluator and that the multiplier applies to WeaponratioATK at the right step.physicalDamageskillFormulaEvaluationskillMultiplier
- SC-003skillcomputableElement advantage: Fire Bolt Lv5 vs Earth-element MandragoraTests magical damage pipeline, element table lookup, and element advantage multiplier. Fire vs Earth lv1 should yield 1.50x; ensure the magical pipeline is structurally separate from physical.magicalDamageelementTableelementAdvantageMATK
- SC-004autoAttackcomputableCard conditional bonus: Hydra Card vs Demi-Human playerTests conditional Modifier evaluation. Hydra Card is '+20% damage to Demi-Human'. Same attack against a non-Demi-Human target should NOT include the bonus. Verifies the condition predicate language.conditionalModifierraceConditiondamageDealtScope
- SC-005autoAttackcomputableCritical strike: Assassin Katar vs BossTests critical hit path: crit ignores soft DEF (verify against rAthena which DEF components are skipped), applies critical multiplier (2.0 by default), and katar weapon type doubles base crit rate (verify rAthena handles this in stat resolution, not in damage formula).criticalHitkatarCritDoublingcritIgnoresSoftDEFbossDefender
- SC-006resolveStatsOnlycomputableMultiple buffs: Blessing + Increase AGI + Two-Hand Quicken stackingTests stat resolution with multiple stacking Effects. Blessing adds +10 STR/INT/DEX (flat). Increase AGI adds +DEX-relative AGI. Two-Hand Quicken adds ASPD%. Verifies that flat and percent Modifiers in the same scope stack correctly (additively for percent per D-005).statResolutionmultipleEffectsadditivePercentStackingASPD
- SC-007skillcomputableAsura Strike: Champion vs Ghost-element targetTests the formulaId escape hatch (per D-010) for skills too unique for the expression language. Asura Strike: damage scales with SP, ignores DEF entirely, but Ghost armor (typical PvP build) has special interaction with Ghost-element. Verify the formulaId function path runs and DEF-ignore both flags are respected.formulaIdEscapeHatchDEFIgnoreFullyasuraStrikeskillElement
- SC-008autoAttackcomputableRefinement comparison: +4 vs +10 weaponSame character, same target, same skill — only the weapon's refine level differs. Tests the refinement formula (D-008) and verifies that refine bonus enters via WeaponATK, not as a generic Modifier. Also tests over-refine (above safe level) bonus.refineFormulaoverRefineBonusweaponLevelDependent
- SC-009computeEffectTickcomputableDoT effect: Poison status damage over timeTests Effect with periodic tickAction. Poison ticks every N seconds dealing damage based on max HP. Verify (a) the library returns per-tick damage when given the tick number, (b) the snapshot policy works (default dynamic: poison damage changes if MaxHP changes mid-poison), (c) total damage over duration matches expected.effectTicksDoTpercentMaxHPDamagedynamicSnapshot
- SC-010skillcomputableAoE per-target evaluation: Magnum Break with 3 enemiesPer D-015, the library does per-target math for AoE — callers pass an array of defenders. Tests that each defender's damage is computed independently with its own element/race/size against the same attacker. Also tests Magnum Break's self-buff (fire-conversion endow on next attack) as a triggered Effect candidate.multipleDefendersmagnumBreakelementConversiontriggeredEffect
- SC-011autoAttackcomputableMiss / Perfect Dodge: low-DEX attacker vs high-AGI defenderTests the accuracy check and perfect-dodge path. Verifies that hit rate is computed correctly and that 'miss' and 'perfect_dodge' are distinct outcomes with different DamageResult shapes.hitFleeCheckperfectDodgemissOutcomeoutcomesEnum
- SC-012calculateDPScomputableLoadout comparison: two builds for the same HunterTests the compareLoadouts utility. Same character stats, two different equipment setups, computes expected DPS for each. This is what build calculators do — and it's the most user-facing function in the simulator.compareLoadoutsDPSexpectedDamagePerHitASPD
- MAG-001skillcomputableHoly Light Lv5 vs Undead lv4 (massive element advantage)Verifies the upper end of the element table. Holy attacking Undead lv4 should be the strongest single-multiplier interaction in the game (typically 175%+). If this number is wrong, the table lookup is wrong.magicalDamageelementTableholyVsUndeadhighMultiplier
- MAG-002skillcomputableFire Bolt Lv5 vs Fire-element target (resistance/immunity)Negative-control complement to SC-003. Same Fire Bolt cast, but defender is Fire-element instead of Earth. Multiplier should be ~25% (Fire vs Fire lv1) or near-zero at higher levels. Tests that the pipeline doesn't crash on heavy resistance and that the minimum-damage clamp fires correctly.magicalDamageelementTableelementResistancedamageFloor
- MAG-003skillcomputableLightning Bolt Lv5 vs Ghost-element target (absorption / negative multiplier)Tests the absorption case — some element interactions yield a NEGATIVE multiplier, meaning the 'damage' heals the target. The library must support this and the outcome should reflect 'absorbed' (a distinct DamageResult outcome).magicalDamageelementTableelementAbsorptionnegativeMultiplier+1
- MAG-004skillcomputableSame Cold Bolt vs same monster at different element levelsThree sub-scenarios with identical attacker and identical Mandragora-type defender, varying only elementLevel (1 vs 2 vs 3). Damage must be monotonically different — proves element LEVEL is being read from the defender, not hardcoded.magicalDamageelementTableelementLevelDependentmonotonicity
- MAG-005resolveStatsOnlycomputableMATK resolution — base Wizard vs buffed Wizard (Magnificat + INT food)resolveStatsOnly action. Verifies MATK derivation pipeline (the magical equivalent of D-003's ATK components). Two cases: base Wizard, then same Wizard with +10 INT food and Magnificat (which boosts SP regen but is included here as a stand-in for buff stacking). Expected MATK values are computed approximately from the Renewal formula.statResolutionMATKComponentsbuffStackingmatkStatusComponent
- MAG-006skillcomputableStorm Gust Lv10 — 10-hit accumulation vs single bossTests multi-hit magical skill behavior. Storm Gust does up to 10 hits per cast, each independently calculated. Each hit re-applies element multiplier and MDEF subtraction. Verifies the library returns 10 distinct damage instances and totalDamage is their sum.magicalDamagemultiHitSkillstormGustperHitIndependence
- MAG-007autoAttackcomputableAspersio endow — auto-attack element switches from Neutral to HolyTests element-conversion buffs. Aspersio is a Priest skill that endows a weapon with Holy element for ~3 minutes. The attack should switch element from the weapon's stored element (Neutral) to Holy. Critically — the weapon's stored element field should NOT change; the active Effect provides the override at calculation time.physicalDamageelementConversionendoweffectOverridesWeaponElement
- MAG-008skillcomputableSoul Strike Lv7 vs Demon-race target (magical race interaction)Tests that race-targeted modifiers apply to MAGICAL damage just as they do to physical. Soul Strike is Ghost-element by default. Mage equipped with a card that adds '+% damage to Demon race' should see the bonus apply.magicalDamageraceConditionalModifierghostElementdamageDealtScope
- MAG-009skillcomputableHeaven's Drive vs high-MDEF target — verify MDEF behaviorHeaven's Drive is an Earth-element AoE that hits ground tiles. This scenario establishes whether (in our implementation) Heaven's Drive respects hard/soft MDEF normally or has a special defIgnore. Run against a Sage-class target with high MDEF.magicalDamageMDEFInteractionearthElementheavensDrive
- MAG-010skillcomputableFrost Diver freeze status — applies Frozen, target becomes Water-elementTests the freeze-status interaction. Frost Diver applies Frozen to the target on success. While Frozen, the target's DEFENSIVE element becomes Water lv1, regardless of its armor — this is a major game-mechanic interaction. Verifies: (1) Frost Diver returns a trigger candidate, (2) once Frozen is active (modeled as an Effect on the defender), a subsequent Wind attack treats the defender as Water lv1.magicalDamagestatusApplicationTriggerfrozenStatuselementOverrideFromStatus+1
- PHYS-001autoAttackcomputableRefine breakpoint sweep — weapon level 3 from +0 to +16The most important test of refine math (D-008). Sweeps refine 0,4,7,8,10,15 on a weapon-level-3 weapon, expects strictly monotonic damage AND a visible inflection at the safe-refine boundary (+7) where over-refine bonus kicks in. If your library handles refine as a simple linear addition, this scenario reveals it.refineFormulaoverRefineBonusweaponLevel3monotonicity
- PHYS-002autoAttackcomputableWeapon-vs-size matrix — dagger, sword, spear vs Small/Medium/LargeTests the per-weapon-type size-multiplier table. Same character, same target stats, only weapon type and target size vary. Daggers should excel vs Small; Spears vs Large; Swords are balanced. If a developer left the size table unwired, all 9 cells will show the same damage — this matrix reveals it instantly.physicalDamageweaponSizeMultiplierweaponTypeTable
- PHYS-003skillcomputableDouble Strafe Lv10 — two-hit ranged skillTests multi-hit physical skill with hitCount=2. Each hit is independent (separate crit roll, separate DEF subtraction). Also verifies ranged-attack flag (Hunter's bow attacks count as ranged for Pneuma/etc.).physicalDamagemultiHitSkilldoubleStraferanged
- PHYS-004autoAttackcomputableDamage floor clamp — tiny attacker vs over-armored targetSpecifically constructs a case where (raw damage) - (hardDEF + softDEF) <= 0. The library must clamp to 1 (D-004 damage floor rule) and the outcome must remain 'hit', not 'immune'. This is the difference between 'hits do nothing' (still progresses certain mechanics) and 'attack misses entirely' (different game logic).physicalDamagedamageFloorminDamageClamphighDEFTarget
- PHYS-005autoAttackcomputableDEF-ignore variants — full vs hard-only vs soft-only vs noneSame attacker, same high-DEF/high-soft-DEF defender. Four skills with different defIgnore configurations. Damage should clearly differ: full-ignore highest, then hard-only or soft-only depending on which dominates, then no-ignore lowest. Verifies that skill.defIgnore.{hard,soft} is wired through correctly.physicalDamagedefIgnorehardDEFvsSoftDEF
- PHYS-006autoAttackcomputablePerfect dodge always succeeds regardless of HIT/FLEEPerfect dodge is checked BEFORE the standard hit-vs-flee roll. Tests with deliberately mismatched accuracy: extremely high HIT, low FLEE — perfect dodge should still proc at its rate. 1000 sampled attacks with seed; expect perfect_dodge count within statistical tolerance of LUK/10 + flat bonuses.perfectDodgerolledModeoutcomeDistributionrngDeterminism
- PHYS-007autoAttackcomputableTriple Attack proc — Monk auto-attack with chance of multi-hitSome passives turn auto-attacks into chance-based multi-hits. Triple Attack (Monk skill) gives auto-attacks a chance to hit 3 times. Tests that the library can express 'this auto-attack might be 1 hit or 3 hits' as a probabilistic outcome. In expected mode, returns the EV; in rolled mode, the outcome is sampled.multiHitProcpassiveSkillProcautoAttackVariantexpectedValueComputation
- PHYS-008skillcomputableMagnum Break — AoE + self-buff trigger (fire endow temporary)Combines AoE math (per-defender independent calculation) with a self-applied trigger (Magnum Break leaves the caster with a fire-endow buff for 10 seconds). Same as SC-010 in shape but with explicit assertions on the self-trigger and a follow-up sub-scenario verifying the next auto-attack uses Fire element.physicalDamageaoeselfTriggeredEffectfireEndow+1
- PHYS-009skillcomputableClass-targeted damage — '+30% damage vs Boss' card vs Boss and Normal class targetsTests the damage.dealt.class.boss modifier scope. Crucially, a player wearing a +Boss card vs a Normal-class monster should NOT receive the bonus — even if everything else matches. Mirrors SC-004's race-condition logic for class.physicalDamageclassConditionalModifierbossClassnegativeControl
- PHYS-010skillcomputableBowling Bash Lv10 — single-target high-multiplier with size-favored weaponBowling Bash is a Knight skill with very high multiplier (~600%+ at Lv10). Tests that high-multiplier skills don't overflow, that the size modifier still applies, and that the breakdown shows the multiplier chain clearly. Use a Spear (favored vs Large) on a Large target to maximize all factors.physicalDamagehighMultiplierSkillspearVsLargebowlingBash
- CARD-001autoAttackcomputableHydra Card stacks additively — three Hydras on a Composite BowVerifies that multiple Modifiers with identical scope and condition stack ADDITIVELY (per D-005: 'two +10% cards give +20%, not +21%'). Three Hydra cards (each +20% vs Demi-Human) should give +60% total, not (1.20)^3 ≈ +73%.conditionalModifieradditiveStackingduplicateCardStacking
- CARD-002autoAttackcomputableMixed cards — Hydra + Skeleton Worker on same weapon vs Demi-Human MediumTwo cards with DIFFERENT scopes (race vs size) on the same weapon. Both should apply independently to a target matching both conditions. Verifies that scope grouping works correctly — race.demihuman bonus and size.medium bonus are in different scope groups and combine multiplicatively across groups but additively within.conditionalModifiermultiScopeStackingraceAndSize
- CARD-003autoAttackcomputableSelf-condition — '+30% damage while HP below 50%' triggers correctlyTests the hpBelow condition predicate targeting self. Run the same skill twice: once at full HP (no bonus), once at 30% HP (bonus applies). The two damage values must clearly differ.conditionalModifierselfHPConditionhpBelowPredicate
- CARD-004autoAttackcomputableWeapon-type condition — Sword Mastery '+20 ATK only while wielding swords'Tests the weaponType condition predicate. The same Effect is active on the attacker for both variants; in one, attacker wields a sword (bonus applies); in the other, a dagger (bonus does not). Effect is in activeEffects either way — the library decides based on weapon at calc time.conditionalModifierweaponTypePredicatepassiveEffect
- CARD-005skillcomputableNested condition — 'NOT (Fire OR Holy element)' means Earth/Water/Wind/etc onlyTests recursive condition combinators. The card applies a bonus to all defenders EXCEPT those that are Fire or Holy. Validates: (a) z.lazy() recursion works, (b) NOT inverts correctly, (c) OR inside NOT evaluates as expected.conditionalModifierrecursiveConditionnotOperatororOperator
- CARD-006autoAttackcomputableCombo card — bonus only when TWO specific cards are equipped togetherCard combos are pairs of cards that grant an extra bonus when both are equipped. Tests an AND combinator over hypothetical 'cardEquipped' or 'hasItem' predicates. NOTE: this requires adding a 'cardEquipped' predicate kind to D-009 — surfacing the gap is part of this scenario's value.conditionalModifiercomboCardmissingPredicateKind
- CARD-007autoAttackcomputableSet bonus — three pieces of a set grant a +ATK% modifierTests set bonuses, which are functionally combo cards across equipment items (not card slots). Same design gap as CARD-006 — requires a 'setEquippedCount >= N' predicate. Documents the requirement; scenario stays draft until resolved.conditionalModifiersetBonusmissingPredicateKind
- CARD-008autoAttackcomputableMap-conditional card — '+20% damage in PvP/GvG maps only'Tests the mapType predicate. Same character, same target — only the context.mapType differs across variants. Card should apply in pvp/gvg, not in pve.conditionalModifiermapTypePredicatecontextDependentModifier
- CARD-009autoAttackcomputableLayered conditions — '+50% damage vs Boss-class Demon-race in PvE only'A real-world-flavored card with AND of three conditions: class=boss, race=demon, mapType=pve. Tests that all three must match. Four variants flip each condition off in turn — exactly one variant should have the bonus active.conditionalModifiernestedAndConditiontripleConditionInteraction
- CARD-010autoAttackcomputableCard vs same-scope Effect — '+10% ATK card' AND '+15% ATK from Cart Boost'Tests that modifiers from DIFFERENT sources (Card vs Effect) in the SAME scope stack additively per D-005. The total atk.percent should be +25%, not (1.10)(1.15)=1.265.conditionalModifiercrossSourceAdditivityatkPercentScope
- STATUS-001resolveStatsOnlycomputableBlessing + Increase AGI buff stacking — no overlap, both applyTwo independent buffs targeting different stats (Blessing → STR/INT/DEX, Increase AGI → AGI/ASPD). Both should fully apply with no interaction. The canonical positive case — if this doesn't work, the buff system is fundamentally broken. (Note: this duplicates SC-006 intentionally as a starting point for the STATUS-* suite.)effectStackingdifferentScopesnoConflict
- STATUS-002resolveStatsOnlycomputableSame buff applied twice — refresh policy resets duration but does NOT double the effectWhen the same Effect is applied to an Actor that already has it active, with stackingPolicy='refresh', the duration restarts but Modifiers do NOT double. Tests that the library de-duplicates by Effect ID, not by Modifier identity.stackingPolicyrefreshPolicynoDoubleApplication
- STATUS-003computeEffectTickcomputablestack_intensity policy — 5 stacks of a bleed-style DoT scale damage by stack countTests that Effects with stackingPolicy='stack_intensity' use the stacks field to multiply Modifier values OR tick damage. This scenario uses tick damage scaling. Demonstrates that 5 stacks of bleed deal 5x the per-stack damage.stackingPolicystackIntensityDoTstackCountScaling
- STATUS-004computeEffectTickcomputableDoT dynamic re-evaluation — Poison tick changes when target's MaxHP changesPer D-004, default snapshot=false means DoT ticks recompute from current state every tick. Two sub-tick computations: same Poison on the same target, but a buff that raises VIT (and therefore MaxHP) is active in the second. Tick damage must differ.DoTdynamicSnapshotsnapshotPolicyDefault
- STATUS-005computeEffectTickcomputableDoT snapshot=true — Burn tick uses caster's stats at apply timeInverse of STATUS-004. When snapshot=true, tick damage is computed from the snapshotState captured at apply time, not from current state. Even if the caster (or target) gets buffed later, ticks use the frozen values.DoTsnapshotPolicysnapshotTruecasterSnapshot
- STATUS-006computeEffectTickcomputablestack_independent — two Acid Bomb DoTs from different casters tick separatelyWith stackingPolicy='stack_independent', applying the same Effect twice creates two distinct Effect instances on the target. Each has its own duration and ticks independently. Common case: two players DoT the same monster.stackingPolicystackIndependentmultipleDoTInstances
- STATUS-007resolveStatsOnlycomputablemaxStacks cap — Earth Spike repeated past cap stays at maxStacksAn Effect with maxStacks=5 should never exceed 5 stacks regardless of how many times it's applied. Tests that the schema's stacks field never exceeds maxStacks. (Note: enforcement is shared between caller (on apply) and library (on read) — both should respect it.)maxStacksstackCapstackIntensity
- STATUS-008skillcomputableStatus condition predicate — '+25% damage while target is Frozen'Tests the hasStatus condition predicate (D-009). A Modifier conditional on the defender having a specific Effect active. Variants: target frozen → bonus applies; target not frozen → bonus does not.conditionalModifierhasStatusPredicatestatusInteraction
- STATUS-009resolveStatsOnlycomputableStat-debuff Effect — Decrease AGI on target reduces FLEE in resolveStatsTests that debuff Effects with negative-value Modifiers reduce resolved stats correctly. Decrease AGI: -AGI flat → lower resolved AGI → lower FLEE. Confirms that flat modifiers with negative values work and don't accidentally clamp to zero.debuffnegativeFlatModifierfleeReductionstatResolution
- STATUS-010resolveStatsOnlycomputableignore stacking — second Kyrie Eleison cast while one is active is a no-opTests stackingPolicy='ignore'. If a buff with this policy is already on the actor, re-applying it does nothing (duration not refreshed, modifiers not doubled). This is rare in RO but exists for certain self-buffs that shouldn't be 'recasted up'. Verifies the library doesn't accidentally duplicate the effect.stackingPolicyignorePolicynoOpReapplication