pokemon-io-core 0.0.73 → 0.0.75
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/api/battle.d.ts +5 -0
- package/dist/api/room.d.ts +5 -2
- package/dist/api/socketTypes.d.ts +4 -2
- package/dist/core/battleState.d.ts +1 -1
- package/dist/core/engine.d.ts +5 -1
- package/dist/core/engine.js +95 -51
- package/dist/skins/CombatSkin.d.ts +6 -3
- package/dist/skins/cliches/clicheSkin.d.ts +2 -2
- package/dist/skins/cliches/clicheSkin.js +21 -14
- package/dist/skins/pokemon/pokemonSkin.d.ts +2 -2
- package/dist/skins/pokemon/pokemonSkin.js +21 -14
- package/package.json +1 -1
package/dist/api/battle.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export interface BattlePlayerView {
|
|
|
9
9
|
nickname: string;
|
|
10
10
|
hp: number;
|
|
11
11
|
statuses: BattlePlayerStatusView[];
|
|
12
|
+
activeFighterId: string;
|
|
12
13
|
}
|
|
13
14
|
export type BattleStatus = "ongoing" | "finished";
|
|
14
15
|
export interface BattleView {
|
|
@@ -23,4 +24,8 @@ export interface BattleView {
|
|
|
23
24
|
[playerId: string]: number;
|
|
24
25
|
};
|
|
25
26
|
turnNumber: number;
|
|
27
|
+
pendingActions?: {
|
|
28
|
+
player1: boolean;
|
|
29
|
+
player2: boolean;
|
|
30
|
+
};
|
|
26
31
|
}
|
package/dist/api/room.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
export interface
|
|
2
|
-
fighterId: string
|
|
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
|
-
|
|
24
|
-
|
|
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;
|
package/dist/core/engine.d.ts
CHANGED
|
@@ -16,10 +16,14 @@ export interface BattleRuntime {
|
|
|
16
16
|
statusesById: Record<StatusId, StatusDefinition>;
|
|
17
17
|
typeEffectiveness: TypeEffectivenessMatrix;
|
|
18
18
|
}
|
|
19
|
-
export interface
|
|
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
|
}
|
package/dist/core/engine.js
CHANGED
|
@@ -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
|
|
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:
|
|
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];
|
|
@@ -480,34 +488,6 @@ const applyEffectsOnTarget = (state, actor, target, moveTypeId, isCritical, effe
|
|
|
480
488
|
}
|
|
481
489
|
return { actor: currentActor, target: currentTarget, events };
|
|
482
490
|
};
|
|
483
|
-
const resolveSwitchFighter = (state, playerKey, action) => {
|
|
484
|
-
if (action.kind !== "switch_fighter") {
|
|
485
|
-
return { state, events: [] };
|
|
486
|
-
}
|
|
487
|
-
const events = [];
|
|
488
|
-
const player = playerKey === "player1" ? state.player1 : state.player2;
|
|
489
|
-
const from = getActiveFighter(player);
|
|
490
|
-
const to = player.fighterTeam[action.newIndex];
|
|
491
|
-
if (!to)
|
|
492
|
-
return { state, events };
|
|
493
|
-
if (!to.isAlive || to.currentHp <= 0)
|
|
494
|
-
return { state, events };
|
|
495
|
-
if (action.newIndex === player.activeIndex)
|
|
496
|
-
return { state, events };
|
|
497
|
-
const updatedPlayer = {
|
|
498
|
-
...player,
|
|
499
|
-
activeIndex: action.newIndex,
|
|
500
|
-
};
|
|
501
|
-
const newState = playerKey === "player1"
|
|
502
|
-
? { ...state, player1: updatedPlayer }
|
|
503
|
-
: { ...state, player2: updatedPlayer };
|
|
504
|
-
events.push({
|
|
505
|
-
...createBaseEvent(state.turnNumber, "fighter_switched", `${from.fighterId} cambia a ${to.fighterId}`),
|
|
506
|
-
fromFighterId: from.fighterId,
|
|
507
|
-
toFighterId: to.fighterId,
|
|
508
|
-
});
|
|
509
|
-
return { state: newState, events };
|
|
510
|
-
};
|
|
511
491
|
const getMovePriorityAndSpeed = (state, playerKey, action) => {
|
|
512
492
|
const { self } = getOpponentAndSelf(state, playerKey);
|
|
513
493
|
if (action.kind === "no_action") {
|
|
@@ -537,6 +517,53 @@ const getMovePriorityAndSpeed = (state, playerKey, action) => {
|
|
|
537
517
|
speed: self.effectiveStats.speed,
|
|
538
518
|
};
|
|
539
519
|
};
|
|
520
|
+
const resolveSwitchFighter = (state, playerKey, action) => {
|
|
521
|
+
if (action.kind !== "switch_fighter")
|
|
522
|
+
return { state, events: [] };
|
|
523
|
+
const events = [];
|
|
524
|
+
const selfPlayer = playerKey === "player1" ? state.player1 : state.player2;
|
|
525
|
+
const fromIndex = selfPlayer.activeIndex;
|
|
526
|
+
const toIndex = action.newIndex;
|
|
527
|
+
// validaciones
|
|
528
|
+
if (toIndex < 0 || toIndex >= selfPlayer.fighterTeam.length) {
|
|
529
|
+
return { state, events };
|
|
530
|
+
}
|
|
531
|
+
if (toIndex === fromIndex) {
|
|
532
|
+
return { state, events };
|
|
533
|
+
}
|
|
534
|
+
const target = selfPlayer.fighterTeam[toIndex];
|
|
535
|
+
if (!target || !target.isAlive || target.currentHp <= 0) {
|
|
536
|
+
return { state, events };
|
|
537
|
+
}
|
|
538
|
+
const fromFighter = selfPlayer.fighterTeam[fromIndex];
|
|
539
|
+
events.push({
|
|
540
|
+
...createBaseEvent(state.turnNumber, "action_declared", `${fromFighter.fighterId} cambia a ${target.fighterId}`),
|
|
541
|
+
actorId: fromFighter.fighterId,
|
|
542
|
+
});
|
|
543
|
+
// actualizar activeIndex
|
|
544
|
+
if (playerKey === "player1") {
|
|
545
|
+
return {
|
|
546
|
+
state: {
|
|
547
|
+
...state,
|
|
548
|
+
player1: {
|
|
549
|
+
...state.player1,
|
|
550
|
+
activeIndex: toIndex,
|
|
551
|
+
},
|
|
552
|
+
},
|
|
553
|
+
events,
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
return {
|
|
557
|
+
state: {
|
|
558
|
+
...state,
|
|
559
|
+
player2: {
|
|
560
|
+
...state.player2,
|
|
561
|
+
activeIndex: toIndex,
|
|
562
|
+
},
|
|
563
|
+
},
|
|
564
|
+
events,
|
|
565
|
+
};
|
|
566
|
+
};
|
|
540
567
|
// ------------------------------------------------------
|
|
541
568
|
// use_move
|
|
542
569
|
// ------------------------------------------------------
|
|
@@ -634,9 +661,9 @@ const resolveItemUse = (state, playerKey, action) => {
|
|
|
634
661
|
if (action.kind !== "use_item") {
|
|
635
662
|
return { state, events: [] };
|
|
636
663
|
}
|
|
637
|
-
const { self, opponent } =
|
|
664
|
+
const { selfPlayer, oppPlayer, self, opponent } = getPlayersAndActives(state, playerKey);
|
|
638
665
|
const events = [];
|
|
639
|
-
const itemSlot =
|
|
666
|
+
const itemSlot = selfPlayer.inventory[action.itemIndex];
|
|
640
667
|
if (!itemSlot || itemSlot.usesRemaining <= 0) {
|
|
641
668
|
dbg("use_item: no charges", {
|
|
642
669
|
playerKey,
|
|
@@ -652,10 +679,10 @@ const resolveItemUse = (state, playerKey, action) => {
|
|
|
652
679
|
});
|
|
653
680
|
return { state, events };
|
|
654
681
|
}
|
|
655
|
-
const
|
|
682
|
+
const updatedInventory = selfPlayer.inventory.map((it, idx) => idx === action.itemIndex
|
|
656
683
|
? { ...it, usesRemaining: Math.max(0, it.usesRemaining - 1) }
|
|
657
684
|
: it);
|
|
658
|
-
let updatedSelf = { ...self
|
|
685
|
+
let updatedSelf = { ...self };
|
|
659
686
|
let updatedOpponent = { ...opponent };
|
|
660
687
|
events.push({
|
|
661
688
|
...createBaseEvent(state.turnNumber, "action_declared", `${self.fighterId} usó ${itemDef.name}`),
|
|
@@ -664,7 +691,26 @@ const resolveItemUse = (state, playerKey, action) => {
|
|
|
664
691
|
const { actor: finalSelf, target: finalOpp, events: extraEvents, } = applyEffectsOnTarget(state, updatedSelf, updatedOpponent, null, // los items no usan fórmula de tipo por ahora
|
|
665
692
|
false, itemDef.effects);
|
|
666
693
|
events.push(...extraEvents);
|
|
667
|
-
|
|
694
|
+
let newState = updateFightersInState(state, playerKey, finalSelf, finalOpp);
|
|
695
|
+
// persistimos el inventario gastado en el jugador que actuó
|
|
696
|
+
if (playerKey === "player1") {
|
|
697
|
+
newState = {
|
|
698
|
+
...newState,
|
|
699
|
+
player1: {
|
|
700
|
+
...newState.player1,
|
|
701
|
+
inventory: updatedInventory,
|
|
702
|
+
},
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
else {
|
|
706
|
+
newState = {
|
|
707
|
+
...newState,
|
|
708
|
+
player2: {
|
|
709
|
+
...newState.player2,
|
|
710
|
+
inventory: updatedInventory,
|
|
711
|
+
},
|
|
712
|
+
};
|
|
713
|
+
}
|
|
668
714
|
return { state: newState, events };
|
|
669
715
|
};
|
|
670
716
|
// ------------------------------------------------------
|
|
@@ -705,10 +751,8 @@ const hasHardCc = (state, fighter) => fighter.statuses.some((st) => {
|
|
|
705
751
|
return def?.kind === "hard_cc";
|
|
706
752
|
});
|
|
707
753
|
const checkWinner = (state) => {
|
|
708
|
-
const
|
|
709
|
-
const
|
|
710
|
-
const p1Alive = f1.isAlive && f1.currentHp > 0;
|
|
711
|
-
const p2Alive = f2.isAlive && f2.currentHp > 0;
|
|
754
|
+
const p1Alive = state.player1.fighterTeam.some((f) => f.isAlive && f.currentHp > 0);
|
|
755
|
+
const p2Alive = state.player2.fighterTeam.some((f) => f.isAlive && f.currentHp > 0);
|
|
712
756
|
if (p1Alive && !p2Alive)
|
|
713
757
|
return "player1";
|
|
714
758
|
if (!p1Alive && p2Alive)
|
|
@@ -861,6 +905,11 @@ export const resolveTurn = (state, actions) => {
|
|
|
861
905
|
});
|
|
862
906
|
continue;
|
|
863
907
|
}
|
|
908
|
+
if (action.kind === "switch_fighter") {
|
|
909
|
+
const result = resolveSwitchFighter(currentState, playerKey, action);
|
|
910
|
+
currentState = result.state;
|
|
911
|
+
events.push(...result.events);
|
|
912
|
+
}
|
|
864
913
|
if (action.kind === "use_move") {
|
|
865
914
|
const result = resolveDamageMove(currentState, playerKey, action);
|
|
866
915
|
currentState = result.state;
|
|
@@ -871,11 +920,6 @@ export const resolveTurn = (state, actions) => {
|
|
|
871
920
|
currentState = result.state;
|
|
872
921
|
events.push(...result.events);
|
|
873
922
|
}
|
|
874
|
-
if (action.kind === "switch_fighter") {
|
|
875
|
-
const result = resolveSwitchFighter(currentState, playerKey, action);
|
|
876
|
-
currentState = result.state;
|
|
877
|
-
events.push(...result.events);
|
|
878
|
-
}
|
|
879
923
|
else {
|
|
880
924
|
// switch_fighter u otros no implementados aún
|
|
881
925
|
continue;
|
|
@@ -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
|
|
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:
|
|
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,
|
|
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:
|
|
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,
|
|
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.
|
|
72
|
-
throw new Error("
|
|
70
|
+
if (!loadout.fighters || loadout.fighters.length === 0) {
|
|
71
|
+
throw new Error("fighters[] is required in PlayerTeamLoadout");
|
|
73
72
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
|
|
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,
|
|
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:
|
|
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,
|
|
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.
|
|
71
|
-
throw new Error("
|
|
69
|
+
if (!loadout.fighters || loadout.fighters.length === 0) {
|
|
70
|
+
throw new Error("fighters[] is required in PlayerTeamLoadout");
|
|
72
71
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
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
|
}
|