Compare commits
No commits in common. "9a32215ec0c6db9b4b129c4d9459517c36b59082" and "210d59e3f2adb296670a7e3927c191f8efec1226" have entirely different histories.
9a32215ec0
...
210d59e3f2
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #126: Bash (BAR)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 126 ("Bash")
|
|
||||||
* - Class: "bar"
|
|
||||||
* - Required Level: 1
|
|
||||||
* - Server Functions: srvstfunc=32, srvdofunc=2, 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: 126,
|
|
||||||
name: "Bash",
|
|
||||||
charClass: "bar",
|
|
||||||
srvStFunc: 32,
|
|
||||||
srvDoFunc: 2,
|
|
||||||
|
|
||||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
|
||||||
return evaluateSkillCore113c(ctx)
|
|
||||||
},
|
|
||||||
|
|
||||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
|
||||||
const outcome = executeSkillCore113c(ctx)
|
|
||||||
return {
|
|
||||||
...outcome,
|
|
||||||
notes: [
|
|
||||||
...outcome.notes,
|
|
||||||
'skill_module:skill-126-bash',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #127: Sword Mastery (BAR)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 127 ("Sword Mastery")
|
|
||||||
* - Class: "bar"
|
|
||||||
* - Required Level: 1
|
|
||||||
* - Server Functions: srvstfunc=0, srvdofunc=0, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
|
||||||
* - Associated Missile / State / Summon: missile="", state="swordmastery", 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: 127,
|
|
||||||
name: "Sword Mastery",
|
|
||||||
charClass: "bar",
|
|
||||||
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-127-sword-mastery',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #128: Axe Mastery (BAR)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 128 ("Axe Mastery")
|
|
||||||
* - Class: "bar"
|
|
||||||
* - Required Level: 1
|
|
||||||
* - Server Functions: srvstfunc=0, srvdofunc=0, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
|
||||||
* - Associated Missile / State / Summon: missile="", state="axemastery", 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: 128,
|
|
||||||
name: "Axe Mastery",
|
|
||||||
charClass: "bar",
|
|
||||||
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-128-axe-mastery',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #129: Mace Mastery (BAR)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 129 ("Mace Mastery")
|
|
||||||
* - Class: "bar"
|
|
||||||
* - Required Level: 1
|
|
||||||
* - Server Functions: srvstfunc=0, srvdofunc=0, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
|
||||||
* - Associated Missile / State / Summon: missile="", state="macemastery", 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: 129,
|
|
||||||
name: "Mace Mastery",
|
|
||||||
charClass: "bar",
|
|
||||||
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-129-mace-mastery',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #130: Howl (BAR)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 130 ("Howl")
|
|
||||||
* - Class: "bar"
|
|
||||||
* - Required Level: 1
|
|
||||||
* - Server Functions: srvstfunc=0, srvdofunc=22, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
|
||||||
* - Associated Missile / State / Summon: missile="howl", 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: 130,
|
|
||||||
name: "Howl",
|
|
||||||
charClass: "bar",
|
|
||||||
srvStFunc: 0,
|
|
||||||
srvDoFunc: 22,
|
|
||||||
|
|
||||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
|
||||||
return evaluateSkillCore113c(ctx)
|
|
||||||
},
|
|
||||||
|
|
||||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
|
||||||
const outcome = executeSkillCore113c(ctx)
|
|
||||||
return {
|
|
||||||
...outcome,
|
|
||||||
notes: [
|
|
||||||
...outcome.notes,
|
|
||||||
'skill_module:skill-130-howl',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #131: Find Potion (BAR)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 131 ("Find Potion")
|
|
||||||
* - Class: "bar"
|
|
||||||
* - Required Level: 1
|
|
||||||
* - Server Functions: srvstfunc=33, srvdofunc=69, 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: 131,
|
|
||||||
name: "Find Potion",
|
|
||||||
charClass: "bar",
|
|
||||||
srvStFunc: 33,
|
|
||||||
srvDoFunc: 69,
|
|
||||||
|
|
||||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
|
||||||
return evaluateSkillCore113c(ctx)
|
|
||||||
},
|
|
||||||
|
|
||||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
|
||||||
const outcome = executeSkillCore113c(ctx)
|
|
||||||
return {
|
|
||||||
...outcome,
|
|
||||||
notes: [
|
|
||||||
...outcome.notes,
|
|
||||||
'skill_module:skill-131-find-potion',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #132: Leap (BAR)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 132 ("Leap")
|
|
||||||
* - Class: "bar"
|
|
||||||
* - Required Level: 6
|
|
||||||
* - Server Functions: srvstfunc=40, srvdofunc=77, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
|
||||||
* - Associated Missile / State / Summon: missile="leapknockback", 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: 132,
|
|
||||||
name: "Leap",
|
|
||||||
charClass: "bar",
|
|
||||||
srvStFunc: 40,
|
|
||||||
srvDoFunc: 77,
|
|
||||||
|
|
||||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
|
||||||
return evaluateSkillCore113c(ctx)
|
|
||||||
},
|
|
||||||
|
|
||||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
|
||||||
const outcome = executeSkillCore113c(ctx)
|
|
||||||
return {
|
|
||||||
...outcome,
|
|
||||||
notes: [
|
|
||||||
...outcome.notes,
|
|
||||||
'skill_module:skill-132-leap',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #133: Double Swing (BAR)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 133 ("Double Swing")
|
|
||||||
* - Class: "bar"
|
|
||||||
* - Required Level: 6
|
|
||||||
* - Server Functions: srvstfunc=0, srvdofunc=70, 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: 133,
|
|
||||||
name: "Double Swing",
|
|
||||||
charClass: "bar",
|
|
||||||
srvStFunc: 0,
|
|
||||||
srvDoFunc: 70,
|
|
||||||
|
|
||||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
|
||||||
return evaluateSkillCore113c(ctx)
|
|
||||||
},
|
|
||||||
|
|
||||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
|
||||||
const outcome = executeSkillCore113c(ctx)
|
|
||||||
return {
|
|
||||||
...outcome,
|
|
||||||
notes: [
|
|
||||||
...outcome.notes,
|
|
||||||
'skill_module:skill-133-double-swing',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #134: Pole Arm Mastery (BAR)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 134 ("Pole Arm Mastery")
|
|
||||||
* - Class: "bar"
|
|
||||||
* - Required Level: 6
|
|
||||||
* - Server Functions: srvstfunc=0, srvdofunc=0, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
|
||||||
* - Associated Missile / State / Summon: missile="", state="polearmmastery", 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: 134,
|
|
||||||
name: "Pole Arm Mastery",
|
|
||||||
charClass: "bar",
|
|
||||||
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-134-pole-arm-mastery',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #110: Resist Lightning (PAL)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 110 ("Resist Lightning")
|
|
||||||
* - Class: "pal"
|
|
||||||
* - Required Level: 12
|
|
||||||
* - Server Functions: srvstfunc=0, srvdofunc=65, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
|
||||||
* - Associated Missile / State / Summon: missile="", state="resistlight", 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: 110,
|
|
||||||
name: "Resist Lightning",
|
|
||||||
charClass: "pal",
|
|
||||||
srvStFunc: 0,
|
|
||||||
srvDoFunc: 65,
|
|
||||||
|
|
||||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
|
||||||
return evaluateSkillCore113c(ctx)
|
|
||||||
},
|
|
||||||
|
|
||||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
|
||||||
const outcome = executeSkillCore113c(ctx)
|
|
||||||
return {
|
|
||||||
...outcome,
|
|
||||||
notes: [
|
|
||||||
...outcome.notes,
|
|
||||||
'skill_module:skill-110-resist-lightning',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #111: Vengeance (PAL)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 111 ("Vengeance")
|
|
||||||
* - Class: "pal"
|
|
||||||
* - Required Level: 18
|
|
||||||
* - Server Functions: srvstfunc=35, srvdofunc=2, 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: 111,
|
|
||||||
name: "Vengeance",
|
|
||||||
charClass: "pal",
|
|
||||||
srvStFunc: 35,
|
|
||||||
srvDoFunc: 2,
|
|
||||||
|
|
||||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
|
||||||
return evaluateSkillCore113c(ctx)
|
|
||||||
},
|
|
||||||
|
|
||||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
|
||||||
const outcome = executeSkillCore113c(ctx)
|
|
||||||
return {
|
|
||||||
...outcome,
|
|
||||||
notes: [
|
|
||||||
...outcome.notes,
|
|
||||||
'skill_module:skill-111-vengeance',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #112: Blessed Hammer (PAL)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 112 ("Blessed Hammer")
|
|
||||||
* - Class: "pal"
|
|
||||||
* - Required Level: 18
|
|
||||||
* - Server Functions: srvstfunc=0, srvdofunc=73, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
|
||||||
* - Associated Missile / State / Summon: missile="blessedhammer", state="", summon=""
|
|
||||||
* - 1.13c Synergy Formulas: EDmgSymPerCalc="(skill('Vigor'.blvl)+skill('Blessed Aim'.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: 112,
|
|
||||||
name: "Blessed Hammer",
|
|
||||||
charClass: "pal",
|
|
||||||
srvStFunc: 0,
|
|
||||||
srvDoFunc: 73,
|
|
||||||
|
|
||||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
|
||||||
return evaluateSkillCore113c(ctx)
|
|
||||||
},
|
|
||||||
|
|
||||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
|
||||||
const outcome = executeSkillCore113c(ctx)
|
|
||||||
return {
|
|
||||||
...outcome,
|
|
||||||
notes: [
|
|
||||||
...outcome.notes,
|
|
||||||
'skill_module:skill-112-blessed-hammer',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #113: Concentration (PAL)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 113 ("Concentration")
|
|
||||||
* - Class: "pal"
|
|
||||||
* - Required Level: 18
|
|
||||||
* - Server Functions: srvstfunc=0, srvdofunc=65, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
|
||||||
* - Associated Missile / State / Summon: missile="", state="concentration", 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: 113,
|
|
||||||
name: "Concentration",
|
|
||||||
charClass: "pal",
|
|
||||||
srvStFunc: 0,
|
|
||||||
srvDoFunc: 65,
|
|
||||||
|
|
||||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
|
||||||
return evaluateSkillCore113c(ctx)
|
|
||||||
},
|
|
||||||
|
|
||||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
|
||||||
const outcome = executeSkillCore113c(ctx)
|
|
||||||
return {
|
|
||||||
...outcome,
|
|
||||||
notes: [
|
|
||||||
...outcome.notes,
|
|
||||||
'skill_module:skill-113-concentration',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #114: Holy Freeze (PAL)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 114 ("Holy Freeze")
|
|
||||||
* - Class: "pal"
|
|
||||||
* - Required Level: 18
|
|
||||||
* - Server Functions: srvstfunc=0, srvdofunc=81, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
|
||||||
* - Associated Missile / State / Summon: missile="", state="holywind", summon=""
|
|
||||||
* - 1.13c Synergy Formulas: EDmgSymPerCalc="skill('Resist Cold'.blvl)*par8+skill('Salvation'.blvl)*par7", DmgSymPerCalc="", ELenSymPerCalc=""
|
|
||||||
*/
|
|
||||||
import type {
|
|
||||||
SkillEvalContext,
|
|
||||||
SkillEvalResult,
|
|
||||||
SkillExecContext,
|
|
||||||
SkillExecOutcome,
|
|
||||||
SkillModule,
|
|
||||||
} from '../../types.ts'
|
|
||||||
import { evaluateSkillCore113c, executeSkillCore113c } from '../../registry.ts'
|
|
||||||
|
|
||||||
export const skillModule: SkillModule = {
|
|
||||||
skillId: 114,
|
|
||||||
name: "Holy Freeze",
|
|
||||||
charClass: "pal",
|
|
||||||
srvStFunc: 0,
|
|
||||||
srvDoFunc: 81,
|
|
||||||
|
|
||||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
|
||||||
return evaluateSkillCore113c(ctx)
|
|
||||||
},
|
|
||||||
|
|
||||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
|
||||||
const outcome = executeSkillCore113c(ctx)
|
|
||||||
return {
|
|
||||||
...outcome,
|
|
||||||
notes: [
|
|
||||||
...outcome.notes,
|
|
||||||
'skill_module:skill-114-holy-freeze',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #115: Vigor (PAL)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 115 ("Vigor")
|
|
||||||
* - Class: "pal"
|
|
||||||
* - Required Level: 18
|
|
||||||
* - Server Functions: srvstfunc=0, srvdofunc=65, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
|
||||||
* - Associated Missile / State / Summon: missile="", state="stamina", 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: 115,
|
|
||||||
name: "Vigor",
|
|
||||||
charClass: "pal",
|
|
||||||
srvStFunc: 0,
|
|
||||||
srvDoFunc: 65,
|
|
||||||
|
|
||||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
|
||||||
return evaluateSkillCore113c(ctx)
|
|
||||||
},
|
|
||||||
|
|
||||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
|
||||||
const outcome = executeSkillCore113c(ctx)
|
|
||||||
return {
|
|
||||||
...outcome,
|
|
||||||
notes: [
|
|
||||||
...outcome.notes,
|
|
||||||
'skill_module:skill-115-vigor',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #116: Conversion (PAL)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 116 ("Conversion")
|
|
||||||
* - Class: "pal"
|
|
||||||
* - Required Level: 24
|
|
||||||
* - Server Functions: srvstfunc=32, srvdofunc=79, 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: 116,
|
|
||||||
name: "Conversion",
|
|
||||||
charClass: "pal",
|
|
||||||
srvStFunc: 32,
|
|
||||||
srvDoFunc: 79,
|
|
||||||
|
|
||||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
|
||||||
return evaluateSkillCore113c(ctx)
|
|
||||||
},
|
|
||||||
|
|
||||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
|
||||||
const outcome = executeSkillCore113c(ctx)
|
|
||||||
return {
|
|
||||||
...outcome,
|
|
||||||
notes: [
|
|
||||||
...outcome.notes,
|
|
||||||
'skill_module:skill-116-conversion',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #117: Holy Shield (PAL)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 117 ("Holy Shield")
|
|
||||||
* - Class: "pal"
|
|
||||||
* - Required Level: 24
|
|
||||||
* - Server Functions: srvstfunc=36, srvdofunc=18, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
|
||||||
* - Associated Missile / State / Summon: missile="", state="holyshield", 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: 117,
|
|
||||||
name: "Holy Shield",
|
|
||||||
charClass: "pal",
|
|
||||||
srvStFunc: 36,
|
|
||||||
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-117-holy-shield',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #118: Holy Shock (PAL)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 118 ("Holy Shock")
|
|
||||||
* - Class: "pal"
|
|
||||||
* - Required Level: 24
|
|
||||||
* - Server Functions: srvstfunc=0, srvdofunc=66, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
|
||||||
* - Associated Missile / State / Summon: missile="", state="holyshock", summon=""
|
|
||||||
* - 1.13c Synergy Formulas: EDmgSymPerCalc="skill('Resist Lightning'.blvl)*par8+skill('Salvation'.blvl)*par7", DmgSymPerCalc="", ELenSymPerCalc=""
|
|
||||||
*/
|
|
||||||
import type {
|
|
||||||
SkillEvalContext,
|
|
||||||
SkillEvalResult,
|
|
||||||
SkillExecContext,
|
|
||||||
SkillExecOutcome,
|
|
||||||
SkillModule,
|
|
||||||
} from '../../types.ts'
|
|
||||||
import { evaluateSkillCore113c, executeSkillCore113c } from '../../registry.ts'
|
|
||||||
|
|
||||||
export const skillModule: SkillModule = {
|
|
||||||
skillId: 118,
|
|
||||||
name: "Holy Shock",
|
|
||||||
charClass: "pal",
|
|
||||||
srvStFunc: 0,
|
|
||||||
srvDoFunc: 66,
|
|
||||||
|
|
||||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
|
||||||
return evaluateSkillCore113c(ctx)
|
|
||||||
},
|
|
||||||
|
|
||||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
|
||||||
const outcome = executeSkillCore113c(ctx)
|
|
||||||
return {
|
|
||||||
...outcome,
|
|
||||||
notes: [
|
|
||||||
...outcome.notes,
|
|
||||||
'skill_module:skill-118-holy-shock',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #119: Sanctuary (PAL)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 119 ("Sanctuary")
|
|
||||||
* - Class: "pal"
|
|
||||||
* - Required Level: 24
|
|
||||||
* - Server Functions: srvstfunc=0, srvdofunc=66, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
|
||||||
* - Associated Missile / State / Summon: missile="", state="sanctuary", summon=""
|
|
||||||
* - 1.13c Synergy Formulas: EDmgSymPerCalc="skill('Cleansing'.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: 119,
|
|
||||||
name: "Sanctuary",
|
|
||||||
charClass: "pal",
|
|
||||||
srvStFunc: 0,
|
|
||||||
srvDoFunc: 66,
|
|
||||||
|
|
||||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
|
||||||
return evaluateSkillCore113c(ctx)
|
|
||||||
},
|
|
||||||
|
|
||||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
|
||||||
const outcome = executeSkillCore113c(ctx)
|
|
||||||
return {
|
|
||||||
...outcome,
|
|
||||||
notes: [
|
|
||||||
...outcome.notes,
|
|
||||||
'skill_module:skill-119-sanctuary',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #120: Meditation (PAL)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 120 ("Meditation")
|
|
||||||
* - Class: "pal"
|
|
||||||
* - Required Level: 24
|
|
||||||
* - Server Functions: srvstfunc=0, srvdofunc=65, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
|
||||||
* - Associated Missile / State / Summon: missile="", state="meditation", 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: 120,
|
|
||||||
name: "Meditation",
|
|
||||||
charClass: "pal",
|
|
||||||
srvStFunc: 0,
|
|
||||||
srvDoFunc: 65,
|
|
||||||
|
|
||||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
|
||||||
return evaluateSkillCore113c(ctx)
|
|
||||||
},
|
|
||||||
|
|
||||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
|
||||||
const outcome = executeSkillCore113c(ctx)
|
|
||||||
return {
|
|
||||||
...outcome,
|
|
||||||
notes: [
|
|
||||||
...outcome.notes,
|
|
||||||
'skill_module:skill-120-meditation',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #121: Fist of the Heavens (PAL)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 121 ("Fist of the Heavens")
|
|
||||||
* - Class: "pal"
|
|
||||||
* - Required Level: 30
|
|
||||||
* - Server Functions: srvstfunc=0, srvdofunc=80, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
|
||||||
* - Associated Missile / State / Summon: missile="fistoftheheavensdelay", state="", summon=""
|
|
||||||
* - 1.13c Synergy Formulas: EDmgSymPerCalc="skill('Holy Shock'.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: 121,
|
|
||||||
name: "Fist of the Heavens",
|
|
||||||
charClass: "pal",
|
|
||||||
srvStFunc: 0,
|
|
||||||
srvDoFunc: 80,
|
|
||||||
|
|
||||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
|
||||||
return evaluateSkillCore113c(ctx)
|
|
||||||
},
|
|
||||||
|
|
||||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
|
||||||
const outcome = executeSkillCore113c(ctx)
|
|
||||||
return {
|
|
||||||
...outcome,
|
|
||||||
notes: [
|
|
||||||
...outcome.notes,
|
|
||||||
'skill_module:skill-121-fist-of-the-heavens',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #122: Fanaticism (PAL)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 122 ("Fanaticism")
|
|
||||||
* - Class: "pal"
|
|
||||||
* - Required Level: 30
|
|
||||||
* - Server Functions: srvstfunc=0, srvdofunc=65, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
|
||||||
* - Associated Missile / State / Summon: missile="", state="fanaticism", 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: 122,
|
|
||||||
name: "Fanaticism",
|
|
||||||
charClass: "pal",
|
|
||||||
srvStFunc: 0,
|
|
||||||
srvDoFunc: 65,
|
|
||||||
|
|
||||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
|
||||||
return evaluateSkillCore113c(ctx)
|
|
||||||
},
|
|
||||||
|
|
||||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
|
||||||
const outcome = executeSkillCore113c(ctx)
|
|
||||||
return {
|
|
||||||
...outcome,
|
|
||||||
notes: [
|
|
||||||
...outcome.notes,
|
|
||||||
'skill_module:skill-122-fanaticism',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #123: Conviction (PAL)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 123 ("Conviction")
|
|
||||||
* - Class: "pal"
|
|
||||||
* - Required Level: 30
|
|
||||||
* - Server Functions: srvstfunc=0, srvdofunc=66, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
|
||||||
* - Associated Missile / State / Summon: missile="", state="conviction", 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: 123,
|
|
||||||
name: "Conviction",
|
|
||||||
charClass: "pal",
|
|
||||||
srvStFunc: 0,
|
|
||||||
srvDoFunc: 66,
|
|
||||||
|
|
||||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
|
||||||
return evaluateSkillCore113c(ctx)
|
|
||||||
},
|
|
||||||
|
|
||||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
|
||||||
const outcome = executeSkillCore113c(ctx)
|
|
||||||
return {
|
|
||||||
...outcome,
|
|
||||||
notes: [
|
|
||||||
...outcome.notes,
|
|
||||||
'skill_module:skill-123-conviction',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #124: Redemption (PAL)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 124 ("Redemption")
|
|
||||||
* - Class: "pal"
|
|
||||||
* - Required Level: 30
|
|
||||||
* - Server Functions: srvstfunc=0, srvdofunc=82, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
|
||||||
* - Associated Missile / State / Summon: missile="", state="redemption", 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: 124,
|
|
||||||
name: "Redemption",
|
|
||||||
charClass: "pal",
|
|
||||||
srvStFunc: 0,
|
|
||||||
srvDoFunc: 82,
|
|
||||||
|
|
||||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
|
||||||
return evaluateSkillCore113c(ctx)
|
|
||||||
},
|
|
||||||
|
|
||||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
|
||||||
const outcome = executeSkillCore113c(ctx)
|
|
||||||
return {
|
|
||||||
...outcome,
|
|
||||||
notes: [
|
|
||||||
...outcome.notes,
|
|
||||||
'skill_module:skill-124-redemption',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Diablo II: Lord of Destruction v1.13c — Skill #125: Salvation (PAL)
|
|
||||||
*
|
|
||||||
* Authoritative 1.13c Ground Truth (`Patch_D2.mpq` -> `data\\global\\excel\\Skills.txt`):
|
|
||||||
* - Skill ID: 125 ("Salvation")
|
|
||||||
* - Class: "pal"
|
|
||||||
* - Required Level: 30
|
|
||||||
* - Server Functions: srvstfunc=0, srvdofunc=65, srvprgfunc1=0, srvprgfunc2=0, srvprgfunc3=0
|
|
||||||
* - Associated Missile / State / Summon: missile="", state="resistall", 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: 125,
|
|
||||||
name: "Salvation",
|
|
||||||
charClass: "pal",
|
|
||||||
srvStFunc: 0,
|
|
||||||
srvDoFunc: 65,
|
|
||||||
|
|
||||||
evaluate(ctx: SkillEvalContext): SkillEvalResult {
|
|
||||||
return evaluateSkillCore113c(ctx)
|
|
||||||
},
|
|
||||||
|
|
||||||
executeDo(ctx: SkillExecContext): SkillExecOutcome {
|
|
||||||
const outcome = executeSkillCore113c(ctx)
|
|
||||||
return {
|
|
||||||
...outcome,
|
|
||||||
notes: [
|
|
||||||
...outcome.notes,
|
|
||||||
'skill_module:skill-125-salvation',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default skillModule
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #126: Bash (BAR)
|
|
||||||
* Gitea Tracking Issue: #280
|
|
||||||
*/
|
|
||||||
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/bar/skill-126-bash.ts'
|
|
||||||
|
|
||||||
describe('[Skill #126] Bash (BAR) — 1.13c Parity (Issue #280)', () => {
|
|
||||||
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(126)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(126)
|
|
||||||
expect(skillModule.name).toBe("Bash")
|
|
||||||
expect(skillModule.charClass).toBe("bar")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(126, 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(126, 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(126, 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(126)!
|
|
||||||
const synId = null
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(126, 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(126, 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: "bar",
|
|
||||||
skillId: 126,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(126)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #127: Sword Mastery (BAR)
|
|
||||||
* Gitea Tracking Issue: #281
|
|
||||||
*/
|
|
||||||
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/bar/skill-127-sword-mastery.ts'
|
|
||||||
|
|
||||||
describe('[Skill #127] Sword Mastery (BAR) — 1.13c Parity (Issue #281)', () => {
|
|
||||||
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(127)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(127)
|
|
||||||
expect(skillModule.name).toBe("Sword Mastery")
|
|
||||||
expect(skillModule.charClass).toBe("bar")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(127, 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(127, 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(127, 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(180)
|
|
||||||
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(127)!
|
|
||||||
const synId = null
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(127, 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(127, 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: "bar",
|
|
||||||
skillId: 127,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(127)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #128: Axe Mastery (BAR)
|
|
||||||
* Gitea Tracking Issue: #282
|
|
||||||
*/
|
|
||||||
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/bar/skill-128-axe-mastery.ts'
|
|
||||||
|
|
||||||
describe('[Skill #128] Axe Mastery (BAR) — 1.13c Parity (Issue #282)', () => {
|
|
||||||
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(128)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(128)
|
|
||||||
expect(skillModule.name).toBe("Axe Mastery")
|
|
||||||
expect(skillModule.charClass).toBe("bar")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(128, 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(128, 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(128, 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(180)
|
|
||||||
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(128)!
|
|
||||||
const synId = null
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(128, 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(128, 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: "bar",
|
|
||||||
skillId: 128,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(128)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #129: Mace Mastery (BAR)
|
|
||||||
* Gitea Tracking Issue: #283
|
|
||||||
*/
|
|
||||||
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/bar/skill-129-mace-mastery.ts'
|
|
||||||
|
|
||||||
describe('[Skill #129] Mace Mastery (BAR) — 1.13c Parity (Issue #283)', () => {
|
|
||||||
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(129)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(129)
|
|
||||||
expect(skillModule.name).toBe("Mace Mastery")
|
|
||||||
expect(skillModule.charClass).toBe("bar")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(129, 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(129, 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(129, 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(180)
|
|
||||||
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(129)!
|
|
||||||
const synId = null
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(129, 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(129, 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: "bar",
|
|
||||||
skillId: 129,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(129)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #130: Howl (BAR)
|
|
||||||
* Gitea Tracking Issue: #284
|
|
||||||
*/
|
|
||||||
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/bar/skill-130-howl.ts'
|
|
||||||
|
|
||||||
describe('[Skill #130] Howl (BAR) — 1.13c Parity (Issue #284)', () => {
|
|
||||||
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(130)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(130)
|
|
||||||
expect(skillModule.name).toBe("Howl")
|
|
||||||
expect(skillModule.charClass).toBe("bar")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(130, 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(130, 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(130, 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(21)
|
|
||||||
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(130)!
|
|
||||||
const synId = null
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(130, 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(130, 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: "bar",
|
|
||||||
skillId: 130,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(130)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #131: Find Potion (BAR)
|
|
||||||
* Gitea Tracking Issue: #285
|
|
||||||
*/
|
|
||||||
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/bar/skill-131-find-potion.ts'
|
|
||||||
|
|
||||||
describe('[Skill #131] Find Potion (BAR) — 1.13c Parity (Issue #285)', () => {
|
|
||||||
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(131)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(131)
|
|
||||||
expect(skillModule.name).toBe("Find Potion")
|
|
||||||
expect(skillModule.charClass).toBe("bar")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(131, 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(131, 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(131, 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(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(131)!
|
|
||||||
const synId = null
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(131, 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(131, 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: "bar",
|
|
||||||
skillId: 131,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(131)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #132: Leap (BAR)
|
|
||||||
* Gitea Tracking Issue: #286
|
|
||||||
*/
|
|
||||||
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/bar/skill-132-leap.ts'
|
|
||||||
|
|
||||||
describe('[Skill #132] Leap (BAR) — 1.13c Parity (Issue #286)', () => {
|
|
||||||
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(132)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(132)
|
|
||||||
expect(skillModule.name).toBe("Leap")
|
|
||||||
expect(skillModule.charClass).toBe("bar")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(132, 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(132, 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(132, 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(26)
|
|
||||||
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(132)!
|
|
||||||
const synId = null
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(132, 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(132, 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: "bar",
|
|
||||||
skillId: 132,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(132)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #133: Double Swing (BAR)
|
|
||||||
* Gitea Tracking Issue: #287
|
|
||||||
*/
|
|
||||||
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/bar/skill-133-double-swing.ts'
|
|
||||||
|
|
||||||
describe('[Skill #133] Double Swing (BAR) — 1.13c Parity (Issue #287)', () => {
|
|
||||||
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(133)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(133)
|
|
||||||
expect(skillModule.name).toBe("Double Swing")
|
|
||||||
expect(skillModule.charClass).toBe("bar")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(133, 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(133, 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(133, 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(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(133)!
|
|
||||||
const synId = null
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(133, 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(133, 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: "bar",
|
|
||||||
skillId: 133,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(133)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #134: Pole Arm Mastery (BAR)
|
|
||||||
* Gitea Tracking Issue: #288
|
|
||||||
*/
|
|
||||||
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/bar/skill-134-pole-arm-mastery.ts'
|
|
||||||
|
|
||||||
describe('[Skill #134] Pole Arm Mastery (BAR) — 1.13c Parity (Issue #288)', () => {
|
|
||||||
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(134)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(134)
|
|
||||||
expect(skillModule.name).toBe("Pole Arm Mastery")
|
|
||||||
expect(skillModule.charClass).toBe("bar")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(134, 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(134, 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(134, 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(182)
|
|
||||||
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(134)!
|
|
||||||
const synId = null
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(134, 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(134, 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: "bar",
|
|
||||||
skillId: 134,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(134)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #110: Resist Lightning (PAL)
|
|
||||||
* Gitea Tracking Issue: #264
|
|
||||||
*/
|
|
||||||
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/pal/skill-110-resist-lightning.ts'
|
|
||||||
|
|
||||||
describe('[Skill #110] Resist Lightning (PAL) — 1.13c Parity (Issue #264)', () => {
|
|
||||||
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(110)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(110)
|
|
||||||
expect(skillModule.name).toBe("Resist Lightning")
|
|
||||||
expect(skillModule.charClass).toBe("pal")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(110, 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(110, 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(110, 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(54)
|
|
||||||
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(110)!
|
|
||||||
const synId = null
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(110, 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(110, 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: "pal",
|
|
||||||
skillId: 110,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(110)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #111: Vengeance (PAL)
|
|
||||||
* Gitea Tracking Issue: #265
|
|
||||||
*/
|
|
||||||
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/pal/skill-111-vengeance.ts'
|
|
||||||
|
|
||||||
describe('[Skill #111] Vengeance (PAL) — 1.13c Parity (Issue #265)', () => {
|
|
||||||
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(111)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(111)
|
|
||||||
expect(skillModule.name).toBe("Vengeance")
|
|
||||||
expect(skillModule.charClass).toBe("pal")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(111, 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(111, 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(0)
|
|
||||||
expect(r10.maxPhysDmg).toBe(0)
|
|
||||||
expect(r10.minElemDmg256).toBe(0)
|
|
||||||
expect(r10.maxElemDmg256).toBe(0)
|
|
||||||
|
|
||||||
const stats20 = new UnitStatList()
|
|
||||||
stats20.setBaseSkillLevel(111, 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(0)
|
|
||||||
expect(r20.maxPhysDmg).toBe(0)
|
|
||||||
expect(r20.minElemDmg256).toBe(0)
|
|
||||||
expect(r20.maxElemDmg256).toBe(0)
|
|
||||||
expect(r20.durationFrames).toBe(315)
|
|
||||||
expect(r20.radiusSubtiles).toBe(184)
|
|
||||||
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(111)!
|
|
||||||
const synId = null
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(111, 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(111, 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: "pal",
|
|
||||||
skillId: 111,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(111)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #112: Blessed Hammer (PAL)
|
|
||||||
* Gitea Tracking Issue: #266
|
|
||||||
*/
|
|
||||||
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/pal/skill-112-blessed-hammer.ts'
|
|
||||||
|
|
||||||
describe('[Skill #112] Blessed Hammer (PAL) — 1.13c Parity (Issue #266)', () => {
|
|
||||||
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(112)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(112)
|
|
||||||
expect(skillModule.name).toBe("Blessed Hammer")
|
|
||||||
expect(skillModule.charClass).toBe("pal")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(112, 1)
|
|
||||||
const r1 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 1, blvl: 1, statList: stats1 })
|
|
||||||
expect(r1.manaCost).toBe(5)
|
|
||||||
expect(r1.manaCost256).toBe(1280)
|
|
||||||
expect(r1.minPhysDmg).toBe(0)
|
|
||||||
expect(r1.maxPhysDmg).toBe(0)
|
|
||||||
expect(r1.minElemDmg256).toBe(3072)
|
|
||||||
expect(r1.maxElemDmg256).toBe(4096)
|
|
||||||
|
|
||||||
const stats10 = new UnitStatList()
|
|
||||||
stats10.setBaseSkillLevel(112, 10)
|
|
||||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
|
||||||
expect(r10.manaCost).toBe(7)
|
|
||||||
expect(r10.manaCost256).toBe(1856)
|
|
||||||
expect(r10.minPhysDmg).toBe(0)
|
|
||||||
expect(r10.maxPhysDmg).toBe(0)
|
|
||||||
expect(r10.minElemDmg256).toBe(22528)
|
|
||||||
expect(r10.maxElemDmg256).toBe(23552)
|
|
||||||
|
|
||||||
const stats20 = new UnitStatList()
|
|
||||||
stats20.setBaseSkillLevel(112, 20)
|
|
||||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
|
||||||
expect(r20.manaCost).toBe(9)
|
|
||||||
expect(r20.manaCost256).toBe(2496)
|
|
||||||
expect(r20.minPhysDmg).toBe(0)
|
|
||||||
expect(r20.maxPhysDmg).toBe(0)
|
|
||||||
expect(r20.minElemDmg256).toBe(50176)
|
|
||||||
expect(r20.maxElemDmg256).toBe(51200)
|
|
||||||
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(112)!
|
|
||||||
const synId = 115
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(112, 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(112, 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: "pal",
|
|
||||||
skillId: 112,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(112)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #113: Concentration (PAL)
|
|
||||||
* Gitea Tracking Issue: #267
|
|
||||||
*/
|
|
||||||
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/pal/skill-113-concentration.ts'
|
|
||||||
|
|
||||||
describe('[Skill #113] Concentration (PAL) — 1.13c Parity (Issue #267)', () => {
|
|
||||||
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(113)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(113)
|
|
||||||
expect(skillModule.name).toBe("Concentration")
|
|
||||||
expect(skillModule.charClass).toBe("pal")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(113, 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(113, 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(113, 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(54)
|
|
||||||
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(113)!
|
|
||||||
const synId = null
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(113, 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(113, 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: "pal",
|
|
||||||
skillId: 113,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(113)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #114: Holy Freeze (PAL)
|
|
||||||
* Gitea Tracking Issue: #268
|
|
||||||
*/
|
|
||||||
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/pal/skill-114-holy-freeze.ts'
|
|
||||||
|
|
||||||
describe('[Skill #114] Holy Freeze (PAL) — 1.13c Parity (Issue #268)', () => {
|
|
||||||
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(114)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(114)
|
|
||||||
expect(skillModule.name).toBe("Holy Freeze")
|
|
||||||
expect(skillModule.charClass).toBe("pal")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(114, 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(512)
|
|
||||||
expect(r1.maxElemDmg256).toBe(768)
|
|
||||||
|
|
||||||
const stats10 = new UnitStatList()
|
|
||||||
stats10.setBaseSkillLevel(114, 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(3328)
|
|
||||||
expect(r10.maxElemDmg256).toBe(3584)
|
|
||||||
|
|
||||||
const stats20 = new UnitStatList()
|
|
||||||
stats20.setBaseSkillLevel(114, 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(9472)
|
|
||||||
expect(r20.maxElemDmg256).toBe(9728)
|
|
||||||
expect(r20.durationFrames).toBe(0)
|
|
||||||
expect(r20.radiusSubtiles).toBe(25)
|
|
||||||
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(114)!
|
|
||||||
const synId = 105
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(114, 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(300)
|
|
||||||
|
|
||||||
// +20 allskills and +33 Marrowwalk charges without hard points must yield 0 synergy
|
|
||||||
const statsSoftOnly = new UnitStatList()
|
|
||||||
statsSoftOnly.setBaseSkillLevel(114, 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: "pal",
|
|
||||||
skillId: 114,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(114)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #115: Vigor (PAL)
|
|
||||||
* Gitea Tracking Issue: #269
|
|
||||||
*/
|
|
||||||
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/pal/skill-115-vigor.ts'
|
|
||||||
|
|
||||||
describe('[Skill #115] Vigor (PAL) — 1.13c Parity (Issue #269)', () => {
|
|
||||||
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(115)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(115)
|
|
||||||
expect(skillModule.name).toBe("Vigor")
|
|
||||||
expect(skillModule.charClass).toBe("pal")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(115, 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(115, 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(115, 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(73)
|
|
||||||
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(115)!
|
|
||||||
const synId = null
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(115, 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(115, 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: "pal",
|
|
||||||
skillId: 115,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(115)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #116: Conversion (PAL)
|
|
||||||
* Gitea Tracking Issue: #270
|
|
||||||
*/
|
|
||||||
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/pal/skill-116-conversion.ts'
|
|
||||||
|
|
||||||
describe('[Skill #116] Conversion (PAL) — 1.13c Parity (Issue #270)', () => {
|
|
||||||
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(116)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(116)
|
|
||||||
expect(skillModule.name).toBe("Conversion")
|
|
||||||
expect(skillModule.charClass).toBe("pal")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(116, 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(116, 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(116, 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(400)
|
|
||||||
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(116)!
|
|
||||||
const synId = null
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(116, 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(116, 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: "pal",
|
|
||||||
skillId: 116,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(116)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #117: Holy Shield (PAL)
|
|
||||||
* Gitea Tracking Issue: #271
|
|
||||||
*/
|
|
||||||
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/pal/skill-117-holy-shield.ts'
|
|
||||||
|
|
||||||
describe('[Skill #117] Holy Shield (PAL) — 1.13c Parity (Issue #271)', () => {
|
|
||||||
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(117)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(117)
|
|
||||||
expect(skillModule.name).toBe("Holy Shield")
|
|
||||||
expect(skillModule.charClass).toBe("pal")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(117, 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(3)
|
|
||||||
expect(r1.maxPhysDmg).toBe(6)
|
|
||||||
expect(r1.minElemDmg256).toBe(0)
|
|
||||||
expect(r1.maxElemDmg256).toBe(0)
|
|
||||||
|
|
||||||
const stats10 = new UnitStatList()
|
|
||||||
stats10.setBaseSkillLevel(117, 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(23)
|
|
||||||
expect(r10.maxPhysDmg).toBe(26)
|
|
||||||
expect(r10.minElemDmg256).toBe(0)
|
|
||||||
expect(r10.maxElemDmg256).toBe(0)
|
|
||||||
|
|
||||||
const stats20 = new UnitStatList()
|
|
||||||
stats20.setBaseSkillLevel(117, 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(57)
|
|
||||||
expect(r20.maxPhysDmg).toBe(60)
|
|
||||||
expect(r20.minElemDmg256).toBe(0)
|
|
||||||
expect(r20.maxElemDmg256).toBe(0)
|
|
||||||
expect(r20.durationFrames).toBe(12625)
|
|
||||||
expect(r20.radiusSubtiles).toBe(12625)
|
|
||||||
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(117)!
|
|
||||||
const synId = null
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(117, 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(117, 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: "pal",
|
|
||||||
skillId: 117,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(117)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #118: Holy Shock (PAL)
|
|
||||||
* Gitea Tracking Issue: #272
|
|
||||||
*/
|
|
||||||
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/pal/skill-118-holy-shock.ts'
|
|
||||||
|
|
||||||
describe('[Skill #118] Holy Shock (PAL) — 1.13c Parity (Issue #272)', () => {
|
|
||||||
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(118)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(118)
|
|
||||||
expect(skillModule.name).toBe("Holy Shock")
|
|
||||||
expect(skillModule.charClass).toBe("pal")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(118, 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(256)
|
|
||||||
expect(r1.maxElemDmg256).toBe(2560)
|
|
||||||
|
|
||||||
const stats10 = new UnitStatList()
|
|
||||||
stats10.setBaseSkillLevel(118, 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(256)
|
|
||||||
expect(r10.maxElemDmg256).toBe(17408)
|
|
||||||
|
|
||||||
const stats20 = new UnitStatList()
|
|
||||||
stats20.setBaseSkillLevel(118, 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(256)
|
|
||||||
expect(r20.maxElemDmg256).toBe(39936)
|
|
||||||
expect(r20.durationFrames).toBe(0)
|
|
||||||
expect(r20.radiusSubtiles).toBe(25)
|
|
||||||
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(118)!
|
|
||||||
const synId = 110
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(118, 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(118, 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: "pal",
|
|
||||||
skillId: 118,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(118)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #119: Sanctuary (PAL)
|
|
||||||
* Gitea Tracking Issue: #273
|
|
||||||
*/
|
|
||||||
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/pal/skill-119-sanctuary.ts'
|
|
||||||
|
|
||||||
describe('[Skill #119] Sanctuary (PAL) — 1.13c Parity (Issue #273)', () => {
|
|
||||||
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(119)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(119)
|
|
||||||
expect(skillModule.name).toBe("Sanctuary")
|
|
||||||
expect(skillModule.charClass).toBe("pal")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(119, 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(2048)
|
|
||||||
expect(r1.maxElemDmg256).toBe(4096)
|
|
||||||
|
|
||||||
const stats10 = new UnitStatList()
|
|
||||||
stats10.setBaseSkillLevel(119, 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(11264)
|
|
||||||
expect(r10.maxElemDmg256).toBe(13824)
|
|
||||||
|
|
||||||
const stats20 = new UnitStatList()
|
|
||||||
stats20.setBaseSkillLevel(119, 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(22528)
|
|
||||||
expect(r20.maxElemDmg256).toBe(27648)
|
|
||||||
expect(r20.durationFrames).toBe(0)
|
|
||||||
expect(r20.radiusSubtiles).toBe(24)
|
|
||||||
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(119)!
|
|
||||||
const synId = 109
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(119, 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(140)
|
|
||||||
|
|
||||||
// +20 allskills and +33 Marrowwalk charges without hard points must yield 0 synergy
|
|
||||||
const statsSoftOnly = new UnitStatList()
|
|
||||||
statsSoftOnly.setBaseSkillLevel(119, 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: "pal",
|
|
||||||
skillId: 119,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(119)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #120: Meditation (PAL)
|
|
||||||
* Gitea Tracking Issue: #274
|
|
||||||
*/
|
|
||||||
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/pal/skill-120-meditation.ts'
|
|
||||||
|
|
||||||
describe('[Skill #120] Meditation (PAL) — 1.13c Parity (Issue #274)', () => {
|
|
||||||
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(120)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(120)
|
|
||||||
expect(skillModule.name).toBe("Meditation")
|
|
||||||
expect(skillModule.charClass).toBe("pal")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(120, 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(120, 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(120, 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(54)
|
|
||||||
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(120)!
|
|
||||||
const synId = null
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(120, 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(120, 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: "pal",
|
|
||||||
skillId: 120,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(120)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #121: Fist of the Heavens (PAL)
|
|
||||||
* Gitea Tracking Issue: #275
|
|
||||||
*/
|
|
||||||
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/pal/skill-121-fist-of-the-heavens.ts'
|
|
||||||
|
|
||||||
describe('[Skill #121] Fist of the Heavens (PAL) — 1.13c Parity (Issue #275)', () => {
|
|
||||||
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(121)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(121)
|
|
||||||
expect(skillModule.name).toBe("Fist of the Heavens")
|
|
||||||
expect(skillModule.charClass).toBe("pal")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(121, 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(38400)
|
|
||||||
expect(r1.maxElemDmg256).toBe(51200)
|
|
||||||
|
|
||||||
const stats10 = new UnitStatList()
|
|
||||||
stats10.setBaseSkillLevel(121, 10)
|
|
||||||
const r10 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 10, blvl: 10, statList: stats10 })
|
|
||||||
expect(r10.manaCost).toBe(25)
|
|
||||||
expect(r10.manaCost256).toBe(6400)
|
|
||||||
expect(r10.minPhysDmg).toBe(0)
|
|
||||||
expect(r10.maxPhysDmg).toBe(0)
|
|
||||||
expect(r10.minElemDmg256).toBe(80640)
|
|
||||||
expect(r10.maxElemDmg256).toBe(93440)
|
|
||||||
|
|
||||||
const stats20 = new UnitStatList()
|
|
||||||
stats20.setBaseSkillLevel(121, 20)
|
|
||||||
const r20 = skillModule.evaluate!({ registry, skill: skillRec, slvl: 20, blvl: 20, statList: stats20 })
|
|
||||||
expect(r20.manaCost).toBe(25)
|
|
||||||
expect(r20.manaCost256).toBe(6400)
|
|
||||||
expect(r20.minPhysDmg).toBe(0)
|
|
||||||
expect(r20.maxPhysDmg).toBe(0)
|
|
||||||
expect(r20.minElemDmg256).toBe(172800)
|
|
||||||
expect(r20.maxElemDmg256).toBe(185600)
|
|
||||||
expect(r20.durationFrames).toBe(0)
|
|
||||||
expect(r20.radiusSubtiles).toBe(20)
|
|
||||||
expect(r20.petMax).toBe(0)
|
|
||||||
expect(r20.cooldownFrames).toBe(25)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('enforces 1.13c blvl synergy rule (hard points boost synergy; +skills and item charges do NOT)', async () => {
|
|
||||||
const registry = await getSharedDataRegistry()
|
|
||||||
const skillRec = registry.getSkillById(121)!
|
|
||||||
const synId = 118
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(121, 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(140)
|
|
||||||
|
|
||||||
// +20 allskills and +33 Marrowwalk charges without hard points must yield 0 synergy
|
|
||||||
const statsSoftOnly = new UnitStatList()
|
|
||||||
statsSoftOnly.setBaseSkillLevel(121, 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: "pal",
|
|
||||||
skillId: 121,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(121)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #122: Fanaticism (PAL)
|
|
||||||
* Gitea Tracking Issue: #276
|
|
||||||
*/
|
|
||||||
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/pal/skill-122-fanaticism.ts'
|
|
||||||
|
|
||||||
describe('[Skill #122] Fanaticism (PAL) — 1.13c Parity (Issue #276)', () => {
|
|
||||||
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(122)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(122)
|
|
||||||
expect(skillModule.name).toBe("Fanaticism")
|
|
||||||
expect(skillModule.charClass).toBe("pal")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(122, 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(122, 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(122, 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(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(122)!
|
|
||||||
const synId = null
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(122, 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(122, 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: "pal",
|
|
||||||
skillId: 122,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(122)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #123: Conviction (PAL)
|
|
||||||
* Gitea Tracking Issue: #277
|
|
||||||
*/
|
|
||||||
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/pal/skill-123-conviction.ts'
|
|
||||||
|
|
||||||
describe('[Skill #123] Conviction (PAL) — 1.13c Parity (Issue #277)', () => {
|
|
||||||
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(123)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(123)
|
|
||||||
expect(skillModule.name).toBe("Conviction")
|
|
||||||
expect(skillModule.charClass).toBe("pal")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(123, 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(123, 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(123, 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(20)
|
|
||||||
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(123)!
|
|
||||||
const synId = null
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(123, 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(123, 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: "pal",
|
|
||||||
skillId: 123,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(123)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #124: Redemption (PAL)
|
|
||||||
* Gitea Tracking Issue: #278
|
|
||||||
*/
|
|
||||||
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/pal/skill-124-redemption.ts'
|
|
||||||
|
|
||||||
describe('[Skill #124] Redemption (PAL) — 1.13c Parity (Issue #278)', () => {
|
|
||||||
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(124)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(124)
|
|
||||||
expect(skillModule.name).toBe("Redemption")
|
|
||||||
expect(skillModule.charClass).toBe("pal")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(124, 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(124, 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(124, 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(16)
|
|
||||||
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(124)!
|
|
||||||
const synId = null
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(124, 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(124, 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: "pal",
|
|
||||||
skillId: 124,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(124)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/**
|
|
||||||
* 1.13c Numerical & Runtime Verification Suite — Skill #125: Salvation (PAL)
|
|
||||||
* Gitea Tracking Issue: #279
|
|
||||||
*/
|
|
||||||
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/pal/skill-125-salvation.ts'
|
|
||||||
|
|
||||||
describe('[Skill #125] Salvation (PAL) — 1.13c Parity (Issue #279)', () => {
|
|
||||||
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(125)!
|
|
||||||
expect(skillRec).toBeDefined()
|
|
||||||
expect(skillModule.skillId).toBe(125)
|
|
||||||
expect(skillModule.name).toBe("Salvation")
|
|
||||||
expect(skillModule.charClass).toBe("pal")
|
|
||||||
|
|
||||||
const stats1 = new UnitStatList()
|
|
||||||
stats1.setBaseSkillLevel(125, 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(125, 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(125, 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(54)
|
|
||||||
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(125)!
|
|
||||||
const synId = null
|
|
||||||
|
|
||||||
const statsBase = new UnitStatList()
|
|
||||||
statsBase.setBaseSkillLevel(125, 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(125, 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: "pal",
|
|
||||||
skillId: 125,
|
|
||||||
slvl: 20,
|
|
||||||
})
|
|
||||||
const outcome = arena.triggerCast()
|
|
||||||
arena.stepTicks(15)
|
|
||||||
const dbg = arena.getDebugState()
|
|
||||||
|
|
||||||
expect(dbg.ready).toBe(true)
|
|
||||||
expect(dbg.skillId).toBe(125)
|
|
||||||
expect(dbg.castCount).toBeGreaterThanOrEqual(1)
|
|
||||||
expect(dbg.actionFrameTriggered).toBe(true)
|
|
||||||
expect(outcome?.executed).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
Loading…
Reference in New Issue