Compare commits
50 Commits
a55829ace8
...
ee217deaf1
| Author | SHA1 | Date |
|---|---|---|
|
|
ee217deaf1 | |
|
|
e91554764f | |
|
|
9892840cdc | |
|
|
5d33bf09ae | |
|
|
c4a16ba115 | |
|
|
8829f881c8 | |
|
|
d9dd6d9adb | |
|
|
9bc13289d4 | |
|
|
c0a86b7cb3 | |
|
|
50725f335b | |
|
|
6890d068bc | |
|
|
bdcb2af7d1 | |
|
|
605e2344e3 | |
|
|
9fe4c77754 | |
|
|
9b016e3365 | |
|
|
53b2f6c9c8 | |
|
|
afc4f1cc25 | |
|
|
76a3cf17f9 | |
|
|
7a0ce882d5 | |
|
|
cf444ded20 | |
|
|
9ece6626fc | |
|
|
4c20bf9fb9 | |
|
|
0eb8368430 | |
|
|
3b23f61791 | |
|
|
e2a5682130 | |
|
|
190a0c5537 | |
|
|
ee12592bab | |
|
|
039ca21ba5 | |
|
|
942b91e428 | |
|
|
72570aa522 | |
|
|
ccc43b8cd1 | |
|
|
8dcd62df87 | |
|
|
946c13c051 | |
|
|
e7c09b2e62 | |
|
|
8560fbdf65 | |
|
|
5b2189a72e | |
|
|
1d57fd725f | |
|
|
ac9984dcc0 | |
|
|
97f832211a | |
|
|
0e30660401 | |
|
|
d2a2dd0629 | |
|
|
67d92834ca | |
|
|
e552bd8310 | |
|
|
a32a8b21c4 | |
|
|
49db34210a | |
|
|
ddc040cc90 | |
|
|
2f582efb21 | |
|
|
996f8edff9 | |
|
|
d15c448422 | |
|
|
022375e1a3 |
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #251: Fire Trauma (ASS)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 251 ("Fire Trauma")
|
||||
* - Class: "ass"
|
||||
* - Required Level: 1
|
||||
* - Server Functions: srvstfunc=0, srvdofunc=0, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
||||
* - Associated Missile / State / Summon: missile="bomb in air", state="", summon=""
|
||||
* - 1.13c Synergy Formulas: EDmgSymPerCalc="(skill('Shock Field'.blvl) + skill('Death Sentry'.blvl) + skill('Charged Bolt Sentry'.blvl) + skill('Lightning Sentry'.blvl) + skill('Wake of Fire Sentry'.blvl) + skill('Inferno 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: 251,
|
||||
name: "Fire Trauma",
|
||||
charClass: "ass",
|
||||
srvStFunc: 0,
|
||||
srvDoFunc: 0,
|
||||
|
||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
||||
return evaluateSkillCore113c(ctx)
|
||||
},
|
||||
|
||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
||||
const outcome = executeSkillCore113c(ctx)
|
||||
return {
|
||||
...outcome,
|
||||
notes: [
|
||||
...outcome.notes,
|
||||
'skill_module:skill-251-fire-trauma',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #252: Claw Mastery (ASS)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 252 ("Claw Mastery")
|
||||
* - Class: "ass"
|
||||
* - Required Level: 1
|
||||
* - Server Functions: srvstfunc=0, srvdofunc=0, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
||||
* - Associated Missile / State / Summon: missile="", state="clawmastery", 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: 252,
|
||||
name: "Claw Mastery",
|
||||
charClass: "ass",
|
||||
srvStFunc: 0,
|
||||
srvDoFunc: 0,
|
||||
|
||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
||||
return evaluateSkillCore113c(ctx)
|
||||
},
|
||||
|
||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
||||
const outcome = executeSkillCore113c(ctx)
|
||||
return {
|
||||
...outcome,
|
||||
notes: [
|
||||
...outcome.notes,
|
||||
'skill_module:skill-252-claw-mastery',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #253: Psychic Hammer (ASS)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 253 ("Psychic Hammer")
|
||||
* - Class: "ass"
|
||||
* - Required Level: 1
|
||||
* - Server Functions: srvstfunc=22, srvdofunc=33, 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: 253,
|
||||
name: "Psychic Hammer",
|
||||
charClass: "ass",
|
||||
srvStFunc: 22,
|
||||
srvDoFunc: 33,
|
||||
|
||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
||||
return evaluateSkillCore113c(ctx)
|
||||
},
|
||||
|
||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
||||
const outcome = executeSkillCore113c(ctx)
|
||||
return {
|
||||
...outcome,
|
||||
notes: [
|
||||
...outcome.notes,
|
||||
'skill_module:skill-253-psychic-hammer',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #254: Tiger Strike (ASS)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 254 ("Tiger Strike")
|
||||
* - Class: "ass"
|
||||
* - Required Level: 1
|
||||
* - Server Functions: srvstfunc=23, srvdofunc=34, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
||||
* - Associated Missile / State / Summon: missile="", state="progressive_damage", 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: 254,
|
||||
name: "Tiger 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-254-tiger-strike',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #255: Dragon Talon (ASS)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 255 ("Dragon Talon")
|
||||
* - Class: "ass"
|
||||
* - Required Level: 1
|
||||
* - Server Functions: srvstfunc=24, srvdofunc=42, 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: 255,
|
||||
name: "Dragon Talon",
|
||||
charClass: "ass",
|
||||
srvStFunc: 24,
|
||||
srvDoFunc: 42,
|
||||
|
||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
||||
return evaluateSkillCore113c(ctx)
|
||||
},
|
||||
|
||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
||||
const outcome = executeSkillCore113c(ctx)
|
||||
return {
|
||||
...outcome,
|
||||
notes: [
|
||||
...outcome.notes,
|
||||
'skill_module:skill-255-dragon-talon',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #256: Shock Field (ASS)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 256 ("Shock Field")
|
||||
* - Class: "ass"
|
||||
* - Required Level: 6
|
||||
* - Server Functions: srvstfunc=0, srvdofunc=43, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
||||
* - Associated Missile / State / Summon: missile="shock field in air", state="", summon=""
|
||||
* - 1.13c Synergy Formulas: EDmgSymPerCalc="(skill('Charged Bolt Sentry'.blvl) + skill('Lightning 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: 256,
|
||||
name: "Shock Field",
|
||||
charClass: "ass",
|
||||
srvStFunc: 0,
|
||||
srvDoFunc: 43,
|
||||
|
||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
||||
return evaluateSkillCore113c(ctx)
|
||||
},
|
||||
|
||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
||||
const outcome = executeSkillCore113c(ctx)
|
||||
return {
|
||||
...outcome,
|
||||
notes: [
|
||||
...outcome.notes,
|
||||
'skill_module:skill-256-shock-field',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #257: Blade Sentinel (ASS)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 257 ("Blade Sentinel")
|
||||
* - Class: "ass"
|
||||
* - Required Level: 6
|
||||
* - Server Functions: srvstfunc=0, srvdofunc=44, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
||||
* - Associated Missile / State / Summon: missile="blade creeper", state="", summon="bladecreeper"
|
||||
* - 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: 257,
|
||||
name: "Blade Sentinel",
|
||||
charClass: "ass",
|
||||
srvStFunc: 0,
|
||||
srvDoFunc: 44,
|
||||
|
||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
||||
return evaluateSkillCore113c(ctx)
|
||||
},
|
||||
|
||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
||||
const outcome = executeSkillCore113c(ctx)
|
||||
return {
|
||||
...outcome,
|
||||
notes: [
|
||||
...outcome.notes,
|
||||
'skill_module:skill-257-blade-sentinel',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #258: Quickness (ASS)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 258 ("Quickness")
|
||||
* - Class: "ass"
|
||||
* - Required Level: 6
|
||||
* - Server Functions: srvstfunc=0, srvdofunc=18, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
||||
* - Associated Missile / State / Summon: missile="", state="quickness", 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: 258,
|
||||
name: "Quickness",
|
||||
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-258-quickness',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #259: Fists of Fire (ASS)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 259 ("Fists of Fire")
|
||||
* - Class: "ass"
|
||||
* - Required Level: 6
|
||||
* - Server Functions: srvstfunc=23, srvdofunc=35, srvprgfunc1=143, srvprgfunc2=38, srvprgfunc3=39
|
||||
* - Associated Missile / State / Summon: missile="", state="progressive_fire", 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: 259,
|
||||
name: "Fists of Fire",
|
||||
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-259-fists-of-fire',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #260: Dragon Claw (ASS)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 260 ("Dragon Claw")
|
||||
* - Class: "ass"
|
||||
* - Required Level: 6
|
||||
* - Server Functions: srvstfunc=25, srvdofunc=46, 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: 260,
|
||||
name: "Dragon Claw",
|
||||
charClass: "ass",
|
||||
srvStFunc: 25,
|
||||
srvDoFunc: 46,
|
||||
|
||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
||||
return evaluateSkillCore113c(ctx)
|
||||
},
|
||||
|
||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
||||
const outcome = executeSkillCore113c(ctx)
|
||||
return {
|
||||
...outcome,
|
||||
notes: [
|
||||
...outcome.notes,
|
||||
'skill_module:skill-260-dragon-claw',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #261: Charged Bolt Sentry (ASS)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 261 ("Charged Bolt Sentry")
|
||||
* - Class: "ass"
|
||||
* - Required Level: 12
|
||||
* - Server Functions: srvstfunc=0, srvdofunc=45, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
||||
* - Associated Missile / State / Summon: missile="", state="", summon="chargeboltsentry"
|
||||
* - 1.13c Synergy Formulas: EDmgSymPerCalc="(skill('Fire Trauma'.blvl) + skill('Lightning 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: 261,
|
||||
name: "Charged Bolt 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-261-charged-bolt-sentry',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #262: Wake of Fire Sentry (ASS)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 262 ("Wake of Fire Sentry")
|
||||
* - Class: "ass"
|
||||
* - Required Level: 12
|
||||
* - Server Functions: srvstfunc=0, srvdofunc=45, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
||||
* - Associated Missile / State / Summon: missile="", state="", summon="wakeofdestruction"
|
||||
* - 1.13c Synergy Formulas: EDmgSymPerCalc="(skill('Fire Trauma'.blvl) + skill('Inferno 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: 262,
|
||||
name: "Wake of Fire 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-262-wake-of-fire-sentry',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #263: Weapon Block (ASS)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 263 ("Weapon Block")
|
||||
* - Class: "ass"
|
||||
* - Required Level: 12
|
||||
* - Server Functions: srvstfunc=0, srvdofunc=0, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
||||
* - Associated Missile / State / Summon: missile="", state="weaponblock", 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: 263,
|
||||
name: "Weapon Block",
|
||||
charClass: "ass",
|
||||
srvStFunc: 0,
|
||||
srvDoFunc: 0,
|
||||
|
||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
||||
return evaluateSkillCore113c(ctx)
|
||||
},
|
||||
|
||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
||||
const outcome = executeSkillCore113c(ctx)
|
||||
return {
|
||||
...outcome,
|
||||
notes: [
|
||||
...outcome.notes,
|
||||
'skill_module:skill-263-weapon-block',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #264: Cloak of Shadows (ASS)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 264 ("Cloak of Shadows")
|
||||
* - Class: "ass"
|
||||
* - Required Level: 12
|
||||
* - Server Functions: srvstfunc=0, srvdofunc=47, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
||||
* - Associated Missile / State / Summon: missile="", state="cloak_of_shadows", 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: 264,
|
||||
name: "Cloak of Shadows",
|
||||
charClass: "ass",
|
||||
srvStFunc: 0,
|
||||
srvDoFunc: 47,
|
||||
|
||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
||||
return evaluateSkillCore113c(ctx)
|
||||
},
|
||||
|
||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
||||
const outcome = executeSkillCore113c(ctx)
|
||||
return {
|
||||
...outcome,
|
||||
notes: [
|
||||
...outcome.notes,
|
||||
'skill_module:skill-264-cloak-of-shadows',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #265: Cobra Strike (ASS)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 265 ("Cobra Strike")
|
||||
* - Class: "ass"
|
||||
* - Required Level: 12
|
||||
* - Server Functions: srvstfunc=23, srvdofunc=34, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
||||
* - Associated Missile / State / Summon: missile="", state="progressive_steal", 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: 265,
|
||||
name: "Cobra 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-265-cobra-strike',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #266: Blade Fury (ASS)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 266 ("Blade Fury")
|
||||
* - Class: "ass"
|
||||
* - Required Level: 18
|
||||
* - Server Functions: srvstfunc=26, srvdofunc=48, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
||||
* - Associated Missile / State / Summon: missile="bladefragment1", 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: 266,
|
||||
name: "Blade Fury",
|
||||
charClass: "ass",
|
||||
srvStFunc: 26,
|
||||
srvDoFunc: 48,
|
||||
|
||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
||||
return evaluateSkillCore113c(ctx)
|
||||
},
|
||||
|
||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
||||
const outcome = executeSkillCore113c(ctx)
|
||||
return {
|
||||
...outcome,
|
||||
notes: [
|
||||
...outcome.notes,
|
||||
'skill_module:skill-266-blade-fury',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #267: Fade (ASS)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 267 ("Fade")
|
||||
* - Class: "ass"
|
||||
* - Required Level: 18
|
||||
* - Server Functions: srvstfunc=0, srvdofunc=18, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
||||
* - Associated Missile / State / Summon: missile="", state="fade", 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: 267,
|
||||
name: "Fade",
|
||||
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-267-fade',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #268: Shadow Warrior (ASS)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 268 ("Shadow Warrior")
|
||||
* - Class: "ass"
|
||||
* - Required Level: 18
|
||||
* - Server Functions: srvstfunc=0, srvdofunc=49, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
||||
* - Associated Missile / State / Summon: missile="", state="shadowwarrior", summon="shadowwarrior"
|
||||
* - 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: 268,
|
||||
name: "Shadow Warrior",
|
||||
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-268-shadow-warrior',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #269: Claws of Thunder (ASS)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 269 ("Claws of Thunder")
|
||||
* - Class: "ass"
|
||||
* - Required Level: 18
|
||||
* - Server Functions: srvstfunc=23, srvdofunc=35, srvprgfunc1=0, srvprgfunc2=36, srvprgfunc3=37
|
||||
* - Associated Missile / State / Summon: missile="", state="progressive_lightning", 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: 269,
|
||||
name: "Claws of Thunder",
|
||||
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-269-claws-of-thunder',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #270: Dragon Tail (ASS)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 270 ("Dragon Tail")
|
||||
* - Class: "ass"
|
||||
* - Required Level: 18
|
||||
* - Server Functions: srvstfunc=27, srvdofunc=50, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
||||
* - Associated Missile / State / Summon: missile="dragontail 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: 270,
|
||||
name: "Dragon Tail",
|
||||
charClass: "ass",
|
||||
srvStFunc: 27,
|
||||
srvDoFunc: 50,
|
||||
|
||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
||||
return evaluateSkillCore113c(ctx)
|
||||
},
|
||||
|
||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
||||
const outcome = executeSkillCore113c(ctx)
|
||||
return {
|
||||
...outcome,
|
||||
notes: [
|
||||
...outcome.notes,
|
||||
'skill_module:skill-270-dragon-tail',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #246: Spirit of Barbs (DRU)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 246 ("Spirit of Barbs")
|
||||
* - Class: "dru"
|
||||
* - Required Level: 30
|
||||
* - Server Functions: srvstfunc=0, srvdofunc=119, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
||||
* - Associated Missile / State / Summon: missile="", state="", summon="spiritofbarbs"
|
||||
* - 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: 246,
|
||||
name: "Spirit of Barbs",
|
||||
charClass: "dru",
|
||||
srvStFunc: 0,
|
||||
srvDoFunc: 119,
|
||||
|
||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
||||
return evaluateSkillCore113c(ctx)
|
||||
},
|
||||
|
||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
||||
const outcome = executeSkillCore113c(ctx)
|
||||
return {
|
||||
...outcome,
|
||||
notes: [
|
||||
...outcome.notes,
|
||||
'skill_module:skill-246-spirit-of-barbs',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #247: Summon Grizzly (DRU)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 247 ("Summon Grizzly")
|
||||
* - Class: "dru"
|
||||
* - Required Level: 30
|
||||
* - Server Functions: srvstfunc=0, srvdofunc=119, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
||||
* - Associated Missile / State / Summon: missile="", state="", summon="druidbear"
|
||||
* - 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: 247,
|
||||
name: "Summon Grizzly",
|
||||
charClass: "dru",
|
||||
srvStFunc: 0,
|
||||
srvDoFunc: 119,
|
||||
|
||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
||||
return evaluateSkillCore113c(ctx)
|
||||
},
|
||||
|
||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
||||
const outcome = executeSkillCore113c(ctx)
|
||||
return {
|
||||
...outcome,
|
||||
notes: [
|
||||
...outcome.notes,
|
||||
'skill_module:skill-247-summon-grizzly',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #248: Fury (DRU)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 248 ("Fury")
|
||||
* - Class: "dru"
|
||||
* - Required Level: 30
|
||||
* - Server Functions: srvstfunc=37, srvdofunc=13, 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: 248,
|
||||
name: "Fury",
|
||||
charClass: "dru",
|
||||
srvStFunc: 37,
|
||||
srvDoFunc: 13,
|
||||
|
||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
||||
return evaluateSkillCore113c(ctx)
|
||||
},
|
||||
|
||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
||||
const outcome = executeSkillCore113c(ctx)
|
||||
return {
|
||||
...outcome,
|
||||
notes: [
|
||||
...outcome.notes,
|
||||
'skill_module:skill-248-fury',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #249: Armageddon (DRU)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 249 ("Armageddon")
|
||||
* - Class: "dru"
|
||||
* - Required Level: 30
|
||||
* - Server Functions: srvstfunc=0, srvdofunc=124, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
||||
* - Associated Missile / State / Summon: missile="armageddoncontrol", state="armageddon", summon=""
|
||||
* - 1.13c Synergy Formulas: EDmgSymPerCalc="(skill('Firestorm'.blvl)+skill('Molten Boulder'.blvl)+skill('Volcano'.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: 249,
|
||||
name: "Armageddon",
|
||||
charClass: "dru",
|
||||
srvStFunc: 0,
|
||||
srvDoFunc: 124,
|
||||
|
||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
||||
return evaluateSkillCore113c(ctx)
|
||||
},
|
||||
|
||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
||||
const outcome = executeSkillCore113c(ctx)
|
||||
return {
|
||||
...outcome,
|
||||
notes: [
|
||||
...outcome.notes,
|
||||
'skill_module:skill-249-armageddon',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Diablo II: Lord of Destruction v1.13c — Skill #250: Hurricane (DRU)
|
||||
*
|
||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
||||
* - Skill ID: 250 ("Hurricane")
|
||||
* - Class: "dru"
|
||||
* - Required Level: 30
|
||||
* - Server Functions: srvstfunc=0, srvdofunc=124, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
||||
* - Associated Missile / State / Summon: missile="", state="hurricane", summon=""
|
||||
* - 1.13c Synergy Formulas: EDmgSymPerCalc="(skill('Twister'.blvl)+skill('Tornado'.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: 250,
|
||||
name: "Hurricane",
|
||||
charClass: "dru",
|
||||
srvStFunc: 0,
|
||||
srvDoFunc: 124,
|
||||
|
||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
||||
return evaluateSkillCore113c(ctx)
|
||||
},
|
||||
|
||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
||||
const outcome = executeSkillCore113c(ctx)
|
||||
return {
|
||||
...outcome,
|
||||
notes: [
|
||||
...outcome.notes,
|
||||
'skill_module:skill-250-hurricane',
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default skillModule
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #251: Fire Trauma (ASS)
|
||||
* Gitea Tracking Issue: #344
|
||||
*/
|
||||
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-251-fire-trauma.ts'
|
||||
|
||||
describe('[Skill #251] Fire Trauma (ASS) — 1.13c Parity (Issue #344)', () => {
|
||||
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(251)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(251)
|
||||
expect(skillModule.name).toBe("Fire Trauma")
|
||||
expect(skillModule.charClass).toBe("ass")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(251, 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(768)
|
||||
expect(r1.maxElemDmg256).toBe(1024)
|
||||
|
||||
const stats10 = new UnitStatList()
|
||||
stats10.setBaseSkillLevel(251, 10)
|
||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
||||
expect(r10.manaCost).toBe(4)
|
||||
expect(r10.manaCost256).toBe(1056)
|
||||
expect(r10.minPhysDmg).toBe(0)
|
||||
expect(r10.maxPhysDmg).toBe(0)
|
||||
expect(r10.minElemDmg256).toBe(5504)
|
||||
expect(r10.maxElemDmg256).toBe(8320)
|
||||
|
||||
const stats20 = new UnitStatList()
|
||||
stats20.setBaseSkillLevel(251, 20)
|
||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
||||
expect(r20.manaCost).toBe(5)
|
||||
expect(r20.manaCost256).toBe(1376)
|
||||
expect(r20.minPhysDmg).toBe(0)
|
||||
expect(r20.maxPhysDmg).toBe(0)
|
||||
expect(r20.minElemDmg256).toBe(21888)
|
||||
expect(r20.maxElemDmg256).toBe(29056)
|
||||
expect(r20.durationFrames).toBe(0)
|
||||
expect(r20.radiusSubtiles).toBe(5)
|
||||
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(251)!
|
||||
const synId = 256
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(251, 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(180)
|
||||
|
||||
// +20 allskills and +33 Marrowwalk charges without hard points must yield 0 synergy
|
||||
const statsSoftOnly = new UnitStatList()
|
||||
statsSoftOnly.setBaseSkillLevel(251, 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: 251,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(251)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #252: Claw Mastery (ASS)
|
||||
* Gitea Tracking Issue: #345
|
||||
*/
|
||||
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-252-claw-mastery.ts'
|
||||
|
||||
describe('[Skill #252] Claw Mastery (ASS) — 1.13c Parity (Issue #345)', () => {
|
||||
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(252)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(252)
|
||||
expect(skillModule.name).toBe("Claw Mastery")
|
||||
expect(skillModule.charClass).toBe("ass")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(252, 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(252, 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(252, 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(0)
|
||||
expect(r20.radiusSubtiles).toBe(220)
|
||||
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(252)!
|
||||
const synId = null
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(252, 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(252, 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: 252,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(252)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #253: Psychic Hammer (ASS)
|
||||
* Gitea Tracking Issue: #346
|
||||
*/
|
||||
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-253-psychic-hammer.ts'
|
||||
|
||||
describe('[Skill #253] Psychic Hammer (ASS) — 1.13c Parity (Issue #346)', () => {
|
||||
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(253)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(253)
|
||||
expect(skillModule.name).toBe("Psychic Hammer")
|
||||
expect(skillModule.charClass).toBe("ass")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(253, 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(2)
|
||||
expect(r1.maxPhysDmg).toBe(6)
|
||||
expect(r1.minElemDmg256).toBe(256)
|
||||
expect(r1.maxElemDmg256).toBe(768)
|
||||
|
||||
const stats10 = new UnitStatList()
|
||||
stats10.setBaseSkillLevel(253, 10)
|
||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
||||
expect(r10.manaCost).toBe(6)
|
||||
expect(r10.manaCost256).toBe(1600)
|
||||
expect(r10.minPhysDmg).toBe(22)
|
||||
expect(r10.maxPhysDmg).toBe(35)
|
||||
expect(r10.minElemDmg256).toBe(2816)
|
||||
expect(r10.maxElemDmg256).toBe(4480)
|
||||
|
||||
const stats20 = new UnitStatList()
|
||||
stats20.setBaseSkillLevel(253, 20)
|
||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
||||
expect(r20.manaCost).toBe(8)
|
||||
expect(r20.manaCost256).toBe(2240)
|
||||
expect(r20.minPhysDmg).toBe(56)
|
||||
expect(r20.maxPhysDmg).toBe(79)
|
||||
expect(r20.minElemDmg256).toBe(7168)
|
||||
expect(r20.maxElemDmg256).toBe(10112)
|
||||
expect(r20.durationFrames).toBe(0)
|
||||
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(253)!
|
||||
const synId = null
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(253, 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(253, 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: 253,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(253)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #254: Tiger Strike (ASS)
|
||||
* Gitea Tracking Issue: #347
|
||||
*/
|
||||
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-254-tiger-strike.ts'
|
||||
|
||||
describe('[Skill #254] Tiger Strike (ASS) — 1.13c Parity (Issue #347)', () => {
|
||||
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(254)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(254)
|
||||
expect(skillModule.name).toBe("Tiger Strike")
|
||||
expect(skillModule.charClass).toBe("ass")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(254, 1)
|
||||
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
|
||||
expect(r1.manaCost).toBe(1)
|
||||
expect(r1.manaCost256).toBe(256)
|
||||
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(254, 10)
|
||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
||||
expect(r10.manaCost).toBe(1)
|
||||
expect(r10.manaCost256).toBe(256)
|
||||
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(254, 20)
|
||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
||||
expect(r20.manaCost).toBe(1)
|
||||
expect(r20.manaCost256).toBe(256)
|
||||
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(480)
|
||||
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(254)!
|
||||
const synId = null
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(254, 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(254, 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: 254,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(254)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #255: Dragon Talon (ASS)
|
||||
* Gitea Tracking Issue: #348
|
||||
*/
|
||||
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-255-dragon-talon.ts'
|
||||
|
||||
describe('[Skill #255] Dragon Talon (ASS) — 1.13c Parity (Issue #348)', () => {
|
||||
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(255)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(255)
|
||||
expect(skillModule.name).toBe("Dragon Talon")
|
||||
expect(skillModule.charClass).toBe("ass")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(255, 1)
|
||||
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
|
||||
expect(r1.manaCost).toBe(6)
|
||||
expect(r1.manaCost256).toBe(1536)
|
||||
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(255, 10)
|
||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
||||
expect(r10.manaCost).toBe(6)
|
||||
expect(r10.manaCost256).toBe(1536)
|
||||
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(255, 20)
|
||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
||||
expect(r20.manaCost).toBe(6)
|
||||
expect(r20.manaCost256).toBe(1536)
|
||||
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(138)
|
||||
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(255)!
|
||||
const synId = null
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(255, 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(255, 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: 255,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(255)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #256: Shock Field (ASS)
|
||||
* Gitea Tracking Issue: #349
|
||||
*/
|
||||
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-256-shock-field.ts'
|
||||
|
||||
describe('[Skill #256] Shock Field (ASS) — 1.13c Parity (Issue #349)', () => {
|
||||
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(256)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(256)
|
||||
expect(skillModule.name).toBe("Shock Field")
|
||||
expect(skillModule.charClass).toBe("ass")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(256, 1)
|
||||
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
|
||||
expect(r1.manaCost).toBe(6)
|
||||
expect(r1.manaCost256).toBe(1536)
|
||||
expect(r1.minPhysDmg).toBe(0)
|
||||
expect(r1.maxPhysDmg).toBe(0)
|
||||
expect(r1.minElemDmg256).toBe(256)
|
||||
expect(r1.maxElemDmg256).toBe(2560)
|
||||
|
||||
const stats10 = new UnitStatList()
|
||||
stats10.setBaseSkillLevel(256, 10)
|
||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
||||
expect(r10.manaCost).toBe(6)
|
||||
expect(r10.manaCost256).toBe(1536)
|
||||
expect(r10.minPhysDmg).toBe(0)
|
||||
expect(r10.maxPhysDmg).toBe(0)
|
||||
expect(r10.minElemDmg256).toBe(256)
|
||||
expect(r10.maxElemDmg256).toBe(11008)
|
||||
|
||||
const stats20 = new UnitStatList()
|
||||
stats20.setBaseSkillLevel(256, 20)
|
||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
||||
expect(r20.manaCost).toBe(6)
|
||||
expect(r20.manaCost256).toBe(1536)
|
||||
expect(r20.minPhysDmg).toBe(0)
|
||||
expect(r20.maxPhysDmg).toBe(0)
|
||||
expect(r20.minElemDmg256).toBe(256)
|
||||
expect(r20.maxElemDmg256).toBe(30464)
|
||||
expect(r20.durationFrames).toBe(0)
|
||||
expect(r20.radiusSubtiles).toBe(3)
|
||||
expect(r20.petMax).toBe(0)
|
||||
expect(r20.cooldownFrames).toBe(15)
|
||||
})
|
||||
|
||||
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(256)!
|
||||
const synId = 261
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(256, 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(220)
|
||||
|
||||
// +20 allskills and +33 Marrowwalk charges without hard points must yield 0 synergy
|
||||
const statsSoftOnly = new UnitStatList()
|
||||
statsSoftOnly.setBaseSkillLevel(256, 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: 256,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(256)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #257: Blade Sentinel (ASS)
|
||||
* Gitea Tracking Issue: #350
|
||||
*/
|
||||
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-257-blade-sentinel.ts'
|
||||
|
||||
describe('[Skill #257] Blade Sentinel (ASS) — 1.13c Parity (Issue #350)', () => {
|
||||
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(257)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(257)
|
||||
expect(skillModule.name).toBe("Blade Sentinel")
|
||||
expect(skillModule.charClass).toBe("ass")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(257, 1)
|
||||
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
|
||||
expect(r1.manaCost).toBe(7)
|
||||
expect(r1.manaCost256).toBe(1792)
|
||||
expect(r1.minPhysDmg).toBe(6)
|
||||
expect(r1.maxPhysDmg).toBe(10)
|
||||
expect(r1.minElemDmg256).toBe(0)
|
||||
expect(r1.maxElemDmg256).toBe(0)
|
||||
|
||||
const stats10 = new UnitStatList()
|
||||
stats10.setBaseSkillLevel(257, 10)
|
||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
||||
expect(r10.manaCost).toBe(7)
|
||||
expect(r10.manaCost256).toBe(1792)
|
||||
expect(r10.minPhysDmg).toBe(35)
|
||||
expect(r10.maxPhysDmg).toBe(39)
|
||||
expect(r10.minElemDmg256).toBe(0)
|
||||
expect(r10.maxElemDmg256).toBe(0)
|
||||
|
||||
const stats20 = new UnitStatList()
|
||||
stats20.setBaseSkillLevel(257, 20)
|
||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
||||
expect(r20.manaCost).toBe(7)
|
||||
expect(r20.manaCost256).toBe(1792)
|
||||
expect(r20.minPhysDmg).toBe(79)
|
||||
expect(r20.maxPhysDmg).toBe(83)
|
||||
expect(r20.minElemDmg256).toBe(0)
|
||||
expect(r20.maxElemDmg256).toBe(0)
|
||||
expect(r20.durationFrames).toBe(0)
|
||||
expect(r20.radiusSubtiles).toBe(328)
|
||||
expect(r20.petMax).toBe(5)
|
||||
expect(r20.cooldownFrames).toBe(50)
|
||||
})
|
||||
|
||||
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(257)!
|
||||
const synId = null
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(257, 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(257, 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: 257,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(257)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #258: Quickness (ASS)
|
||||
* Gitea Tracking Issue: #351
|
||||
*/
|
||||
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-258-quickness.ts'
|
||||
|
||||
describe('[Skill #258] Quickness (ASS) — 1.13c Parity (Issue #351)', () => {
|
||||
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(258)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(258)
|
||||
expect(skillModule.name).toBe("Quickness")
|
||||
expect(skillModule.charClass).toBe("ass")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(258, 1)
|
||||
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
|
||||
expect(r1.manaCost).toBe(10)
|
||||
expect(r1.manaCost256).toBe(2560)
|
||||
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(258, 10)
|
||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
||||
expect(r10.manaCost).toBe(10)
|
||||
expect(r10.manaCost256).toBe(2560)
|
||||
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(258, 20)
|
||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
||||
expect(r20.manaCost).toBe(10)
|
||||
expect(r20.manaCost256).toBe(2560)
|
||||
expect(r20.minPhysDmg).toBe(0)
|
||||
expect(r20.maxPhysDmg).toBe(0)
|
||||
expect(r20.minElemDmg256).toBe(0)
|
||||
expect(r20.maxElemDmg256).toBe(0)
|
||||
expect(r20.durationFrames).toBe(8700)
|
||||
expect(r20.radiusSubtiles).toBe(1345)
|
||||
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(258)!
|
||||
const synId = null
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(258, 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(258, 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: 258,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(258)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #259: Fists of Fire (ASS)
|
||||
* Gitea Tracking Issue: #352
|
||||
*/
|
||||
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-259-fists-of-fire.ts'
|
||||
|
||||
describe('[Skill #259] Fists of Fire (ASS) — 1.13c Parity (Issue #352)', () => {
|
||||
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(259)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(259)
|
||||
expect(skillModule.name).toBe("Fists of Fire")
|
||||
expect(skillModule.charClass).toBe("ass")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(259, 1)
|
||||
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
|
||||
expect(r1.manaCost).toBe(2)
|
||||
expect(r1.manaCost256).toBe(512)
|
||||
expect(r1.minPhysDmg).toBe(0)
|
||||
expect(r1.maxPhysDmg).toBe(0)
|
||||
expect(r1.minElemDmg256).toBe(1536)
|
||||
expect(r1.maxElemDmg256).toBe(2560)
|
||||
|
||||
const stats10 = new UnitStatList()
|
||||
stats10.setBaseSkillLevel(259, 10)
|
||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
||||
expect(r10.manaCost).toBe(2)
|
||||
expect(r10.manaCost256).toBe(512)
|
||||
expect(r10.minPhysDmg).toBe(0)
|
||||
expect(r10.maxPhysDmg).toBe(0)
|
||||
expect(r10.minElemDmg256).toBe(15616)
|
||||
expect(r10.maxElemDmg256).toBe(17152)
|
||||
|
||||
const stats20 = new UnitStatList()
|
||||
stats20.setBaseSkillLevel(259, 20)
|
||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
||||
expect(r20.manaCost).toBe(2)
|
||||
expect(r20.manaCost256).toBe(512)
|
||||
expect(r20.minPhysDmg).toBe(0)
|
||||
expect(r20.maxPhysDmg).toBe(0)
|
||||
expect(r20.minElemDmg256).toBe(51456)
|
||||
expect(r20.maxElemDmg256).toBe(56576)
|
||||
expect(r20.durationFrames).toBe(375)
|
||||
expect(r20.radiusSubtiles).toBe(80)
|
||||
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(259)!
|
||||
const synId = 280
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(259, 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(259, 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: 259,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(259)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #260: Dragon Claw (ASS)
|
||||
* Gitea Tracking Issue: #353
|
||||
*/
|
||||
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-260-dragon-claw.ts'
|
||||
|
||||
describe('[Skill #260] Dragon Claw (ASS) — 1.13c Parity (Issue #353)', () => {
|
||||
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(260)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(260)
|
||||
expect(skillModule.name).toBe("Dragon Claw")
|
||||
expect(skillModule.charClass).toBe("ass")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(260, 1)
|
||||
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
|
||||
expect(r1.manaCost).toBe(2)
|
||||
expect(r1.manaCost256).toBe(512)
|
||||
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(260, 10)
|
||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
||||
expect(r10.manaCost).toBe(2)
|
||||
expect(r10.manaCost256).toBe(512)
|
||||
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(260, 20)
|
||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
||||
expect(r20.manaCost).toBe(2)
|
||||
expect(r20.manaCost256).toBe(512)
|
||||
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(145)
|
||||
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(260)!
|
||||
const synId = 252
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(260, 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(80)
|
||||
|
||||
// +20 allskills and +33 Marrowwalk charges without hard points must yield 0 synergy
|
||||
const statsSoftOnly = new UnitStatList()
|
||||
statsSoftOnly.setBaseSkillLevel(260, 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: 260,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(260)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #261: Charged Bolt Sentry (ASS)
|
||||
* Gitea Tracking Issue: #354
|
||||
*/
|
||||
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-261-charged-bolt-sentry.ts'
|
||||
|
||||
describe('[Skill #261] Charged Bolt Sentry (ASS) — 1.13c Parity (Issue #354)', () => {
|
||||
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(261)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(261)
|
||||
expect(skillModule.name).toBe("Charged Bolt Sentry")
|
||||
expect(skillModule.charClass).toBe("ass")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(261, 1)
|
||||
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
|
||||
expect(r1.manaCost).toBe(13)
|
||||
expect(r1.manaCost256).toBe(3328)
|
||||
expect(r1.minPhysDmg).toBe(0)
|
||||
expect(r1.maxPhysDmg).toBe(0)
|
||||
expect(r1.minElemDmg256).toBe(256)
|
||||
expect(r1.maxElemDmg256).toBe(1792)
|
||||
|
||||
const stats10 = new UnitStatList()
|
||||
stats10.setBaseSkillLevel(261, 10)
|
||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
||||
expect(r10.manaCost).toBe(13)
|
||||
expect(r10.manaCost256).toBe(3328)
|
||||
expect(r10.minPhysDmg).toBe(0)
|
||||
expect(r10.maxPhysDmg).toBe(0)
|
||||
expect(r10.minElemDmg256).toBe(256)
|
||||
expect(r10.maxElemDmg256).toBe(9216)
|
||||
|
||||
const stats20 = new UnitStatList()
|
||||
stats20.setBaseSkillLevel(261, 20)
|
||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
||||
expect(r20.manaCost).toBe(13)
|
||||
expect(r20.manaCost256).toBe(3328)
|
||||
expect(r20.minPhysDmg).toBe(0)
|
||||
expect(r20.maxPhysDmg).toBe(0)
|
||||
expect(r20.minElemDmg256).toBe(256)
|
||||
expect(r20.maxElemDmg256).toBe(21504)
|
||||
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(261)!
|
||||
const synId = 251
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(261, 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(120)
|
||||
|
||||
// +20 allskills and +33 Marrowwalk charges without hard points must yield 0 synergy
|
||||
const statsSoftOnly = new UnitStatList()
|
||||
statsSoftOnly.setBaseSkillLevel(261, 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: 261,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(261)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #262: Wake of Fire Sentry (ASS)
|
||||
* Gitea Tracking Issue: #355
|
||||
*/
|
||||
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-262-wake-of-fire-sentry.ts'
|
||||
|
||||
describe('[Skill #262] Wake of Fire Sentry (ASS) — 1.13c Parity (Issue #355)', () => {
|
||||
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(262)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(262)
|
||||
expect(skillModule.name).toBe("Wake of Fire Sentry")
|
||||
expect(skillModule.charClass).toBe("ass")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(262, 1)
|
||||
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
|
||||
expect(r1.manaCost).toBe(13)
|
||||
expect(r1.manaCost256).toBe(3328)
|
||||
expect(r1.minPhysDmg).toBe(0)
|
||||
expect(r1.maxPhysDmg).toBe(0)
|
||||
expect(r1.minElemDmg256).toBe(1280)
|
||||
expect(r1.maxElemDmg256).toBe(2560)
|
||||
|
||||
const stats10 = new UnitStatList()
|
||||
stats10.setBaseSkillLevel(262, 10)
|
||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
||||
expect(r10.manaCost).toBe(13)
|
||||
expect(r10.manaCost256).toBe(3328)
|
||||
expect(r10.minPhysDmg).toBe(0)
|
||||
expect(r10.maxPhysDmg).toBe(0)
|
||||
expect(r10.minElemDmg256).toBe(6400)
|
||||
expect(r10.maxElemDmg256).toBe(7680)
|
||||
|
||||
const stats20 = new UnitStatList()
|
||||
stats20.setBaseSkillLevel(262, 20)
|
||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
||||
expect(r20.manaCost).toBe(13)
|
||||
expect(r20.manaCost256).toBe(3328)
|
||||
expect(r20.minPhysDmg).toBe(0)
|
||||
expect(r20.maxPhysDmg).toBe(0)
|
||||
expect(r20.minElemDmg256).toBe(16128)
|
||||
expect(r20.maxElemDmg256).toBe(18432)
|
||||
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(262)!
|
||||
const synId = 251
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(262, 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(262, 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: 262,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(262)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #263: Weapon Block (ASS)
|
||||
* Gitea Tracking Issue: #356
|
||||
*/
|
||||
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-263-weapon-block.ts'
|
||||
|
||||
describe('[Skill #263] Weapon Block (ASS) — 1.13c Parity (Issue #356)', () => {
|
||||
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(263)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(263)
|
||||
expect(skillModule.name).toBe("Weapon Block")
|
||||
expect(skillModule.charClass).toBe("ass")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(263, 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(263, 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(263, 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(0)
|
||||
expect(r20.radiusSubtiles).toBe(1255)
|
||||
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(263)!
|
||||
const synId = null
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(263, 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(263, 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: 263,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(263)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #264: Cloak of Shadows (ASS)
|
||||
* Gitea Tracking Issue: #357
|
||||
*/
|
||||
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-264-cloak-of-shadows.ts'
|
||||
|
||||
describe('[Skill #264] Cloak of Shadows (ASS) — 1.13c Parity (Issue #357)', () => {
|
||||
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(264)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(264)
|
||||
expect(skillModule.name).toBe("Cloak of Shadows")
|
||||
expect(skillModule.charClass).toBe("ass")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(264, 1)
|
||||
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
|
||||
expect(r1.manaCost).toBe(13)
|
||||
expect(r1.manaCost256).toBe(3328)
|
||||
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(264, 10)
|
||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
||||
expect(r10.manaCost).toBe(13)
|
||||
expect(r10.manaCost256).toBe(3328)
|
||||
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(264, 20)
|
||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
||||
expect(r20.manaCost).toBe(13)
|
||||
expect(r20.manaCost256).toBe(3328)
|
||||
expect(r20.minPhysDmg).toBe(0)
|
||||
expect(r20.maxPhysDmg).toBe(0)
|
||||
expect(r20.minElemDmg256).toBe(0)
|
||||
expect(r20.maxElemDmg256).toBe(0)
|
||||
expect(r20.durationFrames).toBe(675)
|
||||
expect(r20.radiusSubtiles).toBe(30)
|
||||
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(264)!
|
||||
const synId = null
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(264, 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(264, 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: 264,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(264)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #265: Cobra Strike (ASS)
|
||||
* Gitea Tracking Issue: #358
|
||||
*/
|
||||
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-265-cobra-strike.ts'
|
||||
|
||||
describe('[Skill #265] Cobra Strike (ASS) — 1.13c Parity (Issue #358)', () => {
|
||||
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(265)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(265)
|
||||
expect(skillModule.name).toBe("Cobra Strike")
|
||||
expect(skillModule.charClass).toBe("ass")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(265, 1)
|
||||
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
|
||||
expect(r1.manaCost).toBe(2)
|
||||
expect(r1.manaCost256).toBe(512)
|
||||
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(265, 10)
|
||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
||||
expect(r10.manaCost).toBe(2)
|
||||
expect(r10.manaCost256).toBe(512)
|
||||
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(265, 20)
|
||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
||||
expect(r20.manaCost).toBe(2)
|
||||
expect(r20.manaCost256).toBe(512)
|
||||
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(135)
|
||||
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(265)!
|
||||
const synId = null
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(265, 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(265, 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: 265,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(265)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #266: Blade Fury (ASS)
|
||||
* Gitea Tracking Issue: #359
|
||||
*/
|
||||
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-266-blade-fury.ts'
|
||||
|
||||
describe('[Skill #266] Blade Fury (ASS) — 1.13c Parity (Issue #359)', () => {
|
||||
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(266)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(266)
|
||||
expect(skillModule.name).toBe("Blade Fury")
|
||||
expect(skillModule.charClass).toBe("ass")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(266, 1)
|
||||
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
|
||||
expect(r1.manaCost).toBe(1)
|
||||
expect(r1.manaCost256).toBe(256)
|
||||
expect(r1.minPhysDmg).toBe(8)
|
||||
expect(r1.maxPhysDmg).toBe(10)
|
||||
expect(r1.minElemDmg256).toBe(0)
|
||||
expect(r1.maxElemDmg256).toBe(0)
|
||||
|
||||
const stats10 = new UnitStatList()
|
||||
stats10.setBaseSkillLevel(266, 10)
|
||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
||||
expect(r10.manaCost).toBe(2)
|
||||
expect(r10.manaCost256).toBe(544)
|
||||
expect(r10.minPhysDmg).toBe(39)
|
||||
expect(r10.maxPhysDmg).toBe(41)
|
||||
expect(r10.minElemDmg256).toBe(0)
|
||||
expect(r10.maxElemDmg256).toBe(0)
|
||||
|
||||
const stats20 = new UnitStatList()
|
||||
stats20.setBaseSkillLevel(266, 20)
|
||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
||||
expect(r20.manaCost).toBe(3)
|
||||
expect(r20.manaCost256).toBe(864)
|
||||
expect(r20.minPhysDmg).toBe(101)
|
||||
expect(r20.maxPhysDmg).toBe(103)
|
||||
expect(r20.minElemDmg256).toBe(0)
|
||||
expect(r20.maxElemDmg256).toBe(0)
|
||||
expect(r20.durationFrames).toBe(0)
|
||||
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(266)!
|
||||
const synId = null
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(266, 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(266, 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: 266,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(266)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #267: Fade (ASS)
|
||||
* Gitea Tracking Issue: #360
|
||||
*/
|
||||
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-267-fade.ts'
|
||||
|
||||
describe('[Skill #267] Fade (ASS) — 1.13c Parity (Issue #360)', () => {
|
||||
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(267)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(267)
|
||||
expect(skillModule.name).toBe("Fade")
|
||||
expect(skillModule.charClass).toBe("ass")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(267, 1)
|
||||
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
|
||||
expect(r1.manaCost).toBe(10)
|
||||
expect(r1.manaCost256).toBe(2560)
|
||||
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(267, 10)
|
||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
||||
expect(r10.manaCost).toBe(10)
|
||||
expect(r10.manaCost256).toBe(2560)
|
||||
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(267, 20)
|
||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
||||
expect(r20.manaCost).toBe(10)
|
||||
expect(r20.manaCost256).toBe(2560)
|
||||
expect(r20.minPhysDmg).toBe(0)
|
||||
expect(r20.maxPhysDmg).toBe(0)
|
||||
expect(r20.minElemDmg256).toBe(0)
|
||||
expect(r20.maxElemDmg256).toBe(0)
|
||||
expect(r20.durationFrames).toBe(8700)
|
||||
expect(r20.radiusSubtiles).toBe(1435)
|
||||
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(267)!
|
||||
const synId = null
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(267, 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(267, 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: 267,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(267)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #268: Shadow Warrior (ASS)
|
||||
* Gitea Tracking Issue: #361
|
||||
*/
|
||||
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-268-shadow-warrior.ts'
|
||||
|
||||
describe('[Skill #268] Shadow Warrior (ASS) — 1.13c Parity (Issue #361)', () => {
|
||||
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(268)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(268)
|
||||
expect(skillModule.name).toBe("Shadow Warrior")
|
||||
expect(skillModule.charClass).toBe("ass")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(268, 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(0)
|
||||
expect(r1.maxPhysDmg).toBe(0)
|
||||
expect(r1.minElemDmg256).toBe(0)
|
||||
expect(r1.maxElemDmg256).toBe(0)
|
||||
|
||||
const stats10 = new UnitStatList()
|
||||
stats10.setBaseSkillLevel(268, 10)
|
||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
||||
expect(r10.manaCost).toBe(31)
|
||||
expect(r10.manaCost256).toBe(8064)
|
||||
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(268, 20)
|
||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
||||
expect(r20.manaCost).toBe(36)
|
||||
expect(r20.manaCost256).toBe(9344)
|
||||
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(268)!
|
||||
const synId = null
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(268, 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(268, 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: 268,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(268)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #269: Claws of Thunder (ASS)
|
||||
* Gitea Tracking Issue: #362
|
||||
*/
|
||||
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-269-claws-of-thunder.ts'
|
||||
|
||||
describe('[Skill #269] Claws of Thunder (ASS) — 1.13c Parity (Issue #362)', () => {
|
||||
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(269)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(269)
|
||||
expect(skillModule.name).toBe("Claws of Thunder")
|
||||
expect(skillModule.charClass).toBe("ass")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(269, 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(256)
|
||||
expect(r1.maxElemDmg256).toBe(20480)
|
||||
|
||||
const stats10 = new UnitStatList()
|
||||
stats10.setBaseSkillLevel(269, 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(256)
|
||||
expect(r10.maxElemDmg256).toBe(76800)
|
||||
|
||||
const stats20 = new UnitStatList()
|
||||
stats20.setBaseSkillLevel(269, 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(256)
|
||||
expect(r20.maxElemDmg256).toBe(199680)
|
||||
expect(r20.durationFrames).toBe(375)
|
||||
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(269)!
|
||||
const synId = 280
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(269, 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(269, 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: 269,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(269)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #270: Dragon Tail (ASS)
|
||||
* Gitea Tracking Issue: #363
|
||||
*/
|
||||
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-270-dragon-tail.ts'
|
||||
|
||||
describe('[Skill #270] Dragon Tail (ASS) — 1.13c Parity (Issue #363)', () => {
|
||||
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(270)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(270)
|
||||
expect(skillModule.name).toBe("Dragon Tail")
|
||||
expect(skillModule.charClass).toBe("ass")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(270, 1)
|
||||
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
|
||||
expect(r1.manaCost).toBe(10)
|
||||
expect(r1.manaCost256).toBe(2560)
|
||||
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(270, 10)
|
||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
||||
expect(r10.manaCost).toBe(10)
|
||||
expect(r10.manaCost256).toBe(2560)
|
||||
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(270, 20)
|
||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
||||
expect(r20.manaCost).toBe(10)
|
||||
expect(r20.manaCost256).toBe(2560)
|
||||
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(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(270)!
|
||||
const synId = null
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(270, 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(270, 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: 270,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(270)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #246: Spirit of Barbs (DRU)
|
||||
* Gitea Tracking Issue: #339
|
||||
*/
|
||||
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/dru/skill-246-spirit-of-barbs.ts'
|
||||
|
||||
describe('[Skill #246] Spirit of Barbs (DRU) — 1.13c Parity (Issue #339)', () => {
|
||||
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(246)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(246)
|
||||
expect(skillModule.name).toBe("Spirit of Barbs")
|
||||
expect(skillModule.charClass).toBe("dru")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(246, 1)
|
||||
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
|
||||
expect(r1.manaCost).toBe(25)
|
||||
expect(r1.manaCost256).toBe(6400)
|
||||
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(246, 10)
|
||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
||||
expect(r10.manaCost).toBe(34)
|
||||
expect(r10.manaCost256).toBe(8704)
|
||||
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(246, 20)
|
||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
||||
expect(r20.manaCost).toBe(44)
|
||||
expect(r20.manaCost256).toBe(11264)
|
||||
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(0)
|
||||
expect(r20.petMax).toBe(1)
|
||||
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(246)!
|
||||
const synId = null
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(246, 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(246, 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: "dru",
|
||||
skillId: 246,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(246)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #247: Summon Grizzly (DRU)
|
||||
* Gitea Tracking Issue: #340
|
||||
*/
|
||||
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/dru/skill-247-summon-grizzly.ts'
|
||||
|
||||
describe('[Skill #247] Summon Grizzly (DRU) — 1.13c Parity (Issue #340)', () => {
|
||||
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(247)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(247)
|
||||
expect(skillModule.name).toBe("Summon Grizzly")
|
||||
expect(skillModule.charClass).toBe("dru")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(247, 1)
|
||||
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
|
||||
expect(r1.manaCost).toBe(40)
|
||||
expect(r1.manaCost256).toBe(10240)
|
||||
expect(r1.minPhysDmg).toBe(30)
|
||||
expect(r1.maxPhysDmg).toBe(60)
|
||||
expect(r1.minElemDmg256).toBe(0)
|
||||
expect(r1.maxElemDmg256).toBe(0)
|
||||
|
||||
const stats10 = new UnitStatList()
|
||||
stats10.setBaseSkillLevel(247, 10)
|
||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
||||
expect(r10.manaCost).toBe(40)
|
||||
expect(r10.manaCost256).toBe(10240)
|
||||
expect(r10.minPhysDmg).toBe(130)
|
||||
expect(r10.maxPhysDmg).toBe(160)
|
||||
expect(r10.minElemDmg256).toBe(0)
|
||||
expect(r10.maxElemDmg256).toBe(0)
|
||||
|
||||
const stats20 = new UnitStatList()
|
||||
stats20.setBaseSkillLevel(247, 20)
|
||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
||||
expect(r20.manaCost).toBe(40)
|
||||
expect(r20.manaCost256).toBe(10240)
|
||||
expect(r20.minPhysDmg).toBe(300)
|
||||
expect(r20.maxPhysDmg).toBe(330)
|
||||
expect(r20.minElemDmg256).toBe(0)
|
||||
expect(r20.maxElemDmg256).toBe(0)
|
||||
expect(r20.durationFrames).toBe(0)
|
||||
expect(r20.radiusSubtiles).toBe(215)
|
||||
expect(r20.petMax).toBe(1)
|
||||
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(247)!
|
||||
const synId = null
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(247, 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(247, 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: "dru",
|
||||
skillId: 247,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(247)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #248: Fury (DRU)
|
||||
* Gitea Tracking Issue: #341
|
||||
*/
|
||||
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/dru/skill-248-fury.ts'
|
||||
|
||||
describe('[Skill #248] Fury (DRU) — 1.13c Parity (Issue #341)', () => {
|
||||
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(248)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(248)
|
||||
expect(skillModule.name).toBe("Fury")
|
||||
expect(skillModule.charClass).toBe("dru")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(248, 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(248, 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(248, 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(0)
|
||||
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(248)!
|
||||
const synId = null
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(248, 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(248, 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: "dru",
|
||||
skillId: 248,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(248)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #249: Armageddon (DRU)
|
||||
* Gitea Tracking Issue: #342
|
||||
*/
|
||||
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/dru/skill-249-armageddon.ts'
|
||||
|
||||
describe('[Skill #249] Armageddon (DRU) — 1.13c Parity (Issue #342)', () => {
|
||||
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(249)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(249)
|
||||
expect(skillModule.name).toBe("Armageddon")
|
||||
expect(skillModule.charClass).toBe("dru")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(249, 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(4)
|
||||
expect(r1.maxPhysDmg).toBe(16)
|
||||
expect(r1.minElemDmg256).toBe(6400)
|
||||
expect(r1.maxElemDmg256).toBe(19200)
|
||||
|
||||
const stats10 = new UnitStatList()
|
||||
stats10.setBaseSkillLevel(249, 10)
|
||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
||||
expect(r10.manaCost).toBe(35)
|
||||
expect(r10.manaCost256).toBe(8960)
|
||||
expect(r10.minPhysDmg).toBe(44)
|
||||
expect(r10.maxPhysDmg).toBe(58)
|
||||
expect(r10.minElemDmg256).toBe(43520)
|
||||
expect(r10.maxElemDmg256).toBe(59136)
|
||||
|
||||
const stats20 = new UnitStatList()
|
||||
stats20.setBaseSkillLevel(249, 20)
|
||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
||||
expect(r20.manaCost).toBe(35)
|
||||
expect(r20.manaCost256).toBe(8960)
|
||||
expect(r20.minPhysDmg).toBe(112)
|
||||
expect(r20.maxPhysDmg).toBe(136)
|
||||
expect(r20.minElemDmg256).toBe(99840)
|
||||
expect(r20.maxElemDmg256).toBe(120576)
|
||||
expect(r20.durationFrames).toBe(250)
|
||||
expect(r20.radiusSubtiles).toBe(8)
|
||||
expect(r20.petMax).toBe(0)
|
||||
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(249)!
|
||||
const synId = 225
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(249, 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(280)
|
||||
|
||||
// +20 allskills and +33 Marrowwalk charges without hard points must yield 0 synergy
|
||||
const statsSoftOnly = new UnitStatList()
|
||||
statsSoftOnly.setBaseSkillLevel(249, 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: "dru",
|
||||
skillId: 249,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(249)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* 1.13c Numerical & Runtime Verification Suite — Skill #250: Hurricane (DRU)
|
||||
* Gitea Tracking Issue: #343
|
||||
*/
|
||||
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/dru/skill-250-hurricane.ts'
|
||||
|
||||
describe('[Skill #250] Hurricane (DRU) — 1.13c Parity (Issue #343)', () => {
|
||||
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(250)!
|
||||
expect(skillRec).toBeDefined()
|
||||
expect(skillModule.skillId).toBe(250)
|
||||
expect(skillModule.name).toBe("Hurricane")
|
||||
expect(skillModule.charClass).toBe("dru")
|
||||
|
||||
const stats1 = new UnitStatList()
|
||||
stats1.setBaseSkillLevel(250, 1)
|
||||
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
|
||||
expect(r1.manaCost).toBe(30)
|
||||
expect(r1.manaCost256).toBe(7680)
|
||||
expect(r1.minPhysDmg).toBe(0)
|
||||
expect(r1.maxPhysDmg).toBe(0)
|
||||
expect(r1.minElemDmg256).toBe(6400)
|
||||
expect(r1.maxElemDmg256).toBe(12800)
|
||||
|
||||
const stats10 = new UnitStatList()
|
||||
stats10.setBaseSkillLevel(250, 10)
|
||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
||||
expect(r10.manaCost).toBe(30)
|
||||
expect(r10.manaCost256).toBe(7680)
|
||||
expect(r10.minPhysDmg).toBe(0)
|
||||
expect(r10.maxPhysDmg).toBe(0)
|
||||
expect(r10.minElemDmg256).toBe(24064)
|
||||
expect(r10.maxElemDmg256).toBe(30464)
|
||||
|
||||
const stats20 = new UnitStatList()
|
||||
stats20.setBaseSkillLevel(250, 20)
|
||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
||||
expect(r20.manaCost).toBe(30)
|
||||
expect(r20.manaCost256).toBe(7680)
|
||||
expect(r20.minPhysDmg).toBe(0)
|
||||
expect(r20.maxPhysDmg).toBe(0)
|
||||
expect(r20.minElemDmg256).toBe(51712)
|
||||
expect(r20.maxElemDmg256).toBe(58112)
|
||||
expect(r20.durationFrames).toBe(250)
|
||||
expect(r20.radiusSubtiles).toBe(9)
|
||||
expect(r20.petMax).toBe(0)
|
||||
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(250)!
|
||||
const synId = 240
|
||||
|
||||
const statsBase = new UnitStatList()
|
||||
statsBase.setBaseSkillLevel(250, 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(180)
|
||||
|
||||
// +20 allskills and +33 Marrowwalk charges without hard points must yield 0 synergy
|
||||
const statsSoftOnly = new UnitStatList()
|
||||
statsSoftOnly.setBaseSkillLevel(250, 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: "dru",
|
||||
skillId: 250,
|
||||
slvl: 20,
|
||||
})
|
||||
const outcome = arena.triggerCast()
|
||||
arena.stepTicks(15)
|
||||
const dbg = arena.getDebugState()
|
||||
|
||||
expect(dbg.ready).toBe(true)
|
||||
expect(dbg.skillId).toBe(250)
|
||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
||||
expect(dbg.actionFrameTriggered).toBe(true)
|
||||
expect(outcome?.executed).toBe(true)
|
||||
})
|
||||
})
|
||||
Loading…
Reference in New Issue