pokemon-io-core 0.0.73 → 0.0.74

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.
@@ -23,4 +23,8 @@ export interface BattleView {
23
23
  [playerId: string]: number;
24
24
  };
25
25
  turnNumber: number;
26
+ pendingActions?: {
27
+ player1: boolean;
28
+ player2: boolean;
29
+ };
26
30
  }
@@ -1,6 +1,9 @@
1
- export interface PlayerLoadoutView {
2
- fighterId: string | null;
1
+ export interface PlayerLoadoutFighterView {
2
+ fighterId: string;
3
3
  moveIds: string[];
4
+ }
5
+ export interface PlayerLoadoutView {
6
+ fighters: PlayerLoadoutFighterView[];
4
7
  itemIds: string[];
5
8
  amuletId: string | null;
6
9
  }
@@ -20,8 +20,10 @@ export interface ClientToServerEvents {
20
20
  }) => void;
21
21
  "room:setLoadout": (payload: {
22
22
  roomId: string;
23
- fighterId: string;
24
- moveIds: string[];
23
+ fighters: {
24
+ fighterId: string;
25
+ moveIds: string[];
26
+ }[];
25
27
  itemIds: string[];
26
28
  amuletId?: string | null;
27
29
  }) => void;
@@ -22,7 +22,6 @@ export interface BattleFighter {
22
22
  baseStats: FighterStats;
23
23
  effectiveStats: FighterStats;
24
24
  moves: EquippedMove[];
25
- items: EquippedItem[];
26
25
  amuletId: AmuletId | null;
27
26
  statuses: ActiveStatus[];
28
27
  isAlive: boolean;
@@ -30,6 +29,7 @@ export interface BattleFighter {
30
29
  export interface PlayerBattleState {
31
30
  fighterTeam: BattleFighter[];
32
31
  activeIndex: number;
32
+ inventory: EquippedItem[];
33
33
  }
34
34
  export interface BattleState {
35
35
  turnNumber: number;
@@ -16,10 +16,14 @@ export interface BattleRuntime {
16
16
  statusesById: Record<StatusId, StatusDefinition>;
17
17
  typeEffectiveness: TypeEffectivenessMatrix;
18
18
  }
19
- export interface PlayerBattleConfig {
19
+ export interface PlayerFighterBattleConfig {
20
20
  fighter: FighterDefinition;
21
21
  maxHp: number;
22
22
  moves: MoveDefinition[];
23
+ amulet: AmuletDefinition | null;
24
+ }
25
+ export interface PlayerBattleConfig {
26
+ fighters: PlayerFighterBattleConfig[];
23
27
  items: ItemDefinition[];
24
28
  amulet: AmuletDefinition | null;
25
29
  }
@@ -34,9 +34,6 @@ const createBattleFighter = (cfg) => {
34
34
  if (cfg.moves.length !== 4) {
35
35
  throw new Error("Each fighter must have exactly 4 moves in MVP");
36
36
  }
37
- if (cfg.items.length > 4) {
38
- throw new Error("A fighter cannot have more than 4 items");
39
- }
40
37
  return {
41
38
  fighterId: cfg.fighter.id,
42
39
  classId: cfg.fighter.classId,
@@ -48,10 +45,6 @@ const createBattleFighter = (cfg) => {
48
45
  moveId: move.id,
49
46
  currentPP: move.maxPP,
50
47
  })),
51
- items: cfg.items.map((item) => ({
52
- itemId: item.id,
53
- usesRemaining: item.maxUses,
54
- })),
55
48
  amuletId: cfg.amulet ? cfg.amulet.id : null,
56
49
  statuses: [],
57
50
  isAlive: true,
@@ -90,10 +83,15 @@ const recomputeEffectiveStatsForFighter = (state, fighter) => {
90
83
  };
91
84
  };
92
85
  const createPlayerBattleState = (cfg) => {
93
- const fighter = createBattleFighter(cfg);
86
+ const team = cfg.fighters.map((fCfg) => createBattleFighter(fCfg));
87
+ const inventory = cfg.items.map((item) => ({
88
+ itemId: item.id,
89
+ usesRemaining: item.maxUses,
90
+ }));
94
91
  return {
95
- fighterTeam: [fighter],
92
+ fighterTeam: team,
96
93
  activeIndex: 0,
94
+ inventory,
97
95
  };
98
96
  };
99
97
  export const createInitialBattleState = (config) => {
@@ -132,6 +130,16 @@ const getOpponentAndSelf = (state, playerKey) => {
132
130
  opponent: getActiveFighter(oppPlayer),
133
131
  };
134
132
  };
133
+ const getPlayersAndActives = (state, playerKey) => {
134
+ const selfPlayer = playerKey === "player1" ? state.player1 : state.player2;
135
+ const oppPlayer = playerKey === "player1" ? state.player2 : state.player1;
136
+ return {
137
+ selfPlayer,
138
+ oppPlayer,
139
+ self: getActiveFighter(selfPlayer),
140
+ opponent: getActiveFighter(oppPlayer),
141
+ };
142
+ };
135
143
  const getTypeEffectiveness = (state, attackerTypeId, defenderTypeId) => {
136
144
  const matrix = state.runtime.typeEffectiveness;
137
145
  const row = matrix[attackerTypeId];
@@ -634,9 +642,9 @@ const resolveItemUse = (state, playerKey, action) => {
634
642
  if (action.kind !== "use_item") {
635
643
  return { state, events: [] };
636
644
  }
637
- const { self, opponent } = getOpponentAndSelf(state, playerKey);
645
+ const { selfPlayer, oppPlayer, self, opponent } = getPlayersAndActives(state, playerKey);
638
646
  const events = [];
639
- const itemSlot = self.items[action.itemIndex];
647
+ const itemSlot = selfPlayer.inventory[action.itemIndex];
640
648
  if (!itemSlot || itemSlot.usesRemaining <= 0) {
641
649
  dbg("use_item: no charges", {
642
650
  playerKey,
@@ -652,10 +660,10 @@ const resolveItemUse = (state, playerKey, action) => {
652
660
  });
653
661
  return { state, events };
654
662
  }
655
- const updatedItems = self.items.map((it, idx) => idx === action.itemIndex
663
+ const updatedInventory = selfPlayer.inventory.map((it, idx) => idx === action.itemIndex
656
664
  ? { ...it, usesRemaining: Math.max(0, it.usesRemaining - 1) }
657
665
  : it);
658
- let updatedSelf = { ...self, items: updatedItems };
666
+ let updatedSelf = { ...self };
659
667
  let updatedOpponent = { ...opponent };
660
668
  events.push({
661
669
  ...createBaseEvent(state.turnNumber, "action_declared", `${self.fighterId} usó ${itemDef.name}`),
@@ -664,7 +672,26 @@ const resolveItemUse = (state, playerKey, action) => {
664
672
  const { actor: finalSelf, target: finalOpp, events: extraEvents, } = applyEffectsOnTarget(state, updatedSelf, updatedOpponent, null, // los items no usan fórmula de tipo por ahora
665
673
  false, itemDef.effects);
666
674
  events.push(...extraEvents);
667
- const newState = updateFightersInState(state, playerKey, finalSelf, finalOpp);
675
+ let newState = updateFightersInState(state, playerKey, finalSelf, finalOpp);
676
+ // persistimos el inventario gastado en el jugador que actuó
677
+ if (playerKey === "player1") {
678
+ newState = {
679
+ ...newState,
680
+ player1: {
681
+ ...newState.player1,
682
+ inventory: updatedInventory,
683
+ },
684
+ };
685
+ }
686
+ else {
687
+ newState = {
688
+ ...newState,
689
+ player2: {
690
+ ...newState.player2,
691
+ inventory: updatedInventory,
692
+ },
693
+ };
694
+ }
668
695
  return { state: newState, events };
669
696
  };
670
697
  // ------------------------------------------------------
@@ -1,10 +1,13 @@
1
1
  import type { TypeDefinition, TypeEffectivenessMatrix, MoveDefinition, ItemDefinition, AmuletDefinition, StatusDefinition } from "../core/index.js";
2
2
  import type { PlayerBattleConfig } from "../core/engine.js";
3
- export interface FighterLoadout {
3
+ export interface TeamFighterLoadout {
4
4
  fighterId: string | null;
5
+ moveIds: string[];
6
+ }
7
+ export interface PlayerTeamLoadout {
8
+ fighters: TeamFighterLoadout[];
5
9
  itemIds: string[];
6
10
  amuletId: string | null;
7
- moveIds: string[];
8
11
  }
9
12
  export interface CombatSkin {
10
13
  readonly id: string;
@@ -14,5 +17,5 @@ export interface CombatSkin {
14
17
  getItems(): ItemDefinition[];
15
18
  getAmulets(): AmuletDefinition[];
16
19
  getStatuses(): StatusDefinition[];
17
- buildPlayerConfig(loadout: FighterLoadout): PlayerBattleConfig;
20
+ buildPlayerConfig(loadout: PlayerTeamLoadout): PlayerBattleConfig;
18
21
  }
@@ -1,5 +1,5 @@
1
1
  import { ItemDefinition, MoveDefinition, PlayerBattleConfig } from "../../core/index.js";
2
- import type { CombatSkin, FighterLoadout } from "../CombatSkin.js";
2
+ import type { CombatSkin, PlayerTeamLoadout } from "../CombatSkin.js";
3
3
  export declare class TribeSkin implements CombatSkin {
4
4
  readonly id = "tribe";
5
5
  getTypes(): import("../../index.js").TypeDefinition[];
@@ -8,6 +8,6 @@ export declare class TribeSkin implements CombatSkin {
8
8
  getItems(): ItemDefinition[];
9
9
  getAmulets(): never[];
10
10
  getStatuses(): import("../../index.js").StatusDefinition[];
11
- buildPlayerConfig(loadout: FighterLoadout): PlayerBattleConfig;
11
+ buildPlayerConfig(loadout: PlayerTeamLoadout): PlayerBattleConfig;
12
12
  }
13
13
  export declare const createTribeSkin: () => CombatSkin;
@@ -13,8 +13,7 @@ const findItemById = (id) => {
13
13
  return POKEMON_ITEMS.find((i) => i.id === id) ?? null;
14
14
  };
15
15
  const FILLER_MOVE_ID = "tackle";
16
- const buildMovesFromLoadout = (fighter, loadout) => {
17
- const selectedMoveIds = loadout.moveIds ?? [];
16
+ const buildMovesFromLoadout = (fighter, selectedMoveIds) => {
18
17
  const selectedMoves = selectedMoveIds
19
18
  .map((id) => findMoveById(id))
20
19
  .filter((m) => m !== null);
@@ -68,22 +67,30 @@ export class TribeSkin {
68
67
  return TRIBE_STATUSES; // más adelante
69
68
  }
70
69
  buildPlayerConfig(loadout) {
71
- if (!loadout.fighterId) {
72
- throw new Error("fighterId is required in FighterLoadout");
70
+ if (!loadout.fighters || loadout.fighters.length === 0) {
71
+ throw new Error("fighters[] is required in PlayerTeamLoadout");
73
72
  }
74
- console.log("buildPlayerConfig", loadout.fighterId);
75
- const fighter = findPokemonById(loadout.fighterId);
76
- if (!fighter) {
77
- throw new Error(`Unknown fighterId for Pokemon skin: ${loadout.fighterId}`);
78
- }
79
- const moves = buildMovesFromLoadout(fighter, loadout);
73
+ const fighters = loadout.fighters.map((slot, idx) => {
74
+ if (!slot.fighterId) {
75
+ throw new Error(`fighterId is required in slot ${idx}`);
76
+ }
77
+ const fighter = findPokemonById(slot.fighterId);
78
+ if (!fighter) {
79
+ throw new Error(`Unknown fighterId for Pokemon skin: ${slot.fighterId}`);
80
+ }
81
+ const moves = buildMovesFromLoadout(fighter, slot.moveIds ?? []);
82
+ return {
83
+ fighter,
84
+ maxHp: fighter.baseStats.defense + fighter.baseStats.offense,
85
+ moves,
86
+ amulet: null
87
+ };
88
+ });
80
89
  const items = buildItemsFromLoadout(loadout);
81
90
  return {
82
- fighter,
83
- maxHp: fighter.baseStats.defense + fighter.baseStats.offense,
84
- moves,
91
+ fighters,
85
92
  items,
86
- amulet: null,
93
+ amulet: null
87
94
  };
88
95
  }
89
96
  }
@@ -1,5 +1,5 @@
1
1
  import { ItemDefinition, MoveDefinition, PlayerBattleConfig } from "../../core/index.js";
2
- import type { CombatSkin, FighterLoadout } from "../CombatSkin.js";
2
+ import type { CombatSkin, PlayerTeamLoadout } from "../CombatSkin.js";
3
3
  export declare class PokemonSkin implements CombatSkin {
4
4
  readonly id = "pokemon";
5
5
  getTypes(): import("../../index.js").TypeDefinition[];
@@ -8,6 +8,6 @@ export declare class PokemonSkin implements CombatSkin {
8
8
  getItems(): ItemDefinition[];
9
9
  getAmulets(): never[];
10
10
  getStatuses(): import("../../index.js").StatusDefinition[];
11
- buildPlayerConfig(loadout: FighterLoadout): PlayerBattleConfig;
11
+ buildPlayerConfig(loadout: PlayerTeamLoadout): PlayerBattleConfig;
12
12
  }
13
13
  export declare const createPokemonSkin: () => CombatSkin;
@@ -12,8 +12,7 @@ const findItemById = (id) => {
12
12
  return POKEMON_ITEMS.find((i) => i.id === id) ?? null;
13
13
  };
14
14
  const FILLER_MOVE_ID = "tackle";
15
- const buildMovesFromLoadout = (fighter, loadout) => {
16
- const selectedMoveIds = loadout.moveIds ?? [];
15
+ const buildMovesFromLoadout = (fighter, selectedMoveIds) => {
17
16
  const selectedMoves = selectedMoveIds
18
17
  .map((id) => findMoveById(id))
19
18
  .filter((m) => m !== null);
@@ -67,22 +66,30 @@ export class PokemonSkin {
67
66
  return POKEMON_STATUSES; // más adelante
68
67
  }
69
68
  buildPlayerConfig(loadout) {
70
- if (!loadout.fighterId) {
71
- throw new Error("fighterId is required in FighterLoadout");
69
+ if (!loadout.fighters || loadout.fighters.length === 0) {
70
+ throw new Error("fighters[] is required in PlayerTeamLoadout");
72
71
  }
73
- console.log("buildPlayerConfig", loadout.fighterId);
74
- const fighter = findPokemonById(loadout.fighterId);
75
- if (!fighter) {
76
- throw new Error(`Unknown fighterId for Pokemon skin: ${loadout.fighterId}`);
77
- }
78
- const moves = buildMovesFromLoadout(fighter, loadout);
72
+ const fighters = loadout.fighters.map((slot, idx) => {
73
+ if (!slot.fighterId) {
74
+ throw new Error(`fighterId is required in slot ${idx}`);
75
+ }
76
+ const fighter = findPokemonById(slot.fighterId);
77
+ if (!fighter) {
78
+ throw new Error(`Unknown fighterId for Pokemon skin: ${slot.fighterId}`);
79
+ }
80
+ const moves = buildMovesFromLoadout(fighter, slot.moveIds ?? []);
81
+ return {
82
+ fighter,
83
+ maxHp: fighter.baseStats.defense + fighter.baseStats.offense,
84
+ moves,
85
+ amulet: null
86
+ };
87
+ });
79
88
  const items = buildItemsFromLoadout(loadout);
80
89
  return {
81
- fighter,
82
- maxHp: fighter.baseStats.defense + fighter.baseStats.offense,
83
- moves,
90
+ fighters,
84
91
  items,
85
- amulet: null,
92
+ amulet: null
86
93
  };
87
94
  }
88
95
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pokemon-io-core",
3
- "version": "0.0.73",
3
+ "version": "0.0.74",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "type": "module",