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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/client/ai.server.d.ts +57 -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 +3 -2
  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 +203 -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 +70 -0
  25. package/dist/client/index22.js +226 -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 +1949 -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 +57 -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 +3 -2
  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 +67 -11
  56. package/dist/server/index14.js +207 -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 +1949 -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 +208 -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 +380 -1
  79. package/src/ai.server.ts +963 -137
  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 +387 -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 +72 -1
  96. package/src/core/equipment.ts +9 -5
  97. package/src/core/hit.spec.ts +21 -0
  98. package/src/core/targets.spec.ts +124 -0
  99. package/src/core/targets.ts +150 -0
  100. package/src/enemies/factory.ts +8 -0
  101. package/src/index.ts +111 -2
  102. package/src/locomotion.spec.ts +51 -0
  103. package/src/locomotion.ts +48 -0
  104. package/src/movement.spec.ts +78 -0
  105. package/src/movement.ts +46 -0
  106. package/src/server.ts +242 -66
  107. package/src/types.ts +105 -35
  108. package/src/ui.ts +113 -0
  109. package/src/visual.spec.ts +166 -0
  110. package/src/visual.ts +285 -0
  111. package/README.md +0 -1242
@@ -34,67 +34,108 @@ var DEFAULT_ACTION_BATTLE_OPTIONS = {
34
34
  };
35
35
  var currentActionBattleOptions = DEFAULT_ACTION_BATTLE_OPTIONS;
36
36
  function normalizeActionBattleOptions(options = {}) {
37
+ const combat = {
38
+ ...DEFAULT_ACTION_BATTLE_OPTIONS.systems?.combat,
39
+ ...options.systems?.combat,
40
+ ...options.combat,
41
+ hooks: {
42
+ ...DEFAULT_ACTION_BATTLE_OPTIONS.systems?.combat?.hooks,
43
+ ...options.systems?.combat?.hooks,
44
+ ...options.combat?.hooks
45
+ }
46
+ };
37
47
  const attack = {
38
48
  ...DEFAULT_ACTION_BATTLE_OPTIONS.attack,
39
- ...options.attack
49
+ ...options.attack,
50
+ ...combat.attack
40
51
  };
41
52
  const attackProfile = normalizeActionBattleAttackProfile(attack.profile, {
42
53
  lockMovement: attack.lockMovement,
43
54
  lockDurationMs: attack.lockDurationMs,
44
55
  hitboxes: attack.hitboxes
45
56
  });
57
+ const normalizedAttack = {
58
+ ...attack,
59
+ profile: attackProfile
60
+ };
61
+ const skills = {
62
+ ...DEFAULT_ACTION_BATTLE_OPTIONS.skills,
63
+ ...options.skills
64
+ };
65
+ skills.targeting = skills.targeting ?? skills.getTargeting;
66
+ skills.getTargeting = skills.getTargeting ?? skills.targeting;
67
+ const defaultActionBar = DEFAULT_ACTION_BATTLE_OPTIONS.ui?.actionBar;
68
+ const defaultTargeting = DEFAULT_ACTION_BATTLE_OPTIONS.ui?.targeting;
69
+ const optionActionBar = options.ui?.actionBar;
70
+ const optionTargeting = options.ui?.targeting;
71
+ const optionAttackPreview = options.ui?.attackPreview;
72
+ const actionBar = options.ui?.actionBar === false ? {
73
+ ...defaultActionBar,
74
+ enabled: false
75
+ } : {
76
+ ...defaultActionBar,
77
+ ...options.ui?.actionBar === true ? { enabled: true } : optionActionBar
78
+ };
79
+ const legacyPreviewEnabled = normalizedAttack.showPreview !== false;
80
+ const attackPreview = options.ui?.attackPreview === false ? { enabled: false } : {
81
+ enabled: options.ui?.attackPreview === true ? true : legacyPreviewEnabled,
82
+ ...options.ui?.attackPreview === true ? {} : optionAttackPreview
83
+ };
84
+ const targeting = options.ui?.targeting === false ? {
85
+ ...defaultTargeting,
86
+ enabled: false
87
+ } : {
88
+ ...defaultTargeting,
89
+ ...options.ui?.targeting === true ? { enabled: true } : optionTargeting,
90
+ colors: {
91
+ ...defaultTargeting?.colors,
92
+ ...typeof options.ui?.targeting === "object" ? optionTargeting?.colors : void 0
93
+ }
94
+ };
95
+ const ai = {
96
+ ...DEFAULT_ACTION_BATTLE_OPTIONS.systems?.ai,
97
+ ...options.systems?.ai,
98
+ ...options.ai,
99
+ behaviors: {
100
+ ...DEFAULT_ACTION_BATTLE_OPTIONS.systems?.ai?.behaviors,
101
+ ...options.systems?.ai?.behaviors,
102
+ ...options.ai?.behaviors
103
+ },
104
+ presets: {
105
+ ...DEFAULT_ACTION_BATTLE_OPTIONS.systems?.ai?.presets,
106
+ ...options.systems?.ai?.presets,
107
+ ...options.ai?.presets
108
+ }
109
+ };
46
110
  return {
47
111
  ui: {
48
- actionBar: {
49
- ...DEFAULT_ACTION_BATTLE_OPTIONS.ui?.actionBar,
50
- ...options.ui?.actionBar
51
- },
52
- targeting: {
53
- ...DEFAULT_ACTION_BATTLE_OPTIONS.ui?.targeting,
54
- ...options.ui?.targeting,
55
- colors: {
56
- ...DEFAULT_ACTION_BATTLE_OPTIONS.ui?.targeting?.colors,
57
- ...options.ui?.targeting?.colors
58
- }
59
- }
60
- },
61
- skills: {
62
- ...DEFAULT_ACTION_BATTLE_OPTIONS.skills,
63
- ...options.skills
112
+ ...options.ui,
113
+ actionBar,
114
+ targeting,
115
+ attackPreview
64
116
  },
117
+ skills,
65
118
  targeting: {
66
119
  ...DEFAULT_ACTION_BATTLE_OPTIONS.targeting,
67
120
  ...options.targeting
68
121
  },
69
- debug: {
70
- ...DEFAULT_ACTION_BATTLE_OPTIONS.debug,
71
- ...options.debug
72
- },
73
- attack: {
74
- ...attack,
75
- profile: attackProfile
122
+ attack: normalizedAttack,
123
+ combat: {
124
+ ...combat,
125
+ attack: normalizedAttack
76
126
  },
127
+ ai,
128
+ visual: options.visual,
77
129
  animations: {
78
130
  ...DEFAULT_ACTION_BATTLE_OPTIONS.animations,
79
131
  ...options.animations
80
132
  },
81
133
  systems: {
82
134
  combat: {
83
- ...DEFAULT_ACTION_BATTLE_OPTIONS.systems?.combat,
84
- ...options.systems?.combat,
85
- hooks: {
86
- ...DEFAULT_ACTION_BATTLE_OPTIONS.systems?.combat?.hooks,
87
- ...options.systems?.combat?.hooks
88
- }
135
+ ...combat,
136
+ attack: normalizedAttack
89
137
  },
90
- ai: {
91
- ...DEFAULT_ACTION_BATTLE_OPTIONS.systems?.ai,
92
- ...options.systems?.ai,
93
- behaviors: {
94
- ...DEFAULT_ACTION_BATTLE_OPTIONS.systems?.ai?.behaviors,
95
- ...options.systems?.ai?.behaviors
96
- }
97
- }
138
+ ai
98
139
  }
99
140
  };
100
141
  }
@@ -1,311 +1,70 @@
1
- import { actionBattleTargetingState, actionBattleUiOptions, moveTargetingOffset, startTargeting, stopTargeting } from "./index5.js";
2
- import { RpgClientEngine, getKeyboardControlBind, inject } from "@rpgjs/client";
3
- import { DOMContainer, DOMElement, DOMSprite, computed, cond, effect, h, loop, signal, useDefineProps, useProps } from "canvasengine";
4
- //#region src/components/action-bar.ce
5
- if (typeof document !== "undefined") {
6
- let styleElement = document.getElementById("ce-style--home-runner-work-RPG-JS-RPG-JS-packages-action-battle-src-components-action-bar-ce");
7
- if (!styleElement) {
8
- styleElement = document.createElement("style");
9
- styleElement.id = "ce-style--home-runner-work-RPG-JS-RPG-JS-packages-action-battle-src-components-action-bar-ce";
10
- document.head.appendChild(styleElement);
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;
11
21
  }
12
- styleElement.textContent = ".action-battle-actionbar-root {\n pointer-events: none;\n }\n\n .action-battle-actionbar {\n position: absolute;\n left: 12px;\n right: 12px;\n bottom: 12px;\n pointer-events: auto;\n display: flex;\n justify-content: center;\n }\n\n .action-battle-actionbar-plate {\n width: min(760px, 100%);\n --rpg-ui-hotbar-size: clamp(38px, 8vw, 52px);\n }\n\n .action-battle-actionbar-track {\n --rpg-ui-hotbar-slots: 10;\n }";
22
+ return scheduler(callback, profile.startupMs);
13
23
  }
14
- function component($$props) {
15
- useProps($$props);
16
- const defineProps = useDefineProps($$props);
17
- const engine = inject(RpgClientEngine);
18
- const keyboardControls = engine.globalConfig.keyboardControls;
19
- const { data, onInteraction, onBack } = defineProps();
20
- const ACTION_BAR_SIZE = 10;
21
- const SLOT_LABELS = [
22
- "1",
23
- "2",
24
- "3",
25
- "4",
26
- "5",
27
- "6",
28
- "7",
29
- "8",
30
- "9",
31
- "0"
32
- ];
33
- const SLOT_CONFIG_KEYS = [
34
- "hotbar1",
35
- "hotbar2",
36
- "hotbar3",
37
- "hotbar4",
38
- "hotbar5",
39
- "hotbar6",
40
- "hotbar7",
41
- "hotbar8",
42
- "hotbar9",
43
- "hotbar0"
44
- ];
45
- const selectedSlotIndex = signal(-1);
46
- const uiOptions = computed(() => actionBattleUiOptions());
47
- const showItems = computed(() => {
48
- const mode = uiOptions().actionBar?.mode || "both";
49
- return mode === "items" || mode === "both";
50
- });
51
- const showSkills = computed(() => {
52
- const mode = uiOptions().actionBar?.mode || "both";
53
- return mode === "skills" || mode === "both";
54
- });
55
- const isTargeting = computed(() => actionBattleTargetingState().active);
56
- const iconSheet = (iconId) => ({
57
- definition: engine.getSpriteSheet(iconId),
58
- playing: "default"
59
- });
60
- const resolveProp = (value) => typeof value === "function" ? value() : value;
61
- const actionBarData = computed(() => resolveProp(data) || {
62
- items: [],
63
- skills: []
64
- });
65
- const actionBarSlots = computed(() => {
66
- const entries = [];
67
- if (showSkills()) (actionBarData().skills || []).forEach((skill, index) => {
68
- entries.push({
69
- type: "skill",
70
- skill,
71
- item: null,
72
- sourceIndex: index
73
- });
74
- });
75
- if (showItems()) (actionBarData().items || []).forEach((item, index) => {
76
- entries.push({
77
- type: "item",
78
- skill: null,
79
- item,
80
- sourceIndex: index
81
- });
82
- });
83
- const slots = entries.slice(0, ACTION_BAR_SIZE).map((entry, index) => ({
84
- ...entry,
85
- label: SLOT_LABELS[index]
86
- }));
87
- while (slots.length < ACTION_BAR_SIZE) slots.push({
88
- type: "empty",
89
- skill: null,
90
- item: null,
91
- sourceIndex: -1,
92
- label: SLOT_LABELS[slots.length]
93
- });
94
- return slots;
95
- });
96
- const hasSlotEntry = (slot) => slot.type === "skill" || slot.type === "item";
97
- const isSlotDisabled = (slot) => {
98
- if (!hasSlotEntry(slot)) return true;
99
- const entry = slot.type === "skill" ? slot.skill : slot.item;
100
- return !entry || !entry.usable;
101
- };
102
- const getItemQuantity = (item) => {
103
- if (!item) return 0;
104
- if (typeof item.quantity === "function") return item.quantity();
105
- return item.quantity || 0;
106
- };
107
- const selectItem = (item) => {
108
- if (!item || !item.usable) return;
109
- if (onInteraction) onInteraction("useItem", { id: item.id });
110
- };
111
- const selectSkill = (skill) => {
112
- if (!skill || !skill.usable) return;
113
- if ((skill.range ?? 0) > 0 || skill.aoeMask) {
114
- startTargeting(skill);
115
- return;
116
- }
117
- if (onInteraction) onInteraction("useSkill", { id: skill.id });
118
- };
119
- const selectSlot = (index) => {
120
- const slot = actionBarSlots()[index];
121
- if (!slot || !hasSlotEntry(slot)) return;
122
- if (slot.type === "skill") {
123
- selectSkill(slot.skill);
124
- return;
125
- }
126
- selectItem(slot.item);
24
+ function runActionBattleActiveHitbox(profile, resolveHitboxes, onHitboxes, scheduler = setTimeout) {
25
+ const frames = Math.max(1, Math.ceil(profile.activeMs / 16));
26
+ let frame = 0;
27
+ const step = () => {
28
+ const hitboxes = resolveHitboxes();
29
+ if (hitboxes.length > 0) onHitboxes(hitboxes);
30
+ frame++;
31
+ if (frame < frames) scheduler(step, 16);
127
32
  };
128
- const onSelectSlot = (index) => () => {
129
- selectedSlotIndex.set(index);
130
- selectSlot(index);
131
- };
132
- const getPlayerTile = () => {
133
- const player = engine.scene.getCurrentPlayer();
134
- if (!player) return null;
135
- const hitbox = player.hitbox?.() || {
136
- w: 32,
137
- h: 32
138
- };
139
- const tileWidth = hitbox.w || 32;
140
- const tileHeight = hitbox.h || 32;
141
- return {
142
- x: Math.floor((player.x() + hitbox.w / 2) / tileWidth),
143
- y: Math.floor((player.y() + hitbox.h / 2) / tileHeight)
144
- };
145
- };
146
- const confirmTargeting = () => {
147
- const state = actionBattleTargetingState();
148
- if (!state.skill) return;
149
- const origin = getPlayerTile();
150
- if (!origin) return;
151
- const target = {
152
- x: origin.x + state.offset.x,
153
- y: origin.y + state.offset.y
154
- };
155
- if (onInteraction) onInteraction("useSkill", {
156
- id: state.skill.id,
157
- target
158
- });
159
- stopTargeting();
160
- };
161
- const resolveKeyBind = (key) => {
162
- if (!key) return null;
163
- if (typeof key === "string" && keyboardControls?.[key]) return keyboardControls[key];
164
- return key;
165
- };
166
- const slotBind = (index) => keyboardControls?.[SLOT_CONFIG_KEYS[index]] || SLOT_LABELS[index];
167
- const buildControls = () => {
168
- const hotbarControls = {};
169
- actionBarSlots().forEach((slot, index) => {
170
- if (!hasSlotEntry(slot)) return;
171
- const bind = slotBind(index);
172
- hotbarControls[`slot-${index}`] = {
173
- bind,
174
- keyDown() {
175
- if (isTargeting()) return;
176
- selectedSlotIndex.set(index);
177
- selectSlot(index);
178
- }
179
- };
180
- if (slot.type === "skill") {
181
- const skillBind = resolveKeyBind(slot.skill?.key);
182
- if (!skillBind || skillBind === bind) return;
183
- hotbarControls[`skill-${index}`] = {
184
- bind: skillBind,
185
- keyDown() {
186
- if (isTargeting()) return;
187
- selectedSlotIndex.set(index);
188
- selectSlot(index);
189
- }
190
- };
191
- }
192
- });
193
- return {
194
- left: {
195
- repeat: true,
196
- bind: keyboardControls.left,
197
- throttle: 150,
198
- keyDown() {
199
- if (isTargeting()) moveTargetingOffset(-1, 0);
200
- }
201
- },
202
- right: {
203
- repeat: true,
204
- bind: keyboardControls.right,
205
- throttle: 150,
206
- keyDown() {
207
- if (isTargeting()) moveTargetingOffset(1, 0);
208
- }
209
- },
210
- up: {
211
- repeat: true,
212
- bind: keyboardControls.up,
213
- throttle: 150,
214
- keyDown() {
215
- if (isTargeting()) moveTargetingOffset(0, -1);
216
- }
217
- },
218
- down: {
219
- repeat: true,
220
- bind: keyboardControls.down,
221
- throttle: 150,
222
- keyDown() {
223
- if (isTargeting()) moveTargetingOffset(0, 1);
224
- }
225
- },
226
- action: {
227
- bind: getKeyboardControlBind(keyboardControls.action),
228
- keyDown() {
229
- if (isTargeting()) confirmTargeting();
230
- }
231
- },
232
- escape: {
233
- bind: keyboardControls.escape,
234
- keyDown() {
235
- if (isTargeting()) {
236
- stopTargeting();
237
- return;
238
- }
239
- if (onBack) onBack();
240
- }
241
- },
242
- ...hotbarControls,
243
- gamepad: { enabled: true }
244
- };
245
- };
246
- const controls = signal(buildControls());
247
- effect(() => {
248
- controls.set(buildControls());
249
- });
250
- return h(DOMContainer, {
251
- width: "100%",
252
- height: "100%",
253
- attrs: { class: "action-battle-actionbar-root" },
254
- controls
255
- }, h(DOMElement, {
256
- element: "div",
257
- attrs: { class: "action-battle-actionbar" }
258
- }, h(DOMElement, {
259
- element: "div",
260
- attrs: { class: "rpg-ui-hotbar action-battle-actionbar-plate" }
261
- }, h(DOMElement, {
262
- element: "div",
263
- attrs: { class: "rpg-ui-hotbar-track action-battle-actionbar-track" }
264
- }, loop(actionBarSlots, (slot, index) => h(DOMElement, {
265
- element: "div",
266
- attrs: {
267
- class: "rpg-ui-hotbar-slot action-battle-actionbar-slot",
268
- "data-selected": computed(() => selectedSlotIndex() === index ? "true" : "false"),
269
- "data-disabled": computed(() => isSlotDisabled(slot) ? "true" : "false"),
270
- "data-empty": computed(() => hasSlotEntry(slot) ? "false" : "true"),
271
- "data-type": slot.type,
272
- tabindex: computed(() => hasSlotEntry(slot) ? index : -1),
273
- click: hasSlotEntry(slot) ? onSelectSlot(index) : void 0
274
- }
275
- }, [
276
- h(DOMElement, {
277
- element: "span",
278
- attrs: { class: "rpg-ui-hotbar-key action-battle-actionbar-key" },
279
- textContent: slot.label
280
- }),
281
- cond(computed(() => slot.type === "skill" && slot.skill?.icon), () => h(DOMSprite, {
282
- sheet: computed(() => iconSheet(slot.skill.icon)),
283
- width: "60px",
284
- height: "60px",
285
- scale: 2,
286
- objectFit: "contain"
287
- }), [computed(() => slot.type === "item" && slot.item?.icon), () => h(DOMSprite, {
288
- sheet: computed(() => iconSheet(slot.item.icon)),
289
- width: "60px",
290
- height: "60px",
291
- scale: 2,
292
- objectFit: "contain"
293
- })], [computed(() => slot.type === "skill" && slot.skill), () => h(DOMElement, {
294
- element: "span",
295
- attrs: { class: "rpg-ui-hotbar-text action-battle-actionbar-text" },
296
- textContent: slot.skill.name
297
- })], [computed(() => slot.type === "item" && slot.item), () => h(DOMElement, {
298
- element: "span",
299
- attrs: { class: "rpg-ui-hotbar-text action-battle-actionbar-text" },
300
- textContent: slot.item.name
301
- })]),
302
- cond(computed(() => slot.type === "item" && slot.item), () => h(DOMElement, {
303
- element: "span",
304
- attrs: { class: "rpg-ui-hotbar-count action-battle-actionbar-count" },
305
- textContent: "x" + getItemQuantity(slot.item)
306
- }))
307
- ]))))));
33
+ if (profile.startupMs <= 0) {
34
+ step();
35
+ return null;
36
+ }
37
+ return scheduler(step, profile.startupMs);
38
+ }
39
+ var attackIdCounter = 0;
40
+ function createActionBattleAttackId(attackerId, profileId) {
41
+ attackIdCounter++;
42
+ return `${attackerId ?? "unknown"}:${profileId}:${Date.now()}:${attackIdCounter}`;
308
43
  }
309
- var __ce_component = component;
44
+ var getTargetKey = (target) => {
45
+ if (!target || target.id === void 0 || target.id === null) return null;
46
+ return String(target.id);
47
+ };
48
+ var ActionBattleHitTracker = class {
49
+ hitPolicy;
50
+ hitTargets = /* @__PURE__ */ new Set();
51
+ constructor(hitPolicy) {
52
+ this.hitPolicy = hitPolicy;
53
+ }
54
+ canHit(target) {
55
+ if (this.hitPolicy === "allowRepeatHits") return true;
56
+ const key = getTargetKey(target);
57
+ return !key || !this.hitTargets.has(key);
58
+ }
59
+ recordHit(target) {
60
+ const key = getTargetKey(target);
61
+ if (key) this.hitTargets.add(key);
62
+ }
63
+ tryHit(target) {
64
+ if (!this.canHit(target)) return false;
65
+ this.recordHit(target);
66
+ return true;
67
+ }
68
+ };
310
69
  //#endregion
311
- export { __ce_component as default };
70
+ export { ACTION_BATTLE_HITBOX_FRAME_MS, ActionBattleHitTracker, createActionBattleAttackId, getNormalizedActionBattleAttackProfile, resolveActionBattleHitboxSpeed, runActionBattleActiveHitbox, scheduleActionBattleStartup };
@@ -1,37 +1,37 @@
1
- //#region src/targeting.ts
2
- var normalizeMaskRows = (mask) => {
3
- if (!mask) return ["#"];
4
- if (Array.isArray(mask)) return mask;
5
- return mask.trim().split("\n").map((row) => row.replace(/\r/g, ""));
1
+ //#region src/attack-input.ts
2
+ var ACTION_BATTLE_DIRECTIONS = new Set([
3
+ "up",
4
+ "down",
5
+ "left",
6
+ "right"
7
+ ]);
8
+ var normalizeDirection = (value) => {
9
+ if (typeof value !== "string") return void 0;
10
+ return ACTION_BATTLE_DIRECTIONS.has(value) ? value : void 0;
6
11
  };
7
- var parseAoeMask = (mask) => {
8
- const rows = normalizeMaskRows(mask);
9
- const height = rows.length;
10
- const width = rows.reduce((max, row) => Math.max(max, row.length), 0);
11
- const centerX = Math.floor(width / 2);
12
- const centerY = Math.floor(height / 2);
13
- const cells = [];
14
- rows.forEach((row, y) => {
15
- for (let x = 0; x < row.length; x++) {
16
- const char = row[x];
17
- if (char && char !== "." && char !== " ") cells.push({
18
- dx: x - centerX,
19
- dy: y - centerY
20
- });
12
+ var resolveActionBattleAttackDirection = (entity, input) => {
13
+ const payloadDirection = normalizeDirection(input?.data?.direction) ?? normalizeDirection(input?.data?.attackDirection) ?? normalizeDirection(input?.direction);
14
+ if (payloadDirection) return payloadDirection;
15
+ if (typeof entity?.getDirection === "function") {
16
+ const direction = normalizeDirection(entity.getDirection());
17
+ if (direction) return direction;
18
+ }
19
+ if (typeof entity?.direction === "function") {
20
+ const direction = normalizeDirection(entity.direction());
21
+ if (direction) return direction;
22
+ }
23
+ return normalizeDirection(entity?.direction) ?? "down";
24
+ };
25
+ var applyActionBattleAttackDirection = (entity, direction) => {
26
+ if (typeof entity?.changeDirection === "function") {
27
+ const previousDirectionFixed = entity.directionFixed;
28
+ if (previousDirectionFixed === true) entity.directionFixed = false;
29
+ try {
30
+ entity.changeDirection(direction);
31
+ } finally {
32
+ if (previousDirectionFixed === true) entity.directionFixed = previousDirectionFixed;
21
33
  }
22
- });
23
- if (cells.length === 0) cells.push({
24
- dx: 0,
25
- dy: 0
26
- });
27
- return {
28
- width,
29
- height,
30
- centerX,
31
- centerY,
32
- cells
33
- };
34
+ }
34
35
  };
35
- var manhattanDistance = (a, b) => Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
36
36
  //#endregion
37
- export { manhattanDistance, parseAoeMask };
37
+ export { applyActionBattleAttackDirection, resolveActionBattleAttackDirection };