mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-21 14:59:26 +02:00
Merge remote-tracking branch 'origin/beta' into ability/unburden
This commit is contained in:
commit
1632a52449
@ -1,6 +1,6 @@
|
|||||||
VITE_BYPASS_LOGIN=0
|
VITE_BYPASS_LOGIN=0
|
||||||
VITE_BYPASS_TUTORIAL=0
|
VITE_BYPASS_TUTORIAL=0
|
||||||
VITE_SERVER_URL=https://api.beta.pokerogue.net
|
VITE_SERVER_URL=https://apibeta.pokerogue.net
|
||||||
VITE_DISCORD_CLIENT_ID=1248062921129459756
|
VITE_DISCORD_CLIENT_ID=1248062921129459756
|
||||||
VITE_GOOGLE_CLIENT_ID=955345393540-2k6lfftf0fdnb0krqmpthjnqavfvvf73.apps.googleusercontent.com
|
VITE_GOOGLE_CLIENT_ID=955345393540-2k6lfftf0fdnb0krqmpthjnqavfvvf73.apps.googleusercontent.com
|
||||||
VITE_I18N_DEBUG=1
|
VITE_I18N_DEBUG=1
|
||||||
|
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@ -1 +1 @@
|
|||||||
github: patapancakes
|
github: pagefaultgames
|
||||||
|
43
package-lock.json
generated
43
package-lock.json
generated
@ -37,7 +37,7 @@
|
|||||||
"typedoc": "^0.26.4",
|
"typedoc": "^0.26.4",
|
||||||
"typescript": "^5.5.3",
|
"typescript": "^5.5.3",
|
||||||
"typescript-eslint": "^8.0.0-alpha.54",
|
"typescript-eslint": "^8.0.0-alpha.54",
|
||||||
"vite": "^5.3.5",
|
"vite": "^5.4.8",
|
||||||
"vite-tsconfig-paths": "^4.3.2",
|
"vite-tsconfig-paths": "^4.3.2",
|
||||||
"vitest": "^2.0.4",
|
"vitest": "^2.0.4",
|
||||||
"vitest-canvas-mock": "^0.3.3"
|
"vitest-canvas-mock": "^0.3.3"
|
||||||
@ -3650,7 +3650,6 @@
|
|||||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
@ -5042,7 +5041,6 @@
|
|||||||
"url": "https://github.com/sponsors/ai"
|
"url": "https://github.com/sponsors/ai"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"nanoid": "bin/nanoid.cjs"
|
"nanoid": "bin/nanoid.cjs"
|
||||||
},
|
},
|
||||||
@ -5441,9 +5439,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.39",
|
"version": "8.4.47",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
|
||||||
"integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==",
|
"integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -5459,16 +5457,21 @@
|
|||||||
"url": "https://github.com/sponsors/ai"
|
"url": "https://github.com/sponsors/ai"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.7",
|
"nanoid": "^3.3.7",
|
||||||
"picocolors": "^1.0.1",
|
"picocolors": "^1.1.0",
|
||||||
"source-map-js": "^1.2.0"
|
"source-map-js": "^1.2.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^10 || ^12 || >=14"
|
"node": "^10 || ^12 || >=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/postcss/node_modules/picocolors": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/prelude-ls": {
|
"node_modules/prelude-ls": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||||
@ -5865,11 +5868,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/source-map-js": {
|
"node_modules/source-map-js": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||||
"integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
|
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-3-Clause",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@ -6469,15 +6471,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "5.3.5",
|
"version": "5.4.8",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz",
|
||||||
"integrity": "sha512-MdjglKR6AQXQb9JGiS7Rc2wC6uMjcm7Go/NHNO63EwiJXfuk9PgqiP/n5IDJCziMkfw9n4Ubp7lttNwz+8ZVKA==",
|
"integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.21.3",
|
"esbuild": "^0.21.3",
|
||||||
"postcss": "^8.4.39",
|
"postcss": "^8.4.43",
|
||||||
"rollup": "^4.13.0"
|
"rollup": "^4.20.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"vite": "bin/vite.js"
|
"vite": "bin/vite.js"
|
||||||
@ -6496,6 +6497,7 @@
|
|||||||
"less": "*",
|
"less": "*",
|
||||||
"lightningcss": "^1.21.0",
|
"lightningcss": "^1.21.0",
|
||||||
"sass": "*",
|
"sass": "*",
|
||||||
|
"sass-embedded": "*",
|
||||||
"stylus": "*",
|
"stylus": "*",
|
||||||
"sugarss": "*",
|
"sugarss": "*",
|
||||||
"terser": "^5.4.0"
|
"terser": "^5.4.0"
|
||||||
@ -6513,6 +6515,9 @@
|
|||||||
"sass": {
|
"sass": {
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
"sass-embedded": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"stylus": {
|
"stylus": {
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
"typedoc": "^0.26.4",
|
"typedoc": "^0.26.4",
|
||||||
"typescript": "^5.5.3",
|
"typescript": "^5.5.3",
|
||||||
"typescript-eslint": "^8.0.0-alpha.54",
|
"typescript-eslint": "^8.0.0-alpha.54",
|
||||||
"vite": "^5.3.5",
|
"vite": "^5.4.8",
|
||||||
"vite-tsconfig-paths": "^4.3.2",
|
"vite-tsconfig-paths": "^4.3.2",
|
||||||
"vitest": "^2.0.4",
|
"vitest": "^2.0.4",
|
||||||
"vitest-canvas-mock": "^0.3.3"
|
"vitest-canvas-mock": "^0.3.3"
|
||||||
|
@ -1040,10 +1040,6 @@ export default class BattleScene extends SceneBase {
|
|||||||
|
|
||||||
this.gameMode = getGameMode(GameModes.CLASSIC);
|
this.gameMode = getGameMode(GameModes.CLASSIC);
|
||||||
|
|
||||||
this.setSeed(Overrides.SEED_OVERRIDE || Utils.randomString(24));
|
|
||||||
console.log("Seed:", this.seed);
|
|
||||||
this.resetSeed(); // Properly resets RNG after saving and quitting a session
|
|
||||||
|
|
||||||
this.disableMenu = false;
|
this.disableMenu = false;
|
||||||
|
|
||||||
this.score = 0;
|
this.score = 0;
|
||||||
@ -1078,6 +1074,12 @@ export default class BattleScene extends SceneBase {
|
|||||||
//@ts-ignore - allowing `null` for currentBattle causes a lot of trouble
|
//@ts-ignore - allowing `null` for currentBattle causes a lot of trouble
|
||||||
this.currentBattle = null; // TODO: resolve ts-ignore
|
this.currentBattle = null; // TODO: resolve ts-ignore
|
||||||
|
|
||||||
|
// Reset RNG after end of game or save & quit.
|
||||||
|
// This needs to happen after clearing this.currentBattle or the seed will be affected by the last wave played
|
||||||
|
this.setSeed(Overrides.SEED_OVERRIDE || Utils.randomString(24));
|
||||||
|
console.log("Seed:", this.seed);
|
||||||
|
this.resetSeed();
|
||||||
|
|
||||||
this.biomeWaveText.setText(startingWave.toString());
|
this.biomeWaveText.setText(startingWave.toString());
|
||||||
this.biomeWaveText.setVisible(false);
|
this.biomeWaveText.setVisible(false);
|
||||||
|
|
||||||
@ -3091,11 +3093,6 @@ export default class BattleScene extends SceneBase {
|
|||||||
private isWaveMysteryEncounter(newBattleType: BattleType, waveIndex: number, sessionDataEncounterType?: MysteryEncounterType): boolean {
|
private isWaveMysteryEncounter(newBattleType: BattleType, waveIndex: number, sessionDataEncounterType?: MysteryEncounterType): boolean {
|
||||||
const [lowestMysteryEncounterWave, highestMysteryEncounterWave] = this.gameMode.getMysteryEncounterLegalWaves();
|
const [lowestMysteryEncounterWave, highestMysteryEncounterWave] = this.gameMode.getMysteryEncounterLegalWaves();
|
||||||
if (this.gameMode.hasMysteryEncounters && newBattleType === BattleType.WILD && !this.gameMode.isBoss(waveIndex) && waveIndex < highestMysteryEncounterWave && waveIndex > lowestMysteryEncounterWave) {
|
if (this.gameMode.hasMysteryEncounters && newBattleType === BattleType.WILD && !this.gameMode.isBoss(waveIndex) && waveIndex < highestMysteryEncounterWave && waveIndex > lowestMysteryEncounterWave) {
|
||||||
// If ME type is already defined in session data, no need to roll RNG check
|
|
||||||
if (!isNullOrUndefined(sessionDataEncounterType)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Base spawn weight is BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT/256, and increases by WEIGHT_INCREMENT_ON_SPAWN_MISS/256 for each missed attempt at spawning an encounter on a valid floor
|
// Base spawn weight is BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT/256, and increases by WEIGHT_INCREMENT_ON_SPAWN_MISS/256 for each missed attempt at spawning an encounter on a valid floor
|
||||||
const sessionEncounterRate = this.mysteryEncounterSaveData.encounterSpawnChance;
|
const sessionEncounterRate = this.mysteryEncounterSaveData.encounterSpawnChance;
|
||||||
const encounteredEvents = this.mysteryEncounterSaveData.encounteredEvents;
|
const encounteredEvents = this.mysteryEncounterSaveData.encounteredEvents;
|
||||||
|
@ -497,7 +497,7 @@ function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], rand
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 1/3 chance for evil team grunts to be double battles */
|
/* 1/3 chance for evil team grunts to be double battles */
|
||||||
const evilTeamGrunts = [TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT];
|
const evilTeamGrunts = [TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT, TrainerType.AETHER_GRUNT, TrainerType.SKULL_GRUNT, TrainerType.MACRO_GRUNT, TrainerType.STAR_GRUNT];
|
||||||
const isEvilTeamGrunt = evilTeamGrunts.includes(trainerTypes[rand]);
|
const isEvilTeamGrunt = evilTeamGrunts.includes(trainerTypes[rand]);
|
||||||
|
|
||||||
if (trainerConfigs[trainerTypes[rand]].hasDouble && isEvilTeamGrunt) {
|
if (trainerConfigs[trainerTypes[rand]].hasDouble && isEvilTeamGrunt) {
|
||||||
|
@ -4,7 +4,7 @@ import { Constructor } from "#app/utils";
|
|||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import { getPokemonNameWithAffix } from "../messages";
|
import { getPokemonNameWithAffix } from "../messages";
|
||||||
import { Weather, WeatherType } from "./weather";
|
import { Weather, WeatherType } from "./weather";
|
||||||
import { BattlerTag, GroundedTag, GulpMissileTag, SemiInvulnerableTag } from "./battler-tags";
|
import { BattlerTag, GroundedTag } from "./battler-tags";
|
||||||
import { StatusEffect, getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect";
|
import { StatusEffect, getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect";
|
||||||
import { Gender } from "./gender";
|
import { Gender } from "./gender";
|
||||||
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, MoveAttr, MultiHitAttr, ChargeAttr, SacrificialAttr, SacrificialAttrOnHit, NeutralDamageAgainstFlyingTypeMultiplierAttr, FixedDamageAttr } from "./move";
|
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, MoveAttr, MultiHitAttr, ChargeAttr, SacrificialAttr, SacrificialAttrOnHit, NeutralDamageAgainstFlyingTypeMultiplierAttr, FixedDamageAttr } from "./move";
|
||||||
@ -123,6 +123,7 @@ export class Ability implements Localizable {
|
|||||||
type AbAttrApplyFunc<TAttr extends AbAttr> = (attr: TAttr, passive: boolean) => boolean | Promise<boolean>;
|
type AbAttrApplyFunc<TAttr extends AbAttr> = (attr: TAttr, passive: boolean) => boolean | Promise<boolean>;
|
||||||
type AbAttrCondition = (pokemon: Pokemon) => boolean;
|
type AbAttrCondition = (pokemon: Pokemon) => boolean;
|
||||||
|
|
||||||
|
// TODO: Can this be improved?
|
||||||
type PokemonAttackCondition = (user: Pokemon | null, target: Pokemon | null, move: Move) => boolean;
|
type PokemonAttackCondition = (user: Pokemon | null, target: Pokemon | null, move: Move) => boolean;
|
||||||
type PokemonDefendCondition = (target: Pokemon, user: Pokemon, move: Move) => boolean;
|
type PokemonDefendCondition = (target: Pokemon, user: Pokemon, move: Move) => boolean;
|
||||||
type PokemonStatStageChangeCondition = (target: Pokemon, statsChanged: BattleStat[], stages: number) => boolean;
|
type PokemonStatStageChangeCondition = (target: Pokemon, statsChanged: BattleStat[], stages: number) => boolean;
|
||||||
@ -536,53 +537,6 @@ export class PostDefendAbAttr extends AbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies the effects of Gulp Missile when the user is hit by an attack.
|
|
||||||
* @extends PostDefendAbAttr
|
|
||||||
*/
|
|
||||||
export class PostDefendGulpMissileAbAttr extends PostDefendAbAttr {
|
|
||||||
constructor() {
|
|
||||||
super(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Damages the attacker and triggers the secondary effect based on the form or the BattlerTagType.
|
|
||||||
* @param {Pokemon} pokemon - The defending Pokemon.
|
|
||||||
* @param passive - n/a
|
|
||||||
* @param {Pokemon} attacker - The attacking Pokemon.
|
|
||||||
* @param {Move} move - The move being used.
|
|
||||||
* @param {HitResult} hitResult - n/a
|
|
||||||
* @param {any[]} args - n/a
|
|
||||||
* @returns Whether the effects of the ability are applied.
|
|
||||||
*/
|
|
||||||
applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean | Promise<boolean> {
|
|
||||||
const battlerTag = pokemon.getTag(GulpMissileTag);
|
|
||||||
if (!battlerTag || move.category === MoveCategory.STATUS || pokemon.getTag(SemiInvulnerableTag)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (simulated) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cancelled = new Utils.BooleanHolder(false);
|
|
||||||
applyAbAttrs(BlockNonDirectDamageAbAttr, attacker, cancelled);
|
|
||||||
|
|
||||||
if (!cancelled.value) {
|
|
||||||
attacker.damageAndUpdate(Math.max(1, Math.floor(attacker.getMaxHp() / 4)), HitResult.OTHER);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (battlerTag.tagType === BattlerTagType.GULP_MISSILE_ARROKUDA) {
|
|
||||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, attacker.getBattlerIndex(), false, [ Stat.DEF ], -1));
|
|
||||||
} else {
|
|
||||||
attacker.trySetStatus(StatusEffect.PARALYSIS, true, pokemon);
|
|
||||||
}
|
|
||||||
|
|
||||||
pokemon.removeTag(battlerTag.tagType);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class FieldPriorityMoveImmunityAbAttr extends PreDefendAbAttr {
|
export class FieldPriorityMoveImmunityAbAttr extends PreDefendAbAttr {
|
||||||
applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||||
const attackPriority = new Utils.IntegerHolder(move.priority);
|
const attackPriority = new Utils.IntegerHolder(move.priority);
|
||||||
@ -2481,7 +2435,7 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr {
|
|||||||
pokemon.setStatStage(s, target.getStatStage(s));
|
pokemon.setStatStage(s, target.getStatStage(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
pokemon.summonData.moveset = target.getMoveset().map(m => new PokemonMove(m!.moveId, m!.ppUsed, m!.ppUp)); // TODO: are those bangs correct?
|
pokemon.summonData.moveset = target.getMoveset().map(m => new PokemonMove(m?.moveId ?? Moves.NONE, m?.ppUsed, m?.ppUp));
|
||||||
pokemon.summonData.types = target.getTypes();
|
pokemon.summonData.types = target.getTypes();
|
||||||
|
|
||||||
|
|
||||||
@ -3201,12 +3155,12 @@ export class ForewarnAbAttr extends PostSummonAbAttr {
|
|||||||
} else if (move?.getMove().power === -1) {
|
} else if (move?.getMove().power === -1) {
|
||||||
movePower = 80;
|
movePower = 80;
|
||||||
} else {
|
} else {
|
||||||
movePower = move!.getMove().power; // TODO: is this bang correct?
|
movePower = move?.getMove().power ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (movePower > maxPowerSeen) {
|
if (movePower > maxPowerSeen) {
|
||||||
maxPowerSeen = movePower;
|
maxPowerSeen = movePower;
|
||||||
maxMove = move!.getName(); // TODO: is this bang correct?
|
maxMove = move?.getName() ?? "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5300,8 +5254,7 @@ export function initAbilities() {
|
|||||||
.attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => i18next.t("abilityTriggers:postSummonMoldBreaker", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }))
|
.attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => i18next.t("abilityTriggers:postSummonMoldBreaker", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }))
|
||||||
.attr(MoveAbilityBypassAbAttr),
|
.attr(MoveAbilityBypassAbAttr),
|
||||||
new Ability(Abilities.SUPER_LUCK, 4)
|
new Ability(Abilities.SUPER_LUCK, 4)
|
||||||
.attr(BonusCritAbAttr)
|
.attr(BonusCritAbAttr),
|
||||||
.partial(),
|
|
||||||
new Ability(Abilities.AFTERMATH, 4)
|
new Ability(Abilities.AFTERMATH, 4)
|
||||||
.attr(PostFaintContactDamageAbAttr, 4)
|
.attr(PostFaintContactDamageAbAttr, 4)
|
||||||
.bypassFaint(),
|
.bypassFaint(),
|
||||||
@ -5313,8 +5266,7 @@ export function initAbilities() {
|
|||||||
.attr(IgnoreOpponentStatStagesAbAttr)
|
.attr(IgnoreOpponentStatStagesAbAttr)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.TINTED_LENS, 4)
|
new Ability(Abilities.TINTED_LENS, 4)
|
||||||
//@ts-ignore
|
.attr(DamageBoostAbAttr, 2, (user, target, move) => (target?.getMoveEffectiveness(user!, move) ?? 1) <= 0.5),
|
||||||
.attr(DamageBoostAbAttr, 2, (user, target, move) => target?.getMoveEffectiveness(user, move) <= 0.5), // TODO: fix TS issues
|
|
||||||
new Ability(Abilities.FILTER, 4)
|
new Ability(Abilities.FILTER, 4)
|
||||||
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => target.getMoveEffectiveness(user, move) >= 2, 0.75)
|
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => target.getMoveEffectiveness(user, move) >= 2, 0.75)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
@ -5432,8 +5384,9 @@ export function initAbilities() {
|
|||||||
.attr(WonderSkinAbAttr)
|
.attr(WonderSkinAbAttr)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.ANALYTIC, 5)
|
new Ability(Abilities.ANALYTIC, 5)
|
||||||
//@ts-ignore
|
.attr(MovePowerBoostAbAttr, (user, target, move) =>
|
||||||
.attr(MovePowerBoostAbAttr, (user, target, move) => !!target?.getLastXMoves(1).find(m => m.turn === target?.scene.currentBattle.turn) || user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command !== Command.FIGHT, 1.3), // TODO fix TS issues
|
!!target?.getLastXMoves(1).find(m => m.turn === target?.scene.currentBattle.turn)
|
||||||
|
|| user?.scene.currentBattle.turnCommands[target?.getBattlerIndex() ?? BattlerIndex.ATTACKER]?.command !== Command.FIGHT, 1.3),
|
||||||
new Ability(Abilities.ILLUSION, 5)
|
new Ability(Abilities.ILLUSION, 5)
|
||||||
.attr(UncopiableAbilityAbAttr)
|
.attr(UncopiableAbilityAbAttr)
|
||||||
.attr(UnswappableAbilityAbAttr)
|
.attr(UnswappableAbilityAbAttr)
|
||||||
@ -5598,8 +5551,7 @@ export function initAbilities() {
|
|||||||
.bypassFaint()
|
.bypassFaint()
|
||||||
.partial(),
|
.partial(),
|
||||||
new Ability(Abilities.STAKEOUT, 7)
|
new Ability(Abilities.STAKEOUT, 7)
|
||||||
//@ts-ignore
|
.attr(MovePowerBoostAbAttr, (user, target, move) => user?.scene.currentBattle.turnCommands[target?.getBattlerIndex() ?? BattlerIndex.ATTACKER]?.command === Command.POKEMON, 2),
|
||||||
.attr(MovePowerBoostAbAttr, (user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.POKEMON, 2), // TODO: fix TS issues
|
|
||||||
new Ability(Abilities.WATER_BUBBLE, 7)
|
new Ability(Abilities.WATER_BUBBLE, 7)
|
||||||
.attr(ReceivedTypeDamageMultiplierAbAttr, Type.FIRE, 0.5)
|
.attr(ReceivedTypeDamageMultiplierAbAttr, Type.FIRE, 0.5)
|
||||||
.attr(MoveTypePowerBoostAbAttr, Type.WATER, 2)
|
.attr(MoveTypePowerBoostAbAttr, Type.WATER, 2)
|
||||||
@ -5737,8 +5689,7 @@ export function initAbilities() {
|
|||||||
new Ability(Abilities.PRISM_ARMOR, 7)
|
new Ability(Abilities.PRISM_ARMOR, 7)
|
||||||
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => target.getMoveEffectiveness(user, move) >= 2, 0.75),
|
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => target.getMoveEffectiveness(user, move) >= 2, 0.75),
|
||||||
new Ability(Abilities.NEUROFORCE, 7)
|
new Ability(Abilities.NEUROFORCE, 7)
|
||||||
//@ts-ignore
|
.attr(MovePowerBoostAbAttr, (user, target, move) => (target?.getMoveEffectiveness(user!, move) ?? 1) >= 2, 1.25),
|
||||||
.attr(MovePowerBoostAbAttr, (user, target, move) => target?.getMoveEffectiveness(user, move) >= 2, 1.25), // TODO: fix TS issues
|
|
||||||
new Ability(Abilities.INTREPID_SWORD, 8)
|
new Ability(Abilities.INTREPID_SWORD, 8)
|
||||||
.attr(PostSummonStatStageChangeAbAttr, [ Stat.ATK ], 1, true)
|
.attr(PostSummonStatStageChangeAbAttr, [ Stat.ATK ], 1, true)
|
||||||
.condition(getOncePerBattleCondition(Abilities.INTREPID_SWORD)),
|
.condition(getOncePerBattleCondition(Abilities.INTREPID_SWORD)),
|
||||||
@ -5759,13 +5710,19 @@ export function initAbilities() {
|
|||||||
new Ability(Abilities.MIRROR_ARMOR, 8)
|
new Ability(Abilities.MIRROR_ARMOR, 8)
|
||||||
.ignorable()
|
.ignorable()
|
||||||
.unimplemented(),
|
.unimplemented(),
|
||||||
|
/**
|
||||||
|
* Right now, the logic is attached to Surf and Dive moves. Ideally, the post-defend/hit should be an
|
||||||
|
* ability attribute but the current implementation of move effects for BattlerTag does not support this- in the case
|
||||||
|
* where Cramorant is fainted.
|
||||||
|
* @see {@linkcode GulpMissileTagAttr} and {@linkcode GulpMissileTag} for Gulp Missile implementation
|
||||||
|
*/
|
||||||
new Ability(Abilities.GULP_MISSILE, 8)
|
new Ability(Abilities.GULP_MISSILE, 8)
|
||||||
.attr(UnsuppressableAbilityAbAttr)
|
.attr(UnsuppressableAbilityAbAttr)
|
||||||
.attr(NoTransformAbilityAbAttr)
|
.attr(NoTransformAbilityAbAttr)
|
||||||
.attr(NoFusionAbilityAbAttr)
|
.attr(NoFusionAbilityAbAttr)
|
||||||
.attr(UncopiableAbilityAbAttr)
|
.attr(UncopiableAbilityAbAttr)
|
||||||
.attr(UnswappableAbilityAbAttr)
|
.attr(UnswappableAbilityAbAttr)
|
||||||
.attr(PostDefendGulpMissileAbAttr),
|
.bypassFaint(),
|
||||||
new Ability(Abilities.STALWART, 8)
|
new Ability(Abilities.STALWART, 8)
|
||||||
.attr(BlockRedirectAbAttr),
|
.attr(BlockRedirectAbAttr),
|
||||||
new Ability(Abilities.STEAM_ENGINE, 8)
|
new Ability(Abilities.STEAM_ENGINE, 8)
|
||||||
@ -5830,10 +5787,8 @@ export function initAbilities() {
|
|||||||
.attr(UserFieldStatusEffectImmunityAbAttr, StatusEffect.POISON, StatusEffect.TOXIC)
|
.attr(UserFieldStatusEffectImmunityAbAttr, StatusEffect.POISON, StatusEffect.TOXIC)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.HUNGER_SWITCH, 8)
|
new Ability(Abilities.HUNGER_SWITCH, 8)
|
||||||
//@ts-ignore
|
.attr(PostTurnFormChangeAbAttr, p => p.getFormKey() ? 0 : 1)
|
||||||
.attr(PostTurnFormChangeAbAttr, p => p.getFormKey ? 0 : 1) // TODO: fix ts-ignore
|
.attr(PostTurnFormChangeAbAttr, p => p.getFormKey() ? 1 : 0)
|
||||||
//@ts-ignore
|
|
||||||
.attr(PostTurnFormChangeAbAttr, p => p.getFormKey ? 1 : 0) // TODO: fix ts-ignore
|
|
||||||
.attr(UncopiableAbilityAbAttr)
|
.attr(UncopiableAbilityAbAttr)
|
||||||
.attr(UnswappableAbilityAbAttr)
|
.attr(UnswappableAbilityAbAttr)
|
||||||
.attr(NoTransformAbilityAbAttr)
|
.attr(NoTransformAbilityAbAttr)
|
||||||
|
@ -511,6 +511,39 @@ class WaterSportTag extends WeakenMoveTypeTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arena Tag class for the secondary effect of {@link https://bulbapedia.bulbagarden.net/wiki/Plasma_Fists_(move) | Plasma Fists}.
|
||||||
|
* Converts Normal-type moves to Electric type for the rest of the turn.
|
||||||
|
*/
|
||||||
|
export class PlasmaFistsTag extends ArenaTag {
|
||||||
|
constructor() {
|
||||||
|
super(ArenaTagType.PLASMA_FISTS, 1, Moves.PLASMA_FISTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Queues Plasma Fists' on-add message */
|
||||||
|
onAdd(arena: Arena): void {
|
||||||
|
arena.scene.queueMessage(i18next.t("arenaTag:plasmaFistsOnAdd"));
|
||||||
|
}
|
||||||
|
|
||||||
|
onRemove(arena: Arena): void { } // Removes default on-remove message
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts Normal-type moves to Electric type
|
||||||
|
* @param arena n/a
|
||||||
|
* @param args
|
||||||
|
* - `[0]` {@linkcode Utils.NumberHolder} A container with a move's {@linkcode Type}
|
||||||
|
* @returns `true` if the given move type changed; `false` otherwise.
|
||||||
|
*/
|
||||||
|
apply(arena: Arena, args: any[]): boolean {
|
||||||
|
const moveType = args[0];
|
||||||
|
if (moveType instanceof Utils.NumberHolder && moveType.value === Type.NORMAL) {
|
||||||
|
moveType.value = Type.ELECTRIC;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class to implement arena traps.
|
* Abstract class to implement arena traps.
|
||||||
*/
|
*/
|
||||||
@ -1010,6 +1043,8 @@ export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMov
|
|||||||
return new MudSportTag(turnCount, sourceId);
|
return new MudSportTag(turnCount, sourceId);
|
||||||
case ArenaTagType.WATER_SPORT:
|
case ArenaTagType.WATER_SPORT:
|
||||||
return new WaterSportTag(turnCount, sourceId);
|
return new WaterSportTag(turnCount, sourceId);
|
||||||
|
case ArenaTagType.PLASMA_FISTS:
|
||||||
|
return new PlasmaFistsTag();
|
||||||
case ArenaTagType.SPIKES:
|
case ArenaTagType.SPIKES:
|
||||||
return new SpikesTag(sourceId, side);
|
return new SpikesTag(sourceId, side);
|
||||||
case ArenaTagType.TOXIC_SPIKES:
|
case ArenaTagType.TOXIC_SPIKES:
|
||||||
|
@ -2123,7 +2123,36 @@ export class StockpilingTag extends BattlerTag {
|
|||||||
*/
|
*/
|
||||||
export class GulpMissileTag extends BattlerTag {
|
export class GulpMissileTag extends BattlerTag {
|
||||||
constructor(tagType: BattlerTagType, sourceMove: Moves) {
|
constructor(tagType: BattlerTagType, sourceMove: Moves) {
|
||||||
super(tagType, BattlerTagLapseType.CUSTOM, 0, sourceMove);
|
super(tagType, BattlerTagLapseType.HIT, 0, sourceMove);
|
||||||
|
}
|
||||||
|
|
||||||
|
override lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
|
if (pokemon.getTag(BattlerTagType.UNDERWATER)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const moveEffectPhase = pokemon.scene.getCurrentPhase();
|
||||||
|
if (moveEffectPhase instanceof MoveEffectPhase) {
|
||||||
|
const attacker = moveEffectPhase.getUserPokemon();
|
||||||
|
|
||||||
|
if (!attacker) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cancelled = new Utils.BooleanHolder(false);
|
||||||
|
applyAbAttrs(BlockNonDirectDamageAbAttr, attacker, cancelled);
|
||||||
|
|
||||||
|
if (!cancelled.value) {
|
||||||
|
attacker.damageAndUpdate(Math.max(1, Math.floor(attacker.getMaxHp() / 4)), HitResult.OTHER);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.tagType === BattlerTagType.GULP_MISSILE_ARROKUDA) {
|
||||||
|
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, attacker.getBattlerIndex(), false, [ Stat.DEF ], -1));
|
||||||
|
} else {
|
||||||
|
attacker.trySetStatus(StatusEffect.PARALYSIS, true, pokemon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2589,6 +2618,43 @@ export class ImprisonTag extends MoveRestrictionBattlerTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Battler Tag that applies the effects of Syrup Bomb to the target Pokemon.
|
||||||
|
* For three turns, starting from the turn of hit, at the end of each turn, the target Pokemon's speed will decrease by 1.
|
||||||
|
* The tag can also expire by taking the target Pokemon off the field.
|
||||||
|
*/
|
||||||
|
export class SyrupBombTag extends BattlerTag {
|
||||||
|
constructor() {
|
||||||
|
super(BattlerTagType.SYRUP_BOMB, BattlerTagLapseType.TURN_END, 3, Moves.SYRUP_BOMB);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the Syrup Bomb battler tag to the target Pokemon.
|
||||||
|
* @param {Pokemon} pokemon the target Pokemon
|
||||||
|
*/
|
||||||
|
override onAdd(pokemon: Pokemon) {
|
||||||
|
super.onAdd(pokemon);
|
||||||
|
pokemon.scene.queueMessage(i18next.t("battlerTags:syrupBombOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the single-stage speed down to the target Pokemon and decrements the tag's turn count
|
||||||
|
* @param {Pokemon} pokemon the target Pokemon
|
||||||
|
* @param {BattlerTagLapseType} _lapseType
|
||||||
|
* @returns `true` if the turnCount is still greater than 0 | `false` if the turnCount is 0 or the target Pokemon has been removed from the field
|
||||||
|
*/
|
||||||
|
override lapse(pokemon: Pokemon, _lapseType: BattlerTagLapseType): boolean {
|
||||||
|
if (!pokemon.isActive(true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pokemon.scene.queueMessage(i18next.t("battlerTags:syrupBombLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })); // Custom message in lieu of an animation in mainline
|
||||||
|
pokemon.scene.unshiftPhase(new StatStageChangePhase(
|
||||||
|
pokemon.scene, pokemon.getBattlerIndex(), true,
|
||||||
|
[Stat.SPD], -1, true, false, true
|
||||||
|
));
|
||||||
|
return --this.turnCount > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a {@linkcode BattlerTag} based on the provided tag type, turn count, source move, and source ID.
|
* Retrieves a {@linkcode BattlerTag} based on the provided tag type, turn count, source move, and source ID.
|
||||||
@ -2763,6 +2829,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source
|
|||||||
return new TauntTag();
|
return new TauntTag();
|
||||||
case BattlerTagType.IMPRISON:
|
case BattlerTagType.IMPRISON:
|
||||||
return new ImprisonTag(sourceId);
|
return new ImprisonTag(sourceId);
|
||||||
|
case BattlerTagType.SYRUP_BOMB:
|
||||||
|
return new SyrupBombTag();
|
||||||
case BattlerTagType.NONE:
|
case BattlerTagType.NONE:
|
||||||
default:
|
default:
|
||||||
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
|
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
|
||||||
|
@ -81,7 +81,7 @@ export const speciesEggMoves = {
|
|||||||
[Species.LEDYBA]: [ Moves.POLLEN_PUFF, Moves.THIEF, Moves.PARTING_SHOT, Moves.SPORE ],
|
[Species.LEDYBA]: [ Moves.POLLEN_PUFF, Moves.THIEF, Moves.PARTING_SHOT, Moves.SPORE ],
|
||||||
[Species.SPINARAK]: [ Moves.PARTING_SHOT, Moves.ATTACK_ORDER, Moves.GASTRO_ACID, Moves.STRENGTH_SAP ],
|
[Species.SPINARAK]: [ Moves.PARTING_SHOT, Moves.ATTACK_ORDER, Moves.GASTRO_ACID, Moves.STRENGTH_SAP ],
|
||||||
[Species.CHINCHOU]: [ Moves.THUNDERCLAP, Moves.BOUNCY_BUBBLE, Moves.THUNDER_CAGE, Moves.TAIL_GLOW ],
|
[Species.CHINCHOU]: [ Moves.THUNDERCLAP, Moves.BOUNCY_BUBBLE, Moves.THUNDER_CAGE, Moves.TAIL_GLOW ],
|
||||||
[Species.PICHU]: [ Moves.MOONBLAST, Moves.WAVE_CRASH, Moves.AIR_SLASH, Moves.AURA_WHEEL ],
|
[Species.PICHU]: [ Moves.MOONBLAST, Moves.TRIPLE_AXEL, Moves.FIERY_DANCE, Moves.AURA_WHEEL ],
|
||||||
[Species.CLEFFA]: [ Moves.CALM_MIND, Moves.EARTH_POWER, Moves.WISH, Moves.LIGHT_OF_RUIN ],
|
[Species.CLEFFA]: [ Moves.CALM_MIND, Moves.EARTH_POWER, Moves.WISH, Moves.LIGHT_OF_RUIN ],
|
||||||
[Species.IGGLYBUFF]: [ Moves.DRAIN_PUNCH, Moves.GRAV_APPLE, Moves.SOFT_BOILED, Moves.EXTREME_SPEED ],
|
[Species.IGGLYBUFF]: [ Moves.DRAIN_PUNCH, Moves.GRAV_APPLE, Moves.SOFT_BOILED, Moves.EXTREME_SPEED ],
|
||||||
[Species.TOGEPI]: [ Moves.SCORCHING_SANDS, Moves.ROOST, Moves.RELIC_SONG, Moves.FIERY_DANCE ],
|
[Species.TOGEPI]: [ Moves.SCORCHING_SANDS, Moves.ROOST, Moves.RELIC_SONG, Moves.FIERY_DANCE ],
|
||||||
@ -195,7 +195,7 @@ export const speciesEggMoves = {
|
|||||||
[Species.REGISTEEL]: [ Moves.BODY_PRESS, Moves.SIZZLY_SLIDE, Moves.RECOVER, Moves.GIGATON_HAMMER ],
|
[Species.REGISTEEL]: [ Moves.BODY_PRESS, Moves.SIZZLY_SLIDE, Moves.RECOVER, Moves.GIGATON_HAMMER ],
|
||||||
[Species.LATIAS]: [ Moves.CORE_ENFORCER, Moves.FUSION_FLARE, Moves.SPARKLY_SWIRL, Moves.MYSTICAL_POWER ],
|
[Species.LATIAS]: [ Moves.CORE_ENFORCER, Moves.FUSION_FLARE, Moves.SPARKLY_SWIRL, Moves.MYSTICAL_POWER ],
|
||||||
[Species.LATIOS]: [ Moves.CORE_ENFORCER, Moves.BLUE_FLARE, Moves.NASTY_PLOT, Moves.TACHYON_CUTTER ],
|
[Species.LATIOS]: [ Moves.CORE_ENFORCER, Moves.BLUE_FLARE, Moves.NASTY_PLOT, Moves.TACHYON_CUTTER ],
|
||||||
[Species.KYOGRE]: [ Moves.RECOVER, Moves.HURRICANE, Moves.FLIP_TURN, Moves.WILDBOLT_STORM ],
|
[Species.KYOGRE]: [ Moves.RECOVER, Moves.HURRICANE, Moves.FREEZY_FROST, Moves.WILDBOLT_STORM ],
|
||||||
[Species.GROUDON]: [ Moves.STONE_AXE, Moves.SOLAR_BLADE, Moves.MORNING_SUN, Moves.SACRED_FIRE ],
|
[Species.GROUDON]: [ Moves.STONE_AXE, Moves.SOLAR_BLADE, Moves.MORNING_SUN, Moves.SACRED_FIRE ],
|
||||||
[Species.RAYQUAZA]: [ Moves.V_CREATE, Moves.DRAGON_DARTS, Moves.CORE_ENFORCER, Moves.OBLIVION_WING ],
|
[Species.RAYQUAZA]: [ Moves.V_CREATE, Moves.DRAGON_DARTS, Moves.CORE_ENFORCER, Moves.OBLIVION_WING ],
|
||||||
[Species.JIRACHI]: [ Moves.TACHYON_CUTTER, Moves.TRIPLE_ARROWS, Moves.ROCK_SLIDE, Moves.SHELL_SMASH ],
|
[Species.JIRACHI]: [ Moves.TACHYON_CUTTER, Moves.TRIPLE_ARROWS, Moves.ROCK_SLIDE, Moves.SHELL_SMASH ],
|
||||||
|
168
src/data/move.ts
168
src/data/move.ts
@ -341,7 +341,8 @@ export default class Move implements Localizable {
|
|||||||
* @returns `true` if the move can bypass the target's Substitute; `false` otherwise.
|
* @returns `true` if the move can bypass the target's Substitute; `false` otherwise.
|
||||||
*/
|
*/
|
||||||
hitsSubstitute(user: Pokemon, target: Pokemon | null): boolean {
|
hitsSubstitute(user: Pokemon, target: Pokemon | null): boolean {
|
||||||
if (this.moveTarget === MoveTarget.USER || !target?.getTag(BattlerTagType.SUBSTITUTE)) {
|
if ([MoveTarget.USER, MoveTarget.USER_SIDE, MoveTarget.ENEMY_SIDE, MoveTarget.BOTH_SIDES].includes(this.moveTarget)
|
||||||
|
|| !target?.getTag(BattlerTagType.SUBSTITUTE)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,220 +399,202 @@ export default class Move implements Localizable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@linkcode MoveFlags.MAKES_CONTACT} flag for the calling Move
|
* Sets the {@linkcode MoveFlags.MAKES_CONTACT} flag for the calling Move
|
||||||
* @param makesContact The value (boolean) to set the flag to
|
* @param setFlag Default `true`, set to `false` if the move doesn't make contact
|
||||||
|
* @see {@linkcode Abilities.STATIC}
|
||||||
* @returns The {@linkcode Move} that called this function
|
* @returns The {@linkcode Move} that called this function
|
||||||
*/
|
*/
|
||||||
makesContact(makesContact: boolean = true): this {
|
makesContact(setFlag: boolean = true): this {
|
||||||
this.setFlag(MoveFlags.MAKES_CONTACT, makesContact);
|
this.setFlag(MoveFlags.MAKES_CONTACT, setFlag);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@linkcode MoveFlags.IGNORE_PROTECT} flag for the calling Move
|
* Sets the {@linkcode MoveFlags.IGNORE_PROTECT} flag for the calling Move
|
||||||
* @param ignoresProtect The value (boolean) to set the flag to
|
* @see {@linkcode Moves.CURSE}
|
||||||
* example: @see {@linkcode Moves.CURSE}
|
|
||||||
* @returns The {@linkcode Move} that called this function
|
* @returns The {@linkcode Move} that called this function
|
||||||
*/
|
*/
|
||||||
ignoresProtect(ignoresProtect: boolean = true): this {
|
ignoresProtect(): this {
|
||||||
this.setFlag(MoveFlags.IGNORE_PROTECT, ignoresProtect);
|
this.setFlag(MoveFlags.IGNORE_PROTECT, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@linkcode MoveFlags.IGNORE_VIRTUAL} flag for the calling Move
|
* Sets the {@linkcode MoveFlags.IGNORE_VIRTUAL} flag for the calling Move
|
||||||
* @param ignoresVirtual The value (boolean) to set the flag to
|
* @see {@linkcode Moves.NATURE_POWER}
|
||||||
* example: @see {@linkcode Moves.NATURE_POWER}
|
|
||||||
* @returns The {@linkcode Move} that called this function
|
* @returns The {@linkcode Move} that called this function
|
||||||
*/
|
*/
|
||||||
ignoresVirtual(ignoresVirtual: boolean = true): this {
|
ignoresVirtual(): this {
|
||||||
this.setFlag(MoveFlags.IGNORE_VIRTUAL, ignoresVirtual);
|
this.setFlag(MoveFlags.IGNORE_VIRTUAL, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@linkcode MoveFlags.SOUND_BASED} flag for the calling Move
|
* Sets the {@linkcode MoveFlags.SOUND_BASED} flag for the calling Move
|
||||||
* @param soundBased The value (boolean) to set the flag to
|
* @see {@linkcode Moves.UPROAR}
|
||||||
* example: @see {@linkcode Moves.UPROAR}
|
|
||||||
* @returns The {@linkcode Move} that called this function
|
* @returns The {@linkcode Move} that called this function
|
||||||
*/
|
*/
|
||||||
soundBased(soundBased: boolean = true): this {
|
soundBased(): this {
|
||||||
this.setFlag(MoveFlags.SOUND_BASED, soundBased);
|
this.setFlag(MoveFlags.SOUND_BASED, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@linkcode MoveFlags.HIDE_USER} flag for the calling Move
|
* Sets the {@linkcode MoveFlags.HIDE_USER} flag for the calling Move
|
||||||
* @param hidesUser The value (boolean) to set the flag to
|
* @see {@linkcode Moves.TELEPORT}
|
||||||
* example: @see {@linkcode Moves.TELEPORT}
|
|
||||||
* @returns The {@linkcode Move} that called this function
|
* @returns The {@linkcode Move} that called this function
|
||||||
*/
|
*/
|
||||||
hidesUser(hidesUser: boolean = true): this {
|
hidesUser(): this {
|
||||||
this.setFlag(MoveFlags.HIDE_USER, hidesUser);
|
this.setFlag(MoveFlags.HIDE_USER, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@linkcode MoveFlags.HIDE_TARGET} flag for the calling Move
|
* Sets the {@linkcode MoveFlags.HIDE_TARGET} flag for the calling Move
|
||||||
* @param hidesTarget The value (boolean) to set the flag to
|
* @see {@linkcode Moves.WHIRLWIND}
|
||||||
* example: @see {@linkcode Moves.WHIRLWIND}
|
|
||||||
* @returns The {@linkcode Move} that called this function
|
* @returns The {@linkcode Move} that called this function
|
||||||
*/
|
*/
|
||||||
hidesTarget(hidesTarget: boolean = true): this {
|
hidesTarget(): this {
|
||||||
this.setFlag(MoveFlags.HIDE_TARGET, hidesTarget);
|
this.setFlag(MoveFlags.HIDE_TARGET, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@linkcode MoveFlags.BITING_MOVE} flag for the calling Move
|
* Sets the {@linkcode MoveFlags.BITING_MOVE} flag for the calling Move
|
||||||
* @param bitingMove The value (boolean) to set the flag to
|
* @see {@linkcode Moves.BITE}
|
||||||
* example: @see {@linkcode Moves.BITE}
|
|
||||||
* @returns The {@linkcode Move} that called this function
|
* @returns The {@linkcode Move} that called this function
|
||||||
*/
|
*/
|
||||||
bitingMove(bitingMove: boolean = true): this {
|
bitingMove(): this {
|
||||||
this.setFlag(MoveFlags.BITING_MOVE, bitingMove);
|
this.setFlag(MoveFlags.BITING_MOVE, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@linkcode MoveFlags.PULSE_MOVE} flag for the calling Move
|
* Sets the {@linkcode MoveFlags.PULSE_MOVE} flag for the calling Move
|
||||||
* @param pulseMove The value (boolean) to set the flag to
|
* @see {@linkcode Moves.WATER_PULSE}
|
||||||
* example: @see {@linkcode Moves.WATER_PULSE}
|
|
||||||
* @returns The {@linkcode Move} that called this function
|
* @returns The {@linkcode Move} that called this function
|
||||||
*/
|
*/
|
||||||
pulseMove(pulseMove: boolean = true): this {
|
pulseMove(): this {
|
||||||
this.setFlag(MoveFlags.PULSE_MOVE, pulseMove);
|
this.setFlag(MoveFlags.PULSE_MOVE, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@linkcode MoveFlags.PUNCHING_MOVE} flag for the calling Move
|
* Sets the {@linkcode MoveFlags.PUNCHING_MOVE} flag for the calling Move
|
||||||
* @param punchingMove The value (boolean) to set the flag to
|
* @see {@linkcode Moves.DRAIN_PUNCH}
|
||||||
* example: @see {@linkcode Moves.DRAIN_PUNCH}
|
|
||||||
* @returns The {@linkcode Move} that called this function
|
* @returns The {@linkcode Move} that called this function
|
||||||
*/
|
*/
|
||||||
punchingMove(punchingMove: boolean = true): this {
|
punchingMove(): this {
|
||||||
this.setFlag(MoveFlags.PUNCHING_MOVE, punchingMove);
|
this.setFlag(MoveFlags.PUNCHING_MOVE, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@linkcode MoveFlags.SLICING_MOVE} flag for the calling Move
|
* Sets the {@linkcode MoveFlags.SLICING_MOVE} flag for the calling Move
|
||||||
* @param slicingMove The value (boolean) to set the flag to
|
* @see {@linkcode Moves.X_SCISSOR}
|
||||||
* example: @see {@linkcode Moves.X_SCISSOR}
|
|
||||||
* @returns The {@linkcode Move} that called this function
|
* @returns The {@linkcode Move} that called this function
|
||||||
*/
|
*/
|
||||||
slicingMove(slicingMove: boolean = true): this {
|
slicingMove(): this {
|
||||||
this.setFlag(MoveFlags.SLICING_MOVE, slicingMove);
|
this.setFlag(MoveFlags.SLICING_MOVE, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@linkcode MoveFlags.RECKLESS_MOVE} flag for the calling Move
|
* Sets the {@linkcode MoveFlags.RECKLESS_MOVE} flag for the calling Move
|
||||||
* @see {@linkcode Abilities.RECKLESS}
|
* @see {@linkcode Abilities.RECKLESS}
|
||||||
* @param recklessMove The value to set the flag to
|
|
||||||
* @returns The {@linkcode Move} that called this function
|
* @returns The {@linkcode Move} that called this function
|
||||||
*/
|
*/
|
||||||
recklessMove(recklessMove: boolean = true): this {
|
recklessMove(): this {
|
||||||
this.setFlag(MoveFlags.RECKLESS_MOVE, recklessMove);
|
this.setFlag(MoveFlags.RECKLESS_MOVE, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@linkcode MoveFlags.BALLBOMB_MOVE} flag for the calling Move
|
* Sets the {@linkcode MoveFlags.BALLBOMB_MOVE} flag for the calling Move
|
||||||
* @param ballBombMove The value (boolean) to set the flag to
|
* @see {@linkcode Moves.ELECTRO_BALL}
|
||||||
* example: @see {@linkcode Moves.ELECTRO_BALL}
|
|
||||||
* @returns The {@linkcode Move} that called this function
|
* @returns The {@linkcode Move} that called this function
|
||||||
*/
|
*/
|
||||||
ballBombMove(ballBombMove: boolean = true): this {
|
ballBombMove(): this {
|
||||||
this.setFlag(MoveFlags.BALLBOMB_MOVE, ballBombMove);
|
this.setFlag(MoveFlags.BALLBOMB_MOVE, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@linkcode MoveFlags.POWDER_MOVE} flag for the calling Move
|
* Sets the {@linkcode MoveFlags.POWDER_MOVE} flag for the calling Move
|
||||||
* @param powderMove The value (boolean) to set the flag to
|
* @see {@linkcode Moves.STUN_SPORE}
|
||||||
* example: @see {@linkcode Moves.STUN_SPORE}
|
|
||||||
* @returns The {@linkcode Move} that called this function
|
* @returns The {@linkcode Move} that called this function
|
||||||
*/
|
*/
|
||||||
powderMove(powderMove: boolean = true): this {
|
powderMove(): this {
|
||||||
this.setFlag(MoveFlags.POWDER_MOVE, powderMove);
|
this.setFlag(MoveFlags.POWDER_MOVE, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@linkcode MoveFlags.DANCE_MOVE} flag for the calling Move
|
* Sets the {@linkcode MoveFlags.DANCE_MOVE} flag for the calling Move
|
||||||
* @param danceMove The value (boolean) to set the flag to
|
* @see {@linkcode Moves.PETAL_DANCE}
|
||||||
* example: @see {@linkcode Moves.PETAL_DANCE}
|
|
||||||
* @returns The {@linkcode Move} that called this function
|
* @returns The {@linkcode Move} that called this function
|
||||||
*/
|
*/
|
||||||
danceMove(danceMove: boolean = true): this {
|
danceMove(): this {
|
||||||
this.setFlag(MoveFlags.DANCE_MOVE, danceMove);
|
this.setFlag(MoveFlags.DANCE_MOVE, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@linkcode MoveFlags.WIND_MOVE} flag for the calling Move
|
* Sets the {@linkcode MoveFlags.WIND_MOVE} flag for the calling Move
|
||||||
* @param windMove The value (boolean) to set the flag to
|
* @see {@linkcode Moves.HURRICANE}
|
||||||
* example: @see {@linkcode Moves.HURRICANE}
|
|
||||||
* @returns The {@linkcode Move} that called this function
|
* @returns The {@linkcode Move} that called this function
|
||||||
*/
|
*/
|
||||||
windMove(windMove: boolean = true): this {
|
windMove(): this {
|
||||||
this.setFlag(MoveFlags.WIND_MOVE, windMove);
|
this.setFlag(MoveFlags.WIND_MOVE, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@linkcode MoveFlags.TRIAGE_MOVE} flag for the calling Move
|
* Sets the {@linkcode MoveFlags.TRIAGE_MOVE} flag for the calling Move
|
||||||
* @param triageMove The value (boolean) to set the flag to
|
* @see {@linkcode Moves.ABSORB}
|
||||||
* example: @see {@linkcode Moves.ABSORB}
|
|
||||||
* @returns The {@linkcode Move} that called this function
|
* @returns The {@linkcode Move} that called this function
|
||||||
*/
|
*/
|
||||||
triageMove(triageMove: boolean = true): this {
|
triageMove(): this {
|
||||||
this.setFlag(MoveFlags.TRIAGE_MOVE, triageMove);
|
this.setFlag(MoveFlags.TRIAGE_MOVE, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@linkcode MoveFlags.IGNORE_ABILITIES} flag for the calling Move
|
* Sets the {@linkcode MoveFlags.IGNORE_ABILITIES} flag for the calling Move
|
||||||
* @param ignoresAbilities sThe value (boolean) to set the flag to
|
* @see {@linkcode Moves.SUNSTEEL_STRIKE}
|
||||||
* example: @see {@linkcode Moves.SUNSTEEL_STRIKE}
|
|
||||||
* @returns The {@linkcode Move} that called this function
|
* @returns The {@linkcode Move} that called this function
|
||||||
*/
|
*/
|
||||||
ignoresAbilities(ignoresAbilities: boolean = true): this {
|
ignoresAbilities(): this {
|
||||||
this.setFlag(MoveFlags.IGNORE_ABILITIES, ignoresAbilities);
|
this.setFlag(MoveFlags.IGNORE_ABILITIES, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@linkcode MoveFlags.CHECK_ALL_HITS} flag for the calling Move
|
* Sets the {@linkcode MoveFlags.CHECK_ALL_HITS} flag for the calling Move
|
||||||
* @param checkAllHits The value (boolean) to set the flag to
|
* @see {@linkcode Moves.TRIPLE_AXEL}
|
||||||
* example: @see {@linkcode Moves.TRIPLE_AXEL}
|
|
||||||
* @returns The {@linkcode Move} that called this function
|
* @returns The {@linkcode Move} that called this function
|
||||||
*/
|
*/
|
||||||
checkAllHits(checkAllHits: boolean = true): this {
|
checkAllHits(): this {
|
||||||
this.setFlag(MoveFlags.CHECK_ALL_HITS, checkAllHits);
|
this.setFlag(MoveFlags.CHECK_ALL_HITS, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@linkcode MoveFlags.IGNORE_SUBSTITUTE} flag for the calling Move
|
* Sets the {@linkcode MoveFlags.IGNORE_SUBSTITUTE} flag for the calling Move
|
||||||
* @param ignoresSubstitute The value (boolean) to set the flag to
|
* @see {@linkcode Moves.WHIRLWIND}
|
||||||
* example: @see {@linkcode Moves.WHIRLWIND}
|
|
||||||
* @returns The {@linkcode Move} that called this function
|
* @returns The {@linkcode Move} that called this function
|
||||||
*/
|
*/
|
||||||
ignoresSubstitute(ignoresSubstitute: boolean = true): this {
|
ignoresSubstitute(): this {
|
||||||
this.setFlag(MoveFlags.IGNORE_SUBSTITUTE, ignoresSubstitute);
|
this.setFlag(MoveFlags.IGNORE_SUBSTITUTE, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@linkcode MoveFlags.REDIRECT_COUNTER} flag for the calling Move
|
* Sets the {@linkcode MoveFlags.REDIRECT_COUNTER} flag for the calling Move
|
||||||
* @param redirectCounter The value (boolean) to set the flag to
|
* @see {@linkcode Moves.METAL_BURST}
|
||||||
* example: @see {@linkcode Moves.METAL_BURST}
|
|
||||||
* @returns The {@linkcode Move} that called this function
|
* @returns The {@linkcode Move} that called this function
|
||||||
*/
|
*/
|
||||||
redirectCounter(redirectCounter: boolean = true): this {
|
redirectCounter(): this {
|
||||||
this.setFlag(MoveFlags.REDIRECT_COUNTER, redirectCounter);
|
this.setFlag(MoveFlags.REDIRECT_COUNTER, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4547,6 +4530,7 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
|
|||||||
case BattlerTagType.DROWSY:
|
case BattlerTagType.DROWSY:
|
||||||
case BattlerTagType.DISABLED:
|
case BattlerTagType.DISABLED:
|
||||||
case BattlerTagType.HEAL_BLOCK:
|
case BattlerTagType.HEAL_BLOCK:
|
||||||
|
case BattlerTagType.RECEIVE_DOUBLE_DAMAGE:
|
||||||
return -5;
|
return -5;
|
||||||
case BattlerTagType.SEEDED:
|
case BattlerTagType.SEEDED:
|
||||||
case BattlerTagType.SALT_CURED:
|
case BattlerTagType.SALT_CURED:
|
||||||
@ -4567,6 +4551,7 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
|
|||||||
case BattlerTagType.ENCORE:
|
case BattlerTagType.ENCORE:
|
||||||
return -2;
|
return -2;
|
||||||
case BattlerTagType.MINIMIZED:
|
case BattlerTagType.MINIMIZED:
|
||||||
|
case BattlerTagType.ALWAYS_GET_HIT:
|
||||||
return 0;
|
return 0;
|
||||||
case BattlerTagType.INGRAIN:
|
case BattlerTagType.INGRAIN:
|
||||||
case BattlerTagType.IGNORE_ACCURACY:
|
case BattlerTagType.IGNORE_ACCURACY:
|
||||||
@ -5229,6 +5214,9 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
|
|||||||
*/
|
*/
|
||||||
const switchOutTarget = this.selfSwitch ? user : target;
|
const switchOutTarget = this.selfSwitch ? user : target;
|
||||||
if (switchOutTarget instanceof PlayerPokemon) {
|
if (switchOutTarget instanceof PlayerPokemon) {
|
||||||
|
if (switchOutTarget.scene.getParty().filter((p) => p.isAllowedInBattle() && !p.isOnField()).length < 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH);
|
switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH);
|
||||||
|
|
||||||
if (switchOutTarget.hp > 0) {
|
if (switchOutTarget.hp > 0) {
|
||||||
@ -5237,6 +5225,9 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} else if (user.scene.currentBattle.battleType !== BattleType.WILD) {
|
} else if (user.scene.currentBattle.battleType !== BattleType.WILD) {
|
||||||
|
if (switchOutTarget.scene.getEnemyParty().filter((p) => p.isAllowedInBattle() && !p.isOnField()).length < 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// Switch out logic for trainer battles
|
// Switch out logic for trainer battles
|
||||||
switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH);
|
switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH);
|
||||||
|
|
||||||
@ -5247,7 +5238,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
|
|||||||
false, false), MoveEndPhase);
|
false, false), MoveEndPhase);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (switchOutTarget.isBoss()) {
|
if (user.scene.currentBattle.waveIndex % 10 === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Switch out logic for everything else (eg: WILD battles)
|
// Switch out logic for everything else (eg: WILD battles)
|
||||||
@ -5345,7 +5336,7 @@ export class ChillyReceptionAttr extends ForceSwitchOutAttr {
|
|||||||
|
|
||||||
getCondition(): MoveConditionFunc {
|
getCondition(): MoveConditionFunc {
|
||||||
// chilly reception move will go through if the weather is change-able to snow, or the user can switch out, else move will fail
|
// chilly reception move will go through if the weather is change-able to snow, or the user can switch out, else move will fail
|
||||||
return (user, target, move) => user.scene.arena.trySetWeather(WeatherType.SNOW, true) || super.getSwitchOutCondition()(user, target, move);
|
return (user, target, move) => user.scene.arena.weather?.weatherType !== WeatherType.SNOW || super.getSwitchOutCondition()(user, target, move);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class RemoveTypeAttr extends MoveEffectAttr {
|
export class RemoveTypeAttr extends MoveEffectAttr {
|
||||||
@ -6586,7 +6577,7 @@ export class MoveCondition {
|
|||||||
|
|
||||||
export class FirstMoveCondition extends MoveCondition {
|
export class FirstMoveCondition extends MoveCondition {
|
||||||
constructor() {
|
constructor() {
|
||||||
super((user, target, move) => user.battleSummonData?.turnCount === 1);
|
super((user, target, move) => user.battleSummonData?.waveTurnCount === 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer {
|
getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer {
|
||||||
@ -7263,7 +7254,7 @@ export function initMoves() {
|
|||||||
new StatusMove(Moves.CURSE, Type.GHOST, -1, 10, -1, 0, 2)
|
new StatusMove(Moves.CURSE, Type.GHOST, -1, 10, -1, 0, 2)
|
||||||
.attr(CurseAttr)
|
.attr(CurseAttr)
|
||||||
.ignoresSubstitute()
|
.ignoresSubstitute()
|
||||||
.ignoresProtect(true)
|
.ignoresProtect()
|
||||||
.target(MoveTarget.CURSE),
|
.target(MoveTarget.CURSE),
|
||||||
new AttackMove(Moves.FLAIL, Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 15, -1, 0, 2)
|
new AttackMove(Moves.FLAIL, Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 15, -1, 0, 2)
|
||||||
.attr(LowHpPowerAttr),
|
.attr(LowHpPowerAttr),
|
||||||
@ -8903,8 +8894,8 @@ export function initMoves() {
|
|||||||
.attr(HalfSacrificialAttr)
|
.attr(HalfSacrificialAttr)
|
||||||
.target(MoveTarget.ALL_NEAR_OTHERS),
|
.target(MoveTarget.ALL_NEAR_OTHERS),
|
||||||
new AttackMove(Moves.PLASMA_FISTS, Type.ELECTRIC, MoveCategory.PHYSICAL, 100, 100, 15, -1, 0, 7)
|
new AttackMove(Moves.PLASMA_FISTS, Type.ELECTRIC, MoveCategory.PHYSICAL, 100, 100, 15, -1, 0, 7)
|
||||||
.punchingMove()
|
.attr(AddArenaTagAttr, ArenaTagType.PLASMA_FISTS, 1)
|
||||||
.partial(),
|
.punchingMove(),
|
||||||
new AttackMove(Moves.PHOTON_GEYSER, Type.PSYCHIC, MoveCategory.SPECIAL, 100, 100, 5, -1, 0, 7)
|
new AttackMove(Moves.PHOTON_GEYSER, Type.PSYCHIC, MoveCategory.SPECIAL, 100, 100, 5, -1, 0, 7)
|
||||||
.attr(PhotonGeyserCategoryAttr)
|
.attr(PhotonGeyserCategoryAttr)
|
||||||
.ignoresAbilities()
|
.ignoresAbilities()
|
||||||
@ -8934,7 +8925,7 @@ export function initMoves() {
|
|||||||
.partial()
|
.partial()
|
||||||
.ignoresVirtual(),
|
.ignoresVirtual(),
|
||||||
/* End Unused */
|
/* End Unused */
|
||||||
new AttackMove(Moves.ZIPPY_ZAP, Type.ELECTRIC, MoveCategory.PHYSICAL, 50, 100, 15, 100, 2, 7) //LGPE Implementation
|
new AttackMove(Moves.ZIPPY_ZAP, Type.ELECTRIC, MoveCategory.PHYSICAL, 50, 100, 15, -1, 2, 7) //LGPE Implementation
|
||||||
.attr(CritOnlyAttr),
|
.attr(CritOnlyAttr),
|
||||||
new AttackMove(Moves.SPLISHY_SPLASH, Type.WATER, MoveCategory.SPECIAL, 90, 100, 15, 30, 0, 7)
|
new AttackMove(Moves.SPLISHY_SPLASH, Type.WATER, MoveCategory.SPECIAL, 90, 100, 15, 30, 0, 7)
|
||||||
.attr(StatusEffectAttr, StatusEffect.PARALYSIS)
|
.attr(StatusEffectAttr, StatusEffect.PARALYSIS)
|
||||||
@ -9619,9 +9610,8 @@ export function initMoves() {
|
|||||||
.target(MoveTarget.ALL_NEAR_ENEMIES)
|
.target(MoveTarget.ALL_NEAR_ENEMIES)
|
||||||
.triageMove(),
|
.triageMove(),
|
||||||
new AttackMove(Moves.SYRUP_BOMB, Type.GRASS, MoveCategory.SPECIAL, 60, 85, 10, -1, 0, 9)
|
new AttackMove(Moves.SYRUP_BOMB, Type.GRASS, MoveCategory.SPECIAL, 60, 85, 10, -1, 0, 9)
|
||||||
.attr(StatStageChangeAttr, [ Stat.SPD ], -1) //Temporary
|
.attr(AddBattlerTagAttr, BattlerTagType.SYRUP_BOMB, false, false, 3)
|
||||||
.ballBombMove()
|
.ballBombMove(),
|
||||||
.partial(),
|
|
||||||
new AttackMove(Moves.IVY_CUDGEL, Type.GRASS, MoveCategory.PHYSICAL, 100, 100, 10, -1, 0, 9)
|
new AttackMove(Moves.IVY_CUDGEL, Type.GRASS, MoveCategory.PHYSICAL, 100, 100, 10, -1, 0, 9)
|
||||||
.attr(IvyCudgelTypeAttr)
|
.attr(IvyCudgelTypeAttr)
|
||||||
.attr(HighCritAttr)
|
.attr(HighCritAttr)
|
||||||
|
@ -159,7 +159,7 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
onHover: () => {
|
onHover: () => {
|
||||||
const formName = tradePokemon.species.forms && tradePokemon.species.forms.length > tradePokemon.formIndex ? tradePokemon.species.forms[pokemon.formIndex].formName : null;
|
const formName = tradePokemon.species.forms && tradePokemon.species.forms.length > tradePokemon.formIndex ? tradePokemon.species.forms[tradePokemon.formIndex].formName : null;
|
||||||
const line1 = i18next.t("pokemonInfoContainer:ability") + " " + tradePokemon.getAbility().name + (tradePokemon.getGender() !== Gender.GENDERLESS ? " | " + i18next.t("pokemonInfoContainer:gender") + " " + getGenderSymbol(tradePokemon.getGender()) : "");
|
const line1 = i18next.t("pokemonInfoContainer:ability") + " " + tradePokemon.getAbility().name + (tradePokemon.getGender() !== Gender.GENDERLESS ? " | " + i18next.t("pokemonInfoContainer:gender") + " " + getGenderSymbol(tradePokemon.getGender()) : "");
|
||||||
const line2 = i18next.t("pokemonInfoContainer:nature") + " " + getNatureName(tradePokemon.getNature()) + (formName ? " | " + i18next.t("pokemonInfoContainer:form") + " " + formName : "");
|
const line2 = i18next.t("pokemonInfoContainer:nature") + " " + getNatureName(tradePokemon.getNature()) + (formName ? " | " + i18next.t("pokemonInfoContainer:form") + " " + formName : "");
|
||||||
showEncounterText(scene, `${line1}\n${line2}`, 0, 0, false);
|
showEncounterText(scene, `${line1}\n${line2}`, 0, 0, false);
|
||||||
|
@ -224,7 +224,7 @@ export function getRandomSpeciesByStarterTier(starterTiers: number | [number, nu
|
|||||||
// If no filtered mons exist at specified starter tiers, will expand starter search range until there are
|
// If no filtered mons exist at specified starter tiers, will expand starter search range until there are
|
||||||
// Starts by decrementing starter tier min until it is 0, then increments tier max up to 10
|
// Starts by decrementing starter tier min until it is 0, then increments tier max up to 10
|
||||||
let tryFilterStarterTiers: [PokemonSpecies, number][] = filteredSpecies.filter(s => (s[1] >= min && s[1] <= max));
|
let tryFilterStarterTiers: [PokemonSpecies, number][] = filteredSpecies.filter(s => (s[1] >= min && s[1] <= max));
|
||||||
while (tryFilterStarterTiers.length === 0 && (min !== 0 && max !== 10)) {
|
while (tryFilterStarterTiers.length === 0 && !(min === 0 && max === 10)) {
|
||||||
if (min > 0) {
|
if (min > 0) {
|
||||||
min--;
|
min--;
|
||||||
} else {
|
} else {
|
||||||
|
@ -11,6 +11,7 @@ import { Biome } from "#enums/biome";
|
|||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import { TimeOfDay } from "#enums/time-of-day";
|
import { TimeOfDay } from "#enums/time-of-day";
|
||||||
|
import { DamageMoneyRewardModifier, ExtraModifierModifier, MoneyMultiplierModifier } from "#app/modifier/modifier";
|
||||||
|
|
||||||
export enum SpeciesWildEvolutionDelay {
|
export enum SpeciesWildEvolutionDelay {
|
||||||
NONE,
|
NONE,
|
||||||
@ -1647,8 +1648,14 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||||||
new SpeciesEvolution(Species.FROSMOTH, 1, null, new SpeciesFriendshipEvolutionCondition(90, p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT), SpeciesWildEvolutionDelay.MEDIUM)
|
new SpeciesEvolution(Species.FROSMOTH, 1, null, new SpeciesFriendshipEvolutionCondition(90, p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT), SpeciesWildEvolutionDelay.MEDIUM)
|
||||||
],
|
],
|
||||||
[Species.GIMMIGHOUL]: [
|
[Species.GIMMIGHOUL]: [
|
||||||
new SpeciesFormEvolution(Species.GHOLDENGO, "chest", "", 1, null, new SpeciesEvolutionCondition( p => p.evoCounter > 9 ), SpeciesWildEvolutionDelay.VERY_LONG),
|
new SpeciesFormEvolution(Species.GHOLDENGO, "chest", "", 1, null, new SpeciesEvolutionCondition(p => p.evoCounter
|
||||||
new SpeciesFormEvolution(Species.GHOLDENGO, "roaming", "", 1, null, new SpeciesEvolutionCondition( p => p.evoCounter > 9 ), SpeciesWildEvolutionDelay.VERY_LONG)
|
+ p.getHeldItems().filter(m => m instanceof DamageMoneyRewardModifier).length
|
||||||
|
+ p.scene.findModifiers(m => m instanceof MoneyMultiplierModifier
|
||||||
|
|| m instanceof ExtraModifierModifier).length > 9), SpeciesWildEvolutionDelay.VERY_LONG),
|
||||||
|
new SpeciesFormEvolution(Species.GHOLDENGO, "roaming", "", 1, null, new SpeciesEvolutionCondition(p => p.evoCounter
|
||||||
|
+ p.getHeldItems().filter(m => m instanceof DamageMoneyRewardModifier).length
|
||||||
|
+ p.scene.findModifiers(m => m instanceof MoneyMultiplierModifier
|
||||||
|
|| m instanceof ExtraModifierModifier).length > 9), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import { SpeciesFormKey } from "./pokemon-species";
|
|||||||
import { StatusEffect } from "./status-effect";
|
import { StatusEffect } from "./status-effect";
|
||||||
import { MoveCategory, allMoves } from "./move";
|
import { MoveCategory, allMoves } from "./move";
|
||||||
import { Type } from "./type";
|
import { Type } from "./type";
|
||||||
import { Constructor } from "#app/utils";
|
import { Constructor, nil } from "#app/utils";
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
@ -185,7 +185,7 @@ export class SpeciesFormChange {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
findTrigger(triggerType: Constructor<SpeciesFormChangeTrigger>): SpeciesFormChangeTrigger | null {
|
findTrigger(triggerType: Constructor<SpeciesFormChangeTrigger>): SpeciesFormChangeTrigger | nil {
|
||||||
if (!this.trigger.hasTriggerType(triggerType)) {
|
if (!this.trigger.hasTriggerType(triggerType)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -193,7 +193,7 @@ export class SpeciesFormChange {
|
|||||||
const trigger = this.trigger;
|
const trigger = this.trigger;
|
||||||
|
|
||||||
if (trigger instanceof SpeciesFormChangeCompoundTrigger) {
|
if (trigger instanceof SpeciesFormChangeCompoundTrigger) {
|
||||||
return trigger.triggers.find(t => t.hasTriggerType(triggerType))!; // TODO: is this bang correct?
|
return trigger.triggers.find(t => t.hasTriggerType(triggerType));
|
||||||
}
|
}
|
||||||
|
|
||||||
return trigger;
|
return trigger;
|
||||||
@ -202,11 +202,11 @@ export class SpeciesFormChange {
|
|||||||
|
|
||||||
export class SpeciesFormChangeCondition {
|
export class SpeciesFormChangeCondition {
|
||||||
public predicate: SpeciesFormChangeConditionPredicate;
|
public predicate: SpeciesFormChangeConditionPredicate;
|
||||||
public enforceFunc: SpeciesFormChangeConditionEnforceFunc | null;
|
public enforceFunc: SpeciesFormChangeConditionEnforceFunc | nil;
|
||||||
|
|
||||||
constructor(predicate: SpeciesFormChangeConditionPredicate, enforceFunc?: SpeciesFormChangeConditionEnforceFunc) {
|
constructor(predicate: SpeciesFormChangeConditionPredicate, enforceFunc?: SpeciesFormChangeConditionEnforceFunc) {
|
||||||
this.predicate = predicate;
|
this.predicate = predicate;
|
||||||
this.enforceFunc = enforceFunc!; // TODO: is this bang correct?
|
this.enforceFunc = enforceFunc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,11 @@ import {Species} from "#enums/species";
|
|||||||
import {TrainerType} from "#enums/trainer-type";
|
import {TrainerType} from "#enums/trainer-type";
|
||||||
import {Gender} from "./gender";
|
import {Gender} from "./gender";
|
||||||
|
|
||||||
|
/** Minimum BST for Pokemon generated onto the Elite Four's teams */
|
||||||
|
const ELITE_FOUR_MINIMUM_BST = 460;
|
||||||
|
/** Minimum BST for Pokemon generated onto the E4 Champion's team */
|
||||||
|
const CHAMPION_MINIMUM_BST = 508;
|
||||||
|
|
||||||
export enum TrainerPoolTier {
|
export enum TrainerPoolTier {
|
||||||
COMMON,
|
COMMON,
|
||||||
UNCOMMON,
|
UNCOMMON,
|
||||||
@ -860,10 +865,10 @@ export class TrainerConfig {
|
|||||||
|
|
||||||
// Set species filter and specialty types if provided, otherwise filter by base total.
|
// Set species filter and specialty types if provided, otherwise filter by base total.
|
||||||
if (specialtyTypes.length) {
|
if (specialtyTypes.length) {
|
||||||
this.setSpeciesFilter(p => specialtyTypes.some(t => p.isOfType(t)) && p.baseTotal >= 450);
|
this.setSpeciesFilter(p => specialtyTypes.some(t => p.isOfType(t)) && p.baseTotal >= ELITE_FOUR_MINIMUM_BST);
|
||||||
this.setSpecialtyTypes(...specialtyTypes);
|
this.setSpecialtyTypes(...specialtyTypes);
|
||||||
} else {
|
} else {
|
||||||
this.setSpeciesFilter(p => p.baseTotal >= 450);
|
this.setSpeciesFilter(p => p.baseTotal >= ELITE_FOUR_MINIMUM_BST);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Localize the trainer's name by converting it to lowercase and replacing spaces with underscores.
|
// Localize the trainer's name by converting it to lowercase and replacing spaces with underscores.
|
||||||
@ -913,8 +918,7 @@ export class TrainerConfig {
|
|||||||
this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool));
|
this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set species filter to only include species with a base total of 470 or higher.
|
this.setSpeciesFilter(p => p.baseTotal >= CHAMPION_MINIMUM_BST);
|
||||||
this.setSpeciesFilter(p => p.baseTotal >= 470);
|
|
||||||
|
|
||||||
// Localize the trainer's name by converting it to lowercase and replacing spaces with underscores.
|
// Localize the trainer's name by converting it to lowercase and replacing spaces with underscores.
|
||||||
const nameForCall = this.name.toLowerCase().replace(/\s/g, "_");
|
const nameForCall = this.name.toLowerCase().replace(/\s/g, "_");
|
||||||
|
@ -25,4 +25,5 @@ export enum ArenaTagType {
|
|||||||
SAFEGUARD = "SAFEGUARD",
|
SAFEGUARD = "SAFEGUARD",
|
||||||
NO_CRIT = "NO_CRIT",
|
NO_CRIT = "NO_CRIT",
|
||||||
IMPRISON = "IMPRISON",
|
IMPRISON = "IMPRISON",
|
||||||
|
PLASMA_FISTS = "PLASMA_FISTS",
|
||||||
}
|
}
|
||||||
|
@ -85,4 +85,5 @@ export enum BattlerTagType {
|
|||||||
TORMENT = "TORMENT",
|
TORMENT = "TORMENT",
|
||||||
TAUNT = "TAUNT",
|
TAUNT = "TAUNT",
|
||||||
IMPRISON = "IMPRISON",
|
IMPRISON = "IMPRISON",
|
||||||
|
SYRUP_BOMB = "SYRUP_BOMB",
|
||||||
}
|
}
|
||||||
|
@ -63,6 +63,12 @@ import { PLAYER_PARTY_MAX_SIZE } from "#app/constants";
|
|||||||
import { MysteryEncounterPokemonData } from "#app/data/mystery-encounters/mystery-encounter-pokemon-data";
|
import { MysteryEncounterPokemonData } from "#app/data/mystery-encounters/mystery-encounter-pokemon-data";
|
||||||
import { SwitchType } from "#enums/switch-type";
|
import { SwitchType } from "#enums/switch-type";
|
||||||
|
|
||||||
|
/** `64/65536 -> 1/1024` */
|
||||||
|
const BASE_SHINY_CHANCE = 64;
|
||||||
|
|
||||||
|
/** `1/256` */
|
||||||
|
const BASE_HIDDEN_ABILITY_CHANCE = 256;
|
||||||
|
|
||||||
export enum FieldPosition {
|
export enum FieldPosition {
|
||||||
CENTER,
|
CENTER,
|
||||||
LEFT,
|
LEFT,
|
||||||
@ -139,7 +145,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
throw `Cannot create a player Pokemon for species '${species.getName(formIndex)}'`;
|
throw `Cannot create a player Pokemon for species '${species.getName(formIndex)}'`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hiddenAbilityChance = new Utils.IntegerHolder(256);
|
const hiddenAbilityChance = new Utils.IntegerHolder(BASE_HIDDEN_ABILITY_CHANCE);
|
||||||
if (!this.hasTrainer()) {
|
if (!this.hasTrainer()) {
|
||||||
this.scene.applyModifiers(HiddenAbilityRateBoosterModifier, true, hiddenAbilityChance);
|
this.scene.applyModifiers(HiddenAbilityRateBoosterModifier, true, hiddenAbilityChance);
|
||||||
}
|
}
|
||||||
@ -1512,6 +1518,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
applyMoveAttrs(VariableMoveTypeAttr, this, null, move, moveTypeHolder);
|
applyMoveAttrs(VariableMoveTypeAttr, this, null, move, moveTypeHolder);
|
||||||
applyPreAttackAbAttrs(MoveTypeChangeAbAttr, this, null, move, simulated, moveTypeHolder);
|
applyPreAttackAbAttrs(MoveTypeChangeAbAttr, this, null, move, simulated, moveTypeHolder);
|
||||||
|
|
||||||
|
this.scene.arena.applyTags(ArenaTagType.PLASMA_FISTS, moveTypeHolder);
|
||||||
|
|
||||||
return moveTypeHolder.value as Type;
|
return moveTypeHolder.value as Type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1822,7 +1830,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
* The exact mechanic is that it calculates E as the XOR of the player's trainer ID and secret ID.
|
* The exact mechanic is that it calculates E as the XOR of the player's trainer ID and secret ID.
|
||||||
* F is calculated as the XOR of the first 16 bits of the Pokemon's ID with the last 16 bits.
|
* F is calculated as the XOR of the first 16 bits of the Pokemon's ID with the last 16 bits.
|
||||||
* The XOR of E and F are then compared to the {@linkcode shinyThreshold} (or {@linkcode thresholdOverride} if set) to see whether or not to generate a shiny.
|
* The XOR of E and F are then compared to the {@linkcode shinyThreshold} (or {@linkcode thresholdOverride} if set) to see whether or not to generate a shiny.
|
||||||
* The base shiny odds are {@linkcode baseShinyChance} / 65536
|
* The base shiny odds are {@linkcode BASE_SHINY_CHANCE} / 65536
|
||||||
* @param thresholdOverride number that is divided by 2^16 (65536) to get the shiny chance, overrides {@linkcode shinyThreshold} if set (bypassing shiny rate modifiers such as Shiny Charm)
|
* @param thresholdOverride number that is divided by 2^16 (65536) to get the shiny chance, overrides {@linkcode shinyThreshold} if set (bypassing shiny rate modifiers such as Shiny Charm)
|
||||||
* @returns true if the Pokemon has been set as a shiny, false otherwise
|
* @returns true if the Pokemon has been set as a shiny, false otherwise
|
||||||
*/
|
*/
|
||||||
@ -1838,9 +1846,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
const E = this.scene.gameData.trainerId ^ this.scene.gameData.secretId;
|
const E = this.scene.gameData.trainerId ^ this.scene.gameData.secretId;
|
||||||
const F = rand1 ^ rand2;
|
const F = rand1 ^ rand2;
|
||||||
|
|
||||||
/** `64/65536 -> 1/1024` */
|
const shinyThreshold = new Utils.IntegerHolder(BASE_SHINY_CHANCE);
|
||||||
const baseShinyChance = 64;
|
|
||||||
const shinyThreshold = new Utils.IntegerHolder(baseShinyChance);
|
|
||||||
if (thresholdOverride === undefined) {
|
if (thresholdOverride === undefined) {
|
||||||
if (this.scene.eventManager.isEventActive()) {
|
if (this.scene.eventManager.isEventActive()) {
|
||||||
shinyThreshold.value *= this.scene.eventManager.getShinyMultiplier();
|
shinyThreshold.value *= this.scene.eventManager.getShinyMultiplier();
|
||||||
@ -1865,15 +1871,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
* Function that tries to set a Pokemon shiny based on seed.
|
* Function that tries to set a Pokemon shiny based on seed.
|
||||||
* For manual use only, usually to roll a Pokemon's shiny chance a second time.
|
* For manual use only, usually to roll a Pokemon's shiny chance a second time.
|
||||||
*
|
*
|
||||||
* The base shiny odds are {@linkcode baseShinyChance} / 65536
|
* The base shiny odds are {@linkcode BASE_SHINY_CHANCE} / 65536
|
||||||
* @param thresholdOverride number that is divided by 2^16 (65536) to get the shiny chance, overrides {@linkcode shinyThreshold} if set (bypassing shiny rate modifiers such as Shiny Charm)
|
* @param thresholdOverride number that is divided by 2^16 (65536) to get the shiny chance, overrides {@linkcode shinyThreshold} if set (bypassing shiny rate modifiers such as Shiny Charm)
|
||||||
* @param applyModifiersToOverride If {@linkcode thresholdOverride} is set and this is true, will apply Shiny Charm and event modifiers to {@linkcode thresholdOverride}
|
* @param applyModifiersToOverride If {@linkcode thresholdOverride} is set and this is true, will apply Shiny Charm and event modifiers to {@linkcode thresholdOverride}
|
||||||
* @returns true if the Pokemon has been set as a shiny, false otherwise
|
* @returns true if the Pokemon has been set as a shiny, false otherwise
|
||||||
*/
|
*/
|
||||||
trySetShinySeed(thresholdOverride?: integer, applyModifiersToOverride?: boolean): boolean {
|
trySetShinySeed(thresholdOverride?: integer, applyModifiersToOverride?: boolean): boolean {
|
||||||
/** `64/65536 -> 1/1024` */
|
const shinyThreshold = new Utils.IntegerHolder(BASE_SHINY_CHANCE);
|
||||||
const baseShinyChance = 64;
|
|
||||||
const shinyThreshold = new Utils.IntegerHolder(baseShinyChance);
|
|
||||||
if (thresholdOverride === undefined || applyModifiersToOverride) {
|
if (thresholdOverride === undefined || applyModifiersToOverride) {
|
||||||
if (thresholdOverride !== undefined && applyModifiersToOverride) {
|
if (thresholdOverride !== undefined && applyModifiersToOverride) {
|
||||||
shinyThreshold.value = thresholdOverride;
|
shinyThreshold.value = thresholdOverride;
|
||||||
@ -1931,7 +1935,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
generateFusionSpecies(forStarter?: boolean): void {
|
generateFusionSpecies(forStarter?: boolean): void {
|
||||||
const hiddenAbilityChance = new Utils.IntegerHolder(256);
|
const hiddenAbilityChance = new Utils.IntegerHolder(BASE_HIDDEN_ABILITY_CHANCE);
|
||||||
if (!this.hasTrainer()) {
|
if (!this.hasTrainer()) {
|
||||||
this.scene.applyModifiers(HiddenAbilityRateBoosterModifier, true, hiddenAbilityChance);
|
this.scene.applyModifiers(HiddenAbilityRateBoosterModifier, true, hiddenAbilityChance);
|
||||||
}
|
}
|
||||||
@ -3979,7 +3983,8 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
let compatible = false;
|
let compatible = false;
|
||||||
for (const p of tmSpecies[tm]) {
|
for (const p of tmSpecies[tm]) {
|
||||||
if (Array.isArray(p)) {
|
if (Array.isArray(p)) {
|
||||||
if (p[0] === this.species.speciesId || (this.fusionSpecies && p[0] === this.fusionSpecies.speciesId) && p.slice(1).indexOf(this.species.forms[this.formIndex]) > -1) {
|
const [pkm, form] = p;
|
||||||
|
if ((pkm === this.species.speciesId || this.fusionSpecies && pkm === this.fusionSpecies.speciesId) && form === this.getFormKey()) {
|
||||||
compatible = true;
|
compatible = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -4995,6 +5000,8 @@ export class PokemonBattleData {
|
|||||||
export class PokemonBattleSummonData {
|
export class PokemonBattleSummonData {
|
||||||
/** The number of turns the pokemon has passed since entering the battle */
|
/** The number of turns the pokemon has passed since entering the battle */
|
||||||
public turnCount: number = 1;
|
public turnCount: number = 1;
|
||||||
|
/** The number of turns the pokemon has passed since the start of the wave */
|
||||||
|
public waveTurnCount: number = 1;
|
||||||
/** The list of moves the pokemon has used since entering the battle */
|
/** The list of moves the pokemon has used since entering the battle */
|
||||||
public moveHistory: TurnMove[] = [];
|
public moveHistory: TurnMove[] = [];
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
"mudSportOnRemove": "Lehmsuhler hört auf zu wirken!",
|
"mudSportOnRemove": "Lehmsuhler hört auf zu wirken!",
|
||||||
"waterSportOnAdd": "Die Stärke aller Feuer-Attacken wurde reduziert!",
|
"waterSportOnAdd": "Die Stärke aller Feuer-Attacken wurde reduziert!",
|
||||||
"waterSportOnRemove": "Nassmacher hört auf zu wirken!",
|
"waterSportOnRemove": "Nassmacher hört auf zu wirken!",
|
||||||
|
"plasmaFistsOnAdd": "Ein elektrisch geladener Niederschlag regnet auf das Kampffeld herab!",
|
||||||
"spikesOnAdd": "Die {{opponentDesc}} sind von Stacheln umgeben!",
|
"spikesOnAdd": "Die {{opponentDesc}} sind von Stacheln umgeben!",
|
||||||
"spikesActivateTrap": "Die {{pokemonNameWithAffix}} wurde durch Stachler verletzt!!",
|
"spikesActivateTrap": "Die {{pokemonNameWithAffix}} wurde durch Stachler verletzt!!",
|
||||||
"toxicSpikesOnAdd": "Die {{opponentDesc}} sind überall von giftigen Stacheln umgeben",
|
"toxicSpikesOnAdd": "Die {{opponentDesc}} sind überall von giftigen Stacheln umgeben",
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
"outro": "Schau wie glücklich dein {{chosenPokemon}} nun ist!$Hier, diese Pokémon-Eier kannst du auch haben.",
|
"outro": "Schau wie glücklich dein {{chosenPokemon}} nun ist!$Hier, diese Pokémon-Eier kannst du auch haben.",
|
||||||
"outro_failed": "Wie enttäuschend...$Es sieht so aus, als hättest du noch einen langen Weg vor dir, um das Vertrauen deines Pokémon zu gewinnen!",
|
"outro_failed": "Wie enttäuschend...$Es sieht so aus, als hättest du noch einen langen Weg vor dir, um das Vertrauen deines Pokémon zu gewinnen!",
|
||||||
"gained_eggs": "@s{item_fanfare}Du erhählst {{numEggs}}!",
|
"gained_eggs": "@s{item_fanfare}Du erhählst {{numEggs}}!",
|
||||||
"eggs_tooltip": "\n(+) Erhalte @[TOOLTIP_TITLE]{{{eggs}}}",
|
"eggs_tooltip": "\n(+) Erhalte {{eggs}}",
|
||||||
"numEggs_one": "{{count}} Ei der Stufe {{rarity}}",
|
"numEggs_one": "{{count}} Ei der Stufe {{rarity}}",
|
||||||
"numEggs_other": "{{count}} Eier der Stufe {{rarity}}"
|
"numEggs_other": "{{count}} Eier der Stufe {{rarity}}"
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
"mudSportOnRemove": "The effects of Mud Sport\nhave faded.",
|
"mudSportOnRemove": "The effects of Mud Sport\nhave faded.",
|
||||||
"waterSportOnAdd": "Fire's power was weakened!",
|
"waterSportOnAdd": "Fire's power was weakened!",
|
||||||
"waterSportOnRemove": "The effects of Water Sport\nhave faded.",
|
"waterSportOnRemove": "The effects of Water Sport\nhave faded.",
|
||||||
|
"plasmaFistsOnAdd": "A deluge of ions showers the battlefield!",
|
||||||
"spikesOnAdd": "{{moveName}} were scattered\nall around {{opponentDesc}}'s feet!",
|
"spikesOnAdd": "{{moveName}} were scattered\nall around {{opponentDesc}}'s feet!",
|
||||||
"spikesActivateTrap": "{{pokemonNameWithAffix}} is hurt\nby the spikes!",
|
"spikesActivateTrap": "{{pokemonNameWithAffix}} is hurt\nby the spikes!",
|
||||||
"toxicSpikesOnAdd": "{{moveName}} were scattered\nall around {{opponentDesc}}'s feet!",
|
"toxicSpikesOnAdd": "{{moveName}} were scattered\nall around {{opponentDesc}}'s feet!",
|
||||||
|
@ -78,5 +78,7 @@
|
|||||||
"tormentOnAdd": "{{pokemonNameWithAffix}} was subjected to torment!",
|
"tormentOnAdd": "{{pokemonNameWithAffix}} was subjected to torment!",
|
||||||
"tauntOnAdd": "{{pokemonNameWithAffix}} fell for the taunt!",
|
"tauntOnAdd": "{{pokemonNameWithAffix}} fell for the taunt!",
|
||||||
"imprisonOnAdd": "{{pokemonNameWithAffix}} sealed the opponents move(s)!",
|
"imprisonOnAdd": "{{pokemonNameWithAffix}} sealed the opponents move(s)!",
|
||||||
"autotomizeOnAdd": "{{pokemonNameWithAffix}} became nimble!"
|
"autotomizeOnAdd": "{{pokemonNameWithAffix}} became nimble!",
|
||||||
|
"syrupBombOnAdd": "{{pokemonNameWithAffix}} got covered in sticky, candy syrup!",
|
||||||
|
"syrupBombLapse": "The sticky syrup slowed down {{pokemonNameWithAffix}}!"
|
||||||
}
|
}
|
||||||
|
@ -71,5 +71,5 @@
|
|||||||
"safeguard": "{{targetName}} is protected by Safeguard!",
|
"safeguard": "{{targetName}} is protected by Safeguard!",
|
||||||
"substituteOnOverlap": "{{pokemonName}} already\nhas a substitute!",
|
"substituteOnOverlap": "{{pokemonName}} already\nhas a substitute!",
|
||||||
"substituteNotEnoughHp": "But it does not have enough HP\nleft to make a substitute!",
|
"substituteNotEnoughHp": "But it does not have enough HP\nleft to make a substitute!",
|
||||||
"afterYou": "{{pokemonName}} took the kind offer!"
|
"afterYou": "{{targetName}} took the kind offer!"
|
||||||
}
|
}
|
@ -28,6 +28,7 @@
|
|||||||
"mudSportOnRemove": "Chapoteo Lodo ha dejado de surtir efecto.",
|
"mudSportOnRemove": "Chapoteo Lodo ha dejado de surtir efecto.",
|
||||||
"waterSportOnAdd": "¡Se han debilitado los ataques\nde tipo Fuego!",
|
"waterSportOnAdd": "¡Se han debilitado los ataques\nde tipo Fuego!",
|
||||||
"waterSportOnRemove": "Hidrochorro ha dejado de surtir efecto.",
|
"waterSportOnRemove": "Hidrochorro ha dejado de surtir efecto.",
|
||||||
|
"plasmaFistsOnAdd": "¡Una lluvia de electrones cae sobre\nel terreno de combate!",
|
||||||
"spikesOnAdd": "¡El equipo de {{opponentDesc}} ha sido rodeado por {{moveName}}!",
|
"spikesOnAdd": "¡El equipo de {{opponentDesc}} ha sido rodeado por {{moveName}}!",
|
||||||
"spikesActivateTrap": "¡Las púas han herido a {{pokemonNameWithAffix}}!",
|
"spikesActivateTrap": "¡Las púas han herido a {{pokemonNameWithAffix}}!",
|
||||||
"toxicSpikesOnAdd": "¡El equipo de {{opponentDesc}} ha sido rodeado por {{moveName}}!",
|
"toxicSpikesOnAdd": "¡El equipo de {{opponentDesc}} ha sido rodeado por {{moveName}}!",
|
||||||
|
@ -67,5 +67,5 @@
|
|||||||
"swapArenaTags": "¡{{pokemonName}} ha intercambiado los efectos del terreno de combate!",
|
"swapArenaTags": "¡{{pokemonName}} ha intercambiado los efectos del terreno de combate!",
|
||||||
"exposedMove": "¡{{pokemonName}} ha identificado\n{{targetPokemonName}}!",
|
"exposedMove": "¡{{pokemonName}} ha identificado\n{{targetPokemonName}}!",
|
||||||
"safeguard": "¡{{targetName}} está protegido por Velo Sagrado!",
|
"safeguard": "¡{{targetName}} está protegido por Velo Sagrado!",
|
||||||
"afterYou": "¡{{pokemonName}} ha decidido aprovechar la oportunidad!"
|
"afterYou": "¡{{targetName}} ha decidido aprovechar la oportunidad!"
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
"mudSportOnRemove": "L’effet de Lance-Boue se dissipe !",
|
"mudSportOnRemove": "L’effet de Lance-Boue se dissipe !",
|
||||||
"waterSportOnAdd": "La puissance des capacités\nde type Feu diminue !",
|
"waterSportOnAdd": "La puissance des capacités\nde type Feu diminue !",
|
||||||
"waterSportOnRemove": "L’effet de Tourniquet se dissipe !",
|
"waterSportOnRemove": "L’effet de Tourniquet se dissipe !",
|
||||||
|
"plasmaFistsOnAdd": "Un déluge de plasma s’abat sur le terrain !",
|
||||||
"spikesOnAdd": "Des {{moveName}} s’éparpillent autour de {{opponentDesc}} !",
|
"spikesOnAdd": "Des {{moveName}} s’éparpillent autour de {{opponentDesc}} !",
|
||||||
"spikesActivateTrap": "{{pokemonNameWithAffix}} est blessé\npar les picots !",
|
"spikesActivateTrap": "{{pokemonNameWithAffix}} est blessé\npar les picots !",
|
||||||
"toxicSpikesOnAdd": "Des {{moveName}} s’éparpillent autour de {{opponentDesc}} !",
|
"toxicSpikesOnAdd": "Des {{moveName}} s’éparpillent autour de {{opponentDesc}} !",
|
||||||
|
@ -71,5 +71,5 @@
|
|||||||
"safeguard": "{{targetName}} est protégé\npar la capacité Rune Protect !",
|
"safeguard": "{{targetName}} est protégé\npar la capacité Rune Protect !",
|
||||||
"substituteOnOverlap": "{{pokemonName}} a déjà\nun clone !",
|
"substituteOnOverlap": "{{pokemonName}} a déjà\nun clone !",
|
||||||
"substituteNotEnoughHp": "Mais il est trop faible\npour créer un clone !",
|
"substituteNotEnoughHp": "Mais il est trop faible\npour créer un clone !",
|
||||||
"afterYou": "{{pokemonName}} accepte\navec joie !"
|
"afterYou": "{{targetName}} accepte\navec joie !"
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
"select_prompt": "Choisissez un objet à donner.",
|
"select_prompt": "Choisissez un objet à donner.",
|
||||||
"invalid_selection": "Ce Pokémon ne porte pas ce genre d’objet.",
|
"invalid_selection": "Ce Pokémon ne porte pas ce genre d’objet.",
|
||||||
"selected": "Vous remettez l’objet {{selectedItem}} au Dresseur.",
|
"selected": "Vous remettez l’objet {{selectedItem}} au Dresseur.",
|
||||||
"selected_dialogue": "Sérieux ? {{selectedItem}}, comme ça en cadeau ?\nC’est très générieux !$En guise de ma reconnaissance, laisse-moi\nte faire un cadeau un peu spécial !$Il est dans ma famille depusi des générations, et ça me ferait plaisir de te l’offrir !"
|
"selected_dialogue": "Sérieux ? {{selectedItem}}, comme ça en cadeau ?\nC’est très générieux !$En guise de ma reconnaissance, laisse-moi\nte faire un cadeau un peu spécial !$Il est dans ma famille depuis des générations, et ça me ferait plaisir de te l’offrir !"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"battle_won": "Tes connaissances et tes capacités ont totalement exploité nos faiblesses !$En remerciement de cette leçon, permets-moi\nd’apprendre une capacité Insecte à un de tes Pokémon !",
|
"battle_won": "Tes connaissances et tes capacités ont totalement exploité nos faiblesses !$En remerciement de cette leçon, permets-moi\nd’apprendre une capacité Insecte à un de tes Pokémon !",
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
"outro": "Ton {{chosenPokemon}} et toi avez\nl’air très heureux !$Tiens, prends ça aussi.",
|
"outro": "Ton {{chosenPokemon}} et toi avez\nl’air très heureux !$Tiens, prends ça aussi.",
|
||||||
"outro_failed": "Voilà qui est bien décevant…$T’as encore visiblement bien du chemin à faire\npour acquérir la confiance de tes Pokémon !",
|
"outro_failed": "Voilà qui est bien décevant…$T’as encore visiblement bien du chemin à faire\npour acquérir la confiance de tes Pokémon !",
|
||||||
"gained_eggs": "@s{item_fanfare}Vous recevez\n{{numEggs}} !",
|
"gained_eggs": "@s{item_fanfare}Vous recevez\n{{numEggs}} !",
|
||||||
"eggs_tooltip": "\n(+) Recevez @[TOOLTIP_TITLE]{{{eggs}}}",
|
"eggs_tooltip": "\n(+) Recevez {{eggs}}",
|
||||||
"numEggs_one": "{{count}} Œuf {{rarity}}",
|
"numEggs_one": "{{count}} Œuf {{rarity}}",
|
||||||
"numEggs_other": "{{count}} Œufs {{rarity}}s"
|
"numEggs_other": "{{count}} Œufs {{rarity}}s"
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"intro": "Vous tombez sur du matériel d’entrainement.",
|
"intro": "Vous tombez sur du matériel d’entrainement.",
|
||||||
"title": "Session d’entrainement",
|
"title": "Session d’entrainement",
|
||||||
"description": "Ce matériel semble pouvoir être utilisé pour entrainer un membre de votre équipe ! Il existe plusieurs moyens avec lesquels vous pourriez entrainer un Pokémon, comme @[TOOLTIP_TITLE]{en le faisant combattre et vaincre le reste de votre équipe}.",
|
"description": "Ce matériel semble pouvoir être utilisé pour entrainer un membre de votre équipe ! Il existe plusieurs moyens avec lesquels vous pourriez entrainer un Pokémon, comme @[TOOLTIP_TITLE]{en le combattant et le vainquant avec le reste de votre équipe}.",
|
||||||
"query": "Quel entrainement choisir ?",
|
"query": "Quel entrainement choisir ?",
|
||||||
"invalid_selection": "Le Pokémon doit être en bonne santé.",
|
"invalid_selection": "Le Pokémon doit être en bonne santé.",
|
||||||
"option": {
|
"option": {
|
||||||
|
@ -14,13 +14,13 @@
|
|||||||
"label": "Le nourrir",
|
"label": "Le nourrir",
|
||||||
"disabled_tooltip": "Vous avez besoin de 4 Baies pour choisir cette option",
|
"disabled_tooltip": "Vous avez besoin de 4 Baies pour choisir cette option",
|
||||||
"tooltip": "(-) Donner 4 Baies\n(+) Le {{enemyPokemon}} vous apprécie",
|
"tooltip": "(-) Donner 4 Baies\n(+) Le {{enemyPokemon}} vous apprécie",
|
||||||
"selected": "Vous lancer quelques Baies\nau {{enemyPokemon}} !$Il les engloutit avec joie !$Le {{enemyPokemon}} veut se joindre\nà votre équipe !"
|
"selected": "Vous lancez quelques Baies\nau {{enemyPokemon}} !$Il les engloutit avec joie !$Le {{enemyPokemon}} veut se joindre\nà votre équipe !"
|
||||||
},
|
},
|
||||||
"3": {
|
"3": {
|
||||||
"label": "Devenir amis",
|
"label": "Devenir amis",
|
||||||
"disabled_tooltip": "Votre Pokémon doit connaitre certaines capacités pour choisir cette option",
|
"disabled_tooltip": "Votre Pokémon doit connaitre certaines capacités pour choisir cette option",
|
||||||
"tooltip": "(+) {{option3PrimaryName}} utilise {{option3PrimaryMove}}\n(+) Le {{enemyPokemon}} vous apprécie",
|
"tooltip": "(+) {{option3PrimaryName}} utilise {{option3PrimaryMove}}\n(+) Le {{enemyPokemon}} vous apprécie",
|
||||||
"selected": "Votre {{option3PrimaryName}} utilise {{option3PrimaryMove}} pour charmer le {{enemyPokemon}} !$The {{enemyPokemon}} veut se joindre\nà votre équipe !"
|
"selected": "Votre {{option3PrimaryName}} utilise {{option3PrimaryMove}} pour charmer le {{enemyPokemon}} !$Le {{enemyPokemon}} veut se joindre\nà votre équipe !"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
"expGainsSpeed": "Vit. barre d’Exp",
|
"expGainsSpeed": "Vit. barre d’Exp",
|
||||||
"expPartyDisplay": "Afficher Exp équipe",
|
"expPartyDisplay": "Afficher Exp équipe",
|
||||||
"skipSeenDialogues": "Passer dialogues connus",
|
"skipSeenDialogues": "Passer dialogues connus",
|
||||||
"eggSkip": "Animation d’éclosion",
|
"eggSkip": "Passer les éclosions",
|
||||||
"never": "Jamais",
|
"never": "Jamais",
|
||||||
"always": "Toujours",
|
"always": "Toujours",
|
||||||
"ask": "Demander",
|
"ask": "Demander",
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"plasmaFistsOnAdd": "Una pioggia di elettroni si rovescia sui Pokémon!",
|
||||||
"safeguardOnAdd": "Un velo mistico ricopre il campo!",
|
"safeguardOnAdd": "Un velo mistico ricopre il campo!",
|
||||||
"safeguardOnAddPlayer": "Un velo mistico ricopre la tua squadra!",
|
"safeguardOnAddPlayer": "Un velo mistico ricopre la tua squadra!",
|
||||||
"safeguardOnAddEnemy": "Un velo mistico ricopre la squadra avversaria!",
|
"safeguardOnAddEnemy": "Un velo mistico ricopre la squadra avversaria!",
|
||||||
|
@ -68,5 +68,5 @@
|
|||||||
"exposedMove": "{{pokemonName}} ha identificato\n{{targetPokemonName}}!",
|
"exposedMove": "{{pokemonName}} ha identificato\n{{targetPokemonName}}!",
|
||||||
"chillyReception": "{{pokemonName}} sta per fare una battuta!",
|
"chillyReception": "{{pokemonName}} sta per fare una battuta!",
|
||||||
"safeguard": "Salvaguardia protegge {{targetName}}!",
|
"safeguard": "Salvaguardia protegge {{targetName}}!",
|
||||||
"afterYou": "{{pokemonName}} approfitta della cortesia!"
|
"afterYou": "{{targetName}} approfitta della cortesia!"
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
"perishBody": "{{pokemonName}}の {{abilityName}}で\nおたがいは 3ターン後に ほろびいてしまう!",
|
"perishBody": "{{pokemonName}}の {{abilityName}}で\nおたがいは 3ターン後に ほろびいてしまう!",
|
||||||
"poisonHeal": "{{pokemonName}}は {{abilityName}}で 回復した!",
|
"poisonHeal": "{{pokemonName}}は {{abilityName}}で 回復した!",
|
||||||
"trace": "{{pokemonName}}は 相手の {{targetName}}の\n{{abilityName}}を トレースした!",
|
"trace": "{{pokemonName}}は 相手の {{targetName}}の\n{{abilityName}}を トレースした!",
|
||||||
"windPowerCharged": "{{pokemonNameWithAffix}}は\n{{moveName}}を 受けて じゅうでんした!",
|
"windPowerCharged": "{{pokemonName}} は\n{{moveName}}を 受けて じゅうでんした!",
|
||||||
"quickDraw": "{{pokemonName}}は クイックドロウで\n行動が はやくなった!",
|
"quickDraw": "{{pokemonName}}は クイックドロウで\n行動が はやくなった!",
|
||||||
"disguiseAvoidedDamage": "{{pokemonNameWithAffix}}の\nばけのかわが はがれた!",
|
"disguiseAvoidedDamage": "{{pokemonNameWithAffix}}の\nばけのかわが はがれた!",
|
||||||
"blockItemTheft": "{{pokemonNameWithAffix}}の {{abilityName}}で\n道具を うばわれない!",
|
"blockItemTheft": "{{pokemonNameWithAffix}}の {{abilityName}}で\n道具を うばわれない!",
|
||||||
@ -48,8 +48,8 @@
|
|||||||
"weatherEffectDisappeared": "天候の影響が なくなった!",
|
"weatherEffectDisappeared": "天候の影響が なくなった!",
|
||||||
"postSummonMoldBreaker": "{{pokemonNameWithAffix}}は\nかたやぶりだ!",
|
"postSummonMoldBreaker": "{{pokemonNameWithAffix}}は\nかたやぶりだ!",
|
||||||
"postSummonAnticipation": "{{pokemonNameWithAffix}}は\nみぶるいした!",
|
"postSummonAnticipation": "{{pokemonNameWithAffix}}は\nみぶるいした!",
|
||||||
"postSummonTurboblaze": "{{pokemonNameWithAffix}}は\n燃え盛(もえさか)る オーラを 放っている!",
|
"postSummonTurboblaze": "{{pokemonNameWithAffix}}は\n燃え盛る オーラを 放っている!",
|
||||||
"postSummonTeravolt": "{{pokemonNameWithAffix}}は\n弾(はじ)ける オーラを 放っている!",
|
"postSummonTeravolt": "{{pokemonNameWithAffix}}は\n弾ける オーラを 放っている!",
|
||||||
"postSummonDarkAura": "{{pokemonNameWithAffix}}は\nダークオーラを 放っている!",
|
"postSummonDarkAura": "{{pokemonNameWithAffix}}は\nダークオーラを 放っている!",
|
||||||
"postSummonFairyAura": "{{pokemonNameWithAffix}}は\nフェアリーオーラを 放っている!",
|
"postSummonFairyAura": "{{pokemonNameWithAffix}}は\nフェアリーオーラを 放っている!",
|
||||||
"postSummonAuraBreak": "{{pokemonNameWithAffix}}は\nすべての オーラを 制圧する!",
|
"postSummonAuraBreak": "{{pokemonNameWithAffix}}は\nすべての オーラを 制圧する!",
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
"mudSportOnRemove": "どろあそびの 効果が なくなった!",
|
"mudSportOnRemove": "どろあそびの 効果が なくなった!",
|
||||||
"waterSportOnAdd": "炎の威力が 弱まった!",
|
"waterSportOnAdd": "炎の威力が 弱まった!",
|
||||||
"waterSportOnRemove": "みずあそびの 効果が なくなった!",
|
"waterSportOnRemove": "みずあそびの 効果が なくなった!",
|
||||||
|
"plasmaFistsOnAdd": "電子のシャワーが 降りそそいだ!",
|
||||||
"spikesOnAdd": "{{opponentDesc}}の 足下に\n{{moveName}}が 散らばった!",
|
"spikesOnAdd": "{{opponentDesc}}の 足下に\n{{moveName}}が 散らばった!",
|
||||||
"spikesActivateTrap": "{{pokemonNameWithAffix}}は\nまきびしの ダメージを 受けた!",
|
"spikesActivateTrap": "{{pokemonNameWithAffix}}は\nまきびしの ダメージを 受けた!",
|
||||||
"toxicSpikesOnAdd": "{{opponentDesc}}の 足下に\n{{moveName}}が 散らばった!",
|
"toxicSpikesOnAdd": "{{opponentDesc}}の 足下に\n{{moveName}}が 散らばった!",
|
||||||
|
@ -68,5 +68,5 @@
|
|||||||
"chillyReception": "{{pokemonName}}は\n寒い ギャグを かました!",
|
"chillyReception": "{{pokemonName}}は\n寒い ギャグを かました!",
|
||||||
"swapArenaTags": "{{pokemonName}}は\nお互いの 場の 効果を 入れ替えた!",
|
"swapArenaTags": "{{pokemonName}}は\nお互いの 場の 効果を 入れ替えた!",
|
||||||
"exposedMove": "{{pokemonName}}は {{targetPokemonName}}の\n正体を 見破った!",
|
"exposedMove": "{{pokemonName}}は {{targetPokemonName}}の\n正体を 見破った!",
|
||||||
"afterYou": "{{pokemonName}}は\nお言葉に 甘えることにした!"
|
"afterYou": "{{targetName}}は\nお言葉に 甘えることにした!"
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
"outro": "ねえ、 {{chosenPokemon}} すごく 嬉しくなったわ!$そして、 これらも どうぞ!",
|
"outro": "ねえ、 {{chosenPokemon}} すごく 嬉しくなったわ!$そして、 これらも どうぞ!",
|
||||||
"outro_failed": "なんか ガッカリ ね……$手持ち ポケモンの 信用を 得るまで\nまだまだ みたいんだわ!",
|
"outro_failed": "なんか ガッカリ ね……$手持ち ポケモンの 信用を 得るまで\nまだまだ みたいんだわ!",
|
||||||
"gained_eggs": "@s{item_fanfare}{{numEggs}}を もらいました!",
|
"gained_eggs": "@s{item_fanfare}{{numEggs}}を もらいました!",
|
||||||
"eggs_tooltip": "\n(+) @[TOOLTIP_TITLE]{{{eggs}}}を得る",
|
"eggs_tooltip": "\n(+) {{eggs}}を得る",
|
||||||
"numEggs_one": "{{count}} {{rarity}} タマゴ",
|
"numEggs_one": "{{count}} {{rarity}} タマゴ",
|
||||||
"numEggs_other": "{{count}} {{rarity}} タマゴ"
|
"numEggs_other": "{{count}} {{rarity}} タマゴ"
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
"mudSportOnRemove": "흙놀이의 효과가\n없어졌다!",
|
"mudSportOnRemove": "흙놀이의 효과가\n없어졌다!",
|
||||||
"waterSportOnAdd": "불꽃의 위력이 약해졌다!",
|
"waterSportOnAdd": "불꽃의 위력이 약해졌다!",
|
||||||
"waterSportOnRemove": "물놀이의 효과가\n없어졌다!",
|
"waterSportOnRemove": "물놀이의 효과가\n없어졌다!",
|
||||||
|
"plasmaFistsOnAdd": "전기 입자가 쏟아졌다!",
|
||||||
"spikesOnAdd": "{{opponentDesc}}의 발밑에\n압정이 뿌려졌다!",
|
"spikesOnAdd": "{{opponentDesc}}의 발밑에\n압정이 뿌려졌다!",
|
||||||
"spikesActivateTrap": "{{pokemonNameWithAffix}}[[는]]\n압정뿌리기의 데미지를 입었다!",
|
"spikesActivateTrap": "{{pokemonNameWithAffix}}[[는]]\n압정뿌리기의 데미지를 입었다!",
|
||||||
"toxicSpikesOnAdd": "{{opponentDesc}}의 발밑에\n독압정이 뿌려졌다!",
|
"toxicSpikesOnAdd": "{{opponentDesc}}의 발밑에\n독압정이 뿌려졌다!",
|
||||||
|
@ -69,5 +69,5 @@
|
|||||||
"chillyReception": "{{pokemonName}}[[는]] 썰렁한 개그를 선보였다!",
|
"chillyReception": "{{pokemonName}}[[는]] 썰렁한 개그를 선보였다!",
|
||||||
"exposedMove": "{{pokemonName}}[[는]]\n{{targetPokemonName}}의 정체를 꿰뚫어 보았다!",
|
"exposedMove": "{{pokemonName}}[[는]]\n{{targetPokemonName}}의 정체를 꿰뚫어 보았다!",
|
||||||
"safeguard": "{{targetName}}[[는]] 신비의 베일이 지켜 주고 있다!",
|
"safeguard": "{{targetName}}[[는]] 신비의 베일이 지켜 주고 있다!",
|
||||||
"afterYou": "{{pokemonName}}[[는]]\n배려를 받아들이기로 했다!"
|
"afterYou": "{{targetName}}[[는]]\n배려를 받아들이기로 했다!"
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
"outro": "{{chosenPokemon}}[[가]] 정말 행복해 보이네요!$여기, 이것도 드릴게요.",
|
"outro": "{{chosenPokemon}}[[가]] 정말 행복해 보이네요!$여기, 이것도 드릴게요.",
|
||||||
"outro_failed": "실망이네요….$포켓몬의 신뢰를 얻으려면 아직 멀었어요!",
|
"outro_failed": "실망이네요….$포켓몬의 신뢰를 얻으려면 아직 멀었어요!",
|
||||||
"gained_eggs": "@s{item_fanfare}{{numEggs}}[[를]] 받았습니다!",
|
"gained_eggs": "@s{item_fanfare}{{numEggs}}[[를]] 받았습니다!",
|
||||||
"eggs_tooltip": "\n(+) @[TOOLTIP_TITLE]{{{eggs}}} 획득",
|
"eggs_tooltip": "\n(+) {{eggs}} 획득",
|
||||||
"numEggs_one": "{{rarity}}알 {{count}}개",
|
"numEggs_one": "{{rarity}}알 {{count}}개",
|
||||||
"numEggs_other": "{{rarity}}알 {{count}}개"
|
"numEggs_other": "{{rarity}}알 {{count}}개"
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
"mudSportOnRemove": "Os efeitos de Mud Sport\nsumiram.",
|
"mudSportOnRemove": "Os efeitos de Mud Sport\nsumiram.",
|
||||||
"waterSportOnAdd": "O poder de movimentos de fogo foi enfraquecido!",
|
"waterSportOnAdd": "O poder de movimentos de fogo foi enfraquecido!",
|
||||||
"waterSportOnRemove": "Os efeitos de Water Sport\nsumiram.",
|
"waterSportOnRemove": "Os efeitos de Water Sport\nsumiram.",
|
||||||
|
"plasmaFistsOnAdd": "Um dilúvio de íons chove sobre o campo de batalha!",
|
||||||
"spikesOnAdd": "{{moveName}} foram espalhados\nno chão ao redor de {{opponentDesc}}!",
|
"spikesOnAdd": "{{moveName}} foram espalhados\nno chão ao redor de {{opponentDesc}}!",
|
||||||
"spikesActivateTrap": "{{pokemonNameWithAffix}} foi ferido\npelos espinhos!",
|
"spikesActivateTrap": "{{pokemonNameWithAffix}} foi ferido\npelos espinhos!",
|
||||||
"toxicSpikesOnAdd": "{{moveName}} foram espalhados\nno chão ao redor de {{opponentDesc}}!",
|
"toxicSpikesOnAdd": "{{moveName}} foram espalhados\nno chão ao redor de {{opponentDesc}}!",
|
||||||
|
@ -25,5 +25,6 @@
|
|||||||
"unlinkGoogle": "Desconectar Google",
|
"unlinkGoogle": "Desconectar Google",
|
||||||
"cancel": "Cancelar",
|
"cancel": "Cancelar",
|
||||||
"losingProgressionWarning": "Você vai perder todo o progresso desde o início da batalha. Confirmar?",
|
"losingProgressionWarning": "Você vai perder todo o progresso desde o início da batalha. Confirmar?",
|
||||||
"noEggs": "Você não está chocando nenhum ovo\nno momento!"
|
"noEggs": "Você não está chocando nenhum ovo\nno momento!",
|
||||||
|
"donate": "Contribuir"
|
||||||
}
|
}
|
||||||
|
@ -64,5 +64,5 @@
|
|||||||
"chillyReception": "{{pokemonName}} está prestes a contar uma piada gelada!",
|
"chillyReception": "{{pokemonName}} está prestes a contar uma piada gelada!",
|
||||||
"exposedMove": "{{pokemonName}} identificou\n{{targetPokemonName}}!",
|
"exposedMove": "{{pokemonName}} identificou\n{{targetPokemonName}}!",
|
||||||
"safeguard": "{{targetName}} está protegido por Safeguard!",
|
"safeguard": "{{targetName}} está protegido por Safeguard!",
|
||||||
"afterYou": "{{pokemonName}} aceitou a gentil oferta!"
|
"afterYou": "{{targetName}} aceitou a gentil oferta!"
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
"outro": "Veja como seu {{chosenPokemon}} está feliz agora!$Aqui, você também pode ficar com isso.",
|
"outro": "Veja como seu {{chosenPokemon}} está feliz agora!$Aqui, você também pode ficar com isso.",
|
||||||
"outro_failed": "Que decepção...$Parece que você ainda tem um longo caminho\na percorrer para ganhar a confiança dos seus Pokémon!",
|
"outro_failed": "Que decepção...$Parece que você ainda tem um longo caminho\na percorrer para ganhar a confiança dos seus Pokémon!",
|
||||||
"gained_eggs": "@s{item_fanfare}Você recebeu {{numEggs}}!",
|
"gained_eggs": "@s{item_fanfare}Você recebeu {{numEggs}}!",
|
||||||
"eggs_tooltip": "\n(+) Ganhe @[TOOLTIP_TITLE]{{{eggs}}}",
|
"eggs_tooltip": "\n(+) Ganhe {{eggs}}",
|
||||||
"numEggs_one": "{{count}} Ovo {{rarity}}",
|
"numEggs_one": "{{count}} Ovo {{rarity}}",
|
||||||
"numEggs_other": "{{count}} Ovos {{rarity}}"
|
"numEggs_other": "{{count}} Ovos {{rarity}}"
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
"tooManyItems": "{{pokemonName}} já tem\nmuitos desse item!",
|
"tooManyItems": "{{pokemonName}} já tem\nmuitos desse item!",
|
||||||
"anyEffect": "Isso não terá nenhum efeito.",
|
"anyEffect": "Isso não terá nenhum efeito.",
|
||||||
"unpausedEvolutions": "Evoluções foram despausadas para {{pokemonName}}.",
|
"unpausedEvolutions": "Evoluções foram despausadas para {{pokemonName}}.",
|
||||||
"unspliceConfirmation": "Você realmente deseja desfazer a fusão de {{fusionName}}\ncom {{pokemonName}}? {{fusionName}} será perdido.",
|
"unspliceConfirmation": "Você realmente deseja desfazer a fusão de\n{{fusionName}} com {{pokemonName}}? {{fusionName}} será perdido.",
|
||||||
"wasReverted": "{{fusionName}} foi revertido para {{pokemonName}}.",
|
"wasReverted": "{{fusionName}} foi revertido para {{pokemonName}}.",
|
||||||
"releaseConfirmation": "Você realmente deseja soltar {{pokemonName}}?",
|
"releaseConfirmation": "Você realmente deseja soltar {{pokemonName}}?",
|
||||||
"releaseInBattle": "Você não pode soltar um Pokémon que está em batalha!",
|
"releaseInBattle": "Você não pode soltar um Pokémon que está em batalha!",
|
||||||
|
@ -11,6 +11,10 @@
|
|||||||
"expGainsSpeed": "Velocidade do Ganho de EXP",
|
"expGainsSpeed": "Velocidade do Ganho de EXP",
|
||||||
"expPartyDisplay": "Exibição de EXP da Equipe",
|
"expPartyDisplay": "Exibição de EXP da Equipe",
|
||||||
"skipSeenDialogues": "Pular Diálogos Vistos",
|
"skipSeenDialogues": "Pular Diálogos Vistos",
|
||||||
|
"eggSkip": "Pular Eclosões de Ovos",
|
||||||
|
"never": "Nunca",
|
||||||
|
"always": "Sempre",
|
||||||
|
"ask": "Perguntar",
|
||||||
"battleStyle": "Estilo de Batalha",
|
"battleStyle": "Estilo de Batalha",
|
||||||
"enableRetries": "Habilitar Novas Tentativas",
|
"enableRetries": "Habilitar Novas Tentativas",
|
||||||
"hideIvs": "Esconder scanner de IV",
|
"hideIvs": "Esconder scanner de IV",
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
"mudSportOnRemove": "玩泥巴的效果消失了!",
|
"mudSportOnRemove": "玩泥巴的效果消失了!",
|
||||||
"waterSportOnAdd": "火焰的威力减弱了!",
|
"waterSportOnAdd": "火焰的威力减弱了!",
|
||||||
"waterSportOnRemove": "玩水的效果消失了!",
|
"waterSportOnRemove": "玩水的效果消失了!",
|
||||||
|
"plasmaFistsOnAdd": "等离子雨倾盆而下!",
|
||||||
"spikesOnAdd": "{{opponentDesc}}脚下\n散落着{{moveName}}!",
|
"spikesOnAdd": "{{opponentDesc}}脚下\n散落着{{moveName}}!",
|
||||||
"spikesActivateTrap": "{{pokemonNameWithAffix}}\n受到了撒菱的伤害!",
|
"spikesActivateTrap": "{{pokemonNameWithAffix}}\n受到了撒菱的伤害!",
|
||||||
"toxicSpikesOnAdd": "{{opponentDesc}}脚下\n散落着{{moveName}}!",
|
"toxicSpikesOnAdd": "{{opponentDesc}}脚下\n散落着{{moveName}}!",
|
||||||
|
@ -88,6 +88,14 @@
|
|||||||
"statHarshlyFell_other": "{{pokemonNameWithAffix}}的{{stats}}大幅降低了!",
|
"statHarshlyFell_other": "{{pokemonNameWithAffix}}的{{stats}}大幅降低了!",
|
||||||
"statSeverelyFell_other": "{{pokemonNameWithAffix}}的{{stats}}极大幅降低了!",
|
"statSeverelyFell_other": "{{pokemonNameWithAffix}}的{{stats}}极大幅降低了!",
|
||||||
"statWontGoAnyLower_other": "{{pokemonNameWithAffix}}的{{stats}}已经无法再降低了!",
|
"statWontGoAnyLower_other": "{{pokemonNameWithAffix}}的{{stats}}已经无法再降低了!",
|
||||||
|
"statRose_one": "{{pokemonNameWithAffix}}的{{stats}}提高了!",
|
||||||
|
"statSharplyRose_one": "{{pokemonNameWithAffix}}的{{stats}}大幅提高了!",
|
||||||
|
"statRoseDrastically_one": "{{pokemonNameWithAffix}}的{{stats}}极大幅提高了!",
|
||||||
|
"statWontGoAnyHigher_one": "{{pokemonNameWithAffix}}的{{stats}}已经无法再提高了!",
|
||||||
|
"statFell_one": "{{pokemonNameWithAffix}}的{{stats}}降低了!",
|
||||||
|
"statHarshlyFell_one": "{{pokemonNameWithAffix}}的{{stats}}大幅降低了!",
|
||||||
|
"statSeverelyFell_one": "{{pokemonNameWithAffix}}的{{stats}}极大幅降低了!",
|
||||||
|
"statWontGoAnyLower_one": "{{pokemonNameWithAffix}}的{{stats}}已经无法再降低了!",
|
||||||
"transformedIntoType": "{{pokemonName}}变成了\n{{type}}属性!",
|
"transformedIntoType": "{{pokemonName}}变成了\n{{type}}属性!",
|
||||||
"ppReduced": "降低了{{targetName}}的\n{{moveName}}的PP{{reduction}}点!",
|
"ppReduced": "降低了{{targetName}}的\n{{moveName}}的PP{{reduction}}点!",
|
||||||
"retryBattle": "你要从对战开始时重试么?",
|
"retryBattle": "你要从对战开始时重试么?",
|
||||||
|
@ -299,6 +299,28 @@
|
|||||||
"1": "真奇怪…怎么会这样…我不应该被打败的。"
|
"1": "真奇怪…怎么会这样…我不应该被打败的。"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"snow_worker": {
|
||||||
|
"encounter": {
|
||||||
|
"1": "天冷了,便要添衣。\n只有人类会有这么聪明的想法!"
|
||||||
|
},
|
||||||
|
"victory": {
|
||||||
|
"1": "即使是徒劳的挣扎,\n到头来也还是展示了人类的智慧啊!"
|
||||||
|
},
|
||||||
|
"defeat": {
|
||||||
|
"1": "我来告诉你一个小技巧。\n如果你对着冻住的宝可梦用火系技能,冰就化啦!"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"snow_worker_double": {
|
||||||
|
"encounter": {
|
||||||
|
"1": "……\n……准……准备好战……战斗了吗?"
|
||||||
|
},
|
||||||
|
"victory": {
|
||||||
|
"1": "……\n……我冻得直,直打哆嗦!"
|
||||||
|
},
|
||||||
|
"defeat": {
|
||||||
|
"1": "……\n……知……知道吗?\n...这……这地方蛮冷。"
|
||||||
|
}
|
||||||
|
},
|
||||||
"hex_maniac": {
|
"hex_maniac": {
|
||||||
"encounter": {
|
"encounter": {
|
||||||
"1": "我通常只听古典音乐,但如果我输了,$我想我应该试试新时代的音乐!",
|
"1": "我通常只听古典音乐,但如果我输了,$我想我应该试试新时代的音乐!",
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
"gachaTypeLegendary": "传说概率上升",
|
"gachaTypeLegendary": "传说概率上升",
|
||||||
"gachaTypeMove": "稀有概率上升",
|
"gachaTypeMove": "稀有概率上升",
|
||||||
"gachaTypeShiny": "闪光概率上升",
|
"gachaTypeShiny": "闪光概率上升",
|
||||||
"eventType": "Mystery Event",
|
"eventType": "神秘事件",
|
||||||
"selectMachine": "选择一个机器。",
|
"selectMachine": "选择一个机器。",
|
||||||
"notEnoughVouchers": "你没有足够的兑换券!",
|
"notEnoughVouchers": "你没有足够的兑换券!",
|
||||||
"tooManyEggs": "你的蛋太多啦!",
|
"tooManyEggs": "你的蛋太多啦!",
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
"description": "遭遇双打概率提升四倍,持续{{battleCount}}场战斗。"
|
"description": "遭遇双打概率提升四倍,持续{{battleCount}}场战斗。"
|
||||||
},
|
},
|
||||||
"TempStatStageBoosterModifierType": {
|
"TempStatStageBoosterModifierType": {
|
||||||
"description": "提升全队的{{stat}}{{amount}}级,持续5场战斗。",
|
"description": "提升全队的{{stat}}{{amount}},持续5场战斗。",
|
||||||
"extra": {
|
"extra": {
|
||||||
"stage": "1阶",
|
"stage": "1阶",
|
||||||
"percentage": "30%"
|
"percentage": "30%"
|
||||||
@ -63,24 +63,24 @@
|
|||||||
"description": "使一只宝可梦的等级提升{{levels}}级。"
|
"description": "使一只宝可梦的等级提升{{levels}}级。"
|
||||||
},
|
},
|
||||||
"AllPokemonLevelIncrementModifierType": {
|
"AllPokemonLevelIncrementModifierType": {
|
||||||
"description": "使一只寶可夢的等級提升{{levels}}級。"
|
"description": "使所有宝可梦的等级提升{{levels}}级。"
|
||||||
},
|
},
|
||||||
"BaseStatBoosterModifierType": {
|
"BaseStatBoosterModifierType": {
|
||||||
"description": "增加10%持有者的{{stat}},\n个体值越高堆叠上限越高。"
|
"description": "增加10%持有者的{{stat}},\n个体值越高堆叠上限越高。"
|
||||||
},
|
},
|
||||||
"PokemonBaseStatTotalModifierType": {
|
"PokemonBaseStatTotalModifierType": {
|
||||||
"name": "Shuckle Juice",
|
"name": "壶壶果汁",
|
||||||
"description": "{{increaseDecrease}} all of the holder's base stats by {{statValue}}. You were {{blessCurse}} by the Shuckle.",
|
"description": "{{increaseDecrease}}持有者的所有基础属性{{statValue}}级。你被壶壶{{blessCurse}}了。",
|
||||||
"extra": {
|
"extra": {
|
||||||
"increase": "Increases",
|
"increase": "提升",
|
||||||
"decrease": "Decreases",
|
"decrease": "降低",
|
||||||
"blessed": "blessed",
|
"blessed": "强化",
|
||||||
"cursed": "cursed"
|
"cursed": "诅咒"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"PokemonBaseStatFlatModifierType": {
|
"PokemonBaseStatFlatModifierType": {
|
||||||
"name": "Old Gateau",
|
"name": "森之羊羹",
|
||||||
"description": "Increases the holder's {{stats}} base stats by {{statValue}}. Found after a strange dream."
|
"description": "增加持有者{{stats}}的基础属性{{statValue}},来自于一场怪梦。"
|
||||||
},
|
},
|
||||||
"AllPokemonFullHpRestoreModifierType": {
|
"AllPokemonFullHpRestoreModifierType": {
|
||||||
"description": "所有宝可梦完全回复HP。"
|
"description": "所有宝可梦完全回复HP。"
|
||||||
@ -109,7 +109,7 @@
|
|||||||
"description": "招式命中率增加{{accuracyAmount}}(最大100)。"
|
"description": "招式命中率增加{{accuracyAmount}}(最大100)。"
|
||||||
},
|
},
|
||||||
"PokemonMultiHitModifierType": {
|
"PokemonMultiHitModifierType": {
|
||||||
"description": "攻击以60/75/82.5%的伤害造成2/3/4次伤害。"
|
"description": "伤害降低60/75/82.5%的同时造成2/3/4次伤害。"
|
||||||
},
|
},
|
||||||
"TmModifierType": {
|
"TmModifierType": {
|
||||||
"name": "招式学习器\n{{moveId}} - {{moveName}}",
|
"name": "招式学习器\n{{moveId}} - {{moveName}}",
|
||||||
@ -126,7 +126,7 @@
|
|||||||
"description": "使某些宝可梦更改形态。"
|
"description": "使某些宝可梦更改形态。"
|
||||||
},
|
},
|
||||||
"FusePokemonModifierType": {
|
"FusePokemonModifierType": {
|
||||||
"description": "融合两只宝可梦 (改变特性, 平分基础点数\n和属性, 共享招式池)。"
|
"description": "融合两只宝可梦(改变特性, 平分基础点数\n和属性, 共享招式池)。"
|
||||||
},
|
},
|
||||||
"TerastallizeModifierType": {
|
"TerastallizeModifierType": {
|
||||||
"name": "{{teraType}}太晶碎块",
|
"name": "{{teraType}}太晶碎块",
|
||||||
@ -359,8 +359,8 @@
|
|||||||
"description": "触碰后会放出热量的神奇宝珠。\n携带后,在战斗时会变成灼伤状态。"
|
"description": "触碰后会放出热量的神奇宝珠。\n携带后,在战斗时会变成灼伤状态。"
|
||||||
},
|
},
|
||||||
"EVOLUTION_TRACKER_GIMMIGHOUL": {
|
"EVOLUTION_TRACKER_GIMMIGHOUL": {
|
||||||
"name": "金子宝物",
|
"name": "宝藏金币",
|
||||||
"description": "这个小精靈爱金子! 继续挑金子然后谁知道什么会发生!"
|
"description": "这个宝可梦最爱金币!多收集点金币的话会发生什么呢?"
|
||||||
},
|
},
|
||||||
"BATON": {
|
"BATON": {
|
||||||
"name": "接力棒",
|
"name": "接力棒",
|
||||||
@ -421,11 +421,11 @@
|
|||||||
"description": "增加1%野生融合宝可梦出现概率。"
|
"description": "增加1%野生融合宝可梦出现概率。"
|
||||||
},
|
},
|
||||||
|
|
||||||
"MYSTERY_ENCOUNTER_SHUCKLE_JUICE": { "name": "Shuckle Juice" },
|
"MYSTERY_ENCOUNTER_SHUCKLE_JUICE": { "name": "壶壶果汁" },
|
||||||
"MYSTERY_ENCOUNTER_BLACK_SLUDGE": { "name": "Black Sludge", "description": "The stench is so powerful that shops will only sell you items at a steep cost increase." },
|
"MYSTERY_ENCOUNTER_BLACK_SLUDGE": { "name": "黑色污泥", "description": "由于恶臭扑鼻,商店会以非常高昂的价格向您出售商品。" },
|
||||||
"MYSTERY_ENCOUNTER_MACHO_BRACE": { "name": "Macho Brace", "description": "Defeating a Pokémon grants the holder a Macho Brace stack. Each stack slightly boosts stats, with an extra bonus at max stacks." },
|
"MYSTERY_ENCOUNTER_MACHO_BRACE": { "name": "强制锻炼器", "description": "击败对手后获得一层锻炼等级。每层会略微提升属性,\n达到最大层数时还会获得额外奖励。" },
|
||||||
"MYSTERY_ENCOUNTER_OLD_GATEAU": { "name": "Old Gateau", "description": "Increases the holder's {{stats}} stats by {{statValue}}." },
|
"MYSTERY_ENCOUNTER_OLD_GATEAU": { "name": "森之羊羔", "description": "提升持有者的{{stats}}的{{statValue}}。" },
|
||||||
"MYSTERY_ENCOUNTER_GOLDEN_BUG_NET": { "name": "Golden Bug Net", "description": "Imbues the owner with luck to find Bug Type Pokémon more often. Has a strange heft to it." }
|
"MYSTERY_ENCOUNTER_GOLDEN_BUG_NET": { "name": "金捕虫网", "description": "赋予主人好运,使其更容易\n找到虫属性宝可梦,手感很奇妙。" }
|
||||||
},
|
},
|
||||||
"SpeciesBoosterItem": {
|
"SpeciesBoosterItem": {
|
||||||
"LIGHT_BALL": {
|
"LIGHT_BALL": {
|
||||||
|
@ -68,5 +68,5 @@
|
|||||||
"chillyReception": "{{pokemonName}}\n说出了冷笑话!",
|
"chillyReception": "{{pokemonName}}\n说出了冷笑话!",
|
||||||
"exposedMove": "{{pokemonName}}识破了\n{{targetPokemonName}}的原型!",
|
"exposedMove": "{{pokemonName}}识破了\n{{targetPokemonName}}的原型!",
|
||||||
"safeguard": "{{targetName}}\n正受到神秘之幕的保护!",
|
"safeguard": "{{targetName}}\n正受到神秘之幕的保护!",
|
||||||
"afterYou": "{{pokemonName}}\n接受了对手的好意!"
|
"afterYou": "{{targetName}}\n接受了对手的好意!"
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
{
|
{
|
||||||
"intro": "一伙{{delibirdName}}出现了!",
|
"intro": "一伙{{delibirdName}}出现了!",
|
||||||
"title": "信使鸟快递",
|
"title": "信使鸟快递",
|
||||||
"description": "{{delibirdName}}满怀期待地看着你,\n它们好像想要什么东西。\n\n也许给它们一件道具或一些钱能让它们满意?",
|
"description": "{{delibirdName}}满怀期待地看着你,\n它们好像想要什么东西。\n\n给它们一件道具或一些钱的话\n会不会让它们满意呢?",
|
||||||
"query": "你要给它们什么?",
|
"query": "你要给它们什么?",
|
||||||
"invalid_selection": "宝可梦身上并没有那种道具。",
|
"invalid_selection": "宝可梦身上并没有那种道具。",
|
||||||
"option": {
|
"option": {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"intro": "一位提着一大堆购物袋的女士。",
|
"intro": "一位提着一大堆购物袋的女士。",
|
||||||
"speaker": "大促销",
|
"speaker": "大促销",
|
||||||
"intro_dialogue": "你好!你也是来参加促销活动的吗?\n在促销期间,可以领取一张特别优惠券,用于购买免费商品!\n我这有一张多余的优惠券。送你了!",
|
"intro_dialogue": "你好!你也是来参加促销活动的吗?\n在促销期间,可以领取一张特别优惠券!\n可以用于免费兑换商品哦!\n我这有一张多余的优惠券。送你了!",
|
||||||
"title": "百货公司促销",
|
"title": "百货公司促销",
|
||||||
"description": "到处都是商品!\n好像有4个柜台可以让你用优惠券兑换商品。\n无尽可能!",
|
"description": "到处都是商品!\n共有4个柜台可以用优惠券兑换商品。\n好礼多多!",
|
||||||
"query": "你要去哪里?",
|
"query": "你要去哪里?",
|
||||||
"option": {
|
"option": {
|
||||||
"1": {
|
"1": {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"intro": "是GTS系统的交互面板!",
|
"intro": "是GTS系统的交互面板!",
|
||||||
"title": "全球交换系统(GTS)",
|
"title": "全球交换系统(GTS)",
|
||||||
"description": "啊,GTS!科学的奇迹,\\nn你可以与世界各地的任何人联系,\n与他们交换宝可梦!\n今天你的交换会有好运吗?",
|
"description": "啊,GTS!科学的奇迹,\n你可以与世界各地的任何人联系,\n并与他们交换宝可梦!\n今天你的交换运会如何呢?",
|
||||||
"query": "你要怎么做?",
|
"query": "你要怎么做?",
|
||||||
"option": {
|
"option": {
|
||||||
"1": {
|
"1": {
|
||||||
@ -11,13 +11,13 @@
|
|||||||
},
|
},
|
||||||
"2": {
|
"2": {
|
||||||
"label": "奇迹交换",
|
"label": "奇迹交换",
|
||||||
"tooltip": "(+)将一只宝可梦送至GTS,\n并获得一只随机宝可梦"
|
"tooltip": "(+)发送一只宝可梦,\n并获得一只随机宝可梦"
|
||||||
},
|
},
|
||||||
"3": {
|
"3": {
|
||||||
"label": "道具交换",
|
"label": "道具交换",
|
||||||
"trade_options_prompt": "选择要发送的道具",
|
"trade_options_prompt": "选择要发送的道具",
|
||||||
"invalid_selection": "这只宝可梦没有合法道具\n可以被交换。",
|
"invalid_selection": "这只宝可梦没有合法道具\n可以被交换。",
|
||||||
"tooltip": "(+)将你的一件道具发送到GTS并获得一件随机新道具"
|
"tooltip": "(+)发送一件道具\n并获得一件随机新道具"
|
||||||
},
|
},
|
||||||
"4": {
|
"4": {
|
||||||
"label": "离开",
|
"label": "离开",
|
||||||
|
@ -8,19 +8,19 @@
|
|||||||
"1": {
|
"1": {
|
||||||
"label": "轻量训练",
|
"label": "轻量训练",
|
||||||
"tooltip": "(-)轻松战斗\n(+)提升随机2只\n宝可梦的个体",
|
"tooltip": "(-)轻松战斗\n(+)提升随机2只\n宝可梦的个体",
|
||||||
"finished": "{{selectedPokemon}}回来了,感觉\n虽然疲惫不堪,但很有成就!$它的{{stat1}}和{{stat2}}的个体得到了改善!"
|
"finished": "{{selectedPokemon}}回来了,感觉虽然疲惫不堪,\n但很有成就感!$它的{{stat1}}和{{stat2}}的个体得到了改善!"
|
||||||
},
|
},
|
||||||
"2": {
|
"2": {
|
||||||
"label": "适度训练",
|
"label": "适度训练",
|
||||||
"tooltip": "(-)适中的战斗\n(+)改变宝可梦的性格",
|
"tooltip": "(-)适中的战斗\n(+)改变宝可梦的性格",
|
||||||
"select_prompt": "选择一种想要的性格\n来训练你的神奇宝贝。",
|
"select_prompt": "选择一种想要的性格\n来训练你的神奇宝贝。",
|
||||||
"finished": "{{selectedPokemon}}回来了,感觉\n虽然疲惫不堪,但很有成就!$它的性格变成了{{nature}}!"
|
"finished": "{{selectedPokemon}}回来了,感觉虽然疲惫不堪,\n但很有成就感!$它的性格变成了{{nature}}!"
|
||||||
},
|
},
|
||||||
"3": {
|
"3": {
|
||||||
"label": "重磅训练",
|
"label": "重磅训练",
|
||||||
"tooltip": "(-)艰苦的战斗\n(+)改变宝可梦的特性",
|
"tooltip": "(-)艰苦的战斗\n(+)改变宝可梦的特性",
|
||||||
"select_prompt": "选择一种想要的特性\n来训练你的神奇宝贝。",
|
"select_prompt": "选择一种想要的特性\n来训练你的神奇宝贝。",
|
||||||
"finished": "{{selectedPokemon}}回来了,感觉\n虽然疲惫不堪,但很有成就!$它的特性变成了{{nature}}!"
|
"finished": "{{selectedPokemon}}回来了,感觉虽然疲惫不堪,\n但很有成就感!$它的特性变成了{{ability}}!"
|
||||||
},
|
},
|
||||||
"4": {
|
"4": {
|
||||||
"label": "离开",
|
"label": "离开",
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
"2": {
|
"2": {
|
||||||
"label": "探究来源",
|
"label": "探究来源",
|
||||||
"tooltip": "(?)找到垃圾的来源",
|
"tooltip": "(?)找到垃圾的来源",
|
||||||
"selected": "你在这堆东西周围徘徊,寻找表明这东西可能出现在这里的任何迹象……",
|
"selected": "你在这堆东西周围徘徊,\n寻找表明这东西可能出现在这里的任何迹象……",
|
||||||
"selected_2": "突然,垃圾动了!那不是垃圾,是一只宝可梦!"
|
"selected_2": "突然,垃圾动了!那不是垃圾,是一只宝可梦!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"intro": "这可不是一只普通的宝可梦!",
|
"intro": "这可不是一只普通的宝可梦!",
|
||||||
"title": "罕见物种",
|
"title": "罕见物种",
|
||||||
"description": "{{enemyPokemon}}看起来与其他同种宝可梦大相径庭。\n@[TOOLTIP_TITLE]{也许它会特殊招式?}\n你可以直接进行战斗并尝试捕获它,\n但可能也有办法和它交朋友。",
|
"description": "{{enemyPokemon}}看起来\n与其他同种宝可梦大相径庭。\n@[TOOLTIP_TITLE]{也许它会特殊招式?}\n你可以直接进行战斗并尝试捕获它,\n但可能也有办法和它交朋友。",
|
||||||
"query": "你要怎么做?",
|
"query": "你要怎么做?",
|
||||||
"option": {
|
"option": {
|
||||||
"1": {
|
"1": {
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
"ALL": "全部道具",
|
"ALL": "全部道具",
|
||||||
"PASS_BATON": "接棒",
|
"PASS_BATON": "接棒",
|
||||||
"UNPAUSE_EVOLUTION": "解除进化暂停",
|
"UNPAUSE_EVOLUTION": "解除进化暂停",
|
||||||
|
"PAUSE_EVOLUTION": "暂停进化",
|
||||||
"REVIVE": "复活",
|
"REVIVE": "复活",
|
||||||
"RENAME": "起名",
|
"RENAME": "起名",
|
||||||
"SELECT": "选择",
|
"SELECT": "选择",
|
||||||
|
@ -11,6 +11,10 @@
|
|||||||
"expGainsSpeed": "经验值获取动画速度",
|
"expGainsSpeed": "经验值获取动画速度",
|
||||||
"expPartyDisplay": "显示队伍经验",
|
"expPartyDisplay": "显示队伍经验",
|
||||||
"skipSeenDialogues": "跳过已读对话",
|
"skipSeenDialogues": "跳过已读对话",
|
||||||
|
"eggSkip": "孵蛋跳过",
|
||||||
|
"never": "从不",
|
||||||
|
"always": "永久",
|
||||||
|
"ask": "询问",
|
||||||
"battleStyle": "对战模式",
|
"battleStyle": "对战模式",
|
||||||
"enableRetries": "允许重试",
|
"enableRetries": "允许重试",
|
||||||
"hideIvs": "禁用个体值探测器信息",
|
"hideIvs": "禁用个体值探测器信息",
|
||||||
@ -60,9 +64,10 @@
|
|||||||
"playerGender": "玩家性别",
|
"playerGender": "玩家性别",
|
||||||
"typeHints": "属性提示",
|
"typeHints": "属性提示",
|
||||||
"masterVolume": "主音量",
|
"masterVolume": "主音量",
|
||||||
"bgmVolume": "音乐",
|
"bgmVolume": "音乐音量",
|
||||||
"fieldVolume": "场景音量",
|
"fieldVolume": "场景音量",
|
||||||
"seVolume": "音效",
|
"seVolume": "音效音量",
|
||||||
|
"uiVolume": "界面音量",
|
||||||
"musicPreference": "音乐偏好",
|
"musicPreference": "音乐偏好",
|
||||||
"mixed": "全曲混合",
|
"mixed": "全曲混合",
|
||||||
"gamepadPleasePlug": "请链接手柄或按任意键",
|
"gamepadPleasePlug": "请链接手柄或按任意键",
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
"mudSportOnRemove": "玩泥巴的效果消失了!",
|
"mudSportOnRemove": "玩泥巴的效果消失了!",
|
||||||
"waterSportOnAdd": "火焰的威力減弱了!",
|
"waterSportOnAdd": "火焰的威力減弱了!",
|
||||||
"waterSportOnRemove": "玩水的效果消失了!",
|
"waterSportOnRemove": "玩水的效果消失了!",
|
||||||
|
"plasmaFistsOnAdd": "等離子雨傾盆而下!",
|
||||||
"spikesOnAdd": "{{opponentDesc}}腳下\n散落著{{moveName}}!",
|
"spikesOnAdd": "{{opponentDesc}}腳下\n散落著{{moveName}}!",
|
||||||
"spikesActivateTrap": "{{pokemonNameWithAffix}}\n受到了撒菱的傷害!",
|
"spikesActivateTrap": "{{pokemonNameWithAffix}}\n受到了撒菱的傷害!",
|
||||||
"toxicSpikesOnAdd": "{{opponentDesc}}腳下\n散落著{{moveName}}!",
|
"toxicSpikesOnAdd": "{{opponentDesc}}腳下\n散落著{{moveName}}!",
|
||||||
|
@ -68,5 +68,5 @@
|
|||||||
"chillyReception": "{{pokemonName}}\n說了冷笑話!",
|
"chillyReception": "{{pokemonName}}\n說了冷笑話!",
|
||||||
"exposedMove": "{{pokemonName}}識破了\n{{targetPokemonName}}的原形!",
|
"exposedMove": "{{pokemonName}}識破了\n{{targetPokemonName}}的原形!",
|
||||||
"safeguard": "{{targetName}}\n正受到神秘之幕的保護!",
|
"safeguard": "{{targetName}}\n正受到神秘之幕的保護!",
|
||||||
"afterYou": "{{pokemonName}}\n接受了對手的好意!"
|
"afterYou": "{{targetName}}\n接受了對手的好意!"
|
||||||
}
|
}
|
||||||
|
@ -1387,7 +1387,8 @@ export const modifierTypes = {
|
|||||||
FORM_CHANGE_ITEM: () => new FormChangeItemModifierTypeGenerator(false),
|
FORM_CHANGE_ITEM: () => new FormChangeItemModifierTypeGenerator(false),
|
||||||
RARE_FORM_CHANGE_ITEM: () => new FormChangeItemModifierTypeGenerator(true),
|
RARE_FORM_CHANGE_ITEM: () => new FormChangeItemModifierTypeGenerator(true),
|
||||||
|
|
||||||
EVOLUTION_TRACKER_GIMMIGHOUL: () => new PokemonHeldItemModifierType("modifierType:ModifierType.EVOLUTION_TRACKER_GIMMIGHOUL", "relic_gold", (type, _args) => new Modifiers.EvoTrackerModifier(type, (_args[0] as Pokemon).id, Species.GIMMIGHOUL, 10)),
|
EVOLUTION_TRACKER_GIMMIGHOUL: () => new PokemonHeldItemModifierType("modifierType:ModifierType.EVOLUTION_TRACKER_GIMMIGHOUL", "relic_gold",
|
||||||
|
(type, args) => new Modifiers.EvoTrackerModifier(type, (args[0] as Pokemon).id, Species.GIMMIGHOUL, 10)),
|
||||||
|
|
||||||
MEGA_BRACELET: () => new ModifierType("modifierType:ModifierType.MEGA_BRACELET", "mega_bracelet", (type, _args) => new Modifiers.MegaEvolutionAccessModifier(type)),
|
MEGA_BRACELET: () => new ModifierType("modifierType:ModifierType.MEGA_BRACELET", "mega_bracelet", (type, _args) => new Modifiers.MegaEvolutionAccessModifier(type)),
|
||||||
DYNAMAX_BAND: () => new ModifierType("modifierType:ModifierType.DYNAMAX_BAND", "dynamax_band", (type, _args) => new Modifiers.GigantamaxAccessModifier(type)),
|
DYNAMAX_BAND: () => new ModifierType("modifierType:ModifierType.DYNAMAX_BAND", "dynamax_band", (type, _args) => new Modifiers.GigantamaxAccessModifier(type)),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as ModifierTypes from "./modifier-type";
|
import * as ModifierTypes from "./modifier-type";
|
||||||
import { ModifierType, modifierTypes } from "./modifier-type";
|
import { getModifierType, ModifierType, modifierTypes } from "./modifier-type";
|
||||||
import BattleScene from "../battle-scene";
|
import BattleScene from "../battle-scene";
|
||||||
import { getLevelTotalExp } from "../data/exp";
|
import { getLevelTotalExp } from "../data/exp";
|
||||||
import { MAX_PER_TYPE_POKEBALLS, PokeballType } from "../data/pokeball";
|
import { MAX_PER_TYPE_POKEBALLS, PokeballType } from "../data/pokeball";
|
||||||
@ -852,26 +852,47 @@ export class EvoTrackerModifier extends PokemonHeldItemModifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
matchType(modifier: Modifier): boolean {
|
matchType(modifier: Modifier): boolean {
|
||||||
if (modifier instanceof EvoTrackerModifier) {
|
return modifier instanceof EvoTrackerModifier && modifier.species === this.species && modifier.required === this.required;
|
||||||
return (modifier as EvoTrackerModifier).species === this.species;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clone(): PersistentModifier {
|
clone(): PersistentModifier {
|
||||||
return new EvoTrackerModifier(this.type, this.pokemonId, this.species, this.stackCount);
|
return new EvoTrackerModifier(this.type, this.pokemonId, this.species, this.required, this.stackCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
getArgs(): any[] {
|
getArgs(): any[] {
|
||||||
return super.getArgs().concat(this.species);
|
return super.getArgs().concat([this.species, this.required]);
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(args: any[]): boolean {
|
apply(args: any[]): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
getMaxHeldItemCount(_pokemon: Pokemon): integer {
|
getIconStackText(scene: BattleScene, virtual?: boolean): Phaser.GameObjects.BitmapText | null {
|
||||||
return this.required;
|
if (this.getMaxStackCount(scene) === 1 || (virtual && !this.virtualStackCount)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pokemon = scene.getPokemonById(this.pokemonId);
|
||||||
|
|
||||||
|
this.stackCount = pokemon
|
||||||
|
? pokemon.evoCounter + pokemon.getHeldItems().filter(m => m instanceof DamageMoneyRewardModifier).length
|
||||||
|
+ pokemon.scene.findModifiers(m => m instanceof MoneyMultiplierModifier || m instanceof ExtraModifierModifier).length
|
||||||
|
: this.stackCount;
|
||||||
|
|
||||||
|
const text = scene.add.bitmapText(10, 15, "item-count", this.stackCount.toString(), 11);
|
||||||
|
text.letterSpacing = -0.5;
|
||||||
|
if (this.getStackCount() >= this.required) {
|
||||||
|
text.setTint(0xf89890);
|
||||||
|
}
|
||||||
|
text.setOrigin(0, 0);
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
getMaxHeldItemCount(pokemon: Pokemon): integer {
|
||||||
|
this.stackCount = pokemon.evoCounter + pokemon.getHeldItems().filter(m => m instanceof DamageMoneyRewardModifier).length
|
||||||
|
+ pokemon.scene.findModifiers(m => m instanceof MoneyMultiplierModifier || m instanceof ExtraModifierModifier).length;
|
||||||
|
return 999;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2414,9 +2435,8 @@ export class MoneyRewardModifier extends ConsumableModifier {
|
|||||||
|
|
||||||
scene.getParty().map(p => {
|
scene.getParty().map(p => {
|
||||||
if (p.species?.speciesId === Species.GIMMIGHOUL || p.fusionSpecies?.speciesId === Species.GIMMIGHOUL) {
|
if (p.species?.speciesId === Species.GIMMIGHOUL || p.fusionSpecies?.speciesId === Species.GIMMIGHOUL) {
|
||||||
p.evoCounter++;
|
p.evoCounter ? p.evoCounter++ : p.evoCounter = 1;
|
||||||
const modifierType: ModifierType = modifierTypes.EVOLUTION_TRACKER_GIMMIGHOUL();
|
const modifier = getModifierType(modifierTypes.EVOLUTION_TRACKER_GIMMIGHOUL).newModifier(p) as EvoTrackerModifier;
|
||||||
const modifier = modifierType!.newModifier(p);
|
|
||||||
scene.addModifier(modifier);
|
scene.addModifier(modifier);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -2586,7 +2606,7 @@ export class HealShopCostModifier extends PersistentModifier {
|
|||||||
constructor(type: ModifierType, shopMultiplier: number, stackCount?: integer) {
|
constructor(type: ModifierType, shopMultiplier: number, stackCount?: integer) {
|
||||||
super(type, stackCount);
|
super(type, stackCount);
|
||||||
|
|
||||||
this.shopMultiplier = shopMultiplier;
|
this.shopMultiplier = shopMultiplier ?? 2.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
match(modifier: Modifier): boolean {
|
match(modifier: Modifier): boolean {
|
||||||
@ -2598,11 +2618,16 @@ export class HealShopCostModifier extends PersistentModifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
apply(args: any[]): boolean {
|
apply(args: any[]): boolean {
|
||||||
(args[0] as Utils.IntegerHolder).value *= this.shopMultiplier;
|
const moneyCost = args[0] as Utils.NumberHolder;
|
||||||
|
moneyCost.value = Math.floor(moneyCost.value * this.shopMultiplier);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getArgs(): any[] {
|
||||||
|
return super.getArgs().concat(this.shopMultiplier);
|
||||||
|
}
|
||||||
|
|
||||||
getMaxStackCount(scene: BattleScene): integer {
|
getMaxStackCount(scene: BattleScene): integer {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,12 @@ export class BattleEndPhase extends BattlePhase {
|
|||||||
this.scene.unshiftPhase(new GameOverPhase(this.scene, true));
|
this.scene.unshiftPhase(new GameOverPhase(this.scene, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const pokemon of this.scene.getField()) {
|
||||||
|
if (pokemon && pokemon.battleSummonData) {
|
||||||
|
pokemon.battleSummonData.waveTurnCount = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const pokemon of this.scene.getParty().filter(p => p.isAllowedInBattle())) {
|
for (const pokemon of this.scene.getParty().filter(p => p.isAllowedInBattle())) {
|
||||||
applyPostBattleAbAttrs(PostBattleAbAttr, pokemon);
|
applyPostBattleAbAttrs(PostBattleAbAttr, pokemon);
|
||||||
}
|
}
|
||||||
|
@ -1,34 +1,28 @@
|
|||||||
import { clientSessionId } from "#app/account";
|
import { clientSessionId } from "#app/account";
|
||||||
import BattleScene from "#app/battle-scene";
|
|
||||||
import { BattleType } from "#app/battle";
|
import { BattleType } from "#app/battle";
|
||||||
|
import BattleScene from "#app/battle-scene";
|
||||||
import { getCharVariantFromDialogue } from "#app/data/dialogue";
|
import { getCharVariantFromDialogue } from "#app/data/dialogue";
|
||||||
import { pokemonEvolutions } from "#app/data/pokemon-evolutions";
|
import { pokemonEvolutions } from "#app/data/pokemon-evolutions";
|
||||||
import PokemonSpecies, { getPokemonSpecies } from "#app/data/pokemon-species";
|
import PokemonSpecies, { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||||
import { trainerConfigs } from "#app/data/trainer-config";
|
import { trainerConfigs } from "#app/data/trainer-config";
|
||||||
import { PlayerGender } from "#app/enums/player-gender";
|
|
||||||
import { TrainerType } from "#app/enums/trainer-type";
|
|
||||||
import Pokemon from "#app/field/pokemon";
|
import Pokemon from "#app/field/pokemon";
|
||||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||||
|
import { BattlePhase } from "#app/phases/battle-phase";
|
||||||
|
import { CheckSwitchPhase } from "#app/phases/check-switch-phase";
|
||||||
|
import { EncounterPhase } from "#app/phases/encounter-phase";
|
||||||
|
import { EndCardPhase } from "#app/phases/end-card-phase";
|
||||||
|
import { GameOverModifierRewardPhase } from "#app/phases/game-over-modifier-reward-phase";
|
||||||
|
import { PostGameOverPhase } from "#app/phases/post-game-over-phase";
|
||||||
|
import { RibbonModifierRewardPhase } from "#app/phases/ribbon-modifier-reward-phase";
|
||||||
|
import { SummonPhase } from "#app/phases/summon-phase";
|
||||||
|
import { UnlockPhase } from "#app/phases/unlock-phase";
|
||||||
import { achvs, ChallengeAchv } from "#app/system/achv";
|
import { achvs, ChallengeAchv } from "#app/system/achv";
|
||||||
import { Unlockables } from "#app/system/unlockables";
|
import { Unlockables } from "#app/system/unlockables";
|
||||||
import { Mode } from "#app/ui/ui";
|
import { Mode } from "#app/ui/ui";
|
||||||
import i18next from "i18next";
|
|
||||||
import * as Utils from "#app/utils";
|
import * as Utils from "#app/utils";
|
||||||
import { BattlePhase } from "./battle-phase";
|
import { PlayerGender } from "#enums/player-gender";
|
||||||
import { CheckSwitchPhase } from "./check-switch-phase";
|
import { TrainerType } from "#enums/trainer-type";
|
||||||
import { EncounterPhase } from "./encounter-phase";
|
import i18next from "i18next";
|
||||||
import { GameOverModifierRewardPhase } from "./game-over-modifier-reward-phase";
|
|
||||||
import { RibbonModifierRewardPhase } from "./ribbon-modifier-reward-phase";
|
|
||||||
import { SummonPhase } from "./summon-phase";
|
|
||||||
import { EndCardPhase } from "./end-card-phase";
|
|
||||||
import { PostGameOverPhase } from "./post-game-over-phase";
|
|
||||||
import { UnlockPhase } from "./unlock-phase";
|
|
||||||
import { SessionSaveData } from "../system/game-data";
|
|
||||||
import TrainerData from "../system/trainer-data";
|
|
||||||
import PokemonData from "../system/pokemon-data";
|
|
||||||
import PersistentModifierData from "../system/modifier-data";
|
|
||||||
import ChallengeData from "../system/challenge-data";
|
|
||||||
import ArenaData from "../system/arena-data";
|
|
||||||
|
|
||||||
export class GameOverPhase extends BattlePhase {
|
export class GameOverPhase extends BattlePhase {
|
||||||
private victory: boolean;
|
private victory: boolean;
|
||||||
@ -114,7 +108,7 @@ export class GameOverPhase extends BattlePhase {
|
|||||||
this.scene.gameData.gameStats.dailyRunSessionsWon++;
|
this.scene.gameData.gameStats.dailyRunSessionsWon++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.scene.gameData.saveRunHistory(this.scene, this.getFinalSessionData(), this.victory);
|
this.scene.gameData.saveRunHistory(this.scene, this.scene.gameData.getSessionSaveData(this.scene), this.victory);
|
||||||
const fadeDuration = this.victory ? 10000 : 5000;
|
const fadeDuration = this.victory ? 10000 : 5000;
|
||||||
this.scene.fadeOutBgm(fadeDuration, true);
|
this.scene.fadeOutBgm(fadeDuration, true);
|
||||||
const activeBattlers = this.scene.getField().filter(p => p?.isActive(true));
|
const activeBattlers = this.scene.getField().filter(p => p?.isActive(true));
|
||||||
@ -221,34 +215,5 @@ export class GameOverPhase extends BattlePhase {
|
|||||||
this.firstRibbons.push(getPokemonSpecies(pokemon.species.getRootSpeciesId(forStarter)));
|
this.firstRibbons.push(getPokemonSpecies(pokemon.species.getRootSpeciesId(forStarter)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This function mirrors game-data.ts' getSessionSaveData() to update the session data to reflect any changes that occurred within the last wave
|
|
||||||
* This means that level ups, item usage, evolutions, etc. will all be accurately reflected.
|
|
||||||
* @returns {@linkCode SessionSaveData} an updated version of the wave's SessionSaveData that accurately reflects the events of the wave
|
|
||||||
*/
|
|
||||||
private getFinalSessionData(): SessionSaveData {
|
|
||||||
return {
|
|
||||||
seed: this.scene.seed,
|
|
||||||
playTime: this.scene.sessionPlayTime,
|
|
||||||
gameMode: this.scene.gameMode.modeId,
|
|
||||||
party: this.scene.getParty().map(p => new PokemonData(p)),
|
|
||||||
enemyParty: this.scene.getEnemyParty().map(p => new PokemonData(p)),
|
|
||||||
modifiers: this.scene.findModifiers(() => true).map(m => new PersistentModifierData(m, true)),
|
|
||||||
enemyModifiers: this.scene.findModifiers(() => true, false).map(m => new PersistentModifierData(m, false)),
|
|
||||||
arena: new ArenaData(this.scene.arena),
|
|
||||||
pokeballCounts: this.scene.pokeballCounts,
|
|
||||||
money: this.scene.money,
|
|
||||||
score: this.scene.score,
|
|
||||||
waveIndex: this.scene.currentBattle.waveIndex,
|
|
||||||
battleType: this.scene.currentBattle.battleType,
|
|
||||||
trainer: this.scene.currentBattle.battleType === BattleType.TRAINER ? new TrainerData(this.scene.currentBattle.trainer) : null,
|
|
||||||
gameVersion: this.scene.game.config.gameVersion,
|
|
||||||
timestamp: new Date().getTime(),
|
|
||||||
challenges: this.scene.gameMode.challenges.map(c => new ChallengeData(c)),
|
|
||||||
mysteryEncounterType: this.scene.currentBattle.mysteryEncounter?.encounterType ?? -1,
|
|
||||||
mysteryEncounterSaveData: this.scene.mysteryEncounterSaveData
|
|
||||||
} as SessionSaveData;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ import { GameOverPhase } from "#app/phases/game-over-phase";
|
|||||||
import { SwitchPhase } from "#app/phases/switch-phase";
|
import { SwitchPhase } from "#app/phases/switch-phase";
|
||||||
import { SeenEncounterData } from "#app/data/mystery-encounters/mystery-encounter-save-data";
|
import { SeenEncounterData } from "#app/data/mystery-encounters/mystery-encounter-save-data";
|
||||||
import { SwitchType } from "#enums/switch-type";
|
import { SwitchType } from "#enums/switch-type";
|
||||||
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will handle (in order):
|
* Will handle (in order):
|
||||||
@ -218,9 +219,17 @@ export class MysteryEncounterBattleStartCleanupPhase extends Phase {
|
|||||||
start() {
|
start() {
|
||||||
super.start();
|
super.start();
|
||||||
|
|
||||||
|
// Lapse any residual flinches/endures but ignore all other turn-end battle tags
|
||||||
|
const includedLapseTags = [BattlerTagType.FLINCHED, BattlerTagType.ENDURING];
|
||||||
const field = this.scene.getField(true).filter(p => p.summonData);
|
const field = this.scene.getField(true).filter(p => p.summonData);
|
||||||
field.forEach(pokemon => {
|
field.forEach(pokemon => {
|
||||||
pokemon.lapseTags(BattlerTagLapseType.TURN_END);
|
const tags = pokemon.summonData.tags;
|
||||||
|
tags.filter(t => includedLapseTags.includes(t.tagType)
|
||||||
|
&& t.lapseTypes.includes(BattlerTagLapseType.TURN_END)
|
||||||
|
&& !(t.lapse(pokemon, BattlerTagLapseType.TURN_END))).forEach(t => {
|
||||||
|
t.onRemove(pokemon);
|
||||||
|
tags.splice(tags.indexOf(t), 1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remove any status tick phases
|
// Remove any status tick phases
|
||||||
|
@ -46,8 +46,7 @@ export class PokemonHealPhase extends CommonAnimPhase {
|
|||||||
const pokemon = this.getPokemon();
|
const pokemon = this.getPokemon();
|
||||||
|
|
||||||
if (!pokemon.isOnField() || (!this.revive && !pokemon.isActive())) {
|
if (!pokemon.isOnField() || (!this.revive && !pokemon.isActive())) {
|
||||||
super.end();
|
return super.end();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasMessage = !!this.message;
|
const hasMessage = !!this.message;
|
||||||
@ -58,7 +57,7 @@ export class PokemonHealPhase extends CommonAnimPhase {
|
|||||||
if (healBlock && this.hpHealed > 0) {
|
if (healBlock && this.hpHealed > 0) {
|
||||||
this.scene.queueMessage(healBlock.onActivation(pokemon));
|
this.scene.queueMessage(healBlock.onActivation(pokemon));
|
||||||
this.message = null;
|
this.message = null;
|
||||||
super.end();
|
return super.end();
|
||||||
} else if (healOrDamage) {
|
} else if (healOrDamage) {
|
||||||
const hpRestoreMultiplier = new Utils.IntegerHolder(1);
|
const hpRestoreMultiplier = new Utils.IntegerHolder(1);
|
||||||
if (!this.revive) {
|
if (!this.revive) {
|
||||||
|
@ -173,6 +173,7 @@ export class SwitchSummonPhase extends SummonPhase {
|
|||||||
// Or compensate for force switch move if switched out pokemon is not fainted
|
// Or compensate for force switch move if switched out pokemon is not fainted
|
||||||
if (currentCommand === Command.POKEMON || lastPokemonIsForceSwitchedAndNotFainted) {
|
if (currentCommand === Command.POKEMON || lastPokemonIsForceSwitchedAndNotFainted) {
|
||||||
pokemon.battleSummonData.turnCount--;
|
pokemon.battleSummonData.turnCount--;
|
||||||
|
pokemon.battleSummonData.waveTurnCount--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.switchType === SwitchType.BATON_PASS && pokemon) {
|
if (this.switchType === SwitchType.BATON_PASS && pokemon) {
|
||||||
|
@ -44,6 +44,7 @@ export class TurnEndPhase extends FieldPhase {
|
|||||||
this.scene.applyModifiers(TurnHeldItemTransferModifier, pokemon.isPlayer(), pokemon);
|
this.scene.applyModifiers(TurnHeldItemTransferModifier, pokemon.isPlayer(), pokemon);
|
||||||
|
|
||||||
pokemon.battleSummonData.turnCount++;
|
pokemon.battleSummonData.turnCount++;
|
||||||
|
pokemon.battleSummonData.waveTurnCount++;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.executeForAll(handlePokemon);
|
this.executeForAll(handlePokemon);
|
||||||
|
@ -43,20 +43,17 @@ export class TurnStartPhase extends FieldPhase {
|
|||||||
orderedTargets = Utils.randSeedShuffle(orderedTargets);
|
orderedTargets = Utils.randSeedShuffle(orderedTargets);
|
||||||
}, this.scene.currentBattle.turn, this.scene.waveSeed);
|
}, this.scene.currentBattle.turn, this.scene.waveSeed);
|
||||||
|
|
||||||
orderedTargets.sort((a: Pokemon, b: Pokemon) => {
|
// Next, a check for Trick Room is applied to determine sort order.
|
||||||
const aSpeed = a?.getEffectiveStat(Stat.SPD) || 0;
|
|
||||||
const bSpeed = b?.getEffectiveStat(Stat.SPD) || 0;
|
|
||||||
|
|
||||||
return bSpeed - aSpeed;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Next, a check for Trick Room is applied. If Trick Room is present, the order is reversed.
|
|
||||||
const speedReversed = new Utils.BooleanHolder(false);
|
const speedReversed = new Utils.BooleanHolder(false);
|
||||||
this.scene.arena.applyTags(TrickRoomTag, speedReversed);
|
this.scene.arena.applyTags(TrickRoomTag, speedReversed);
|
||||||
|
|
||||||
if (speedReversed.value) {
|
// Adjust the sort function based on whether Trick Room is active.
|
||||||
orderedTargets = orderedTargets.reverse();
|
orderedTargets.sort((a: Pokemon, b: Pokemon) => {
|
||||||
}
|
const aSpeed = a?.getEffectiveStat(Stat.SPD) ?? 0;
|
||||||
|
const bSpeed = b?.getEffectiveStat(Stat.SPD) ?? 0;
|
||||||
|
|
||||||
|
return speedReversed.value ? aSpeed - bSpeed : bSpeed - aSpeed;
|
||||||
|
});
|
||||||
|
|
||||||
return orderedTargets.map(t => t.getFieldIndex() + (!t.isPlayer() ? BattlerIndex.ENEMY : BattlerIndex.PLAYER));
|
return orderedTargets.map(t => t.getFieldIndex() + (!t.isPlayer() ? BattlerIndex.ENEMY : BattlerIndex.PLAYER));
|
||||||
}
|
}
|
||||||
|
@ -957,7 +957,7 @@ export class GameData {
|
|||||||
enemyModifiers: scene.findModifiers(() => true, false).map(m => new PersistentModifierData(m, false)),
|
enemyModifiers: scene.findModifiers(() => true, false).map(m => new PersistentModifierData(m, false)),
|
||||||
arena: new ArenaData(scene.arena),
|
arena: new ArenaData(scene.arena),
|
||||||
pokeballCounts: scene.pokeballCounts,
|
pokeballCounts: scene.pokeballCounts,
|
||||||
money: scene.money,
|
money: Math.floor(scene.money),
|
||||||
score: scene.score,
|
score: scene.score,
|
||||||
waveIndex: scene.currentBattle.waveIndex,
|
waveIndex: scene.currentBattle.waveIndex,
|
||||||
battleType: scene.currentBattle.battleType,
|
battleType: scene.currentBattle.battleType,
|
||||||
@ -1047,7 +1047,7 @@ export class GameData {
|
|||||||
scene.pokeballCounts = Overrides.POKEBALL_OVERRIDE.pokeballs;
|
scene.pokeballCounts = Overrides.POKEBALL_OVERRIDE.pokeballs;
|
||||||
}
|
}
|
||||||
|
|
||||||
scene.money = sessionData.money || 0;
|
scene.money = Math.floor(sessionData.money || 0);
|
||||||
scene.updateMoneyText();
|
scene.updateMoneyText();
|
||||||
|
|
||||||
if (scene.money > this.gameStats.highestMoney) {
|
if (scene.money > this.gameStats.highestMoney) {
|
||||||
|
@ -6,6 +6,10 @@ const LATEST_VERSION = "1.0.5";
|
|||||||
|
|
||||||
export function applySessionDataPatches(data: SessionSaveData) {
|
export function applySessionDataPatches(data: SessionSaveData) {
|
||||||
const curVersion = data.gameVersion;
|
const curVersion = data.gameVersion;
|
||||||
|
|
||||||
|
// Always sanitize money as a safeguard
|
||||||
|
data.money = Math.floor(data.money);
|
||||||
|
|
||||||
if (curVersion !== LATEST_VERSION) {
|
if (curVersion !== LATEST_VERSION) {
|
||||||
switch (curVersion) {
|
switch (curVersion) {
|
||||||
case "1.0.0":
|
case "1.0.0":
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import { BattlerTagType } from "#app/enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { StatusEffect } from "#app/enums/status-effect";
|
import { StatusEffect } from "#enums/status-effect";
|
||||||
import Pokemon from "#app/field/pokemon";
|
import Pokemon from "#app/field/pokemon";
|
||||||
import { BerryPhase } from "#app/phases/berry-phase";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { MoveEndPhase } from "#app/phases/move-end-phase";
|
|
||||||
import { TurnEndPhase } from "#app/phases/turn-end-phase";
|
|
||||||
import { TurnStartPhase } from "#app/phases/turn-start-phase";
|
|
||||||
import GameManager from "#app/test/utils/gameManager";
|
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
@ -53,13 +49,13 @@ describe("Abilities - Gulp Missile", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("changes to Gulping Form if HP is over half when Surf or Dive is used", async () => {
|
it("changes to Gulping Form if HP is over half when Surf or Dive is used", async () => {
|
||||||
await game.startBattle([Species.CRAMORANT]);
|
await game.classicMode.startBattle([Species.CRAMORANT]);
|
||||||
const cramorant = game.scene.getPlayerPokemon()!;
|
const cramorant = game.scene.getPlayerPokemon()!;
|
||||||
|
|
||||||
game.move.select(Moves.DIVE);
|
game.move.select(Moves.DIVE);
|
||||||
await game.toNextTurn();
|
await game.toNextTurn();
|
||||||
game.move.select(Moves.DIVE);
|
game.move.select(Moves.DIVE);
|
||||||
await game.phaseInterceptor.to(MoveEndPhase);
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
|
||||||
expect(cramorant.getHpRatio()).toBeGreaterThanOrEqual(.5);
|
expect(cramorant.getHpRatio()).toBeGreaterThanOrEqual(.5);
|
||||||
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
||||||
@ -67,21 +63,21 @@ describe("Abilities - Gulp Missile", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("changes to Gorging Form if HP is under half when Surf or Dive is used", async () => {
|
it("changes to Gorging Form if HP is under half when Surf or Dive is used", async () => {
|
||||||
await game.startBattle([Species.CRAMORANT]);
|
await game.classicMode.startBattle([Species.CRAMORANT]);
|
||||||
const cramorant = game.scene.getPlayerPokemon()!;
|
const cramorant = game.scene.getPlayerPokemon()!;
|
||||||
|
|
||||||
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.49);
|
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.49);
|
||||||
expect(cramorant.getHpRatio()).toBe(.49);
|
expect(cramorant.getHpRatio()).toBe(.49);
|
||||||
|
|
||||||
game.move.select(Moves.SURF);
|
game.move.select(Moves.SURF);
|
||||||
await game.phaseInterceptor.to(MoveEndPhase);
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
|
||||||
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_PIKACHU)).toBeDefined();
|
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_PIKACHU)).toBeDefined();
|
||||||
expect(cramorant.formIndex).toBe(GORGING_FORM);
|
expect(cramorant.formIndex).toBe(GORGING_FORM);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("changes to base form when switched out after Surf or Dive is used", async () => {
|
it("changes to base form when switched out after Surf or Dive is used", async () => {
|
||||||
await game.startBattle([Species.CRAMORANT, Species.MAGIKARP]);
|
await game.classicMode.startBattle([Species.CRAMORANT, Species.MAGIKARP]);
|
||||||
const cramorant = game.scene.getPlayerPokemon()!;
|
const cramorant = game.scene.getPlayerPokemon()!;
|
||||||
|
|
||||||
game.move.select(Moves.SURF);
|
game.move.select(Moves.SURF);
|
||||||
@ -96,51 +92,51 @@ describe("Abilities - Gulp Missile", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("changes form during Dive's charge turn", async () => {
|
it("changes form during Dive's charge turn", async () => {
|
||||||
await game.startBattle([Species.CRAMORANT]);
|
await game.classicMode.startBattle([Species.CRAMORANT]);
|
||||||
const cramorant = game.scene.getPlayerPokemon()!;
|
const cramorant = game.scene.getPlayerPokemon()!;
|
||||||
|
|
||||||
game.move.select(Moves.DIVE);
|
game.move.select(Moves.DIVE);
|
||||||
await game.phaseInterceptor.to(MoveEndPhase);
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
|
||||||
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
||||||
expect(cramorant.formIndex).toBe(GULPING_FORM);
|
expect(cramorant.formIndex).toBe(GULPING_FORM);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("deals 1/4 of the attacker's maximum HP when hit by a damaging attack", async () => {
|
it("deals 1/4 of the attacker's maximum HP when hit by a damaging attack", async () => {
|
||||||
game.override.enemyMoveset([Moves.TACKLE]);
|
game.override.enemyMoveset(Moves.TACKLE);
|
||||||
await game.startBattle([Species.CRAMORANT]);
|
await game.classicMode.startBattle([Species.CRAMORANT]);
|
||||||
|
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
vi.spyOn(enemy, "damageAndUpdate");
|
vi.spyOn(enemy, "damageAndUpdate");
|
||||||
|
|
||||||
game.move.select(Moves.SURF);
|
game.move.select(Moves.SURF);
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
expect(enemy.damageAndUpdate).toHaveReturnedWith(getEffectDamage(enemy));
|
expect(enemy.damageAndUpdate).toHaveReturnedWith(getEffectDamage(enemy));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not have any effect when hit by non-damaging attack", async () => {
|
it("does not have any effect when hit by non-damaging attack", async () => {
|
||||||
game.override.enemyMoveset([Moves.TAIL_WHIP]);
|
game.override.enemyMoveset(Moves.TAIL_WHIP);
|
||||||
await game.startBattle([Species.CRAMORANT]);
|
await game.classicMode.startBattle([Species.CRAMORANT]);
|
||||||
|
|
||||||
const cramorant = game.scene.getPlayerPokemon()!;
|
const cramorant = game.scene.getPlayerPokemon()!;
|
||||||
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55);
|
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55);
|
||||||
|
|
||||||
game.move.select(Moves.SURF);
|
game.move.select(Moves.SURF);
|
||||||
await game.phaseInterceptor.to(MoveEndPhase);
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
|
||||||
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
||||||
expect(cramorant.formIndex).toBe(GULPING_FORM);
|
expect(cramorant.formIndex).toBe(GULPING_FORM);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
||||||
expect(cramorant.formIndex).toBe(GULPING_FORM);
|
expect(cramorant.formIndex).toBe(GULPING_FORM);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("lowers attacker's DEF stat stage by 1 when hit in Gulping form", async () => {
|
it("lowers attacker's DEF stat stage by 1 when hit in Gulping form", async () => {
|
||||||
game.override.enemyMoveset([Moves.TACKLE]);
|
game.override.enemyMoveset(Moves.TACKLE);
|
||||||
await game.startBattle([Species.CRAMORANT]);
|
await game.classicMode.startBattle([Species.CRAMORANT]);
|
||||||
|
|
||||||
const cramorant = game.scene.getPlayerPokemon()!;
|
const cramorant = game.scene.getPlayerPokemon()!;
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
@ -149,12 +145,12 @@ describe("Abilities - Gulp Missile", () => {
|
|||||||
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55);
|
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55);
|
||||||
|
|
||||||
game.move.select(Moves.SURF);
|
game.move.select(Moves.SURF);
|
||||||
await game.phaseInterceptor.to(MoveEndPhase);
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
|
||||||
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
||||||
expect(cramorant.formIndex).toBe(GULPING_FORM);
|
expect(cramorant.formIndex).toBe(GULPING_FORM);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
expect(enemy.damageAndUpdate).toHaveReturnedWith(getEffectDamage(enemy));
|
expect(enemy.damageAndUpdate).toHaveReturnedWith(getEffectDamage(enemy));
|
||||||
expect(enemy.getStatStage(Stat.DEF)).toBe(-1);
|
expect(enemy.getStatStage(Stat.DEF)).toBe(-1);
|
||||||
@ -163,8 +159,8 @@ describe("Abilities - Gulp Missile", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("paralyzes the enemy when hit in Gorging form", async () => {
|
it("paralyzes the enemy when hit in Gorging form", async () => {
|
||||||
game.override.enemyMoveset([Moves.TACKLE]);
|
game.override.enemyMoveset(Moves.TACKLE);
|
||||||
await game.startBattle([Species.CRAMORANT]);
|
await game.classicMode.startBattle([Species.CRAMORANT]);
|
||||||
|
|
||||||
const cramorant = game.scene.getPlayerPokemon()!;
|
const cramorant = game.scene.getPlayerPokemon()!;
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
@ -173,12 +169,12 @@ describe("Abilities - Gulp Missile", () => {
|
|||||||
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.45);
|
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.45);
|
||||||
|
|
||||||
game.move.select(Moves.SURF);
|
game.move.select(Moves.SURF);
|
||||||
await game.phaseInterceptor.to(MoveEndPhase);
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
|
||||||
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_PIKACHU)).toBeDefined();
|
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_PIKACHU)).toBeDefined();
|
||||||
expect(cramorant.formIndex).toBe(GORGING_FORM);
|
expect(cramorant.formIndex).toBe(GORGING_FORM);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
expect(enemy.damageAndUpdate).toHaveReturnedWith(getEffectDamage(enemy));
|
expect(enemy.damageAndUpdate).toHaveReturnedWith(getEffectDamage(enemy));
|
||||||
expect(enemy.status?.effect).toBe(StatusEffect.PARALYSIS);
|
expect(enemy.status?.effect).toBe(StatusEffect.PARALYSIS);
|
||||||
@ -187,21 +183,21 @@ describe("Abilities - Gulp Missile", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("does not activate the ability when underwater", async () => {
|
it("does not activate the ability when underwater", async () => {
|
||||||
game.override.enemyMoveset([Moves.SURF]);
|
game.override.enemyMoveset(Moves.SURF);
|
||||||
await game.startBattle([Species.CRAMORANT]);
|
await game.classicMode.startBattle([Species.CRAMORANT]);
|
||||||
|
|
||||||
const cramorant = game.scene.getPlayerPokemon()!;
|
const cramorant = game.scene.getPlayerPokemon()!;
|
||||||
|
|
||||||
game.move.select(Moves.DIVE);
|
game.move.select(Moves.DIVE);
|
||||||
await game.phaseInterceptor.to(BerryPhase, false);
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
|
||||||
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
||||||
expect(cramorant.formIndex).toBe(GULPING_FORM);
|
expect(cramorant.formIndex).toBe(GULPING_FORM);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("prevents effect damage but inflicts secondary effect on attacker with Magic Guard", async () => {
|
it("prevents effect damage but inflicts secondary effect on attacker with Magic Guard", async () => {
|
||||||
game.override.enemyMoveset([Moves.TACKLE]).enemyAbility(Abilities.MAGIC_GUARD);
|
game.override.enemyMoveset(Moves.TACKLE).enemyAbility(Abilities.MAGIC_GUARD);
|
||||||
await game.startBattle([Species.CRAMORANT]);
|
await game.classicMode.startBattle([Species.CRAMORANT]);
|
||||||
|
|
||||||
const cramorant = game.scene.getPlayerPokemon()!;
|
const cramorant = game.scene.getPlayerPokemon()!;
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
@ -209,13 +205,13 @@ describe("Abilities - Gulp Missile", () => {
|
|||||||
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55);
|
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55);
|
||||||
|
|
||||||
game.move.select(Moves.SURF);
|
game.move.select(Moves.SURF);
|
||||||
await game.phaseInterceptor.to(MoveEndPhase);
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
const enemyHpPreEffect = enemy.hp;
|
const enemyHpPreEffect = enemy.hp;
|
||||||
|
|
||||||
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
||||||
expect(cramorant.formIndex).toBe(GULPING_FORM);
|
expect(cramorant.formIndex).toBe(GULPING_FORM);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
expect(enemy.hp).toBe(enemyHpPreEffect);
|
expect(enemy.hp).toBe(enemyHpPreEffect);
|
||||||
expect(enemy.getStatStage(Stat.DEF)).toBe(-1);
|
expect(enemy.getStatStage(Stat.DEF)).toBe(-1);
|
||||||
@ -223,20 +219,36 @@ describe("Abilities - Gulp Missile", () => {
|
|||||||
expect(cramorant.formIndex).toBe(NORMAL_FORM);
|
expect(cramorant.formIndex).toBe(NORMAL_FORM);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("activates on faint", async () => {
|
||||||
|
game.override.enemyMoveset(Moves.THUNDERBOLT);
|
||||||
|
await game.classicMode.startBattle([Species.CRAMORANT]);
|
||||||
|
|
||||||
|
const cramorant = game.scene.getPlayerPokemon()!;
|
||||||
|
|
||||||
|
game.move.select(Moves.SURF);
|
||||||
|
await game.phaseInterceptor.to("FaintPhase");
|
||||||
|
|
||||||
|
expect(cramorant.hp).toBe(0);
|
||||||
|
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeUndefined();
|
||||||
|
expect(cramorant.formIndex).toBe(NORMAL_FORM);
|
||||||
|
expect(game.scene.getEnemyPokemon()!.getStatStage(Stat.DEF)).toBe(-1);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
it("cannot be suppressed", async () => {
|
it("cannot be suppressed", async () => {
|
||||||
game.override.enemyMoveset([Moves.GASTRO_ACID]);
|
game.override.enemyMoveset(Moves.GASTRO_ACID);
|
||||||
await game.startBattle([Species.CRAMORANT]);
|
await game.classicMode.startBattle([Species.CRAMORANT]);
|
||||||
|
|
||||||
const cramorant = game.scene.getPlayerPokemon()!;
|
const cramorant = game.scene.getPlayerPokemon()!;
|
||||||
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55);
|
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55);
|
||||||
|
|
||||||
game.move.select(Moves.SURF);
|
game.move.select(Moves.SURF);
|
||||||
await game.phaseInterceptor.to(MoveEndPhase);
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
|
||||||
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
||||||
expect(cramorant.formIndex).toBe(GULPING_FORM);
|
expect(cramorant.formIndex).toBe(GULPING_FORM);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
expect(cramorant.hasAbility(Abilities.GULP_MISSILE)).toBe(true);
|
expect(cramorant.hasAbility(Abilities.GULP_MISSILE)).toBe(true);
|
||||||
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
||||||
@ -244,19 +256,19 @@ describe("Abilities - Gulp Missile", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("cannot be swapped with another ability", async () => {
|
it("cannot be swapped with another ability", async () => {
|
||||||
game.override.enemyMoveset([Moves.SKILL_SWAP]);
|
game.override.enemyMoveset(Moves.SKILL_SWAP);
|
||||||
await game.startBattle([Species.CRAMORANT]);
|
await game.classicMode.startBattle([Species.CRAMORANT]);
|
||||||
|
|
||||||
const cramorant = game.scene.getPlayerPokemon()!;
|
const cramorant = game.scene.getPlayerPokemon()!;
|
||||||
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55);
|
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55);
|
||||||
|
|
||||||
game.move.select(Moves.SURF);
|
game.move.select(Moves.SURF);
|
||||||
await game.phaseInterceptor.to(MoveEndPhase);
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
|
||||||
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
||||||
expect(cramorant.formIndex).toBe(GULPING_FORM);
|
expect(cramorant.formIndex).toBe(GULPING_FORM);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
expect(cramorant.hasAbility(Abilities.GULP_MISSILE)).toBe(true);
|
expect(cramorant.hasAbility(Abilities.GULP_MISSILE)).toBe(true);
|
||||||
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
||||||
@ -266,9 +278,9 @@ describe("Abilities - Gulp Missile", () => {
|
|||||||
it("cannot be copied", async () => {
|
it("cannot be copied", async () => {
|
||||||
game.override.enemyAbility(Abilities.TRACE);
|
game.override.enemyAbility(Abilities.TRACE);
|
||||||
|
|
||||||
await game.startBattle([Species.CRAMORANT]);
|
await game.classicMode.startBattle([Species.CRAMORANT]);
|
||||||
game.move.select(Moves.SPLASH);
|
game.move.select(Moves.SPLASH);
|
||||||
await game.phaseInterceptor.to(TurnStartPhase);
|
await game.phaseInterceptor.to("TurnStartPhase");
|
||||||
|
|
||||||
expect(game.scene.getEnemyPokemon()?.hasAbility(Abilities.GULP_MISSILE)).toBe(false);
|
expect(game.scene.getEnemyPokemon()?.hasAbility(Abilities.GULP_MISSILE)).toBe(false);
|
||||||
});
|
});
|
||||||
|
@ -3,6 +3,7 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
|||||||
import GameManager from "../utils/gameManager";
|
import GameManager from "../utils/gameManager";
|
||||||
import { PokeballType } from "#app/enums/pokeball";
|
import { PokeballType } from "#app/enums/pokeball";
|
||||||
import BattleScene from "#app/battle-scene";
|
import BattleScene from "#app/battle-scene";
|
||||||
|
import { Moves } from "#app/enums/moves";
|
||||||
|
|
||||||
describe("Spec - Pokemon", () => {
|
describe("Spec - Pokemon", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
@ -63,4 +64,15 @@ describe("Spec - Pokemon", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should not share tms between different forms", async () => {
|
||||||
|
game.override.starterForms({ [Species.ROTOM]: 4 });
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([Species.ROTOM]);
|
||||||
|
|
||||||
|
const fanRotom = game.scene.getPlayerPokemon()!;
|
||||||
|
|
||||||
|
expect(fanRotom.compatibleTms).not.toContain(Moves.BLIZZARD);
|
||||||
|
expect(fanRotom.compatibleTms).toContain(Moves.AIR_SLASH);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -4,6 +4,7 @@ import { Species } from "#enums/species";
|
|||||||
import { WeatherType } from "#enums/weather-type";
|
import { WeatherType } from "#enums/weather-type";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
|
//import { TurnInitPhase } from "#app/phases/turn-init-phase";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
describe("Moves - Chilly Reception", () => {
|
describe("Moves - Chilly Reception", () => {
|
||||||
@ -66,4 +67,58 @@ describe("Moves - Chilly Reception", () => {
|
|||||||
expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.SNOW);
|
expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.SNOW);
|
||||||
expect(game.scene.getPlayerField()[0].species.speciesId).toBe(Species.MEOWTH);
|
expect(game.scene.getPlayerField()[0].species.speciesId).toBe(Species.MEOWTH);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// enemy uses another move and weather doesn't change
|
||||||
|
it("check case - enemy not selecting chilly reception doesn't change weather ", async () => {
|
||||||
|
game.override.battleType("single")
|
||||||
|
.enemyMoveset([Moves.CHILLY_RECEPTION, Moves.TACKLE])
|
||||||
|
.enemyAbility(Abilities.NONE)
|
||||||
|
.moveset(Array(4).fill(Moves.SPLASH));
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([Species.SLOWKING, Species.MEOWTH]);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.forceEnemyMove(Moves.TACKLE);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
expect(game.scene.arena.weather?.weatherType).toBe(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("enemy trainer - expected behavior ", async () => {
|
||||||
|
game.override.battleType("single")
|
||||||
|
.startingWave(8)
|
||||||
|
.enemyMoveset(Array(4).fill(Moves.CHILLY_RECEPTION))
|
||||||
|
.enemyAbility(Abilities.NONE)
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.moveset([Moves.SPLASH, Moves.THUNDERBOLT]);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([Species.JOLTEON]);
|
||||||
|
const RIVAL_MAGIKARP1 = game.scene.getEnemyPokemon()?.id;
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.SNOW);
|
||||||
|
expect(game.scene.getEnemyPokemon()?.id !== RIVAL_MAGIKARP1);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("TurnInitPhase", false);
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
|
||||||
|
// second chilly reception should still switch out
|
||||||
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.SNOW);
|
||||||
|
await game.phaseInterceptor.to("TurnInitPhase", false);
|
||||||
|
expect(game.scene.getEnemyPokemon()?.id === RIVAL_MAGIKARP1);
|
||||||
|
game.move.select(Moves.THUNDERBOLT);
|
||||||
|
|
||||||
|
// enemy chilly recep move should fail: it's snowing and no option to switch out
|
||||||
|
// no crashing
|
||||||
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.SNOW);
|
||||||
|
await game.phaseInterceptor.to("TurnInitPhase", false);
|
||||||
|
expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.SNOW);
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.SNOW);
|
||||||
|
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -23,14 +23,15 @@ describe("Moves - Fake Out", () => {
|
|||||||
game.override
|
game.override
|
||||||
.battleType("single")
|
.battleType("single")
|
||||||
.enemySpecies(Species.CORVIKNIGHT)
|
.enemySpecies(Species.CORVIKNIGHT)
|
||||||
.starterSpecies(Species.FEEBAS)
|
|
||||||
.moveset([Moves.FAKE_OUT, Moves.SPLASH])
|
.moveset([Moves.FAKE_OUT, Moves.SPLASH])
|
||||||
.enemyMoveset(Moves.SPLASH)
|
.enemyMoveset(Moves.SPLASH)
|
||||||
|
.enemyLevel(10)
|
||||||
|
.startingLevel(10) // prevent LevelUpPhase from happening
|
||||||
.disableCrits();
|
.disableCrits();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("can only be used on the first turn a pokemon is sent out", async() => {
|
it("can only be used on the first turn a pokemon is sent out in a battle", async() => {
|
||||||
await game.classicMode.startBattle();
|
await game.classicMode.startBattle([Species.FEEBAS]);
|
||||||
|
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
@ -44,22 +45,27 @@ describe("Moves - Fake Out", () => {
|
|||||||
await game.toNextTurn();
|
await game.toNextTurn();
|
||||||
|
|
||||||
expect(enemy.hp).toBe(postTurnOneHp);
|
expect(enemy.hp).toBe(postTurnOneHp);
|
||||||
|
}, 20000);
|
||||||
|
|
||||||
game.move.select(Moves.SPLASH);
|
// This is a PokeRogue buff to Fake Out
|
||||||
await game.doKillOpponents();
|
it("can be used at the start of every wave even if the pokemon wasn't recalled", async() => {
|
||||||
|
await game.classicMode.startBattle([Species.FEEBAS]);
|
||||||
|
|
||||||
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
|
enemy.damageAndUpdate(enemy.getMaxHp() - 1);
|
||||||
|
|
||||||
|
game.move.select(Moves.FAKE_OUT);
|
||||||
await game.toNextWave();
|
await game.toNextWave();
|
||||||
|
|
||||||
const newEnemy = game.scene.getEnemyPokemon()!;
|
|
||||||
|
|
||||||
game.move.select(Moves.FAKE_OUT);
|
game.move.select(Moves.FAKE_OUT);
|
||||||
await game.toNextTurn();
|
await game.toNextTurn();
|
||||||
|
|
||||||
expect(newEnemy.hp).toBe(newEnemy.getMaxHp());
|
expect(game.scene.getEnemyPokemon()!.isFullHp()).toBe(false);
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
it("can be used again if recalled and sent back out", async() => {
|
it("can be used again if recalled and sent back out", async() => {
|
||||||
game.override.startingWave(4);
|
game.override.startingWave(4);
|
||||||
await game.classicMode.startBattle();
|
await game.classicMode.startBattle([Species.FEEBAS, Species.MAGIKARP]);
|
||||||
|
|
||||||
const enemy1 = game.scene.getEnemyPokemon()!;
|
const enemy1 = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
@ -76,6 +82,18 @@ describe("Moves - Fake Out", () => {
|
|||||||
|
|
||||||
const enemy2 = game.scene.getEnemyPokemon()!;
|
const enemy2 = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
expect(enemy2.hp).toBeLessThan(enemy2.getMaxHp());
|
||||||
|
enemy2.hp = enemy2.getMaxHp();
|
||||||
|
|
||||||
|
game.doSwitchPokemon(1);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
game.doSwitchPokemon(1);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
game.move.select(Moves.FAKE_OUT);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
expect(enemy2.hp).toBeLessThan(enemy2.getMaxHp());
|
expect(enemy2.hp).toBeLessThan(enemy2.getMaxHp());
|
||||||
}, 20000);
|
}, 20000);
|
||||||
});
|
});
|
||||||
|
98
src/test/moves/plasma_fists.test.ts
Normal file
98
src/test/moves/plasma_fists.test.ts
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
import { Type } from "#app/data/type";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, it, expect, vi } from "vitest";
|
||||||
|
|
||||||
|
describe("Moves - Plasma Fists", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({
|
||||||
|
type: Phaser.HEADLESS,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
game.override
|
||||||
|
.moveset([Moves.PLASMA_FISTS, Moves.TACKLE])
|
||||||
|
.battleType("double")
|
||||||
|
.startingLevel(100)
|
||||||
|
.enemySpecies(Species.DUSCLOPS)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset(Moves.TACKLE)
|
||||||
|
.enemyLevel(100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should convert all subsequent Normal-type attacks to Electric-type", async () => {
|
||||||
|
await game.classicMode.startBattle([Species.DUSCLOPS, Species.BLASTOISE]);
|
||||||
|
|
||||||
|
const field = game.scene.getField(true);
|
||||||
|
field.forEach(p => vi.spyOn(p, "getMoveType"));
|
||||||
|
|
||||||
|
game.move.select(Moves.PLASMA_FISTS, 0, BattlerIndex.ENEMY);
|
||||||
|
game.move.select(Moves.TACKLE, 1, BattlerIndex.ENEMY_2);
|
||||||
|
|
||||||
|
await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER);
|
||||||
|
await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2);
|
||||||
|
|
||||||
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
|
||||||
|
field.forEach(p => {
|
||||||
|
expect(p.getMoveType).toHaveLastReturnedWith(Type.ELECTRIC);
|
||||||
|
expect(p.hp).toBeLessThan(p.getMaxHp());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not affect Normal-type attacks boosted by Pixilate", async () => {
|
||||||
|
game.override
|
||||||
|
.battleType("single")
|
||||||
|
.enemyAbility(Abilities.PIXILATE);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([Species.ONIX]);
|
||||||
|
|
||||||
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
vi.spyOn(enemyPokemon, "getMoveType");
|
||||||
|
|
||||||
|
game.move.select(Moves.PLASMA_FISTS);
|
||||||
|
|
||||||
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
|
||||||
|
expect(enemyPokemon.getMoveType).toHaveLastReturnedWith(Type.FAIRY);
|
||||||
|
expect(playerPokemon.hp).toBeLessThan(playerPokemon.getMaxHp());
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should affect moves that become Normal type due to Normalize", async () => {
|
||||||
|
game.override
|
||||||
|
.battleType("single")
|
||||||
|
.enemyAbility(Abilities.NORMALIZE)
|
||||||
|
.enemyMoveset(Moves.WATER_GUN);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([Species.DUSCLOPS]);
|
||||||
|
|
||||||
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
vi.spyOn(enemyPokemon, "getMoveType");
|
||||||
|
|
||||||
|
game.move.select(Moves.PLASMA_FISTS);
|
||||||
|
|
||||||
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
|
||||||
|
expect(enemyPokemon.getMoveType).toHaveLastReturnedWith(Type.ELECTRIC);
|
||||||
|
expect(playerPokemon.hp).toBeLessThan(playerPokemon.getMaxHp());
|
||||||
|
});
|
||||||
|
});
|
@ -1,13 +1,15 @@
|
|||||||
import { BattlerIndex } from "#app/battle";
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
import { ArenaTagSide } from "#app/data/arena-tag";
|
||||||
import { SubstituteTag, TrappedTag } from "#app/data/battler-tags";
|
import { SubstituteTag, TrappedTag } from "#app/data/battler-tags";
|
||||||
import { allMoves, StealHeldItemChanceAttr } from "#app/data/move";
|
import { allMoves, StealHeldItemChanceAttr } from "#app/data/move";
|
||||||
import { StatusEffect } from "#app/data/status-effect";
|
import { StatusEffect } from "#app/data/status-effect";
|
||||||
import { Abilities } from "#app/enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { BattlerTagType } from "#app/enums/battler-tag-type";
|
import { ArenaTagType } from "#enums/arena-tag-type";
|
||||||
import { BerryType } from "#app/enums/berry-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { Moves } from "#app/enums/moves";
|
import { BerryType } from "#enums/berry-type";
|
||||||
import { Species } from "#app/enums/species";
|
import { Moves } from "#enums/moves";
|
||||||
import { Stat } from "#app/enums/stat";
|
import { Species } from "#enums/species";
|
||||||
|
import { Stat } from "#enums/stat";
|
||||||
import { MoveResult } from "#app/field/pokemon";
|
import { MoveResult } from "#app/field/pokemon";
|
||||||
import { CommandPhase } from "#app/phases/command-phase";
|
import { CommandPhase } from "#app/phases/command-phase";
|
||||||
import GameManager from "#app/test/utils/gameManager";
|
import GameManager from "#app/test/utils/gameManager";
|
||||||
@ -194,6 +196,71 @@ describe("Moves - Substitute", () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
"shouldn't block moves that target the user's side of the field",
|
||||||
|
async () => {
|
||||||
|
game.override.moveset(Moves.LIGHT_SCREEN);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([Species.BLASTOISE]);
|
||||||
|
|
||||||
|
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
vi.spyOn(leadPokemon, "getMoveEffectiveness");
|
||||||
|
|
||||||
|
leadPokemon.addTag(BattlerTagType.SUBSTITUTE, 0, Moves.NONE, leadPokemon.id);
|
||||||
|
|
||||||
|
game.move.select(Moves.LIGHT_SCREEN);
|
||||||
|
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
expect(leadPokemon.getMoveEffectiveness).not.toHaveReturnedWith(0);
|
||||||
|
expect(game.scene.arena.getTagOnSide(ArenaTagType.LIGHT_SCREEN, ArenaTagSide.PLAYER)).toBeDefined();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
"shouldn't block the opponent from setting hazards",
|
||||||
|
async () => {
|
||||||
|
game.override.enemyMoveset(Moves.STEALTH_ROCK);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([Species.BLASTOISE]);
|
||||||
|
|
||||||
|
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
vi.spyOn(leadPokemon, "getMoveEffectiveness");
|
||||||
|
|
||||||
|
game.move.select(Moves.SUBSTITUTE);
|
||||||
|
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
expect(leadPokemon.getMoveEffectiveness).not.toHaveReturnedWith(0);
|
||||||
|
expect(game.scene.arena.getTagOnSide(ArenaTagType.STEALTH_ROCK, ArenaTagSide.PLAYER)).toBeDefined();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
"shouldn't block moves that target both sides of the field",
|
||||||
|
async () => {
|
||||||
|
game.override
|
||||||
|
.moveset(Moves.TRICK_ROOM)
|
||||||
|
.enemyMoveset(Moves.GRAVITY);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([Species.BLASTOISE]);
|
||||||
|
|
||||||
|
const pokemon = game.scene.getField(true);
|
||||||
|
pokemon.forEach(p => {
|
||||||
|
vi.spyOn(p, "getMoveEffectiveness");
|
||||||
|
p.addTag(BattlerTagType.SUBSTITUTE, 0, Moves.NONE, p.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
game.move.select(Moves.TRICK_ROOM);
|
||||||
|
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
pokemon.forEach(p => expect(p.getMoveEffectiveness).not.toHaveReturnedWith(0));
|
||||||
|
expect(game.scene.arena.getTag(ArenaTagType.TRICK_ROOM)).toBeDefined();
|
||||||
|
expect(game.scene.arena.getTag(ArenaTagType.GRAVITY)).toBeDefined();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
it(
|
it(
|
||||||
"should protect the user from flinching",
|
"should protect the user from flinching",
|
||||||
async () => {
|
async () => {
|
||||||
|
82
src/test/moves/syrup_bomb.test.ts
Normal file
82
src/test/moves/syrup_bomb.test.ts
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import { allMoves } from "#app/data/move";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
|
import { Stat } from "#enums/stat";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
describe("Moves - SYRUP BOMB", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({
|
||||||
|
type: Phaser.HEADLESS,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
game.override
|
||||||
|
.starterSpecies(Species.MAGIKARP)
|
||||||
|
.enemySpecies(Species.SNORLAX)
|
||||||
|
.startingLevel(30)
|
||||||
|
.enemyLevel(100)
|
||||||
|
.moveset([Moves.SYRUP_BOMB, Moves.SPLASH])
|
||||||
|
.enemyMoveset(Moves.SPLASH);
|
||||||
|
vi.spyOn(allMoves[Moves.SYRUP_BOMB], "accuracy", "get").mockReturnValue(100);
|
||||||
|
});
|
||||||
|
|
||||||
|
//Bulbapedia Reference: https://bulbapedia.bulbagarden.net/wiki/syrup_bomb_(move)
|
||||||
|
|
||||||
|
it("decreases the target Pokemon's speed stat once per turn for 3 turns",
|
||||||
|
async () => {
|
||||||
|
await game.startBattle([Species.MAGIKARP]);
|
||||||
|
|
||||||
|
const targetPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
expect(targetPokemon.getStatStage(Stat.SPD)).toBe(0);
|
||||||
|
|
||||||
|
game.move.select(Moves.SYRUP_BOMB);
|
||||||
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||||
|
await game.move.forceHit();
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(targetPokemon.getTag(BattlerTagType.SYRUP_BOMB)).toBeDefined();
|
||||||
|
expect(targetPokemon.getStatStage(Stat.SPD)).toBe(-1);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(targetPokemon.getTag(BattlerTagType.SYRUP_BOMB)).toBeDefined();
|
||||||
|
expect(targetPokemon.getStatStage(Stat.SPD)).toBe(-2);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(targetPokemon.getTag(BattlerTagType.SYRUP_BOMB)).toBeUndefined();
|
||||||
|
expect(targetPokemon.getStatStage(Stat.SPD)).toBe(-3);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it("does not affect Pokemon with the ability Bulletproof",
|
||||||
|
async () => {
|
||||||
|
game.override.enemyAbility(Abilities.BULLETPROOF);
|
||||||
|
await game.startBattle([Species.MAGIKARP]);
|
||||||
|
|
||||||
|
const targetPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
game.move.select(Moves.SYRUP_BOMB);
|
||||||
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||||
|
await game.move.forceHit();
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(targetPokemon.isFullHp()).toBe(true);
|
||||||
|
expect(targetPokemon.getTag(BattlerTagType.SYRUP_BOMB)).toBeUndefined();
|
||||||
|
expect(targetPokemon.getStatStage(Stat.SPD)).toBe(0);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
@ -303,7 +303,7 @@ export default class GameManager {
|
|||||||
|
|
||||||
vi.spyOn(enemy, "getNextMove").mockReturnValueOnce({
|
vi.spyOn(enemy, "getNextMove").mockReturnValueOnce({
|
||||||
move: moveId,
|
move: moveId,
|
||||||
targets: (target && !legalTargets.multiple && legalTargets.targets.includes(target))
|
targets: (target !== undefined && !legalTargets.multiple && legalTargets.targets.includes(target))
|
||||||
? [target]
|
? [target]
|
||||||
: enemy.getNextTargets(moveId)
|
: enemy.getNextTargets(moveId)
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import BattleScene from "#app/battle-scene";
|
import BattleScene from "#app/battle-scene";
|
||||||
import { TextStyle, addTextObject } from "#app/ui/text";
|
import { TextStyle, addTextObject } from "#app/ui/text";
|
||||||
|
import { nil } from "#app/utils";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
|
||||||
export enum EventType {
|
export enum EventType {
|
||||||
@ -64,19 +65,19 @@ export class TimedEventManager {
|
|||||||
let multiplier = 1;
|
let multiplier = 1;
|
||||||
const shinyEvents = timedEvents.filter((te) => te.eventType === EventType.SHINY && this.isActive(te));
|
const shinyEvents = timedEvents.filter((te) => te.eventType === EventType.SHINY && this.isActive(te));
|
||||||
shinyEvents.forEach((se) => {
|
shinyEvents.forEach((se) => {
|
||||||
multiplier *= se.shinyMultiplier!; // TODO: is this bang correct?
|
multiplier *= se.shinyMultiplier ?? 1;
|
||||||
});
|
});
|
||||||
|
|
||||||
return multiplier;
|
return multiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
getEventBannerFilename(): string {
|
getEventBannerFilename(): string {
|
||||||
return timedEvents.find((te: TimedEvent) => this.isActive(te))?.bannerKey!; // TODO: is this bang correct?
|
return timedEvents.find((te: TimedEvent) => this.isActive(te))?.bannerKey ?? "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TimedEventDisplay extends Phaser.GameObjects.Container {
|
export class TimedEventDisplay extends Phaser.GameObjects.Container {
|
||||||
private event: TimedEvent | null;
|
private event: TimedEvent | nil;
|
||||||
private eventTimerText: Phaser.GameObjects.Text;
|
private eventTimerText: Phaser.GameObjects.Text;
|
||||||
private banner: Phaser.GameObjects.Image;
|
private banner: Phaser.GameObjects.Image;
|
||||||
private bannerShadow: Phaser.GameObjects.Rectangle;
|
private bannerShadow: Phaser.GameObjects.Rectangle;
|
||||||
@ -84,7 +85,7 @@ export class TimedEventDisplay extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
constructor(scene: BattleScene, x: number, y: number, event?: TimedEvent) {
|
constructor(scene: BattleScene, x: number, y: number, event?: TimedEvent) {
|
||||||
super(scene, x, y);
|
super(scene, x, y);
|
||||||
this.event = event!; // TODO: is this bang correct?
|
this.event = event;
|
||||||
this.setVisible(false);
|
this.setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,8 +99,9 @@ export default class EggSummaryUiHandler extends MessageUiHandler {
|
|||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
super.clear();
|
super.clear();
|
||||||
this.cursor = -1;
|
|
||||||
this.scrollGridHandler.reset();
|
this.scrollGridHandler.reset();
|
||||||
|
this.cursor = -1;
|
||||||
|
|
||||||
this.summaryContainer.setVisible(false);
|
this.summaryContainer.setVisible(false);
|
||||||
this.pokemonIconsContainer.removeAll(true);
|
this.pokemonIconsContainer.removeAll(true);
|
||||||
this.pokemonContainers = [];
|
this.pokemonContainers = [];
|
||||||
@ -164,8 +165,8 @@ export default class EggSummaryUiHandler extends MessageUiHandler {
|
|||||||
|
|
||||||
this.scrollGridHandler.setTotalElements(this.eggHatchData.length);
|
this.scrollGridHandler.setTotalElements(this.eggHatchData.length);
|
||||||
this.updatePokemonIcons();
|
this.updatePokemonIcons();
|
||||||
|
|
||||||
this.setCursor(0);
|
this.setCursor(0);
|
||||||
|
|
||||||
this.scene.playSoundWithoutBgm("evolution_fanfare");
|
this.scene.playSoundWithoutBgm("evolution_fanfare");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import { TextStyle, addTextObject, getTextStyleOptions } from "./text";
|
|||||||
import { getSplashMessages } from "../data/splash-messages";
|
import { getSplashMessages } from "../data/splash-messages";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { TimedEventDisplay } from "#app/timed-event-manager";
|
import { TimedEventDisplay } from "#app/timed-event-manager";
|
||||||
|
import { version } from "../../package.json";
|
||||||
|
|
||||||
export default class TitleUiHandler extends OptionSelectUiHandler {
|
export default class TitleUiHandler extends OptionSelectUiHandler {
|
||||||
/** If the stats can not be retrieved, use this fallback value */
|
/** If the stats can not be retrieved, use this fallback value */
|
||||||
@ -16,6 +17,7 @@ export default class TitleUiHandler extends OptionSelectUiHandler {
|
|||||||
private splashMessage: string;
|
private splashMessage: string;
|
||||||
private splashMessageText: Phaser.GameObjects.Text;
|
private splashMessageText: Phaser.GameObjects.Text;
|
||||||
private eventDisplay: TimedEventDisplay;
|
private eventDisplay: TimedEventDisplay;
|
||||||
|
private appVersionText: Phaser.GameObjects.Text;
|
||||||
|
|
||||||
private titleStatsTimer: NodeJS.Timeout | null;
|
private titleStatsTimer: NodeJS.Timeout | null;
|
||||||
|
|
||||||
@ -68,6 +70,11 @@ export default class TitleUiHandler extends OptionSelectUiHandler {
|
|||||||
loop: -1,
|
loop: -1,
|
||||||
yoyo: true,
|
yoyo: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.appVersionText = addTextObject(this.scene, logo.x - 60, logo.y + logo.displayHeight + 4, "", TextStyle.MONEY, { fontSize: "54px" });
|
||||||
|
this.appVersionText.setOrigin(0.5, 0.5);
|
||||||
|
this.appVersionText.setAngle(0);
|
||||||
|
this.titleContainer.add(this.appVersionText);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTitleStats(): void {
|
updateTitleStats(): void {
|
||||||
@ -91,6 +98,8 @@ export default class TitleUiHandler extends OptionSelectUiHandler {
|
|||||||
this.splashMessage = Utils.randItem(getSplashMessages());
|
this.splashMessage = Utils.randItem(getSplashMessages());
|
||||||
this.splashMessageText.setText(i18next.t(this.splashMessage, { count: TitleUiHandler.BATTLES_WON_FALLBACK }));
|
this.splashMessageText.setText(i18next.t(this.splashMessage, { count: TitleUiHandler.BATTLES_WON_FALLBACK }));
|
||||||
|
|
||||||
|
this.appVersionText.setText("v"+version);
|
||||||
|
|
||||||
const ui = this.getUi();
|
const ui = this.getUi();
|
||||||
|
|
||||||
if (this.scene.eventManager.isEventActive()) {
|
if (this.scene.eventManager.isEventActive()) {
|
||||||
|
@ -2,6 +2,8 @@ import { MoneyFormat } from "#enums/money-format";
|
|||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
|
||||||
|
export type nil = null | undefined;
|
||||||
|
|
||||||
export const MissingTextureKey = "__MISSING";
|
export const MissingTextureKey = "__MISSING";
|
||||||
|
|
||||||
export function toReadableString(str: string): string {
|
export function toReadableString(str: string): string {
|
||||||
@ -443,7 +445,7 @@ export function deltaRgb(rgb1: integer[], rgb2: integer[]): integer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function rgbHexToRgba(hex: string) {
|
export function rgbHexToRgba(hex: string) {
|
||||||
const color = hex.match(/^([\da-f]{2})([\da-f]{2})([\da-f]{2})$/i)!; // TODO: is this bang correct?
|
const color = hex.match(/^([\da-f]{2})([\da-f]{2})([\da-f]{2})$/i) ?? ["000000", "00", "00", "00"];
|
||||||
return {
|
return {
|
||||||
r: parseInt(color[1], 16),
|
r: parseInt(color[1], 16),
|
||||||
g: parseInt(color[2], 16),
|
g: parseInt(color[2], 16),
|
||||||
|
Loading…
Reference in New Issue
Block a user