@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.
Files changed (103) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/LICENSE +19 -0
  3. package/README.md +392 -22
  4. package/dist/{ai.server.d.ts → client/ai.server.d.ts} +90 -28
  5. package/dist/client/animations.d.ts +16 -0
  6. package/dist/{client.d.ts → client/client.d.ts} +3 -2
  7. package/dist/{config.d.ts → client/config.d.ts} +2 -0
  8. package/dist/client/core/attack-profile.d.ts +9 -0
  9. package/dist/client/core/attack-runtime.d.ts +20 -0
  10. package/dist/client/core/context.d.ts +5 -0
  11. package/dist/client/core/defaults.d.ts +81 -0
  12. package/dist/client/core/enemy-attack-profiles.d.ts +6 -0
  13. package/dist/client/core/equipment.d.ts +2 -0
  14. package/dist/client/core/hit-reaction.d.ts +5 -0
  15. package/dist/client/core/hit.d.ts +2 -0
  16. package/dist/client/enemies/factory.d.ts +7 -0
  17. package/dist/client/index.d.ts +21 -0
  18. package/dist/client/index.js +24 -31
  19. package/dist/client/index10.js +61 -0
  20. package/dist/client/index11.js +55 -0
  21. package/dist/client/index12.js +106 -0
  22. package/dist/client/index13.js +143 -0
  23. package/dist/client/index14.js +25 -0
  24. package/dist/client/index15.js +72 -0
  25. package/dist/client/index16.js +1343 -0
  26. package/dist/client/index17.js +13 -0
  27. package/dist/client/index18.js +60 -0
  28. package/dist/client/index19.js +10 -0
  29. package/dist/client/index2.js +30 -45
  30. package/dist/client/index20.js +504 -0
  31. package/dist/client/index3.js +45 -1288
  32. package/dist/client/index4.js +105 -330
  33. package/dist/client/index5.js +84 -291
  34. package/dist/client/index6.js +309 -95
  35. package/dist/client/index7.js +35 -59
  36. package/dist/client/index8.js +101 -54
  37. package/dist/client/index9.js +79 -30
  38. package/dist/{server.d.ts → client/server.d.ts} +12 -4
  39. package/dist/client/ui/state.d.ts +35 -0
  40. package/dist/server/ai.server.d.ts +569 -0
  41. package/dist/server/animations.d.ts +16 -0
  42. package/dist/server/config.d.ts +5 -0
  43. package/dist/server/core/attack-profile.d.ts +9 -0
  44. package/dist/server/core/attack-runtime.d.ts +20 -0
  45. package/dist/server/core/context.d.ts +5 -0
  46. package/dist/server/core/defaults.d.ts +81 -0
  47. package/dist/server/core/enemy-attack-profiles.d.ts +6 -0
  48. package/dist/server/core/equipment.d.ts +2 -0
  49. package/dist/server/core/hit-reaction.d.ts +5 -0
  50. package/dist/server/core/hit.d.ts +2 -0
  51. package/dist/server/enemies/factory.d.ts +7 -0
  52. package/dist/server/index.d.ts +21 -0
  53. package/dist/server/index.js +23 -31
  54. package/dist/server/index10.js +1342 -0
  55. package/dist/server/index11.js +37 -0
  56. package/dist/server/index12.js +60 -0
  57. package/dist/server/index13.js +13 -0
  58. package/dist/server/index14.js +503 -0
  59. package/dist/server/index15.js +10 -0
  60. package/dist/server/index2.js +59 -332
  61. package/dist/server/index3.js +29 -1286
  62. package/dist/server/index4.js +45 -53
  63. package/dist/server/index5.js +107 -29
  64. package/dist/server/index6.js +143 -0
  65. package/dist/server/index7.js +25 -0
  66. package/dist/server/index8.js +72 -0
  67. package/dist/server/index9.js +55 -0
  68. package/dist/server/server.d.ts +106 -0
  69. package/dist/server/targeting.d.ts +19 -0
  70. package/package.json +12 -12
  71. package/src/ai.server.spec.ts +120 -0
  72. package/src/ai.server.ts +515 -91
  73. package/src/animations.ts +149 -0
  74. package/src/canvas-engine-shim.ts +4 -0
  75. package/src/client.ts +130 -2
  76. package/src/components/action-bar.ce +5 -3
  77. package/src/components/attack-preview.ce +90 -0
  78. package/src/config.ts +61 -0
  79. package/src/core/attack-profile.spec.ts +118 -0
  80. package/src/core/attack-profile.ts +100 -0
  81. package/src/core/attack-runtime.spec.ts +103 -0
  82. package/src/core/attack-runtime.ts +83 -0
  83. package/src/core/context.ts +35 -0
  84. package/src/core/contracts.ts +126 -0
  85. package/src/core/defaults.ts +162 -0
  86. package/src/core/enemy-attack-profiles.spec.ts +35 -0
  87. package/src/core/enemy-attack-profiles.ts +103 -0
  88. package/src/core/equipment.spec.ts +37 -0
  89. package/src/core/equipment.ts +17 -0
  90. package/src/core/hit-reaction.spec.ts +43 -0
  91. package/src/core/hit-reaction.ts +70 -0
  92. package/src/core/hit.spec.ts +111 -0
  93. package/src/core/hit.ts +92 -0
  94. package/src/enemies/factory.ts +25 -0
  95. package/src/index.ts +94 -1
  96. package/src/server.ts +427 -93
  97. package/src/targeting.spec.ts +24 -0
  98. package/src/types/canvas-engine.d.ts +4 -0
  99. package/src/types.ts +148 -0
  100. package/src/ui/state.ts +57 -0
  101. package/dist/index.d.ts +0 -11
  102. package/dist/ui/state.d.ts +0 -18
  103. /package/dist/{targeting.d.ts → client/targeting.d.ts} +0 -0
@@ -1,7 +1,75 @@
1
1
  import { RpgEvent, RpgPlayer } from '@rpgjs/server';
2
+ import { ActionBattleEnemyAttackProfileMap } from './core/enemy-attack-profiles';
3
+ import { ActionBattleDamageResult } from './core/contracts';
4
+ import { NormalizedActionBattleHitReactionProfile, ActionBattleAnimationOptions } from './types';
2
5
  type RpgEventWithBattleAi = RpgEvent & {
3
- battleAi: BattleAi;
6
+ battleAi?: BattleAi;
4
7
  };
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 {
33
+ enemyType?: EnemyType;
34
+ attackCooldown?: number;
35
+ visionRange?: number;
36
+ attackRange?: number;
37
+ dodgeChance?: number;
38
+ dodgeCooldown?: number;
39
+ fleeThreshold?: number;
40
+ attackSkill?: any;
41
+ attackPatterns?: AttackPattern[];
42
+ attackProfiles?: ActionBattleEnemyAttackProfileMap;
43
+ patrolWaypoints?: Array<{
44
+ x: number;
45
+ y: number;
46
+ }>;
47
+ groupBehavior?: boolean;
48
+ moveToCooldown?: number;
49
+ retreatCooldown?: number;
50
+ poise?: number;
51
+ hitstunMs?: number;
52
+ invincibilityMs?: number;
53
+ behavior?: {
54
+ baseScore?: number;
55
+ updateInterval?: number;
56
+ minStateDuration?: number;
57
+ assaultThreshold?: number;
58
+ retreatThreshold?: number;
59
+ };
60
+ behaviorKey?: string;
61
+ animations?: ActionBattleAnimationOptions;
62
+ rewards?: BattleAiRewards;
63
+ autoAwardRewards?: boolean;
64
+ }
65
+ export interface BattleAiOptions extends BattleAiBaseOptions {
66
+ /** Callback called when the AI is defeated */
67
+ onDefeated?: BattleAiDefeatedCallback;
68
+ }
69
+ export interface BattleAiLegacyOptions extends BattleAiBaseOptions {
70
+ /** @deprecated Use the context callback signature instead. */
71
+ onDefeated?: BattleAiLegacyDefeatedCallback;
72
+ }
5
73
  /**
6
74
  * Hit result data returned after applying damage
7
75
  *
@@ -221,6 +289,8 @@ export declare class BattleAi {
221
289
  private fleeThreshold;
222
290
  private attackSkill;
223
291
  private attackPatterns;
292
+ private attackProfiles;
293
+ private animations?;
224
294
  private comboCount;
225
295
  private comboMax;
226
296
  private chargingAttack;
@@ -234,6 +304,9 @@ export declare class BattleAi {
234
304
  private damageCheckInterval;
235
305
  private isMovingToTarget;
236
306
  private onDefeatedCallback?;
307
+ private rewards?;
308
+ private autoAwardRewards;
309
+ private defeated;
237
310
  private lastFacingDirection;
238
311
  private behaviorScore;
239
312
  private behaviorMode;
@@ -247,6 +320,11 @@ export declare class BattleAi {
247
320
  private lastMoveToTime;
248
321
  private retreatCooldown;
249
322
  private lastRetreatTime;
323
+ private timers;
324
+ private behaviorKey?;
325
+ private poise;
326
+ private hitstunMs;
327
+ private invincibilityMs;
250
328
  /**
251
329
  * Create a new Battle AI Controller
252
330
  *
@@ -271,33 +349,8 @@ export declare class BattleAi {
271
349
  * });
272
350
  * ```
273
351
  */
274
- constructor(event: RpgEventWithBattleAi, options?: {
275
- enemyType?: EnemyType;
276
- attackCooldown?: number;
277
- visionRange?: number;
278
- attackRange?: number;
279
- dodgeChance?: number;
280
- dodgeCooldown?: number;
281
- fleeThreshold?: number;
282
- attackSkill?: any;
283
- attackPatterns?: AttackPattern[];
284
- patrolWaypoints?: Array<{
285
- x: number;
286
- y: number;
287
- }>;
288
- groupBehavior?: boolean;
289
- moveToCooldown?: number;
290
- retreatCooldown?: number;
291
- behavior?: {
292
- baseScore?: number;
293
- updateInterval?: number;
294
- minStateDuration?: number;
295
- assaultThreshold?: number;
296
- retreatThreshold?: number;
297
- };
298
- /** Callback called when the AI is defeated */
299
- onDefeated?: (event: RpgEvent, attacker?: RpgPlayer) => void;
300
- });
352
+ constructor(event: RpgEventWithBattleAi, options?: BattleAiOptions);
353
+ constructor(event: RpgEventWithBattleAi, options?: BattleAiLegacyOptions);
301
354
  /**
302
355
  * Apply enemy type-specific behavior modifiers
303
356
  *
@@ -354,6 +407,7 @@ export declare class BattleAi {
354
407
  * Uses skill if configured, otherwise creates hitbox
355
408
  */
356
409
  private performMeleeAttack;
410
+ private executeMeleeAttack;
357
411
  /**
358
412
  * Perform basic hitbox attack when no skill is set
359
413
  */
@@ -421,6 +475,9 @@ export declare class BattleAi {
421
475
  * Perform dash attack
422
476
  */
423
477
  private performDashAttack;
478
+ private getAttackProfile;
479
+ private telegraphAttack;
480
+ private scheduleAttackStartup;
424
481
  /**
425
482
  * Face the current target with hysteresis to prevent animation flickering
426
483
  *
@@ -479,6 +536,9 @@ export declare class BattleAi {
479
536
  * The actual damage is applied externally via RPGJS API.
480
537
  */
481
538
  takeDamage(attacker: RpgPlayer): boolean;
539
+ handleDamage(attacker: RpgPlayer, damageResult: ActionBattleDamageResult & {
540
+ reaction?: NormalizedActionBattleHitReactionProfile;
541
+ }): boolean;
482
542
  /**
483
543
  * Kill this AI
484
544
  *
@@ -491,9 +551,11 @@ export declare class BattleAi {
491
551
  */
492
552
  private getDistance;
493
553
  private updateBehavior;
554
+ private applyCustomBehavior;
494
555
  private handleTacticalMovement;
495
556
  private handleAssaultMovement;
496
557
  private requestMoveTo;
558
+ private schedule;
497
559
  getHealth(): number;
498
560
  getMaxHealth(): number;
499
561
  getTarget(): InstanceType<typeof RpgPlayer> | null;
@@ -0,0 +1,16 @@
1
+ import { ActionBattleAnimationContext, ActionBattleAnimationEntity, ActionBattleAnimationKey, ActionBattleAnimationOptions } from './types';
2
+ export declare const DEFAULT_DIE_ANIMATION_DELAY_MS = 500;
3
+ export interface ResolvedActionBattleAnimation {
4
+ animationName: string;
5
+ graphic?: string | string[];
6
+ repeat: number;
7
+ waitEnd: boolean;
8
+ delayMs?: number;
9
+ }
10
+ export interface ActionBattleAnimationDefaults {
11
+ animationName?: string;
12
+ repeat?: number;
13
+ }
14
+ export declare function resolveActionBattleAnimation(key: ActionBattleAnimationKey, entity: ActionBattleAnimationEntity, animations?: ActionBattleAnimationOptions, context?: ActionBattleAnimationContext, defaults?: ActionBattleAnimationDefaults): ResolvedActionBattleAnimation | null;
15
+ export declare function playActionBattleAnimation(key: ActionBattleAnimationKey, entity: ActionBattleAnimationEntity, animations?: ActionBattleAnimationOptions, context?: ActionBattleAnimationContext, defaults?: ActionBattleAnimationDefaults): ResolvedActionBattleAnimation | null;
16
+ export declare function getActionBattleAnimationRemovalDelay(animation: ResolvedActionBattleAnimation | null): number;
@@ -1,4 +1,5 @@
1
+ import { RpgClient } from '@rpgjs/client';
1
2
  import { ActionBattleOptions } from './types';
2
- export declare const createActionBattleClient: (options?: ActionBattleOptions) => any;
3
- declare const _default: any;
3
+ export declare const createActionBattleClient: (options?: ActionBattleOptions) => RpgClient;
4
+ declare const _default: RpgClient;
4
5
  export default _default;
@@ -1,3 +1,5 @@
1
1
  import { ActionBattleOptions } from './types';
2
2
  export declare const DEFAULT_ACTION_BATTLE_OPTIONS: ActionBattleOptions;
3
3
  export declare function normalizeActionBattleOptions(options?: ActionBattleOptions): ActionBattleOptions;
4
+ export declare function setActionBattleOptions(options: ActionBattleOptions): void;
5
+ export declare function getActionBattleOptions(): ActionBattleOptions;
@@ -0,0 +1,9 @@
1
+ import { ActionBattleAttackHitboxMap, ActionBattleAttackProfile, NormalizedActionBattleAttackProfile } from '../types';
2
+ export declare const DEFAULT_ACTION_BATTLE_ATTACK_PROFILE: NormalizedActionBattleAttackProfile;
3
+ export interface ActionBattleAttackProfileFallbacks {
4
+ id?: string;
5
+ lockMovement?: boolean;
6
+ lockDurationMs?: number;
7
+ hitboxes?: ActionBattleAttackHitboxMap;
8
+ }
9
+ export declare function normalizeActionBattleAttackProfile(profile?: ActionBattleAttackProfile | undefined, fallbacks?: ActionBattleAttackProfileFallbacks): NormalizedActionBattleAttackProfile;
@@ -0,0 +1,20 @@
1
+ import { ActionBattleAttackHitPolicy, ActionBattleOptions, NormalizedActionBattleAttackProfile } from '../types';
2
+ export declare const ACTION_BATTLE_HITBOX_FRAME_MS = 16;
3
+ export declare function getNormalizedActionBattleAttackProfile(options?: ActionBattleOptions): NormalizedActionBattleAttackProfile;
4
+ export declare function resolveActionBattleHitboxSpeed(profile: NormalizedActionBattleAttackProfile, hitboxCount: number): number;
5
+ export declare function scheduleActionBattleStartup(profile: NormalizedActionBattleAttackProfile, callback: () => void, scheduler?: (callback: () => void, delayMs: number) => unknown): unknown;
6
+ export declare function createActionBattleAttackId(attackerId: string | number | undefined, profileId: string): string;
7
+ export declare class ActionBattleHitTracker {
8
+ private readonly hitPolicy;
9
+ private hitTargets;
10
+ constructor(hitPolicy: ActionBattleAttackHitPolicy);
11
+ canHit(target: {
12
+ id?: string | number;
13
+ } | undefined): boolean;
14
+ recordHit(target: {
15
+ id?: string | number;
16
+ } | undefined): void;
17
+ tryHit(target: {
18
+ id?: string | number;
19
+ } | undefined): boolean;
20
+ }
@@ -0,0 +1,5 @@
1
+ import { ActionBattleOptions } from '../types';
2
+ import { ActionBattleSystems } from './contracts';
3
+ export declare const setActionBattleSystems: (options?: ActionBattleOptions) => void;
4
+ export declare const getActionBattleSystems: () => ActionBattleSystems;
5
+ export declare const createActionBattleSystems: (options?: ActionBattleOptions) => ActionBattleSystems;
@@ -0,0 +1,81 @@
1
+ import { RpgPlayer } from '@rpgjs/server';
2
+ import { ActionBattleAiBehavior, ActionBattleAttackContext, ActionBattleCombatSystem, ActionBattleDamageContext, ActionBattleKnockbackContext, ActionBattleKnockbackResult, ActionBattleSystems } from './contracts';
3
+ export declare const DEFAULT_ZELDA_PLAYER_HITBOXES: {
4
+ up: {
5
+ offsetX: number;
6
+ offsetY: number;
7
+ width: number;
8
+ height: number;
9
+ };
10
+ down: {
11
+ offsetX: number;
12
+ offsetY: number;
13
+ width: number;
14
+ height: number;
15
+ };
16
+ left: {
17
+ offsetX: number;
18
+ offsetY: number;
19
+ width: number;
20
+ height: number;
21
+ };
22
+ right: {
23
+ offsetX: number;
24
+ offsetY: number;
25
+ width: number;
26
+ height: number;
27
+ };
28
+ default: {
29
+ offsetX: number;
30
+ offsetY: number;
31
+ width: number;
32
+ height: number;
33
+ };
34
+ };
35
+ export declare const createDefaultPlayerHitboxResolver: (hitboxes?: {
36
+ up: {
37
+ offsetX: number;
38
+ offsetY: number;
39
+ width: number;
40
+ height: number;
41
+ };
42
+ down: {
43
+ offsetX: number;
44
+ offsetY: number;
45
+ width: number;
46
+ height: number;
47
+ };
48
+ left: {
49
+ offsetX: number;
50
+ offsetY: number;
51
+ width: number;
52
+ height: number;
53
+ };
54
+ right: {
55
+ offsetX: number;
56
+ offsetY: number;
57
+ width: number;
58
+ height: number;
59
+ };
60
+ default: {
61
+ offsetX: number;
62
+ offsetY: number;
63
+ width: number;
64
+ height: number;
65
+ };
66
+ }) => (context: ActionBattleAttackContext) => {
67
+ x: any;
68
+ y: any;
69
+ width: number;
70
+ height: number;
71
+ }[];
72
+ export declare const defaultRpgjsDamageResolver: (context: ActionBattleDamageContext) => {
73
+ damage: any;
74
+ defeated: boolean;
75
+ raw: any;
76
+ };
77
+ export declare const defaultKnockbackResolver: (context: ActionBattleKnockbackContext) => ActionBattleKnockbackResult;
78
+ export declare const defaultCombatSystem: ActionBattleCombatSystem;
79
+ export declare const defaultEnemyBehaviors: Record<string, ActionBattleAiBehavior>;
80
+ export declare const defaultActionBattleSystems: ActionBattleSystems;
81
+ export declare const getEntityWeaponKnockbackForce: (entity: RpgPlayer) => number;
@@ -0,0 +1,6 @@
1
+ import { ActionBattleAttackProfile, NormalizedActionBattleAttackProfile } from '../types';
2
+ export type ActionBattleEnemyAttackProfileKey = "melee" | "combo" | "charged" | "zone" | "dashAttack";
3
+ export declare const DEFAULT_ACTION_BATTLE_ENEMY_ATTACK_PROFILES: Record<ActionBattleEnemyAttackProfileKey, ActionBattleAttackProfile>;
4
+ export type ActionBattleEnemyAttackProfileMap = Partial<Record<ActionBattleEnemyAttackProfileKey, ActionBattleAttackProfile>>;
5
+ export type NormalizedActionBattleEnemyAttackProfileMap = Record<ActionBattleEnemyAttackProfileKey, NormalizedActionBattleAttackProfile>;
6
+ export declare function normalizeActionBattleEnemyAttackProfiles(overrides?: ActionBattleEnemyAttackProfileMap): NormalizedActionBattleEnemyAttackProfileMap;
@@ -0,0 +1,2 @@
1
+ import { ActionBattleAttackProfile } from '../types';
2
+ export declare function resolveActionBattleWeaponAttackProfile(entity: any): ActionBattleAttackProfile | null;
@@ -0,0 +1,5 @@
1
+ import { ActionBattleHitReactionProfile, NormalizedActionBattleHitReactionProfile } from '../types';
2
+ export declare const DEFAULT_ACTION_BATTLE_HIT_REACTION: NormalizedActionBattleHitReactionProfile;
3
+ export declare function normalizeActionBattleHitReaction(reaction: ActionBattleHitReactionProfile | undefined, defaults?: NormalizedActionBattleHitReactionProfile): NormalizedActionBattleHitReactionProfile;
4
+ export declare function isActionBattleEntityInvincible(entity: any, now?: number): boolean;
5
+ export declare function setActionBattleInvincibility(entity: any, durationMs: number, now?: number): void;
@@ -0,0 +1,2 @@
1
+ import { ActionBattleCombatSystem, ActionBattleHitContext, ActionBattleHitResult } from './contracts';
2
+ export declare const applyActionBattleHit: (system: ActionBattleCombatSystem, context: ActionBattleHitContext) => ActionBattleHitResult;
@@ -0,0 +1,7 @@
1
+ import { RpgEvent } from '@rpgjs/server';
2
+ import { BattleAi, BattleAiOptions } from '../ai.server';
3
+ export interface ActionBattleEnemyPreset extends BattleAiOptions {
4
+ stats?: (event: RpgEvent) => void;
5
+ }
6
+ export type ActionBattleEnemyPresetMap = Record<string, ActionBattleEnemyPreset>;
7
+ export declare const createActionEnemy: (event: RpgEvent, presetOrOptions: string | BattleAiOptions, presets?: ActionBattleEnemyPresetMap) => BattleAi;
@@ -0,0 +1,21 @@
1
+ import { ActionBattleOptions } from './types';
2
+ export { BattleAi, AiState, EnemyType, AttackPattern, AiDebug, DEFAULT_KNOCKBACK } from './ai.server';
3
+ export type { HitResult, ApplyHitHooks, BattleAiOptions, BattleAiDefeatedCallback, BattleAiDefeatedContext, BattleAiDefeatReward, BattleAiLegacyDefeatedCallback, BattleAiLegacyOptions, BattleAiRewardItem, BattleAiRewards, } from './ai.server';
4
+ export type { ActionBattleAnimationContext, ActionBattleAnimationEntity, ActionBattleAnimationKey, ActionBattleAnimationOptions, ActionBattleAnimationResolver, ActionBattleAnimationResult, ActionBattleOptions, ActionBattleActionBarData, ActionBattleActionBarItem, ActionBattleActionBarSkill, ActionBattleSkillTargeting, ActionBattleSkillTargetingResolver, ActionBattleAttackOptions, ActionBattleUiOptions, ActionBattleUiActionBarOptions, ActionBattleUiTargetingOptions, ActionBattleAttackDirection, ActionBattleAttackHitboxConfig, ActionBattleAttackHitboxMap, ActionBattleAttackHitPolicy, ActionBattleAttackProfile, ActionBattleDebugOptions, ActionBattleHitReactionProfile, NormalizedActionBattleHitReactionProfile, NormalizedActionBattleAttackProfile, ActionBattleCombatOptions, ActionBattleSystemOptions, ActionBattleAiSystemOptions, } from './types';
5
+ export type { ActionBattleAiBehavior, ActionBattleAiContext, ActionBattleAiDecision, ActionBattleAttackContext, ActionBattleCombatSystem, ActionBattleDamageContext, ActionBattleDamageResult, ActionBattleDirection, ActionBattleEntity, ActionBattleHitContext, ActionBattleHitHooks, ActionBattleHitResult, ActionBattleHitbox, ActionBattleKnockbackContext, ActionBattleKnockbackResult, ActionBattleSystems, } from './core/contracts';
6
+ export { DEFAULT_ACTION_BATTLE_ATTACK_PROFILE, normalizeActionBattleAttackProfile, type ActionBattleAttackProfileFallbacks, } from './core/attack-profile';
7
+ export { ACTION_BATTLE_HITBOX_FRAME_MS, ActionBattleHitTracker, createActionBattleAttackId, getNormalizedActionBattleAttackProfile, resolveActionBattleHitboxSpeed, scheduleActionBattleStartup, } from './core/attack-runtime';
8
+ export { DEFAULT_ACTION_BATTLE_HIT_REACTION, isActionBattleEntityInvincible, normalizeActionBattleHitReaction, setActionBattleInvincibility, } from './core/hit-reaction';
9
+ export { DEFAULT_ACTION_BATTLE_ENEMY_ATTACK_PROFILES, normalizeActionBattleEnemyAttackProfiles, type ActionBattleEnemyAttackProfileKey, type ActionBattleEnemyAttackProfileMap, type NormalizedActionBattleEnemyAttackProfileMap, } from './core/enemy-attack-profiles';
10
+ export { resolveActionBattleWeaponAttackProfile } from './core/equipment';
11
+ export { DEFAULT_ZELDA_PLAYER_HITBOXES, createDefaultPlayerHitboxResolver, defaultCombatSystem, defaultEnemyBehaviors, defaultKnockbackResolver, defaultRpgjsDamageResolver, } from './core/defaults';
12
+ export { createActionBattleSystems, getActionBattleSystems, } from './core/context';
13
+ export { applyActionBattleHit } from './core/hit';
14
+ export { createActionEnemy, type ActionBattleEnemyPreset, type ActionBattleEnemyPresetMap, } from './enemies/factory';
15
+ export { DEFAULT_PLAYER_ATTACK_HITBOXES, getPlayerWeaponKnockbackForce, applyPlayerHitToEvent, ACTION_BATTLE_ACTION_BAR_GUI_ID, openActionBattleActionBar, updateActionBattleActionBar, createActionBattleServer, } from './server';
16
+ export declare function provideActionBattle(options?: ActionBattleOptions): any[];
17
+ declare const _default: {
18
+ server: import('@rpgjs/server').RpgServer;
19
+ client: import('@rpgjs/client').RpgClient;
20
+ };
21
+ export default _default;
@@ -1,35 +1,28 @@
1
- import client, { createActionBattleClient } from "./index2.js";
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";
2
13
  import { createModule } from "@rpgjs/common";
3
- import { AiDebug, AiState, AttackPattern, BattleAi, DEFAULT_KNOCKBACK, EnemyType } from "./index3.js";
4
- import { ACTION_BATTLE_ACTION_BAR_GUI_ID, DEFAULT_PLAYER_ATTACK_HITBOXES, applyPlayerHitToEvent, createActionBattleServer, getPlayerWeaponKnockbackForce, openActionBattleActionBar, updateActionBattleActionBar } from "./index4.js";
5
- const server = null;
6
- const createActionBattleServer2 = null;
14
+ //#region src/index.ts
15
+ var server = null;
16
+ var createActionBattleServer$1 = null;
7
17
  function provideActionBattle(options = {}) {
8
- return createModule("ActionBattle", [
9
- {
10
- server: createActionBattleServer2?.(options),
11
- client: createActionBattleClient?.(options)
12
- }
13
- ]);
18
+ return createModule("ActionBattle", [{
19
+ server: createActionBattleServer$1?.(options),
20
+ client: createActionBattleClient?.(options)
21
+ }]);
14
22
  }
15
- const index = {
16
- server,
17
- client
18
- };
19
- export {
20
- ACTION_BATTLE_ACTION_BAR_GUI_ID,
21
- AiDebug,
22
- AiState,
23
- AttackPattern,
24
- BattleAi,
25
- DEFAULT_KNOCKBACK,
26
- DEFAULT_PLAYER_ATTACK_HITBOXES,
27
- EnemyType,
28
- applyPlayerHitToEvent,
29
- createActionBattleServer,
30
- index as default,
31
- getPlayerWeaponKnockbackForce,
32
- openActionBattleActionBar,
33
- provideActionBattle,
34
- updateActionBattleActionBar
23
+ var src_default = {
24
+ server,
25
+ client: client_default
35
26
  };
27
+ //#endregion
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 };
@@ -0,0 +1,61 @@
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
21
+ };
22
+ return {
23
+ hasConfiguredAnimation: false,
24
+ configured: void 0
25
+ };
26
+ };
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
+ };
40
+ return {
41
+ animationName: result.animationName ?? defaultAnimationName,
42
+ graphic: result.graphic,
43
+ repeat: result.repeat ?? defaultRepeat,
44
+ waitEnd: result.waitEnd ?? false,
45
+ delayMs: result.delayMs
46
+ };
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
+ }
60
+ //#endregion
61
+ export { getActionBattleAnimationRemovalDelay, playActionBattleAnimation, resolveActionBattleAnimation };
@@ -0,0 +1,55 @@
1
+ import { normalizeActionBattleAttackProfile } from "./index3.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 };