@rpgjs/action-battle 5.0.0-beta.11 → 5.0.0-beta.13
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 +22 -0
- package/dist/client/ai.server.d.ts +57 -8
- package/dist/client/attack-input.d.ts +3 -0
- package/dist/client/core/action-use.d.ts +18 -0
- package/dist/client/core/ai-behavior-tree.d.ts +99 -0
- package/dist/client/core/attack-runtime.d.ts +2 -0
- package/dist/client/core/defaults.d.ts +3 -2
- package/dist/client/core/equipment.d.ts +1 -0
- package/dist/client/core/targets.d.ts +15 -0
- package/dist/client/enemies/factory.d.ts +2 -0
- package/dist/client/index.d.ts +12 -7
- package/dist/client/index.js +16 -11
- package/dist/client/index10.js +32 -56
- package/dist/client/index11.js +99 -52
- package/dist/client/index12.js +76 -103
- package/dist/client/index13.js +72 -135
- package/dist/client/index14.js +67 -23
- package/dist/client/index15.js +197 -63
- package/dist/client/index16.js +112 -1337
- package/dist/client/index17.js +203 -7
- package/dist/client/index18.js +32 -58
- package/dist/client/index19.js +70 -8
- package/dist/client/index20.js +57 -501
- package/dist/client/index21.js +70 -0
- package/dist/client/index22.js +226 -0
- package/dist/client/index23.js +16 -0
- package/dist/client/index24.js +25 -0
- package/dist/client/index25.js +107 -0
- package/dist/client/index26.js +1949 -0
- package/dist/client/index27.js +12 -0
- package/dist/client/index28.js +589 -0
- package/dist/client/index4.js +79 -38
- package/dist/client/index6.js +65 -306
- package/dist/client/index7.js +33 -33
- package/dist/client/index8.js +24 -100
- package/dist/client/index9.js +293 -61
- package/dist/client/locomotion.d.ts +16 -0
- package/dist/client/movement.d.ts +14 -0
- package/dist/client/server.d.ts +7 -3
- package/dist/client/ui.d.ts +22 -0
- package/dist/client/visual.d.ts +15 -0
- package/dist/server/ai.server.d.ts +57 -8
- package/dist/server/attack-input.d.ts +3 -0
- package/dist/server/core/action-use.d.ts +18 -0
- package/dist/server/core/ai-behavior-tree.d.ts +99 -0
- package/dist/server/core/attack-runtime.d.ts +2 -0
- package/dist/server/core/defaults.d.ts +3 -2
- package/dist/server/core/equipment.d.ts +1 -0
- package/dist/server/core/targets.d.ts +15 -0
- package/dist/server/enemies/factory.d.ts +2 -0
- package/dist/server/index.d.ts +12 -7
- package/dist/server/index.js +14 -9
- package/dist/server/index10.js +64 -1336
- package/dist/server/index11.js +33 -33
- package/dist/server/index13.js +67 -11
- package/dist/server/index14.js +207 -484
- package/dist/server/index15.js +15 -9
- package/dist/server/index16.js +26 -0
- package/dist/server/index17.js +25 -0
- package/dist/server/index18.js +107 -0
- package/dist/server/index19.js +1949 -0
- package/dist/server/index2.js +10 -2
- package/dist/server/index20.js +37 -0
- package/dist/server/index21.js +588 -0
- package/dist/server/index22.js +78 -0
- package/dist/server/index23.js +12 -0
- package/dist/server/index5.js +79 -38
- package/dist/server/index6.js +192 -129
- package/dist/server/index7.js +208 -24
- package/dist/server/index8.js +28 -66
- package/dist/server/index9.js +68 -51
- package/dist/server/locomotion.d.ts +16 -0
- package/dist/server/movement.d.ts +14 -0
- package/dist/server/server.d.ts +7 -3
- package/dist/server/ui.d.ts +22 -0
- package/dist/server/visual.d.ts +15 -0
- package/package.json +5 -5
- package/src/ai.server.spec.ts +380 -1
- package/src/ai.server.ts +963 -137
- package/src/animations.spec.ts +40 -0
- package/src/animations.ts +31 -9
- package/src/attack-input.spec.ts +51 -0
- package/src/attack-input.ts +59 -0
- package/src/client.ts +75 -62
- package/src/config.ts +84 -37
- package/src/core/action-use.spec.ts +317 -0
- package/src/core/action-use.ts +387 -0
- package/src/core/ai-behavior-tree.spec.ts +116 -0
- package/src/core/ai-behavior-tree.ts +272 -0
- package/src/core/attack-profile.spec.ts +46 -0
- package/src/core/attack-runtime.spec.ts +35 -0
- package/src/core/attack-runtime.ts +32 -0
- package/src/core/context.ts +9 -0
- package/src/core/contracts.ts +146 -1
- package/src/core/defaults.ts +72 -1
- package/src/core/equipment.ts +9 -5
- package/src/core/hit.spec.ts +21 -0
- package/src/core/targets.spec.ts +124 -0
- package/src/core/targets.ts +150 -0
- package/src/enemies/factory.ts +8 -0
- package/src/index.ts +111 -2
- package/src/locomotion.spec.ts +51 -0
- package/src/locomotion.ts +48 -0
- package/src/movement.spec.ts +78 -0
- package/src/movement.ts +46 -0
- package/src/server.ts +242 -66
- package/src/types.ts +105 -35
- package/src/ui.ts +113 -0
- package/src/visual.spec.ts +166 -0
- package/src/visual.ts +285 -0
- package/README.md +0 -1242
package/src/server.ts
CHANGED
|
@@ -8,7 +8,15 @@ import {
|
|
|
8
8
|
} from "./types";
|
|
9
9
|
import { normalizeActionBattleOptions, setActionBattleOptions } from "./config";
|
|
10
10
|
import { manhattanDistance, parseAoeMask } from "./targeting";
|
|
11
|
-
import {
|
|
11
|
+
import { emitActionBattleClientVisual } from "./visual";
|
|
12
|
+
import {
|
|
13
|
+
applyActionBattleAttackDirection,
|
|
14
|
+
resolveActionBattleAttackDirection,
|
|
15
|
+
} from "./attack-input";
|
|
16
|
+
import {
|
|
17
|
+
forceActionBattleLocomotionAnimation,
|
|
18
|
+
withActionBattleAnimationUnlocked,
|
|
19
|
+
} from "./locomotion";
|
|
12
20
|
import { getActionBattleSystems, setActionBattleSystems } from "./core/context";
|
|
13
21
|
import { applyActionBattleHit } from "./core/hit";
|
|
14
22
|
import { DEFAULT_ZELDA_PLAYER_HITBOXES } from "./core/defaults";
|
|
@@ -16,12 +24,25 @@ import {
|
|
|
16
24
|
ActionBattleHitTracker,
|
|
17
25
|
createActionBattleAttackId,
|
|
18
26
|
getNormalizedActionBattleAttackProfile,
|
|
19
|
-
|
|
20
|
-
scheduleActionBattleStartup,
|
|
27
|
+
runActionBattleActiveHitbox,
|
|
21
28
|
} from "./core/attack-runtime";
|
|
29
|
+
import {
|
|
30
|
+
canActionBattleUseTarget,
|
|
31
|
+
executeActionBattleUse,
|
|
32
|
+
getActionBattleActionConfig,
|
|
33
|
+
handleActionBattleProjectileDestroy,
|
|
34
|
+
handleActionBattleProjectileImpact,
|
|
35
|
+
} from "./core/action-use";
|
|
22
36
|
import { normalizeActionBattleAttackProfile } from "./core/attack-profile";
|
|
23
|
-
import {
|
|
37
|
+
import {
|
|
38
|
+
resolveActionBattleWeapon,
|
|
39
|
+
resolveActionBattleWeaponAttackProfile,
|
|
40
|
+
} from "./core/equipment";
|
|
24
41
|
import type { ActionBattleHitbox } from "./core/contracts";
|
|
42
|
+
import {
|
|
43
|
+
canActionBattleTarget,
|
|
44
|
+
getActionBattleTargets,
|
|
45
|
+
} from "./core/targets";
|
|
25
46
|
import type {
|
|
26
47
|
ActionBattleAttackProfile,
|
|
27
48
|
NormalizedActionBattleAttackProfile,
|
|
@@ -82,6 +103,9 @@ const beginPlayerAttackLock = (
|
|
|
82
103
|
player.canMove = previousCanMove;
|
|
83
104
|
player.directionFixed = previousDirectionFixed;
|
|
84
105
|
player.animationFixed = previousAnimationFixed;
|
|
106
|
+
if (locks.movement && !previousAnimationFixed) {
|
|
107
|
+
forceActionBattleLocomotionAnimation(player, "stand");
|
|
108
|
+
}
|
|
85
109
|
}, durationMs);
|
|
86
110
|
|
|
87
111
|
return true;
|
|
@@ -98,12 +122,12 @@ const rectsOverlap = (
|
|
|
98
122
|
a.y < b.y + b.height &&
|
|
99
123
|
a.y + a.height > b.y;
|
|
100
124
|
|
|
101
|
-
const
|
|
125
|
+
const entityRect = (entity: RpgPlayer | RpgEvent | any) => {
|
|
102
126
|
const hitbox =
|
|
103
|
-
typeof
|
|
127
|
+
typeof entity.hitbox === "function" ? entity.hitbox() : entity.hitbox;
|
|
104
128
|
return {
|
|
105
|
-
x:
|
|
106
|
-
y:
|
|
129
|
+
x: entity.x(),
|
|
130
|
+
y: entity.y(),
|
|
107
131
|
width: hitbox?.w ?? 32,
|
|
108
132
|
height: hitbox?.h ?? 32,
|
|
109
133
|
};
|
|
@@ -143,7 +167,7 @@ const getVisibleActionEvents = (
|
|
|
143
167
|
}
|
|
144
168
|
|
|
145
169
|
for (const event of map.getEvents()) {
|
|
146
|
-
const rect =
|
|
170
|
+
const rect = entityRect(event);
|
|
147
171
|
if (hitboxes.some((hitbox) => rectsOverlap(hitbox, rect))) {
|
|
148
172
|
addEvent(event);
|
|
149
173
|
}
|
|
@@ -229,9 +253,19 @@ export function applyPlayerHitToEvent(
|
|
|
229
253
|
target: RpgEvent,
|
|
230
254
|
hooks?: ApplyHitHooks,
|
|
231
255
|
metadata?: Record<string, any>
|
|
256
|
+
): HitResult | undefined {
|
|
257
|
+
if (!(target as any).battleAi) return undefined;
|
|
258
|
+
return applyActionBattleEntityHit(player, target, hooks, metadata);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export function applyActionBattleEntityHit(
|
|
262
|
+
attacker: RpgPlayer | RpgEvent,
|
|
263
|
+
target: RpgPlayer | RpgEvent,
|
|
264
|
+
hooks?: ApplyHitHooks,
|
|
265
|
+
metadata?: Record<string, any>
|
|
232
266
|
): HitResult | undefined {
|
|
233
267
|
const ai = (target as any).battleAi as BattleAi;
|
|
234
|
-
if (!ai) return undefined;
|
|
268
|
+
if (target instanceof RpgEvent && !ai) return undefined;
|
|
235
269
|
|
|
236
270
|
const systems = getActionBattleSystems();
|
|
237
271
|
const result = applyActionBattleHit(
|
|
@@ -269,15 +303,15 @@ export function applyPlayerHitToEvent(
|
|
|
269
303
|
: systems.combat.hooks,
|
|
270
304
|
},
|
|
271
305
|
{
|
|
272
|
-
attacker
|
|
306
|
+
attacker,
|
|
273
307
|
target,
|
|
274
308
|
metadata,
|
|
275
309
|
reaction: metadata?.reaction,
|
|
276
310
|
}
|
|
277
311
|
);
|
|
278
312
|
|
|
279
|
-
if (!result.cancelled) {
|
|
280
|
-
ai.handleDamage(
|
|
313
|
+
if (!result.cancelled && ai) {
|
|
314
|
+
ai.handleDamage(attacker, {
|
|
281
315
|
damage: result.damage,
|
|
282
316
|
defeated: result.defeated,
|
|
283
317
|
raw: result.rawDamage,
|
|
@@ -329,6 +363,39 @@ const resolvePlayerAttackHitboxes = (
|
|
|
329
363
|
);
|
|
330
364
|
};
|
|
331
365
|
|
|
366
|
+
const getActionBattleHitboxCandidates = (
|
|
367
|
+
map: ReturnType<RpgPlayer["getCurrentMap"]> | undefined,
|
|
368
|
+
hitboxes: ActionBattleHitbox[],
|
|
369
|
+
options: { excludeIds?: string[]; kinds?: Array<"players" | "events"> } = {}
|
|
370
|
+
) => {
|
|
371
|
+
if (!map) return [];
|
|
372
|
+
if (typeof (map as any).queryHitbox === "function") {
|
|
373
|
+
const candidates = new Map<string, RpgPlayer | RpgEvent>();
|
|
374
|
+
for (const hitbox of hitboxes) {
|
|
375
|
+
for (const entity of (map as any).queryHitbox(hitbox, options)) {
|
|
376
|
+
if (entity?.id) candidates.set(entity.id, entity);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return Array.from(candidates.values());
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const candidates = new Map<string, RpgPlayer | RpgEvent>();
|
|
383
|
+
const excluded = new Set(options.excludeIds ?? []);
|
|
384
|
+
const add = (entity: RpgPlayer | RpgEvent | undefined) => {
|
|
385
|
+
if (!entity?.id) return;
|
|
386
|
+
if (excluded.has(entity.id)) return;
|
|
387
|
+
const rect = entityRect(entity);
|
|
388
|
+
if (hitboxes.some((hitbox) => rectsOverlap(hitbox, rect))) {
|
|
389
|
+
candidates.set(entity.id, entity);
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
const kinds = new Set(options.kinds ?? ["players", "events"]);
|
|
394
|
+
if (kinds.has("players")) map.getPlayers?.().forEach(add);
|
|
395
|
+
if (kinds.has("events")) map.getEvents?.().forEach(add);
|
|
396
|
+
return Array.from(candidates.values());
|
|
397
|
+
};
|
|
398
|
+
|
|
332
399
|
const mergeAttackProfileOverrides = (
|
|
333
400
|
base: NormalizedActionBattleAttackProfile,
|
|
334
401
|
override: ActionBattleAttackProfile
|
|
@@ -381,6 +448,16 @@ const resolveSkillData = (player: RpgPlayer, skillId: string) => {
|
|
|
381
448
|
}
|
|
382
449
|
};
|
|
383
450
|
|
|
451
|
+
const resolvePlayerSkillUsable = (player: RpgPlayer, skillId: string) => {
|
|
452
|
+
try {
|
|
453
|
+
return (
|
|
454
|
+
(player as any).getSkill?.(skillId) ?? resolveSkillData(player, skillId)
|
|
455
|
+
);
|
|
456
|
+
} catch {
|
|
457
|
+
return resolveSkillData(player, skillId);
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
|
|
384
461
|
const resolveSkillTargeting = (
|
|
385
462
|
player: RpgPlayer,
|
|
386
463
|
skillId: string,
|
|
@@ -552,11 +629,24 @@ const handleActionBattleSkillUse = (
|
|
|
552
629
|
target: { x: number; y: number } | undefined,
|
|
553
630
|
options: ActionBattleOptions
|
|
554
631
|
) => {
|
|
555
|
-
const skillData =
|
|
632
|
+
const skillData = resolvePlayerSkillUsable(player, skillId);
|
|
633
|
+
const actionConfig = getActionBattleActionConfig(skillData);
|
|
634
|
+
|
|
635
|
+
if (actionConfig?.target === "self") {
|
|
636
|
+
executeActionBattleUse({
|
|
637
|
+
attacker: player,
|
|
638
|
+
target: player,
|
|
639
|
+
usable: skillData,
|
|
640
|
+
skill: skillData,
|
|
641
|
+
});
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
556
644
|
|
|
557
645
|
const map = player.getCurrentMap();
|
|
558
646
|
if (!map) {
|
|
559
|
-
|
|
647
|
+
emitActionBattleClientVisual({
|
|
648
|
+
moment: "castSkill",
|
|
649
|
+
entity: player,
|
|
560
650
|
skill: skillData,
|
|
561
651
|
});
|
|
562
652
|
player.useSkill(skillId);
|
|
@@ -564,7 +654,9 @@ const handleActionBattleSkillUse = (
|
|
|
564
654
|
}
|
|
565
655
|
const targeting = resolveSkillTargeting(player, skillId, options);
|
|
566
656
|
if (!targeting || !target) {
|
|
567
|
-
|
|
657
|
+
emitActionBattleClientVisual({
|
|
658
|
+
moment: "castSkill",
|
|
659
|
+
entity: player,
|
|
568
660
|
skill: skillData,
|
|
569
661
|
});
|
|
570
662
|
player.useSkill(skillId);
|
|
@@ -590,11 +682,20 @@ const handleActionBattleSkillUse = (
|
|
|
590
682
|
});
|
|
591
683
|
|
|
592
684
|
const targets: any[] = [];
|
|
685
|
+
const actionTarget = actionConfig?.target ?? "enemy";
|
|
593
686
|
const affects = options.targeting?.affects || "events";
|
|
594
687
|
if (affects === "events" || affects === "both") {
|
|
595
688
|
map.getEvents().forEach((event: RpgEvent) => {
|
|
596
689
|
const tile = getEntityTile(event, tileSize);
|
|
597
|
-
if (
|
|
690
|
+
if (
|
|
691
|
+
affected.has(`${tile.x},${tile.y}`) &&
|
|
692
|
+
canActionBattleUseTarget(
|
|
693
|
+
player,
|
|
694
|
+
event,
|
|
695
|
+
actionTarget,
|
|
696
|
+
options.combat?.targets
|
|
697
|
+
)
|
|
698
|
+
) {
|
|
598
699
|
targets.push(event);
|
|
599
700
|
}
|
|
600
701
|
});
|
|
@@ -603,7 +704,15 @@ const handleActionBattleSkillUse = (
|
|
|
603
704
|
map.getPlayers().forEach((other: RpgPlayer) => {
|
|
604
705
|
if (other.id === player.id) return;
|
|
605
706
|
const tile = getEntityTile(other, tileSize);
|
|
606
|
-
if (
|
|
707
|
+
if (
|
|
708
|
+
affected.has(`${tile.x},${tile.y}`) &&
|
|
709
|
+
canActionBattleUseTarget(
|
|
710
|
+
player,
|
|
711
|
+
other,
|
|
712
|
+
actionTarget,
|
|
713
|
+
options.combat?.targets
|
|
714
|
+
)
|
|
715
|
+
) {
|
|
607
716
|
targets.push(other);
|
|
608
717
|
}
|
|
609
718
|
});
|
|
@@ -613,11 +722,12 @@ const handleActionBattleSkillUse = (
|
|
|
613
722
|
return;
|
|
614
723
|
}
|
|
615
724
|
|
|
616
|
-
|
|
725
|
+
executeActionBattleUse({
|
|
726
|
+
attacker: player,
|
|
727
|
+
target: targets,
|
|
728
|
+
usable: skillData,
|
|
617
729
|
skill: skillData,
|
|
618
|
-
target: targets[0],
|
|
619
730
|
});
|
|
620
|
-
player.useSkill(skillId, targets as any);
|
|
621
731
|
};
|
|
622
732
|
|
|
623
733
|
export const createActionBattleServer = (
|
|
@@ -642,20 +752,22 @@ export const createActionBattleServer = (
|
|
|
642
752
|
onInput(player: RpgPlayer, input: any) {
|
|
643
753
|
if (input.action == Control.Action) {
|
|
644
754
|
const map = player.getCurrentMap();
|
|
645
|
-
const direction = player
|
|
755
|
+
const direction = resolveActionBattleAttackDirection(player, input);
|
|
756
|
+
applyActionBattleAttackDirection(player, direction);
|
|
646
757
|
const attackProfile = resolvePlayerAttackProfile(player, options);
|
|
647
758
|
|
|
648
759
|
// Convert Direction enum to string key
|
|
649
760
|
const directionKey = direction as string;
|
|
650
761
|
|
|
651
|
-
const
|
|
762
|
+
const resolveActiveHitboxes = () => resolvePlayerAttackHitboxes(
|
|
652
763
|
player,
|
|
653
764
|
directionKey,
|
|
654
765
|
options,
|
|
655
766
|
attackProfile
|
|
656
767
|
);
|
|
768
|
+
const initialHitboxes = resolveActiveHitboxes();
|
|
657
769
|
|
|
658
|
-
if (isActionReservedForNormalEvent(player, map,
|
|
770
|
+
if (isActionReservedForNormalEvent(player, map, initialHitboxes)) {
|
|
659
771
|
return;
|
|
660
772
|
}
|
|
661
773
|
|
|
@@ -675,7 +787,12 @@ export const createActionBattleServer = (
|
|
|
675
787
|
return;
|
|
676
788
|
}
|
|
677
789
|
|
|
678
|
-
|
|
790
|
+
withActionBattleAnimationUnlocked(player, () => {
|
|
791
|
+
emitActionBattleClientVisual({
|
|
792
|
+
moment: "attack",
|
|
793
|
+
entity: player,
|
|
794
|
+
});
|
|
795
|
+
});
|
|
679
796
|
if (actionLocked) {
|
|
680
797
|
player.animationFixed = true;
|
|
681
798
|
}
|
|
@@ -683,53 +800,60 @@ export const createActionBattleServer = (
|
|
|
683
800
|
player.id,
|
|
684
801
|
attackProfile.id
|
|
685
802
|
);
|
|
803
|
+
const weapon = resolveActionBattleWeapon(player);
|
|
686
804
|
const hitTracker = new ActionBattleHitTracker(
|
|
687
805
|
attackProfile.hitPolicy
|
|
688
806
|
);
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
807
|
+
const targetSelector = getActionBattleTargets(player, "events");
|
|
808
|
+
|
|
809
|
+
const processHits = (hits: any[]) => {
|
|
810
|
+
hits.forEach((hit: any) => {
|
|
811
|
+
if (
|
|
812
|
+
!canActionBattleTarget(
|
|
813
|
+
player,
|
|
814
|
+
hit,
|
|
815
|
+
targetSelector,
|
|
816
|
+
options.combat?.targets
|
|
817
|
+
)
|
|
818
|
+
) {
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
if (!hitTracker.tryHit(hit)) return;
|
|
822
|
+
const handledByWeapon =
|
|
823
|
+
weapon &&
|
|
824
|
+
executeActionBattleUse({
|
|
825
|
+
attacker: player,
|
|
826
|
+
target: hit,
|
|
827
|
+
usable: weapon,
|
|
828
|
+
weapon,
|
|
829
|
+
profile: attackProfile,
|
|
830
|
+
playVisual: false,
|
|
831
|
+
});
|
|
832
|
+
if (handledByWeapon) return;
|
|
833
|
+
applyActionBattleEntityHit(player, hit, undefined, {
|
|
834
|
+
attackId,
|
|
835
|
+
attackProfileId: attackProfile.id,
|
|
836
|
+
reaction: attackProfile.reaction,
|
|
837
|
+
});
|
|
695
838
|
});
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
})
|
|
706
|
-
.subscribe({
|
|
707
|
-
next(hits: any[]) {
|
|
708
|
-
hits.forEach((hit: any) => {
|
|
709
|
-
if (hit instanceof RpgEvent) {
|
|
710
|
-
if (!hitTracker.tryHit(hit)) return;
|
|
711
|
-
const result = applyPlayerHitToEvent(
|
|
712
|
-
player,
|
|
713
|
-
hit,
|
|
714
|
-
undefined,
|
|
715
|
-
{
|
|
716
|
-
attackId,
|
|
717
|
-
attackProfileId: attackProfile.id,
|
|
718
|
-
reaction: attackProfile.reaction,
|
|
719
|
-
}
|
|
720
|
-
);
|
|
721
|
-
if (result?.defeated) {
|
|
722
|
-
console.log(`Player ${player.id} defeated AI ${hit.id}`);
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
});
|
|
726
|
-
},
|
|
839
|
+
};
|
|
840
|
+
|
|
841
|
+
runActionBattleActiveHitbox(
|
|
842
|
+
attackProfile,
|
|
843
|
+
resolveActiveHitboxes,
|
|
844
|
+
(activeHitboxes) => {
|
|
845
|
+
const candidates = getActionBattleHitboxCandidates(map, activeHitboxes, {
|
|
846
|
+
excludeIds: [player.id],
|
|
847
|
+
kinds: ["players", "events"],
|
|
727
848
|
});
|
|
728
|
-
|
|
849
|
+
processHits(candidates);
|
|
850
|
+
}
|
|
851
|
+
);
|
|
729
852
|
}
|
|
730
853
|
},
|
|
731
854
|
onConnected(player: RpgPlayer) {
|
|
732
|
-
|
|
855
|
+
const actionBar = options.ui?.actionBar as any;
|
|
856
|
+
if (actionBar?.enabled && actionBar?.autoOpen) {
|
|
733
857
|
openActionBattleActionBar(player, options);
|
|
734
858
|
}
|
|
735
859
|
},
|
|
@@ -765,6 +889,23 @@ export const createActionBattleServer = (
|
|
|
765
889
|
ai?.onDetectOutShape(player, shape);
|
|
766
890
|
},
|
|
767
891
|
},
|
|
892
|
+
projectiles: {
|
|
893
|
+
onImpact(context: any) {
|
|
894
|
+
handleActionBattleProjectileImpact({
|
|
895
|
+
attacker:
|
|
896
|
+
context.projectile?.payload?.attackerId
|
|
897
|
+
? context.map?.getObjectById?.(context.projectile.payload.attackerId)
|
|
898
|
+
: undefined,
|
|
899
|
+
target: context.target,
|
|
900
|
+
projectile: context.projectile,
|
|
901
|
+
hit: context.hit,
|
|
902
|
+
map: context.map,
|
|
903
|
+
} as any);
|
|
904
|
+
},
|
|
905
|
+
onDestroy(context: any) {
|
|
906
|
+
handleActionBattleProjectileDestroy(context.projectile?.id);
|
|
907
|
+
},
|
|
908
|
+
},
|
|
768
909
|
});
|
|
769
910
|
};
|
|
770
911
|
|
|
@@ -776,6 +917,7 @@ export {
|
|
|
776
917
|
createActionBattleAttackId,
|
|
777
918
|
getNormalizedActionBattleAttackProfile,
|
|
778
919
|
resolveActionBattleHitboxSpeed,
|
|
920
|
+
runActionBattleActiveHitbox,
|
|
779
921
|
scheduleActionBattleStartup,
|
|
780
922
|
} from "./core/attack-runtime";
|
|
781
923
|
export {
|
|
@@ -789,11 +931,31 @@ export type {
|
|
|
789
931
|
ActionBattleAttackHitboxMap,
|
|
790
932
|
ActionBattleAttackHitPolicy,
|
|
791
933
|
ActionBattleAttackProfile,
|
|
792
|
-
ActionBattleDebugOptions,
|
|
793
934
|
ActionBattleHitReactionProfile,
|
|
794
935
|
NormalizedActionBattleHitReactionProfile,
|
|
795
936
|
NormalizedActionBattleAttackProfile,
|
|
796
937
|
} from "./types";
|
|
938
|
+
export type {
|
|
939
|
+
ActionBattleActionConfig,
|
|
940
|
+
ActionBattleActionMode,
|
|
941
|
+
ActionBattleActionTarget,
|
|
942
|
+
ActionBattleProjectileImpactContext,
|
|
943
|
+
ActionBattleProjectileOptions,
|
|
944
|
+
ActionBattleTargetContext,
|
|
945
|
+
ActionBattleTargetOptions,
|
|
946
|
+
ActionBattleTargetSelector,
|
|
947
|
+
ActionBattleUsable,
|
|
948
|
+
ActionBattleUseContext,
|
|
949
|
+
} from "./core/contracts";
|
|
950
|
+
export {
|
|
951
|
+
canActionBattleUseTarget,
|
|
952
|
+
executeActionBattleUse,
|
|
953
|
+
getActionBattleActionConfig,
|
|
954
|
+
getActionBattleActionRange,
|
|
955
|
+
handleActionBattleProjectileDestroy,
|
|
956
|
+
handleActionBattleProjectileImpact,
|
|
957
|
+
shouldUseActionBattleUsable,
|
|
958
|
+
} from "./core/action-use";
|
|
797
959
|
export {
|
|
798
960
|
DEFAULT_ACTION_BATTLE_HIT_REACTION,
|
|
799
961
|
isActionBattleEntityInvincible,
|
|
@@ -807,7 +969,21 @@ export {
|
|
|
807
969
|
type ActionBattleEnemyAttackProfileMap,
|
|
808
970
|
type NormalizedActionBattleEnemyAttackProfileMap,
|
|
809
971
|
} from "./core/enemy-attack-profiles";
|
|
810
|
-
export {
|
|
972
|
+
export {
|
|
973
|
+
resolveActionBattleWeapon,
|
|
974
|
+
resolveActionBattleWeaponAttackProfile,
|
|
975
|
+
} from "./core/equipment";
|
|
976
|
+
export {
|
|
977
|
+
ACTION_BATTLE_ENEMY_FACTION,
|
|
978
|
+
ACTION_BATTLE_PLAYER_FACTION,
|
|
979
|
+
canActionBattleTarget,
|
|
980
|
+
getActionBattleFaction,
|
|
981
|
+
getActionBattleTargets,
|
|
982
|
+
isActionBattleCombatEntity,
|
|
983
|
+
isActionBattleEvent,
|
|
984
|
+
isActionBattlePlayer,
|
|
985
|
+
matchesActionBattleTargetSelector,
|
|
986
|
+
} from "./core/targets";
|
|
811
987
|
export {
|
|
812
988
|
AiDebug,
|
|
813
989
|
AiState,
|
package/src/types.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ActionBattleAiBehavior,
|
|
3
|
+
ActionBattleAiPreset,
|
|
4
|
+
ActionBattleTargetOptions,
|
|
3
5
|
ActionBattleCombatSystem,
|
|
4
6
|
ActionBattleHitHooks,
|
|
5
7
|
ActionBattleHitbox,
|
|
@@ -31,12 +33,8 @@ export type ActionBattleAnimationResult =
|
|
|
31
33
|
| undefined;
|
|
32
34
|
|
|
33
35
|
export type ActionBattleAnimationEntity = {
|
|
34
|
-
setGraphicAnimation(
|
|
35
|
-
|
|
36
|
-
animationName: string,
|
|
37
|
-
graphic: string | string[],
|
|
38
|
-
repeat: number
|
|
39
|
-
): void;
|
|
36
|
+
setGraphicAnimation?: (...args: any[]) => unknown;
|
|
37
|
+
setAnimation?: (...args: any[]) => unknown;
|
|
40
38
|
[key: string]: any;
|
|
41
39
|
};
|
|
42
40
|
|
|
@@ -67,28 +65,6 @@ export type ActionBattleSkillTargetingResolver = (
|
|
|
67
65
|
skill: any
|
|
68
66
|
) => ActionBattleSkillTargeting | null | undefined;
|
|
69
67
|
|
|
70
|
-
export interface ActionBattleUiActionBarOptions {
|
|
71
|
-
enabled?: boolean;
|
|
72
|
-
autoOpen?: boolean;
|
|
73
|
-
mode?: ActionBattleActionBarMode;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export interface ActionBattleUiTargetingOptions {
|
|
77
|
-
enabled?: boolean;
|
|
78
|
-
showGrid?: boolean;
|
|
79
|
-
tileSize?: { width: number; height: number };
|
|
80
|
-
colors?: {
|
|
81
|
-
area?: number;
|
|
82
|
-
edge?: number;
|
|
83
|
-
cursor?: number;
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export interface ActionBattleUiOptions {
|
|
88
|
-
actionBar?: ActionBattleUiActionBarOptions;
|
|
89
|
-
targeting?: ActionBattleUiTargetingOptions;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
68
|
export type ActionBattleAttackDirection =
|
|
93
69
|
| "up"
|
|
94
70
|
| "down"
|
|
@@ -145,6 +121,7 @@ export interface NormalizedActionBattleAttackProfile
|
|
|
145
121
|
}
|
|
146
122
|
|
|
147
123
|
export interface ActionBattleSkillOptions {
|
|
124
|
+
targeting?: ActionBattleSkillTargetingResolver;
|
|
148
125
|
getTargeting?: ActionBattleSkillTargetingResolver;
|
|
149
126
|
defaultAoeMask?: ActionBattleAoeMask;
|
|
150
127
|
}
|
|
@@ -154,10 +131,6 @@ export interface ActionBattleTargetingOptions {
|
|
|
154
131
|
allowEmptyTarget?: boolean;
|
|
155
132
|
}
|
|
156
133
|
|
|
157
|
-
export interface ActionBattleDebugOptions {
|
|
158
|
-
attacks?: boolean;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
134
|
export interface ActionBattleAttackOptions {
|
|
162
135
|
profile?: ActionBattleAttackProfile;
|
|
163
136
|
lockMovement?: boolean;
|
|
@@ -175,26 +148,123 @@ export interface ActionBattleAttackOptions {
|
|
|
175
148
|
}
|
|
176
149
|
|
|
177
150
|
export interface ActionBattleCombatOptions {
|
|
151
|
+
attack?: ActionBattleAttackOptions;
|
|
178
152
|
damage?: ActionBattleCombatSystem["resolveDamage"];
|
|
179
153
|
knockback?: ActionBattleCombatSystem["resolveKnockback"];
|
|
180
154
|
hooks?: ActionBattleHitHooks;
|
|
155
|
+
targets?: ActionBattleTargetOptions;
|
|
181
156
|
}
|
|
182
157
|
|
|
183
|
-
export interface
|
|
158
|
+
export interface ActionBattleAiOptions {
|
|
184
159
|
behaviors?: Record<string, ActionBattleAiBehavior>;
|
|
160
|
+
presets?: Record<string, ActionBattleAiPreset>;
|
|
185
161
|
}
|
|
186
162
|
|
|
163
|
+
export type ActionBattleAiSystemOptions = ActionBattleAiOptions;
|
|
164
|
+
|
|
187
165
|
export interface ActionBattleSystemOptions {
|
|
188
166
|
combat?: ActionBattleCombatOptions;
|
|
189
|
-
ai?:
|
|
167
|
+
ai?: ActionBattleAiOptions;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export type ActionBattleVisualMoment =
|
|
171
|
+
| "attack"
|
|
172
|
+
| "castSkill"
|
|
173
|
+
| "hit"
|
|
174
|
+
| "hurt"
|
|
175
|
+
| "defeat"
|
|
176
|
+
| "preview";
|
|
177
|
+
|
|
178
|
+
export interface ActionBattleVisualContext {
|
|
179
|
+
moment: ActionBattleVisualMoment;
|
|
180
|
+
entity?: any;
|
|
181
|
+
target?: any;
|
|
182
|
+
attacker?: any;
|
|
183
|
+
damage?: number;
|
|
184
|
+
defeated?: boolean;
|
|
185
|
+
result?: any;
|
|
186
|
+
skill?: any;
|
|
187
|
+
pattern?: string;
|
|
188
|
+
animations?: ActionBattleAnimationOptions;
|
|
189
|
+
animationDefaults?: {
|
|
190
|
+
animationName?: string;
|
|
191
|
+
repeat?: number;
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export interface ActionBattleVisualHelpers {
|
|
196
|
+
graphic(entity: any, keyOrOptions: ActionBattleAnimationKey | ActionBattleAnimationResult): void;
|
|
197
|
+
flash(entity: any, options?: Record<string, any>): void;
|
|
198
|
+
damageText(entity: any, damageOrText?: number | string): void;
|
|
199
|
+
component(entity: any, id: string, params?: Record<string, any>): void;
|
|
200
|
+
preview(entity: any, options?: Record<string, any>): void;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export type ActionBattleVisualPart = (
|
|
204
|
+
context: ActionBattleVisualContext,
|
|
205
|
+
helpers: ActionBattleVisualHelpers
|
|
206
|
+
) => void;
|
|
207
|
+
|
|
208
|
+
export type ActionBattleVisualComposer = (
|
|
209
|
+
context: ActionBattleVisualContext
|
|
210
|
+
) => void;
|
|
211
|
+
|
|
212
|
+
export type ActionBattleVisualPreset = "classic" | "fx" | "none";
|
|
213
|
+
|
|
214
|
+
export type ActionBattleVisualInput =
|
|
215
|
+
| ActionBattleVisualPreset
|
|
216
|
+
| ActionBattleVisualComposer
|
|
217
|
+
| Partial<Record<ActionBattleVisualMoment, ActionBattleVisualPart>>;
|
|
218
|
+
|
|
219
|
+
export interface ActionBattleUiActionBarOptions {
|
|
220
|
+
enabled?: boolean;
|
|
221
|
+
autoOpen?: boolean;
|
|
222
|
+
mode?: ActionBattleActionBarMode;
|
|
223
|
+
component?: any;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export interface ActionBattleUiTargetingOptions {
|
|
227
|
+
enabled?: boolean;
|
|
228
|
+
component?: any;
|
|
229
|
+
showGrid?: boolean;
|
|
230
|
+
tileSize?: { width: number; height: number };
|
|
231
|
+
colors?: {
|
|
232
|
+
area?: number;
|
|
233
|
+
edge?: number;
|
|
234
|
+
cursor?: number;
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export interface ActionBattleUiAttackPreviewOptions {
|
|
239
|
+
enabled?: boolean;
|
|
240
|
+
component?: any;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export interface ActionBattleUiGuiEntry {
|
|
244
|
+
id: string;
|
|
245
|
+
component: any;
|
|
246
|
+
dependencies?: Function;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export interface ActionBattleUiOptions {
|
|
250
|
+
actionBar?: boolean | ActionBattleUiActionBarOptions;
|
|
251
|
+
targeting?: boolean | ActionBattleUiTargetingOptions;
|
|
252
|
+
attackPreview?: boolean | ActionBattleUiAttackPreviewOptions;
|
|
253
|
+
gui?: ActionBattleUiGuiEntry[];
|
|
254
|
+
spriteComponents?: {
|
|
255
|
+
front?: any[];
|
|
256
|
+
back?: any[];
|
|
257
|
+
} | any[];
|
|
190
258
|
}
|
|
191
259
|
|
|
192
260
|
export interface ActionBattleOptions {
|
|
261
|
+
combat?: ActionBattleCombatOptions;
|
|
262
|
+
visual?: ActionBattleVisualInput;
|
|
193
263
|
ui?: ActionBattleUiOptions;
|
|
264
|
+
ai?: ActionBattleAiOptions;
|
|
194
265
|
skills?: ActionBattleSkillOptions;
|
|
195
266
|
targeting?: ActionBattleTargetingOptions;
|
|
196
267
|
attack?: ActionBattleAttackOptions;
|
|
197
|
-
debug?: ActionBattleDebugOptions;
|
|
198
268
|
animations?: ActionBattleAnimationOptions;
|
|
199
269
|
systems?: ActionBattleSystemOptions;
|
|
200
270
|
}
|