Compare commits
No commits in common. "3c827be346298bed9273a0a66a2d8d47f753db6b" and "ee217deaf119a88c17622b6e2c90ff955639d621" have entirely different histories.
3c827be346
...
ee217deaf1
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
Loading…
Reference in New Issue