@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
@@ -0,0 +1,103 @@
1
+ import type {
2
+ ActionBattleAttackProfile,
3
+ NormalizedActionBattleAttackProfile,
4
+ } from "../types";
5
+ import { normalizeActionBattleAttackProfile } from "./attack-profile";
6
+
7
+ export type ActionBattleEnemyAttackProfileKey =
8
+ | "melee"
9
+ | "combo"
10
+ | "charged"
11
+ | "zone"
12
+ | "dashAttack";
13
+
14
+ export const DEFAULT_ACTION_BATTLE_ENEMY_ATTACK_PROFILES: Record<
15
+ ActionBattleEnemyAttackProfileKey,
16
+ ActionBattleAttackProfile
17
+ > = {
18
+ melee: {
19
+ id: "enemy-melee",
20
+ startupMs: 120,
21
+ activeMs: 100,
22
+ recoveryMs: 220,
23
+ cooldownMs: 440,
24
+ reaction: {
25
+ invincibilityMs: 250,
26
+ hitstunMs: 120,
27
+ staggerPower: 1,
28
+ },
29
+ },
30
+ combo: {
31
+ id: "enemy-combo",
32
+ startupMs: 80,
33
+ activeMs: 80,
34
+ recoveryMs: 140,
35
+ cooldownMs: 300,
36
+ reaction: {
37
+ invincibilityMs: 180,
38
+ hitstunMs: 90,
39
+ staggerPower: 0.75,
40
+ },
41
+ },
42
+ charged: {
43
+ id: "enemy-charged",
44
+ startupMs: 800,
45
+ activeMs: 140,
46
+ recoveryMs: 320,
47
+ cooldownMs: 1260,
48
+ reaction: {
49
+ invincibilityMs: 350,
50
+ hitstunMs: 220,
51
+ staggerPower: 2,
52
+ },
53
+ },
54
+ zone: {
55
+ id: "enemy-zone",
56
+ startupMs: 450,
57
+ activeMs: 180,
58
+ recoveryMs: 320,
59
+ cooldownMs: 950,
60
+ reaction: {
61
+ invincibilityMs: 300,
62
+ hitstunMs: 160,
63
+ staggerPower: 1.25,
64
+ },
65
+ },
66
+ dashAttack: {
67
+ id: "enemy-dash",
68
+ startupMs: 180,
69
+ activeMs: 120,
70
+ recoveryMs: 260,
71
+ cooldownMs: 560,
72
+ reaction: {
73
+ invincibilityMs: 280,
74
+ hitstunMs: 150,
75
+ staggerPower: 1.2,
76
+ },
77
+ },
78
+ };
79
+
80
+ export type ActionBattleEnemyAttackProfileMap = Partial<
81
+ Record<ActionBattleEnemyAttackProfileKey, ActionBattleAttackProfile>
82
+ >;
83
+
84
+ export type NormalizedActionBattleEnemyAttackProfileMap = Record<
85
+ ActionBattleEnemyAttackProfileKey,
86
+ NormalizedActionBattleAttackProfile
87
+ >;
88
+
89
+ export function normalizeActionBattleEnemyAttackProfiles(
90
+ overrides: ActionBattleEnemyAttackProfileMap = {}
91
+ ): NormalizedActionBattleEnemyAttackProfileMap {
92
+ return Object.fromEntries(
93
+ Object.entries(DEFAULT_ACTION_BATTLE_ENEMY_ATTACK_PROFILES).map(
94
+ ([key, defaultProfile]) => [
95
+ key,
96
+ normalizeActionBattleAttackProfile({
97
+ ...defaultProfile,
98
+ ...overrides[key as ActionBattleEnemyAttackProfileKey],
99
+ }),
100
+ ]
101
+ )
102
+ ) as NormalizedActionBattleEnemyAttackProfileMap;
103
+ }
@@ -0,0 +1,37 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import { resolveActionBattleWeaponAttackProfile } from "./equipment";
3
+
4
+ describe("equipment helpers", () => {
5
+ test("resolves attack profile from equipped weapon data", () => {
6
+ const attackProfile = {
7
+ id: "dagger",
8
+ startupMs: 40,
9
+ activeMs: 70,
10
+ recoveryMs: 120,
11
+ };
12
+ const entity = {
13
+ equipments: () => [{ id: () => "dagger" }],
14
+ databaseById: (id: string) =>
15
+ id === "dagger"
16
+ ? {
17
+ _type: "weapon",
18
+ attackProfile,
19
+ }
20
+ : null,
21
+ };
22
+
23
+ expect(resolveActionBattleWeaponAttackProfile(entity)).toBe(attackProfile);
24
+ });
25
+
26
+ test("ignores non-weapon equipment", () => {
27
+ const entity = {
28
+ equipments: () => [{ id: () => "ring" }],
29
+ databaseById: () => ({
30
+ _type: "armor",
31
+ attackProfile: { id: "invalid" },
32
+ }),
33
+ };
34
+
35
+ expect(resolveActionBattleWeaponAttackProfile(entity)).toBeNull();
36
+ });
37
+ });
@@ -0,0 +1,17 @@
1
+ import type { ActionBattleAttackProfile } from "../types";
2
+
3
+ const resolveItemId = (item: any) => item?.id?.() ?? item?.id;
4
+
5
+ export function resolveActionBattleWeaponAttackProfile(
6
+ entity: any
7
+ ): ActionBattleAttackProfile | null {
8
+ const equipments = entity?.equipments?.() || [];
9
+ for (const item of equipments) {
10
+ const itemId = resolveItemId(item);
11
+ const itemData = entity?.databaseById?.(itemId);
12
+ if (itemData?._type === "weapon" && itemData.attackProfile) {
13
+ return itemData.attackProfile;
14
+ }
15
+ }
16
+ return null;
17
+ }
@@ -0,0 +1,43 @@
1
+ import { afterEach, describe, expect, test, vi } from "vitest";
2
+ import {
3
+ DEFAULT_ACTION_BATTLE_HIT_REACTION,
4
+ isActionBattleEntityInvincible,
5
+ normalizeActionBattleHitReaction,
6
+ setActionBattleInvincibility,
7
+ } from "./hit-reaction";
8
+
9
+ describe("hit reaction helpers", () => {
10
+ afterEach(() => {
11
+ vi.restoreAllMocks();
12
+ });
13
+
14
+ test("normalizes hit reaction defaults", () => {
15
+ expect(normalizeActionBattleHitReaction(undefined)).toEqual(
16
+ DEFAULT_ACTION_BATTLE_HIT_REACTION
17
+ );
18
+ });
19
+
20
+ test("normalizes unsafe reaction values", () => {
21
+ expect(
22
+ normalizeActionBattleHitReaction({
23
+ invincibilityMs: -10,
24
+ hitstunMs: -20,
25
+ staggerPower: -1,
26
+ })
27
+ ).toEqual({
28
+ invincibilityMs: 0,
29
+ hitstunMs: 0,
30
+ staggerPower: 0,
31
+ });
32
+ });
33
+
34
+ test("tracks invincibility windows on entities", () => {
35
+ const entity = {};
36
+ vi.spyOn(Date, "now").mockReturnValue(1000);
37
+
38
+ setActionBattleInvincibility(entity, 250);
39
+
40
+ expect(isActionBattleEntityInvincible(entity, 1100)).toBe(true);
41
+ expect(isActionBattleEntityInvincible(entity, 1300)).toBe(false);
42
+ });
43
+ });
@@ -0,0 +1,70 @@
1
+ import type {
2
+ ActionBattleHitReactionProfile,
3
+ NormalizedActionBattleHitReactionProfile,
4
+ } from "../types";
5
+
6
+ export const DEFAULT_ACTION_BATTLE_HIT_REACTION: NormalizedActionBattleHitReactionProfile = {
7
+ invincibilityMs: 250,
8
+ hitstunMs: 150,
9
+ staggerPower: 1,
10
+ };
11
+
12
+ const STATE_KEY = "__actionBattleHitReaction";
13
+
14
+ interface ActionBattleHitReactionRuntimeState {
15
+ invincibleUntil: number;
16
+ }
17
+
18
+ const isFiniteNumber = (value: unknown): value is number =>
19
+ typeof value === "number" && Number.isFinite(value);
20
+
21
+ const nonNegativeMs = (value: unknown, fallback: number) =>
22
+ isFiniteNumber(value) ? Math.max(0, value) : fallback;
23
+
24
+ const nonNegativeValue = (value: unknown, fallback: number) =>
25
+ isFiniteNumber(value) ? Math.max(0, value) : fallback;
26
+
27
+ const getRuntimeState = (entity: any): ActionBattleHitReactionRuntimeState => {
28
+ if (!entity[STATE_KEY]) {
29
+ entity[STATE_KEY] = {
30
+ invincibleUntil: 0,
31
+ };
32
+ }
33
+ return entity[STATE_KEY];
34
+ };
35
+
36
+ export function normalizeActionBattleHitReaction(
37
+ reaction: ActionBattleHitReactionProfile | undefined,
38
+ defaults: NormalizedActionBattleHitReactionProfile =
39
+ DEFAULT_ACTION_BATTLE_HIT_REACTION
40
+ ): NormalizedActionBattleHitReactionProfile {
41
+ return {
42
+ invincibilityMs: nonNegativeMs(
43
+ reaction?.invincibilityMs,
44
+ defaults.invincibilityMs
45
+ ),
46
+ hitstunMs: nonNegativeMs(reaction?.hitstunMs, defaults.hitstunMs),
47
+ staggerPower: nonNegativeValue(
48
+ reaction?.staggerPower,
49
+ defaults.staggerPower
50
+ ),
51
+ };
52
+ }
53
+
54
+ export function isActionBattleEntityInvincible(
55
+ entity: any,
56
+ now = Date.now()
57
+ ): boolean {
58
+ if (!entity) return false;
59
+ return getRuntimeState(entity).invincibleUntil > now;
60
+ }
61
+
62
+ export function setActionBattleInvincibility(
63
+ entity: any,
64
+ durationMs: number,
65
+ now = Date.now()
66
+ ): void {
67
+ if (!entity || durationMs <= 0) return;
68
+ const state = getRuntimeState(entity);
69
+ state.invincibleUntil = Math.max(state.invincibleUntil, now + durationMs);
70
+ }
@@ -0,0 +1,111 @@
1
+ import { afterEach, describe, expect, test, vi } from "vitest";
2
+ import { applyActionBattleHit } from "./hit";
3
+ import type { ActionBattleCombatSystem } from "./contracts";
4
+ import { setActionBattleInvincibility } from "./hit-reaction";
5
+
6
+ const entity = (hp = 100) => ({
7
+ hp,
8
+ x: () => 0,
9
+ y: () => 0,
10
+ knockback: vi.fn(),
11
+ });
12
+
13
+ describe("applyActionBattleHit", () => {
14
+ afterEach(() => {
15
+ vi.restoreAllMocks();
16
+ });
17
+
18
+ test("runs beforeHit before resolving damage", () => {
19
+ const calls: string[] = [];
20
+ const attacker = entity();
21
+ const target = entity();
22
+ const system: ActionBattleCombatSystem = {
23
+ resolveHitboxes: () => [],
24
+ resolveDamage: () => {
25
+ calls.push("damage");
26
+ return { damage: 12, defeated: false };
27
+ },
28
+ resolveKnockback: () => ({ force: 0, duration: 0 }),
29
+ hooks: {
30
+ beforeHit() {
31
+ calls.push("before");
32
+ },
33
+ afterHit() {
34
+ calls.push("after");
35
+ },
36
+ },
37
+ };
38
+
39
+ const result = applyActionBattleHit(system, { attacker: attacker as any, target: target as any });
40
+
41
+ expect(result.damage).toBe(12);
42
+ expect(calls).toEqual(["before", "damage", "after"]);
43
+ });
44
+
45
+ test("can cancel a hit before damage is resolved", () => {
46
+ const resolveDamage = vi.fn();
47
+ const attacker = entity();
48
+ const target = entity();
49
+ const system: ActionBattleCombatSystem = {
50
+ resolveHitboxes: () => [],
51
+ resolveDamage,
52
+ resolveKnockback: () => ({ force: 0, duration: 0 }),
53
+ hooks: {
54
+ beforeHit: () => false,
55
+ },
56
+ };
57
+
58
+ const result = applyActionBattleHit(system, { attacker: attacker as any, target: target as any });
59
+
60
+ expect(result.cancelled).toBe(true);
61
+ expect(resolveDamage).not.toHaveBeenCalled();
62
+ });
63
+
64
+ test("cancels a hit when the target is invincible", () => {
65
+ const resolveDamage = vi.fn();
66
+ const attacker = entity();
67
+ const target = entity();
68
+ setActionBattleInvincibility(target, 500, 1000);
69
+ vi.spyOn(Date, "now").mockReturnValue(1100);
70
+ const system: ActionBattleCombatSystem = {
71
+ resolveHitboxes: () => [],
72
+ resolveDamage,
73
+ resolveKnockback: () => ({ force: 0, duration: 0 }),
74
+ };
75
+
76
+ const result = applyActionBattleHit(system, {
77
+ attacker: attacker as any,
78
+ target: target as any,
79
+ });
80
+
81
+ expect(result.cancelled).toBe(true);
82
+ expect(resolveDamage).not.toHaveBeenCalled();
83
+ });
84
+
85
+ test("applies invincibility from hit reaction after damage", () => {
86
+ vi.spyOn(Date, "now").mockReturnValue(2000);
87
+ const attacker = entity();
88
+ const target = entity();
89
+ const system: ActionBattleCombatSystem = {
90
+ resolveHitboxes: () => [],
91
+ resolveDamage: () => ({ damage: 12, defeated: false }),
92
+ resolveKnockback: () => ({ force: 0, duration: 0 }),
93
+ };
94
+
95
+ const result = applyActionBattleHit(system, {
96
+ attacker: attacker as any,
97
+ target: target as any,
98
+ reaction: {
99
+ invincibilityMs: 300,
100
+ hitstunMs: 120,
101
+ staggerPower: 1,
102
+ },
103
+ });
104
+
105
+ expect(result.cancelled).toBeUndefined();
106
+ expect(applyActionBattleHit(system, {
107
+ attacker: attacker as any,
108
+ target: target as any,
109
+ }).cancelled).toBe(true);
110
+ });
111
+ });
@@ -0,0 +1,92 @@
1
+ import type { ActionBattleCombatSystem, ActionBattleHitContext, ActionBattleHitResult } from "./contracts";
2
+ import {
3
+ isActionBattleEntityInvincible,
4
+ setActionBattleInvincibility,
5
+ } from "./hit-reaction";
6
+
7
+ export const applyActionBattleHit = (
8
+ system: ActionBattleCombatSystem,
9
+ context: ActionBattleHitContext
10
+ ): ActionBattleHitResult => {
11
+ let hitContext = { ...context };
12
+ const before = system.hooks?.beforeHit?.(hitContext);
13
+ if (before === false) {
14
+ return {
15
+ damage: 0,
16
+ knockbackForce: 0,
17
+ knockbackDuration: 0,
18
+ defeated: false,
19
+ attacker: hitContext.attacker,
20
+ target: hitContext.target,
21
+ cancelled: true,
22
+ metadata: hitContext.metadata,
23
+ };
24
+ }
25
+ if (before) hitContext = before;
26
+
27
+ if (isActionBattleEntityInvincible(hitContext.target)) {
28
+ return {
29
+ damage: 0,
30
+ knockbackForce: 0,
31
+ knockbackDuration: 0,
32
+ defeated: false,
33
+ attacker: hitContext.attacker,
34
+ target: hitContext.target,
35
+ cancelled: true,
36
+ metadata: hitContext.metadata,
37
+ reaction: hitContext.reaction,
38
+ };
39
+ }
40
+
41
+ const damage =
42
+ hitContext.damage ??
43
+ system.resolveDamage({
44
+ attacker: hitContext.attacker,
45
+ target: hitContext.target,
46
+ skill: hitContext.skill,
47
+ pattern: hitContext.pattern,
48
+ });
49
+ hitContext.damage = damage;
50
+
51
+ const afterDamage = system.hooks?.afterDamage?.(hitContext);
52
+ if (afterDamage) hitContext = afterDamage;
53
+
54
+ const knockback =
55
+ hitContext.knockback ??
56
+ system.resolveKnockback({
57
+ attacker: hitContext.attacker,
58
+ target: hitContext.target,
59
+ damage,
60
+ });
61
+ hitContext.knockback = knockback;
62
+
63
+ if (!damage.defeated && knockback.force > 0 && knockback.direction) {
64
+ (hitContext.target as any).knockback?.(
65
+ knockback.direction,
66
+ knockback.force,
67
+ knockback.duration
68
+ );
69
+ }
70
+
71
+ if (!damage.defeated && hitContext.reaction?.invincibilityMs) {
72
+ setActionBattleInvincibility(
73
+ hitContext.target,
74
+ hitContext.reaction.invincibilityMs
75
+ );
76
+ }
77
+
78
+ const result: ActionBattleHitResult = {
79
+ damage: damage.damage,
80
+ knockbackForce: knockback.force,
81
+ knockbackDuration: knockback.duration,
82
+ defeated: damage.defeated,
83
+ attacker: hitContext.attacker,
84
+ target: hitContext.target,
85
+ rawDamage: damage.raw,
86
+ reaction: hitContext.reaction,
87
+ metadata: hitContext.metadata,
88
+ };
89
+
90
+ system.hooks?.afterHit?.(result);
91
+ return result;
92
+ };
@@ -0,0 +1,25 @@
1
+ import type { RpgEvent } from "@rpgjs/server";
2
+ import { BattleAi, type BattleAiOptions } from "../ai.server";
3
+
4
+ export interface ActionBattleEnemyPreset extends BattleAiOptions {
5
+ stats?: (event: RpgEvent) => void;
6
+ }
7
+
8
+ export type ActionBattleEnemyPresetMap = Record<string, ActionBattleEnemyPreset>;
9
+
10
+ export const createActionEnemy = (
11
+ event: RpgEvent,
12
+ presetOrOptions: string | BattleAiOptions,
13
+ presets: ActionBattleEnemyPresetMap = {}
14
+ ) => {
15
+ const options =
16
+ typeof presetOrOptions === "string"
17
+ ? presets[presetOrOptions]
18
+ : presetOrOptions;
19
+ if (!options) {
20
+ throw new Error(`Action battle enemy preset not found: ${presetOrOptions}`);
21
+ }
22
+ const preset = options as ActionBattleEnemyPreset;
23
+ preset.stats?.(event);
24
+ return new BattleAi(event, options);
25
+ };
package/src/index.ts CHANGED
@@ -7,18 +7,111 @@ import type { ActionBattleOptions } from "./types";
7
7
  export { BattleAi, AiState, EnemyType, AttackPattern, AiDebug, DEFAULT_KNOCKBACK } from "./ai.server";
8
8
 
9
9
  // Types exports
10
- export type { HitResult, ApplyHitHooks } from "./ai.server";
11
10
  export type {
11
+ HitResult,
12
+ ApplyHitHooks,
13
+ BattleAiOptions,
14
+ BattleAiDefeatedCallback,
15
+ BattleAiDefeatedContext,
16
+ BattleAiDefeatReward,
17
+ BattleAiLegacyDefeatedCallback,
18
+ BattleAiLegacyOptions,
19
+ BattleAiRewardItem,
20
+ BattleAiRewards,
21
+ } from "./ai.server";
22
+ export type {
23
+ ActionBattleAnimationContext,
24
+ ActionBattleAnimationEntity,
25
+ ActionBattleAnimationKey,
26
+ ActionBattleAnimationOptions,
27
+ ActionBattleAnimationResolver,
28
+ ActionBattleAnimationResult,
12
29
  ActionBattleOptions,
13
30
  ActionBattleActionBarData,
14
31
  ActionBattleActionBarItem,
15
32
  ActionBattleActionBarSkill,
16
33
  ActionBattleSkillTargeting,
17
34
  ActionBattleSkillTargetingResolver,
35
+ ActionBattleAttackOptions,
18
36
  ActionBattleUiOptions,
19
37
  ActionBattleUiActionBarOptions,
20
38
  ActionBattleUiTargetingOptions,
39
+ ActionBattleAttackDirection,
40
+ ActionBattleAttackHitboxConfig,
41
+ ActionBattleAttackHitboxMap,
42
+ ActionBattleAttackHitPolicy,
43
+ ActionBattleAttackProfile,
44
+ ActionBattleDebugOptions,
45
+ ActionBattleHitReactionProfile,
46
+ NormalizedActionBattleHitReactionProfile,
47
+ NormalizedActionBattleAttackProfile,
48
+ ActionBattleCombatOptions,
49
+ ActionBattleSystemOptions,
50
+ ActionBattleAiSystemOptions,
21
51
  } from "./types";
52
+ export type {
53
+ ActionBattleAiBehavior,
54
+ ActionBattleAiContext,
55
+ ActionBattleAiDecision,
56
+ ActionBattleAttackContext,
57
+ ActionBattleCombatSystem,
58
+ ActionBattleDamageContext,
59
+ ActionBattleDamageResult,
60
+ ActionBattleDirection,
61
+ ActionBattleEntity,
62
+ ActionBattleHitContext,
63
+ ActionBattleHitHooks,
64
+ ActionBattleHitResult,
65
+ ActionBattleHitbox,
66
+ ActionBattleKnockbackContext,
67
+ ActionBattleKnockbackResult,
68
+ ActionBattleSystems,
69
+ } from "./core/contracts";
70
+ export {
71
+ DEFAULT_ACTION_BATTLE_ATTACK_PROFILE,
72
+ normalizeActionBattleAttackProfile,
73
+ type ActionBattleAttackProfileFallbacks,
74
+ } from "./core/attack-profile";
75
+ export {
76
+ ACTION_BATTLE_HITBOX_FRAME_MS,
77
+ ActionBattleHitTracker,
78
+ createActionBattleAttackId,
79
+ getNormalizedActionBattleAttackProfile,
80
+ resolveActionBattleHitboxSpeed,
81
+ scheduleActionBattleStartup,
82
+ } from "./core/attack-runtime";
83
+ export {
84
+ DEFAULT_ACTION_BATTLE_HIT_REACTION,
85
+ isActionBattleEntityInvincible,
86
+ normalizeActionBattleHitReaction,
87
+ setActionBattleInvincibility,
88
+ } from "./core/hit-reaction";
89
+ export {
90
+ DEFAULT_ACTION_BATTLE_ENEMY_ATTACK_PROFILES,
91
+ normalizeActionBattleEnemyAttackProfiles,
92
+ type ActionBattleEnemyAttackProfileKey,
93
+ type ActionBattleEnemyAttackProfileMap,
94
+ type NormalizedActionBattleEnemyAttackProfileMap,
95
+ } from "./core/enemy-attack-profiles";
96
+ export { resolveActionBattleWeaponAttackProfile } from "./core/equipment";
97
+ export {
98
+ DEFAULT_ZELDA_PLAYER_HITBOXES,
99
+ createDefaultPlayerHitboxResolver,
100
+ defaultCombatSystem,
101
+ defaultEnemyBehaviors,
102
+ defaultKnockbackResolver,
103
+ defaultRpgjsDamageResolver,
104
+ } from "./core/defaults";
105
+ export {
106
+ createActionBattleSystems,
107
+ getActionBattleSystems,
108
+ } from "./core/context";
109
+ export { applyActionBattleHit } from "./core/hit";
110
+ export {
111
+ createActionEnemy,
112
+ type ActionBattleEnemyPreset,
113
+ type ActionBattleEnemyPresetMap,
114
+ } from "./enemies/factory";
22
115
 
23
116
  // Server exports
24
117
  export {