@bct-app/game-engine 0.1.6-beta.3 → 0.1.6-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -10,6 +10,21 @@ type TApplyOperationToPlayersArgs = {
10
10
  };
11
11
  declare const applyOperationToPlayers: ({ players, operations, allAbilities, characters, timelines, timelineIndexAtNow, }: TApplyOperationToPlayersArgs) => TPlayer[];
12
12
 
13
+ type TCanInvokeAbilityArgs = {
14
+ ability: TAbility;
15
+ effector: TPlayer | undefined;
16
+ currentTimelineIdx: number;
17
+ timelines: TTimeline[];
18
+ priorOperations?: TOperation[];
19
+ };
20
+ type TCanInvokeAbilityResult = {
21
+ allowed: true;
22
+ } | {
23
+ allowed: false;
24
+ reason: string;
25
+ };
26
+ declare const canInvokeAbility: ({ ability, effector, currentTimelineIdx, timelines, priorOperations, }: TCanInvokeAbilityArgs) => TCanInvokeAbilityResult;
27
+
13
28
  declare const transformEmptyArray: <T>(arr: T[]) => T[];
14
29
  declare const copyPlayers: (players: TPlayer[]) => TPlayer[];
15
30
  declare const buildPlayerSeatMap: (players: TPlayer[]) => Map<number, TPlayer>;
@@ -42,4 +57,4 @@ declare const isReminder: (value: unknown) => value is TReminder;
42
57
  */
43
58
  declare const isPlayerReminderArray: (value: unknown) => value is TPlayerReminder[];
44
59
 
45
- export { adjustValueAsNumber, adjustValueAsNumberArray, applyOperationToPlayers, buildPlayerSeatMap, copyPlayers, getSourceValue, getValueFromPayloads, isNumberOrNumberArray, isPlayerReminderArray, isReminder, resolveSourceValue, transformEmptyArray };
60
+ export { type TCanInvokeAbilityArgs, type TCanInvokeAbilityResult, adjustValueAsNumber, adjustValueAsNumberArray, applyOperationToPlayers, buildPlayerSeatMap, canInvokeAbility, copyPlayers, getSourceValue, getValueFromPayloads, isNumberOrNumberArray, isPlayerReminderArray, isReminder, resolveSourceValue, transformEmptyArray };
package/dist/index.d.ts CHANGED
@@ -10,6 +10,21 @@ type TApplyOperationToPlayersArgs = {
10
10
  };
11
11
  declare const applyOperationToPlayers: ({ players, operations, allAbilities, characters, timelines, timelineIndexAtNow, }: TApplyOperationToPlayersArgs) => TPlayer[];
12
12
 
13
+ type TCanInvokeAbilityArgs = {
14
+ ability: TAbility;
15
+ effector: TPlayer | undefined;
16
+ currentTimelineIdx: number;
17
+ timelines: TTimeline[];
18
+ priorOperations?: TOperation[];
19
+ };
20
+ type TCanInvokeAbilityResult = {
21
+ allowed: true;
22
+ } | {
23
+ allowed: false;
24
+ reason: string;
25
+ };
26
+ declare const canInvokeAbility: ({ ability, effector, currentTimelineIdx, timelines, priorOperations, }: TCanInvokeAbilityArgs) => TCanInvokeAbilityResult;
27
+
13
28
  declare const transformEmptyArray: <T>(arr: T[]) => T[];
14
29
  declare const copyPlayers: (players: TPlayer[]) => TPlayer[];
15
30
  declare const buildPlayerSeatMap: (players: TPlayer[]) => Map<number, TPlayer>;
@@ -42,4 +57,4 @@ declare const isReminder: (value: unknown) => value is TReminder;
42
57
  */
43
58
  declare const isPlayerReminderArray: (value: unknown) => value is TPlayerReminder[];
44
59
 
45
- export { adjustValueAsNumber, adjustValueAsNumberArray, applyOperationToPlayers, buildPlayerSeatMap, copyPlayers, getSourceValue, getValueFromPayloads, isNumberOrNumberArray, isPlayerReminderArray, isReminder, resolveSourceValue, transformEmptyArray };
60
+ export { type TCanInvokeAbilityArgs, type TCanInvokeAbilityResult, adjustValueAsNumber, adjustValueAsNumberArray, applyOperationToPlayers, buildPlayerSeatMap, canInvokeAbility, copyPlayers, getSourceValue, getValueFromPayloads, isNumberOrNumberArray, isPlayerReminderArray, isReminder, resolveSourceValue, transformEmptyArray };
package/dist/index.js CHANGED
@@ -193,7 +193,7 @@ var createEffectHandler = (type, handler) => {
193
193
  };
194
194
 
195
195
  // src/effects/handlers/ability-change.ts
196
- var toAbilityIdList = (value) => {
196
+ var toIdList = (value) => {
197
197
  if (typeof value === "string") {
198
198
  return value.length > 0 ? [value] : void 0;
199
199
  }
@@ -211,8 +211,8 @@ var applyAbilityChange = createEffectHandler("ABILITY_CHANGE", ({
211
211
  writableInputs,
212
212
  getSnapshotSeatMap,
213
213
  abilityMap,
214
- makePlayersEffect,
215
- characterMap
214
+ characterMap,
215
+ makePlayersEffect
216
216
  }) => {
217
217
  const resolvedRaw = resolveSourceValue(
218
218
  effect.source,
@@ -220,45 +220,49 @@ var applyAbilityChange = createEffectHandler("ABILITY_CHANGE", ({
220
220
  payloads,
221
221
  effector,
222
222
  getSnapshotSeatMap(),
223
- (player) => player.abilities,
223
+ (player) => player.characterId,
224
224
  (value) => typeof value === "string" && value.length > 0 || Array.isArray(value) && value.every((item) => typeof item === "string"),
225
- (characterId) => {
226
- const character = characterMap.get(characterId);
227
- if (!character) {
228
- console.warn("Character not found for ABILITY_CHANGE effect source:", characterId);
229
- return [];
230
- }
231
- return character.abilities.map((a) => a.id);
232
- }
225
+ (characterId) => characterId
233
226
  );
234
- const resolvedAbilityIds = toAbilityIdList(resolvedRaw);
235
- if (!resolvedAbilityIds) {
236
- console.warn("Ability ID not found for ABILITY_CHANGE effect:", effect.source);
227
+ const resolvedCharacterIds = toIdList(resolvedRaw);
228
+ if (!resolvedCharacterIds) {
229
+ console.warn("Character ID not found for ABILITY_CHANGE effect:", effect.source);
237
230
  return;
238
231
  }
232
+ const mode = effect.mode ?? "REPLACE";
239
233
  makePlayersEffect.forEach((player) => {
240
234
  const overrideRaw = operation.abilityChangeOverrides?.[String(player.seat)];
241
- const overrideIds = toAbilityIdList(overrideRaw);
242
- const finalAbilityIds = overrideIds ?? resolvedAbilityIds;
243
- finalAbilityIds.forEach((finalAbilityId) => {
244
- const newAbility = abilityMap.get(finalAbilityId);
245
- if (!newAbility) {
246
- console.warn("Ability not found for ABILITY_CHANGE effect:", finalAbilityId);
247
- return;
248
- }
249
- const replaceAtSameStage = (abilities) => {
250
- const idx = abilities.findIndex((aid) => abilityMap.get(aid)?.stage === newAbility.stage);
251
- if (idx >= 0) {
252
- abilities[idx] = finalAbilityId;
253
- } else {
254
- abilities.push(finalAbilityId);
235
+ const overrideIds = toIdList(overrideRaw);
236
+ const finalCharacterIds = overrideIds ?? resolvedCharacterIds;
237
+ if (!player.gainCharactersAbility) {
238
+ player.gainCharactersAbility = [];
239
+ }
240
+ if (mode === "REPLACE") {
241
+ player.gainCharactersAbility = [...finalCharacterIds];
242
+ } else {
243
+ for (const characterId of finalCharacterIds) {
244
+ if (!player.gainCharactersAbility.includes(characterId)) {
245
+ player.gainCharactersAbility.push(characterId);
255
246
  }
256
- };
257
- replaceAtSameStage(player.abilities);
258
- if (player.perceivedCharacter?.asCharacter) {
259
- replaceAtSameStage(player.perceivedCharacter.abilities);
260
247
  }
261
- });
248
+ }
249
+ if (player.perceivedCharacter?.asCharacter) {
250
+ const perceived = player.perceivedCharacter;
251
+ finalCharacterIds.forEach((characterId) => {
252
+ const character = characterMap.get(characterId);
253
+ if (!character) return;
254
+ character.abilities.forEach((newAbility) => {
255
+ const idx = perceived.abilities.findIndex(
256
+ (aid) => abilityMap.get(aid)?.stage === newAbility.stage
257
+ );
258
+ if (idx >= 0) {
259
+ perceived.abilities[idx] = newAbility.id;
260
+ } else {
261
+ perceived.abilities.push(newAbility.id);
262
+ }
263
+ });
264
+ });
265
+ }
262
266
  });
263
267
  });
264
268
 
package/dist/index.mjs CHANGED
@@ -155,7 +155,7 @@ var createEffectHandler = (type, handler) => {
155
155
  };
156
156
 
157
157
  // src/effects/handlers/ability-change.ts
158
- var toAbilityIdList = (value) => {
158
+ var toIdList = (value) => {
159
159
  if (typeof value === "string") {
160
160
  return value.length > 0 ? [value] : void 0;
161
161
  }
@@ -173,8 +173,8 @@ var applyAbilityChange = createEffectHandler("ABILITY_CHANGE", ({
173
173
  writableInputs,
174
174
  getSnapshotSeatMap,
175
175
  abilityMap,
176
- makePlayersEffect,
177
- characterMap
176
+ characterMap,
177
+ makePlayersEffect
178
178
  }) => {
179
179
  const resolvedRaw = resolveSourceValue(
180
180
  effect.source,
@@ -182,45 +182,49 @@ var applyAbilityChange = createEffectHandler("ABILITY_CHANGE", ({
182
182
  payloads,
183
183
  effector,
184
184
  getSnapshotSeatMap(),
185
- (player) => player.abilities,
185
+ (player) => player.characterId,
186
186
  (value) => typeof value === "string" && value.length > 0 || Array.isArray(value) && value.every((item) => typeof item === "string"),
187
- (characterId) => {
188
- const character = characterMap.get(characterId);
189
- if (!character) {
190
- console.warn("Character not found for ABILITY_CHANGE effect source:", characterId);
191
- return [];
192
- }
193
- return character.abilities.map((a) => a.id);
194
- }
187
+ (characterId) => characterId
195
188
  );
196
- const resolvedAbilityIds = toAbilityIdList(resolvedRaw);
197
- if (!resolvedAbilityIds) {
198
- console.warn("Ability ID not found for ABILITY_CHANGE effect:", effect.source);
189
+ const resolvedCharacterIds = toIdList(resolvedRaw);
190
+ if (!resolvedCharacterIds) {
191
+ console.warn("Character ID not found for ABILITY_CHANGE effect:", effect.source);
199
192
  return;
200
193
  }
194
+ const mode = effect.mode ?? "REPLACE";
201
195
  makePlayersEffect.forEach((player) => {
202
196
  const overrideRaw = operation.abilityChangeOverrides?.[String(player.seat)];
203
- const overrideIds = toAbilityIdList(overrideRaw);
204
- const finalAbilityIds = overrideIds ?? resolvedAbilityIds;
205
- finalAbilityIds.forEach((finalAbilityId) => {
206
- const newAbility = abilityMap.get(finalAbilityId);
207
- if (!newAbility) {
208
- console.warn("Ability not found for ABILITY_CHANGE effect:", finalAbilityId);
209
- return;
210
- }
211
- const replaceAtSameStage = (abilities) => {
212
- const idx = abilities.findIndex((aid) => abilityMap.get(aid)?.stage === newAbility.stage);
213
- if (idx >= 0) {
214
- abilities[idx] = finalAbilityId;
215
- } else {
216
- abilities.push(finalAbilityId);
197
+ const overrideIds = toIdList(overrideRaw);
198
+ const finalCharacterIds = overrideIds ?? resolvedCharacterIds;
199
+ if (!player.gainCharactersAbility) {
200
+ player.gainCharactersAbility = [];
201
+ }
202
+ if (mode === "REPLACE") {
203
+ player.gainCharactersAbility = [...finalCharacterIds];
204
+ } else {
205
+ for (const characterId of finalCharacterIds) {
206
+ if (!player.gainCharactersAbility.includes(characterId)) {
207
+ player.gainCharactersAbility.push(characterId);
217
208
  }
218
- };
219
- replaceAtSameStage(player.abilities);
220
- if (player.perceivedCharacter?.asCharacter) {
221
- replaceAtSameStage(player.perceivedCharacter.abilities);
222
209
  }
223
- });
210
+ }
211
+ if (player.perceivedCharacter?.asCharacter) {
212
+ const perceived = player.perceivedCharacter;
213
+ finalCharacterIds.forEach((characterId) => {
214
+ const character = characterMap.get(characterId);
215
+ if (!character) return;
216
+ character.abilities.forEach((newAbility) => {
217
+ const idx = perceived.abilities.findIndex(
218
+ (aid) => abilityMap.get(aid)?.stage === newAbility.stage
219
+ );
220
+ if (idx >= 0) {
221
+ perceived.abilities[idx] = newAbility.id;
222
+ } else {
223
+ perceived.abilities.push(newAbility.id);
224
+ }
225
+ });
226
+ });
227
+ }
224
228
  });
225
229
  });
226
230
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bct-app/game-engine",
3
- "version": "0.1.6-beta.3",
3
+ "version": "0.1.6-beta.4",
4
4
  "description": "Game engine utilities for BCT",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -37,7 +37,7 @@
37
37
  "access": "public"
38
38
  },
39
39
  "dependencies": {
40
- "@bct-app/game-model": "0.1.3-beta.0"
40
+ "@bct-app/game-model": "0.1.3-beta.1"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@vitest/ui": "^4.1.3",