@rpgjs/action-battle 5.0.0-beta.5 → 5.0.0-beta.7
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 +161 -22
- package/dist/ai.server.d.ts +55 -4
- package/dist/client/index.js +13 -8
- package/dist/client/index10.js +54 -136
- package/dist/client/index11.js +52 -23
- package/dist/client/index12.js +101 -1217
- package/dist/client/index13.js +139 -42
- package/dist/client/index14.js +23 -8
- package/dist/client/index15.js +68 -444
- 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 +25 -87
- package/dist/client/index20.js +504 -0
- package/dist/client/index3.js +45 -83
- package/dist/client/index4.js +98 -297
- package/dist/client/index5.js +81 -33
- package/dist/client/index6.js +284 -78
- package/dist/client/index7.js +33 -74
- package/dist/client/index8.js +95 -55
- package/dist/client/index9.js +75 -96
- package/dist/core/attack-profile.d.ts +9 -0
- package/dist/core/attack-runtime.d.ts +20 -0
- package/dist/core/enemy-attack-profiles.d.ts +6 -0
- package/dist/core/equipment.d.ts +2 -0
- package/dist/core/hit-reaction.d.ts +5 -0
- package/dist/index.d.ts +7 -2
- package/dist/server/index.js +12 -7
- package/dist/server/index10.js +1340 -8
- 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 +1 -1
- package/dist/server/index3.js +25 -87
- package/dist/server/index4.js +45 -141
- package/dist/server/index5.js +104 -21
- package/dist/server/index6.js +137 -1215
- package/dist/server/index7.js +22 -34
- package/dist/server/index8.js +70 -44
- package/dist/server/index9.js +44 -437
- package/dist/server.d.ts +8 -2
- package/dist/ui/state.d.ts +5 -5
- package/package.json +5 -5
- package/src/ai.server.spec.ts +120 -0
- package/src/ai.server.ts +362 -56
- package/src/client.ts +21 -12
- package/src/config.ts +17 -2
- 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/contracts.ts +3 -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 +54 -1
- package/src/core/hit.ts +26 -0
- package/src/index.ts +48 -1
- package/src/server.ts +192 -34
- package/src/types.ts +62 -6
package/README.md
CHANGED
|
@@ -231,6 +231,24 @@ new BattleAi(event, {
|
|
|
231
231
|
AttackPattern.Combo,
|
|
232
232
|
AttackPattern.DashAttack
|
|
233
233
|
],
|
|
234
|
+
|
|
235
|
+
// Per-pattern enemy attack timing and reactions
|
|
236
|
+
attackProfiles: {
|
|
237
|
+
charged: {
|
|
238
|
+
startupMs: 900,
|
|
239
|
+
activeMs: 140,
|
|
240
|
+
recoveryMs: 300,
|
|
241
|
+
reaction: {
|
|
242
|
+
hitstunMs: 240,
|
|
243
|
+
staggerPower: 2
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
|
|
248
|
+
// Hit reaction tuning
|
|
249
|
+
poise: 1,
|
|
250
|
+
hitstunMs: 150,
|
|
251
|
+
invincibilityMs: 250,
|
|
234
252
|
|
|
235
253
|
// Patrol waypoints (for idle state)
|
|
236
254
|
patrolWaypoints: [
|
|
@@ -242,13 +260,18 @@ new BattleAi(event, {
|
|
|
242
260
|
groupBehavior: true,
|
|
243
261
|
|
|
244
262
|
// Callback when AI is defeated
|
|
245
|
-
onDefeated: (event, attacker) => {
|
|
263
|
+
onDefeated: ({ event, attacker }) => {
|
|
246
264
|
const name = attacker?.name?.() ?? "Unknown";
|
|
247
265
|
console.log(`${event.name()} was defeated by ${name}!`);
|
|
248
266
|
}
|
|
249
267
|
});
|
|
250
268
|
```
|
|
251
269
|
|
|
270
|
+
`attackProfiles` lets enemies telegraph attacks with `startupMs`, keep hitboxes
|
|
271
|
+
active for `activeMs`, and apply hit reactions. `poise` controls interruption:
|
|
272
|
+
an incoming hit only stuns the enemy when its `reaction.staggerPower` is greater
|
|
273
|
+
than or equal to the enemy's `poise`.
|
|
274
|
+
|
|
252
275
|
## Enemy Types
|
|
253
276
|
|
|
254
277
|
Types modify AI **behavior** (cooldowns, ranges, dodge), not stats:
|
|
@@ -607,6 +630,98 @@ Player attacks are resolved with `createMovingHitbox()` instead of a passive
|
|
|
607
630
|
contact collision. You can still customize the generated hitboxes with
|
|
608
631
|
`attack.hitboxes` or `attack.resolveHitboxes`.
|
|
609
632
|
|
|
633
|
+
### Attack profile model
|
|
634
|
+
|
|
635
|
+
Use `attack.profile` to describe the timing model of a player attack in one
|
|
636
|
+
typed object. A profile separates the attack into startup, active, and recovery
|
|
637
|
+
phases so combat systems can share the same vocabulary.
|
|
638
|
+
|
|
639
|
+
```ts
|
|
640
|
+
import { provideActionBattle } from "@rpgjs/action-battle/server";
|
|
641
|
+
|
|
642
|
+
export default provideActionBattle({
|
|
643
|
+
attack: {
|
|
644
|
+
profile: {
|
|
645
|
+
id: "iron-sword",
|
|
646
|
+
startupMs: 80,
|
|
647
|
+
activeMs: 120,
|
|
648
|
+
recoveryMs: 180,
|
|
649
|
+
cooldownMs: 380,
|
|
650
|
+
movementLock: true,
|
|
651
|
+
directionLock: true,
|
|
652
|
+
animationKey: "attack",
|
|
653
|
+
hitPolicy: "oncePerTarget",
|
|
654
|
+
reaction: {
|
|
655
|
+
invincibilityMs: 250,
|
|
656
|
+
hitstunMs: 150,
|
|
657
|
+
staggerPower: 1
|
|
658
|
+
},
|
|
659
|
+
hitboxes: {
|
|
660
|
+
right: { offsetX: 18, offsetY: -18, width: 42, height: 36 }
|
|
661
|
+
}
|
|
662
|
+
},
|
|
663
|
+
lockDurationMs: 380
|
|
664
|
+
}
|
|
665
|
+
});
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
The default profile mirrors the legacy attack lock: no startup, a short active
|
|
669
|
+
window, and recovery that totals `350ms`. The player attack runtime uses
|
|
670
|
+
`startupMs` before creating the hitbox, `activeMs` to keep the hitbox active,
|
|
671
|
+
and `totalDurationMs` for movement and direction locks. `hitPolicy:
|
|
672
|
+
"oncePerTarget"` prevents the same attack window from damaging the same target
|
|
673
|
+
multiple times.
|
|
674
|
+
|
|
675
|
+
`reaction` describes what happens after the hit connects:
|
|
676
|
+
|
|
677
|
+
- `invincibilityMs`: temporary invincibility after damage.
|
|
678
|
+
- `hitstunMs`: stun duration requested by the hit.
|
|
679
|
+
- `staggerPower`: value compared against enemy `poise`.
|
|
680
|
+
|
|
681
|
+
```ts
|
|
682
|
+
import {
|
|
683
|
+
normalizeActionBattleAttackProfile,
|
|
684
|
+
type ActionBattleAttackProfile
|
|
685
|
+
} from "@rpgjs/action-battle/server";
|
|
686
|
+
|
|
687
|
+
const sword: ActionBattleAttackProfile = {
|
|
688
|
+
id: "sword",
|
|
689
|
+
startupMs: 70,
|
|
690
|
+
activeMs: 110,
|
|
691
|
+
recoveryMs: 170
|
|
692
|
+
};
|
|
693
|
+
|
|
694
|
+
const normalized = normalizeActionBattleAttackProfile(sword);
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
Equipped weapons can override the player attack profile:
|
|
698
|
+
|
|
699
|
+
```ts
|
|
700
|
+
const Dagger = {
|
|
701
|
+
id: "dagger",
|
|
702
|
+
name: "Dagger",
|
|
703
|
+
_type: "weapon" as const,
|
|
704
|
+
atk: 8,
|
|
705
|
+
knockbackForce: 20,
|
|
706
|
+
attackProfile: {
|
|
707
|
+
id: "dagger",
|
|
708
|
+
startupMs: 40,
|
|
709
|
+
activeMs: 70,
|
|
710
|
+
recoveryMs: 110
|
|
711
|
+
}
|
|
712
|
+
};
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
Enable lightweight attack logs while tuning profiles:
|
|
716
|
+
|
|
717
|
+
```ts
|
|
718
|
+
provideActionBattle({
|
|
719
|
+
debug: {
|
|
720
|
+
attacks: true
|
|
721
|
+
}
|
|
722
|
+
});
|
|
723
|
+
```
|
|
724
|
+
|
|
610
725
|
When the action targets a normal event with no `BattleAi`, the server lets the
|
|
611
726
|
event handle `onAction` and does not create the combat hitbox. Enemy events
|
|
612
727
|
with `BattleAi` still trigger the A-RPG attack.
|
|
@@ -724,8 +839,9 @@ new BattleAi(this, {
|
|
|
724
839
|
});
|
|
725
840
|
```
|
|
726
841
|
|
|
727
|
-
`waitEnd: true`
|
|
728
|
-
|
|
842
|
+
`waitEnd: true` uses the default defeated transition timeout. Use `delayMs`
|
|
843
|
+
when you need an exact duration. The visual transition itself is handled by the
|
|
844
|
+
client `sprite.onBeforeRemove` hook.
|
|
729
845
|
|
|
730
846
|
## Knockback System
|
|
731
847
|
|
|
@@ -877,25 +993,57 @@ console.log(`Player knockback force: ${force}`);
|
|
|
877
993
|
|
|
878
994
|
## onDefeated Hook
|
|
879
995
|
|
|
880
|
-
The `onDefeated` callback is triggered when an AI enemy is killed.
|
|
996
|
+
The `onDefeated` callback is triggered when an AI enemy is killed. The simplest
|
|
997
|
+
reward flow is configured directly on `BattleAi`; the reward is given to the
|
|
998
|
+
player who landed the killing blow.
|
|
999
|
+
|
|
1000
|
+
```typescript
|
|
1001
|
+
new BattleAi(this, {
|
|
1002
|
+
enemyType: EnemyType.Aggressive,
|
|
1003
|
+
animations: {
|
|
1004
|
+
die: {
|
|
1005
|
+
animationName: "die",
|
|
1006
|
+
graphic: "goblin_die",
|
|
1007
|
+
repeat: 1,
|
|
1008
|
+
delayMs: 700
|
|
1009
|
+
}
|
|
1010
|
+
},
|
|
1011
|
+
rewards: {
|
|
1012
|
+
exp: 50,
|
|
1013
|
+
gold: 25,
|
|
1014
|
+
items: [{ itemId: "health_potion", amount: 1, chance: 30 }],
|
|
1015
|
+
showNotification: true
|
|
1016
|
+
}
|
|
1017
|
+
});
|
|
1018
|
+
```
|
|
1019
|
+
|
|
1020
|
+
On defeat, `BattleAi` stops the AI, awards configured rewards once, and calls
|
|
1021
|
+
`event.remove({ reason: "defeated", transition })`. The client can use
|
|
1022
|
+
`sprite.onBeforeRemove` to play the `die` transition before the sprite
|
|
1023
|
+
disappears.
|
|
1024
|
+
|
|
1025
|
+
`onDefeated` receives a context object in new code:
|
|
881
1026
|
- Award experience, gold, or items to the player
|
|
882
1027
|
- Spawn loot drops
|
|
883
1028
|
- Trigger events or cutscenes
|
|
884
1029
|
- Update quest progress
|
|
885
|
-
- Play death
|
|
1030
|
+
- Play death sounds
|
|
886
1031
|
|
|
887
1032
|
### Basic Usage
|
|
888
1033
|
|
|
889
1034
|
```typescript
|
|
890
1035
|
new BattleAi(this, {
|
|
891
1036
|
enemyType: EnemyType.Aggressive,
|
|
892
|
-
onDefeated: (event, attacker) => {
|
|
1037
|
+
onDefeated: ({ event, attacker }) => {
|
|
893
1038
|
const name = attacker?.name?.() ?? "Unknown";
|
|
894
1039
|
console.log(`${event.name()} was defeated by ${name}!`);
|
|
895
1040
|
}
|
|
896
1041
|
});
|
|
897
1042
|
```
|
|
898
1043
|
|
|
1044
|
+
The legacy `(event, attacker)` callback signature is still supported for
|
|
1045
|
+
two-argument callbacks.
|
|
1046
|
+
|
|
899
1047
|
### Award Rewards on Kill
|
|
900
1048
|
|
|
901
1049
|
```typescript
|
|
@@ -910,19 +1058,10 @@ function Goblin() {
|
|
|
910
1058
|
|
|
911
1059
|
new BattleAi(this, {
|
|
912
1060
|
enemyType: EnemyType.Aggressive,
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
attacker.gold += 25;
|
|
918
|
-
|
|
919
|
-
// Award experience
|
|
920
|
-
attacker.exp += 50;
|
|
921
|
-
|
|
922
|
-
// Random loot drop
|
|
923
|
-
if (Math.random() < 0.3) {
|
|
924
|
-
attacker.addItem(HealthPotion);
|
|
925
|
-
}
|
|
1061
|
+
rewards: {
|
|
1062
|
+
gold: 25,
|
|
1063
|
+
exp: 50,
|
|
1064
|
+
items: [{ item: HealthPotion, amount: 1, chance: 30 }]
|
|
926
1065
|
}
|
|
927
1066
|
});
|
|
928
1067
|
}
|
|
@@ -934,7 +1073,7 @@ function Goblin() {
|
|
|
934
1073
|
|
|
935
1074
|
```typescript
|
|
936
1075
|
new BattleAi(this, {
|
|
937
|
-
onDefeated: (event
|
|
1076
|
+
onDefeated: ({ event }) => {
|
|
938
1077
|
const map = event.getCurrentMap();
|
|
939
1078
|
if (!map) return;
|
|
940
1079
|
|
|
@@ -954,7 +1093,7 @@ new BattleAi(this, {
|
|
|
954
1093
|
let killCount = 0;
|
|
955
1094
|
|
|
956
1095
|
new BattleAi(this, {
|
|
957
|
-
onDefeated: (
|
|
1096
|
+
onDefeated: () => {
|
|
958
1097
|
killCount++;
|
|
959
1098
|
|
|
960
1099
|
// Check quest progress
|
|
@@ -978,7 +1117,7 @@ function DragonBoss() {
|
|
|
978
1117
|
|
|
979
1118
|
new BattleAi(this, {
|
|
980
1119
|
enemyType: EnemyType.Tank,
|
|
981
|
-
onDefeated: (event
|
|
1120
|
+
onDefeated: ({ event }) => {
|
|
982
1121
|
const map = event.getCurrentMap();
|
|
983
1122
|
|
|
984
1123
|
// Announce victory
|
package/dist/ai.server.d.ts
CHANGED
|
@@ -1,10 +1,35 @@
|
|
|
1
1
|
import { RpgEvent, RpgPlayer } from '@rpgjs/server';
|
|
2
|
+
import { ActionBattleEnemyAttackProfileMap } from './core/enemy-attack-profiles';
|
|
2
3
|
import { ActionBattleDamageResult } from './core/contracts';
|
|
3
|
-
import { ActionBattleAnimationOptions } from './types';
|
|
4
|
+
import { NormalizedActionBattleHitReactionProfile, ActionBattleAnimationOptions } from './types';
|
|
4
5
|
type RpgEventWithBattleAi = RpgEvent & {
|
|
5
6
|
battleAi?: BattleAi;
|
|
6
7
|
};
|
|
7
|
-
export interface
|
|
8
|
+
export interface BattleAiRewardItem {
|
|
9
|
+
item?: any;
|
|
10
|
+
itemId?: string;
|
|
11
|
+
amount?: number;
|
|
12
|
+
chance?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface BattleAiRewards {
|
|
15
|
+
exp?: number;
|
|
16
|
+
gold?: number;
|
|
17
|
+
items?: Array<BattleAiRewardItem | string>;
|
|
18
|
+
showNotification?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface BattleAiDefeatReward {
|
|
21
|
+
readonly awarded: boolean;
|
|
22
|
+
giveTo(player?: RpgPlayer | null): void;
|
|
23
|
+
}
|
|
24
|
+
export interface BattleAiDefeatedContext {
|
|
25
|
+
event: RpgEvent;
|
|
26
|
+
attacker?: RpgPlayer;
|
|
27
|
+
reward: BattleAiDefeatReward;
|
|
28
|
+
remove: () => void;
|
|
29
|
+
}
|
|
30
|
+
export type BattleAiDefeatedCallback = (context: BattleAiDefeatedContext) => void;
|
|
31
|
+
export type BattleAiLegacyDefeatedCallback = (event: RpgEvent, attacker?: RpgPlayer) => void;
|
|
32
|
+
export interface BattleAiBaseOptions {
|
|
8
33
|
enemyType?: EnemyType;
|
|
9
34
|
attackCooldown?: number;
|
|
10
35
|
visionRange?: number;
|
|
@@ -14,6 +39,7 @@ export interface BattleAiOptions {
|
|
|
14
39
|
fleeThreshold?: number;
|
|
15
40
|
attackSkill?: any;
|
|
16
41
|
attackPatterns?: AttackPattern[];
|
|
42
|
+
attackProfiles?: ActionBattleEnemyAttackProfileMap;
|
|
17
43
|
patrolWaypoints?: Array<{
|
|
18
44
|
x: number;
|
|
19
45
|
y: number;
|
|
@@ -21,6 +47,9 @@ export interface BattleAiOptions {
|
|
|
21
47
|
groupBehavior?: boolean;
|
|
22
48
|
moveToCooldown?: number;
|
|
23
49
|
retreatCooldown?: number;
|
|
50
|
+
poise?: number;
|
|
51
|
+
hitstunMs?: number;
|
|
52
|
+
invincibilityMs?: number;
|
|
24
53
|
behavior?: {
|
|
25
54
|
baseScore?: number;
|
|
26
55
|
updateInterval?: number;
|
|
@@ -30,8 +59,16 @@ export interface BattleAiOptions {
|
|
|
30
59
|
};
|
|
31
60
|
behaviorKey?: string;
|
|
32
61
|
animations?: ActionBattleAnimationOptions;
|
|
62
|
+
rewards?: BattleAiRewards;
|
|
63
|
+
autoAwardRewards?: boolean;
|
|
64
|
+
}
|
|
65
|
+
export interface BattleAiOptions extends BattleAiBaseOptions {
|
|
33
66
|
/** Callback called when the AI is defeated */
|
|
34
|
-
onDefeated?:
|
|
67
|
+
onDefeated?: BattleAiDefeatedCallback;
|
|
68
|
+
}
|
|
69
|
+
export interface BattleAiLegacyOptions extends BattleAiBaseOptions {
|
|
70
|
+
/** @deprecated Use the context callback signature instead. */
|
|
71
|
+
onDefeated?: BattleAiLegacyDefeatedCallback;
|
|
35
72
|
}
|
|
36
73
|
/**
|
|
37
74
|
* Hit result data returned after applying damage
|
|
@@ -252,6 +289,7 @@ export declare class BattleAi {
|
|
|
252
289
|
private fleeThreshold;
|
|
253
290
|
private attackSkill;
|
|
254
291
|
private attackPatterns;
|
|
292
|
+
private attackProfiles;
|
|
255
293
|
private animations?;
|
|
256
294
|
private comboCount;
|
|
257
295
|
private comboMax;
|
|
@@ -266,6 +304,9 @@ export declare class BattleAi {
|
|
|
266
304
|
private damageCheckInterval;
|
|
267
305
|
private isMovingToTarget;
|
|
268
306
|
private onDefeatedCallback?;
|
|
307
|
+
private rewards?;
|
|
308
|
+
private autoAwardRewards;
|
|
309
|
+
private defeated;
|
|
269
310
|
private lastFacingDirection;
|
|
270
311
|
private behaviorScore;
|
|
271
312
|
private behaviorMode;
|
|
@@ -281,6 +322,9 @@ export declare class BattleAi {
|
|
|
281
322
|
private lastRetreatTime;
|
|
282
323
|
private timers;
|
|
283
324
|
private behaviorKey?;
|
|
325
|
+
private poise;
|
|
326
|
+
private hitstunMs;
|
|
327
|
+
private invincibilityMs;
|
|
284
328
|
/**
|
|
285
329
|
* Create a new Battle AI Controller
|
|
286
330
|
*
|
|
@@ -306,6 +350,7 @@ export declare class BattleAi {
|
|
|
306
350
|
* ```
|
|
307
351
|
*/
|
|
308
352
|
constructor(event: RpgEventWithBattleAi, options?: BattleAiOptions);
|
|
353
|
+
constructor(event: RpgEventWithBattleAi, options?: BattleAiLegacyOptions);
|
|
309
354
|
/**
|
|
310
355
|
* Apply enemy type-specific behavior modifiers
|
|
311
356
|
*
|
|
@@ -362,6 +407,7 @@ export declare class BattleAi {
|
|
|
362
407
|
* Uses skill if configured, otherwise creates hitbox
|
|
363
408
|
*/
|
|
364
409
|
private performMeleeAttack;
|
|
410
|
+
private executeMeleeAttack;
|
|
365
411
|
/**
|
|
366
412
|
* Perform basic hitbox attack when no skill is set
|
|
367
413
|
*/
|
|
@@ -429,6 +475,9 @@ export declare class BattleAi {
|
|
|
429
475
|
* Perform dash attack
|
|
430
476
|
*/
|
|
431
477
|
private performDashAttack;
|
|
478
|
+
private getAttackProfile;
|
|
479
|
+
private telegraphAttack;
|
|
480
|
+
private scheduleAttackStartup;
|
|
432
481
|
/**
|
|
433
482
|
* Face the current target with hysteresis to prevent animation flickering
|
|
434
483
|
*
|
|
@@ -487,7 +536,9 @@ export declare class BattleAi {
|
|
|
487
536
|
* The actual damage is applied externally via RPGJS API.
|
|
488
537
|
*/
|
|
489
538
|
takeDamage(attacker: RpgPlayer): boolean;
|
|
490
|
-
handleDamage(attacker: RpgPlayer, damageResult: ActionBattleDamageResult
|
|
539
|
+
handleDamage(attacker: RpgPlayer, damageResult: ActionBattleDamageResult & {
|
|
540
|
+
reaction?: NormalizedActionBattleHitReactionProfile;
|
|
541
|
+
}): boolean;
|
|
491
542
|
/**
|
|
492
543
|
* Kill this AI
|
|
493
544
|
*
|
package/dist/client/index.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
1
|
+
import { DEFAULT_ACTION_BATTLE_HIT_REACTION, isActionBattleEntityInvincible, normalizeActionBattleHitReaction, setActionBattleInvincibility } from "./index2.js";
|
|
2
|
+
import { DEFAULT_ACTION_BATTLE_ATTACK_PROFILE, normalizeActionBattleAttackProfile } from "./index3.js";
|
|
3
|
+
import { ACTION_BATTLE_HITBOX_FRAME_MS, ActionBattleHitTracker, createActionBattleAttackId, getNormalizedActionBattleAttackProfile, resolveActionBattleHitboxSpeed, scheduleActionBattleStartup } from "./index11.js";
|
|
4
|
+
import client_default, { createActionBattleClient } from "./index12.js";
|
|
5
|
+
import { DEFAULT_ZELDA_PLAYER_HITBOXES, createDefaultPlayerHitboxResolver, defaultCombatSystem, defaultEnemyBehaviors, defaultKnockbackResolver, defaultRpgjsDamageResolver } from "./index13.js";
|
|
6
|
+
import { createActionBattleSystems, getActionBattleSystems } from "./index14.js";
|
|
7
|
+
import { DEFAULT_ACTION_BATTLE_ENEMY_ATTACK_PROFILES, normalizeActionBattleEnemyAttackProfiles } from "./index15.js";
|
|
8
|
+
import { AiDebug, AiState, AttackPattern, BattleAi, DEFAULT_KNOCKBACK, EnemyType } from "./index16.js";
|
|
9
|
+
import { resolveActionBattleWeaponAttackProfile } from "./index17.js";
|
|
10
|
+
import { applyActionBattleHit } from "./index18.js";
|
|
11
|
+
import { createActionEnemy } from "./index19.js";
|
|
12
|
+
import { ACTION_BATTLE_ACTION_BAR_GUI_ID, DEFAULT_PLAYER_ATTACK_HITBOXES, applyPlayerHitToEvent, createActionBattleServer, getPlayerWeaponKnockbackForce, openActionBattleActionBar, updateActionBattleActionBar } from "./index20.js";
|
|
8
13
|
import { createModule } from "@rpgjs/common";
|
|
9
14
|
//#region src/index.ts
|
|
10
15
|
var server = null;
|
|
@@ -20,4 +25,4 @@ var src_default = {
|
|
|
20
25
|
client: client_default
|
|
21
26
|
};
|
|
22
27
|
//#endregion
|
|
23
|
-
export { ACTION_BATTLE_ACTION_BAR_GUI_ID, AiDebug, AiState, AttackPattern, BattleAi, DEFAULT_KNOCKBACK, DEFAULT_PLAYER_ATTACK_HITBOXES, DEFAULT_ZELDA_PLAYER_HITBOXES, EnemyType, applyActionBattleHit, applyPlayerHitToEvent, createActionBattleServer, createActionBattleSystems, createActionEnemy, createDefaultPlayerHitboxResolver, src_default as default, defaultCombatSystem, defaultEnemyBehaviors, defaultKnockbackResolver, defaultRpgjsDamageResolver, getActionBattleSystems, getPlayerWeaponKnockbackForce, openActionBattleActionBar, provideActionBattle, updateActionBattleActionBar };
|
|
28
|
+
export { ACTION_BATTLE_ACTION_BAR_GUI_ID, ACTION_BATTLE_HITBOX_FRAME_MS, ActionBattleHitTracker, AiDebug, AiState, AttackPattern, BattleAi, DEFAULT_ACTION_BATTLE_ATTACK_PROFILE, DEFAULT_ACTION_BATTLE_ENEMY_ATTACK_PROFILES, DEFAULT_ACTION_BATTLE_HIT_REACTION, DEFAULT_KNOCKBACK, DEFAULT_PLAYER_ATTACK_HITBOXES, DEFAULT_ZELDA_PLAYER_HITBOXES, EnemyType, applyActionBattleHit, applyPlayerHitToEvent, createActionBattleAttackId, createActionBattleServer, createActionBattleSystems, createActionEnemy, createDefaultPlayerHitboxResolver, src_default as default, defaultCombatSystem, defaultEnemyBehaviors, defaultKnockbackResolver, defaultRpgjsDamageResolver, getActionBattleSystems, getNormalizedActionBattleAttackProfile, getPlayerWeaponKnockbackForce, isActionBattleEntityInvincible, normalizeActionBattleAttackProfile, normalizeActionBattleEnemyAttackProfiles, normalizeActionBattleHitReaction, openActionBattleActionBar, provideActionBattle, resolveActionBattleHitboxSpeed, resolveActionBattleWeaponAttackProfile, scheduleActionBattleStartup, setActionBattleInvincibility, updateActionBattleActionBar };
|
package/dist/client/index10.js
CHANGED
|
@@ -1,143 +1,61 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
|
1
|
+
var DEFAULT_ANIMATION_BY_KEY = {
|
|
2
|
+
attack: "attack",
|
|
3
|
+
hurt: "hurt",
|
|
4
|
+
die: "die",
|
|
5
|
+
castSkill: "skill",
|
|
6
|
+
castSpell: "skill"
|
|
7
|
+
};
|
|
8
|
+
var getConfiguredAnimation = (key, animations) => {
|
|
9
|
+
if (!animations) return {
|
|
10
|
+
hasConfiguredAnimation: false,
|
|
11
|
+
configured: void 0
|
|
12
|
+
};
|
|
13
|
+
const hasConfiguredAnimation = Object.prototype.hasOwnProperty.call(animations, key);
|
|
14
|
+
if (hasConfiguredAnimation) return {
|
|
15
|
+
hasConfiguredAnimation,
|
|
16
|
+
configured: animations[key]
|
|
17
|
+
};
|
|
18
|
+
if (key === "castSkill") return {
|
|
19
|
+
hasConfiguredAnimation: Object.prototype.hasOwnProperty.call(animations, "castSpell"),
|
|
20
|
+
configured: animations.castSpell
|
|
69
21
|
};
|
|
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
22
|
return {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
raw
|
|
23
|
+
hasConfiguredAnimation: false,
|
|
24
|
+
configured: void 0
|
|
88
25
|
};
|
|
89
26
|
};
|
|
90
|
-
|
|
91
|
-
const
|
|
27
|
+
function resolveActionBattleAnimation(key, entity, animations, context, defaults = {}) {
|
|
28
|
+
const defaultAnimationName = defaults.animationName ?? DEFAULT_ANIMATION_BY_KEY[key];
|
|
29
|
+
const defaultRepeat = defaults.repeat ?? 1;
|
|
30
|
+
const { hasConfiguredAnimation, configured: configuredAnimation } = getConfiguredAnimation(key, animations);
|
|
31
|
+
if (!hasConfiguredAnimation && key !== "attack") return null;
|
|
32
|
+
const configured = hasConfiguredAnimation ? configuredAnimation : defaultAnimationName;
|
|
33
|
+
const result = typeof configured === "function" ? configured(entity, context) : configured;
|
|
34
|
+
if (result == null) return null;
|
|
35
|
+
if (typeof result === "string") return {
|
|
36
|
+
animationName: result,
|
|
37
|
+
repeat: defaultRepeat,
|
|
38
|
+
waitEnd: false
|
|
39
|
+
};
|
|
92
40
|
return {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
41
|
+
animationName: result.animationName ?? defaultAnimationName,
|
|
42
|
+
graphic: result.graphic,
|
|
43
|
+
repeat: result.repeat ?? defaultRepeat,
|
|
44
|
+
waitEnd: result.waitEnd ?? false,
|
|
45
|
+
delayMs: result.delayMs
|
|
96
46
|
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
-
};
|
|
47
|
+
}
|
|
48
|
+
function playActionBattleAnimation(key, entity, animations, context, defaults = {}) {
|
|
49
|
+
const animation = resolveActionBattleAnimation(key, entity, animations, context, defaults);
|
|
50
|
+
if (!animation) return null;
|
|
51
|
+
if (animation.graphic !== void 0) entity.setGraphicAnimation(animation.animationName, animation.graphic, animation.repeat);
|
|
52
|
+
else entity.setGraphicAnimation(animation.animationName, animation.repeat);
|
|
53
|
+
return animation;
|
|
54
|
+
}
|
|
55
|
+
function getActionBattleAnimationRemovalDelay(animation) {
|
|
56
|
+
if (!animation) return 0;
|
|
57
|
+
if (animation.delayMs !== void 0) return animation.delayMs;
|
|
58
|
+
return animation.waitEnd ? 500 : 0;
|
|
59
|
+
}
|
|
142
60
|
//#endregion
|
|
143
|
-
export {
|
|
61
|
+
export { getActionBattleAnimationRemovalDelay, playActionBattleAnimation, resolveActionBattleAnimation };
|