Compare commits

..

No commits in common. "3c827be346298bed9273a0a66a2d8d47f753db6b" and "ee217deaf119a88c17622b6e2c90ff955639d621" have entirely different histories.

22 changed files with 0 additions and 1683 deletions

View File

@ -1,44 +0,0 @@
/**
* Diablo II: Lord of Destruction v1.13c — Skill #271: Lightning Sentry (ASS)
*
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
* - Skill ID: 271 ("Lightning Sentry")
* - Class: "ass"
* - Required Level: 24
* - Server Functions: srvstfunc=0, srvdofunc=45, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
* - Associated Missile / State / Summon: missile="", state="", summon="lightningsentry"
* - 1.13c Synergy Formulas: EDmgSymPerCalc="(skill('Shock Field'.blvl) + skill('Charged Bolt Sentry'.blvl) + skill('Death Sentry'.blvl))*par8", DmgSymPerCalc="", ELenSymPerCalc=""
*/
import type {
SkillEvalContext,
SkillEvalResult,
SkillExecContext,
SkillExecOutcome,
SkillModule,
} from '../../types.ts'
import { evaluateSkillCore113c, executeSkillCore113c } from '../../registry.ts'
export const skillModule: SkillModule = {
skillId: 271,
name: "Lightning Sentry",
charClass: "ass",
srvStFunc: 0,
srvDoFunc: 45,
evaluate(ctx: SkillEvalContext): SkillEvalResult {
return evaluateSkillCore113c(ctx)
},
executeDo(ctx: SkillExecContext): SkillExecOutcome {
const outcome = executeSkillCore113c(ctx)
return {
...outcome,
notes: [
...outcome.notes,
'skill_module:skill-271-lightning-sentry',
],
}
},
}
export default skillModule

View File

@ -1,44 +0,0 @@
/**
* Diablo II: Lord of Destruction v1.13c — Skill #272: Inferno Sentry (ASS)
*
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
* - Skill ID: 272 ("Inferno Sentry")
* - Class: "ass"
* - Required Level: 24
* - Server Functions: srvstfunc=0, srvdofunc=45, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
* - Associated Missile / State / Summon: missile="", state="", summon="infernosentry"
* - 1.13c Synergy Formulas: EDmgSymPerCalc="(skill('Fire Trauma'.blvl) + skill('Death Sentry'.blvl)) * par7 + skill('Wake of Fire Sentry'.blvl)*par8", DmgSymPerCalc="", ELenSymPerCalc=""
*/
import type {
SkillEvalContext,
SkillEvalResult,
SkillExecContext,
SkillExecOutcome,
SkillModule,
} from '../../types.ts'
import { evaluateSkillCore113c, executeSkillCore113c } from '../../registry.ts'
export const skillModule: SkillModule = {
skillId: 272,
name: "Inferno Sentry",
charClass: "ass",
srvStFunc: 0,
srvDoFunc: 45,
evaluate(ctx: SkillEvalContext): SkillEvalResult {
return evaluateSkillCore113c(ctx)
},
executeDo(ctx: SkillExecContext): SkillExecOutcome {
const outcome = executeSkillCore113c(ctx)
return {
...outcome,
notes: [
...outcome.notes,
'skill_module:skill-272-inferno-sentry',
],
}
},
}
export default skillModule

View File

@ -1,44 +0,0 @@
/**
* Diablo II: Lord of Destruction v1.13c — Skill #273: Mind Blast (ASS)
*
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
* - Skill ID: 273 ("Mind Blast")
* - Class: "ass"
* - Required Level: 24
* - Server Functions: srvstfunc=0, srvdofunc=51, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
* - Associated Missile / State / Summon: missile="", state="", summon=""
* - 1.13c Synergy Formulas: EDmgSymPerCalc="", DmgSymPerCalc="", ELenSymPerCalc=""
*/
import type {
SkillEvalContext,
SkillEvalResult,
SkillExecContext,
SkillExecOutcome,
SkillModule,
} from '../../types.ts'
import { evaluateSkillCore113c, executeSkillCore113c } from '../../registry.ts'
export const skillModule: SkillModule = {
skillId: 273,
name: "Mind Blast",
charClass: "ass",
srvStFunc: 0,
srvDoFunc: 51,
evaluate(ctx: SkillEvalContext): SkillEvalResult {
return evaluateSkillCore113c(ctx)
},
executeDo(ctx: SkillExecContext): SkillExecOutcome {
const outcome = executeSkillCore113c(ctx)
return {
...outcome,
notes: [
...outcome.notes,
'skill_module:skill-273-mind-blast',
],
}
},
}
export default skillModule

View File

@ -1,44 +0,0 @@
/**
* Diablo II: Lord of Destruction v1.13c — Skill #274: Blades of Ice (ASS)
*
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
* - Skill ID: 274 ("Blades of Ice")
* - Class: "ass"
* - Required Level: 24
* - Server Functions: srvstfunc=23, srvdofunc=35, srvprgfunc1=0, srvprgfunc2=38, srvprgfunc3=39
* - Associated Missile / State / Summon: missile="", state="progressive_cold", summon=""
* - 1.13c Synergy Formulas: EDmgSymPerCalc="(skill('Royal Strike'.blvl)) * par8", DmgSymPerCalc="", ELenSymPerCalc=""
*/
import type {
SkillEvalContext,
SkillEvalResult,
SkillExecContext,
SkillExecOutcome,
SkillModule,
} from '../../types.ts'
import { evaluateSkillCore113c, executeSkillCore113c } from '../../registry.ts'
export const skillModule: SkillModule = {
skillId: 274,
name: "Blades of Ice",
charClass: "ass",
srvStFunc: 23,
srvDoFunc: 35,
evaluate(ctx: SkillEvalContext): SkillEvalResult {
return evaluateSkillCore113c(ctx)
},
executeDo(ctx: SkillExecContext): SkillExecOutcome {
const outcome = executeSkillCore113c(ctx)
return {
...outcome,
notes: [
...outcome.notes,
'skill_module:skill-274-blades-of-ice',
],
}
},
}
export default skillModule

View File

@ -1,44 +0,0 @@
/**
* Diablo II: Lord of Destruction v1.13c — Skill #275: Dragon Flight (ASS)
*
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
* - Skill ID: 275 ("Dragon Flight")
* - Class: "ass"
* - Required Level: 24
* - Server Functions: srvstfunc=12, srvdofunc=52, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
* - Associated Missile / State / Summon: missile="", state="", summon=""
* - 1.13c Synergy Formulas: EDmgSymPerCalc="", DmgSymPerCalc="", ELenSymPerCalc=""
*/
import type {
SkillEvalContext,
SkillEvalResult,
SkillExecContext,
SkillExecOutcome,
SkillModule,
} from '../../types.ts'
import { evaluateSkillCore113c, executeSkillCore113c } from '../../registry.ts'
export const skillModule: SkillModule = {
skillId: 275,
name: "Dragon Flight",
charClass: "ass",
srvStFunc: 12,
srvDoFunc: 52,
evaluate(ctx: SkillEvalContext): SkillEvalResult {
return evaluateSkillCore113c(ctx)
},
executeDo(ctx: SkillExecContext): SkillExecOutcome {
const outcome = executeSkillCore113c(ctx)
return {
...outcome,
notes: [
...outcome.notes,
'skill_module:skill-275-dragon-flight',
],
}
},
}
export default skillModule

View File

@ -1,44 +0,0 @@
/**
* Diablo II: Lord of Destruction v1.13c — Skill #276: Death Sentry (ASS)
*
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
* - Skill ID: 276 ("Death Sentry")
* - Class: "ass"
* - Required Level: 30
* - Server Functions: srvstfunc=0, srvdofunc=45, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
* - Associated Missile / State / Summon: missile="", state="", summon="deathsentry"
* - 1.13c Synergy Formulas: EDmgSymPerCalc="(skill('Lightning Sentry'.blvl))*par8", DmgSymPerCalc="", ELenSymPerCalc=""
*/
import type {
SkillEvalContext,
SkillEvalResult,
SkillExecContext,
SkillExecOutcome,
SkillModule,
} from '../../types.ts'
import { evaluateSkillCore113c, executeSkillCore113c } from '../../registry.ts'
export const skillModule: SkillModule = {
skillId: 276,
name: "Death Sentry",
charClass: "ass",
srvStFunc: 0,
srvDoFunc: 45,
evaluate(ctx: SkillEvalContext): SkillEvalResult {
return evaluateSkillCore113c(ctx)
},
executeDo(ctx: SkillExecContext): SkillExecOutcome {
const outcome = executeSkillCore113c(ctx)
return {
...outcome,
notes: [
...outcome.notes,
'skill_module:skill-276-death-sentry',
],
}
},
}
export default skillModule

View File

@ -1,44 +0,0 @@
/**
* Diablo II: Lord of Destruction v1.13c — Skill #277: Blade Shield (ASS)
*
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
* - Skill ID: 277 ("Blade Shield")
* - Class: "ass"
* - Required Level: 30
* - Server Functions: srvstfunc=28, srvdofunc=54, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
* - Associated Missile / State / Summon: missile="blade shield attachment", state="bladeshield", summon=""
* - 1.13c Synergy Formulas: EDmgSymPerCalc="", DmgSymPerCalc="", ELenSymPerCalc=""
*/
import type {
SkillEvalContext,
SkillEvalResult,
SkillExecContext,
SkillExecOutcome,
SkillModule,
} from '../../types.ts'
import { evaluateSkillCore113c, executeSkillCore113c } from '../../registry.ts'
export const skillModule: SkillModule = {
skillId: 277,
name: "Blade Shield",
charClass: "ass",
srvStFunc: 28,
srvDoFunc: 54,
evaluate(ctx: SkillEvalContext): SkillEvalResult {
return evaluateSkillCore113c(ctx)
},
executeDo(ctx: SkillExecContext): SkillExecOutcome {
const outcome = executeSkillCore113c(ctx)
return {
...outcome,
notes: [
...outcome.notes,
'skill_module:skill-277-blade-shield',
],
}
},
}
export default skillModule

View File

@ -1,44 +0,0 @@
/**
* Diablo II: Lord of Destruction v1.13c — Skill #278: Venom (ASS)
*
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
* - Skill ID: 278 ("Venom")
* - Class: "ass"
* - Required Level: 30
* - Server Functions: srvstfunc=0, srvdofunc=18, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
* - Associated Missile / State / Summon: missile="", state="venomclaws", summon=""
* - 1.13c Synergy Formulas: EDmgSymPerCalc="", DmgSymPerCalc="", ELenSymPerCalc=""
*/
import type {
SkillEvalContext,
SkillEvalResult,
SkillExecContext,
SkillExecOutcome,
SkillModule,
} from '../../types.ts'
import { evaluateSkillCore113c, executeSkillCore113c } from '../../registry.ts'
export const skillModule: SkillModule = {
skillId: 278,
name: "Venom",
charClass: "ass",
srvStFunc: 0,
srvDoFunc: 18,
evaluate(ctx: SkillEvalContext): SkillEvalResult {
return evaluateSkillCore113c(ctx)
},
executeDo(ctx: SkillExecContext): SkillExecOutcome {
const outcome = executeSkillCore113c(ctx)
return {
...outcome,
notes: [
...outcome.notes,
'skill_module:skill-278-venom',
],
}
},
}
export default skillModule

View File

@ -1,44 +0,0 @@
/**
* Diablo II: Lord of Destruction v1.13c — Skill #279: Shadow Master (ASS)
*
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
* - Skill ID: 279 ("Shadow Master")
* - Class: "ass"
* - Required Level: 30
* - Server Functions: srvstfunc=0, srvdofunc=49, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
* - Associated Missile / State / Summon: missile="", state="shadowwarrior", summon="shadowmaster"
* - 1.13c Synergy Formulas: EDmgSymPerCalc="", DmgSymPerCalc="", ELenSymPerCalc=""
*/
import type {
SkillEvalContext,
SkillEvalResult,
SkillExecContext,
SkillExecOutcome,
SkillModule,
} from '../../types.ts'
import { evaluateSkillCore113c, executeSkillCore113c } from '../../registry.ts'
export const skillModule: SkillModule = {
skillId: 279,
name: "Shadow Master",
charClass: "ass",
srvStFunc: 0,
srvDoFunc: 49,
evaluate(ctx: SkillEvalContext): SkillEvalResult {
return evaluateSkillCore113c(ctx)
},
executeDo(ctx: SkillExecContext): SkillExecOutcome {
const outcome = executeSkillCore113c(ctx)
return {
...outcome,
notes: [
...outcome.notes,
'skill_module:skill-279-shadow-master',
],
}
},
}
export default skillModule

View File

@ -1,44 +0,0 @@
/**
* Diablo II: Lord of Destruction v1.13c — Skill #280: Royal Strike (ASS)
*
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
* - Skill ID: 280 ("Royal Strike")
* - Class: "ass"
* - Required Level: 30
* - Server Functions: srvstfunc=23, srvdofunc=34, srvprgfunc1=40, srvprgfunc2=143, srvprgfunc3=41
* - Associated Missile / State / Summon: missile="royalstrikemeteorcenter", state="progressive_other", summon=""
* - 1.13c Synergy Formulas: EDmgSymPerCalc="", DmgSymPerCalc="", ELenSymPerCalc=""
*/
import type {
SkillEvalContext,
SkillEvalResult,
SkillExecContext,
SkillExecOutcome,
SkillModule,
} from '../../types.ts'
import { evaluateSkillCore113c, executeSkillCore113c } from '../../registry.ts'
export const skillModule: SkillModule = {
skillId: 280,
name: "Royal Strike",
charClass: "ass",
srvStFunc: 23,
srvDoFunc: 34,
evaluate(ctx: SkillEvalContext): SkillEvalResult {
return evaluateSkillCore113c(ctx)
},
executeDo(ctx: SkillExecContext): SkillExecOutcome {
const outcome = executeSkillCore113c(ctx)
return {
...outcome,
notes: [
...outcome.notes,
'skill_module:skill-280-royal-strike',
],
}
},
}
export default skillModule

View File

@ -1,44 +0,0 @@
/**
* Diablo II: Lord of Destruction v1.13c — Skill #350: Delerium Change (UNI)
*
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
* - Skill ID: 350 ("Delerium Change")
* - Class: "uni"
* - Required Level: 1
* - Server Functions: srvstfunc=0, srvdofunc=116, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
* - Associated Missile / State / Summon: missile="", state="delerium", summon=""
* - 1.13c Synergy Formulas: EDmgSymPerCalc="", DmgSymPerCalc="", ELenSymPerCalc=""
*/
import type {
SkillEvalContext,
SkillEvalResult,
SkillExecContext,
SkillExecOutcome,
SkillModule,
} from '../../types.ts'
import { evaluateSkillCore113c, executeSkillCore113c } from '../../registry.ts'
export const skillModule: SkillModule = {
skillId: 350,
name: "Delerium Change",
charClass: "uni",
srvStFunc: 0,
srvDoFunc: 116,
evaluate(ctx: SkillEvalContext): SkillEvalResult {
return evaluateSkillCore113c(ctx)
},
executeDo(ctx: SkillExecContext): SkillExecOutcome {
const outcome = executeSkillCore113c(ctx)
return {
...outcome,
notes: [
...outcome.notes,
'skill_module:skill-350-delerium-change',
],
}
},
}
export default skillModule

View File

@ -1,109 +0,0 @@
/**
* 1.13c Numerical & Runtime Verification Suite — Skill #271: Lightning Sentry (ASS)
* Gitea Tracking Issue: #364
*/
import { describe, expect, it } from 'vitest'
import { getSharedDataRegistry } from '../../../src/game/engine/data-registry.ts'
import { UnitStatList } from '../../../src/game/engine/stat-list.ts'
import { WorldArena } from '../../../src/game/engine/world-arena.ts'
import { skillModule } from '../../../src/game/skills/impl/ass/skill-271-lightning-sentry.ts'
describe('[Skill #271] Lightning Sentry (ASS) — 1.13c Parity (Issue #364)', () => {
it('evaluates exact 1.13c Skills.txt / Missiles.txt formulas at slvl 1, 10, and 20', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(271)!
expect(skillRec).toBeDefined()
expect(skillModule.skillId).toBe(271)
expect(skillModule.name).toBe("Lightning Sentry")
expect(skillModule.charClass).toBe("ass")
const stats1 = new UnitStatList()
stats1.setBaseSkillLevel(271, 1)
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
expect(r1.manaCost).toBe(20)
expect(r1.manaCost256).toBe(5120)
expect(r1.minPhysDmg).toBe(0)
expect(r1.maxPhysDmg).toBe(0)
expect(r1.minElemDmg256).toBe(256)
expect(r1.maxElemDmg256).toBe(5120)
const stats10 = new UnitStatList()
stats10.setBaseSkillLevel(271, 10)
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
expect(r10.manaCost).toBe(20)
expect(r10.manaCost256).toBe(5120)
expect(r10.minPhysDmg).toBe(0)
expect(r10.maxPhysDmg).toBe(0)
expect(r10.minElemDmg256).toBe(256)
expect(r10.maxElemDmg256).toBe(31232)
const stats20 = new UnitStatList()
stats20.setBaseSkillLevel(271, 20)
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
expect(r20.manaCost).toBe(20)
expect(r20.manaCost256).toBe(5120)
expect(r20.minPhysDmg).toBe(0)
expect(r20.maxPhysDmg).toBe(0)
expect(r20.minElemDmg256).toBe(256)
expect(r20.maxElemDmg256).toBe(80384)
expect(r20.durationFrames).toBe(0)
expect(r20.radiusSubtiles).toBe(0)
expect(r20.petMax).toBe(5)
expect(r20.cooldownFrames).toBe(0)
})
it('enforces 1.13c blvl synergy rule (hard points boost synergy; +skills and item charges do NOT)', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(271)!
const synId = 256
const statsBase = new UnitStatList()
statsBase.setBaseSkillLevel(271, 20)
if (synId !== null) {
statsBase.setBaseSkillLevel(synId, 20)
}
const withHardPoints = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsBase,
})
expect(withHardPoints.synergyBonusPct).toBe(240)
// +20 allskills and +33 Marrowwalk charges without hard points must yield 0 synergy
const statsSoftOnly = new UnitStatList()
statsSoftOnly.setBaseSkillLevel(271, 20)
statsSoftOnly.addStat('item_allskills', 20)
if (synId !== null) {
statsSoftOnly.setChargedSkillLevel(synId, 33)
}
const withSoftOnly = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsSoftOnly,
})
expect(withSoftOnly.synergyBonusPct).toBe(0)
})
it('executes runtime skill effect in WorldArena (castCount, action frame, and combat/state/missile/summon outcome)', async () => {
const registry = await getSharedDataRegistry()
const arena = new WorldArena({
registry,
classCode: "ass",
skillId: 271,
slvl: 20,
})
const outcome = arena.triggerCast()
arena.stepTicks(15)
const dbg = arena.getDebugState()
expect(dbg.ready).toBe(true)
expect(dbg.skillId).toBe(271)
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
expect(dbg.actionFrameTriggered).toBe(true)
expect(outcome?.executed).toBe(true)
})
})

View File

@ -1,109 +0,0 @@
/**
* 1.13c Numerical & Runtime Verification Suite — Skill #272: Inferno Sentry (ASS)
* Gitea Tracking Issue: #365
*/
import { describe, expect, it } from 'vitest'
import { getSharedDataRegistry } from '../../../src/game/engine/data-registry.ts'
import { UnitStatList } from '../../../src/game/engine/stat-list.ts'
import { WorldArena } from '../../../src/game/engine/world-arena.ts'
import { skillModule } from '../../../src/game/skills/impl/ass/skill-272-inferno-sentry.ts'
describe('[Skill #272] Inferno Sentry (ASS) — 1.13c Parity (Issue #365)', () => {
it('evaluates exact 1.13c Skills.txt / Missiles.txt formulas at slvl 1, 10, and 20', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(272)!
expect(skillRec).toBeDefined()
expect(skillModule.skillId).toBe(272)
expect(skillModule.name).toBe("Inferno Sentry")
expect(skillModule.charClass).toBe("ass")
const stats1 = new UnitStatList()
stats1.setBaseSkillLevel(272, 1)
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
expect(r1.manaCost).toBe(20)
expect(r1.manaCost256).toBe(5120)
expect(r1.minPhysDmg).toBe(0)
expect(r1.maxPhysDmg).toBe(0)
expect(r1.minElemDmg256).toBe(320)
expect(r1.maxElemDmg256).toBe(800)
const stats10 = new UnitStatList()
stats10.setBaseSkillLevel(272, 10)
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
expect(r10.manaCost).toBe(20)
expect(r10.manaCost256).toBe(5120)
expect(r10.minPhysDmg).toBe(0)
expect(r10.maxPhysDmg).toBe(0)
expect(r10.minElemDmg256).toBe(2896)
expect(r10.maxElemDmg256).toBe(3664)
const stats20 = new UnitStatList()
stats20.setBaseSkillLevel(272, 20)
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
expect(r20.manaCost).toBe(20)
expect(r20.manaCost256).toBe(5120)
expect(r20.minPhysDmg).toBe(0)
expect(r20.maxPhysDmg).toBe(0)
expect(r20.minElemDmg256).toBe(6576)
expect(r20.maxElemDmg256).toBe(7664)
expect(r20.durationFrames).toBe(0)
expect(r20.radiusSubtiles).toBe(0)
expect(r20.petMax).toBe(5)
expect(r20.cooldownFrames).toBe(0)
})
it('enforces 1.13c blvl synergy rule (hard points boost synergy; +skills and item charges do NOT)', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(272)!
const synId = 251
const statsBase = new UnitStatList()
statsBase.setBaseSkillLevel(272, 20)
if (synId !== null) {
statsBase.setBaseSkillLevel(synId, 20)
}
const withHardPoints = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsBase,
})
expect(withHardPoints.synergyBonusPct).toBe(200)
// +20 allskills and +33 Marrowwalk charges without hard points must yield 0 synergy
const statsSoftOnly = new UnitStatList()
statsSoftOnly.setBaseSkillLevel(272, 20)
statsSoftOnly.addStat('item_allskills', 20)
if (synId !== null) {
statsSoftOnly.setChargedSkillLevel(synId, 33)
}
const withSoftOnly = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsSoftOnly,
})
expect(withSoftOnly.synergyBonusPct).toBe(0)
})
it('executes runtime skill effect in WorldArena (castCount, action frame, and combat/state/missile/summon outcome)', async () => {
const registry = await getSharedDataRegistry()
const arena = new WorldArena({
registry,
classCode: "ass",
skillId: 272,
slvl: 20,
})
const outcome = arena.triggerCast()
arena.stepTicks(15)
const dbg = arena.getDebugState()
expect(dbg.ready).toBe(true)
expect(dbg.skillId).toBe(272)
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
expect(dbg.actionFrameTriggered).toBe(true)
expect(outcome?.executed).toBe(true)
})
})

View File

@ -1,109 +0,0 @@
/**
* 1.13c Numerical & Runtime Verification Suite — Skill #273: Mind Blast (ASS)
* Gitea Tracking Issue: #366
*/
import { describe, expect, it } from 'vitest'
import { getSharedDataRegistry } from '../../../src/game/engine/data-registry.ts'
import { UnitStatList } from '../../../src/game/engine/stat-list.ts'
import { WorldArena } from '../../../src/game/engine/world-arena.ts'
import { skillModule } from '../../../src/game/skills/impl/ass/skill-273-mind-blast.ts'
describe('[Skill #273] Mind Blast (ASS) — 1.13c Parity (Issue #366)', () => {
it('evaluates exact 1.13c Skills.txt / Missiles.txt formulas at slvl 1, 10, and 20', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(273)!
expect(skillRec).toBeDefined()
expect(skillModule.skillId).toBe(273)
expect(skillModule.name).toBe("Mind Blast")
expect(skillModule.charClass).toBe("ass")
const stats1 = new UnitStatList()
stats1.setBaseSkillLevel(273, 1)
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
expect(r1.manaCost).toBe(15)
expect(r1.manaCost256).toBe(3840)
expect(r1.minPhysDmg).toBe(10)
expect(r1.maxPhysDmg).toBe(20)
expect(r1.minElemDmg256).toBe(0)
expect(r1.maxElemDmg256).toBe(0)
const stats10 = new UnitStatList()
stats10.setBaseSkillLevel(273, 10)
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
expect(r10.manaCost).toBe(15)
expect(r10.manaCost256).toBe(3840)
expect(r10.minPhysDmg).toBe(34)
expect(r10.maxPhysDmg).toBe(44)
expect(r10.minElemDmg256).toBe(0)
expect(r10.maxElemDmg256).toBe(0)
const stats20 = new UnitStatList()
stats20.setBaseSkillLevel(273, 20)
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
expect(r20.manaCost).toBe(15)
expect(r20.manaCost256).toBe(3840)
expect(r20.minPhysDmg).toBe(96)
expect(r20.maxPhysDmg).toBe(106)
expect(r20.minElemDmg256).toBe(0)
expect(r20.maxElemDmg256).toBe(0)
expect(r20.durationFrames).toBe(145)
expect(r20.radiusSubtiles).toBe(4)
expect(r20.petMax).toBe(0)
expect(r20.cooldownFrames).toBe(0)
})
it('enforces 1.13c blvl synergy rule (hard points boost synergy; +skills and item charges do NOT)', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(273)!
const synId = null
const statsBase = new UnitStatList()
statsBase.setBaseSkillLevel(273, 20)
if (synId !== null) {
statsBase.setBaseSkillLevel(synId, 20)
}
const withHardPoints = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsBase,
})
expect(withHardPoints.synergyBonusPct).toBe(0)
// +20 allskills and +33 Marrowwalk charges without hard points must yield 0 synergy
const statsSoftOnly = new UnitStatList()
statsSoftOnly.setBaseSkillLevel(273, 20)
statsSoftOnly.addStat('item_allskills', 20)
if (synId !== null) {
statsSoftOnly.setChargedSkillLevel(synId, 33)
}
const withSoftOnly = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsSoftOnly,
})
expect(withSoftOnly.synergyBonusPct).toBe(0)
})
it('executes runtime skill effect in WorldArena (castCount, action frame, and combat/state/missile/summon outcome)', async () => {
const registry = await getSharedDataRegistry()
const arena = new WorldArena({
registry,
classCode: "ass",
skillId: 273,
slvl: 20,
})
const outcome = arena.triggerCast()
arena.stepTicks(15)
const dbg = arena.getDebugState()
expect(dbg.ready).toBe(true)
expect(dbg.skillId).toBe(273)
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
expect(dbg.actionFrameTriggered).toBe(true)
expect(outcome?.executed).toBe(true)
})
})

View File

@ -1,109 +0,0 @@
/**
* 1.13c Numerical & Runtime Verification Suite — Skill #274: Blades of Ice (ASS)
* Gitea Tracking Issue: #367
*/
import { describe, expect, it } from 'vitest'
import { getSharedDataRegistry } from '../../../src/game/engine/data-registry.ts'
import { UnitStatList } from '../../../src/game/engine/stat-list.ts'
import { WorldArena } from '../../../src/game/engine/world-arena.ts'
import { skillModule } from '../../../src/game/skills/impl/ass/skill-274-blades-of-ice.ts'
describe('[Skill #274] Blades of Ice (ASS) — 1.13c Parity (Issue #367)', () => {
it('evaluates exact 1.13c Skills.txt / Missiles.txt formulas at slvl 1, 10, and 20', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(274)!
expect(skillRec).toBeDefined()
expect(skillModule.skillId).toBe(274)
expect(skillModule.name).toBe("Blades of Ice")
expect(skillModule.charClass).toBe("ass")
const stats1 = new UnitStatList()
stats1.setBaseSkillLevel(274, 1)
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
expect(r1.manaCost).toBe(3)
expect(r1.manaCost256).toBe(768)
expect(r1.minPhysDmg).toBe(0)
expect(r1.maxPhysDmg).toBe(0)
expect(r1.minElemDmg256).toBe(3840)
expect(r1.maxElemDmg256).toBe(8960)
const stats10 = new UnitStatList()
stats10.setBaseSkillLevel(274, 10)
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
expect(r10.manaCost).toBe(3)
expect(r10.manaCost256).toBe(768)
expect(r10.minPhysDmg).toBe(0)
expect(r10.maxPhysDmg).toBe(0)
expect(r10.minElemDmg256).toBe(23296)
expect(r10.maxElemDmg256).toBe(28416)
const stats20 = new UnitStatList()
stats20.setBaseSkillLevel(274, 20)
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
expect(r20.manaCost).toBe(3)
expect(r20.manaCost256).toBe(768)
expect(r20.minPhysDmg).toBe(0)
expect(r20.maxPhysDmg).toBe(0)
expect(r20.minElemDmg256).toBe(59136)
expect(r20.maxElemDmg256).toBe(66304)
expect(r20.durationFrames).toBe(375)
expect(r20.radiusSubtiles).toBe(63)
expect(r20.petMax).toBe(0)
expect(r20.cooldownFrames).toBe(0)
})
it('enforces 1.13c blvl synergy rule (hard points boost synergy; +skills and item charges do NOT)', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(274)!
const synId = 280
const statsBase = new UnitStatList()
statsBase.setBaseSkillLevel(274, 20)
if (synId !== null) {
statsBase.setBaseSkillLevel(synId, 20)
}
const withHardPoints = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsBase,
})
expect(withHardPoints.synergyBonusPct).toBe(160)
// +20 allskills and +33 Marrowwalk charges without hard points must yield 0 synergy
const statsSoftOnly = new UnitStatList()
statsSoftOnly.setBaseSkillLevel(274, 20)
statsSoftOnly.addStat('item_allskills', 20)
if (synId !== null) {
statsSoftOnly.setChargedSkillLevel(synId, 33)
}
const withSoftOnly = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsSoftOnly,
})
expect(withSoftOnly.synergyBonusPct).toBe(0)
})
it('executes runtime skill effect in WorldArena (castCount, action frame, and combat/state/missile/summon outcome)', async () => {
const registry = await getSharedDataRegistry()
const arena = new WorldArena({
registry,
classCode: "ass",
skillId: 274,
slvl: 20,
})
const outcome = arena.triggerCast()
arena.stepTicks(15)
const dbg = arena.getDebugState()
expect(dbg.ready).toBe(true)
expect(dbg.skillId).toBe(274)
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
expect(dbg.actionFrameTriggered).toBe(true)
expect(outcome?.executed).toBe(true)
})
})

View File

@ -1,109 +0,0 @@
/**
* 1.13c Numerical & Runtime Verification Suite — Skill #275: Dragon Flight (ASS)
* Gitea Tracking Issue: #368
*/
import { describe, expect, it } from 'vitest'
import { getSharedDataRegistry } from '../../../src/game/engine/data-registry.ts'
import { UnitStatList } from '../../../src/game/engine/stat-list.ts'
import { WorldArena } from '../../../src/game/engine/world-arena.ts'
import { skillModule } from '../../../src/game/skills/impl/ass/skill-275-dragon-flight.ts'
describe('[Skill #275] Dragon Flight (ASS) — 1.13c Parity (Issue #368)', () => {
it('evaluates exact 1.13c Skills.txt / Missiles.txt formulas at slvl 1, 10, and 20', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(275)!
expect(skillRec).toBeDefined()
expect(skillModule.skillId).toBe(275)
expect(skillModule.name).toBe("Dragon Flight")
expect(skillModule.charClass).toBe("ass")
const stats1 = new UnitStatList()
stats1.setBaseSkillLevel(275, 1)
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
expect(r1.manaCost).toBe(15)
expect(r1.manaCost256).toBe(3840)
expect(r1.minPhysDmg).toBe(0)
expect(r1.maxPhysDmg).toBe(0)
expect(r1.minElemDmg256).toBe(0)
expect(r1.maxElemDmg256).toBe(0)
const stats10 = new UnitStatList()
stats10.setBaseSkillLevel(275, 10)
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
expect(r10.manaCost).toBe(15)
expect(r10.manaCost256).toBe(3840)
expect(r10.minPhysDmg).toBe(0)
expect(r10.maxPhysDmg).toBe(0)
expect(r10.minElemDmg256).toBe(0)
expect(r10.maxElemDmg256).toBe(0)
const stats20 = new UnitStatList()
stats20.setBaseSkillLevel(275, 20)
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
expect(r20.manaCost).toBe(15)
expect(r20.manaCost256).toBe(3840)
expect(r20.minPhysDmg).toBe(0)
expect(r20.maxPhysDmg).toBe(0)
expect(r20.minElemDmg256).toBe(0)
expect(r20.maxElemDmg256).toBe(0)
expect(r20.durationFrames).toBe(0)
expect(r20.radiusSubtiles).toBe(27)
expect(r20.petMax).toBe(0)
expect(r20.cooldownFrames).toBe(25)
})
it('enforces 1.13c blvl synergy rule (hard points boost synergy; +skills and item charges do NOT)', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(275)!
const synId = null
const statsBase = new UnitStatList()
statsBase.setBaseSkillLevel(275, 20)
if (synId !== null) {
statsBase.setBaseSkillLevel(synId, 20)
}
const withHardPoints = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsBase,
})
expect(withHardPoints.synergyBonusPct).toBe(0)
// +20 allskills and +33 Marrowwalk charges without hard points must yield 0 synergy
const statsSoftOnly = new UnitStatList()
statsSoftOnly.setBaseSkillLevel(275, 20)
statsSoftOnly.addStat('item_allskills', 20)
if (synId !== null) {
statsSoftOnly.setChargedSkillLevel(synId, 33)
}
const withSoftOnly = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsSoftOnly,
})
expect(withSoftOnly.synergyBonusPct).toBe(0)
})
it('executes runtime skill effect in WorldArena (castCount, action frame, and combat/state/missile/summon outcome)', async () => {
const registry = await getSharedDataRegistry()
const arena = new WorldArena({
registry,
classCode: "ass",
skillId: 275,
slvl: 20,
})
const outcome = arena.triggerCast()
arena.stepTicks(15)
const dbg = arena.getDebugState()
expect(dbg.ready).toBe(true)
expect(dbg.skillId).toBe(275)
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
expect(dbg.actionFrameTriggered).toBe(true)
expect(outcome?.executed).toBe(true)
})
})

View File

@ -1,109 +0,0 @@
/**
* 1.13c Numerical & Runtime Verification Suite — Skill #276: Death Sentry (ASS)
* Gitea Tracking Issue: #369
*/
import { describe, expect, it } from 'vitest'
import { getSharedDataRegistry } from '../../../src/game/engine/data-registry.ts'
import { UnitStatList } from '../../../src/game/engine/stat-list.ts'
import { WorldArena } from '../../../src/game/engine/world-arena.ts'
import { skillModule } from '../../../src/game/skills/impl/ass/skill-276-death-sentry.ts'
describe('[Skill #276] Death Sentry (ASS) — 1.13c Parity (Issue #369)', () => {
it('evaluates exact 1.13c Skills.txt / Missiles.txt formulas at slvl 1, 10, and 20', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(276)!
expect(skillRec).toBeDefined()
expect(skillModule.skillId).toBe(276)
expect(skillModule.name).toBe("Death Sentry")
expect(skillModule.charClass).toBe("ass")
const stats1 = new UnitStatList()
stats1.setBaseSkillLevel(276, 1)
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
expect(r1.manaCost).toBe(20)
expect(r1.manaCost256).toBe(5120)
expect(r1.minPhysDmg).toBe(0)
expect(r1.maxPhysDmg).toBe(0)
expect(r1.minElemDmg256).toBe(256)
expect(r1.maxElemDmg256).toBe(12800)
const stats10 = new UnitStatList()
stats10.setBaseSkillLevel(276, 10)
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
expect(r10.manaCost).toBe(20)
expect(r10.manaCost256).toBe(5120)
expect(r10.minPhysDmg).toBe(0)
expect(r10.maxPhysDmg).toBe(0)
expect(r10.minElemDmg256).toBe(256)
expect(r10.maxElemDmg256).toBe(34304)
const stats20 = new UnitStatList()
stats20.setBaseSkillLevel(276, 20)
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
expect(r20.manaCost).toBe(20)
expect(r20.manaCost256).toBe(5120)
expect(r20.minPhysDmg).toBe(0)
expect(r20.maxPhysDmg).toBe(0)
expect(r20.minElemDmg256).toBe(256)
expect(r20.maxElemDmg256).toBe(78336)
expect(r20.durationFrames).toBe(0)
expect(r20.radiusSubtiles).toBe(0)
expect(r20.petMax).toBe(5)
expect(r20.cooldownFrames).toBe(0)
})
it('enforces 1.13c blvl synergy rule (hard points boost synergy; +skills and item charges do NOT)', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(276)!
const synId = 271
const statsBase = new UnitStatList()
statsBase.setBaseSkillLevel(276, 20)
if (synId !== null) {
statsBase.setBaseSkillLevel(synId, 20)
}
const withHardPoints = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsBase,
})
expect(withHardPoints.synergyBonusPct).toBe(240)
// +20 allskills and +33 Marrowwalk charges without hard points must yield 0 synergy
const statsSoftOnly = new UnitStatList()
statsSoftOnly.setBaseSkillLevel(276, 20)
statsSoftOnly.addStat('item_allskills', 20)
if (synId !== null) {
statsSoftOnly.setChargedSkillLevel(synId, 33)
}
const withSoftOnly = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsSoftOnly,
})
expect(withSoftOnly.synergyBonusPct).toBe(0)
})
it('executes runtime skill effect in WorldArena (castCount, action frame, and combat/state/missile/summon outcome)', async () => {
const registry = await getSharedDataRegistry()
const arena = new WorldArena({
registry,
classCode: "ass",
skillId: 276,
slvl: 20,
})
const outcome = arena.triggerCast()
arena.stepTicks(15)
const dbg = arena.getDebugState()
expect(dbg.ready).toBe(true)
expect(dbg.skillId).toBe(276)
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
expect(dbg.actionFrameTriggered).toBe(true)
expect(outcome?.executed).toBe(true)
})
})

View File

@ -1,109 +0,0 @@
/**
* 1.13c Numerical & Runtime Verification Suite — Skill #277: Blade Shield (ASS)
* Gitea Tracking Issue: #370
*/
import { describe, expect, it } from 'vitest'
import { getSharedDataRegistry } from '../../../src/game/engine/data-registry.ts'
import { UnitStatList } from '../../../src/game/engine/stat-list.ts'
import { WorldArena } from '../../../src/game/engine/world-arena.ts'
import { skillModule } from '../../../src/game/skills/impl/ass/skill-277-blade-shield.ts'
describe('[Skill #277] Blade Shield (ASS) — 1.13c Parity (Issue #370)', () => {
it('evaluates exact 1.13c Skills.txt / Missiles.txt formulas at slvl 1, 10, and 20', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(277)!
expect(skillRec).toBeDefined()
expect(skillModule.skillId).toBe(277)
expect(skillModule.name).toBe("Blade Shield")
expect(skillModule.charClass).toBe("ass")
const stats1 = new UnitStatList()
stats1.setBaseSkillLevel(277, 1)
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
expect(r1.manaCost).toBe(27)
expect(r1.manaCost256).toBe(6912)
expect(r1.minPhysDmg).toBe(1)
expect(r1.maxPhysDmg).toBe(30)
expect(r1.minElemDmg256).toBe(0)
expect(r1.maxElemDmg256).toBe(0)
const stats10 = new UnitStatList()
stats10.setBaseSkillLevel(277, 10)
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
expect(r10.manaCost).toBe(45)
expect(r10.manaCost256).toBe(11520)
expect(r10.minPhysDmg).toBe(48)
expect(r10.maxPhysDmg).toBe(77)
expect(r10.minElemDmg256).toBe(0)
expect(r10.maxElemDmg256).toBe(0)
const stats20 = new UnitStatList()
stats20.setBaseSkillLevel(277, 20)
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
expect(r20.manaCost).toBe(65)
expect(r20.manaCost256).toBe(16640)
expect(r20.minPhysDmg).toBe(112)
expect(r20.maxPhysDmg).toBe(141)
expect(r20.minElemDmg256).toBe(0)
expect(r20.maxElemDmg256).toBe(0)
expect(r20.durationFrames).toBe(2875)
expect(r20.radiusSubtiles).toBe(6)
expect(r20.petMax).toBe(0)
expect(r20.cooldownFrames).toBe(0)
})
it('enforces 1.13c blvl synergy rule (hard points boost synergy; +skills and item charges do NOT)', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(277)!
const synId = null
const statsBase = new UnitStatList()
statsBase.setBaseSkillLevel(277, 20)
if (synId !== null) {
statsBase.setBaseSkillLevel(synId, 20)
}
const withHardPoints = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsBase,
})
expect(withHardPoints.synergyBonusPct).toBe(0)
// +20 allskills and +33 Marrowwalk charges without hard points must yield 0 synergy
const statsSoftOnly = new UnitStatList()
statsSoftOnly.setBaseSkillLevel(277, 20)
statsSoftOnly.addStat('item_allskills', 20)
if (synId !== null) {
statsSoftOnly.setChargedSkillLevel(synId, 33)
}
const withSoftOnly = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsSoftOnly,
})
expect(withSoftOnly.synergyBonusPct).toBe(0)
})
it('executes runtime skill effect in WorldArena (castCount, action frame, and combat/state/missile/summon outcome)', async () => {
const registry = await getSharedDataRegistry()
const arena = new WorldArena({
registry,
classCode: "ass",
skillId: 277,
slvl: 20,
})
const outcome = arena.triggerCast()
arena.stepTicks(15)
const dbg = arena.getDebugState()
expect(dbg.ready).toBe(true)
expect(dbg.skillId).toBe(277)
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
expect(dbg.actionFrameTriggered).toBe(true)
expect(outcome?.executed).toBe(true)
})
})

View File

@ -1,109 +0,0 @@
/**
* 1.13c Numerical & Runtime Verification Suite — Skill #278: Venom (ASS)
* Gitea Tracking Issue: #371
*/
import { describe, expect, it } from 'vitest'
import { getSharedDataRegistry } from '../../../src/game/engine/data-registry.ts'
import { UnitStatList } from '../../../src/game/engine/stat-list.ts'
import { WorldArena } from '../../../src/game/engine/world-arena.ts'
import { skillModule } from '../../../src/game/skills/impl/ass/skill-278-venom.ts'
describe('[Skill #278] Venom (ASS) — 1.13c Parity (Issue #371)', () => {
it('evaluates exact 1.13c Skills.txt / Missiles.txt formulas at slvl 1, 10, and 20', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(278)!
expect(skillRec).toBeDefined()
expect(skillModule.skillId).toBe(278)
expect(skillModule.name).toBe("Venom")
expect(skillModule.charClass).toBe("ass")
const stats1 = new UnitStatList()
stats1.setBaseSkillLevel(278, 1)
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
expect(r1.manaCost).toBe(12)
expect(r1.manaCost256).toBe(3072)
expect(r1.minPhysDmg).toBe(0)
expect(r1.maxPhysDmg).toBe(0)
expect(r1.minElemDmg256).toBe(1536)
expect(r1.maxElemDmg256).toBe(2048)
const stats10 = new UnitStatList()
stats10.setBaseSkillLevel(278, 10)
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
expect(r10.manaCost).toBe(12)
expect(r10.manaCost256).toBe(3072)
expect(r10.minPhysDmg).toBe(0)
expect(r10.maxPhysDmg).toBe(0)
expect(r10.minElemDmg256).toBe(5248)
expect(r10.maxElemDmg256).toBe(5760)
const stats20 = new UnitStatList()
stats20.setBaseSkillLevel(278, 20)
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
expect(r20.manaCost).toBe(12)
expect(r20.manaCost256).toBe(3072)
expect(r20.minPhysDmg).toBe(0)
expect(r20.maxPhysDmg).toBe(0)
expect(r20.minElemDmg256).toBe(10880)
expect(r20.maxElemDmg256).toBe(11392)
expect(r20.durationFrames).toBe(4900)
expect(r20.radiusSubtiles).toBe(4900)
expect(r20.petMax).toBe(0)
expect(r20.cooldownFrames).toBe(0)
})
it('enforces 1.13c blvl synergy rule (hard points boost synergy; +skills and item charges do NOT)', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(278)!
const synId = null
const statsBase = new UnitStatList()
statsBase.setBaseSkillLevel(278, 20)
if (synId !== null) {
statsBase.setBaseSkillLevel(synId, 20)
}
const withHardPoints = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsBase,
})
expect(withHardPoints.synergyBonusPct).toBe(0)
// +20 allskills and +33 Marrowwalk charges without hard points must yield 0 synergy
const statsSoftOnly = new UnitStatList()
statsSoftOnly.setBaseSkillLevel(278, 20)
statsSoftOnly.addStat('item_allskills', 20)
if (synId !== null) {
statsSoftOnly.setChargedSkillLevel(synId, 33)
}
const withSoftOnly = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsSoftOnly,
})
expect(withSoftOnly.synergyBonusPct).toBe(0)
})
it('executes runtime skill effect in WorldArena (castCount, action frame, and combat/state/missile/summon outcome)', async () => {
const registry = await getSharedDataRegistry()
const arena = new WorldArena({
registry,
classCode: "ass",
skillId: 278,
slvl: 20,
})
const outcome = arena.triggerCast()
arena.stepTicks(15)
const dbg = arena.getDebugState()
expect(dbg.ready).toBe(true)
expect(dbg.skillId).toBe(278)
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
expect(dbg.actionFrameTriggered).toBe(true)
expect(outcome?.executed).toBe(true)
})
})

View File

@ -1,109 +0,0 @@
/**
* 1.13c Numerical & Runtime Verification Suite — Skill #279: Shadow Master (ASS)
* Gitea Tracking Issue: #372
*/
import { describe, expect, it } from 'vitest'
import { getSharedDataRegistry } from '../../../src/game/engine/data-registry.ts'
import { UnitStatList } from '../../../src/game/engine/stat-list.ts'
import { WorldArena } from '../../../src/game/engine/world-arena.ts'
import { skillModule } from '../../../src/game/skills/impl/ass/skill-279-shadow-master.ts'
describe('[Skill #279] Shadow Master (ASS) — 1.13c Parity (Issue #372)', () => {
it('evaluates exact 1.13c Skills.txt / Missiles.txt formulas at slvl 1, 10, and 20', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(279)!
expect(skillRec).toBeDefined()
expect(skillModule.skillId).toBe(279)
expect(skillModule.name).toBe("Shadow Master")
expect(skillModule.charClass).toBe("ass")
const stats1 = new UnitStatList()
stats1.setBaseSkillLevel(279, 1)
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
expect(r1.manaCost).toBe(35)
expect(r1.manaCost256).toBe(8960)
expect(r1.minPhysDmg).toBe(0)
expect(r1.maxPhysDmg).toBe(0)
expect(r1.minElemDmg256).toBe(0)
expect(r1.maxElemDmg256).toBe(0)
const stats10 = new UnitStatList()
stats10.setBaseSkillLevel(279, 10)
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
expect(r10.manaCost).toBe(39)
expect(r10.manaCost256).toBe(10112)
expect(r10.minPhysDmg).toBe(0)
expect(r10.maxPhysDmg).toBe(0)
expect(r10.minElemDmg256).toBe(0)
expect(r10.maxElemDmg256).toBe(0)
const stats20 = new UnitStatList()
stats20.setBaseSkillLevel(279, 20)
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
expect(r20.manaCost).toBe(44)
expect(r20.manaCost256).toBe(11392)
expect(r20.minPhysDmg).toBe(0)
expect(r20.maxPhysDmg).toBe(0)
expect(r20.minElemDmg256).toBe(0)
expect(r20.maxElemDmg256).toBe(0)
expect(r20.durationFrames).toBe(0)
expect(r20.radiusSubtiles).toBe(775)
expect(r20.petMax).toBe(1)
expect(r20.cooldownFrames).toBe(150)
})
it('enforces 1.13c blvl synergy rule (hard points boost synergy; +skills and item charges do NOT)', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(279)!
const synId = null
const statsBase = new UnitStatList()
statsBase.setBaseSkillLevel(279, 20)
if (synId !== null) {
statsBase.setBaseSkillLevel(synId, 20)
}
const withHardPoints = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsBase,
})
expect(withHardPoints.synergyBonusPct).toBe(0)
// +20 allskills and +33 Marrowwalk charges without hard points must yield 0 synergy
const statsSoftOnly = new UnitStatList()
statsSoftOnly.setBaseSkillLevel(279, 20)
statsSoftOnly.addStat('item_allskills', 20)
if (synId !== null) {
statsSoftOnly.setChargedSkillLevel(synId, 33)
}
const withSoftOnly = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsSoftOnly,
})
expect(withSoftOnly.synergyBonusPct).toBe(0)
})
it('executes runtime skill effect in WorldArena (castCount, action frame, and combat/state/missile/summon outcome)', async () => {
const registry = await getSharedDataRegistry()
const arena = new WorldArena({
registry,
classCode: "ass",
skillId: 279,
slvl: 20,
})
const outcome = arena.triggerCast()
arena.stepTicks(15)
const dbg = arena.getDebugState()
expect(dbg.ready).toBe(true)
expect(dbg.skillId).toBe(279)
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
expect(dbg.actionFrameTriggered).toBe(true)
expect(outcome?.executed).toBe(true)
})
})

View File

@ -1,109 +0,0 @@
/**
* 1.13c Numerical & Runtime Verification Suite — Skill #280: Royal Strike (ASS)
* Gitea Tracking Issue: #373
*/
import { describe, expect, it } from 'vitest'
import { getSharedDataRegistry } from '../../../src/game/engine/data-registry.ts'
import { UnitStatList } from '../../../src/game/engine/stat-list.ts'
import { WorldArena } from '../../../src/game/engine/world-arena.ts'
import { skillModule } from '../../../src/game/skills/impl/ass/skill-280-royal-strike.ts'
describe('[Skill #280] Royal Strike (ASS) — 1.13c Parity (Issue #373)', () => {
it('evaluates exact 1.13c Skills.txt / Missiles.txt formulas at slvl 1, 10, and 20', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(280)!
expect(skillRec).toBeDefined()
expect(skillModule.skillId).toBe(280)
expect(skillModule.name).toBe("Royal Strike")
expect(skillModule.charClass).toBe("ass")
const stats1 = new UnitStatList()
stats1.setBaseSkillLevel(280, 1)
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
expect(r1.manaCost).toBe(4)
expect(r1.manaCost256).toBe(1024)
expect(r1.minPhysDmg).toBe(0)
expect(r1.maxPhysDmg).toBe(0)
expect(r1.minElemDmg256).toBe(0)
expect(r1.maxElemDmg256).toBe(0)
const stats10 = new UnitStatList()
stats10.setBaseSkillLevel(280, 10)
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
expect(r10.manaCost).toBe(4)
expect(r10.manaCost256).toBe(1024)
expect(r10.minPhysDmg).toBe(0)
expect(r10.maxPhysDmg).toBe(0)
expect(r10.minElemDmg256).toBe(0)
expect(r10.maxElemDmg256).toBe(0)
const stats20 = new UnitStatList()
stats20.setBaseSkillLevel(280, 20)
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
expect(r20.manaCost).toBe(4)
expect(r20.manaCost256).toBe(1024)
expect(r20.minPhysDmg).toBe(0)
expect(r20.maxPhysDmg).toBe(0)
expect(r20.minElemDmg256).toBe(0)
expect(r20.maxElemDmg256).toBe(0)
expect(r20.durationFrames).toBe(375)
expect(r20.radiusSubtiles).toBe(8)
expect(r20.petMax).toBe(0)
expect(r20.cooldownFrames).toBe(0)
})
it('enforces 1.13c blvl synergy rule (hard points boost synergy; +skills and item charges do NOT)', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(280)!
const synId = null
const statsBase = new UnitStatList()
statsBase.setBaseSkillLevel(280, 20)
if (synId !== null) {
statsBase.setBaseSkillLevel(synId, 20)
}
const withHardPoints = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsBase,
})
expect(withHardPoints.synergyBonusPct).toBe(0)
// +20 allskills and +33 Marrowwalk charges without hard points must yield 0 synergy
const statsSoftOnly = new UnitStatList()
statsSoftOnly.setBaseSkillLevel(280, 20)
statsSoftOnly.addStat('item_allskills', 20)
if (synId !== null) {
statsSoftOnly.setChargedSkillLevel(synId, 33)
}
const withSoftOnly = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsSoftOnly,
})
expect(withSoftOnly.synergyBonusPct).toBe(0)
})
it('executes runtime skill effect in WorldArena (castCount, action frame, and combat/state/missile/summon outcome)', async () => {
const registry = await getSharedDataRegistry()
const arena = new WorldArena({
registry,
classCode: "ass",
skillId: 280,
slvl: 20,
})
const outcome = arena.triggerCast()
arena.stepTicks(15)
const dbg = arena.getDebugState()
expect(dbg.ready).toBe(true)
expect(dbg.skillId).toBe(280)
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
expect(dbg.actionFrameTriggered).toBe(true)
expect(outcome?.executed).toBe(true)
})
})

View File

@ -1,109 +0,0 @@
/**
* 1.13c Numerical & Runtime Verification Suite — Skill #350: Delerium Change (UNI)
* Gitea Tracking Issue: #374
*/
import { describe, expect, it } from 'vitest'
import { getSharedDataRegistry } from '../../../src/game/engine/data-registry.ts'
import { UnitStatList } from '../../../src/game/engine/stat-list.ts'
import { WorldArena } from '../../../src/game/engine/world-arena.ts'
import { skillModule } from '../../../src/game/skills/impl/uni/skill-350-delerium-change.ts'
describe('[Skill #350] Delerium Change (UNI) — 1.13c Parity (Issue #374)', () => {
it('evaluates exact 1.13c Skills.txt / Missiles.txt formulas at slvl 1, 10, and 20', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(350)!
expect(skillRec).toBeDefined()
expect(skillModule.skillId).toBe(350)
expect(skillModule.name).toBe("Delerium Change")
expect(skillModule.charClass).toBe("uni")
const stats1 = new UnitStatList()
stats1.setBaseSkillLevel(350, 1)
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
expect(r1.manaCost).toBe(0)
expect(r1.manaCost256).toBe(0)
expect(r1.minPhysDmg).toBe(0)
expect(r1.maxPhysDmg).toBe(0)
expect(r1.minElemDmg256).toBe(0)
expect(r1.maxElemDmg256).toBe(0)
const stats10 = new UnitStatList()
stats10.setBaseSkillLevel(350, 10)
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
expect(r10.manaCost).toBe(0)
expect(r10.manaCost256).toBe(0)
expect(r10.minPhysDmg).toBe(0)
expect(r10.maxPhysDmg).toBe(0)
expect(r10.minElemDmg256).toBe(0)
expect(r10.maxElemDmg256).toBe(0)
const stats20 = new UnitStatList()
stats20.setBaseSkillLevel(350, 20)
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
expect(r20.manaCost).toBe(0)
expect(r20.manaCost256).toBe(0)
expect(r20.minPhysDmg).toBe(0)
expect(r20.maxPhysDmg).toBe(0)
expect(r20.minElemDmg256).toBe(0)
expect(r20.maxElemDmg256).toBe(0)
expect(r20.durationFrames).toBe(1500)
expect(r20.radiusSubtiles).toBe(0)
expect(r20.petMax).toBe(0)
expect(r20.cooldownFrames).toBe(0)
})
it('enforces 1.13c blvl synergy rule (hard points boost synergy; +skills and item charges do NOT)', async () => {
const registry = await getSharedDataRegistry()
const skillRec = registry.getSkillById(350)!
const synId = null
const statsBase = new UnitStatList()
statsBase.setBaseSkillLevel(350, 20)
if (synId !== null) {
statsBase.setBaseSkillLevel(synId, 20)
}
const withHardPoints = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsBase,
})
expect(withHardPoints.synergyBonusPct).toBe(0)
// +20 allskills and +33 Marrowwalk charges without hard points must yield 0 synergy
const statsSoftOnly = new UnitStatList()
statsSoftOnly.setBaseSkillLevel(350, 20)
statsSoftOnly.addStat('item_allskills', 20)
if (synId !== null) {
statsSoftOnly.setChargedSkillLevel(synId, 33)
}
const withSoftOnly = skillModule.evaluate!({
registry,
skill: skillRec,
slvl: 20,
blvl: 20,
statList: statsSoftOnly,
})
expect(withSoftOnly.synergyBonusPct).toBe(0)
})
it('executes runtime skill effect in WorldArena (castCount, action frame, and combat/state/missile/summon outcome)', async () => {
const registry = await getSharedDataRegistry()
const arena = new WorldArena({
registry,
classCode: "uni",
skillId: 350,
slvl: 20,
})
const outcome = arena.triggerCast()
arena.stepTicks(15)
const dbg = arena.getDebugState()
expect(dbg.ready).toBe(true)
expect(dbg.skillId).toBe(350)
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
expect(dbg.actionFrameTriggered).toBe(true)
expect(outcome?.executed).toBe(true)
})
})