pokemon-io-core 0.0.95 → 0.0.97
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/socketTypes.d.ts +1 -4
- package/dist/core/battleState.d.ts +9 -0
- package/dist/core/events.d.ts +14 -2
- package/dist/engine/actions/move.js +8 -3
- package/dist/engine/combat/stages.d.ts +5 -0
- package/dist/engine/combat/stages.js +53 -0
- package/dist/engine/effects/applyEffects.js +70 -1
- package/dist/engine/fighters/fighter.js +20 -3
- package/dist/skins/pokemon/moves.js +37 -7
- package/package.json +1 -1
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { BattleView } from "./battle.js";
|
|
2
2
|
import { RoomView } from "./room.js";
|
|
3
3
|
export interface ClientToServerEvents {
|
|
4
|
-
"player:hello": (payload: {
|
|
5
|
-
playerKey: string;
|
|
6
|
-
}) => void;
|
|
7
4
|
"room:create": (payload: {
|
|
8
5
|
nickname: string;
|
|
9
6
|
roomName: string;
|
|
@@ -19,7 +16,7 @@ export interface ClientToServerEvents {
|
|
|
19
16
|
}) => void;
|
|
20
17
|
"room:reconnect": (payload: {
|
|
21
18
|
roomId: string;
|
|
22
|
-
|
|
19
|
+
oldPlayerId: string;
|
|
23
20
|
}) => void;
|
|
24
21
|
"room:setLoadout": (payload: {
|
|
25
22
|
roomId: string;
|
|
@@ -21,11 +21,20 @@ export interface BattleFighter {
|
|
|
21
21
|
currentHp: number;
|
|
22
22
|
baseStats: FighterStats;
|
|
23
23
|
effectiveStats: FighterStats;
|
|
24
|
+
statStages: StatStages;
|
|
24
25
|
moves: EquippedMove[];
|
|
25
26
|
amuletId: AmuletId | null;
|
|
26
27
|
statuses: ActiveStatus[];
|
|
27
28
|
isAlive: boolean;
|
|
28
29
|
}
|
|
30
|
+
export interface StatStages {
|
|
31
|
+
offense: number;
|
|
32
|
+
defense: number;
|
|
33
|
+
speed: number;
|
|
34
|
+
crit: number;
|
|
35
|
+
accuracy: number;
|
|
36
|
+
evasion: number;
|
|
37
|
+
}
|
|
29
38
|
export interface PlayerBattleState {
|
|
30
39
|
fighterTeam: BattleFighter[];
|
|
31
40
|
activeIndex: number;
|
package/dist/core/events.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { FighterId, MoveId, ItemId, StatusId } from "./ids.js";
|
|
2
|
-
export type BattleEventKind = "turn_start" | "action_declared" | "action_skipped_hard_cc" | "move_miss" | "move_hit" | "item_used" | "status_cleared" | "damage" | "heal" | "fighter_switched" | "shield_applied" | "status_applied" | "status_refreshed" | "status_expired" | "fighter_fainted" | "turn_end" | "battle_end";
|
|
2
|
+
export type BattleEventKind = "turn_start" | "action_declared" | "action_skipped_hard_cc" | "move_miss" | "move_hit" | "item_used" | "status_cleared" | "damage" | "heal" | "fighter_switched" | "shield_applied" | "status_applied" | "status_refreshed" | "status_expired" | "fighter_fainted" | "turn_end" | "stats_changed" | "battle_end";
|
|
3
3
|
export interface BaseBattleEvent {
|
|
4
4
|
id: string;
|
|
5
5
|
turnNumber: number;
|
|
@@ -7,6 +7,18 @@ export interface BaseBattleEvent {
|
|
|
7
7
|
message: string;
|
|
8
8
|
timestamp: number;
|
|
9
9
|
}
|
|
10
|
+
export interface StatsChangedEvent extends BaseBattleEvent {
|
|
11
|
+
kind: "stats_changed";
|
|
12
|
+
targetId: FighterId;
|
|
13
|
+
changes: {
|
|
14
|
+
offense?: number;
|
|
15
|
+
defense?: number;
|
|
16
|
+
speed?: number;
|
|
17
|
+
crit?: number;
|
|
18
|
+
accuracy?: number;
|
|
19
|
+
evasion?: number;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
10
22
|
export interface ActionDeclaredEvent extends BaseBattleEvent {
|
|
11
23
|
kind: "action_declared";
|
|
12
24
|
actorId: FighterId;
|
|
@@ -75,4 +87,4 @@ export interface BattleEndEvent extends BaseBattleEvent {
|
|
|
75
87
|
kind: "battle_end";
|
|
76
88
|
winner: "player1" | "player2" | "draw";
|
|
77
89
|
}
|
|
78
|
-
export type BattleEvent = ActionDeclaredEvent | MoveMissEvent | MoveHitEvent | ItemUsedEvent | DamageEvent | HealEvent | StatusAppliedEvent | StatusExpiredEvent | FighterFaintedEvent | FighterSwitchedEvent | BattleEndEvent | BaseBattleEvent;
|
|
90
|
+
export type BattleEvent = ActionDeclaredEvent | MoveMissEvent | MoveHitEvent | ItemUsedEvent | DamageEvent | HealEvent | StatusAppliedEvent | StatusExpiredEvent | FighterFaintedEvent | FighterSwitchedEvent | BattleEndEvent | StatsChangedEvent | BaseBattleEvent;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { computeCritChance } from "../combat/crit.js";
|
|
2
|
+
import { getAccuracyMultiplier } from "../combat/stages.js";
|
|
2
3
|
import { getTypeEffectiveness } from "../combat/typeEffectiveness.js";
|
|
3
4
|
import { dbg } from "../debug.js";
|
|
4
5
|
import { applyEffectsOnTarget } from "../effects/applyEffects.js";
|
|
@@ -38,9 +39,13 @@ export const resolveDamageMove = (state, playerKey, action) => {
|
|
|
38
39
|
...createBaseEvent(state.turnNumber, "action_declared", `${self.fighterId} usó ${move.name}`),
|
|
39
40
|
actorId: self.fighterId,
|
|
40
41
|
});
|
|
41
|
-
|
|
42
|
+
// Cálculo de puntería con Stages
|
|
43
|
+
const accStage = self.statStages.accuracy - opponent.statStages.evasion;
|
|
44
|
+
const accMult = getAccuracyMultiplier(accStage);
|
|
45
|
+
const baseAcc = move.accuracy ?? 100;
|
|
46
|
+
const finalAccuracy = baseAcc * accMult;
|
|
42
47
|
const hitRoll = randomInRange(0, 100);
|
|
43
|
-
const hit = hitRoll <
|
|
48
|
+
const hit = hitRoll < finalAccuracy;
|
|
44
49
|
const updatedMoves = self.moves.map((m, idx) => idx === action.moveIndex
|
|
45
50
|
? { ...m, currentPP: Math.max(0, m.currentPP - 1) }
|
|
46
51
|
: m);
|
|
@@ -52,7 +57,7 @@ export const resolveDamageMove = (state, playerKey, action) => {
|
|
|
52
57
|
moveId: move.id,
|
|
53
58
|
moveName: move.name,
|
|
54
59
|
hitRoll,
|
|
55
|
-
accuracy,
|
|
60
|
+
accuracy: finalAccuracy,
|
|
56
61
|
});
|
|
57
62
|
events.push({
|
|
58
63
|
...createBaseEvent(state.turnNumber, "move_miss", `${self.fighterId} falla ${move.name}`),
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const STAGE_MULTIPLIERS_STATS: Record<number, number>;
|
|
2
|
+
export declare const STAGE_MULTIPLIERS_ACCURACY: Record<number, number>;
|
|
3
|
+
export declare const getCritChanceFromStage: (stage: number) => number;
|
|
4
|
+
export declare const getStatMultiplier: (stage: number) => number;
|
|
5
|
+
export declare const getAccuracyMultiplier: (stage: number) => number;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export const STAGE_MULTIPLIERS_STATS = {
|
|
2
|
+
"-6": 2 / 8,
|
|
3
|
+
"-5": 2 / 7,
|
|
4
|
+
"-4": 2 / 6,
|
|
5
|
+
"-3": 2 / 5,
|
|
6
|
+
"-2": 2 / 4,
|
|
7
|
+
"-1": 2 / 3,
|
|
8
|
+
0: 2 / 2,
|
|
9
|
+
1: 3 / 2,
|
|
10
|
+
2: 4 / 2,
|
|
11
|
+
3: 5 / 2,
|
|
12
|
+
4: 6 / 2,
|
|
13
|
+
5: 7 / 2,
|
|
14
|
+
6: 8 / 2,
|
|
15
|
+
};
|
|
16
|
+
// Accuracy/Evasion multipliers (3/3 base)
|
|
17
|
+
export const STAGE_MULTIPLIERS_ACCURACY = {
|
|
18
|
+
"-6": 3 / 9,
|
|
19
|
+
"-5": 3 / 8,
|
|
20
|
+
"-4": 3 / 7,
|
|
21
|
+
"-3": 3 / 6,
|
|
22
|
+
"-2": 3 / 5,
|
|
23
|
+
"-1": 3 / 4,
|
|
24
|
+
0: 3 / 3,
|
|
25
|
+
1: 4 / 3,
|
|
26
|
+
2: 5 / 3,
|
|
27
|
+
3: 6 / 3,
|
|
28
|
+
4: 7 / 3,
|
|
29
|
+
5: 8 / 3,
|
|
30
|
+
6: 9 / 3,
|
|
31
|
+
};
|
|
32
|
+
// Critical Hit Ratio (Table)
|
|
33
|
+
// Stage 0: ~4.17% (1/24)
|
|
34
|
+
// Stage 1: 12.5% (1/8)
|
|
35
|
+
// Stage 2: 50% (1/2)
|
|
36
|
+
// Stage 3+: 100% (1/1)
|
|
37
|
+
export const getCritChanceFromStage = (stage) => {
|
|
38
|
+
if (stage <= 0)
|
|
39
|
+
return 1 / 24;
|
|
40
|
+
if (stage === 1)
|
|
41
|
+
return 1 / 8;
|
|
42
|
+
if (stage === 2)
|
|
43
|
+
return 1 / 2;
|
|
44
|
+
return 1;
|
|
45
|
+
};
|
|
46
|
+
export const getStatMultiplier = (stage) => {
|
|
47
|
+
const clamped = Math.max(-6, Math.min(6, stage));
|
|
48
|
+
return STAGE_MULTIPLIERS_STATS[clamped] ?? 1;
|
|
49
|
+
};
|
|
50
|
+
export const getAccuracyMultiplier = (stage) => {
|
|
51
|
+
const clamped = Math.max(-6, Math.min(6, stage));
|
|
52
|
+
return STAGE_MULTIPLIERS_ACCURACY[clamped] ?? 1;
|
|
53
|
+
};
|
|
@@ -4,6 +4,8 @@ import { dbg } from "../debug.js";
|
|
|
4
4
|
import { applyStatusToFighter } from "../status/apply.js";
|
|
5
5
|
import { clearStatusFromFighter } from "../status/clear.js";
|
|
6
6
|
import { resolveEffectTarget } from "./target.js";
|
|
7
|
+
import { createBaseEvent } from "../events.js";
|
|
8
|
+
import { recomputeEffectiveStatsForFighter } from "../fighters/fighter.js";
|
|
7
9
|
export const applyEffectsOnTarget = (state, actor, target, moveTypeId, isCritical, effects) => {
|
|
8
10
|
dbg("applyEffectsOnTarget", {
|
|
9
11
|
actorId: actor.fighterId,
|
|
@@ -94,7 +96,74 @@ export const applyEffectsOnTarget = (state, actor, target, moveTypeId, isCritica
|
|
|
94
96
|
}
|
|
95
97
|
break;
|
|
96
98
|
}
|
|
97
|
-
|
|
99
|
+
case "modify_stats": {
|
|
100
|
+
const { primary, isSelf } = resolveEffectTarget(eff, currentActor, currentTarget);
|
|
101
|
+
const newStages = { ...primary.statStages };
|
|
102
|
+
const changes = {};
|
|
103
|
+
if (eff.offenseDelta) {
|
|
104
|
+
newStages.offense = Math.max(-6, Math.min(6, newStages.offense + eff.offenseDelta));
|
|
105
|
+
changes.offense = eff.offenseDelta;
|
|
106
|
+
}
|
|
107
|
+
if (eff.defenseDelta) {
|
|
108
|
+
newStages.defense = Math.max(-6, Math.min(6, newStages.defense + eff.defenseDelta));
|
|
109
|
+
changes.defense = eff.defenseDelta;
|
|
110
|
+
}
|
|
111
|
+
if (eff.speedDelta) {
|
|
112
|
+
newStages.speed = Math.max(-6, Math.min(6, newStages.speed + eff.speedDelta));
|
|
113
|
+
changes.speed = eff.speedDelta;
|
|
114
|
+
}
|
|
115
|
+
if (eff.critDelta) {
|
|
116
|
+
newStages.crit = Math.max(0, Math.min(6, newStages.crit + eff.critDelta));
|
|
117
|
+
changes.crit = eff.critDelta;
|
|
118
|
+
}
|
|
119
|
+
let updated = { ...primary, statStages: newStages };
|
|
120
|
+
updated = recomputeEffectiveStatsForFighter(state, updated);
|
|
121
|
+
events.push({
|
|
122
|
+
...createBaseEvent(state.turnNumber, "stats_changed", `Estadísticas cambiadas`),
|
|
123
|
+
targetId: primary.fighterId,
|
|
124
|
+
changes
|
|
125
|
+
});
|
|
126
|
+
if (isSelf)
|
|
127
|
+
currentActor = updated;
|
|
128
|
+
else
|
|
129
|
+
currentTarget = updated;
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
case "modify_crit_chance": {
|
|
133
|
+
const { primary, isSelf } = resolveEffectTarget(eff, currentActor, currentTarget);
|
|
134
|
+
const newStages = { ...primary.statStages };
|
|
135
|
+
newStages.crit = Math.max(0, Math.min(6, newStages.crit + eff.delta));
|
|
136
|
+
let updated = { ...primary, statStages: newStages };
|
|
137
|
+
updated = recomputeEffectiveStatsForFighter(state, updated);
|
|
138
|
+
events.push({
|
|
139
|
+
...createBaseEvent(state.turnNumber, "stats_changed", `Ratio de crítico cambiado`),
|
|
140
|
+
targetId: primary.fighterId,
|
|
141
|
+
changes: { crit: eff.delta }
|
|
142
|
+
});
|
|
143
|
+
if (isSelf)
|
|
144
|
+
currentActor = updated;
|
|
145
|
+
else
|
|
146
|
+
currentTarget = updated;
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
case "modify_hit_chance": {
|
|
150
|
+
// Interpreted as Accuracy Stage
|
|
151
|
+
const { primary, isSelf } = resolveEffectTarget(eff, currentActor, currentTarget);
|
|
152
|
+
const newStages = { ...primary.statStages };
|
|
153
|
+
newStages.accuracy = Math.max(-6, Math.min(6, newStages.accuracy + eff.delta));
|
|
154
|
+
let updated = { ...primary, statStages: newStages };
|
|
155
|
+
updated = recomputeEffectiveStatsForFighter(state, updated);
|
|
156
|
+
events.push({
|
|
157
|
+
...createBaseEvent(state.turnNumber, "stats_changed", `Precisión cambiada`),
|
|
158
|
+
targetId: primary.fighterId,
|
|
159
|
+
changes: { accuracy: eff.delta }
|
|
160
|
+
});
|
|
161
|
+
if (isSelf)
|
|
162
|
+
currentActor = updated;
|
|
163
|
+
else
|
|
164
|
+
currentTarget = updated;
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
98
167
|
default:
|
|
99
168
|
break;
|
|
100
169
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { cloneStats } from "../runtime.js";
|
|
2
|
+
import { getCritChanceFromStage, getStatMultiplier, } from "../combat/stages.js";
|
|
2
3
|
export const createBattleFighter = (cfg) => {
|
|
3
4
|
if (cfg.moves.length !== 4) {
|
|
4
5
|
throw new Error("Each fighter must have exactly 4 moves in MVP");
|
|
@@ -10,6 +11,14 @@ export const createBattleFighter = (cfg) => {
|
|
|
10
11
|
currentHp: cfg.maxHp,
|
|
11
12
|
baseStats: cloneStats(cfg.fighter.baseStats),
|
|
12
13
|
effectiveStats: cloneStats(cfg.fighter.baseStats),
|
|
14
|
+
statStages: {
|
|
15
|
+
offense: 0,
|
|
16
|
+
defense: 0,
|
|
17
|
+
speed: 0,
|
|
18
|
+
crit: 0,
|
|
19
|
+
accuracy: 0,
|
|
20
|
+
evasion: 0,
|
|
21
|
+
},
|
|
13
22
|
moves: cfg.moves.map((move) => ({
|
|
14
23
|
moveId: move.id,
|
|
15
24
|
currentPP: move.maxPP,
|
|
@@ -22,7 +31,14 @@ export const createBattleFighter = (cfg) => {
|
|
|
22
31
|
export const recomputeEffectiveStatsForFighter = (state, fighter) => {
|
|
23
32
|
// Partimos de base
|
|
24
33
|
let eff = { ...fighter.baseStats };
|
|
25
|
-
// 1) Aplicar
|
|
34
|
+
// 1) Aplicar Etapas (Stages)
|
|
35
|
+
eff.offense = Math.floor(eff.offense * getStatMultiplier(fighter.statStages.offense));
|
|
36
|
+
eff.defense = Math.floor(eff.defense * getStatMultiplier(fighter.statStages.defense));
|
|
37
|
+
eff.speed = Math.floor(eff.speed * getStatMultiplier(fighter.statStages.speed));
|
|
38
|
+
// Crit se reemplaza por el valor de la etapa (o se suma si baseStats tuviera un % base)
|
|
39
|
+
// Asumimos que baseStats.crit es 0 o un bono base pequeño.
|
|
40
|
+
eff.crit = getCritChanceFromStage(fighter.statStages.crit) + eff.crit;
|
|
41
|
+
// 2) Aplicar estados (Bonificadores temporales/external)
|
|
26
42
|
for (const st of fighter.statuses) {
|
|
27
43
|
const def = state.runtime.statusesById[st.statusId];
|
|
28
44
|
if (!def)
|
|
@@ -32,10 +48,11 @@ export const recomputeEffectiveStatsForFighter = (state, fighter) => {
|
|
|
32
48
|
const totalStacks = stacks; // podrías multiplicar efectos por stacks
|
|
33
49
|
switch (effDef.kind) {
|
|
34
50
|
case "modify_stats":
|
|
51
|
+
// Estos serían bonos flat POST-etapas
|
|
35
52
|
eff.offense += (effDef.offenseDelta ?? 0) * totalStacks;
|
|
36
53
|
eff.defense += (effDef.defenseDelta ?? 0) * totalStacks;
|
|
37
54
|
eff.speed += (effDef.speedDelta ?? 0) * totalStacks;
|
|
38
|
-
eff.crit += (effDef.critDelta ?? 0) * totalStacks;
|
|
55
|
+
// eff.crit += (effDef.critDelta ?? 0) * totalStacks; // Crit ya va por stages
|
|
39
56
|
break;
|
|
40
57
|
case "modify_effective_speed":
|
|
41
58
|
eff.speed = Math.floor(eff.speed * Math.pow(effDef.multiplier, totalStacks));
|
|
@@ -45,7 +62,7 @@ export const recomputeEffectiveStatsForFighter = (state, fighter) => {
|
|
|
45
62
|
}
|
|
46
63
|
}
|
|
47
64
|
}
|
|
48
|
-
//
|
|
65
|
+
// 3) Aquí podrías aplicar amuletos, buffs temporales o lo que quieras
|
|
49
66
|
return {
|
|
50
67
|
...fighter,
|
|
51
68
|
effectiveStats: eff,
|
|
@@ -26,8 +26,8 @@ export const POKEMON_MOVES = [
|
|
|
26
26
|
"basePower": 40
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
|
-
"kind": "
|
|
30
|
-
"
|
|
29
|
+
"kind": "modify_stats",
|
|
30
|
+
"offenseDelta": -2,
|
|
31
31
|
"target": "self"
|
|
32
32
|
}
|
|
33
33
|
]
|
|
@@ -97,6 +97,11 @@ export const POKEMON_MOVES = [
|
|
|
97
97
|
{
|
|
98
98
|
"kind": "damage",
|
|
99
99
|
"basePower": 15
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"kind": "modify_crit_chance",
|
|
103
|
+
"delta": 1,
|
|
104
|
+
"target": "self"
|
|
100
105
|
}
|
|
101
106
|
]
|
|
102
107
|
},
|
|
@@ -129,7 +134,7 @@ export const POKEMON_MOVES = [
|
|
|
129
134
|
},
|
|
130
135
|
{
|
|
131
136
|
"kind": "modify_stats",
|
|
132
|
-
"offenseDelta": -
|
|
137
|
+
"offenseDelta": -2
|
|
133
138
|
}
|
|
134
139
|
]
|
|
135
140
|
},
|
|
@@ -198,6 +203,11 @@ export const POKEMON_MOVES = [
|
|
|
198
203
|
{
|
|
199
204
|
"kind": "damage",
|
|
200
205
|
"basePower": 15
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"kind": "modify_stats",
|
|
209
|
+
"offenseDelta": 1,
|
|
210
|
+
"target": "self"
|
|
201
211
|
}
|
|
202
212
|
]
|
|
203
213
|
},
|
|
@@ -230,7 +240,7 @@ export const POKEMON_MOVES = [
|
|
|
230
240
|
},
|
|
231
241
|
{
|
|
232
242
|
"kind": "modify_stats",
|
|
233
|
-
"offenseDelta": -
|
|
243
|
+
"offenseDelta": -2
|
|
234
244
|
}
|
|
235
245
|
]
|
|
236
246
|
},
|
|
@@ -299,6 +309,11 @@ export const POKEMON_MOVES = [
|
|
|
299
309
|
{
|
|
300
310
|
"kind": "damage",
|
|
301
311
|
"basePower": 15
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
"kind": "modify_hit_chance",
|
|
315
|
+
"delta": -1,
|
|
316
|
+
"target": "enemy"
|
|
302
317
|
}
|
|
303
318
|
]
|
|
304
319
|
},
|
|
@@ -331,7 +346,7 @@ export const POKEMON_MOVES = [
|
|
|
331
346
|
},
|
|
332
347
|
{
|
|
333
348
|
"kind": "modify_stats",
|
|
334
|
-
"offenseDelta": -
|
|
349
|
+
"offenseDelta": -2
|
|
335
350
|
}
|
|
336
351
|
]
|
|
337
352
|
},
|
|
@@ -400,6 +415,11 @@ export const POKEMON_MOVES = [
|
|
|
400
415
|
{
|
|
401
416
|
"kind": "damage",
|
|
402
417
|
"basePower": 15
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
"kind": "modify_stats",
|
|
421
|
+
"defenseDelta": -1,
|
|
422
|
+
"target": "enemy"
|
|
403
423
|
}
|
|
404
424
|
]
|
|
405
425
|
},
|
|
@@ -432,7 +452,7 @@ export const POKEMON_MOVES = [
|
|
|
432
452
|
},
|
|
433
453
|
{
|
|
434
454
|
"kind": "modify_stats",
|
|
435
|
-
"offenseDelta": -
|
|
455
|
+
"offenseDelta": -2
|
|
436
456
|
}
|
|
437
457
|
]
|
|
438
458
|
},
|
|
@@ -501,6 +521,11 @@ export const POKEMON_MOVES = [
|
|
|
501
521
|
{
|
|
502
522
|
"kind": "damage",
|
|
503
523
|
"basePower": 15
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
"kind": "modify_crit_chance",
|
|
527
|
+
"delta": 1,
|
|
528
|
+
"target": "self"
|
|
504
529
|
}
|
|
505
530
|
]
|
|
506
531
|
},
|
|
@@ -533,7 +558,7 @@ export const POKEMON_MOVES = [
|
|
|
533
558
|
},
|
|
534
559
|
{
|
|
535
560
|
"kind": "modify_stats",
|
|
536
|
-
"offenseDelta": -
|
|
561
|
+
"offenseDelta": -2
|
|
537
562
|
}
|
|
538
563
|
]
|
|
539
564
|
},
|
|
@@ -602,6 +627,11 @@ export const POKEMON_MOVES = [
|
|
|
602
627
|
{
|
|
603
628
|
"kind": "damage",
|
|
604
629
|
"basePower": 15
|
|
630
|
+
},
|
|
631
|
+
{
|
|
632
|
+
"kind": "modify_stats",
|
|
633
|
+
"speedDelta": 1,
|
|
634
|
+
"target": "self"
|
|
605
635
|
}
|
|
606
636
|
]
|
|
607
637
|
},
|