Merge branch 'beta' into deep-sea-items
|
@ -4,4 +4,19 @@
|
|||
* @pagefaultgames/junior-dev-team
|
||||
|
||||
# github actions/templates etc. - Dev Leads
|
||||
/.github @pagefaultgames/dev-leads
|
||||
/.github @pagefaultgames/senior-dev-team
|
||||
|
||||
# Art Team
|
||||
/public/**/*.png @pagefaultgames/art-team
|
||||
/public/**/*.json @pagefaultgames/art-team
|
||||
/public/images @pagefaultgames/art-team
|
||||
/public/battle-anims @pagefaultgames/art-team
|
||||
|
||||
# Audio files
|
||||
*.mp3 @pagefaultgames/composer-team
|
||||
*.wav @pagefaultgames/composer-team
|
||||
*.ogg @pagefaultgames/composer-team
|
||||
/public/audio @pagefaultgames/composer-team
|
||||
|
||||
# Balance Files; contain actual code logic and must also be owned by dev team
|
||||
/src/data/balance @pagefaultgames/balance-team @pagefaultgames/junior-dev-team
|
|
@ -133,7 +133,7 @@
|
|||
<span class="apad-label">V</span>
|
||||
</div>
|
||||
<!-- buttons to display battle-specific information -->
|
||||
<div id="apadInfo" class="apad-button apad-rectangle apad-small" data-key="V">
|
||||
<div id="apadInfo" class="apad-button apad-rectangle apad-small" data-key="CYCLE_TERA">
|
||||
<span class="apad-label">V</span>
|
||||
</div>
|
||||
<div id="apadStats" class="apad-button apad-rectangle apad-small" data-key="STATS">
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "pokemon-rogue-battle",
|
||||
"version": "1.7.0",
|
||||
"version": "1.7.6",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pokemon-rogue-battle",
|
||||
"version": "1.7.0",
|
||||
"version": "1.7.6",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@material/material-color-utilities": "^0.2.7",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "pokemon-rogue-battle",
|
||||
"private": true,
|
||||
"version": "1.7.0",
|
||||
"version": "1.7.6",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "vite",
|
||||
|
|
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 507 B After Width: | Height: | Size: 528 B |
|
@ -3,12 +3,12 @@
|
|||
"838394": "4d7dc5",
|
||||
"62ace6": "8363af",
|
||||
"7bcdff": "9c75c2",
|
||||
"ffec8c": "ddfff9",
|
||||
"fdea88": "ddfff9",
|
||||
"a1a1c4": "7ab7ec",
|
||||
"c9b241": "97d6e2",
|
||||
"dfcf77": "bae7e8",
|
||||
"ccbd70": "bae7e8",
|
||||
"174592": "37408c",
|
||||
"fdfdfd": "b1e5ff",
|
||||
"f8f8f8": "b1e5ff",
|
||||
"9c9cc5": "5385c7",
|
||||
"cdcde6": "7eb7e8",
|
||||
"396a83": "362864",
|
||||
|
@ -18,12 +18,12 @@
|
|||
"838394": "cc6845",
|
||||
"62ace6": "c44848",
|
||||
"7bcdff": "dd6155",
|
||||
"ffec8c": "ddfff9",
|
||||
"fdea88": "ddfff9",
|
||||
"a1a1c4": "f7c685",
|
||||
"c9b241": "97d6e2",
|
||||
"dfcf77": "bae7e8",
|
||||
"ccbd70": "bae7e8",
|
||||
"174592": "198158",
|
||||
"fdfdfd": "fff4bd",
|
||||
"f8f8f8": "fff4bd",
|
||||
"9c9cc5": "c96a48",
|
||||
"cdcde6": "f7b785",
|
||||
"396a83": "5c0d33",
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
{
|
||||
"1": {
|
||||
"838394": "4d7dc5",
|
||||
"848496": "4d7dc5",
|
||||
"7bcdff": "9c75c2",
|
||||
"62ace6": "8363af",
|
||||
"ffffff": "b1e5ff",
|
||||
"396a83": "362864",
|
||||
"9c9cc5": "5385c7",
|
||||
"cdcde6": "7eb7e8",
|
||||
"174592": "198158",
|
||||
"174592": "37408c",
|
||||
"5a94cd": "7054a4"
|
||||
},
|
||||
"2": {
|
||||
"838394": "cc6845",
|
||||
"848496": "cc6845",
|
||||
"7bcdff": "dd6155",
|
||||
"62ace6": "c44848",
|
||||
"ffffff": "fff4bd",
|
||||
|
|
After Width: | Height: | Size: 253 B |
After Width: | Height: | Size: 262 B |
|
@ -1 +1 @@
|
|||
Subproject commit ef43efffe5fe454862c350f1b9393c3ad755bcc2
|
||||
Subproject commit 0e5c6096ba26f6b87aed1aab3fe9b0b23f6cbb7b
|
|
@ -1865,6 +1865,58 @@ export default class BattleScene extends SceneBase {
|
|||
this.getCurrentPhase()?.constructor.name ?? "",
|
||||
);
|
||||
|
||||
if ( // Give trainers with specialty types an appropriately-typed form for Wormadam, Rotom, Arceus, Oricorio, Silvally, or Paldean Tauros.
|
||||
!isEggPhase &&
|
||||
this.currentBattle?.battleType === BattleType.TRAINER && !isNullOrUndefined(this.currentBattle.trainer) &&
|
||||
this.currentBattle.trainer.config.hasSpecialtyType()
|
||||
) {
|
||||
if (species.speciesId === Species.WORMADAM) {
|
||||
switch (this.currentBattle.trainer.config.specialtyType) {
|
||||
case Type.GROUND:
|
||||
return 1; // Sandy Cloak
|
||||
case Type.STEEL:
|
||||
return 2; // Trash Cloak
|
||||
case Type.GRASS:
|
||||
return 0; // Plant Cloak
|
||||
}
|
||||
} else if (species.speciesId === Species.ROTOM) {
|
||||
switch (this.currentBattle.trainer.config.specialtyType) {
|
||||
case Type.FLYING:
|
||||
return 4; // Fan Rotom
|
||||
case Type.GHOST:
|
||||
return 0; // Lightbulb Rotom
|
||||
case Type.FIRE:
|
||||
return 1; // Heat Rotom
|
||||
case Type.GRASS:
|
||||
return 5; // Mow Rotom
|
||||
case Type.WATER:
|
||||
return 2; // Wash Rotom
|
||||
case Type.ICE:
|
||||
return 3; // Frost Rotom
|
||||
}
|
||||
} else if (species.speciesId === Species.ORICORIO) {
|
||||
switch (this.currentBattle.trainer.config.specialtyType) {
|
||||
case Type.GHOST:
|
||||
return 3; // Sensu Style
|
||||
case Type.FIRE:
|
||||
return 0; // Baile Style
|
||||
case Type.ELECTRIC:
|
||||
return 1; // Pom-Pom Style
|
||||
case Type.PSYCHIC:
|
||||
return 2; // Pa'u Style
|
||||
}
|
||||
} else if (species.speciesId === Species.PALDEA_TAUROS) {
|
||||
switch (this.currentBattle.trainer.config.specialtyType) {
|
||||
case Type.FIRE:
|
||||
return 1; // Blaze Breed
|
||||
case Type.WATER:
|
||||
return 2; // Aqua Breed
|
||||
}
|
||||
} else if (species.speciesId === Species.SILVALLY || species.speciesId === Species.ARCEUS) { // Would probably never happen, but might as well
|
||||
return this.currentBattle.trainer.config.specialtyType;
|
||||
}
|
||||
}
|
||||
|
||||
switch (species.speciesId) {
|
||||
case Species.UNOWN:
|
||||
case Species.SHELLOS:
|
||||
|
@ -1872,8 +1924,6 @@ export default class BattleScene extends SceneBase {
|
|||
case Species.BASCULIN:
|
||||
case Species.DEERLING:
|
||||
case Species.SAWSBUCK:
|
||||
case Species.FROAKIE:
|
||||
case Species.FROGADIER:
|
||||
case Species.SCATTERBUG:
|
||||
case Species.SPEWPA:
|
||||
case Species.VIVILLON:
|
||||
|
@ -1907,9 +1957,14 @@ export default class BattleScene extends SceneBase {
|
|||
return 0; // No Partner Eevee for Wave 12 Preschoolers
|
||||
}
|
||||
return Utils.randSeedInt(2);
|
||||
case Species.FROAKIE:
|
||||
case Species.FROGADIER:
|
||||
case Species.GRENINJA:
|
||||
if (this.currentBattle?.battleType === BattleType.TRAINER) {
|
||||
return 0; // Don't give trainers Battle Bond Greninja
|
||||
if (
|
||||
this.currentBattle?.battleType === BattleType.TRAINER &&
|
||||
!isEggPhase
|
||||
) {
|
||||
return 0; // Don't give trainers Battle Bond Greninja, Froakie or Frogadier
|
||||
}
|
||||
return Utils.randSeedInt(2);
|
||||
case Species.URSHIFU:
|
||||
|
@ -3448,8 +3503,6 @@ export default class BattleScene extends SceneBase {
|
|||
for (const modifier of modifiers) {
|
||||
this.addEnemyModifier(modifier, true, true);
|
||||
}
|
||||
|
||||
this.currentBattle.trainer.genAI(party);
|
||||
}
|
||||
|
||||
party.forEach((enemyPokemon: EnemyPokemon, i: number) => {
|
||||
|
|
|
@ -12,7 +12,7 @@ import { getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffect
|
|||
import { Gender } from "./gender";
|
||||
import type Move from "./move";
|
||||
import { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, NeutralDamageAgainstFlyingTypeMultiplierAttr, FixedDamageAttr } from "./move";
|
||||
import type { ArenaTrapTag } from "./arena-tag";
|
||||
import type { ArenaTrapTag, SuppressAbilitiesTag } from "./arena-tag";
|
||||
import { ArenaTagSide } from "./arena-tag";
|
||||
import { BerryModifier, HitHealModifier, PokemonHeldItemModifier } from "../modifier/modifier";
|
||||
import { TerrainType } from "./terrain";
|
||||
|
@ -2197,6 +2197,34 @@ export class PostSummonRemoveArenaTagAbAttr extends PostSummonAbAttr {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic class to add an arena tag upon switching in
|
||||
*/
|
||||
export class PostSummonAddArenaTagAbAttr extends PostSummonAbAttr {
|
||||
private readonly tagType: ArenaTagType;
|
||||
private readonly turnCount: number;
|
||||
private readonly side?: ArenaTagSide;
|
||||
private readonly quiet?: boolean;
|
||||
private sourceId: number;
|
||||
|
||||
|
||||
constructor(tagType: ArenaTagType, turnCount: number, side?: ArenaTagSide, quiet?: boolean) {
|
||||
super(false);
|
||||
this.tagType = tagType;
|
||||
this.turnCount = turnCount;
|
||||
this.side = side;
|
||||
this.quiet = quiet;
|
||||
}
|
||||
|
||||
public override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean {
|
||||
this.sourceId = pokemon.id;
|
||||
if (!simulated) {
|
||||
globalScene.arena.addTag(this.tagType, this.turnCount, undefined, this.sourceId, this.side, this.quiet);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export class PostSummonMessageAbAttr extends PostSummonAbAttr {
|
||||
private messageFunc: (pokemon: Pokemon) => string;
|
||||
|
||||
|
@ -2941,6 +2969,26 @@ export class PreLeaveFieldClearWeatherAbAttr extends PreLeaveFieldAbAttr {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the active {@linkcode SuppressAbilitiesTag} when a pokemon with {@linkcode Abilities.NEUTRALIZING_GAS} leaves the field
|
||||
*/
|
||||
export class PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr extends PreLeaveFieldAbAttr {
|
||||
constructor() {
|
||||
super(false);
|
||||
}
|
||||
|
||||
public override applyPreLeaveField(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean {
|
||||
if (!simulated) {
|
||||
const suppressTag = globalScene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS) as SuppressAbilitiesTag;
|
||||
if (suppressTag) {
|
||||
suppressTag.onSourceLeave(globalScene.arena);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return simulated;
|
||||
}
|
||||
}
|
||||
|
||||
export class PreStatStageChangeAbAttr extends AbAttr {
|
||||
applyPreStatStageChange(
|
||||
pokemon: Pokemon | null,
|
||||
|
@ -4692,21 +4740,6 @@ export class MoveAbilityBypassAbAttr extends AbAttr {
|
|||
}
|
||||
}
|
||||
|
||||
export class SuppressFieldAbilitiesAbAttr extends AbAttr {
|
||||
constructor() {
|
||||
super(false);
|
||||
}
|
||||
|
||||
apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||
const ability = (args[0] as Ability);
|
||||
if (!ability.hasAttr(UnsuppressableAbilityAbAttr) && !ability.hasAttr(SuppressFieldAbilitiesAbAttr)) {
|
||||
cancelled.value = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export class AlwaysHitAbAttr extends AbAttr { }
|
||||
|
||||
/** Attribute for abilities that allow moves that make contact to ignore protection (i.e. Unseen Fist) */
|
||||
|
@ -5021,7 +5054,7 @@ export class PreventBypassSpeedChanceAbAttr extends AbAttr {
|
|||
const turnCommand = globalScene.currentBattle.turnCommands[pokemon.getBattlerIndex()];
|
||||
const isCommandFight = turnCommand?.command === Command.FIGHT;
|
||||
const move = turnCommand?.move?.move ? allMoves[turnCommand.move.move] : null;
|
||||
if (this.condition(pokemon, move!) && isCommandFight) {
|
||||
if (isCommandFight && this.condition(pokemon, move!)) {
|
||||
bypassSpeed.value = false;
|
||||
canCheckHeldItems.value = false;
|
||||
return false;
|
||||
|
@ -5119,6 +5152,10 @@ function applySingleAbAttrs<TAttr extends AbAttr>(
|
|||
showAbilityInstant: boolean = false,
|
||||
messages: string[] = []
|
||||
) {
|
||||
if (!pokemon?.canApplyAbility(passive) || (passive && (pokemon.getPassiveAbility().id === pokemon.getAbility().id))) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ability = passive ? pokemon.getPassiveAbility() : pokemon.getAbility();
|
||||
if (gainedMidTurn && ability.getAttrs(attrType).some(attr => attr instanceof PostSummonAbAttr && !attr.shouldActivateOnGain())) {
|
||||
return;
|
||||
|
@ -5412,12 +5449,10 @@ function applyAbAttrsInternal<TAttr extends AbAttr>(
|
|||
gainedMidTurn: boolean = false
|
||||
) {
|
||||
for (const passive of [ false, true ]) {
|
||||
if (!pokemon?.canApplyAbility(passive) || (passive && (pokemon.getPassiveAbility().id === pokemon.getAbility().id))) {
|
||||
continue;
|
||||
if (pokemon) {
|
||||
applySingleAbAttrs(pokemon, passive, attrType, applyFunc, args, gainedMidTurn, simulated, showAbilityInstant, messages);
|
||||
globalScene.clearPhaseQueueSplice();
|
||||
}
|
||||
|
||||
applySingleAbAttrs(pokemon, passive, attrType, applyFunc, args, gainedMidTurn, simulated, showAbilityInstant, messages);
|
||||
globalScene.clearPhaseQueueSplice();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5946,10 +5981,10 @@ export function applyOnGainAbAttrs(pokemon: Pokemon, passive: boolean = false, s
|
|||
}
|
||||
|
||||
/**
|
||||
* Clears primal weather during the turn if {@linkcode pokemon}'s ability corresponds to one
|
||||
* Clears primal weather/neutralizing gas during the turn if {@linkcode pokemon}'s ability corresponds to one
|
||||
*/
|
||||
export function applyOnLoseClearWeatherAbAttrs(pokemon: Pokemon, passive: boolean = false, simulated: boolean = false, ...args: any[]): void {
|
||||
applySingleAbAttrs<PreLeaveFieldClearWeatherAbAttr>(pokemon, passive, PreLeaveFieldClearWeatherAbAttr, (attr, passive) => attr.applyPreLeaveField(pokemon, passive, simulated, [ ...args, true ]), args, true, simulated);
|
||||
export function applyOnLoseAbAttrs(pokemon: Pokemon, passive: boolean = false, simulated: boolean = false, ...args: any[]): void {
|
||||
applySingleAbAttrs<PreLeaveFieldAbAttr>(pokemon, passive, PreLeaveFieldAbAttr, (attr, passive) => attr.applyPreLeaveField(pokemon, passive, simulated, [ ...args, true ]), args, true, simulated);
|
||||
}
|
||||
function queueShowAbility(pokemon: Pokemon, passive: boolean): void {
|
||||
globalScene.unshiftPhase(new ShowAbilityPhase(pokemon.id, passive));
|
||||
|
@ -6838,12 +6873,12 @@ export function initAbilities() {
|
|||
new Ability(Abilities.GORILLA_TACTICS, 8)
|
||||
.attr(GorillaTacticsAbAttr),
|
||||
new Ability(Abilities.NEUTRALIZING_GAS, 8)
|
||||
.attr(SuppressFieldAbilitiesAbAttr)
|
||||
.attr(PostSummonAddArenaTagAbAttr, ArenaTagType.NEUTRALIZING_GAS, 0)
|
||||
.attr(PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr)
|
||||
.attr(UncopiableAbilityAbAttr)
|
||||
.attr(UnswappableAbilityAbAttr)
|
||||
.attr(NoTransformAbilityAbAttr)
|
||||
.attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => i18next.t("abilityTriggers:postSummonNeutralizingGas", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }))
|
||||
.partial(), // A bunch of weird interactions with other abilities being suppressed then unsuppressed
|
||||
.bypassFaint(),
|
||||
new Ability(Abilities.PASTEL_VEIL, 8)
|
||||
.attr(PostSummonUserFieldRemoveStatusEffectAbAttr, StatusEffect.POISON, StatusEffect.TOXIC)
|
||||
.attr(UserFieldStatusEffectImmunityAbAttr, StatusEffect.POISON, StatusEffect.TOXIC)
|
||||
|
|
|
@ -8,7 +8,7 @@ import type Pokemon from "#app/field/pokemon";
|
|||
import { HitResult, PokemonMove } from "#app/field/pokemon";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
import type { BattlerIndex } from "#app/battle";
|
||||
import { BlockNonDirectDamageAbAttr, InfiltratorAbAttr, ProtectStatAbAttr, applyAbAttrs } from "#app/data/ability";
|
||||
import { BlockNonDirectDamageAbAttr, InfiltratorAbAttr, PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr, ProtectStatAbAttr, applyAbAttrs, applyOnGainAbAttrs, applyOnLoseAbAttrs } from "#app/data/ability";
|
||||
import { Stat } from "#enums/stat";
|
||||
import { CommonAnim, CommonBattleAnim } from "#app/data/battle-anims";
|
||||
import i18next from "i18next";
|
||||
|
@ -1221,6 +1221,76 @@ export class FairyLockTag extends ArenaTag {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Arena tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Neutralizing_Gas_(Ability) Neutralizing Gas}
|
||||
*
|
||||
* Keeps track of the number of pokemon on the field with Neutralizing Gas - If it drops to zero, the effect is ended and abilities are reactivated
|
||||
*
|
||||
* Additionally ends onLose abilities when it is activated
|
||||
*/
|
||||
export class SuppressAbilitiesTag extends ArenaTag {
|
||||
private sourceCount: number;
|
||||
private beingRemoved: boolean;
|
||||
|
||||
constructor(sourceId: number) {
|
||||
super(ArenaTagType.NEUTRALIZING_GAS, 0, undefined, sourceId);
|
||||
this.sourceCount = 1;
|
||||
this.beingRemoved = false;
|
||||
}
|
||||
|
||||
public override onAdd(arena: Arena): void {
|
||||
const pokemon = this.getSourcePokemon();
|
||||
if (pokemon) {
|
||||
globalScene.queueMessage(i18next.t("arenaTag:neutralizingGasOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||
|
||||
for (const fieldPokemon of globalScene.getField()) {
|
||||
if (fieldPokemon && fieldPokemon.id !== pokemon.id) {
|
||||
[ true, false ].forEach((passive) => applyOnLoseAbAttrs(fieldPokemon, passive));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override onOverlap(arena: Arena): void {
|
||||
this.sourceCount++;
|
||||
}
|
||||
|
||||
public onSourceLeave(arena: Arena): void {
|
||||
this.sourceCount--;
|
||||
if (this.sourceCount <= 0) {
|
||||
arena.removeTag(ArenaTagType.NEUTRALIZING_GAS);
|
||||
} else if (this.sourceCount === 1) {
|
||||
// With 1 source left, that pokemon's other abilities should reactivate
|
||||
// This may be confusing for players but would be the most accurate gameplay-wise
|
||||
// Could have a custom message that plays when a specific pokemon's NG ends? This entire thing exists due to passives after all
|
||||
const setter = globalScene.getField().filter((p) => p && p.hasAbilityWithAttr(PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr, false))[0];
|
||||
applyOnGainAbAttrs(setter, setter.getAbility().hasAttr(PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr));
|
||||
}
|
||||
}
|
||||
|
||||
public override onRemove(arena: Arena, quiet: boolean = false) {
|
||||
this.beingRemoved = true;
|
||||
if (!quiet) {
|
||||
globalScene.queueMessage(i18next.t("arenaTag:neutralizingGasOnRemove"));
|
||||
}
|
||||
|
||||
for (const pokemon of globalScene.getField()) {
|
||||
// There is only one pokemon with this attr on the field on removal, so its abilities are already active
|
||||
if (pokemon && !pokemon.hasAbilityWithAttr(PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr, false)) {
|
||||
[ true, false ].forEach((passive) => applyOnGainAbAttrs(pokemon, passive));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public shouldApplyToSelf(): boolean {
|
||||
return this.sourceCount > 1;
|
||||
}
|
||||
|
||||
public isBeingRemoved() {
|
||||
return this.beingRemoved;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: swap `sourceMove` and `sourceId` and make `sourceMove` an optional parameter
|
||||
export function getArenaTag(tagType: ArenaTagType, turnCount: number, sourceMove: Moves | undefined, sourceId: number, targetIndex?: BattlerIndex, side: ArenaTagSide = ArenaTagSide.BOTH): ArenaTag | null {
|
||||
switch (tagType) {
|
||||
|
@ -1281,6 +1351,8 @@ export function getArenaTag(tagType: ArenaTagType, turnCount: number, sourceMove
|
|||
return new GrassWaterPledgeTag(sourceId, side);
|
||||
case ArenaTagType.FAIRY_LOCK:
|
||||
return new FairyLockTag(turnCount, sourceId);
|
||||
case ArenaTagType.NEUTRALIZING_GAS:
|
||||
return new SuppressAbilitiesTag(sourceId);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ export const speciesEggMoves = {
|
|||
[Species.DROWZEE]: [ Moves.BADDY_BAD, Moves.STRENGTH_SAP, Moves.LUMINA_CRASH, Moves.DARK_VOID ],
|
||||
[Species.KRABBY]: [ Moves.DIRE_CLAW, Moves.DRAGON_HAMMER, Moves.IVY_CUDGEL, Moves.JET_PUNCH ],
|
||||
[Species.VOLTORB]: [ Moves.NASTY_PLOT, Moves.FUSION_FLARE, Moves.FROST_BREATH, Moves.ELECTRO_DRIFT ],
|
||||
[Species.EXEGGCUTE]: [ Moves.FICKLE_BEAM, Moves.APPLE_ACID, Moves.TRICK_ROOM, Moves.LUMINA_CRASH ],
|
||||
[Species.EXEGGCUTE]: [ Moves.FICKLE_BEAM, Moves.APPLE_ACID, Moves.HEAT_WAVE, Moves.LUMINA_CRASH ],
|
||||
[Species.CUBONE]: [ Moves.HEAD_SMASH, Moves.WOOD_HAMMER, Moves.SHADOW_SNEAK, Moves.BITTER_BLADE ],
|
||||
[Species.LICKITUNG]: [ Moves.CRUSH_GRIP, Moves.FIRE_LASH, Moves.SLACK_OFF, Moves.MAGICAL_TORQUE ],
|
||||
[Species.KOFFING]: [ Moves.SCALD, Moves.RECOVER, Moves.BODY_PRESS, Moves.MALIGNANT_CHAIN ],
|
||||
|
@ -59,7 +59,7 @@ export const speciesEggMoves = {
|
|||
[Species.SCYTHER]: [ Moves.MIGHTY_CLEAVE, Moves.GEAR_GRIND, Moves.STORM_THROW, Moves.BITTER_BLADE ],
|
||||
[Species.PINSIR]: [ Moves.HEADLONG_RUSH, Moves.LEECH_LIFE, Moves.CRUSH_GRIP, Moves.EXTREME_SPEED ],
|
||||
[Species.TAUROS]: [ Moves.SWORDS_DANCE, Moves.FIRE_LASH, Moves.WICKED_TORQUE, Moves.COLLISION_COURSE ],
|
||||
[Species.MAGIKARP]: [ Moves.FLIP_TURN, Moves.ICE_SPINNER, Moves.DRAGON_ASCENT, Moves.SURGING_STRIKES ],
|
||||
[Species.MAGIKARP]: [ Moves.FLIP_TURN, Moves.ICE_SPINNER, Moves.KNOCK_OFF, Moves.DRAGON_ASCENT ],
|
||||
[Species.LAPRAS]: [ Moves.RECOVER, Moves.FREEZE_DRY, Moves.SCALD, Moves.SHELL_SMASH ],
|
||||
[Species.DITTO]: [ Moves.MIMIC, Moves.SKETCH, Moves.METRONOME, Moves.IMPRISON ],
|
||||
[Species.EEVEE]: [ Moves.WISH, Moves.NO_RETREAT, Moves.ZIPPY_ZAP, Moves.BOOMBURST ],
|
||||
|
@ -76,7 +76,7 @@ export const speciesEggMoves = {
|
|||
|
||||
[Species.CHIKORITA]: [ Moves.SAPPY_SEED, Moves.STONE_AXE, Moves.DRAGON_DANCE, Moves.SPORE ],
|
||||
[Species.CYNDAQUIL]: [ Moves.NASTY_PLOT, Moves.EARTH_POWER, Moves.FIERY_DANCE, Moves.ELECTRO_DRIFT ],
|
||||
[Species.TOTODILE]: [ Moves.THUNDER_PUNCH, Moves.DRAGON_DANCE, Moves.TRIPLE_AXEL, Moves.SURGING_STRIKES ],
|
||||
[Species.TOTODILE]: [ Moves.THUNDER_PUNCH, Moves.DRAGON_DANCE, Moves.PLAY_ROUGH, Moves.SURGING_STRIKES ],
|
||||
[Species.SENTRET]: [ Moves.TIDY_UP, Moves.FAKE_OUT, Moves.NUZZLE, Moves.EXTREME_SPEED ],
|
||||
[Species.HOOTHOOT]: [ Moves.CALM_MIND, Moves.ESPER_WING, Moves.AEROBLAST, Moves.BOOMBURST ],
|
||||
[Species.LEDYBA]: [ Moves.POLLEN_PUFF, Moves.MAT_BLOCK, Moves.PARTING_SHOT, Moves.SPORE ],
|
||||
|
@ -159,7 +159,7 @@ export const speciesEggMoves = {
|
|||
[Species.VOLBEAT]: [ Moves.BATON_PASS, Moves.STICKY_WEB, Moves.DECORATE, Moves.VICTORY_DANCE ],
|
||||
[Species.ILLUMISE]: [ Moves.PARTING_SHOT, Moves.GLITZY_GLOW, Moves.POWDER, Moves.QUIVER_DANCE ],
|
||||
[Species.GULPIN]: [ Moves.MALIGNANT_CHAIN, Moves.EARTH_POWER, Moves.CALM_MIND, Moves.STRENGTH_SAP ],
|
||||
[Species.CARVANHA]: [ Moves.THUNDER_FANG, Moves.SWORDS_DANCE, Moves.OBSTRUCT, Moves.SURGING_STRIKES ],
|
||||
[Species.CARVANHA]: [ Moves.THUNDER_FANG, Moves.GUNK_SHOT, Moves.OBSTRUCT, Moves.SURGING_STRIKES ],
|
||||
[Species.WAILMER]: [ Moves.TAKE_HEART, Moves.COMEUPPANCE, Moves.SLACK_OFF, Moves.STEAM_ERUPTION ],
|
||||
[Species.NUMEL]: [ Moves.TRICK_ROOM, Moves.ENERGY_BALL, Moves.SLACK_OFF, Moves.BLUE_FLARE ],
|
||||
[Species.TORKOAL]: [ Moves.MORNING_SUN, Moves.BURNING_BULWARK, Moves.BODY_PRESS, Moves.HYDRO_STEAM ],
|
||||
|
@ -235,7 +235,7 @@ export const speciesEggMoves = {
|
|||
[Species.RIOLU]: [ Moves.THUNDEROUS_KICK, Moves.TACHYON_CUTTER, Moves.TRIPLE_AXEL, Moves.SUNSTEEL_STRIKE ],
|
||||
[Species.HIPPOPOTAS]: [ Moves.SHORE_UP, Moves.STONE_AXE, Moves.BULK_UP, Moves.SALT_CURE ],
|
||||
[Species.SKORUPI]: [ Moves.COIL, Moves.DIRE_CLAW, Moves.CRABHAMMER, Moves.WICKED_BLOW ],
|
||||
[Species.CROAGUNK]: [ Moves.DIRE_CLAW, Moves.ICE_SPINNER, Moves.THUNDEROUS_KICK, Moves.VICTORY_DANCE ],
|
||||
[Species.CROAGUNK]: [ Moves.DIRE_CLAW, Moves.TRIPLE_AXEL, Moves.THUNDEROUS_KICK, Moves.VICTORY_DANCE ],
|
||||
[Species.CARNIVINE]: [ Moves.STRENGTH_SAP, Moves.FIRE_LASH, Moves.COIL, Moves.SAPPY_SEED ],
|
||||
[Species.FINNEON]: [ Moves.QUIVER_DANCE, Moves.SPLISHY_SPLASH, Moves.FREEZE_DRY, Moves.OBLIVION_WING ],
|
||||
[Species.MANTYKE]: [ Moves.SPLISHY_SPLASH, Moves.FREEZY_FROST, Moves.NASTY_PLOT, Moves.OBLIVION_WING ],
|
||||
|
@ -267,7 +267,7 @@ export const speciesEggMoves = {
|
|||
[Species.PANSEAR]: [ Moves.NASTY_PLOT, Moves.HYDRO_STEAM, Moves.EARTH_POWER, Moves.ERUPTION ],
|
||||
[Species.PANPOUR]: [ Moves.NASTY_PLOT, Moves.ENERGY_BALL, Moves.EARTH_POWER, Moves.WATER_SPOUT ],
|
||||
[Species.MUNNA]: [ Moves.COSMIC_POWER, Moves.AURA_SPHERE, Moves.LUNAR_BLESSING, Moves.MYSTICAL_POWER ],
|
||||
[Species.PIDOVE]: [ Moves.GUNK_SHOT, Moves.TIDY_UP, Moves.FLOATY_FALL, Moves.TRIPLE_ARROWS ],
|
||||
[Species.PIDOVE]: [ Moves.SLASH, Moves.TIDY_UP, Moves.FLOATY_FALL, Moves.TRIPLE_ARROWS ],
|
||||
[Species.BLITZLE]: [ Moves.HORN_LEECH, Moves.SWORDS_DANCE, Moves.FLARE_BLITZ, Moves.BOLT_STRIKE ],
|
||||
[Species.ROGGENROLA]: [ Moves.BODY_PRESS, Moves.CURSE, Moves.SHORE_UP, Moves.DIAMOND_STORM ],
|
||||
[Species.WOOBAT]: [ Moves.ESPER_WING, Moves.STORED_POWER, Moves.MYSTICAL_FIRE, Moves.OBLIVION_WING ],
|
||||
|
@ -282,7 +282,7 @@ export const speciesEggMoves = {
|
|||
[Species.COTTONEE]: [ Moves.POLLEN_PUFF, Moves.PARTING_SHOT, Moves.SLEEP_POWDER, Moves.SEED_FLARE ],
|
||||
[Species.PETILIL]: [ Moves.THUNDEROUS_KICK, Moves.SPARKLING_ARIA, Moves.FIERY_DANCE, Moves.FLOWER_TRICK ],
|
||||
[Species.BASCULIN]: [ Moves.LAST_RESPECTS, Moves.CLOSE_COMBAT, Moves.SPLISHY_SPLASH, Moves.NO_RETREAT ],
|
||||
[Species.SANDILE]: [ Moves.DIRE_CLAW, Moves.HEADLONG_RUSH, Moves.FIRE_LASH, Moves.WICKED_BLOW ],
|
||||
[Species.SANDILE]: [ Moves.DIRE_CLAW, Moves.SUCKER_PUNCH, Moves.FIRE_LASH, Moves.HEADLONG_RUSH ],
|
||||
[Species.DARUMAKA]: [ Moves.DRAIN_PUNCH, Moves.ZIPPY_ZAP, Moves.HEADLONG_RUSH, Moves.PYRO_BALL ],
|
||||
[Species.MARACTUS]: [ Moves.EARTH_POWER, Moves.QUIVER_DANCE, Moves.FIERY_DANCE, Moves.SEED_FLARE ],
|
||||
[Species.DWEBBLE]: [ Moves.CRABHAMMER, Moves.STONE_AXE, Moves.LEECH_LIFE, Moves.MIGHTY_CLEAVE ],
|
||||
|
@ -327,8 +327,8 @@ export const speciesEggMoves = {
|
|||
[Species.DEINO]: [ Moves.FIERY_WRATH, Moves.ESPER_WING, Moves.SLUDGE_BOMB, Moves.FICKLE_BEAM ],
|
||||
[Species.LARVESTA]: [ Moves.THUNDERBOLT, Moves.DAZZLING_GLEAM, Moves.EARTH_POWER, Moves.HYDRO_STEAM ],
|
||||
[Species.COBALION]: [ Moves.BEHEMOTH_BLADE, Moves.MIGHTY_CLEAVE, Moves.CEASELESS_EDGE, Moves.VICTORY_DANCE ],
|
||||
[Species.TERRAKION]: [ Moves.MIGHTY_CLEAVE, Moves.HEADLONG_RUSH, Moves.CEASELESS_EDGE, Moves.VICTORY_DANCE ],
|
||||
[Species.VIRIZION]: [ Moves.SAPPY_SEED, Moves.PSYBLADE, Moves.CEASELESS_EDGE, Moves.VICTORY_DANCE ],
|
||||
[Species.TERRAKION]: [ Moves.MIGHTY_CLEAVE, Moves.HEADLONG_RUSH, Moves.KNOCK_OFF, Moves.VICTORY_DANCE ],
|
||||
[Species.VIRIZION]: [ Moves.SAPPY_SEED, Moves.PSYBLADE, Moves.STONE_AXE, Moves.VICTORY_DANCE ],
|
||||
[Species.TORNADUS]: [ Moves.SANDSEAR_STORM, Moves.PARTING_SHOT, Moves.SPLISHY_SPLASH, Moves.OBLIVION_WING ],
|
||||
[Species.THUNDURUS]: [ Moves.SANDSEAR_STORM, Moves.HURRICANE, Moves.FROST_BREATH, Moves.ELECTRO_SHOT ],
|
||||
[Species.RESHIRAM]: [ Moves.ENERGY_BALL, Moves.TAKE_HEART, Moves.FICKLE_BEAM, Moves.ERUPTION ],
|
||||
|
@ -342,7 +342,7 @@ export const speciesEggMoves = {
|
|||
[Species.CHESPIN]: [ Moves.COMBAT_TORQUE, Moves.SYNTHESIS, Moves.CEASELESS_EDGE, Moves.SAPPY_SEED ],
|
||||
[Species.FENNEKIN]: [ Moves.TWIN_BEAM, Moves.FIERY_DANCE, Moves.THUNDERBOLT, Moves.SPARKLY_SWIRL ],
|
||||
[Species.FROAKIE]: [ Moves.MOONBLAST, Moves.SHELL_SIDE_ARM, Moves.FIERY_WRATH, Moves.STEAM_ERUPTION ],
|
||||
[Species.BUNNELBY]: [ Moves.DRAIN_PUNCH, Moves.TIDY_UP, Moves.FACADE, Moves.EXTREME_SPEED ],
|
||||
[Species.BUNNELBY]: [ Moves.DRAIN_PUNCH, Moves.TIDY_UP, Moves.LANDS_WRATH, Moves.EXTREME_SPEED ],
|
||||
[Species.FLETCHLING]: [ Moves.DRILL_RUN, Moves.BURNING_BULWARK, Moves.HEAD_SMASH, Moves.VOLT_TACKLE ],
|
||||
[Species.SCATTERBUG]: [ Moves.FOCUS_BLAST, Moves.AFTER_YOU, Moves.DECORATE, Moves.BLIZZARD ],
|
||||
[Species.LITLEO]: [ Moves.EARTH_POWER, Moves.NASTY_PLOT, Moves.BURNING_BULWARK, Moves.BLUE_FLARE ],
|
||||
|
@ -372,7 +372,7 @@ export const speciesEggMoves = {
|
|||
[Species.NOIBAT]: [ Moves.AEROBLAST, Moves.OVERDRIVE, Moves.NASTY_PLOT, Moves.CLANGING_SCALES ],
|
||||
[Species.XERNEAS]: [ Moves.EARTH_POWER, Moves.SPRINGTIDE_STORM, Moves.STRENGTH_SAP, Moves.TAIL_GLOW ],
|
||||
[Species.YVELTAL]: [ Moves.SLUDGE_WAVE, Moves.POWER_TRIP, Moves.FIERY_WRATH, Moves.CLANGOROUS_SOUL ],
|
||||
[Species.ZYGARDE]: [ Moves.DRAGON_DARTS, Moves.HEAL_ORDER, Moves.CLANGOROUS_SOUL, Moves.DOUBLE_IRON_BASH ],
|
||||
[Species.ZYGARDE]: [ Moves.DRAGON_DARTS, Moves.V_CREATE, Moves.CLANGOROUS_SOUL, Moves.HEAL_ORDER ],
|
||||
[Species.DIANCIE]: [ Moves.MAGICAL_TORQUE, Moves.FIERY_DANCE, Moves.SHORE_UP, Moves.GEOMANCY ],
|
||||
[Species.HOOPA]: [ Moves.PHOTON_GEYSER, Moves.SECRET_SWORD, Moves.FIERY_WRATH, Moves.SHELL_SMASH ],
|
||||
[Species.VOLCANION]: [ Moves.HYDRO_STEAM, Moves.CALM_MIND, Moves.SEARING_SHOT, Moves.THUNDERCLAP ],
|
||||
|
@ -415,7 +415,7 @@ export const speciesEggMoves = {
|
|||
[Species.JANGMO_O]: [ Moves.BODY_PRESS, Moves.SHELL_SIDE_ARM, Moves.SECRET_SWORD, Moves.GLAIVE_RUSH ],
|
||||
[Species.TAPU_KOKO]: [ Moves.MAGICAL_TORQUE, Moves.TRIPLE_AXEL, Moves.SWORDS_DANCE, Moves.BOLT_STRIKE ],
|
||||
[Species.TAPU_LELE]: [ Moves.MOONLIGHT, Moves.NASTY_PLOT, Moves.HEAT_WAVE, Moves.EXPANDING_FORCE ],
|
||||
[Species.TAPU_BULU]: [ Moves.SAPPY_SEED, Moves.DRAIN_PUNCH, Moves.MAGICAL_TORQUE, Moves.VICTORY_DANCE ],
|
||||
[Species.TAPU_BULU]: [ Moves.SAPPY_SEED, Moves.LANDS_WRATH, Moves.MAGICAL_TORQUE, Moves.VICTORY_DANCE ],
|
||||
[Species.TAPU_FINI]: [ Moves.SPRINGTIDE_STORM, Moves.EARTH_POWER, Moves.RECOVER, Moves.QUIVER_DANCE ],
|
||||
[Species.COSMOG]: [ Moves.PHOTON_GEYSER, Moves.PRECIPICE_BLADES, Moves.SACRED_FIRE, Moves.ASTRAL_BARRAGE ],
|
||||
[Species.NIHILEGO]: [ Moves.STRENGTH_SAP, Moves.MALIGNANT_CHAIN, Moves.EARTH_POWER, Moves.QUIVER_DANCE ],
|
||||
|
@ -505,7 +505,7 @@ export const speciesEggMoves = {
|
|||
[Species.HISUI_VOLTORB]: [ Moves.FROST_BREATH, Moves.NASTY_PLOT, Moves.APPLE_ACID, Moves.ELECTRO_DRIFT ],
|
||||
[Species.HISUI_QWILFISH]: [ Moves.CEASELESS_EDGE, Moves.KNOCK_OFF, Moves.RECOVER, Moves.FISHIOUS_REND ],
|
||||
[Species.HISUI_SNEASEL]: [ Moves.DRAIN_PUNCH, Moves.KNOCK_OFF, Moves.PSYCHIC_FANGS, Moves.TRIPLE_AXEL ],
|
||||
[Species.HISUI_ZORUA]: [ Moves.MOONBLAST, Moves.HYPER_VOICE, Moves.PARTING_SHOT, Moves.BLOOD_MOON ],
|
||||
[Species.HISUI_ZORUA]: [ Moves.MOONBLAST, Moves.SECRET_SWORD, Moves.PARTING_SHOT, Moves.BLOOD_MOON ],
|
||||
|
||||
[Species.SPRIGATITO]: [ Moves.FIRE_LASH, Moves.TRIPLE_AXEL, Moves.SUCKER_PUNCH, Moves.WICKED_BLOW ],
|
||||
[Species.FUECOCO]: [ Moves.ALLURING_VOICE, Moves.SLACK_OFF, Moves.OVERDRIVE, Moves.MOONGEIST_BEAM ],
|
||||
|
@ -538,7 +538,7 @@ export const speciesEggMoves = {
|
|||
[Species.CYCLIZAR]: [ Moves.PARTING_SHOT, Moves.FIRE_LASH, Moves.MAGICAL_TORQUE, Moves.GLAIVE_RUSH ],
|
||||
[Species.ORTHWORM]: [ Moves.SIZZLY_SLIDE, Moves.COIL, Moves.BODY_PRESS, Moves.SHORE_UP ],
|
||||
[Species.GLIMMET]: [ Moves.CALM_MIND, Moves.GIGA_DRAIN, Moves.FIERY_DANCE, Moves.MALIGNANT_CHAIN ],
|
||||
[Species.GREAVARD]: [ Moves.SHADOW_BONE, Moves.YAWN, Moves.SHORE_UP, Moves.COLLISION_COURSE ],
|
||||
[Species.GREAVARD]: [ Moves.SHADOW_BONE, Moves.SIZZLY_SLIDE, Moves.SHORE_UP, Moves.COLLISION_COURSE ],
|
||||
[Species.FLAMIGO]: [ Moves.THUNDEROUS_KICK, Moves.TRIPLE_AXEL, Moves.FLOATY_FALL, Moves.VICTORY_DANCE ],
|
||||
[Species.CETODDLE]: [ Moves.ZING_ZAP, Moves.HIGH_HORSEPOWER, Moves.SLACK_OFF, Moves.DRAGON_DANCE ],
|
||||
[Species.VELUZA]: [ Moves.PSYBLADE, Moves.LEAF_BLADE, Moves.CEASELESS_EDGE, Moves.BITTER_BLADE ],
|
||||
|
@ -550,7 +550,7 @@ export const speciesEggMoves = {
|
|||
[Species.FLUTTER_MANE]: [ Moves.MOONLIGHT, Moves.NASTY_PLOT, Moves.EARTH_POWER, Moves.MOONGEIST_BEAM ],
|
||||
[Species.SLITHER_WING]: [ Moves.MIGHTY_CLEAVE, Moves.THUNDEROUS_KICK, Moves.FIRE_LASH, Moves.VICTORY_DANCE ],
|
||||
[Species.SANDY_SHOCKS]: [ Moves.MORNING_SUN, Moves.ICE_BEAM, Moves.NASTY_PLOT, Moves.THUNDERCLAP ],
|
||||
[Species.IRON_TREADS]: [ Moves.FUSION_BOLT, Moves.BULK_UP, Moves.SHORE_UP, Moves.SUNSTEEL_STRIKE ],
|
||||
[Species.IRON_TREADS]: [ Moves.FUSION_BOLT, Moves.SHIFT_GEAR, Moves.SHORE_UP, Moves.SUNSTEEL_STRIKE ],
|
||||
[Species.IRON_BUNDLE]: [ Moves.EARTH_POWER, Moves.SPLISHY_SPLASH, Moves.VOLT_SWITCH, Moves.NASTY_PLOT ],
|
||||
[Species.IRON_HANDS]: [ Moves.DRAIN_PUNCH, Moves.BULK_UP, Moves.PLASMA_FISTS, Moves.ICE_HAMMER ],
|
||||
[Species.IRON_JUGULIS]: [ Moves.FIERY_WRATH, Moves.ROOST, Moves.NASTY_PLOT, Moves.OBLIVION_WING ],
|
||||
|
@ -562,7 +562,7 @@ export const speciesEggMoves = {
|
|||
[Species.CHIEN_PAO]: [ Moves.KNOCK_OFF, Moves.PARTING_SHOT, Moves.TRIPLE_AXEL, Moves.BITTER_BLADE ],
|
||||
[Species.TING_LU]: [ Moves.SHORE_UP, Moves.CEASELESS_EDGE, Moves.SAPPY_SEED, Moves.PRECIPICE_BLADES ],
|
||||
[Species.CHI_YU]: [ Moves.FIERY_WRATH, Moves.HYDRO_STEAM, Moves.MORNING_SUN, Moves.BLUE_FLARE ],
|
||||
[Species.ROARING_MOON]: [ Moves.FIRE_LASH, Moves.DRAGON_HAMMER, Moves.SUCKER_PUNCH, Moves.WICKED_BLOW ],
|
||||
[Species.ROARING_MOON]: [ Moves.FIRE_LASH, Moves.DRAGON_HAMMER, Moves.METEOR_MASH, Moves.DRAGON_ASCENT ],
|
||||
[Species.IRON_VALIANT]: [ Moves.PLASMA_FISTS, Moves.NO_RETREAT, Moves.SECRET_SWORD, Moves.MAGICAL_TORQUE ],
|
||||
[Species.KORAIDON]: [ Moves.SUNSTEEL_STRIKE, Moves.SOLAR_BLADE, Moves.DRAGON_DARTS, Moves.BITTER_BLADE ],
|
||||
[Species.MIRAIDON]: [ Moves.ICE_BEAM, Moves.CLANGOROUS_SOUL, Moves.CORE_ENFORCER, Moves.RISING_VOLTAGE ],
|
||||
|
@ -577,7 +577,7 @@ export const speciesEggMoves = {
|
|||
[Species.RAGING_BOLT]: [ Moves.NASTY_PLOT, Moves.FLAMETHROWER, Moves.MORNING_SUN, Moves.ELECTRO_DRIFT ],
|
||||
[Species.IRON_BOULDER]: [ Moves.PSYBLADE, Moves.KOWTOW_CLEAVE, Moves.STONE_AXE, Moves.BITTER_BLADE ],
|
||||
[Species.IRON_CROWN]: [ Moves.NASTY_PLOT, Moves.SECRET_SWORD, Moves.PSYSTRIKE, Moves.ELECTRO_DRIFT ],
|
||||
[Species.TERAPAGOS]: [ Moves.MOONBLAST, Moves.RECOVER, Moves.ICE_BEAM, Moves.SHELL_SMASH ],
|
||||
[Species.TERAPAGOS]: [ Moves.MOONBLAST, Moves.NASTY_PLOT, Moves.ASTRAL_BARRAGE, Moves.RECOVER ],
|
||||
[Species.PECHARUNT]: [ Moves.TAKE_HEART, Moves.BODY_PRESS, Moves.SAPPY_SEED, Moves.ASTRAL_BARRAGE ],
|
||||
[Species.PALDEA_TAUROS]: [ Moves.NO_RETREAT, Moves.BLAZING_TORQUE, Moves.AQUA_STEP, Moves.THUNDEROUS_KICK ],
|
||||
[Species.PALDEA_WOOPER]: [ Moves.STONE_AXE, Moves.RECOVER, Moves.BANEFUL_BUNKER, Moves.BARB_BARRAGE ],
|
||||
|
|
|
@ -555,7 +555,7 @@ export const starterPassiveAbilities: StarterPassiveAbilities = {
|
|||
[Species.FLUTTER_MANE]: { 0: Abilities.DAZZLING },
|
||||
[Species.SLITHER_WING]: { 0: Abilities.SCRAPPY },
|
||||
[Species.SANDY_SHOCKS]: { 0: Abilities.ELECTRIC_SURGE },
|
||||
[Species.IRON_TREADS]: { 0: Abilities.STEELY_SPIRIT },
|
||||
[Species.IRON_TREADS]: { 0: Abilities.DAUNTLESS_SHIELD },
|
||||
[Species.IRON_BUNDLE]: { 0: Abilities.SNOW_WARNING },
|
||||
[Species.IRON_HANDS]: { 0: Abilities.IRON_FIST },
|
||||
[Species.IRON_JUGULIS]: { 0: Abilities.LIGHTNING_ROD },
|
||||
|
@ -567,7 +567,7 @@ export const starterPassiveAbilities: StarterPassiveAbilities = {
|
|||
[Species.CHIEN_PAO]: { 0: Abilities.INTIMIDATE },
|
||||
[Species.TING_LU]: { 0: Abilities.STAMINA },
|
||||
[Species.CHI_YU]: { 0: Abilities.BERSERK },
|
||||
[Species.ROARING_MOON]: { 0: Abilities.TOUGH_CLAWS },
|
||||
[Species.ROARING_MOON]: { 0: Abilities.INTIMIDATE },
|
||||
[Species.IRON_VALIANT]: { 0: Abilities.NEUROFORCE },
|
||||
[Species.KORAIDON]: { 0: Abilities.OPPORTUNIST },
|
||||
[Species.MIRAIDON]: { 0: Abilities.OPPORTUNIST },
|
||||
|
@ -582,7 +582,7 @@ export const starterPassiveAbilities: StarterPassiveAbilities = {
|
|||
[Species.RAGING_BOLT]: { 0: Abilities.BEAST_BOOST },
|
||||
[Species.IRON_BOULDER]: { 0: Abilities.SHARPNESS },
|
||||
[Species.IRON_CROWN]: { 0: Abilities.SHARPNESS },
|
||||
[Species.TERAPAGOS]: { 0: Abilities.SOUL_HEART },
|
||||
[Species.TERAPAGOS]: { 0: Abilities.SHIELD_DUST },
|
||||
[Species.PECHARUNT]: { 0: Abilities.TOXIC_CHAIN },
|
||||
[Species.PALDEA_TAUROS]: { 0: Abilities.ADAPTABILITY },
|
||||
[Species.PALDEA_WOOPER]: { 0: Abilities.THICK_FAT },
|
||||
|
|
|
@ -290,7 +290,7 @@ export const speciesStarterCosts = {
|
|||
[Species.SHAYMIN]: 6,
|
||||
[Species.ARCEUS]: 9,
|
||||
|
||||
[Species.VICTINI]: 7,
|
||||
[Species.VICTINI]: 6,
|
||||
[Species.SNIVY]: 3,
|
||||
[Species.TEPIG]: 3,
|
||||
[Species.OSHAWOTT]: 3,
|
||||
|
@ -461,7 +461,7 @@ export const speciesStarterCosts = {
|
|||
[Species.GUZZLORD]: 6,
|
||||
[Species.NECROZMA]: 8,
|
||||
[Species.MAGEARNA]: 7,
|
||||
[Species.MARSHADOW]: 7,
|
||||
[Species.MARSHADOW]: 8,
|
||||
[Species.POIPOLE]: 8,
|
||||
[Species.STAKATAKA]: 6,
|
||||
[Species.BLACEPHALON]: 7,
|
||||
|
@ -611,7 +611,7 @@ export const speciesStarterCosts = {
|
|||
[Species.RAGING_BOLT]: 7,
|
||||
[Species.IRON_BOULDER]: 7,
|
||||
[Species.IRON_CROWN]: 7,
|
||||
[Species.TERAPAGOS]: 8,
|
||||
[Species.TERAPAGOS]: 9,
|
||||
[Species.PECHARUNT]: 6,
|
||||
[Species.PALDEA_TAUROS]: 5,
|
||||
[Species.PALDEA_WOOPER]: 3,
|
||||
|
|
|
@ -1,7 +1,20 @@
|
|||
import { globalScene } from "#app/global-scene";
|
||||
import { AttackMove, BeakBlastHeaderAttr, DelayedAttackAttr, MoveFlags, SelfStatusMove, allMoves } from "./move";
|
||||
import {
|
||||
AttackMove,
|
||||
BeakBlastHeaderAttr,
|
||||
DelayedAttackAttr,
|
||||
MoveFlags,
|
||||
SelfStatusMove,
|
||||
allMoves,
|
||||
} from "./move";
|
||||
import type Pokemon from "../field/pokemon";
|
||||
import * as Utils from "../utils";
|
||||
import {
|
||||
type nil,
|
||||
getFrameMs,
|
||||
getEnumKeys,
|
||||
getEnumValues,
|
||||
animationFileName,
|
||||
} from "../utils";
|
||||
import type { BattlerIndex } from "../battle";
|
||||
import type { Element } from "json-stable-stringify";
|
||||
import { Moves } from "#enums/moves";
|
||||
|
@ -401,7 +414,7 @@ class AnimTimedUpdateBgEvent extends AnimTimedBgEvent {
|
|||
if (Object.keys(tweenProps).length) {
|
||||
globalScene.tweens.add(Object.assign({
|
||||
targets: moveAnim.bgSprite,
|
||||
duration: Utils.getFrameMs(this.duration * 3)
|
||||
duration: getFrameMs(this.duration * 3)
|
||||
}, tweenProps));
|
||||
}
|
||||
return this.duration * 2;
|
||||
|
@ -437,7 +450,7 @@ class AnimTimedAddBgEvent extends AnimTimedBgEvent {
|
|||
|
||||
globalScene.tweens.add({
|
||||
targets: moveAnim.bgSprite,
|
||||
duration: Utils.getFrameMs(this.duration * 3)
|
||||
duration: getFrameMs(this.duration * 3)
|
||||
});
|
||||
|
||||
return this.duration * 2;
|
||||
|
@ -455,8 +468,8 @@ export const encounterAnims = new Map<EncounterAnim, AnimConfig>();
|
|||
|
||||
export function initCommonAnims(): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
const commonAnimNames = Utils.getEnumKeys(CommonAnim);
|
||||
const commonAnimIds = Utils.getEnumValues(CommonAnim);
|
||||
const commonAnimNames = getEnumKeys(CommonAnim);
|
||||
const commonAnimIds = getEnumValues(CommonAnim);
|
||||
const commonAnimFetches: Promise<Map<CommonAnim, AnimConfig>>[] = [];
|
||||
for (let ca = 0; ca < commonAnimIds.length; ca++) {
|
||||
const commonAnimId = commonAnimIds[ca];
|
||||
|
@ -493,7 +506,7 @@ export function initMoveAnim(move: Moves): Promise<void> {
|
|||
const defaultMoveAnim = allMoves[move] instanceof AttackMove ? Moves.TACKLE : allMoves[move] instanceof SelfStatusMove ? Moves.FOCUS_ENERGY : Moves.TAIL_WHIP;
|
||||
|
||||
const fetchAnimAndResolve = (move: Moves) => {
|
||||
globalScene.cachedFetch(`./battle-anims/${Utils.animationFileName(move)}.json`)
|
||||
globalScene.cachedFetch(`./battle-anims/${animationFileName(move)}.json`)
|
||||
.then(response => {
|
||||
const contentType = response.headers.get("content-type");
|
||||
if (!response.ok || contentType?.indexOf("application/json") === -1) {
|
||||
|
@ -550,7 +563,7 @@ function useDefaultAnim(move: Moves, defaultMoveAnim: Moves) {
|
|||
* @remarks use {@linkcode useDefaultAnim} to use a default animation
|
||||
*/
|
||||
function logMissingMoveAnim(move: Moves, ...optionalParams: any[]) {
|
||||
const moveName = Utils.animationFileName(move);
|
||||
const moveName = animationFileName(move);
|
||||
console.warn(`Could not load animation file for move '${moveName}'`, ...optionalParams);
|
||||
}
|
||||
|
||||
|
@ -560,7 +573,7 @@ function logMissingMoveAnim(move: Moves, ...optionalParams: any[]) {
|
|||
*/
|
||||
export async function initEncounterAnims(encounterAnim: EncounterAnim | EncounterAnim[]): Promise<void> {
|
||||
const anims = Array.isArray(encounterAnim) ? encounterAnim : [ encounterAnim ];
|
||||
const encounterAnimNames = Utils.getEnumKeys(EncounterAnim);
|
||||
const encounterAnimNames = getEnumKeys(EncounterAnim);
|
||||
const encounterAnimFetches: Promise<Map<EncounterAnim, AnimConfig>>[] = [];
|
||||
for (const anim of anims) {
|
||||
if (encounterAnims.has(anim) && !isNullOrUndefined(encounterAnims.get(anim))) {
|
||||
|
@ -922,7 +935,7 @@ export abstract class BattleAnim {
|
|||
let f = 0;
|
||||
|
||||
globalScene.tweens.addCounter({
|
||||
duration: Utils.getFrameMs(3),
|
||||
duration: getFrameMs(3),
|
||||
repeat: anim?.frames.length ?? 0,
|
||||
onRepeat: () => {
|
||||
if (!f) {
|
||||
|
@ -994,47 +1007,39 @@ export abstract class BattleAnim {
|
|||
const moveSprite = sprites[graphicIndex];
|
||||
if (spritePriorities[graphicIndex] !== frame.priority) {
|
||||
spritePriorities[graphicIndex] = frame.priority;
|
||||
/** Move the position that the moveSprite is rendered in based on the priority.
|
||||
* @param priority The priority level to draw the sprite.
|
||||
* - 0: Draw the sprite in front of the pokemon on the field.
|
||||
* - 1: Draw the sprite in front of the user pokemon.
|
||||
* - 2: Draw the sprite in front of its `bgSprite` (if it has one), or its
|
||||
* `AnimFocus` (if that is user/target), otherwise behind everything.
|
||||
* - 3: Draw the sprite behind its `AnimFocus` (if that is user/target), otherwise in front of everything.
|
||||
*/
|
||||
const setSpritePriority = (priority: number) => {
|
||||
switch (priority) {
|
||||
case 0:
|
||||
globalScene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, globalScene.getEnemyPokemon(false) ?? globalScene.getPlayerPokemon(false)!); // TODO: is this bang correct?
|
||||
break;
|
||||
case 1:
|
||||
globalScene.field.moveTo(moveSprite, globalScene.field.getAll().length - 1);
|
||||
break;
|
||||
case 2:
|
||||
switch (frame.focus) {
|
||||
case AnimFocus.USER:
|
||||
if (this.bgSprite) {
|
||||
globalScene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.bgSprite);
|
||||
} else {
|
||||
globalScene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, this.user!); // TODO: is this bang correct?
|
||||
}
|
||||
break;
|
||||
case AnimFocus.TARGET:
|
||||
globalScene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, this.target!); // TODO: is this bang correct?
|
||||
break;
|
||||
default:
|
||||
setSpritePriority(1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
switch (frame.focus) {
|
||||
case AnimFocus.USER:
|
||||
globalScene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.user!); // TODO: is this bang correct?
|
||||
break;
|
||||
case AnimFocus.TARGET:
|
||||
globalScene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.target!); // TODO: is this bang correct?
|
||||
break;
|
||||
default:
|
||||
setSpritePriority(1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
setSpritePriority(1);
|
||||
/** The sprite we are moving the moveSprite in relation to */
|
||||
let targetSprite: Phaser.GameObjects.GameObject | nil;
|
||||
/** The method that is being used to move the sprite.*/
|
||||
let moveFunc: ((sprite: Phaser.GameObjects.GameObject, target: Phaser.GameObjects.GameObject) => void) |
|
||||
((sprite: Phaser.GameObjects.GameObject) => void) = globalScene.field.bringToTop;
|
||||
|
||||
if (priority === 0) { // Place the sprite in front of the pokemon on the field.
|
||||
targetSprite = globalScene.getEnemyField().find(p => p) ?? globalScene.getPlayerField().find(p => p);
|
||||
console.log(typeof targetSprite);
|
||||
moveFunc = globalScene.field.moveBelow;
|
||||
} else if (priority === 2 && this.bgSprite) {
|
||||
moveFunc = globalScene.field.moveAbove;
|
||||
targetSprite = this.bgSprite;
|
||||
} else if (priority === 2 || priority === 3) {
|
||||
moveFunc = priority === 2 ? globalScene.field.moveBelow : globalScene.field.moveAbove;
|
||||
if (frame.focus === AnimFocus.USER) {
|
||||
targetSprite = this.user;
|
||||
} else if (frame.focus === AnimFocus.TARGET) {
|
||||
targetSprite = this.target;
|
||||
}
|
||||
}
|
||||
// If target sprite is not undefined and exists in the field container, then move the sprite using the moveFunc.
|
||||
// Otherwise, default to just bringing it to the top.
|
||||
targetSprite && globalScene.field.exists(targetSprite) ? moveFunc.bind(globalScene.field)(moveSprite as Phaser.GameObjects.GameObject, targetSprite) : globalScene.field.bringToTop(moveSprite as Phaser.GameObjects.GameObject);
|
||||
};
|
||||
setSpritePriority(frame.priority);
|
||||
}
|
||||
|
@ -1052,11 +1057,13 @@ export abstract class BattleAnim {
|
|||
}
|
||||
}
|
||||
if (anim?.frameTimedEvents.has(f)) {
|
||||
for (const event of anim.frameTimedEvents.get(f)!) { // TODO: is this bang correct?
|
||||
r = Math.max((anim.frames.length - f) + event.execute(this), r);
|
||||
const base = anim.frames.length - f;
|
||||
// Bang is correct due to `has` check above, which cannot return true for an undefined / null `f`
|
||||
for (const event of anim.frameTimedEvents.get(f)!) {
|
||||
r = Math.max(base + event.execute(this), r);
|
||||
}
|
||||
}
|
||||
const targets = Utils.getEnumValues(AnimFrameTarget);
|
||||
const targets = getEnumValues(AnimFrameTarget);
|
||||
for (const i of targets) {
|
||||
const count = i === AnimFrameTarget.GRAPHIC ? g : i === AnimFrameTarget.USER ? u : t;
|
||||
if (count < spriteCache[i].length) {
|
||||
|
@ -1084,7 +1091,7 @@ export abstract class BattleAnim {
|
|||
}
|
||||
if (r) {
|
||||
globalScene.tweens.addCounter({
|
||||
duration: Utils.getFrameMs(r),
|
||||
duration: getFrameMs(r),
|
||||
onComplete: () => cleanUpAndComplete()
|
||||
});
|
||||
} else {
|
||||
|
@ -1166,7 +1173,7 @@ export abstract class BattleAnim {
|
|||
let existingFieldSprites = globalScene.field.getAll().slice(0);
|
||||
|
||||
globalScene.tweens.addCounter({
|
||||
duration: Utils.getFrameMs(3) * frameTimeMult,
|
||||
duration: getFrameMs(3) * frameTimeMult,
|
||||
repeat: anim!.frames.length,
|
||||
onRepeat: () => {
|
||||
existingFieldSprites = globalScene.field.getAll().slice(0);
|
||||
|
@ -1215,11 +1222,12 @@ export abstract class BattleAnim {
|
|||
}
|
||||
}
|
||||
if (anim?.frameTimedEvents.get(frameCount)) {
|
||||
const base = anim.frames.length - frameCount;
|
||||
for (const event of anim.frameTimedEvents.get(frameCount)!) {
|
||||
totalFrames = Math.max((anim.frames.length - frameCount) + event.execute(this, frameTimedEventPriority), totalFrames);
|
||||
totalFrames = Math.max(base + event.execute(this, frameTimedEventPriority), totalFrames);
|
||||
}
|
||||
}
|
||||
const targets = Utils.getEnumValues(AnimFrameTarget);
|
||||
const targets = getEnumValues(AnimFrameTarget);
|
||||
for (const i of targets) {
|
||||
const count = graphicFrameCount;
|
||||
if (count < spriteCache[i].length) {
|
||||
|
@ -1244,7 +1252,7 @@ export abstract class BattleAnim {
|
|||
}
|
||||
if (totalFrames) {
|
||||
globalScene.tweens.addCounter({
|
||||
duration: Utils.getFrameMs(totalFrames),
|
||||
duration: getFrameMs(totalFrames),
|
||||
onComplete: () => cleanUpAndComplete()
|
||||
});
|
||||
} else {
|
||||
|
@ -1342,15 +1350,15 @@ export class EncounterBattleAnim extends BattleAnim {
|
|||
}
|
||||
|
||||
export async function populateAnims() {
|
||||
const commonAnimNames = Utils.getEnumKeys(CommonAnim).map(k => k.toLowerCase());
|
||||
const commonAnimNames = getEnumKeys(CommonAnim).map(k => k.toLowerCase());
|
||||
const commonAnimMatchNames = commonAnimNames.map(k => k.replace(/\_/g, ""));
|
||||
const commonAnimIds = Utils.getEnumValues(CommonAnim) as CommonAnim[];
|
||||
const chargeAnimNames = Utils.getEnumKeys(ChargeAnim).map(k => k.toLowerCase());
|
||||
const commonAnimIds = getEnumValues(CommonAnim) as CommonAnim[];
|
||||
const chargeAnimNames = getEnumKeys(ChargeAnim).map(k => k.toLowerCase());
|
||||
const chargeAnimMatchNames = chargeAnimNames.map(k => k.replace(/\_/g, " "));
|
||||
const chargeAnimIds = Utils.getEnumValues(ChargeAnim) as ChargeAnim[];
|
||||
const chargeAnimIds = getEnumValues(ChargeAnim) as ChargeAnim[];
|
||||
const commonNamePattern = /name: (?:Common:)?(Opp )?(.*)/;
|
||||
const moveNameToId = {};
|
||||
for (const move of Utils.getEnumValues(Moves).slice(1)) {
|
||||
for (const move of getEnumValues(Moves).slice(1)) {
|
||||
const moveName = Moves[move].toUpperCase().replace(/\_/g, "");
|
||||
moveNameToId[moveName] = move;
|
||||
}
|
||||
|
|
|
@ -1866,11 +1866,14 @@ export class HalfSacrificialAttr extends MoveEffectAttr {
|
|||
export class AddSubstituteAttr extends MoveEffectAttr {
|
||||
/** The ratio of the user's max HP that is required to apply this effect */
|
||||
private hpCost: number;
|
||||
/** Whether the damage taken should be rounded up (Shed Tail rounds up) */
|
||||
private roundUp: boolean;
|
||||
|
||||
constructor(hpCost: number = 0.25) {
|
||||
constructor(hpCost: number, roundUp: boolean) {
|
||||
super(true);
|
||||
|
||||
this.hpCost = hpCost;
|
||||
this.roundUp = roundUp;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1886,7 +1889,8 @@ export class AddSubstituteAttr extends MoveEffectAttr {
|
|||
return false;
|
||||
}
|
||||
|
||||
user.damageAndUpdate(Math.floor(user.getMaxHp() * this.hpCost), HitResult.OTHER, false, true, true);
|
||||
const damageTaken = this.roundUp ? Math.ceil(user.getMaxHp() * this.hpCost) : Math.floor(user.getMaxHp() * this.hpCost);
|
||||
user.damageAndUpdate(damageTaken, HitResult.OTHER, false, true, true);
|
||||
user.addTag(BattlerTagType.SUBSTITUTE, 0, move.id, user.id);
|
||||
return true;
|
||||
}
|
||||
|
@ -1899,7 +1903,7 @@ export class AddSubstituteAttr extends MoveEffectAttr {
|
|||
}
|
||||
|
||||
getCondition(): MoveConditionFunc {
|
||||
return (user, target, move) => !user.getTag(SubstituteTag) && user.hp > Math.floor(user.getMaxHp() * this.hpCost) && user.getMaxHp() > 1;
|
||||
return (user, target, move) => !user.getTag(SubstituteTag) && user.hp > (this.roundUp ? Math.ceil(user.getMaxHp() * this.hpCost) : Math.floor(user.getMaxHp() * this.hpCost)) && user.getMaxHp() > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5232,7 +5236,7 @@ export class CombinedPledgeTypeAttr extends VariableMoveTypeAttr {
|
|||
return false;
|
||||
}
|
||||
|
||||
const combinedPledgeMove = user.turnData.combiningPledge;
|
||||
const combinedPledgeMove = user?.turnData?.combiningPledge;
|
||||
if (!combinedPledgeMove) {
|
||||
return false;
|
||||
}
|
||||
|
@ -7811,11 +7815,12 @@ export class SuppressAbilitiesAttr extends MoveEffectAttr {
|
|||
return false;
|
||||
}
|
||||
|
||||
target.summonData.abilitySuppressed = true;
|
||||
globalScene.arena.triggerWeatherBasedFormChangesToNormal();
|
||||
|
||||
globalScene.queueMessage(i18next.t("moveTriggers:suppressAbilities", { pokemonName: getPokemonNameWithAffix(target) }));
|
||||
|
||||
target.suppressAbility();
|
||||
|
||||
globalScene.arena.triggerWeatherBasedFormChangesToNormal();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -9035,7 +9040,7 @@ export function initMoves() {
|
|||
.attr(HighCritAttr)
|
||||
.slicingMove(),
|
||||
new SelfStatusMove(Moves.SUBSTITUTE, Type.NORMAL, -1, 10, -1, 0, 1)
|
||||
.attr(AddSubstituteAttr),
|
||||
.attr(AddSubstituteAttr, 0.25, false),
|
||||
new AttackMove(Moves.STRUGGLE, Type.NORMAL, MoveCategory.PHYSICAL, 50, -1, 1, -1, 0, 1)
|
||||
.attr(RecoilAttr, true, 0.25, true)
|
||||
.attr(TypelessAttr)
|
||||
|
@ -9379,7 +9384,7 @@ export function initMoves() {
|
|||
.attr(BypassBurnDamageReductionAttr),
|
||||
new AttackMove(Moves.FOCUS_PUNCH, Type.FIGHTING, MoveCategory.PHYSICAL, 150, 100, 20, -1, -3, 3)
|
||||
.attr(MessageHeaderAttr, (user, move) => i18next.t("moveTriggers:isTighteningFocus", { pokemonName: getPokemonNameWithAffix(user) }))
|
||||
.attr(PreUseInterruptAttr, i18next.t("moveTriggers:lostFocus"), user => !!user.turnData.attacksReceived.find(r => r.damage))
|
||||
.attr(PreUseInterruptAttr, (user, target, move) => i18next.t("moveTriggers:lostFocus", { pokemonName: getPokemonNameWithAffix(user) }), user => !!user.turnData.attacksReceived.find(r => r.damage))
|
||||
.punchingMove(),
|
||||
new AttackMove(Moves.SMELLING_SALTS, Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 10, -1, 0, 3)
|
||||
.attr(MovePowerMultiplierAttr, (user, target, move) => target.status?.effect === StatusEffect.PARALYSIS ? 2 : 1)
|
||||
|
@ -11381,7 +11386,7 @@ export function initMoves() {
|
|||
.attr(MovePowerMultiplierAttr, (user, target, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2 ? 5461 / 4096 : 1)
|
||||
.makesContact(),
|
||||
new SelfStatusMove(Moves.SHED_TAIL, Type.NORMAL, -1, 10, -1, 0, 9)
|
||||
.attr(AddSubstituteAttr, 0.5)
|
||||
.attr(AddSubstituteAttr, 0.5, true)
|
||||
.attr(ForceSwitchOutAttr, true, SwitchType.SHED_TAIL)
|
||||
.condition(failIfLastInPartyCondition),
|
||||
new SelfStatusMove(Moves.CHILLY_RECEPTION, Type.ICE, -1, 10, -1, 0, 9)
|
||||
|
|
|
@ -749,7 +749,7 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali
|
|||
if (this.speciesId === Species.ARCEUS) {
|
||||
ret = i18next.t(`pokemonInfo:Type.${formText?.toUpperCase()}`);
|
||||
} else if ([ SpeciesFormKey.MEGA, SpeciesFormKey.MEGA_X, SpeciesFormKey.MEGA_Y, SpeciesFormKey.PRIMAL, SpeciesFormKey.GIGANTAMAX, SpeciesFormKey.GIGANTAMAX_RAPID, SpeciesFormKey.GIGANTAMAX_SINGLE, SpeciesFormKey.ETERNAMAX ].includes(formKey as SpeciesFormKey)) {
|
||||
return i18next.t(`battlePokemonForm:${formKey}`, { pokemonName: (append ? this.name : "") });
|
||||
return append ? i18next.t(`battlePokemonForm:${formKey}`, { pokemonName: this.name }) : i18next.t(`pokemonForm:battleForm.${formKey}`);
|
||||
} else if (region === Region.NORMAL || (this.speciesId === Species.GALAR_DARMANITAN && formIndex > 0) || this.speciesId === Species.PALDEA_TAUROS) { // More special cases can be added here
|
||||
const i18key = `pokemonForm:${speciesName}${formText}`;
|
||||
if (i18next.exists(i18key)) {
|
||||
|
|
|
@ -26,6 +26,9 @@ import { Gender } from "#app/data/gender";
|
|||
/** Minimum BST for Pokemon generated onto the Elite Four's teams */
|
||||
const ELITE_FOUR_MINIMUM_BST = 460;
|
||||
|
||||
/** The wave at which (non-Paldean) Gym Leaders start having Tera mons*/
|
||||
const GYM_LEADER_TERA_WAVE = 100;
|
||||
|
||||
export enum TrainerPoolTier {
|
||||
COMMON,
|
||||
UNCOMMON,
|
||||
|
@ -211,8 +214,8 @@ export class TrainerAI {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets a pokemon on this AI to just instantly tera on first move used
|
||||
* @param index The index of the pokemon to instantly tera
|
||||
* Sets a pokemon on this AI to just instantly Tera on first move used
|
||||
* @param index The index of the pokemon to instantly tera.
|
||||
*/
|
||||
public setInstantTera(index: number) {
|
||||
this.teraMode = TeraAIMode.INSTANT_TERA;
|
||||
|
@ -251,7 +254,7 @@ export class TrainerConfig {
|
|||
public partyMemberFuncs: PartyMemberFuncs = {};
|
||||
public speciesPools: TrainerTierPools;
|
||||
public speciesFilter: PokemonSpeciesFilter;
|
||||
public specialtyTypes: Type[] = [];
|
||||
public specialtyType: Type;
|
||||
public hasVoucher: boolean = false;
|
||||
public trainerAI: TrainerAI;
|
||||
|
||||
|
@ -583,8 +586,8 @@ export class TrainerConfig {
|
|||
return this;
|
||||
}
|
||||
|
||||
setSpecialtyTypes(...specialtyTypes: Type[]): TrainerConfig {
|
||||
this.specialtyTypes = specialtyTypes;
|
||||
setSpecialtyType(specialtyType: Type): TrainerConfig {
|
||||
this.specialtyType = specialtyType;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -594,18 +597,22 @@ export class TrainerConfig {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets random pokemon from the trainers team to instant tera. Uses their specialty types is they have one.
|
||||
* @param count The amount of pokemon to have instant tera
|
||||
* Sets random pokemon from the trainer's team to instant tera. Also sets Tera type to specialty type and checks for Shedinja as appropriate.
|
||||
* @param count A callback (yucky) to see how many teras should be used
|
||||
* @param slot Optional, a specified slot that should be terastallized. Wraps to match party size (-1 will get the last slot and so on).
|
||||
* @returns this
|
||||
*/
|
||||
setRandomTeraModifiers(count: () => integer): TrainerConfig {
|
||||
setRandomTeraModifiers(count: () => number, slot?: number): TrainerConfig {
|
||||
this.genAIFuncs.push((party: EnemyPokemon[]) => {
|
||||
const partyMemberIndexes = new Array(party.length).fill(null).map((_, i) => i);
|
||||
const shedinjaCanTera = !this.hasSpecialtyType() || this.specialtyType === Type.BUG; // Better to check one time than 6
|
||||
const partyMemberIndexes = new Array(party.length).fill(null).map((_, i) => i)
|
||||
.filter(i => shedinjaCanTera || party[i].species.speciesId !== Species.SHEDINJA); // Shedinja can only Tera on Bug specialty type (or no specialty type)
|
||||
const setPartySlot = !Utils.isNullOrUndefined(slot) ? Phaser.Math.Wrap(slot, 0, party.length) : -1; // If we have a tera slot defined, wrap it to party size.
|
||||
for (let t = 0; t < Math.min(count(), party.length); t++) {
|
||||
const randomIndex = Utils.randSeedItem(partyMemberIndexes);
|
||||
const randomIndex = partyMemberIndexes.indexOf(setPartySlot) > -1 ? setPartySlot : Utils.randSeedItem(partyMemberIndexes);
|
||||
partyMemberIndexes.splice(partyMemberIndexes.indexOf(randomIndex), 1);
|
||||
if (this.specialtyTypes?.length) {
|
||||
party[randomIndex].teraType = Utils.randSeedItem(this.specialtyTypes);
|
||||
if (this.hasSpecialtyType()) {
|
||||
party[randomIndex].teraType = this.specialtyType;
|
||||
}
|
||||
this.trainerAI.setInstantTera(randomIndex);
|
||||
}
|
||||
|
@ -614,8 +621,8 @@ export class TrainerConfig {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets a specific pokemon to instant tera
|
||||
* @param index The index within the team to have instant tera
|
||||
* Sets a specific pokemon to instantly Tera
|
||||
* @param index The index within the team to have instant Tera.
|
||||
* @returns this
|
||||
*/
|
||||
setInstantTera(index: number): TrainerConfig {
|
||||
|
@ -779,12 +786,18 @@ export class TrainerConfig {
|
|||
* @param title The title of the evil team admin.
|
||||
* @param poolName The evil team the admin belongs to.
|
||||
* @param {Species | Species[]} signatureSpecies The signature species for the evil team leader.
|
||||
* @param specialtyType The specialty Type of the admin, if they have one
|
||||
* @returns {TrainerConfig} The updated TrainerConfig instance.
|
||||
* **/
|
||||
initForEvilTeamAdmin(title: string, poolName: string, signatureSpecies: (Species | Species[])[],): TrainerConfig {
|
||||
initForEvilTeamAdmin(title: string, poolName: string, signatureSpecies: (Species | Species[])[], specialtyType?: Type): TrainerConfig {
|
||||
if (!getIsInitialized()) {
|
||||
initI18n();
|
||||
}
|
||||
|
||||
if (!Utils.isNullOrUndefined(specialtyType)) {
|
||||
this.setSpecialtyType(specialtyType);
|
||||
}
|
||||
|
||||
this.setPartyTemplates(trainerPartyTemplates.RIVAL_5);
|
||||
|
||||
// Set the species pools for the evil team admin.
|
||||
|
@ -812,28 +825,16 @@ export class TrainerConfig {
|
|||
|
||||
/**
|
||||
* Initializes the trainer configuration for a Stat Trainer, as part of the Trainer's Test Mystery Encounter.
|
||||
* @param {Species | Species[]} signatureSpecies The signature species for the Elite Four member.
|
||||
* @param {Type[]} specialtyTypes The specialty types for the Stat Trainer.
|
||||
* @param isMale Whether the Elite Four Member is Male or Female (for localization of the title).
|
||||
* @param isMale Whether the stat trainer is Male or Female (for localization of the title).
|
||||
* @returns {TrainerConfig} The updated TrainerConfig instance.
|
||||
**/
|
||||
initForStatTrainer(signatureSpecies: (Species | Species[])[], isMale: boolean, ...specialtyTypes: Type[]): TrainerConfig {
|
||||
initForStatTrainer(isMale: boolean = false): TrainerConfig {
|
||||
if (!getIsInitialized()) {
|
||||
initI18n();
|
||||
}
|
||||
|
||||
this.setPartyTemplates(trainerPartyTemplates.ELITE_FOUR);
|
||||
|
||||
signatureSpecies.forEach((speciesPool, s) => {
|
||||
if (!Array.isArray(speciesPool)) {
|
||||
speciesPool = [ speciesPool ];
|
||||
}
|
||||
this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool));
|
||||
});
|
||||
if (specialtyTypes.length) {
|
||||
this.setSpeciesFilter(p => specialtyTypes.find(t => p.isOfType(t)) !== undefined);
|
||||
this.setSpecialtyTypes(...specialtyTypes);
|
||||
}
|
||||
const nameForCall = this.name.toLowerCase().replace(/\s/g, "_");
|
||||
this.name = i18next.t(`trainerNames:${nameForCall}`);
|
||||
this.setMoneyMultiplier(2);
|
||||
|
@ -850,11 +851,11 @@ export class TrainerConfig {
|
|||
/**
|
||||
* Initializes the trainer configuration for an evil team leader. Temporarily hardcoding evil leader teams though.
|
||||
* @param {Species | Species[]} signatureSpecies The signature species for the evil team leader.
|
||||
* @param {Type[]} specialtyTypes The specialty types for the evil team Leader.
|
||||
* @param {Type} specialtyType The specialty type for the evil team Leader.
|
||||
* @param boolean Whether or not this is the rematch fight
|
||||
* @returns {TrainerConfig} The updated TrainerConfig instance.
|
||||
* **/
|
||||
initForEvilTeamLeader(title: string, signatureSpecies: (Species | Species[])[], rematch: boolean = false, ...specialtyTypes: Type[]): TrainerConfig {
|
||||
initForEvilTeamLeader(title: string, signatureSpecies: (Species | Species[])[], rematch: boolean = false, specialtyType?: Type): TrainerConfig {
|
||||
if (!getIsInitialized()) {
|
||||
initI18n();
|
||||
}
|
||||
|
@ -869,9 +870,9 @@ export class TrainerConfig {
|
|||
}
|
||||
this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool));
|
||||
});
|
||||
if (specialtyTypes.length) {
|
||||
this.setSpeciesFilter(p => specialtyTypes.find(t => p.isOfType(t)) !== undefined);
|
||||
this.setSpecialtyTypes(...specialtyTypes);
|
||||
if (!Utils.isNullOrUndefined(specialtyType)) {
|
||||
this.setSpeciesFilter(p => p.isOfType(specialtyType));
|
||||
this.setSpecialtyType(specialtyType);
|
||||
}
|
||||
const nameForCall = this.name.toLowerCase().replace(/\s/g, "_");
|
||||
this.name = i18next.t(`trainerNames:${nameForCall}`);
|
||||
|
@ -888,12 +889,14 @@ export class TrainerConfig {
|
|||
|
||||
/**
|
||||
* Initializes the trainer configuration for a Gym Leader.
|
||||
* @param {Species | Species[]} signatureSpecies The signature species for the Gym Leader.
|
||||
* @param {Type[]} specialtyTypes The specialty types for the Gym Leader.
|
||||
* @param {Species | Species[]} signatureSpecies The signature species for the Gym Leader. Added to party in reverse order.
|
||||
* @param isMale Whether the Gym Leader is Male or Not (for localization of the title).
|
||||
* @param {Type} specialtyType The specialty type for the Gym Leader.
|
||||
* @param ignoreMinTeraWave Whether the Gym Leader always uses Tera (true), or only Teras after {@linkcode GYM_LEADER_TERA_WAVE} (false). Defaults to false.
|
||||
* @param teraSlot Optional, sets the party member in this slot to Terastallize. Wraps based on party size.
|
||||
* @returns {TrainerConfig} The updated TrainerConfig instance.
|
||||
* **/
|
||||
initForGymLeader(signatureSpecies: (Species | Species[])[], isMale: boolean, ...specialtyTypes: Type[]): TrainerConfig {
|
||||
initForGymLeader(signatureSpecies: (Species | Species[])[], isMale: boolean, specialtyType: Type, ignoreMinTeraWave: boolean = false, teraSlot?: number): TrainerConfig {
|
||||
// Check if the internationalization (i18n) system is initialized.
|
||||
if (!getIsInitialized()) {
|
||||
initI18n();
|
||||
|
@ -912,11 +915,9 @@ export class TrainerConfig {
|
|||
this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool));
|
||||
});
|
||||
|
||||
// If specialty types are provided, set species filter and specialty types.
|
||||
if (specialtyTypes.length) {
|
||||
this.setSpeciesFilter(p => specialtyTypes.find(t => p.isOfType(t)) !== undefined);
|
||||
this.setSpecialtyTypes(...specialtyTypes);
|
||||
}
|
||||
// If specialty type is provided, set species filter and specialty type.
|
||||
this.setSpeciesFilter(p => p.isOfType(specialtyType));
|
||||
this.setSpecialtyType(specialtyType);
|
||||
|
||||
// Localize the trainer's name by converting it to lowercase and replacing spaces with underscores.
|
||||
const nameForCall = this.name.toLowerCase().replace(/\s/g, "_");
|
||||
|
@ -935,7 +936,7 @@ export class TrainerConfig {
|
|||
this.setHasVoucher(true);
|
||||
this.setBattleBgm("battle_unova_gym");
|
||||
this.setVictoryBgm("victory_gym");
|
||||
this.setRandomTeraModifiers(() => globalScene.currentBattle.waveIndex >= 100 ? 1 : 0);
|
||||
this.setRandomTeraModifiers(() => (ignoreMinTeraWave || globalScene.currentBattle.waveIndex >= GYM_LEADER_TERA_WAVE) ? 1 : 0, teraSlot);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -943,11 +944,12 @@ export class TrainerConfig {
|
|||
/**
|
||||
* Initializes the trainer configuration for an Elite Four member.
|
||||
* @param {Species | Species[]} signatureSpecies The signature species for the Elite Four member.
|
||||
* @param {Type[]} specialtyTypes The specialty types for the Elite Four member.
|
||||
* @param isMale Whether the Elite Four Member is Male or Female (for localization of the title).
|
||||
* @param specialtyType {Type} The specialty type for the Elite Four member.
|
||||
* @param teraSlot Optional, sets the party member in this slot to Terastallize.
|
||||
* @returns {TrainerConfig} The updated TrainerConfig instance.
|
||||
**/
|
||||
initForEliteFour(signatureSpecies: (Species | Species[])[], isMale: boolean, ...specialtyTypes: Type[]): TrainerConfig {
|
||||
initForEliteFour(signatureSpecies: (Species | Species[])[], isMale: boolean, specialtyType?: Type, teraSlot?: number): TrainerConfig {
|
||||
// Check if the internationalization (i18n) system is initialized.
|
||||
if (!getIsInitialized()) {
|
||||
initI18n();
|
||||
|
@ -966,10 +968,10 @@ export class TrainerConfig {
|
|||
this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool));
|
||||
});
|
||||
|
||||
// Set species filter and specialty types if provided, otherwise filter by base total.
|
||||
if (specialtyTypes.length) {
|
||||
this.setSpeciesFilter(p => specialtyTypes.some(t => p.isOfType(t)) && p.baseTotal >= ELITE_FOUR_MINIMUM_BST);
|
||||
this.setSpecialtyTypes(...specialtyTypes);
|
||||
// Set species filter and specialty type if provided, otherwise filter by base total.
|
||||
if (!Utils.isNullOrUndefined(specialtyType)) {
|
||||
this.setSpeciesFilter(p => p.isOfType(specialtyType) && p.baseTotal >= ELITE_FOUR_MINIMUM_BST);
|
||||
this.setSpecialtyType(specialtyType);
|
||||
} else {
|
||||
this.setSpeciesFilter(p => p.baseTotal >= ELITE_FOUR_MINIMUM_BST);
|
||||
}
|
||||
|
@ -991,7 +993,7 @@ export class TrainerConfig {
|
|||
this.setHasVoucher(true);
|
||||
this.setBattleBgm("battle_unova_elite");
|
||||
this.setVictoryBgm("victory_gym");
|
||||
this.setRandomTeraModifiers(() => 1);
|
||||
this.setRandomTeraModifiers(() => 1, teraSlot);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -1142,6 +1144,14 @@ export class TrainerConfig {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to check if a specialty type is set
|
||||
* @returns true if specialtyType is defined and not Type.UNKNOWN
|
||||
*/
|
||||
hasSpecialtyType(): boolean {
|
||||
return !Utils.isNullOrUndefined(this.specialtyType) && this.specialtyType !== Type.UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a shallow copy of a trainer config so that it can be modified without affecting the {@link trainerConfigs} source map
|
||||
*/
|
||||
|
@ -1183,9 +1193,7 @@ export class TrainerConfig {
|
|||
|
||||
clone = this.speciesPools ? clone.setSpeciesPools(this.speciesPools) : clone;
|
||||
clone = this.speciesFilter ? clone.setSpeciesFilter(this.speciesFilter) : clone;
|
||||
if (this.specialtyTypes) {
|
||||
clone.specialtyTypes = this.specialtyTypes.slice(0);
|
||||
}
|
||||
clone.specialtyType = this.specialtyType;
|
||||
|
||||
clone.encounterMessages = this.encounterMessages?.slice(0);
|
||||
clone.victoryMessages = this.victoryMessages?.slice(0);
|
||||
|
@ -1352,28 +1360,28 @@ export const signatureSpecies: SignatureSpecies = {
|
|||
PIERS: [ Species.GALAR_ZIGZAGOON, Species.SCRAGGY, Species.INKAY ],
|
||||
MARNIE: [ Species.IMPIDIMP, Species.PURRLOIN, Species.MORPEKO ],
|
||||
RAIHAN: [ Species.DURALUDON, Species.TURTONATOR, Species.GOOMY ],
|
||||
KATY: [ Species.NYMBLE, Species.TAROUNTULA, Species.HERACROSS ],
|
||||
BRASSIUS: [ Species.SMOLIV, Species.SHROOMISH, Species.ODDISH ],
|
||||
IONO: [ Species.TADBULB, Species.WATTREL, Species.VOLTORB ],
|
||||
KOFU: [ Species.VELUZA, Species.WIGLETT, Species.WINGULL ],
|
||||
LARRY: [ Species.STARLY, Species.DUNSPARCE, Species.LECHONK, Species.KOMALA ],
|
||||
RYME: [ Species.GREAVARD, Species.SHUPPET, Species.MIMIKYU ],
|
||||
TULIP: [ Species.GIRAFARIG, Species.FLITTLE, Species.RALTS ],
|
||||
GRUSHA: [ Species.CETODDLE, Species.ALOLA_VULPIX, Species.CUBCHOO ],
|
||||
LORELEI: [ Species.JYNX, [ Species.SLOWBRO, Species.GALAR_SLOWBRO ], Species.LAPRAS, [ Species.ALOLA_SANDSLASH, Species.CLOYSTER ]],
|
||||
BRUNO: [ Species.MACHAMP, Species.HITMONCHAN, Species.HITMONLEE, [ Species.ALOLA_GOLEM, Species.GOLEM ]],
|
||||
KATY: [ Species.TEDDIURSA, Species.NYMBLE, Species.TAROUNTULA ], // Tera Bug Teddiursa
|
||||
BRASSIUS: [ Species.SUDOWOODO, Species.BRAMBLIN, Species.SMOLIV ], // Tera Grass Sudowoodo
|
||||
IONO: [ Species.MISDREAVUS, Species.TADBULB, Species.WATTREL ], // Tera Ghost Misdreavus
|
||||
KOFU: [ Species.CRABRAWLER, Species.VELUZA, Species.WIGLETT, Species.WINGULL ], // Tera Water Crabrawler
|
||||
LARRY: [ Species.STARLY, Species.DUNSPARCE, Species.LECHONK, Species.KOMALA ], // Tera Normal Starly
|
||||
RYME: [ Species.TOXEL, Species.GREAVARD, Species.SHUPPET, Species.MIMIKYU ], // Tera Ghost Toxel
|
||||
TULIP: [ Species.FLABEBE, Species.FLITTLE, Species.RALTS, Species.GIRAFARIG ], // Tera Psychic Flabebe
|
||||
GRUSHA: [ Species.SWABLU, Species.CETODDLE, Species.CUBCHOO, Species.ALOLA_VULPIX ], // Tera Ice Swablu
|
||||
LORELEI: [ Species.JYNX, [ Species.SLOWBRO, Species.GALAR_SLOWBRO ], Species.LAPRAS, [ Species.CLOYSTER, Species.ALOLA_SANDSLASH ]],
|
||||
BRUNO: [ Species.MACHAMP, Species.HITMONCHAN, Species.HITMONLEE, [ Species.GOLEM, Species.ALOLA_GOLEM ]],
|
||||
AGATHA: [ Species.GENGAR, [ Species.ARBOK, Species.WEEZING ], Species.CROBAT, Species.ALOLA_MAROWAK ],
|
||||
LANCE: [ Species.DRAGONITE, Species.GYARADOS, Species.AERODACTYL, Species.ALOLA_EXEGGUTOR ],
|
||||
WILL: [ Species.XATU, Species.JYNX, [ Species.SLOWBRO, Species.SLOWKING ], Species.EXEGGUTOR ],
|
||||
KOGA: [[ Species.WEEZING, Species.MUK ], [ Species.VENOMOTH, Species.ARIADOS ], Species.CROBAT, Species.TENTACRUEL ],
|
||||
KOGA: [[ Species.MUK, Species.WEEZING ], [ Species.VENOMOTH, Species.ARIADOS ], Species.CROBAT, Species.TENTACRUEL ],
|
||||
KAREN: [ Species.UMBREON, Species.HONCHKROW, Species.HOUNDOOM, Species.WEAVILE ],
|
||||
SIDNEY: [[ Species.SHIFTRY, Species.CACTURNE ], [ Species.SHARPEDO, Species.CRAWDAUNT ], Species.ABSOL, Species.MIGHTYENA ],
|
||||
PHOEBE: [ Species.SABLEYE, Species.DUSKNOIR, Species.BANETTE, [ Species.MISMAGIUS, Species.DRIFBLIM ]],
|
||||
PHOEBE: [ Species.SABLEYE, Species.DUSKNOIR, Species.BANETTE, [ Species.DRIFBLIM, Species.MISMAGIUS ]],
|
||||
GLACIA: [ Species.GLALIE, Species.WALREIN, Species.FROSLASS, Species.ABOMASNOW ],
|
||||
DRAKE: [ Species.ALTARIA, Species.SALAMENCE, Species.FLYGON, Species.KINGDRA ],
|
||||
AARON: [[ Species.SCIZOR, Species.KLEAVOR ], Species.HERACROSS, [ Species.VESPIQUEN, Species.YANMEGA ], Species.DRAPION ],
|
||||
BERTHA: [ Species.WHISCASH, Species.HIPPOWDON, Species.GLISCOR, Species.RHYPERIOR ],
|
||||
FLINT: [[ Species.FLAREON, Species.RAPIDASH ], Species.MAGMORTAR, [ Species.STEELIX, Species.LOPUNNY ], Species.INFERNAPE ],
|
||||
FLINT: [[ Species.RAPIDASH, Species.FLAREON ], Species.MAGMORTAR, [ Species.STEELIX, Species.LOPUNNY ], Species.INFERNAPE ], // Tera Fire Steelix or Lopunny
|
||||
LUCIAN: [ Species.MR_MIME, Species.GALLADE, Species.BRONZONG, [ Species.ALAKAZAM, Species.ESPEON ]],
|
||||
SHAUNTAL: [ Species.COFAGRIGUS, Species.CHANDELURE, Species.GOLURK, Species.JELLICENT ],
|
||||
MARSHAL: [ Species.CONKELDURR, Species.MIENSHAO, Species.THROH, Species.SAWK ],
|
||||
|
@ -1389,18 +1397,18 @@ export const signatureSpecies: SignatureSpecies = {
|
|||
ACEROLA: [[ Species.BANETTE, Species.DRIFBLIM ], Species.MIMIKYU, Species.DHELMISE, Species.PALOSSAND ],
|
||||
KAHILI: [[ Species.BRAVIARY, Species.MANDIBUZZ ], Species.HAWLUCHA, Species.ORICORIO, Species.TOUCANNON ],
|
||||
MARNIE_ELITE: [ Species.MORPEKO, Species.LIEPARD, [ Species.TOXICROAK, Species.SCRAFTY ], Species.GRIMMSNARL ],
|
||||
NESSA_ELITE: [ Species.GOLISOPOD, [ Species.PELIPPER, Species.QUAGSIRE ], Species.TOXAPEX, Species.DREDNAW ],
|
||||
NESSA_ELITE: [ Species.GOLISOPOD, [ Species.QUAGSIRE, Species.PELIPPER ], Species.TOXAPEX, Species.DREDNAW ],
|
||||
BEA_ELITE: [ Species.HAWLUCHA, [ Species.GRAPPLOCT, Species.SIRFETCHD ], Species.FALINKS, Species.MACHAMP ],
|
||||
ALLISTER_ELITE: [ Species.DUSKNOIR, [ Species.POLTEAGEIST, Species.RUNERIGUS ], Species.CURSOLA, Species.GENGAR ],
|
||||
RAIHAN_ELITE: [ Species.GOODRA, [ Species.TORKOAL, Species.TURTONATOR ], Species.FLYGON, Species.ARCHALUDON ],
|
||||
RIKA: [ Species.WHISCASH, [ Species.DONPHAN, Species.DUGTRIO ], Species.CAMERUPT, Species.CLODSIRE ],
|
||||
POPPY: [ Species.COPPERAJAH, Species.BRONZONG, Species.CORVIKNIGHT, Species.TINKATON ],
|
||||
LARRY_ELITE: [ Species.STARAPTOR, Species.FLAMIGO, Species.ALTARIA, Species.TROPIUS ],
|
||||
HASSEL: [ Species.NOIVERN, [ Species.FLAPPLE, Species.APPLETUN ], Species.DRAGALGE, Species.BAXCALIBUR ],
|
||||
CRISPIN: [ Species.TALONFLAME, Species.CAMERUPT, Species.MAGMORTAR, Species.BLAZIKEN ],
|
||||
AMARYS: [ Species.SKARMORY, Species.EMPOLEON, Species.SCIZOR, Species.METAGROSS ],
|
||||
LACEY: [ Species.EXCADRILL, Species.PRIMARINA, [ Species.ALCREMIE, Species.GRANBULL ], Species.WHIMSICOTT ],
|
||||
DRAYTON: [ Species.DRAGONITE, Species.ARCHALUDON, Species.HAXORUS, Species.SCEPTILE ],
|
||||
RIKA: [ Species.CLODSIRE, [ Species.DUGTRIO, Species.DONPHAN ], Species.CAMERUPT, Species.WHISCASH ], // Tera Ground Clodsire
|
||||
POPPY: [ Species.TINKATON, Species.BRONZONG, Species.CORVIKNIGHT, Species.COPPERAJAH ], // Tera Steel Tinkaton
|
||||
LARRY_ELITE: [ Species.FLAMIGO, Species.STARAPTOR, [ Species.ALTARIA, Species.TROPIUS ], Species.ORICORIO ], // Tera Flying Flamigo; random Oricorio
|
||||
HASSEL: [ Species.BAXCALIBUR, [ Species.FLAPPLE, Species.APPLETUN ], Species.DRAGALGE, Species.NOIVERN ], // Tera Dragon Baxcalibur
|
||||
CRISPIN: [ Species.BLAZIKEN, Species.MAGMORTAR, [ Species.CAMERUPT, Species.TALONFLAME ], Species.ROTOM ], // Tera Fire Blaziken; Heat Rotom
|
||||
AMARYS: [ Species.METAGROSS, Species.SCIZOR, Species.EMPOLEON, Species.SKARMORY ], // Tera Steel Metagross
|
||||
LACEY: [ Species.EXCADRILL, Species.PRIMARINA, [ Species.WHIMSICOTT, Species.ALCREMIE ], Species.GRANBULL ], // Tera Fairy Excadrill
|
||||
DRAYTON: [ Species.ARCHALUDON, Species.DRAGONITE, Species.HAXORUS, Species.SCEPTILE ], // Tera Dragon Archaludon
|
||||
};
|
||||
|
||||
export const trainerConfigs: TrainerConfigs = {
|
||||
|
@ -1421,7 +1429,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
[TrainerType.BAKER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CLERK).setMoneyMultiplier(1.35).setSpeciesFilter(s => s.isOfType(Type.GRASS) || s.isOfType(Type.FIRE)),
|
||||
[TrainerType.BEAUTY]: new TrainerConfig(++t).setMoneyMultiplier(1.55).setEncounterBgm(TrainerType.PARASOL_LADY),
|
||||
[TrainerType.BIKER]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setEncounterBgm(TrainerType.ROUGHNECK).setSpeciesFilter(s => s.isOfType(Type.POISON)),
|
||||
[TrainerType.BLACK_BELT]: new TrainerConfig(++t).setHasGenders("Battle Girl", TrainerType.PSYCHIC).setHasDouble("Crush Kin").setEncounterBgm(TrainerType.ROUGHNECK).setSpecialtyTypes(Type.FIGHTING)
|
||||
[TrainerType.BLACK_BELT]: new TrainerConfig(++t).setHasGenders("Battle Girl", TrainerType.PSYCHIC).setHasDouble("Crush Kin").setEncounterBgm(TrainerType.ROUGHNECK).setSpecialtyType(Type.FIGHTING)
|
||||
.setPartyTemplates(trainerPartyTemplates.TWO_WEAK_ONE_AVG, trainerPartyTemplates.TWO_WEAK_ONE_AVG, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_WEAK_ONE_STRONG, trainerPartyTemplates.THREE_AVG, trainerPartyTemplates.TWO_AVG_ONE_STRONG)
|
||||
.setSpeciesPools({
|
||||
[TrainerPoolTier.COMMON]: [ Species.NIDORAN_F, Species.NIDORAN_M, Species.MACHOP, Species.MAKUHITA, Species.MEDITITE, Species.CROAGUNK, Species.TIMBURR ],
|
||||
|
@ -1461,7 +1469,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
.setSpeciesFilter(s => !!s.getLevelMoves().find(plm => plm[1] === Moves.HEAL_PULSE)),
|
||||
[TrainerType.FIREBREATHER]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setEncounterBgm(TrainerType.ROUGHNECK)
|
||||
.setSpeciesFilter(s => !!s.getLevelMoves().find(plm => plm[1] === Moves.SMOG) || s.isOfType(Type.FIRE)),
|
||||
[TrainerType.FISHERMAN]: new TrainerConfig(++t).setMoneyMultiplier(1.25).setEncounterBgm(TrainerType.BACKPACKER).setSpecialtyTypes(Type.WATER)
|
||||
[TrainerType.FISHERMAN]: new TrainerConfig(++t).setMoneyMultiplier(1.25).setEncounterBgm(TrainerType.BACKPACKER).setSpecialtyType(Type.WATER)
|
||||
.setPartyTemplates(trainerPartyTemplates.TWO_WEAK_SAME_ONE_AVG, trainerPartyTemplates.ONE_AVG, trainerPartyTemplates.THREE_WEAK_SAME, trainerPartyTemplates.ONE_STRONG, trainerPartyTemplates.SIX_WEAKER)
|
||||
.setSpeciesPools({
|
||||
[TrainerPoolTier.COMMON]: [ Species.TENTACOOL, Species.MAGIKARP, Species.GOLDEEN, Species.STARYU, Species.REMORAID, Species.SKRELP, Species.CLAUNCHER, Species.ARROKUDA ],
|
||||
|
@ -1469,7 +1477,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
[TrainerPoolTier.RARE]: [ Species.CHINCHOU, Species.CORSOLA, Species.WAILMER, Species.BARBOACH, Species.CLAMPERL, Species.LUVDISC, Species.MANTYKE, Species.ALOMOMOLA, Species.TATSUGIRI, Species.VELUZA ],
|
||||
[TrainerPoolTier.SUPER_RARE]: [ Species.LAPRAS, Species.FEEBAS, Species.RELICANTH, Species.DONDOZO ]
|
||||
}),
|
||||
[TrainerType.GUITARIST]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.ROUGHNECK).setSpecialtyTypes(Type.ELECTRIC).setSpeciesFilter(s => s.isOfType(Type.ELECTRIC)),
|
||||
[TrainerType.GUITARIST]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.ROUGHNECK).setSpecialtyType(Type.ELECTRIC).setSpeciesFilter(s => s.isOfType(Type.ELECTRIC)),
|
||||
[TrainerType.HARLEQUIN]: new TrainerConfig(++t).setEncounterBgm(TrainerType.PSYCHIC).setSpeciesFilter(s => tmSpecies[Moves.TRICK_ROOM].indexOf(s.speciesId) > -1),
|
||||
[TrainerType.HIKER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.BACKPACKER)
|
||||
.setPartyTemplates(trainerPartyTemplates.TWO_AVG_SAME_ONE_AVG, trainerPartyTemplates.TWO_AVG_SAME_ONE_STRONG, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.FOUR_WEAK, trainerPartyTemplates.ONE_STRONG)
|
||||
|
@ -1548,7 +1556,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
[TrainerPoolTier.RARE]: [ Species.TANGELA, Species.EEVEE, Species.YANMA ],
|
||||
[TrainerPoolTier.SUPER_RARE]: [ Species.TADBULB ]
|
||||
}),
|
||||
[TrainerType.SWIMMER]: new TrainerConfig(++t).setMoneyMultiplier(1.3).setEncounterBgm(TrainerType.PARASOL_LADY).setHasGenders("Swimmer Female").setHasDouble("Swimmers").setSpecialtyTypes(Type.WATER).setSpeciesFilter(s => s.isOfType(Type.WATER)),
|
||||
[TrainerType.SWIMMER]: new TrainerConfig(++t).setMoneyMultiplier(1.3).setEncounterBgm(TrainerType.PARASOL_LADY).setHasGenders("Swimmer Female").setHasDouble("Swimmers").setSpecialtyType(Type.WATER).setSpeciesFilter(s => s.isOfType(Type.WATER)),
|
||||
[TrainerType.TWINS]: new TrainerConfig(++t).setDoubleOnly().setMoneyMultiplier(0.65).setUseSameSeedForAllMembers()
|
||||
.setPartyTemplateFunc(() => getWavePartyTemplate(trainerPartyTemplates.TWO_WEAK, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_STRONG))
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.PLUSLE, Species.VOLBEAT, Species.PACHIRISU, Species.SILCOON, Species.METAPOD, Species.IGGLYBUFF, Species.PETILIL, Species.EEVEE ]))
|
||||
|
@ -1654,27 +1662,27 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
[TrainerPoolTier.RARE]: [ Species.MANKEY, Species.PAWNIARD, Species.CHARCADET, Species.FLITTLE, Species.VAROOM, Species.ORTHWORM ],
|
||||
[TrainerPoolTier.SUPER_RARE]: [ Species.DONDOZO, Species.GIMMIGHOUL ]
|
||||
}),
|
||||
[TrainerType.GIACOMO]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("star_admin", "star_1", [ Species.KINGAMBIT ]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_star_admin").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(() => getEvilGruntPartyTemplate())
|
||||
[TrainerType.GIACOMO]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("star_admin", "star_1", [ Species.KINGAMBIT ], Type.DARK).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_star_admin").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(() => getEvilGruntPartyTemplate())
|
||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.REVAVROOM ], TrainerSlot.TRAINER, true, p => {
|
||||
p.formIndex = 1; // Segin Starmobile
|
||||
p.moveset = [ new PokemonMove(Moves.WICKED_TORQUE), new PokemonMove(Moves.SPIN_OUT), new PokemonMove(Moves.SHIFT_GEAR), new PokemonMove(Moves.HIGH_HORSEPOWER) ];
|
||||
})),
|
||||
[TrainerType.MELA]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("star_admin", "star_2", [ Species.ARMAROUGE ]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_star_admin").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(() => getEvilGruntPartyTemplate())
|
||||
[TrainerType.MELA]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("star_admin", "star_2", [ Species.ARMAROUGE ], Type.FIRE).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_star_admin").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(() => getEvilGruntPartyTemplate())
|
||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.REVAVROOM ], TrainerSlot.TRAINER, true, p => {
|
||||
p.formIndex = 2; // Schedar Starmobile
|
||||
p.moveset = [ new PokemonMove(Moves.BLAZING_TORQUE), new PokemonMove(Moves.SPIN_OUT), new PokemonMove(Moves.SHIFT_GEAR), new PokemonMove(Moves.HIGH_HORSEPOWER) ];
|
||||
})),
|
||||
[TrainerType.ATTICUS]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("star_admin", "star_3", [ Species.REVAVROOM ]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_star_admin").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(() => getEvilGruntPartyTemplate())
|
||||
[TrainerType.ATTICUS]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("star_admin", "star_3", [ Species.REVAVROOM ], Type.POISON).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_star_admin").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(() => getEvilGruntPartyTemplate())
|
||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.REVAVROOM ], TrainerSlot.TRAINER, true, p => {
|
||||
p.formIndex = 3; // Navi Starmobile
|
||||
p.moveset = [ new PokemonMove(Moves.NOXIOUS_TORQUE), new PokemonMove(Moves.SPIN_OUT), new PokemonMove(Moves.SHIFT_GEAR), new PokemonMove(Moves.HIGH_HORSEPOWER) ];
|
||||
})),
|
||||
[TrainerType.ORTEGA]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("star_admin", "star_4", [ Species.DACHSBUN ]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_star_admin").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(() => getEvilGruntPartyTemplate())
|
||||
[TrainerType.ORTEGA]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("star_admin", "star_4", [ Species.DACHSBUN ], Type.FAIRY).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_star_admin").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(() => getEvilGruntPartyTemplate())
|
||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.REVAVROOM ], TrainerSlot.TRAINER, true, p => {
|
||||
p.formIndex = 4; // Ruchbah Starmobile
|
||||
p.moveset = [ new PokemonMove(Moves.MAGICAL_TORQUE), new PokemonMove(Moves.SPIN_OUT), new PokemonMove(Moves.SHIFT_GEAR), new PokemonMove(Moves.HIGH_HORSEPOWER) ];
|
||||
})),
|
||||
[TrainerType.ERI]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("star_admin", "star_5", [ Species.ANNIHILAPE ]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_star_admin").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(() => getEvilGruntPartyTemplate())
|
||||
[TrainerType.ERI]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("star_admin", "star_5", [ Species.ANNIHILAPE ], Type.FIGHTING).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_star_admin").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(() => getEvilGruntPartyTemplate())
|
||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.REVAVROOM ], TrainerSlot.TRAINER, true, p => {
|
||||
p.formIndex = 5; // Caph Starmobile
|
||||
p.moveset = [ new PokemonMove(Moves.COMBAT_TORQUE), new PokemonMove(Moves.SPIN_OUT), new PokemonMove(Moves.SHIFT_GEAR), new PokemonMove(Moves.HIGH_HORSEPOWER) ];
|
||||
|
@ -1746,14 +1754,14 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
[TrainerType.PIERS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["PIERS"], true, Type.DARK).setHasDouble("piers_marnie_double").setDoubleTrainerType(TrainerType.MARNIE).setDoubleTitle("gym_leader_double").setMixedBattleBgm("battle_galar_gym"),
|
||||
[TrainerType.MARNIE]: new TrainerConfig(++t).setName("Marnie").initForGymLeader(signatureSpecies["MARNIE"], false, Type.DARK).setHasDouble("marnie_piers_double").setDoubleTrainerType(TrainerType.PIERS).setDoubleTitle("gym_leader_double").setMixedBattleBgm("battle_galar_gym"),
|
||||
[TrainerType.RAIHAN]: new TrainerConfig(++t).setName("Raihan").initForGymLeader(signatureSpecies["RAIHAN"], true, Type.DRAGON).setMixedBattleBgm("battle_galar_gym"),
|
||||
[TrainerType.KATY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KATY"], false, Type.BUG).setMixedBattleBgm("battle_paldea_gym"),
|
||||
[TrainerType.BRASSIUS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BRASSIUS"], true, Type.GRASS).setMixedBattleBgm("battle_paldea_gym"),
|
||||
[TrainerType.IONO]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["IONO"], false, Type.ELECTRIC).setMixedBattleBgm("battle_paldea_gym"),
|
||||
[TrainerType.KOFU]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KOFU"], true, Type.WATER).setMixedBattleBgm("battle_paldea_gym"),
|
||||
[TrainerType.LARRY]: new TrainerConfig(++t).setName("Larry").initForGymLeader(signatureSpecies["LARRY"], true, Type.NORMAL).setMixedBattleBgm("battle_paldea_gym"),
|
||||
[TrainerType.RYME]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["RYME"], false, Type.GHOST).setMixedBattleBgm("battle_paldea_gym"),
|
||||
[TrainerType.TULIP]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["TULIP"], false, Type.PSYCHIC).setMixedBattleBgm("battle_paldea_gym"),
|
||||
[TrainerType.GRUSHA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GRUSHA"], true, Type.ICE).setMixedBattleBgm("battle_paldea_gym"),
|
||||
[TrainerType.KATY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KATY"], false, Type.BUG, true, -1).setMixedBattleBgm("battle_paldea_gym"),
|
||||
[TrainerType.BRASSIUS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BRASSIUS"], true, Type.GRASS, true, -1).setMixedBattleBgm("battle_paldea_gym"),
|
||||
[TrainerType.IONO]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["IONO"], false, Type.ELECTRIC, true, -1).setMixedBattleBgm("battle_paldea_gym"),
|
||||
[TrainerType.KOFU]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KOFU"], true, Type.WATER, true, -1).setMixedBattleBgm("battle_paldea_gym"),
|
||||
[TrainerType.LARRY]: new TrainerConfig(++t).setName("Larry").initForGymLeader(signatureSpecies["LARRY"], true, Type.NORMAL, true, -1).setMixedBattleBgm("battle_paldea_gym"),
|
||||
[TrainerType.RYME]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["RYME"], false, Type.GHOST, true, -1).setMixedBattleBgm("battle_paldea_gym"),
|
||||
[TrainerType.TULIP]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["TULIP"], false, Type.PSYCHIC, true, -1).setMixedBattleBgm("battle_paldea_gym"),
|
||||
[TrainerType.GRUSHA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GRUSHA"], true, Type.ICE, true, -1).setMixedBattleBgm("battle_paldea_gym"),
|
||||
|
||||
[TrainerType.LORELEI]: new TrainerConfig((t = TrainerType.LORELEI)).initForEliteFour(signatureSpecies["LORELEI"], false, Type.ICE).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"),
|
||||
[TrainerType.BRUNO]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["BRUNO"], true, Type.FIGHTING).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"),
|
||||
|
@ -1768,7 +1776,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
[TrainerType.DRAKE]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["DRAKE"], true, Type.DRAGON).setMixedBattleBgm("battle_hoenn_elite"),
|
||||
[TrainerType.AARON]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["AARON"], true, Type.BUG).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"),
|
||||
[TrainerType.BERTHA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["BERTHA"], false, Type.GROUND).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"),
|
||||
[TrainerType.FLINT]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["FLINT"], true, Type.FIRE).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"),
|
||||
[TrainerType.FLINT]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["FLINT"], true, Type.FIRE, 3).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"),
|
||||
[TrainerType.LUCIAN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["LUCIAN"], true, Type.PSYCHIC).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"),
|
||||
[TrainerType.SHAUNTAL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["SHAUNTAL"], false, Type.GHOST).setMixedBattleBgm("battle_unova_elite"),
|
||||
[TrainerType.MARSHAL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["MARSHAL"], true, Type.FIGHTING).setMixedBattleBgm("battle_unova_elite"),
|
||||
|
@ -1788,14 +1796,14 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
[TrainerType.BEA_ELITE]: new TrainerConfig(++t).setName("Bea").initForEliteFour(signatureSpecies["BEA_ELITE"], false, Type.FIGHTING).setMixedBattleBgm("battle_galar_elite"),
|
||||
[TrainerType.ALLISTER_ELITE]: new TrainerConfig(++t).setName("Allister").initForEliteFour(signatureSpecies["ALLISTER_ELITE"], true, Type.GHOST).setMixedBattleBgm("battle_galar_elite"),
|
||||
[TrainerType.RAIHAN_ELITE]: new TrainerConfig(++t).setName("Raihan").initForEliteFour(signatureSpecies["RAIHAN_ELITE"], true, Type.DRAGON).setMixedBattleBgm("battle_galar_elite"),
|
||||
[TrainerType.RIKA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["RIKA"], false, Type.GROUND).setMixedBattleBgm("battle_paldea_elite"),
|
||||
[TrainerType.POPPY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["POPPY"], false, Type.STEEL).setMixedBattleBgm("battle_paldea_elite"),
|
||||
[TrainerType.LARRY_ELITE]: new TrainerConfig(++t).setName("Larry").initForEliteFour(signatureSpecies["LARRY_ELITE"], true, Type.NORMAL, Type.FLYING).setMixedBattleBgm("battle_paldea_elite"),
|
||||
[TrainerType.HASSEL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["HASSEL"], true, Type.DRAGON).setMixedBattleBgm("battle_paldea_elite"),
|
||||
[TrainerType.CRISPIN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["CRISPIN"], true, Type.FIRE).setMixedBattleBgm("battle_bb_elite"),
|
||||
[TrainerType.AMARYS]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["AMARYS"], false, Type.STEEL).setMixedBattleBgm("battle_bb_elite"),
|
||||
[TrainerType.LACEY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["LACEY"], false, Type.FAIRY).setMixedBattleBgm("battle_bb_elite"),
|
||||
[TrainerType.DRAYTON]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["DRAYTON"], true, Type.DRAGON).setMixedBattleBgm("battle_bb_elite"),
|
||||
[TrainerType.RIKA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["RIKA"], false, Type.GROUND, 5).setMixedBattleBgm("battle_paldea_elite"),
|
||||
[TrainerType.POPPY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["POPPY"], false, Type.STEEL, 5).setMixedBattleBgm("battle_paldea_elite"),
|
||||
[TrainerType.LARRY_ELITE]: new TrainerConfig(++t).setName("Larry").initForEliteFour(signatureSpecies["LARRY_ELITE"], true, Type.FLYING, 5).setMixedBattleBgm("battle_paldea_elite"),
|
||||
[TrainerType.HASSEL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["HASSEL"], true, Type.DRAGON, 5).setMixedBattleBgm("battle_paldea_elite"),
|
||||
[TrainerType.CRISPIN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["CRISPIN"], true, Type.FIRE, 5).setMixedBattleBgm("battle_bb_elite"),
|
||||
[TrainerType.AMARYS]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["AMARYS"], false, Type.STEEL, 5).setMixedBattleBgm("battle_bb_elite"),
|
||||
[TrainerType.LACEY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["LACEY"], false, Type.FAIRY, 5).setMixedBattleBgm("battle_bb_elite"),
|
||||
[TrainerType.DRAYTON]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["DRAYTON"], true, Type.DRAGON, 5).setMixedBattleBgm("battle_bb_elite"),
|
||||
|
||||
[TrainerType.BLUE]: new TrainerConfig((t = TrainerType.BLUE)).initForChampion(true).setBattleBgm("battle_kanto_champion").setMixedBattleBgm("battle_kanto_champion").setHasDouble("blue_red_double").setDoubleTrainerType(TrainerType.RED).setDoubleTitle("champion_double")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.ALAKAZAM ]))
|
||||
|
@ -1815,7 +1823,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
p.generateName();
|
||||
p.gender = Gender.MALE;
|
||||
}))
|
||||
.setInstantTera(3),
|
||||
.setInstantTera(3), // Tera Ground or Rock Rhyperior / Electric Electivire / Fire Magmortar
|
||||
[TrainerType.RED]: new TrainerConfig(++t).initForChampion(true).setBattleBgm("battle_johto_champion").setMixedBattleBgm("battle_johto_champion").setHasDouble("red_blue_double").setDoubleTrainerType(TrainerType.BLUE).setDoubleTitle("champion_double")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.PIKACHU ], TrainerSlot.TRAINER, true, p => {
|
||||
p.formIndex = 8; // G-Max Pikachu
|
||||
|
@ -1839,7 +1847,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
p.generateName();
|
||||
p.gender = Gender.MALE;
|
||||
}))
|
||||
.setInstantTera(3),
|
||||
.setInstantTera(3), // Tera Grass Meganium / Fire Typhlosion / Water Feraligatr
|
||||
[TrainerType.LANCE_CHAMPION]: new TrainerConfig(++t).setName("Lance").initForChampion(true).setBattleBgm("battle_johto_champion").setMixedBattleBgm("battle_johto_champion")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GYARADOS, Species.KINGDRA ]))
|
||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.AERODACTYL ]))
|
||||
|
@ -1850,14 +1858,15 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
}))
|
||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.CHARIZARD ]))
|
||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.TYRANITAR, Species.GARCHOMP, Species.KOMMO_O ], TrainerSlot.TRAINER, true, p => {
|
||||
p.teraType = p.species.type1;
|
||||
p.teraType = Type.DRAGON;
|
||||
p.abilityIndex = p.species.speciesId === Species.KOMMO_O ? 1 : 2; // Soundproof Kommo-o, Unnerve Tyranitar, Rough Skin Garchomp
|
||||
}))
|
||||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.DRAGONITE ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
p.gender = Gender.MALE;
|
||||
p.setBoss(true, 2);
|
||||
}))
|
||||
.setInstantTera(4),
|
||||
.setInstantTera(4), // Tera Dragon Tyranitar / Garchomp / Kommo-o
|
||||
[TrainerType.STEVEN]: new TrainerConfig(++t).initForChampion(true).setBattleBgm("battle_hoenn_champion_g5").setMixedBattleBgm("battle_hoenn_champion_g6").setHasDouble("steven_wallace_double").setDoubleTrainerType(TrainerType.WALLACE).setDoubleTitle("champion_double")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SKARMORY ]))
|
||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.CRADILY, Species.ARMALDO ]))
|
||||
|
@ -1875,7 +1884,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
p.generateAndPopulateMoveset();
|
||||
p.generateName();
|
||||
}))
|
||||
.setInstantTera(4),
|
||||
.setInstantTera(4), // Tera Rock Regirock / Ice Regice / Steel Registeel
|
||||
[TrainerType.WALLACE]: new TrainerConfig(++t).initForChampion(true).setBattleBgm("battle_hoenn_champion_g5").setMixedBattleBgm("battle_hoenn_champion_g6").setHasDouble("wallace_steven_double").setDoubleTrainerType(TrainerType.STEVEN).setDoubleTitle("champion_double")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.PELIPPER ], TrainerSlot.TRAINER, true, p => {
|
||||
p.abilityIndex = 1; // Drizzle
|
||||
|
@ -1898,7 +1907,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
p.gender = Gender.FEMALE;
|
||||
p.setBoss(true, 2);
|
||||
}))
|
||||
.setInstantTera(4),
|
||||
.setInstantTera(4), // Tera Electric Regieleki / Dragon Regidrago
|
||||
[TrainerType.CYNTHIA]: new TrainerConfig(++t).initForChampion(false).setBattleBgm("battle_sinnoh_champion").setMixedBattleBgm("battle_sinnoh_champion")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SPIRITOMB ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
|
@ -1921,7 +1930,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
p.generateName();
|
||||
p.gender = Gender.FEMALE;
|
||||
}))
|
||||
.setInstantTera(3),
|
||||
.setInstantTera(3), // Tera Water Milotic / Grass Roserade / Fire Hisuian Arcanine
|
||||
[TrainerType.ALDER]: new TrainerConfig(++t).initForChampion(true).setHasDouble("alder_iris_double").setDoubleTrainerType(TrainerType.IRIS).setDoubleTitle("champion_double").setBattleBgm("battle_champion_alder").setMixedBattleBgm("battle_champion_alder")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BOUFFALANT, Species.BRAVIARY ]))
|
||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HISUI_LILLIGANT, Species.HISUI_ZOROARK, Species.BASCULEGION ], TrainerSlot.TRAINER, true, p => {
|
||||
|
@ -1944,7 +1953,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
p.gender = Gender.MALE;
|
||||
p.setBoss(true, 2);
|
||||
}))
|
||||
.setInstantTera(4),
|
||||
.setInstantTera(4), // Tera Ghost Chandelure / Dark Krookodile / Psychic Reuniclus / Fighting Conkeldurr
|
||||
[TrainerType.IRIS]: new TrainerConfig(++t).initForChampion(false).setBattleBgm("battle_champion_iris").setMixedBattleBgm("battle_champion_iris").setHasDouble("iris_alder_double").setDoubleTrainerType(TrainerType.ALDER).setDoubleTitle("champion_double")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.DRUDDIGON ]))
|
||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.ARCHEOPS ]))
|
||||
|
@ -1966,7 +1975,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
p.gender = Gender.FEMALE;
|
||||
p.setBoss(true, 2);
|
||||
}))
|
||||
.setInstantTera(3),
|
||||
.setInstantTera(3), // Tera Dragon Salamence / Hydreigon / Archaludon
|
||||
[TrainerType.DIANTHA]: new TrainerConfig(++t).initForChampion(false).setMixedBattleBgm("battle_kalos_champion")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.HAWLUCHA ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
|
@ -1979,7 +1988,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.TYRANTRUM, Species.AURORUS ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
p.abilityIndex = 2; // Rock Head Tyrantrum, Snow Warning Aurorus
|
||||
p.teraType = p.species.speciesId === Species.TYRANTRUM ? Type.DRAGON : Type.ICE;
|
||||
p.teraType = p.species.type2!;
|
||||
}))
|
||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.GOODRA ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
|
@ -1991,7 +2000,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
p.generateName();
|
||||
p.gender = Gender.FEMALE;
|
||||
}))
|
||||
.setInstantTera(3),
|
||||
.setInstantTera(3), // Tera Dragon Tyrantrum / Ice Aurorus
|
||||
[TrainerType.KUKUI]: new TrainerConfig(++t).initForChampion(true).setMixedBattleBgm("battle_champion_kukui")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.LYCANROC ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
|
@ -1999,7 +2008,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
}))
|
||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.MAGNEZONE, Species.ALOLA_NINETALES ]))
|
||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.TORNADUS, Species.THUNDURUS, Species.LANDORUS ], TrainerSlot.TRAINER, true, p => {
|
||||
p.formIndex = 1; // Therian Forms
|
||||
p.formIndex = 1; // Therian Formes
|
||||
p.generateAndPopulateMoveset();
|
||||
p.pokeball = PokeballType.ULTRA_BALL;
|
||||
}))
|
||||
|
@ -2015,9 +2024,9 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.INCINEROAR, Species.HISUI_DECIDUEYE ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
p.gender = Gender.MALE;
|
||||
p.teraType = p.species.speciesId === Species.INCINEROAR ? Type.DARK : Type.FIGHTING;
|
||||
p.teraType = p.species.type2!;
|
||||
}))
|
||||
.setInstantTera(5),
|
||||
.setInstantTera(5), // Tera Dark Incineroar / Fighting Hisuian Decidueye
|
||||
[TrainerType.HAU]: new TrainerConfig(++t).initForChampion(true).setMixedBattleBgm("battle_alola_champion")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.ALOLA_RAICHU ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
|
@ -2042,7 +2051,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
p.setBoss(true, 2);
|
||||
p.gender = p.species.speciesId === Species.PRIMARINA ? Gender.FEMALE : Gender.MALE;
|
||||
}))
|
||||
.setInstantTera(3),
|
||||
.setInstantTera(3), // Tera Psychic Tapu Lele / Grass Tapu Bulu
|
||||
[TrainerType.LEON]: new TrainerConfig(++t).initForChampion(true).setMixedBattleBgm("battle_galar_champion")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.AEGISLASH ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
|
@ -2063,7 +2072,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
p.generateName();
|
||||
p.gender = Gender.MALE;
|
||||
}))
|
||||
.setInstantTera(3),
|
||||
.setInstantTera(3), // Tera Dragapult to Ghost or Dragon
|
||||
[TrainerType.MUSTARD]: new TrainerConfig(++t).initForChampion(true).setMixedBattleBgm("battle_mustard")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.CORVIKNIGHT ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
|
@ -2094,7 +2103,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
p.gender = Gender.MALE;
|
||||
p.pokeball = PokeballType.ULTRA_BALL;
|
||||
}))
|
||||
.setInstantTera(2),
|
||||
.setInstantTera(2), // Tera Psychic Galar-Slowbro / Galar-Slowking
|
||||
[TrainerType.GEETA]: new TrainerConfig(++t).initForChampion(false).setMixedBattleBgm("battle_champion_geeta")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GLIMMORA ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
|
@ -2113,7 +2122,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
p.abilityIndex = 1; // Supreme Overlord
|
||||
p.teraType = Type.FLYING;
|
||||
}))
|
||||
.setInstantTera(5),
|
||||
.setInstantTera(5), // Tera Flying Kingambit
|
||||
[TrainerType.NEMONA]: new TrainerConfig(++t).initForChampion(false).setMixedBattleBgm("battle_champion_nemona")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.LYCANROC ], TrainerSlot.TRAINER, true, p => {
|
||||
p.formIndex = 0; // Midday form
|
||||
|
@ -2126,25 +2135,21 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
}))
|
||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GHOLDENGO ]))
|
||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.ARMAROUGE, Species.CERULEDGE ], TrainerSlot.TRAINER, true, p => {
|
||||
p.teraType = p.species.speciesId === Species.ARMAROUGE ? Type.PSYCHIC : Type.GHOST;
|
||||
p.teraType = p.species.type2!;
|
||||
}))
|
||||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
p.gender = Gender.MALE;
|
||||
p.setBoss(true, 2);
|
||||
}))
|
||||
.setInstantTera(4),
|
||||
.setInstantTera(4), // Tera Psychic Armarouge / Ghost Ceruledge
|
||||
[TrainerType.KIERAN]: new TrainerConfig(++t).initForChampion(true).setMixedBattleBgm("battle_champion_kieran")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.POLIWRATH, Species.POLITOED ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
}))
|
||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.INCINEROAR, Species.GRIMMSNARL ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
if (p.species.speciesId === Species.INCINEROAR) {
|
||||
p.abilityIndex = 2; // Intimidate
|
||||
} else if (p.species.speciesId === Species.GRIMMSNARL) {
|
||||
p.abilityIndex = 0; // Prankster
|
||||
}
|
||||
p.abilityIndex = p.species.speciesId === Species.INCINEROAR ? 2 : 0; // Intimidate Incineroar, Prankster Grimmsnarl
|
||||
}))
|
||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.TERAPAGOS ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
|
@ -2167,7 +2172,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
p.gender = Gender.MALE;
|
||||
p.setBoss(true, 2);
|
||||
}))
|
||||
.setInstantTera(4),
|
||||
.setInstantTera(4), // Tera Ogerpon
|
||||
|
||||
[TrainerType.RIVAL]: new TrainerConfig((t = TrainerType.RIVAL)).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setStaticParty().setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival").setMixedBattleBgm("battle_rival").setPartyTemplates(trainerPartyTemplates.RIVAL)
|
||||
.setModifierRewardFuncs(() => modifierTypes.SUPER_EXP_CHARM, () => modifierTypes.EXP_SHARE)
|
||||
|
@ -2198,7 +2203,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.PIDGEOT, Species.NOCTOWL, Species.SWELLOW, Species.STARAPTOR, Species.UNFEZANT, Species.TALONFLAME, Species.TOUCANNON, Species.CORVIKNIGHT, Species.KILOWATTREL ], TrainerSlot.TRAINER, true))
|
||||
.setPartyMemberFunc(2, getSpeciesFilterRandomPartyMemberFunc((species: PokemonSpecies) => !pokemonEvolutions.hasOwnProperty(species.speciesId) && !pokemonPrevolutions.hasOwnProperty(species.speciesId) && species.baseTotal >= 450))
|
||||
.setSpeciesFilter(species => species.baseTotal >= 540)
|
||||
.setInstantTera(0),
|
||||
.setInstantTera(0), // Tera starter to primary type
|
||||
[TrainerType.RIVAL_5]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setBoss().setStaticParty().setMoneyMultiplier(2.25).setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival_3").setMixedBattleBgm("battle_rival_3").setPartyTemplates(trainerPartyTemplates.RIVAL_5)
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE, Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR, Species.SCEPTILE, Species.BLAZIKEN, Species.SWAMPERT, Species.TORTERRA, Species.INFERNAPE, Species.EMPOLEON, Species.SERPERIOR, Species.EMBOAR, Species.SAMUROTT, Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA, Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA, Species.RILLABOOM, Species.CINDERACE, Species.INTELEON, Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL ], TrainerSlot.TRAINER, true,
|
||||
p => {
|
||||
|
@ -2215,7 +2220,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
p.shiny = true;
|
||||
p.variant = 1;
|
||||
}))
|
||||
.setInstantTera(0),
|
||||
.setInstantTera(0), // Tera starter to primary type
|
||||
[TrainerType.RIVAL_6]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setBoss().setStaticParty().setMoneyMultiplier(3).setEncounterBgm("final").setBattleBgm("battle_rival_3").setMixedBattleBgm("battle_rival_3").setPartyTemplates(trainerPartyTemplates.RIVAL_6)
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE, Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR, Species.SCEPTILE, Species.BLAZIKEN, Species.SWAMPERT, Species.TORTERRA, Species.INFERNAPE, Species.EMPOLEON, Species.SERPERIOR, Species.EMBOAR, Species.SAMUROTT, Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA, Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA, Species.RILLABOOM, Species.CINDERACE, Species.INTELEON, Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL ], TrainerSlot.TRAINER, true,
|
||||
p => {
|
||||
|
@ -2240,7 +2245,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
p.formIndex = 1; // Mega Rayquaza
|
||||
p.generateName();
|
||||
}))
|
||||
.setInstantTera(0),
|
||||
.setInstantTera(0), // Tera starter to primary type
|
||||
|
||||
[TrainerType.ROCKET_BOSS_GIOVANNI_1]: new TrainerConfig(t = TrainerType.ROCKET_BOSS_GIOVANNI_1).setName("Giovanni").initForEvilTeamLeader("Rocket Boss", []).setMixedBattleBgm("battle_rocket_boss").setVictoryBgm("victory_team_plasma")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.PERSIAN ], TrainerSlot.TRAINER, true, p => {
|
||||
|
@ -2638,7 +2643,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
}))
|
||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.CRAWDAUNT, Species.HISUI_SAMUROTT ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
p.abilityIndex = 2; // Sharpness Hisui Samurott, Adaptability Crawdaunt
|
||||
p.abilityIndex = 2; // Sharpness Hisuian Samurott, Adaptability Crawdaunt
|
||||
}))
|
||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.XURKITREE ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
|
@ -2738,7 +2743,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
p.pokeball = PokeballType.ULTRA_BALL;
|
||||
p.generateName();
|
||||
}))
|
||||
.setInstantTera(4),
|
||||
.setInstantTera(4), // Tera Fairy Sylveon
|
||||
[TrainerType.PENNY_2]: new TrainerConfig(++t).setName("Cassiopeia").initForEvilTeamLeader("Star Boss", [], true).setMixedBattleBgm("battle_star_boss").setVictoryBgm("victory_team_plasma")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SYLVEON ], TrainerSlot.TRAINER, true, p => {
|
||||
p.setBoss(true, 2);
|
||||
|
@ -2771,13 +2776,8 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
p.generateName();
|
||||
p.pokeball = PokeballType.ULTRA_BALL;
|
||||
}))
|
||||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.ZAMAZENTA ], TrainerSlot.TRAINER, true, p => {
|
||||
p.setBoss(true, 2);
|
||||
p.generateAndPopulateMoveset();
|
||||
p.pokeball = PokeballType.MASTER_BALL;
|
||||
}))
|
||||
.setInstantTera(0),
|
||||
[TrainerType.BUCK]: new TrainerConfig(++t).setName("Buck").initForStatTrainer([], true)
|
||||
.setInstantTera(0), // Tera Fairy Sylveon
|
||||
[TrainerType.BUCK]: new TrainerConfig(++t).setName("Buck").initForStatTrainer(true)
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.CLAYDOL ], TrainerSlot.TRAINER, true, p => {
|
||||
p.setBoss(true, 3);
|
||||
p.generateAndPopulateMoveset();
|
||||
|
@ -2809,7 +2809,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
p.generateAndPopulateMoveset();
|
||||
p.pokeball = PokeballType.MASTER_BALL;
|
||||
})),
|
||||
[TrainerType.CHERYL]: new TrainerConfig(++t).setName("Cheryl").initForStatTrainer([], false)
|
||||
[TrainerType.CHERYL]: new TrainerConfig(++t).setName("Cheryl").initForStatTrainer()
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BLISSEY ], TrainerSlot.TRAINER, true, p => {
|
||||
p.setBoss(true, 3);
|
||||
p.generateAndPopulateMoveset();
|
||||
|
@ -2837,7 +2837,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
}
|
||||
p.pokeball = PokeballType.MASTER_BALL;
|
||||
})),
|
||||
[TrainerType.MARLEY]: new TrainerConfig(++t).setName("Marley").initForStatTrainer([], false)
|
||||
[TrainerType.MARLEY]: new TrainerConfig(++t).setName("Marley").initForStatTrainer()
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.ARCANINE ], TrainerSlot.TRAINER, true, p => {
|
||||
p.setBoss(true, 3);
|
||||
p.generateAndPopulateMoveset();
|
||||
|
@ -2861,7 +2861,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
p.generateAndPopulateMoveset();
|
||||
p.pokeball = PokeballType.MASTER_BALL;
|
||||
})),
|
||||
[TrainerType.MIRA]: new TrainerConfig(++t).setName("Mira").initForStatTrainer([], false)
|
||||
[TrainerType.MIRA]: new TrainerConfig(++t).setName("Mira").initForStatTrainer()
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.ALAKAZAM ], TrainerSlot.TRAINER, true, p => {
|
||||
p.setBoss(true, 2);
|
||||
p.generateAndPopulateMoveset();
|
||||
|
@ -2883,7 +2883,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||
p.generateAndPopulateMoveset();
|
||||
p.pokeball = PokeballType.MASTER_BALL;
|
||||
})),
|
||||
[TrainerType.RILEY]: new TrainerConfig(++t).setName("Riley").initForStatTrainer([], true)
|
||||
[TrainerType.RILEY]: new TrainerConfig(++t).setName("Riley").initForStatTrainer(true)
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.LUCARIO ], TrainerSlot.TRAINER, true, p => {
|
||||
p.setBoss(true, 2);
|
||||
p.generateAndPopulateMoveset();
|
||||
|
|
|
@ -29,4 +29,5 @@ export enum ArenaTagType {
|
|||
WATER_FIRE_PLEDGE = "WATER_FIRE_PLEDGE",
|
||||
GRASS_WATER_PLEDGE = "GRASS_WATER_PLEDGE",
|
||||
FAIRY_LOCK = "FAIRY_LOCK",
|
||||
NEUTRALIZING_GAS = "NEUTRALIZING_GAS"
|
||||
}
|
||||
|
|
|
@ -588,8 +588,8 @@ export class Arena {
|
|||
// creates a new tag object
|
||||
const newTag = getArenaTag(tagType, turnCount || 0, sourceMove, sourceId, targetIndex, side);
|
||||
if (newTag) {
|
||||
this.tags.push(newTag);
|
||||
newTag.onAdd(this, quiet);
|
||||
this.tags.push(newTag);
|
||||
|
||||
const { layers = 0, maxLayers = 0 } = newTag instanceof ArenaTrapTag ? newTag : {};
|
||||
|
||||
|
|
|
@ -63,8 +63,9 @@ import { reverseCompatibleTms, tmSpecies, tmPoolTiers } from "#app/data/balance/
|
|||
import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, SubstituteTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag, MoveRestrictionBattlerTag, ExposedTag, DragonCheerTag, CritBoostTag, TrappedTag, TarShotTag, AutotomizedTag, PowerTrickTag } from "../data/battler-tags";
|
||||
import { WeatherType } from "#enums/weather-type";
|
||||
import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "#app/data/arena-tag";
|
||||
import type { SuppressAbilitiesTag } from "#app/data/arena-tag";
|
||||
import type { Ability, AbAttr } from "#app/data/ability";
|
||||
import { StatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatStagesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldStatMultiplierAbAttrs, FieldMultiplyStatAbAttr, AddSecondStrikeAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr, FullHpResistTypeAbAttr, applyCheckTrappedAbAttrs, CheckTrappedAbAttr, PostSetStatusAbAttr, applyPostSetStatusAbAttrs, InfiltratorAbAttr, AlliedFieldDamageReductionAbAttr, PostDamageAbAttr, applyPostDamageAbAttrs, CommanderAbAttr, applyPostItemLostAbAttrs, PostItemLostAbAttr, applyOnGainAbAttrs, PreLeaveFieldAbAttr, applyPreLeaveFieldAbAttrs, applyOnLoseClearWeatherAbAttrs } from "#app/data/ability";
|
||||
import { StatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatStagesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldStatMultiplierAbAttrs, FieldMultiplyStatAbAttr, AddSecondStrikeAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr, FullHpResistTypeAbAttr, applyCheckTrappedAbAttrs, CheckTrappedAbAttr, PostSetStatusAbAttr, applyPostSetStatusAbAttrs, InfiltratorAbAttr, AlliedFieldDamageReductionAbAttr, PostDamageAbAttr, applyPostDamageAbAttrs, CommanderAbAttr, applyPostItemLostAbAttrs, PostItemLostAbAttr, applyOnGainAbAttrs, PreLeaveFieldAbAttr, applyPreLeaveFieldAbAttrs, applyOnLoseAbAttrs, PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr } from "#app/data/ability";
|
||||
import type PokemonData from "#app/system/pokemon-data";
|
||||
import { BattlerIndex } from "#app/battle";
|
||||
import { Mode } from "#app/ui/ui";
|
||||
|
@ -1225,10 +1226,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
/**
|
||||
* Checks if the {@linkcode Pokemon} has is the specified {@linkcode Species} or is fused with it.
|
||||
* @param species the pokemon {@linkcode Species} to check
|
||||
* @param formKey If provided, requires the species to be in that form
|
||||
* @returns `true` if the pokemon is the species or is fused with it, `false` otherwise
|
||||
*/
|
||||
hasSpecies(species: Species): boolean {
|
||||
return this.species.speciesId === species || this.fusionSpecies?.speciesId === species;
|
||||
hasSpecies(species: Species, formKey?: string): boolean {
|
||||
if (Utils.isNullOrUndefined(formKey)) {
|
||||
return this.species.speciesId === species || this.fusionSpecies?.speciesId === species;
|
||||
}
|
||||
|
||||
return (this.species.speciesId === species && this.getFormKey() === formKey) || (this.fusionSpecies?.speciesId === species && this.getFusionFormKey() === formKey);
|
||||
}
|
||||
|
||||
abstract isBoss(): boolean;
|
||||
|
@ -1487,7 +1493,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
* @param ability New Ability
|
||||
*/
|
||||
public setTempAbility(ability: Ability, passive: boolean = false): void {
|
||||
applyOnLoseClearWeatherAbAttrs(this, passive);
|
||||
applyOnLoseAbAttrs(this, passive);
|
||||
if (passive) {
|
||||
this.summonData.passiveAbility = ability.id;
|
||||
} else {
|
||||
|
@ -1496,6 +1502,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
applyOnGainAbAttrs(this, passive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Suppresses an ability and calls its onlose attributes
|
||||
*/
|
||||
public suppressAbility() {
|
||||
[ true, false ].forEach((passive) => applyOnLoseAbAttrs(this, passive));
|
||||
this.summonData.abilitySuppressed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a pokemon has a passive either from:
|
||||
* - bought with starter candy
|
||||
|
@ -1553,17 +1567,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
if (this.summonData?.abilitySuppressed && !ability.hasAttr(UnsuppressableAbilityAbAttr)) {
|
||||
return false;
|
||||
}
|
||||
if (this.isOnField() && !ability.hasAttr(SuppressFieldAbilitiesAbAttr)) {
|
||||
const suppressed = new Utils.BooleanHolder(false);
|
||||
globalScene.getField(true).filter(p => p !== this).map(p => {
|
||||
if (p.getAbility().hasAttr(SuppressFieldAbilitiesAbAttr) && p.canApplyAbility()) {
|
||||
p.getAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, false, false, suppressed, [ ability ]));
|
||||
}
|
||||
if (p.getPassiveAbility().hasAttr(SuppressFieldAbilitiesAbAttr) && p.canApplyAbility(true)) {
|
||||
p.getPassiveAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, true, false, suppressed, [ ability ]));
|
||||
}
|
||||
});
|
||||
if (suppressed.value) {
|
||||
const suppressAbilitiesTag = arena.getTag(ArenaTagType.NEUTRALIZING_GAS) as SuppressAbilitiesTag;
|
||||
if (this.isOnField() && suppressAbilitiesTag && !suppressAbilitiesTag.isBeingRemoved()) {
|
||||
const thisAbilitySuppressing = ability.hasAttr(PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr);
|
||||
const hasSuppressingAbility = this.hasAbilityWithAttr(PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr, false);
|
||||
// Neutralizing gas is up - suppress abilities unless they are unsuppressable or this pokemon is responsible for the gas
|
||||
// (Balance decided that the other ability of a neutralizing gas pokemon should not be neutralized)
|
||||
// If the ability itself is neutralizing gas, don't suppress it (handled through arena tag)
|
||||
const unsuppressable = ability.hasAttr(UnsuppressableAbilityAbAttr) || thisAbilitySuppressing || (hasSuppressingAbility && !suppressAbilitiesTag.shouldApplyToSelf());
|
||||
if (!unsuppressable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -3197,6 +3209,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
return maxForms.includes(this.getFormKey()) || (!!this.getFusionFormKey() && maxForms.includes(this.getFusionFormKey()!));
|
||||
}
|
||||
|
||||
isMega(): boolean {
|
||||
const megaForms = [ SpeciesFormKey.MEGA, SpeciesFormKey.MEGA_X, SpeciesFormKey.MEGA_Y, SpeciesFormKey.PRIMAL ] as string[];
|
||||
return megaForms.includes(this.getFormKey()) || (!!this.getFusionFormKey() && megaForms.includes(this.getFusionFormKey()!));
|
||||
}
|
||||
|
||||
canAddTag(tagType: BattlerTagType): boolean {
|
||||
if (this.getTag(tagType)) {
|
||||
return false;
|
||||
|
|
|
@ -416,14 +416,16 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
|||
}
|
||||
}
|
||||
|
||||
if (!retry && this.config.specialtyTypes.length && !this.config.specialtyTypes.find(t => ret.isOfType(t))) {
|
||||
// Prompts reroll of party member species if doesn't fit specialty type.
|
||||
// Can be removed by adding a type parameter to getTrainerSpeciesForLevel and filtering the list of evolutions for that type.
|
||||
if (!retry && this.config.hasSpecialtyType() && !ret.isOfType(this.config.specialtyType)) {
|
||||
retry = true;
|
||||
console.log("Attempting reroll of species evolution to fit specialty type...");
|
||||
let evoAttempt = 0;
|
||||
while (retry && evoAttempt++ < 10) {
|
||||
ret = getPokemonSpecies(baseSpecies.getTrainerSpeciesForLevel(level, true, strength, globalScene.currentBattle.waveIndex));
|
||||
console.log(ret.name);
|
||||
if (this.config.specialtyTypes.find(t => ret.isOfType(t))) {
|
||||
if (ret.isOfType(this.config.specialtyType)) {
|
||||
retry = false;
|
||||
}
|
||||
}
|
||||
|
@ -677,6 +679,11 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a Trainer should Terastallize their Pokemon
|
||||
* @param pokemon {@linkcode EnemyPokemon} Trainer Pokemon in question
|
||||
* @returns boolean Whether the EnemyPokemon should Terastalize this turn
|
||||
*/
|
||||
shouldTera(pokemon: EnemyPokemon): boolean {
|
||||
if (this.config.trainerAI.teraMode === TeraAIMode.INSTANT_TERA) {
|
||||
if (!pokemon.isTerastallized && this.config.trainerAI.instantTeras.includes(pokemon.initialTeamIndex)) {
|
||||
|
|
|
@ -564,6 +564,15 @@ export class InputsController {
|
|||
if (!this.configs[selectedDevice]) {
|
||||
this.configs[selectedDevice] = {};
|
||||
}
|
||||
// A proper way of handling migrating keybinds would be much better
|
||||
const mappingOverrides = {
|
||||
"BUTTON_CYCLE_VARIANT": "BUTTON_CYCLE_TERA",
|
||||
};
|
||||
for (const key in mappingConfigs.custom) {
|
||||
if (mappingConfigs.custom[key] in mappingOverrides) {
|
||||
mappingConfigs.custom[key] = mappingOverrides[mappingConfigs.custom[key]];
|
||||
}
|
||||
}
|
||||
this.configs[selectedDevice].custom = mappingConfigs.custom;
|
||||
}
|
||||
|
||||
|
|
|
@ -101,6 +101,7 @@ export class LoadingScene extends SceneBase {
|
|||
this.loadImage("icon_lock", "ui", "icon_lock.png");
|
||||
this.loadImage("icon_stop", "ui", "icon_stop.png");
|
||||
this.loadImage("icon_tera", "ui");
|
||||
this.loadImage("cursor_tera", "ui");
|
||||
this.loadImage("type_tera", "ui");
|
||||
this.loadAtlas("type_bgs", "ui");
|
||||
this.loadAtlas("button_tera", "ui");
|
||||
|
@ -250,9 +251,9 @@ export class LoadingScene extends SceneBase {
|
|||
}
|
||||
const availableLangs = [ "en", "de", "it", "fr", "ja", "ko", "es-ES", "pt-BR", "zh-CN" ];
|
||||
if (lang && availableLangs.includes(lang)) {
|
||||
this.loadImage("valentines2025event-" + lang, "events");
|
||||
this.loadImage("pkmnday2025event-" + lang, "events");
|
||||
} else {
|
||||
this.loadImage("valentines2025event-en", "events");
|
||||
this.loadImage("pkmnday2025event-en", "events");
|
||||
}
|
||||
|
||||
this.loadAtlas("statuses", "");
|
||||
|
|
|
@ -2561,7 +2561,7 @@ export function getPartyLuckValue(party: Pokemon[]): number {
|
|||
return DailyLuck.value;
|
||||
}
|
||||
const eventSpecies = globalScene.eventManager.getEventLuckBoostedSpecies();
|
||||
const luck = Phaser.Math.Clamp(party.map(p => p.isAllowedInBattle() ? p.getLuck() + (eventSpecies.includes(p.species.speciesId) ? 3 : 0) : 0)
|
||||
const luck = Phaser.Math.Clamp(party.map(p => p.isAllowedInBattle() ? p.getLuck() + (eventSpecies.includes(p.species.speciesId) ? 1 : 0) : 0)
|
||||
.reduce((total: number, value: number) => total += value, 0), 0, 14);
|
||||
return Math.min(globalScene.eventManager.getEventLuckBoost() + (luck ?? 0), 14);
|
||||
}
|
||||
|
|
|
@ -253,7 +253,10 @@ export class EncounterPhase extends BattlePhase {
|
|||
globalScene.getEnemyField().forEach(enemy => {
|
||||
overrideHeldItems(enemy, false);
|
||||
});
|
||||
}
|
||||
|
||||
if (battle.battleType === BattleType.TRAINER) {
|
||||
globalScene.currentBattle.trainer!.genAI(globalScene.getEnemyParty());
|
||||
}
|
||||
|
||||
globalScene.ui.setMode(Mode.MESSAGE).then(() => {
|
||||
|
|
|
@ -1645,11 +1645,19 @@ export class GameData {
|
|||
} else if (formIndex === 3) {
|
||||
dexEntry.caughtAttr |= globalScene.gameData.getFormAttr(1);
|
||||
}
|
||||
}
|
||||
const allFormChanges = pokemonFormChanges.hasOwnProperty(species.speciesId) ? pokemonFormChanges[species.speciesId] : [];
|
||||
const toCurrentFormChanges = allFormChanges.filter(f => (f.formKey === formKey));
|
||||
if (toCurrentFormChanges.length > 0) {
|
||||
dexEntry.caughtAttr |= globalScene.gameData.getFormAttr(0);
|
||||
} else if (pokemon.species.speciesId === Species.ZYGARDE) {
|
||||
if (formIndex === 4) {
|
||||
dexEntry.caughtAttr |= globalScene.gameData.getFormAttr(2);
|
||||
} else if (formIndex === 5) {
|
||||
dexEntry.caughtAttr |= globalScene.gameData.getFormAttr(3);
|
||||
}
|
||||
} else {
|
||||
const allFormChanges = pokemonFormChanges.hasOwnProperty(species.speciesId) ? pokemonFormChanges[species.speciesId] : [];
|
||||
const toCurrentFormChanges = allFormChanges.filter(f => (f.formKey === formKey));
|
||||
if (toCurrentFormChanges.length > 0) {
|
||||
// Needs to do this or Castform can unlock the wrong form, etc.
|
||||
dexEntry.caughtAttr |= globalScene.gameData.getFormAttr(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,29 @@
|
|||
import { getPokemonSpeciesForm } from "#app/data/pokemon-species";
|
||||
import type { SessionSaveData } from "#app/system/game-data";
|
||||
import { getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { DexAttr, type SessionSaveData, type SystemSaveData } from "#app/system/game-data";
|
||||
import * as Utils from "#app/utils";
|
||||
|
||||
export const systemMigrators = [] as const;
|
||||
export const systemMigrators = [
|
||||
/**
|
||||
* If a starter is caught, but the only forms registered as caught are not starterSelectable,
|
||||
* unlock the default form.
|
||||
* @param data {@linkcode SystemSaveData}
|
||||
*/
|
||||
function migrateUnselectableForms(data: SystemSaveData) {
|
||||
if (data.starterData && data.dexData) {
|
||||
Object.keys(data.starterData).forEach(sd => {
|
||||
const caughtAttr = data.dexData[sd]?.caughtAttr;
|
||||
const species = getPokemonSpecies(Number(sd));
|
||||
if (caughtAttr && species.forms?.length > 1) {
|
||||
const selectableForms = species.forms.filter((form, formIndex) => form.isStarterSelectable && (caughtAttr & globalScene.gameData.getFormAttr(formIndex)));
|
||||
if (selectableForms.length === 0) {
|
||||
data.dexData[sd].caughtAttr += DexAttr.DEFAULT_FORM;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
] as const;
|
||||
|
||||
export const settingsMigrators = [] as const;
|
||||
|
||||
|
|
|
@ -169,7 +169,7 @@ const timedEvents: TimedEvent[] = [
|
|||
{ species: Species.WOOBAT },
|
||||
{ species: Species.FRILLISH },
|
||||
{ species: Species.ALOMOMOLA },
|
||||
{ species: Species.FURFROU, formIndex: 1 }, // Heart trim
|
||||
{ species: Species.FURFROU, formIndex: 1 }, // Heart Trim
|
||||
{ species: Species.ESPURR },
|
||||
{ species: Species.SPRITZEE },
|
||||
{ species: Species.SWIRLIX },
|
||||
|
@ -180,6 +180,33 @@ const timedEvents: TimedEvent[] = [
|
|||
{ species: Species.ENAMORUS }
|
||||
],
|
||||
luckBoostedSpecies: [ Species.LUVDISC ]
|
||||
},
|
||||
{
|
||||
name: "PKMNDAY2025",
|
||||
eventType: EventType.LUCK,
|
||||
startDate: new Date(Date.UTC(2025, 1, 27)),
|
||||
endDate: new Date(Date.UTC(2025, 2, 4)),
|
||||
classicFriendshipMultiplier: 4,
|
||||
bannerKey: "pkmnday2025event-",
|
||||
scale: 0.21,
|
||||
availableLangs: [ "en", "de", "it", "fr", "ja", "ko", "es-ES", "pt-BR", "zh-CN" ],
|
||||
eventEncounters: [
|
||||
{ species: Species.PIKACHU, formIndex: 1, blockEvolution: true }, // Partner Form
|
||||
{ species: Species.EEVEE, formIndex: 1, blockEvolution: true }, // Partner Form
|
||||
{ species: Species.CHIKORITA },
|
||||
{ species: Species.TOTODILE },
|
||||
{ species: Species.TEPIG }
|
||||
],
|
||||
luckBoostedSpecies: [
|
||||
Species.PICHU, Species.PIKACHU, Species.RAICHU, Species.ALOLA_RAICHU,
|
||||
Species.PSYDUCK, Species.GOLDUCK,
|
||||
Species.EEVEE, Species.FLAREON, Species.JOLTEON, Species.VAPOREON, Species.ESPEON, Species.UMBREON, Species.LEAFEON, Species.GLACEON, Species.SYLVEON,
|
||||
Species.CHIKORITA, Species.BAYLEEF, Species.MEGANIUM,
|
||||
Species.TOTODILE, Species.CROCONAW, Species.FERALIGATR,
|
||||
Species.TEPIG, Species.PIGNITE, Species.EMBOAR,
|
||||
Species.ZYGARDE,
|
||||
Species.ETERNAL_FLOETTE
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ export class UiInputs {
|
|||
[Button.CYCLE_GENDER]: () => undefined,
|
||||
[Button.CYCLE_ABILITY]: () => undefined,
|
||||
[Button.CYCLE_NATURE]: () => undefined,
|
||||
[Button.CYCLE_TERA]: () => undefined,
|
||||
[Button.CYCLE_TERA]: () => this.buttonInfo(false),
|
||||
[Button.SPEED_UP]: () => undefined,
|
||||
[Button.SLOW_DOWN]: () => undefined,
|
||||
};
|
||||
|
|
|
@ -147,7 +147,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
|
|||
itemIcon.setScale(3 * this.scale);
|
||||
this.optionSelectIcons.push(itemIcon);
|
||||
|
||||
this.optionSelectContainer.add(itemIcon);
|
||||
this.optionSelectTextContainer.add(itemIcon);
|
||||
|
||||
itemIcon.setPositionRelative(this.optionSelectText, 36 * this.scale, 7 + i * (114 * this.scale - 3));
|
||||
|
||||
|
@ -156,7 +156,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
|
|||
itemOverlayIcon.setScale(3 * this.scale);
|
||||
this.optionSelectIcons.push(itemOverlayIcon);
|
||||
|
||||
this.optionSelectContainer.add(itemOverlayIcon);
|
||||
this.optionSelectTextContainer.add(itemOverlayIcon);
|
||||
|
||||
itemOverlayIcon.setPositionRelative(this.optionSelectText, 36 * this.scale, 7 + i * (114 * this.scale - 3));
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import { globalScene } from "#app/global-scene";
|
|||
import { TerastallizeAccessModifier } from "#app/modifier/modifier";
|
||||
import { Type } from "#app/enums/type";
|
||||
import { getTypeRgb } from "#app/data/type";
|
||||
import { Species } from "#enums/species";
|
||||
|
||||
export enum Command {
|
||||
FIGHT = 0,
|
||||
|
@ -180,9 +181,11 @@ export default class CommandUiHandler extends UiHandler {
|
|||
|
||||
canTera(): boolean {
|
||||
const hasTeraMod = !!globalScene.getModifiers(TerastallizeAccessModifier).length;
|
||||
const activePokemon = globalScene.getField()[this.fieldIndex];
|
||||
const isBlockedForm = activePokemon.isMega() || activePokemon.isMax() || activePokemon.hasSpecies(Species.NECROZMA, "ultra");
|
||||
const currentTeras = globalScene.arena.playerTerasUsed;
|
||||
const plannedTera = globalScene.currentBattle.preTurnCommands[0]?.command === Command.TERA && this.fieldIndex > 0 ? 1 : 0;
|
||||
return hasTeraMod && (currentTeras + plannedTera) < 1;
|
||||
return hasTeraMod && !isBlockedForm && (currentTeras + plannedTera) < 1;
|
||||
}
|
||||
|
||||
toggleTeraButton() {
|
||||
|
|
|
@ -629,6 +629,8 @@ export class DropDown extends Phaser.GameObjects.Container {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.onChange();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -226,7 +226,9 @@ export default class FightUiHandler extends UiHandler implements InfoToggle {
|
|||
}
|
||||
|
||||
if (!this.cursorObj) {
|
||||
this.cursorObj = globalScene.add.image(0, 0, "cursor");
|
||||
const isTera = this.fromCommand === Command.TERA;
|
||||
this.cursorObj = globalScene.add.image(0, 0, isTera ? "cursor_tera" : "cursor");
|
||||
this.cursorObj.setScale(isTera ? 0.7 : 1);
|
||||
ui.add(this.cursorObj);
|
||||
}
|
||||
|
||||
|
|
|
@ -86,6 +86,15 @@ export class FilterBar extends Phaser.GameObjects.Container {
|
|||
return this.dropDowns[this.columns.indexOf(col)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DropDownColumn associated to a given index
|
||||
* @param index the index of the column to retrieve
|
||||
* @returns the associated DropDownColumn if it exists, undefined otherwise
|
||||
*/
|
||||
public getColumn(index: number): DropDownColumn {
|
||||
return this.columns[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight the labels of the FilterBar if the filters are different from their default values
|
||||
*/
|
||||
|
@ -185,6 +194,11 @@ export class FilterBar extends Phaser.GameObjects.Container {
|
|||
return this.getFilter(col).getVals();
|
||||
}
|
||||
|
||||
public resetSelection(col: DropDownColumn): void {
|
||||
this.dropDowns[col].resetToDefault();
|
||||
this.updateFilterLabels();
|
||||
}
|
||||
|
||||
setValsToDefault(): void {
|
||||
for (const dropDown of this.dropDowns) {
|
||||
dropDown.resetToDefault();
|
||||
|
|
|
@ -422,7 +422,10 @@ export default class PartyUiHandler extends MessageUiHandler {
|
|||
if (option === PartyOption.TRANSFER) {
|
||||
if (this.transferCursor !== this.cursor) {
|
||||
if (this.transferAll) {
|
||||
getTransferrableItemsFromPokemon(globalScene.getPlayerParty()[this.transferCursor]).forEach((_, i) => (this.selectCallback as PartyModifierTransferSelectCallback)(this.transferCursor, i, this.transferQuantitiesMax[i], this.cursor));
|
||||
getTransferrableItemsFromPokemon(globalScene.getPlayerParty()[this.transferCursor]).forEach((_, i, array) => {
|
||||
const invertedIndex = array.length - 1 - i;
|
||||
(this.selectCallback as PartyModifierTransferSelectCallback)(this.transferCursor, invertedIndex, this.transferQuantitiesMax[invertedIndex], this.cursor);
|
||||
});
|
||||
} else {
|
||||
(this.selectCallback as PartyModifierTransferSelectCallback)(this.transferCursor, this.transferOptionCursor, this.transferQuantities[this.transferOptionCursor], this.cursor);
|
||||
}
|
||||
|
@ -1187,7 +1190,6 @@ class PartySlot extends Phaser.GameObjects.Container {
|
|||
public slotHpText: Phaser.GameObjects.Text;
|
||||
public slotDescriptionLabel: Phaser.GameObjects.Text; // this is used to show text instead of the HP bar i.e. for showing "Able"/"Not Able" for TMs when you try to learn them
|
||||
|
||||
|
||||
private pokemonIcon: Phaser.GameObjects.Container;
|
||||
private iconAnimHandler: PokemonIconAnimHandler;
|
||||
|
||||
|
@ -1208,6 +1210,10 @@ class PartySlot extends Phaser.GameObjects.Container {
|
|||
}
|
||||
|
||||
setup(partyUiMode: PartyUiMode, tmMoveId: Moves) {
|
||||
|
||||
const currentLanguage = i18next.resolvedLanguage ?? "en";
|
||||
const offsetJa = currentLanguage === "ja";
|
||||
|
||||
const battlerCount = globalScene.currentBattle.getBattlerCount();
|
||||
|
||||
const slotKey = `party_slot${this.slotIndex >= battlerCount ? "" : "_main"}`;
|
||||
|
@ -1246,15 +1252,15 @@ class PartySlot extends Phaser.GameObjects.Container {
|
|||
nameSizeTest.destroy();
|
||||
|
||||
this.slotName = addTextObject(0, 0, displayName, TextStyle.PARTY);
|
||||
this.slotName.setPositionRelative(slotBg, this.slotIndex >= battlerCount ? 21 : 24, this.slotIndex >= battlerCount ? 2 : 10);
|
||||
this.slotName.setPositionRelative(slotBg, this.slotIndex >= battlerCount ? 21 : 24, (this.slotIndex >= battlerCount ? 2 : 10) + (offsetJa ? 2 : 0));
|
||||
this.slotName.setOrigin(0, 0);
|
||||
|
||||
const slotLevelLabel = globalScene.add.image(0, 0, "party_slot_overlay_lv");
|
||||
slotLevelLabel.setPositionRelative(this.slotName, 8, 12);
|
||||
slotLevelLabel.setPositionRelative(slotBg, (this.slotIndex >= battlerCount ? 21 : 24) + 8, (this.slotIndex >= battlerCount ? 2 : 10) + 12);
|
||||
slotLevelLabel.setOrigin(0, 0);
|
||||
|
||||
const slotLevelText = addTextObject(0, 0, this.pokemon.level.toString(), this.pokemon.level < globalScene.getMaxExpLevel() ? TextStyle.PARTY : TextStyle.PARTY_RED);
|
||||
slotLevelText.setPositionRelative(slotLevelLabel, 9, 0);
|
||||
slotLevelText.setPositionRelative(slotLevelLabel, 9, offsetJa ? 1.5 : 0);
|
||||
slotLevelText.setOrigin(0, 0.25);
|
||||
|
||||
slotInfoContainer.add([ this.slotName, slotLevelLabel, slotLevelText ]);
|
||||
|
@ -1331,7 +1337,7 @@ class PartySlot extends Phaser.GameObjects.Container {
|
|||
this.slotHpOverlay.setVisible(false);
|
||||
|
||||
this.slotHpText = addTextObject(0, 0, `${this.pokemon.hp}/${this.pokemon.getMaxHp()}`, TextStyle.PARTY);
|
||||
this.slotHpText.setPositionRelative(this.slotHpBar, this.slotHpBar.width - 3, this.slotHpBar.height - 2);
|
||||
this.slotHpText.setPositionRelative(this.slotHpBar, this.slotHpBar.width - 3, this.slotHpBar.height - 2 + (offsetJa ? 2 : 0));
|
||||
this.slotHpText.setOrigin(1, 0);
|
||||
this.slotHpText.setVisible(false);
|
||||
|
||||
|
|
|
@ -250,6 +250,8 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||
private availableVariants: number;
|
||||
private unlockedVariants: boolean[];
|
||||
|
||||
private canUseCandies: boolean;
|
||||
|
||||
constructor() {
|
||||
super(Mode.POKEDEX_PAGE);
|
||||
}
|
||||
|
@ -556,6 +558,9 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||
|
||||
show(args: any[]): boolean {
|
||||
|
||||
// Allow the use of candies if we are in one of the whitelisted phases
|
||||
this.canUseCandies = [ "TitlePhase", "SelectStarterPhase", "CommandPhase" ].includes(globalScene.getCurrentPhase()?.constructor.name ?? "");
|
||||
|
||||
if (args.length >= 1 && args[0] === "refresh") {
|
||||
return false;
|
||||
} else {
|
||||
|
@ -597,6 +602,14 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||
this.battleForms = [];
|
||||
|
||||
const species = this.species;
|
||||
|
||||
let formKey = this.species?.forms.length > 0 ? this.species.forms[this.formIndex].formKey : "";
|
||||
this.isFormGender = formKey === "male" || formKey === "female";
|
||||
if (this.isFormGender && ((this.savedStarterAttributes.female === true && formKey === "male") || (this.savedStarterAttributes.female === false && formKey === "female"))) {
|
||||
this.formIndex = (this.formIndex + 1) % 2;
|
||||
formKey = this.species.forms[this.formIndex].formKey;
|
||||
}
|
||||
|
||||
const formIndex = this.formIndex ?? 0;
|
||||
|
||||
this.starterId = this.getStarterSpeciesId(this.species.speciesId);
|
||||
|
@ -630,12 +643,9 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||
this.eggMoves = speciesEggMoves[this.starterId] ?? [];
|
||||
this.hasEggMoves = Array.from({ length: 4 }, (_, em) => (globalScene.gameData.starterData[this.starterId].eggMoves & (1 << em)) !== 0);
|
||||
|
||||
const formKey = this.species?.forms.length > 0 ? this.species.forms[this.formIndex].formKey : "";
|
||||
this.tmMoves = speciesTmMoves[species.speciesId]?.filter(m => Array.isArray(m) ? (m[0] === formKey ? true : false ) : true)
|
||||
.map(m => Array.isArray(m) ? m[1] : m).sort((a, b) => allMoves[a].name > allMoves[b].name ? 1 : -1) ?? [];
|
||||
|
||||
this.isFormGender = formKey === "male" || formKey === "female";
|
||||
|
||||
const passiveId = starterPassiveAbilities.hasOwnProperty(species.speciesId) ? species.speciesId :
|
||||
starterPassiveAbilities.hasOwnProperty(this.starterId) ? this.starterId : pokemonPrevolutions[this.starterId];
|
||||
const passives = starterPassiveAbilities[passiveId];
|
||||
|
@ -779,6 +789,10 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||
const formIndex = otherFormIndex !== undefined ? otherFormIndex : this.formIndex;
|
||||
const caughtAttr = this.isCaught(species);
|
||||
|
||||
if (caughtAttr && (!species.forms.length || species.forms.length === 1)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const isFormCaught = (caughtAttr & globalScene.gameData.getFormAttr(formIndex ?? 0)) > 0n;
|
||||
return isFormCaught;
|
||||
}
|
||||
|
@ -1570,15 +1584,14 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||
|
||||
starterAttributes.variant = newVariant; // store the selected variant
|
||||
this.savedStarterAttributes.variant = starterAttributes.variant;
|
||||
if (newVariant > props.variant) {
|
||||
this.setSpeciesDetails(this.species, { variant: newVariant as Variant });
|
||||
success = true;
|
||||
} else {
|
||||
if ((this.isCaught() & DexAttr.NON_SHINY) && (newVariant <= props.variant)) {
|
||||
this.setSpeciesDetails(this.species, { shiny: false, variant: 0 });
|
||||
success = true;
|
||||
|
||||
starterAttributes.shiny = false;
|
||||
this.savedStarterAttributes.shiny = starterAttributes.shiny;
|
||||
} else {
|
||||
this.setSpeciesDetails(this.species, { variant: newVariant as Variant });
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1626,7 +1639,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||
}
|
||||
break;
|
||||
case Button.STATS:
|
||||
if (!isCaught || !isFormCaught) {
|
||||
if (!isCaught || !isFormCaught || !this.canUseCandies) {
|
||||
error = true;
|
||||
} else {
|
||||
const ui = this.getUi();
|
||||
|
@ -1888,7 +1901,9 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||
|
||||
if (this.isCaught()) {
|
||||
if (isFormCaught) {
|
||||
this.updateButtonIcon(SettingKeyboard.Button_Stats, gamepadType, this.candyUpgradeIconElement, this.candyUpgradeLabel);
|
||||
if (this.canUseCandies) {
|
||||
this.updateButtonIcon(SettingKeyboard.Button_Stats, gamepadType, this.candyUpgradeIconElement, this.candyUpgradeLabel);
|
||||
}
|
||||
if (this.canCycleShiny) {
|
||||
this.updateButtonIcon(SettingKeyboard.Button_Cycle_Shiny, gamepadType, this.shinyIconElement, this.shinyLabel);
|
||||
}
|
||||
|
@ -2189,7 +2204,8 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||
const isNonShinyCaught = !!(caughtAttr & DexAttr.NON_SHINY);
|
||||
const isShinyCaught = !!(caughtAttr & DexAttr.SHINY);
|
||||
|
||||
this.canCycleShiny = isNonShinyCaught && isShinyCaught;
|
||||
const caughtVariants = [ DexAttr.DEFAULT_VARIANT, DexAttr.VARIANT_2, DexAttr.VARIANT_3 ].filter(v => caughtAttr & v);
|
||||
this.canCycleShiny = (isNonShinyCaught && isShinyCaught) || (isShinyCaught && caughtVariants.length > 1);
|
||||
|
||||
const isMaleCaught = !!(caughtAttr & DexAttr.MALE);
|
||||
const isFemaleCaught = !!(caughtAttr & DexAttr.FEMALE);
|
||||
|
|
|
@ -898,16 +898,11 @@ export default class PokedexUiHandler extends MessageUiHandler {
|
|||
if (this.filterMode && this.filterBar.openDropDown) {
|
||||
// CANCEL with a filter menu open > close it
|
||||
this.filterBar.toggleDropDown(this.filterBarCursor);
|
||||
|
||||
// if there are possible pokemon go the first one of the list
|
||||
if (numberOfStarters > 0) {
|
||||
this.setFilterMode(false);
|
||||
this.scrollCursor = 0;
|
||||
this.updateScroll();
|
||||
this.setCursor(0);
|
||||
}
|
||||
success = true;
|
||||
|
||||
} else if (this.filterMode && !this.filterBar.getFilter(this.filterBarCursor).hasDefaultValues()) {
|
||||
this.filterBar.resetSelection(this.filterBarCursor);
|
||||
this.updateStarters();
|
||||
success = true;
|
||||
} else if (this.filterTextMode && !(this.filterText.getValue(this.filterTextCursor) === this.filterText.defaultText)) {
|
||||
this.filterText.resetSelection(this.filterTextCursor);
|
||||
success = true;
|
||||
|
@ -991,7 +986,7 @@ export default class PokedexUiHandler extends MessageUiHandler {
|
|||
this.updateScroll();
|
||||
const proportion = this.filterBarCursor / Math.max(1, this.filterBar.numFilters - 1);
|
||||
const targetCol = Math.min(8, proportion < 0.5 ? Math.floor(proportion * 8) : Math.ceil(proportion * 8));
|
||||
this.setCursor(Math.min(targetCol, numberOfStarters));
|
||||
this.setCursor(Math.min(targetCol, numberOfStarters - 1));
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
|
@ -1113,7 +1108,7 @@ export default class PokedexUiHandler extends MessageUiHandler {
|
|||
}
|
||||
break;
|
||||
case Button.DOWN:
|
||||
if (currentRow < numOfRows - 1) { // not last row
|
||||
if ((currentRow < numOfRows - 1) && (this.cursor + 9 < this.filteredPokemonData.length)) { // not last row
|
||||
if (currentRow - this.scrollCursor === 8) { // last row of visible pokemon
|
||||
this.scrollCursor++;
|
||||
this.updateScroll();
|
||||
|
@ -1582,6 +1577,37 @@ export default class PokedexUiHandler extends MessageUiHandler {
|
|||
container.icon.setTint(0);
|
||||
}
|
||||
|
||||
if (data.eggMove1) {
|
||||
container.eggMove1Icon.setVisible(true);
|
||||
} else {
|
||||
container.eggMove1Icon.setVisible(false);
|
||||
}
|
||||
if (data.eggMove2) {
|
||||
container.eggMove2Icon.setVisible(true);
|
||||
} else {
|
||||
container.eggMove2Icon.setVisible(false);
|
||||
}
|
||||
if (data.tmMove1) {
|
||||
container.tmMove1Icon.setVisible(true);
|
||||
} else {
|
||||
container.tmMove1Icon.setVisible(false);
|
||||
}
|
||||
if (data.tmMove2) {
|
||||
container.tmMove2Icon.setVisible(true);
|
||||
} else {
|
||||
container.tmMove2Icon.setVisible(false);
|
||||
}
|
||||
if (data.passive1) {
|
||||
container.passive1Icon.setVisible(true);
|
||||
} else {
|
||||
container.passive1Icon.setVisible(false);
|
||||
}
|
||||
if (data.passive2) {
|
||||
container.passive2Icon.setVisible(true);
|
||||
} else {
|
||||
container.passive2Icon.setVisible(false);
|
||||
}
|
||||
|
||||
if (this.showDecorations) {
|
||||
|
||||
if (this.pokerusSpecies.includes(data.species)) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import i18next from "i18next";
|
|||
import type BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext";
|
||||
import { starterColors } from "#app/battle-scene";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import type { Ability } from "#app/data/ability";
|
||||
import { allAbilities } from "#app/data/ability";
|
||||
import { speciesEggMoves } from "#app/data/balance/egg-moves";
|
||||
import { GrowthRate, getGrowthRateColor } from "#app/data/exp";
|
||||
|
@ -1080,10 +1081,18 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||
/**
|
||||
* Set the selections for all filters to their default starting value
|
||||
*/
|
||||
resetFilters() : void {
|
||||
public resetFilters(): void {
|
||||
this.filterBar.setValsToDefault();
|
||||
this.resetCaughtDropdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default value for the caught dropdown, which only shows caught mons
|
||||
*/
|
||||
public resetCaughtDropdown(): void {
|
||||
const caughtDropDown: DropDown = this.filterBar.getFilter(DropDownColumn.CAUGHT);
|
||||
|
||||
this.filterBar.setValsToDefault();
|
||||
caughtDropDown.resetToDefault();
|
||||
|
||||
// initial setting, in caught filter, select the options excluding the uncaught option
|
||||
for (let i = 0; i < caughtDropDown.options.length; i++) {
|
||||
|
@ -1323,16 +1332,15 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||
if (this.filterMode && this.filterBar.openDropDown) {
|
||||
// CANCEL with a filter menu open > close it
|
||||
this.filterBar.toggleDropDown(this.filterBarCursor);
|
||||
|
||||
// if there are possible starters go the first one of the list
|
||||
if (numberOfStarters > 0) {
|
||||
this.setFilterMode(false);
|
||||
this.scrollCursor = 0;
|
||||
this.updateScroll();
|
||||
this.setCursor(0);
|
||||
}
|
||||
success = true;
|
||||
|
||||
} else if (this.filterMode && !this.filterBar.getFilter(this.filterBar.getColumn(this.filterBarCursor)).hasDefaultValues()) {
|
||||
if (this.filterBar.getColumn(this.filterBarCursor) === DropDownColumn.CAUGHT) {
|
||||
this.resetCaughtDropdown();
|
||||
} else {
|
||||
this.filterBar.resetSelection(this.filterBarCursor);
|
||||
}
|
||||
this.updateStarters();
|
||||
success = true;
|
||||
} else if (this.statsMode) {
|
||||
this.toggleStatsMode(false);
|
||||
success = true;
|
||||
|
@ -2060,20 +2068,20 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||
}
|
||||
} while (newVariant !== props.variant);
|
||||
starterAttributes.variant = newVariant; // store the selected variant
|
||||
// If going to a higher variant, display that
|
||||
if (newVariant > props.variant) {
|
||||
if ((this.speciesStarterDexEntry!.caughtAttr & DexAttr.NON_SHINY) && (newVariant <= props.variant)) {
|
||||
// If we have run out of variants, go back to non shiny
|
||||
this.setSpeciesDetails(this.lastSpecies, { shiny: false, variant: 0 });
|
||||
this.pokemonShinyIcon.setVisible(false);
|
||||
success = true;
|
||||
starterAttributes.shiny = false;
|
||||
} else {
|
||||
// If going to a higher variant, or only shiny forms are caught, go to next variant
|
||||
this.setSpeciesDetails(this.lastSpecies, { variant: newVariant as Variant });
|
||||
// Cycle tint based on current sprite tint
|
||||
const tint = getVariantTint(newVariant as Variant);
|
||||
this.pokemonShinyIcon.setFrame(getVariantIcon(newVariant as Variant));
|
||||
this.pokemonShinyIcon.setTint(tint);
|
||||
success = true;
|
||||
// If we have run out of variants, go back to non shiny
|
||||
} else {
|
||||
this.setSpeciesDetails(this.lastSpecies, { shiny: false, variant: 0 });
|
||||
this.pokemonShinyIcon.setVisible(false);
|
||||
success = true;
|
||||
starterAttributes.shiny = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3320,7 +3328,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||
const isNonShinyCaught = !!(caughtAttr & DexAttr.NON_SHINY);
|
||||
const isShinyCaught = !!(caughtAttr & DexAttr.SHINY);
|
||||
|
||||
this.canCycleShiny = isNonShinyCaught && isShinyCaught;
|
||||
const caughtVariants = [ DexAttr.DEFAULT_VARIANT, DexAttr.VARIANT_2, DexAttr.VARIANT_3 ].filter(v => caughtAttr & v);
|
||||
this.canCycleShiny = (isNonShinyCaught && isShinyCaught) || (isShinyCaught && caughtVariants.length > 1);
|
||||
|
||||
const isMaleCaught = !!(caughtAttr & DexAttr.MALE);
|
||||
const isFemaleCaught = !!(caughtAttr & DexAttr.FEMALE);
|
||||
|
@ -3344,7 +3353,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||
this.canCycleForm = species.forms.filter(f => f.isStarterSelectable || !pokemonFormChanges[species.speciesId]?.find(fc => fc.formKey))
|
||||
.map((_, f) => dexEntry.caughtAttr & globalScene.gameData.getFormAttr(f)).filter(f => f).length > 1;
|
||||
this.canCycleNature = globalScene.gameData.getNaturesForAttr(dexEntry.natureAttr).length > 1;
|
||||
this.canCycleTera = globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id) && !Utils.isNullOrUndefined(getPokemonSpeciesForm(species.speciesId, formIndex ?? 0).type2);
|
||||
this.canCycleTera = !this.statsMode && globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id) && !Utils.isNullOrUndefined(getPokemonSpeciesForm(species.speciesId, formIndex ?? 0).type2);
|
||||
}
|
||||
|
||||
if (dexEntry.caughtAttr && species.malePercent !== null) {
|
||||
|
@ -3357,7 +3366,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||
}
|
||||
|
||||
if (dexEntry.caughtAttr) {
|
||||
const ability = allAbilities[this.lastSpecies.getAbility(abilityIndex!)]; // TODO: is this bang correct?
|
||||
let ability: Ability;
|
||||
if (this.lastSpecies.forms?.length > 1) {
|
||||
ability = allAbilities[this.lastSpecies.forms[formIndex ?? 0].getAbility(abilityIndex!)];
|
||||
} else {
|
||||
ability = allAbilities[this.lastSpecies.getAbility(abilityIndex!)]; // TODO: is this bang correct?
|
||||
}
|
||||
this.pokemonAbilityText.setText(ability.name);
|
||||
|
||||
const isHidden = abilityIndex === (this.lastSpecies.ability2 ? 2 : 1);
|
||||
|
@ -3844,12 +3858,20 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||
this.showStats();
|
||||
this.statsMode = true;
|
||||
this.pokemonSprite.setVisible(false);
|
||||
this.teraIcon.setVisible(false);
|
||||
this.canCycleTera = false;
|
||||
this.updateInstructions();
|
||||
} else {
|
||||
this.statsMode = false;
|
||||
this.statsContainer.setVisible(false);
|
||||
this.pokemonSprite.setVisible(!!this.speciesStarterDexEntry?.caughtAttr);
|
||||
//@ts-ignore
|
||||
this.statsContainer.updateIvs(null); // TODO: resolve ts-ignore. !?!?
|
||||
this.teraIcon.setVisible(globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id));
|
||||
const props = globalScene.gameData.getSpeciesDexAttrProps(this.lastSpecies, this.getCurrentDexProps(this.lastSpecies.speciesId));
|
||||
const formIndex = props.formIndex;
|
||||
this.canCycleTera = !this.statsMode && globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id) && !Utils.isNullOrUndefined(getPokemonSpeciesForm(this.lastSpecies.speciesId, formIndex ?? 0).type2);
|
||||
this.updateInstructions();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import { modifierSortFunc } from "#app/modifier/modifier";
|
|||
import { PlayerGender } from "#enums/player-gender";
|
||||
import { Stat, PERMANENT_STATS, getStatKey } from "#enums/stat";
|
||||
import { Nature } from "#enums/nature";
|
||||
import { achvs } from "#app/system/achv";
|
||||
|
||||
enum Page {
|
||||
PROFILE,
|
||||
|
@ -783,9 +784,6 @@ export default class SummaryUiHandler extends UiHandler {
|
|||
if (types.length > 1) {
|
||||
profileContainer.add(getTypeIcon(1, types[1]));
|
||||
}
|
||||
if (this.pokemon?.isTerastallized) {
|
||||
profileContainer.add(getTypeIcon(types.length, this.pokemon.getTeraType(), true));
|
||||
}
|
||||
|
||||
if (this.pokemon?.getLuck()) {
|
||||
const luckLabelText = addTextObject(141, 28, i18next.t("common:luckIndicator"), TextStyle.SUMMARY_ALT);
|
||||
|
@ -798,6 +796,13 @@ export default class SummaryUiHandler extends UiHandler {
|
|||
profileContainer.add(luckText);
|
||||
}
|
||||
|
||||
if (globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id) && !Utils.isNullOrUndefined(this.pokemon)) {
|
||||
const teraIcon = globalScene.add.sprite(123, 26, "button_tera");
|
||||
teraIcon.setName("terrastallize-icon");
|
||||
teraIcon.setFrame(Type[this.pokemon.getTeraType()].toLowerCase());
|
||||
profileContainer.add(teraIcon);
|
||||
}
|
||||
|
||||
this.abilityContainer = {
|
||||
labelImage: globalScene.add.image(0, 0, "summary_profile_ability"),
|
||||
ability: this.pokemon?.getAbility(true)!, // TODO: is this bang correct?
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
import { BattlerIndex } from "#app/battle";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { ArenaTagType } from "#enums/arena-tag-type";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { PokeballType } from "#enums/pokeball";
|
||||
import { Species } from "#enums/species";
|
||||
import { Stat } from "#enums/stat";
|
||||
import GameManager from "#test/testUtils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
describe("Abilities - Neutralizing Gas", () => {
|
||||
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.SPLASH ])
|
||||
.ability(Abilities.NEUTRALIZING_GAS)
|
||||
.battleType("single")
|
||||
.disableCrits()
|
||||
.enemySpecies(Species.MAGIKARP)
|
||||
.enemyAbility(Abilities.BALL_FETCH)
|
||||
.enemyMoveset(Moves.SPLASH);
|
||||
});
|
||||
|
||||
it("should prevent other abilities from activating", async () => {
|
||||
game.override.enemyAbility(Abilities.INTIMIDATE);
|
||||
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||
|
||||
game.move.select(Moves.SPLASH);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
// Intimidate is suppressed, so the attack stat should not be lowered
|
||||
expect(game.scene.getPlayerPokemon()?.getStatStage(Stat.ATK)).toBe(0);
|
||||
});
|
||||
|
||||
it("should allow the user's passive to activate", async () => {
|
||||
game.override.passiveAbility(Abilities.INTREPID_SWORD);
|
||||
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||
|
||||
game.move.select(Moves.SPLASH);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
expect(game.scene.getPlayerPokemon()?.getStatStage(Stat.ATK)).toBe(1);
|
||||
});
|
||||
|
||||
it.todo("should activate before other abilities", async () => {
|
||||
game.override.enemySpecies(Species.ACCELGOR)
|
||||
.enemyLevel(100)
|
||||
.enemyAbility(Abilities.INTIMIDATE);
|
||||
|
||||
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||
|
||||
game.move.select(Moves.SPLASH);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
// Intimidate is suppressed even when the user's speed is lower
|
||||
expect(game.scene.getPlayerPokemon()?.getStatStage(Stat.ATK)).toBe(0);
|
||||
});
|
||||
|
||||
it("should activate other abilities when removed", async () => {
|
||||
game.override.enemyAbility(Abilities.INTREPID_SWORD)
|
||||
.enemyPassiveAbility(Abilities.DAUNTLESS_SHIELD)
|
||||
.enemyMoveset(Moves.ENTRAINMENT);
|
||||
|
||||
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon();
|
||||
expect(enemyPokemon?.getStatStage(Stat.ATK)).toBe(0);
|
||||
expect(enemyPokemon?.getStatStage(Stat.DEF)).toBe(0);
|
||||
|
||||
game.move.select(Moves.SPLASH);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
// Enemy removes user's ability, so both abilities are activated
|
||||
expect(enemyPokemon?.getStatStage(Stat.ATK)).toBe(1);
|
||||
expect(enemyPokemon?.getStatStage(Stat.DEF)).toBe(1);
|
||||
});
|
||||
|
||||
it("should not activate the user's other ability when removed", async () => {
|
||||
game.override.passiveAbility(Abilities.INTIMIDATE)
|
||||
.enemyMoveset(Moves.ENTRAINMENT);
|
||||
|
||||
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||
// Neutralising gas user's passive is still active
|
||||
const enemyPokemon = game.scene.getEnemyPokemon();
|
||||
expect(enemyPokemon?.getStatStage(Stat.ATK)).toBe(-1);
|
||||
|
||||
game.move.select(Moves.SPLASH);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
// Intimidate did not reactivate after neutralizing gas was removed
|
||||
expect(enemyPokemon?.getStatStage(Stat.ATK)).toBe(-1);
|
||||
});
|
||||
|
||||
it("should only deactivate when all setters are off the field", async () => {
|
||||
game.override.enemyMoveset([ Moves.ENTRAINMENT, Moves.SPLASH ])
|
||||
.battleType("double");
|
||||
|
||||
await game.classicMode.startBattle([ Species.ACCELGOR, Species.ACCELGOR ]);
|
||||
game.move.select(Moves.SPLASH, 0);
|
||||
game.move.select(Moves.SPLASH, 1);
|
||||
await game.forceEnemyMove(Moves.ENTRAINMENT, BattlerIndex.PLAYER);
|
||||
await game.forceEnemyMove(Moves.SPLASH);
|
||||
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeDefined(); // Now one neut gas user is left
|
||||
|
||||
game.move.select(Moves.SPLASH, 0);
|
||||
game.move.select(Moves.SPLASH, 1);
|
||||
await game.forceEnemyMove(Moves.ENTRAINMENT, BattlerIndex.PLAYER_2);
|
||||
await game.forceEnemyMove(Moves.SPLASH);
|
||||
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeUndefined(); // No neut gas users are left
|
||||
});
|
||||
|
||||
it("should deactivate when suppressed by gastro acid", async () => {
|
||||
game.override.enemyMoveset(Moves.GASTRO_ACID);
|
||||
|
||||
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||
|
||||
game.move.select(Moves.SPLASH);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should deactivate when the pokemon faints", async () => {
|
||||
game.override.ability(Abilities.BALL_FETCH)
|
||||
.enemyAbility(Abilities.NEUTRALIZING_GAS);
|
||||
|
||||
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||
game.move.select(Moves.SPLASH);
|
||||
expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeDefined();
|
||||
await game.doKillOpponents();
|
||||
|
||||
expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should deactivate upon catching a wild pokemon", async () => {
|
||||
game.override
|
||||
.battleType("single")
|
||||
.enemyAbility(Abilities.NEUTRALIZING_GAS)
|
||||
.ability(Abilities.BALL_FETCH);
|
||||
await game.classicMode.startBattle([ Species.MAGIKARP ]);
|
||||
expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeDefined();
|
||||
|
||||
game.scene.pokeballCounts[PokeballType.MASTER_BALL] = 1;
|
||||
game.doThrowPokeball(PokeballType.MASTER_BALL);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeUndefined();
|
||||
});
|
||||
});
|
|
@ -140,6 +140,6 @@ describe("Moves - Focus Punch", () => {
|
|||
await game.phaseInterceptor.to("MessagePhase", false);
|
||||
const consoleSpy = vi.spyOn(console, "log");
|
||||
await game.phaseInterceptor.to("MoveEndPhase", true);
|
||||
expect(consoleSpy).nthCalledWith(1, i18next.t("moveTriggers:lostFocus"));
|
||||
expect(consoleSpy).nthCalledWith(1, i18next.t("moveTriggers:lostFocus", { pokemonName: "Charizard" }));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -46,11 +46,8 @@ describe("Moves - Shed Tail", () => {
|
|||
|
||||
expect(feebas).not.toBe(magikarp);
|
||||
expect(feebas.hp).toBe(feebas.getMaxHp());
|
||||
// Note: Shed Tail's HP cost is currently not accurate to mainline, as it
|
||||
// should cost ceil(maxHP / 2) instead of max(floor(maxHp / 2), 1). The current
|
||||
// implementation is consistent with Substitute's HP cost logic, but that's not
|
||||
// the case in mainline for some reason :regiDespair:.
|
||||
expect(magikarp.hp).toBe(Math.ceil(magikarp.getMaxHp() / 2));
|
||||
// Note: Altered the test to be consistent with the correct HP cost :yipeevee_static:
|
||||
expect(magikarp.hp).toBe(Math.floor(magikarp.getMaxHp() / 2));
|
||||
expect(substituteTag).toBeDefined();
|
||||
expect(substituteTag?.hp).toBe(Math.floor(magikarp.getMaxHp() / 4));
|
||||
});
|
||||
|
|
|
@ -223,14 +223,14 @@ describe("Mystery Encounter Utils", () => {
|
|||
});
|
||||
|
||||
it("excludes species from search", () => {
|
||||
// Only 9 tiers are: Koraidon, Miraidon, Arceus, Rayquaza, Kyogre, Groudon, Zacian
|
||||
const result = getRandomSpeciesByStarterCost(9, [ Species.KORAIDON, Species.MIRAIDON, Species.ARCEUS, Species.RAYQUAZA, Species.KYOGRE, Species.GROUDON ]);
|
||||
// Only 9 tiers are: Kyogre, Groudon, Rayquaza, Arceus, Zacian, Koraidon, Miraidon, Terapagos
|
||||
const result = getRandomSpeciesByStarterCost(9, [ Species.KYOGRE, Species.GROUDON, Species.RAYQUAZA, Species.ARCEUS, Species.KORAIDON, Species.MIRAIDON, Species.TERAPAGOS ]);
|
||||
const pokeSpecies = getPokemonSpecies(result);
|
||||
expect(pokeSpecies.speciesId).toBe(Species.ZACIAN);
|
||||
});
|
||||
|
||||
it("gets species of specified types", () => {
|
||||
// Only 9 tiers are: Koraidon, Miraidon, Arceus, Rayquaza, Kyogre, Groudon, Zacian
|
||||
// Only 9 tiers are: Kyogre, Groudon, Rayquaza, Arceus, Zacian, Koraidon, Miraidon, Terapagos
|
||||
const result = getRandomSpeciesByStarterCost(9, undefined, [ Type.GROUND ]);
|
||||
const pokeSpecies = getPokemonSpecies(result);
|
||||
expect(pokeSpecies.speciesId).toBe(Species.GROUDON);
|
||||
|
|