@rpgjs/action-battle 5.0.0-alpha.44 → 5.0.0-beta.10
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/CHANGELOG.md +38 -0
- package/LICENSE +19 -0
- package/README.md +392 -22
- package/dist/{ai.server.d.ts → client/ai.server.d.ts} +90 -28
- package/dist/client/animations.d.ts +16 -0
- package/dist/{client.d.ts → client/client.d.ts} +3 -2
- package/dist/{config.d.ts → client/config.d.ts} +2 -0
- package/dist/client/core/attack-profile.d.ts +9 -0
- package/dist/client/core/attack-runtime.d.ts +20 -0
- package/dist/client/core/context.d.ts +5 -0
- package/dist/client/core/defaults.d.ts +81 -0
- package/dist/client/core/enemy-attack-profiles.d.ts +6 -0
- package/dist/client/core/equipment.d.ts +2 -0
- package/dist/client/core/hit-reaction.d.ts +5 -0
- package/dist/client/core/hit.d.ts +2 -0
- package/dist/client/enemies/factory.d.ts +7 -0
- package/dist/client/index.d.ts +21 -0
- package/dist/client/index.js +24 -31
- package/dist/client/index10.js +61 -0
- package/dist/client/index11.js +55 -0
- package/dist/client/index12.js +106 -0
- package/dist/client/index13.js +143 -0
- package/dist/client/index14.js +25 -0
- package/dist/client/index15.js +72 -0
- package/dist/client/index16.js +1343 -0
- package/dist/client/index17.js +13 -0
- package/dist/client/index18.js +60 -0
- package/dist/client/index19.js +10 -0
- package/dist/client/index2.js +30 -45
- package/dist/client/index20.js +504 -0
- package/dist/client/index3.js +45 -1288
- package/dist/client/index4.js +105 -330
- package/dist/client/index5.js +84 -291
- package/dist/client/index6.js +309 -95
- package/dist/client/index7.js +35 -59
- package/dist/client/index8.js +101 -54
- package/dist/client/index9.js +79 -30
- package/dist/{server.d.ts → client/server.d.ts} +12 -4
- package/dist/client/ui/state.d.ts +35 -0
- package/dist/server/ai.server.d.ts +569 -0
- package/dist/server/animations.d.ts +16 -0
- package/dist/server/config.d.ts +5 -0
- package/dist/server/core/attack-profile.d.ts +9 -0
- package/dist/server/core/attack-runtime.d.ts +20 -0
- package/dist/server/core/context.d.ts +5 -0
- package/dist/server/core/defaults.d.ts +81 -0
- package/dist/server/core/enemy-attack-profiles.d.ts +6 -0
- package/dist/server/core/equipment.d.ts +2 -0
- package/dist/server/core/hit-reaction.d.ts +5 -0
- package/dist/server/core/hit.d.ts +2 -0
- package/dist/server/enemies/factory.d.ts +7 -0
- package/dist/server/index.d.ts +21 -0
- package/dist/server/index.js +23 -31
- package/dist/server/index10.js +1342 -0
- package/dist/server/index11.js +37 -0
- package/dist/server/index12.js +60 -0
- package/dist/server/index13.js +13 -0
- package/dist/server/index14.js +503 -0
- package/dist/server/index15.js +10 -0
- package/dist/server/index2.js +59 -332
- package/dist/server/index3.js +29 -1286
- package/dist/server/index4.js +45 -53
- package/dist/server/index5.js +107 -29
- package/dist/server/index6.js +143 -0
- package/dist/server/index7.js +25 -0
- package/dist/server/index8.js +72 -0
- package/dist/server/index9.js +55 -0
- package/dist/server/server.d.ts +106 -0
- package/dist/server/targeting.d.ts +19 -0
- package/package.json +12 -12
- package/src/ai.server.spec.ts +120 -0
- package/src/ai.server.ts +515 -91
- package/src/animations.ts +149 -0
- package/src/canvas-engine-shim.ts +4 -0
- package/src/client.ts +130 -2
- package/src/components/action-bar.ce +5 -3
- package/src/components/attack-preview.ce +90 -0
- package/src/config.ts +61 -0
- package/src/core/attack-profile.spec.ts +118 -0
- package/src/core/attack-profile.ts +100 -0
- package/src/core/attack-runtime.spec.ts +103 -0
- package/src/core/attack-runtime.ts +83 -0
- package/src/core/context.ts +35 -0
- package/src/core/contracts.ts +126 -0
- package/src/core/defaults.ts +162 -0
- package/src/core/enemy-attack-profiles.spec.ts +35 -0
- package/src/core/enemy-attack-profiles.ts +103 -0
- package/src/core/equipment.spec.ts +37 -0
- package/src/core/equipment.ts +17 -0
- package/src/core/hit-reaction.spec.ts +43 -0
- package/src/core/hit-reaction.ts +70 -0
- package/src/core/hit.spec.ts +111 -0
- package/src/core/hit.ts +92 -0
- package/src/enemies/factory.ts +25 -0
- package/src/index.ts +94 -1
- package/src/server.ts +427 -93
- package/src/targeting.spec.ts +24 -0
- package/src/types/canvas-engine.d.ts +4 -0
- package/src/types.ts +148 -0
- package/src/ui/state.ts +57 -0
- package/dist/index.d.ts +0 -11
- package/dist/ui/state.d.ts +0 -18
- /package/dist/{targeting.d.ts → client/targeting.d.ts} +0 -0
package/dist/server/index4.js
CHANGED
|
@@ -1,55 +1,47 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
},
|
|
18
|
-
skills: {
|
|
19
|
-
defaultAoeMask: ["#"]
|
|
20
|
-
},
|
|
21
|
-
targeting: {
|
|
22
|
-
affects: "events",
|
|
23
|
-
allowEmptyTarget: true
|
|
24
|
-
}
|
|
1
|
+
import { DEFAULT_ACTION_BATTLE_HIT_REACTION, normalizeActionBattleHitReaction } from "./index3.js";
|
|
2
|
+
//#region src/core/attack-profile.ts
|
|
3
|
+
var DEFAULT_ACTION_BATTLE_ATTACK_PROFILE = {
|
|
4
|
+
id: "basic",
|
|
5
|
+
startupMs: 0,
|
|
6
|
+
activeMs: 120,
|
|
7
|
+
recoveryMs: 230,
|
|
8
|
+
cooldownMs: 350,
|
|
9
|
+
movementLock: true,
|
|
10
|
+
directionLock: true,
|
|
11
|
+
animationKey: "attack",
|
|
12
|
+
hitPolicy: "oncePerTarget",
|
|
13
|
+
reaction: DEFAULT_ACTION_BATTLE_HIT_REACTION,
|
|
14
|
+
totalDurationMs: 350
|
|
25
15
|
};
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
16
|
+
var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
17
|
+
var nonNegativeMs = (value, fallback) => isFiniteNumber(value) ? Math.max(0, value) : fallback;
|
|
18
|
+
var positiveMs = (value, fallback) => isFiniteNumber(value) ? Math.max(1, value) : fallback;
|
|
19
|
+
var resolveHitPolicy = (value) => value === "allowRepeatHits" ? "allowRepeatHits" : "oncePerTarget";
|
|
20
|
+
var resolveAnimationKey = (value) => value ?? DEFAULT_ACTION_BATTLE_ATTACK_PROFILE.animationKey;
|
|
21
|
+
function normalizeActionBattleAttackProfile(profile = {}, fallbacks = {}) {
|
|
22
|
+
const startupMs = nonNegativeMs(profile.startupMs, DEFAULT_ACTION_BATTLE_ATTACK_PROFILE.startupMs);
|
|
23
|
+
const activeMs = positiveMs(profile.activeMs, DEFAULT_ACTION_BATTLE_ATTACK_PROFILE.activeMs);
|
|
24
|
+
const legacyDuration = nonNegativeMs(fallbacks.lockDurationMs, DEFAULT_ACTION_BATTLE_ATTACK_PROFILE.totalDurationMs);
|
|
25
|
+
const fallbackRecoveryMs = Math.max(0, legacyDuration - startupMs - activeMs);
|
|
26
|
+
const recoveryMs = nonNegativeMs(profile.recoveryMs, fallbackRecoveryMs);
|
|
27
|
+
const totalDurationMs = startupMs + activeMs + recoveryMs;
|
|
28
|
+
const cooldownMs = nonNegativeMs(profile.cooldownMs, totalDurationMs);
|
|
29
|
+
const hitboxes = profile.hitboxes ?? fallbacks.hitboxes;
|
|
30
|
+
const normalized = {
|
|
31
|
+
id: profile.id || fallbacks.id || DEFAULT_ACTION_BATTLE_ATTACK_PROFILE.id,
|
|
32
|
+
startupMs,
|
|
33
|
+
activeMs,
|
|
34
|
+
recoveryMs,
|
|
35
|
+
cooldownMs,
|
|
36
|
+
movementLock: profile.movementLock ?? fallbacks.lockMovement ?? DEFAULT_ACTION_BATTLE_ATTACK_PROFILE.movementLock,
|
|
37
|
+
directionLock: profile.directionLock ?? DEFAULT_ACTION_BATTLE_ATTACK_PROFILE.directionLock,
|
|
38
|
+
animationKey: resolveAnimationKey(profile.animationKey),
|
|
39
|
+
hitPolicy: resolveHitPolicy(profile.hitPolicy),
|
|
40
|
+
reaction: normalizeActionBattleHitReaction(profile.reaction),
|
|
41
|
+
totalDurationMs
|
|
42
|
+
};
|
|
43
|
+
if (hitboxes) normalized.hitboxes = hitboxes;
|
|
44
|
+
return normalized;
|
|
51
45
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
normalizeActionBattleOptions
|
|
55
|
-
};
|
|
46
|
+
//#endregion
|
|
47
|
+
export { DEFAULT_ACTION_BATTLE_ATTACK_PROFILE, normalizeActionBattleAttackProfile };
|
package/dist/server/index5.js
CHANGED
|
@@ -1,30 +1,108 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
1
|
+
import { normalizeActionBattleAttackProfile } from "./index4.js";
|
|
2
|
+
//#region src/config.ts
|
|
3
|
+
var DEFAULT_ACTION_BATTLE_OPTIONS = {
|
|
4
|
+
ui: {
|
|
5
|
+
actionBar: {
|
|
6
|
+
enabled: false,
|
|
7
|
+
autoOpen: false,
|
|
8
|
+
mode: "both"
|
|
9
|
+
},
|
|
10
|
+
targeting: {
|
|
11
|
+
enabled: true,
|
|
12
|
+
showGrid: true,
|
|
13
|
+
colors: {
|
|
14
|
+
area: 3120887,
|
|
15
|
+
edge: 1796760,
|
|
16
|
+
cursor: 16765286
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
skills: { defaultAoeMask: ["#"] },
|
|
21
|
+
targeting: {
|
|
22
|
+
affects: "events",
|
|
23
|
+
allowEmptyTarget: true
|
|
24
|
+
},
|
|
25
|
+
attack: {
|
|
26
|
+
lockMovement: true,
|
|
27
|
+
lockDurationMs: 350,
|
|
28
|
+
showPreview: true,
|
|
29
|
+
previewDurationMs: 180,
|
|
30
|
+
previewColor: 16774064,
|
|
31
|
+
previewAccentColor: 16777215
|
|
32
|
+
},
|
|
33
|
+
animations: {}
|
|
30
34
|
};
|
|
35
|
+
var currentActionBattleOptions = DEFAULT_ACTION_BATTLE_OPTIONS;
|
|
36
|
+
function normalizeActionBattleOptions(options = {}) {
|
|
37
|
+
const attack = {
|
|
38
|
+
...DEFAULT_ACTION_BATTLE_OPTIONS.attack,
|
|
39
|
+
...options.attack
|
|
40
|
+
};
|
|
41
|
+
const attackProfile = normalizeActionBattleAttackProfile(attack.profile, {
|
|
42
|
+
lockMovement: attack.lockMovement,
|
|
43
|
+
lockDurationMs: attack.lockDurationMs,
|
|
44
|
+
hitboxes: attack.hitboxes
|
|
45
|
+
});
|
|
46
|
+
return {
|
|
47
|
+
ui: {
|
|
48
|
+
actionBar: {
|
|
49
|
+
...DEFAULT_ACTION_BATTLE_OPTIONS.ui?.actionBar,
|
|
50
|
+
...options.ui?.actionBar
|
|
51
|
+
},
|
|
52
|
+
targeting: {
|
|
53
|
+
...DEFAULT_ACTION_BATTLE_OPTIONS.ui?.targeting,
|
|
54
|
+
...options.ui?.targeting,
|
|
55
|
+
colors: {
|
|
56
|
+
...DEFAULT_ACTION_BATTLE_OPTIONS.ui?.targeting?.colors,
|
|
57
|
+
...options.ui?.targeting?.colors
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
skills: {
|
|
62
|
+
...DEFAULT_ACTION_BATTLE_OPTIONS.skills,
|
|
63
|
+
...options.skills
|
|
64
|
+
},
|
|
65
|
+
targeting: {
|
|
66
|
+
...DEFAULT_ACTION_BATTLE_OPTIONS.targeting,
|
|
67
|
+
...options.targeting
|
|
68
|
+
},
|
|
69
|
+
debug: {
|
|
70
|
+
...DEFAULT_ACTION_BATTLE_OPTIONS.debug,
|
|
71
|
+
...options.debug
|
|
72
|
+
},
|
|
73
|
+
attack: {
|
|
74
|
+
...attack,
|
|
75
|
+
profile: attackProfile
|
|
76
|
+
},
|
|
77
|
+
animations: {
|
|
78
|
+
...DEFAULT_ACTION_BATTLE_OPTIONS.animations,
|
|
79
|
+
...options.animations
|
|
80
|
+
},
|
|
81
|
+
systems: {
|
|
82
|
+
combat: {
|
|
83
|
+
...DEFAULT_ACTION_BATTLE_OPTIONS.systems?.combat,
|
|
84
|
+
...options.systems?.combat,
|
|
85
|
+
hooks: {
|
|
86
|
+
...DEFAULT_ACTION_BATTLE_OPTIONS.systems?.combat?.hooks,
|
|
87
|
+
...options.systems?.combat?.hooks
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
ai: {
|
|
91
|
+
...DEFAULT_ACTION_BATTLE_OPTIONS.systems?.ai,
|
|
92
|
+
...options.systems?.ai,
|
|
93
|
+
behaviors: {
|
|
94
|
+
...DEFAULT_ACTION_BATTLE_OPTIONS.systems?.ai?.behaviors,
|
|
95
|
+
...options.systems?.ai?.behaviors
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function setActionBattleOptions(options) {
|
|
102
|
+
currentActionBattleOptions = options;
|
|
103
|
+
}
|
|
104
|
+
function getActionBattleOptions() {
|
|
105
|
+
return currentActionBattleOptions;
|
|
106
|
+
}
|
|
107
|
+
//#endregion
|
|
108
|
+
export { getActionBattleOptions, normalizeActionBattleOptions, setActionBattleOptions };
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
//#region src/core/defaults.ts
|
|
2
|
+
var DEFAULT_CORE_KNOCKBACK = {
|
|
3
|
+
force: 50,
|
|
4
|
+
duration: 300
|
|
5
|
+
};
|
|
6
|
+
var CoreAttackPattern = {
|
|
7
|
+
Melee: "melee",
|
|
8
|
+
Combo: "combo",
|
|
9
|
+
Charged: "charged",
|
|
10
|
+
Zone: "zone",
|
|
11
|
+
DashAttack: "dashAttack"
|
|
12
|
+
};
|
|
13
|
+
var CoreEnemyType = {
|
|
14
|
+
Aggressive: "aggressive",
|
|
15
|
+
Defensive: "defensive",
|
|
16
|
+
Ranged: "ranged",
|
|
17
|
+
Tank: "tank",
|
|
18
|
+
Berserker: "berserker"
|
|
19
|
+
};
|
|
20
|
+
var DEFAULT_ZELDA_PLAYER_HITBOXES = {
|
|
21
|
+
up: {
|
|
22
|
+
offsetX: -16,
|
|
23
|
+
offsetY: -48,
|
|
24
|
+
width: 32,
|
|
25
|
+
height: 32
|
|
26
|
+
},
|
|
27
|
+
down: {
|
|
28
|
+
offsetX: -16,
|
|
29
|
+
offsetY: 16,
|
|
30
|
+
width: 32,
|
|
31
|
+
height: 32
|
|
32
|
+
},
|
|
33
|
+
left: {
|
|
34
|
+
offsetX: -48,
|
|
35
|
+
offsetY: -16,
|
|
36
|
+
width: 32,
|
|
37
|
+
height: 32
|
|
38
|
+
},
|
|
39
|
+
right: {
|
|
40
|
+
offsetX: 16,
|
|
41
|
+
offsetY: -16,
|
|
42
|
+
width: 32,
|
|
43
|
+
height: 32
|
|
44
|
+
},
|
|
45
|
+
default: {
|
|
46
|
+
offsetX: 0,
|
|
47
|
+
offsetY: -32,
|
|
48
|
+
width: 32,
|
|
49
|
+
height: 32
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
var resolveEquippedWeapon = (entity) => {
|
|
53
|
+
const equipments = entity?.equipments?.() || [];
|
|
54
|
+
for (const item of equipments) {
|
|
55
|
+
const itemId = item?.id?.() ?? item?.id;
|
|
56
|
+
const itemData = entity?.databaseById?.(itemId);
|
|
57
|
+
if (itemData?._type === "weapon") return itemData;
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
};
|
|
61
|
+
var resolveDirection = (attacker, target) => {
|
|
62
|
+
const dx = target.x() - attacker.x();
|
|
63
|
+
const dy = target.y() - attacker.y();
|
|
64
|
+
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
65
|
+
if (distance <= 0) return void 0;
|
|
66
|
+
return {
|
|
67
|
+
x: dx / distance,
|
|
68
|
+
y: dy / distance
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
var createDefaultPlayerHitboxResolver = (hitboxes = DEFAULT_ZELDA_PLAYER_HITBOXES) => (context) => {
|
|
72
|
+
const attacker = context.attacker;
|
|
73
|
+
const config = hitboxes[context.direction ?? (typeof attacker.getDirection === "function" ? attacker.getDirection() : "default")] || hitboxes.default;
|
|
74
|
+
return [{
|
|
75
|
+
x: attacker.x() + config.offsetX,
|
|
76
|
+
y: attacker.y() + config.offsetY,
|
|
77
|
+
width: config.width,
|
|
78
|
+
height: config.height
|
|
79
|
+
}];
|
|
80
|
+
};
|
|
81
|
+
var defaultRpgjsDamageResolver = (context) => {
|
|
82
|
+
const target = context.target;
|
|
83
|
+
const raw = target.applyDamage(context.attacker, context.skill);
|
|
84
|
+
return {
|
|
85
|
+
damage: raw?.damage ?? 0,
|
|
86
|
+
defeated: target.hp <= 0,
|
|
87
|
+
raw
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
var defaultKnockbackResolver = (context) => {
|
|
91
|
+
const weapon = context.weapon ?? resolveEquippedWeapon(context.attacker);
|
|
92
|
+
return {
|
|
93
|
+
force: weapon?.knockbackForce ?? DEFAULT_CORE_KNOCKBACK.force,
|
|
94
|
+
duration: weapon?.knockbackDuration ?? DEFAULT_CORE_KNOCKBACK.duration,
|
|
95
|
+
direction: resolveDirection(context.attacker, context.target)
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
var defaultCombatSystem = {
|
|
99
|
+
resolveHitboxes: createDefaultPlayerHitboxResolver(),
|
|
100
|
+
resolveDamage: defaultRpgjsDamageResolver,
|
|
101
|
+
resolveKnockback: defaultKnockbackResolver
|
|
102
|
+
};
|
|
103
|
+
var defaultEnemyBehaviors = {
|
|
104
|
+
[CoreEnemyType.Aggressive]: ({ hpPercent }) => ({
|
|
105
|
+
mode: hpPercent !== null && hpPercent < .15 ? "retreat" : "assault",
|
|
106
|
+
attackPatterns: [
|
|
107
|
+
CoreAttackPattern.Melee,
|
|
108
|
+
CoreAttackPattern.Combo,
|
|
109
|
+
CoreAttackPattern.DashAttack
|
|
110
|
+
]
|
|
111
|
+
}),
|
|
112
|
+
[CoreEnemyType.Defensive]: ({ hpPercent }) => ({
|
|
113
|
+
mode: hpPercent !== null && hpPercent < .3 ? "retreat" : "tactical",
|
|
114
|
+
attackPatterns: [CoreAttackPattern.Melee, CoreAttackPattern.Charged]
|
|
115
|
+
}),
|
|
116
|
+
[CoreEnemyType.Ranged]: ({ distance }) => ({
|
|
117
|
+
mode: distance !== null && distance < 80 ? "retreat" : "tactical",
|
|
118
|
+
attackPatterns: [CoreAttackPattern.Melee, CoreAttackPattern.Zone]
|
|
119
|
+
}),
|
|
120
|
+
[CoreEnemyType.Tank]: () => ({
|
|
121
|
+
mode: "assault",
|
|
122
|
+
attackPatterns: [
|
|
123
|
+
CoreAttackPattern.Melee,
|
|
124
|
+
CoreAttackPattern.Charged,
|
|
125
|
+
CoreAttackPattern.Zone
|
|
126
|
+
]
|
|
127
|
+
}),
|
|
128
|
+
[CoreEnemyType.Berserker]: ({ hpPercent }) => ({
|
|
129
|
+
mode: "assault",
|
|
130
|
+
attackCooldown: hpPercent === null ? void 0 : Math.max(250, 800 * Math.max(.3, hpPercent)),
|
|
131
|
+
attackPatterns: [
|
|
132
|
+
CoreAttackPattern.Melee,
|
|
133
|
+
CoreAttackPattern.Combo,
|
|
134
|
+
CoreAttackPattern.DashAttack
|
|
135
|
+
]
|
|
136
|
+
})
|
|
137
|
+
};
|
|
138
|
+
var defaultActionBattleSystems = {
|
|
139
|
+
combat: defaultCombatSystem,
|
|
140
|
+
ai: { behaviors: defaultEnemyBehaviors }
|
|
141
|
+
};
|
|
142
|
+
//#endregion
|
|
143
|
+
export { DEFAULT_ZELDA_PLAYER_HITBOXES, createDefaultPlayerHitboxResolver, defaultActionBattleSystems, defaultCombatSystem, defaultEnemyBehaviors, defaultKnockbackResolver, defaultRpgjsDamageResolver };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { defaultActionBattleSystems } from "./index6.js";
|
|
2
|
+
//#region src/core/context.ts
|
|
3
|
+
var mergeSystems = (options = {}) => ({
|
|
4
|
+
combat: {
|
|
5
|
+
...defaultActionBattleSystems.combat,
|
|
6
|
+
resolveDamage: options.systems?.combat?.damage ?? defaultActionBattleSystems.combat.resolveDamage,
|
|
7
|
+
resolveKnockback: options.systems?.combat?.knockback ?? defaultActionBattleSystems.combat.resolveKnockback,
|
|
8
|
+
hooks: {
|
|
9
|
+
...defaultActionBattleSystems.combat.hooks,
|
|
10
|
+
...options.systems?.combat?.hooks
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
ai: { behaviors: {
|
|
14
|
+
...defaultActionBattleSystems.ai.behaviors,
|
|
15
|
+
...options.systems?.ai?.behaviors
|
|
16
|
+
} }
|
|
17
|
+
});
|
|
18
|
+
var currentActionBattleSystems = mergeSystems();
|
|
19
|
+
var setActionBattleSystems = (options = {}) => {
|
|
20
|
+
currentActionBattleSystems = mergeSystems(options);
|
|
21
|
+
};
|
|
22
|
+
var getActionBattleSystems = () => currentActionBattleSystems;
|
|
23
|
+
var createActionBattleSystems = mergeSystems;
|
|
24
|
+
//#endregion
|
|
25
|
+
export { createActionBattleSystems, getActionBattleSystems, setActionBattleSystems };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { normalizeActionBattleAttackProfile } from "./index4.js";
|
|
2
|
+
//#region src/core/enemy-attack-profiles.ts
|
|
3
|
+
var DEFAULT_ACTION_BATTLE_ENEMY_ATTACK_PROFILES = {
|
|
4
|
+
melee: {
|
|
5
|
+
id: "enemy-melee",
|
|
6
|
+
startupMs: 120,
|
|
7
|
+
activeMs: 100,
|
|
8
|
+
recoveryMs: 220,
|
|
9
|
+
cooldownMs: 440,
|
|
10
|
+
reaction: {
|
|
11
|
+
invincibilityMs: 250,
|
|
12
|
+
hitstunMs: 120,
|
|
13
|
+
staggerPower: 1
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
combo: {
|
|
17
|
+
id: "enemy-combo",
|
|
18
|
+
startupMs: 80,
|
|
19
|
+
activeMs: 80,
|
|
20
|
+
recoveryMs: 140,
|
|
21
|
+
cooldownMs: 300,
|
|
22
|
+
reaction: {
|
|
23
|
+
invincibilityMs: 180,
|
|
24
|
+
hitstunMs: 90,
|
|
25
|
+
staggerPower: .75
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
charged: {
|
|
29
|
+
id: "enemy-charged",
|
|
30
|
+
startupMs: 800,
|
|
31
|
+
activeMs: 140,
|
|
32
|
+
recoveryMs: 320,
|
|
33
|
+
cooldownMs: 1260,
|
|
34
|
+
reaction: {
|
|
35
|
+
invincibilityMs: 350,
|
|
36
|
+
hitstunMs: 220,
|
|
37
|
+
staggerPower: 2
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
zone: {
|
|
41
|
+
id: "enemy-zone",
|
|
42
|
+
startupMs: 450,
|
|
43
|
+
activeMs: 180,
|
|
44
|
+
recoveryMs: 320,
|
|
45
|
+
cooldownMs: 950,
|
|
46
|
+
reaction: {
|
|
47
|
+
invincibilityMs: 300,
|
|
48
|
+
hitstunMs: 160,
|
|
49
|
+
staggerPower: 1.25
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
dashAttack: {
|
|
53
|
+
id: "enemy-dash",
|
|
54
|
+
startupMs: 180,
|
|
55
|
+
activeMs: 120,
|
|
56
|
+
recoveryMs: 260,
|
|
57
|
+
cooldownMs: 560,
|
|
58
|
+
reaction: {
|
|
59
|
+
invincibilityMs: 280,
|
|
60
|
+
hitstunMs: 150,
|
|
61
|
+
staggerPower: 1.2
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
function normalizeActionBattleEnemyAttackProfiles(overrides = {}) {
|
|
66
|
+
return Object.fromEntries(Object.entries(DEFAULT_ACTION_BATTLE_ENEMY_ATTACK_PROFILES).map(([key, defaultProfile]) => [key, normalizeActionBattleAttackProfile({
|
|
67
|
+
...defaultProfile,
|
|
68
|
+
...overrides[key]
|
|
69
|
+
})]));
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
export { DEFAULT_ACTION_BATTLE_ENEMY_ATTACK_PROFILES, normalizeActionBattleEnemyAttackProfiles };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { normalizeActionBattleAttackProfile } from "./index4.js";
|
|
2
|
+
//#region src/core/attack-runtime.ts
|
|
3
|
+
var ACTION_BATTLE_HITBOX_FRAME_MS = 16;
|
|
4
|
+
function getNormalizedActionBattleAttackProfile(options = {}) {
|
|
5
|
+
const attack = options.attack ?? {};
|
|
6
|
+
return normalizeActionBattleAttackProfile(attack.profile, {
|
|
7
|
+
lockMovement: attack.lockMovement,
|
|
8
|
+
lockDurationMs: attack.lockDurationMs,
|
|
9
|
+
hitboxes: attack.hitboxes
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
function resolveActionBattleHitboxSpeed(profile, hitboxCount) {
|
|
13
|
+
const positions = Math.max(1, Math.floor(hitboxCount));
|
|
14
|
+
const activeFrames = Math.max(1, Math.ceil(profile.activeMs / 16));
|
|
15
|
+
return Math.max(1, Math.ceil(activeFrames / positions));
|
|
16
|
+
}
|
|
17
|
+
function scheduleActionBattleStartup(profile, callback, scheduler = setTimeout) {
|
|
18
|
+
if (profile.startupMs <= 0) {
|
|
19
|
+
callback();
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
return scheduler(callback, profile.startupMs);
|
|
23
|
+
}
|
|
24
|
+
var attackIdCounter = 0;
|
|
25
|
+
function createActionBattleAttackId(attackerId, profileId) {
|
|
26
|
+
attackIdCounter++;
|
|
27
|
+
return `${attackerId ?? "unknown"}:${profileId}:${Date.now()}:${attackIdCounter}`;
|
|
28
|
+
}
|
|
29
|
+
var getTargetKey = (target) => {
|
|
30
|
+
if (!target || target.id === void 0 || target.id === null) return null;
|
|
31
|
+
return String(target.id);
|
|
32
|
+
};
|
|
33
|
+
var ActionBattleHitTracker = class {
|
|
34
|
+
hitPolicy;
|
|
35
|
+
hitTargets = /* @__PURE__ */ new Set();
|
|
36
|
+
constructor(hitPolicy) {
|
|
37
|
+
this.hitPolicy = hitPolicy;
|
|
38
|
+
}
|
|
39
|
+
canHit(target) {
|
|
40
|
+
if (this.hitPolicy === "allowRepeatHits") return true;
|
|
41
|
+
const key = getTargetKey(target);
|
|
42
|
+
return !key || !this.hitTargets.has(key);
|
|
43
|
+
}
|
|
44
|
+
recordHit(target) {
|
|
45
|
+
const key = getTargetKey(target);
|
|
46
|
+
if (key) this.hitTargets.add(key);
|
|
47
|
+
}
|
|
48
|
+
tryHit(target) {
|
|
49
|
+
if (!this.canHit(target)) return false;
|
|
50
|
+
this.recordHit(target);
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
//#endregion
|
|
55
|
+
export { ACTION_BATTLE_HITBOX_FRAME_MS, ActionBattleHitTracker, createActionBattleAttackId, getNormalizedActionBattleAttackProfile, resolveActionBattleHitboxSpeed, scheduleActionBattleStartup };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { RpgEvent, RpgPlayer, RpgServer } from '@rpgjs/server';
|
|
2
|
+
import { HitResult, ApplyHitHooks } from './ai.server';
|
|
3
|
+
import { ActionBattleOptions } from './types';
|
|
4
|
+
export declare const ACTION_BATTLE_ACTION_BAR_GUI_ID = "action-battle-action-bar";
|
|
5
|
+
/**
|
|
6
|
+
* Default player attack hitboxes offsets for each direction
|
|
7
|
+
*
|
|
8
|
+
* These hitboxes define the attack areas relative to the player's position
|
|
9
|
+
* for each cardinal direction. They are converted to absolute coordinates
|
|
10
|
+
* when creating the moving hitbox.
|
|
11
|
+
*/
|
|
12
|
+
export declare const DEFAULT_PLAYER_ATTACK_HITBOXES: {
|
|
13
|
+
up: {
|
|
14
|
+
offsetX: number;
|
|
15
|
+
offsetY: number;
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
};
|
|
19
|
+
down: {
|
|
20
|
+
offsetX: number;
|
|
21
|
+
offsetY: number;
|
|
22
|
+
width: number;
|
|
23
|
+
height: number;
|
|
24
|
+
};
|
|
25
|
+
left: {
|
|
26
|
+
offsetX: number;
|
|
27
|
+
offsetY: number;
|
|
28
|
+
width: number;
|
|
29
|
+
height: number;
|
|
30
|
+
};
|
|
31
|
+
right: {
|
|
32
|
+
offsetX: number;
|
|
33
|
+
offsetY: number;
|
|
34
|
+
width: number;
|
|
35
|
+
height: number;
|
|
36
|
+
};
|
|
37
|
+
default: {
|
|
38
|
+
offsetX: number;
|
|
39
|
+
offsetY: number;
|
|
40
|
+
width: number;
|
|
41
|
+
height: number;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Get knockback force from player's equipped weapon
|
|
46
|
+
*
|
|
47
|
+
* Retrieves the knockbackForce property from the player's equipped weapon.
|
|
48
|
+
* Falls back to DEFAULT_KNOCKBACK.force if no weapon or property is set.
|
|
49
|
+
*
|
|
50
|
+
* @param player - The player to get weapon knockback from
|
|
51
|
+
* @returns Knockback force value
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* // Player with weapon having knockbackForce: 80
|
|
56
|
+
* const force = getPlayerWeaponKnockbackForce(player); // 80
|
|
57
|
+
*
|
|
58
|
+
* // No weapon equipped
|
|
59
|
+
* const force = getPlayerWeaponKnockbackForce(player); // 50 (default)
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare function getPlayerWeaponKnockbackForce(player: RpgPlayer): number;
|
|
63
|
+
/**
|
|
64
|
+
* Apply hit from player to target (event with AI)
|
|
65
|
+
*
|
|
66
|
+
* Handles damage calculation, knockback based on weapon, and visual effects.
|
|
67
|
+
* Can be customized using hooks.
|
|
68
|
+
*
|
|
69
|
+
* @param player - The attacking player
|
|
70
|
+
* @param target - The event being hit
|
|
71
|
+
* @param hooks - Optional hooks for customizing hit behavior
|
|
72
|
+
* @returns Hit result if AI exists, undefined otherwise
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* // Basic hit
|
|
77
|
+
* const result = applyPlayerHitToEvent(player, event);
|
|
78
|
+
*
|
|
79
|
+
* // With custom hooks
|
|
80
|
+
* const result = applyPlayerHitToEvent(player, event, {
|
|
81
|
+
* onBeforeHit(result) {
|
|
82
|
+
* result.knockbackForce *= 2; // Double knockback
|
|
83
|
+
* return result;
|
|
84
|
+
* },
|
|
85
|
+
* onAfterHit(result) {
|
|
86
|
+
* if (result.defeated) {
|
|
87
|
+
* player.gold += 10;
|
|
88
|
+
* }
|
|
89
|
+
* }
|
|
90
|
+
* });
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export declare function applyPlayerHitToEvent(player: RpgPlayer, target: RpgEvent, hooks?: ApplyHitHooks, metadata?: Record<string, any>): HitResult | undefined;
|
|
94
|
+
export declare const openActionBattleActionBar: (player: RpgPlayer, rawOptions?: ActionBattleOptions) => void;
|
|
95
|
+
export declare const updateActionBattleActionBar: (player: RpgPlayer, rawOptions?: ActionBattleOptions) => void;
|
|
96
|
+
export declare const createActionBattleServer: (rawOptions?: ActionBattleOptions) => RpgServer;
|
|
97
|
+
declare const _default: RpgServer;
|
|
98
|
+
export default _default;
|
|
99
|
+
export { ACTION_BATTLE_HITBOX_FRAME_MS, ActionBattleHitTracker, createActionBattleAttackId, getNormalizedActionBattleAttackProfile, resolveActionBattleHitboxSpeed, scheduleActionBattleStartup, } from './core/attack-runtime';
|
|
100
|
+
export { DEFAULT_ACTION_BATTLE_ATTACK_PROFILE, normalizeActionBattleAttackProfile, type ActionBattleAttackProfileFallbacks, } from './core/attack-profile';
|
|
101
|
+
export type { ActionBattleAttackDirection, ActionBattleAttackHitboxConfig, ActionBattleAttackHitboxMap, ActionBattleAttackHitPolicy, ActionBattleAttackProfile, ActionBattleDebugOptions, ActionBattleHitReactionProfile, NormalizedActionBattleHitReactionProfile, NormalizedActionBattleAttackProfile, } from './types';
|
|
102
|
+
export { DEFAULT_ACTION_BATTLE_HIT_REACTION, isActionBattleEntityInvincible, normalizeActionBattleHitReaction, setActionBattleInvincibility, } from './core/hit-reaction';
|
|
103
|
+
export { DEFAULT_ACTION_BATTLE_ENEMY_ATTACK_PROFILES, normalizeActionBattleEnemyAttackProfiles, type ActionBattleEnemyAttackProfileKey, type ActionBattleEnemyAttackProfileMap, type NormalizedActionBattleEnemyAttackProfileMap, } from './core/enemy-attack-profiles';
|
|
104
|
+
export { resolveActionBattleWeaponAttackProfile } from './core/equipment';
|
|
105
|
+
export { AiDebug, AiState, AttackPattern, BattleAi, DEFAULT_KNOCKBACK, EnemyType, } from './ai.server';
|
|
106
|
+
export type { ApplyHitHooks, BattleAiDefeatedCallback, BattleAiDefeatedContext, BattleAiDefeatReward, BattleAiLegacyDefeatedCallback, BattleAiLegacyOptions, BattleAiOptions, BattleAiRewardItem, BattleAiRewards, HitResult, } from './ai.server';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ActionBattleAoeMask } from './types';
|
|
2
|
+
export interface ParsedAoeMask {
|
|
3
|
+
width: number;
|
|
4
|
+
height: number;
|
|
5
|
+
centerX: number;
|
|
6
|
+
centerY: number;
|
|
7
|
+
cells: Array<{
|
|
8
|
+
dx: number;
|
|
9
|
+
dy: number;
|
|
10
|
+
}>;
|
|
11
|
+
}
|
|
12
|
+
export declare const parseAoeMask: (mask: ActionBattleAoeMask | undefined) => ParsedAoeMask;
|
|
13
|
+
export declare const manhattanDistance: (a: {
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
}, b: {
|
|
17
|
+
x: number;
|
|
18
|
+
y: number;
|
|
19
|
+
}) => number;
|