← Back to Runs
Compare Runs
A (baseline)
B (current)
Avg Error A0.20%
Avg Error B0.14%
Δ Avg Error-0.06%
Changed41
Improved28
Regressed13
Added113
Retired0
Testcase Delta
414 / 414
Code / Config Changes
Commits (7f6ec1ee → 2b3f7928)
2b3f7928Various issues causng small sim-game diferences fixedpiddlyminx25/09/2026, 05:51:17
Code Changes (Run A → Run B)
Index: simulator/config/hero_definitions/Ahmose.json===================================================================--- simulator/config/hero_definitions/Ahmose.json prev run+++ simulator/config/hero_definitions/Ahmose.json this run@@ -5,10 +5,11 @@"skills": {"ViperFormation": {"description": "His infantry pauses the attack once every 4 times reducing damage taken by Lancers and Marksmen by X% and Infantry by X% for 2 turns","trigger": {- "type": "turn",- "every": 4+ "type": "attack",+ "every": 4,+ "source": "infantry"},"effects": {"ViperFormation/1": {"type": "no_attack",@@ -18,57 +19,56 @@]},"duration": {"turns": {- "count": 1+ "count": 1,+ "delay": 1}},- "reason": "Protection is earned by using the Infantry pause. Delay its child effects so protection covers two complete turns, independent of attack order.",- "trigger_effects": {- "ViperFormation/2": {- "type": "active.hero.damageTaken.down",- "value": [- 10,- 15,- 20,- 25,- 30- ],- "units": {- "applies_to": [- "lancer",- "marksman"- ]- },- "duration": {- "turns": {- "count": 2,- "delay": 1- }- }- },- "ViperFormation/3": {- "type": "active.hero.damageTaken.down",- "value": [- 10,- 25,- 40,- 55,- 70- ],- "units": {- "applies_to": [- "infantry"- ]- },- "duration": {- "turns": {- "count": 2,- "delay": 1- }- }+ "reason": "Protection starts when the Infantry pause is used, with no additional turn delay."+ },+ "ViperFormation/2": {+ "type": "active.hero.damageTaken.down",+ "value": [+ 10,+ 15,+ 20,+ 25,+ 30+ ],+ "units": {+ "applies_to": [+ "lancer",+ "marksman"+ ]+ },+ "duration": {+ "turns": {+ "count": 2,+ "delay": 1}}+ },+ "ViperFormation/3": {+ "type": "active.hero.damageTaken.down",+ "value": [+ 10,+ 25,+ 40,+ 55,+ 70+ ],+ "units": {+ "applies_to": [+ "infantry"+ ]+ },+ "duration": {+ "turns": {+ "count": 2,+ "delay": 1+ }+ }}}},"PrayerOfFlame": {@@ -101,9 +101,9 @@"source": "infantry"},"effects": {"BladeOfLight/1": {- "type": "active.hero.damage.up",+ "type": "extra_skill_attack","value": [12,24,36,@@ -114,13 +114,14 @@"applies_to": ["infantry"]},- "duration": {- "attacks": {- "count": 1+ "trigger_damage_jobs": [+ {+ "source": "use.source",+ "target": "use.target"}- }+ ]},"BladeOfLight/2": {"type": "active.hero.damageTaken.up","value": [Index: simulator/config/hero_definitions/Gordon.json===================================================================--- simulator/config/hero_definitions/Gordon.json prev run+++ simulator/config/hero_definitions/Gordon.json this run@@ -21,10 +21,10 @@80,100],"units": {- "applies_to": "trigger.source",- "applies_vs": "trigger.target"+ "applies_to": "trigger.source",+ "applies_vs": "trigger.target"},"duration": {"attacks": {"count": 1@@ -60,8 +60,9 @@},"effects": {"ChemicalTerror/1": {"type": "active.hero.damage.up",+ "applies_to_damage_kinds": ["normal"],"value": [30,60,90,@@ -74,9 +75,10 @@]},"duration": {"turns": {- "count": 1+ "count": 1,+ "delay": 1}},"same_effect_stacking": "max"},@@ -98,8 +100,30 @@"count": 1}},"same_effect_stacking": "max"+ },+ "ChemicalTerror/3": {+ "type": "active.hero.damage.up",+ "applies_to_damage_kinds": ["skill"],+ "value": [+ 30,+ 60,+ 90,+ 120,+ 150+ ],+ "units": {+ "applies_to": [+ "lancer"+ ]+ },+ "duration": {+ "turns": {+ "count": 1+ }+ },+ "same_effect_stacking": "max"}}},"ToxicRelease": {Index: simulator/config/hero_definitions/Gwen.json===================================================================--- simulator/config/hero_definitions/Gwen.json prev run+++ simulator/config/hero_definitions/Gwen.json this run@@ -19,9 +19,9 @@20,25],"units": {- "applies_to": "enemy.any"+ "applies_to": "trigger.target"},"duration": {"attacks": {"count": 1,@@ -34,9 +34,8 @@"AirDominance": {"description": "Grants all troops' attack X% extra damage after every 5 attacks and causes the target to receive X% extra damage for its next attack received","trigger": {"type": "attack",- "first": 5,"every": 6,"source": "self.any"},"effects": {@@ -57,30 +56,28 @@{"source": "use.source","target": "use.target"}- ]- },- "AirDominance/2": {- "type": "active.hero.damageTaken.up",- "value": [- 5,- 7.5,- 10,- 12.5,- 15],- "units": {- "applies_to": "trigger.target"- },- "same_effect_stacking": "max",- "duration": {- "turns": {- "count": 1,- "delay": 1- },- "attacks": {- "count": 1+ "trigger_effects": {+ "AirDominance/2": {+ "type": "active.hero.damageTaken.up",+ "value": [+ 5,+ 7.5,+ 10,+ 12.5,+ 15+ ],+ "units": {+ "applies_to": "parent.use.target"+ },+ "same_effect_stacking": "max",+ "duration": {+ "attacks": {+ "count": 1+ }+ }}}}}@@ -88,10 +85,9 @@"Blastmaster": {"description": "Gwen equips her Marksmen with grenades, dealing X% extra damage to all enemies on the next attack of every 4 attacks","trigger": {"type": "attack",- "first": 5,- "every": 4,+ "every": 5,"source": "marksman"},"effects": {"Blastmaster/1": {Index: simulator/config/hero_definitions/README.md===================================================================--- simulator/config/hero_definitions/README.md prev run+++ simulator/config/hero_definitions/README.md this run@@ -347,8 +347,10 @@For example, an attack-triggered effect created during round 3 with `{ "turns": { "delay": 1, "count": 2 } }` is active in rounds 4 and 5 and expires at the start of round 6.An attack-triggered effect with `{ "turns": { "count": 1 } }` is available for later jobs in the same round, but expires before the next round begins. It does not mean “the next full turn.”+The native troop skills MasterBrawler, Charge, and RangedStrike use source/target matchup conditions on their attack triggers, apply their buffs to `trigger.source`, and use `{ "turns": { "count": 1 } }`. They omit effect-level `applies_vs`: the matchup controls activation, not subsequent recipients. The buff applies to the triggering attack and later attacks by that troop type in the same round, including extra attacks against other troop types. Extra attacks do not activate these skills again.+**Battle-start delay gotcha.** Battle-start effects are created at setup round 0, while the earliest active round is clamped to 1. Consequently, both `turns.delay: 0` and `turns.delay: 1` start in round 1. A battle-start effect needs `delay: 2` to begin in round 2. No current hero definition combines `battle_start` with a turn delay, but the distinction matters when authoring one.### `attacks`@@ -452,12 +454,16 @@If selectors produce multiple sources and targets, the simulator considers their Cartesian product. Sources or targets with zero round-start troops are skipped. In normal PvP mode, a target already exhausted by earlier same-round jobs is also skipped before calculation. For example, one source and `enemy.living` can produce up to three skill jobs, but fewer may actually run.The job selector determines the actual side as well as the unit. The runtime does not enforce that a generated source and target are opponents, so scopes misconfigured onto the same side can generate friendly-fire or same-side jobs.+Target-specific modifiers are selected against each generated job's actual recipient. They do not inherit the initiating normal attack's target or its matchup bonuses.+The extra-attack effect is charged once for the parent normal attack if at least one of its jobs runs. If its `value` is non-positive, every job lacks living source/target troops, or every job is skipped because its target is already exhausted, the effect is not charged and can remain available.-When an `extra_skill_attack` is materialized as a carrier's `trigger_effects` child, its completed damage result is captured in the carrier-use round and stored on that child ActiveEffect. The child can deliver that fixed result only when a later normal attack matches its resolved source and target scope. Delivery does not run the damage equation again; if the matching attack never occurs during the child's duration, the pending damage expires with the effect.+Immediate and delayed hits share the same generation and delivery routines. Generation uses reusable scratch and the prepared modifier-group index to calculate non-shield damage. Delivery selects applicable shields from a small live list, consumes protection, and applies the current target-troop cap. Shield activation and expiry use the ordinary effect scheduler; shields retain group identity for stacking and dependencies but are excluded from the modifier job-shape lists.+When an `extra_skill_attack` is materialized as a carrier's `trigger_effects` child, its generated damage is retained on that child ActiveEffect. Fast and standard modes retain scalar calculation state and the recording context; only trace mode copies the full bucket factors. Shields are not selected, advanced, or consumed during generation. The child can deliver its damage only when a later normal attack matches its resolved source and target scope, after that normal hit has resolved. Delivery uses the generation-time health conversion factor for shield-budget conversion without recalculating the damage. If the matching attack never occurs during the child's duration, the pending damage expires without consuming shields.+Renee's Nightmare Trace uses this form with a one-turn delay: the even-round Lancer attack locks the target and calculates the damage, then the following odd-round Lancer attack delivers it. The precise capture ordering and treatment of defensive state are provisional reverse-engineering assumptions, not confirmed game mechanics.All jobs emitted by one use read the parent extra-attack effect's same current `value`; its use/evolution is charged only after those jobs finish. Other attack-limited **modifier** effects are different: each generated skill job is a separate modifier use, and modifiers are charged after each job, so a one-job modifier can expire before the second target in the same extra attack is calculated.Index: simulator/config/hero_definitions/Renee.json===================================================================--- simulator/config/hero_definitions/Renee.json prev run+++ simulator/config/hero_definitions/Renee.json this run@@ -23,9 +23,9 @@"NightmareTrace/1": {"type": "extra_skill_attack","value": [40, 80, 120, 160, 200],"units": {- "applies_to": "parent.use.source",+ "applies_to": "self.any","applies_vs": "parent.use.target"},"trigger_damage_jobs": [{@@ -95,9 +95,8 @@},"trigger_effects": {"Dreamslice/1": {"type": "active.hero.damageTaken.up",- "applies_to_damage_kinds": ["normal"],"value": [15, 30, 45, 60, 75],"units": {"applies_to": "parent.use.target","applies_vs": "any"Index: simulator/config/troop_skills.json===================================================================--- simulator/config/troop_skills.json prev run+++ simulator/config/troop_skills.json this run@@ -11,23 +11,23 @@"value": 0}],"trigger": {- "type": "battle_start"+ "type": "attack",+ "source": "infantry",+ "target": "lancer"},"effects": {"MasterBrawler/1": {"type": "type.single_target.damage.up","value": [10],"units": {- "applies_to": [- "infantry"- ],- "applies_vs": [- "lancer"- ]+ "applies_to": "trigger.source"+ },+ "duration": {+ "turns": { "count": 1 }}}}},@@ -162,23 +162,23 @@"value": 0}],"trigger": {- "type": "battle_start"+ "type": "attack",+ "source": "lancer",+ "target": "marksman"},"effects": {"Charge/1": {"type": "type.single_target.damage.up","value": [10],"units": {- "applies_to": [- "lancer"- ],- "applies_vs": [- "marksman"- ]+ "applies_to": "trigger.source"+ },+ "duration": {+ "turns": { "count": 1 }}}}},@@ -320,23 +320,23 @@"value": 0}],"trigger": {- "type": "battle_start"+ "type": "attack",+ "source": "marksman",+ "target": "infantry"},"effects": {"RangedStrike/1": {"type": "type.single_target.damage.up","value": [10],"units": {- "applies_to": [- "marksman"- ],- "applies_vs": [- "infantry"- ]+ "applies_to": "trigger.source"+ },+ "duration": {+ "turns": { "count": 1 }}}}},Index: simulator/src/damage.test.ts===================================================================--- simulator/src/damage.test.ts prev run+++ simulator/src/damage.test.ts this run@@ -1,19 +1,22 @@import assert from "node:assert/strict";import { test } from "node:test";import {- calculateDamageJob,+ generateDamageJob,+ deliverDamageJob,+ retainGeneratedDamage,+ type DamageJobOptions,ceilIgnoringFloatResidue,createDamageScratch,evaluateDamageExpression} from "./damage";import { DYNAMIC_BUCKETS, STATIC_BUCKETS, type BucketJobSide, type BucketPlacement } from "./damageBuckets";-import { createEffectIndex, damageShapeSlotsForEffect, DAMAGE_JOB_SHAPE_SLOTS, indexEffect } from "./effectIndex";+import { createEffectIndex, damageShapeSlotsForEffect, DAMAGE_JOB_SHAPE_SLOTS, expireEffectIndex, indexEffect } from "./effectIndex";import { activateEffect, evolvingActiveEffectValue, resolvedEffectScopeKey } from "./effects";import { buildStaticDamageBucketFactors, buildStaticDamageProfile } from "./staticDamageProfile";-import { createRecorder, type BattleRecorder } from "./recorder";-import type { ActiveEffect, DamageJob, ResolvedFighter } from "./types";+import { createRecorder } from "./recorder";+import type { ActiveEffect, DamageJob, EvolvingActiveEffect, ResolvedFighter } from "./types";import { ALL_UNIT_MASK, unitMask } from "./types";const job: DamageJob = {round: 1,@@ -61,10 +64,21 @@function calculateIndexedDamageJob(damageJob: DamageJob,fighters: Record<"attacker" | "defender", ResolvedFighter>,effects: ActiveEffect[],- options: Omit<Partial<Parameters<typeof calculateDamageJob>[2]>, "recorder"> & { recorder?: BattleRecorder; trace?: boolean } = {}+ options: Partial<DamageJobOptions> & { trace?: boolean } = {}) {+ const preparedOptions = damageJobOptions(fighters, effects, options);+ const generated = generateDamageJob(damageJob, fighters, preparedOptions);+ const result = deliverDamageJob(damageJob, generated, preparedOptions);+ return { ...result, usedEffectIds: preparedOptions.usedEffects!.map((usedEffect) => usedEffect.intent.id) };+}++function damageJobOptions(+ fighters: Record<"attacker" | "defender", ResolvedFighter>,+ effects: ActiveEffect[],+ options: Partial<DamageJobOptions> & { trace?: boolean } = {}+): DamageJobOptions {const effectIndex = options.effectIndex ?? preparedEffectIndex(effects);if (!options.effectIndex) {for (const activeEffect of effects) {if (activeEffect.effectGroup) indexEffect(effectIndex, activeEffect);@@ -76,10 +90,9 @@throw new Error("damage-only test recorder has no battle resolution");});recorder.recordStaticProfile(fighters, effects);const { trace: _trace, ...damageOptions } = options;- const result = calculateDamageJob(damageJob, fighters, { ...damageOptions, recorder, effectIndex, staticDamageProfile, usedEffects });- return { ...result, usedEffectIds: [...usedEffects].map((usedEffect) => usedEffect.intent.id) };+ return { ...damageOptions, recorder, effectIndex, staticDamageProfile, usedEffects };}function preparedEffectIndex(effects: ActiveEffect[]): ReturnType<typeof createEffectIndex> {const groups: NonNullable<ActiveEffect["effectGroup"]>[] = [];@@ -97,17 +110,19 @@sameEffectStacking: activeEffect.sameEffectStacking};byResolvedGroup.set(key, group);groups.push(group);- for (const slot of slots) byShape[slot].push(group);+ if (activeEffect.kind !== "shield") {+ for (const slot of slots) byShape[slot].push(group);+ }}activeEffect.effectGroup = group;}return createEffectIndex(groups, byShape);}test("damage calculator requires indexed effect candidates", () => {- assert.throws(() => calculateDamageJob(job, simpleFighters(), { trace: true } as never), /effectIndex/i);+ assert.throws(() => generateDamageJob(job, simpleFighters(), { trace: true } as never), /effectIndex/i);});test("damage calculator counts every positive fractional remainder as one living troop", () => {const fractionalJob: DamageJob = {@@ -472,8 +487,171 @@assert.ok(Math.abs(damageTakenUp.kills - baseline.kills * 1.25) < 1e-12);assert.ok(Math.abs(damageTakenDown.kills - baseline.kills / 1.25) < 1e-12);});+test("retained damage preserves generation modifiers and health conversion across scratch reuse", () => {+ for (const mode of ["fast", "trace"] as const) {+ const fighters = simpleFighters();+ const health = effect("active.hero.health.up", "defender", 100);+ const shield: ActiveEffect = {+ ...effect("active.hero.shield", "defender", 8),+ kind: "shield",+ duration: { turns: { count: 2 } },+ intent: {+ id: "source-shield",+ type: "active.hero.shield",+ value: 8,+ value_formula: { type: "percent_of", source: "trigger.source_attack" }+ }+ };+ const index = preparedEffectIndex([health, shield]);+ indexEffect(index, health);+ const options = damageJobOptions(fighters, [], {+ effectIndex: index,+ scratch: createDamageScratch(),+ recorder: createRecorder(mode, [], () => { throw new Error("damage-only recorder"); })+ });+ const expected = calculateIndexedDamageJob(job, fighters, [effect("active.hero.health.up", "defender", 100)]);+ const retained = retainGeneratedDamage(generateDamageJob(job, fighters, options));+ expireEffectIndex(index, health);+ const interveningJob = { ...job, sourceMultiplier: 3 };+ const intervening = deliverDamageJob(interveningJob, generateDamageJob(interveningJob, fighters, options), options);+ assert.ok(intervening.kills > expected.kills);+ indexEffect(index, shield);+ const delivered = deliverDamageJob({ ...job, round: 2 }, retained, options);+ assert.ok(Math.abs(delivered.kills - Math.max(0, expected.kills - 4)) < 1e-12, mode);+ if (mode === "trace") {+ assert.equal(delivered.trace?.atomicBuckets["active.hero.health.up"].totalPct, 100);+ assert.equal(delivered.trace?.damageBeforeOffsets, expected.kills);+ assert.equal(delivered.trace?.offsetDamage, 4);+ }+ }+});++test("damage generation leaves shield delay and protection untouched until delivery", () => {+ const fighters = simpleFighters();+ const shield: ActiveEffect = {+ ...effect("active.hero.shield", "defender", 4),+ kind: "shield",+ duration: { turns: { count: 2 } },+ remainingAttackDelay: 1+ };+ const options = damageJobOptions(fighters, [shield], { trace: true, scratch: createDamageScratch() });+ const baseline = calculateIndexedDamageJob(job, fighters, []).kills;+ const first = retainGeneratedDamage(generateDamageJob(job, fighters, options));+ const second = retainGeneratedDamage(generateDamageJob(job, fighters, options));+ const firstArrival = deliverDamageJob(job, first, options);+ const secondArrival = deliverDamageJob(job, second, options);+ assert.equal(firstArrival.kills, baseline);+ assert.equal(secondArrival.kills, Math.max(0, baseline - 4));+ assert.equal(firstArrival.trace?.offsetDamage, 0);+ assert.equal(secondArrival.trace?.offsetDamage, 4);+});++test("delayed damage ignores shields that expire or deplete before arrival", () => {+ const fighters = simpleFighters();+ const expired: ActiveEffect = {+ ...effect("active.hero.shield", "defender", 100),+ kind: "shield",+ duration: { turns: { count: 1 } }+ };+ const depleted: ActiveEffect = {+ ...effect("active.hero.shield", "defender", 3),+ kind: "shield",+ duration: { turns: { count: 2 } }+ };+ const options = damageJobOptions(fighters, [expired, depleted], { trace: true, scratch: createDamageScratch() });+ const baseline = calculateIndexedDamageJob(job, fighters, []).kills;+ const retained = retainGeneratedDamage(generateDamageJob(job, fighters, options));+ expireEffectIndex(options.effectIndex, expired);+ const preceding = deliverDamageJob(job, generateDamageJob(job, fighters, options), options);+ assert.equal(preceding.kills, Math.max(0, baseline - 3));+ const arrival = deliverDamageJob({ ...job, round: 2 }, retained, options);+ assert.equal(arrival.kills, baseline);+ assert.equal(arrival.trace?.offsetDamage, 0);+ assert.equal(arrival.appliedEffects?.some((applied) => "kind" in applied && applied.kind === "shield"), false);+});++test("additive turn shields conserve same-group and independent budgets across successive hits", () => {+ const fighters = simpleFighters();+ const baseline = calculateIndexedDamageJob(job, fighters, []).kills;+ const first: ActiveEffect = {+ ...effect("active.hero.shield", "defender", baseline * 0.5),+ kind: "shield",+ duration: { turns: { count: 2 } }+ };+ const second: ActiveEffect = {+ ...effect("active.hero.shield", "defender", baseline * 0.5),+ kind: "shield",+ duration: { turns: { count: 2 } }+ };+ const troop: ActiveEffect = {+ ...effect("active.troop.shield", "defender", baseline * 0.5, "troop_skill"),+ kind: "shield",+ duration: { turns: { count: 2 } }+ };+ const options = damageJobOptions(fighters, [first, second, troop], { trace: true });+ const outcomes = Array.from({ length: 3 }, () => deliverDamageJob(job, generateDamageJob(job, fighters, options), options));+ assert.equal(outcomes[0].kills, 0);+ assert.ok(Math.abs(outcomes[1].kills - baseline * 0.5) < 1e-12);+ assert.equal(outcomes[2].kills, baseline);+ assert.ok(Math.abs(outcomes.reduce((total, outcome) => total + outcome.trace!.offsetDamage, 0) - baseline * 1.5) < 1e-12);+});++test("max-stacked turn shields drain suppressed siblings without adding their protection", () => {+ const fighters = simpleFighters();+ const baseline = calculateIndexedDamageJob(job, fighters, []).kills;+ const weaker: ActiveEffect = {+ ...effect("active.hero.shield", "defender", baseline * 1.25),+ intent: { id: "weaker", type: "active.hero.shield", value: baseline * 1.25 },+ kind: "shield",+ duration: { turns: { count: 2 } },+ sameEffectStacking: "max"+ };+ const stronger: ActiveEffect = {+ ...effect("active.hero.shield", "defender", baseline * 1.5),+ intent: { id: "stronger", type: "active.hero.shield", value: baseline * 1.5 },+ kind: "shield",+ duration: { turns: { count: 2 } },+ sameEffectStacking: "max"+ };+ const options = damageJobOptions(fighters, [weaker, stronger], { trace: true });+ const first = deliverDamageJob(job, generateDamageJob(job, fighters, options), options);+ assert.equal(first.kills, 0);+ assert.deepEqual(options.usedEffects!.map((active) => active.intent.id).sort(), ["stronger", "weaker"]);+ assert.deepEqual(first.appliedEffects?.filter((applied) => "kind" in applied && applied.kind === "shield").map((applied) => "value" in applied ? applied.value : undefined), [baseline]);+ const second = deliverDamageJob(job, generateDamageJob(job, fighters, options), options);+ const third = deliverDamageJob(job, generateDamageJob(job, fighters, options), options);+ assert.ok(Math.abs(second.kills - baseline * 0.5) < 1e-12);+ assert.equal(third.kills, baseline);+});++test("only shield-eligible damage kinds and source-target scopes advance attack delay", () => {+ const fighters = simpleFighters();+ const shield: ActiveEffect = {+ ...effect("active.hero.shield", "defender", 4),+ kind: "shield",+ intent: { id: "scoped-shield", type: "active.hero.shield", value: 4, applies_to_damage_kinds: ["normal"] },+ appliesTo: { side: "defender", units: unitMask("lancer") },+ appliesVs: { side: "attacker", units: unitMask("infantry") },+ remainingAttackDelay: 1+ };+ const options = damageJobOptions(fighters, [shield], { trace: true });+ const reverse: DamageJob = {+ ...job, dealerSide: "defender", dealerUnit: "lancer", takerSide: "attacker", takerUnit: "infantry"+ };+ for (const ineligible of [{ ...job, kind: "skill" as const }, reverse]) {+ const outcome = deliverDamageJob(ineligible, generateDamageJob(ineligible, fighters, options), options);+ assert.equal(outcome.kills, calculateIndexedDamageJob(ineligible, fighters, []).kills);+ assert.equal(outcome.trace?.offsetDamage, 0);+ }+ const firstEligible = deliverDamageJob(job, generateDamageJob(job, fighters, options), options);+ const secondEligible = deliverDamageJob(job, generateDamageJob(job, fighters, options), options);+ assert.equal(firstEligible.trace?.offsetDamage, 0);+ assert.equal(secondEligible.trace?.offsetDamage, 4);+ assert.equal(secondEligible.kills, Math.max(0, firstEligible.kills - 4));+});+test("a durationless shield subtracts its full raw value from normal and skill damage jobs", () => {const fighters = simpleFighters();const shield = {...effect("active.hero.shield", "defender", 25),@@ -550,8 +728,58 @@: 0;assert.equal(infantryApplied + lancerApplied, Math.min(shieldValue, infantryBaseline.kills + lancerBaseline.kills));});+test("source-attack shields conserve their budget when health modifiers change", () => {+ const fighters = simpleFighters();+ const incoming = { ...job, sourceMultiplier: 0.3 };+ const health = effect("active.hero.health.up", "defender", 100);+ const shield: ActiveEffect = {+ ...effect("active.hero.shield", "defender", 4),+ kind: "shield",+ duration: { turns: { count: 1 } },+ intent: {+ id: "source-shield",+ type: "active.hero.shield",+ value: 4,+ value_formula: { type: "percent_of", source: "trigger.source_attack" }+ }+ };++ const first = calculateIndexedDamageJob(incoming, fighters, [health, shield]);+ const afterHealthExpires = calculateIndexedDamageJob(incoming, fighters, [shield]);+ const afterShieldExhaustion = calculateIndexedDamageJob(incoming, fighters, [health, shield]);++ assert.equal(first.kills, 0);+ assert.ok(Math.abs(afterHealthExpires.kills - 2) < 1e-12);+ assert.ok(Math.abs(afterShieldExhaustion.kills - 1.5) < 1e-12);+});++test("kill-derived shield budgets are not converted twice by health modifiers", () => {+ const fighters = simpleFighters();+ const incoming = { ...job, sourceMultiplier: 0.3 };+ const health = effect("active.hero.health.up", "defender", 100);+ const shield: ActiveEffect = {+ ...effect("active.hero.shield", "defender", 4),+ kind: "shield",+ duration: { turns: { count: 1 } },+ intent: {+ id: "kill-shield",+ type: "active.hero.shield",+ value: 4,+ value_formula: { type: "percent_of", source: "trigger.total_kills" }+ }+ };++ const first = calculateIndexedDamageJob(incoming, fighters, [health, shield]);+ const second = calculateIndexedDamageJob(incoming, fighters, [health, shield]);+ const third = calculateIndexedDamageJob(incoming, fighters, [health, shield]);++ assert.equal(first.kills, 0);+ assert.equal(second.kills, 0);+ assert.ok(Math.abs(third.kills - 0.5) < 1e-12);+});+test("an attack-duration shield keeps its full value in a mixed-formation army", () => {const fighters = simpleFighters();fighters.attacker.initialTroops = { infantry: 1000, lancer: 10, marksman: 0 };fighters.attacker.troopDetails.lancer = {Index: simulator/src/damage.ts===================================================================--- simulator/src/damage.ts prev run+++ simulator/src/damage.ts this run@@ -25,9 +25,9 @@type DynamicDamageBucket,type StaticDamageBucket} from "./damageBuckets";import { advanceEffectAttackDelay, isEffectAttackReady } from "./effects";-import { damageJobShapeSlot, damageJobSlot, type EffectIndex } from "./effectIndex";+import { damageJobSlot, shieldEffectApplies, type EffectIndex } from "./effectIndex";import type { BattleRecorder, DamageJobRecorder } from "./recorder";type NumericBucketId = number;interface DamageFactorTerm {@@ -39,8 +39,9 @@interface NumericDamageBuckets {factors: Float64Array;turnShield?: ActiveEffect;turnShieldGroup?: ActiveEffect[];+ generated?: GeneratedDamage;}interface CompiledDamageExpression {numeratorSlots: Int32Array;@@ -113,32 +114,91 @@primaryUsedEffects?: ActiveEffect[];minInitialArmy?: number;}-export function calculateDamageJob(+/** Borrowed during immediate delivery; retainGeneratedDamage owns delayed state. */+export interface GeneratedDamage {+ factors?: Float64Array;+ recording: DamageJobRecorder;+ armyTerm: number;+ damageBeforeOffsets: number;+ healthFactor: number;+}++export function generateDamageJob(job: DamageJob,fighters: Record<SideId, ResolvedFighter>,options: DamageJobOptions-): DamageResult {- if (!options?.effectIndex) throw new Error("calculateDamageJob requires an effectIndex");- if (!options.recorder) throw new Error("calculateDamageJob requires a recorder");- if (!options.staticDamageProfile) throw new Error("calculateDamageJob requires a staticDamageProfile");+): GeneratedDamage {+ if (!options?.effectIndex) throw new Error("generateDamageJob requires an effectIndex");+ if (!options.recorder) throw new Error("generateDamageJob requires a recorder");+ if (!options.staticDamageProfile) throw new Error("generateDamageJob requires a staticDamageProfile");const recording = options.recorder.startDamageJob();- const staticProfile = options.staticDamageProfile;+ const buckets = options.scratch ? resetDamageScratch(options.scratch) : createNumericDamageBuckets();+ const usedEffects = options.usedEffects ?? [];+ const armyTerm = populateDamageBuckets(job, fighters, options, buckets, recording, usedEffects, options.primaryUsedEffects ?? usedEffects);+ const generated = buckets.generated ??= {+ factors: buckets.factors, recording, armyTerm, damageBeforeOffsets: 0, healthFactor: 1+ };+ generated.recording = recording;+ generated.armyTerm = armyTerm;+ generated.damageBeforeOffsets = evaluateDamageExpressionForJob(job, buckets, options.staticDamageProfile);+ generated.healthFactor = buckets.factors[DYNAMIC_BUCKET_INDEX["active.hero.health.up"]] *+ buckets.factors[DYNAMIC_BUCKET_INDEX["active.troop.health.up"]] /+ buckets.factors[DYNAMIC_BUCKET_INDEX["active.hero.health.down"]] /+ buckets.factors[DYNAMIC_BUCKET_INDEX["active.troop.health.down"]];+ return generated;+}++export function retainGeneratedDamage(generated: GeneratedDamage): GeneratedDamage {+ return {+ factors: generated.recording.needsFactors ? generated.factors!.slice() : undefined,+ recording: generated.recording,+ armyTerm: generated.armyTerm,+ damageBeforeOffsets: generated.damageBeforeOffsets,+ healthFactor: generated.healthFactor+ };+}++export function deliverDamageJob(+ job: DamageJob,+ generated: GeneratedDamage,+ options: DamageJobOptions+): DamageResult {+ const { recording, armyTerm, damageBeforeOffsets, healthFactor } = generated;+ const buckets = options.scratch ?? createNumericDamageBuckets();+ if (generated.factors !== buckets.factors) {+ resetDamageScratch(buckets);+ if (generated.factors) buckets.factors.set(generated.factors);+ }+ const usedEffects = options.usedEffects ?? [];+ const primaryUsedEffects = options.primaryUsedEffects ?? usedEffects;+ const offsetDamage = applyShields(job, options.effectIndex, buckets, recording, damageBeforeOffsets, healthFactor, usedEffects, primaryUsedEffects);+ const rawDamage = Math.max(0, damageBeforeOffsets - offsetDamage);+ const takerTroops = job.roundStartTroops[job.takerSide][job.takerUnit] ?? 0;+ const kills = options.capToTakerTroops === false ? rawDamage : Math.min(takerTroops, rawDamage);+ return recording.finish({ job, factors: buckets.factors, armyTerm, damageBeforeOffsets, offsetDamage, rawDamage, kills });+}++function populateDamageBuckets(+ job: DamageJob,+ fighters: Record<SideId, ResolvedFighter>,+ options: DamageJobOptions,+ buckets: NumericDamageBuckets,+ recording: DamageJobRecorder,+ usedEffects: ActiveEffect[],+ primaryUsedEffects: ActiveEffect[]+): number {// Fractional casualties carry between rounds, but every positive remainder is// still one living troop and contributes fully to the next attack.const dealerTroops = ceilIgnoringFloatResidue(Math.max(0, job.roundStartTroops[job.dealerSide][job.dealerUnit] ?? 0));- const takerTroops = job.roundStartTroops[job.takerSide][job.takerUnit] ?? 0;const initialArmy = options.minInitialArmy ?? minInitialArmy(fighters);const armyTerm = Math.sqrt(dealerTroops) * Math.sqrt(initialArmy);- const buckets = options.scratch ? resetDamageScratch(options.scratch) : createNumericDamageBuckets();applyDynamicDamageBucketValue(buckets, "troops.count", armyTerm);applyDynamicDamageBucketValue(buckets, "source.multiplier", job.sourceMultiplier ?? 1);- const usedEffects = options.usedEffects ?? [];- const primaryUsedEffects = options.primaryUsedEffects ?? usedEffects;const jobSlot = damageJobSlot(job);applyBucketEffects(options.effectIndex.damageGroupsByJobShape[jobSlot],options.effectIndex.liveEffectsByGroup,@@ -148,26 +208,12 @@recording,usedEffects,primaryUsedEffects);-- const damageBeforeOffsets = evaluateDamageExpressionForJob(job, buckets, staticProfile);- let offsetDamage = sumSlots(buckets.factors, DYNAMIC_EXPRESSIONS[job.kind].postSubtractSlots);- offsetDamage += applyTurnShield(- buckets,- job.round,- Math.max(0, damageBeforeOffsets - offsetDamage),- recording,- usedEffects,- primaryUsedEffects- );- const unroundedDamage = Math.max(0, damageBeforeOffsets - offsetDamage);- const rawDamage = unroundedDamage;- const uncappedKills = rawDamage;- const kills = options.capToTakerTroops === false ? uncappedKills : Math.min(takerTroops, uncappedKills);- return recording.finish({ job, factors: buckets.factors, armyTerm, damageBeforeOffsets, offsetDamage, rawDamage, kills });+ return armyTerm;}+function applyBucketEffects(groups: ActiveEffectGroup[],liveEffectsByGroup: ActiveEffect[][],round: number,@@ -177,44 +223,103 @@usedEffects: ActiveEffect[],primaryUsedEffects: ActiveEffect[]): void {for (const group of groups) {- const dependency = group.requiredGroupOrdinalsByJobShape;- if (dependency && !requiredEffectIsApplicable(dependency, liveEffectsByGroup, round, jobSlot)) continue;- const effects = liveEffectsByGroup[group.ordinal];- if (effects.length === 0) continue;- if (group.sameEffectStacking !== "max") {- for (const effect of effects) {- if (!advanceEffectAttackDelay(effect)) continue;- applyBucketEffect(effect, round, buckets, recording, usedEffects, primaryUsedEffects);- }- continue;- }- if (effects.length === 1) {- const effect = effects[0];- if (advanceEffectAttackDelay(effect)) {- applyBucketEffect(effect, round, buckets, recording, usedEffects, primaryUsedEffects);- }- continue;- }- let selected: ActiveEffect | undefined;- let selectedValue = Number.NEGATIVE_INFINITY;- const eligible: ActiveEffect[] = [];+ applyEffectGroup(group, liveEffectsByGroup, round, jobSlot, buckets, recording, usedEffects, primaryUsedEffects);+ }+}++function applyEffectGroup(+ group: ActiveEffectGroup,+ liveEffectsByGroup: ActiveEffect[][],+ round: number,+ jobSlot: number,+ buckets: NumericDamageBuckets,+ recording: DamageJobRecorder,+ usedEffects: ActiveEffect[],+ primaryUsedEffects: ActiveEffect[]+): void {+ const dependency = group.requiredGroupOrdinalsByJobShape;+ if (dependency && !requiredEffectIsApplicable(dependency, liveEffectsByGroup, round, jobSlot)) return;+ const effects = liveEffectsByGroup[group.ordinal];+ if (effects.length === 0) return;+ if (group.sameEffectStacking !== "max") {for (const effect of effects) {if (!advanceEffectAttackDelay(effect)) continue;- eligible.push(effect);- const appliedValue = effect.getCurrentValue(round);- if (!selected || appliedValue > selectedValue) {- selected = effect;- selectedValue = appliedValue;- }+ applyBucketEffect(effect, round, buckets, recording, usedEffects, primaryUsedEffects);}- if (selected) {- applyBucketEffectGroup(selected, eligible, selectedValue, buckets, recording, usedEffects, primaryUsedEffects);+ return;+ }+ if (effects.length === 1) {+ const effect = effects[0];+ if (advanceEffectAttackDelay(effect)) {+ applyBucketEffect(effect, round, buckets, recording, usedEffects, primaryUsedEffects);}+ return;}+ let selected: ActiveEffect | undefined;+ let selectedValue = Number.NEGATIVE_INFINITY;+ const eligible: ActiveEffect[] = [];+ for (const effect of effects) {+ if (!advanceEffectAttackDelay(effect)) continue;+ eligible.push(effect);+ const appliedValue = effect.getCurrentValue(round);+ if (!selected || appliedValue > selectedValue) {+ selected = effect;+ selectedValue = appliedValue;+ }+ }+ if (selected) {+ applyBucketEffectGroup(selected, eligible, selectedValue, buckets, recording, usedEffects, primaryUsedEffects);+ }}+function applyShields(+ job: DamageJob,+ index: EffectIndex,+ buckets: NumericDamageBuckets,+ recording: DamageJobRecorder,+ damage: number,+ healthFactor: number,+ usedEffects: ActiveEffect[],+ primaryUsedEffects: ActiveEffect[]+): number {+ if (index.shields.length === 0) return 0;+ const jobSlot = damageJobSlot(job);+ let previousGroup: ActiveEffectGroup | undefined;+ // Flat offsets precede consumable protection, as in the damage equation.+ for (const shield of index.shields) {+ const group = shield.effectGroup!;+ if (group === previousGroup) continue;+ previousGroup = group;+ if (isTurnShield(shield) || !shieldEffectApplies(shield, job)) continue;+ applyEffectGroup(group, index.liveEffectsByGroup, job.round, jobSlot, buckets, recording, usedEffects, primaryUsedEffects);+ }+ let offsetDamage = sumSlots(buckets.factors, DYNAMIC_EXPRESSIONS[job.kind].postSubtractSlots);+ previousGroup = undefined;+ for (const shield of index.shields) {+ const group = shield.effectGroup!;+ if (group === previousGroup) continue;+ previousGroup = group;+ if (!isTurnShield(shield) || !shieldEffectApplies(shield, job)) continue;+ buckets.turnShield = undefined;+ buckets.turnShieldGroup = undefined;+ if (group.sameEffectStacking === "max") {+ applyEffectGroup(group, index.liveEffectsByGroup, job.round, jobSlot, buckets, recording, usedEffects, primaryUsedEffects);+ offsetDamage += applyTurnShield(buckets, job.round, Math.max(0, damage - offsetDamage), healthFactor, recording, usedEffects, primaryUsedEffects);+ } else {+ const dependency = group.requiredGroupOrdinalsByJobShape;+ if (dependency && !requiredEffectIsApplicable(dependency, index.liveEffectsByGroup, job.round, jobSlot)) continue;+ for (const effect of index.liveEffectsByGroup[group.ordinal]) {+ if (!advanceEffectAttackDelay(effect)) continue;+ buckets.turnShield = effect;+ offsetDamage += applyTurnShield(buckets, job.round, Math.max(0, damage - offsetDamage), healthFactor, recording, usedEffects, primaryUsedEffects);+ }+ }+ }+ return offsetDamage;+}+function requiredEffectIsApplicable(dependency: Array<number[] | undefined>,liveEffectsByGroup: ActiveEffect[][],round: number,@@ -306,28 +411,32 @@function applyTurnShield(buckets: NumericDamageBuckets,round: number,damage: number,+ generatedHealthFactor: number,recording: DamageJobRecorder,usedEffects: ActiveEffect[],primaryUsedEffects: ActiveEffect[]): number {const selected = buckets.turnShield;if (!selected || damage <= 0) return 0;- const appliedValue = Math.min(selected.getCurrentValue(round), damage);+ // Source-attack budgets exclude runtime health modifiers; incoming casualties include them.+ const healthFactor = selected.intent.value_formula?.source === "trigger.source_attack" ? generatedHealthFactor : 1;+ const budgetUsed = Math.min(selected.getCurrentValue(round), damage * healthFactor);+ const appliedValue = Math.min(damage, budgetUsed / healthFactor);if (appliedValue <= 0) return 0;applySelectedBucket(selected, appliedValue, buckets, recording);const group = buckets.turnShieldGroup;if (!group) {- selected.initialValue = Math.max(0, selected.initialValue - appliedValue);+ selected.initialValue = Math.max(0, selected.initialValue - budgetUsed);usedEffects.push(selected);if (primaryUsedEffects !== usedEffects && selected.triggerEffects?.length) primaryUsedEffects.push(selected);return appliedValue;}for (const effect of group) {- effect.initialValue = Math.max(0, effect.initialValue - appliedValue);+ effect.initialValue = Math.max(0, effect.initialValue - budgetUsed);usedEffects.push(effect);if (effect !== selected) recording.recordRejected(effect, "same_effect_max_suppressed");}if (primaryUsedEffects !== usedEffects && selected.triggerEffects?.length) primaryUsedEffects.push(selected);Index: simulator/src/effectIndex.test.ts===================================================================--- simulator/src/effectIndex.test.ts prev run+++ simulator/src/effectIndex.test.ts this run@@ -51,9 +51,9 @@assert.deepEqual(index.damageGroupsByJobShape[damageJobSlot(job())].flatMap((group) => index.liveEffectsByGroup[group.ordinal]), [active]);});-test("expiring a modifier swap-removes it once from its shared job-shape group", () => {+test("expiring a modifier preserves the remaining candidates in its shared group", () => {const first = effect("active.hero.lethality.up");const second = effect("active.hero.lethality.up");second.intent = first.intent;const index = preparedIndex([first, second]);@@ -64,12 +64,32 @@assert.deepEqual(index.liveEffectsByGroup[group.ordinal], [first, second]);expireEffectIndex(index, first);assert.deepEqual(index.liveEffectsByGroup[group.ordinal], [second]);- assert.equal(second.effectGroupPosition, 0);- assert.equal(first.effectGroup, undefined);+ expireEffectIndex(index, first);+ assert.deepEqual(index.liveEffectsByGroup[group.ordinal], [second]);});+test("expiring shields preserves other live shields and their dependency candidates", () => {+ const first: ActiveEffect = { ...effect("active.hero.shield"), kind: "shield" };+ const second: ActiveEffect = { ...effect("active.hero.shield"), kind: "shield" };+ const index = preparedIndex([first, second]);+ const group = first.effectGroup!;+ indexEffect(index, first);+ indexEffect(index, second);+ assert.deepEqual(index.shields, [first, second]);+ assert.deepEqual(index.liveEffectsByGroup[group.ordinal], [first, second]);++ expireEffectIndex(index, first);+ expireEffectIndex(index, first);+ assert.deepEqual(index.shields, [second]);+ assert.deepEqual(index.liveEffectsByGroup[group.ordinal], [second]);++ expireEffectIndex(index, second);+ assert.deepEqual(index.shields, []);+ assert.deepEqual(index.liveEffectsByGroup[group.ordinal], []);+});+function effect(type: string): ActiveEffect {return {source: { kind: "hero_skill", side: "attacker", effectId: type },intent: { id: type, type, value: 25 },@@ -105,9 +125,11 @@sameEffectStacking: effect.sameEffectStacking};byResolvedGroup.set(key, group);groups.push(group);- for (const slot of slots) byShape[slot].push(group);+ if (effect.kind !== "shield") {+ for (const slot of slots) byShape[slot].push(group);+ }}effect.effectGroup = group;}return createEffectIndex(groups, byShape);Index: simulator/src/effectIndex.ts===================================================================--- simulator/src/effectIndex.ts prev run+++ simulator/src/effectIndex.ts this run@@ -1,6 +1,6 @@import type { ActiveEffect, ActiveEffectGroup, DamageJob, DamageKind, SideId, UnitType } from "./types";-import { unitsFromMask } from "./types";+import { unitMaskHas, unitsFromMask } from "./types";import { DYNAMIC_BUCKET_INDEX, dynamicBucketDefinition, type DynamicDamageBucket } from "./damageBuckets";/*** Runtime lookup structure for live effects, designed around the damage hot path.@@ -18,9 +18,9 @@* - A group is also the unit of same-effect max stacking: the max is selected among the* group's live effects, and preparation asserts that a max-stacking definition's* differently-scoped groups never overlap on a slot.*- * Control, extra-attack, and battle-order effects are rare and cheap; they stay in flat+ * Shield, control, extra-attack, and battle-order effects are rare and cheap; they stay in flat* lists matched per use. This split was benchmarked, not assumed — the group index beat a* per-job classifier scan by ~3x on long battles while staying byte-identical on parity.** Group descriptors and the two group arrays belong to the prepared battle and are@@ -31,8 +31,9 @@damageGroupsByJobShape: ActiveEffectGroup[][];effectGroups: ActiveEffectGroup[];// This run's live activations, parallel to effectGroups (indexed by group.ordinal).liveEffectsByGroup: ActiveEffect[][];+ shields: ActiveEffect[];controls: ActiveEffect[];extraAttacks: ActiveEffect[];battleOrder: ActiveEffect[];carriers: ActiveEffect[];@@ -48,8 +49,9 @@return {damageGroupsByJobShape,effectGroups,liveEffectsByGroup: effectGroups.map(() => []),+ shields: [],controls: [],extraAttacks: [],battleOrder: [],carriers: []@@ -80,8 +82,18 @@const live = index.liveEffectsByGroup[group.ordinal];effect.effectGroupPosition = live.length;live.push(effect);effect.bucketIndex = group.bucketIndex;+ if (effect.kind === "shield") {+ // Keep prepared group order; liveEffectsByGroup retains stacking/dependency identity.+ let position = index.shields.length;+ index.shields.push(effect);+ while (position > 0 && index.shields[position - 1].effectGroup!.ordinal > group.ordinal) {+ index.shields[position] = index.shields[position - 1];+ position -= 1;+ }+ index.shields[position] = effect;+ }}export function isRuntimeIndexableEffect(effect: ActiveEffect): boolean {if (effect.kind === "control" || effect.kind === "extra_attack" || effect.kind === "battle_order" || effect.kind === "carrier") return true;@@ -93,11 +105,20 @@if (effect.kind === "control") removeStable(index.controls, effect);else if (effect.kind === "extra_attack") removeStable(index.extraAttacks, effect);else if (effect.kind === "battle_order") removeStable(index.battleOrder, effect);else if (effect.kind === "carrier") removeStable(index.carriers, effect);+ else if (effect.kind === "shield") removeStable(index.shields, effect);removeEffectGroupEntry(index, effect);}+export function shieldEffectApplies(effect: ActiveEffect, job: DamageJob): boolean {+ return effect.appliesTo.side === job.takerSide &&+ unitMaskHas(effect.appliesTo.units, job.takerUnit) &&+ effect.appliesVs.side === job.dealerSide &&+ unitMaskHas(effect.appliesVs.units, job.dealerUnit) &&+ (effect.intent.applies_to_damage_kinds === undefined || effect.intent.applies_to_damage_kinds.includes(job.kind));+}+export function damageJobSlot(job: DamageJob): number {return damageJobShapeSlot(job.kind, job.dealerSide, job.dealerUnit, job.takerSide, job.takerUnit);}Index: simulator/src/extraAttacks.ts===================================================================--- simulator/src/extraAttacks.ts prev run+++ simulator/src/extraAttacks.ts this run@@ -8,9 +8,9 @@UnitType} from "./types";import { UNIT_TYPES, unitMaskHas, unitsFromMask } from "./types";import { advanceEffectAttackDelay } from "./effects";-import { calculateDamageJob, type DamageJobOptions } from "./damage";+import { generateDamageJob, deliverDamageJob, retainGeneratedDamage, ceilIgnoringFloatResidue, type DamageJobOptions } from "./damage";import { normalizeUnitType } from "./normalize";import {capJobToRemainingTarget,chargeEffectUse,@@ -25,9 +25,9 @@// Spawn, calculate, and charge extra attacks riding on one normal attack.// Returns the finalized kills from every generated job in this normal attack's// cluster. A triggered child can instead carry damage captured in an earlier round;-// that fixed result is emitted only when the child's locked normal attack matches.+// shields are settled only when the child's locked normal attack matches.// The effect is charged one use only when at least one of its own jobs actually ran.// Spawning reads only round-start state and the effect's own gates, so running earlier// effects' jobs first cannot change what later effects spawn.export function processExtraAttacks(@@ -57,36 +57,39 @@for (const pending of effect.pendingDamageJobs) {const deliveryJob: DamageJob = {...pending.job,round,- calculationRound: pending.job.round+ calculationRound: pending.job.round,+ roundStartTroops};if (loopOptions.capRoundKills && targetExhausted(deliveryJob, roundStartTroops, roundTargetDamage)) continue;recorder.recordScheduledDamageJob(deliveryJob);+ const result = deliverDamageJob(deliveryJob, pending.generated, damageJobOptions);if (loopOptions.capRoundKills) {- capJobToRemainingTarget(pending.result, deliveryJob, roundStartTroops, roundTargetDamage, recorder);+ capJobToRemainingTarget(result, deliveryJob, roundStartTroops, roundTargetDamage, recorder);} else if (loopOptions.capJobKills) {- pending.result.kills = Math.min(- pending.result.kills,+ result.kills = Math.min(+ result.kills,Math.max(0, roundStartTroops[deliveryJob.takerSide][deliveryJob.takerUnit] ?? 0));- recorder.recordFinalKills(pending.result);+ recorder.recordFinalKills(result);}- results.push({ job: deliveryJob, result: pending.result, intent });- totalKills += pending.result.kills;+ results.push({ job: deliveryJob, result, intent });+ totalKills += result.kills;processedJobCount += 1;firstProcessedJob ??= deliveryJob;+ chargeUsedEffectsForJob(runtime, deliveryJob, recorder);}} else {for (const definition of effect.triggerDamageJobs ?? []) {const sources = resolveTriggerJobSelector(definition.source, "source", effect, normalAttack, roundStartTroops);const targets = resolveTriggerJobSelector(definition.target, "target", effect, normalAttack, roundStartTroops);const multiplier = effect.getCurrentValue(round) / 100;if (multiplier <= 0) continue;for (const source of sources) {- if ((roundStartTroops[source.side][source.unit] ?? 0) <= 0) continue;+ if (ceilIgnoringFloatResidue(roundStartTroops[source.side][source.unit] ?? 0) <= 0) continue;for (const target of targets) {- if ((roundStartTroops[target.side][target.unit] ?? 0) <= 0) continue;+ if (ceilIgnoringFloatResidue(roundStartTroops[target.side][target.unit] ?? 0) <= 0) continue;const job: DamageJob = {round,kind: definition.damage_kind ?? "skill",roundStartTroops,@@ -98,9 +101,10 @@sourceMultiplier: multiplier};if (loopOptions.capRoundKills && targetExhausted(job, roundStartTroops, roundTargetDamage)) continue;recorder.recordScheduledDamageJob(job);- const result = calculateDamageJob(job, fighters, damageJobOptions);+ const generated = generateDamageJob(job, fighters, damageJobOptions);+ const result = deliverDamageJob(job, generated, damageJobOptions);if (job.kind === "skill") recorder.recordSkillDamageJob(job, effect);if (loopOptions.capRoundKills) {capJobToRemainingTarget(result, job, roundStartTroops, roundTargetDamage, recorder);}@@ -142,11 +146,11 @@for (const definition of effect.triggerDamageJobs ?? []) {const sources = resolveTriggerJobSelector(definition.source, "source", effect, normalAttack, roundStartTroops);const targets = resolveTriggerJobSelector(definition.target, "target", effect, normalAttack, roundStartTroops);for (const source of sources) {- if ((roundStartTroops[source.side][source.unit] ?? 0) <= 0) continue;+ if (ceilIgnoringFloatResidue(roundStartTroops[source.side][source.unit] ?? 0) <= 0) continue;for (const target of targets) {- if ((roundStartTroops[target.side][target.unit] ?? 0) <= 0) continue;+ if (ceilIgnoringFloatResidue(roundStartTroops[target.side][target.unit] ?? 0) <= 0) continue;const job: DamageJob = {round,kind: definition.damage_kind ?? "skill",roundStartTroops,@@ -156,10 +160,10 @@takerUnit: target.unit,sourceEffectId: effect.source.effectId ?? effect.intent.id,sourceMultiplier: multiplier};- const result = calculateDamageJob(job, fighters, { ...damageJobOptions, capToTakerTroops: false });- pending.push({ job, result });+ const generated = retainGeneratedDamage(generateDamageJob(job, fighters, damageJobOptions));+ pending.push({ job, generated });chargeUsedEffectsForJob(runtime, job, damageJobOptions.recorder);}}}@@ -202,9 +206,9 @@return units.map((unit) => ({ side: fallbackSide, unit }));}function livingUnits(side: SideId, roundStartTroops: DamageJob["roundStartTroops"]): TriggerJobUnit[] {- return UNIT_TYPES.filter((unit) => (roundStartTroops[side][unit] ?? 0) > 0).map((unit) => ({ side, unit }));+ return UNIT_TYPES.filter((unit) => ceilIgnoringFloatResidue(roundStartTroops[side][unit] ?? 0) > 0).map((unit) => ({ side, unit }));}function unitListFromSelector(selector: TriggerDamageJobSelector): UnitType[] | undefined {if (Array.isArray(selector)) {Index: simulator/src/recorder.ts===================================================================--- simulator/src/recorder.ts prev run+++ simulator/src/recorder.ts this run@@ -55,8 +55,9 @@}/** Per-damage-job observation sink selected by the enclosing battle recorder. */export interface DamageJobRecorder {+ readonly needsFactors: boolean;recordEffect(effect: ActiveEffect, value: number): void;recordRejected(effect: ActiveEffect, reason: RejectedEffectReason): void;finish(result: DamageRecordingResult): DamageResult;}@@ -121,8 +122,9 @@const NO_APPLIED_EFFECTS: AppliedEffect[] = [];const EMPTY_SKILL_REPORT: Record<SideId, SkillReportEntry[]> = { attacker: [], defender: [] };const NULL_DAMAGE_JOB_RECORDER: DamageJobRecorder = {+ needsFactors: false,recordEffect() {},recordRejected() {},finish({ kills }) {return { kills };@@ -390,8 +392,9 @@}}class BasicDamageJobRecorder implements DamageJobRecorder {+ readonly needsFactors = false;private readonly appliedEffects: AppliedEffect[] = [];constructor(private readonly staticApplied?: StaticAppliedIndex) {}@@ -409,8 +412,9 @@}}class FullDamageJobRecorder implements DamageJobRecorder {+ readonly needsFactors = true;private readonly appliedEffects: DamageEquationTrace["appliedEffects"] = [];private readonly contributors: DamageBucketTrace["contributors"][] = Array.from({ length: DYNAMIC_BUCKETS.length },() => []Index: simulator/src/runtime.ts===================================================================--- simulator/src/runtime.ts prev run+++ simulator/src/runtime.ts this run@@ -16,9 +16,9 @@skillMatchesTrigger,type Rng} from "./effects";import { createEffectIndex, expireEffectIndex, indexEffect, isRuntimeIndexableEffect, type EffectIndex } from "./effectIndex";-import { createDamageScratch, type DamageResult, type DamageScratch, type StaticDamageProfile } from "./damage";+import { ceilIgnoringFloatResidue, createDamageScratch, type DamageResult, type DamageScratch, type StaticDamageProfile } from "./damage";import type { DeferredEffectPlan, PreparedAttackSkill, RuntimeSkills } from "./runtimeSkills";import type { BattleRecorder } from "./recorder";import { emptyTroops } from "./fighterResolution";@@ -238,9 +238,9 @@roundStartTroops: DamageJob["roundStartTroops"],roundTargetDamage: Record<SideId, Record<UnitType, number>>): boolean {const available = Math.max(0, roundStartTroops[job.takerSide][job.takerUnit] ?? 0);- return available <= 0 || roundTargetDamage[job.takerSide][job.takerUnit] >= available;+ return ceilIgnoringFloatResidue(Math.max(0, available - roundTargetDamage[job.takerSide][job.takerUnit])) === 0;}export function capJobToRemainingTarget(result: DamageResult,Index: simulator/src/runtimeSkills.ts===================================================================--- simulator/src/runtimeSkills.ts prev run+++ simulator/src/runtimeSkills.ts this run@@ -160,8 +160,17 @@intent.effectGroupsByScopeKey = groupsByScopeKey;}}linkRequiredEffectGroups(effectGroups, damageGroupsByJobShape, groupMetadata);+ // Dependencies retain group identity, but shield delivery uses the small live list.+ const heroShield = damageBucketIndex("active.hero.shield");+ const troopShield = damageBucketIndex("active.troop.shield");+ for (const groups of damageGroupsByJobShape) {+ for (let i = groups.length - 1; i >= 0; i -= 1) {+ const bucket = groups[i].bucketIndex;+ if (bucket === heroShield || bucket === troopShield) groups.splice(i, 1);+ }+ }return {preBattle,battleStart,roundStart,Index: simulator/src/simulator.test.ts===================================================================--- simulator/src/simulator.test.ts prev run+++ simulator/src/simulator.test.ts this run@@ -20,8 +20,84 @@function runOnce(input: BattleInput, config: SimulatorConfig, options: SimulationOptions = {}) {return runPrepared(prepareBattle(input, config), undefined, options);}+test("Gordon suppresses on third turns and boosts normal Lancer damage on the following turns", () => {+ const result = runOnce({+ maxRounds: 7,+ attacker: {+ troops: { lancer_t6: 1000 },+ heroes: { Gordon: { skill_1: 2, skill_2: 2, skill_3: 2 } }+ },+ defender: { troops: { lancer_t6: 1000 } }+ }, loadSimulatorConfig(), { mode: "standard" });++ assert.deepEqual(result.attacks+ .filter((attack) => attack.appliedEffects?.some((effect) => effect.effectId === "ChemicalTerror/1"))+ .map((attack) => attack.round), [4, 7]);+ assert.deepEqual(result.attacks+ .filter((attack) => attack.appliedEffects?.some((effect) => effect.effectId === "ChemicalTerror/2"))+ .map((attack) => attack.round), [3, 6]);+});++test("Gordon boosts Wayne skill damage on Chemical Terror's triggering turn", () => {+ const [input] = JSON.parse(readFileSync(new URL("../../testcases/emulator_verified/gordon_interactions_20260925/gordon_wayne_1200l_vs_4800l.json", import.meta.url), "utf8"));+ assert.equal(signedRemainingScore(runOnce(input, loadSimulatorConfig())), -313);+});++test("Ahmose Blade of Light deals separate skill damage with Bradley and against Wu Ming", () => {+ const config = loadSimulatorConfig();+ for (const [path, survivors] of [+ ["ahmose_bradley_1000i_vs_3700i", -77],+ ["ahmose_1000i_vs_wuming_1000i", -82]+ ] as const) {+ const [input] = JSON.parse(readFileSync(new URL(`../../testcases/emulator_verified/ahmose_isolation_20260925/${path}.json`, import.meta.url), "utf8"));+ assert.equal(signedRemainingScore(runOnce(input, config)), survivors, path);+ }+});++test("Renee Dreamslice amplifies allied skill damage against the marked target", () => {+ const [input] = JSON.parse(readFileSync(new URL("../../testcases/emulator_verified/ahmose_gordon_renee/ahmose_renee_vs_jasser_mark_kind.json", import.meta.url), "utf8"));+ assert.equal(signedRemainingScore(runOnce(input, loadSimulatorConfig())), 937);+});++test("Renee's captured Dream Mark survives the loss of its Lancer source", () => {+ const [input] = JSON.parse(readFileSync(new URL("../../testcases/emulator_verified/renee_isolation_20260925/renee_mark_source_death.json", import.meta.url), "utf8"));+ assert.equal(signedRemainingScore(runOnce(input, loadSimulatorConfig())), 184);+});++test("delayed damage settles shields on arrival in recorded Gatot battles", () => {+ const config = loadSimulatorConfig();+ for (const [path, survivors] of [+ ["renee_s2_bucket_confirmations/gatot_shield_500_150.json", 157],+ ["renee_s2_families/defense_gatot.json", 339]+ ] as const) {+ const [input] = JSON.parse(readFileSync(new URL(`../../testcases/emulator_verified/${path}`, import.meta.url), "utf8"));+ assert.equal(signedRemainingScore(runOnce(input, config)), survivors, path);+ }+});++test("exhausted infantry cannot shield marksmen through floating-point residue", () => {+ const [input] = JSON.parse(readFileSync(new URL("../../testcases/emulator_verified/gwen_s2_source_binding/gwen_s2_source_5.json", import.meta.url), "utf8"));+ const config = loadSimulatorConfig();+ delete config.heroDefinitions.Gwen.skills.AirDominance.effects["AirDominance/1"].trigger_effects!["AirDominance/2"].units!.applies_vs;+ const result = runOnce(input, config, { mode: "standard" });+ const incoming = result.attacks.filter(attack => attack.round === 15 && attack.dealerSide === "defender");+ assert.deepEqual(incoming.map(attack => attack.takerUnit), ["marksman", "marksman"]);+ assert.equal(signedRemainingScore(result), 383);+});++test("same-turn exhausted targets cannot receive phantom extra skill hits", () => {+ const [input] = JSON.parse(readFileSync(new URL("../../testcases/emulator_verified/alonso_norah_combo.json", import.meta.url), "utf8"));+ const seed = "simulator-default:testcases/emulator_verified/alonso_norah_combo.json:alonso_norah_combo:0:264";+ const result = runPrepared(prepareBattle(input, loadSimulatorConfig()), seed, { mode: "standard" });+ const phantomHits = result.attacks.filter(attack =>+ attack.round === 10 && attack.kind === "skill" && attack.dealerSide === "defender" &&+ attack.dealerUnit === "marksman" && attack.takerUnit === "infantry"+ );+ assert.deepEqual(phantomHits, []);+});+test("runPrepared reuses the compiled input seed when no override is supplied", () => {const config = loadSimulatorConfig();const stats = {inf: { attack: 200, defense: 200, lethality: 150, health: 150 },@@ -84,8 +160,44 @@assert.equal(bothEmpty.rounds, 0);assert.equal(bothEmpty.attacks.length, 0);});+test("Gwen preparation cycles match recorded survivors and skill counts", () => {+ const path = fileURLToPath(new URL("../testcases/emulator_verified/gwen_blastmaster_cadence_800m_vs_1200i_100l_100m.json", import.meta.url));+ const [input] = JSON.parse(readFileSync(path, "utf8")) as BattleInput[];+ const result = runOnce(input, loadSimulatorConfig());++ assert.deepEqual(result.remaining, {+ attacker: { infantry: 0, lancer: 0, marksman: 0 },+ defender: { infantry: 461, lancer: 58, marksman: 44 }+ });+ assert.equal(result.skillReport.attacker.find((skill) => skill.skillId === "AirDominance")?.skillActivations, 7);+ assert.equal(result.skillReport.attacker.find((skill) => skill.skillId === "Blastmaster")?.skillActivations, 9);+});++test("Ahmose counts four Infantry attacks without counting pauses or stuns", () => {+ const result = runOnce(+ {+ maxRounds: 12,+ attacker: { troops: { infantry_t6: 1000, lancer_t6: 1000 }, heroes: { Ahmose: { skill_1: 1 } } },+ defender: { troops: { lancer_t6: 1000 }, heroes: { Sonya: { skill_3: 1 } } }+ },+ loadSimulatorConfig()+ );+ const infantry = result.attacks.filter(+ (attack) => attack.dealerSide === "attacker" && attack.dealerUnit === "infantry" && attack.kind === "normal"+ );++ assert.deepEqual(+ infantry.filter((attack) => !attack.cancelReason).map((attack) => attack.round),+ [1, 2, 3, 4, 7, 8, 9, 10, 12]+ );+ assert.deepEqual(+ infantry.filter((attack) => attack.cancelReason === "no_attack").map((attack) => attack.round),+ [5, 6, 11]+ );+});+test("runPrepared returns structured result for a no-hero battle", () => {const config = loadSimulatorConfig();const result = runOnce({@@ -659,16 +771,15 @@for (const fixture of [{ id: "ahmose_no_infantry_240l_vs_125i", attacker: { infantry: 0, lancer: 0, marksman: 0 }, defender: { infantry: 11, lancer: 0, marksman: 0 } },{ id: "ahmose_source_dies_001i_480l_vs_250i", attacker: { infantry: 0, lancer: 3, marksman: 0 }, defender: { infantry: 0, lancer: 0, marksman: 0 } }]) {- test(`Ahmose Viper schedules unused pauses without protection: ${fixture.id}`, () => {+ test(`Ahmose earns no protection without four Infantry attacks: ${fixture.id}`, () => {const path = new URL(`../testcases/emulator_verified/${fixture.id}.json`, import.meta.url);const [input] = JSON.parse(readFileSync(path, "utf8")) as BattleInput[];const result = runOnce(input, loadSimulatorConfig());assert.equal(result.randomness.deterministic, true);assert.deepEqual(result.remaining, { attacker: fixture.attacker, defender: fixture.defender });- assert.equal(result.skillReport.attacker.find(entry => entry.skillId === "ViperFormation")!.skillActivations, Math.floor(result.rounds / 4));assert.equal(result.attackControlCounts.no_attack, 0);});}@@ -1753,8 +1864,54 @@const uncharged = roundTwoKills({ useEffectsOnNoAttack: false });assert.ok(uncharged > charged, `expected uncharged buff to boost round 2 (${uncharged} > ${charged})`);});+test("cancelled incoming attacks charge attack-limited shields only when cancellation charging is enabled", () => {+ const input: BattleInput = {+ maxRounds: 2,+ seed: "cancel-shield-charge",+ attacker: { troops: { infantry_t1: 1000 }, heroes: {} },+ defender: { troops: { infantry_t1: 1000 }, heroes: { ShieldAndPause: { skill_1: 1 } } }+ };+ const config = minimalConfig({+ ShieldAndPause: {+ name: "ShieldAndPause",+ skills: {+ OpeningProtection: {+ trigger: { type: "battle_start" },+ effects: {+ pause: {+ type: "no_attack",+ value: 100,+ units: { applies_to: "enemy.infantry", applies_vs: "self.infantry" },+ duration: { turns: { count: 1, delay: 1 } }+ },+ shield: {+ type: "active.hero.shield",+ value: 100,+ units: { applies_to: "self.infantry", applies_vs: "enemy.infantry" },+ duration: { attacks: { count: 1 } }+ }+ }+ }+ }+ }+ });+ const [charged, preserved] = [{}, { useEffectsOnNoAttack: false }].map((options) =>+ runOnce(input, config, { ...options, mode: "trace" }).attacks.filter(+ (attack) => attack.dealerSide === "attacker" && attack.kind === "normal"+ )+ );+ assert.equal(charged[0].cancelReason, "no_attack");+ assert.equal(preserved[0].cancelReason, "no_attack");+ assert.equal(charged[1].round, 2);+ assert.equal(preserved[1].round, 2);+ assert.ok(charged[1].kills > 0);+ assert.equal(preserved[1].kills, 0);+ assert.equal((charged[1].appliedEffects ?? []).some((applied) => hasEffectKind(applied, "shield")), false);+ assert.equal(preserved[1].appliedEffects?.some((applied) => hasEffectKind(applied, "shield")), true);+});+test("no_attack does not advance normal attack cadence counters", () => {const result = runOnce({maxRounds: 4,@@ -2929,8 +3086,71 @@);assert.deepEqual(result.extraSkillAttackJobsByEffect, { hitAgain: 1 });});+for (const delayed of [false, true]) {+ test(`extra hits apply target modifiers to each actual recipient (${delayed ? "captured" : "immediate"})`, () => {+ const splash: Omit<EffectIntentDefinition, "id"> = {+ type: "extra_skill_attack",+ value: 100,+ units: {+ applies_to: delayed ? "parent.use.source" : "self.marksman",+ applies_vs: delayed ? "parent.use.target" : "enemy.any"+ },+ trigger_damage_jobs: [{ source: "use.source", target: "enemy.living" }],+ duration: { turns: { delay: delayed ? 1 : 0, count: 1 }, attacks: { count: 1 } }+ };+ const result = runOnce(+ {+ maxRounds: delayed ? 2 : 1,+ attacker: { troops: { marksman_t1: 1000000 }, heroes: { MultiTarget: { skill_1: 1, skill_2: 1 } } },+ defender: { troops: { infantry_t1: 1000000, lancer_t1: 1000000, marksman_t1: 1000000 }, heroes: {} }+ },+ minimalConfig({+ MultiTarget: {+ name: "MultiTarget",+ troop_type: "marksman",+ skills: {+ TargetModifiers: {+ trigger: { type: "battle_start" },+ effects: {+ infantryBonus: { type: "type.single_target.damage.up", value: 25, units: { applies_vs: "enemy.infantry" } },+ lancerBonus: { type: "type.single_target.damage.up", value: 40, units: { applies_vs: "enemy.lancer" } },+ marksmanPenalty: { type: "type.single_target.damage.down", value: 100, units: { applies_vs: "enemy.marksman" } }+ }+ },+ Splash: {+ trigger: { type: "turn", first: 1, every: 10 },+ effects: delayed ? {+ carrier: {+ units: { applies_to: "self.marksman", applies_vs: "enemy.any" },+ duration: { turns: { count: 1 }, attacks: { count: 1 } },+ trigger_effects: { splash }+ }+ } : { splash }+ }+ }+ }+ })+ );+ const parent = result.attacks.find(attack =>+ attack.round === 1 && attack.dealerSide === "attacker" && attack.kind === "normal"+ );+ assert.ok(parent);+ assert.equal(parent.takerUnit, "infantry");+ const hits = result.attacks.filter(attack => attack.sourceEffectId === "splash");+ assert.deepEqual(hits.map(hit => hit.takerUnit), UNIT_TYPES);+ const factors = { infantry: 1.25, lancer: 1.4, marksman: 0.5 };+ for (const hit of hits) {+ assert.equal(hit.round, delayed ? 2 : 1);+ assert.ok(+ Math.abs(hit.kills - parent.kills * factors[hit.takerUnit] / 1.25) < 1e-9,+ `${hit.takerUnit} casualties must use that recipient's modifiers`+ );+ }+ });+}+test("extra skill trigger damage jobs can resolve to multiple living enemy targets without recursive attack triggers", () => {const result = runOnce({maxRounds: 1,Index: simulator/src/simulator.ts===================================================================--- simulator/src/simulator.ts prev run+++ simulator/src/simulator.ts this run@@ -14,9 +14,9 @@SimulatorConfig,UnitType} from "./types";import { UNIT_TYPES, unitMaskHas } from "./types";-import { calculateDamageJob, ceilIgnoringFloatResidue, minInitialArmy, type DamageResult } from "./damage";+import { generateDamageJob, deliverDamageJob, ceilIgnoringFloatResidue, minInitialArmy, type DamageResult } from "./damage";import { createRecorder, type BattleRecorder } from "./recorder";import {activateEffect,advanceEffectAttackDelay,@@ -25,9 +25,9 @@isEffectAttackReady,oppositeSide,type Rng} from "./effects";-import { damageJobShapeSlot, damageJobSlot, type EffectIndex } from "./effectIndex";+import { damageJobShapeSlot, damageJobSlot, shieldEffectApplies, type EffectIndex } from "./effectIndex";import { buildRuntimeSkills, type RuntimeSkills } from "./runtimeSkills";import { activatePreBattleEffects, buildResolved, prepareBattle, type CompiledBattle } from "./prepare";import {addActiveEffect,@@ -262,9 +262,9 @@const orderIndexBySide: Record<SideId, number> = { attacker: 0, defender: 0 };for (const dealerUnit of UNIT_TYPES) {for (const side of ["attacker", "defender"] as SideId[]) {const takerSide = oppositeSide(side);- if ((roundStartTroops[side][dealerUnit] ?? 0) <= 0) continue;+ if (ceilIgnoringFloatResidue(roundStartTroops[side][dealerUnit] ?? 0) <= 0) continue;const ordered = orderFromEffects(dealerUnit, side, runtime.effectIndex, true);const takerUnit = firstLivingUnit(ordered?.order ?? UNIT_TYPES, takerSide, roundStartTroops);if (!takerUnit) continue;const intent = makeNormalIntent(@@ -314,9 +314,10 @@materializeTriggeredEffects(dodge.effect, round, intent, runtime, recorder);if (useEffectsOnCancel.dodge) chargeCancelledAttack(job, dodge.effect, dodge.attackDurationEffects, runtime);} else {recorder.recordScheduledDamageJob(job);- const normalResult = calculateDamageJob(job, fighters, damageJobOptions);+ const generated = generateDamageJob(job, fighters, damageJobOptions);+ const normalResult = deliverDamageJob(job, generated, damageJobOptions);if (loopOptions.capRoundKills) capJobToRemainingTarget(normalResult, job, roundStartTroops, roundTargetDamage, recorder);normalKills = normalResult.kills;if (loopOptions.scoreSide && job.dealerSide === loopOptions.scoreSide.dealerSide && job.takerSide === loopOptions.scoreSide.takerSide) {score += normalResult.kills;@@ -445,9 +446,9 @@};}function firstLivingUnit(order: readonly UnitType[], side: SideId, roundStartTroops: DamageJob["roundStartTroops"]): UnitType | undefined {- return order.find((unit) => (roundStartTroops[side][unit] ?? 0) > 0);+ return order.find((unit) => ceilIgnoringFloatResidue(roundStartTroops[side][unit] ?? 0) > 0);}function orderFromEffects(dealerUnit: UnitType,@@ -556,9 +557,10 @@losses[job.takerSide][job.takerUnit] += result.kills;}for (const side of ["attacker", "defender"] as SideId[]) {for (const unit of UNIT_TYPES) {- runtime.troops[side][unit] = Math.max(0, runtime.troops[side][unit] - losses[side][unit]);+ const remaining = Math.max(0, runtime.troops[side][unit] - losses[side][unit]);+ runtime.troops[side][unit] = ceilIgnoringFloatResidue(remaining) === 0 ? 0 : remaining;}}}@@ -574,16 +576,20 @@if (!advanceEffectAttackDelay(effect)) continue;if (hasAttackDurationConstraint(effect)) used.push(effect);}}+ for (const effect of runtime.effectIndex.shields) {+ if (!shieldEffectApplies(effect, job) || !advanceEffectAttackDelay(effect)) continue;+ if (hasAttackDurationConstraint(effect)) used.push(effect);+ }for (const effect of controlEffects) used.push(effect);if (!controlEffects.includes(winningControl)) used.push(winningControl);chargeUsedEffects(runtime);}function winnerFor(troops: Record<SideId, Record<UnitType, number>>): SideId | "draw" | undefined {- const attackerAlive = total(troops.attacker) > 0;- const defenderAlive = total(troops.defender) > 0;+ const attackerAlive = UNIT_TYPES.some((unit) => ceilIgnoringFloatResidue(troops.attacker[unit]) > 0);+ const defenderAlive = UNIT_TYPES.some((unit) => ceilIgnoringFloatResidue(troops.defender[unit]) > 0);if (attackerAlive && !defenderAlive) return "attacker";if (defenderAlive && !attackerAlive) return "defender";if (!attackerAlive && !defenderAlive) return "draw";return undefined;Index: simulator/src/tooling/testcases.test.ts===================================================================--- simulator/src/tooling/testcases.test.ts prev run+++ simulator/src/tooling/testcases.test.ts this run@@ -1,6 +1,6 @@import assert from "node:assert/strict";-import { mkdirSync, writeFileSync } from "node:fs";+import { mkdirSync, rmSync, writeFileSync } from "node:fs";import { tmpdir } from "node:os";import { resolve } from "node:path";import { test } from "node:test";@@ -25,8 +25,46 @@assert.ok(files.some((file) => file.endsWith("emulator_verified/jasser_solo.json.disabled")));assert.ok(files.some((file) => file.endsWith("emulator_verified/reina_logan_combo_v2.json.stale_troops")));});+test("discoverTestcaseFiles matches filenames or heroes on either side, including joiners", (t) => {+ const testcaseRoot = tempDir("simulator-hero-matching");+ t.after(() => rmSync(testcaseRoot, { recursive: true, force: true }));+ const fixtures = {+ "attacker.json": { attacker: { heroes: { Gwen: {} } } },+ "defender.json": [{}, { defender: { heroes: { Gwen: {} } } }],+ "attacker-joiner.json": { attacker: { joiner_heroes: { Gwen: {} } } },+ "defender-joiner.json": { defender: { joiner_heroes: { Gwen: {} } } },+ "unrelated.json": { description: "Gwen", attacker: { heroes: { Sergey: {} } } },+ "disabled.json.disabled": { attacker: { heroes: { Gwen: {} } } },+ "stale.json.stale_troops": { defender: { heroes: { Gwen: {} } } },+ };+ for (const [file, entry] of Object.entries(fixtures)) {+ writeFileSync(resolve(testcaseRoot, file), JSON.stringify(entry));+ }+ writeFileSync(resolve(testcaseRoot, "Gwen-invalid.json"), "{");+ writeFileSync(resolve(testcaseRoot, "invalid.json"), "{");++ const expected = [+ "Gwen-invalid.json", "attacker-joiner.json", "attacker.json",+ "defender-joiner.json", "defender.json",+ ];+ assert.deepEqual(+ discoverTestcaseFiles({ testcaseRoot, matching: "Gwe" }),+ expected.map((file) => resolve(testcaseRoot, file)).sort(),+ );+ assert.deepEqual(+ discoverTestcaseFiles({ testcaseRoot, matching: "Gwe", includeDisabled: true }),+ [...expected, "disabled.json.disabled", "stale.json.stale_troops"]+ .map((file) => resolve(testcaseRoot, file)).sort(),+ );+ assert.deepEqual(+ discoverTestcaseFiles({ testcaseRoot, matching: "unrelated" }),+ [resolve(testcaseRoot, "unrelated.json")],+ );+ assert.deepEqual(discoverTestcaseFiles({ testcaseRoot, matching: "missing" }), []);+});+test("runTestcases returns compact summary entries and full detail entries separately", () => {const config = loadSimulatorConfig();const report = runTestcases({ matching: "simple_001", repeat: 5 }, config);const key = Object.keys(report.testcases)[0];@@ -260,8 +298,73 @@assert.notEqual(adjustment.unadjusted.mu_candidate, summary?.game?.mu_candidate);assert.deepEqual(detail?.comparisonSamples, [summary?.game?.mu_candidate]);});+test("exact comparisons reject off-by-one and equal-mean outcomes but allow stat rounding correction", (t) => {+ const testcaseRoot = tempDir("simulator-exact");+ t.after(() => rmSync(testcaseRoot, { recursive: true, force: true }));+ const file = resolve(testcaseRoot, "exact.json");+ const entry = {+ attacker: { troops: { infantry_t1: 1000 }, stats: { infantry: { attack: 100.001 } } },+ defender: { troops: { infantry_t1: 900 } }+ };+ const config = testcaseFixtureConfig();+ writeFileSync(file, JSON.stringify(entry));+ const score = battleScoreDelta(runTestcases({ testcaseRoot }, config).details[0]!.result)!;+ const outcome = (value: number) => ({ attacker: Math.max(0, value), defender: Math.max(0, -value) });+ writeFileSync(file, JSON.stringify([+ { ...entry, test_id: "same", game_report_result: outcome(score) },+ { ...entry, test_id: "off_by_one", game_report_result: outcome(score + 1) },+ { ...entry, test_id: "same_mean", game_report_result: [outcome(score - 1), outcome(score + 1)] }+ ]));+ const normal = runTestcases({ testcaseRoot }, config);+ assert.ok(Object.values(normal.testcases).every((summary) => summary.game?.passes));+ const exact = runTestcases({ testcaseRoot, exact: true }, config);+ assert.deepEqual(Object.values(exact.testcases).map((summary) => summary.game?.passes), [true, false, false]);++ const adjusted = runTestcases({ matching: "determinism_test_normal", exact: true }, loadSimulatorConfig());+ const summary = Object.values(adjusted.testcases)[0]!;+ assert.equal(summary.game?.passes, true);+ assert.equal(summary.game?.bias_raw, 0);+ assert.equal(summary.gameStatAdjustment?.mode, "deterministic_exact");+});++for (const preciseSide of ["attacker", "defender"] as const) {+ test(`three-decimal ${preciseSide} stats keep game comparisons unadjusted`, (t) => {+ const testcaseRoot = tempDir(`simulator-precise-stats-${preciseSide}`);+ t.after(() => rmSync(testcaseRoot, { recursive: true, force: true }));+ writeFileSync(resolve(testcaseRoot, "precise.json"), JSON.stringify({+ attacker: {+ troops: { infantry_t1: 1000 },+ stats: { infantry: { attack: preciseSide === "attacker" ? 100.001 : 100.1 } }+ },+ defender: {+ troops: { infantry_t1: 900 },+ stats: { infantry: { health: preciseSide === "defender" ? 100.001 : 100.1 } }+ },+ game_report_result: { attacker: 264, defender: 0 }+ }));+ const report = runTestcases({ testcaseRoot, includeSamples: true }, testcaseFixtureConfig());+ const summary = Object.values(report.testcases)[0]!;+ const detail = report.details[0]!;++ assert.notEqual(summary.game?.bias_raw, 0);+ assert.equal(summary.gameStatAdjustment, undefined);+ assert.equal(summary.game?.mu_candidate, battleScoreDelta(detail.result));+ assert.deepEqual(detail.comparisonSamples, [battleScoreDelta(detail.result)]);+ });+}++test("two-decimal rounding corrections recover exact no-hero outcomes within 0.005", () => {+ const report = runTestcases({ matching: "1-testcases_no-heroes_t6_single-type", deterministic: true, exact: true }, loadSimulatorConfig());+ const summaries = Object.values(report.testcases);+ assert.equal(summaries.length, 18);+ assert.ok(summaries.every((entry) => entry.game?.passes));+ const corrected = summaries.filter((entry) => entry.gameStatAdjustment);+ assert.equal(corrected.length, 11);+ assert.ok(corrected.every((entry) => Math.abs(entry.gameStatAdjustment!.value) <= 0.005));+});+test("deterministic testcase tolerance increases by 0.1 percent every ten rounds and caps at 0.7 percent", () => {assert.equal(deterministicRoundTolerancePct(0), 0.2);assert.equal(deterministicRoundTolerancePct(9), 0.2);assert.equal(deterministicRoundTolerancePct(10), 0.3);Index: simulator/src/tooling/testcases.ts===================================================================--- simulator/src/tooling/testcases.ts prev run+++ simulator/src/tooling/testcases.ts this run@@ -24,8 +24,10 @@testcaseRoot?: string;calibrationReportPath?: string;matching?: string;includeDisabled?: boolean;+ deterministic?: boolean;+ exact?: boolean;repeat?: number;seed?: string | number;workers?: number;includeSamples?: boolean;@@ -150,13 +152,15 @@repeat: number;seed?: string | number;includeSamples?: boolean;simulationMode?: SimulationMode;+ deterministic?: boolean;}export interface TestcaseExecutionResult {testcaseId: string;index: number;+ skipped?: boolean;result?: BattleResult;deterministic?: boolean;sampleCount?: number;simulatorStats?: SampleStats;@@ -198,12 +202,31 @@walk(root, files);return files.filter((file) => isDiscoverableTestcaseFile(file, options.includeDisabled)).filter((file) => options.includeDisabled || (!file.endsWith(".disabled") && !file.endsWith(".stale_troops")))- .filter((file) => !options.matching || file.includes(options.matching))+ .filter((file) => !options.matching || file.includes(options.matching) || fileHeroesMatch(file, options.matching)).sort();}+function fileHeroesMatch(file: string, matching: string): boolean {+ let parsed: unknown;+ try {+ parsed = JSON.parse(readFileSync(file, "utf8"));+ } catch {+ return false;+ }+ const entries = Array.isArray(parsed) ? parsed : [parsed];+ return entries.some((entry) => {+ const testcase = asObject(entry);+ return [testcase.attacker, testcase.defender].some((side) => {+ const army = asObject(side);+ return [army.heroes, army.joiner_heroes].some((heroes) =>+ Object.keys(asObject(heroes)).some((name) => name.includes(matching)),+ );+ });+ });+}+export function runTestcases(options: TestcaseRunOptions, config: SimulatorConfig): TestcaseRunReport {const prepared = prepareTestcaseCases(options);return runPreparedTestcases(options, config, prepared, (job) => executeTestcaseCase(job, config));}@@ -270,9 +293,10 @@report.details.push(detail);continue;}try {- const execution = execute({ file, reportFile, testcaseId, index, input: preparedCase.input, repeat, seed: options.seed }, config);+ const execution = execute({ file, reportFile, testcaseId, index, input: preparedCase.input, repeat, seed: options.seed, deterministic: options.deterministic }, config);+ if (execution.skipped) continue;applyExecutionResult(report, comparison, preparedCase, execution, config);} catch (error) {detail.error = errorMessage(error);detail.errorDetails = errorDetails(error);@@ -316,9 +340,10 @@testcaseId: preparedCase.testcaseId,index: preparedCase.index,input: preparedCase.input,repeat,- seed: options.seed+ seed: options.seed,+ deterministic: options.deterministic});return { preparedCase, execution };} catch (error) {return { preparedCase, error };@@ -326,8 +351,9 @@});for (const { preparedCase, execution, error } of await Promise.all(jobs)) {const { reportFile, testcaseId, index, detail } = preparedCase;+ if (execution?.skipped) continue;if (!preparedCase.input || !preparedCase.key) {if (preparedCase.adaptError) report.errors.push(preparedCase.adaptError);report.details.push(detail);continue;@@ -388,10 +414,9 @@thresholds: comparison.thresholds}): null;if (game) {- const unroundedBiasRaw = stats.mu - mean(gameSamples);- game = adjustedForRoundingRules(game, result.randomness.deterministic, initialTroops, result.rounds, unroundedBiasRaw);+ game = adjustedForRoundingRules(game, result.randomness.deterministic, initialTroops, result.rounds, simulatorSamples, gameSamples, report.options.exact);}const gameStatAdjustment = game && preparedCase.input? findGameStatAdjustment({game,@@ -401,8 +426,9 @@reference: gameSamples,initialTroops,averageRounds: result.rounds,deterministic: result.randomness.deterministic,+ exact: report.options.exact,thresholds: comparison.thresholds}): undefined;if (gameStatAdjustment) game = gameStatAdjustment.adjusted;@@ -456,15 +482,27 @@initialTroops: number;averageRounds: number;deterministic: boolean;thresholds?: Record<string, number>;+ exact?: boolean;}): InternalStatAdjustment | undefined {+ let maxAdjustment = STAT_ROUNDING_MAX_ADJUSTMENT;+ for (const fighter of [options.input.attacker, options.input.defender]) {+ for (const stats of Object.values(fighter.stats ?? {}) as Array<Partial<StatBlock>>) {+ for (const key of ["attack", "defense", "lethality", "health"] as const) {+ const value = stats[key];+ if (value === undefined) continue;+ if (Math.abs(value * 100 - Math.round(value * 100)) > 1e-9) return undefined;+ if (Math.abs(value * 10 - Math.round(value * 10)) > 1e-9) maxAdjustment = 0.005;+ }+ }+ }// Deterministic cases correct any nonzero bias; stochastic cases correct only outright misses.// Either way a nonzero bias is needed to pick a search direction.const shouldCorrect = options.deterministic ? options.game.bias_raw !== 0 : !options.game.passes;if (!shouldCorrect || options.game.bias_raw === 0) return undefined;const direction = -Math.sign(options.game.bias_raw);- const maxCandidate = evaluateStatAdjustment(options, direction * STAT_ROUNDING_MAX_ADJUSTMENT);+ const maxCandidate = evaluateStatAdjustment(options, direction * maxAdjustment);let best = maxCandidate;if (maxCandidate.mode === "deterministic_exact") return maxCandidate;let low = { value: 0, bias: options.game.bias_raw };@@ -500,8 +538,9 @@initialTroops: number;averageRounds: number;deterministic: boolean;thresholds?: Record<string, number>;+ exact?: boolean;}, value: number): InternalStatAdjustment {const adjustedInput = inputWithStatAdjustment(options.input, value);const candidateSamples = simulateAdjustedOutcomes(adjustedInput, options.job, options.config);const adjusted = compareOutcomeDistribution({@@ -523,9 +562,11 @@adjusted,options.deterministic,options.initialTroops,options.averageRounds,- mean(candidateSamples) - mean(options.reference)+ candidateSamples,+ options.reference,+ options.exact),samples: candidateSamples};}@@ -585,12 +626,23 @@metric: ParityComparisonMetrics,deterministic: boolean,initialTroops: number,averageRounds: number,- unroundedBiasRaw: number+ candidate: readonly number[],+ reference: readonly number[],+ exact = false): ParityComparisonMetrics {+ if (exact) {+ const expected = reference[0];+ return {+ ...metric,+ passes: Number.isInteger(expected)+ && reference.every((value) => value === expected)+ && candidate.every((value) => value === expected)+ };+ }if (!deterministic) return metric;- const unroundedBiasPct = Math.abs(unroundedBiasRaw / (initialTroops || 1)) * 100;+ const unroundedBiasPct = Math.abs((mean(candidate) - mean(reference)) / (initialTroops || 1)) * 100;return { ...metric, passes: unroundedBiasPct <= deterministicRoundTolerancePct(averageRounds) };}export function deterministicRoundTolerancePct(averageRounds: number): number {@@ -613,9 +665,9 @@};}function roundStatAdjustment(value: number): number {- return Number(value.toFixed(3));+ return Number(value.toFixed(4));}function finalizeReport(report: TestcaseRunReport): void {report.counts.warnings = report.warnings.length;@@ -634,8 +686,11 @@const sampleOutcomes: TestcaseSampleOutcome[] = [];const sampleDeltas: number[] = [];// Resolve the battle once and reuse it across every seeded sample of this case.const compiled = prepareBattle(job.input, config);+ if (job.deterministic && !compiled.runtimeSkills.randomness.deterministic) {+ return { testcaseId: job.testcaseId, index: job.index, skipped: true, diagnostics: [] };+ }const baseSeed = job.seed ?? job.input.seed;const sample = (iteration: number) => runPrepared(compiled,sampleSeed(baseSeed, job.file, job.testcaseId, job.index, iteration),Index: simulator/src/types.ts===================================================================--- simulator/src/types.ts prev run+++ simulator/src/types.ts this run@@ -1,4 +1,6 @@+import type { GeneratedDamage } from "./damage";+export type SideId = "attacker" | "defender";export type UnitType = "infantry" | "lancer" | "marksman";export type DamageKind = "normal" | "skill";export type UnitMask = number;@@ -325,9 +327,9 @@// unless useEffectsOnDodge/useEffectsOnNoAttack disable that.uses: number;sameEffectStacking: SameEffectStacking;triggerEffects?: ResolvedEffectIntentDefinition[];- /** Completed damage captured when this runtime effect was materialized and emitted on its later matching attack. */+ /** Generation-time damage awaiting shield settlement on its later matching attack. */pendingDamageJobs?: PendingDamageJob[];effectGroup?: ActiveEffectGroup;effectGroupPosition?: number;}@@ -375,9 +377,9 @@}export interface PendingDamageJob {job: DamageJob;- result: DamageResult;+ generated: GeneratedDamage;}export interface CounterDelta {side: SideId;Index: testcases/emulator_verified/ahmose_blade_categories/ahmose_vs_jasser_01.json===================================================================--- testcases/emulator_verified/ahmose_blade_categories/ahmose_vs_jasser_01.json prev run+++ testcases/emulator_verified/ahmose_blade_categories/ahmose_vs_jasser_01.json this run@@ -0,0 +1,167 @@+[+ {+ "test_id": "ahmose_vs_jasser_01",+ "description": "C2 battle report 2734693171196384",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 900,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 800,+ "lancer_t6": 150,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T15:01:47.000Z",+ "randomseed": 1790089308,+ "attacker": 402,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171196384",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T15-02-04.099Z-66897957-94ec-40d9-b035-eb9f41c2b9ba.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1000,+ "survivors": 402,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 388,+ "kills": 438+ },+ "defender": {+ "troops": 1250,+ "survivors": 0,+ "losses": 0,+ "injured": 438,+ "lightly_injured": 812,+ "kills": 210+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 900,+ "survivors": 302,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 388,+ "kills": 216+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 100,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 222+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 800,+ "survivors": 0,+ "losses": 0,+ "injured": 280,+ "lightly_injured": 520,+ "kills": 26+ },+ "lancer_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 48+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 136+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 14,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_blade_categories/ahmose_vs_wu_ming.json===================================================================--- testcases/emulator_verified/ahmose_blade_categories/ahmose_vs_wu_ming.json prev run+++ testcases/emulator_verified/ahmose_blade_categories/ahmose_vs_wu_ming.json this run@@ -0,0 +1,178 @@+[+ {+ "test_id": "ahmose_vs_wu_ming",+ "description": "C2 battle report 2734693171196841",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 750,+ "lancer_t6": 100,+ "marksman_t6": 400+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 800,+ "lancer_t6": 300,+ "marksman_t6": 150+ },+ "stats": {+ "infantry": {+ "attack": 453.71,+ "defense": 446.26,+ "lethality": 223.57,+ "health": 274.97+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T15:06:27.000Z",+ "randomseed": 1790089588,+ "attacker": 508,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171196841",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T15-06-44.108Z-44747d89-70eb-4823-af8a-28057f564319.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1250,+ "survivors": 508,+ "losses": 0,+ "injured": 260,+ "lightly_injured": 482,+ "kills": 438+ },+ "defender": {+ "troops": 1250,+ "survivors": 0,+ "losses": 0,+ "injured": 438,+ "lightly_injured": 812,+ "kills": 260+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 750,+ "survivors": 8,+ "losses": 0,+ "injured": 260,+ "lightly_injured": 482,+ "kills": 77+ },+ "lancer_t6": {+ "troops": 100,+ "survivors": 100,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 96+ },+ "marksman_t6": {+ "troops": 400,+ "survivors": 400,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 265+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 800,+ "survivors": 0,+ "losses": 0,+ "injured": 280,+ "lightly_injured": 520,+ "kills": 67+ },+ "lancer_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 90+ },+ "marksman_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 103+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 16,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_blade_categories/ahmose_wayne_vs_jasser.json===================================================================--- testcases/emulator_verified/ahmose_blade_categories/ahmose_wayne_vs_jasser.json prev run+++ testcases/emulator_verified/ahmose_blade_categories/ahmose_wayne_vs_jasser.json this run@@ -0,0 +1,191 @@+[+ {+ "test_id": "ahmose_wayne_vs_jasser",+ "description": "C2 battle report 2734693171197180",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Wayne": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 300,+ "lancer_t6": 100,+ "marksman_t6": 250+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 421.39,+ "defense": 427.39,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 950,+ "lancer_t6": 150,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T15:09:51.000Z",+ "randomseed": 1790089792,+ "attacker": 0,+ "defender": 278,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171197180",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T15-10-08.100Z-a59787e4-e5da-4bf6-b497-d4927adc11de.json",+ "winner": "defender",+ "attacker": {+ "troops": 650,+ "survivors": 0,+ "losses": 0,+ "injured": 228,+ "lightly_injured": 422,+ "kills": 394+ },+ "defender": {+ "troops": 1400,+ "survivors": 278,+ "losses": 0,+ "injured": 394,+ "lightly_injured": 728,+ "kills": 228+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 40+ },+ "lancer_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 62+ },+ "marksman_t6": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 292+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 950,+ "survivors": 0,+ "losses": 0,+ "injured": 333,+ "lightly_injured": 617,+ "kills": 24+ },+ "lancer_t6": {+ "troops": 150,+ "survivors": 20,+ "losses": 0,+ "injured": 46,+ "lightly_injured": 84,+ "kills": 56+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 258,+ "losses": 0,+ "injured": 15,+ "lightly_injured": 27,+ "kills": 148+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Roundabout Hit": {+ "triggered": 30,+ "displayed_kills": 41+ },+ "Thunder Strike": {+ "triggered": 37,+ "displayed_kills": 29+ }+ },+ "Ahmose": {+ "Viper Formation": {+ "triggered": 8,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_blade_categories/jasser_vs_ahmose_01.json===================================================================--- testcases/emulator_verified/ahmose_blade_categories/jasser_vs_ahmose_01.json prev run+++ testcases/emulator_verified/ahmose_blade_categories/jasser_vs_ahmose_01.json this run@@ -0,0 +1,176 @@+[+ {+ "test_id": "jasser_vs_ahmose_01",+ "description": "C2 battle report 2734693171196709",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 950,+ "lancer_t6": 300,+ "marksman_t6": 150+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 750,+ "lancer_t6": 100,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T15:04:59.000Z",+ "randomseed": 1790089500,+ "attacker": 0,+ "defender": 438,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171196709",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T15-05-27.108Z-177fb503-6608-4232-b234-35ad851c8d8b.json",+ "winner": "defender",+ "attacker": {+ "troops": 1400,+ "survivors": 0,+ "losses": 0,+ "injured": 491,+ "lightly_injured": 909,+ "kills": 180+ },+ "defender": {+ "troops": 950,+ "survivors": 438,+ "losses": 0,+ "injured": 180,+ "lightly_injured": 332,+ "kills": 491+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 950,+ "survivors": 0,+ "losses": 0,+ "injured": 333,+ "lightly_injured": 617,+ "kills": 27+ },+ "lancer_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 65+ },+ "marksman_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 88+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 750,+ "survivors": 238,+ "losses": 0,+ "injured": 180,+ "lightly_injured": 332,+ "kills": 168+ },+ "lancer_t6": {+ "troops": 100,+ "survivors": 100,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 132+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 100,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 191+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 13,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_blade_categories/jasser_vs_ahmose_wayne.json===================================================================--- testcases/emulator_verified/ahmose_blade_categories/jasser_vs_ahmose_wayne.json prev run+++ testcases/emulator_verified/ahmose_blade_categories/jasser_vs_ahmose_wayne.json this run@@ -0,0 +1,191 @@+[+ {+ "test_id": "jasser_vs_ahmose_wayne",+ "description": "C2 battle report 2734693171197304",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 950,+ "lancer_t6": 150,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Wayne": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 300,+ "lancer_t6": 100,+ "marksman_t6": 250+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 421.39,+ "defense": 427.39,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T15:11:07.000Z",+ "randomseed": 1790089868,+ "attacker": 278,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171197304",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T15-11-35.107Z-5217e120-fe91-45f4-8363-1f6c9245855c.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1400,+ "survivors": 278,+ "losses": 0,+ "injured": 394,+ "lightly_injured": 728,+ "kills": 228+ },+ "defender": {+ "troops": 650,+ "survivors": 0,+ "losses": 0,+ "injured": 228,+ "lightly_injured": 422,+ "kills": 394+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 950,+ "survivors": 0,+ "losses": 0,+ "injured": 333,+ "lightly_injured": 617,+ "kills": 24+ },+ "lancer_t6": {+ "troops": 150,+ "survivors": 20,+ "losses": 0,+ "injured": 46,+ "lightly_injured": 84,+ "kills": 56+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 258,+ "losses": 0,+ "injured": 15,+ "lightly_injured": 27,+ "kills": 148+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 40+ },+ "lancer_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 62+ },+ "marksman_t6": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 292+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {+ "Wayne": {+ "Roundabout Hit": {+ "triggered": 30,+ "displayed_kills": 41+ },+ "Thunder Strike": {+ "triggered": 37,+ "displayed_kills": 29+ }+ },+ "Ahmose": {+ "Viper Formation": {+ "triggered": 8,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_blade_categories/wu_ming_vs_ahmose.json===================================================================--- testcases/emulator_verified/ahmose_blade_categories/wu_ming_vs_ahmose.json prev run+++ testcases/emulator_verified/ahmose_blade_categories/wu_ming_vs_ahmose.json this run@@ -0,0 +1,160 @@+[+ {+ "test_id": "wu_ming_vs_ahmose",+ "description": "C2 battle report 2734693171196993",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 950,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 453.71,+ "defense": 446.26,+ "lethality": 223.57,+ "health": 274.97+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 1000,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T15:08:10.000Z",+ "randomseed": 1790089691,+ "attacker": 538,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171196993",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T15-08-38.109Z-694b6315-6393-46a5-864a-5d4c442c7458.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1250,+ "survivors": 538,+ "losses": 0,+ "injured": 250,+ "lightly_injured": 462,+ "kills": 385+ },+ "defender": {+ "troops": 1100,+ "survivors": 0,+ "losses": 0,+ "injured": 385,+ "lightly_injured": 715,+ "kills": 250+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 950,+ "survivors": 238,+ "losses": 0,+ "injured": 250,+ "lightly_injured": 462,+ "kills": 137+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 300,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 248+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 113+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 137+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 26,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_bucket_interactions/ahmose_hendrik_vs_jasser.json===================================================================--- testcases/emulator_verified/ahmose_bucket_interactions/ahmose_hendrik_vs_jasser.json prev run+++ testcases/emulator_verified/ahmose_bucket_interactions/ahmose_hendrik_vs_jasser.json this run@@ -0,0 +1,160 @@+[+ {+ "test_id": "ahmose_hendrik_vs_jasser",+ "description": "C2 battle report 2734693171218664",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Hendrik": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 400+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 444.21,+ "defense": 450.21,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 200,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T18:22:40.000Z",+ "randomseed": 1790101361,+ "attacker": 23,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171218664",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T18-22-57.101Z-5b529683-511e-4294-905a-3e51e4794114.json",+ "winner": "attacker",+ "attacker": {+ "troops": 400,+ "survivors": 23,+ "losses": 0,+ "injured": 132,+ "lightly_injured": 245,+ "kills": 175+ },+ "defender": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 132+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 400,+ "survivors": 23,+ "losses": 0,+ "injured": 132,+ "lightly_injured": 245,+ "kills": 175+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 7+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 125+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 25,+ "displayed_kills": null+ }+ },+ "Hendrik": {+ "Armor of Barnacles": {+ "triggered": 31,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_bucket_interactions/ahmose_jasser_vs_jasser.json===================================================================--- testcases/emulator_verified/ahmose_bucket_interactions/ahmose_jasser_vs_jasser.json prev run+++ testcases/emulator_verified/ahmose_bucket_interactions/ahmose_jasser_vs_jasser.json this run@@ -0,0 +1,144 @@+[+ {+ "test_id": "ahmose_jasser_vs_jasser",+ "description": "C2 battle report 2734693171218409",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Jasser": {+ "skill_1": 4,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 800+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 354.37,+ "defense": 360.37,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 950+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T18:21:21.000Z",+ "randomseed": 1790101282,+ "attacker": 649,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171218409",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T18-21-38.098Z-b4fbf9d1-bb4e-4447-9a20-a9399f385138.json",+ "winner": "attacker",+ "attacker": {+ "troops": 800,+ "survivors": 649,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 98,+ "kills": 333+ },+ "defender": {+ "troops": 950,+ "survivors": 0,+ "losses": 0,+ "injured": 333,+ "lightly_injured": 617,+ "kills": 53+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 800,+ "survivors": 649,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 98,+ "kills": 333+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 950,+ "survivors": 0,+ "losses": 0,+ "injured": 333,+ "lightly_injured": 617,+ "kills": 53+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 25,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_bucket_interactions/ahmose_reina_vs_jasser.json===================================================================--- testcases/emulator_verified/ahmose_bucket_interactions/ahmose_reina_vs_jasser.json prev run+++ testcases/emulator_verified/ahmose_bucket_interactions/ahmose_reina_vs_jasser.json this run@@ -0,0 +1,397 @@+[+ {+ "test_id": "ahmose_reina_vs_jasser",+ "description": "C2 battle report 2734693171219563",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Reina": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 250+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 364.28,+ "defense": 368.53,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 600+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T18:28:49.000Z",+ "randomseed": 1790101730,+ "attacker": 92,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171219563",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T18-29-06.104Z-bc3b073a-db1a-47ab-adc2-aabf264a1b99.json",+ "winner": "attacker",+ "attacker": {+ "troops": 250,+ "survivors": 92,+ "losses": 0,+ "injured": 56,+ "lightly_injured": 102,+ "kills": 210+ },+ "defender": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 56+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 250,+ "survivors": 92,+ "losses": 0,+ "injured": 56,+ "lightly_injured": 102,+ "kills": 210+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 56+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 66,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ },+ {+ "timestamp": "2026-09-22T18:29:34.000Z",+ "randomseed": 1790101775,+ "attacker": 101,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171219676",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T18-29-51.095Z-caba2cae-6f33-4cbf-abe8-ad9ded73fddf.json",+ "winner": "attacker",+ "attacker": {+ "troops": 250,+ "survivors": 101,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 96,+ "kills": 210+ },+ "defender": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 53+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 250,+ "survivors": 101,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 96,+ "kills": 210+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 53+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 65,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ },+ {+ "timestamp": "2026-09-22T18:30:19.000Z",+ "randomseed": 1790101820,+ "attacker": 95,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171219858",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T18-30-36.096Z-07a2c638-c1cf-44b3-8873-a80398a2dcb4.json",+ "winner": "attacker",+ "attacker": {+ "troops": 250,+ "survivors": 95,+ "losses": 0,+ "injured": 55,+ "lightly_injured": 100,+ "kills": 210+ },+ "defender": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 55+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 250,+ "survivors": 95,+ "losses": 0,+ "injured": 55,+ "lightly_injured": 100,+ "kills": 210+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 55+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 66,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ },+ {+ "timestamp": "2026-09-22T18:31:04.000Z",+ "randomseed": 1790101865,+ "attacker": 99,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171219894",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T18-31-21.099Z-c095dc57-96aa-4f1e-ae83-15f618e82c9c.json",+ "winner": "attacker",+ "attacker": {+ "troops": 250,+ "survivors": 99,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 98,+ "kills": 210+ },+ "defender": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 53+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 250,+ "survivors": 99,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 98,+ "kills": 210+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 53+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 65,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ },+ {+ "timestamp": "2026-09-22T18:31:49.000Z",+ "randomseed": 1790101910,+ "attacker": 89,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171219929",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T18-32-06.096Z-b125850c-1b83-4ff7-a940-cfbc1aed6e0b.json",+ "winner": "attacker",+ "attacker": {+ "troops": 250,+ "survivors": 89,+ "losses": 0,+ "injured": 57,+ "lightly_injured": 104,+ "kills": 210+ },+ "defender": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 57+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 250,+ "survivors": 89,+ "losses": 0,+ "injured": 57,+ "lightly_injured": 104,+ "kills": 210+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 57+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 67,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_bucket_interactions/ahmose_seo_yoon_vs_jasser.json===================================================================--- testcases/emulator_verified/ahmose_bucket_interactions/ahmose_seo_yoon_vs_jasser.json prev run+++ testcases/emulator_verified/ahmose_bucket_interactions/ahmose_seo_yoon_vs_jasser.json this run@@ -0,0 +1,144 @@+[+ {+ "test_id": "ahmose_seo_yoon_vs_jasser",+ "description": "C2 battle report 2734693171218011",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Seo-yoon": {+ "skill_1": 4,+ "skill_2": 3+ }+ },+ "troops": {+ "infantry_t6": 800+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 354.37,+ "defense": 360.37,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 950+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T18:19:04.000Z",+ "randomseed": 1790101145,+ "attacker": 649,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171218011",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T18-19-21.104Z-1f3b53e8-b674-4271-b4ce-f3f76cb10fb7.json",+ "winner": "attacker",+ "attacker": {+ "troops": 800,+ "survivors": 649,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 98,+ "kills": 333+ },+ "defender": {+ "troops": 950,+ "survivors": 0,+ "losses": 0,+ "injured": 333,+ "lightly_injured": 617,+ "kills": 53+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 800,+ "survivors": 649,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 98,+ "kills": 333+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 950,+ "survivors": 0,+ "losses": 0,+ "injured": 333,+ "lightly_injured": 617,+ "kills": 53+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 25,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_bucket_interactions/ahmose_vs_gatot.json===================================================================--- testcases/emulator_verified/ahmose_bucket_interactions/ahmose_vs_gatot.json prev run+++ testcases/emulator_verified/ahmose_bucket_interactions/ahmose_vs_gatot.json this run@@ -0,0 +1,158 @@+[+ {+ "test_id": "ahmose_vs_gatot",+ "description": "C2 battle report 2734693171218916",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gatot": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 50,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 627.31,+ "defense": 619.86,+ "lethality": 230.66,+ "health": 281.02+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T18:24:10.000Z",+ "randomseed": 1790101451,+ "attacker": 698,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171218916",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T18-24-27.118Z-7d42dc50-f6ac-49b2-930d-fd68c445b6f0.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1000,+ "survivors": 698,+ "losses": 0,+ "injured": 106,+ "lightly_injured": 196,+ "kills": 123+ },+ "defender": {+ "troops": 350,+ "survivors": 0,+ "losses": 0,+ "injured": 123,+ "lightly_injured": 227,+ "kills": 106+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 698,+ "losses": 0,+ "injured": 106,+ "lightly_injured": 196,+ "kills": 123+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 16+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 90+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 22,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Gatot": {+ "King's Bestowal": {+ "triggered": 93,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_bucket_interactions/ahmose_vs_wu_ming.json===================================================================--- testcases/emulator_verified/ahmose_bucket_interactions/ahmose_vs_wu_ming.json prev run+++ testcases/emulator_verified/ahmose_bucket_interactions/ahmose_vs_wu_ming.json this run@@ -0,0 +1,160 @@+[+ {+ "test_id": "ahmose_vs_wu_ming",+ "description": "C2 battle report 2734693171220225",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 800,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 600,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 453.71,+ "defense": 446.26,+ "lethality": 223.57,+ "health": 274.97+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T18:36:21.000Z",+ "randomseed": 1790102182,+ "attacker": 0,+ "defender": 72,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171220225",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T18-36-38.097Z-ab3e31af-03a2-4f46-b002-02d8bc8e5c64.json",+ "winner": "defender",+ "attacker": {+ "troops": 900,+ "survivors": 0,+ "losses": 0,+ "injured": 315,+ "lightly_injured": 585,+ "kills": 290+ },+ "defender": {+ "troops": 900,+ "survivors": 72,+ "losses": 0,+ "injured": 290,+ "lightly_injured": 538,+ "kills": 315+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 800,+ "survivors": 0,+ "losses": 0,+ "injured": 280,+ "lightly_injured": 520,+ "kills": 96+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 194+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 78+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 72,+ "losses": 0,+ "injured": 80,+ "lightly_injured": 148,+ "kills": 237+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 26,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_bucket_interactions/wu_ming_vs_ahmose.json===================================================================--- testcases/emulator_verified/ahmose_bucket_interactions/wu_ming_vs_ahmose.json prev run+++ testcases/emulator_verified/ahmose_bucket_interactions/wu_ming_vs_ahmose.json this run@@ -0,0 +1,151 @@+[+ {+ "test_id": "wu_ming_vs_ahmose",+ "description": "C2 battle report 2734693171220596",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 400,+ "marksman_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 453.71,+ "defense": 446.26,+ "lethality": 223.57,+ "health": 274.97+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T18:42:46.000Z",+ "randomseed": 1790102567,+ "attacker": 0,+ "defender": 200,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171220596",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T18-43-14.097Z-265e8ca3-c43f-4d36-abf1-87639a7daf66.json",+ "winner": "defender",+ "attacker": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 280+ },+ "defender": {+ "troops": 1000,+ "survivors": 200,+ "losses": 0,+ "injured": 280,+ "lightly_injured": 520,+ "kills": 210+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 77+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 203+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 200,+ "losses": 0,+ "injured": 280,+ "lightly_injured": 520,+ "kills": 210+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 40,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_c2_discriminators/ahmose_renee_vs_jasser_01.json===================================================================--- testcases/emulator_verified/ahmose_c2_discriminators/ahmose_renee_vs_jasser_01.json prev run+++ testcases/emulator_verified/ahmose_c2_discriminators/ahmose_renee_vs_jasser_01.json this run@@ -0,0 +1,178 @@+[+ {+ "test_id": "ahmose_renee_vs_jasser_01",+ "description": "C2 battle report 2734693171177035",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ },+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 60,+ "lancer_t6": 650,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 345.57,+ "defense": 338.12,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Jasser": {+ "skill_1": 4,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 700,+ "marksman_t6": 450+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 354.37,+ "defense": 360.37,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T12:45:14.000Z",+ "randomseed": 1790081115,+ "attacker": 0,+ "defender": 366,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171177035",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T12-45-42.099Z-de3bbdf9-4bcd-49fa-87a0-3c3db458e46c.json",+ "winner": "defender",+ "attacker": {+ "troops": 1010,+ "survivors": 0,+ "losses": 0,+ "injured": 354,+ "lightly_injured": 656,+ "kills": 275+ },+ "defender": {+ "troops": 1150,+ "survivors": 366,+ "losses": 0,+ "injured": 275,+ "lightly_injured": 509,+ "kills": 354+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 60,+ "survivors": 0,+ "losses": 0,+ "injured": 21,+ "lightly_injured": 39,+ "kills": 0+ },+ "lancer_t6": {+ "troops": 650,+ "survivors": 0,+ "losses": 0,+ "injured": 228,+ "lightly_injured": 422,+ "kills": 167+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 108+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 700,+ "survivors": 0,+ "losses": 0,+ "injured": 245,+ "lightly_injured": 455,+ "kills": 38+ },+ "marksman_t6": {+ "troops": 450,+ "survivors": 366,+ "losses": 0,+ "injured": 30,+ "lightly_injured": 54,+ "kills": 316+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 1,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 16,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_c2_discriminators/ahmose_renee_vs_jasser_02.json===================================================================--- testcases/emulator_verified/ahmose_c2_discriminators/ahmose_renee_vs_jasser_02.json prev run+++ testcases/emulator_verified/ahmose_c2_discriminators/ahmose_renee_vs_jasser_02.json this run@@ -0,0 +1,188 @@+[+ {+ "test_id": "ahmose_renee_vs_jasser_02",+ "description": "C2 battle report 2734693171177020",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 20,+ "lancer_t6": 150,+ "marksman_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 607.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 300,+ "lancer_t6": 300,+ "marksman_t6": 150+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T12:45:00.000Z",+ "randomseed": 1790081101,+ "attacker": 0,+ "defender": 227,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171177020",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T12-45-17.101Z-18bff28d-9e22-4981-a0e1-62e0c4fabf17.json",+ "winner": "defender",+ "attacker": {+ "troops": 370,+ "survivors": 0,+ "losses": 0,+ "injured": 130,+ "lightly_injured": 240,+ "kills": 184+ },+ "defender": {+ "troops": 750,+ "survivors": 227,+ "losses": 0,+ "injured": 184,+ "lightly_injured": 339,+ "kills": 130+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 20,+ "survivors": 0,+ "losses": 0,+ "injured": 7,+ "lightly_injured": 13,+ "kills": 0+ },+ "lancer_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 64+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 120+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 5+ },+ "lancer_t6": {+ "troops": 300,+ "survivors": 77,+ "losses": 0,+ "injured": 79,+ "lightly_injured": 144,+ "kills": 53+ },+ "marksman_t6": {+ "troops": 150,+ "survivors": 150,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 72+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 1,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 15,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_c2_discriminators/ahmose_vs_jasser_02.json===================================================================--- testcases/emulator_verified/ahmose_c2_discriminators/ahmose_vs_jasser_02.json prev run+++ testcases/emulator_verified/ahmose_c2_discriminators/ahmose_vs_jasser_02.json this run@@ -0,0 +1,166 @@+[+ {+ "test_id": "ahmose_vs_jasser_02",+ "description": "C2 battle report 2734693171177957",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 320,+ "lancer_t6": 350,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 345.57,+ "defense": 338.12,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Jasser": {+ "skill_1": 4,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 300,+ "lancer_t6": 600+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 354.37,+ "defense": 360.37,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T12:55:54.000Z",+ "randomseed": 1790081755,+ "attacker": 0,+ "defender": 54,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171177957",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T12-56-22.104Z-84298a33-fbb1-4b2d-b18d-32141cb25279.json",+ "winner": "defender",+ "attacker": {+ "troops": 970,+ "survivors": 0,+ "losses": 0,+ "injured": 340,+ "lightly_injured": 630,+ "kills": 297+ },+ "defender": {+ "troops": 900,+ "survivors": 54,+ "losses": 0,+ "injured": 297,+ "lightly_injured": 549,+ "kills": 340+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 320,+ "survivors": 0,+ "losses": 0,+ "injured": 112,+ "lightly_injured": 208,+ "kills": 15+ },+ "lancer_t6": {+ "troops": 350,+ "survivors": 0,+ "losses": 0,+ "injured": 123,+ "lightly_injured": 227,+ "kills": 90+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 192+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 15+ },+ "lancer_t6": {+ "troops": 600,+ "survivors": 54,+ "losses": 0,+ "injured": 192,+ "lightly_injured": 354,+ "kills": 325+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 7,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_c2_discriminators/ahmose_vs_jasser_03.json===================================================================--- testcases/emulator_verified/ahmose_c2_discriminators/ahmose_vs_jasser_03.json prev run+++ testcases/emulator_verified/ahmose_c2_discriminators/ahmose_vs_jasser_03.json this run@@ -0,0 +1,176 @@+[+ {+ "test_id": "ahmose_vs_jasser_03",+ "description": "C2 battle report 2734693171177931",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 30,+ "lancer_t6": 350,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 300,+ "lancer_t6": 150,+ "marksman_t6": 150+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T12:55:40.000Z",+ "randomseed": 1790081741,+ "attacker": 0,+ "defender": 117,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171177931",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T12-55-57.105Z-ff77fd1d-cc80-4c0a-9f4e-0d5f7089a607.json",+ "winner": "defender",+ "attacker": {+ "troops": 680,+ "survivors": 0,+ "losses": 0,+ "injured": 239,+ "lightly_injured": 441,+ "kills": 170+ },+ "defender": {+ "troops": 600,+ "survivors": 117,+ "losses": 0,+ "injured": 170,+ "lightly_injured": 313,+ "kills": 239+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 30,+ "survivors": 0,+ "losses": 0,+ "injured": 11,+ "lightly_injured": 19,+ "kills": 1+ },+ "lancer_t6": {+ "troops": 350,+ "survivors": 0,+ "losses": 0,+ "injured": 123,+ "lightly_injured": 227,+ "kills": 36+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 133+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 16+ },+ "lancer_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 72+ },+ "marksman_t6": {+ "troops": 150,+ "survivors": 117,+ "losses": 0,+ "injured": 12,+ "lightly_injured": 21,+ "kills": 151+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 1,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_c2_discriminators/ahmose_vs_sonya_01.json===================================================================--- testcases/emulator_verified/ahmose_c2_discriminators/ahmose_vs_sonya_01.json prev run+++ testcases/emulator_verified/ahmose_c2_discriminators/ahmose_vs_sonya_01.json this run@@ -0,0 +1,188 @@+[+ {+ "test_id": "ahmose_vs_sonya_01",+ "description": "C2 battle report 2734693171176841",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 500,+ "lancer_t6": 150,+ "marksman_t6": 450+ },+ "stats": {+ "infantry": {+ "attack": 345.57,+ "defense": 338.12,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 150,+ "lancer_t6": 250,+ "marksman_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 529.96,+ "defense": 534.21,+ "lethality": 323.16,+ "health": 285.53+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T12:42:45.000Z",+ "randomseed": 1790080966,+ "attacker": 367,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171176841",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T12-43-13.106Z-fc4468ad-1626-4ce4-a2db-c796c024455b.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1100,+ "survivors": 367,+ "losses": 0,+ "injured": 258,+ "lightly_injured": 475,+ "kills": 211+ },+ "defender": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 211,+ "lightly_injured": 389,+ "kills": 258+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 18+ },+ "lancer_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 41+ },+ "marksman_t6": {+ "troops": 450,+ "survivors": 367,+ "losses": 0,+ "injured": 30,+ "lightly_injured": 53,+ "kills": 152+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 4+ },+ "lancer_t6": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 116+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 138+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 7,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 19,+ "displayed_kills": 7+ },+ "Torrential Impact": {+ "triggered": 7,+ "displayed_kills": 9+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_c2_discriminators/ahmose_vs_sonya_02.json===================================================================--- testcases/emulator_verified/ahmose_c2_discriminators/ahmose_vs_sonya_02.json prev run+++ testcases/emulator_verified/ahmose_c2_discriminators/ahmose_vs_sonya_02.json this run@@ -0,0 +1,184 @@+[+ {+ "test_id": "ahmose_vs_sonya_02",+ "description": "C2 battle report 2734693171176800",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 100,+ "lancer_t6": 650,+ "marksman_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 150,+ "lancer_t6": 700,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 369.5,+ "defense": 368.8,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T12:42:31.000Z",+ "randomseed": 1790080952,+ "attacker": 0,+ "defender": 141,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171176800",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T12-42-48.098Z-15a8c01d-faeb-4cc4-ad14-44de148e5a3d.json",+ "winner": "defender",+ "attacker": {+ "troops": 950,+ "survivors": 0,+ "losses": 0,+ "injured": 333,+ "lightly_injured": 617,+ "kills": 354+ },+ "defender": {+ "troops": 1150,+ "survivors": 141,+ "losses": 0,+ "injured": 354,+ "lightly_injured": 655,+ "kills": 333+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 6+ },+ "lancer_t6": {+ "troops": 650,+ "survivors": 0,+ "losses": 0,+ "injured": 228,+ "lightly_injured": 422,+ "kills": 137+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 211+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 1+ },+ "lancer_t6": {+ "troops": 700,+ "survivors": 0,+ "losses": 0,+ "injured": 245,+ "lightly_injured": 455,+ "kills": 147+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 141,+ "losses": 0,+ "injured": 56,+ "lightly_injured": 103,+ "kills": 185+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 2,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 15,+ "displayed_kills": 10+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_c2_discriminators/jasser_vs_ahmose_02.json===================================================================--- testcases/emulator_verified/ahmose_c2_discriminators/jasser_vs_ahmose_02.json prev run+++ testcases/emulator_verified/ahmose_c2_discriminators/jasser_vs_ahmose_02.json this run@@ -0,0 +1,157 @@+[+ {+ "test_id": "jasser_vs_ahmose_02",+ "description": "C2 battle report 2734693171177279",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Jasser": {+ "skill_1": 4,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 900+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 354.37,+ "defense": 360.37,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 160,+ "lancer_t6": 80,+ "marksman_t6": 600+ },+ "stats": {+ "infantry": {+ "attack": 345.57,+ "defense": 338.12,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T12:48:07.000Z",+ "randomseed": 1790081288,+ "attacker": 0,+ "defender": 148,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171177279",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T12-48-24.097Z-fe44dfcc-6d2b-41be-8307-7954dfa4fae4.json",+ "winner": "defender",+ "attacker": {+ "troops": 900,+ "survivors": 0,+ "losses": 0,+ "injured": 315,+ "lightly_injured": 585,+ "kills": 243+ },+ "defender": {+ "troops": 840,+ "survivors": 148,+ "losses": 0,+ "injured": 243,+ "lightly_injured": 449,+ "kills": 315+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 900,+ "survivors": 0,+ "losses": 0,+ "injured": 315,+ "lightly_injured": 585,+ "kills": 243+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 160,+ "survivors": 0,+ "losses": 0,+ "injured": 56,+ "lightly_injured": 104,+ "kills": 13+ },+ "lancer_t6": {+ "troops": 80,+ "survivors": 0,+ "losses": 0,+ "injured": 28,+ "lightly_injured": 52,+ "kills": 32+ },+ "marksman_t6": {+ "troops": 600,+ "survivors": 148,+ "losses": 0,+ "injured": 159,+ "lightly_injured": 293,+ "kills": 270+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 11,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_c2_discriminators/jasser_vs_ahmose_03.json===================================================================--- testcases/emulator_verified/ahmose_c2_discriminators/jasser_vs_ahmose_03.json prev run+++ testcases/emulator_verified/ahmose_c2_discriminators/jasser_vs_ahmose_03.json this run@@ -0,0 +1,158 @@+[+ {+ "test_id": "jasser_vs_ahmose_03",+ "description": "C2 battle report 2734693171177298",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 900+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 20,+ "lancer_t6": 350,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T12:48:21.000Z",+ "randomseed": 1790081302,+ "attacker": 35,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171177298",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T12-48-49.096Z-fbc5d85f-5dec-46f2-8056-c4c7aee685fc.json",+ "winner": "attacker",+ "attacker": {+ "troops": 900,+ "survivors": 35,+ "losses": 0,+ "injured": 303,+ "lightly_injured": 562,+ "kills": 165+ },+ "defender": {+ "troops": 470,+ "survivors": 0,+ "losses": 0,+ "injured": 165,+ "lightly_injured": 305,+ "kills": 303+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 900,+ "survivors": 35,+ "losses": 0,+ "injured": 303,+ "lightly_injured": 562,+ "kills": 165+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 20,+ "survivors": 0,+ "losses": 0,+ "injured": 7,+ "lightly_injured": 13,+ "kills": 3+ },+ "lancer_t6": {+ "troops": 350,+ "survivors": 0,+ "losses": 0,+ "injured": 123,+ "lightly_injured": 227,+ "kills": 119+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 181+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 3,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_c2_discriminators/jasser_vs_ahmose_04.json===================================================================--- testcases/emulator_verified/ahmose_c2_discriminators/jasser_vs_ahmose_04.json prev run+++ testcases/emulator_verified/ahmose_c2_discriminators/jasser_vs_ahmose_04.json this run@@ -0,0 +1,157 @@+[+ {+ "test_id": "jasser_vs_ahmose_04",+ "description": "C2 battle report 2734693171177719",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Jasser": {+ "skill_1": 4,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 600+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 354.37,+ "defense": 360.37,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 130,+ "lancer_t6": 150,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 345.57,+ "defense": 338.12,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T12:52:46.000Z",+ "randomseed": 1790081567,+ "attacker": 0,+ "defender": 377,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171177719",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T12-53-03.101Z-337f0e8b-d52c-4e1b-8e59-84b2c53e8a9e.json",+ "winner": "defender",+ "attacker": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 72+ },+ "defender": {+ "troops": 580,+ "survivors": 377,+ "losses": 0,+ "injured": 72,+ "lightly_injured": 131,+ "kills": 210+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 72+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 130,+ "survivors": 0,+ "losses": 0,+ "injured": 46,+ "lightly_injured": 84,+ "kills": 14+ },+ "lancer_t6": {+ "troops": 150,+ "survivors": 77,+ "losses": 0,+ "injured": 26,+ "lightly_injured": 47,+ "kills": 61+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 300,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 135+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 14,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_c2_discriminators/jasser_vs_ahmose_05.json===================================================================--- testcases/emulator_verified/ahmose_c2_discriminators/jasser_vs_ahmose_05.json prev run+++ testcases/emulator_verified/ahmose_c2_discriminators/jasser_vs_ahmose_05.json this run@@ -0,0 +1,158 @@+[+ {+ "test_id": "jasser_vs_ahmose_05",+ "description": "C2 battle report 2734693171177754",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 900+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 30,+ "lancer_t6": 500,+ "marksman_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T12:53:00.000Z",+ "randomseed": 1790081581,+ "attacker": 0,+ "defender": 526,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171177754",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T12-53-28.100Z-3e2a12a6-6e6e-4dc7-ae84-7be9834d769f.json",+ "winner": "defender",+ "attacker": {+ "troops": 900,+ "survivors": 0,+ "losses": 0,+ "injured": 315,+ "lightly_injured": 585,+ "kills": 72+ },+ "defender": {+ "troops": 730,+ "survivors": 526,+ "losses": 0,+ "injured": 72,+ "lightly_injured": 132,+ "kills": 315+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 900,+ "survivors": 0,+ "losses": 0,+ "injured": 315,+ "lightly_injured": 585,+ "kills": 72+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 30,+ "survivors": 0,+ "losses": 0,+ "injured": 11,+ "lightly_injured": 19,+ "kills": 7+ },+ "lancer_t6": {+ "troops": 500,+ "survivors": 326,+ "losses": 0,+ "injured": 61,+ "lightly_injured": 113,+ "kills": 152+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 200,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 156+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 4,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_c2_discriminators/jasser_vs_ahmose_renee_01.json===================================================================--- testcases/emulator_verified/ahmose_c2_discriminators/jasser_vs_ahmose_renee_01.json prev run+++ testcases/emulator_verified/ahmose_c2_discriminators/jasser_vs_ahmose_renee_01.json this run@@ -0,0 +1,178 @@+[+ {+ "test_id": "jasser_vs_ahmose_renee_01",+ "description": "C2 battle report 2734693171177561",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Jasser": {+ "skill_1": 4,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 500,+ "lancer_t6": 300,+ "marksman_t6": 450+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 354.37,+ "defense": 360.37,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ },+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 500,+ "lancer_t6": 350+ },+ "stats": {+ "infantry": {+ "attack": 345.57,+ "defense": 338.12,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T12:51:05.000Z",+ "randomseed": 1790081466,+ "attacker": 0,+ "defender": 11,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171177561",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T12-51-22.103Z-fe039a6d-4ca4-4470-9541-9029e88157a9.json",+ "winner": "defender",+ "attacker": {+ "troops": 1250,+ "survivors": 0,+ "losses": 0,+ "injured": 438,+ "lightly_injured": 812,+ "kills": 294+ },+ "defender": {+ "troops": 850,+ "survivors": 11,+ "losses": 0,+ "injured": 294,+ "lightly_injured": 545,+ "kills": 438+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 17+ },+ "lancer_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 62+ },+ "marksman_t6": {+ "troops": 450,+ "survivors": 0,+ "losses": 0,+ "injured": 158,+ "lightly_injured": 292,+ "kills": 215+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 19+ },+ "lancer_t6": {+ "troops": 350,+ "survivors": 11,+ "losses": 0,+ "injured": 119,+ "lightly_injured": 220,+ "kills": 419+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 5,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 22,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_c2_discriminators/jasser_vs_ahmose_renee_02.json===================================================================--- testcases/emulator_verified/ahmose_c2_discriminators/jasser_vs_ahmose_renee_02.json prev run+++ testcases/emulator_verified/ahmose_c2_discriminators/jasser_vs_ahmose_renee_02.json this run@@ -0,0 +1,179 @@+[+ {+ "test_id": "jasser_vs_ahmose_renee_02",+ "description": "C2 battle report 2734693171177580",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 500,+ "marksman_t6": 650+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 100,+ "lancer_t6": 150,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 607.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T12:51:19.000Z",+ "randomseed": 1790081480,+ "attacker": 224,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171177580",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T12-51-47.104Z-def3d98f-8305-41c6-8f29-79e7b22ec82a.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1150,+ "survivors": 224,+ "losses": 0,+ "injured": 325,+ "lightly_injured": 601,+ "kills": 123+ },+ "defender": {+ "troops": 350,+ "survivors": 0,+ "losses": 0,+ "injured": 123,+ "lightly_injured": 227,+ "kills": 325+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 6+ },+ "marksman_t6": {+ "troops": 650,+ "survivors": 224,+ "losses": 0,+ "injured": 150,+ "lightly_injured": 276,+ "kills": 117+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 10+ },+ "lancer_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 179+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 136+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 4,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 21,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_c2_discriminators/sonya_vs_ahmose_01.json===================================================================--- testcases/emulator_verified/ahmose_c2_discriminators/sonya_vs_ahmose_01.json prev run+++ testcases/emulator_verified/ahmose_c2_discriminators/sonya_vs_ahmose_01.json this run@@ -0,0 +1,188 @@+[+ {+ "test_id": "sonya_vs_ahmose_01",+ "description": "C2 battle report 2734693171177424",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 80,+ "lancer_t6": 400,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 529.96,+ "defense": 534.21,+ "lethality": 323.16,+ "health": 285.53+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 400,+ "lancer_t6": 650,+ "marksman_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 345.57,+ "defense": 338.12,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T12:49:41.000Z",+ "randomseed": 1790081382,+ "attacker": 0,+ "defender": 125,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171177424",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T12-49-58.101Z-fe87620a-3310-42f9-83c9-51edb37e6018.json",+ "winner": "defender",+ "attacker": {+ "troops": 580,+ "survivors": 0,+ "losses": 0,+ "injured": 203,+ "lightly_injured": 377,+ "kills": 395+ },+ "defender": {+ "troops": 1250,+ "survivors": 125,+ "losses": 0,+ "injured": 395,+ "lightly_injured": 730,+ "kills": 203+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 80,+ "survivors": 0,+ "losses": 0,+ "injured": 28,+ "lightly_injured": 52,+ "kills": 2+ },+ "lancer_t6": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 237+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 156+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 12+ },+ "lancer_t6": {+ "troops": 650,+ "survivors": 0,+ "losses": 0,+ "injured": 228,+ "lightly_injured": 422,+ "kills": 80+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 125,+ "losses": 0,+ "injured": 27,+ "lightly_injured": 48,+ "kills": 111+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 22,+ "displayed_kills": 14+ },+ "Torrential Impact": {+ "triggered": 9,+ "displayed_kills": 20+ }+ }+ },+ "defender": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 5,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_c2_discriminators/sonya_vs_ahmose_02.json===================================================================--- testcases/emulator_verified/ahmose_c2_discriminators/sonya_vs_ahmose_02.json prev run+++ testcases/emulator_verified/ahmose_c2_discriminators/sonya_vs_ahmose_02.json this run@@ -0,0 +1,166 @@+[+ {+ "test_id": "sonya_vs_ahmose_02",+ "description": "C2 battle report 2734693171177460",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 400+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 369.5,+ "defense": 368.8,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 12,+ "lancer_t6": 80,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T12:49:55.000Z",+ "randomseed": 1790081396,+ "attacker": 0,+ "defender": 148,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171177460",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T12-50-23.096Z-b7da47c0-3c38-4710-b51d-6d8667f2b36a.json",+ "winner": "defender",+ "attacker": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 87+ },+ "defender": {+ "troops": 392,+ "survivors": 148,+ "losses": 0,+ "injured": 87,+ "lightly_injured": 157,+ "kills": 140+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 87+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 12,+ "survivors": 0,+ "losses": 0,+ "injured": 5,+ "lightly_injured": 7,+ "kills": 1+ },+ "lancer_t6": {+ "troops": 80,+ "survivors": 0,+ "losses": 0,+ "injured": 28,+ "lightly_injured": 52,+ "kills": 16+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 148,+ "losses": 0,+ "injured": 54,+ "lightly_injured": 98,+ "kills": 123+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 14,+ "displayed_kills": 4+ }+ }+ },+ "defender": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 1,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_c2_discriminators/sonya_vs_ahmose_03.json===================================================================--- testcases/emulator_verified/ahmose_c2_discriminators/sonya_vs_ahmose_03.json prev run+++ testcases/emulator_verified/ahmose_c2_discriminators/sonya_vs_ahmose_03.json this run@@ -0,0 +1,170 @@+[+ {+ "test_id": "sonya_vs_ahmose_03",+ "description": "C2 battle report 2734693171177838",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 30,+ "lancer_t6": 150,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 529.96,+ "defense": 534.21,+ "lethality": 323.16,+ "health": 285.53+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 950+ },+ "stats": {+ "infantry": {+ "attack": 345.57,+ "defense": 338.12,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T12:54:10.000Z",+ "randomseed": 1790081651,+ "attacker": 265,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171177838",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T12-54-27.099Z-8da60204-2311-4dfe-bfc9-71d3c4939aee.json",+ "winner": "attacker",+ "attacker": {+ "troops": 480,+ "survivors": 265,+ "losses": 0,+ "injured": 77,+ "lightly_injured": 138,+ "kills": 333+ },+ "defender": {+ "troops": 950,+ "survivors": 0,+ "losses": 0,+ "injured": 333,+ "lightly_injured": 617,+ "kills": 77+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 30,+ "survivors": 0,+ "losses": 0,+ "injured": 11,+ "lightly_injured": 19,+ "kills": 1+ },+ "lancer_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 131+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 265,+ "losses": 0,+ "injured": 13,+ "lightly_injured": 22,+ "kills": 201+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 950,+ "survivors": 0,+ "losses": 0,+ "injured": 333,+ "lightly_injured": 617,+ "kills": 77+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 41,+ "displayed_kills": 6+ },+ "Torrential Impact": {+ "triggered": 16,+ "displayed_kills": 10+ }+ }+ },+ "defender": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 20,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_c2_discriminators/sonya_vs_ahmose_04.json===================================================================--- testcases/emulator_verified/ahmose_c2_discriminators/sonya_vs_ahmose_04.json prev run+++ testcases/emulator_verified/ahmose_c2_discriminators/sonya_vs_ahmose_04.json this run@@ -0,0 +1,252 @@+[+ {+ "test_id": "sonya_vs_ahmose_04",+ "description": "C2 battle report 2734693171177863",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 600,+ "lancer_t6": 250,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 369.5,+ "defense": 368.8,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 950+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T12:54:24.000Z",+ "randomseed": 1790081665,+ "attacker": 147,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171177863",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T12-54-52.100Z-5db46442-8faa-4a7f-826c-f45cdb88de3d.json",+ "winner": "attacker",+ "attacker": {+ "troops": 950,+ "survivors": 147,+ "losses": 0,+ "injured": 282,+ "lightly_injured": 521,+ "kills": 333+ },+ "defender": {+ "troops": 950,+ "survivors": 0,+ "losses": 0,+ "injured": 333,+ "lightly_injured": 617,+ "kills": 282+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 35+ },+ "lancer_t6": {+ "troops": 250,+ "survivors": 47,+ "losses": 0,+ "injured": 72,+ "lightly_injured": 131,+ "kills": 182+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 100,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 116+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 950,+ "survivors": 0,+ "losses": 0,+ "injured": 333,+ "lightly_injured": 617,+ "kills": 282+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 67,+ "displayed_kills": 14+ }+ }+ },+ "defender": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 27,+ "displayed_kills": null+ }+ }+ }+ }+ }+ },+ {+ "timestamp": "2026-09-22T12:57:52.000Z",+ "randomseed": 1790081873,+ "attacker": 147,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171178088",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T12-58-20.101Z-a73e8bc8-9d90-4523-8acb-80c29e136dc2.json",+ "winner": "attacker",+ "attacker": {+ "troops": 950,+ "survivors": 147,+ "losses": 0,+ "injured": 282,+ "lightly_injured": 521,+ "kills": 333+ },+ "defender": {+ "troops": 950,+ "survivors": 0,+ "losses": 0,+ "injured": 333,+ "lightly_injured": 617,+ "kills": 282+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 35+ },+ "lancer_t6": {+ "troops": 250,+ "survivors": 47,+ "losses": 0,+ "injured": 72,+ "lightly_injured": 131,+ "kills": 182+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 100,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 116+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 950,+ "survivors": 0,+ "losses": 0,+ "injured": 333,+ "lightly_injured": 617,+ "kills": 282+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 67,+ "displayed_kills": 14+ }+ }+ },+ "defender": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 27,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_c2_discriminators/sonya_vs_ahmose_05.json===================================================================--- testcases/emulator_verified/ahmose_c2_discriminators/sonya_vs_ahmose_05.json prev run+++ testcases/emulator_verified/ahmose_c2_discriminators/sonya_vs_ahmose_05.json this run@@ -0,0 +1,166 @@+[+ {+ "test_id": "sonya_vs_ahmose_05",+ "description": "C2 battle report 2734693171178226",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 600,+ "lancer_t6": 250,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 369.5,+ "defense": 368.8,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 900+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T12:59:23.000Z",+ "randomseed": 1790081964,+ "attacker": 323,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171178226",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T12-59-51.099Z-5306b071-25d2-4a37-bafa-051232d24bcb.json",+ "winner": "attacker",+ "attacker": {+ "troops": 950,+ "survivors": 323,+ "losses": 0,+ "injured": 220,+ "lightly_injured": 407,+ "kills": 315+ },+ "defender": {+ "troops": 900,+ "survivors": 0,+ "losses": 0,+ "injured": 315,+ "lightly_injured": 585,+ "kills": 220+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 34+ },+ "lancer_t6": {+ "troops": 250,+ "survivors": 223,+ "losses": 0,+ "injured": 10,+ "lightly_injured": 17,+ "kills": 173+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 100,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 108+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 900,+ "survivors": 0,+ "losses": 0,+ "injured": 315,+ "lightly_injured": 585,+ "kills": 220+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 61,+ "displayed_kills": 8+ }+ }+ },+ "defender": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 24,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_c2_discriminators/sonya_vs_ahmose_06.json===================================================================--- testcases/emulator_verified/ahmose_c2_discriminators/sonya_vs_ahmose_06.json prev run+++ testcases/emulator_verified/ahmose_c2_discriminators/sonya_vs_ahmose_06.json this run@@ -0,0 +1,166 @@+[+ {+ "test_id": "sonya_vs_ahmose_06",+ "description": "C2 battle report 2734693171178339",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 600,+ "lancer_t6": 250,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 369.5,+ "defense": 368.8,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T13:00:45.000Z",+ "randomseed": 1790082046,+ "attacker": 0,+ "defender": 130,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171178339",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T13-01-13.104Z-d4d26eb2-c4e5-4af7-bc00-3136cdfaa568.json",+ "winner": "defender",+ "attacker": {+ "troops": 950,+ "survivors": 0,+ "losses": 0,+ "injured": 333,+ "lightly_injured": 617,+ "kills": 305+ },+ "defender": {+ "troops": 1000,+ "survivors": 130,+ "losses": 0,+ "injured": 305,+ "lightly_injured": 565,+ "kills": 333+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 30+ },+ "lancer_t6": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 162+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 113+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 130,+ "losses": 0,+ "injured": 305,+ "lightly_injured": 565,+ "kills": 333+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 60,+ "displayed_kills": 10+ }+ }+ },+ "defender": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 25,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_c2_discriminators/sonya_vs_ahmose_07.json===================================================================--- testcases/emulator_verified/ahmose_c2_discriminators/sonya_vs_ahmose_07.json prev run+++ testcases/emulator_verified/ahmose_c2_discriminators/sonya_vs_ahmose_07.json this run@@ -0,0 +1,166 @@+[+ {+ "test_id": "sonya_vs_ahmose_07",+ "description": "C2 battle report 2734693171178496",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 550,+ "lancer_t6": 250,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 369.5,+ "defense": 368.8,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 950+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T13:02:11.000Z",+ "randomseed": 1790082132,+ "attacker": 0,+ "defender": 133,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171178496",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T13-02-39.102Z-807088f1-f3f0-4607-b064-c4d00fe444be.json",+ "winner": "defender",+ "attacker": {+ "troops": 900,+ "survivors": 0,+ "losses": 0,+ "injured": 316,+ "lightly_injured": 584,+ "kills": 286+ },+ "defender": {+ "troops": 950,+ "survivors": 133,+ "losses": 0,+ "injured": 286,+ "lightly_injured": 531,+ "kills": 316+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 550,+ "survivors": 0,+ "losses": 0,+ "injured": 193,+ "lightly_injured": 357,+ "kills": 30+ },+ "lancer_t6": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 152+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 104+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 950,+ "survivors": 133,+ "losses": 0,+ "injured": 286,+ "lightly_injured": 531,+ "kills": 316+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 58,+ "displayed_kills": 12+ }+ }+ },+ "defender": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 25,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_gordon_renee/ahmose_bradley_vs_wuming.json===================================================================--- testcases/emulator_verified/ahmose_gordon_renee/ahmose_bradley_vs_wuming.json prev run+++ testcases/emulator_verified/ahmose_gordon_renee/ahmose_bradley_vs_wuming.json this run@@ -0,0 +1,154 @@+[+ {+ "test_id": "ahmose_bradley_vs_wuming",+ "description": "C2 battle report 2734693171229499",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Bradley": {+ "skill_1": 5,+ "skill_2": 4,+ "skill_3": 3,+ "skill_4": 1+ }+ },+ "troops": {+ "infantry_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 734.42,+ "defense": 740.42,+ "lethality": 375.19,+ "health": 331.96+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 1350+ },+ "stats": {+ "infantry": {+ "attack": 453.71,+ "defense": 446.26,+ "lethality": 223.57,+ "health": 274.97+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T19:47:56.000Z",+ "randomseed": 1790106477,+ "attacker": 22,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171229499",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T19-48-12.093Z-06182c38-1c44-40a2-a58b-1fe14cded29a.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1000,+ "survivors": 22,+ "losses": 0,+ "injured": 343,+ "lightly_injured": 635,+ "kills": 473+ },+ "defender": {+ "troops": 1350,+ "survivors": 0,+ "losses": 0,+ "injured": 473,+ "lightly_injured": 877,+ "kills": 343+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 22,+ "losses": 0,+ "injured": 343,+ "lightly_injured": 635,+ "kills": 473+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1350,+ "survivors": 0,+ "losses": 0,+ "injured": 473,+ "lightly_injured": 877,+ "kills": 343+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 82,+ "displayed_kills": null+ }+ },+ "Bradley": {+ "Tactical Assistance": {+ "triggered": 103,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_gordon_renee/ahmose_gordon_vs_jasser_control.json===================================================================--- testcases/emulator_verified/ahmose_gordon_renee/ahmose_gordon_vs_jasser_control.json prev run+++ testcases/emulator_verified/ahmose_gordon_renee/ahmose_gordon_vs_jasser_control.json this run@@ -0,0 +1,169 @@+[+ {+ "test_id": "ahmose_gordon_vs_jasser_control",+ "description": "C2 battle report 2734693171228925",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 800,+ "lancer_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 488.62,+ "defense": 492.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T19:35:25.000Z",+ "randomseed": 1790105726,+ "attacker": 1047,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171228925",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T19-35-41.097Z-cf5e92d1-3386-4d3e-9306-eebfb4dc1b35.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1100,+ "survivors": 1047,+ "losses": 0,+ "injured": 19,+ "lightly_injured": 34,+ "kills": 350+ },+ "defender": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 19+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 800,+ "survivors": 747,+ "losses": 0,+ "injured": 19,+ "lightly_injured": 34,+ "kills": 125+ },+ "lancer_t6": {+ "troops": 300,+ "survivors": 300,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 225+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 19+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 8,+ "displayed_kills": null+ }+ },+ "Gordon": {+ "Venom Infusion": {+ "triggered": 20,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 13,+ "displayed_kills": null+ },+ "Toxic Release": {+ "triggered": 10,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_gordon_renee/ahmose_gordon_vs_wuming.json===================================================================--- testcases/emulator_verified/ahmose_gordon_renee/ahmose_gordon_vs_wuming.json prev run+++ testcases/emulator_verified/ahmose_gordon_renee/ahmose_gordon_vs_wuming.json this run@@ -0,0 +1,189 @@+[+ {+ "test_id": "ahmose_gordon_vs_wuming",+ "description": "C2 battle report 2734693171229289",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 300,+ "lancer_t6": 1200+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 488.62,+ "defense": 492.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 900,+ "lancer_t6": 300,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 453.71,+ "defense": 446.26,+ "lethality": 223.57,+ "health": 274.97+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T19:43:36.000Z",+ "randomseed": 1790106217,+ "attacker": 140,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171229289",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T19-43-52.098Z-de42fee8-50c1-4f26-a45b-c802bfb3c10e.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1500,+ "survivors": 140,+ "losses": 0,+ "injured": 476,+ "lightly_injured": 884,+ "kills": 525+ },+ "defender": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 476+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 16+ },+ "lancer_t6": {+ "troops": 1200,+ "survivors": 140,+ "losses": 0,+ "injured": 371,+ "lightly_injured": 689,+ "kills": 509+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 900,+ "survivors": 0,+ "losses": 0,+ "injured": 315,+ "lightly_injured": 585,+ "kills": 87+ },+ "lancer_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 154+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 235+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 5,+ "displayed_kills": null+ }+ },+ "Gordon": {+ "Venom Infusion": {+ "triggered": 34,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 22,+ "displayed_kills": null+ },+ "Toxic Release": {+ "triggered": 17,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_gordon_renee/ahmose_gordon_wayne_pure_lancers_vs_jasser.json===================================================================--- testcases/emulator_verified/ahmose_gordon_renee/ahmose_gordon_wayne_pure_lancers_vs_jasser.json prev run+++ testcases/emulator_verified/ahmose_gordon_renee/ahmose_gordon_wayne_pure_lancers_vs_jasser.json this run@@ -0,0 +1,175 @@+[+ {+ "test_id": "ahmose_gordon_wayne_pure_lancers_vs_jasser",+ "description": "C2 battle report 2734693171229777",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ },+ "Wayne": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 488.62,+ "defense": 492.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 421.39,+ "defense": 427.39,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 900+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T19:56:25.000Z",+ "randomseed": 1790106986,+ "attacker": 0,+ "defender": 21,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171229777",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T19-56-41.089Z-ed4aef91-632f-45a8-878b-192f58ed94ef.json",+ "winner": "defender",+ "attacker": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 308+ },+ "defender": {+ "troops": 900,+ "survivors": 21,+ "losses": 0,+ "injured": 308,+ "lightly_injured": 571,+ "kills": 105+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 308+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 900,+ "survivors": 21,+ "losses": 0,+ "injured": 308,+ "lightly_injured": 571,+ "kills": 105+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ },+ "Thunder Strike": {+ "triggered": 43,+ "displayed_kills": 22+ }+ },+ "Ahmose": {+ "Viper Formation": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Gordon": {+ "Venom Infusion": {+ "triggered": 86,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 57,+ "displayed_kills": null+ },+ "Toxic Release": {+ "triggered": 43,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_gordon_renee/ahmose_gordon_wayne_vs_jasser.json===================================================================--- testcases/emulator_verified/ahmose_gordon_renee/ahmose_gordon_wayne_vs_jasser.json prev run+++ testcases/emulator_verified/ahmose_gordon_renee/ahmose_gordon_wayne_vs_jasser.json this run@@ -0,0 +1,193 @@+[+ {+ "test_id": "ahmose_gordon_wayne_vs_jasser",+ "description": "C2 battle report 2734693171229258",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ },+ "Wayne": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 300,+ "lancer_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 488.62,+ "defense": 492.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 421.39,+ "defense": 427.39,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 1000,+ "marksman_t6": 500+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T19:42:26.000Z",+ "randomseed": 1790106147,+ "attacker": 0,+ "defender": 327,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171229258",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T19-42-42.089Z-be88920c-6660-44b1-b166-e5d6dfa22f1b.json",+ "winner": "defender",+ "attacker": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 411+ },+ "defender": {+ "troops": 1500,+ "survivors": 327,+ "losses": 0,+ "injured": 411,+ "lightly_injured": 762,+ "kills": 210+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 55+ },+ "lancer_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 356+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 24+ },+ "marksman_t6": {+ "troops": 500,+ "survivors": 327,+ "losses": 0,+ "injured": 61,+ "lightly_injured": 112,+ "kills": 186+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ },+ "Thunder Strike": {+ "triggered": 30,+ "displayed_kills": 31+ }+ },+ "Ahmose": {+ "Viper Formation": {+ "triggered": 10,+ "displayed_kills": null+ }+ },+ "Gordon": {+ "Venom Infusion": {+ "triggered": 36,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 24,+ "displayed_kills": null+ },+ "Toxic Release": {+ "triggered": 18,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_gordon_renee/ahmose_renee_vs_jasser_addition.json===================================================================--- testcases/emulator_verified/ahmose_gordon_renee/ahmose_renee_vs_jasser_addition.json prev run+++ testcases/emulator_verified/ahmose_gordon_renee/ahmose_renee_vs_jasser_addition.json this run@@ -0,0 +1,170 @@+[+ {+ "test_id": "ahmose_renee_vs_jasser_addition",+ "description": "C2 battle report 2734693171229602",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 200,+ "lancer_t6": 150+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 607.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 1000,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T19:51:15.000Z",+ "randomseed": 1790106676,+ "attacker": 0,+ "defender": 320,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171229602",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T19-51-31.092Z-606ba725-4bd3-4869-bb85-4dcc3998391d.json",+ "winner": "defender",+ "attacker": {+ "troops": 350,+ "survivors": 0,+ "losses": 0,+ "injured": 123,+ "lightly_injured": 227,+ "kills": 343+ },+ "defender": {+ "troops": 1300,+ "survivors": 320,+ "losses": 0,+ "injured": 343,+ "lightly_injured": 637,+ "kills": 123+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 43+ },+ "lancer_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 300+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 20,+ "losses": 0,+ "injured": 343,+ "lightly_injured": 637,+ "kills": 22+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 300,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 101+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 9,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 34,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_gordon_renee/ahmose_renee_vs_jasser_control.json===================================================================--- testcases/emulator_verified/ahmose_gordon_renee/ahmose_renee_vs_jasser_control.json prev run+++ testcases/emulator_verified/ahmose_gordon_renee/ahmose_renee_vs_jasser_control.json this run@@ -0,0 +1,161 @@+[+ {+ "test_id": "ahmose_renee_vs_jasser_control",+ "description": "C2 battle report 2734693171229020",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 800,+ "lancer_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 607.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T19:37:09.000Z",+ "randomseed": 1790105830,+ "attacker": 1067,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171229020",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T19-37-25.104Z-b438d950-d174-47a7-9e11-1fd4fdd6e7aa.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1100,+ "survivors": 1067,+ "losses": 0,+ "injured": 12,+ "lightly_injured": 21,+ "kills": 350+ },+ "defender": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 12+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 800,+ "survivors": 767,+ "losses": 0,+ "injured": 12,+ "lightly_injured": 21,+ "kills": 100+ },+ "lancer_t6": {+ "troops": 300,+ "survivors": 300,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 250+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 12+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 4,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 11,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_gordon_renee/ahmose_renee_vs_jasser_mark_kind.json===================================================================--- testcases/emulator_verified/ahmose_gordon_renee/ahmose_renee_vs_jasser_mark_kind.json prev run+++ testcases/emulator_verified/ahmose_gordon_renee/ahmose_renee_vs_jasser_mark_kind.json this run@@ -0,0 +1,170 @@+[+ {+ "test_id": "ahmose_renee_vs_jasser_mark_kind",+ "description": "C2 battle report 2734693171229547",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 1000,+ "lancer_t6": 150+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 607.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 1000,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T19:49:24.000Z",+ "randomseed": 1790106565,+ "attacker": 937,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171229547",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T19-49-40.089Z-3411a2d5-f80c-458b-b110-c099b8af3982.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1150,+ "survivors": 937,+ "losses": 0,+ "injured": 75,+ "lightly_injured": 138,+ "kills": 455+ },+ "defender": {+ "troops": 1300,+ "survivors": 0,+ "losses": 0,+ "injured": 455,+ "lightly_injured": 845,+ "kills": 75+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 787,+ "losses": 0,+ "injured": 75,+ "lightly_injured": 138,+ "kills": 169+ },+ "lancer_t6": {+ "troops": 150,+ "survivors": 150,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 286+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 17+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 58+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 6,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 14,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_gordon_renee/ahmose_wayne_vs_jasser.json===================================================================--- testcases/emulator_verified/ahmose_gordon_renee/ahmose_wayne_vs_jasser.json prev run+++ testcases/emulator_verified/ahmose_gordon_renee/ahmose_wayne_vs_jasser.json this run@@ -0,0 +1,155 @@+[+ {+ "test_id": "ahmose_wayne_vs_jasser",+ "description": "C2 battle report 2734693171229364",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Wayne": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 550+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 421.39,+ "defense": 427.39,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 1500+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T19:45:01.000Z",+ "randomseed": 1790106302,+ "attacker": 0,+ "defender": 141,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171229364",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T19-45-17.099Z-390f5034-d940-451a-992f-9b3df252c21c.json",+ "winner": "defender",+ "attacker": {+ "troops": 550,+ "survivors": 0,+ "losses": 0,+ "injured": 193,+ "lightly_injured": 357,+ "kills": 476+ },+ "defender": {+ "troops": 1500,+ "survivors": 141,+ "losses": 0,+ "injured": 476,+ "lightly_injured": 883,+ "kills": 193+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 550,+ "survivors": 0,+ "losses": 0,+ "injured": 193,+ "lightly_injured": 357,+ "kills": 476+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1500,+ "survivors": 141,+ "losses": 0,+ "injured": 476,+ "lightly_injured": 883,+ "kills": 193+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ },+ "Thunder Strike": {+ "triggered": 115,+ "displayed_kills": 40+ }+ },+ "Ahmose": {+ "Viper Formation": {+ "triggered": 92,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_gordon_renee/ahmose_wayne_vs_wuming.json===================================================================--- testcases/emulator_verified/ahmose_gordon_renee/ahmose_wayne_vs_wuming.json prev run+++ testcases/emulator_verified/ahmose_gordon_renee/ahmose_wayne_vs_wuming.json this run@@ -0,0 +1,157 @@+[+ {+ "test_id": "ahmose_wayne_vs_wuming",+ "description": "C2 battle report 2734693171229424",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Wayne": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 421.39,+ "defense": 427.39,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 1050+ },+ "stats": {+ "infantry": {+ "attack": 453.71,+ "defense": 446.26,+ "lethality": 223.57,+ "health": 274.97+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T19:46:29.000Z",+ "randomseed": 1790106390,+ "attacker": 0,+ "defender": 50,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171229424",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T19-46-45.093Z-c16372d3-8764-4387-945b-7b3024675da9.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 350+ },+ "defender": {+ "troops": 1050,+ "survivors": 50,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 350+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1050,+ "survivors": 50,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ },+ "Thunder Strike": {+ "triggered": 111,+ "displayed_kills": 26+ }+ },+ "Ahmose": {+ "Viper Formation": {+ "triggered": 89,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_gordon_renee/wuming_renee_vs_jasser.json===================================================================--- testcases/emulator_verified/ahmose_gordon_renee/wuming_renee_vs_jasser.json prev run+++ testcases/emulator_verified/ahmose_gordon_renee/wuming_renee_vs_jasser.json this run@@ -0,0 +1,164 @@+[+ {+ "test_id": "wuming_renee_vs_jasser",+ "description": "C2 battle report 2734693171229643",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 2,+ "skill_4": 0+ },+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 200,+ "lancer_t6": 150+ },+ "stats": {+ "infantry": {+ "attack": 508.98,+ "defense": 501.98,+ "lethality": 250.71,+ "health": 274.79+ },+ "lancer": {+ "attack": 607.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 1000,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T19:52:37.000Z",+ "randomseed": 1790106758,+ "attacker": 176,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171229643",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T19-52-53.093Z-a798fb63-9966-43c9-a6b3-2faea7d87a9c.json",+ "winner": "attacker",+ "attacker": {+ "troops": 350,+ "survivors": 176,+ "losses": 0,+ "injured": 61,+ "lightly_injured": 113,+ "kills": 455+ },+ "defender": {+ "troops": 1300,+ "survivors": 0,+ "losses": 0,+ "injured": 455,+ "lightly_injured": 845,+ "kills": 61+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 26,+ "losses": 0,+ "injured": 61,+ "lightly_injured": 113,+ "kills": 64+ },+ "lancer_t6": {+ "troops": 150,+ "survivors": 150,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 391+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 13+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 48+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 32,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_isolation_20260925/ahmose_1000i_vs_wuming_1000i.json===================================================================--- testcases/emulator_verified/ahmose_isolation_20260925/ahmose_1000i_vs_wuming_1000i.json prev run+++ testcases/emulator_verified/ahmose_isolation_20260925/ahmose_1000i_vs_wuming_1000i.json this run@@ -0,0 +1,142 @@+[+ {+ "test_id": "ahmose_1000i_vs_wuming_1000i",+ "description": "C2 battle report 2734693171342058",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 422.61,+ "defense": 405.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 453.71,+ "defense": 446.26,+ "lethality": 223.57,+ "health": 274.97+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T05:36:02.000Z",+ "randomseed": 1790314563,+ "attacker": 0,+ "defender": 82,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171342058",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T05-36-18.192Z-96efaf92-abb7-4e28-b03f-e99c019d96b2.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 322+ },+ "defender": {+ "troops": 1000,+ "survivors": 82,+ "losses": 0,+ "injured": 322,+ "lightly_injured": 596,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 322+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 82,+ "losses": 0,+ "injured": 322,+ "lightly_injured": 596,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 86,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_isolation_20260925/ahmose_bradley_1000i_vs_3700i.json===================================================================--- testcases/emulator_verified/ahmose_isolation_20260925/ahmose_bradley_1000i_vs_3700i.json prev run+++ testcases/emulator_verified/ahmose_isolation_20260925/ahmose_bradley_1000i_vs_3700i.json this run@@ -0,0 +1,147 @@+[+ {+ "test_id": "ahmose_bradley_1000i_vs_3700i",+ "description": "C2 battle report 2734693171341989",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Bradley": {+ "skill_1": 5,+ "skill_2": 4,+ "skill_3": 3,+ "skill_4": 1+ }+ },+ "troops": {+ "infantry_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 422.61,+ "defense": 405.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 739.42,+ "defense": 735.42,+ "lethality": 375.19,+ "health": 331.96+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 3700+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T05:34:09.000Z",+ "randomseed": 1790314450,+ "attacker": 0,+ "defender": 77,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171341989",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T05-34-25.223Z-c513bff5-30c5-4e1a-87ec-4e00ce0d0b8e.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 1269+ },+ "defender": {+ "troops": 3700,+ "survivors": 77,+ "losses": 0,+ "injured": 1269,+ "lightly_injured": 2354,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 1269+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 3700,+ "survivors": 77,+ "losses": 0,+ "injured": 1269,+ "lightly_injured": 2354,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 97,+ "displayed_kills": null+ }+ },+ "Bradley": {+ "Tactical Assistance": {+ "triggered": 121,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gatot_sonya_hendrik_precise.json===================================================================--- testcases/emulator_verified/gatot_sonya_hendrik_precise.json prev run+++ testcases/emulator_verified/gatot_sonya_hendrik_precise.json this run@@ -0,0 +1,239 @@+[+ {+ "test_id": "c2_2734693170978104",+ "description": "C2 battle report 2734693170978104",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gatot": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ },+ "Hendrik": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 300,+ "lancer_t6": 300,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 623.17,+ "defense": 619.79,+ "lethality": 228.98,+ "health": 279.34+ },+ "lancer": {+ "attack": 369.36,+ "defense": 368.73,+ "lethality": 186.82,+ "health": 181.88+ },+ "marksman": {+ "attack": 478.86,+ "defense": 467.73,+ "lethality": 244.02,+ "health": 220.98+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gatot": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ },+ "Hendrik": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 300,+ "lancer_t6": 300,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 665.38,+ "defense": 662.63,+ "lethality": 316.11,+ "health": 338.06+ },+ "lancer": {+ "attack": 529.96,+ "defense": 533.71,+ "lethality": 323.16,+ "health": 285.53+ },+ "marksman": {+ "attack": 439.96,+ "defense": 445.46,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-18T05:10:41.000Z",+ "randomseed": 1789708242,+ "attacker": 0,+ "defender": 367,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693170978104",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../c2/data/runs/2026-09-18T05-09-57.549Z.json",+ "winner": "defender",+ "attacker": {+ "troops": 900,+ "survivors": 0,+ "losses": 0,+ "injured": 315,+ "lightly_injured": 585,+ "kills": 188+ },+ "defender": {+ "troops": 900,+ "survivors": 367,+ "losses": 0,+ "injured": 188,+ "lightly_injured": 345,+ "kills": 315+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 1+ },+ "lancer_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 21+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 166+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 300,+ "survivors": 5,+ "losses": 0,+ "injured": 104,+ "lightly_injured": 191,+ "kills": 18+ },+ "lancer_t6": {+ "troops": 300,+ "survivors": 215,+ "losses": 0,+ "injured": 30,+ "lightly_injured": 55,+ "kills": 176+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 147,+ "losses": 0,+ "injured": 54,+ "lightly_injured": 99,+ "kills": 121+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 25,+ "displayed_kills": 2+ }+ },+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 19,+ "displayed_kills": 89+ },+ "Armor of Barnacles": {+ "triggered": 14,+ "displayed_kills": null+ }+ },+ "Gatot": {+ "King's Bestowal": {+ "triggered": 37,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 29,+ "displayed_kills": 11+ },+ "Torrential Impact": {+ "triggered": 11,+ "displayed_kills": 14+ }+ },+ "Gatot": {+ "King's Bestowal": {+ "triggered": 58,+ "displayed_kills": null+ }+ },+ "Hendrik": {+ "Armor of Barnacles": {+ "triggered": 14,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gordon_interactions_20260925/gordon_wayne_1200l_vs_4800l.json===================================================================--- testcases/emulator_verified/gordon_interactions_20260925/gordon_wayne_1200l_vs_4800l.json prev run+++ testcases/emulator_verified/gordon_interactions_20260925/gordon_wayne_1200l_vs_4800l.json this run@@ -0,0 +1,158 @@+[+ {+ "test_id": "gordon_wayne_1200l_vs_4800l",+ "description": "C2 battle report 2734693171342597",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ },+ "Wayne": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1200+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 493.62,+ "defense": 487.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 426.39,+ "defense": 422.39,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t6": 4800+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T06:14:41.000Z",+ "randomseed": 1790316882,+ "attacker": 0,+ "defender": 313,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171342597",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T06-14-57.221Z-3bf37809-1abc-47ba-b785-c77cc590787c.json",+ "winner": "defender",+ "attacker": {+ "troops": 1200,+ "survivors": 0,+ "losses": 0,+ "injured": 420,+ "lightly_injured": 780,+ "kills": 1571+ },+ "defender": {+ "troops": 4800,+ "survivors": 313,+ "losses": 0,+ "injured": 1571,+ "lightly_injured": 2916,+ "kills": 420+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1200,+ "survivors": 0,+ "losses": 0,+ "injured": 420,+ "lightly_injured": 780,+ "kills": 1571+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 4800,+ "survivors": 313,+ "losses": 0,+ "injured": 1571,+ "lightly_injured": 2916,+ "kills": 420+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ },+ "Thunder Strike": {+ "triggered": 16,+ "displayed_kills": 115+ }+ },+ "Gordon": {+ "Toxic Release": {+ "triggered": 16,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 32,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 21,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gordon_interactions_20260925/gordon_wayne_800l_vs_3200l.json===================================================================--- testcases/emulator_verified/gordon_interactions_20260925/gordon_wayne_800l_vs_3200l.json prev run+++ testcases/emulator_verified/gordon_interactions_20260925/gordon_wayne_800l_vs_3200l.json this run@@ -0,0 +1,158 @@+[+ {+ "test_id": "gordon_wayne_800l_vs_3200l",+ "description": "C2 battle report 2734693171342685",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ },+ "Wayne": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 800+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 493.62,+ "defense": 487.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 426.39,+ "defense": 422.39,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t6": 3200+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T06:21:27.000Z",+ "randomseed": 1790317288,+ "attacker": 0,+ "defender": 207,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171342685",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T06-21-43.168Z-a2ec92c0-70f6-46df-87e5-9726a2d79078.json",+ "winner": "defender",+ "attacker": {+ "troops": 800,+ "survivors": 0,+ "losses": 0,+ "injured": 280,+ "lightly_injured": 520,+ "kills": 1048+ },+ "defender": {+ "troops": 3200,+ "survivors": 207,+ "losses": 0,+ "injured": 1048,+ "lightly_injured": 1945,+ "kills": 280+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 800,+ "survivors": 0,+ "losses": 0,+ "injured": 280,+ "lightly_injured": 520,+ "kills": 1048+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 3200,+ "survivors": 207,+ "losses": 0,+ "injured": 1048,+ "lightly_injured": 1945,+ "kills": 280+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ },+ "Thunder Strike": {+ "triggered": 16,+ "displayed_kills": 77+ }+ },+ "Gordon": {+ "Toxic Release": {+ "triggered": 16,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 32,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 21,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gordon_interactions_20260925/wayne_control_1000l_vs_1700l.json===================================================================--- testcases/emulator_verified/gordon_interactions_20260925/wayne_control_1000l_vs_1700l.json prev run+++ testcases/emulator_verified/gordon_interactions_20260925/wayne_control_1000l_vs_1700l.json this run@@ -0,0 +1,138 @@+[+ {+ "test_id": "wayne_control_1000l_vs_1700l",+ "description": "C2 battle report 2734693171342643",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Wayne": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 426.39,+ "defense": 422.39,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t6": 1700+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T06:16:54.000Z",+ "randomseed": 1790317015,+ "attacker": 0,+ "defender": 21,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171342643",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T06-17-10.150Z-1d7cb8fe-496f-4f61-86aa-a9b8c7c42f6d.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 588+ },+ "defender": {+ "troops": 1700,+ "survivors": 21,+ "losses": 0,+ "injured": 588,+ "lightly_injured": 1091,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 588+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 1700,+ "survivors": 21,+ "losses": 0,+ "injured": 588,+ "lightly_injured": 1091,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ },+ "Thunder Strike": {+ "triggered": 16,+ "displayed_kills": 51+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gordon_isolation_20260925/gordon_solo_1329l_vs_5000l.json===================================================================--- testcases/emulator_verified/gordon_isolation_20260925/gordon_solo_1329l_vs_5000l.json prev run+++ testcases/emulator_verified/gordon_isolation_20260925/gordon_solo_1329l_vs_5000l.json this run@@ -0,0 +1,143 @@+[+ {+ "test_id": "gordon_solo_1329l_vs_5000l",+ "description": "C2 battle report 2734693171341664",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1329+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 493.62,+ "defense": 487.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t6": 5000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T05:14:22.000Z",+ "randomseed": 1790313263,+ "attacker": 0,+ "defender": 48,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171341664",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T05-14-38.197Z-8d1d14e8-8e60-4737-ac95-88710595908c.json",+ "winner": "defender",+ "attacker": {+ "troops": 1329,+ "survivors": 0,+ "losses": 0,+ "injured": 466,+ "lightly_injured": 863,+ "kills": 1734+ },+ "defender": {+ "troops": 5000,+ "survivors": 48,+ "losses": 0,+ "injured": 1734,+ "lightly_injured": 3218,+ "kills": 466+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1329,+ "survivors": 0,+ "losses": 0,+ "injured": 466,+ "lightly_injured": 863,+ "kills": 1734+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 5000,+ "survivors": 48,+ "losses": 0,+ "injured": 1734,+ "lightly_injured": 3218,+ "kills": 466+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gordon": {+ "Toxic Release": {+ "triggered": 18,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 37,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 24,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gordon_isolation_20260925/gordon_solo_180l_vs_700l.json===================================================================--- testcases/emulator_verified/gordon_isolation_20260925/gordon_solo_180l_vs_700l.json prev run+++ testcases/emulator_verified/gordon_isolation_20260925/gordon_solo_180l_vs_700l.json this run@@ -0,0 +1,143 @@+[+ {+ "test_id": "gordon_solo_180l_vs_700l",+ "description": "C2 battle report 2734693171341527",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 180+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 493.62,+ "defense": 487.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t6": 700+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T05:08:41.000Z",+ "randomseed": 1790312922,+ "attacker": 0,+ "defender": 87,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171341527",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T05-08-57.209Z-36d9e066-50bd-4705-a318-219ee52b9cde.json",+ "winner": "defender",+ "attacker": {+ "troops": 180,+ "survivors": 0,+ "losses": 0,+ "injured": 63,+ "lightly_injured": 117,+ "kills": 215+ },+ "defender": {+ "troops": 700,+ "survivors": 87,+ "losses": 0,+ "injured": 215,+ "lightly_injured": 398,+ "kills": 63+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 180,+ "survivors": 0,+ "losses": 0,+ "injured": 63,+ "lightly_injured": 117,+ "kills": 215+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 700,+ "survivors": 87,+ "losses": 0,+ "injured": 215,+ "lightly_injured": 398,+ "kills": 63+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gordon": {+ "Toxic Release": {+ "triggered": 15,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 30,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 20,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gordon_isolation_20260925/gordon_solo_1860l_vs_7000l.json===================================================================--- testcases/emulator_verified/gordon_isolation_20260925/gordon_solo_1860l_vs_7000l.json prev run+++ testcases/emulator_verified/gordon_isolation_20260925/gordon_solo_1860l_vs_7000l.json this run@@ -0,0 +1,143 @@+[+ {+ "test_id": "gordon_solo_1860l_vs_7000l",+ "description": "C2 battle report 2734693171341599",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1860+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 493.62,+ "defense": 487.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t6": 7000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T05:11:58.000Z",+ "randomseed": 1790313119,+ "attacker": 0,+ "defender": 87,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171341599",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T05-12-14.175Z-267a9f20-5b01-4fc0-bd80-6897148d3bc3.json",+ "winner": "defender",+ "attacker": {+ "troops": 1860,+ "survivors": 0,+ "losses": 0,+ "injured": 651,+ "lightly_injured": 1209,+ "kills": 2420+ },+ "defender": {+ "troops": 7000,+ "survivors": 87,+ "losses": 0,+ "injured": 2420,+ "lightly_injured": 4493,+ "kills": 651+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1860,+ "survivors": 0,+ "losses": 0,+ "injured": 651,+ "lightly_injured": 1209,+ "kills": 2420+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 7000,+ "survivors": 87,+ "losses": 0,+ "injured": 2420,+ "lightly_injured": 4493,+ "kills": 651+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gordon": {+ "Toxic Release": {+ "triggered": 18,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 36,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 24,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gordon_isolation_20260925/nohero_300l_vs_600l.json===================================================================--- testcases/emulator_verified/gordon_isolation_20260925/nohero_300l_vs_600l.json prev run+++ testcases/emulator_verified/gordon_isolation_20260925/nohero_300l_vs_600l.json this run@@ -0,0 +1,121 @@+[+ {+ "test_id": "nohero_300l_vs_600l",+ "description": "C2 battle report 2734693171341609",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t6": 600+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T05:13:14.000Z",+ "randomseed": 1790313195,+ "attacker": 0,+ "defender": 255,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171341609",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T05-13-30.230Z-95c8ccc6-056c-4a9b-be3e-bf585dba13a8.json",+ "winner": "defender",+ "attacker": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 121+ },+ "defender": {+ "troops": 600,+ "survivors": 255,+ "losses": 0,+ "injured": 121,+ "lightly_injured": 224,+ "kills": 105+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 121+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 600,+ "survivors": 255,+ "losses": 0,+ "injured": 121,+ "lightly_injured": 224,+ "kills": 105+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_blastmaster_replay_550m_vs_810i_45l_45m.json===================================================================--- testcases/emulator_verified/gwen_blastmaster_replay_550m_vs_810i_45l_45m.json prev run+++ testcases/emulator_verified/gwen_blastmaster_replay_550m_vs_810i_45l_45m.json this run@@ -0,0 +1,98 @@+[+ {+ "test_id": "gwen_blastmaster_replay_550m_vs_810i_45l_45m",+ "description": "Fresh full-kit Gwen 3/1/1 replay investigating the deterministic Blastmaster cadence discrepancy; both participants and current report stats verified during capture.",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1+ }+ },+ "troops": {+ "marksman_t6": 550+ },+ "stats": {+ "inf": {+ "attack": 305.0,+ "defense": 288.0,+ "lethality": 254.0,+ "health": 238.4+ },+ "lanc": {+ "attack": 286.9,+ "defense": 281.2,+ "lethality": 234.3,+ "health": 230.0+ },+ "mark": {+ "attack": 439.8,+ "defense": 435.8,+ "lethality": 245.8,+ "health": 230.3+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 810,+ "lancer_t6": 45,+ "marksman_t6": 45+ },+ "stats": {+ "inf": {+ "attack": 257.1,+ "defense": 249.7,+ "lethality": 196.5,+ "health": 192.0+ },+ "lanc": {+ "attack": 208.7,+ "defense": 208.0,+ "lethality": 197.0,+ "health": 186.1+ },+ "mark": {+ "attack": 231.0,+ "defense": 219.8,+ "lethality": 191.5,+ "health": 177.2+ }+ },+ "joiner_heroes": {}+ },+ "game_report_result": [+ {+ "attacker": 0,+ "defender": 172,+ "metadata": {+ "source": "emulator",+ "report_timestamp_displayed": "2026-09-21 10:36:45",+ "world_coord": { "x": 791, "y": 577 },+ "winner": "defender",+ "stat_units": "percentage_points",+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Eagle Vision": { "triggered": 1, "displayed_kills": null },+ "Air Dominance": { "triggered": 10, "displayed_kills": 7 },+ "Blastmaster": { "triggered": 13, "displayed_kills": 32 }+ }+ }+ },+ "evidence": {+ "overview": "../../docs/mechanics-audit/reviews/attack-target-2026-09-21/gwen-overview.png",+ "stats": "../../docs/mechanics-audit/reviews/attack-target-2026-09-21/gwen-stats.png",+ "skill_counters": "../../docs/mechanics-audit/reviews/attack-target-2026-09-21/gwen-skill-counters.png",+ "parsed_report": "../../docs/mechanics-audit/reviews/attack-target-2026-09-21/gwen-report.json"+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_c2_twenty/ahmose_gordon_gwen_vs_gatot_patrick_hendrik.json===================================================================--- testcases/emulator_verified/gwen_c2_twenty/ahmose_gordon_gwen_vs_gatot_patrick_hendrik.json prev run+++ testcases/emulator_verified/gwen_c2_twenty/ahmose_gordon_gwen_vs_gatot_patrick_hendrik.json this run@@ -0,0 +1,225 @@+[+ {+ "test_id": "ahmose_gordon_gwen_vs_gatot_patrick_hendrik",+ "description": "C2 battle report 2734693171109692",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ },+ "Gordon": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 302,+ "lancer_t6": 340,+ "marksman_t6": 392+ },+ "stats": {+ "infantry": {+ "attack": 345.57,+ "defense": 338.12,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 364.09,+ "defense": 363.39,+ "lethality": 191.83,+ "health": 190.89+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gatot": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Patrick": {+ "skill_1": 3,+ "skill_2": 2+ },+ "Hendrik": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 257,+ "lancer_t6": 337,+ "marksman_t6": 230+ },+ "stats": {+ "infantry": {+ "attack": 670.13,+ "defense": 663.13,+ "lethality": 316.11,+ "health": 338.06+ },+ "lancer": {+ "attack": 391.69,+ "defense": 395.94,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 444.21,+ "defense": 450.21,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-21T22:32:54.000Z",+ "randomseed": 1790029975,+ "attacker": 0,+ "defender": 764,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171109692",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-21T22-33-22.264Z-9fe5f826-92fd-4ad5-b6d2-13a330adb2ee.json",+ "winner": "defender",+ "attacker": {+ "troops": 1034,+ "survivors": 0,+ "losses": 0,+ "injured": 363,+ "lightly_injured": 671,+ "kills": 21+ },+ "defender": {+ "troops": 824,+ "survivors": 764,+ "losses": 0,+ "injured": 21,+ "lightly_injured": 39,+ "kills": 363+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 302,+ "survivors": 0,+ "losses": 0,+ "injured": 106,+ "lightly_injured": 196,+ "kills": 0+ },+ "lancer_t6": {+ "troops": 340,+ "survivors": 0,+ "losses": 0,+ "injured": 119,+ "lightly_injured": 221,+ "kills": 3+ },+ "marksman_t6": {+ "troops": 392,+ "survivors": 0,+ "losses": 0,+ "injured": 138,+ "lightly_injured": 254,+ "kills": 18+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 257,+ "survivors": 197,+ "losses": 0,+ "injured": 21,+ "lightly_injured": 39,+ "kills": 75+ },+ "lancer_t6": {+ "troops": 337,+ "survivors": 337,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 133+ },+ "marksman_t6": {+ "troops": 230,+ "survivors": 230,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 155+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 9,+ "displayed_kills": 1+ }+ },+ "Ahmose": {+ "Viper Formation": {+ "triggered": 3,+ "displayed_kills": null+ }+ },+ "Gordon": {+ "Venom Infusion": {+ "triggered": 10,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 8,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Gatot": {+ "King's Bestowal": {+ "triggered": 26,+ "displayed_kills": null+ }+ },+ "Hendrik": {+ "Armor of Barnacles": {+ "triggered": 6,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_c2_twenty/ahmose_renee_gwen_vs_sergey_patrick_hendrik.json===================================================================--- testcases/emulator_verified/gwen_c2_twenty/ahmose_renee_gwen_vs_sergey_patrick_hendrik.json prev run+++ testcases/emulator_verified/gwen_c2_twenty/ahmose_renee_gwen_vs_sergey_patrick_hendrik.json this run@@ -0,0 +1,225 @@+[+ {+ "test_id": "ahmose_renee_gwen_vs_sergey_patrick_hendrik",+ "description": "C2 battle report 2734693171109795",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 221,+ "lancer_t6": 259,+ "marksman_t6": 311+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 607.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Sergey": {+ "skill_1": 2,+ "skill_2": 2+ },+ "Patrick": {+ "skill_1": 4,+ "skill_2": 4+ },+ "Hendrik": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 377,+ "lancer_t6": 256,+ "marksman_t6": 350+ },+ "stats": {+ "infantry": {+ "attack": 346.14,+ "defense": 338.69,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 293.2,+ "defense": 292.5,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 479,+ "defense": 467.8,+ "lethality": 244.2,+ "health": 221.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-21T22:46:34.000Z",+ "randomseed": 1790030795,+ "attacker": 0,+ "defender": 252,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171109795",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-21T22-46-51.115Z-443535a5-97f8-4b8d-8b23-1cdba2bfbb5c.json",+ "winner": "defender",+ "attacker": {+ "troops": 791,+ "survivors": 0,+ "losses": 0,+ "injured": 278,+ "lightly_injured": 513,+ "kills": 257+ },+ "defender": {+ "troops": 983,+ "survivors": 252,+ "losses": 0,+ "injured": 257,+ "lightly_injured": 474,+ "kills": 278+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 221,+ "survivors": 0,+ "losses": 0,+ "injured": 78,+ "lightly_injured": 143,+ "kills": 8+ },+ "lancer_t6": {+ "troops": 259,+ "survivors": 0,+ "losses": 0,+ "injured": 91,+ "lightly_injured": 168,+ "kills": 99+ },+ "marksman_t6": {+ "troops": 311,+ "survivors": 0,+ "losses": 0,+ "injured": 109,+ "lightly_injured": 202,+ "kills": 150+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 377,+ "survivors": 0,+ "losses": 0,+ "injured": 132,+ "lightly_injured": 245,+ "kills": 7+ },+ "lancer_t6": {+ "troops": 256,+ "survivors": 0,+ "losses": 0,+ "injured": 90,+ "lightly_injured": 166,+ "kills": 33+ },+ "marksman_t6": {+ "troops": 350,+ "survivors": 252,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 63,+ "kills": 238+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 8,+ "displayed_kills": 5+ },+ "Blastmaster": {+ "triggered": 5,+ "displayed_kills": 5+ }+ },+ "Ahmose": {+ "Viper Formation": {+ "triggered": 2,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 13,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 9,+ "displayed_kills": 46+ },+ "Armor of Barnacles": {+ "triggered": 6,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_c2_twenty/edith_patrick_gwen_vs_ahmose_renee_bradley.json===================================================================--- testcases/emulator_verified/gwen_c2_twenty/edith_patrick_gwen_vs_ahmose_renee_bradley.json prev run+++ testcases/emulator_verified/gwen_c2_twenty/edith_patrick_gwen_vs_ahmose_renee_bradley.json this run@@ -0,0 +1,222 @@+[+ {+ "test_id": "edith_patrick_gwen_vs_ahmose_renee_bradley",+ "description": "C2 battle report 2734693171109940",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Edith": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Patrick": {+ "skill_1": 3,+ "skill_2": 2+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 362,+ "lancer_t6": 400,+ "marksman_t6": 251+ },+ "stats": {+ "infantry": {+ "attack": 521.6,+ "defense": 514.6,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 391.69,+ "defense": 395.94,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ },+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Bradley": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 1+ }+ },+ "troops": {+ "infantry_t6": 317,+ "lancer_t6": 397,+ "marksman_t6": 290+ },+ "stats": {+ "infantry": {+ "attack": 345.57,+ "defense": 338.12,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 681.96,+ "defense": 670.76,+ "lethality": 322.27,+ "health": 273.25+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-21T22:58:10.000Z",+ "randomseed": 1790031491,+ "attacker": 0,+ "defender": 461,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171109940",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-21T22-58-27.117Z-51ecb336-999c-4119-b6ea-2ac7e5b0babc.json",+ "winner": "defender",+ "attacker": {+ "troops": 1013,+ "survivors": 0,+ "losses": 0,+ "injured": 355,+ "lightly_injured": 658,+ "kills": 191+ },+ "defender": {+ "troops": 1004,+ "survivors": 461,+ "losses": 0,+ "injured": 191,+ "lightly_injured": 352,+ "kills": 355+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 362,+ "survivors": 0,+ "losses": 0,+ "injured": 127,+ "lightly_injured": 235,+ "kills": 11+ },+ "lancer_t6": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 69+ },+ "marksman_t6": {+ "troops": 251,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 163,+ "kills": 111+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 317,+ "survivors": 0,+ "losses": 0,+ "injured": 111,+ "lightly_injured": 206,+ "kills": 5+ },+ "lancer_t6": {+ "troops": 397,+ "survivors": 176,+ "losses": 0,+ "injured": 78,+ "lightly_injured": 143,+ "kills": 135+ },+ "marksman_t6": {+ "troops": 290,+ "survivors": 285,+ "losses": 0,+ "injured": 2,+ "lightly_injured": 3,+ "kills": 215+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 7,+ "displayed_kills": 4+ },+ "Blastmaster": {+ "triggered": 3,+ "displayed_kills": 4+ }+ }+ },+ "defender": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 2,+ "displayed_kills": null+ }+ },+ "Bradley": {+ "Tactical Assistance": {+ "triggered": 4,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 9,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_c2_twenty/flint_patrick_gwen_vs_ahmose_renee_jasser.json===================================================================--- testcases/emulator_verified/gwen_c2_twenty/flint_patrick_gwen_vs_ahmose_renee_jasser.json prev run+++ testcases/emulator_verified/gwen_c2_twenty/flint_patrick_gwen_vs_ahmose_renee_jasser.json this run@@ -0,0 +1,209 @@+[+ {+ "test_id": "flint_patrick_gwen_vs_ahmose_renee_jasser",+ "description": "C2 battle report 2734693171109744",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Flint": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ },+ "Patrick": {+ "skill_1": 4,+ "skill_2": 4+ },+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 242,+ "lancer_t6": 280,+ "marksman_t6": 332+ },+ "stats": {+ "infantry": {+ "attack": 326.34,+ "defense": 318.89,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 293.2,+ "defense": 292.5,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Jasser": {+ "skill_1": 4,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 398,+ "lancer_t6": 277,+ "marksman_t6": 371+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 607.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 354.37,+ "defense": 360.37,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-21T22:37:44.000Z",+ "randomseed": 1790030265,+ "attacker": 0,+ "defender": 917,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171109744",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-21T22-38-12.117Z-1c4565ff-8a6b-4e3e-a6e4-9865a6a47c42.json",+ "winner": "defender",+ "attacker": {+ "troops": 854,+ "survivors": 0,+ "losses": 0,+ "injured": 300,+ "lightly_injured": 554,+ "kills": 46+ },+ "defender": {+ "troops": 1046,+ "survivors": 917,+ "losses": 0,+ "injured": 46,+ "lightly_injured": 83,+ "kills": 300+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 242,+ "survivors": 0,+ "losses": 0,+ "injured": 85,+ "lightly_injured": 157,+ "kills": 2+ },+ "lancer_t6": {+ "troops": 280,+ "survivors": 0,+ "losses": 0,+ "injured": 98,+ "lightly_injured": 182,+ "kills": 14+ },+ "marksman_t6": {+ "troops": 332,+ "survivors": 0,+ "losses": 0,+ "injured": 117,+ "lightly_injured": 215,+ "kills": 30+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 398,+ "survivors": 269,+ "losses": 0,+ "injured": 46,+ "lightly_injured": 83,+ "kills": 41+ },+ "lancer_t6": {+ "troops": 277,+ "survivors": 277,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 151+ },+ "marksman_t6": {+ "troops": 371,+ "survivors": 371,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 108+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 3,+ "displayed_kills": 1+ }+ }+ },+ "defender": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 2,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 5,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_c2_twenty/gatot_renee_gwen_vs_sergey_sonya_wayne.json===================================================================--- testcases/emulator_verified/gwen_c2_twenty/gatot_renee_gwen_vs_sergey_sonya_wayne.json prev run+++ testcases/emulator_verified/gwen_c2_twenty/gatot_renee_gwen_vs_sergey_sonya_wayne.json this run@@ -0,0 +1,231 @@+[+ {+ "test_id": "gatot_renee_gwen_vs_sergey_sonya_wayne",+ "description": "C2 battle report 2734693171109665",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gatot": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 349,+ "lancer_t6": 387,+ "marksman_t6": 238+ },+ "stats": {+ "infantry": {+ "attack": 627.31,+ "defense": 619.86,+ "lethality": 230.66,+ "health": 281.02+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Sergey": {+ "skill_1": 4,+ "skill_2": 4+ },+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ },+ "Wayne": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 304,+ "lancer_t6": 384,+ "marksman_t6": 277+ },+ "stats": {+ "infantry": {+ "attack": 409.72,+ "defense": 402.72,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 529.96,+ "defense": 534.21,+ "lethality": 323.16,+ "health": 285.53+ },+ "marksman": {+ "attack": 421.39,+ "defense": 427.39,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-21T22:31:00.000Z",+ "randomseed": 1790029861,+ "attacker": 744,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171109665",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-21T22-31-28.112Z-bf1315a8-7d67-484e-bc96-42abbb15d173.json",+ "winner": "attacker",+ "attacker": {+ "troops": 974,+ "survivors": 744,+ "losses": 0,+ "injured": 81,+ "lightly_injured": 149,+ "kills": 339+ },+ "defender": {+ "troops": 965,+ "survivors": 0,+ "losses": 0,+ "injured": 339,+ "lightly_injured": 626,+ "kills": 81+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 349,+ "survivors": 161,+ "losses": 0,+ "injured": 66,+ "lightly_injured": 122,+ "kills": 40+ },+ "lancer_t6": {+ "troops": 387,+ "survivors": 367,+ "losses": 0,+ "injured": 7,+ "lightly_injured": 13,+ "kills": 207+ },+ "marksman_t6": {+ "troops": 238,+ "survivors": 216,+ "losses": 0,+ "injured": 8,+ "lightly_injured": 14,+ "kills": 92+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 304,+ "survivors": 0,+ "losses": 0,+ "injured": 107,+ "lightly_injured": 197,+ "kills": 0+ },+ "lancer_t6": {+ "troops": 384,+ "survivors": 0,+ "losses": 0,+ "injured": 135,+ "lightly_injured": 249,+ "kills": 29+ },+ "marksman_t6": {+ "troops": 277,+ "survivors": 0,+ "losses": 0,+ "injured": 97,+ "lightly_injured": 180,+ "kills": 52+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 13,+ "displayed_kills": 7+ }+ },+ "Gatot": {+ "King's Bestowal": {+ "triggered": 26,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 15,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 13,+ "displayed_kills": 2+ },+ "Torrential Impact": {+ "triggered": 5,+ "displayed_kills": 3+ }+ },+ "Wayne": {+ "Thunder Strike": {+ "triggered": 17,+ "displayed_kills": 5+ },+ "Roundabout Hit": {+ "triggered": 15,+ "displayed_kills": 14+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_c2_twenty/gatot_sonya_gwen_vs_edith_gordon_bradley.json===================================================================--- testcases/emulator_verified/gwen_c2_twenty/gatot_sonya_gwen_vs_edith_gordon_bradley.json prev run+++ testcases/emulator_verified/gwen_c2_twenty/gatot_sonya_gwen_vs_edith_gordon_bradley.json this run@@ -0,0 +1,237 @@+[+ {+ "test_id": "gatot_sonya_gwen_vs_edith_gordon_bradley",+ "description": "C2 battle report 2734693171109854",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gatot": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 268,+ "lancer_t6": 306,+ "marksman_t6": 358+ },+ "stats": {+ "infantry": {+ "attack": 670.13,+ "defense": 663.13,+ "lethality": 316.11,+ "health": 338.06+ },+ "lancer": {+ "attack": 529.96,+ "defense": 534.21,+ "lethality": 323.16,+ "health": 285.53+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Edith": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ },+ "Gordon": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ },+ "Bradley": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 1+ }+ },+ "troops": {+ "infantry_t6": 223,+ "lancer_t6": 303,+ "marksman_t6": 397+ },+ "stats": {+ "infantry": {+ "attack": 401.82,+ "defense": 394.37,+ "lethality": 193.33,+ "health": 198.83+ },+ "lancer": {+ "attack": 364.09,+ "defense": 363.39,+ "lethality": 191.83,+ "health": 190.89+ },+ "marksman": {+ "attack": 681.96,+ "defense": 670.76,+ "lethality": 322.27,+ "health": 273.25+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-21T22:51:47.000Z",+ "randomseed": 1790031108,+ "attacker": 743,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171109854",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-21T22-52-04.127Z-975a0b21-a192-49d6-8c21-cc9b20548611.json",+ "winner": "attacker",+ "attacker": {+ "troops": 932,+ "survivors": 743,+ "losses": 0,+ "injured": 67,+ "lightly_injured": 122,+ "kills": 325+ },+ "defender": {+ "troops": 923,+ "survivors": 0,+ "losses": 0,+ "injured": 325,+ "lightly_injured": 598,+ "kills": 67+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 268,+ "survivors": 79,+ "losses": 0,+ "injured": 67,+ "lightly_injured": 122,+ "kills": 39+ },+ "lancer_t6": {+ "troops": 306,+ "survivors": 306,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 162+ },+ "marksman_t6": {+ "troops": 358,+ "survivors": 358,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 124+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 223,+ "survivors": 0,+ "losses": 0,+ "injured": 79,+ "lightly_injured": 144,+ "kills": 0+ },+ "lancer_t6": {+ "troops": 303,+ "survivors": 0,+ "losses": 0,+ "injured": 107,+ "lightly_injured": 196,+ "kills": 7+ },+ "marksman_t6": {+ "troops": 397,+ "survivors": 0,+ "losses": 0,+ "injured": 139,+ "lightly_injured": 258,+ "kills": 60+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 10,+ "displayed_kills": 8+ },+ "Torrential Impact": {+ "triggered": 4,+ "displayed_kills": 16+ }+ },+ "Gwen": {+ "Blastmaster": {+ "triggered": 3,+ "displayed_kills": 4+ },+ "Air Dominance": {+ "triggered": 9,+ "displayed_kills": 8+ }+ },+ "Gatot": {+ "King's Bestowal": {+ "triggered": 21,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Gordon": {+ "Venom Infusion": {+ "triggered": 6,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 7,+ "displayed_kills": null+ }+ },+ "Bradley": {+ "Tactical Assistance": {+ "triggered": 5,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_c2_twenty/gwen_vs_ahmose.json===================================================================--- testcases/emulator_verified/gwen_c2_twenty/gwen_vs_ahmose.json prev run+++ testcases/emulator_verified/gwen_c2_twenty/gwen_vs_ahmose.json this run@@ -0,0 +1,188 @@+[+ {+ "test_id": "gwen_vs_ahmose",+ "description": "C2 battle report 2734693171109662",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 341,+ "lancer_t6": 379,+ "marksman_t6": 230+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 296,+ "lancer_t6": 376,+ "marksman_t6": 269+ },+ "stats": {+ "infantry": {+ "attack": 345.57,+ "defense": 338.12,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-21T22:30:46.000Z",+ "randomseed": 1790029847,+ "attacker": 738,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171109662",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-21T22-31-03.121Z-46ea4b77-3e2d-48be-b483-c9d514d772f4.json",+ "winner": "attacker",+ "attacker": {+ "troops": 950,+ "survivors": 738,+ "losses": 0,+ "injured": 75,+ "lightly_injured": 137,+ "kills": 331+ },+ "defender": {+ "troops": 941,+ "survivors": 0,+ "losses": 0,+ "injured": 331,+ "lightly_injured": 610,+ "kills": 75+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 341,+ "survivors": 129,+ "losses": 0,+ "injured": 75,+ "lightly_injured": 137,+ "kills": 32+ },+ "lancer_t6": {+ "troops": 379,+ "survivors": 379,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 126+ },+ "marksman_t6": {+ "troops": 230,+ "survivors": 230,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 173+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 296,+ "survivors": 0,+ "losses": 0,+ "injured": 104,+ "lightly_injured": 192,+ "kills": 6+ },+ "lancer_t6": {+ "troops": 376,+ "survivors": 0,+ "losses": 0,+ "injured": 132,+ "lightly_injured": 244,+ "kills": 28+ },+ "marksman_t6": {+ "troops": 269,+ "survivors": 0,+ "losses": 0,+ "injured": 95,+ "lightly_injured": 174,+ "kills": 41+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 11,+ "displayed_kills": 8+ },+ "Blastmaster": {+ "triggered": 4,+ "displayed_kills": 12+ }+ }+ },+ "defender": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 3,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_c2_twenty/gwen_vs_bradley.json===================================================================--- testcases/emulator_verified/gwen_c2_twenty/gwen_vs_bradley.json prev run+++ testcases/emulator_verified/gwen_c2_twenty/gwen_vs_bradley.json this run@@ -0,0 +1,189 @@+[+ {+ "test_id": "gwen_vs_bradley",+ "description": "C2 battle report 2734693171109763",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 375,+ "lancer_t6": 212,+ "marksman_t6": 264+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Bradley": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 1+ }+ },+ "troops": {+ "infantry_t6": 330,+ "lancer_t6": 209,+ "marksman_t6": 303+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 681.96,+ "defense": 670.76,+ "lethality": 322.27,+ "health": 273.25+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-21T22:43:05.000Z",+ "randomseed": 1790030586,+ "attacker": 0,+ "defender": 502,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171109763",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-21T22-43-22.124Z-0a665ace-25f4-423b-ad5f-f952b37f55f0.json",+ "winner": "defender",+ "attacker": {+ "troops": 851,+ "survivors": 0,+ "losses": 0,+ "injured": 300,+ "lightly_injured": 551,+ "kills": 121+ },+ "defender": {+ "troops": 842,+ "survivors": 502,+ "losses": 0,+ "injured": 121,+ "lightly_injured": 219,+ "kills": 300+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 375,+ "survivors": 0,+ "losses": 0,+ "injured": 132,+ "lightly_injured": 243,+ "kills": 9+ },+ "lancer_t6": {+ "troops": 212,+ "survivors": 0,+ "losses": 0,+ "injured": 75,+ "lightly_injured": 137,+ "kills": 26+ },+ "marksman_t6": {+ "troops": 264,+ "survivors": 0,+ "losses": 0,+ "injured": 93,+ "lightly_injured": 171,+ "kills": 86+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 330,+ "survivors": 6,+ "losses": 0,+ "injured": 114,+ "lightly_injured": 210,+ "kills": 10+ },+ "lancer_t6": {+ "troops": 209,+ "survivors": 197,+ "losses": 0,+ "injured": 5,+ "lightly_injured": 7,+ "kills": 45+ },+ "marksman_t6": {+ "troops": 303,+ "survivors": 299,+ "losses": 0,+ "injured": 2,+ "lightly_injured": 2,+ "kills": 245+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 5,+ "displayed_kills": 2+ },+ "Blastmaster": {+ "triggered": 3,+ "displayed_kills": 7+ }+ }+ },+ "defender": {+ "Bradley": {+ "Tactical Assistance": {+ "triggered": 4,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_c2_twenty/gwen_vs_flint_jessie_wayne.json===================================================================--- testcases/emulator_verified/gwen_c2_twenty/gwen_vs_flint_jessie_wayne.json prev run+++ testcases/emulator_verified/gwen_c2_twenty/gwen_vs_flint_jessie_wayne.json this run@@ -0,0 +1,197 @@+[+ {+ "test_id": "gwen_vs_flint_jessie_wayne",+ "description": "C2 battle report 2734693171109628",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 208,+ "lancer_t6": 246,+ "marksman_t6": 298+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Flint": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 1,+ "skill_4": 0+ },+ "Jessie": {+ "skill_1": 5,+ "skill_2": 5+ },+ "Wayne": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 364,+ "lancer_t6": 243,+ "marksman_t6": 337+ },+ "stats": {+ "infantry": {+ "attack": 398.37,+ "defense": 391.37,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 391.69,+ "defense": 395.94,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 421.39,+ "defense": 427.39,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-21T22:26:45.000Z",+ "randomseed": 1790029606,+ "attacker": 0,+ "defender": 875,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171109628",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-21T22-27-13.118Z-c477820f-ed56-4d7c-a7cd-93141be5ae8a.json",+ "winner": "defender",+ "attacker": {+ "troops": 752,+ "survivors": 0,+ "losses": 0,+ "injured": 265,+ "lightly_injured": 487,+ "kills": 25+ },+ "defender": {+ "troops": 944,+ "survivors": 875,+ "losses": 0,+ "injured": 25,+ "lightly_injured": 44,+ "kills": 265+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 208,+ "survivors": 0,+ "losses": 0,+ "injured": 73,+ "lightly_injured": 135,+ "kills": 0+ },+ "lancer_t6": {+ "troops": 246,+ "survivors": 0,+ "losses": 0,+ "injured": 87,+ "lightly_injured": 159,+ "kills": 5+ },+ "marksman_t6": {+ "troops": 298,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 193,+ "kills": 20+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 364,+ "survivors": 295,+ "losses": 0,+ "injured": 25,+ "lightly_injured": 44,+ "kills": 50+ },+ "lancer_t6": {+ "troops": 243,+ "survivors": 243,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 87+ },+ "marksman_t6": {+ "troops": 337,+ "survivors": 337,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 128+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 3,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Wayne": {+ "Roundabout Hit": {+ "triggered": 5,+ "displayed_kills": 9+ },+ "Thunder Strike": {+ "triggered": 6,+ "displayed_kills": 12+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_c2_twenty/gwen_vs_gatot.json===================================================================--- testcases/emulator_verified/gwen_c2_twenty/gwen_vs_gatot.json prev run+++ testcases/emulator_verified/gwen_c2_twenty/gwen_vs_gatot.json this run@@ -0,0 +1,189 @@+[+ {+ "test_id": "gwen_vs_gatot",+ "description": "C2 battle report 2734693171109689",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 388,+ "lancer_t6": 225,+ "marksman_t6": 277+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gatot": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 343,+ "lancer_t6": 222,+ "marksman_t6": 316+ },+ "stats": {+ "infantry": {+ "attack": 627.31,+ "defense": 619.86,+ "lethality": 230.66,+ "health": 281.02+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-21T22:32:40.000Z",+ "randomseed": 1790029961,+ "attacker": 0,+ "defender": 660,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171109689",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-21T22-32-57.117Z-12de6902-a18b-40f7-b312-d7f405b624ae.json",+ "winner": "defender",+ "attacker": {+ "troops": 890,+ "survivors": 0,+ "losses": 0,+ "injured": 312,+ "lightly_injured": 578,+ "kills": 78+ },+ "defender": {+ "troops": 881,+ "survivors": 660,+ "losses": 0,+ "injured": 78,+ "lightly_injured": 143,+ "kills": 312+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 388,+ "survivors": 0,+ "losses": 0,+ "injured": 136,+ "lightly_injured": 252,+ "kills": 1+ },+ "lancer_t6": {+ "troops": 225,+ "survivors": 0,+ "losses": 0,+ "injured": 79,+ "lightly_injured": 146,+ "kills": 0+ },+ "marksman_t6": {+ "troops": 277,+ "survivors": 0,+ "losses": 0,+ "injured": 97,+ "lightly_injured": 180,+ "kills": 77+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 343,+ "survivors": 201,+ "losses": 0,+ "injured": 50,+ "lightly_injured": 92,+ "kills": 84+ },+ "lancer_t6": {+ "troops": 222,+ "survivors": 188,+ "losses": 0,+ "injured": 12,+ "lightly_injured": 22,+ "kills": 85+ },+ "marksman_t6": {+ "troops": 316,+ "survivors": 271,+ "losses": 0,+ "injured": 16,+ "lightly_injured": 29,+ "kills": 143+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 20,+ "displayed_kills": 2+ },+ "Blastmaster": {+ "triggered": 10,+ "displayed_kills": 28+ }+ }+ },+ "defender": {+ "Gatot": {+ "King's Bestowal": {+ "triggered": 52,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_c2_twenty/gwen_vs_hendrik.json===================================================================--- testcases/emulator_verified/gwen_c2_twenty/gwen_vs_hendrik.json prev run+++ testcases/emulator_verified/gwen_c2_twenty/gwen_vs_hendrik.json this run@@ -0,0 +1,193 @@+[+ {+ "test_id": "gwen_vs_hendrik",+ "description": "C2 battle report 2734693171109754",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 328,+ "lancer_t6": 366,+ "marksman_t6": 217+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Hendrik": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 283,+ "lancer_t6": 363,+ "marksman_t6": 256+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 479,+ "defense": 467.8,+ "lethality": 244.2,+ "health": 221.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-21T22:40:13.000Z",+ "randomseed": 1790030414,+ "attacker": 220,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171109754",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-21T22-40-30.115Z-8677dc63-aba5-4971-95a9-6f610a9ff354.json",+ "winner": "attacker",+ "attacker": {+ "troops": 911,+ "survivors": 220,+ "losses": 0,+ "injured": 243,+ "lightly_injured": 448,+ "kills": 318+ },+ "defender": {+ "troops": 902,+ "survivors": 0,+ "losses": 0,+ "injured": 318,+ "lightly_injured": 584,+ "kills": 243+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 328,+ "survivors": 0,+ "losses": 0,+ "injured": 115,+ "lightly_injured": 213,+ "kills": 15+ },+ "lancer_t6": {+ "troops": 366,+ "survivors": 71,+ "losses": 0,+ "injured": 104,+ "lightly_injured": 191,+ "kills": 117+ },+ "marksman_t6": {+ "troops": 217,+ "survivors": 149,+ "losses": 0,+ "injured": 24,+ "lightly_injured": 44,+ "kills": 186+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 283,+ "survivors": 0,+ "losses": 0,+ "injured": 100,+ "lightly_injured": 183,+ "kills": 4+ },+ "lancer_t6": {+ "troops": 363,+ "survivors": 0,+ "losses": 0,+ "injured": 128,+ "lightly_injured": 235,+ "kills": 29+ },+ "marksman_t6": {+ "troops": 256,+ "survivors": 0,+ "losses": 0,+ "injured": 90,+ "lightly_injured": 166,+ "kills": 210+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 11,+ "displayed_kills": 8+ },+ "Blastmaster": {+ "triggered": 5,+ "displayed_kills": 8+ }+ }+ },+ "defender": {+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 9,+ "displayed_kills": 54+ },+ "Armor of Barnacles": {+ "triggered": 7,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_c2_twenty/gwen_vs_patrick.json===================================================================--- testcases/emulator_verified/gwen_c2_twenty/gwen_vs_patrick.json prev run+++ testcases/emulator_verified/gwen_c2_twenty/gwen_vs_patrick.json this run@@ -0,0 +1,180 @@+[+ {+ "test_id": "gwen_vs_patrick",+ "description": "C2 battle report 2734693171109637",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 294,+ "lancer_t6": 332,+ "marksman_t6": 384+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Patrick": {+ "skill_1": 4,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 249,+ "lancer_t6": 329,+ "marksman_t6": 222+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 293.2,+ "defense": 292.5,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-21T22:28:45.000Z",+ "randomseed": 1790029726,+ "attacker": 812,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171109637",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-21T22-29-02.118Z-a4a0b05f-df6f-4711-a8e4-42f45ed04065.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1010,+ "survivors": 812,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 128,+ "kills": 282+ },+ "defender": {+ "troops": 800,+ "survivors": 0,+ "losses": 0,+ "injured": 282,+ "lightly_injured": 518,+ "kills": 70+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 294,+ "survivors": 96,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 128,+ "kills": 22+ },+ "lancer_t6": {+ "troops": 332,+ "survivors": 332,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 84+ },+ "marksman_t6": {+ "troops": 384,+ "survivors": 384,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 176+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 249,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 161,+ "kills": 2+ },+ "lancer_t6": {+ "troops": 329,+ "survivors": 0,+ "losses": 0,+ "injured": 116,+ "lightly_injured": 213,+ "kills": 32+ },+ "marksman_t6": {+ "troops": 222,+ "survivors": 0,+ "losses": 0,+ "injured": 78,+ "lightly_injured": 144,+ "kills": 36+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 9,+ "displayed_kills": 3+ },+ "Blastmaster": {+ "triggered": 4,+ "displayed_kills": 11+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_c2_twenty/gwen_vs_renee.json===================================================================--- testcases/emulator_verified/gwen_c2_twenty/gwen_vs_renee.json prev run+++ testcases/emulator_verified/gwen_c2_twenty/gwen_vs_renee.json this run@@ -0,0 +1,189 @@+[+ {+ "test_id": "gwen_vs_renee",+ "description": "C2 battle report 2734693171109713",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 234,+ "lancer_t6": 272,+ "marksman_t6": 324+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 390,+ "lancer_t6": 269,+ "marksman_t6": 363+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-21T22:34:34.000Z",+ "randomseed": 1790030075,+ "attacker": 0,+ "defender": 586,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171109713",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-21T22-34-51.108Z-5e78224f-002d-4ecb-afa1-f1e7f430c91d.json",+ "winner": "defender",+ "attacker": {+ "troops": 830,+ "survivors": 0,+ "losses": 0,+ "injured": 292,+ "lightly_injured": 538,+ "kills": 154+ },+ "defender": {+ "troops": 1022,+ "survivors": 586,+ "losses": 0,+ "injured": 154,+ "lightly_injured": 282,+ "kills": 292+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 234,+ "survivors": 0,+ "losses": 0,+ "injured": 82,+ "lightly_injured": 152,+ "kills": 5+ },+ "lancer_t6": {+ "troops": 272,+ "survivors": 0,+ "losses": 0,+ "injured": 96,+ "lightly_injured": 176,+ "kills": 33+ },+ "marksman_t6": {+ "troops": 324,+ "survivors": 0,+ "losses": 0,+ "injured": 114,+ "lightly_injured": 210,+ "kills": 116+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 390,+ "survivors": 0,+ "losses": 0,+ "injured": 137,+ "lightly_injured": 253,+ "kills": 14+ },+ "lancer_t6": {+ "troops": 269,+ "survivors": 243,+ "losses": 0,+ "injured": 10,+ "lightly_injured": 16,+ "kills": 184+ },+ "marksman_t6": {+ "troops": 363,+ "survivors": 343,+ "losses": 0,+ "injured": 7,+ "lightly_injured": 13,+ "kills": 94+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 6,+ "displayed_kills": 3+ },+ "Blastmaster": {+ "triggered": 4,+ "displayed_kills": 11+ }+ }+ },+ "defender": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 10,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_c2_twenty/gwen_vs_sergey.json===================================================================--- testcases/emulator_verified/gwen_c2_twenty/gwen_vs_sergey.json prev run+++ testcases/emulator_verified/gwen_c2_twenty/gwen_vs_sergey.json this run@@ -0,0 +1,180 @@+[+ {+ "test_id": "gwen_vs_sergey",+ "description": "C2 battle report 2734693171109624",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 247,+ "lancer_t6": 285,+ "marksman_t6": 337+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Sergey": {+ "skill_1": 2,+ "skill_2": 2+ }+ },+ "troops": {+ "infantry_t6": 202,+ "lancer_t6": 282,+ "marksman_t6": 376+ },+ "stats": {+ "infantry": {+ "attack": 346.14,+ "defense": 338.69,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-21T22:26:31.000Z",+ "randomseed": 1790029592,+ "attacker": 699,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171109624",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-21T22-26-48.114Z-26005942-440c-4725-83ba-0cce79a5bf1d.json",+ "winner": "attacker",+ "attacker": {+ "troops": 869,+ "survivors": 699,+ "losses": 0,+ "injured": 60,+ "lightly_injured": 110,+ "kills": 302+ },+ "defender": {+ "troops": 860,+ "survivors": 0,+ "losses": 0,+ "injured": 302,+ "lightly_injured": 558,+ "kills": 60+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 247,+ "survivors": 77,+ "losses": 0,+ "injured": 60,+ "lightly_injured": 110,+ "kills": 18+ },+ "lancer_t6": {+ "troops": 285,+ "survivors": 285,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 93+ },+ "marksman_t6": {+ "troops": 337,+ "survivors": 337,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 191+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 202,+ "survivors": 0,+ "losses": 0,+ "injured": 71,+ "lightly_injured": 131,+ "kills": 4+ },+ "lancer_t6": {+ "troops": 282,+ "survivors": 0,+ "losses": 0,+ "injured": 99,+ "lightly_injured": 183,+ "kills": 17+ },+ "marksman_t6": {+ "troops": 376,+ "survivors": 0,+ "losses": 0,+ "injured": 132,+ "lightly_injured": 244,+ "kills": 39+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 9,+ "displayed_kills": 7+ },+ "Blastmaster": {+ "triggered": 4,+ "displayed_kills": 10+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_c2_twenty/gwen_vs_sonya.json===================================================================--- testcases/emulator_verified/gwen_c2_twenty/gwen_vs_sonya.json prev run+++ testcases/emulator_verified/gwen_c2_twenty/gwen_vs_sonya.json this run@@ -0,0 +1,188 @@+[+ {+ "test_id": "gwen_vs_sonya",+ "description": "C2 battle report 2734693171109740",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 281,+ "lancer_t6": 319,+ "marksman_t6": 371+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 236,+ "lancer_t6": 316,+ "marksman_t6": 209+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 369.5,+ "defense": 368.8,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-21T22:37:30.000Z",+ "randomseed": 1790030251,+ "attacker": 808,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171109740",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-21T22-37-47.115Z-db520607-beb7-40e6-83c8-50a7c52d731b.json",+ "winner": "attacker",+ "attacker": {+ "troops": 971,+ "survivors": 808,+ "losses": 0,+ "injured": 58,+ "lightly_injured": 105,+ "kills": 268+ },+ "defender": {+ "troops": 761,+ "survivors": 0,+ "losses": 0,+ "injured": 268,+ "lightly_injured": 493,+ "kills": 58+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 281,+ "survivors": 118,+ "losses": 0,+ "injured": 58,+ "lightly_injured": 105,+ "kills": 21+ },+ "lancer_t6": {+ "troops": 319,+ "survivors": 319,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 83+ },+ "marksman_t6": {+ "troops": 371,+ "survivors": 371,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 164+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 236,+ "survivors": 0,+ "losses": 0,+ "injured": 83,+ "lightly_injured": 153,+ "kills": 2+ },+ "lancer_t6": {+ "troops": 316,+ "survivors": 0,+ "losses": 0,+ "injured": 111,+ "lightly_injured": 205,+ "kills": 30+ },+ "marksman_t6": {+ "troops": 209,+ "survivors": 0,+ "losses": 0,+ "injured": 74,+ "lightly_injured": 135,+ "kills": 26+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 9,+ "displayed_kills": 8+ },+ "Blastmaster": {+ "triggered": 3,+ "displayed_kills": 10+ }+ }+ },+ "defender": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 8,+ "displayed_kills": 2+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_c2_twenty/gwen_vs_wu_ming_sonya_jasser.json===================================================================--- testcases/emulator_verified/gwen_c2_twenty/gwen_vs_wu_ming_sonya_jasser.json prev run+++ testcases/emulator_verified/gwen_c2_twenty/gwen_vs_wu_ming_sonya_jasser.json this run@@ -0,0 +1,198 @@+[+ {+ "test_id": "gwen_vs_wu_ming_sonya_jasser",+ "description": "C2 battle report 2734693171109640",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 255,+ "lancer_t6": 293,+ "marksman_t6": 345+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 2,+ "skill_4": 0+ },+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ },+ "Jasser": {+ "skill_1": 4,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 210,+ "lancer_t6": 290,+ "marksman_t6": 384+ },+ "stats": {+ "infantry": {+ "attack": 508.98,+ "defense": 501.98,+ "lethality": 250.71,+ "health": 274.79+ },+ "lancer": {+ "attack": 529.96,+ "defense": 534.21,+ "lethality": 323.16,+ "health": 285.53+ },+ "marksman": {+ "attack": 354.37,+ "defense": 360.37,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-21T22:28:59.000Z",+ "randomseed": 1790029740,+ "attacker": 0,+ "defender": 822,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171109640",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-21T22-29-27.112Z-fbed3d97-9e4a-4e31-be38-4278c8987343.json",+ "winner": "defender",+ "attacker": {+ "troops": 893,+ "survivors": 0,+ "losses": 0,+ "injured": 314,+ "lightly_injured": 579,+ "kills": 22+ },+ "defender": {+ "troops": 884,+ "survivors": 822,+ "losses": 0,+ "injured": 22,+ "lightly_injured": 40,+ "kills": 314+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 255,+ "survivors": 0,+ "losses": 0,+ "injured": 90,+ "lightly_injured": 165,+ "kills": 0+ },+ "lancer_t6": {+ "troops": 293,+ "survivors": 0,+ "losses": 0,+ "injured": 103,+ "lightly_injured": 190,+ "kills": 5+ },+ "marksman_t6": {+ "troops": 345,+ "survivors": 0,+ "losses": 0,+ "injured": 121,+ "lightly_injured": 224,+ "kills": 17+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 210,+ "survivors": 148,+ "losses": 0,+ "injured": 22,+ "lightly_injured": 40,+ "kills": 33+ },+ "lancer_t6": {+ "troops": 290,+ "survivors": 290,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 165+ },+ "marksman_t6": {+ "troops": 384,+ "survivors": 384,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 116+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 2,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 5,+ "displayed_kills": 11+ },+ "Torrential Impact": {+ "triggered": 2,+ "displayed_kills": 17+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_c2_twenty/sergey_jessie_hendrik_vs_gwen.json===================================================================--- testcases/emulator_verified/gwen_c2_twenty/sergey_jessie_hendrik_vs_gwen.json prev run+++ testcases/emulator_verified/gwen_c2_twenty/sergey_jessie_hendrik_vs_gwen.json this run@@ -0,0 +1,201 @@+[+ {+ "test_id": "sergey_jessie_hendrik_vs_gwen",+ "description": "C2 battle report 2734693171110008",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Sergey": {+ "skill_1": 2,+ "skill_2": 2+ },+ "Jessie": {+ "skill_1": 1,+ "skill_2": 1+ },+ "Hendrik": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 289,+ "lancer_t6": 327,+ "marksman_t6": 379+ },+ "stats": {+ "infantry": {+ "attack": 346.14,+ "defense": 338.69,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 297.72,+ "defense": 297.02,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 479,+ "defense": 467.8,+ "lethality": 244.2,+ "health": 221.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 244,+ "lancer_t6": 324,+ "marksman_t6": 217+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-21T22:59:54.000Z",+ "randomseed": 1790031595,+ "attacker": 779,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171110008",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-21T23-00-22.116Z-d2388695-f2f3-405e-ab4b-154e91116689.json",+ "winner": "attacker",+ "attacker": {+ "troops": 995,+ "survivors": 779,+ "losses": 0,+ "injured": 77,+ "lightly_injured": 139,+ "kills": 276+ },+ "defender": {+ "troops": 785,+ "survivors": 0,+ "losses": 0,+ "injured": 276,+ "lightly_injured": 509,+ "kills": 77+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 289,+ "survivors": 84,+ "losses": 0,+ "injured": 72,+ "lightly_injured": 133,+ "kills": 16+ },+ "lancer_t6": {+ "troops": 327,+ "survivors": 321,+ "losses": 0,+ "injured": 3,+ "lightly_injured": 3,+ "kills": 67+ },+ "marksman_t6": {+ "troops": 379,+ "survivors": 374,+ "losses": 0,+ "injured": 2,+ "lightly_injured": 3,+ "kills": 193+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 244,+ "survivors": 0,+ "losses": 0,+ "injured": 86,+ "lightly_injured": 158,+ "kills": 4+ },+ "lancer_t6": {+ "troops": 324,+ "survivors": 0,+ "losses": 0,+ "injured": 114,+ "lightly_injured": 210,+ "kills": 22+ },+ "marksman_t6": {+ "troops": 217,+ "survivors": 0,+ "losses": 0,+ "injured": 76,+ "lightly_injured": 141,+ "kills": 51+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 6,+ "displayed_kills": 42+ },+ "Armor of Barnacles": {+ "triggered": 4,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 6,+ "displayed_kills": 1+ },+ "Blastmaster": {+ "triggered": 3,+ "displayed_kills": 4+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_c2_twenty/wu_ming_gordon_gwen_vs_gatot_jessie_hendrik.json===================================================================--- testcases/emulator_verified/gwen_c2_twenty/wu_ming_gordon_gwen_vs_gatot_jessie_hendrik.json prev run+++ testcases/emulator_verified/gwen_c2_twenty/wu_ming_gordon_gwen_vs_gatot_jessie_hendrik.json this run@@ -0,0 +1,235 @@+[+ {+ "test_id": "wu_ming_gordon_gwen_vs_gatot_jessie_hendrik",+ "description": "C2 battle report 2734693171109873",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 2,+ "skill_4": 0+ },+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 315,+ "lancer_t6": 353,+ "marksman_t6": 204+ },+ "stats": {+ "infantry": {+ "attack": 508.98,+ "defense": 501.98,+ "lethality": 250.71,+ "health": 274.79+ },+ "lancer": {+ "attack": 488.62,+ "defense": 492.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gatot": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Jessie": {+ "skill_1": 1,+ "skill_2": 1+ },+ "Hendrik": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 270,+ "lancer_t6": 350,+ "marksman_t6": 243+ },+ "stats": {+ "infantry": {+ "attack": 627.31,+ "defense": 619.86,+ "lethality": 230.66,+ "health": 281.02+ },+ "lancer": {+ "attack": 297.72,+ "defense": 297.02,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 479,+ "defense": 467.8,+ "lethality": 244.2,+ "health": 221.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-21T22:55:11.000Z",+ "randomseed": 1790031312,+ "attacker": 0,+ "defender": 595,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171109873",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-21T22-55-28.118Z-9f15ffab-841a-41b7-8e4c-b895076ab9aa.json",+ "winner": "defender",+ "attacker": {+ "troops": 872,+ "survivors": 0,+ "losses": 0,+ "injured": 307,+ "lightly_injured": 565,+ "kills": 96+ },+ "defender": {+ "troops": 863,+ "survivors": 595,+ "losses": 0,+ "injured": 96,+ "lightly_injured": 172,+ "kills": 307+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 315,+ "survivors": 0,+ "losses": 0,+ "injured": 111,+ "lightly_injured": 204,+ "kills": 0+ },+ "lancer_t6": {+ "troops": 353,+ "survivors": 0,+ "losses": 0,+ "injured": 124,+ "lightly_injured": 229,+ "kills": 35+ },+ "marksman_t6": {+ "troops": 204,+ "survivors": 0,+ "losses": 0,+ "injured": 72,+ "lightly_injured": 132,+ "kills": 61+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 270,+ "survivors": 35,+ "losses": 0,+ "injured": 83,+ "lightly_injured": 152,+ "kills": 29+ },+ "lancer_t6": {+ "troops": 350,+ "survivors": 332,+ "losses": 0,+ "injured": 7,+ "lightly_injured": 11,+ "kills": 80+ },+ "marksman_t6": {+ "troops": 243,+ "survivors": 228,+ "losses": 0,+ "injured": 6,+ "lightly_injured": 9,+ "kills": 198+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 18,+ "displayed_kills": 3+ },+ "Blastmaster": {+ "triggered": 8,+ "displayed_kills": 12+ }+ },+ "Gordon": {+ "Toxic Release": {+ "triggered": 10,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 20,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 14,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 14,+ "displayed_kills": 60+ },+ "Armor of Barnacles": {+ "triggered": 10,+ "displayed_kills": null+ }+ },+ "Gatot": {+ "King's Bestowal": {+ "triggered": 43,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_c2_twenty/wu_ming_sonya_bradley_vs_gatot_patrick_gwen.json===================================================================--- testcases/emulator_verified/gwen_c2_twenty/wu_ming_sonya_bradley_vs_gatot_patrick_gwen.json prev run+++ testcases/emulator_verified/gwen_c2_twenty/wu_ming_sonya_bradley_vs_gatot_patrick_gwen.json this run@@ -0,0 +1,222 @@+[+ {+ "test_id": "wu_ming_sonya_bradley_vs_gatot_patrick_gwen",+ "description": "C2 battle report 2734693171110114",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ },+ "Bradley": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 1+ }+ },+ "troops": {+ "infantry_t6": 336,+ "lancer_t6": 374,+ "marksman_t6": 225+ },+ "stats": {+ "infantry": {+ "attack": 453.71,+ "defense": 446.26,+ "lethality": 223.57,+ "health": 274.97+ },+ "lancer": {+ "attack": 369.5,+ "defense": 368.8,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 681.96,+ "defense": 670.76,+ "lethality": 322.27,+ "health": 273.25+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gatot": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Patrick": {+ "skill_1": 3,+ "skill_2": 2+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 291,+ "lancer_t6": 371,+ "marksman_t6": 264+ },+ "stats": {+ "infantry": {+ "attack": 670.13,+ "defense": 663.13,+ "lethality": 316.11,+ "health": 338.06+ },+ "lancer": {+ "attack": 391.69,+ "defense": 395.94,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-21T23:12:03.000Z",+ "randomseed": 1790032324,+ "attacker": 0,+ "defender": 338,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171110114",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-21T23-12-31.120Z-d5acb885-462b-4622-92b1-a617896c9ae8.json",+ "winner": "defender",+ "attacker": {+ "troops": 935,+ "survivors": 0,+ "losses": 0,+ "injured": 328,+ "lightly_injured": 607,+ "kills": 206+ },+ "defender": {+ "troops": 926,+ "survivors": 338,+ "losses": 0,+ "injured": 206,+ "lightly_injured": 382,+ "kills": 328+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 336,+ "survivors": 0,+ "losses": 0,+ "injured": 118,+ "lightly_injured": 218,+ "kills": 0+ },+ "lancer_t6": {+ "troops": 374,+ "survivors": 0,+ "losses": 0,+ "injured": 131,+ "lightly_injured": 243,+ "kills": 30+ },+ "marksman_t6": {+ "troops": 225,+ "survivors": 0,+ "losses": 0,+ "injured": 79,+ "lightly_injured": 146,+ "kills": 176+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 291,+ "survivors": 0,+ "losses": 0,+ "injured": 102,+ "lightly_injured": 189,+ "kills": 25+ },+ "lancer_t6": {+ "troops": 371,+ "survivors": 74,+ "losses": 0,+ "injured": 104,+ "lightly_injured": 193,+ "kills": 131+ },+ "marksman_t6": {+ "troops": 264,+ "survivors": 264,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 172+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 15,+ "displayed_kills": 2+ }+ },+ "Bradley": {+ "Tactical Assistance": {+ "triggered": 9,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 15,+ "displayed_kills": 8+ },+ "Blastmaster": {+ "triggered": 7,+ "displayed_kills": 9+ }+ },+ "Gatot": {+ "King's Bestowal": {+ "triggered": 29,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_c2_twenty/wu_ming_sonya_gwen_vs_edith_gordon_bradley.json===================================================================--- testcases/emulator_verified/gwen_c2_twenty/wu_ming_sonya_gwen_vs_edith_gordon_bradley.json prev run+++ testcases/emulator_verified/gwen_c2_twenty/wu_ming_sonya_gwen_vs_edith_gordon_bradley.json this run@@ -0,0 +1,227 @@+[+ {+ "test_id": "wu_ming_sonya_gwen_vs_edith_gordon_bradley",+ "description": "C2 battle report 2734693171109718",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 396,+ "lancer_t6": 233,+ "marksman_t6": 285+ },+ "stats": {+ "infantry": {+ "attack": 453.71,+ "defense": 446.26,+ "lethality": 223.57,+ "health": 274.97+ },+ "lancer": {+ "attack": 369.5,+ "defense": 368.8,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Edith": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ },+ "Bradley": {+ "skill_1": 5,+ "skill_2": 4,+ "skill_3": 3,+ "skill_4": 1+ }+ },+ "troops": {+ "infantry_t6": 351,+ "lancer_t6": 230,+ "marksman_t6": 324+ },+ "stats": {+ "infantry": {+ "attack": 521.6,+ "defense": 514.6,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 488.62,+ "defense": 492.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 734.42,+ "defense": 740.42,+ "lethality": 375.19,+ "health": 331.96+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-21T22:34:48.000Z",+ "randomseed": 1790030089,+ "attacker": 0,+ "defender": 784,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171109718",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-21T22-35-16.112Z-492cca79-3c4c-4812-9c99-8232733151c2.json",+ "winner": "defender",+ "attacker": {+ "troops": 914,+ "survivors": 0,+ "losses": 0,+ "injured": 321,+ "lightly_injured": 593,+ "kills": 43+ },+ "defender": {+ "troops": 905,+ "survivors": 784,+ "losses": 0,+ "injured": 43,+ "lightly_injured": 78,+ "kills": 321+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 396,+ "survivors": 0,+ "losses": 0,+ "injured": 139,+ "lightly_injured": 257,+ "kills": 5+ },+ "lancer_t6": {+ "troops": 233,+ "survivors": 0,+ "losses": 0,+ "injured": 82,+ "lightly_injured": 151,+ "kills": 16+ },+ "marksman_t6": {+ "troops": 285,+ "survivors": 0,+ "losses": 0,+ "injured": 100,+ "lightly_injured": 185,+ "kills": 22+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 351,+ "survivors": 230,+ "losses": 0,+ "injured": 43,+ "lightly_injured": 78,+ "kills": 33+ },+ "lancer_t6": {+ "troops": 230,+ "survivors": 230,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 104+ },+ "marksman_t6": {+ "troops": 324,+ "survivors": 324,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 184+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 6,+ "displayed_kills": 1+ }+ },+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 7,+ "displayed_kills": 1+ }+ }+ },+ "defender": {+ "Gordon": {+ "Toxic Release": {+ "triggered": 4,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 8,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 5,+ "displayed_kills": null+ }+ },+ "Bradley": {+ "Tactical Assistance": {+ "triggered": 4,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_gatot_cadence/gwen_60m_vs_gatot_400i.json===================================================================--- testcases/emulator_verified/gwen_gatot_cadence/gwen_60m_vs_gatot_400i.json prev run+++ testcases/emulator_verified/gwen_gatot_cadence/gwen_60m_vs_gatot_400i.json this run@@ -0,0 +1,153 @@+[+ {+ "test_id": "gwen_60m_vs_gatot_400i",+ "description": "C2 battle report 2734693171294010",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "marksman_t6": 60+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gatot": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 400+ },+ "stats": {+ "infantry": {+ "attack": 627.31,+ "defense": 619.86,+ "lethality": 230.66,+ "health": 281.02+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-24T02:23:42.000Z",+ "randomseed": 1790216623,+ "attacker": 0,+ "defender": 400,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171294010",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-24T02-23-58.156Z-e0fb75af-a407-4874-a70c-dab3439fda9f.json",+ "winner": "defender",+ "attacker": {+ "troops": 60,+ "survivors": 0,+ "losses": 0,+ "injured": 21,+ "lightly_injured": 39,+ "kills": 0+ },+ "defender": {+ "troops": 400,+ "survivors": 400,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 21+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 60,+ "survivors": 0,+ "losses": 0,+ "injured": 21,+ "lightly_injured": 39,+ "kills": 0+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 400,+ "survivors": 400,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 21+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 3,+ "displayed_kills": null+ },+ "Blastmaster": {+ "triggered": 4,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Gatot": {+ "King's Bestowal": {+ "triggered": 22,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_gatot_cadence/gwen_65m_vs_gatot_200i.json===================================================================--- testcases/emulator_verified/gwen_gatot_cadence/gwen_65m_vs_gatot_200i.json prev run+++ testcases/emulator_verified/gwen_gatot_cadence/gwen_65m_vs_gatot_200i.json this run@@ -0,0 +1,153 @@+[+ {+ "test_id": "gwen_65m_vs_gatot_200i",+ "description": "C2 battle report 2734693171294108",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "marksman_t6": 65+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gatot": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 627.31,+ "defense": 619.86,+ "lethality": 230.66,+ "health": 281.02+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-24T02:24:44.000Z",+ "randomseed": 1790216685,+ "attacker": 0,+ "defender": 200,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171294108",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-24T02-25-00.153Z-2ca94310-9a4f-46f7-b65b-aa092194ff41.json",+ "winner": "defender",+ "attacker": {+ "troops": 65,+ "survivors": 0,+ "losses": 0,+ "injured": 23,+ "lightly_injured": 42,+ "kills": 0+ },+ "defender": {+ "troops": 200,+ "survivors": 200,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 23+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 65,+ "survivors": 0,+ "losses": 0,+ "injured": 23,+ "lightly_injured": 42,+ "kills": 0+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 200,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 23+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 5,+ "displayed_kills": null+ },+ "Blastmaster": {+ "triggered": 6,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Gatot": {+ "King's Bestowal": {+ "triggered": 32,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_s1_probes/gwen_s1_a.json===================================================================--- testcases/emulator_verified/gwen_s1_probes/gwen_s1_a.json prev run+++ testcases/emulator_verified/gwen_s1_probes/gwen_s1_a.json this run@@ -0,0 +1,139 @@+[+ {+ "test_id": "gwen_s1_a",+ "description": "C2 battle report 2734693171299391",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "marksman_t6": 10+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "marksman_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-24T05:59:58.000Z",+ "randomseed": 1790229599,+ "attacker": 0,+ "defender": 997,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171299391",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-24T06-00-14.187Z-f1d2d710-fc28-4500-aa4e-cbbaf7a672fa.json",+ "winner": "defender",+ "attacker": {+ "troops": 10,+ "survivors": 0,+ "losses": 0,+ "injured": 4,+ "lightly_injured": 6,+ "kills": 2+ },+ "defender": {+ "troops": 1000,+ "survivors": 997,+ "losses": 0,+ "injured": 2,+ "lightly_injured": 1,+ "kills": 4+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 10,+ "survivors": 0,+ "losses": 0,+ "injured": 4,+ "lightly_injured": 6,+ "kills": 2+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 1000,+ "survivors": 997,+ "losses": 0,+ "injured": 2,+ "lightly_injured": 1,+ "kills": 4+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": null,+ "displayed_kills": null+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_s1_probes/gwen_s1_b.json===================================================================--- testcases/emulator_verified/gwen_s1_probes/gwen_s1_b.json prev run+++ testcases/emulator_verified/gwen_s1_probes/gwen_s1_b.json this run@@ -0,0 +1,166 @@+[+ {+ "test_id": "gwen_s1_b",+ "description": "C2 battle report 2734693171299415",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 1,+ "marksman_t6": 10+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 1,+ "lancer_t6": 500,+ "marksman_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-24T06:01:08.000Z",+ "randomseed": 1790229669,+ "attacker": 0,+ "defender": 1501,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171299415",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-24T06-01-24.215Z-b85f1aec-427b-47a4-aeef-f336aa5a6a78.json",+ "winner": "defender",+ "attacker": {+ "troops": 11,+ "survivors": 0,+ "losses": 0,+ "injured": 5,+ "lightly_injured": 6,+ "kills": 0+ },+ "defender": {+ "troops": 1501,+ "survivors": 1501,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 5+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 1,+ "survivors": 0,+ "losses": 0,+ "injured": 1,+ "lightly_injured": 0,+ "kills": 0+ },+ "marksman_t6": {+ "troops": 10,+ "survivors": 0,+ "losses": 0,+ "injured": 4,+ "lightly_injured": 6,+ "kills": 0+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1,+ "survivors": 1,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 0+ },+ "lancer_t6": {+ "troops": 500,+ "survivors": 500,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 1+ },+ "marksman_t6": {+ "troops": 1000,+ "survivors": 1000,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 4+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": null,+ "displayed_kills": null+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_s1_probes/gwen_s1_c.json===================================================================--- testcases/emulator_verified/gwen_s1_probes/gwen_s1_c.json prev run+++ testcases/emulator_verified/gwen_s1_probes/gwen_s1_c.json this run@@ -0,0 +1,166 @@+[+ {+ "test_id": "gwen_s1_c",+ "description": "C2 battle report 2734693171299444",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 5,+ "marksman_t6": 40+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 1,+ "lancer_t6": 500,+ "marksman_t6": 4000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-24T06:02:12.000Z",+ "randomseed": 1790229733,+ "attacker": 0,+ "defender": 4492,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171299444",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-24T06-02-28.239Z-b8f11dfe-1c41-43f3-ac40-45789e323b21.json",+ "winner": "defender",+ "attacker": {+ "troops": 45,+ "survivors": 0,+ "losses": 0,+ "injured": 16,+ "lightly_injured": 29,+ "kills": 4+ },+ "defender": {+ "troops": 4501,+ "survivors": 4492,+ "losses": 0,+ "injured": 4,+ "lightly_injured": 5,+ "kills": 16+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 5,+ "survivors": 0,+ "losses": 0,+ "injured": 2,+ "lightly_injured": 3,+ "kills": 0+ },+ "marksman_t6": {+ "troops": 40,+ "survivors": 0,+ "losses": 0,+ "injured": 14,+ "lightly_injured": 26,+ "kills": 4+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1,+ "survivors": 0,+ "losses": 0,+ "injured": 1,+ "lightly_injured": 0,+ "kills": 0+ },+ "lancer_t6": {+ "troops": 500,+ "survivors": 492,+ "losses": 0,+ "injured": 3,+ "lightly_injured": 5,+ "kills": 3+ },+ "marksman_t6": {+ "troops": 4000,+ "survivors": 4000,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 13+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": null,+ "displayed_kills": null+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_s1_probes/gwen_s1_d.json===================================================================--- testcases/emulator_verified/gwen_s1_probes/gwen_s1_d.json prev run+++ testcases/emulator_verified/gwen_s1_probes/gwen_s1_d.json this run@@ -0,0 +1,157 @@+[+ {+ "test_id": "gwen_s1_d",+ "description": "C2 battle report 2734693171300136",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "marksman_t6": 96+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 5,+ "lancer_t6": 500,+ "marksman_t6": 5000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-24T06:33:09.000Z",+ "randomseed": 1790231590,+ "attacker": 0,+ "defender": 5497,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171300136",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-24T06-33-25.251Z-b1bce01b-6b69-4063-90b4-1e16d97e4e79.json",+ "winner": "defender",+ "attacker": {+ "troops": 96,+ "survivors": 0,+ "losses": 0,+ "injured": 34,+ "lightly_injured": 62,+ "kills": 4+ },+ "defender": {+ "troops": 5505,+ "survivors": 5497,+ "losses": 0,+ "injured": 4,+ "lightly_injured": 4,+ "kills": 34+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 96,+ "survivors": 0,+ "losses": 0,+ "injured": 34,+ "lightly_injured": 62,+ "kills": 4+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 5,+ "survivors": 0,+ "losses": 0,+ "injured": 2,+ "lightly_injured": 3,+ "kills": 0+ },+ "lancer_t6": {+ "troops": 500,+ "survivors": 497,+ "losses": 0,+ "injured": 2,+ "lightly_injured": 1,+ "kills": 6+ },+ "marksman_t6": {+ "troops": 5000,+ "survivors": 5000,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 28+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": null,+ "displayed_kills": null+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_s1_probes/gwen_s1_e.json===================================================================--- testcases/emulator_verified/gwen_s1_probes/gwen_s1_e.json prev run+++ testcases/emulator_verified/gwen_s1_probes/gwen_s1_e.json this run@@ -0,0 +1,166 @@+[+ {+ "test_id": "gwen_s1_e",+ "description": "C2 battle report 2734693171300156",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 5,+ "marksman_t6": 64+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 2,+ "lancer_t6": 500,+ "marksman_t6": 6000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-24T06:34:42.000Z",+ "randomseed": 1790231683,+ "attacker": 0,+ "defender": 6486,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171300156",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-24T06-34-58.271Z-30dd00a4-269b-48aa-9373-6dd4c64b6afe.json",+ "winner": "defender",+ "attacker": {+ "troops": 69,+ "survivors": 0,+ "losses": 0,+ "injured": 25,+ "lightly_injured": 44,+ "kills": 6+ },+ "defender": {+ "troops": 6502,+ "survivors": 6486,+ "losses": 0,+ "injured": 6,+ "lightly_injured": 10,+ "kills": 25+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 5,+ "survivors": 0,+ "losses": 0,+ "injured": 2,+ "lightly_injured": 3,+ "kills": 0+ },+ "marksman_t6": {+ "troops": 64,+ "survivors": 0,+ "losses": 0,+ "injured": 23,+ "lightly_injured": 41,+ "kills": 6+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 2,+ "survivors": 0,+ "losses": 0,+ "injured": 1,+ "lightly_injured": 1,+ "kills": 0+ },+ "lancer_t6": {+ "troops": 500,+ "survivors": 486,+ "losses": 0,+ "injured": 5,+ "lightly_injured": 9,+ "kills": 4+ },+ "marksman_t6": {+ "troops": 6000,+ "survivors": 6000,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 21+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": null,+ "displayed_kills": null+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_s2_probes/gwen_s2_calibration.json===================================================================--- testcases/emulator_verified/gwen_s2_probes/gwen_s2_calibration.json prev run+++ testcases/emulator_verified/gwen_s2_probes/gwen_s2_calibration.json this run@@ -0,0 +1,143 @@+[+ {+ "test_id": "gwen_s2_calibration",+ "description": "C2 battle report 2734693171300786",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 100,+ "marksman_t6": 400+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "infantry_t6": 400+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-24T07:08:35.000Z",+ "randomseed": 1790233716,+ "attacker": 427,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171300786",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-24T07-09-00.147Z-1ed536bb-1203-4904-9c1a-55f74e3962a4.json",+ "winner": "attacker",+ "attacker": {+ "troops": 500,+ "survivors": 427,+ "losses": 0,+ "injured": 26,+ "lightly_injured": 47,+ "kills": 140+ },+ "defender": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 26+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 100,+ "survivors": 27,+ "losses": 0,+ "injured": 26,+ "lightly_injured": 47,+ "kills": 9+ },+ "marksman_t6": {+ "troops": 400,+ "survivors": 400,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 131+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 26+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 20,+ "displayed_kills": 4+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_s2_probes/gwen_s2_curse_timing.json===================================================================--- testcases/emulator_verified/gwen_s2_probes/gwen_s2_curse_timing.json prev run+++ testcases/emulator_verified/gwen_s2_probes/gwen_s2_curse_timing.json this run@@ -0,0 +1,152 @@+[+ {+ "test_id": "gwen_s2_curse_timing",+ "description": "C2 battle report 2734693171300885",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 100,+ "marksman_t6": 400+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "infantry_t6": 400,+ "marksman_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-24T07:13:39.000Z",+ "randomseed": 1790234020,+ "attacker": 0,+ "defender": 423,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171300885",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-24T07-14-04.140Z-f5e7eadc-389b-438f-92c7-3cb39c9db764.json",+ "winner": "defender",+ "attacker": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 62+ },+ "defender": {+ "troops": 600,+ "survivors": 423,+ "losses": 0,+ "injured": 62,+ "lightly_injured": 115,+ "kills": 175+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 1+ },+ "marksman_t6": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 61+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 400,+ "survivors": 223,+ "losses": 0,+ "injured": 62,+ "lightly_injured": 115,+ "kills": 42+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 200,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 133+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 7,+ "displayed_kills": 1+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_s2_probes/gwen_s2_first_trigger.json===================================================================--- testcases/emulator_verified/gwen_s2_probes/gwen_s2_first_trigger.json prev run+++ testcases/emulator_verified/gwen_s2_probes/gwen_s2_first_trigger.json this run@@ -0,0 +1,152 @@+[+ {+ "test_id": "gwen_s2_first_trigger",+ "description": "C2 battle report 2734693171300907",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 50,+ "marksman_t6": 1200+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "infantry_t6": 400,+ "marksman_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-24T07:15:16.000Z",+ "randomseed": 1790234117,+ "attacker": 369,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171300907",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-24T07-15-41.154Z-ba8b20e7-91c1-4bb8-8ba4-728cfd859c56.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1250,+ "survivors": 369,+ "losses": 0,+ "injured": 309,+ "lightly_injured": 572,+ "kills": 210+ },+ "defender": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 309+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 0+ },+ "marksman_t6": {+ "troops": 1200,+ "survivors": 369,+ "losses": 0,+ "injured": 291,+ "lightly_injured": 540,+ "kills": 210+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 51+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 258+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 8,+ "displayed_kills": 5+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_s2_probes/gwen_s2_mark_consumption.json===================================================================--- testcases/emulator_verified/gwen_s2_probes/gwen_s2_mark_consumption.json prev run+++ testcases/emulator_verified/gwen_s2_probes/gwen_s2_mark_consumption.json this run@@ -0,0 +1,152 @@+[+ {+ "test_id": "gwen_s2_mark_consumption",+ "description": "C2 battle report 2734693171300981",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 200,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "infantry_t6": 100,+ "marksman_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-24T07:17:38.000Z",+ "randomseed": 1790234259,+ "attacker": 41,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171300981",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-24T07-18-03.176Z-be6f20f3-0757-4697-b312-cffcd4db25c8.json",+ "winner": "attacker",+ "attacker": {+ "troops": 300,+ "survivors": 41,+ "losses": 0,+ "injured": 91,+ "lightly_injured": 168,+ "kills": 105+ },+ "defender": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 91+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 9+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 41,+ "losses": 0,+ "injured": 21,+ "lightly_injured": 38,+ "kills": 96+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 4+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 87+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 15,+ "displayed_kills": 3+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_s2_source_binding/gwen_s2_source_1.json===================================================================--- testcases/emulator_verified/gwen_s2_source_binding/gwen_s2_source_1.json prev run+++ testcases/emulator_verified/gwen_s2_source_binding/gwen_s2_source_1.json this run@@ -0,0 +1,152 @@+[+ {+ "test_id": "gwen_s2_source_1",+ "description": "C2 battle report 2734693171302235",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 125,+ "marksman_t6": 600+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "infantry_t6": 200,+ "marksman_t6": 250+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-24T08:17:42.000Z",+ "randomseed": 1790237863,+ "attacker": 332,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171302235",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-24T08-18-07.123Z-4eef9a68-53c5-4a57-909c-62d350c71bc4.json",+ "winner": "attacker",+ "attacker": {+ "troops": 725,+ "survivors": 332,+ "losses": 0,+ "injured": 138,+ "lightly_injured": 255,+ "kills": 158+ },+ "defender": {+ "troops": 450,+ "survivors": 0,+ "losses": 0,+ "injured": 158,+ "lightly_injured": 292,+ "kills": 138+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 125,+ "survivors": 0,+ "losses": 0,+ "injured": 44,+ "lightly_injured": 81,+ "kills": 2+ },+ "marksman_t6": {+ "troops": 600,+ "survivors": 332,+ "losses": 0,+ "injured": 94,+ "lightly_injured": 174,+ "kills": 156+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 9+ },+ "marksman_t6": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 129+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 8,+ "displayed_kills": 3+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_s2_source_binding/gwen_s2_source_2.json===================================================================--- testcases/emulator_verified/gwen_s2_source_binding/gwen_s2_source_2.json prev run+++ testcases/emulator_verified/gwen_s2_source_binding/gwen_s2_source_2.json this run@@ -0,0 +1,152 @@+[+ {+ "test_id": "gwen_s2_source_2",+ "description": "C2 battle report 2734693171302281",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 125,+ "marksman_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "infantry_t6": 300,+ "marksman_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-24T08:19:49.000Z",+ "randomseed": 1790237990,+ "attacker": 737,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171302281",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-24T08-20-14.140Z-ccc3bc84-5048-4d69-97d7-95a03f728d0c.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1125,+ "survivors": 737,+ "losses": 0,+ "injured": 137,+ "lightly_injured": 251,+ "kills": 175+ },+ "defender": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 137+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 125,+ "survivors": 0,+ "losses": 0,+ "injured": 44,+ "lightly_injured": 81,+ "kills": 2+ },+ "marksman_t6": {+ "troops": 1000,+ "survivors": 737,+ "losses": 0,+ "injured": 93,+ "lightly_injured": 170,+ "kills": 173+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 16+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 121+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 8,+ "displayed_kills": 5+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_s2_source_binding/gwen_s2_source_3.json===================================================================--- testcases/emulator_verified/gwen_s2_source_binding/gwen_s2_source_3.json prev run+++ testcases/emulator_verified/gwen_s2_source_binding/gwen_s2_source_3.json this run@@ -0,0 +1,152 @@+[+ {+ "test_id": "gwen_s2_source_3",+ "description": "C2 battle report 2734693171302300",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 50,+ "marksman_t6": 400+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "infantry_t6": 150,+ "marksman_t6": 125+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-24T08:20:59.000Z",+ "randomseed": 1790238060,+ "attacker": 60,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171302300",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-24T08-21-24.126Z-fcd8ff89-287a-48fd-ab22-99aae56642fc.json",+ "winner": "attacker",+ "attacker": {+ "troops": 450,+ "survivors": 60,+ "losses": 0,+ "injured": 137,+ "lightly_injured": 253,+ "kills": 97+ },+ "defender": {+ "troops": 275,+ "survivors": 0,+ "losses": 0,+ "injured": 97,+ "lightly_injured": 178,+ "kills": 137+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 0+ },+ "marksman_t6": {+ "troops": 400,+ "survivors": 60,+ "losses": 0,+ "injured": 119,+ "lightly_injured": 221,+ "kills": 97+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 14+ },+ "marksman_t6": {+ "troops": 125,+ "survivors": 0,+ "losses": 0,+ "injured": 44,+ "lightly_injured": 81,+ "kills": 123+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 9,+ "displayed_kills": 2+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_s2_source_binding/gwen_s2_source_4.json===================================================================--- testcases/emulator_verified/gwen_s2_source_binding/gwen_s2_source_4.json prev run+++ testcases/emulator_verified/gwen_s2_source_binding/gwen_s2_source_4.json this run@@ -0,0 +1,152 @@+[+ {+ "test_id": "gwen_s2_source_4",+ "description": "C2 battle report 2734693171302326",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 200,+ "marksman_t6": 150+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "infantry_t6": 150,+ "marksman_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-24T08:22:13.000Z",+ "randomseed": 1790238134,+ "attacker": 0,+ "defender": 113,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171302326",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-24T08-22-38.124Z-6985cf51-83ae-44f0-8509-12fef7ccbe26.json",+ "winner": "defender",+ "attacker": {+ "troops": 350,+ "survivors": 0,+ "losses": 0,+ "injured": 123,+ "lightly_injured": 227,+ "kills": 84+ },+ "defender": {+ "troops": 350,+ "survivors": 113,+ "losses": 0,+ "injured": 84,+ "lightly_injured": 153,+ "kills": 123+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 5+ },+ "marksman_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 79+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 9+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 113,+ "losses": 0,+ "injured": 31,+ "lightly_injured": 56,+ "kills": 114+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 14,+ "displayed_kills": 2+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_s2_source_binding/gwen_s2_source_5.json===================================================================--- testcases/emulator_verified/gwen_s2_source_binding/gwen_s2_source_5.json prev run+++ testcases/emulator_verified/gwen_s2_source_binding/gwen_s2_source_5.json this run@@ -0,0 +1,152 @@+[+ {+ "test_id": "gwen_s2_source_5",+ "description": "C2 battle report 2734693171302350",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 50,+ "marksman_t6": 600+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "infantry_t6": 200,+ "marksman_t6": 75+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-24T08:23:22.000Z",+ "randomseed": 1790238203,+ "attacker": 383,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171302350",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-24T08-23-47.140Z-8f0fdcd6-7967-4afc-84fa-9eef13f6d292.json",+ "winner": "attacker",+ "attacker": {+ "troops": 650,+ "survivors": 383,+ "losses": 0,+ "injured": 94,+ "lightly_injured": 173,+ "kills": 97+ },+ "defender": {+ "troops": 275,+ "survivors": 0,+ "losses": 0,+ "injured": 97,+ "lightly_injured": 178,+ "kills": 94+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 1+ },+ "marksman_t6": {+ "troops": 600,+ "survivors": 383,+ "losses": 0,+ "injured": 76,+ "lightly_injured": 141,+ "kills": 96+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 17+ },+ "marksman_t6": {+ "troops": 75,+ "survivors": 0,+ "losses": 0,+ "injured": 27,+ "lightly_injured": 48,+ "kills": 77+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 8,+ "displayed_kills": 3+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/interaction_map/gordon_bradley_pure_lancers.json===================================================================--- testcases/emulator_verified/interaction_map/gordon_bradley_pure_lancers.json prev run+++ testcases/emulator_verified/interaction_map/gordon_bradley_pure_lancers.json this run@@ -0,0 +1,160 @@+[+ {+ "test_id": "gordon_bradley_pure_lancers",+ "description": "C2 battle report 2734693171240660",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ },+ "Bradley": {+ "skill_1": 5,+ "skill_2": 4,+ "skill_3": 3,+ "skill_4": 1+ }+ },+ "troops": {+ "lancer_t6": 350+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 493.62,+ "defense": 492.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 739.42,+ "defense": 740.42,+ "lethality": 375.19,+ "health": 331.96+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "lancer_t6": 1800+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T22:18:13.000Z",+ "randomseed": 1790115494,+ "attacker": 0,+ "defender": 241,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171240660",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T22-18-30.101Z-8c95c337-b5dd-4d55-84c4-c9bf71a44dd7.json",+ "winner": "defender",+ "attacker": {+ "troops": 350,+ "survivors": 0,+ "losses": 0,+ "injured": 123,+ "lightly_injured": 227,+ "kills": 546+ },+ "defender": {+ "troops": 1800,+ "survivors": 241,+ "losses": 0,+ "injured": 546,+ "lightly_injured": 1013,+ "kills": 123+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 350,+ "survivors": 0,+ "losses": 0,+ "injured": 123,+ "lightly_injured": 227,+ "kills": 546+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 1800,+ "survivors": 241,+ "losses": 0,+ "injured": 546,+ "lightly_injured": 1013,+ "kills": 123+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gordon": {+ "Toxic Release": {+ "triggered": 12,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 24,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 16,+ "displayed_kills": null+ }+ },+ "Bradley": {+ "Tactical Assistance": {+ "triggered": 12,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/interaction_map/gordon_wuming_pure_lancers.json===================================================================--- testcases/emulator_verified/interaction_map/gordon_wuming_pure_lancers.json prev run+++ testcases/emulator_verified/interaction_map/gordon_wuming_pure_lancers.json this run@@ -0,0 +1,154 @@+[+ {+ "test_id": "gordon_wuming_pure_lancers",+ "description": "C2 battle report 2734693171241065",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 2,+ "skill_4": 0+ },+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 600+ },+ "stats": {+ "infantry": {+ "attack": 513.98,+ "defense": 501.98,+ "lethality": 250.71,+ "health": 274.79+ },+ "lancer": {+ "attack": 493.62,+ "defense": 492.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "lancer_t6": 2400+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T22:24:24.000Z",+ "randomseed": 1790115865,+ "attacker": 0,+ "defender": 434,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171241065",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T22-24-41.098Z-348f904c-625c-4308-ae98-cdc1d52e9840.json",+ "winner": "defender",+ "attacker": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 689+ },+ "defender": {+ "troops": 2400,+ "survivors": 434,+ "losses": 0,+ "injured": 689,+ "lightly_injured": 1277,+ "kills": 210+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 689+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 2400,+ "survivors": 434,+ "losses": 0,+ "injured": 689,+ "lightly_injured": 1277,+ "kills": 210+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gordon": {+ "Toxic Release": {+ "triggered": 13,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 26,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 17,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/interaction_map/renee_bradley_pure_lancers.json===================================================================--- testcases/emulator_verified/interaction_map/renee_bradley_pure_lancers.json prev run+++ testcases/emulator_verified/interaction_map/renee_bradley_pure_lancers.json this run@@ -0,0 +1,152 @@+[+ {+ "test_id": "renee_bradley_pure_lancers",+ "description": "C2 battle report 2734693171240812",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Bradley": {+ "skill_1": 5,+ "skill_2": 4,+ "skill_3": 3,+ "skill_4": 1+ }+ },+ "troops": {+ "lancer_t6": 150+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 739.42,+ "defense": 740.42,+ "lethality": 375.19,+ "health": 331.96+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "lancer_t6": 1400+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T22:20:17.000Z",+ "randomseed": 1790115618,+ "attacker": 0,+ "defender": 133,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171240812",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T22-20-34.089Z-2225efdf-bceb-4656-8157-b37b7dcf5a7f.json",+ "winner": "defender",+ "attacker": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 444+ },+ "defender": {+ "troops": 1400,+ "survivors": 133,+ "losses": 0,+ "injured": 444,+ "lightly_injured": 823,+ "kills": 53+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 444+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 1400,+ "survivors": 133,+ "losses": 0,+ "injured": 444,+ "lightly_injured": 823,+ "kills": 53+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 20,+ "displayed_kills": null+ }+ },+ "Bradley": {+ "Tactical Assistance": {+ "triggered": 10,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/interaction_map/renee_jasser_pure_lancers.json===================================================================--- testcases/emulator_verified/interaction_map/renee_jasser_pure_lancers.json prev run+++ testcases/emulator_verified/interaction_map/renee_jasser_pure_lancers.json this run@@ -0,0 +1,144 @@+[+ {+ "test_id": "renee_jasser_pure_lancers",+ "description": "C2 battle report 2734693171240879",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Jasser": {+ "skill_1": 4,+ "skill_2": 4+ }+ },+ "troops": {+ "lancer_t6": 250+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 359.37,+ "defense": 360.37,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "lancer_t6": 1800+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T22:21:33.000Z",+ "randomseed": 1790115694,+ "attacker": 17,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171240879",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T22-21-50.093Z-a2ce0c11-644e-4af8-b11e-5d966f7ccab6.json",+ "winner": "attacker",+ "attacker": {+ "troops": 250,+ "survivors": 17,+ "losses": 0,+ "injured": 82,+ "lightly_injured": 151,+ "kills": 630+ },+ "defender": {+ "troops": 1800,+ "survivors": 0,+ "losses": 0,+ "injured": 630,+ "lightly_injured": 1170,+ "kills": 82+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 250,+ "survivors": 17,+ "losses": 0,+ "injured": 82,+ "lightly_injured": 151,+ "kills": 630+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 1800,+ "survivors": 0,+ "losses": 0,+ "injured": 630,+ "lightly_injured": 1170,+ "kills": 82+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 23,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/interaction_map/renee_wuming_pure_lancers.json===================================================================--- testcases/emulator_verified/interaction_map/renee_wuming_pure_lancers.json prev run+++ testcases/emulator_verified/interaction_map/renee_wuming_pure_lancers.json this run@@ -0,0 +1,146 @@+[+ {+ "test_id": "renee_wuming_pure_lancers",+ "description": "C2 battle report 2734693171240945",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 2,+ "skill_4": 0+ },+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 250+ },+ "stats": {+ "infantry": {+ "attack": 513.98,+ "defense": 501.98,+ "lethality": 250.71,+ "health": 274.79+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "lancer_t6": 1800+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T22:22:49.000Z",+ "randomseed": 1790115770,+ "attacker": 0,+ "defender": 214,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171240945",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T22-23-06.100Z-052071e0-8658-46a9-bc71-78d8ac9a3c47.json",+ "winner": "defender",+ "attacker": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 556+ },+ "defender": {+ "troops": 1800,+ "survivors": 214,+ "losses": 0,+ "injured": 556,+ "lightly_injured": 1030,+ "kills": 88+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 556+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 1800,+ "survivors": 214,+ "losses": 0,+ "injured": 556,+ "lightly_injured": 1030,+ "kills": 88+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 23,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/nohero_controls/nohero_explicit_empty_100m_vs_100m.json===================================================================--- testcases/emulator_verified/nohero_controls/nohero_explicit_empty_100m_vs_100m.json prev run+++ testcases/emulator_verified/nohero_controls/nohero_explicit_empty_100m_vs_100m.json this run@@ -0,0 +1,121 @@+[+ {+ "test_id": "nohero_explicit_empty_100m_vs_100m",+ "description": "C2 battle report 2734693171297894",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-24T04:53:49.000Z",+ "randomseed": 1790225630,+ "attacker": 62,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171297894",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-24T04-54-05.219Z-d2cd817a-f43d-4211-9846-09c474c4ad4c.json",+ "winner": "attacker",+ "attacker": {+ "troops": 100,+ "survivors": 62,+ "losses": 0,+ "injured": 14,+ "lightly_injured": 24,+ "kills": 35+ },+ "defender": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 14+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 100,+ "survivors": 62,+ "losses": 0,+ "injured": 14,+ "lightly_injured": 24,+ "kills": 35+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 14+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_isolation_20260925/renee_gwen_300l_100m_vs_2700l.json===================================================================--- testcases/emulator_verified/renee_isolation_20260925/renee_gwen_300l_100m_vs_2700l.json prev run+++ testcases/emulator_verified/renee_isolation_20260925/renee_gwen_300l_100m_vs_2700l.json this run@@ -0,0 +1,165 @@+[+ {+ "test_id": "renee_gwen_300l_100m_vs_2700l",+ "description": "C2 battle report 2734693171344569",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 300,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 607.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 435.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "lancer_t6": 2700+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T08:19:54.000Z",+ "randomseed": 1790324395,+ "attacker": 0,+ "defender": 187,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171344569",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T08-20-10.049Z-4be46d45-bc54-44bf-b329-d44015892a02.json",+ "winner": "defender",+ "attacker": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 880+ },+ "defender": {+ "troops": 2700,+ "survivors": 187,+ "losses": 0,+ "injured": 880,+ "lightly_injured": 1633,+ "kills": 140+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 456+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 424+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 2700,+ "survivors": 187,+ "losses": 0,+ "injured": 880,+ "lightly_injured": 1633,+ "kills": 140+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 12,+ "displayed_kills": 15+ },+ "Blastmaster": {+ "triggered": 9,+ "displayed_kills": 6+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 23,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_isolation_20260925/renee_mark_source_death.json===================================================================--- testcases/emulator_verified/renee_isolation_20260925/renee_mark_source_death.json prev run+++ testcases/emulator_verified/renee_isolation_20260925/renee_mark_source_death.json this run@@ -0,0 +1,188 @@+[+ {+ "test_id": "renee_mark_source_death",+ "description": "C2 battle report 2734693171344530",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 80,+ "lancer_t6": 450,+ "marksman_t6": 1600+ },+ "stats": {+ "infantry": {+ "attack": 422.61,+ "defense": 405.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 607.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 1200,+ "lancer_t6": 1200,+ "marksman_t6": 600+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T08:17:36.000Z",+ "randomseed": 1790324257,+ "attacker": 184,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171344530",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T08-17-52.027Z-1936b5fc-f7c3-4861-b1bb-bbf609c3c508.json",+ "winner": "attacker",+ "attacker": {+ "troops": 2130,+ "survivors": 184,+ "losses": 0,+ "injured": 682,+ "lightly_injured": 1264,+ "kills": 1050+ },+ "defender": {+ "troops": 3000,+ "survivors": 0,+ "losses": 0,+ "injured": 1050,+ "lightly_injured": 1950,+ "kills": 682+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 80,+ "survivors": 0,+ "losses": 0,+ "injured": 28,+ "lightly_injured": 52,+ "kills": 4+ },+ "lancer_t6": {+ "troops": 450,+ "survivors": 0,+ "losses": 0,+ "injured": 158,+ "lightly_injured": 292,+ "kills": 167+ },+ "marksman_t6": {+ "troops": 1600,+ "survivors": 184,+ "losses": 0,+ "injured": 496,+ "lightly_injured": 920,+ "kills": 879+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1200,+ "survivors": 0,+ "losses": 0,+ "injured": 420,+ "lightly_injured": 780,+ "kills": 19+ },+ "lancer_t6": {+ "troops": 1200,+ "survivors": 0,+ "losses": 0,+ "injured": 420,+ "lightly_injured": 780,+ "kills": 206+ },+ "marksman_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 457+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 1,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 18,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_s2_bucket_confirmations/gatot_shield_500_150.json===================================================================--- testcases/emulator_verified/renee_s2_bucket_confirmations/gatot_shield_500_150.json prev run+++ testcases/emulator_verified/renee_s2_bucket_confirmations/gatot_shield_500_150.json this run@@ -0,0 +1,149 @@+[+ {+ "test_id": "gatot_shield_500_150",+ "description": "C2 battle report 2734693171255861",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 500+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gatot": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t9": 150+ },+ "stats": {+ "infantry": {+ "attack": 627.31,+ "defense": 619.86,+ "lethality": 230.66,+ "health": 281.02+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-23T03:02:22.000Z",+ "randomseed": 1790132543,+ "attacker": 157,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171255861",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-23T03-02-43.099Z-ca20fbc3-5de1-4d29-a07a-a15a3bec7041.json",+ "winner": "attacker",+ "attacker": {+ "troops": 500,+ "survivors": 157,+ "losses": 0,+ "injured": 121,+ "lightly_injured": 222,+ "kills": 53+ },+ "defender": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 121+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 500,+ "survivors": 157,+ "losses": 0,+ "injured": 121,+ "lightly_injured": 222,+ "kills": 53+ }+ },+ "defender": {+ "infantry_t9": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 121+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 93,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Gatot": {+ "King's Bestowal": {+ "triggered": 186,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_s2_bucket_confirmations/gwen_next_hit_150_1050.json===================================================================--- testcases/emulator_verified/renee_s2_bucket_confirmations/gwen_next_hit_150_1050.json prev run+++ testcases/emulator_verified/renee_s2_bucket_confirmations/gwen_next_hit_150_1050.json this run@@ -0,0 +1,156 @@+[+ {+ "test_id": "gwen_next_hit_150_1050",+ "description": "C2 battle report 2734693171255782",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 150+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "lancer_t6": 1050+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-23T02:57:45.000Z",+ "randomseed": 1790132266,+ "attacker": 0,+ "defender": 111,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171255782",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-23T02-58-06.094Z-04f345fe-3bcb-4fee-ac76-0047566b8a9e.json",+ "winner": "defender",+ "attacker": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 329+ },+ "defender": {+ "troops": 1050,+ "survivors": 111,+ "losses": 0,+ "injured": 329,+ "lightly_injured": 610,+ "kills": 53+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 329+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 1050,+ "survivors": 111,+ "losses": 0,+ "injured": 329,+ "lightly_injured": 610,+ "kills": 53+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 7,+ "displayed_kills": 3+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 23,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_s2_families/defense_gatot.json===================================================================--- testcases/emulator_verified/renee_s2_families/defense_gatot.json prev run+++ testcases/emulator_verified/renee_s2_families/defense_gatot.json this run@@ -0,0 +1,149 @@+[+ {+ "test_id": "defense_gatot",+ "description": "C2 battle report 2734693171252715",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 750+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gatot": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t9": 225+ },+ "stats": {+ "infantry": {+ "attack": 627.31,+ "defense": 619.86,+ "lethality": 230.66,+ "health": 281.02+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-23T01:23:08.000Z",+ "randomseed": 1790126589,+ "attacker": 339,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171252715",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-23T01-23-29.105Z-de756fa0-f794-4b26-9336-675b3ff5ae23.json",+ "winner": "attacker",+ "attacker": {+ "troops": 750,+ "survivors": 339,+ "losses": 0,+ "injured": 144,+ "lightly_injured": 267,+ "kills": 79+ },+ "defender": {+ "troops": 225,+ "survivors": 0,+ "losses": 0,+ "injured": 79,+ "lightly_injured": 146,+ "kills": 144+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 750,+ "survivors": 339,+ "losses": 0,+ "injured": 144,+ "lightly_injured": 267,+ "kills": 79+ }+ },+ "defender": {+ "infantry_t9": {+ "troops": 225,+ "survivors": 0,+ "losses": 0,+ "injured": 79,+ "lightly_injured": 146,+ "kills": 144+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 73,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Gatot": {+ "King's Bestowal": {+ "triggered": 147,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_s2_families/defense_hendrik.json===================================================================--- testcases/emulator_verified/renee_s2_families/defense_hendrik.json prev run+++ testcases/emulator_verified/renee_s2_families/defense_hendrik.json this run@@ -0,0 +1,153 @@+[+ {+ "test_id": "defense_hendrik",+ "description": "C2 battle report 2734693171245400",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1500+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Hendrik": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "marksman_t6": 3750+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 479,+ "defense": 467.8,+ "lethality": 244.2,+ "health": 221.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T23:27:03.000Z",+ "randomseed": 1790119624,+ "attacker": 0,+ "defender": 1266,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171245400",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T23-27-20.096Z-157ab07e-c18d-41f7-952b-e2d82c09dd57.json",+ "winner": "defender",+ "attacker": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 870+ },+ "defender": {+ "troops": 3750,+ "survivors": 1266,+ "losses": 0,+ "injured": 870,+ "lightly_injured": 1614,+ "kills": 525+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 870+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 3750,+ "survivors": 1266,+ "losses": 0,+ "injured": 870,+ "lightly_injured": 1614,+ "kills": 525+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 10,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 6,+ "displayed_kills": 36+ },+ "Armor of Barnacles": {+ "triggered": 5,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_s2_families/defense_logan.json===================================================================--- testcases/emulator_verified/renee_s2_families/defense_logan.json prev run+++ testcases/emulator_verified/renee_s2_families/defense_logan.json this run@@ -0,0 +1,140 @@+[+ {+ "test_id": "defense_logan",+ "description": "C2 battle report 2734693171252843",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 500+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Logan": {+ "skill_1": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "marksman_t6": 3500+ },+ "stats": {+ "infantry": {+ "attack": 307.37,+ "defense": 299.92,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-23T01:28:23.000Z",+ "randomseed": 1790126904,+ "attacker": 0,+ "defender": 356,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171252843",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-23T01-28-44.093Z-27976ce7-e06d-48d8-adcb-9daf5d10124b.json",+ "winner": "defender",+ "attacker": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 1101+ },+ "defender": {+ "troops": 3500,+ "survivors": 356,+ "losses": 0,+ "injured": 1101,+ "lightly_injured": 2043,+ "kills": 175+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 1101+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 3500,+ "survivors": 356,+ "losses": 0,+ "injured": 1101,+ "lightly_injured": 2043,+ "kills": 175+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 18,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_s2_families/defense_lumak.json===================================================================--- testcases/emulator_verified/renee_s2_families/defense_lumak.json prev run+++ testcases/emulator_verified/renee_s2_families/defense_lumak.json this run@@ -0,0 +1,140 @@+[+ {+ "test_id": "defense_lumak",+ "description": "C2 battle report 2734693171245257",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 500+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Lumak Bokan": {+ "skill_1": 3,+ "skill_2": 1+ }+ },+ "troops": {+ "marksman_t6": 3500+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 266.12,+ "defense": 265.42,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T23:24:24.000Z",+ "randomseed": 1790119465,+ "attacker": 0,+ "defender": 742,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171245257",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T23-24-41.096Z-e0e3fcfb-ff3a-469f-832e-3335e0476621.json",+ "winner": "defender",+ "attacker": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 966+ },+ "defender": {+ "troops": 3500,+ "survivors": 742,+ "losses": 0,+ "injured": 966,+ "lightly_injured": 1792,+ "kills": 175+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 966+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 3500,+ "survivors": 742,+ "losses": 0,+ "injured": 966,+ "lightly_injured": 1792,+ "kills": 175+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 16,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_s2_families/defense_patrick.json===================================================================--- testcases/emulator_verified/renee_s2_families/defense_patrick.json prev run+++ testcases/emulator_verified/renee_s2_families/defense_patrick.json this run@@ -0,0 +1,140 @@+[+ {+ "test_id": "defense_patrick",+ "description": "C2 battle report 2734693171245547",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 500+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Patrick": {+ "skill_1": 4,+ "skill_2": 4+ }+ },+ "troops": {+ "marksman_t6": 3000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 293.2,+ "defense": 292.5,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T23:29:37.000Z",+ "randomseed": 1790119778,+ "attacker": 0,+ "defender": 721,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171245547",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T23-29-54.100Z-044fcf49-7a90-4ced-bd36-b93a49e5c633.json",+ "winner": "defender",+ "attacker": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 798+ },+ "defender": {+ "troops": 3000,+ "survivors": 721,+ "losses": 0,+ "injured": 798,+ "lightly_injured": 1481,+ "kills": 175+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 798+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 3000,+ "survivors": 721,+ "losses": 0,+ "injured": 798,+ "lightly_injured": 1481,+ "kills": 175+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 15,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_s2_families/defense_sergey.json===================================================================--- testcases/emulator_verified/renee_s2_families/defense_sergey.json prev run+++ testcases/emulator_verified/renee_s2_families/defense_sergey.json this run@@ -0,0 +1,140 @@+[+ {+ "test_id": "defense_sergey",+ "description": "C2 battle report 2734693171245004",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 500+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Sergey": {+ "skill_1": 2,+ "skill_2": 2+ }+ },+ "troops": {+ "marksman_t6": 3500+ },+ "stats": {+ "infantry": {+ "attack": 346.14,+ "defense": 338.69,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T23:20:44.000Z",+ "randomseed": 1790119245,+ "attacker": 0,+ "defender": 917,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171245004",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T23-21-01.102Z-b0fdf93d-2e08-4aa7-bc08-c65ef06b44e4.json",+ "winner": "defender",+ "attacker": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 905+ },+ "defender": {+ "troops": 3500,+ "survivors": 917,+ "losses": 0,+ "injured": 905,+ "lightly_injured": 1678,+ "kills": 175+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 905+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 3500,+ "survivors": 917,+ "losses": 0,+ "injured": 905,+ "lightly_injured": 1678,+ "kills": 175+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 16,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_s2_families/defense_wuming.json===================================================================--- testcases/emulator_verified/renee_s2_families/defense_wuming.json prev run+++ testcases/emulator_verified/renee_s2_families/defense_wuming.json this run@@ -0,0 +1,142 @@+[+ {+ "test_id": "defense_wuming",+ "description": "C2 battle report 2734693171252668",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 2000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t9": 2000+ },+ "stats": {+ "infantry": {+ "attack": 453.71,+ "defense": 446.26,+ "lethality": 223.57,+ "health": 274.97+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-23T01:21:30.000Z",+ "randomseed": 1790126491,+ "attacker": 0,+ "defender": 329,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171252668",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-23T01-21-51.099Z-ec52c5d3-9f33-4a5b-8628-06b291c1eee5.json",+ "winner": "defender",+ "attacker": {+ "troops": 2000,+ "survivors": 0,+ "losses": 0,+ "injured": 700,+ "lightly_injured": 1300,+ "kills": 585+ },+ "defender": {+ "troops": 2000,+ "survivors": 329,+ "losses": 0,+ "injured": 585,+ "lightly_injured": 1086,+ "kills": 700+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 2000,+ "survivors": 0,+ "losses": 0,+ "injured": 700,+ "lightly_injured": 1300,+ "kills": 585+ }+ },+ "defender": {+ "infantry_t9": {+ "troops": 2000,+ "survivors": 329,+ "losses": 0,+ "injured": 585,+ "lightly_injured": 1086,+ "kills": 700+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 48,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_s2_families/renee_edith_hendrik.json===================================================================--- testcases/emulator_verified/renee_s2_families/renee_edith_hendrik.json prev run+++ testcases/emulator_verified/renee_s2_families/renee_edith_hendrik.json this run@@ -0,0 +1,157 @@+[+ {+ "test_id": "renee_edith_hendrik",+ "description": "C2 battle report 2734693171244433",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Edith": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Hendrik": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 150+ },+ "stats": {+ "infantry": {+ "attack": 526.6,+ "defense": 514.6,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 449.21,+ "defense": 450.21,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "lancer_t6": 1300+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T23:13:29.000Z",+ "randomseed": 1790118810,+ "attacker": 0,+ "defender": 269,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171244433",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T23-13-46.098Z-66bc4c6f-259a-454e-a210-b7c27e477c25.json",+ "winner": "defender",+ "attacker": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 361+ },+ "defender": {+ "troops": 1300,+ "survivors": 269,+ "losses": 0,+ "injured": 361,+ "lightly_injured": 670,+ "kills": 53+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 361+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 1300,+ "survivors": 269,+ "losses": 0,+ "injured": 361,+ "lightly_injured": 670,+ "kills": 53+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 23,+ "displayed_kills": null+ }+ },+ "Hendrik": {+ "Armor of Barnacles": {+ "triggered": 11,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_s2_families/renee_gwen.json===================================================================--- testcases/emulator_verified/renee_s2_families/renee_gwen.json prev run+++ testcases/emulator_verified/renee_s2_families/renee_gwen.json this run@@ -0,0 +1,165 @@+[+ {+ "test_id": "renee_gwen",+ "description": "C2 battle report 2734693171244855",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 125,+ "marksman_t6": 1+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "lancer_t6": 975+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T23:18:45.000Z",+ "randomseed": 1790119126,+ "attacker": 0,+ "defender": 243,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171244855",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T23-19-02.101Z-b6c174ca-43b7-49e3-8f13-5d4b9b2eb2cc.json",+ "winner": "defender",+ "attacker": {+ "troops": 126,+ "survivors": 0,+ "losses": 0,+ "injured": 45,+ "lightly_injured": 81,+ "kills": 257+ },+ "defender": {+ "troops": 975,+ "survivors": 243,+ "losses": 0,+ "injured": 257,+ "lightly_injured": 475,+ "kills": 45+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 125,+ "survivors": 0,+ "losses": 0,+ "injured": 44,+ "lightly_injured": 81,+ "kills": 230+ },+ "marksman_t6": {+ "troops": 1,+ "survivors": 0,+ "losses": 0,+ "injured": 1,+ "lightly_injured": 0,+ "kills": 27+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 975,+ "survivors": 243,+ "losses": 0,+ "injured": 257,+ "lightly_injured": 475,+ "kills": 45+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 12,+ "displayed_kills": 3+ },+ "Blastmaster": {+ "triggered": 8,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 20,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_s2_families/renee_gwen_25_marksmen.json===================================================================--- testcases/emulator_verified/renee_s2_families/renee_gwen_25_marksmen.json prev run+++ testcases/emulator_verified/renee_s2_families/renee_gwen_25_marksmen.json this run@@ -0,0 +1,165 @@+[+ {+ "test_id": "renee_gwen_25_marksmen",+ "description": "C2 battle report 2734693171253084",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 125,+ "marksman_t6": 25+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "lancer_t6": 1100+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-23T01:34:29.000Z",+ "randomseed": 1790127270,+ "attacker": 0,+ "defender": 162,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171253084",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-23T01-34-50.101Z-106dbcf3-feb3-49d9-a3fa-1e947fba87ed.json",+ "winner": "defender",+ "attacker": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 329+ },+ "defender": {+ "troops": 1100,+ "survivors": 162,+ "losses": 0,+ "injured": 329,+ "lightly_injured": 609,+ "kills": 53+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 125,+ "survivors": 0,+ "losses": 0,+ "injured": 44,+ "lightly_injured": 81,+ "kills": 198+ },+ "marksman_t6": {+ "troops": 25,+ "survivors": 0,+ "losses": 0,+ "injured": 9,+ "lightly_injured": 16,+ "kills": 131+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 1100,+ "survivors": 162,+ "losses": 0,+ "injured": 329,+ "lightly_injured": 609,+ "kills": 53+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 12,+ "displayed_kills": 5+ },+ "Blastmaster": {+ "triggered": 8,+ "displayed_kills": 1+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 21,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_s2_families/renee_gwen_no_marksmen.json===================================================================--- testcases/emulator_verified/renee_s2_families/renee_gwen_no_marksmen.json prev run+++ testcases/emulator_verified/renee_s2_families/renee_gwen_no_marksmen.json this run@@ -0,0 +1,156 @@+[+ {+ "test_id": "renee_gwen_no_marksmen",+ "description": "C2 battle report 2734693171253006",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 125+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "lancer_t6": 975+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-23T01:32:06.000Z",+ "randomseed": 1790127127,+ "attacker": 0,+ "defender": 305,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171253006",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-23T01-32-27.097Z-66a7d1ad-30b1-4e2d-bbde-e950d2afdfc9.json",+ "winner": "defender",+ "attacker": {+ "troops": 125,+ "survivors": 0,+ "losses": 0,+ "injured": 44,+ "lightly_injured": 81,+ "kills": 235+ },+ "defender": {+ "troops": 975,+ "survivors": 305,+ "losses": 0,+ "injured": 235,+ "lightly_injured": 435,+ "kills": 44+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 125,+ "survivors": 0,+ "losses": 0,+ "injured": 44,+ "lightly_injured": 81,+ "kills": 235+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 975,+ "survivors": 305,+ "losses": 0,+ "injured": 235,+ "lightly_injured": 435,+ "kills": 44+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 6,+ "displayed_kills": 2+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 19,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_s2_families/renee_seo_charge.json===================================================================--- testcases/emulator_verified/renee_s2_families/renee_seo_charge.json prev run+++ testcases/emulator_verified/renee_s2_families/renee_seo_charge.json this run@@ -0,0 +1,144 @@+[+ {+ "test_id": "renee_seo_charge",+ "description": "C2 battle report 2734693171244593",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Seo-yoon": {+ "skill_1": 4,+ "skill_2": 3+ }+ },+ "troops": {+ "lancer_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 359.37,+ "defense": 360.37,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "marksman_t6": 640+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T23:15:52.000Z",+ "randomseed": 1790118953,+ "attacker": 0,+ "defender": 167,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171244593",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T23-16-09.095Z-0a431c58-909b-4bd9-b30e-40c56a87811b.json",+ "winner": "defender",+ "attacker": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 166+ },+ "defender": {+ "troops": 640,+ "survivors": 167,+ "losses": 0,+ "injured": 166,+ "lightly_injured": 307,+ "kills": 35+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 166+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 640,+ "survivors": 167,+ "losses": 0,+ "injured": 166,+ "lightly_injured": 307,+ "kills": 35+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 13,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_s2_families/skill_fleet_captain.json===================================================================--- testcases/emulator_verified/renee_s2_families/skill_fleet_captain.json prev run+++ testcases/emulator_verified/renee_s2_families/skill_fleet_captain.json this run@@ -0,0 +1,853 @@+[+ {+ "test_id": "skill_fleet_captain",+ "description": "C2 battle report 2734693171244469",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Wayne": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 600+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 402.68,+ "defense": 391.48,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Jasser": {+ "skill_1": 4,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t9": 800+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 359.37,+ "defense": 360.37,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-22T23:13:42.000Z",+ "randomseed": 1790118823,+ "attacker": 0,+ "defender": 142,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171244469",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T23-14-10.095Z-735cc25a-570d-4946-afee-aed1f9cfff51.json",+ "winner": "defender",+ "attacker": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 231+ },+ "defender": {+ "troops": 800,+ "survivors": 142,+ "losses": 0,+ "injured": 231,+ "lightly_injured": 427,+ "kills": 210+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 231+ }+ },+ "defender": {+ "infantry_t9": {+ "troops": 800,+ "survivors": 142,+ "losses": 0,+ "injured": 231,+ "lightly_injured": 427,+ "kills": 210+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Fleet": {+ "triggered": 8,+ "displayed_kills": 16+ },+ "Thunder Strike": {+ "triggered": 20,+ "displayed_kills": 12+ },+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 41,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ },+ {+ "timestamp": "2026-09-22T23:14:52.000Z",+ "randomseed": 1790118893,+ "attacker": 0,+ "defender": 114,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171244510",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T23-15-20.108Z-a9e08cd6-0825-457d-aa34-a79bb954abc8.json",+ "winner": "defender",+ "attacker": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 241+ },+ "defender": {+ "troops": 800,+ "survivors": 114,+ "losses": 0,+ "injured": 241,+ "lightly_injured": 445,+ "kills": 210+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 241+ }+ },+ "defender": {+ "infantry_t9": {+ "troops": 800,+ "survivors": 114,+ "losses": 0,+ "injured": 241,+ "lightly_injured": 445,+ "kills": 210+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Fleet": {+ "triggered": 11,+ "displayed_kills": 20+ },+ "Thunder Strike": {+ "triggered": 21,+ "displayed_kills": 13+ },+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 42,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ },+ {+ "timestamp": "2026-09-22T23:16:02.000Z",+ "randomseed": 1790118963,+ "attacker": 0,+ "defender": 115,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171244602",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T23-16-30.111Z-c3f01fb5-9f53-40d2-bc40-353717d01840.json",+ "winner": "defender",+ "attacker": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 240+ },+ "defender": {+ "troops": 800,+ "survivors": 115,+ "losses": 0,+ "injured": 240,+ "lightly_injured": 445,+ "kills": 210+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 240+ }+ },+ "defender": {+ "infantry_t9": {+ "troops": 800,+ "survivors": 115,+ "losses": 0,+ "injured": 240,+ "lightly_injured": 445,+ "kills": 210+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Fleet": {+ "triggered": 14,+ "displayed_kills": 23+ },+ "Thunder Strike": {+ "triggered": 21,+ "displayed_kills": 12+ },+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 42,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ },+ {+ "timestamp": "2026-09-22T23:17:12.000Z",+ "randomseed": 1790119033,+ "attacker": 0,+ "defender": 107,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171244680",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T23-17-40.097Z-8cad79aa-198d-4567-8908-2e358dc0c2ad.json",+ "winner": "defender",+ "attacker": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 243+ },+ "defender": {+ "troops": 800,+ "survivors": 107,+ "losses": 0,+ "injured": 243,+ "lightly_injured": 450,+ "kills": 210+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 243+ }+ },+ "defender": {+ "infantry_t9": {+ "troops": 800,+ "survivors": 107,+ "losses": 0,+ "injured": 243,+ "lightly_injured": 450,+ "kills": 210+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Fleet": {+ "triggered": 14,+ "displayed_kills": 24+ },+ "Thunder Strike": {+ "triggered": 21,+ "displayed_kills": 12+ },+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 42,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ },+ {+ "timestamp": "2026-09-22T23:18:22.000Z",+ "randomseed": 1790119103,+ "attacker": 0,+ "defender": 117,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171244831",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T23-18-50.103Z-4741e745-275e-4636-a19d-a5ec881663c8.json",+ "winner": "defender",+ "attacker": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 240+ },+ "defender": {+ "troops": 800,+ "survivors": 117,+ "losses": 0,+ "injured": 240,+ "lightly_injured": 443,+ "kills": 210+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 240+ }+ },+ "defender": {+ "infantry_t9": {+ "troops": 800,+ "survivors": 117,+ "losses": 0,+ "injured": 240,+ "lightly_injured": 443,+ "kills": 210+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Fleet": {+ "triggered": 11,+ "displayed_kills": 20+ },+ "Thunder Strike": {+ "triggered": 21,+ "displayed_kills": 14+ },+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 42,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ },+ {+ "timestamp": "2026-09-22T23:26:02.000Z",+ "randomseed": 1790119563,+ "attacker": 0,+ "defender": 136,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171245332",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T23-26-30.108Z-0a07c369-a883-4d2e-b797-07bd6e7e55e7.json",+ "winner": "defender",+ "attacker": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 233+ },+ "defender": {+ "troops": 800,+ "survivors": 136,+ "losses": 0,+ "injured": 233,+ "lightly_injured": 431,+ "kills": 210+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 233+ }+ },+ "defender": {+ "infantry_t9": {+ "troops": 800,+ "survivors": 136,+ "losses": 0,+ "injured": 233,+ "lightly_injured": 431,+ "kills": 210+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Fleet": {+ "triggered": 11,+ "displayed_kills": 15+ },+ "Thunder Strike": {+ "triggered": 20,+ "displayed_kills": 13+ },+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 41,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ },+ {+ "timestamp": "2026-09-22T23:27:12.000Z",+ "randomseed": 1790119633,+ "attacker": 0,+ "defender": 96,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171245405",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T23-27-40.095Z-e17e782b-6667-4581-ad5d-64db8bdf57d3.json",+ "winner": "defender",+ "attacker": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 247+ },+ "defender": {+ "troops": 800,+ "survivors": 96,+ "losses": 0,+ "injured": 247,+ "lightly_injured": 457,+ "kills": 210+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 247+ }+ },+ "defender": {+ "infantry_t9": {+ "troops": 800,+ "survivors": 96,+ "losses": 0,+ "injured": 247,+ "lightly_injured": 457,+ "kills": 210+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Fleet": {+ "triggered": 17,+ "displayed_kills": 24+ },+ "Thunder Strike": {+ "triggered": 21,+ "displayed_kills": 13+ },+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 43,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ },+ {+ "timestamp": "2026-09-22T23:28:22.000Z",+ "randomseed": 1790119703,+ "attacker": 0,+ "defender": 189,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171245491",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T23-28-50.100Z-5ef9f66f-9537-407c-8e8c-434645b7c829.json",+ "winner": "defender",+ "attacker": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 214+ },+ "defender": {+ "troops": 800,+ "survivors": 189,+ "losses": 0,+ "injured": 214,+ "lightly_injured": 397,+ "kills": 210+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 214+ }+ },+ "defender": {+ "infantry_t9": {+ "troops": 800,+ "survivors": 189,+ "losses": 0,+ "injured": 214,+ "lightly_injured": 397,+ "kills": 210+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Fleet": {+ "triggered": 3,+ "displayed_kills": 5+ },+ "Thunder Strike": {+ "triggered": 19,+ "displayed_kills": 12+ },+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 39,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ },+ {+ "timestamp": "2026-09-22T23:29:32.000Z",+ "randomseed": 1790119773,+ "attacker": 0,+ "defender": 121,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171245535",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T23-30-00.101Z-c6148a9e-2687-4d83-8422-66a62d5f1f48.json",+ "winner": "defender",+ "attacker": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 238+ },+ "defender": {+ "troops": 800,+ "survivors": 121,+ "losses": 0,+ "injured": 238,+ "lightly_injured": 441,+ "kills": 210+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 238+ }+ },+ "defender": {+ "infantry_t9": {+ "troops": 800,+ "survivors": 121,+ "losses": 0,+ "injured": 238,+ "lightly_injured": 441,+ "kills": 210+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Fleet": {+ "triggered": 12,+ "displayed_kills": 21+ },+ "Thunder Strike": {+ "triggered": 21,+ "displayed_kills": 12+ },+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 42,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ },+ {+ "timestamp": "2026-09-22T23:30:42.000Z",+ "randomseed": 1790119843,+ "attacker": 0,+ "defender": 120,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171245600",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-22T23-31-10.094Z-1e9ce1bd-e7d1-4997-b97b-f7ba31b0850c.json",+ "winner": "defender",+ "attacker": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 238+ },+ "defender": {+ "troops": 800,+ "survivors": 120,+ "losses": 0,+ "injured": 238,+ "lightly_injured": 442,+ "kills": 210+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 238+ }+ },+ "defender": {+ "infantry_t9": {+ "troops": 800,+ "survivors": 120,+ "losses": 0,+ "injured": 238,+ "lightly_injured": 442,+ "kills": 210+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Fleet": {+ "triggered": 11,+ "displayed_kills": 19+ },+ "Thunder Strike": {+ "triggered": 21,+ "displayed_kills": 12+ },+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 42,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]
Show raw per-run patches
Run B dirty state patch
diff --git a/simulator/config/hero_definitions/Ahmose.json b/simulator/config/hero_definitions/Ahmose.json--- a/simulator/config/hero_definitions/Ahmose.json+++ b/simulator/config/hero_definitions/Ahmose.json@@ -102,7 +102,7 @@},"effects": {"BladeOfLight/1": {- "type": "active.hero.damage.up",+ "type": "extra_skill_attack","value": [12,24,@@ -115,11 +115,12 @@"infantry"]},- "duration": {- "attacks": {- "count": 1+ "trigger_damage_jobs": [+ {+ "source": "use.source",+ "target": "use.target"}- }+ ]},"BladeOfLight/2": {"type": "active.hero.damageTaken.up",diff --git a/simulator/config/hero_definitions/Gordon.json b/simulator/config/hero_definitions/Gordon.json--- a/simulator/config/hero_definitions/Gordon.json+++ b/simulator/config/hero_definitions/Gordon.json@@ -22,8 +22,8 @@100],"units": {- "applies_to": "trigger.source",- "applies_vs": "trigger.target"+ "applies_to": "trigger.source",+ "applies_vs": "trigger.target"},"duration": {"attacks": {@@ -61,6 +61,7 @@"effects": {"ChemicalTerror/1": {"type": "active.hero.damage.up",+ "applies_to_damage_kinds": ["normal"],"value": [30,60,@@ -75,7 +76,8 @@},"duration": {"turns": {- "count": 1+ "count": 1,+ "delay": 1}},"same_effect_stacking": "max"@@ -99,6 +101,28 @@}},"same_effect_stacking": "max"+ },+ "ChemicalTerror/3": {+ "type": "active.hero.damage.up",+ "applies_to_damage_kinds": ["skill"],+ "value": [+ 30,+ 60,+ 90,+ 120,+ 150+ ],+ "units": {+ "applies_to": [+ "lancer"+ ]+ },+ "duration": {+ "turns": {+ "count": 1+ }+ },+ "same_effect_stacking": "max"}}},diff --git a/simulator/config/hero_definitions/Renee.json b/simulator/config/hero_definitions/Renee.json--- a/simulator/config/hero_definitions/Renee.json+++ b/simulator/config/hero_definitions/Renee.json@@ -24,7 +24,7 @@"type": "extra_skill_attack","value": [40, 80, 120, 160, 200],"units": {- "applies_to": "parent.use.source",+ "applies_to": "self.any","applies_vs": "parent.use.target"},"trigger_damage_jobs": [@@ -96,7 +96,6 @@"trigger_effects": {"Dreamslice/1": {"type": "active.hero.damageTaken.up",- "applies_to_damage_kinds": ["normal"],"value": [15, 30, 45, 60, 75],"units": {"applies_to": "parent.use.target",diff --git a/simulator/src/simulator.test.ts b/simulator/src/simulator.test.ts--- a/simulator/src/simulator.test.ts+++ b/simulator/src/simulator.test.ts@@ -21,6 +21,50 @@return runPrepared(prepareBattle(input, config), undefined, options);}+test("Gordon suppresses on third turns and boosts normal Lancer damage on the following turns", () => {+ const result = runOnce({+ maxRounds: 7,+ attacker: {+ troops: { lancer_t6: 1000 },+ heroes: { Gordon: { skill_1: 2, skill_2: 2, skill_3: 2 } }+ },+ defender: { troops: { lancer_t6: 1000 } }+ }, loadSimulatorConfig(), { mode: "standard" });++ assert.deepEqual(result.attacks+ .filter((attack) => attack.appliedEffects?.some((effect) => effect.effectId === "ChemicalTerror/1"))+ .map((attack) => attack.round), [4, 7]);+ assert.deepEqual(result.attacks+ .filter((attack) => attack.appliedEffects?.some((effect) => effect.effectId === "ChemicalTerror/2"))+ .map((attack) => attack.round), [3, 6]);+});++test("Gordon boosts Wayne skill damage on Chemical Terror's triggering turn", () => {+ const [input] = JSON.parse(readFileSync(new URL("../../testcases/emulator_verified/gordon_interactions_20260925/gordon_wayne_1200l_vs_4800l.json", import.meta.url), "utf8"));+ assert.equal(signedRemainingScore(runOnce(input, loadSimulatorConfig())), -313);+});++test("Ahmose Blade of Light deals separate skill damage with Bradley and against Wu Ming", () => {+ const config = loadSimulatorConfig();+ for (const [path, survivors] of [+ ["ahmose_bradley_1000i_vs_3700i", -77],+ ["ahmose_1000i_vs_wuming_1000i", -82]+ ] as const) {+ const [input] = JSON.parse(readFileSync(new URL(`../../testcases/emulator_verified/ahmose_isolation_20260925/${path}.json`, import.meta.url), "utf8"));+ assert.equal(signedRemainingScore(runOnce(input, config)), survivors, path);+ }+});++test("Renee Dreamslice amplifies allied skill damage against the marked target", () => {+ const [input] = JSON.parse(readFileSync(new URL("../../testcases/emulator_verified/ahmose_gordon_renee/ahmose_renee_vs_jasser_mark_kind.json", import.meta.url), "utf8"));+ assert.equal(signedRemainingScore(runOnce(input, loadSimulatorConfig())), 937);+});++test("Renee's captured Dream Mark survives the loss of its Lancer source", () => {+ const [input] = JSON.parse(readFileSync(new URL("../../testcases/emulator_verified/renee_isolation_20260925/renee_mark_source_death.json", import.meta.url), "utf8"));+ assert.equal(signedRemainingScore(runOnce(input, loadSimulatorConfig())), 184);+});+test("delayed damage settles shields on arrival in recorded Gatot battles", () => {const config = loadSimulatorConfig();for (const [path, survivors] of [