@vibemancer/core 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -28
- package/dist/{chunk-L7Z7OFXD.js → chunk-7VDJHO22.js} +3 -3
- package/dist/chunk-7VDJHO22.js.map +1 -0
- package/dist/index-browser.d.ts +1 -1
- package/dist/index-browser.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +79 -78
- package/src/bots/berserker/01_Stormchaser.ts +457 -457
- package/src/bots/berserker/02_Stormcaller.ts +417 -417
- package/src/bots/berserker/03_Stormforger.ts +481 -481
- package/src/bots/caster/01_Flamecaller.ts +286 -286
- package/src/bots/caster/02_Pyromancer.ts +350 -350
- package/src/bots/caster/03_Infernalist.ts +492 -492
- package/src/bots/defensive/01_Turtle.ts +151 -151
- package/src/bots/defensive/02_Sentinel.ts +134 -134
- package/src/bots/defensive/03_Golem.ts +357 -357
- package/src/bots/duelist/01_Battlemage.ts +433 -433
- package/src/bots/duelist/02_Warmage.ts +438 -438
- package/src/bots/duelist/03_Archmage.ts +588 -588
- package/src/bots/homing/01_Bonemancer.ts +67 -67
- package/src/bots/homing/02_Lich.ts +356 -356
- package/src/bots/homing/03_Archlich.ts +220 -220
- package/src/bots/kiter/01_Spellspinner.ts +398 -398
- package/src/bots/kiter/02_Spellweaver.ts +378 -378
- package/src/bots/kiter/03_Spellbinder.ts +448 -448
- package/src/bots/melee/01_Shadowblade.ts +270 -270
- package/src/bots/melee/02_Nightblade.ts +437 -437
- package/src/bots/melee/03_Voidblade.ts +582 -582
- package/src/bots/sniper/01_Spellshot.ts +385 -385
- package/src/bots/sniper/02_Spelltracer.ts +441 -441
- package/src/bots/sniper/03_Spellseeker.ts +546 -546
- package/src/bots/standalone/Critter.ts +89 -89
- package/src/bots/standalone/Doombringer.ts +91 -91
- package/src/bots/standalone/Hogger.ts +228 -228
- package/src/bots/standalone/Rookie.ts +50 -50
- package/src/bots/standalone/TargetDummy.ts +21 -21
- package/src/bots/test/cheater.ts +405 -405
- package/src/bots/test/crasher.ts +81 -81
- package/src/engine/hooks-runtime.ts +394 -394
- package/src/engine/manual-match.ts +289 -289
- package/src/engine/missile-templates.ts +155 -155
- package/src/engine/physics.ts +143 -143
- package/src/engine/simulation.ts +828 -828
- package/src/engine/spells.ts +128 -128
- package/src/engine-version.ts +1 -1
- package/src/index.ts +23 -23
- package/src/rules.ts +254 -254
- package/src/types.ts +193 -193
- package/src/utils/index.ts +6 -6
- package/dist/chunk-L7Z7OFXD.js.map +0 -1
package/src/engine/spells.ts
CHANGED
|
@@ -1,128 +1,128 @@
|
|
|
1
|
-
import {WizardState, MissileConfig, ProjectileState} from '../types.js';
|
|
2
|
-
import {
|
|
3
|
-
SHIELD_MAX_BLOCK,
|
|
4
|
-
SHIELD_DECAY_PER_SECOND,
|
|
5
|
-
SHIELD_MIN_BLOCK,
|
|
6
|
-
TICKS_PER_SECOND,
|
|
7
|
-
GCD_DURATION,
|
|
8
|
-
SHIELD_CAST_TIME,
|
|
9
|
-
BLINK_CAST_TIME,
|
|
10
|
-
calculateMissileCastTime,
|
|
11
|
-
calculateWarmupMultiplier,
|
|
12
|
-
} from '../rules.js';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Start casting a spell.
|
|
16
|
-
* For missiles, applies warmup system (bonus for similar, penalty for switching).
|
|
17
|
-
*/
|
|
18
|
-
export function startCast(wizard: WizardState, spell: 'missile' | 'shield' | 'blink', config?: MissileConfig): void
|
|
19
|
-
{
|
|
20
|
-
wizard.state = 'casting';
|
|
21
|
-
wizard.castingSpell = spell;
|
|
22
|
-
wizard.castProgress = 0;
|
|
23
|
-
|
|
24
|
-
if (spell === 'missile' && config)
|
|
25
|
-
{
|
|
26
|
-
// calculateMissileCastTime includes warmup when lastMissileConfig is passed
|
|
27
|
-
const castTimeSec = calculateMissileCastTime(config, wizard.lastMissileConfig);
|
|
28
|
-
wizard.castDuration = Math.max(1, Math.round(castTimeSec * TICKS_PER_SECOND));
|
|
29
|
-
// Store warmup multiplier for visualization
|
|
30
|
-
wizard.warmupMultiplier = calculateWarmupMultiplier(wizard.lastMissileConfig, config);
|
|
31
|
-
}
|
|
32
|
-
else if (spell === 'shield')
|
|
33
|
-
{
|
|
34
|
-
wizard.castDuration = SHIELD_CAST_TIME;
|
|
35
|
-
}
|
|
36
|
-
else if (spell === 'blink')
|
|
37
|
-
{
|
|
38
|
-
wizard.castDuration = BLINK_CAST_TIME;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Cancel the current cast.
|
|
44
|
-
*/
|
|
45
|
-
export function cancelCast(wizard: WizardState): void
|
|
46
|
-
{
|
|
47
|
-
wizard.state = 'idle';
|
|
48
|
-
delete wizard.castingSpell;
|
|
49
|
-
delete wizard.castProgress;
|
|
50
|
-
delete wizard.castDuration;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Complete the current cast and trigger the spell effect.
|
|
55
|
-
*/
|
|
56
|
-
export function completeCast(wizard: WizardState): void
|
|
57
|
-
{
|
|
58
|
-
const spell = wizard.castingSpell;
|
|
59
|
-
|
|
60
|
-
if (spell === 'shield')
|
|
61
|
-
{
|
|
62
|
-
wizard.state = 'channeling';
|
|
63
|
-
wizard.channelingSpell = 'shield';
|
|
64
|
-
wizard.channelDuration = 0;
|
|
65
|
-
}
|
|
66
|
-
else if (spell === 'missile')
|
|
67
|
-
{
|
|
68
|
-
wizard.state = 'gcd_locked';
|
|
69
|
-
wizard.gcdRemaining = GCD_DURATION;
|
|
70
|
-
}
|
|
71
|
-
else
|
|
72
|
-
{
|
|
73
|
-
// Blink: no GCD — can act immediately after teleporting
|
|
74
|
-
wizard.state = 'idle';
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
delete wizard.castingSpell;
|
|
78
|
-
delete wizard.castProgress;
|
|
79
|
-
delete wizard.castDuration;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Update the shield channel state.
|
|
84
|
-
*/
|
|
85
|
-
export function updateShield(wizard: WizardState, deltaTicks: number): void
|
|
86
|
-
{
|
|
87
|
-
if (wizard.state === 'channeling' && wizard.channelingSpell === 'shield')
|
|
88
|
-
{
|
|
89
|
-
wizard.channelDuration = (wizard.channelDuration ?? 0) + deltaTicks;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Calculate the current block percentage of a shield based on channel duration.
|
|
95
|
-
*/
|
|
96
|
-
export function calculateShieldBlock(channelDurationTicks: number): number
|
|
97
|
-
{
|
|
98
|
-
const channelSeconds = channelDurationTicks / TICKS_PER_SECOND;
|
|
99
|
-
const decay = channelSeconds * SHIELD_DECAY_PER_SECOND;
|
|
100
|
-
return Math.max(SHIELD_MIN_BLOCK, SHIELD_MAX_BLOCK - decay);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Apply damage to a wizard, considering shield mitigation.
|
|
105
|
-
*
|
|
106
|
-
* Shield blocks a percentage of damage based on channel duration:
|
|
107
|
-
* - Fresh shield (0s): 90% block → 10% damage through
|
|
108
|
-
* - Decayed shield: block % decreases over time (20%/sec)
|
|
109
|
-
* - Minimum: 30% block → 70% damage through
|
|
110
|
-
*
|
|
111
|
-
* (Design doc lines 196-212)
|
|
112
|
-
*/
|
|
113
|
-
export function applyDamage(wizard: WizardState, damage: number, _projectile?: ProjectileState): number
|
|
114
|
-
{
|
|
115
|
-
if (wizard.invincible) return 0;
|
|
116
|
-
|
|
117
|
-
let finalDamage = damage;
|
|
118
|
-
|
|
119
|
-
if (wizard.state === 'channeling' && wizard.channelingSpell === 'shield')
|
|
120
|
-
{
|
|
121
|
-
const blockPercent = calculateShieldBlock(wizard.channelDuration ?? 0);
|
|
122
|
-
// Simple block: damage through = damage * (1 - blockPercent)
|
|
123
|
-
finalDamage = damage * (1 - blockPercent);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
wizard.health = Math.max(0, wizard.health - finalDamage);
|
|
127
|
-
return finalDamage;
|
|
128
|
-
}
|
|
1
|
+
import {WizardState, MissileConfig, ProjectileState} from '../types.js';
|
|
2
|
+
import {
|
|
3
|
+
SHIELD_MAX_BLOCK,
|
|
4
|
+
SHIELD_DECAY_PER_SECOND,
|
|
5
|
+
SHIELD_MIN_BLOCK,
|
|
6
|
+
TICKS_PER_SECOND,
|
|
7
|
+
GCD_DURATION,
|
|
8
|
+
SHIELD_CAST_TIME,
|
|
9
|
+
BLINK_CAST_TIME,
|
|
10
|
+
calculateMissileCastTime,
|
|
11
|
+
calculateWarmupMultiplier,
|
|
12
|
+
} from '../rules.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Start casting a spell.
|
|
16
|
+
* For missiles, applies warmup system (bonus for similar, penalty for switching).
|
|
17
|
+
*/
|
|
18
|
+
export function startCast(wizard: WizardState, spell: 'missile' | 'shield' | 'blink', config?: MissileConfig): void
|
|
19
|
+
{
|
|
20
|
+
wizard.state = 'casting';
|
|
21
|
+
wizard.castingSpell = spell;
|
|
22
|
+
wizard.castProgress = 0;
|
|
23
|
+
|
|
24
|
+
if (spell === 'missile' && config)
|
|
25
|
+
{
|
|
26
|
+
// calculateMissileCastTime includes warmup when lastMissileConfig is passed
|
|
27
|
+
const castTimeSec = calculateMissileCastTime(config, wizard.lastMissileConfig);
|
|
28
|
+
wizard.castDuration = Math.max(1, Math.round(castTimeSec * TICKS_PER_SECOND));
|
|
29
|
+
// Store warmup multiplier for visualization
|
|
30
|
+
wizard.warmupMultiplier = calculateWarmupMultiplier(wizard.lastMissileConfig, config);
|
|
31
|
+
}
|
|
32
|
+
else if (spell === 'shield')
|
|
33
|
+
{
|
|
34
|
+
wizard.castDuration = SHIELD_CAST_TIME;
|
|
35
|
+
}
|
|
36
|
+
else if (spell === 'blink')
|
|
37
|
+
{
|
|
38
|
+
wizard.castDuration = BLINK_CAST_TIME;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Cancel the current cast.
|
|
44
|
+
*/
|
|
45
|
+
export function cancelCast(wizard: WizardState): void
|
|
46
|
+
{
|
|
47
|
+
wizard.state = 'idle';
|
|
48
|
+
delete wizard.castingSpell;
|
|
49
|
+
delete wizard.castProgress;
|
|
50
|
+
delete wizard.castDuration;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Complete the current cast and trigger the spell effect.
|
|
55
|
+
*/
|
|
56
|
+
export function completeCast(wizard: WizardState): void
|
|
57
|
+
{
|
|
58
|
+
const spell = wizard.castingSpell;
|
|
59
|
+
|
|
60
|
+
if (spell === 'shield')
|
|
61
|
+
{
|
|
62
|
+
wizard.state = 'channeling';
|
|
63
|
+
wizard.channelingSpell = 'shield';
|
|
64
|
+
wizard.channelDuration = 0;
|
|
65
|
+
}
|
|
66
|
+
else if (spell === 'missile')
|
|
67
|
+
{
|
|
68
|
+
wizard.state = 'gcd_locked';
|
|
69
|
+
wizard.gcdRemaining = GCD_DURATION;
|
|
70
|
+
}
|
|
71
|
+
else
|
|
72
|
+
{
|
|
73
|
+
// Blink: no GCD — can act immediately after teleporting
|
|
74
|
+
wizard.state = 'idle';
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
delete wizard.castingSpell;
|
|
78
|
+
delete wizard.castProgress;
|
|
79
|
+
delete wizard.castDuration;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Update the shield channel state.
|
|
84
|
+
*/
|
|
85
|
+
export function updateShield(wizard: WizardState, deltaTicks: number): void
|
|
86
|
+
{
|
|
87
|
+
if (wizard.state === 'channeling' && wizard.channelingSpell === 'shield')
|
|
88
|
+
{
|
|
89
|
+
wizard.channelDuration = (wizard.channelDuration ?? 0) + deltaTicks;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Calculate the current block percentage of a shield based on channel duration.
|
|
95
|
+
*/
|
|
96
|
+
export function calculateShieldBlock(channelDurationTicks: number): number
|
|
97
|
+
{
|
|
98
|
+
const channelSeconds = channelDurationTicks / TICKS_PER_SECOND;
|
|
99
|
+
const decay = channelSeconds * SHIELD_DECAY_PER_SECOND;
|
|
100
|
+
return Math.max(SHIELD_MIN_BLOCK, SHIELD_MAX_BLOCK - decay);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Apply damage to a wizard, considering shield mitigation.
|
|
105
|
+
*
|
|
106
|
+
* Shield blocks a percentage of damage based on channel duration:
|
|
107
|
+
* - Fresh shield (0s): 90% block → 10% damage through
|
|
108
|
+
* - Decayed shield: block % decreases over time (20%/sec)
|
|
109
|
+
* - Minimum: 30% block → 70% damage through
|
|
110
|
+
*
|
|
111
|
+
* (Design doc lines 196-212)
|
|
112
|
+
*/
|
|
113
|
+
export function applyDamage(wizard: WizardState, damage: number, _projectile?: ProjectileState): number
|
|
114
|
+
{
|
|
115
|
+
if (wizard.invincible) return 0;
|
|
116
|
+
|
|
117
|
+
let finalDamage = damage;
|
|
118
|
+
|
|
119
|
+
if (wizard.state === 'channeling' && wizard.channelingSpell === 'shield')
|
|
120
|
+
{
|
|
121
|
+
const blockPercent = calculateShieldBlock(wizard.channelDuration ?? 0);
|
|
122
|
+
// Simple block: damage through = damage * (1 - blockPercent)
|
|
123
|
+
finalDamage = damage * (1 - blockPercent);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
wizard.health = Math.max(0, wizard.health - finalDamage);
|
|
127
|
+
return finalDamage;
|
|
128
|
+
}
|
package/src/engine-version.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
export * from './types.js';
|
|
2
|
-
export * from './rules.js';
|
|
3
|
-
export * from './engine-version.js';
|
|
4
|
-
export * from './engine/simulation.js';
|
|
5
|
-
export * from './engine/hooks-runtime.js';
|
|
6
|
-
export * from './engine/physics.js';
|
|
7
|
-
export * from './engine/spells.js';
|
|
8
|
-
export * from './engine/manual-match.js';
|
|
9
|
-
export * from './engine/missile-templates.js';
|
|
10
|
-
export * from './utils/index.js';
|
|
11
|
-
export * from './bots/index.js';
|
|
12
|
-
export * from './hooks/index.js';
|
|
13
|
-
export * from './engine/params-runtime.js';
|
|
14
|
-
export * from './engine/optimizer.js';
|
|
15
|
-
export {BotBundle, compileMatchBundle, MatchSandbox, sandboxFight, sandboxSimulate} from './engine/sandbox.js';
|
|
16
|
-
export type {CompileOptions, SandboxOptions} from './engine/sandbox.js';
|
|
17
|
-
export {BrowserMatchSandbox, BrowserManualMatchSandbox, browserSandboxFight, browserSandboxSimulate, createWorkerScript} from './engine/sandbox-browser.js';
|
|
18
|
-
export type {BrowserSandboxOptions, ManualMatchInitOptions, ManualMatchStepRequest, WorkerFactory, WorkerLike} from './engine/sandbox-browser.js';
|
|
19
|
-
export {testBot} from './testing.js';
|
|
20
|
-
export {extractStats, formatStats} from './stats.js';
|
|
21
|
-
export type {FightStats} from './stats.js';
|
|
22
|
-
export {extractTraceEvents, summarizeTrace, formatTraceEvents, formatTraceSummary, diagnoseTrace, formatDiagnosis} from './trace.js';
|
|
23
|
-
export type {TraceEvent, TraceEventType, TraceSummary, TraceBotSummary} from './trace.js';
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export * from './rules.js';
|
|
3
|
+
export * from './engine-version.js';
|
|
4
|
+
export * from './engine/simulation.js';
|
|
5
|
+
export * from './engine/hooks-runtime.js';
|
|
6
|
+
export * from './engine/physics.js';
|
|
7
|
+
export * from './engine/spells.js';
|
|
8
|
+
export * from './engine/manual-match.js';
|
|
9
|
+
export * from './engine/missile-templates.js';
|
|
10
|
+
export * from './utils/index.js';
|
|
11
|
+
export * from './bots/index.js';
|
|
12
|
+
export * from './hooks/index.js';
|
|
13
|
+
export * from './engine/params-runtime.js';
|
|
14
|
+
export * from './engine/optimizer.js';
|
|
15
|
+
export {BotBundle, compileMatchBundle, MatchSandbox, sandboxFight, sandboxSimulate} from './engine/sandbox.js';
|
|
16
|
+
export type {CompileOptions, SandboxOptions} from './engine/sandbox.js';
|
|
17
|
+
export {BrowserMatchSandbox, BrowserManualMatchSandbox, browserSandboxFight, browserSandboxSimulate, createWorkerScript} from './engine/sandbox-browser.js';
|
|
18
|
+
export type {BrowserSandboxOptions, ManualMatchInitOptions, ManualMatchStepRequest, WorkerFactory, WorkerLike} from './engine/sandbox-browser.js';
|
|
19
|
+
export {testBot} from './testing.js';
|
|
20
|
+
export {extractStats, formatStats} from './stats.js';
|
|
21
|
+
export type {FightStats} from './stats.js';
|
|
22
|
+
export {extractTraceEvents, summarizeTrace, formatTraceEvents, formatTraceSummary, diagnoseTrace, formatDiagnosis} from './trace.js';
|
|
23
|
+
export type {TraceEvent, TraceEventType, TraceSummary, TraceBotSummary} from './trace.js';
|
|
24
24
|
export type {TestBotBuilder, TestFightResult, TestSimulateResult} from './testing.js';
|