pokemon-io-core 0.0.70 → 0.0.71

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.
@@ -16,15 +16,44 @@ export interface BattleRuntime {
16
16
  statusesById: Record<StatusId, StatusDefinition>;
17
17
  typeEffectiveness: TypeEffectivenessMatrix;
18
18
  }
19
+ /**
20
+ * Slot de equipo: UN luchador con sus stats base y movimientos.
21
+ * OJO: aquí NO van los items; los items son por jugador.
22
+ */
19
23
  export interface PlayerFighterConfig {
20
24
  fighter: FighterDefinition;
21
25
  maxHp: number;
22
26
  moves: MoveDefinition[];
23
- items: ItemDefinition[];
27
+ amulet: AmuletDefinition | null;
28
+ }
29
+ /**
30
+ * Configuración de un jugador para el combate.
31
+ *
32
+ * - Forma nueva (multi-team): usar `team`.
33
+ * - Forma legacy (1 vs 1): usar fighter/maxHp/moves/items/amulet como hasta ahora.
34
+ * Si `team` no viene o está vacío, el engine construye un equipo de 1 con esos datos.
35
+ */
36
+ export interface FighterSlotConfig {
37
+ fighter: FighterDefinition;
38
+ maxHp: number;
39
+ moves: MoveDefinition[];
24
40
  amulet: AmuletDefinition | null;
25
41
  }
26
42
  export interface PlayerBattleConfig {
27
- team: PlayerFighterConfig[];
43
+ /**
44
+ * Nueva forma: equipo completo. Si existe y tiene elementos,
45
+ * el engine usará esto como fuente de verdad.
46
+ */
47
+ team?: FighterSlotConfig[];
48
+ /**
49
+ * Forma legacy (1 vs 1). Se mantiene para compatibilidad
50
+ * con skins y backends actuales.
51
+ */
52
+ fighter: FighterDefinition;
53
+ maxHp: number;
54
+ moves: MoveDefinition[];
55
+ items: ItemDefinition[];
56
+ amulet: AmuletDefinition | null;
28
57
  }
29
58
  export interface BattleConfig {
30
59
  types: TypeDefinition[];
@@ -30,29 +30,26 @@ const cloneStats = (stats) => ({
30
30
  // ------------------------------------------------------
31
31
  // Creación de estado inicial
32
32
  // ------------------------------------------------------
33
- const createBattleFighter = (cfg) => {
34
- if (cfg.moves.length !== 4) {
35
- throw new Error("Each fighter must have exactly 4 moves in MVP");
36
- }
37
- if (cfg.items.length > 4) {
38
- throw new Error("A fighter cannot have more than 4 items");
39
- }
33
+ const createBattleFighter = (slot, playerItems) => {
40
34
  return {
41
- fighterId: cfg.fighter.id,
42
- classId: cfg.fighter.classId,
43
- maxHp: cfg.maxHp,
44
- currentHp: cfg.maxHp,
45
- baseStats: cloneStats(cfg.fighter.baseStats),
46
- effectiveStats: cloneStats(cfg.fighter.baseStats),
47
- moves: cfg.moves.map((move) => ({
48
- moveId: move.id,
49
- currentPP: move.maxPP,
35
+ fighterId: slot.fighter.id,
36
+ classId: slot.fighter.classId,
37
+ maxHp: slot.maxHp,
38
+ currentHp: slot.maxHp,
39
+ baseStats: slot.fighter.baseStats,
40
+ effectiveStats: slot.fighter.baseStats,
41
+ moves: slot.moves.map((m) => ({
42
+ moveId: m.id,
43
+ currentPP: m.maxPP,
50
44
  })),
51
- items: cfg.items.map((item) => ({
52
- itemId: item.id,
53
- usesRemaining: item.maxUses,
45
+ // ⚠️ De momento mantenemos el comportamiento actual:
46
+ // cada luchador tiene su copia de items.
47
+ // Más adelante, si quieres, los movemos a nivel jugador.
48
+ items: playerItems.map((it) => ({
49
+ itemId: it.id,
50
+ usesRemaining: it.maxUses ?? 1,
54
51
  })),
55
- amuletId: cfg.amulet ? cfg.amulet.id : null,
52
+ amuletId: slot.amulet?.id ?? null,
56
53
  statuses: [],
57
54
  isAlive: true,
58
55
  };
@@ -89,11 +86,37 @@ const recomputeEffectiveStatsForFighter = (state, fighter) => {
89
86
  effectiveStats: eff,
90
87
  };
91
88
  };
89
+ const normalizeTeamFromConfig = (cfg) => {
90
+ // Si ya viene en forma de equipo, úsalo tal cual
91
+ if (cfg.team && cfg.team.length > 0) {
92
+ return cfg.team;
93
+ }
94
+ // Forma legacy: un solo fighter → lo envolvemos en un array
95
+ return [
96
+ {
97
+ fighter: cfg.fighter,
98
+ maxHp: cfg.maxHp,
99
+ moves: cfg.moves,
100
+ amulet: cfg.amulet,
101
+ },
102
+ ];
103
+ };
92
104
  const createPlayerBattleState = (cfg) => {
93
- const fighterTeam = cfg.team.map((f) => createBattleFighter(f));
105
+ // Si viene team, lo usamos; si no, construimos equipo de 1 (modo legacy)
106
+ const teamSlots = cfg.team && cfg.team.length > 0
107
+ ? cfg.team
108
+ : [
109
+ {
110
+ fighter: cfg.fighter,
111
+ maxHp: cfg.maxHp,
112
+ moves: cfg.moves,
113
+ amulet: cfg.amulet,
114
+ },
115
+ ];
116
+ const fighterTeam = teamSlots.map((slot) => createBattleFighter(slot, cfg.items));
94
117
  return {
95
118
  fighterTeam,
96
- activeIndex: 0, // siempre el primero al empezar
119
+ activeIndex: 0,
97
120
  };
98
121
  };
99
122
  export const createInitialBattleState = (config) => {
@@ -2,9 +2,24 @@ import type { TypeDefinition, TypeEffectivenessMatrix, MoveDefinition, ItemDefin
2
2
  import type { PlayerBattleConfig } from "../core/engine.js";
3
3
  export interface FighterLoadout {
4
4
  fighterId: string | null;
5
+ moveIds: string[];
5
6
  itemIds: string[];
6
7
  amuletId: string | null;
7
- moveIds: string[];
8
+ /**
9
+ * Lista de luchadores del equipo (máx. 6).
10
+ * Si solo hay uno, puede contener un único id.
11
+ */
12
+ fighterIds?: string[];
13
+ /**
14
+ * Movimientos por luchador. Si falta para alguno, se usan
15
+ * `moveIds` como fallback.
16
+ */
17
+ movesByFighterId?: Record<string, string[]>;
18
+ /**
19
+ * (Opcional) Futuro: cuál es el activo actual.
20
+ * Si no se define, se asume fighterIds[0].
21
+ */
22
+ activeFighterId?: string | null;
8
23
  }
9
24
  export interface CombatSkin {
10
25
  readonly id: string;
@@ -71,22 +71,31 @@ export class TribeSkin {
71
71
  if (!loadout.fighterId) {
72
72
  throw new Error("fighterId is required in FighterLoadout");
73
73
  }
74
+ console.log("buildPlayerConfig", loadout.fighterId);
74
75
  const fighter = findTribeFighterById(loadout.fighterId);
75
76
  if (!fighter) {
76
- throw new Error(`Unknown fighterId for tribe skin: ${loadout.fighterId}`);
77
+ throw new Error(`Unknown fighterId for Pokemon skin: ${loadout.fighterId}`);
77
78
  }
78
79
  const moves = buildMovesFromLoadout(fighter, loadout);
79
80
  const items = buildItemsFromLoadout(loadout);
81
+ const maxHp = fighter.baseStats.defense + fighter.baseStats.offense;
80
82
  return {
83
+ // ✅ NUEVO: modelo multi-equipo
81
84
  team: [
82
85
  {
83
86
  fighter,
84
- maxHp: fighter.baseStats.defense + fighter.baseStats.offense,
87
+ maxHp,
85
88
  moves,
86
- items,
87
89
  amulet: null,
88
90
  },
89
91
  ],
92
+ // ✅ LEGACY: seguimos rellenando los campos antiguos
93
+ // por si algún sitio sigue leyéndolos.
94
+ fighter,
95
+ maxHp,
96
+ moves,
97
+ items,
98
+ amulet: null,
90
99
  };
91
100
  }
92
101
  }
@@ -70,22 +70,31 @@ export class PokemonSkin {
70
70
  if (!loadout.fighterId) {
71
71
  throw new Error("fighterId is required in FighterLoadout");
72
72
  }
73
+ console.log("buildPlayerConfig", loadout.fighterId);
73
74
  const fighter = findPokemonById(loadout.fighterId);
74
75
  if (!fighter) {
75
76
  throw new Error(`Unknown fighterId for Pokemon skin: ${loadout.fighterId}`);
76
77
  }
77
78
  const moves = buildMovesFromLoadout(fighter, loadout);
78
79
  const items = buildItemsFromLoadout(loadout);
80
+ const maxHp = fighter.baseStats.defense + fighter.baseStats.offense;
79
81
  return {
82
+ // ✅ NUEVO: modelo multi-equipo
80
83
  team: [
81
84
  {
82
85
  fighter,
83
- maxHp: fighter.baseStats.defense + fighter.baseStats.offense,
86
+ maxHp,
84
87
  moves,
85
- items,
86
88
  amulet: null,
87
89
  },
88
90
  ],
91
+ // ✅ LEGACY: seguimos rellenando los campos antiguos
92
+ // por si algún sitio sigue leyéndolos.
93
+ fighter,
94
+ maxHp,
95
+ moves,
96
+ items,
97
+ amulet: null,
89
98
  };
90
99
  }
91
100
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pokemon-io-core",
3
- "version": "0.0.70",
3
+ "version": "0.0.71",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "type": "module",