@rpgjs/action-battle 5.0.0-beta.11 → 5.0.0-beta.12

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 (110) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/client/ai.server.d.ts +45 -8
  3. package/dist/client/attack-input.d.ts +3 -0
  4. package/dist/client/core/action-use.d.ts +18 -0
  5. package/dist/client/core/ai-behavior-tree.d.ts +99 -0
  6. package/dist/client/core/attack-runtime.d.ts +2 -0
  7. package/dist/client/core/defaults.d.ts +2 -1
  8. package/dist/client/core/equipment.d.ts +1 -0
  9. package/dist/client/core/targets.d.ts +15 -0
  10. package/dist/client/enemies/factory.d.ts +2 -0
  11. package/dist/client/index.d.ts +12 -7
  12. package/dist/client/index.js +16 -11
  13. package/dist/client/index10.js +32 -56
  14. package/dist/client/index11.js +99 -52
  15. package/dist/client/index12.js +76 -103
  16. package/dist/client/index13.js +72 -135
  17. package/dist/client/index14.js +67 -23
  18. package/dist/client/index15.js +197 -63
  19. package/dist/client/index16.js +112 -1337
  20. package/dist/client/index17.js +193 -7
  21. package/dist/client/index18.js +32 -58
  22. package/dist/client/index19.js +70 -8
  23. package/dist/client/index20.js +57 -501
  24. package/dist/client/index21.js +69 -0
  25. package/dist/client/index22.js +225 -0
  26. package/dist/client/index23.js +16 -0
  27. package/dist/client/index24.js +25 -0
  28. package/dist/client/index25.js +107 -0
  29. package/dist/client/index26.js +1707 -0
  30. package/dist/client/index27.js +12 -0
  31. package/dist/client/index28.js +589 -0
  32. package/dist/client/index4.js +79 -38
  33. package/dist/client/index6.js +65 -306
  34. package/dist/client/index7.js +33 -33
  35. package/dist/client/index8.js +24 -100
  36. package/dist/client/index9.js +293 -61
  37. package/dist/client/locomotion.d.ts +16 -0
  38. package/dist/client/movement.d.ts +14 -0
  39. package/dist/client/server.d.ts +7 -3
  40. package/dist/client/ui.d.ts +22 -0
  41. package/dist/client/visual.d.ts +15 -0
  42. package/dist/server/ai.server.d.ts +45 -8
  43. package/dist/server/attack-input.d.ts +3 -0
  44. package/dist/server/core/action-use.d.ts +18 -0
  45. package/dist/server/core/ai-behavior-tree.d.ts +99 -0
  46. package/dist/server/core/attack-runtime.d.ts +2 -0
  47. package/dist/server/core/defaults.d.ts +2 -1
  48. package/dist/server/core/equipment.d.ts +1 -0
  49. package/dist/server/core/targets.d.ts +15 -0
  50. package/dist/server/enemies/factory.d.ts +2 -0
  51. package/dist/server/index.d.ts +12 -7
  52. package/dist/server/index.js +14 -9
  53. package/dist/server/index10.js +64 -1336
  54. package/dist/server/index11.js +33 -33
  55. package/dist/server/index13.js +66 -11
  56. package/dist/server/index14.js +206 -484
  57. package/dist/server/index15.js +15 -9
  58. package/dist/server/index16.js +26 -0
  59. package/dist/server/index17.js +25 -0
  60. package/dist/server/index18.js +107 -0
  61. package/dist/server/index19.js +1707 -0
  62. package/dist/server/index2.js +10 -2
  63. package/dist/server/index20.js +37 -0
  64. package/dist/server/index21.js +588 -0
  65. package/dist/server/index22.js +78 -0
  66. package/dist/server/index23.js +12 -0
  67. package/dist/server/index5.js +79 -38
  68. package/dist/server/index6.js +192 -129
  69. package/dist/server/index7.js +198 -24
  70. package/dist/server/index8.js +28 -66
  71. package/dist/server/index9.js +68 -51
  72. package/dist/server/locomotion.d.ts +16 -0
  73. package/dist/server/movement.d.ts +14 -0
  74. package/dist/server/server.d.ts +7 -3
  75. package/dist/server/ui.d.ts +22 -0
  76. package/dist/server/visual.d.ts +15 -0
  77. package/package.json +5 -5
  78. package/src/ai.server.spec.ts +233 -0
  79. package/src/ai.server.ts +627 -108
  80. package/src/animations.spec.ts +40 -0
  81. package/src/animations.ts +31 -9
  82. package/src/attack-input.spec.ts +51 -0
  83. package/src/attack-input.ts +59 -0
  84. package/src/client.ts +75 -62
  85. package/src/config.ts +84 -37
  86. package/src/core/action-use.spec.ts +317 -0
  87. package/src/core/action-use.ts +386 -0
  88. package/src/core/ai-behavior-tree.spec.ts +116 -0
  89. package/src/core/ai-behavior-tree.ts +272 -0
  90. package/src/core/attack-profile.spec.ts +46 -0
  91. package/src/core/attack-runtime.spec.ts +35 -0
  92. package/src/core/attack-runtime.ts +32 -0
  93. package/src/core/context.ts +9 -0
  94. package/src/core/contracts.ts +146 -1
  95. package/src/core/defaults.ts +56 -0
  96. package/src/core/equipment.ts +9 -5
  97. package/src/core/targets.spec.ts +112 -0
  98. package/src/core/targets.ts +147 -0
  99. package/src/enemies/factory.ts +8 -0
  100. package/src/index.ts +111 -2
  101. package/src/locomotion.spec.ts +51 -0
  102. package/src/locomotion.ts +48 -0
  103. package/src/movement.spec.ts +78 -0
  104. package/src/movement.ts +46 -0
  105. package/src/server.ts +242 -66
  106. package/src/types.ts +105 -35
  107. package/src/ui.ts +113 -0
  108. package/src/visual.spec.ts +166 -0
  109. package/src/visual.ts +285 -0
  110. package/README.md +0 -1242
@@ -1,13 +1,199 @@
1
- //#region src/core/equipment.ts
2
- var resolveItemId = (item) => item?.id?.() ?? item?.id;
3
- function resolveActionBattleWeaponAttackProfile(entity) {
1
+ //#region src/core/defaults.ts
2
+ var DEFAULT_CORE_KNOCKBACK = {
3
+ force: 50,
4
+ duration: 300
5
+ };
6
+ var CoreAttackPattern = {
7
+ Melee: "melee",
8
+ Combo: "combo",
9
+ Charged: "charged",
10
+ Zone: "zone",
11
+ DashAttack: "dashAttack"
12
+ };
13
+ var CoreEnemyType = {
14
+ Aggressive: "aggressive",
15
+ Defensive: "defensive",
16
+ Ranged: "ranged",
17
+ Tank: "tank",
18
+ Berserker: "berserker"
19
+ };
20
+ var DEFAULT_ZELDA_PLAYER_HITBOXES = {
21
+ up: {
22
+ offsetX: -16,
23
+ offsetY: -48,
24
+ width: 32,
25
+ height: 32
26
+ },
27
+ down: {
28
+ offsetX: -16,
29
+ offsetY: 16,
30
+ width: 32,
31
+ height: 32
32
+ },
33
+ left: {
34
+ offsetX: -48,
35
+ offsetY: -16,
36
+ width: 32,
37
+ height: 32
38
+ },
39
+ right: {
40
+ offsetX: 16,
41
+ offsetY: -16,
42
+ width: 32,
43
+ height: 32
44
+ },
45
+ default: {
46
+ offsetX: 0,
47
+ offsetY: -32,
48
+ width: 32,
49
+ height: 32
50
+ }
51
+ };
52
+ var resolveEquippedWeapon = (entity) => {
4
53
  const equipments = entity?.equipments?.() || [];
5
54
  for (const item of equipments) {
6
- const itemId = resolveItemId(item);
55
+ const itemId = item?.id?.() ?? item?.id;
7
56
  const itemData = entity?.databaseById?.(itemId);
8
- if (itemData?._type === "weapon" && itemData.attackProfile) return itemData.attackProfile;
57
+ if (itemData?._type === "weapon") return itemData;
9
58
  }
10
59
  return null;
11
- }
60
+ };
61
+ var resolveDirection = (attacker, target) => {
62
+ const dx = target.x() - attacker.x();
63
+ const dy = target.y() - attacker.y();
64
+ const distance = Math.sqrt(dx * dx + dy * dy);
65
+ if (distance <= 0) return void 0;
66
+ return {
67
+ x: dx / distance,
68
+ y: dy / distance
69
+ };
70
+ };
71
+ var createDefaultPlayerHitboxResolver = (hitboxes = DEFAULT_ZELDA_PLAYER_HITBOXES) => (context) => {
72
+ const attacker = context.attacker;
73
+ const config = hitboxes[context.direction ?? (typeof attacker.getDirection === "function" ? attacker.getDirection() : "default")] || hitboxes.default;
74
+ return [{
75
+ x: attacker.x() + config.offsetX,
76
+ y: attacker.y() + config.offsetY,
77
+ width: config.width,
78
+ height: config.height
79
+ }];
80
+ };
81
+ var defaultRpgjsDamageResolver = (context) => {
82
+ const target = context.target;
83
+ const raw = target.applyDamage(context.attacker, context.skill);
84
+ return {
85
+ damage: raw?.damage ?? 0,
86
+ defeated: target.hp <= 0,
87
+ raw
88
+ };
89
+ };
90
+ var defaultKnockbackResolver = (context) => {
91
+ const weapon = context.weapon ?? resolveEquippedWeapon(context.attacker);
92
+ return {
93
+ force: weapon?.knockbackForce ?? DEFAULT_CORE_KNOCKBACK.force,
94
+ duration: weapon?.knockbackDuration ?? DEFAULT_CORE_KNOCKBACK.duration,
95
+ direction: resolveDirection(context.attacker, context.target)
96
+ };
97
+ };
98
+ var defaultCombatSystem = {
99
+ resolveHitboxes: createDefaultPlayerHitboxResolver(),
100
+ resolveDamage: defaultRpgjsDamageResolver,
101
+ resolveKnockback: defaultKnockbackResolver
102
+ };
103
+ var defaultEnemyBehaviors = {
104
+ [CoreEnemyType.Aggressive]: ({ hpPercent }) => ({
105
+ mode: hpPercent !== null && hpPercent < .15 ? "retreat" : "assault",
106
+ attackPatterns: [
107
+ CoreAttackPattern.Melee,
108
+ CoreAttackPattern.Combo,
109
+ CoreAttackPattern.DashAttack
110
+ ]
111
+ }),
112
+ [CoreEnemyType.Defensive]: ({ hpPercent }) => ({
113
+ mode: hpPercent !== null && hpPercent < .3 ? "retreat" : "tactical",
114
+ attackPatterns: [CoreAttackPattern.Melee, CoreAttackPattern.Charged]
115
+ }),
116
+ [CoreEnemyType.Ranged]: ({ distance }) => ({
117
+ mode: distance !== null && distance < 80 ? "retreat" : "tactical",
118
+ attackPatterns: [CoreAttackPattern.Melee, CoreAttackPattern.Zone]
119
+ }),
120
+ [CoreEnemyType.Tank]: () => ({
121
+ mode: "assault",
122
+ attackPatterns: [
123
+ CoreAttackPattern.Melee,
124
+ CoreAttackPattern.Charged,
125
+ CoreAttackPattern.Zone
126
+ ]
127
+ }),
128
+ [CoreEnemyType.Berserker]: ({ hpPercent }) => ({
129
+ mode: "assault",
130
+ attackCooldown: hpPercent === null ? void 0 : Math.max(250, 800 * Math.max(.3, hpPercent)),
131
+ attackPatterns: [
132
+ CoreAttackPattern.Melee,
133
+ CoreAttackPattern.Combo,
134
+ CoreAttackPattern.DashAttack
135
+ ]
136
+ })
137
+ };
138
+ var defaultEnemyPresets = {
139
+ [CoreEnemyType.Aggressive]: {
140
+ enemyType: CoreEnemyType.Aggressive,
141
+ attackCooldown: 600,
142
+ visionRange: 150,
143
+ attackRange: 50,
144
+ dodgeChance: .1,
145
+ dodgeCooldown: 3e3,
146
+ fleeThreshold: .15,
147
+ behaviorKey: CoreEnemyType.Aggressive
148
+ },
149
+ [CoreEnemyType.Defensive]: {
150
+ enemyType: CoreEnemyType.Defensive,
151
+ attackCooldown: 1500,
152
+ visionRange: 120,
153
+ attackRange: 60,
154
+ dodgeChance: .5,
155
+ dodgeCooldown: 1500,
156
+ fleeThreshold: .3,
157
+ behaviorKey: CoreEnemyType.Defensive
158
+ },
159
+ [CoreEnemyType.Ranged]: {
160
+ enemyType: CoreEnemyType.Ranged,
161
+ attackCooldown: 1200,
162
+ visionRange: 200,
163
+ attackRange: 120,
164
+ dodgeChance: .4,
165
+ dodgeCooldown: 2e3,
166
+ fleeThreshold: .25,
167
+ behaviorKey: CoreEnemyType.Ranged
168
+ },
169
+ [CoreEnemyType.Tank]: {
170
+ enemyType: CoreEnemyType.Tank,
171
+ attackCooldown: 2e3,
172
+ visionRange: 100,
173
+ attackRange: 50,
174
+ dodgeChance: 0,
175
+ dodgeCooldown: 5e3,
176
+ fleeThreshold: .1,
177
+ poise: 2,
178
+ behaviorKey: CoreEnemyType.Tank
179
+ },
180
+ [CoreEnemyType.Berserker]: {
181
+ enemyType: CoreEnemyType.Berserker,
182
+ attackCooldown: 800,
183
+ visionRange: 180,
184
+ attackRange: 55,
185
+ dodgeChance: .15,
186
+ dodgeCooldown: 2500,
187
+ fleeThreshold: .05,
188
+ behaviorKey: CoreEnemyType.Berserker
189
+ }
190
+ };
191
+ var defaultActionBattleSystems = {
192
+ combat: defaultCombatSystem,
193
+ ai: {
194
+ behaviors: defaultEnemyBehaviors,
195
+ presets: defaultEnemyPresets
196
+ }
197
+ };
12
198
  //#endregion
13
- export { resolveActionBattleWeaponAttackProfile };
199
+ export { DEFAULT_ZELDA_PLAYER_HITBOXES, createDefaultPlayerHitboxResolver, defaultActionBattleSystems, defaultCombatSystem, defaultEnemyBehaviors, defaultEnemyPresets, defaultKnockbackResolver, defaultRpgjsDamageResolver };
@@ -1,60 +1,34 @@
1
- import { isActionBattleEntityInvincible, setActionBattleInvincibility } from "./index2.js";
2
- //#region src/core/hit.ts
3
- var applyActionBattleHit = (system, context) => {
4
- let hitContext = { ...context };
5
- const before = system.hooks?.beforeHit?.(hitContext);
6
- if (before === false) return {
7
- damage: 0,
8
- knockbackForce: 0,
9
- knockbackDuration: 0,
10
- defeated: false,
11
- attacker: hitContext.attacker,
12
- target: hitContext.target,
13
- cancelled: true,
14
- metadata: hitContext.metadata
15
- };
16
- if (before) hitContext = before;
17
- if (isActionBattleEntityInvincible(hitContext.target)) return {
18
- damage: 0,
19
- knockbackForce: 0,
20
- knockbackDuration: 0,
21
- defeated: false,
22
- attacker: hitContext.attacker,
23
- target: hitContext.target,
24
- cancelled: true,
25
- metadata: hitContext.metadata,
26
- reaction: hitContext.reaction
27
- };
28
- const damage = hitContext.damage ?? system.resolveDamage({
29
- attacker: hitContext.attacker,
30
- target: hitContext.target,
31
- skill: hitContext.skill,
32
- pattern: hitContext.pattern
33
- });
34
- hitContext.damage = damage;
35
- const afterDamage = system.hooks?.afterDamage?.(hitContext);
36
- if (afterDamage) hitContext = afterDamage;
37
- const knockback = hitContext.knockback ?? system.resolveKnockback({
38
- attacker: hitContext.attacker,
39
- target: hitContext.target,
40
- damage
41
- });
42
- hitContext.knockback = knockback;
43
- if (!damage.defeated && knockback.force > 0 && knockback.direction) hitContext.target.knockback?.(knockback.direction, knockback.force, knockback.duration);
44
- if (!damage.defeated && hitContext.reaction?.invincibilityMs) setActionBattleInvincibility(hitContext.target, hitContext.reaction.invincibilityMs);
45
- const result = {
46
- damage: damage.damage,
47
- knockbackForce: knockback.force,
48
- knockbackDuration: knockback.duration,
49
- defeated: damage.defeated,
50
- attacker: hitContext.attacker,
51
- target: hitContext.target,
52
- rawDamage: damage.raw,
53
- reaction: hitContext.reaction,
54
- metadata: hitContext.metadata
55
- };
56
- system.hooks?.afterHit?.(result);
57
- return result;
1
+ import { defaultActionBattleSystems } from "./index17.js";
2
+ //#region src/core/context.ts
3
+ var mergeSystems = (options = {}) => ({
4
+ combat: {
5
+ ...defaultActionBattleSystems.combat,
6
+ resolveDamage: options.combat?.damage ?? options.systems?.combat?.damage ?? defaultActionBattleSystems.combat.resolveDamage,
7
+ resolveKnockback: options.combat?.knockback ?? options.systems?.combat?.knockback ?? defaultActionBattleSystems.combat.resolveKnockback,
8
+ hooks: {
9
+ ...defaultActionBattleSystems.combat.hooks,
10
+ ...options.systems?.combat?.hooks,
11
+ ...options.combat?.hooks
12
+ }
13
+ },
14
+ ai: {
15
+ behaviors: {
16
+ ...defaultActionBattleSystems.ai.behaviors,
17
+ ...options.systems?.ai?.behaviors,
18
+ ...options.ai?.behaviors
19
+ },
20
+ presets: {
21
+ ...defaultActionBattleSystems.ai.presets,
22
+ ...options.systems?.ai?.presets,
23
+ ...options.ai?.presets
24
+ }
25
+ }
26
+ });
27
+ var currentActionBattleSystems = mergeSystems();
28
+ var setActionBattleSystems = (options = {}) => {
29
+ currentActionBattleSystems = mergeSystems(options);
58
30
  };
31
+ var getActionBattleSystems = () => currentActionBattleSystems;
32
+ var createActionBattleSystems = mergeSystems;
59
33
  //#endregion
60
- export { applyActionBattleHit };
34
+ export { createActionBattleSystems, getActionBattleSystems, setActionBattleSystems };
@@ -1,10 +1,72 @@
1
- //#region src/enemies/factory.ts
2
- var BattleAi = null;
3
- var createActionEnemy = (event, presetOrOptions, presets = {}) => {
4
- const options = typeof presetOrOptions === "string" ? presets[presetOrOptions] : presetOrOptions;
5
- if (!options) throw new Error(`Action battle enemy preset not found: ${presetOrOptions}`);
6
- options.stats?.(event);
7
- return new BattleAi(event, options);
1
+ import { normalizeActionBattleAttackProfile } from "./index3.js";
2
+ //#region src/core/enemy-attack-profiles.ts
3
+ var DEFAULT_ACTION_BATTLE_ENEMY_ATTACK_PROFILES = {
4
+ melee: {
5
+ id: "enemy-melee",
6
+ startupMs: 120,
7
+ activeMs: 100,
8
+ recoveryMs: 220,
9
+ cooldownMs: 440,
10
+ reaction: {
11
+ invincibilityMs: 250,
12
+ hitstunMs: 120,
13
+ staggerPower: 1
14
+ }
15
+ },
16
+ combo: {
17
+ id: "enemy-combo",
18
+ startupMs: 80,
19
+ activeMs: 80,
20
+ recoveryMs: 140,
21
+ cooldownMs: 300,
22
+ reaction: {
23
+ invincibilityMs: 180,
24
+ hitstunMs: 90,
25
+ staggerPower: .75
26
+ }
27
+ },
28
+ charged: {
29
+ id: "enemy-charged",
30
+ startupMs: 800,
31
+ activeMs: 140,
32
+ recoveryMs: 320,
33
+ cooldownMs: 1260,
34
+ reaction: {
35
+ invincibilityMs: 350,
36
+ hitstunMs: 220,
37
+ staggerPower: 2
38
+ }
39
+ },
40
+ zone: {
41
+ id: "enemy-zone",
42
+ startupMs: 450,
43
+ activeMs: 180,
44
+ recoveryMs: 320,
45
+ cooldownMs: 950,
46
+ reaction: {
47
+ invincibilityMs: 300,
48
+ hitstunMs: 160,
49
+ staggerPower: 1.25
50
+ }
51
+ },
52
+ dashAttack: {
53
+ id: "enemy-dash",
54
+ startupMs: 180,
55
+ activeMs: 120,
56
+ recoveryMs: 260,
57
+ cooldownMs: 560,
58
+ reaction: {
59
+ invincibilityMs: 280,
60
+ hitstunMs: 150,
61
+ staggerPower: 1.2
62
+ }
63
+ }
8
64
  };
65
+ function normalizeActionBattleEnemyAttackProfiles(overrides = {}) {
66
+ return Object.fromEntries(Object.entries(DEFAULT_ACTION_BATTLE_ENEMY_ATTACK_PROFILES).map(([key, defaultProfile]) => [key, normalizeActionBattleAttackProfile({
67
+ ...defaultProfile,
68
+ ...overrides[key]
69
+ })]));
70
+ }
9
71
  //#endregion
10
- export { createActionEnemy };
72
+ export { DEFAULT_ACTION_BATTLE_ENEMY_ATTACK_PROFILES, normalizeActionBattleEnemyAttackProfiles };