pokemon-io-core 0.0.10 → 0.0.12
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/core/engine.js +146 -17
- package/dist/core/moves.d.ts +1 -0
- package/dist/skins/pokemon/index.d.ts +2 -0
- package/dist/skins/pokemon/index.js +2 -0
- package/dist/skins/pokemon/items.d.ts +2 -0
- package/dist/skins/pokemon/items.js +26 -0
- package/dist/skins/pokemon/moves.js +36 -16
- package/dist/skins/pokemon/pokemonSkin.d.ts +3 -4
- package/dist/skins/pokemon/pokemonSkin.js +23 -19
- package/dist/skins/pokemon/statuses.d.ts +2 -0
- package/dist/skins/pokemon/statuses.js +21 -0
- package/package.json +1 -1
package/dist/core/engine.js
CHANGED
|
@@ -175,6 +175,89 @@ const applyDamageToFighter = (state, defender, amount, actorId, isCritical) => {
|
|
|
175
175
|
}
|
|
176
176
|
return { updatedDefender, events };
|
|
177
177
|
};
|
|
178
|
+
const applyStatusToFighter = (state, target, statusId) => {
|
|
179
|
+
const def = state.runtime.statusesById[statusId];
|
|
180
|
+
if (!def)
|
|
181
|
+
return { updated: target, events: [] };
|
|
182
|
+
const events = [];
|
|
183
|
+
const existing = target.statuses.find((s) => s.statusId === statusId);
|
|
184
|
+
const duration = Math.floor(randomInRange(def.minDurationTurns, def.maxDurationTurns + 1)) ||
|
|
185
|
+
def.minDurationTurns;
|
|
186
|
+
let newStatuses = [...target.statuses];
|
|
187
|
+
if (!existing) {
|
|
188
|
+
newStatuses.push({
|
|
189
|
+
statusId,
|
|
190
|
+
stacks: 1,
|
|
191
|
+
remainingTurns: duration,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
else if (existing.stacks === 1) {
|
|
195
|
+
newStatuses = newStatuses.map((s) => s.statusId === statusId
|
|
196
|
+
? { ...s, stacks: 2, remainingTurns: duration }
|
|
197
|
+
: s);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
newStatuses = newStatuses.map((s) => s.statusId === statusId ? { ...s, remainingTurns: duration } : s);
|
|
201
|
+
}
|
|
202
|
+
events.push({
|
|
203
|
+
...createBaseEvent(state.turnNumber, "status_applied", `Se aplica ${statusId} a ${target.fighterId}`),
|
|
204
|
+
targetId: target.fighterId,
|
|
205
|
+
statusId,
|
|
206
|
+
});
|
|
207
|
+
return {
|
|
208
|
+
updated: { ...target, statuses: newStatuses },
|
|
209
|
+
events,
|
|
210
|
+
};
|
|
211
|
+
};
|
|
212
|
+
const applyHealToFighter = (state, target, amount, sourceId) => {
|
|
213
|
+
const newHp = Math.min(target.maxHp, target.currentHp + amount);
|
|
214
|
+
const healed = newHp - target.currentHp;
|
|
215
|
+
const updated = {
|
|
216
|
+
...target,
|
|
217
|
+
currentHp: newHp,
|
|
218
|
+
isAlive: newHp > 0,
|
|
219
|
+
};
|
|
220
|
+
const events = [];
|
|
221
|
+
events.push({
|
|
222
|
+
...createBaseEvent(state.turnNumber, "heal", `${sourceId} cura ${healed} a ${target.fighterId}`),
|
|
223
|
+
actorId: sourceId,
|
|
224
|
+
targetId: target.fighterId,
|
|
225
|
+
amount: healed,
|
|
226
|
+
});
|
|
227
|
+
return { updated, events };
|
|
228
|
+
};
|
|
229
|
+
const applyEffectsOnTarget = (state, actor, target, effects) => {
|
|
230
|
+
let currentActor = actor;
|
|
231
|
+
let currentTarget = target;
|
|
232
|
+
const events = [];
|
|
233
|
+
for (const eff of effects) {
|
|
234
|
+
switch (eff.kind) {
|
|
235
|
+
case "heal": {
|
|
236
|
+
const res = applyHealToFighter(state, currentActor, eff.amount, actor.fighterId);
|
|
237
|
+
currentActor = res.updated;
|
|
238
|
+
events.push(...res.events);
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
case "apply_status": {
|
|
242
|
+
const res = applyStatusToFighter(state, currentTarget, eff.statusId);
|
|
243
|
+
currentTarget = res.updated;
|
|
244
|
+
events.push(...res.events);
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
case "damage": {
|
|
248
|
+
if (typeof eff.amount === "number") {
|
|
249
|
+
const res = applyDamageToFighter(state, currentTarget, eff.amount, actor.fighterId, false);
|
|
250
|
+
currentTarget = res.updatedDefender;
|
|
251
|
+
events.push(...res.events);
|
|
252
|
+
}
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
default:
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return { actor: currentActor, target: currentTarget, events };
|
|
260
|
+
};
|
|
178
261
|
const getMovePriorityAndSpeed = (state, playerKey, action) => {
|
|
179
262
|
const { self } = getOpponentAndSelf(state, playerKey);
|
|
180
263
|
if (action.kind === "no_action") {
|
|
@@ -200,43 +283,51 @@ const getMovePriorityAndSpeed = (state, playerKey, action) => {
|
|
|
200
283
|
};
|
|
201
284
|
const resolveDamageMove = (state, playerKey, action) => {
|
|
202
285
|
if (action.kind !== "use_move") {
|
|
203
|
-
// por ahora ignoramos otros tipos aquí
|
|
204
286
|
return { state, events: [] };
|
|
205
287
|
}
|
|
206
288
|
const { self, opponent } = getOpponentAndSelf(state, playerKey);
|
|
207
289
|
const events = [];
|
|
208
290
|
const moveSlot = self.moves[action.moveIndex];
|
|
209
291
|
if (!moveSlot) {
|
|
210
|
-
// movimiento vacío → no hace nada
|
|
211
292
|
return { state, events };
|
|
212
293
|
}
|
|
213
294
|
const move = state.runtime.movesById[moveSlot.moveId];
|
|
214
295
|
if (!move) {
|
|
215
296
|
return { state, events };
|
|
216
297
|
}
|
|
217
|
-
// Sin PP → no hace nada
|
|
298
|
+
// Sin PP → no hace nada
|
|
218
299
|
if (moveSlot.currentPP <= 0) {
|
|
219
300
|
return { state, events };
|
|
220
301
|
}
|
|
221
|
-
//
|
|
222
|
-
if (move.kind === "
|
|
223
|
-
|
|
224
|
-
|
|
302
|
+
// Movimiento solo de curación → no calculamos daño base
|
|
303
|
+
if (move.kind === "heal") {
|
|
304
|
+
events.push({
|
|
305
|
+
...createBaseEvent(state.turnNumber, "action_declared", `${self.fighterId} usa ${move.name}`),
|
|
306
|
+
actorId: self.fighterId,
|
|
307
|
+
});
|
|
308
|
+
const updatedMoves = self.moves.map((m, idx) => idx === action.moveIndex
|
|
309
|
+
? { ...m, currentPP: Math.max(0, m.currentPP - 1) }
|
|
310
|
+
: m);
|
|
311
|
+
let updatedSelf = { ...self, moves: updatedMoves };
|
|
312
|
+
let updatedOpponent = { ...opponent };
|
|
313
|
+
const { actor: finalSelf, target: finalOpp, events: extraEvents, } = applyEffectsOnTarget(state, updatedSelf, updatedOpponent, move.effects);
|
|
314
|
+
events.push(...extraEvents);
|
|
315
|
+
const newState = updateFightersInState(state, playerKey, finalSelf, finalOpp);
|
|
316
|
+
return { state: newState, events };
|
|
225
317
|
}
|
|
226
|
-
//
|
|
318
|
+
// Movimiento de daño/hybrid
|
|
227
319
|
events.push({
|
|
228
320
|
...createBaseEvent(state.turnNumber, "action_declared", `${self.fighterId} usa ${move.name}`),
|
|
229
321
|
actorId: self.fighterId,
|
|
230
322
|
});
|
|
231
|
-
// Comprobar accuracy
|
|
232
323
|
const accuracy = move.accuracy ?? 100;
|
|
233
324
|
const hitRoll = randomInRange(0, 100);
|
|
234
325
|
const hit = hitRoll < accuracy;
|
|
235
|
-
// Reducir PP
|
|
236
326
|
const updatedMoves = self.moves.map((m, idx) => idx === action.moveIndex
|
|
237
327
|
? { ...m, currentPP: Math.max(0, m.currentPP - 1) }
|
|
238
328
|
: m);
|
|
239
329
|
let updatedSelf = { ...self, moves: updatedMoves };
|
|
330
|
+
let updatedOpponent = { ...opponent };
|
|
240
331
|
if (!hit) {
|
|
241
332
|
events.push({
|
|
242
333
|
...createBaseEvent(state.turnNumber, "move_miss", `${self.fighterId} falla ${move.name}`),
|
|
@@ -244,16 +335,16 @@ const resolveDamageMove = (state, playerKey, action) => {
|
|
|
244
335
|
moveId: move.id,
|
|
245
336
|
targetId: opponent.fighterId,
|
|
246
337
|
});
|
|
247
|
-
const newState = updateFightersInState(state, playerKey, updatedSelf,
|
|
338
|
+
const newState = updateFightersInState(state, playerKey, updatedSelf, updatedOpponent);
|
|
248
339
|
return { state: newState, events };
|
|
249
340
|
}
|
|
250
|
-
// Crítico
|
|
341
|
+
// Crítico y daño base
|
|
251
342
|
const critChance = computeCritChance(state.runtime.rules, updatedSelf.effectiveStats.crit);
|
|
252
343
|
const isCritical = chance(critChance);
|
|
253
344
|
const { damage, effectiveness } = computeDamage({
|
|
254
345
|
state,
|
|
255
346
|
attacker: updatedSelf,
|
|
256
|
-
defender:
|
|
347
|
+
defender: updatedOpponent,
|
|
257
348
|
move,
|
|
258
349
|
isCritical,
|
|
259
350
|
});
|
|
@@ -265,9 +356,42 @@ const resolveDamageMove = (state, playerKey, action) => {
|
|
|
265
356
|
isCritical,
|
|
266
357
|
effectiveness,
|
|
267
358
|
});
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
359
|
+
const damageRes = applyDamageToFighter(state, updatedOpponent, damage, updatedSelf.fighterId, isCritical);
|
|
360
|
+
updatedOpponent = damageRes.updatedDefender;
|
|
361
|
+
events.push(...damageRes.events);
|
|
362
|
+
// Efectos secundarios del movimiento (quemado, buffs, daño extra fijo, etc.)
|
|
363
|
+
const { actor: finalSelf, target: finalOpp, events: extraEvents, } = applyEffectsOnTarget(state, updatedSelf, updatedOpponent, move.effects);
|
|
364
|
+
events.push(...extraEvents);
|
|
365
|
+
const newState = updateFightersInState(state, playerKey, finalSelf, finalOpp);
|
|
366
|
+
return { state: newState, events };
|
|
367
|
+
};
|
|
368
|
+
const resolveItemUse = (state, playerKey, action) => {
|
|
369
|
+
if (action.kind !== "use_item") {
|
|
370
|
+
return { state, events: [] };
|
|
371
|
+
}
|
|
372
|
+
const { self, opponent } = getOpponentAndSelf(state, playerKey);
|
|
373
|
+
const events = [];
|
|
374
|
+
const itemSlot = self.items[action.itemIndex];
|
|
375
|
+
if (!itemSlot || itemSlot.usesRemaining <= 0) {
|
|
376
|
+
return { state, events };
|
|
377
|
+
}
|
|
378
|
+
const itemDef = state.runtime.itemsById[itemSlot.itemId];
|
|
379
|
+
if (!itemDef) {
|
|
380
|
+
return { state, events };
|
|
381
|
+
}
|
|
382
|
+
// Reducir usos
|
|
383
|
+
const updatedItems = self.items.map((it, idx) => idx === action.itemIndex
|
|
384
|
+
? { ...it, usesRemaining: Math.max(0, it.usesRemaining - 1) }
|
|
385
|
+
: it);
|
|
386
|
+
let updatedSelf = { ...self, items: updatedItems };
|
|
387
|
+
let updatedOpponent = { ...opponent };
|
|
388
|
+
events.push({
|
|
389
|
+
...createBaseEvent(state.turnNumber, "action_declared", `${self.fighterId} usa objeto ${itemDef.name}`),
|
|
390
|
+
actorId: self.fighterId,
|
|
391
|
+
});
|
|
392
|
+
const { actor: finalSelf, target: finalOpp, events: extraEvents, } = applyEffectsOnTarget(state, updatedSelf, updatedOpponent, itemDef.effects);
|
|
393
|
+
events.push(...extraEvents);
|
|
394
|
+
const newState = updateFightersInState(state, playerKey, finalSelf, finalOpp);
|
|
271
395
|
return { state: newState, events };
|
|
272
396
|
};
|
|
273
397
|
const updateFightersInState = (state, actingPlayerKey, updatedSelf, updatedOpponent) => {
|
|
@@ -433,8 +557,13 @@ export const resolveTurn = (state, actions) => {
|
|
|
433
557
|
currentState = result.state;
|
|
434
558
|
events.push(...result.events);
|
|
435
559
|
}
|
|
560
|
+
else if (action.kind === "use_item") {
|
|
561
|
+
const result = resolveItemUse(currentState, playerKey, action);
|
|
562
|
+
currentState = result.state;
|
|
563
|
+
events.push(...result.events);
|
|
564
|
+
}
|
|
436
565
|
else {
|
|
437
|
-
//
|
|
566
|
+
// switch_fighter y otros aún no implementados
|
|
438
567
|
continue;
|
|
439
568
|
}
|
|
440
569
|
// Comprobar victoria inmediata tras cada acción
|
package/dist/core/moves.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export type TargetKind = "self" | "enemy";
|
|
|
4
4
|
export type EffectKind = "damage" | "heal" | "shield" | "modify_stats" | "apply_status" | "modify_hit_chance" | "modify_crit_chance" | "modify_priority" | "modify_effective_speed";
|
|
5
5
|
export interface DamageEffect {
|
|
6
6
|
kind: "damage";
|
|
7
|
+
amount: number;
|
|
7
8
|
powerMultiplier?: number;
|
|
8
9
|
flatBonus?: number;
|
|
9
10
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const POKEMON_ITEMS = [
|
|
2
|
+
{
|
|
3
|
+
id: "potion",
|
|
4
|
+
name: "Poción",
|
|
5
|
+
category: "heal_shield",
|
|
6
|
+
maxUses: 2,
|
|
7
|
+
effects: [{ kind: "heal", amount: 30 }]
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
id: "super_potion",
|
|
11
|
+
name: "Super Poción",
|
|
12
|
+
category: "heal_shield",
|
|
13
|
+
maxUses: 1,
|
|
14
|
+
effects: [{ kind: "heal", amount: 60 }]
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: "burn_bomb",
|
|
18
|
+
name: "Bomba de Fuego",
|
|
19
|
+
category: "damage",
|
|
20
|
+
maxUses: 1,
|
|
21
|
+
effects: [
|
|
22
|
+
{ kind: "damage", amount: 20 },
|
|
23
|
+
{ kind: "apply_status", statusId: "burn" }
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
];
|
|
@@ -12,9 +12,10 @@ export const POKEMON_MOVES = [
|
|
|
12
12
|
target: "enemy",
|
|
13
13
|
effects: [
|
|
14
14
|
{
|
|
15
|
-
kind: "damage"
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
kind: "damage",
|
|
16
|
+
amount: 20,
|
|
17
|
+
},
|
|
18
|
+
],
|
|
18
19
|
},
|
|
19
20
|
{
|
|
20
21
|
id: "ember",
|
|
@@ -28,9 +29,10 @@ export const POKEMON_MOVES = [
|
|
|
28
29
|
target: "enemy",
|
|
29
30
|
effects: [
|
|
30
31
|
{
|
|
31
|
-
kind: "
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
kind: "apply_status",
|
|
33
|
+
statusId: "burn",
|
|
34
|
+
},
|
|
35
|
+
],
|
|
34
36
|
},
|
|
35
37
|
{
|
|
36
38
|
id: "water_gun",
|
|
@@ -44,9 +46,10 @@ export const POKEMON_MOVES = [
|
|
|
44
46
|
target: "enemy",
|
|
45
47
|
effects: [
|
|
46
48
|
{
|
|
47
|
-
kind: "damage"
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
kind: "damage",
|
|
50
|
+
amount: 20,
|
|
51
|
+
},
|
|
52
|
+
],
|
|
50
53
|
},
|
|
51
54
|
{
|
|
52
55
|
id: "vine_whip",
|
|
@@ -60,9 +63,10 @@ export const POKEMON_MOVES = [
|
|
|
60
63
|
target: "enemy",
|
|
61
64
|
effects: [
|
|
62
65
|
{
|
|
63
|
-
kind: "damage"
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
kind: "damage",
|
|
67
|
+
amount: 20,
|
|
68
|
+
},
|
|
69
|
+
],
|
|
66
70
|
},
|
|
67
71
|
{
|
|
68
72
|
id: "thunder_shock",
|
|
@@ -76,8 +80,24 @@ export const POKEMON_MOVES = [
|
|
|
76
80
|
target: "enemy",
|
|
77
81
|
effects: [
|
|
78
82
|
{
|
|
79
|
-
kind: "damage"
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
kind: "damage",
|
|
84
|
+
amount: 20,
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: "fire_fang",
|
|
90
|
+
name: "Colmillo Ígneo",
|
|
91
|
+
typeId: "fire",
|
|
92
|
+
kind: "damage",
|
|
93
|
+
basePower: 65,
|
|
94
|
+
accuracy: 95,
|
|
95
|
+
maxPP: 15,
|
|
96
|
+
priority: 0,
|
|
97
|
+
target: "enemy",
|
|
98
|
+
effects: [
|
|
99
|
+
{ kind: "damage", amount: 10 },
|
|
100
|
+
{ kind: "apply_status", statusId: "burn" },
|
|
101
|
+
],
|
|
102
|
+
},
|
|
83
103
|
];
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
+
import { ItemDefinition, MoveDefinition, PlayerBattleConfig } from "../../core";
|
|
1
2
|
import type { CombatSkin, FighterLoadout } from "../CombatSkin";
|
|
2
|
-
import type { MoveDefinition, ItemDefinition, AmuletDefinition, StatusDefinition } from "../../core";
|
|
3
|
-
import type { PlayerBattleConfig } from "../../core/engine";
|
|
4
3
|
export declare class PokemonSkin implements CombatSkin {
|
|
5
4
|
readonly id = "pokemon";
|
|
6
5
|
getTypes(): import("../..").TypeDefinition[];
|
|
7
6
|
getTypeEffectiveness(): import("../..").TypeEffectivenessMatrix;
|
|
8
7
|
getMoves(): MoveDefinition[];
|
|
9
8
|
getItems(): ItemDefinition[];
|
|
10
|
-
getAmulets():
|
|
11
|
-
getStatuses():
|
|
9
|
+
getAmulets(): never[];
|
|
10
|
+
getStatuses(): never[];
|
|
12
11
|
buildPlayerConfig(loadout: FighterLoadout): PlayerBattleConfig;
|
|
13
12
|
}
|
|
14
13
|
export declare const createPokemonSkin: () => CombatSkin;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// src/skins/pokemon/pokemonSkin.ts
|
|
2
|
-
import { POKEMON_TYPES, POKEMON_TYPE_MATRIX, POKEMON_MOVES, POKEMON_FIGHTERS } from "./index";
|
|
1
|
+
// pokemon-io-core/src/skins/pokemon/pokemonSkin.ts
|
|
2
|
+
import { POKEMON_TYPES, POKEMON_TYPE_MATRIX, POKEMON_MOVES, POKEMON_FIGHTERS, POKEMON_ITEMS } from "./index";
|
|
3
3
|
const MAX_HP_DEFAULT = 100;
|
|
4
|
-
//
|
|
4
|
+
// --- helpers ---
|
|
5
5
|
const findPokemonById = (id) => {
|
|
6
6
|
const lower = id.toLowerCase();
|
|
7
7
|
return (POKEMON_FIGHTERS.find((f) => f.id.toLowerCase() === lower || f.name.toLowerCase() === lower) ?? null);
|
|
@@ -9,19 +9,19 @@ const findPokemonById = (id) => {
|
|
|
9
9
|
const findMoveById = (id) => {
|
|
10
10
|
return POKEMON_MOVES.find((m) => m.id === id) ?? null;
|
|
11
11
|
};
|
|
12
|
+
const findItemById = (id) => {
|
|
13
|
+
return POKEMON_ITEMS.find((i) => i.id === id) ?? null;
|
|
14
|
+
};
|
|
12
15
|
const FILLER_MOVE_ID = "tackle";
|
|
13
16
|
const buildMovesFromLoadout = (fighter, loadout) => {
|
|
14
|
-
// 1) si el jugador ha elegido moveIds, intentamos respetarlos
|
|
15
17
|
const selectedMoveIds = loadout.moveIds ?? [];
|
|
16
18
|
const selectedMoves = selectedMoveIds
|
|
17
19
|
.map((id) => findMoveById(id))
|
|
18
20
|
.filter((m) => m !== null);
|
|
19
|
-
// 2) si ya hay 4 válidos → nos quedamos con los primeros 4
|
|
20
21
|
if (selectedMoves.length >= 4) {
|
|
21
22
|
return selectedMoves.slice(0, 4);
|
|
22
23
|
}
|
|
23
24
|
const result = [...selectedMoves];
|
|
24
|
-
// 3) completamos con recommendedMoves del fighter
|
|
25
25
|
const recommendedIds = fighter.recommendedMoves ?? [];
|
|
26
26
|
for (const recId of recommendedIds) {
|
|
27
27
|
if (result.length >= 4)
|
|
@@ -31,22 +31,27 @@ const buildMovesFromLoadout = (fighter, loadout) => {
|
|
|
31
31
|
result.push(move);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
-
// 4) si sigue faltando, rellenamos con "tackle"
|
|
35
34
|
const filler = findMoveById(FILLER_MOVE_ID);
|
|
36
35
|
while (result.length < 4 && filler) {
|
|
37
36
|
result.push(filler);
|
|
38
37
|
}
|
|
39
|
-
// Garantizamos que haya al menos 1 movimiento
|
|
40
38
|
if (result.length === 0 && filler) {
|
|
41
39
|
result.push(filler);
|
|
42
40
|
}
|
|
43
|
-
// Cortamos por si acaso
|
|
44
41
|
return result.slice(0, 4);
|
|
45
42
|
};
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
|
|
43
|
+
const buildItemsFromLoadout = (loadout) => {
|
|
44
|
+
const selectedItemIds = loadout.itemIds ?? [];
|
|
45
|
+
const selectedItems = selectedItemIds
|
|
46
|
+
.map((id) => findItemById(id))
|
|
47
|
+
.filter((i) => i !== null);
|
|
48
|
+
// Si tu motor sigue exigiendo 4 items, puedes rellenar aquí:
|
|
49
|
+
// while (selectedItems.length < 4 && POKEMON_ITEMS[selectedItems.length]) {
|
|
50
|
+
// selectedItems.push(POKEMON_ITEMS[selectedItems.length]);
|
|
51
|
+
// }
|
|
52
|
+
return selectedItems;
|
|
53
|
+
};
|
|
54
|
+
// --- skin ---
|
|
50
55
|
export class PokemonSkin {
|
|
51
56
|
id = "pokemon";
|
|
52
57
|
getTypes() {
|
|
@@ -62,10 +67,10 @@ export class PokemonSkin {
|
|
|
62
67
|
return POKEMON_ITEMS;
|
|
63
68
|
}
|
|
64
69
|
getAmulets() {
|
|
65
|
-
return
|
|
70
|
+
return []; // más adelante
|
|
66
71
|
}
|
|
67
72
|
getStatuses() {
|
|
68
|
-
return
|
|
73
|
+
return []; // más adelante
|
|
69
74
|
}
|
|
70
75
|
buildPlayerConfig(loadout) {
|
|
71
76
|
if (!loadout.fighterId) {
|
|
@@ -76,17 +81,16 @@ export class PokemonSkin {
|
|
|
76
81
|
throw new Error(`Unknown fighterId for Pokemon skin: ${loadout.fighterId}`);
|
|
77
82
|
}
|
|
78
83
|
const moves = buildMovesFromLoadout(fighter, loadout);
|
|
79
|
-
|
|
84
|
+
const items = buildItemsFromLoadout(loadout);
|
|
80
85
|
return {
|
|
81
86
|
fighter,
|
|
82
87
|
maxHp: MAX_HP_DEFAULT,
|
|
83
88
|
moves,
|
|
84
|
-
items
|
|
85
|
-
amulet: null
|
|
89
|
+
items,
|
|
90
|
+
amulet: null
|
|
86
91
|
};
|
|
87
92
|
}
|
|
88
93
|
}
|
|
89
|
-
// Helper para crear la skin (así importas siempre una factoría)
|
|
90
94
|
export const createPokemonSkin = () => {
|
|
91
95
|
return new PokemonSkin();
|
|
92
96
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const POKEMON_STATUSES = [
|
|
2
|
+
{
|
|
3
|
+
id: "burn",
|
|
4
|
+
name: "Quemado",
|
|
5
|
+
kind: "soft",
|
|
6
|
+
minDurationTurns: 2,
|
|
7
|
+
maxDurationTurns: 4,
|
|
8
|
+
effectsPerStack: [
|
|
9
|
+
// DoT ligero
|
|
10
|
+
{ kind: "damage", amount: 10 }
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
id: "stun",
|
|
15
|
+
name: "Aturdido",
|
|
16
|
+
kind: "hard_cc",
|
|
17
|
+
minDurationTurns: 1,
|
|
18
|
+
maxDurationTurns: 1,
|
|
19
|
+
effectsPerStack: []
|
|
20
|
+
}
|
|
21
|
+
];
|