Serene Grace, Shield Dust, Sheer Force (P)

This commit is contained in:
Flashfyre 2024-04-19 17:19:24 -04:00 committed by NxKarim
parent ee6c3e8fbc
commit 3a46ee4a6a
53 changed files with 4154 additions and 1445 deletions

View File

@ -7,8 +7,11 @@ PokéRogue is a browser based Pokémon fangame heavily inspired by the roguelite
If you have the motivation and experience with Typescript/Javascript (or are willing to learn) please feel free to fork the repository and make pull requests with contributions. If you don't know what to work on but want to help, reference the below **To-Do** section or the **#vote** channel in the discord.
### 💻 Environment Setup
node: 18.3.0
#### Prerequisites
- node: 18.3.0
- npm: [how to install](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)
#### Running Locally
1. Clone the repo and in the root directory run `npm install`
- *if you run into any errors, reach out in the **#dev-corner** channel in discord*
2. Run `npm run start:dev` to locally run the project in `localhost:8000`

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -4,30 +4,30 @@
"image": "1024-stellar.png",
"format": "RGBA8888",
"size": {
"w": 96,
"h": 96
"w": 119,
"h": 119
},
"scale": 0.5,
"scale": 1,
"frames": [
{
"filename": "0001.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 96,
"h": 96
"w": 119,
"h": 119
},
"spriteSourceSize": {
"x": 9,
"x": 0,
"y": 0,
"w": 78,
"h": 96
"w": 115,
"h": 119
},
"frame": {
"x": 0,
"y": 0,
"w": 78,
"h": 96
"w": 115,
"h": 119
}
}
]
@ -36,6 +36,6 @@
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:c9ee64bda72f2dadb06109338796ccac:1313f1218b7da2c57ad9f290d1323840:c1508f3b01ae78a28a1267fd6caa4f7b$"
"smartupdate": "$TexturePacker:SmartUpdate:bc663acf2e62803fce6c3a525dc8dd98:ccd7d0de8a487235cfbd6f372afa931f:c1508f3b01ae78a28a1267fd6caa4f7b$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -4,30 +4,30 @@
"image": "1024-stellar.png",
"format": "RGBA8888",
"size": {
"w": 96,
"h": 96
"w": 119,
"h": 119
},
"scale": 0.333,
"scale": 1,
"frames": [
{
"filename": "0001.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 96,
"h": 96
"w": 119,
"h": 119
},
"spriteSourceSize": {
"x": 5,
"x": 0,
"y": 0,
"w": 86,
"h": 96
"w": 115,
"h": 119
},
"frame": {
"x": 0,
"y": 0,
"w": 86,
"h": 96
"w": 115,
"h": 119
}
}
]
@ -36,6 +36,6 @@
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:ac5e775f77477eeabd029932804747c4:f7a112a87c35dc81cb0da88b7cbb39e8:c1508f3b01ae78a28a1267fd6caa4f7b$"
"smartupdate": "$TexturePacker:SmartUpdate:210ba1c2e6e58501571ae226d073a3c5:f12bdf191842f7ec3a4be98a43fb8121:c1508f3b01ae78a28a1267fd6caa4f7b$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -4,30 +4,30 @@
"image": "1024-stellar.png",
"format": "RGBA8888",
"size": {
"w": 96,
"h": 96
"w": 119,
"h": 119
},
"scale": 0.333,
"scale": 1,
"frames": [
{
"filename": "0001.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 96,
"h": 96
"w": 119,
"h": 119
},
"spriteSourceSize": {
"x": 5,
"x": 0,
"y": 0,
"w": 86,
"h": 96
"w": 115,
"h": 119
},
"frame": {
"x": 0,
"y": 0,
"w": 86,
"h": 96
"w": 115,
"h": 119
}
}
]
@ -36,6 +36,6 @@
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:2bd25bae0fabcfbc35e24bd578a7b4b5:aec60788a0d77f38fb599d721e41a0d6:c1508f3b01ae78a28a1267fd6caa4f7b$"
"smartupdate": "$TexturePacker:SmartUpdate:210ba1c2e6e58501571ae226d073a3c5:f12bdf191842f7ec3a4be98a43fb8121:c1508f3b01ae78a28a1267fd6caa4f7b$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@ -4,30 +4,30 @@
"image": "1024-stellar.png",
"format": "RGBA8888",
"size": {
"w": 96,
"h": 96
"w": 119,
"h": 119
},
"scale": 0.5,
"scale": 1,
"frames": [
{
"filename": "0001.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 96,
"h": 96
"w": 119,
"h": 119
},
"spriteSourceSize": {
"x": 9,
"x": 0,
"y": 0,
"w": 78,
"h": 96
"w": 115,
"h": 119
},
"frame": {
"x": 0,
"y": 0,
"w": 78,
"h": 96
"w": 115,
"h": 119
}
}
]
@ -36,6 +36,6 @@
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:a7e89af07a22475413df24b510c193f7:45261af90c4a51e3dc73cccb894a2aad:c1508f3b01ae78a28a1267fd6caa4f7b$"
"smartupdate": "$TexturePacker:SmartUpdate:3510deaf42eaa3ee2fdfa22c00a2b30b:3beb6b12ca1bb50ad260593b41939f27:c1508f3b01ae78a28a1267fd6caa4f7b$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -17,7 +17,7 @@ import { TextStyle, addTextObject } from './ui/text';
import { Moves } from "./data/enums/moves";
import { allMoves } from "./data/move";
import { initMoves } from './data/move';
import { ModifierPoolType, getDefaultModifierTypeForTier, getEnemyModifierTypesForWave } from './modifier/modifier-type';
import { ModifierPoolType, getDefaultModifierTypeForTier, getEnemyModifierTypesForWave, getModifierPoolForType } from './modifier/modifier-type';
import AbilityBar from './ui/ability-bar';
import { BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, IncrementMovePriorityAbAttr, applyAbAttrs, initAbilities } from './data/ability';
import { Abilities } from "./data/enums/abilities";
@ -37,7 +37,7 @@ import SettingsUiHandler from './ui/settings-ui-handler';
import MessageUiHandler from './ui/message-ui-handler';
import { Species } from './data/enums/species';
import InvertPostFX from './pipelines/invert';
import { Achv, ModifierAchv, achvs } from './system/achv';
import { Achv, ModifierAchv, MoneyAchv, achvs } from './system/achv';
import { Voucher, vouchers } from './system/voucher';
import { Gender } from './data/gender';
import UIPlugin from 'phaser3-rex-plugins/templates/ui/ui-plugin';
@ -795,7 +795,11 @@ export default class BattleScene extends SceneBase {
this.trainer.setVisible(true);
if (reloadI18n) {
const localizable: Localizable[] = [ ...allMoves ];
const localizable: Localizable[] = [
...allSpecies,
...allMoves,
...Utils.getEnumValues(ModifierPoolType).map(mpt => getModifierPoolForType(mpt)).map(mp => Object.values(mp).flat().map(mt => mt.modifierType).filter(mt => 'localize' in mt).map(lpb => lpb as unknown as Localizable)).flat()
];
for (let item of localizable)
item.localize();
}
@ -889,7 +893,26 @@ export default class BattleScene extends SceneBase {
//this.pushPhase(new TrainerMessageTestPhase(this, TrainerType.RIVAL, TrainerType.RIVAL_2, TrainerType.RIVAL_3, TrainerType.RIVAL_4, TrainerType.RIVAL_5, TrainerType.RIVAL_6));
if (!waveIndex && lastBattle) {
const isNewBiome = !(lastBattle.waveIndex % 10) || (this.gameMode.isDaily && lastBattle.waveIndex === 49);
let isNewBiome = !(lastBattle.waveIndex % 10) || ((this.gameMode.hasShortBiomes || this.gameMode.isDaily) && (lastBattle.waveIndex % 50) === 49);
if (!isNewBiome && this.gameMode.hasShortBiomes) {
let w = lastBattle.waveIndex - ((lastBattle.waveIndex % 10) - 1);
let biomeWaves = 1;
while (w < lastBattle.waveIndex) {
let wasNewBiome = false;
this.executeWithSeedOffset(() => {
wasNewBiome = !Utils.randSeedInt(6 - biomeWaves);
}, w << 4);
if (wasNewBiome)
biomeWaves = 1;
else
biomeWaves++;
w++;
}
this.executeWithSeedOffset(() => {
isNewBiome = !Utils.randSeedInt(6 - biomeWaves);
}, lastBattle.waveIndex << 4);
}
const resetArenaState = isNewBiome || this.currentBattle.battleType === BattleType.TRAINER || this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS;
this.getEnemyParty().forEach(enemyPokemon => enemyPokemon.destroy());
this.trySpreadPokerus();
@ -975,6 +998,9 @@ export default class BattleScene extends SceneBase {
case Species.DEERLING:
case Species.SAWSBUCK:
case Species.VIVILLON:
case Species.FLABEBE:
case Species.FLOETTE:
case Species.FLORGES:
case Species.ORICORIO:
case Species.SQUAWKABILLY:
case Species.TATSUGIRI:
@ -1673,6 +1699,12 @@ export default class BattleScene extends SceneBase {
this.phaseQueue.push(new TurnInitPhase(this));
}
addMoney(amount: integer): void {
this.money = Math.min(this.money + amount, Number.MAX_SAFE_INTEGER);
this.updateMoneyText();
this.validateAchvs(MoneyAchv);
}
getWaveMoneyAmount(moneyMultiplier: number): integer {
const waveIndex = this.currentBattle.waveIndex;
const waveSetIndex = Math.ceil(waveIndex / 10) - 1;

View File

@ -157,10 +157,8 @@ export default class Battle {
const moneyAmount = new Utils.IntegerHolder(scene.currentBattle.moneyScattered);
scene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount);
scene.money += moneyAmount.value;
scene.updateMoneyText();
scene.addMoney(moneyAmount.value);
scene.validateAchvs(MoneyAchv);
scene.queueMessage(`You picked up ₽${moneyAmount.value.toLocaleString('en-US')}!`, null, true);
scene.currentBattle.moneyScattered = 0;

View File

@ -9,7 +9,8 @@ import { BattlerTag } from "./battler-tags";
import { BattlerTagType } from "./enums/battler-tag-type";
import { StatusEffect, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect";
import { Gender } from "./gender";
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, RecoilAttr, StatusMoveTypeImmunityAttr, FlinchAttr, allMoves } from "./move";
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, RecoilAttr, StatusMoveTypeImmunityAttr, FlinchAttr, OneHitKOAttr, HitHealAttr, StrengthSapHealAttr, allMoves } from "./move";
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
import { ArenaTagType } from "./enums/arena-tag-type";
import { Stat } from "./pokemon-stat";
import { PokemonHeldItemModifier } from "../modifier/modifier";
@ -520,6 +521,16 @@ export class MoveImmunityStatChangeAbAttr extends MoveImmunityAbAttr {
}
}
export class ReverseDrainAbAttr extends PostDefendAbAttr {
applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean {
if (!!move.getMove().getAttrs(HitHealAttr).length || !!move.getMove().getAttrs(StrengthSapHealAttr).length ) {
pokemon.scene.queueMessage(getPokemonMessage(attacker, ` sucked up the liquid ooze!`));
return true;
}
return false;
}
}
export class PostDefendStatChangeAbAttr extends PostDefendAbAttr {
private condition: PokemonDefendCondition;
private stat: BattleStat;
@ -545,6 +556,29 @@ export class PostDefendStatChangeAbAttr extends PostDefendAbAttr {
}
}
export class PostDefendApplyArenaTrapTagAbAttr extends PostDefendAbAttr {
private condition: PokemonDefendCondition;
private tagType: ArenaTagType;
constructor(condition: PokemonDefendCondition, tagType: ArenaTagType) {
super(true);
this.condition = condition;
this.tagType = tagType;
}
applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean {
if (this.condition(pokemon, attacker, move.getMove())) {
const tag = pokemon.scene.arena.getTag(this.tagType) as ArenaTrapTag;
if (!pokemon.scene.arena.getTag(this.tagType) || tag.layers < tag.maxLayers) {
pokemon.scene.arena.addTag(this.tagType, 0, undefined, pokemon.id, pokemon.isPlayer() ? ArenaTagSide.ENEMY : ArenaTagSide.PLAYER);
return true;
}
}
return false;
}
}
export class PostDefendApplyBattlerTagAbAttr extends PostDefendAbAttr {
private condition: PokemonDefendCondition;
private tagType: BattlerTagType;
@ -774,6 +808,58 @@ export class PreAttackAbAttr extends AbAttr {
}
}
export class MoveEffectChanceMultiplierAbAttr extends AbAttr {
private chanceMultiplier: number;
constructor(chanceMultiplier?: number){
super(true);
this.chanceMultiplier = chanceMultiplier;
}
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
if((args[0] as Utils.NumberHolder).value >=1) {
(args[0] as Utils.NumberHolder).value *= this.chanceMultiplier;
(args[0] as Utils.NumberHolder).value = Math.min((args[0] as Utils.NumberHolder).value, 100)
return true;
}
return false;
}
}
export class IgnoreMoveEffectsAbAttr extends PreDefendAbAttr {
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean {
if((args[0] as Utils.NumberHolder).value >=1) {
(args[0] as Utils.NumberHolder).value = 0;
return true;
}
return false;
}
}
/*export class SheerForceIgnoredAbilities extends PreAttackAbAttr {
applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: PokemonMove, args: any[]): boolean {
const ability = defender.getAbility().id
if (move.getMove().chance >= 1 && (
ability == Abilities.COLOR_CHANGE || ability == Abilities.PICKPOCKET ||
ability == Abilities.WIMP_OUT || ability == Abilities.EMERGENCY_EXIT ||
ability == Abilities.BERSERK || ability == Abilities.ANGER_SHELL
)){
(args[0] as Utils.BooleanHolder).value = true;
return true;
}
return false;
}
}*/
export class VariableMovePowerAbAttr extends PreAttackAbAttr {
applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: PokemonMove, args: any[]): boolean {
//const power = args[0] as Utils.NumberHolder;
@ -1569,6 +1655,43 @@ function getWeatherCondition(...weatherTypes: WeatherType[]): AbAttrCondition {
};
}
function getAnticipationCondition(): AbAttrCondition {
return (pokemon: Pokemon) => {
for (let opponent of pokemon.getOpponents()) {
for (let move of opponent.moveset) {
// move is super effective
if (move.getMove() instanceof AttackMove && pokemon.getAttackTypeEffectiveness(move.getMove().type) >= 2) {
return true;
}
// move is a OHKO
if (move.getMove().findAttr(attr => attr instanceof OneHitKOAttr)) {
return true;
}
// edge case for hidden power, type is computed
if (move.getMove().id === Moves.HIDDEN_POWER) {
const iv_val = Math.floor(((opponent.ivs[Stat.HP] & 1)
+(opponent.ivs[Stat.ATK] & 1) * 2
+(opponent.ivs[Stat.DEF] & 1) * 4
+(opponent.ivs[Stat.SPD] & 1) * 8
+(opponent.ivs[Stat.SPATK] & 1) * 16
+(opponent.ivs[Stat.SPDEF] & 1) * 32) * 15/63);
const type = [
Type.FIGHTING, Type.FLYING, Type.POISON, Type.GROUND,
Type.ROCK, Type.BUG, Type.GHOST, Type.STEEL,
Type.FIRE, Type.WATER, Type.GRASS, Type.ELECTRIC,
Type.PSYCHIC, Type.ICE, Type.DRAGON, Type.DARK][iv_val];
if (pokemon.getAttackTypeEffectiveness(type) >= 2) {
return true;
}
}
}
}
return false;
};
}
export class PostWeatherChangeAbAttr extends AbAttr {
applyPostWeatherChange(pokemon: Pokemon, passive: boolean, weather: WeatherType, args: any[]): boolean {
return false;
@ -2092,6 +2215,9 @@ export class SuppressFieldAbilitiesAbAttr extends AbAttr {
}
}
export class AlwaysHitAbAttr extends AbAttr { }
export class UncopiableAbilityAbAttr extends AbAttr {
constructor() {
super(false);
@ -2367,7 +2493,8 @@ export function initAbilities() {
new Ability(Abilities.FLASH_FIRE, "Flash Fire", "Powers up the Pokémon's Fire-type moves if it's hit by one.", 3)
.attr(TypeImmunityAddBattlerTagAbAttr, Type.FIRE, BattlerTagType.FIRE_BOOST, 1, (pokemon: Pokemon) => !pokemon.status || pokemon.status.effect !== StatusEffect.FREEZE)
.ignorable(),
new Ability(Abilities.SHIELD_DUST, "Shield Dust (N)", "This Pokémon's dust blocks the additional effects of attacks taken.", 3)
new Ability(Abilities.SHIELD_DUST, "Shield Dust", "This Pokémon's dust blocks the additional effects of attacks taken.", 3)
.attr(IgnoreMoveEffectsAbAttr)
.ignorable(),
new Ability(Abilities.OWN_TEMPO, "Own Tempo", "This Pokémon has its own tempo, and that prevents it from becoming confused.", 3)
.attr(BattlerTagImmunityAbAttr, BattlerTagType.CONFUSED)
@ -2402,7 +2529,8 @@ export function initAbilities() {
.attr(RedirectTypeMoveAbAttr, Type.ELECTRIC)
.attr(TypeImmunityStatChangeAbAttr, Type.ELECTRIC, BattleStat.SPATK, 1)
.ignorable(),
new Ability(Abilities.SERENE_GRACE, "Serene Grace (N)", "Boosts the likelihood of additional effects occurring when attacking.", 3),
new Ability(Abilities.SERENE_GRACE, "Serene Grace", "Boosts the likelihood of additional effects occurring when attacking.", 3)
.attr(MoveEffectChanceMultiplierAbAttr, 2),
new Ability(Abilities.SWIFT_SWIM, "Swift Swim", "Boosts the Pokémon's Speed stat in rain.", 3)
.attr(BattleStatMultiplierAbAttr, BattleStat.SPD, 2)
.condition(getWeatherCondition(WeatherType.RAIN, WeatherType.HEAVY_RAIN)),
@ -2485,7 +2613,8 @@ export function initAbilities() {
new Ability(Abilities.MARVEL_SCALE, "Marvel Scale", "The Pokémon's marvelous scales boost the Defense stat if it has a status condition.", 3)
.conditionalAttr(pokemon => !!pokemon.status, BattleStatMultiplierAbAttr, BattleStat.DEF, 1.5)
.ignorable(),
new Ability(Abilities.LIQUID_OOZE, "Liquid Ooze (N)", "The oozed liquid has a strong stench, which damages attackers using any draining move.", 3),
new Ability(Abilities.LIQUID_OOZE, "Liquid Ooze", "The oozed liquid has a strong stench, which damages attackers using any draining move.", 3)
.attr(ReverseDrainAbAttr),
new Ability(Abilities.OVERGROW, "Overgrow", "Powers up Grass-type moves when the Pokémon's HP is low.", 3)
.attr(LowHpMoveTypePowerBoostAbAttr, Type.GRASS),
new Ability(Abilities.BLAZE, "Blaze", "Powers up Fire-type moves when the Pokémon's HP is low.", 3)
@ -2573,7 +2702,9 @@ export function initAbilities() {
new Ability(Abilities.SNIPER, "Sniper (N)", "Powers up moves if they become critical hits when attacking.", 4),
new Ability(Abilities.MAGIC_GUARD, "Magic Guard", "The Pokémon only takes damage from attacks.", 4)
.attr(BlockNonDirectDamageAbAttr),
new Ability(Abilities.NO_GUARD, "No Guard (N)", "The Pokémon employs no-guard tactics to ensure incoming and outgoing attacks always land.", 4),
new Ability(Abilities.NO_GUARD, "No Guard", "The Pokémon employs no-guard tactics to ensure incoming and outgoing attacks always land.", 4)
.attr(AlwaysHitAbAttr)
.attr(DoubleBattleChanceAbAttr),
new Ability(Abilities.STALL, "Stall (N)", "The Pokémon moves after all other Pokémon do.", 4),
new Ability(Abilities.TECHNICIAN, "Technician", "Powers up the Pokémon's weaker moves.", 4)
.attr(MovePowerBoostAbAttr, (user, target, move) => move.power <= 60, 1.5),
@ -2590,7 +2721,8 @@ export function initAbilities() {
new Ability(Abilities.AFTERMATH, "Aftermath", "Damages the attacker if it contacts the Pokémon with a finishing hit.", 4)
.attr(PostFaintContactDamageAbAttr,4)
.bypassFaint(),
new Ability(Abilities.ANTICIPATION, "Anticipation (N)", "The Pokémon can sense an opposing Pokémon's dangerous moves.", 4),
new Ability(Abilities.ANTICIPATION, "Anticipation", "The Pokémon can sense an opposing Pokémon's dangerous moves.", 4)
.conditionalAttr(getAnticipationCondition(), PostSummonMessageAbAttr, (pokemon: Pokemon) => getPokemonMessage(pokemon, ' shuddered!')),
new Ability(Abilities.FOREWARN, "Forewarn (N)", "When it enters a battle, the Pokémon can tell one of the moves an opposing Pokémon has.", 4),
new Ability(Abilities.UNAWARE, "Unaware", "When attacking, the Pokémon ignores the target Pokémon's stat changes.", 4)
.attr(IgnoreOpponentStatChangesAbAttr)
@ -2634,7 +2766,9 @@ export function initAbilities() {
new Ability(Abilities.BAD_DREAMS, "Bad Dreams (N)", "Reduces the HP of sleeping opposing Pokémon.", 4),
new Ability(Abilities.PICKPOCKET, "Pickpocket", "Steals an item from an attacker that made direct contact.", 5)
.attr(PostDefendStealHeldItemAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT)),
new Ability(Abilities.SHEER_FORCE, "Sheer Force (N)", "Removes additional effects to increase the power of moves when attacking.", 5),
new Ability(Abilities.SHEER_FORCE, "Sheer Force (P)", "Removes additional effects to increase the power of moves when attacking.", 5)
.attr(MovePowerBoostAbAttr, (user, target, move) => move.chance >= 1, 5461/4096)
.attr(MoveEffectChanceMultiplierAbAttr, 0),
new Ability(Abilities.CONTRARY, "Contrary", "Makes stat changes have an opposite effect.", 5)
.attr(StatChangeMultiplierAbAttr, -1)
.ignorable(),
@ -2953,7 +3087,7 @@ export function initAbilities() {
.attr(NoFusionAbilityAbAttr),
new Ability(Abilities.STALWART, "Stalwart (N)", "Ignores the effects of opposing Pokémon's Abilities and moves that draw in moves.", 8),
new Ability(Abilities.STEAM_ENGINE, "Steam Engine", "Boosts the Pokémon's Speed stat drastically if hit by a Fire- or Water-type move.", 8)
.attr(PostDefendStatChangeAbAttr, (target, user, move) => move.type === Type.FIRE || move.type === Type.WATER, BattleStat.SPD, 6),
.attr(PostDefendStatChangeAbAttr, (target, user, move) => (move.type === Type.FIRE || move.type === Type.WATER) && move.category !== MoveCategory.STATUS, BattleStat.SPD, 6),
new Ability(Abilities.PUNK_ROCK, "Punk Rock", "Boosts the power of sound-based moves. The Pokémon also takes half the damage from these kinds of moves.", 8)
.attr(MovePowerBoostAbAttr, (user, target, move) => move.hasFlag(MoveFlags.SOUND_BASED), 1.3)
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.hasFlag(MoveFlags.SOUND_BASED), 0.5)
@ -3093,7 +3227,9 @@ export function initAbilities() {
.attr(MovePowerBoostAbAttr, (user, target, move) => move.hasFlag(MoveFlags.SLICING_MOVE), 1.5),
new Ability(Abilities.SUPREME_OVERLORD, "Supreme Overlord (N)", "When the Pokémon enters a battle, its Attack and Sp. Atk stats are slightly boosted for each of the allies in its party that have already been defeated.", 9),
new Ability(Abilities.COSTAR, "Costar (N)", "When the Pokémon enters a battle, it copies an ally's stat changes.", 9),
new Ability(Abilities.TOXIC_DEBRIS, "Toxic Debris (N)", "Scatters poison spikes at the feet of the opposing team when the Pokémon takes damage from physical moves.", 9),
new Ability(Abilities.TOXIC_DEBRIS, "Toxic Debris", "Scatters poison spikes at the feet of the opposing team when the Pokémon takes damage from physical moves.", 9)
.attr(PostDefendApplyArenaTrapTagAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL, ArenaTagType.TOXIC_SPIKES)
.bypassFaint(),
new Ability(Abilities.ARMOR_TAIL, "Armor Tail", "The mysterious tail covering the Pokémon's head makes opponents unable to use priority moves against the Pokémon or its allies.", 9)
.attr(FieldPriorityMoveImmunityAbAttr)
.ignorable(),

View File

@ -249,7 +249,7 @@ export async function printPokemon() {
Math.max(abilities.indexOf(pokemon.abilities.find(a => a.slot === 3)?.ability.name), 0)
];
const pokemonSpecies = new PokemonSpecies(dexId, species.names.find(n => n.language.name === 'en').name, generationIndex, species.is_legendary && baseTotal < 660, species.is_legendary && baseTotal >= 660, species.is_mythical,
const pokemonSpecies = new PokemonSpecies(dexId, generationIndex, species.is_legendary && baseTotal < 660, species.is_legendary && baseTotal >= 660, species.is_mythical,
species.genera.find(g => g.language.name === 'en')?.genus, type1 as Type, type2 > -1 ? type2 as Type : null, pokemon.height / 10, pokemon.weight / 10, ability1 as Abilities, ability2 as Abilities, abilityHidden as Abilities,
baseTotal, baseStats[0], baseStats[1], baseStats[2], baseStats[3], baseStats[4], baseStats[5], species.capture_rate, species.base_happiness, pokemon.base_experience, growthRateMap[species.growth_rate.name],
species.gender_rate < 9 ? 100 - (species.gender_rate * 12.5) : null, species.has_gender_differences, species.forms_switchable);

View File

@ -65,7 +65,7 @@ export class MistTag extends ArenaTag {
super.onAdd(arena);
const source = arena.scene.getPokemonById(this.sourceId);
arena.scene.queueMessage(getPokemonMessage(source, `'s team became\nshrowded in mist!`));
arena.scene.queueMessage(getPokemonMessage(source, `'s team became\nshrouded in mist!`));
}
apply(arena: Arena, args: any[]): boolean {

View File

@ -8,7 +8,7 @@ import * as Utils from "../utils";
import { Moves } from "./enums/moves";
import { ChargeAttr, MoveFlags, allMoves } from "./move";
import { Type } from "./type";
import { BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, applyAbAttrs } from "./ability";
import { BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, ReverseDrainAbAttr, applyAbAttrs } from "./ability";
import { Abilities } from "./enums/abilities";
import { BattlerTagType } from "./enums/battler-tag-type";
import { TerrainType } from "./terrain";
@ -292,7 +292,11 @@ export class SeedTag extends BattlerTag {
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, source.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.LEECH_SEED));
const damage = pokemon.damageAndUpdate(Math.max(Math.floor(pokemon.getMaxHp() / 8), 1));
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, source.getBattlerIndex(), damage, getPokemonMessage(pokemon, '\'s health is\nsapped by Leech Seed!'), false, true));
const reverseDrain = pokemon.hasAbilityWithAttr(ReverseDrainAbAttr);
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, source.getBattlerIndex(),
!reverseDrain ? damage : damage * -1,
!reverseDrain ? getPokemonMessage(pokemon, '\'s health is\nsapped by Leech Seed!') : getPokemonMessage(source, '\'s Leech Seed\nsucked up the liquid ooze!'),
false, true));
}
}
}
@ -1017,6 +1021,39 @@ export class SaltCuredTag extends BattlerTag {
}
}
export class CursedTag extends BattlerTag {
private sourceIndex: integer;
constructor(sourceId: integer) {
super(BattlerTagType.CURSED, BattlerTagLapseType.TURN_END, 1, Moves.CURSE, sourceId);
}
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ' has been cursed!'));
this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId).getBattlerIndex();
}
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
if (ret) {
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.SALT_CURE));
const cancelled = new Utils.BooleanHolder(false);
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
if (!cancelled.value) {
pokemon.damageAndUpdate(Math.floor(pokemon.getMaxHp() / 4));
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` is hurt by the ${this.getMoveName()}!`));
}
}
return ret;
}
}
export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourceMove: Moves, sourceId: integer): BattlerTag {
switch (tagType) {
case BattlerTagType.RECHARGING:
@ -1114,6 +1151,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc
return new BattlerTag(tagType, BattlerTagLapseType.TURN_END, turnCount - 1, sourceMove);
case BattlerTagType.SALT_CURED:
return new SaltCuredTag(sourceId);
case BattlerTagType.CURSED:
return new CursedTag(sourceId);
case BattlerTagType.CHARGED:
return new TypeBoostTag(tagType, sourceMove, Type.ELECTRIC, 2, true);
case BattlerTagType.NONE:

View File

@ -1453,7 +1453,7 @@ export const trainerTypeDialogue = {
`I thought that you would be able to get this far. Let's get this started.`
],
victory: [
`You got me. You are magneficent!`,
`You got me. You are magnificent!`,
`I never expected another trainer to beat me… I'm surprised.`
],
defeat: [

View File

@ -250,88 +250,88 @@ export const speciesEggMoves = {
[Species.DARKRAI]: [ Moves.FIERY_WRATH, Moves.MOONBLAST, Moves.SEARING_SHOT, Moves.MALIGNANT_CHAIN ],
[Species.SHAYMIN]: [ Moves.SPRINGTIDE_STORM, Moves.HEAT_WAVE, Moves.BLEAKWIND_STORM, Moves.MATCHA_GOTCHA ],
[Species.ARCEUS]: [ Moves.QUIVER_DANCE, Moves.SPIRIT_SHACKLE, Moves.VICTORY_DANCE, Moves.COLLISION_COURSE ],
[Species.VICTINI]: [ Moves.PHOTON_GEYSER, Moves.BOLT_STRIKE, Moves.BLUE_FLARE, Moves.VICTORY_DANCE ],
[Species.SNIVY]: [ Moves.SYNTHESIS, Moves.SAPPY_SEED, Moves.POWER_GEM, Moves.DRACO_METEOR ],
[Species.TEPIG]: [ Moves.SUCKER_PUNCH, Moves.SLACK_OFF, Moves.MACH_PUNCH, Moves.VICTORY_DANCE ],
[Species.OSHAWOTT]: [ Moves.SECRET_SWORD, Moves.AQUA_CUTTER, Moves.NASTY_PLOT, Moves.BEHEMOTH_BLADE ],
[Species.PATRAT]: [ Moves.COVET, Moves.EXTREME_SPEED, Moves.ACUPRESSURE, Moves.LAST_RESORT ],
[Species.LILLIPUP]: [ Moves.COVET, Moves.LAST_RESPECTS, Moves.HIGH_HORSEPOWER, Moves.NO_RETREAT ],
[Species.PURRLOIN]: [ Moves.PSYCHIC_FANGS, Moves.SWORDS_DANCE, Moves.PARTING_SHOT, Moves.WICKED_BLOW ],
[Species.PANSAGE]: [ Moves.NASTY_PLOT, Moves.AURA_SPHERE, Moves.TRAILBLAZE, Moves.FRENZY_PLANT ],
[Species.PANSEAR]: [ Moves.NASTY_PLOT, Moves.AURA_SPHERE, Moves.SCORCHING_SANDS, Moves.BLAST_BURN ],
[Species.PANPOUR]: [ Moves.NASTY_PLOT, Moves.AURA_SPHERE, Moves.FREEZE_DRY, Moves.HYDRO_CANNON ],
[Species.VICTINI]: [ Moves.RECOVER, Moves.BOLT_STRIKE, Moves.PHOTON_GEYSER, Moves.VICTORY_DANCE ],
[Species.SNIVY]: [ Moves.BURNING_JEALOUSY, Moves.SAPPY_SEED, Moves.SUPERPOWER, Moves.FLEUR_CANNON ],
[Species.TEPIG]: [ Moves.AXE_KICK, Moves.VOLT_TACKLE, Moves.DRAIN_PUNCH, Moves.VICTORY_DANCE ],
[Species.OSHAWOTT]: [ Moves.ICE_SPINNER, Moves.SHELL_SIDE_ARM, Moves.SACRED_SWORD, Moves.SHELL_SMASH ],
[Species.PATRAT]: [ Moves.YAWN, Moves.PSYCHIC_FANGS, Moves.GLARE, Moves.EXTREME_SPEED ],
[Species.LILLIPUP]: [ Moves.CLOSE_COMBAT, Moves.THIEF, Moves.HIGH_HORSEPOWER, Moves.LAST_RESPECTS ],
[Species.PURRLOIN]: [ Moves.ENCORE, Moves.ASSIST, Moves.PARTING_SHOT, Moves.WICKED_BLOW ],
[Species.PANSAGE]: [ Moves.SWORDS_DANCE, Moves.TEMPER_FLARE, Moves.EARTHQUAKE, Moves.IVY_CUDGEL ],
[Species.PANSEAR]: [ Moves.NASTY_PLOT, Moves.SCALD, Moves.SCORCHING_SANDS, Moves.SEARING_SHOT ],
[Species.PANPOUR]: [ Moves.NASTY_PLOT, Moves.ENERGY_BALL, Moves.AURA_SPHERE, Moves.STEAM_ERUPTION ],
[Species.MUNNA]: [ Moves.COSMIC_POWER, Moves.AURA_SPHERE, Moves.EARTH_POWER, Moves.MYSTICAL_POWER ],
[Species.PIDOVE]: [ Moves.SUCKER_PUNCH, Moves.TIDY_UP, Moves.COVET, Moves.FLOATY_FALL ],
[Species.BLITZLE]: [ Moves.HIGH_HORSEPOWER, Moves.TRAILBLAZE, Moves.WORK_UP, Moves.VOLT_TACKLE ],
[Species.ROGGENROLA]: [ Moves.BODY_PRESS, Moves.CURSE, Moves.STONE_AXE, Moves.DIAMOND_STORM ],
[Species.WOOBAT]: [ Moves.MYSTICAL_POWER, Moves.ESPER_WING, Moves.MYSTICAL_FIRE, Moves.OBLIVION_WING ],
[Species.DRILBUR]: [ Moves.IRON_HEAD, Moves.HYPER_DRILL, Moves.TRAILBLAZE, Moves.BEHEMOTH_BLADE ],
[Species.AUDINO]: [ Moves.BOOMBURST, Moves.MOONBLAST, Moves.METRONOME, Moves.COSMIC_POWER ],
[Species.TIMBURR]: [ Moves.MACH_PUNCH, Moves.BULLET_PUNCH, Moves.SWORDS_DANCE, Moves.ACCELEROCK ],
[Species.TYMPOLE]: [ Moves.LIQUIDATION, Moves.STOMPING_TANTRUM, Moves.RECOVER, Moves.JET_PUNCH ],
[Species.THROH]: [ Moves.UPPER_HAND, Moves.MACH_PUNCH, Moves.SPIN_OUT, Moves.DRAIN_PUNCH ],
[Species.SAWK]: [ Moves.UPPER_HAND, Moves.MACH_PUNCH, Moves.SMART_STRIKE, Moves.THUNDEROUS_KICK ],
[Species.SEWADDLE]: [ Moves.SMACK_DOWN, Moves.TROP_KICK, Moves.TIDY_UP, Moves.FIRST_IMPRESSION ],
[Species.VENIPEDE]: [ Moves.STEAMROLLER, Moves.MORTAL_SPIN, Moves.NOXIOUS_TORQUE, Moves.EARTHQUAKE ],
[Species.COTTONEE]: [ Moves.MUD_SHOT, Moves.STEALTH_ROCK, Moves.AIR_SLASH, Moves.SEED_FLARE ],
[Species.PETILIL]: [ Moves.DRAIN_PUNCH, Moves.BATON_PASS, Moves.EARTH_POWER, Moves.ICE_BEAM ],
[Species.BASCULIN]: [ Moves.LAST_RESPECTS, Moves.CLOSE_COMBAT, Moves.SHADOW_SNEAK, Moves.FISHIOUS_REND ],
[Species.SANDILE]: [ Moves.DIRE_CLAW, Moves.PARTING_SHOT, Moves.RAGING_FURY, Moves.PRECIPICE_BLADES ],
[Species.DARUMAKA]: [ Moves.DRAIN_PUNCH, Moves.THUNDER_PUNCH, Moves.BURNING_BULWARK, Moves.V_CREATE ],
[Species.MARACTUS]: [ Moves.SPIKY_SHIELD, Moves.FLOWER_TRICK, Moves.BARB_BARRAGE, Moves.SEED_FLARE ],
[Species.DWEBBLE]: [ Moves.CRABHAMMER, Moves.STONE_AXE, Moves.LEECH_LIFE, Moves.SHELL_TRAP ],
[Species.SCRAGGY]: [ Moves.SUCKER_PUNCH, Moves.GUNK_SHOT, Moves.SHED_TAIL, Moves.ATTACK_ORDER ],
[Species.SIGILYPH]: [ Moves.METEOR_BEAM, Moves.LUNAR_BLESSING, Moves.FREEZING_GLARE, Moves.OBLIVION_WING ],
[Species.YAMASK]: [ Moves.RECOVER, Moves.COSMIC_POWER, Moves.AURA_SPHERE, Moves.MAKE_IT_RAIN ],
[Species.TIRTOUGA]: [ Moves.RAZOR_SHELL, Moves.SHELL_SIDE_ARM, Moves.JAW_LOCK, Moves.NO_RETREAT ],
[Species.ARCHEN]: [ Moves.FLOATY_FALL, Moves.HEAD_SMASH, Moves.BRAVE_BIRD, Moves.DRAGON_DANCE ],
[Species.TRUBBISH]: [ Moves.CORROSIVE_GAS, Moves.DEFEND_ORDER, Moves.DIRE_CLAW, Moves.GIGATON_HAMMER ],
[Species.ZORUA]: [ Moves.BADDY_BAD, Moves.EXTRASENSORY, Moves.AURA_SPHERE, Moves.TRANSFORM ],
[Species.MINCCINO]: [ Moves.COVET, Moves.TIDY_UP, Moves.BONE_RUSH, Moves.POPULATION_BOMB ],
[Species.GOTHITA]: [ Moves.MILK_DRINK, Moves.MYSTICAL_POWER, Moves.MYSTICAL_FIRE, Moves.DARK_VOID ],
[Species.SOLOSIS]: [ Moves.COSMIC_POWER, Moves.MOONBLAST, Moves.FREEZE_DRY, Moves.PSYSTRIKE ],
[Species.PIDOVE]: [ Moves.NIGHT_SLASH, Moves.TIDY_UP, Moves.FLOATY_FALL, Moves.TRIPLE_ARROWS ],
[Species.BLITZLE]: [ Moves.HIGH_HORSEPOWER, Moves.THUNDEROUS_KICK, Moves.FLARE_BLITZ, Moves.VOLT_TACKLE ],
[Species.ROGGENROLA]: [ Moves.BODY_PRESS, Moves.CURSE, Moves.SHORE_UP, Moves.DIAMOND_STORM ],
[Species.WOOBAT]: [ Moves.QUIVER_DANCE, Moves.STORED_POWER, Moves.MYSTICAL_FIRE, Moves.OBLIVION_WING ],
[Species.DRILBUR]: [ Moves.IRON_HEAD, Moves.ICE_SPINNER, Moves.SHIFT_GEAR, Moves.BEHEMOTH_BASH ],
[Species.AUDINO]: [ Moves.FOLLOW_ME, Moves.MOONBLAST, Moves.WISH, Moves.LUNAR_BLESSING ],
[Species.TIMBURR]: [ Moves.MACH_PUNCH, Moves.DRAIN_PUNCH, Moves.ICE_HAMMER, Moves.DOUBLE_IRON_BASH ],
[Species.TYMPOLE]: [ Moves.LIQUIDATION, Moves.HIGH_HORSEPOWER, Moves.TOXIC, Moves.SHORE_UP ],
[Species.THROH]: [ Moves.DRAIN_PUNCH, Moves.SLACK_OFF, Moves.METEOR_MASH, Moves.NO_RETREAT ],
[Species.SAWK]: [ Moves.DRAIN_PUNCH, Moves.MACH_PUNCH, Moves.ENDEAVOR, Moves.VICTORY_DANCE ],
[Species.SEWADDLE]: [ Moves.STONE_AXE, Moves.PSYCHO_CUT, Moves.TIDY_UP, Moves.BITTER_BLADE ],
[Species.VENIPEDE]: [ Moves.SWORDS_DANCE, Moves.BATON_PASS, Moves.NOXIOUS_TORQUE, Moves.EARTHQUAKE ],
[Species.COTTONEE]: [ Moves.POLLEN_PUFF, Moves.PARTING_SHOT, Moves.SLEEP_POWDER, Moves.SEED_FLARE ],
[Species.PETILIL]: [ Moves.THUNDEROUS_KICK, Moves.BATON_PASS, Moves.AQUA_STEP, Moves.FIERY_DANCE ],
[Species.BASCULIN]: [ Moves.LAST_RESPECTS, Moves.CLOSE_COMBAT, Moves.DRAGON_DANCE, Moves.FISHIOUS_REND ],
[Species.SANDILE]: [ Moves.DIRE_CLAW, Moves.PARTING_SHOT, Moves.FIRE_LASH, Moves.PRECIPICE_BLADES ],
[Species.DARUMAKA]: [ Moves.DRAIN_PUNCH, Moves.THUNDER_PUNCH, Moves.BLAZING_TORQUE, Moves.V_CREATE ],
[Species.MARACTUS]: [ Moves.SCORCHING_SANDS, Moves.QUIVER_DANCE, Moves.FIERY_DANCE, Moves.SEED_FLARE ],
[Species.DWEBBLE]: [ Moves.CRABHAMMER, Moves.STONE_AXE, Moves.LEECH_LIFE, Moves.SHORE_UP ],
[Species.SCRAGGY]: [ Moves.SUCKER_PUNCH, Moves.TRIPLE_AXEL, Moves.DRAGON_DANCE, Moves.COLLISION_COURSE ],
[Species.SIGILYPH]: [ Moves.STORED_POWER, Moves.TAKE_HEART, Moves.FREEZING_GLARE, Moves.OBLIVION_WING ],
[Species.YAMASK]: [ Moves.RECOVER, Moves.INFERNAL_PARADE, Moves.AURA_SPHERE, Moves.TOPSY_TURVY ],
[Species.TIRTOUGA]: [ Moves.ICE_SPINNER, Moves.ACCELEROCK, Moves.SHORE_UP, Moves.WAVE_CRASH ],
[Species.ARCHEN]: [ Moves.ROOST, Moves.ACCELEROCK, Moves.FLOATY_FALL, Moves.MIGHTY_CLEAVE ],
[Species.TRUBBISH]: [ Moves.TIDY_UP, Moves.RECOVER, Moves.DIRE_CLAW, Moves.GIGATON_HAMMER ],
[Species.ZORUA]: [ Moves.BADDY_BAD, Moves.PSYCHIC, Moves.AURA_SPHERE, Moves.WICKED_BLOW ],
[Species.MINCCINO]: [ Moves.ICICLE_SPEAR, Moves.TIDY_UP, Moves.BONE_RUSH, Moves.POPULATION_BOMB ],
[Species.GOTHITA]: [ Moves.MILK_DRINK, Moves.COSMIC_POWER, Moves.AURA_SPHERE, Moves.PSYSTRIKE ],
[Species.SOLOSIS]: [ Moves.COSMIC_POWER, Moves.MOONBLAST, Moves.AURA_SPHERE, Moves.PSYSTRIKE ],
[Species.DUCKLETT]: [ Moves.QUIVER_DANCE, Moves.EARTH_POWER, Moves.FREEZE_DRY, Moves.OBLIVION_WING ],
[Species.VANILLITE]: [ Moves.MILK_DRINK, Moves.DECORATE, Moves.LOCK_ON, Moves.EARTH_POWER ],
[Species.DEERLING]: [ Moves.TIDY_UP, Moves.HEADBUTT, Moves.JUMP_KICK, Moves.FLOWER_TRICK ],
[Species.EMOLGA]: [ Moves.ROOST, Moves.CHARM, Moves.THUNDER_WAVE, Moves.THUNDER_CAGE ],
[Species.KARRABLAST]: [ Moves.SHIFT_GEAR, Moves.LEECH_LIFE, Moves.ROCK_WRECKER, Moves.DOUBLE_IRON_BASH ],
[Species.FOONGUS]: [ Moves.PAIN_SPLIT, Moves.CORROSIVE_GAS, Moves.SHELL_SIDE_ARM, Moves.STRENGTH_SAP ],
[Species.FRILLISH]: [ Moves.STRENGTH_SAP, Moves.BOUNCY_BUBBLE, Moves.FREEZE_DRY, Moves.MOONGEIST_BEAM ],
[Species.ALOMOMOLA]: [ Moves.BOUNCY_BUBBLE, Moves.HEART_SWAP, Moves.ATTRACT, Moves.TAKE_HEART ],
[Species.JOLTIK]: [ Moves.THUNDER_CAGE, Moves.PARABOLIC_CHARGE, Moves.QUIVER_DANCE, Moves.EARTH_POWER ],
[Species.FERROSEED]: [ Moves.STRENGTH_SAP, Moves.BODY_PRESS, Moves.DRILL_RUN, Moves.DOUBLE_IRON_BASH ],
[Species.KLINK]: [ Moves.TRAILBLAZE, Moves.HIGH_HORSEPOWER, Moves.FUSION_BOLT, Moves.DOUBLE_IRON_BASH ],
[Species.TYNAMO]: [ Moves.PARABOLIC_CHARGE, Moves.LEECH_LIFE, Moves.DRAGON_DANCE, Moves.FUSION_BOLT ],
[Species.ELGYEM]: [ Moves.MYSTICAL_POWER, Moves.METEOR_BEAM, Moves.COSMIC_POWER, Moves.MOONGEIST_BEAM ],
[Species.LITWICK]: [ Moves.NASTY_PLOT, Moves.SCORCHING_SANDS, Moves.TORCH_SONG, Moves.MOONGEIST_BEAM ],
[Species.AXEW]: [ Moves.STONE_AXE, Moves.GLAIVE_RUSH, Moves.TEMPER_FLARE, Moves.VICTORY_DANCE ],
[Species.CUBCHOO]: [ Moves.MOUNTAIN_GALE, Moves.DRAIN_PUNCH, Moves.SWORDS_DANCE, Moves.WAVE_CRASH ],
[Species.CRYOGONAL]: [ Moves.SURF, Moves.EARTH_POWER, Moves.NASTY_PLOT, Moves.BLEAKWIND_STORM ],
[Species.SHELMET]: [ Moves.SHED_TAIL, Moves.LEECH_LIFE, Moves.SILK_TRAP, Moves.CEASELESS_EDGE ],
[Species.STUNFISK]: [ Moves.SPIKES, Moves.BANEFUL_BUNKER, Moves.SUPERCELL_SLAM, Moves.DRAGON_DANCE ],
[Species.MIENFOO]: [ Moves.TIDY_UP, Moves.ICE_SPINNER, Moves.SUPERCELL_SLAM, Moves.BRAVE_BIRD ],
[Species.DRUDDIGON]: [ Moves.SPIKY_SHIELD, Moves.STOMPING_TANTRUM, Moves.CLANGOROUS_SOUL, Moves.DIAMOND_STORM ],
[Species.GOLETT]: [ Moves.BULK_UP, Moves.RAGE_FIST, Moves.HEADLONG_RUSH, Moves.DOUBLE_IRON_BASH ],
[Species.PAWNIARD]: [ Moves.SUCKER_PUNCH, Moves.CEASELESS_EDGE, Moves.AQUA_CUTTER, Moves.PSYBLADE ],
[Species.BOUFFALANT]: [ Moves.EARTHQUAKE, Moves.FLAME_CHARGE, Moves.IRON_HEAD, Moves.RAGING_BULL ],
[Species.RUFFLET]: [ Moves.FLOATY_FALL, Moves.DAZZLING_GLEAM, Moves.HEAT_WAVE, Moves.BOLT_BEAK ],
[Species.VULLABY]: [ Moves.RUINATION, Moves.BODY_PRESS, Moves.ROOST, Moves.BADDY_BAD ],
[Species.HEATMOR]: [ Moves.SCORCHING_SANDS, Moves.NASTY_PLOT, Moves.FLASH_CANNON, Moves.SEARING_SHOT ],
[Species.DURANT]: [ Moves.SMART_STRIKE, Moves.FIRST_IMPRESSION, Moves.HONE_CLAWS, Moves.EXTREME_SPEED ],
[Species.DEINO]: [ Moves.FIERY_WRATH, Moves.HYDRO_STEAM, Moves.CORROSIVE_GAS, Moves.FICKLE_BEAM ],
[Species.LARVESTA]: [ Moves.TORCH_SONG, Moves.POLLEN_PUFF, Moves.EARTH_POWER, Moves.BLUE_FLARE ],
[Species.VANILLITE]: [ Moves.EARTH_POWER, Moves.AURORA_VEIL, Moves.LOCK_ON, Moves.MILK_DRINK ],
[Species.DEERLING]: [ Moves.TIDY_UP, Moves.HEADBUTT, Moves.BODY_SLAM, Moves.FLOWER_TRICK ],
[Species.EMOLGA]: [ Moves.ROOST, Moves.HEAT_WAVE, Moves.TAILWIND, Moves.ZING_ZAP ],
[Species.KARRABLAST]: [ Moves.TRICK_ROOM, Moves.SHORE_UP, Moves.MIGHTY_CLEAVE, Moves.BITTER_BLADE ],
[Species.FOONGUS]: [ Moves.POLLEN_PUFF, Moves.PARTING_SHOT, Moves.FOUL_PLAY, Moves.STRENGTH_SAP ],
[Species.FRILLISH]: [ Moves.STRENGTH_SAP, Moves.INFERNAL_PARADE, Moves.FREEZE_DRY, Moves.STEAM_ERUPTION ],
[Species.ALOMOMOLA]: [ Moves.FLIP_TURN, Moves.HEART_SWAP, Moves.TOXIC, Moves.GLITZY_GLOW ],
[Species.JOLTIK]: [ Moves.THUNDER, Moves.PARABOLIC_CHARGE, Moves.EARTH_POWER, Moves.QUIVER_DANCE ],
[Species.FERROSEED]: [ Moves.STRENGTH_SAP, Moves.BODY_PRESS, Moves.SPIKY_SHIELD, Moves.SAPPY_SEED ],
[Species.KLINK]: [ Moves.FLARE_BLITZ, Moves.HIGH_HORSEPOWER, Moves.FUSION_BOLT, Moves.DOUBLE_IRON_BASH ],
[Species.TYNAMO]: [ Moves.LIQUIDATION, Moves.RECOVER, Moves.PARTING_SHOT, Moves.BOLT_BEAK ],
[Species.ELGYEM]: [ Moves.MYSTICAL_POWER, Moves.TRICK_ROOM, Moves.STORED_POWER, Moves.PSYSTRIKE ],
[Species.LITWICK]: [ Moves.FIERY_DANCE, Moves.EARTH_POWER, Moves.MOONBLAST, Moves.ASTRAL_BARRAGE ],
[Species.AXEW]: [ Moves.STONE_AXE, Moves.DIRE_CLAW, Moves.FIRE_LASH, Moves.GLAIVE_RUSH ],
[Species.CUBCHOO]: [ Moves.MOUNTAIN_GALE, Moves.WOOD_HAMMER, Moves.SWORDS_DANCE, Moves.WAVE_CRASH ],
[Species.CRYOGONAL]: [ Moves.SURF, Moves.EARTH_POWER, Moves.NASTY_PLOT, Moves.FREEZY_FROST ],
[Species.SHELMET]: [ Moves.SHED_TAIL, Moves.NASTY_PLOT, Moves.BATON_PASS, Moves.HEAT_WAVE ],
[Species.STUNFISK]: [ Moves.SHORE_UP, Moves.BANEFUL_BUNKER, Moves.THUNDER_CAGE, Moves.THUNDERCLAP ],
[Species.MIENFOO]: [ Moves.GUNK_SHOT, Moves.TRIPLE_AXEL, Moves.SUPERCELL_SLAM, Moves.TIDY_UP ],
[Species.DRUDDIGON]: [ Moves.SPIKY_SHIELD, Moves.ROOST, Moves.DRAGON_HAMMER, Moves.FIRE_LASH ],
[Species.GOLETT]: [ Moves.BULK_UP, Moves.BULLET_PUNCH, Moves.HEADLONG_RUSH, Moves.RAGE_FIST ],
[Species.PAWNIARD]: [ Moves.SUCKER_PUNCH, Moves.CEASELESS_EDGE, Moves.BITTER_BLADE, Moves.LAST_RESPECTS ],
[Species.BOUFFALANT]: [ Moves.SLACK_OFF, Moves.JUMP_KICK, Moves.HEAD_SMASH, Moves.FLARE_BLITZ ],
[Species.RUFFLET]: [ Moves.FLOATY_FALL, Moves.MOONBLAST, Moves.HEAT_WAVE, Moves.BOLT_BEAK ],
[Species.VULLABY]: [ Moves.TOXIC, Moves.BODY_PRESS, Moves.ROOST, Moves.TOPSY_TURVY ],
[Species.HEATMOR]: [ Moves.EARTH_POWER, Moves.OVERHEAT, Moves.FLASH_CANNON, Moves.V_CREATE ],
[Species.DURANT]: [ Moves.HIGH_HORSEPOWER, Moves.FIRST_IMPRESSION, Moves.SWORDS_DANCE, Moves.BEHEMOTH_BASH ],
[Species.DEINO]: [ Moves.FIERY_WRATH, Moves.ESPER_WING, Moves.SLUDGE_WAVE, Moves.FICKLE_BEAM ],
[Species.LARVESTA]: [ Moves.THUNDERBOLT, Moves.ERUPTION, Moves.EARTH_POWER, Moves.TORCH_SONG ],
[Species.COBALION]: [ Moves.TACHYON_CUTTER, Moves.BODY_PRESS, Moves.CEASELESS_EDGE, Moves.VICTORY_DANCE ],
[Species.TERRAKION]: [ Moves.MIGHTY_CLEAVE, Moves.HEADLONG_RUSH, Moves.CEASELESS_EDGE, Moves.VICTORY_DANCE ],
[Species.VIRIZION]: [ Moves.PSYBLADE, Moves.SAPPY_SEED, Moves.CEASELESS_EDGE, Moves.VICTORY_DANCE ],
[Species.TORNADUS]: [ Moves.MIST_BALL, Moves.BRAVE_BIRD, Moves.DRAIN_PUNCH, Moves.BLIZZARD ],
[Species.THUNDURUS]: [ Moves.THUNDER_CAGE, Moves.BULK_UP, Moves.FLOATY_FALL, Moves.THUNDERCLAP ],
[Species.RESHIRAM]: [ Moves.FUSION_BOLT, Moves.FIERY_DANCE, Moves.POWER_GEM, Moves.DRAGON_ENERGY ],
[Species.ZEKROM]: [ Moves.FUSION_FLARE, Moves.BOLT_BEAK, Moves.DRAGON_HAMMER, Moves.VOLT_TACKLE ],
[Species.LANDORUS]: [ Moves.ROCK_SLIDE, Moves.LANDS_WRATH, Moves.AERIAL_ACE, Moves.AQUA_TAIL ],
[Species.KYUREM]: [ Moves.ICICLE_CRASH, Moves.DRAGON_HAMMER, Moves.ICE_SHARD, Moves.GLACIAL_LANCE ],
[Species.KELDEO]: [ Moves.WATER_PLEDGE, Moves.AIR_SLASH, Moves.ICE_BEAM, Moves.TACHYON_CUTTER ],
[Species.MELOETTA]: [ Moves.TORCH_SONG, Moves.QUIVER_DANCE, Moves.VICTORY_DANCE, Moves.BOOMBURST ],
[Species.GENESECT]: [ Moves.FOCUS_BLAST, Moves.STEEL_BEAM, Moves.SHIFT_GEAR, Moves.QUIVER_DANCE ],
[Species.TORNADUS]: [ Moves.EARTH_POWER, Moves.U_TURN, Moves.ICE_BEAM, Moves.AEROBLAST ],
[Species.THUNDURUS]: [ Moves.EARTH_POWER, Moves.AEROBLAST, Moves.THUNDERCLAP, Moves.ELECTRO_SHOT ],
[Species.RESHIRAM]: [ Moves.FUSION_BOLT, Moves.CALM_MIND, Moves.SOLAR_BEAM, Moves.DRAGON_ENERGY ],
[Species.ZEKROM]: [ Moves.FUSION_FLARE, Moves.THUNDEROUS_KICK, Moves.DRAGON_HAMMER, Moves.BOLT_BEAK ],
[Species.LANDORUS]: [ Moves.STONE_AXE, Moves.HIGH_HORSEPOWER, Moves.ROOST, Moves.FLOATY_FALL ],
[Species.KYUREM]: [ Moves.ICICLE_CRASH, Moves.DRAGON_ENERGY, Moves.PHOTON_GEYSER, Moves.GLACIAL_LANCE ],
[Species.KELDEO]: [ Moves.TACHYON_CUTTER, Moves.THUNDERBOLT, Moves.ICE_BEAM, Moves.STEAM_ERUPTION ],
[Species.MELOETTA]: [ Moves.THUNDEROUS_KICK, Moves.QUIVER_DANCE, Moves.VICTORY_DANCE, Moves.BOOMBURST ],
[Species.GENESECT]: [ Moves.AURA_SPHERE, Moves.U_TURN, Moves.SHIFT_GEAR, Moves.TAIL_GLOW ],
[Species.CHESPIN]: [ Moves.DRAIN_PUNCH, Moves.BELLY_DRUM, Moves.TAUNT, Moves.SAPPY_SEED ],
[Species.FENNEKIN]: [ Moves.DRAGON_PULSE, Moves.STRANGE_STEAM, Moves.HYPNOSIS, Moves.MYSTICAL_POWER ],
[Species.FROAKIE]: [ Moves.FAKE_OUT, Moves.ICY_WIND, Moves.FLIP_TURN, Moves.SURGING_STRIKES ],
@ -369,61 +369,61 @@ export const speciesEggMoves = {
[Species.DIANCIE]: [ Moves.DECORATE, Moves.COSMIC_POWER, Moves.EARTH_POWER, Moves.SPARKLY_SWIRL ],
[Species.HOOPA]: [ Moves.PSYCHIC_NOISE, Moves.TOPSY_TURVY, Moves.BATON_PASS, Moves.SPECTRAL_THIEF ],
[Species.VOLCANION]: [ Moves.HYDRO_STEAM, Moves.HYDRO_CANNON, Moves.BLAST_BURN, Moves.METEOR_BEAM ],
[Species.ROWLET]: [ Moves.SNIPE_SHOT, Moves.ESPER_WING, Moves.TRIPLE_ARROWS, Moves.THOUSAND_ARROWS ],
[Species.LITTEN]: [ Moves.FAKE_OUT, Moves.PARTING_SHOT, Moves.PSYCHIC_FANGS, Moves.FLYING_PRESS ],
[Species.POPPLIO]: [ Moves.ENCORE, Moves.BOUNCY_BUBBLE, Moves.ALLURING_VOICE, Moves.BOOMBURST ],
[Species.PIKIPEK]: [ Moves.BOOMBURST, Moves.FLAME_CHARGE, Moves.KNOCK_OFF, Moves.BURNING_BULWARK ],
[Species.YUNGOOS]: [ Moves.HYPER_FANG, Moves.POISON_FANG, Moves.SWORDS_DANCE, Moves.FORESIGHT ],
[Species.GRUBBIN]: [ Moves.ELECTROWEB, Moves.AIR_SLASH, Moves.SIGNAL_BEAM, Moves.ELECTRO_SHOT ],
[Species.CRABRAWLER]: [ Moves.MACH_PUNCH, Moves.FIRE_PUNCH, Moves.JET_PUNCH, Moves.WOOD_HAMMER ],
[Species.ROWLET]: [ Moves.SNIPE_SHOT, Moves.POLTERGEIST, Moves.FIRST_IMPRESSION, Moves.VICTORY_DANCE ],
[Species.LITTEN]: [ Moves.FAKE_OUT, Moves.PARTING_SHOT, Moves.SUCKER_PUNCH, Moves.SACRED_FIRE ],
[Species.POPPLIO]: [ Moves.PSYCHIC_NOISE, Moves.BOUNCY_BUBBLE, Moves.ALLURING_VOICE, Moves.TORCH_SONG ],
[Species.PIKIPEK]: [ Moves.FLOATY_FALL, Moves.BONE_RUSH, Moves.KNOCK_OFF, Moves.BURNING_BULWARK ],
[Species.YUNGOOS]: [ Moves.EXTREME_SPEED, Moves.PURSUIT, Moves.TIDY_UP, Moves.MULTI_ATTACK ],
[Species.GRUBBIN]: [ Moves.ICE_BEAM, Moves.EARTH_POWER, Moves.QUIVER_DANCE, Moves.THUNDERCLAP ],
[Species.CRABRAWLER]: [ Moves.CURSE, Moves.SHORE_UP, Moves.SUCKER_PUNCH, Moves.SURGING_STRIKES ],
[Species.ORICORIO]: [ Moves.QUIVER_DANCE, Moves.FIERY_DANCE, Moves.PETAL_DANCE, Moves.LUNAR_DANCE ],
[Species.CUTIEFLY]: [ Moves.FOLLOW_ME, Moves.TAILWIND, Moves.GRASS_WHISTLE, Moves.INSTRUCT ],
[Species.ROCKRUFF]: [ Moves.KNOCK_OFF, Moves.BULK_UP, Moves.FLAME_CHARGE, Moves.STONE_AXE ],
[Species.WISHIWASHI]: [ Moves.FLIP_TURN, Moves.SCALE_SHOT, Moves.SWORDS_DANCE, Moves.POPULATION_BOMB ],
[Species.MAREANIE]: [ Moves.SPIKES, Moves.AQUA_RING, Moves.STOCKPILE, Moves.MORTAL_SPIN ],
[Species.MUDBRAY]: [ Moves.BODY_PRESS, Moves.YAWN, Moves.IRON_DEFENSE, Moves.RECOVER ],
[Species.DEWPIDER]: [ Moves.STICKY_WEB, Moves.SILK_TRAP, Moves.WAVE_CRASH, Moves.HEAD_SMASH ],
[Species.FOMANTIS]: [ Moves.SUPERPOWER, Moves.HEADLONG_RUSH, Moves.DRACO_METEOR, Moves.FLEUR_CANNON ],
[Species.MORELULL]: [ Moves.STUN_SPORE, Moves.LEECH_SEED, Moves.POLLEN_PUFF, Moves.FLOWER_SHIELD ],
[Species.SALANDIT]: [ Moves.FAKE_OUT, Moves.TEMPER_FLARE, Moves.SLUDGE_WAVE, Moves.SCALD ],
[Species.STUFFUL]: [ Moves.RAGE, Moves.COACHING, Moves.TEATIME, Moves.SKY_UPPERCUT ],
[Species.BOUNSWEET]: [ Moves.TRIPLE_AXEL, Moves.PLAY_ROUGH, Moves.GRASSY_GLIDE, Moves.AQUA_STEP ],
[Species.COMFEY]: [ Moves.DECORATE, Moves.POLLEN_PUFF, Moves.TAILWIND, Moves.FLOWER_SHIELD ],
[Species.ORANGURU]: [ Moves.FOUL_PLAY, Moves.YAWN, Moves.CRAFTY_SHIELD, Moves.BOOMBURST ],
[Species.PASSIMIAN]: [ Moves.TRAILBLAZE, Moves.BULK_UP, Moves.PROTECT, Moves.MACH_PUNCH ],
[Species.WIMPOD]: [ Moves.ICE_PUNCH, Moves.FLIP_TURN, Moves.KOWTOW_CLEAVE, Moves.SURGING_STRIKES ],
[Species.SANDYGAST]: [ Moves.TRICK_ROOM, Moves.BREAKING_SWIPE, Moves.GYRO_BALL, Moves.BODY_PRESS ],
[Species.PYUKUMUKU]: [ Moves.SUBSTITUTE, Moves.RECYCLE, Moves.LIFE_DEW, Moves.MIRROR_COAT ],
[Species.TYPE_NULL]: [ Moves.CALM_MIND, Moves.RECOVER, Moves.RETURN, Moves.JUDGMENT ],
[Species.MINIOR]: [ Moves.DRACO_METEOR, Moves.FLOATY_FALL, Moves.METEOR_MASH, Moves.SPACIAL_REND ],
[Species.KOMALA]: [ Moves.SLACK_OFF, Moves.THRASH, Moves.PSYSHIELD_BASH, Moves.DRAGON_HAMMER ],
[Species.TURTONATOR]: [ Moves.BURNING_BULWARK, Moves.BODY_PRESS, Moves.SCORCHING_SANDS, Moves.DRACO_METEOR ],
[Species.TOGEDEMARU]: [ Moves.FAKE_OUT, Moves.PIN_MISSILE, Moves.WISH, Moves.BARB_BARRAGE ],
[Species.MIMIKYU]: [ Moves.LEECH_LIFE, Moves.THUNDER_WAVE, Moves.WILL_O_WISP, Moves.SHADOW_FORCE ],
[Species.CUTIEFLY]: [ Moves.SILK_TRAP, Moves.DECORATE, Moves.PARTING_SHOT, Moves.FLORAL_HEALING ],
[Species.ROCKRUFF]: [ Moves.KNOCK_OFF, Moves.TIDY_UP, Moves.ICE_SPINNER, Moves.MIGHTY_CLEAVE ],
[Species.WISHIWASHI]: [ Moves.FLIP_TURN, Moves.ICE_SPINNER, Moves.SWORDS_DANCE, Moves.POPULATION_BOMB ],
[Species.MAREANIE]: [ Moves.SPIKES, Moves.SIZZLY_SLIDE, Moves.MORTAL_SPIN, Moves.LEECH_SEED ],
[Species.MUDBRAY]: [ Moves.BODY_PRESS, Moves.YAWN, Moves.SHORE_UP, Moves.LANDS_WRATH ],
[Species.DEWPIDER]: [ Moves.AQUA_JET, Moves.SILK_TRAP, Moves.ROCK_SLIDE, Moves.AQUA_STEP ],
[Species.FOMANTIS]: [ Moves.SUPERPOWER, Moves.STONE_AXE, Moves.PSYCHO_CUT, Moves.BITTER_BLADE ],
[Species.MORELULL]: [ Moves.CALM_MIND, Moves.LEECH_SEED, Moves.STRENGTH_SAP, Moves.SPARKLY_SWIRL ],
[Species.SALANDIT]: [ Moves.FAKE_OUT, Moves.FIERY_DANCE, Moves.SCALD, Moves.MALIGNANT_CHAIN ],
[Species.STUFFUL]: [ Moves.DRAIN_PUNCH, Moves.THUNDER_PUNCH, Moves.ICE_PUNCH, Moves.RAGE_FIST ],
[Species.BOUNSWEET]: [ Moves.TRIPLE_AXEL, Moves.AQUA_STEP, Moves.THUNDEROUS_KICK, Moves.SAPPY_SEED ],
[Species.COMFEY]: [ Moves.BUZZY_BUZZ, Moves.POLLEN_PUFF, Moves.STRENGTH_SAP, Moves.MATCHA_GOTCHA ],
[Species.ORANGURU]: [ Moves.FOUL_PLAY, Moves.YAWN, Moves.FOLLOW_ME, Moves.LUNAR_BLESSING ],
[Species.PASSIMIAN]: [ Moves.FAKE_OUT, Moves.SUCKER_PUNCH, Moves.SPIKES, Moves.SWORDS_DANCE ],
[Species.WIMPOD]: [ Moves.ICE_SPINNER, Moves.OBSTRUCT, Moves.KNOCK_OFF, Moves.SURGING_STRIKES ],
[Species.SANDYGAST]: [ Moves.SCORCHING_SANDS, Moves.PARTING_SHOT, Moves.CURSE, Moves.SALT_CURE ],
[Species.PYUKUMUKU]: [ Moves.MIRROR_COAT, Moves.BANEFUL_BUNKER, Moves.TOXIC_SPIKES, Moves.SALT_CURE ],
[Species.TYPE_NULL]: [ Moves.DIRE_CLAW, Moves.RECOVER, Moves.EXTREME_SPEED, Moves.NO_RETREAT ],
[Species.MINIOR]: [ Moves.EARTH_POWER, Moves.FLOATY_FALL, Moves.SUPERCELL_SLAM, Moves.DIAMOND_STORM ],
[Species.KOMALA]: [ Moves.SLACK_OFF, Moves.EXTREME_SPEED, Moves.DARKEST_LARIAT, Moves.CLOSE_COMBAT ],
[Species.TURTONATOR]: [ Moves.SHELL_SMASH, Moves.ARMOR_CANNON, Moves.EARTH_POWER, Moves.CLANGING_SCALES ],
[Species.TOGEDEMARU]: [ Moves.SIZZLY_SLIDE, Moves.RECOVER, Moves.SPIKES, Moves.DOUBLE_IRON_BASH ],
[Species.MIMIKYU]: [ Moves.SPIRIT_BREAK, Moves.NUZZLE, Moves.PARTING_SHOT, Moves.SPECTRAL_THIEF ],
[Species.BRUXISH]: [ Moves.SUPER_FANG, Moves.JAW_LOCK, Moves.PAIN_SPLIT, Moves.FISHIOUS_REND ],
[Species.DRAMPA]: [ Moves.THUNDER_WAVE, Moves.HEAT_WAVE, Moves.TAILWIND, Moves.BOOMBURST ],
[Species.DHELMISE]: [ Moves.TOXIC, Moves.GRASSY_GLIDE, Moves.STEEL_ROLLER, Moves.SOAK ],
[Species.JANGMO_O]: [ Moves.SCALE_SHOT, Moves.DRAGON_CHEER, Moves.AURA_SPHERE, Moves.MAT_BLOCK ],
[Species.TAPU_KOKO]: [ Moves.SPIRIT_BREAK, Moves.PSYSHIELD_BASH, Moves.FLIP_TURN, Moves.BOLT_BEAK ],
[Species.TAPU_LELE]: [ Moves.FLORAL_HEALING, Moves.HELPING_HAND, Moves.ALLY_SWITCH, Moves.GEOMANCY ],
[Species.TAPU_BULU]: [ Moves.JUNGLE_HEALING, Moves.SPIKY_SHIELD, Moves.COACHING, Moves.GRASSY_GLIDE ],
[Species.TAPU_FINI]: [ Moves.WATER_SPOUT, Moves.COSMIC_POWER, Moves.RECOVER, Moves.SPARKLY_SWIRL ],
[Species.COSMOG]: [ Moves.MYSTICAL_POWER, Moves.METEOR_MASH, Moves.PSYSHIELD_BASH, Moves.ASTRAL_BARRAGE ],
[Species.NIHILEGO]: [ Moves.INFESTATION, Moves.POWER_WHIP, Moves.GIGA_DRAIN, Moves.MALIGNANT_CHAIN ],
[Species.BUZZWOLE]: [ Moves.HORN_LEECH, Moves.DIZZY_PUNCH, Moves.METEOR_MASH, Moves.PLASMA_FISTS ],
[Species.PHEROMOSA]: [ Moves.DAZZLING_GLEAM, Moves.EXTREME_SPEED, Moves.AXE_KICK, Moves.THUNDEROUS_KICK ],
[Species.XURKITREE]: [ Moves.THUNDER, Moves.EXPLOSION, Moves.RISING_VOLTAGE, Moves.TAIL_GLOW ],
[Species.CELESTEELA]: [ Moves.FOCUS_BLAST, Moves.HEAT_WAVE, Moves.TERA_BLAST, Moves.AEROBLAST ],
[Species.KARTANA]: [ Moves.SLASH, Moves.PSYBLADE, Moves.BITTER_BLADE, Moves.BEHEMOTH_BLADE ],
[Species.GUZZLORD]: [ Moves.RECYCLE, Moves.STUFF_CHEEKS, Moves.TEATIME, Moves.SLACK_OFF ],
[Species.NECROZMA]: [ Moves.DAZZLING_GLEAM, Moves.FLAMETHROWER, Moves.AURORA_BEAM, Moves.LIGHT_OF_RUIN ],
[Species.MAGEARNA]: [ Moves.GEAR_GRIND, Moves.EARTH_POWER, Moves.MAKE_IT_RAIN, Moves.SPARKLY_SWIRL ],
[Species.MARSHADOW]: [ Moves.POWER_UP_PUNCH, Moves.THIEF, Moves.SNATCH, Moves.NO_RETREAT ],
[Species.POIPOLE]: [ Moves.POISON_STING, Moves.SHELL_SIDE_ARM, Moves.STICKY_WEB, Moves.DRAGON_ENERGY ],
[Species.STAKATAKA]: [ Moves.SHELTER, Moves.SHELL_TRAP, Moves.OBSTRUCT, Moves.CRUSH_GRIP ],
[Species.BLACEPHALON]: [ Moves.PYRO_BALL, Moves.POLLEN_PUFF, Moves.BOOMBURST, Moves.ASTRAL_BARRAGE ],
[Species.ZERAORA]: [ Moves.ZIPPY_ZAP, Moves.EXTREME_SPEED, Moves.DOUBLE_SHOCK, Moves.WICKED_BLOW ],
[Species.MELTAN]: [ Moves.MAKE_IT_RAIN, Moves.DRAIN_PUNCH, Moves.BULLET_PUNCH, Moves.PLASMA_FISTS ],
[Species.DRAMPA]: [ Moves.YAWN, Moves.FLAMETHROWER, Moves.CLANGING_SCALES, Moves.CLANGOROUS_SOUL ],
[Species.DHELMISE]: [ Moves.POLTERGEIST, Moves.SHIFT_GEAR, Moves.LEAF_BLADE, Moves.DOUBLE_IRON_BASH ],
[Species.JANGMO_O]: [ Moves.ICE_BEAM, Moves.RECOVER, Moves.SECRET_SWORD, Moves.GLAIVE_RUSH ],
[Species.TAPU_KOKO]: [ Moves.PLAY_ROUGH, Moves.ICE_SPINNER, Moves.RISING_VOLTAGE, Moves.BOLT_BEAK ],
[Species.TAPU_LELE]: [ Moves.MOONLIGHT, Moves.NASTY_PLOT, Moves.HEAT_WAVE, Moves.EXPANDING_FORCE ],
[Species.TAPU_BULU]: [ Moves.JUNGLE_HEALING, Moves.CLOSE_COMBAT, Moves.PLAY_ROUGH, Moves.GRASSY_GLIDE ],
[Species.TAPU_FINI]: [ Moves.AURA_SPHERE, Moves.EARTH_POWER, Moves.RECOVER, Moves.QUIVER_DANCE ],
[Species.COSMOG]: [ Moves.VICTORY_DANCE, Moves.QUIVER_DANCE, Moves.STORED_POWER, Moves.PHOTON_GEYSER ],
[Species.NIHILEGO]: [ Moves.RECOVER, Moves.QUIVER_DANCE, Moves.GIGA_DRAIN, Moves.MALIGNANT_CHAIN ],
[Species.BUZZWOLE]: [ Moves.LEECH_LIFE, Moves.BULLET_PUNCH, Moves.DARKEST_LARIAT, Moves.COLLISION_COURSE ],
[Species.PHEROMOSA]: [ Moves.AURA_SPHERE, Moves.MAKE_IT_RAIN, Moves.ATTACK_ORDER, Moves.COLLISION_COURSE ],
[Species.XURKITREE]: [ Moves.OVERHEAT, Moves.GIGA_DRAIN, Moves.THUNDERCLAP, Moves.TAIL_GLOW ],
[Species.CELESTEELA]: [ Moves.ROOST, Moves.BUZZY_BUZZ, Moves.SPIKES, Moves.OBLIVION_WING ],
[Species.KARTANA]: [ Moves.MIGHTY_CLEAVE, Moves.CEASELESS_EDGE, Moves.BITTER_BLADE, Moves.BEHEMOTH_BLADE ],
[Species.GUZZLORD]: [ Moves.DIRE_CLAW, Moves.GLAIVE_RUSH, Moves.SLACK_OFF, Moves.BADDY_BAD ],
[Species.NECROZMA]: [ Moves.COSMIC_POWER, Moves.SACRED_FIRE, Moves.ASTRAL_BARRAGE, Moves.CLANGOROUS_SOUL ],
[Species.MAGEARNA]: [ Moves.RECOVER, Moves.EARTH_POWER, Moves.COSMIC_POWER, Moves.MAKE_IT_RAIN ],
[Species.MARSHADOW]: [ Moves.POWER_UP_PUNCH, Moves.TRIPLE_AXEL, Moves.STORM_THROW, Moves.DOUBLE_IRON_BASH ],
[Species.POIPOLE]: [ Moves.SLUDGE_BOMB, Moves.BUG_BUZZ, Moves.SEARING_SHOT, Moves.DRAGON_ENERGY ],
[Species.STAKATAKA]: [ Moves.SALT_CURE, Moves.SHORE_UP, Moves.CURSE, Moves.DOUBLE_IRON_BASH ],
[Species.BLACEPHALON]: [ Moves.NASTY_PLOT, Moves.SEARING_SHOT, Moves.GIGA_DRAIN, Moves.ASTRAL_BARRAGE ],
[Species.ZERAORA]: [ Moves.SWORDS_DANCE, Moves.TRIPLE_AXEL, Moves.BOLT_STRIKE, Moves.PYRO_BALL ],
[Species.MELTAN]: [ Moves.BULLET_PUNCH, Moves.DRAIN_PUNCH, Moves.BULK_UP, Moves.RECOVER ],
[Species.GROOKEY]: [ Moves.JUNGLE_HEALING, Moves.CLOSE_COMBAT, Moves.BOOMBURST, Moves.BELLY_DRUM ],
[Species.SCORBUNNY]: [ Moves.EXTREME_SPEED, Moves.TROP_KICK, Moves.WILD_CHARGE, Moves.THUNDEROUS_KICK ],
[Species.SOBBLE]: [ Moves.SHELL_SIDE_ARM, Moves.FROST_BREATH, Moves.AURA_SPHERE, Moves.SURGING_STRIKES ],
@ -543,13 +543,13 @@ export const speciesEggMoves = {
[Species.IRON_CROWN]: [ Moves.KINGS_SHIELD, Moves.SECRET_SWORD, Moves.PHOTON_GEYSER, Moves.ELECTRO_DRIFT ],
[Species.TERAPAGOS]: [ Moves.EARTH_POWER, Moves.SHORE_UP, Moves.ICE_BEAM, Moves.SHELL_SMASH ],
[Species.PECHARUNT]: [ Moves.TOXIC_SPIKES, Moves.BODY_PRESS, Moves.HEX, Moves.BANEFUL_BUNKER ],
[Species.ALOLA_RATTATA]: [ Moves.STUFF_CHEEKS, Moves.BADDY_BAD, Moves.FLAME_WHEEL, Moves.RECYCLE ],
[Species.ALOLA_SANDSHREW]: [ Moves.SPIKY_SHIELD, Moves.ICE_SHARD, Moves.CRUSH_CLAW, Moves.SPIN_OUT ],
[Species.ALOLA_VULPIX]: [ Moves.MOONBLAST, Moves.HYPNOSIS, Moves.CHILLING_WATER, Moves.FREEZY_FROST ],
[Species.ALOLA_DIGLETT]: [ Moves.STONE_EDGE, Moves.SWORDS_DANCE, Moves.THIEF, Moves.POPULATION_BOMB ],
[Species.ALOLA_MEOWTH]: [ Moves.MAKE_IT_RAIN, Moves.COVET, Moves.HYPNOSIS, Moves.PARTING_SHOT ],
[Species.ALOLA_GEODUDE]: [ Moves.HEAD_CHARGE, Moves.RAPID_SPIN, Moves.MAGNET_RISE, Moves.HEAD_SMASH ],
[Species.ALOLA_GRIMER]: [ Moves.SUCKER_PUNCH, Moves.DIRE_CLAW, Moves.RECYCLE, Moves.EMBARGO ],
[Species.ALOLA_RATTATA]: [ Moves.STORM_THROW, Moves.PLAY_ROUGH, Moves.TIDY_UP, Moves.POPULATION_BOMB ],
[Species.ALOLA_SANDSHREW]: [ Moves.SPIKY_SHIELD, Moves.AQUA_CUTTER, Moves.SHIFT_GEAR, Moves.GLACIAL_LANCE ],
[Species.ALOLA_VULPIX]: [ Moves.MOONBLAST, Moves.AURORA_VEIL, Moves.PARTING_SHOT, Moves.FREEZY_FROST ],
[Species.ALOLA_DIGLETT]: [ Moves.LANDS_WRATH, Moves.SWORDS_DANCE, Moves.TRIPLE_DIVE, Moves.DOUBLE_IRON_BASH ],
[Species.ALOLA_MEOWTH]: [ Moves.MAKE_IT_RAIN, Moves.BUZZY_BUZZ, Moves.PARTING_SHOT, Moves.BADDY_BAD ],
[Species.ALOLA_GEODUDE]: [ Moves.HIGH_HORSEPOWER, Moves.BULK_UP, Moves.STONE_AXE, Moves.EXTREME_SPEED ],
[Species.ALOLA_GRIMER]: [ Moves.SUCKER_PUNCH, Moves.DIRE_CLAW, Moves.STRENGTH_SAP, Moves.SURGING_STRIKES ],
[Species.ETERNAL_FLOETTE]: [ Moves.DECORATE, Moves.FORESTS_CURSE, Moves.POLLEN_PUFF, Moves.QUIVER_DANCE ],
[Species.GALAR_MEOWTH]: [ Moves.MAKE_IT_RAIN, Moves.KNOCK_OFF, Moves.TRAILBLAZE, Moves.BEHEMOTH_BASH ],
[Species.GALAR_PONYTA]: [ Moves.PURIFY, Moves.POISON_JAB, Moves.HORN_LEECH, Moves.PSYSTRIKE ],

View File

@ -49,6 +49,7 @@ export enum BattlerTagType {
BYPASS_SLEEP = "BYPASS_SLEEP",
IGNORE_FLYING = "IGNORE_FLYING",
SALT_CURED = "SALT_CURED",
CURSED = "CURSED",
CHARGED = "CHARGED",
GROUNDED = "GROUNDED"
}

View File

@ -12,7 +12,7 @@ import * as Utils from "../utils";
import { WeatherType } from "./weather";
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
import { ArenaTagType } from "./enums/arena-tag-type";
import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, NoTransformAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr, MoveAbilityBypassAbAttr } from "./ability";
import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, NoTransformAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr, MoveAbilityBypassAbAttr, ReverseDrainAbAttr, IgnoreMoveEffectsAbAttr, applyPreDefendAbAttrs, MoveEffectChanceMultiplierAbAttr } from "./ability";
import { Abilities } from "./enums/abilities";
import { allAbilities } from './ability';
import { PokemonHeldItemModifier } from "../modifier/modifier";
@ -96,9 +96,6 @@ export default class Move implements Localizable {
constructor(id: Moves, type: Type, category: MoveCategory, defaultMoveTarget: MoveTarget, power: integer, accuracy: integer, pp: integer, chance: integer, priority: integer, generation: integer) {
this.id = id;
const i18nKey = Moves[id].split('_').filter(f => f).map((f, i) => i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()).join('') as unknown as string;
this.name = id ? i18next.t(`move:${i18nKey}.name`).toString() : '';
this.nameAppend = '';
this.type = type;
this.category = category;
@ -106,7 +103,6 @@ export default class Move implements Localizable {
this.power = power;
this.accuracy = accuracy;
this.pp = pp;
this.effect = id ? i18next.t(`move:${i18nKey}.effect`).toString() : '';
this.chance = chance;
this.priority = priority;
this.generation = generation;
@ -119,9 +115,11 @@ export default class Move implements Localizable {
this.setFlag(MoveFlags.IGNORE_PROTECT, true);
if (category === MoveCategory.PHYSICAL)
this.setFlag(MoveFlags.MAKES_CONTACT, true);
this.localize();
}
localize() {
localize(): void {
const i18nKey = Moves[this.id].split('_').filter(f => f).map((f, i) => i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()).join('') as unknown as string;
this.name = this.id ? `${i18next.t(`move:${i18nKey}.name`).toString()}${this.nameAppend}` : '';
@ -457,6 +455,14 @@ export class MoveEffectAttr extends MoveAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean | Promise<boolean> {
return this.canApply(user, target, move, args);
}
getMoveChance(user: Pokemon, target: Pokemon, move: Move, selfEffect?: Boolean): integer {
let moveChance = new Utils.NumberHolder(move.chance);
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, moveChance, target, selfEffect);
applyPreDefendAbAttrs(IgnoreMoveEffectsAbAttr,target,user,null,null, moveChance);
return moveChance.value;
}
}
export class PreMoveMessageAttr extends MoveAttr {
@ -846,8 +852,12 @@ export class HitHealAttr extends MoveEffectAttr {
}
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const healAmount = Math.max(Math.floor(user.turnData.damageDealt * this.healRatio), 1);
const reverseDrain = user.hasAbilityWithAttr(ReverseDrainAbAttr);
user.scene.unshiftPhase(new PokemonHealPhase(user.scene, user.getBattlerIndex(),
Math.max(Math.floor(user.turnData.damageDealt * this.healRatio), 1), getPokemonMessage(target, ` had its\nenergy drained!`), false, true));
!reverseDrain ? healAmount : healAmount * -1,
!reverseDrain ? getPokemonMessage(target, ` had its\nenergy drained!`) : undefined,
false, true));
return true;
}
@ -862,9 +872,12 @@ export class StrengthSapHealAttr extends MoveEffectAttr {
}
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const healAmount = target.stats[Stat.ATK] * (Math.max(2, 2 + target.summonData.battleStats[BattleStat.ATK]) / Math.max(2, 2 - target.summonData.battleStats[BattleStat.ATK]));
const reverseDrain = user.hasAbilityWithAttr(ReverseDrainAbAttr);
user.scene.unshiftPhase(new PokemonHealPhase(user.scene, user.getBattlerIndex(),
target.stats[Stat.ATK] * (Math.max(2, 2 + target.summonData.battleStats[BattleStat.ATK]) / Math.max(2, 2 - target.summonData.battleStats[BattleStat.ATK])),
getPokemonMessage(user, ` regained\nhealth!`), false, true));
!reverseDrain ? healAmount : healAmount * -1,
!reverseDrain ? getPokemonMessage(user, ` regained\nhealth!`) : undefined,
false, true));
return true;
}
}
@ -957,7 +970,9 @@ export class StatusEffectAttr extends MoveEffectAttr {
}
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const statusCheck = move.chance < 0 || move.chance === 100 || user.randSeedInt(100) < move.chance;
let moveChance = this.getMoveChance(user,target,move,this.selfTarget);
const statusCheck = moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance;
if (statusCheck) {
const pokemon = this.selfTarget ? user : target;
if (pokemon.status) {
@ -966,14 +981,15 @@ export class StatusEffectAttr extends MoveEffectAttr {
else
return false;
}
if (!pokemon.status || (pokemon.status.effect === this.effect && move.chance < 0))
if (!pokemon.status || (pokemon.status.effect === this.effect && moveChance < 0))
return pokemon.trySetStatus(this.effect, true, this.cureTurn);
}
return false;
}
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
return !(this.selfTarget ? user : target).status && (this.selfTarget ? user : target).canSetStatus(this.effect, true) ? Math.floor(move.chance * -0.1) : 0;
let moveChance = this.getMoveChance(user,target,move,this.selfTarget);
return !(this.selfTarget ? user : target).status && (this.selfTarget ? user : target).canSetStatus(this.effect, true) ? Math.floor(moveChance * -0.1) : 0;
}
}
@ -1392,7 +1408,9 @@ export class StatChangeAttr extends MoveEffectAttr {
if (!super.apply(user, target, move, args) || (this.condition && !this.condition(user, target, move)))
return false;
if (move.chance < 0 || move.chance === 100 || user.randSeedInt(100) < move.chance) {
let moveChance = this.getMoveChance(user,target,move,this.selfTarget);
if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance) {
const levels = this.getLevels(user);
user.scene.unshiftPhase(new StatChangePhase(user.scene, (this.selfTarget ? user : target).getBattlerIndex(), this.selfTarget, this.stats, levels, this.showMessage));
return true;
@ -2296,10 +2314,13 @@ export class WaterSuperEffectTypeMultiplierAttr extends VariableMoveTypeMultipli
}
}
export class OneHitKOAccuracyAttr extends MoveAttr {
export class OneHitKOAccuracyAttr extends VariableAccuracyAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const accuracy = args[0] as Utils.NumberHolder;
accuracy.value = 30 + 70 * Math.min(target.level / user.level, 0.5) * 2;
if (user.level < target.level)
accuracy.value = 0;
else
accuracy.value = Math.min(Math.max(30 + 100 * (1 - target.level / user.level), 0), 100);
return true;
}
}
@ -2462,17 +2483,13 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
if (!super.apply(user, target, move, args))
return false;
const chance = this.getTagChance(user, target, move);
if (chance < 0 || chance === 100 || user.randSeedInt(100) < chance)
let moveChance = this.getMoveChance(user,target,move,this.selfTarget);
if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance)
return (this.selfTarget ? user : target).addTag(this.tagType, user.randSeedInt(this.turnCountMax - this.turnCountMin, this.turnCountMin), move.id, user.id);
return false;
}
getTagChance(user: Pokemon, target: Pokemon, move: Move): integer {
return move.chance;
}
getCondition(): MoveConditionFunc {
return this.failOnOverlap
? (user, target, move) => !(this.selfTarget ? user : target).getTag(this.tagType)
@ -2493,6 +2510,7 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
return -5;
case BattlerTagType.SEEDED:
case BattlerTagType.SALT_CURED:
case BattlerTagType.CURSED:
case BattlerTagType.FRENZY:
case BattlerTagType.TRAPPED:
case BattlerTagType.BIND:
@ -2520,10 +2538,38 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
}
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer {
let chance = this.getTagChance(user, target, move);
if (chance < 0)
chance = 100;
return Math.floor(this.getTagTargetBenefitScore(user, target, move) * (chance / 100));
let moveChance = this.getMoveChance(user,target,move,this.selfTarget);
if (moveChance < 0)
moveChance = 100;
return Math.floor(this.getTagTargetBenefitScore(user, target, move) * (moveChance / 100));
}
}
export class CurseAttr extends MoveEffectAttr {
apply(user: Pokemon, target: Pokemon, move:Move, args: any[]): boolean {
// Determine the correct target based on the user's type
if (!user.getTypes(true).includes(Type.GHOST)) {
// For non-Ghost types, target the user itself
target = user;
}
if (user.getTypes(true).includes(Type.GHOST)) {
if (target.getTag(BattlerTagType.CURSED)) {
user.scene.queueMessage('But it failed!');
return false;
}
let curseRecoilDamage = Math.floor(user.getMaxHp() / 2);
user.damageAndUpdate(curseRecoilDamage, HitResult.OTHER, false, true, true);
user.scene.queueMessage(getPokemonMessage(user, ' cut its own HP!'));
target.addTag(BattlerTagType.CURSED, 0, move.id, user.id);
return true;
} else {
target = user;
user.scene.unshiftPhase(new StatChangePhase(user.scene, user.getBattlerIndex(), this.selfTarget, [BattleStat.ATK, BattleStat.DEF], 1));
user.scene.unshiftPhase(new StatChangePhase(user.scene, user.getBattlerIndex(), this.selfTarget, [BattleStat.SPD], -1));
return true;
}
}
}
@ -3670,7 +3716,7 @@ export function initMoves() {
.punchingMove(),
new AttackMove(Moves.SCRATCH, Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 35, -1, 0, 1),
new AttackMove(Moves.VISE_GRIP, Type.NORMAL, MoveCategory.PHYSICAL, 55, 100, 30, -1, 0, 1),
new AttackMove(Moves.GUILLOTINE, Type.NORMAL, MoveCategory.PHYSICAL, -1, 30, 5, -1, 0, 1)
new AttackMove(Moves.GUILLOTINE, Type.NORMAL, MoveCategory.PHYSICAL, 200, 30, 5, -1, 0, 1)
.attr(OneHitKOAttr)
.attr(OneHitKOAccuracyAttr),
new AttackMove(Moves.RAZOR_WIND, Type.NORMAL, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 1)
@ -3719,7 +3765,7 @@ export function initMoves() {
new AttackMove(Moves.HORN_ATTACK, Type.NORMAL, MoveCategory.PHYSICAL, 65, 100, 25, -1, 0, 1),
new AttackMove(Moves.FURY_ATTACK, Type.NORMAL, MoveCategory.PHYSICAL, 15, 85, 20, -1, 0, 1)
.attr(MultiHitAttr),
new AttackMove(Moves.HORN_DRILL, Type.NORMAL, MoveCategory.PHYSICAL, -1, 30, 5, -1, 0, 1)
new AttackMove(Moves.HORN_DRILL, Type.NORMAL, MoveCategory.PHYSICAL, 200, 30, 5, -1, 0, 1)
.attr(OneHitKOAttr)
.attr(OneHitKOAccuracyAttr),
new AttackMove(Moves.TACKLE, Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 35, -1, 0, 1),
@ -3873,7 +3919,7 @@ export function initMoves() {
.attr(HitsTagAttr, BattlerTagType.UNDERGROUND, true)
.makesContact(false)
.target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.FISSURE, Type.GROUND, MoveCategory.PHYSICAL, -1, 30, 5, -1, 0, 1)
new AttackMove(Moves.FISSURE, Type.GROUND, MoveCategory.PHYSICAL, 200, 30, 5, -1, 0, 1)
.attr(OneHitKOAttr)
.attr(OneHitKOAccuracyAttr)
.attr(HitsTagAttr, BattlerTagType.UNDERGROUND, false)
@ -4398,7 +4444,7 @@ export function initMoves() {
.ignoresVirtual(),
new SelfStatusMove(Moves.INGRAIN, Type.GRASS, -1, 20, -1, 0, 3)
.attr(AddBattlerTagAttr, BattlerTagType.INGRAIN, true, true),
new AttackMove(Moves.SUPERPOWER, Type.FIGHTING, MoveCategory.PHYSICAL, 120, 100, 5, 100, 0, 3)
new AttackMove(Moves.SUPERPOWER, Type.FIGHTING, MoveCategory.PHYSICAL, 120, 100, 5, -1, 0, 3)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], -1, true),
new SelfStatusMove(Moves.MAGIC_COAT, Type.PSYCHIC, -1, 15, -1, 4, 3)
.unimplemented(),
@ -4499,7 +4545,7 @@ export function initMoves() {
.slicingMove()
.windMove()
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.OVERHEAT, Type.FIRE, MoveCategory.SPECIAL, 130, 90, 5, 100, 0, 3)
new AttackMove(Moves.OVERHEAT, Type.FIRE, MoveCategory.SPECIAL, 130, 90, 5, -1, 0, 3)
.attr(StatChangeAttr, BattleStat.SPATK, -2, true)
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE),
new StatusMove(Moves.ODOR_SLEUTH, Type.NORMAL, -1, 40, -1, 0, 3)
@ -4536,7 +4582,7 @@ export function initMoves() {
new AttackMove(Moves.SAND_TOMB, Type.GROUND, MoveCategory.PHYSICAL, 35, 85, 15, 100, 0, 3)
.attr(TrapAttr, BattlerTagType.SAND_TOMB)
.makesContact(false),
new AttackMove(Moves.SHEER_COLD, Type.ICE, MoveCategory.SPECIAL, -1, 30, 5, -1, 0, 3)
new AttackMove(Moves.SHEER_COLD, Type.ICE, MoveCategory.SPECIAL, 200, 30, 5, -1, 0, 3)
.attr(OneHitKOAttr)
.attr(OneHitKOAccuracyAttr),
new AttackMove(Moves.MUDDY_WATER, Type.WATER, MoveCategory.SPECIAL, 90, 85, 10, 30, 0, 3)
@ -4601,7 +4647,7 @@ export function initMoves() {
.pulseMove(),
new AttackMove(Moves.DOOM_DESIRE, Type.STEEL, MoveCategory.SPECIAL, 140, 100, 5, -1, 0, 3)
.attr(DelayedAttackAttr, ArenaTagType.DOOM_DESIRE, ChargeAnim.DOOM_DESIRE_CHARGING, 'chose\nDoom Desire as its destiny!'),
new AttackMove(Moves.PSYCHO_BOOST, Type.PSYCHIC, MoveCategory.SPECIAL, 140, 90, 5, 100, 0, 3)
new AttackMove(Moves.PSYCHO_BOOST, Type.PSYCHIC, MoveCategory.SPECIAL, 140, 90, 5, -1, 0, 3)
.attr(StatChangeAttr, BattleStat.SPATK, -2, true),
new SelfStatusMove(Moves.ROOST, Type.FLYING, -1, 5, -1, 0, 4)
.attr(HealAttr, 0.5)
@ -4615,7 +4661,7 @@ export function initMoves() {
new AttackMove(Moves.WAKE_UP_SLAP, Type.FIGHTING, MoveCategory.PHYSICAL, 70, 100, 10, -1, 0, 4)
.attr(MovePowerMultiplierAttr, (user, target, move) => target.status?.effect === StatusEffect.SLEEP ? 2 : 1)
.attr(HealStatusEffectAttr, false, StatusEffect.SLEEP),
new AttackMove(Moves.HAMMER_ARM, Type.FIGHTING, MoveCategory.PHYSICAL, 100, 90, 10, 100, 0, 4)
new AttackMove(Moves.HAMMER_ARM, Type.FIGHTING, MoveCategory.PHYSICAL, 100, 90, 10, -1, 0, 4)
.attr(StatChangeAttr, BattleStat.SPD, -1, true)
.punchingMove(),
new AttackMove(Moves.GYRO_BALL, Type.STEEL, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 4)
@ -4648,7 +4694,7 @@ export function initMoves() {
.target(MoveTarget.ATTACKER),
new AttackMove(Moves.U_TURN, Type.BUG, MoveCategory.PHYSICAL, 70, 100, 20, -1, 0, 4)
.attr(ForceSwitchOutAttr, true, false),
new AttackMove(Moves.CLOSE_COMBAT, Type.FIGHTING, MoveCategory.PHYSICAL, 120, 100, 5, 100, 0, 4)
new AttackMove(Moves.CLOSE_COMBAT, Type.FIGHTING, MoveCategory.PHYSICAL, 120, 100, 5, -1, 0, 4)
.attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], -1, true),
new AttackMove(Moves.PAYBACK, Type.DARK, MoveCategory.PHYSICAL, 50, 100, 10, -1, 0, 4)
.attr(MovePowerMultiplierAttr, (user, target, move) => target.getLastXMoves(1).find(m => m.turn === target.scene.currentBattle.turn) || user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.BALL ? 2 : 1),
@ -4824,7 +4870,7 @@ export function initMoves() {
.attr(AddArenaTagAttr, ArenaTagType.TRICK_ROOM, 5)
.ignoresProtect()
.target(MoveTarget.BOTH_SIDES),
new AttackMove(Moves.DRACO_METEOR, Type.DRAGON, MoveCategory.SPECIAL, 130, 90, 5, 100, 0, 4)
new AttackMove(Moves.DRACO_METEOR, Type.DRAGON, MoveCategory.SPECIAL, 130, 90, 5, -1, 0, 4)
.attr(StatChangeAttr, BattleStat.SPATK, -2, true),
new AttackMove(Moves.DISCHARGE, Type.ELECTRIC, MoveCategory.SPECIAL, 80, 100, 15, 30, 0, 4)
.attr(StatusEffectAttr, StatusEffect.PARALYSIS)
@ -4832,7 +4878,7 @@ export function initMoves() {
new AttackMove(Moves.LAVA_PLUME, Type.FIRE, MoveCategory.SPECIAL, 80, 100, 15, 30, 0, 4)
.attr(StatusEffectAttr, StatusEffect.BURN)
.target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.LEAF_STORM, Type.GRASS, MoveCategory.SPECIAL, 130, 90, 5, 100, 0, 4)
new AttackMove(Moves.LEAF_STORM, Type.GRASS, MoveCategory.SPECIAL, 130, 90, 5, -1, 0, 4)
.attr(StatChangeAttr, BattleStat.SPATK, -2, true),
new AttackMove(Moves.POWER_WHIP, Type.GRASS, MoveCategory.PHYSICAL, 120, 85, 10, -1, 0, 4),
new AttackMove(Moves.ROCK_WRECKER, Type.ROCK, MoveCategory.PHYSICAL, 150, 90, 5, -1, 0, 4)
@ -5132,6 +5178,7 @@ export function initMoves() {
.attr(StatChangeAttr, BattleStat.SPATK, 1, true)
.danceMove(),
new AttackMove(Moves.FREEZE_SHOCK, Type.ICE, MoveCategory.PHYSICAL, 140, 90, 5, 30, 0, 5)
.attr(ChargeAttr, ChargeAnim.FREEZE_SHOCK_CHARGING, 'became cloaked\nin a freezing light!')
.attr(StatusEffectAttr, StatusEffect.PARALYSIS)
.makesContact(false),
new AttackMove(Moves.ICE_BURN, Type.ICE, MoveCategory.SPECIAL, 140, 90, 5, 30, 0, 5)
@ -5145,7 +5192,7 @@ export function initMoves() {
new AttackMove(Moves.ICICLE_CRASH, Type.ICE, MoveCategory.PHYSICAL, 85, 90, 10, 30, 0, 5)
.attr(FlinchAttr)
.makesContact(false),
new AttackMove(Moves.V_CREATE, Type.FIRE, MoveCategory.PHYSICAL, 180, 95, 5, 100, 0, 5)
new AttackMove(Moves.V_CREATE, Type.FIRE, MoveCategory.PHYSICAL, 180, 95, 5, -1, 0, 5)
.attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF, BattleStat.SPD ], -1, true),
new AttackMove(Moves.FUSION_FLARE, Type.FIRE, MoveCategory.SPECIAL, 100, 100, 5, -1, 0, 5)
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE)
@ -5300,7 +5347,7 @@ export function initMoves() {
new AttackMove(Moves.OBLIVION_WING, Type.FLYING, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 6)
.attr(HitHealAttr, 0.75)
.triageMove(),
new AttackMove(Moves.THOUSAND_ARROWS, Type.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, 100, 0, 6)
new AttackMove(Moves.THOUSAND_ARROWS, Type.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, -1, 0, 6)
.attr(NeutralDamageAgainstFlyingTypeMultiplierAttr)
.attr(HitsTagAttr, BattlerTagType.FLYING, false)
.makesContact(false)
@ -5320,9 +5367,9 @@ export function initMoves() {
new AttackMove(Moves.PRECIPICE_BLADES, Type.GROUND, MoveCategory.PHYSICAL, 120, 85, 10, -1, 0, 6)
.makesContact(false)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.DRAGON_ASCENT, Type.FLYING, MoveCategory.PHYSICAL, 120, 100, 5, 100, 0, 6)
new AttackMove(Moves.DRAGON_ASCENT, Type.FLYING, MoveCategory.PHYSICAL, 120, 100, 5, -1, 0, 6)
.attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], -1, true),
new AttackMove(Moves.HYPERSPACE_FURY, Type.DARK, MoveCategory.PHYSICAL, 100, -1, 5, 100, 0, 6)
new AttackMove(Moves.HYPERSPACE_FURY, Type.DARK, MoveCategory.PHYSICAL, 100, -1, 5, -1, 0, 6)
.attr(StatChangeAttr, BattleStat.DEF, -1, true)
.ignoresProtect(),
/* Unused */
@ -5408,16 +5455,16 @@ export function initMoves() {
.condition(new FirstMoveCondition()),
new SelfStatusMove(Moves.BANEFUL_BUNKER, Type.POISON, -1, 10, -1, 4, 7)
.attr(ProtectAttr, BattlerTagType.BANEFUL_BUNKER),
new AttackMove(Moves.SPIRIT_SHACKLE, Type.GHOST, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 7)
new AttackMove(Moves.SPIRIT_SHACKLE, Type.GHOST, MoveCategory.PHYSICAL, 80, 100, 10, 100, 0, 7)
.makesContact(false)
.partial(),
new AttackMove(Moves.DARKEST_LARIAT, Type.DARK, MoveCategory.PHYSICAL, 85, 100, 10, -1, 0, 7)
.attr(IgnoreOpponentStatChangesAttr),
new AttackMove(Moves.SPARKLING_ARIA, Type.WATER, MoveCategory.SPECIAL, 90, 100, 10, -1, 0, 7)
new AttackMove(Moves.SPARKLING_ARIA, Type.WATER, MoveCategory.SPECIAL, 90, 100, 10, 100, 0, 7)
.attr(HealStatusEffectAttr, false, StatusEffect.BURN)
.soundBased()
.target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.ICE_HAMMER, Type.ICE, MoveCategory.PHYSICAL, 100, 90, 10, 100, 0, 7)
new AttackMove(Moves.ICE_HAMMER, Type.ICE, MoveCategory.PHYSICAL, 100, 90, 10, -1, 0, 7)
.attr(StatChangeAttr, BattleStat.SPD, -1, true)
.punchingMove(),
new StatusMove(Moves.FLORAL_HEALING, Type.FAIRY, -1, 10, -1, 0, 7)
@ -5452,7 +5499,7 @@ export function initMoves() {
new AttackMove(Moves.POLLEN_PUFF, Type.BUG, MoveCategory.SPECIAL, 90, 100, 15, -1, 0, 7)
.ballBombMove()
.partial(),
new AttackMove(Moves.ANCHOR_SHOT, Type.STEEL, MoveCategory.PHYSICAL, 80, 100, 20, -1, 0, 7)
new AttackMove(Moves.ANCHOR_SHOT, Type.STEEL, MoveCategory.PHYSICAL, 80, 100, 20, 100, 0, 7)
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1),
new StatusMove(Moves.PSYCHIC_TERRAIN, Type.PSYCHIC, -1, 10, -1, 0, 7)
.attr(TerrainChangeAttr, TerrainType.PSYCHIC)
@ -5493,7 +5540,7 @@ export function initMoves() {
.ballBombMove()
.makesContact(false)
.partial(),
new AttackMove(Moves.CLANGING_SCALES, Type.DRAGON, MoveCategory.SPECIAL, 110, 100, 5, 100, 0, 7)
new AttackMove(Moves.CLANGING_SCALES, Type.DRAGON, MoveCategory.SPECIAL, 110, 100, 5, -1, 0, 7)
.attr(StatChangeAttr, BattleStat.DEF, -1, true)
.soundBased()
.target(MoveTarget.ALL_NEAR_ENEMIES),
@ -5522,19 +5569,19 @@ export function initMoves() {
.partial(),
new SelfStatusMove(Moves.EXTREME_EVOBOOST, Type.NORMAL, -1, 1, 100, 0, 7)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 2, true),
new AttackMove(Moves.GENESIS_SUPERNOVA, Type.PSYCHIC, MoveCategory.SPECIAL, 185, -1, 1, -1, 0, 7)
new AttackMove(Moves.GENESIS_SUPERNOVA, Type.PSYCHIC, MoveCategory.SPECIAL, 185, -1, 1, 100, 0, 7)
.attr(TerrainChangeAttr, TerrainType.PSYCHIC),
/* End Unused */
new AttackMove(Moves.SHELL_TRAP, Type.FIRE, MoveCategory.SPECIAL, 150, 100, 5, -1, -3, 7)
.target(MoveTarget.ALL_NEAR_ENEMIES)
.partial(),
new AttackMove(Moves.FLEUR_CANNON, Type.FAIRY, MoveCategory.SPECIAL, 130, 90, 5, 100, 0, 7)
new AttackMove(Moves.FLEUR_CANNON, Type.FAIRY, MoveCategory.SPECIAL, 130, 90, 5, -1, 0, 7)
.attr(StatChangeAttr, BattleStat.SPATK, -2, true),
new AttackMove(Moves.PSYCHIC_FANGS, Type.PSYCHIC, MoveCategory.PHYSICAL, 85, 100, 10, -1, 0, 7)
.bitingMove()
.attr(RemoveScreensAttr),
new AttackMove(Moves.STOMPING_TANTRUM, Type.GROUND, MoveCategory.PHYSICAL, 75, 100, 10, -1, 0, 7)
.partial(),
.attr(MovePowerMultiplierAttr, (user, target, move) => user.getLastXMoves(2)[1]?.result == MoveResult.MISS || user.getLastXMoves(2)[1]?.result == MoveResult.FAIL ? 2 : 1),
new AttackMove(Moves.SHADOW_BONE, Type.GHOST, MoveCategory.PHYSICAL, 85, 100, 10, 20, 0, 7)
.attr(StatChangeAttr, BattleStat.DEF, -1)
.makesContact(false),
@ -5647,8 +5694,8 @@ export function initMoves() {
.attr(StatChangeAttr, BattleStat.SPD, -1)
.partial(),
new StatusMove(Moves.MAGIC_POWDER, Type.PSYCHIC, 100, 20, -1, 0, 8)
.powderMove()
.unimplemented(),
.attr(ChangeTypeAttr, Type.PSYCHIC)
.powderMove(),
new AttackMove(Moves.DRAGON_DARTS, Type.DRAGON, MoveCategory.PHYSICAL, 50, 100, 10, -1, 0, 8)
.attr(MultiHitAttr, MultiHitType._2)
.makesContact(false)
@ -5785,7 +5832,7 @@ export function initMoves() {
new AttackMove(Moves.STEEL_ROLLER, Type.STEEL, MoveCategory.PHYSICAL, 130, 100, 5, -1, 0, 8)
.attr(ClearTerrainAttr)
.condition((user, target, move) => !!user.scene.arena.terrain),
new AttackMove(Moves.SCALE_SHOT, Type.DRAGON, MoveCategory.PHYSICAL, 25, 90, 20, 100, 0, 8)
new AttackMove(Moves.SCALE_SHOT, Type.DRAGON, MoveCategory.PHYSICAL, 25, 90, 20, -1, 0, 8)
//.attr(StatChangeAttr, BattleStat.SPD, 1, true) // TODO: Have boosts only apply at end of move, not after every hit
//.attr(StatChangeAttr, BattleStat.DEF, -1, true)
.attr(MultiHitAttr)
@ -5899,7 +5946,7 @@ export function initMoves() {
new SelfStatusMove(Moves.VICTORY_DANCE, Type.FIGHTING, -1, 10, 100, 0, 8)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPD ], 1, true)
.danceMove(),
new AttackMove(Moves.HEADLONG_RUSH, Type.GROUND, MoveCategory.PHYSICAL, 120, 100, 5, 100, 0, 8)
new AttackMove(Moves.HEADLONG_RUSH, Type.GROUND, MoveCategory.PHYSICAL, 120, 100, 5, -1, 0, 8)
.attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], -1, true)
.punchingMove(),
new AttackMove(Moves.BARB_BARRAGE, Type.POISON, MoveCategory.PHYSICAL, 60, 100, 10, 50, 0, 8)
@ -6072,7 +6119,7 @@ export function initMoves() {
new StatusMove(Moves.SPICY_EXTRACT, Type.GRASS, -1, 15, 100, 0, 9)
.attr(StatChangeAttr, BattleStat.ATK, 2)
.attr(StatChangeAttr, BattleStat.DEF, -2),
new AttackMove(Moves.SPIN_OUT, Type.STEEL, MoveCategory.PHYSICAL, 100, 100, 5, 100, 0, 9)
new AttackMove(Moves.SPIN_OUT, Type.STEEL, MoveCategory.PHYSICAL, 100, 100, 5, -1, 0, 9)
.attr(StatChangeAttr, BattleStat.SPD, -2, true),
new AttackMove(Moves.POPULATION_BOMB, Type.NORMAL, MoveCategory.PHYSICAL, 20, 90, 10, -1, 0, 9)
.attr(MultiHitAttr, MultiHitType._1_TO_10)
@ -6132,7 +6179,7 @@ export function initMoves() {
.slicingMove(),
new AttackMove(Moves.HYDRO_STEAM, Type.WATER, MoveCategory.SPECIAL, 80, 100, 15, -1, 0, 9)
.partial(),
new AttackMove(Moves.RUINATION, Type.DARK, MoveCategory.SPECIAL, 1, 90, 10, -1, 0, 9)
new AttackMove(Moves.RUINATION, Type.DARK, MoveCategory.SPECIAL, -1, 90, 10, -1, 0, 9)
.attr(TargetHalfHpDamageAttr),
new AttackMove(Moves.COLLISION_COURSE, Type.FIGHTING, MoveCategory.PHYSICAL, 100, 100, 5, -1, 0, 9)
.attr(MovePowerMultiplierAttr, (user, target, move) => target.getAttackTypeEffectiveness(move.type) >= 2 ? 5461/4096 : 1),
@ -6254,7 +6301,7 @@ export function initMoves() {
new AttackMove(Moves.ALLURING_VOICE, Type.FAIRY, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 9)
.partial(),
new AttackMove(Moves.TEMPER_FLARE, Type.FIRE, MoveCategory.PHYSICAL, 75, 100, 10, -1, 0, 9)
.partial(),
.attr(MovePowerMultiplierAttr, (user, target, move) => user.getLastXMoves(2)[1]?.result == MoveResult.MISS || user.getLastXMoves(2)[1]?.result == MoveResult.FAIL ? 2 : 1),
new AttackMove(Moves.SUPERCELL_SLAM, Type.ELECTRIC, MoveCategory.PHYSICAL, 100, 95, 15, -1, 0, 9)
.attr(MissEffectAttr, crashDamageFunc)
.attr(NoEffectAttr, crashDamageFunc),

View File

@ -1,4 +1,5 @@
import BattleScene from "../battle-scene";
import i18next from '../plugins/i18n';
export enum PokeballType {
POKEBALL,
@ -30,22 +31,22 @@ export function getPokeballName(type: PokeballType): string {
let ret: string;
switch (type) {
case PokeballType.POKEBALL:
ret = 'Poké Ball';
ret = i18next.t('pokeball:pokeBall');
break;
case PokeballType.GREAT_BALL:
ret = 'Great Ball';
ret = i18next.t('pokeball:greatBall');
break;
case PokeballType.ULTRA_BALL:
ret = 'Ultra Ball';
ret = i18next.t('pokeball:ultraBall');
break;
case PokeballType.ROGUE_BALL:
ret = 'Rogue Ball';
ret = i18next.t('pokeball:rogueBall');
break;
case PokeballType.MASTER_BALL:
ret = 'Master Ball';
ret = i18next.t('pokeball:masterBall');
break;
case PokeballType.LUXURY_BALL:
ret = 'Luxury Ball';
ret = i18next.t('pokeball:luxuryBall');
break;
}
return ret;

View File

@ -917,7 +917,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.TRUMBEAK, 14, null, null)
],
[Species.TRUMBEAK]: [
new SpeciesEvolution(Species.TOUCANNON, 36, null, null)
new SpeciesEvolution(Species.TOUCANNON, 28, null, null)
],
[Species.YUNGOOS]: [
new SpeciesEvolution(Species.GUMSHOOS, 20, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAY), SpeciesWildEvolutionDelay.SHORT)

View File

@ -10919,8 +10919,8 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
],
[Species.CHESPIN]: [
[ 1, Moves.TACKLE ],
[ 1, Moves.VINE_WHIP ],
[ 1, Moves.GROWL ],
[ 1, Moves.VINE_WHIP ],
[ 8, Moves.ROLLOUT ],
[ 11, Moves.BITE ],
[ 15, Moves.LEECH_SEED ],
@ -10934,8 +10934,8 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
],
[Species.QUILLADIN]: [
[ 1, Moves.TACKLE ],
[ 1, Moves.VINE_WHIP ],
[ 1, Moves.GROWL ],
[ 1, Moves.VINE_WHIP ],
[ 8, Moves.ROLLOUT ],
[ 11, Moves.BITE ],
[ 15, Moves.LEECH_SEED ],
@ -18391,6 +18391,69 @@ export const pokemonFormLevelMoves: PokemonSpeciesFormLevelMoves = {
[ 60, Moves.STONE_EDGE ],
],
},
[Species.NECROZMA]: {
1: [
[ 0, Moves.SUNSTEEL_STRIKE ],
[ 1, Moves.CONFUSION ],
[ 1, Moves.METAL_CLAW ],
[ 1, Moves.MORNING_SUN ],
[ 1, Moves.MOONLIGHT ],
[ 1, Moves.GRAVITY ],
[ 1, Moves.CHARGE_BEAM ],
[ 8, Moves.STEALTH_ROCK ],
[ 16, Moves.SLASH ],
[ 24, Moves.NIGHT_SLASH ],
[ 32, Moves.PSYCHO_CUT ],
[ 40, Moves.STORED_POWER ],
[ 48, Moves.ROCK_BLAST ],
[ 56, Moves.IRON_DEFENSE ],
[ 64, Moves.POWER_GEM ],
[ 72, Moves.PHOTON_GEYSER ],
[ 80, Moves.AUTOTOMIZE ],
[ 88, Moves.PRISMATIC_LASER ],
],
2: [
[ 0, Moves.MOONGEIST_BEAM ],
[ 1, Moves.CONFUSION ],
[ 1, Moves.METAL_CLAW ],
[ 1, Moves.MORNING_SUN ],
[ 1, Moves.MOONLIGHT ],
[ 1, Moves.GRAVITY ],
[ 1, Moves.CHARGE_BEAM ],
[ 8, Moves.STEALTH_ROCK ],
[ 16, Moves.SLASH ],
[ 24, Moves.NIGHT_SLASH ],
[ 32, Moves.PSYCHO_CUT ],
[ 40, Moves.STORED_POWER ],
[ 48, Moves.ROCK_BLAST ],
[ 56, Moves.IRON_DEFENSE ],
[ 64, Moves.POWER_GEM ],
[ 72, Moves.PHOTON_GEYSER ],
[ 80, Moves.AUTOTOMIZE ],
[ 88, Moves.PRISMATIC_LASER ],
],
3: [
[ 0, Moves.SUNSTEEL_STRIKE ],
[ 0, Moves.MOONGEIST_BEAM ],
[ 1, Moves.CONFUSION ],
[ 1, Moves.METAL_CLAW ],
[ 1, Moves.MORNING_SUN ],
[ 1, Moves.MOONLIGHT ],
[ 1, Moves.GRAVITY ],
[ 1, Moves.CHARGE_BEAM ],
[ 8, Moves.STEALTH_ROCK ],
[ 16, Moves.SLASH ],
[ 24, Moves.NIGHT_SLASH ],
[ 32, Moves.PSYCHO_CUT ],
[ 40, Moves.STORED_POWER ],
[ 48, Moves.ROCK_BLAST ],
[ 56, Moves.IRON_DEFENSE ],
[ 64, Moves.POWER_GEM ],
[ 72, Moves.PHOTON_GEYSER ],
[ 80, Moves.AUTOTOMIZE ],
[ 88, Moves.PRISMATIC_LASER ],
],
},
[Species.TOXTRICITY]: {
1: [
[ 0, Moves.SPARK ],

File diff suppressed because it is too large Load Diff

View File

@ -697,9 +697,9 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerType.GIOVANNI]: new TrainerConfig(++t).initForGymLeader([ Species.SANDILE, Species.MURKROW, Species.NIDORAN_M, Species.NIDORAN_F ], Type.DARK).setBattleBgm('battle_kanto_gym'),
[TrainerType.FALKNER]: new TrainerConfig(++t).initForGymLeader([ Species.PIDGEY, Species.HOOTHOOT, Species.DODUO ], Type.FLYING).setBattleBgm('battle_johto_gym'),
[TrainerType.BUGSY]: new TrainerConfig(++t).initForGymLeader([ Species.SCYTHER, Species.HERACROSS, Species.SHUCKLE, Species.PINSIR ], Type.BUG).setBattleBgm('battle_johto_gym'),
[TrainerType.WHITNEY]: new TrainerConfig(++t).initForGymLeader([ Species.CLEFAIRY, Species.MILTANK ], Type.NORMAL).setBattleBgm('battle_johto_gym'),
[TrainerType.WHITNEY]: new TrainerConfig(++t).initForGymLeader([ Species.GIRAFARIG, Species.MILTANK ], Type.NORMAL).setBattleBgm('battle_johto_gym'),
[TrainerType.MORTY]: new TrainerConfig(++t).initForGymLeader([ Species.GASTLY, Species.MISDREAVUS, Species.SABLEYE ], Type.GHOST).setBattleBgm('battle_johto_gym'),
[TrainerType.CHUCK]: new TrainerConfig(++t).initForGymLeader([ Species.POLIWRATH, ], Type.FIGHTING).setBattleBgm('battle_johto_gym'),
[TrainerType.CHUCK]: new TrainerConfig(++t).initForGymLeader([ Species.POLIWRATH, Species.MANKEY ], Type.FIGHTING).setBattleBgm('battle_johto_gym'),
[TrainerType.JASMINE]: new TrainerConfig(++t).initForGymLeader([ Species.MAGNEMITE, Species.STEELIX ], Type.STEEL).setBattleBgm('battle_johto_gym'),
[TrainerType.PRYCE]: new TrainerConfig(++t).initForGymLeader([ Species.SEEL, Species.SWINUB ], Type.ICE).setBattleBgm('battle_johto_gym'),
[TrainerType.CLAIR]: new TrainerConfig(++t).initForGymLeader([ Species.DRATINI, Species.HORSEA, Species.GYARADOS ], Type.DRAGON).setBattleBgm('battle_johto_gym'),

View File

@ -82,7 +82,11 @@ export class EggHatchPhase extends Phase {
this.eggContainer.add(this.eggLightraysOverlay);
this.eggHatchContainer.add(this.eggContainer);
const getPokemonSprite = () => this.scene.add.sprite(this.eggHatchBg.displayWidth / 2, this.eggHatchBg.displayHeight / 2, `pkmn__sub`);
const getPokemonSprite = () => {
const ret = this.scene.add.sprite(this.eggHatchBg.displayWidth / 2, this.eggHatchBg.displayHeight / 2, `pkmn__sub`);
ret.setPipeline(this.scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], ignoreTimeTint: true });
return ret;
};
this.eggHatchContainer.add((this.pokemonSprite = getPokemonSprite()));
@ -245,7 +249,7 @@ export class EggHatchPhase extends Phase {
this.scene.validateAchv(achvs.HATCH_SHINY);
this.eggContainer.setVisible(false);
this.pokemonSprite.play(this.pokemon.getSpriteKey(true));
this.pokemonSprite.pipelineData['ignoreTimeTint'] = true;
this.pokemonSprite.setPipelineData('ignoreTimeTint', true);
this.pokemonSprite.setPipelineData('spriteKey', this.pokemon.getSpriteKey());
this.pokemonSprite.setPipelineData('shiny', this.pokemon.shiny);
this.pokemonSprite.setPipelineData('variant', this.pokemon.variant);

View File

@ -71,7 +71,11 @@ export class EvolutionPhase extends Phase {
this.evolutionBgOverlay.setAlpha(0);
this.evolutionContainer.add(this.evolutionBgOverlay);
const getPokemonSprite = () => this.scene.addPokemonSprite(this.pokemon, this.evolutionBaseBg.displayWidth / 2, this.evolutionBaseBg.displayHeight / 2, `pkmn__sub`);
const getPokemonSprite = () => {
const ret = this.scene.addPokemonSprite(this.pokemon, this.evolutionBaseBg.displayWidth / 2, this.evolutionBaseBg.displayHeight / 2, `pkmn__sub`);
ret.setPipeline(this.scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], ignoreTimeTint: true });
return ret;
};
this.evolutionContainer.add((this.pokemonSprite = getPokemonSprite()));
this.evolutionContainer.add((this.pokemonTintSprite = getPokemonSprite()));
@ -92,7 +96,10 @@ export class EvolutionPhase extends Phase {
[ this.pokemonSprite, this.pokemonTintSprite, this.pokemonEvoSprite, this.pokemonEvoTintSprite ].map(sprite => {
sprite.play(this.pokemon.getSpriteKey(true));
sprite.setPipeline(this.scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(this.pokemon.getTeraType()) });
sprite.pipelineData['ignoreTimeTint'] = true;
sprite.setPipelineData('ignoreTimeTint', true);
sprite.setPipelineData('spriteKey', this.pokemon.getSpriteKey());
sprite.setPipelineData('shiny', this.pokemon.shiny);
sprite.setPipelineData('variant', this.pokemon.variant);
[ 'spriteColors', 'fusionSpriteColors' ].map(k => {
if (this.pokemon.summonData?.speciesForm)
k += 'Base';

View File

@ -309,7 +309,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (this.shiny) {
const populateVariantColors = (key: string, back: boolean = false): Promise<void> => {
return new Promise(resolve => {
const battleSpritePath = this.getBattleSpriteAtlasPath(back, ignoreOverride);
const battleSpritePath = this.getBattleSpriteAtlasPath(back, ignoreOverride).replace('variant/', '').replace(/_[1-3]$/, '');
let variantSet: VariantSet;
let config = variantData;
battleSpritePath.split('/').map(p => config ? config = config[p] : null);
@ -326,9 +326,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
});
};
if (this.isPlayer())
Promise.all([ populateVariantColors(this.getBattleSpriteKey()), populateVariantColors(this.getBattleSpriteKey(true)) ]).then(() => updateFusionPaletteAndResolve());
Promise.all([ populateVariantColors(this.getBattleSpriteKey(false)), populateVariantColors(this.getBattleSpriteKey(true), true) ]).then(() => updateFusionPaletteAndResolve());
else
populateVariantColors(this.getBattleSpriteKey()).then(() => updateFusionPaletteAndResolve());
populateVariantColors(this.getBattleSpriteKey(false)).then(() => updateFusionPaletteAndResolve());
} else
updateFusionPaletteAndResolve();
});
@ -986,11 +986,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
let shinyThreshold = new Utils.IntegerHolder(32);
if (thresholdOverride === undefined) {
if (!this.hasTrainer()) {
if (new Date() < new Date('4/22/2024'))
shinyThreshold.value *= 3;
if (!this.hasTrainer())
this.scene.applyModifiers(ShinyRateBoosterModifier, true, shinyThreshold);
}
} else
shinyThreshold.value = thresholdOverride;
@ -1828,7 +1825,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return false;
break;
case StatusEffect.FREEZE:
if (this.isOfType(Type.ICE))
if (this.isOfType(Type.ICE) || [WeatherType.SUNNY, WeatherType.HARSH_SUN].includes(this.scene?.arena.weather?.weatherType))
return false;
break;
case StatusEffect.BURN:

View File

@ -20,6 +20,7 @@ interface GameModeConfig {
hasTrainers?: boolean;
hasFixedBattles?: boolean;
hasNoShop?: boolean;
hasShortBiomes?: boolean;
hasRandomBiomes?: boolean;
hasRandomBosses?: boolean;
isSplicedOnly?: boolean;
@ -33,6 +34,7 @@ export class GameMode implements GameModeConfig {
public hasTrainers: boolean;
public hasFixedBattles: boolean;
public hasNoShop: boolean;
public hasShortBiomes: boolean;
public hasRandomBiomes: boolean;
public hasRandomBosses: boolean;
public isSplicedOnly: boolean;
@ -174,7 +176,7 @@ export class GameMode implements GameModeConfig {
export const gameModes = Object.freeze({
[GameModes.CLASSIC]: new GameMode(GameModes.CLASSIC, { isClassic: true, hasTrainers: true, hasFixedBattles: true }),
[GameModes.ENDLESS]: new GameMode(GameModes.ENDLESS, { isEndless: true, hasRandomBiomes: true, hasRandomBosses: true }),
[GameModes.SPLICED_ENDLESS]: new GameMode(GameModes.SPLICED_ENDLESS, { isEndless: true, hasRandomBiomes: true, hasRandomBosses: true, isSplicedOnly: true }),
[GameModes.ENDLESS]: new GameMode(GameModes.ENDLESS, { isEndless: true, hasShortBiomes: true, hasRandomBosses: true }),
[GameModes.SPLICED_ENDLESS]: new GameMode(GameModes.SPLICED_ENDLESS, { isEndless: true, hasShortBiomes: true, hasRandomBosses: true, isSplicedOnly: true }),
[GameModes.DAILY]: new GameMode(GameModes.DAILY, { isDaily: true, hasTrainers: true, hasNoShop: true })
});

View File

@ -1,9 +1,11 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
/**
* The menu namespace holds most miscellaneous text that isn't directly part of the game's
* contents or directly related to Pokemon data. This includes menu navigation, settings,
* account interactions, descriptive text, etc.
*/
export const menu = {
export const menu: SimpleTranslationEntries = {
"cancel": "Cancel",
"continue": "Continue",
"dailyRun": "Daily Run (Beta)",
@ -11,6 +13,22 @@ export const menu = {
"newGame": "New Game",
"selectGameMode": "Select a game mode.",
"logInOrCreateAccount": "Log in or create an account to start. No email required!",
"username": "Username",
"password": "Password",
"login": "Login",
"register": "Register",
"emptyUsername": "Username must not be empty",
"invalidLoginUsername": "The provided username is invalid",
"invalidRegisterUsername": "Username must only contain letters, numbers, or underscores",
"invalidLoginPassword": "The provided password is invalid",
"invalidRegisterPassword": "Password must be 6 characters or longer",
"usernameAlreadyUsed": "The provided username is already in use",
"accountNonExistent": "The provided user does not exist",
"unmatchingPassword": "The provided password does not match",
"passwordNotMatchingConfirmPassword": "Password must match confirm password",
"confirmPassword": "Confirm Password",
"registrationAgeWarning": "By registering, you confirm you are of 13 years of age or older.",
"backToLogin": "Back to Login",
"failedToLoadSaveData": "Failed to load save data. Please reload the page.\nIf this continues, please contact the administrator.",
"sessionSuccess": "Session loaded successfully.",
"failedToLoadSession": "Your session data could not be loaded.\nIt may be corrupted.",

View File

@ -1,6 +1,6 @@
import { MoveTranslations } from "#app/plugins/i18n";
import { MoveTranslationEntries } from "#app/plugins/i18n";
export const move: MoveTranslations = {
export const move: MoveTranslationEntries = {
"pound": {
name: "Pound",
effect: "The target is physically pounded with a long tail, a foreleg, or the like."

View File

@ -0,0 +1,10 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const pokeball: SimpleTranslationEntries = {
"pokeBall": "Poké Ball",
"greatBall": "Great Ball",
"ultraBall": "Ultra Ball",
"rogueBall": "Rogue Ball",
"masterBall": "Master Ball",
"luxuryBall": "Luxury Ball",
} as const;

1086
src/locales/en/pokemon.ts Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,6 @@
export const menu = {
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const menu: SimpleTranslationEntries = {
"cancel": "Annuler",
"continue": "Continuer",
"dailyRun": "Défi du jour (Bêta)",
@ -6,6 +8,22 @@ export const menu = {
"newGame": "Nouvelle partie",
"selectGameMode": "Sélectionnez un mode de jeu.",
"logInOrCreateAccount": "Connectez-vous ou créez un compte pour commencer. Aucun e-mail requis !",
"username": "Nom d'utilisateur",
"password": "Mot de passe",
"login": "Connexion",
"register": "S'inscrire",
"emptyUsername": "Le nom d'utilisateur est manquant",
"invalidLoginUsername": "Le nom d'utilisateur n'est pas valide",
"invalidRegisterUsername": "Le nom d'utilisateur ne doit contenir que \ndes lettres, chiffres ou traits bas",
"invalidLoginPassword": "Le mot de passe n'est pas valide",
"invalidRegisterPassword": "Le mot de passe doit contenir 6 caractères ou plus",
"usernameAlreadyUsed": "Le nom d'utilisateur est déjà utilisé",
"accountNonExistent": "Le nom d'utilisateur n'existe pas",
"unmatchingPassword": "Le mot de passe n'est pas correct",
"passwordNotMatchingConfirmPassword": "Les mots de passe ne correspondent pas",
"confirmPassword": "Confirmer le MDP",
"registrationAgeWarning": "Vous confirmez en vous inscrivant que vous avez 13 ans ou plus.",
"backToLogin": "Retour",
"failedToLoadSaveData": "Échec du chargement des données. Veuillez recharger la page.\nSi cela continue, veuillez contacter l'administrateur.",
"sessionSuccess": "Session chargée avec succès.",
"failedToLoadSession": "Vos données de session n'ont pas pu être chargées.\nElles pourraient être corrompues.",

View File

@ -1,6 +1,6 @@
import { MoveTranslations } from "#app/plugins/i18n";
import { MoveTranslationEntries } from "#app/plugins/i18n";
export const move: MoveTranslations = {
export const move: MoveTranslationEntries = {
"pound": {
name: "Écras'Face",
effect: "Le lanceur écrase la cible avec lun de ses membres, tels quune de ses pattes avant ou sa longue queue."
@ -1443,7 +1443,7 @@ export const move: MoveTranslations = {
},
"healingWish": {
name: "Voeu Soin",
effect: "Un soin qui permet au lanceur de récupérer jusquà la moitié de ses PV max."
effect: "Le lanceur tombe K.O. pour soigner les altérations de statut et les PV du Pokémon qui viendra le remplacer sur le terrain."
},
"brine": {
name: "Saumure",

View File

@ -0,0 +1,10 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const pokeball: SimpleTranslationEntries = {
"pokeBall": "Poké Ball",
"greatBall": "Super Ball",
"ultraBall": "Hyper Ball",
"rogueBall": "Rogue Ball",
"masterBall": "Master Ball",
"luxuryBall": "Luxe Ball",
} as const;

1086
src/locales/fr/pokemon.ts Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,6 @@
export const menu = {
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const menu: SimpleTranslationEntries = {
"cancel": "Annulla",
"continue": "Continua",
"newGame": "Nuova Partita",

View File

@ -19,6 +19,7 @@ import { VoucherType, getVoucherTypeIcon, getVoucherTypeName } from '../system/v
import { FormChangeItem, SpeciesFormChangeItemTrigger, pokemonFormChanges } from '../data/pokemon-forms';
import { ModifierTier } from './modifier-tier';
import { Nature, getNatureName, getNatureStatMultiplier } from '#app/data/nature';
import { Localizable } from '#app/plugins/i18n';
const outputModifierData = false;
const useMaxWeightForOutput = false;
@ -131,10 +132,19 @@ export interface GeneratedPersistentModifierType {
getPregenArgs(): any[];
}
class AddPokeballModifierType extends ModifierType {
class AddPokeballModifierType extends ModifierType implements Localizable {
private pokeballType: PokeballType;
private count: integer;
constructor(pokeballType: PokeballType, count: integer, iconImage?: string) {
super(`${count}x ${getPokeballName(pokeballType)}`, `Receive ${getPokeballName(pokeballType)} x${count}\nCatch Rate: ${getPokeballCatchMultiplier(pokeballType) > -1 ? `${getPokeballCatchMultiplier(pokeballType)}x` : 'Certain'}`,
(_type, _args) => new Modifiers.AddPokeballModifier(this, pokeballType, count), iconImage, 'pb', 'pb_bounce_1');
super('', '', (_type, _args) => new Modifiers.AddPokeballModifier(this, pokeballType, count), iconImage, 'pb', 'pb_bounce_1');
this.pokeballType = pokeballType;
this.count = count;
}
localize(): void {
this.name = `${this.count}x ${getPokeballName(this.pokeballType)}`;
this.description = `Receive ${getPokeballName(this.pokeballType)} x${this.count}\nCatch Rate: ${getPokeballCatchMultiplier(this.pokeballType) > -1 ? `${getPokeballCatchMultiplier(this.pokeballType)}x` : 'Certain'}`;
}
}
@ -934,8 +944,8 @@ export const modifierTypes = {
GOLDEN_POKEBALL: () => new ModifierType(`Golden ${getPokeballName(PokeballType.POKEBALL)}`, 'Adds 1 extra item option at the end of every battle',
(type, _args) => new Modifiers.ExtraModifierModifier(type), 'pb_gold', null, 'pb_bounce_1'),
ENEMY_DAMAGE_BOOSTER: () => new ModifierType('Damage Token', 'Increases damage by 10%', (type, _args) => new Modifiers.EnemyDamageBoosterModifier(type, 10), 'wl_item_drop'),
ENEMY_DAMAGE_REDUCTION: () => new ModifierType('Protection Token', 'Reduces incoming damage by 5%', (type, _args) => new Modifiers.EnemyDamageReducerModifier(type, 5), 'wl_guard_spec'),
ENEMY_DAMAGE_BOOSTER: () => new ModifierType('Damage Token', 'Increases damage by 5%', (type, _args) => new Modifiers.EnemyDamageBoosterModifier(type, 5), 'wl_item_drop'),
ENEMY_DAMAGE_REDUCTION: () => new ModifierType('Protection Token', 'Reduces incoming damage by 2.5%', (type, _args) => new Modifiers.EnemyDamageReducerModifier(type, 2.5), 'wl_guard_spec'),
//ENEMY_SUPER_EFFECT_BOOSTER: () => new ModifierType('Type Advantage Token', 'Increases damage of super effective attacks by 30%', (type, _args) => new Modifiers.EnemySuperEffectiveDamageBoosterModifier(type, 30), 'wl_custom_super_effective'),
ENEMY_HEAL: () => new ModifierType('Recovery Token', 'Heals 3% of max HP every turn', (type, _args) => new Modifiers.EnemyTurnHealModifier(type, 3), 'wl_potion'),
ENEMY_ATTACK_POISON_CHANCE: () => new EnemyAttackStatusEffectChanceModifierType('Poison Token', 10, StatusEffect.POISON, 'wl_antidote'),
@ -944,7 +954,7 @@ export const modifierTypes = {
ENEMY_ATTACK_FREEZE_CHANCE: () => new EnemyAttackStatusEffectChanceModifierType('Freeze Token', 10, StatusEffect.FREEZE, 'wl_ice_heal'),
ENEMY_ATTACK_BURN_CHANCE: () => new EnemyAttackStatusEffectChanceModifierType('Burn Token', 10, StatusEffect.BURN, 'wl_burn_heal'),
ENEMY_STATUS_EFFECT_HEAL_CHANCE: () => new ModifierType('Full Heal Token', 'Adds a 10% chance every turn to heal a status condition', (type, _args) => new Modifiers.EnemyStatusEffectHealChanceModifier(type, 10), 'wl_full_heal'),
ENEMY_ENDURE_CHANCE: () => new EnemyEndureChanceModifierType('Endure Token', 5, 'wl_reset_urge'),
ENEMY_ENDURE_CHANCE: () => new EnemyEndureChanceModifierType('Endure Token', 2.5, 'wl_reset_urge'),
ENEMY_FUSED_CHANCE: () => new ModifierType('Fusion Token', 'Adds a 1% chance that a wild Pokémon will be a fusion', (type, _args) => new Modifiers.EnemyFusionChanceModifier(type, 1), 'wl_custom_spliced'),
};

View File

@ -1578,9 +1578,7 @@ export class MoneyRewardModifier extends ConsumableModifier {
scene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount);
scene.money += moneyAmount.value;
scene.updateMoneyText();
scene.validateAchvs(MoneyAchv);
scene.addMoney(moneyAmount.value);
return true;
}
@ -1627,9 +1625,7 @@ export class DamageMoneyRewardModifier extends PokemonHeldItemModifier {
const scene = (args[0] as Pokemon).scene;
const moneyAmount = new Utils.IntegerHolder(Math.floor((args[1] as Utils.IntegerHolder).value * (0.5 * this.getStackCount())));
scene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount);
scene.money += moneyAmount.value;
scene.updateMoneyText();
scene.validateAchvs(MoneyAchv);
scene.addMoney(moneyAmount.value);
return true;
}
@ -1651,9 +1647,7 @@ export class MoneyInterestModifier extends PersistentModifier {
apply(args: any[]): boolean {
const scene = args[0] as BattleScene;
const interestAmount = Math.floor(scene.money * 0.1 * this.getStackCount());
scene.money += interestAmount;
scene.updateMoneyText();
scene.validateAchvs(MoneyAchv);
scene.addMoney(interestAmount);
scene.queueMessage(`You received interest of ₽${interestAmount.toLocaleString('en-US')}\nfrom the ${this.type.name}!`, null, true);
@ -1963,7 +1957,7 @@ abstract class EnemyDamageMultiplierModifier extends EnemyPersistentModifier {
export class EnemyDamageBoosterModifier extends EnemyDamageMultiplierModifier {
constructor(type: ModifierType, boostPercent: number, stackCount?: integer) {
//super(type, 1 + ((boostPercent || 10) * 0.01), stackCount);
super(type, 1.1, stackCount); // Hardcode multiplier temporarily
super(type, 1.05, stackCount); // Hardcode multiplier temporarily
}
match(modifier: Modifier): boolean {
@ -1986,7 +1980,7 @@ export class EnemyDamageBoosterModifier extends EnemyDamageMultiplierModifier {
export class EnemyDamageReducerModifier extends EnemyDamageMultiplierModifier {
constructor(type: ModifierType, reductionPercent: number, stackCount?: integer) {
//super(type, 1 - ((reductionPercent || 5) * 0.01), stackCount);
super(type, 0.95, stackCount); // Hardcode multiplier temporarily
super(type, 0.975, stackCount); // Hardcode multiplier temporarily
}
match(modifier: Modifier): boolean {
@ -2118,7 +2112,7 @@ export class EnemyEndureChanceModifier extends EnemyPersistentModifier {
constructor(type: ModifierType, chancePercent: number, stackCount?: integer) {
super(type, stackCount);
this.chance = (chancePercent || 5) / 100;
this.chance = (chancePercent || 2.5) / 100;
}
match(modifier: Modifier) {

View File

@ -2,7 +2,7 @@ import BattleScene, { STARTER_FORM_OVERRIDE, STARTER_SPECIES_OVERRIDE, bypassLog
import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove, MoveResult, DamageResult, FieldPosition, HitResult, TurnMove } from "./field/pokemon";
import * as Utils from './utils';
import { Moves } from "./data/enums/moves";
import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveEffectAttr, MoveFlags, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr, MoveTarget, OneHitKOAttr, getMoveTargets, MoveTargetSet, MoveEffectTrigger, CopyMoveAttr, AttackMove, SelfStatusMove, DelayedAttackAttr, RechargeAttr, PreMoveMessageAttr, HealStatusEffectAttr, IgnoreOpponentStatChangesAttr, NoEffectAttr, FixedDamageAttr } from "./data/move";
import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveEffectAttr, MoveFlags, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr, MoveTarget, OneHitKOAttr, getMoveTargets, MoveTargetSet, MoveEffectTrigger, CopyMoveAttr, AttackMove, SelfStatusMove, DelayedAttackAttr, RechargeAttr, PreMoveMessageAttr, HealStatusEffectAttr, IgnoreOpponentStatChangesAttr, NoEffectAttr, FixedDamageAttr, OneHitKOAccuracyAttr } from "./data/move";
import { Mode } from './ui/ui';
import { Command } from "./ui/command-ui-handler";
import { Stat } from "./data/pokemon-stat";
@ -30,20 +30,20 @@ import { Weather, WeatherType, getRandomWeatherType, getTerrainBlockMessage, get
import { TempBattleStat } from "./data/temp-battle-stat";
import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag";
import { ArenaTagType } from "./data/enums/arena-tag-type";
import { CheckTrappedAbAttr, MoveAbilityBypassAbAttr, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, applyPostBattleInitAbAttrs, PostBattleInitAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs } from "./data/ability";
import { CheckTrappedAbAttr, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, applyPostBattleInitAbAttrs, PostBattleInitAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs, AlwaysHitAbAttr } from "./data/ability";
import { Unlockables, getUnlockableName } from "./system/unlockables";
import { getBiomeKey } from "./field/arena";
import { BattleType, BattlerIndex, TurnCommand } from "./battle";
import { BattleSpec } from "./enums/battle-spec";
import { Species } from "./data/enums/species";
import { HealAchv, LevelAchv, MoneyAchv, achvs } from "./system/achv";
import { HealAchv, LevelAchv, achvs } from "./system/achv";
import { TrainerSlot, trainerConfigs } from "./data/trainer-config";
import { TrainerType } from "./data/enums/trainer-type";
import { EggHatchPhase } from "./egg-hatch-phase";
import { Egg } from "./data/egg";
import { vouchers } from "./system/voucher";
import { loggedInUser, updateUserInfo } from "./account";
import { DexAttr, PlayerGender, SessionSaveData } from "./system/game-data";
import { PlayerGender, SessionSaveData } from "./system/game-data";
import { addPokeballCaptureStars, addPokeballOpenParticles } from "./field/anims";
import { SpeciesFormChangeActiveTrigger, SpeciesFormChangeManualTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangePreMoveTrigger } from "./data/pokemon-forms";
import { battleSpecDialogue, getCharVariantFromDialogue } from "./data/dialogue";
@ -379,6 +379,33 @@ export class UnavailablePhase extends Phase {
}
}
export class ReloadSessionPhase extends Phase {
constructor(scene: BattleScene) {
super(scene);
}
start(): void {
this.scene.ui.setMode(Mode.SESSION_RELOAD);
let delayElapsed = false;
let loaded = false;
this.scene.time.delayedCall(Utils.fixedInt(1500), () => {
if (loaded)
this.end();
else
delayElapsed = true;
});
this.scene.gameData.loadSystem().then(() => {
if (delayElapsed)
this.end();
else
loaded = true;
});
}
}
export class OutdatedPhase extends Phase {
constructor(scene: BattleScene) {
super(scene);
@ -675,7 +702,7 @@ export class EncounterPhase extends BattlePhase {
}
if (!this.loaded)
this.scene.gameData.setPokemonSeen(enemyPokemon);
this.scene.gameData.setPokemonSeen(enemyPokemon, true, battle.battleType === BattleType.TRAINER);
if (enemyPokemon.species.speciesId === Species.ETERNATUS) {
if (this.scene.gameMode.isClassic && (battle.battleSpec === BattleSpec.FINAL_BOSS || this.scene.gameMode.isWaveFinal(battle.waveIndex))) {
@ -767,7 +794,8 @@ export class EncounterPhase extends BattlePhase {
pokemon.resetBattleData();
}
this.scene.arena.trySetWeather(getRandomWeatherType(this.scene.arena), false);
if (!this.loaded)
this.scene.arena.trySetWeather(getRandomWeatherType(this.scene.arena), false);
const enemyField = this.scene.getEnemyField();
this.scene.tweens.add({
@ -1021,7 +1049,8 @@ export class SelectBiomePhase extends BattlePhase {
};
if ((this.scene.gameMode.isClassic && this.scene.gameMode.isWaveFinal(this.scene.currentBattle.waveIndex + 9))
|| (this.scene.gameMode.isDaily && this.scene.gameMode.isWaveFinal(this.scene.currentBattle.waveIndex)))
|| (this.scene.gameMode.isDaily && this.scene.gameMode.isWaveFinal(this.scene.currentBattle.waveIndex))
|| (this.scene.gameMode.hasShortBiomes && !(this.scene.currentBattle.waveIndex % 50)))
setNextBiome(Biome.END);
else if (this.scene.gameMode.hasRandomBiomes)
setNextBiome(this.generateNextBiome());
@ -1058,8 +1087,10 @@ export class SelectBiomePhase extends BattlePhase {
});
} else
setNextBiome(biomes[Utils.randSeedInt(biomes.length)]);
} else
} else if (biomeLinks.hasOwnProperty(currentBiome))
setNextBiome(biomeLinks[currentBiome] as Biome);
else
setNextBiome(this.generateNextBiome());
}
generateNextBiome(): Biome {
@ -2173,7 +2204,7 @@ export class MovePhase extends BattlePhase {
const targets = this.scene.getField(true).filter(p => {
if (this.targets.indexOf(p.getBattlerIndex()) > -1) {
const hiddenTag = p.getTag(HiddenTag);
if (hiddenTag && !this.move.getMove().getAttrs(HitsTagAttr).filter(hta => (hta as HitsTagAttr).tagType === hiddenTag.tagType).length)
if (hiddenTag && !this.move.getMove().getAttrs(HitsTagAttr).filter(hta => (hta as HitsTagAttr).tagType === hiddenTag.tagType).length && !p.hasAbilityWithAttr(AlwaysHitAbAttr) && !this.pokemon.hasAbilityWithAttr(AlwaysHitAbAttr))
return false;
return true;
}
@ -2267,6 +2298,7 @@ export class MovePhase extends BattlePhase {
this.cancelled = activated;
break;
}
if (activated) {
this.scene.queueMessage(getPokemonMessage(this.pokemon, getStatusEffectActivationText(this.pokemon.status.effect)));
this.scene.unshiftPhase(new CommonAnimPhase(this.scene, this.pokemon.getBattlerIndex(), undefined, CommonAnim.POISON + (this.pokemon.status.effect - 1)));
@ -2289,6 +2321,7 @@ export class MovePhase extends BattlePhase {
showMoveText(): void {
if (this.move.getMove().getAttrs(ChargeAttr).length) {
this.scene.queueMessage(getPokemonMessage(this.pokemon, ` used\n${this.move.getName()}!`), 500);
const lastMove = this.pokemon.getLastXMoves() as TurnMove[];
if (!lastMove.length || lastMove[0].move !== this.move.getMove().id || lastMove[0].result !== MoveResult.OTHER)
return;
@ -2467,6 +2500,9 @@ export class MoveEffectPhase extends PokemonPhase {
if (user.turnData.hitsLeft < user.turnData.hitCount)
return true;
if (user.hasAbilityWithAttr(AlwaysHitAbAttr) || target.hasAbilityWithAttr(AlwaysHitAbAttr))
return true;
const hiddenTag = target.getTag(HiddenTag);
if (hiddenTag && !this.move.getMove().getAttrs(HitsTagAttr).filter(hta => (hta as HitsTagAttr).tagType === hiddenTag.tagType).length)
return false;
@ -2481,12 +2517,15 @@ export class MoveEffectPhase extends PokemonPhase {
if (moveAccuracy.value === -1)
return true;
user.scene.applyModifiers(PokemonMoveAccuracyBoosterModifier, user.isPlayer(), user, moveAccuracy);
const isOhko = !!this.move.getMove().getAttrs(OneHitKOAccuracyAttr).length;
if (!isOhko)
user.scene.applyModifiers(PokemonMoveAccuracyBoosterModifier, user.isPlayer(), user, moveAccuracy);
if (this.scene.arena.weather?.weatherType === WeatherType.FOG)
moveAccuracy.value = Math.floor(moveAccuracy.value * 0.9);
if (!this.move.getMove().getAttrs(OneHitKOAttr).length && this.scene.arena.getTag(ArenaTagType.GRAVITY))
if (!isOhko && this.scene.arena.getTag(ArenaTagType.GRAVITY))
moveAccuracy.value = Math.floor(moveAccuracy.value * 1.67);
const userAccuracyLevel = new Utils.IntegerHolder(user.summonData.battleStats[BattleStat.ACC]);
@ -3281,10 +3320,7 @@ export class MoneyRewardPhase extends BattlePhase {
this.scene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount);
this.scene.money += moneyAmount.value;
this.scene.updateMoneyText();
this.scene.validateAchvs(MoneyAchv);
this.scene.addMoney(moneyAmount.value);
this.scene.ui.showText(`You got ₽${moneyAmount.value.toLocaleString('en-US')}\nfor winning!`, null, () => this.end(), null, true);
}
@ -3389,6 +3425,8 @@ export class GameOverPhase extends BattlePhase {
handleClearSession(): void {
this.scene.gameData.tryClearSession(this.scene, this.scene.sessionSlotId).then((success: boolean | [boolean, boolean]) => {
if (!success[0])
return this.scene.reset(true);
this.scene.time.delayedCall(1000, () => {
let firstClear = false;
if (this.victory && success[1]) {
@ -3764,11 +3802,15 @@ export class PokemonHealPhase extends CommonAnimPhase {
const hasMessage = !!this.message;
let lastStatusEffect = StatusEffect.NONE;
if (!fullHp) {
if (!fullHp || this.hpHealed < 0) {
const hpRestoreMultiplier = new Utils.IntegerHolder(1);
if (!this.revive)
this.scene.applyModifiers(HealingBoosterModifier, this.player, hpRestoreMultiplier);
const healAmount = new Utils.NumberHolder(Math.floor(this.hpHealed * hpRestoreMultiplier.value));
if (healAmount.value < 0) {
pokemon.damageAndUpdate(healAmount.value * -1, HitResult.HEAL);
healAmount.value = 0;
}
// Prevent healing to full if specified (in case of healing tokens so Sturdy doesn't cause a softlock)
if (this.preventFullHeal && pokemon.hp + healAmount.value >= pokemon.getMaxHp())
healAmount.value = (pokemon.getMaxHp() - pokemon.hp) - 1;
@ -4296,7 +4338,7 @@ export class EggLapsePhase extends Phase {
const eggsToHatch: Egg[] = this.scene.gameData.eggs.filter((egg: Egg) => {
return --egg.hatchWaves < 1
})
});
if (eggsToHatch.length) {
this.scene.queueMessage('Oh?');

View File

@ -6,12 +6,22 @@ import { menu as frMenu } from '../locales/fr/menu';
import { move as enMove } from '../locales/en/move';
import { move as frMove } from '../locales/fr/move';
import { pokeball as enPokeball } from '../locales/en/pokeball';
import { pokeball as frPokeball } from '../locales/fr/pokeball';
import { pokemon as enPokemon } from '../locales/en/pokemon';
import { pokemon as frPokemon } from '../locales/fr/pokemon';
export interface SimpleTranslationEntries {
[key: string]: string
}
export interface MoveTranslationEntry {
name: string,
effect: string
}
export interface MoveTranslations {
export interface MoveTranslationEntries {
[key: string]: MoveTranslationEntry
}
@ -50,6 +60,8 @@ export function initI18n(): void {
en: {
menu: enMenu,
move: enMove,
pokeball: enPokeball,
pokemon: enPokemon,
},
it: {
menu: itMenu,
@ -57,6 +69,8 @@ export function initI18n(): void {
fr: {
menu: frMenu,
move: frMove,
pokeball: frPokeball,
pokemon: frPokemon,
}
},
});
@ -68,6 +82,8 @@ declare module 'i18next' {
resources: {
menu: typeof enMenu;
move: typeof enMove;
pokeball: typeof enPokeball;
pokemon: typeof enPokemon;
};
}
}

View File

@ -1,7 +1,7 @@
import BattleScene, { PokeballCounts, bypassLogin } from "../battle-scene";
import Pokemon, { EnemyPokemon, PlayerPokemon } from "../field/pokemon";
import { pokemonEvolutions, pokemonPrevolutions } from "../data/pokemon-evolutions";
import PokemonSpecies, { SpeciesFormKey, allSpecies, getPokemonSpecies, noStarterFormKeys, speciesStarters } from "../data/pokemon-species";
import PokemonSpecies, { allSpecies, getPokemonSpecies, noStarterFormKeys, speciesStarters } from "../data/pokemon-species";
import { Species, defaultStarterSpecies } from "../data/enums/species";
import * as Utils from "../utils";
import PokemonData from "./pokemon-data";
@ -27,7 +27,7 @@ import { Moves } from "../data/enums/moves";
import { speciesEggMoves } from "../data/egg-moves";
import { allMoves } from "../data/move";
import { TrainerVariant } from "../field/trainer";
import { OutdatedPhase, UnavailablePhase } from "#app/phases";
import { OutdatedPhase, ReloadSessionPhase } from "#app/phases";
import { Variant, variantData } from "#app/data/variant";
const saveKey = 'x0i2O7WRiANTqPmZ'; // Temporary; secure encryption is not yet necessary
@ -280,6 +280,9 @@ export class GameData {
if (error.startsWith('client version out of date')) {
this.scene.clearPhaseQueue();
this.scene.unshiftPhase(new OutdatedPhase(this.scene));
} else if (error.startsWith('session out of date')) {
this.scene.clearPhaseQueue();
this.scene.unshiftPhase(new ReloadSessionPhase(this.scene));
}
console.error(error);
return resolve(false);
@ -340,7 +343,7 @@ export class GameData {
this.starterData[s].eggMoves = starterEggMoveData[s];
}
this.migrateStarterAbilities(systemData);
this.migrateStarterAbilities(systemData, this.starterData);
} else {
if ([ '1.0.0', '1.0.1' ].includes(systemData.gameVersion))
this.migrateStarterAbilities(systemData);
@ -551,6 +554,10 @@ export class GameData {
.then(response => response.text())
.then(error => {
if (error) {
if (error.startsWith('session out of date')) {
this.scene.clearPhaseQueue();
this.scene.unshiftPhase(new ReloadSessionPhase(this.scene));
}
console.error(error);
return resolve(false);
}
@ -715,9 +722,19 @@ export class GameData {
Utils.apiFetch(`savedata/delete?datatype=${GameDataType.SESSION}&slot=${slotId}`, true).then(response => {
if (response.ok) {
loggedInUser.lastSessionSlot = -1;
return resolve(true);
resolve(true);
}
resolve(false);
return response.text();
}).then(error => {
if (error) {
if (error.startsWith('session out of date')) {
this.scene.clearPhaseQueue();
this.scene.unshiftPhase(new ReloadSessionPhase(this.scene));
}
console.error(error);
resolve(false);
}
resolve(true);
});
});
});
@ -735,12 +752,19 @@ export class GameData {
return resolve([false, false]);
const sessionData = this.getSessionSaveData(scene);
Utils.apiPost(`savedata/clear?slot=${slotId}`, JSON.stringify(sessionData)).then(response => {
if (response.ok) {
if (response.ok)
loggedInUser.lastSessionSlot = -1;
return response.json();
return response.json();
}).then(jsonResponse => {
if (!jsonResponse.error)
return resolve([true, jsonResponse.success as boolean]);
if (jsonResponse && jsonResponse.error.startsWith('session out of date')) {
this.scene.clearPhaseQueue();
this.scene.unshiftPhase(new ReloadSessionPhase(this.scene));
}
console.error(jsonResponse);
resolve([false, false]);
}).then(jsonResponse => resolve([true, jsonResponse.success as boolean]));
});
});
});
}
@ -969,13 +993,13 @@ export class GameData {
this.starterData = starterData;
}
setPokemonSeen(pokemon: Pokemon, incrementCount: boolean = true): void {
setPokemonSeen(pokemon: Pokemon, incrementCount: boolean = true, trainer: boolean = false): void {
const dexEntry = this.dexData[pokemon.species.speciesId];
dexEntry.seenAttr |= pokemon.getDexAttr();
if (incrementCount) {
dexEntry.seenCount++;
this.gameStats.pokemonSeen++;
if (pokemon.isShiny())
if (!trainer && pokemon.isShiny())
this.gameStats.shinyPokemonSeen++;
}
}
@ -1207,9 +1231,9 @@ export class GameData {
}
}
migrateStarterAbilities(systemData: SystemSaveData): void {
migrateStarterAbilities(systemData: SystemSaveData, initialStarterData?: StarterData): void {
const starterIds = Object.keys(this.starterData).map(s => parseInt(s) as Species);
const starterData = systemData.starterData;
const starterData = initialStarterData || systemData.starterData;
const dexData = systemData.dexData;
for (let s of starterIds) {
const dexAttr = dexData[s].caughtAttr;

View File

@ -2,14 +2,15 @@ import { FormModalUiHandler } from "./form-modal-ui-handler";
import { ModalConfig } from "./modal-ui-handler";
import * as Utils from "../utils";
import { Mode } from "./ui";
import i18next from '../plugins/i18n';
export default class LoginFormUiHandler extends FormModalUiHandler {
getModalTitle(config?: ModalConfig): string {
return 'Login';
return i18next.t('menu:login');
}
getFields(config?: ModalConfig): string[] {
return [ 'Username', 'Password' ];
return [ i18next.t('menu:username'), i18next.t('menu:password') ];
}
getWidth(config?: ModalConfig): number {
@ -21,7 +22,7 @@ export default class LoginFormUiHandler extends FormModalUiHandler {
}
getButtonLabels(config?: ModalConfig): string[] {
return [ 'Log In', 'Register' ];
return [ i18next.t('menu:login'), i18next.t('menu:register') ];
}
getReadableErrorMessage(error: string): string {
@ -30,13 +31,13 @@ export default class LoginFormUiHandler extends FormModalUiHandler {
error = error.slice(0, colonIndex);
switch (error) {
case 'invalid username':
return 'The provided username is invalid';
return i18next.t('menu:invalidLoginUsername');
case 'invalid password':
return 'The provided password is invalid';
return i18next.t('menu:invalidLoginPassword');
case 'account doesn\'t exist':
return 'The provided user does not exist';
return i18next.t('menu:accountNonExistent');
case 'password doesn\'t match':
return 'The provided password does not match';
return i18next.t('menu:unmatchingPassword');
}
return super.getReadableErrorMessage(error);
@ -57,7 +58,7 @@ export default class LoginFormUiHandler extends FormModalUiHandler {
this.scene.ui.playError();
};
if (!this.inputs[0].text)
return onFail('Username must not be empty');
return onFail(i18next.t('menu:emptyUsername'));
const contentType = 'application/x-www-form-urlencoded';
const headers = {
'Content-Type': contentType,

View File

@ -336,10 +336,14 @@ export default class MenuUiHandler extends MessageUiHandler {
case Button.UP:
if (this.cursor)
success = this.setCursor(this.cursor - 1);
else
success = this.setCursor(this.menuOptions.length - 1);
break;
case Button.DOWN:
if (this.cursor + 1 < this.menuOptions.length)
success = this.setCursor(this.cursor + 1);
else
success = this.setCursor(0);
break;
}
}

View File

@ -3,14 +3,15 @@ import { ModalConfig } from "./modal-ui-handler";
import * as Utils from "../utils";
import { Mode } from "./ui";
import { TextStyle, addTextObject } from "./text";
import i18next from '../plugins/i18n';
export default class RegistrationFormUiHandler extends FormModalUiHandler {
getModalTitle(config?: ModalConfig): string {
return 'Register';
return i18next.t('menu:register');
}
getFields(config?: ModalConfig): string[] {
return [ 'Username', 'Password', 'Confirm Password' ];
return [ i18next.t('menu:username'), i18next.t('menu:password'), i18next.t('menu:confirmPassword') ];
}
getWidth(config?: ModalConfig): number {
@ -26,7 +27,7 @@ export default class RegistrationFormUiHandler extends FormModalUiHandler {
}
getButtonLabels(config?: ModalConfig): string[] {
return [ 'Register', 'Back to Login' ];
return [ i18next.t('menu:register'), i18next.t('menu:backToLogin') ];
}
getReadableErrorMessage(error: string): string {
@ -35,11 +36,11 @@ export default class RegistrationFormUiHandler extends FormModalUiHandler {
error = error.slice(0, colonIndex);
switch (error) {
case 'invalid username':
return 'Username must only contain letters, numbers, or underscores';
return i18next.t('menu:invalidRegisterUsername');
case 'invalid password':
return 'Password must be 6 characters or longer';
return i18next.t('menu:invalidRegisterPassword');
case 'failed to add account record':
return 'The provided username is already in use';
return i18next.t('menu:usernameAlreadyUsed');
}
return super.getReadableErrorMessage(error);
@ -48,7 +49,7 @@ export default class RegistrationFormUiHandler extends FormModalUiHandler {
setup(): void {
super.setup();
const label = addTextObject(this.scene, 10, 87, 'By registering, you confirm you are of 13 years of age or older.', TextStyle.TOOLTIP_CONTENT, { fontSize: '42px' });
const label = addTextObject(this.scene, 10, 87, i18next.t('menu:registrationAgeWarning'), TextStyle.TOOLTIP_CONTENT, { fontSize: '42px' });
this.modalContainer.add(label);
}
@ -68,11 +69,11 @@ export default class RegistrationFormUiHandler extends FormModalUiHandler {
this.scene.ui.playError();
};
if (!this.inputs[0].text)
return onFail('Username must not be empty');
return onFail(i18next.t('menu:emptyUsername'));
if (!this.inputs[1].text)
return onFail(this.getReadableErrorMessage('invalid password'));
if (this.inputs[1].text !== this.inputs[2].text)
return onFail('Password must match confirm password');
return onFail(i18next.t('menu:passwordNotMatchingConfirmPassword'));
const contentType = 'application/x-www-form-urlencoded';
const headers = {
'Content-Type': contentType,

View File

@ -0,0 +1,47 @@
import BattleScene from "../battle-scene";
import { ModalConfig, ModalUiHandler } from "./modal-ui-handler";
import { addTextObject, TextStyle } from "./text";
import { Mode } from "./ui";
export default class SessionReloadModalUiHandler extends ModalUiHandler {
constructor(scene: BattleScene, mode?: Mode) {
super(scene, mode);
}
getModalTitle(): string {
return '';
}
getWidth(): number {
return 160;
}
getHeight(): number {
return 32;
}
getMargin(): [number, number, number, number] {
return [ 0, 0, 48, 0 ];
}
getButtonLabels(): string[] {
return [ ];
}
setup(): void {
super.setup();
const label = addTextObject(this.scene, this.getWidth() / 2, this.getHeight() / 2, 'Your session is out of date.\nYour data will be reloaded…', TextStyle.WINDOW, { fontSize: '48px', align: 'center' });
label.setOrigin(0.5, 0.5);
this.modalContainer.add(label);
}
show(args: any[]): boolean {
const config: ModalConfig = {
buttonActions: []
};
return super.show([ config ]);
}
}

View File

@ -34,6 +34,7 @@ import TitleUiHandler from './title-ui-handler';
import SavingIconHandler from './saving-icon-handler';
import UnavailableModalUiHandler from './unavailable-modal-ui-handler';
import OutdatedModalUiHandler from './outdated-modal-ui-handler';
import SessionReloadModalUiHandler from './session-reload-modal-ui-handler';
export enum Mode {
MESSAGE,
@ -62,6 +63,7 @@ export enum Mode {
LOGIN_FORM,
REGISTRATION_FORM,
LOADING,
SESSION_RELOAD,
UNAVAILABLE,
OUTDATED
};
@ -90,6 +92,7 @@ const noTransitionModes = [
Mode.LOGIN_FORM,
Mode.REGISTRATION_FORM,
Mode.LOADING,
Mode.SESSION_RELOAD,
Mode.UNAVAILABLE,
Mode.OUTDATED
];
@ -141,6 +144,7 @@ export default class UI extends Phaser.GameObjects.Container {
new LoginFormUiHandler(scene),
new RegistrationFormUiHandler(scene),
new LoadingModalUiHandler(scene),
new SessionReloadModalUiHandler(scene),
new UnavailableModalUiHandler(scene),
new OutdatedModalUiHandler(scene)
];