WOS Sim
← Back to Runs

Run Detail

97bcaa8d-9685-40d9-8674-2f4211b6b6ce

Started11/06/2026, 05:27:58
Git SHA40ddd336
Statedirty
Avg Error %0.21%
BH Sig Count4
Total Cases178
Passing161
Run Report

Code Changes Since Previous Run

Index: simulator/src/simulator.test.ts
===================================================================
--- simulator/src/simulator.test.ts prev run
+++ simulator/src/simulator.test.ts this run
@@ -822,8 +822,38 @@
assert.equal(result.remaining.attacker.marksman, 1349);
assert.deepEqual(result.remaining.defender, { infantry: 0, lancer: 0, marksman: 0 });
});
+test("committed losses clamp exhausted floating point residue before next-round target selection", () => {
+ const config = loadSimulatorConfig();
+ const fixturePath = fileURLToPath(new URL("../testcases/emulator_verified/renee_solo_nc.json", import.meta.url));
+ const testcases = JSON.parse(readFileSync(fixturePath, "utf8")) as Array<BattleInput & { test_id: string }>;
+ const input = testcases.find((testcase) => testcase.test_id === "renee_solo_nc");
+ if (!input) throw new Error("missing renee_solo_nc fixture");
+
+ const adjusted = structuredClone(input);
+ for (const [fighter, adjustment] of [
+ [adjusted.attacker, 0.05],
+ [adjusted.defender, -0.05]
+ ] as const) {
+ for (const stats of Object.values(fighter.stats ?? {})) {
+ for (const key of ["attack", "defense", "lethality", "health"] as const) {
+ if (stats[key] !== undefined) stats[key] = Number((Number(stats[key]) + adjustment).toFixed(3));
+ }
+ }
+ }
+ adjusted.trace = true;
+
+ const result = simulateBattle(adjusted, config);
+ const roundSix = result.trace?.rounds.find((round) => round.round === 6);
+ const defenderTargets = roundSix?.intents
+ .filter((intent) => intent.attackerSide === "defender")
+ .map((intent) => intent.defenderUnit);
+
+ assert.equal(roundSix?.roundStartTroops.attacker.infantry, 0);
+ assert.deepEqual(defenderTargets, ["lancer", "lancer", "lancer"]);
+});
+
test("extra skill trigger damage jobs reject missing runtime selectors", () => {
assert.throws(
() =>
simulateBattle(
Index: simulator/src/simulator.ts
===================================================================
--- simulator/src/simulator.ts prev run
+++ simulator/src/simulator.ts this run
@@ -688,12 +688,16 @@
if (matching.length === 0) continue;
const available = Math.max(0, roundStartTroops[side][unit] ?? 0);
const totalKills = matching.reduce((sum, outcome) => sum + outcome.kills, 0);
if (totalKills <= available) continue;
- let remaining = available;
+ let appliedKills = 0;
+ let rawRemaining = available;
for (const outcome of matching) {
- outcome.kills = Math.min(outcome.kills, remaining);
- remaining -= outcome.kills;
+ const rawKills = outcome.kills;
+ outcome.kills = Math.min(rawKills, Math.max(0, available - appliedKills));
+ appliedKills += outcome.kills;
+ rawRemaining = Math.max(0, rawRemaining - rawKills);
+ if (rawRemaining === 0) appliedKills = available;
if (outcome.trace) outcome.trace.finalKills = outcome.kills;
}
}
}
Show Raw Dirty State Patch (vs Clean Baseline)
diff --git a/simulator/src/damage.ts b/simulator/src/damage.ts
--- a/simulator/src/damage.ts
+++ b/simulator/src/damage.ts
@@ -38,6 +38,7 @@
effect: ActiveEffect;
bucket: AtomicBucket;
valuePct: number;
+ carriedInactive?: boolean;
}
interface MaxBucketCandidateGroup {
@@ -123,13 +124,17 @@
const consumedEffectIds = new Set<string>();
const candidates: BucketCandidate[] = [];
const handledCandidateEffectIds = traceEnabled ? new Set<string>() : undefined;
+ const carriedAttackDurationEffectIds = job.carriedAttackDurationEffectIds ? new Set(job.carriedAttackDurationEffectIds) : undefined;
for (const candidate of bucketCandidatesForJob(options.effectIndex, job)) {
- if (!isEffectActive(candidate.effect, job.round)) continue;
+ const active = isEffectActive(candidate.effect, job.round);
+ const carriedInactive = !active && carriedAttackDurationEffectIds?.has(candidate.effect.id) === true;
+ if (!active && !carriedInactive) continue;
handledCandidateEffectIds?.add(candidate.effect.id);
candidates.push({
effect: candidate.effect,
bucket: candidate.bucket,
- valuePct: currentEffectValuePct(candidate.effect, job.round)
+ valuePct: currentEffectValuePct(candidate.effect, job.round),
+ carriedInactive
});
}
@@ -267,7 +272,7 @@
appliedEffects.push(appliedEffect);
}
for (const candidate of candidates) {
- if (candidate.effect.duration.type === "attack") consumedEffectIds.add(candidate.effect.id);
+ if (candidate.effect.duration.type === "attack" && !candidate.carriedInactive) consumedEffectIds.add(candidate.effect.id);
if (detail === "full" && candidate !== selected) {
rejectedEffects.push({ effectId: candidate.effect.source.effectId ?? candidate.effect.id, reason: "same_effect_max_suppressed" });
}
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
@@ -823,6 +823,36 @@
assert.deepEqual(result.remaining.defender, { infantry: 0, lancer: 0, marksman: 0 });
});
+test("committed losses clamp exhausted floating point residue before next-round target selection", () => {
+ const config = loadSimulatorConfig();
+ const fixturePath = fileURLToPath(new URL("../testcases/emulator_verified/renee_solo_nc.json", import.meta.url));
+ const testcases = JSON.parse(readFileSync(fixturePath, "utf8")) as Array<BattleInput & { test_id: string }>;
+ const input = testcases.find((testcase) => testcase.test_id === "renee_solo_nc");
+ if (!input) throw new Error("missing renee_solo_nc fixture");
+
+ const adjusted = structuredClone(input);
+ for (const [fighter, adjustment] of [
+ [adjusted.attacker, 0.05],
+ [adjusted.defender, -0.05]
+ ] as const) {
+ for (const stats of Object.values(fighter.stats ?? {})) {
+ for (const key of ["attack", "defense", "lethality", "health"] as const) {
+ if (stats[key] !== undefined) stats[key] = Number((Number(stats[key]) + adjustment).toFixed(3));
+ }
+ }
+ }
+ adjusted.trace = true;
+
+ const result = simulateBattle(adjusted, config);
+ const roundSix = result.trace?.rounds.find((round) => round.round === 6);
+ const defenderTargets = roundSix?.intents
+ .filter((intent) => intent.attackerSide === "defender")
+ .map((intent) => intent.defenderUnit);
+
+ assert.equal(roundSix?.roundStartTroops.attacker.infantry, 0);
+ assert.deepEqual(defenderTargets, ["lancer", "lancer", "lancer"]);
+});
+
test("extra skill trigger damage jobs reject missing runtime selectors", () => {
assert.throws(
() =>
@@ -1323,6 +1353,87 @@
assert.deepEqual(result.extraSkillAttackJobsByEffect, { hitLiving: 4 });
});
+test("attack-duration normal damage effects do not carry to triggered extra skill damage by default", () => {
+ const result = simulateBattle(
+ {
+ maxRounds: 1,
+ trace: true,
+ attacker: {
+ troops: { marksman_t1: 100 },
+ heroes: { FollowUp: { skill_1: 1, skill_2: 1 } }
+ },
+ defender: {
+ troops: { infantry_t1: 100 },
+ heroes: {}
+ }
+ },
+ attackDurationCarryConfig()
+ );
+
+ const normalBoosts = result.attacks
+ .filter((attack) => attack.kind === "normal" && attack.attackerSide === "attacker")
+ .map((attack) => attack.trace?.atomicBuckets["active.hero.attack.up"].totalPct ?? 0);
+ const skillBoosts = result.attacks
+ .filter((attack) => attack.kind === "skill")
+ .map((attack) => attack.trace?.atomicBuckets["active.hero.attack.up"].totalPct ?? 0);
+ assert.deepEqual(normalBoosts, [100]);
+ assert.deepEqual(skillBoosts, [0]);
+});
+
+test("mechanics flag carries consumed attack-duration effects to matching triggered extra skill damage only", () => {
+ const result = simulateBattle(
+ {
+ maxRounds: 1,
+ trace: true,
+ mechanics: { carryAttackDurationEffectsToTriggeredExtraSkillDamage: true },
+ attacker: {
+ troops: { marksman_t1: 100 },
+ heroes: { FollowUp: { skill_1: 1, skill_2: 1 } }
+ },
+ defender: {
+ troops: { infantry_t1: 100, lancer_t1: 100, marksman_t1: 100 },
+ heroes: {}
+ }
+ },
+ attackDurationCarryConfig({ buffAppliesVs: "infantry", extraTargets: "enemy.living" })
+ );
+
+ const normalBoosts = result.attacks
+ .filter((attack) => attack.kind === "normal" && attack.attackerSide === "attacker")
+ .map((attack) => attack.trace?.atomicBuckets["active.hero.attack.up"].totalPct ?? 0);
+ const skillBoostsByTarget = result.attacks
+ .filter((attack) => attack.kind === "skill")
+ .map((attack) => `${attack.defenderUnit}:${attack.trace?.atomicBuckets["active.hero.attack.up"].totalPct ?? 0}`)
+ .sort();
+ assert.deepEqual(normalBoosts, [100]);
+ assert.deepEqual(skillBoostsByTarget, ["infantry:100", "lancer:0", "marksman:0"]);
+});
+
+test("mechanics flag carries consumed attack-duration effects with any target scope to all matching triggered extra skill damage", () => {
+ const result = simulateBattle(
+ {
+ maxRounds: 1,
+ trace: true,
+ mechanics: { carryAttackDurationEffectsToTriggeredExtraSkillDamage: true },
+ attacker: {
+ troops: { marksman_t1: 100 },
+ heroes: { FollowUp: { skill_1: 1, skill_2: 1 } }
+ },
+ defender: {
+ troops: { infantry_t1: 100, lancer_t1: 100, marksman_t1: 100 },
+ heroes: {}
+ }
+ },
+ attackDurationCarryConfig({ buffAppliesVs: "any", extraTargets: "enemy.living" })
+ );
+
+ const skillBoosts = result.attacks
+ .filter((attack) => attack.kind === "skill")
+ .map((attack) => attack.trace?.atomicBuckets["active.hero.attack.up"].totalPct ?? 0)
+ .sort((left, right) => left - right);
+ assert.deepEqual(skillBoosts, [100, 100, 100]);
+});
+
test("attack-triggered source and target selectors resolve to concrete active scopes", () => {
const result = simulateBattle(
{
@@ -1801,3 +1912,40 @@
diagnostics: { legacyFields: [], effectTypes: {}, unsupportedEffects: [], ambiguousTurnTriggerSelectors: [] }
};
}
+
+function attackDurationCarryConfig(
+ options: { buffAppliesVs?: "any" | "infantry"; extraTargets?: "use.target" | "enemy.living" } = {}
+): SimulatorConfig {
+ const buffAppliesVs = options.buffAppliesVs ?? "any";
+ const extraTargets = options.extraTargets ?? "use.target";
+ return minimalConfig({
+ FollowUp: {
+ name: "FollowUp",
+ skills: {
+ OneUseNormalBoost: {
+ trigger: { type: "battle_start" },
+ effects: {
+ boost: {
+ type: "active.hero.attack.up",
+ value: 100,
+ units: { applies_to: "marksman", applies_vs: buffAppliesVs },
+ duration: { type: "attack", value: 1 }
+ }
+ }
+ },
+ TriggeredExtraDamage: {
+ trigger: { type: "attack", probability: 100, source: "marksman" },
+ effects: {
+ extra: {
+ type: "extra_skill_attack",
+ value: 100,
+ units: { applies_to: "trigger.source", applies_vs: "any" },
+ trigger_damage_jobs: [{ source: "use.source", target: extraTargets }],
+ duration: { type: "attack", value: 1 }
+ }
+ }
+ }
+ }
+ }
+ });
+}
diff --git a/simulator/src/simulator.ts b/simulator/src/simulator.ts
--- a/simulator/src/simulator.ts
+++ b/simulator/src/simulator.ts
@@ -53,6 +53,7 @@
extraSkillAttackJobsByEffect: Record<string, number>;
attackControlCounts: { dodge: number; no_attack: number };
consumedEffectUseKeys: Set<string>;
+ carryAttackDurationEffectsToTriggeredExtraSkillDamage: boolean;
counters: {
attacks: Record<SideId, Record<UnitType, number>>;
received: Record<SideId, Record<UnitType, number>>;
@@ -112,7 +113,7 @@
const attacker = resolveFighter(input.attacker, "attacker", config, input.mechanics);
const defender = resolveFighter(input.defender, "defender", config, input.mechanics);
const fighters: Record<SideId, ResolvedFighter> = { attacker, defender };
- const runtime = createRuntime([attacker, defender], createSeededRng(input.seed ?? "simulator-default"));
+ const runtime = createRuntime([attacker, defender], createSeededRng(input.seed ?? "simulator-default"), input.mechanics);
const detail = options.detail ?? "full";
const traceEnabled = detail === "full" && input.trace;
const trace: BattleTrace | undefined = traceEnabled ? { resolved: buildResolved(attacker, defender), rounds: [] } : undefined;
@@ -289,7 +290,7 @@
return Number.isFinite(value) && value > 0 && value < 100;
}
-function createRuntime(fighters: ResolvedFighter[], rng: Rng): Runtime {
+function createRuntime(fighters: ResolvedFighter[], rng: Rng, mechanics?: BattleInput["mechanics"]): Runtime {
const reports: Record<SideId, Map<string, SkillReportEntry>> = { attacker: new Map(), defender: new Map() };
const skills = buildRuntimeSkills(fighters);
for (const fighter of fighters) {
@@ -321,6 +322,7 @@
extraSkillAttackJobsByEffect: {},
attackControlCounts: { dodge: 0, no_attack: 0 },
consumedEffectUseKeys: new Set(),
+ carryAttackDurationEffectsToTriggeredExtraSkillDamage: mechanics?.carryAttackDurationEffectsToTriggeredExtraSkillDamage === true,
counters: {
attacks: { attacker: emptyTroops(), defender: emptyTroops() },
received: { attacker: emptyTroops(), defender: emptyTroops() }
@@ -513,6 +515,9 @@
roundStartTroops: DamageJob["roundStartTroops"]
): DamageJob[] {
const jobs: DamageJob[] = [];
+ const carriedAttackDurationEffectIds = runtime.carryAttackDurationEffectsToTriggeredExtraSkillDamage
+ ? attackDurationBucketEffectIdsForJob(normalAttack, round, runtime.activeEffects)
+ : undefined;
const effectGroups = selectStackedExtraAttackEffectGroups(
runtime.effectIndex.extraAttacks.filter((effect) => isEffectActive(effect, round) && extraAttackEffectAppliesToNormalAttack(effect, normalAttack)),
round
@@ -548,6 +553,7 @@
sourceEffectId,
sourceSkillReportKey,
sourceMultiplier: multiplier,
+ carriedAttackDurationEffectIds,
consumedEffectIds,
consumedEffectUseKey,
consumedEffectUseId: effect.id,
@@ -683,10 +689,14 @@
const available = Math.max(0, roundStartTroops[side][unit] ?? 0);
const totalKills = matching.reduce((sum, outcome) => sum + outcome.kills, 0);
if (totalKills <= available) continue;
- let remaining = available;
+ let appliedKills = 0;
+ let rawRemaining = available;
for (const outcome of matching) {
- outcome.kills = Math.min(outcome.kills, remaining);
- remaining -= outcome.kills;
+ const rawKills = outcome.kills;
+ outcome.kills = Math.min(rawKills, Math.max(0, available - appliedKills));
+ appliedKills += outcome.kills;
+ rawRemaining = Math.max(0, rawRemaining - rawKills);
+ if (rawRemaining === 0) appliedKills = available;
if (outcome.trace) outcome.trace.finalKills = outcome.kills;
}
}
@@ -745,6 +755,16 @@
.map((effect) => effect.id);
}
+function attackDurationBucketEffectIdsForJob(job: DamageJob, round: number, effects: ActiveEffect[]): string[] {
+ return effects
+ .filter((effect) => {
+ if (effect.kind === "extra_attack" || effect.duration.type !== "attack" || !isEffectActive(effect, round)) return false;
+ const classification = classifyEffectForJob(effect, job);
+ return classification?.kind === "bucket";
+ })
+ .map((effect) => effect.id);
+}
+
function consumeEffects(
runtime: Runtime,
consumedEffectIds: string[],
diff --git a/simulator/src/testcases.test.ts b/simulator/src/testcases.test.ts
--- a/simulator/src/testcases.test.ts
+++ b/simulator/src/testcases.test.ts
@@ -285,6 +285,25 @@
assert.deepEqual(input.mechanics, { weather: "clear", engagement_type: "rally" });
});
+test("adaptTestcaseEntry merges option mechanics without replacing testcase mechanics", () => {
+ const input = adaptTestcaseEntry(
+ {
+ test_id: "mechanics_case",
+ engagement_type: "rally",
+ mechanics: { weather: "clear" },
+ attacker: { troops: { infantry_t1: 1 } },
+ defender: { troops: { infantry_t1: 1 } }
+ },
+ { mechanics: { carryAttackDurationEffectsToTriggeredExtraSkillDamage: true } }
+ );
+
+ assert.deepEqual(input.mechanics, {
+ weather: "clear",
+ carryAttackDurationEffectsToTriggeredExtraSkillDamage: true,
+ engagement_type: "rally"
+ });
+});
+
test("compareOutcomeDistribution matches deterministic zero-bias shape", () => {
const metrics = compareOutcomeDistribution({
candidate: { n: 1, mu: -186, sigma: 0 },
diff --git a/simulator/src/testcases.ts b/simulator/src/testcases.ts
--- a/simulator/src/testcases.ts
+++ b/simulator/src/testcases.ts
@@ -27,6 +27,7 @@
seed?: string | number;
trace?: boolean;
workers?: number;
+ mechanics?: Record<string, unknown>;
}
export interface TestcaseCaseReport {
@@ -207,7 +208,7 @@
const detail = emptyCaseReport(reportFile, testcaseId, index, diagnostics);
const preparedCase: PreparedTestcaseCase = { file, reportFile, entry, testcaseId, index, detail };
try {
- preparedCase.input = adaptTestcaseEntry(entry, { seed: options.seed, trace: options.trace }, diagnostics);
+ preparedCase.input = adaptTestcaseEntry(entry, { seed: options.seed, trace: options.trace, mechanics: options.mechanics }, diagnostics);
preparedCase.key = snapshotKey(reportFile, index);
} catch (error) {
detail.error = errorMessage(error);
@@ -613,7 +614,11 @@
return summary;
}
-export function adaptTestcaseEntry(entry: unknown, options: { seed?: string | number; trace?: boolean } = {}, diagnostics: string[] = []): BattleInput {
+export function adaptTestcaseEntry(
+ entry: unknown,
+ options: { seed?: string | number; trace?: boolean; mechanics?: Record<string, unknown> } = {},
+ diagnostics: string[] = []
+): BattleInput {
const object = entry as {
attacker?: FighterInput;
defender?: FighterInput;
@@ -626,7 +631,7 @@
};
if (!object.attacker || !object.defender) throw new Error(`Testcase ${object.test_id ?? "(unknown)"} is missing attacker or defender`);
diagnostics.push(...diagnoseFighterShape("attacker", object.attacker), ...diagnoseFighterShape("defender", object.defender));
- const mechanics = testcaseMechanics(object);
+ const mechanics = testcaseMechanics(object, options.mechanics);
const maxRounds = optionalNumber(object.maxRounds ?? object.max_rounds);
return {
attacker: object.attacker,
@@ -702,8 +707,12 @@
return diagnostics;
}
-function testcaseMechanics(entry: { mechanics?: Record<string, unknown>; engagement_type?: unknown; engagementType?: unknown }): Record<string, unknown> | undefined {
+function testcaseMechanics(
+ entry: { mechanics?: Record<string, unknown>; engagement_type?: unknown; engagementType?: unknown },
+ optionMechanics?: Record<string, unknown>
+): Record<string, unknown> | undefined {
const mechanics = entry.mechanics && typeof entry.mechanics === "object" ? { ...entry.mechanics } : {};
+ if (optionMechanics && typeof optionMechanics === "object") Object.assign(mechanics, optionMechanics);
if (entry.engagement_type !== undefined) mechanics.engagement_type = entry.engagement_type;
if (entry.engagementType !== undefined) mechanics.engagementType = entry.engagementType;
return Object.keys(mechanics).length > 0 ? mechanics : undefined;
diff --git a/simulator/src/types.ts b/simulator/src/types.ts
--- a/simulator/src/types.ts
+++ b/simulator/src/types.ts
@@ -277,6 +277,7 @@
sourceEffectId?: string;
sourceSkillReportKey?: string;
sourceMultiplier?: number;
+ carriedAttackDurationEffectIds?: string[];
consumedEffectIds?: string[];
consumedEffectUseKey?: string;
consumedEffectUseId?: string;

Accuracy Results

178 / 178
FileCase#AdjS nG nS μG μBias%tqPW
testcases/1-testcases_no-heroes_t6_single-type_nc.jsondaut_viper_90115302.05302.00.00%P
testcases/1-testcases_no-heroes_t6_single-type_nc.jsondaut_viper_10111-1618.0-1618.00.00%P
testcases/1-testcases_no-heroes_t6_single-type_nc.jsondaut_viper_11211-376.0-376.00.00%P
testcases/1-testcases_no-heroes_t6_single-type_nc.jsondaut_viper_12311-6.0-6.00.00%P
testcases/1-testcases_no-heroes_t6_single-type_nc.jsondaut_viper_134111462.01462.00.00%P
testcases/1-testcases_no-heroes_t6_single-type_nc.jsondaut_viper_14511525.0525.00.00%P
testcases/1-testcases_no-heroes_t6_single-type_nc.jsondaut_viper_156+0.015%11-254.0-254.00.00%P
testcases/1-testcases_no-heroes_t6_single-type_nc.jsondaut_viper_167+0.009%111425.01425.00.00%P
testcases/1-testcases_no-heroes_t6_single-type_nc.jsondaut_viper_178-0.003%11986.0986.00.00%P
testcases/1-testcases_no-heroes_t6_single-type_nc.jsondaut_viper_189+0.024%11-177.0-177.00.00%P
testcases/1-testcases_no-heroes_t6_single-type_nc.jsondaut_viper_191011-489.0-489.00.00%P
testcases/1-testcases_no-heroes_t6_single-type_nc.jsondaut_viper_2011-0.01%11712.0712.00.00%P
testcases/1-testcases_no-heroes_t6_single-type_nc.jsondaut_viper_2112+0.016%11-193.0-193.00.00%P
testcases/1-testcases_no-heroes_t6_single-type_nc.jsondaut_viper_2213111309.01309.00.00%P
testcases/1-testcases_no-heroes_t6_single-type_nc.jsondaut_viper_231411-277.0-277.00.00%P
testcases/1-testcases_no-heroes_t6_single-type_nc.jsondaut_viper_2415-0.016%11585.0585.00.00%P
testcases/1-testcases_no-heroes_t6_single-type_nc.jsondaut_viper_251611-45.0-45.00.00%P
testcases/1-testcases_no-heroes_t6_single-type_nc.jsondaut_viper_2617-0.002%11798.0798.00.00%P
testcases/2-testcases_no-heroes_t6_mixed_nc.jsondaut_viper_10+0.05%11735.0741.0-0.32%F
testcases/2-testcases_no-heroes_t6_mixed_nc.jsondaut_viper_21+0.05%11-62.0-61.0-0.06%P
testcases/2-testcases_no-heroes_t6_mixed_nc.jsondaut_viper_32+0.05%11771.0778.0-0.38%F
testcases/2-testcases_no-heroes_t6_mixed_nc.jsondaut_viper_43+0.05%11345.0353.0-0.45%F
testcases/2-testcases_no-heroes_t6_mixed_nc.jsondaut_viper_54+0.047%11264.0264.00.00%P
testcases/2-testcases_no-heroes_t6_mixed_nc.jsondaut_viper_65+0.05%11-90.0-89.0-0.07%P
testcases/3-testcases_mixed-heroes-not-verified.jsondaut_viper_10+0.05%11345.0342.00.19%F
testcases/3-testcases_mixed-heroes-not-verified.jsondaut_viper_211001-3729.0-3729.00.00%P
testcases/3-testcases_mixed-heroes-not-verified.jsondaut_viper_321001-2912.3-2823.0-0.42%-3.470.011P
testcases/3-testcases_mixed-heroes-not-verified.jsondaut_viper_431001-516.1-519.00.02%0.400.89P
testcases/3-testcases_mixed-heroes-not-verified.jsondaut_viper_5410019362.09282.00.64%1.860.44P
testcases/3-testcases_mixed-heroes-not-verified.jsondaut_viper_751001-2274.0-2295.00.16%2.250.24P
testcases/4-testcases_no-heroes_infantry_fc5.jsonNitro_Beast_30_1010013-45545.1-45251.0-0.22%-0.580.88P
testcases/emulator_verified/ahmose_solo_nc.jsonahmose_solo0-0.05%112636.02633.00.06%F
testcases/emulator_verified/alonso_attacker_600_all.jsonalonso_attacker_600_all01006-256.4-253.0-0.14%-0.750.88P
testcases/emulator_verified/alonso_attacker_900_inf_lancer.jsonalonso_attacker_900_inf_lancer01004-463.5-464.50.04%1.820.44P
testcases/emulator_verified/alonso_attacker_900_inf_lancer.jsonalonso_attacker_900_inf_lancer11002-459.6-460.00.02%0.480.88P
testcases/emulator_verified/alonso_minxxx_defender.jsonalonso_minxxx_defender010081453.41450.40.14%0.460.88P
testcases/emulator_verified/alonso_norah_combo.jsonalonso_norah_combo01002-393.3-393.0-0.02%-0.150.95P
testcases/emulator_verified/alonso_norah_combo.jsonalonso_norah_combo11001-353.4-349.0-0.26%-1.650.47P
testcases/emulator_verified/alonso_norah_combo.jsonalonso_norah_combo21002-393.0-390.0-0.18%-1.430.57P
testcases/emulator_verified/alonso_solo.jsonalonso_solo0100101243.41104.82.97%1.200.63P
testcases/emulator_verified/alonso_solo_v2.jsonalonso_solo_v201006-493.2-513.71.58%0.870.83P
testcases/emulator_verified/alonso_solo_v2.jsonalonso_solo_v2110019-10.010.6-1.59%-1.060.73P
testcases/emulator_verified/alonso_vs_alonso.jsonalonso_vs_alonso010081551.01554.6-0.17%-0.660.88P
testcases/emulator_verified/alonso_vs_alonso_inf_lancer.jsonalonso_vs_alonso_inf_lancer01008-751.5-749.0-0.04%-0.470.88P
testcases/emulator_verified/alonso_wip_attacker.jsonalonso_wip_attacker010081768.21768.9-0.03%-0.400.89P
testcases/emulator_verified/ambusher_no_marksmen.jsonambusher_no_marksmen01001-103728.6-105686.00.64%0.990.74P
testcases/emulator_verified/attdef_jasser_patrick_minxxx_attacks_nc.jsonattdef_jasser_patrick_minxxx_attacks0+0.05%13-807.0-807.00.00%P
testcases/emulator_verified/attdef_jasser_patrick_nc.jsonattdef_jasser_patrick013-1138.0-1138.00.00%P
testcases/emulator_verified/attdef_jasser_patrick_swap_nc.jsonattdef_jasser_patrick_swap0131088.01088.00.00%P
testcases/emulator_verified/attdef_jasser_patrick_wip_attacks_nc.jsonattdef_jasser_patrick_wip_attacks0-0.05%11807.0807.00.00%P
testcases/emulator_verified/attdef_jasser_patrick_wip_attacks_nc.jsonattdef_jasser_patrick_wip_attacks1-0.05%12807.0807.00.00%P
testcases/emulator_verified/attdef_test_minxxx_attacks_nc.jsonattdef_test_minxxx_attacks_nc0-0.05%111133.01131.00.08%F
testcases/emulator_verified/attdef_test_wip_attacks_nc.jsonattdef_test_wip_attacks_nc012-1138.0-1138.00.00%P
testcases/emulator_verified/bahiti_norah_combo_nc.jsonbahiti_norah_combo_nc01001197.3269.0-2.99%-0.470.88P
testcases/emulator_verified/bahiti_solo.jsonbahiti_solo010022221.12206.00.32%0.390.89P
testcases/emulator_verified/bahiti_solo_nc.jsonbahiti_solo_nc010013677.03675.00.04%0.380.89P
testcases/emulator_verified/determinism_test_normal_nc.jsondeterminism_test_normal014852.0852.00.00%P
testcases/emulator_verified/determinism_test_swapped_nc.jsondeterminism_test_swapped011-852.0-852.00.00%P
testcases/emulator_verified/flint_reina_zinman_combo.jsonflint_reina_zinman_combo01001-443.2-439.0-0.10%-0.550.88P
testcases/emulator_verified/flint_solo_nc.jsonflint_solo0112862.02862.00.00%P
testcases/emulator_verified/flint_zinman_combo_nc.jsonflint_zinman_combo_nc0111005.01005.00.00%P
testcases/emulator_verified/greg_mia_combo.jsongreg_mia_combo0+0.05%10042392.82508.3-2.47%-1.840.44P
testcases/emulator_verified/greg_mia_combo.jsongreg_mia_combo1-0.05%10053478.13432.80.97%4.620.00034F
testcases/emulator_verified/greg_mia_defender_current.jsongreg_mia_defender_current0100183342.33351.6-0.20%-1.550.50P
testcases/emulator_verified/greg_mia_nohero_control_current.jsongreg_mia_nohero_control_current0133752.03752.00.00%P
testcases/emulator_verified/greg_mia_nohero_control_current.jsongreg_mia_nohero_control_current1+0.05%133652.03652.00.00%P
testcases/emulator_verified/greg_only_defender_current.jsongreg_only_defender_current010063682.73685.8-0.07%-0.960.74P
testcases/emulator_verified/greg_only_defender_current.jsongreg_only_defender_current110023582.23585.0-0.06%-0.560.88P
testcases/emulator_verified/greg_only_defender_current.jsongreg_only_defender_current2100203590.73594.6-0.08%-2.280.24P
testcases/emulator_verified/greg_solo.jsongreg_solo010012695.22697.0-0.04%-0.100.95P
testcases/emulator_verified/gwen_norah_combo_nc.jsongwen_norah_combo_nc010012698.42668.00.65%0.490.88P
testcases/emulator_verified/gwen_solo_nc.jsongwen_solo0-0.05%153017.03006.00.24%F
testcases/emulator_verified/hector_patrick_combo.jsonhector_patrick_combo01001-590.7-590.0-0.05%-0.970.74P
testcases/emulator_verified/hector_renee_wayne.jsondeterminism_test_normal0-0.05%10011607.81597.00.54%4.410.00043F
testcases/emulator_verified/hector_solo.jsonhector_solo01005-388.8-394.40.12%0.510.88P
testcases/emulator_verified/jasser_solo_nc.jsonjasser_solo0+0.05%112740.02740.00.00%P
testcases/emulator_verified/jessie_solo_nc.jsonjessie_solo0-0.05%1379.079.00.00%P
testcases/emulator_verified/ling_xue_solo_nc.jsonling_xue_solo0+0.05%112822.02822.00.00%P
testcases/emulator_verified/ling_xue_solo_nc.jsonling_xue_solo1+0.05%113214.03215.0-0.02%P
testcases/emulator_verified/logan_bahiti_combo_nc.jsonlogan_bahiti_combo_nc01001-507.1-517.00.55%0.800.88P
testcases/emulator_verified/logan_gwen_combo_nc.jsonlogan_gwen_combo_nc0-0.05%11-400.0-403.00.13%F
testcases/emulator_verified/logan_lynn_combo.jsonlogan_lynn_combo01001-551.1-553.00.08%1.130.67P
testcases/emulator_verified/logan_lynn_combo.jsonlogan_lynn_combo11002551.1550.50.03%0.510.88P
testcases/emulator_verified/logan_lynn_combo.jsonlogan_lynn_combo21002551.0551.00.00%0.010.99P
testcases/emulator_verified/logan_reina_bahiti_combo_nc.jsonlogan_reina_bahiti_combo_nc01001-492.9-482.0-0.50%-0.710.88P
testcases/emulator_verified/logan_solo_minxxx_nc.jsonlogan_solo_minxxx011-1995.0-1995.00.00%P
testcases/emulator_verified/logan_solo_v2_nc.jsonlogan_solo_v2011-1134.0-1134.00.00%P
testcases/emulator_verified/lumak_bokan_solo_nc.jsonlumak_bokan_solo0+0.05%112797.02797.00.00%P
testcases/emulator_verified/lumak_bokan_solo_nc.jsonlumak_bokan_solo1+0.05%113127.03127.00.00%P
testcases/emulator_verified/lynn_solo.jsonlynn_solo01005-185.1-181.2-0.08%-0.440.89P
testcases/emulator_verified/mia_only_defender_current.jsonmia_only_defender_current0100103540.83543.9-0.07%-0.630.88P
testcases/emulator_verified/mia_only_defender_current.jsonmia_only_defender_current1100203439.73449.2-0.21%-2.460.24P
testcases/emulator_verified/mia_solo.jsonmia_solo01001-269.3-260.0-0.27%-0.970.74P
testcases/emulator_verified/mia_solo.jsonmia_solo110011297.91293.00.22%0.590.88P
testcases/emulator_verified/mia_solo.jsonmia_solo21001-185.0-180.0-0.32%-1.010.74P
testcases/emulator_verified/mia_solo.jsonmia_solo31001879.6879.00.04%0.140.95P
testcases/emulator_verified/mia_solo.jsonmia_solo41001969.9967.00.21%0.650.88P
testcases/emulator_verified/molly_lynn_combo.jsonmolly_lynn_combo01005-402.8-402.80.00%0.040.98P
testcases/emulator_verified/molly_solo.jsonmolly_solo01005244.0244.8-0.07%-1.670.47P
testcases/emulator_verified/natalia_solo.jsonnatalia_solo0+0.005%10012612.52664.0-1.10%-2.330.24F
testcases/emulator_verified/norah_greg_combo.jsonnorah_greg_combo01005-367.6-366.0-0.10%-1.290.63P
testcases/emulator_verified/norah_hector_zinman_combo.jsonnorah_hector_zinman_combo01005-269.2-270.40.08%1.620.48P
testcases/emulator_verified/norah_s2_inf_only_A.jsonnorah_s2_inf_only_A0+0.05%100492.798.5-0.35%-1.190.63P
testcases/emulator_verified/norah_s2_inf_only_B_nc.jsonnorah_s2_inf_only_B0+0.05%13507.0507.00.00%P
testcases/emulator_verified/norah_s2_splash_A.jsonnorah_s2_splash_A010011785.21780.00.23%0.350.90P
testcases/emulator_verified/norah_s2_splash_B_nc.jsonnorah_s2_splash_B0131900.01900.00.00%P
testcases/emulator_verified/norah_s2_splash_C_nc.jsonnorah_s2_splash_C0131153.01153.00.00%P
testcases/emulator_verified/norah_s2_splash_D.jsonnorah_s2_splash_D01003829.5827.30.12%0.720.88P
testcases/emulator_verified/norah_solo.jsonnorah_solo010072740.12753.1-0.28%-0.710.88P
testcases/emulator_verified/norah_zinman_combo_nc.jsonnorah_zinman_combo_nc01001679.3670.00.39%0.130.95P
testcases/emulator_verified/patrick_solo_nc.jsonpatrick_solo0+0.011%112581.02582.0-0.02%P
testcases/emulator_verified/philly_bahiti_combo.jsonphilly_bahiti_combo01001-558.3-556.0-0.13%-1.220.63P
testcases/emulator_verified/philly_bahiti_combo.jsonphilly_bahiti_combo11004-453.9-458.30.24%1.770.44P
testcases/emulator_verified/philly_solo.jsonphilly_solo010022264.32253.00.24%0.200.95P
testcases/emulator_verified/philly_solo.jsonphilly_solo110033620.93619.70.03%0.170.95P
testcases/emulator_verified/reina_attacker_wip.jsonreina_attacker_wip01001-1991.7-1992.00.01%0.520.88P
testcases/emulator_verified/reina_bahiti_combo_nc.jsonreina_bahiti_combo_nc01001-481.8-502.01.12%1.260.63P
testcases/emulator_verified/reina_logan_combo_simulator.jsonreina_logan_combo_simulator01001-549.5-553.00.14%1.280.63P
testcases/emulator_verified/reina_solo_wip.jsonreina_solo_wip010011991.61992.0-0.02%-0.590.88P
testcases/emulator_verified/renee_solo_nc.jsonrenee_solo_nc0+0.033%15-562.0-554.0-0.43%F
testcases/emulator_verified/seo_yoon_solo_nc.jsonseo_yoon_solo0-0.05%13-619.0-620.00.10%P
testcases/emulator_verified/sergey_norah_zinman_combo_nc.jsonsergey_norah_zinman_combo_nc010011328.91372.0-1.44%-0.710.88P
testcases/emulator_verified/sergey_reina_combo_nc.jsonsergey_reina_combo_nc01001-303.3-295.0-0.35%-0.290.92P
testcases/emulator_verified/sergey_solo_nc.jsonsergey_solo0-0.05%121348.01348.00.00%P
testcases/emulator_verified/simple_001_nc.jsonsimple_00101001-186.0-186.00.00%P
testcases/emulator_verified/troop_check_nc.jsontroop_check011-279.0-279.00.00%P
testcases/emulator_verified/type_triangle_A_nc.jsontype_triangle_A_nc0+0.05%11-895.0-895.00.00%P
testcases/emulator_verified/type_triangle_B_nc.jsontype_triangle_B_nc011-929.0-929.00.00%P
testcases/emulator_verified/wayne_mixed_solo.jsonwayne_mixed_solo01004232.9237.0-0.23%-0.110.95P
testcases/emulator_verified/wayne_mixed_solo.jsonwayne_mixed_solo11007310.4346.6-2.01%-1.770.44P
testcases/emulator_verified/wayne_reina_combo.jsonwayne_reina_combo010081550.41559.4-0.37%-1.710.47P
testcases/emulator_verified/wayne_reina_wuming_combo.jsonwayne_reina_wuming_combo010081698.21694.00.18%1.990.40P
testcases/emulator_verified/wayne_s1_solo.jsonwayne_s1_solo01005254.0251.80.36%1.300.63P
testcases/emulator_verified/wayne_s2_solo.jsonwayne_s2_solo01002363.7361.50.43%1.250.63P
testcases/emulator_verified/wos425_wip_nohero_control_nc.jsonwos425_wip_nohero_control_nc011774.0774.00.00%P
testcases/emulator_verified/wos425_wip_patrick_health_nc.jsonwos425_wip_patrick_health_nc011762.0762.00.00%P
testcases/emulator_verified/wos425_wip_philly_defense.jsonwos425_wip_philly_defense01005768.4768.6-0.02%-0.590.88P
testcases/emulator_verified/wos425_wip_sergey_damage_taken_nc.jsonwos425_wip_sergey_damage_taken_nc011749.0749.00.00%P
testcases/emulator_verified/wos425_wip_sergey_patrick_combo_nc.jsonwos425_wip_sergey_patrick_combo_nc011726.0726.00.00%P
testcases/emulator_verified/wos425_wip_sergey_philly_combo.jsonwos425_wip_sergey_philly_combo01005738.1738.2-0.01%-0.240.95P
testcases/emulator_verified/wos427_wip_sergey_philly_840.jsonwos427_wip_sergey_philly_8400100417.922.5-0.28%-0.310.92P
testcases/emulator_verified/wu_ming_solo_nc.jsonwu_ming_solo0111392.01392.00.00%P
testcases/emulator_verified/zinman_solo_nc.jsonzinman_solo0+0.05%113177.03177.00.00%P
testcases/heroes_unittests/Flint_tc.jsondaut_viper_10+0.05%15-150.0-149.8-0.01%P
testcases/heroes_unittests/Flint_tc.jsondaut_viper_21-0.05%165773.05732.70.56%F
testcases/heroes_unittests/Hector_tc.jsondaut_viper_101001-441.6-441.00.00%-0.130.95P
testcases/heroes_unittests/Jessie_tc_nc.jsondaut_viper_10+0.05%11-62.0-61.0-0.06%P
testcases/heroes_unittests/Jessie_tc_nc.jsondaut_viper_21+0.05%11-90.0-89.0-0.07%P
testcases/heroes_unittests/Jessie_tc_nc.jsondaut_viper_32-0.039%11481.0481.00.00%P
testcases/heroes_unittests/Jessie_tc_nc.jsondaut_viper_43-0.024%11217.0217.00.00%P
testcases/heroes_unittests/Jessie_tc_nc.jsondaut_viper_5411578.0578.00.00%P
testcases/heroes_unittests/Jessie_tc_nc.jsondaut_viper_65+0.05%11-97.0-96.0-0.06%P
testcases/heroes_unittests/Jessie_tc_nc.jsondaut_viper_76+0.05%11-75.0-74.0-0.05%P
testcases/heroes_unittests/Jessie_tc_nc.jsondaut_viper_8711-988.0-988.00.00%P
testcases/heroes_unittests/Mia_tc.jsondaut_viper_101001-173.5-181.00.17%1.570.50P
testcases/heroes_unittests/Mia_tc.jsondaut_viper_21+0.05%10071591.81625.1-0.77%-2.250.24F
testcases/heroes_unittests/Mia_tc.jsondaut_viper_3210061122.01124.2-0.10%-1.480.54P
testcases/heroes_unittests/Mia_tc.jsondaut_viper_431001668.1671.0-0.13%-0.310.92P
testcases/heroes_unittests/Mia_tc.jsondaut_viper_541004-124.3-121.8-0.11%-1.250.63P
testcases/heroes_unittests/Molly_tc.jsondaut_viper_10+0.05%11-62.0-61.0-0.06%P
testcases/heroes_unittests/Molly_tc.jsondaut_viper_21+0.05%11-90.0-89.0-0.07%P
testcases/heroes_unittests/Molly_tc.jsondaut_viper_32-0.039%11481.0481.00.00%P
testcases/heroes_unittests/Molly_tc.jsondaut_viper_431001-63.5-68.00.33%3.730.0055P
testcases/heroes_unittests/Molly_tc.jsondaut_viper_541001-190.3-190.0-0.02%-0.210.95P
testcases/heroes_unittests/Reina_tc.jsondaut_viper_10+0.05%11-66.0-62.0-0.18%F
testcases/heroes_unittests/Reina_tc.jsondaut_viper_2111-40.0-40.00.00%P
testcases/heroes_unittests/Reina_tc.jsondaut_viper_4210061413.41428.3-0.46%-0.280.92P
testcases/heroes_unittests/Reina_tc.jsondaut_viper_531001-201.9-202.00.01%0.060.98P
testcases/heroes_unittests/Seo-yoon_tc_nc.jsondaut_viper_10+0.05%11-62.0-61.0-0.06%P
testcases/heroes_unittests/Seo-yoon_tc_nc.jsondaut_viper_61+0.05%11-90.0-89.0-0.07%P
testcases/heroes_unittests/Seo-yoon_tc_nc.jsondaut_viper_32-0.039%11481.0481.00.00%P
testcases/heroes_unittests/Seo-yoon_tc_nc.jsondaut_viper_43+0.05%114339.04341.0-0.04%F
testcases/heroes_unittests/Seo-yoon_tc_nc.jsondaut_viper_54+0.05%113802.03805.0-0.06%F
testcases/heroes_unittests/Seo-yoon_tc_nc.jsondaut_viper_65-0.03%11915.0915.00.00%P
testcases/heroes_unittests/Seo-yoon_tc_nc.jsondaut_viper_76-0.034%112129.02128.00.02%P
testcases/heroes_unittests/Zinman_tc.jsondaut_viper_10-0.05%11-122.0-122.00.00%P
testcases/heroes_unittests/Zinman_tc.jsondaut_viper_21-0.032%114018.04018.00.00%P
testcases/heroes_unittests/Zinman_tc.jsondaut_viper_32-0.05%11-130.0-130.00.00%P