pokemon-io-core 0.0.82 → 0.0.84

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.
Files changed (76) hide show
  1. package/dist/core/battleState.d.ts +1 -1
  2. package/dist/core/engine.js +43 -7
  3. package/dist/core/index.d.ts +0 -1
  4. package/dist/core/index.js +0 -1
  5. package/dist/engine/actions/forcedSwitch.d.ts +5 -0
  6. package/dist/engine/actions/forcedSwitch.js +44 -0
  7. package/dist/engine/actions/index.d.ts +5 -0
  8. package/dist/engine/actions/index.js +5 -0
  9. package/dist/engine/actions/item.d.ts +6 -0
  10. package/dist/engine/actions/item.js +61 -0
  11. package/dist/engine/actions/move.d.ts +6 -0
  12. package/dist/engine/actions/move.js +120 -0
  13. package/dist/engine/actions/priority.d.ts +6 -0
  14. package/dist/engine/actions/priority.js +30 -0
  15. package/dist/engine/actions/switch.d.ts +6 -0
  16. package/dist/engine/actions/switch.js +55 -0
  17. package/dist/engine/combat/crit.d.ts +2 -0
  18. package/dist/engine/combat/crit.js +4 -0
  19. package/dist/engine/combat/damage.d.ts +20 -0
  20. package/dist/engine/combat/damage.js +66 -0
  21. package/dist/engine/combat/heal.d.ts +6 -0
  22. package/dist/engine/combat/heal.js +25 -0
  23. package/dist/engine/combat/index.d.ts +5 -0
  24. package/dist/engine/combat/index.js +5 -0
  25. package/dist/engine/combat/typeEffectiveness.d.ts +3 -0
  26. package/dist/engine/combat/typeEffectiveness.js +7 -0
  27. package/dist/engine/combat/winner.d.ts +2 -0
  28. package/dist/engine/combat/winner.js +11 -0
  29. package/dist/engine/debug.d.ts +1 -0
  30. package/dist/engine/debug.js +6 -0
  31. package/dist/engine/effects/applyEffects.d.ts +7 -0
  32. package/dist/engine/effects/applyEffects.js +103 -0
  33. package/dist/engine/effects/index.d.ts +2 -0
  34. package/dist/engine/effects/index.js +2 -0
  35. package/dist/engine/effects/target.d.ts +6 -0
  36. package/dist/engine/effects/target.js +26 -0
  37. package/dist/engine/engine.d.ts +53 -0
  38. package/dist/engine/engine.js +1046 -0
  39. package/dist/engine/events.d.ts +4 -0
  40. package/dist/engine/events.js +12 -0
  41. package/dist/engine/fighters/fighter.d.ts +4 -0
  42. package/dist/engine/fighters/fighter.js +53 -0
  43. package/dist/engine/fighters/index.d.ts +3 -0
  44. package/dist/engine/fighters/index.js +3 -0
  45. package/dist/engine/fighters/selectors.d.ts +13 -0
  46. package/dist/engine/fighters/selectors.js +19 -0
  47. package/dist/engine/fighters/update.d.ts +3 -0
  48. package/dist/engine/fighters/update.js +30 -0
  49. package/dist/engine/index.d.ts +11 -1
  50. package/dist/engine/index.js +11 -1
  51. package/dist/engine/rng.d.ts +2 -0
  52. package/dist/engine/rng.js +8 -0
  53. package/dist/engine/rules.d.ts +44 -0
  54. package/dist/engine/rules.js +10 -0
  55. package/dist/engine/runtime.d.ts +7 -0
  56. package/dist/engine/runtime.js +49 -0
  57. package/dist/engine/status/apply.d.ts +6 -0
  58. package/dist/engine/status/apply.js +49 -0
  59. package/dist/engine/status/clear.d.ts +6 -0
  60. package/dist/engine/status/clear.js +47 -0
  61. package/dist/engine/status/endOfTurn.d.ts +6 -0
  62. package/dist/engine/status/endOfTurn.js +80 -0
  63. package/dist/engine/status/hardCc.d.ts +3 -0
  64. package/dist/engine/status/hardCc.js +4 -0
  65. package/dist/engine/status/index.d.ts +4 -0
  66. package/dist/engine/status/index.js +4 -0
  67. package/dist/engine/turn/index.d.ts +1 -0
  68. package/dist/engine/turn/index.js +1 -0
  69. package/dist/engine/turn/resolveTurn.d.ts +5 -0
  70. package/dist/engine/turn/resolveTurn.js +139 -0
  71. package/dist/index.d.ts +1 -0
  72. package/dist/index.js +1 -0
  73. package/dist/skins/CombatSkin.d.ts +1 -1
  74. package/dist/skins/cliches/clicheSkin.d.ts +2 -1
  75. package/dist/skins/pokemon/pokemonSkin.d.ts +2 -1
  76. package/package.json +1 -1
@@ -0,0 +1,4 @@
1
+ import { BattleEvent } from "../core";
2
+ export declare const createBaseEvent: (turnNumber: number, kind: BattleEvent["kind"], message: string) => Omit<BattleEvent, "kind"> & {
3
+ kind: typeof kind;
4
+ };
@@ -0,0 +1,12 @@
1
+ let eventCounter = 0;
2
+ const nextEventId = () => {
3
+ eventCounter += 1;
4
+ return `evt_${eventCounter}`;
5
+ };
6
+ export const createBaseEvent = (turnNumber, kind, message) => ({
7
+ id: nextEventId(),
8
+ kind,
9
+ turnNumber,
10
+ message,
11
+ timestamp: Date.now(),
12
+ });
@@ -0,0 +1,4 @@
1
+ import { BattleFighter } from "../../core";
2
+ import { PlayerFighterBattleConfig, RuntimeBattleState } from "../rules";
3
+ export declare const createBattleFighter: (cfg: PlayerFighterBattleConfig) => BattleFighter;
4
+ export declare const recomputeEffectiveStatsForFighter: (state: RuntimeBattleState, fighter: BattleFighter) => BattleFighter;
@@ -0,0 +1,53 @@
1
+ import { cloneStats } from "../runtime";
2
+ export const createBattleFighter = (cfg) => {
3
+ if (cfg.moves.length !== 4) {
4
+ throw new Error("Each fighter must have exactly 4 moves in MVP");
5
+ }
6
+ return {
7
+ fighterId: cfg.fighter.id,
8
+ classId: cfg.fighter.classId,
9
+ maxHp: cfg.maxHp,
10
+ currentHp: cfg.maxHp,
11
+ baseStats: cloneStats(cfg.fighter.baseStats),
12
+ effectiveStats: cloneStats(cfg.fighter.baseStats),
13
+ moves: cfg.moves.map((move) => ({
14
+ moveId: move.id,
15
+ currentPP: move.maxPP,
16
+ })),
17
+ amuletId: cfg.amulet ? cfg.amulet.id : null,
18
+ statuses: [],
19
+ isAlive: true,
20
+ };
21
+ };
22
+ export const recomputeEffectiveStatsForFighter = (state, fighter) => {
23
+ // Partimos de base
24
+ let eff = { ...fighter.baseStats };
25
+ // 1) Aplicar estados
26
+ for (const st of fighter.statuses) {
27
+ const def = state.runtime.statusesById[st.statusId];
28
+ if (!def)
29
+ continue;
30
+ const stacks = st.stacks === 2 ? 2 : 1;
31
+ for (const effDef of def.effectsPerStack) {
32
+ const totalStacks = stacks; // podrías multiplicar efectos por stacks
33
+ switch (effDef.kind) {
34
+ case "modify_stats":
35
+ eff.offense += (effDef.offenseDelta ?? 0) * totalStacks;
36
+ eff.defense += (effDef.defenseDelta ?? 0) * totalStacks;
37
+ eff.speed += (effDef.speedDelta ?? 0) * totalStacks;
38
+ eff.crit += (effDef.critDelta ?? 0) * totalStacks;
39
+ break;
40
+ case "modify_effective_speed":
41
+ eff.speed = Math.floor(eff.speed * Math.pow(effDef.multiplier, totalStacks));
42
+ break;
43
+ default:
44
+ break;
45
+ }
46
+ }
47
+ }
48
+ // 2) Aquí podrías aplicar amuletos, buffs temporales o lo que quieras
49
+ return {
50
+ ...fighter,
51
+ effectiveStats: eff,
52
+ };
53
+ };
@@ -0,0 +1,3 @@
1
+ export * from './fighter.js';
2
+ export * from './selectors.js';
3
+ export * from './update.js';
@@ -0,0 +1,3 @@
1
+ export * from './fighter.js';
2
+ export * from './selectors.js';
3
+ export * from './update.js';
@@ -0,0 +1,13 @@
1
+ import { BattleFighter, PlayerBattleState } from "../../core";
2
+ import { RuntimeBattleState } from "../rules";
3
+ export declare const getActiveFighter: (player: PlayerBattleState) => BattleFighter;
4
+ export declare const getOpponentAndSelf: (state: RuntimeBattleState, playerKey: "player1" | "player2") => {
5
+ self: BattleFighter;
6
+ opponent: BattleFighter;
7
+ };
8
+ export declare const getPlayersAndActives: (state: RuntimeBattleState, playerKey: "player1" | "player2") => {
9
+ selfPlayer: PlayerBattleState;
10
+ oppPlayer: PlayerBattleState;
11
+ self: BattleFighter;
12
+ opponent: BattleFighter;
13
+ };
@@ -0,0 +1,19 @@
1
+ export const getActiveFighter = (player) => player.fighterTeam[player.activeIndex];
2
+ export const getOpponentAndSelf = (state, playerKey) => {
3
+ const selfPlayer = playerKey === "player1" ? state.player1 : state.player2;
4
+ const oppPlayer = playerKey === "player1" ? state.player2 : state.player1;
5
+ return {
6
+ self: getActiveFighter(selfPlayer),
7
+ opponent: getActiveFighter(oppPlayer),
8
+ };
9
+ };
10
+ export const getPlayersAndActives = (state, playerKey) => {
11
+ const selfPlayer = playerKey === "player1" ? state.player1 : state.player2;
12
+ const oppPlayer = playerKey === "player1" ? state.player2 : state.player1;
13
+ return {
14
+ selfPlayer,
15
+ oppPlayer,
16
+ self: getActiveFighter(selfPlayer),
17
+ opponent: getActiveFighter(oppPlayer),
18
+ };
19
+ };
@@ -0,0 +1,3 @@
1
+ import { BattleFighter } from "../../core";
2
+ import { RuntimeBattleState } from "../rules";
3
+ export declare const updateFightersInState: (state: RuntimeBattleState, actingPlayerKey: "player1" | "player2", updatedSelf: BattleFighter, updatedOpponent: BattleFighter) => RuntimeBattleState;
@@ -0,0 +1,30 @@
1
+ // ------------------------------------------------------
2
+ // Actualizar fighters en el estado
3
+ // ------------------------------------------------------
4
+ export const updateFightersInState = (state, actingPlayerKey, updatedSelf, updatedOpponent) => {
5
+ const player1 = { ...state.player1 };
6
+ const player2 = { ...state.player2 };
7
+ const updateInPlayer = (player, updated) => {
8
+ const newTeam = player.fighterTeam.map((f, idx) => idx === player.activeIndex ? updated : f);
9
+ return {
10
+ ...player,
11
+ fighterTeam: newTeam,
12
+ };
13
+ };
14
+ if (actingPlayerKey === "player1") {
15
+ const selfPlayer = updateInPlayer(player1, updatedSelf);
16
+ const oppPlayer = updateInPlayer(player2, updatedOpponent);
17
+ return {
18
+ ...state,
19
+ player1: selfPlayer,
20
+ player2: oppPlayer,
21
+ };
22
+ }
23
+ const selfPlayer = updateInPlayer(player2, updatedSelf);
24
+ const oppPlayer = updateInPlayer(player1, updatedOpponent);
25
+ return {
26
+ ...state,
27
+ player1: oppPlayer,
28
+ player2: selfPlayer,
29
+ };
30
+ };
@@ -1 +1,11 @@
1
- export * from './pokemonBattleService.js';
1
+ export * from './debug.js';
2
+ export * from './events.js';
3
+ export * from './rng.js';
4
+ export * from './rules.js';
5
+ export * from './runtime.js';
6
+ export * from './actions/index.js';
7
+ export * from './combat/index.js';
8
+ export * from './effects/index.js';
9
+ export * from './fighters/index.js';
10
+ export * from './status/index.js';
11
+ export * from './turn/index.js';
@@ -1 +1,11 @@
1
- export * from './pokemonBattleService.js';
1
+ export * from './debug.js';
2
+ export * from './events.js';
3
+ export * from './rng.js';
4
+ export * from './rules.js';
5
+ export * from './runtime.js';
6
+ export * from './actions/index.js';
7
+ export * from './combat/index.js';
8
+ export * from './effects/index.js';
9
+ export * from './fighters/index.js';
10
+ export * from './status/index.js';
11
+ export * from './turn/index.js';
@@ -0,0 +1,2 @@
1
+ export declare const randomInRange: (min: number, max: number) => number;
2
+ export declare const chance: (probability: number) => boolean;
@@ -0,0 +1,8 @@
1
+ export const randomInRange = (min, max) => Math.random() * (max - min) + min;
2
+ export const chance = (probability) => {
3
+ if (probability <= 0)
4
+ return false;
5
+ if (probability >= 1)
6
+ return true;
7
+ return Math.random() < probability;
8
+ };
@@ -0,0 +1,44 @@
1
+ import { AmuletDefinition, BattleState, FighterDefinition, ItemDefinition, ItemId, MoveDefinition, MoveId, StatusDefinition, StatusId, TypeDefinition, TypeEffectivenessMatrix, TypeId } from "../core";
2
+ export interface BattleRules {
3
+ baseCritChance: number;
4
+ critPerStat: number;
5
+ critMultiplier: number;
6
+ stabMultiplier: number;
7
+ randomMinDamageFactor: number;
8
+ randomMaxDamageFactor: number;
9
+ }
10
+ export interface BattleRuntime {
11
+ rules: BattleRules;
12
+ typesById: Record<TypeId, TypeDefinition>;
13
+ movesById: Record<MoveId, MoveDefinition>;
14
+ itemsById: Record<ItemId, ItemDefinition>;
15
+ amuletsById: Record<string, AmuletDefinition>;
16
+ statusesById: Record<StatusId, StatusDefinition>;
17
+ typeEffectiveness: TypeEffectivenessMatrix;
18
+ }
19
+ export interface PlayerFighterBattleConfig {
20
+ fighter: FighterDefinition;
21
+ maxHp: number;
22
+ moves: MoveDefinition[];
23
+ amulet: AmuletDefinition | null;
24
+ }
25
+ export interface PlayerBattleConfig {
26
+ fighters: PlayerFighterBattleConfig[];
27
+ items: ItemDefinition[];
28
+ amulet: AmuletDefinition | null;
29
+ }
30
+ export interface BattleConfig {
31
+ types: TypeDefinition[];
32
+ typeEffectiveness: TypeEffectivenessMatrix;
33
+ moves: MoveDefinition[];
34
+ items: ItemDefinition[];
35
+ amulets: AmuletDefinition[];
36
+ statuses: StatusDefinition[];
37
+ player1: PlayerBattleConfig;
38
+ player2: PlayerBattleConfig;
39
+ rules?: Partial<BattleRules>;
40
+ }
41
+ export interface RuntimeBattleState extends BattleState {
42
+ runtime: BattleRuntime;
43
+ }
44
+ export declare const DEFAULT_RULES: BattleRules;
@@ -0,0 +1,10 @@
1
+ // ------------------------------------------------------
2
+ // Config & runtime
3
+ export const DEFAULT_RULES = {
4
+ baseCritChance: 0.05,
5
+ critPerStat: 0.002,
6
+ critMultiplier: 1.1,
7
+ stabMultiplier: 1.1,
8
+ randomMinDamageFactor: 0.8,
9
+ randomMaxDamageFactor: 1.0,
10
+ };
@@ -0,0 +1,7 @@
1
+ import { BattleState, FighterStats } from "../core";
2
+ import { BattleConfig } from "./rules";
3
+ export declare const buildMap: <T extends {
4
+ id: string;
5
+ }>(list: T[]) => Record<string, T>;
6
+ export declare const cloneStats: (stats: FighterStats) => FighterStats;
7
+ export declare const createInitialBattleState: (config: BattleConfig) => BattleState;
@@ -0,0 +1,49 @@
1
+ import { createBattleFighter } from "./fighters/fighter";
2
+ import { DEFAULT_RULES, } from "./rules";
3
+ export const buildMap = (list) => list.reduce((acc, item) => {
4
+ acc[item.id] = item;
5
+ return acc;
6
+ }, {});
7
+ export const cloneStats = (stats) => ({
8
+ offense: stats.offense,
9
+ defense: stats.defense,
10
+ speed: stats.speed,
11
+ crit: stats.crit,
12
+ });
13
+ const createPlayerBattleState = (cfg) => {
14
+ const team = cfg.fighters.map((fCfg) => createBattleFighter(fCfg));
15
+ const inventory = cfg.items.map((item) => ({
16
+ itemId: item.id,
17
+ usesRemaining: item.maxUses,
18
+ }));
19
+ return {
20
+ fighterTeam: team,
21
+ activeIndex: 0,
22
+ inventory,
23
+ };
24
+ };
25
+ export const createInitialBattleState = (config) => {
26
+ const rules = {
27
+ ...DEFAULT_RULES,
28
+ ...config.rules,
29
+ };
30
+ const runtime = {
31
+ rules,
32
+ typesById: buildMap(config.types),
33
+ movesById: buildMap(config.moves),
34
+ itemsById: buildMap(config.items),
35
+ amuletsById: buildMap(config.amulets),
36
+ statusesById: buildMap(config.statuses),
37
+ typeEffectiveness: config.typeEffectiveness,
38
+ };
39
+ const player1 = createPlayerBattleState(config.player1);
40
+ const player2 = createPlayerBattleState(config.player2);
41
+ const state = {
42
+ turnNumber: 1,
43
+ player1,
44
+ player2,
45
+ runtime,
46
+ forcedSwitch: null,
47
+ };
48
+ return state;
49
+ };
@@ -0,0 +1,6 @@
1
+ import { BattleEvent, BattleFighter, StatusId } from "../../core";
2
+ import { RuntimeBattleState } from "../rules";
3
+ export declare const applyStatusToFighter: (state: RuntimeBattleState, target: BattleFighter, statusId: StatusId) => {
4
+ updated: BattleFighter;
5
+ events: BattleEvent[];
6
+ };
@@ -0,0 +1,49 @@
1
+ import { dbg } from "../debug";
2
+ import { createBaseEvent } from "../events";
3
+ import { randomInRange } from "../rng";
4
+ export const applyStatusToFighter = (state, target, statusId) => {
5
+ const def = state.runtime.statusesById[statusId];
6
+ dbg("APPLY_STATUS_FN", {
7
+ targetId: target.fighterId,
8
+ statusId,
9
+ hasDef: !!def,
10
+ currentStatuses: target.statuses,
11
+ });
12
+ if (!def)
13
+ return { updated: target, events: [] };
14
+ const events = [];
15
+ const existing = target.statuses.find((s) => s.statusId === statusId);
16
+ const duration = Math.floor(randomInRange(def.minDurationTurns, def.maxDurationTurns + 1)) ||
17
+ def.minDurationTurns;
18
+ let newStatuses = [...target.statuses];
19
+ if (!existing) {
20
+ newStatuses.push({
21
+ statusId,
22
+ stacks: 1,
23
+ remainingTurns: duration,
24
+ });
25
+ }
26
+ else if (existing.stacks === 1) {
27
+ newStatuses = newStatuses.map((s) => s.statusId === statusId
28
+ ? { ...s, stacks: 2, remainingTurns: duration }
29
+ : s);
30
+ }
31
+ else {
32
+ newStatuses = newStatuses.map((s) => s.statusId === statusId ? { ...s, remainingTurns: duration } : s);
33
+ }
34
+ dbg("STATUS_APPLY", {
35
+ fighterId: target.fighterId,
36
+ statusId,
37
+ duration,
38
+ prevStacks: existing?.stacks ?? 0,
39
+ });
40
+ events.push({
41
+ ...createBaseEvent(state.turnNumber, "status_applied", `Se aplica ${statusId} a ${target.fighterId}`),
42
+ targetId: target.fighterId,
43
+ statusId,
44
+ });
45
+ return {
46
+ updated: { ...target, statuses: newStatuses },
47
+ events,
48
+ };
49
+ };
@@ -0,0 +1,6 @@
1
+ import { BattleEvent, BattleFighter, ClearStatusEffect } from "../../core";
2
+ import { RuntimeBattleState } from "../rules";
3
+ export declare const clearStatusFromFighter: (state: RuntimeBattleState, target: BattleFighter, effect: ClearStatusEffect) => {
4
+ updated: BattleFighter;
5
+ events: BattleEvent[];
6
+ };
@@ -0,0 +1,47 @@
1
+ import { dbg } from "../debug";
2
+ import { createBaseEvent } from "../events";
3
+ export const clearStatusFromFighter = (state, target, effect) => {
4
+ const { statusIds, kinds, clearAll } = effect;
5
+ const events = [];
6
+ const before = target.statuses;
7
+ let after = before;
8
+ if (clearAll) {
9
+ after = [];
10
+ }
11
+ else {
12
+ after = before.filter((st) => {
13
+ const def = state.runtime.statusesById[st.statusId];
14
+ if (statusIds && statusIds.includes(st.statusId)) {
15
+ return false;
16
+ }
17
+ if (kinds && def && kinds.includes(def.kind)) {
18
+ return false;
19
+ }
20
+ return true;
21
+ });
22
+ }
23
+ if (after.length === before.length) {
24
+ // nada que limpiar
25
+ return { updated: target, events };
26
+ }
27
+ const removed = before
28
+ .filter((old) => !after.some((st) => st.statusId === old.statusId))
29
+ .map((st) => st.statusId);
30
+ dbg("STATUS_CLEAR", {
31
+ fighterId: target.fighterId,
32
+ cleared: removed,
33
+ clearAll: !!clearAll,
34
+ });
35
+ events.push({
36
+ ...createBaseEvent(state.turnNumber, "status_cleared", `Se limpian estados (${removed.join(", ")}) de ${target.fighterId}`),
37
+ targetId: target.fighterId,
38
+ statusIds: removed,
39
+ });
40
+ return {
41
+ updated: {
42
+ ...target,
43
+ statuses: after,
44
+ },
45
+ events,
46
+ };
47
+ };
@@ -0,0 +1,6 @@
1
+ import { BattleEvent } from "../../core";
2
+ import { RuntimeBattleState } from "../rules";
3
+ export declare const applyEndOfTurnStatuses: (state: RuntimeBattleState) => {
4
+ state: RuntimeBattleState;
5
+ events: BattleEvent[];
6
+ };
@@ -0,0 +1,80 @@
1
+ import { applyDamageToFighter } from "../combat/damage";
2
+ import { dbg } from "../debug";
3
+ import { createBaseEvent } from "../events";
4
+ import { getActiveFighter } from "../fighters/selectors";
5
+ export const applyEndOfTurnStatuses = (state) => {
6
+ const events = [];
7
+ const applyForPlayer = (player) => {
8
+ const active = getActiveFighter(player);
9
+ let updated = { ...active };
10
+ const updatedStatuses = [];
11
+ for (const st of active.statuses) {
12
+ const def = state.runtime.statusesById[st.statusId];
13
+ if (!def) {
14
+ dbg("STATUS_MISSING_DEF", {
15
+ fighterId: active.fighterId,
16
+ statusId: st.statusId,
17
+ });
18
+ continue;
19
+ }
20
+ let damageFromStatus = 0;
21
+ def.effectsPerStack.forEach((eff) => {
22
+ if (eff.kind === "damage") {
23
+ const stacksMultiplier = st.stacks === 2 ? 2 : 1;
24
+ const base = typeof eff.flatAmount === "number"
25
+ ? eff.flatAmount
26
+ : typeof eff.basePower === "number"
27
+ ? eff.basePower
28
+ : 10; // fallback
29
+ damageFromStatus += base * stacksMultiplier;
30
+ }
31
+ });
32
+ if (damageFromStatus > 0 && updated.isAlive) {
33
+ dbg("STATUS_DOT", {
34
+ fighterId: updated.fighterId,
35
+ statusId: st.statusId,
36
+ damageFromStatus,
37
+ stacks: st.stacks,
38
+ });
39
+ const damageRes = applyDamageToFighter(state, updated, damageFromStatus, updated.fighterId, false);
40
+ updated = damageRes.updatedDefender;
41
+ events.push(...damageRes.events);
42
+ }
43
+ const remaining = st.remainingTurns - 1;
44
+ if (remaining > 0) {
45
+ updatedStatuses.push({
46
+ ...st,
47
+ remainingTurns: remaining,
48
+ });
49
+ }
50
+ else {
51
+ dbg("STATUS_EXPIRE", {
52
+ fighterId: updated.fighterId,
53
+ statusId: st.statusId,
54
+ });
55
+ events.push({
56
+ ...createBaseEvent(state.turnNumber, "status_expired", `El estado ${st.statusId} expira en ${updated.fighterId}`),
57
+ targetId: updated.fighterId,
58
+ statusId: st.statusId,
59
+ });
60
+ }
61
+ }
62
+ updated = {
63
+ ...updated,
64
+ statuses: updatedStatuses,
65
+ };
66
+ const newTeam = player.fighterTeam.map((f, idx) => idx === player.activeIndex ? updated : f);
67
+ return {
68
+ ...player,
69
+ fighterTeam: newTeam,
70
+ };
71
+ };
72
+ const p1 = applyForPlayer(state.player1);
73
+ const p2 = applyForPlayer(state.player2);
74
+ const newState = {
75
+ ...state,
76
+ player1: p1,
77
+ player2: p2,
78
+ };
79
+ return { state: newState, events };
80
+ };
@@ -0,0 +1,3 @@
1
+ import { BattleFighter } from "../../core";
2
+ import { RuntimeBattleState } from "../rules";
3
+ export declare const hasHardCc: (state: RuntimeBattleState, fighter: BattleFighter) => boolean;
@@ -0,0 +1,4 @@
1
+ export const hasHardCc = (state, fighter) => fighter.statuses.some((st) => {
2
+ const def = state.runtime.statusesById[st.statusId];
3
+ return def?.kind === "hard_cc";
4
+ });
@@ -0,0 +1,4 @@
1
+ export * from './apply.js';
2
+ export * from './clear.js';
3
+ export * from './endOfTurn.js';
4
+ export * from './hardCc.js';
@@ -0,0 +1,4 @@
1
+ export * from './apply.js';
2
+ export * from './clear.js';
3
+ export * from './endOfTurn.js';
4
+ export * from './hardCc.js';
@@ -0,0 +1 @@
1
+ export * from './resolveTurn.js';
@@ -0,0 +1 @@
1
+ export * from './resolveTurn.js';
@@ -0,0 +1,5 @@
1
+ import { BattleActions, BattleEvent, BattleState } from "../../core";
2
+ export declare const resolveTurn: (state: BattleState, actions: BattleActions) => {
3
+ newState: BattleState;
4
+ events: BattleEvent[];
5
+ };