mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-21 14:59:26 +02:00
Merge branch 'beta' into charge-move-overhaul
This commit is contained in:
commit
9abd520db0
@ -4,7 +4,7 @@ import { Type } from "#app/data/type";
|
|||||||
import * as Utils from "#app/utils";
|
import * as Utils from "#app/utils";
|
||||||
import { MoveCategory, allMoves, MoveTarget, IncrementMovePriorityAttr, applyMoveAttrs } from "#app/data/move";
|
import { MoveCategory, allMoves, MoveTarget, IncrementMovePriorityAttr, applyMoveAttrs } from "#app/data/move";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import Pokemon, { HitResult, PlayerPokemon, PokemonMove, EnemyPokemon } from "#app/field/pokemon";
|
import Pokemon, { HitResult, PokemonMove } from "#app/field/pokemon";
|
||||||
import { StatusEffect } from "#app/data/status-effect";
|
import { StatusEffect } from "#app/data/status-effect";
|
||||||
import { BattlerIndex } from "#app/battle";
|
import { BattlerIndex } from "#app/battle";
|
||||||
import { BlockNonDirectDamageAbAttr, ChangeMovePriorityAbAttr, ProtectStatAbAttr, applyAbAttrs } from "#app/data/ability";
|
import { BlockNonDirectDamageAbAttr, ChangeMovePriorityAbAttr, ProtectStatAbAttr, applyAbAttrs } from "#app/data/ability";
|
||||||
@ -71,6 +71,32 @@ export abstract class ArenaTag {
|
|||||||
this.sourceId = source.sourceId;
|
this.sourceId = source.sourceId;
|
||||||
this.side = source.side;
|
this.side = source.side;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function that retrieves the source Pokemon
|
||||||
|
* @param scene medium to retrieve the source Pokemon
|
||||||
|
* @returns The source {@linkcode Pokemon} or `null` if none is found
|
||||||
|
*/
|
||||||
|
public getSourcePokemon(scene: BattleScene): Pokemon | null {
|
||||||
|
return this.sourceId ? scene.getPokemonById(this.sourceId) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function that retrieves the Pokemon affected
|
||||||
|
* @param scene - medium to retrieve the involved Pokemon
|
||||||
|
* @returns list of PlayerPokemon or EnemyPokemon on the field
|
||||||
|
*/
|
||||||
|
public getAffectedPokemon(scene: BattleScene): Pokemon[] {
|
||||||
|
switch (this.side) {
|
||||||
|
case ArenaTagSide.PLAYER:
|
||||||
|
return scene.getPlayerField() ?? [];
|
||||||
|
case ArenaTagSide.ENEMY:
|
||||||
|
return scene.getEnemyField() ?? [];
|
||||||
|
case ArenaTagSide.BOTH:
|
||||||
|
default:
|
||||||
|
return scene.getField(true) ?? [];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -981,36 +1007,24 @@ class NoneTag extends ArenaTag {
|
|||||||
* Imprison will apply to any opposing Pokemon that switch onto the field as well.
|
* Imprison will apply to any opposing Pokemon that switch onto the field as well.
|
||||||
*/
|
*/
|
||||||
class ImprisonTag extends ArenaTrapTag {
|
class ImprisonTag extends ArenaTrapTag {
|
||||||
private source: Pokemon;
|
|
||||||
|
|
||||||
constructor(sourceId: number, side: ArenaTagSide) {
|
constructor(sourceId: number, side: ArenaTagSide) {
|
||||||
super(ArenaTagType.IMPRISON, Moves.IMPRISON, sourceId, side, 1);
|
super(ArenaTagType.IMPRISON, Moves.IMPRISON, sourceId, side, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function that retrieves the Pokemon affected
|
|
||||||
* @param {BattleScene} scene medium to retrieve the involved Pokemon
|
|
||||||
* @returns list of PlayerPokemon or EnemyPokemon on the field
|
|
||||||
*/
|
|
||||||
private retrieveField(scene: BattleScene): PlayerPokemon[] | EnemyPokemon[] {
|
|
||||||
if (!this.source.isPlayer()) {
|
|
||||||
return scene.getPlayerField() ?? [];
|
|
||||||
}
|
|
||||||
return scene.getEnemyField() ?? [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function applies the effects of Imprison to the opposing Pokemon already present on the field.
|
* This function applies the effects of Imprison to the opposing Pokemon already present on the field.
|
||||||
* @param arena
|
* @param arena
|
||||||
*/
|
*/
|
||||||
override onAdd({ scene }: Arena) {
|
override onAdd({ scene }: Arena) {
|
||||||
this.source = scene.getPokemonById(this.sourceId!)!;
|
const source = this.getSourcePokemon(scene);
|
||||||
if (this.source) {
|
if (source) {
|
||||||
const party = this.retrieveField(scene);
|
const party = this.getAffectedPokemon(scene);
|
||||||
party?.forEach((p: PlayerPokemon | EnemyPokemon ) => {
|
party?.forEach((p: Pokemon ) => {
|
||||||
p.addTag(BattlerTagType.IMPRISON, 1, Moves.IMPRISON, this.sourceId);
|
if (p.isAllowedInBattle()) {
|
||||||
|
p.addTag(BattlerTagType.IMPRISON, 1, Moves.IMPRISON, this.sourceId);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
scene.queueMessage(i18next.t("battlerTags:imprisonOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(this.source) }));
|
scene.queueMessage(i18next.t("battlerTags:imprisonOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(source) }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1019,8 +1033,9 @@ class ImprisonTag extends ArenaTrapTag {
|
|||||||
* @param _arena
|
* @param _arena
|
||||||
* @returns `true` if the source of the tag is still active on the field | `false` if not
|
* @returns `true` if the source of the tag is still active on the field | `false` if not
|
||||||
*/
|
*/
|
||||||
override lapse(_arena: Arena): boolean {
|
override lapse({ scene }: Arena): boolean {
|
||||||
return this.source.isActive(true);
|
const source = this.getSourcePokemon(scene);
|
||||||
|
return source ? source.isActive(true) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1029,7 +1044,8 @@ class ImprisonTag extends ArenaTrapTag {
|
|||||||
* @returns `true`
|
* @returns `true`
|
||||||
*/
|
*/
|
||||||
override activateTrap(pokemon: Pokemon): boolean {
|
override activateTrap(pokemon: Pokemon): boolean {
|
||||||
if (this.source.isActive(true)) {
|
const source = this.getSourcePokemon(pokemon.scene);
|
||||||
|
if (source && source.isActive(true) && pokemon.isAllowedInBattle()) {
|
||||||
pokemon.addTag(BattlerTagType.IMPRISON, 1, Moves.IMPRISON, this.sourceId);
|
pokemon.addTag(BattlerTagType.IMPRISON, 1, Moves.IMPRISON, this.sourceId);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -1040,8 +1056,8 @@ class ImprisonTag extends ArenaTrapTag {
|
|||||||
* @param arena
|
* @param arena
|
||||||
*/
|
*/
|
||||||
override onRemove({ scene }: Arena): void {
|
override onRemove({ scene }: Arena): void {
|
||||||
const party = this.retrieveField(scene);
|
const party = this.getAffectedPokemon(scene);
|
||||||
party?.forEach((p: PlayerPokemon | EnemyPokemon) => {
|
party?.forEach((p: Pokemon) => {
|
||||||
p.removeTag(BattlerTagType.IMPRISON);
|
p.removeTag(BattlerTagType.IMPRISON);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
|
|||||||
import { ShowAbilityPhase } from "#app/phases/show-ability-phase";
|
import { ShowAbilityPhase } from "#app/phases/show-ability-phase";
|
||||||
import { StatStageChangePhase, StatStageChangeCallback } from "#app/phases/stat-stage-change-phase";
|
import { StatStageChangePhase, StatStageChangeCallback } from "#app/phases/stat-stage-change-phase";
|
||||||
import { PokemonAnimType } from "#app/enums/pokemon-anim-type";
|
import { PokemonAnimType } from "#app/enums/pokemon-anim-type";
|
||||||
|
import BattleScene from "#app/battle-scene";
|
||||||
|
|
||||||
export enum BattlerTagLapseType {
|
export enum BattlerTagLapseType {
|
||||||
FAINT,
|
FAINT,
|
||||||
@ -90,6 +91,15 @@ export class BattlerTag {
|
|||||||
this.sourceMove = source.sourceMove;
|
this.sourceMove = source.sourceMove;
|
||||||
this.sourceId = source.sourceId;
|
this.sourceId = source.sourceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function that retrieves the source Pokemon object
|
||||||
|
* @param scene medium to retrieve the source Pokemon
|
||||||
|
* @returns The source {@linkcode Pokemon} or `null` if none is found
|
||||||
|
*/
|
||||||
|
public getSourcePokemon(scene: BattleScene): Pokemon | null {
|
||||||
|
return this.sourceId ? scene.getPokemonById(this.sourceId) : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WeatherBattlerTag {
|
export interface WeatherBattlerTag {
|
||||||
@ -120,7 +130,7 @@ export abstract class MoveRestrictionBattlerTag extends BattlerTag {
|
|||||||
const phase = pokemon.scene.getCurrentPhase() as MovePhase;
|
const phase = pokemon.scene.getCurrentPhase() as MovePhase;
|
||||||
const move = phase.move;
|
const move = phase.move;
|
||||||
|
|
||||||
if (this.isMoveRestricted(move.moveId)) {
|
if (this.isMoveRestricted(move.moveId, pokemon)) {
|
||||||
if (this.interruptedText(pokemon, move.moveId)) {
|
if (this.interruptedText(pokemon, move.moveId)) {
|
||||||
pokemon.scene.queueMessage(this.interruptedText(pokemon, move.moveId));
|
pokemon.scene.queueMessage(this.interruptedText(pokemon, move.moveId));
|
||||||
}
|
}
|
||||||
@ -136,10 +146,11 @@ export abstract class MoveRestrictionBattlerTag extends BattlerTag {
|
|||||||
/**
|
/**
|
||||||
* Gets whether this tag is restricting a move.
|
* Gets whether this tag is restricting a move.
|
||||||
*
|
*
|
||||||
* @param {Moves} move {@linkcode Moves} ID to check restriction for.
|
* @param move - {@linkcode Moves} ID to check restriction for.
|
||||||
* @returns {boolean} `true` if the move is restricted by this tag, otherwise `false`.
|
* @param user - The {@linkcode Pokemon} involved
|
||||||
|
* @returns `true` if the move is restricted by this tag, otherwise `false`.
|
||||||
*/
|
*/
|
||||||
abstract isMoveRestricted(move: Moves): boolean;
|
public abstract isMoveRestricted(move: Moves, user?: Pokemon): boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if this tag is restricting a move based on a user's decisions during the target selection phase
|
* Checks if this tag is restricting a move based on a user's decisions during the target selection phase
|
||||||
@ -327,6 +338,16 @@ export class GorillaTacticsTag extends MoveRestrictionBattlerTag {
|
|||||||
pokemon.setStat(Stat.ATK, pokemon.getStat(Stat.ATK, false) * 1.5, false);
|
pokemon.setStat(Stat.ATK, pokemon.getStat(Stat.ATK, false) * 1.5, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the Gorilla Tactics Battler Tag along with its unique class variable moveId
|
||||||
|
* @override
|
||||||
|
* @param source Gorilla Tactics' {@linkcode BattlerTag} information
|
||||||
|
*/
|
||||||
|
public override loadTag(source: BattlerTag | any): void {
|
||||||
|
super.loadTag(source);
|
||||||
|
this.moveId = source.moveId;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @override
|
* @override
|
||||||
@ -2506,8 +2527,6 @@ export class MysteryEncounterPostSummonTag extends BattlerTag {
|
|||||||
* Torment does not interrupt the move if the move is performed consecutively in the same turn and right after Torment is applied
|
* Torment does not interrupt the move if the move is performed consecutively in the same turn and right after Torment is applied
|
||||||
*/
|
*/
|
||||||
export class TormentTag extends MoveRestrictionBattlerTag {
|
export class TormentTag extends MoveRestrictionBattlerTag {
|
||||||
private target: Pokemon;
|
|
||||||
|
|
||||||
constructor(sourceId: number) {
|
constructor(sourceId: number) {
|
||||||
super(BattlerTagType.TORMENT, BattlerTagLapseType.AFTER_MOVE, 1, Moves.TORMENT, sourceId);
|
super(BattlerTagType.TORMENT, BattlerTagLapseType.AFTER_MOVE, 1, Moves.TORMENT, sourceId);
|
||||||
}
|
}
|
||||||
@ -2519,7 +2538,6 @@ export class TormentTag extends MoveRestrictionBattlerTag {
|
|||||||
*/
|
*/
|
||||||
override onAdd(pokemon: Pokemon) {
|
override onAdd(pokemon: Pokemon) {
|
||||||
super.onAdd(pokemon);
|
super.onAdd(pokemon);
|
||||||
this.target = pokemon;
|
|
||||||
pokemon.scene.queueMessage(i18next.t("battlerTags:tormentOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }), 1500);
|
pokemon.scene.queueMessage(i18next.t("battlerTags:tormentOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }), 1500);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2538,15 +2556,18 @@ export class TormentTag extends MoveRestrictionBattlerTag {
|
|||||||
* @param {Moves} move the move under investigation
|
* @param {Moves} move the move under investigation
|
||||||
* @returns `true` if there is valid consecutive usage | `false` if the moves are different from each other
|
* @returns `true` if there is valid consecutive usage | `false` if the moves are different from each other
|
||||||
*/
|
*/
|
||||||
override isMoveRestricted(move: Moves): boolean {
|
public override isMoveRestricted(move: Moves, user: Pokemon): boolean {
|
||||||
const lastMove = this.target.getLastXMoves(1)[0];
|
if (!user) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const lastMove = user.getLastXMoves(1)[0];
|
||||||
if ( !lastMove ) {
|
if ( !lastMove ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// This checks for locking / momentum moves like Rollout and Hydro Cannon + if the user is under the influence of BattlerTagType.FRENZY
|
// This checks for locking / momentum moves like Rollout and Hydro Cannon + if the user is under the influence of BattlerTagType.FRENZY
|
||||||
// Because Uproar's unique behavior is not implemented, it does not check for Uproar. Torment has been marked as partial in moves.ts
|
// Because Uproar's unique behavior is not implemented, it does not check for Uproar. Torment has been marked as partial in moves.ts
|
||||||
const moveObj = allMoves[lastMove.move];
|
const moveObj = allMoves[lastMove.move];
|
||||||
const isUnaffected = moveObj.hasAttr(ConsecutiveUseDoublePowerAttr) || this.target.getTag(BattlerTagType.FRENZY);
|
const isUnaffected = moveObj.hasAttr(ConsecutiveUseDoublePowerAttr) || user.getTag(BattlerTagType.FRENZY);
|
||||||
const validLastMoveResult = (lastMove.result === MoveResult.SUCCESS) || (lastMove.result === MoveResult.MISS);
|
const validLastMoveResult = (lastMove.result === MoveResult.SUCCESS) || (lastMove.result === MoveResult.MISS);
|
||||||
if (lastMove.move === move && validLastMoveResult && lastMove.move !== Moves.STRUGGLE && !isUnaffected) {
|
if (lastMove.move === move && validLastMoveResult && lastMove.move !== Moves.STRUGGLE && !isUnaffected) {
|
||||||
return true;
|
return true;
|
||||||
@ -2598,37 +2619,39 @@ export class TauntTag extends MoveRestrictionBattlerTag {
|
|||||||
* The tag is only removed when the source-user is removed from the field.
|
* The tag is only removed when the source-user is removed from the field.
|
||||||
*/
|
*/
|
||||||
export class ImprisonTag extends MoveRestrictionBattlerTag {
|
export class ImprisonTag extends MoveRestrictionBattlerTag {
|
||||||
private source: Pokemon | null;
|
|
||||||
|
|
||||||
constructor(sourceId: number) {
|
constructor(sourceId: number) {
|
||||||
super(BattlerTagType.IMPRISON, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.AFTER_MOVE ], 1, Moves.IMPRISON, sourceId);
|
super(BattlerTagType.IMPRISON, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.AFTER_MOVE ], 1, Moves.IMPRISON, sourceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
override onAdd(pokemon: Pokemon) {
|
|
||||||
if (this.sourceId) {
|
|
||||||
this.source = pokemon.scene.getPokemonById(this.sourceId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the source of Imprison is still active
|
* Checks if the source of Imprison is still active
|
||||||
* @param _pokemon
|
* @override
|
||||||
* @param _lapseType
|
* @param pokemon The pokemon this tag is attached to
|
||||||
* @returns `true` if the source is still active
|
* @returns `true` if the source is still active
|
||||||
*/
|
*/
|
||||||
override lapse(_pokemon: Pokemon, _lapseType: BattlerTagLapseType): boolean {
|
public override lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
return this.source?.isActive(true) ?? false;
|
const source = this.getSourcePokemon(pokemon.scene);
|
||||||
|
if (source) {
|
||||||
|
if (lapseType === BattlerTagLapseType.PRE_MOVE) {
|
||||||
|
return super.lapse(pokemon, lapseType) && source.isActive(true);
|
||||||
|
} else {
|
||||||
|
return source.isActive(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the source of the tag has the parameter move in its moveset and that the source is still active
|
* Checks if the source of the tag has the parameter move in its moveset and that the source is still active
|
||||||
|
* @override
|
||||||
* @param {Moves} move the move under investigation
|
* @param {Moves} move the move under investigation
|
||||||
* @returns `false` if either condition is not met
|
* @returns `false` if either condition is not met
|
||||||
*/
|
*/
|
||||||
override isMoveRestricted(move: Moves): boolean {
|
public override isMoveRestricted(move: Moves, user: Pokemon): boolean {
|
||||||
if (this.source) {
|
const source = this.getSourcePokemon(user.scene);
|
||||||
const sourceMoveset = this.source.getMoveset().map(m => m!.moveId);
|
if (source) {
|
||||||
return sourceMoveset?.includes(move) && this.source.isActive(true);
|
const sourceMoveset = source.getMoveset().map(m => m!.moveId);
|
||||||
|
return sourceMoveset?.includes(move) && source.isActive(true);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2697,6 +2720,44 @@ export class TelekinesisTag extends BattlerTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tag that swaps the user's base ATK stat with its base DEF stat.
|
||||||
|
* @extends BattlerTag
|
||||||
|
*/
|
||||||
|
export class PowerTrickTag extends BattlerTag {
|
||||||
|
constructor(sourceMove: Moves, sourceId: number) {
|
||||||
|
super(BattlerTagType.POWER_TRICK, BattlerTagLapseType.CUSTOM, 0, sourceMove, sourceId, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
onAdd(pokemon: Pokemon): void {
|
||||||
|
this.swapStat(pokemon);
|
||||||
|
pokemon.scene.queueMessage(i18next.t("battlerTags:powerTrickActive", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
|
}
|
||||||
|
|
||||||
|
onRemove(pokemon: Pokemon): void {
|
||||||
|
this.swapStat(pokemon);
|
||||||
|
pokemon.scene.queueMessage(i18next.t("battlerTags:powerTrickActive", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the Power Trick tag and reverts any stat changes if the tag is already applied.
|
||||||
|
* @param {Pokemon} pokemon The {@linkcode Pokemon} that already has the Power Trick tag.
|
||||||
|
*/
|
||||||
|
onOverlap(pokemon: Pokemon): void {
|
||||||
|
pokemon.removeTag(this.tagType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swaps the user's base ATK stat with its base DEF stat.
|
||||||
|
* @param {Pokemon} pokemon The {@linkcode Pokemon} whose stats will be swapped.
|
||||||
|
*/
|
||||||
|
swapStat(pokemon: Pokemon): void {
|
||||||
|
const temp = pokemon.getStat(Stat.ATK, false);
|
||||||
|
pokemon.setStat(Stat.ATK, pokemon.getStat(Stat.DEF, false), false);
|
||||||
|
pokemon.setStat(Stat.DEF, temp, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a {@linkcode BattlerTag} based on the provided tag type, turn count, source move, and source ID.
|
* Retrieves a {@linkcode BattlerTag} based on the provided tag type, turn count, source move, and source ID.
|
||||||
* @param sourceId - The ID of the pokemon adding the tag
|
* @param sourceId - The ID of the pokemon adding the tag
|
||||||
@ -2872,6 +2933,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source
|
|||||||
return new SyrupBombTag(sourceId);
|
return new SyrupBombTag(sourceId);
|
||||||
case BattlerTagType.TELEKINESIS:
|
case BattlerTagType.TELEKINESIS:
|
||||||
return new TelekinesisTag(sourceMove);
|
return new TelekinesisTag(sourceMove);
|
||||||
|
case BattlerTagType.POWER_TRICK:
|
||||||
|
return new PowerTrickTag(sourceMove, sourceId);
|
||||||
case BattlerTagType.NONE:
|
case BattlerTagType.NONE:
|
||||||
default:
|
default:
|
||||||
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
|
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
|
||||||
|
@ -5549,37 +5549,38 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
|
|||||||
*/
|
*/
|
||||||
const switchOutTarget = this.selfSwitch ? user : target;
|
const switchOutTarget = this.selfSwitch ? user : target;
|
||||||
if (switchOutTarget instanceof PlayerPokemon) {
|
if (switchOutTarget instanceof PlayerPokemon) {
|
||||||
|
// Switch out logic for the player's Pokemon
|
||||||
if (switchOutTarget.scene.getParty().filter((p) => p.isAllowedInBattle() && !p.isOnField()).length < 1) {
|
if (switchOutTarget.scene.getParty().filter((p) => p.isAllowedInBattle() && !p.isOnField()).length < 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH);
|
|
||||||
|
|
||||||
if (switchOutTarget.hp > 0) {
|
if (switchOutTarget.hp > 0) {
|
||||||
|
switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH);
|
||||||
user.scene.prependToPhase(new SwitchPhase(user.scene, this.switchType, switchOutTarget.getFieldIndex(), true, true), MoveEndPhase);
|
user.scene.prependToPhase(new SwitchPhase(user.scene, this.switchType, switchOutTarget.getFieldIndex(), true, true), MoveEndPhase);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} else if (user.scene.currentBattle.battleType !== BattleType.WILD) {
|
} else if (user.scene.currentBattle.battleType !== BattleType.WILD) {
|
||||||
|
// Switch out logic for trainer battles
|
||||||
if (switchOutTarget.scene.getEnemyParty().filter((p) => p.isAllowedInBattle() && !p.isOnField()).length < 1) {
|
if (switchOutTarget.scene.getEnemyParty().filter((p) => p.isAllowedInBattle() && !p.isOnField()).length < 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Switch out logic for trainer battles
|
|
||||||
switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH);
|
|
||||||
|
|
||||||
if (switchOutTarget.hp > 0) {
|
if (switchOutTarget.hp > 0) {
|
||||||
// for opponent switching out
|
// for opponent switching out
|
||||||
|
switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH);
|
||||||
user.scene.prependToPhase(new SwitchSummonPhase(user.scene, this.switchType, switchOutTarget.getFieldIndex(),
|
user.scene.prependToPhase(new SwitchSummonPhase(user.scene, this.switchType, switchOutTarget.getFieldIndex(),
|
||||||
(user.scene.currentBattle.trainer ? user.scene.currentBattle.trainer.getNextSummonIndex((switchOutTarget as EnemyPokemon).trainerSlot) : 0),
|
(user.scene.currentBattle.trainer ? user.scene.currentBattle.trainer.getNextSummonIndex((switchOutTarget as EnemyPokemon).trainerSlot) : 0),
|
||||||
false, false), MoveEndPhase);
|
false, false), MoveEndPhase);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Switch out logic for everything else (eg: WILD battles)
|
||||||
if (user.scene.currentBattle.waveIndex % 10 === 0) {
|
if (user.scene.currentBattle.waveIndex % 10 === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Switch out logic for everything else (eg: WILD battles)
|
|
||||||
switchOutTarget.leaveField(false);
|
|
||||||
|
|
||||||
if (switchOutTarget.hp) {
|
if (switchOutTarget.hp > 0) {
|
||||||
|
switchOutTarget.leaveField(false);
|
||||||
user.scene.queueMessage(i18next.t("moveTriggers:fled", { pokemonName: getPokemonNameWithAffix(switchOutTarget) }), null, true, 500);
|
user.scene.queueMessage(i18next.t("moveTriggers:fled", { pokemonName: getPokemonNameWithAffix(switchOutTarget) }), null, true, 500);
|
||||||
|
|
||||||
// in double battles redirect potential moves off fled pokemon
|
// in double battles redirect potential moves off fled pokemon
|
||||||
@ -6494,6 +6495,9 @@ export class TransformAttr extends MoveEffectAttr {
|
|||||||
user.summonData.gender = target.getGender();
|
user.summonData.gender = target.getGender();
|
||||||
user.summonData.fusionGender = target.getFusionGender();
|
user.summonData.fusionGender = target.getFusionGender();
|
||||||
|
|
||||||
|
// Power Trick's effect will not preserved after using Transform
|
||||||
|
user.removeTag(BattlerTagType.POWER_TRICK);
|
||||||
|
|
||||||
// Copy all stats (except HP)
|
// Copy all stats (except HP)
|
||||||
for (const s of EFFECTIVE_STATS) {
|
for (const s of EFFECTIVE_STATS) {
|
||||||
user.setStat(s, target.getStat(s, false), false);
|
user.setStat(s, target.getStat(s, false), false);
|
||||||
@ -7969,7 +7973,8 @@ export function initMoves() {
|
|||||||
.attr(SwitchAbilitiesAttr),
|
.attr(SwitchAbilitiesAttr),
|
||||||
new StatusMove(Moves.IMPRISON, Type.PSYCHIC, 100, 10, -1, 0, 3)
|
new StatusMove(Moves.IMPRISON, Type.PSYCHIC, 100, 10, -1, 0, 3)
|
||||||
.ignoresSubstitute()
|
.ignoresSubstitute()
|
||||||
.attr(AddArenaTagAttr, ArenaTagType.IMPRISON, 1, true, false),
|
.attr(AddArenaTagAttr, ArenaTagType.IMPRISON, 1, true, false)
|
||||||
|
.target(MoveTarget.ENEMY_SIDE),
|
||||||
new SelfStatusMove(Moves.REFRESH, Type.NORMAL, -1, 20, -1, 0, 3)
|
new SelfStatusMove(Moves.REFRESH, Type.NORMAL, -1, 20, -1, 0, 3)
|
||||||
.attr(HealStatusEffectAttr, true, StatusEffect.PARALYSIS, StatusEffect.POISON, StatusEffect.TOXIC, StatusEffect.BURN)
|
.attr(HealStatusEffectAttr, true, StatusEffect.PARALYSIS, StatusEffect.POISON, StatusEffect.TOXIC, StatusEffect.BURN)
|
||||||
.condition((user, target, move) => !!user.status && (user.status.effect === StatusEffect.PARALYSIS || user.status.effect === StatusEffect.POISON || user.status.effect === StatusEffect.TOXIC || user.status.effect === StatusEffect.BURN)),
|
.condition((user, target, move) => !!user.status && (user.status.effect === StatusEffect.PARALYSIS || user.status.effect === StatusEffect.POISON || user.status.effect === StatusEffect.TOXIC || user.status.effect === StatusEffect.BURN)),
|
||||||
@ -8239,7 +8244,7 @@ export function initMoves() {
|
|||||||
.attr(OpponentHighHpPowerAttr, 120)
|
.attr(OpponentHighHpPowerAttr, 120)
|
||||||
.makesContact(),
|
.makesContact(),
|
||||||
new SelfStatusMove(Moves.POWER_TRICK, Type.PSYCHIC, -1, 10, -1, 0, 4)
|
new SelfStatusMove(Moves.POWER_TRICK, Type.PSYCHIC, -1, 10, -1, 0, 4)
|
||||||
.unimplemented(),
|
.attr(AddBattlerTagAttr, BattlerTagType.POWER_TRICK, true),
|
||||||
new StatusMove(Moves.GASTRO_ACID, Type.POISON, 100, 10, -1, 0, 4)
|
new StatusMove(Moves.GASTRO_ACID, Type.POISON, 100, 10, -1, 0, 4)
|
||||||
.attr(SuppressAbilitiesAttr),
|
.attr(SuppressAbilitiesAttr),
|
||||||
new StatusMove(Moves.LUCKY_CHANT, Type.NORMAL, -1, 30, -1, 0, 4)
|
new StatusMove(Moves.LUCKY_CHANT, Type.NORMAL, -1, 30, -1, 0, 4)
|
||||||
|
@ -574,13 +574,13 @@ export class TrainerConfig {
|
|||||||
case "magma": {
|
case "magma": {
|
||||||
return {
|
return {
|
||||||
[TrainerPoolTier.COMMON]: [ Species.GROWLITHE, Species.SLUGMA, Species.SOLROCK, Species.HIPPOPOTAS, Species.BALTOY, Species.ROLYCOLY, Species.GLIGAR, Species.TORKOAL, Species.HOUNDOUR, Species.MAGBY ],
|
[TrainerPoolTier.COMMON]: [ Species.GROWLITHE, Species.SLUGMA, Species.SOLROCK, Species.HIPPOPOTAS, Species.BALTOY, Species.ROLYCOLY, Species.GLIGAR, Species.TORKOAL, Species.HOUNDOUR, Species.MAGBY ],
|
||||||
[TrainerPoolTier.UNCOMMON]: [ Species.TRAPINCH, Species.SILICOBRA, Species.RHYHORN, Species.ANORITH, Species.LILEEP, Species.HISUI_GROWLITHE, Species.TURTONATOR, Species.ARON, Species.BARBOACH ],
|
[TrainerPoolTier.UNCOMMON]: [ Species.TRAPINCH, Species.SILICOBRA, Species.RHYHORN, Species.ANORITH, Species.LILEEP, Species.HISUI_GROWLITHE, Species.TURTONATOR, Species.ARON, Species.TOEDSCOOL ],
|
||||||
[TrainerPoolTier.RARE]: [ Species.CAPSAKID, Species.CHARCADET ]
|
[TrainerPoolTier.RARE]: [ Species.CAPSAKID, Species.CHARCADET ]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case "aqua": {
|
case "aqua": {
|
||||||
return {
|
return {
|
||||||
[TrainerPoolTier.COMMON]: [ Species.CORPHISH, Species.SPHEAL, Species.CLAMPERL, Species.CHINCHOU, Species.WOOPER, Species.WINGULL, Species.TENTACOOL, Species.AZURILL, Species.LOTAD, Species.WAILMER, Species.REMORAID ],
|
[TrainerPoolTier.COMMON]: [ Species.CORPHISH, Species.SPHEAL, Species.CLAMPERL, Species.CHINCHOU, Species.WOOPER, Species.WINGULL, Species.TENTACOOL, Species.AZURILL, Species.LOTAD, Species.WAILMER, Species.REMORAID, Species.BARBOACH ],
|
||||||
[TrainerPoolTier.UNCOMMON]: [ Species.MANTYKE, Species.HISUI_QWILFISH, Species.ARROKUDA, Species.DHELMISE, Species.CLOBBOPUS, Species.FEEBAS, Species.PALDEA_WOOPER, Species.HORSEA, Species.SKRELP ],
|
[TrainerPoolTier.UNCOMMON]: [ Species.MANTYKE, Species.HISUI_QWILFISH, Species.ARROKUDA, Species.DHELMISE, Species.CLOBBOPUS, Species.FEEBAS, Species.PALDEA_WOOPER, Species.HORSEA, Species.SKRELP ],
|
||||||
[TrainerPoolTier.RARE]: [ Species.DONDOZO, Species.BASCULEGION ]
|
[TrainerPoolTier.RARE]: [ Species.DONDOZO, Species.BASCULEGION ]
|
||||||
};
|
};
|
||||||
@ -601,9 +601,9 @@ export class TrainerConfig {
|
|||||||
}
|
}
|
||||||
case "flare": {
|
case "flare": {
|
||||||
return {
|
return {
|
||||||
[TrainerPoolTier.COMMON]: [ Species.FLETCHLING, Species.LITLEO, Species.INKAY, Species.HELIOPTILE, Species.ELECTRIKE, Species.SKORUPI, Species.PURRLOIN, Species.CLAWITZER, Species.PANCHAM, Species.ESPURR, Species.BUNNELBY ],
|
[TrainerPoolTier.COMMON]: [ Species.FLETCHLING, Species.LITLEO, Species.INKAY, Species.FOONGUS, Species.HELIOPTILE, Species.ELECTRIKE, Species.SKORUPI, Species.PURRLOIN, Species.CLAWITZER, Species.PANCHAM, Species.ESPURR, Species.BUNNELBY ],
|
||||||
[TrainerPoolTier.UNCOMMON]: [ Species.LITWICK, Species.SNEASEL, Species.PUMPKABOO, Species.PHANTUMP, Species.HONEDGE, Species.BINACLE, Species.HOUNDOUR, Species.SKRELP, Species.SLIGGOO ],
|
[TrainerPoolTier.UNCOMMON]: [ Species.LITWICK, Species.SNEASEL, Species.PUMPKABOO, Species.PHANTUMP, Species.HONEDGE, Species.BINACLE, Species.HOUNDOUR, Species.SKRELP, Species.SLIGGOO ],
|
||||||
[TrainerPoolTier.RARE]: [ Species.NOIVERN, Species.HISUI_AVALUGG, Species.HISUI_SLIGGOO ]
|
[TrainerPoolTier.RARE]: [ Species.NOIBAT, Species.HISUI_AVALUGG, Species.HISUI_SLIGGOO ]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case "aether": {
|
case "aether": {
|
||||||
@ -1504,7 +1504,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
.setSpeciesPools({
|
.setSpeciesPools({
|
||||||
[TrainerPoolTier.COMMON]: [ Species.SLUGMA, Species.POOCHYENA, Species.NUMEL, Species.ZIGZAGOON, Species.DIGLETT, Species.MAGBY, Species.TORKOAL, Species.GROWLITHE, Species.BALTOY ],
|
[TrainerPoolTier.COMMON]: [ Species.SLUGMA, Species.POOCHYENA, Species.NUMEL, Species.ZIGZAGOON, Species.DIGLETT, Species.MAGBY, Species.TORKOAL, Species.GROWLITHE, Species.BALTOY ],
|
||||||
[TrainerPoolTier.UNCOMMON]: [ Species.SOLROCK, Species.HIPPOPOTAS, Species.SANDACONDA, Species.PHANPY, Species.ROLYCOLY, Species.GLIGAR, Species.RHYHORN, Species.HEATMOR ],
|
[TrainerPoolTier.UNCOMMON]: [ Species.SOLROCK, Species.HIPPOPOTAS, Species.SANDACONDA, Species.PHANPY, Species.ROLYCOLY, Species.GLIGAR, Species.RHYHORN, Species.HEATMOR ],
|
||||||
[TrainerPoolTier.RARE]: [ Species.TRAPINCH, Species.LILEEP, Species.ANORITH, Species.HISUI_GROWLITHE, Species.TURTONATOR, Species.ARON ],
|
[TrainerPoolTier.RARE]: [ Species.TRAPINCH, Species.LILEEP, Species.ANORITH, Species.HISUI_GROWLITHE, Species.TURTONATOR, Species.ARON, Species.TOEDSCOOL ],
|
||||||
[TrainerPoolTier.SUPER_RARE]: [ Species.CAPSAKID, Species.CHARCADET ]
|
[TrainerPoolTier.SUPER_RARE]: [ Species.CAPSAKID, Species.CHARCADET ]
|
||||||
}),
|
}),
|
||||||
[TrainerType.TABITHA]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("magma_admin", "magma", [ Species.CAMERUPT ]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)),
|
[TrainerType.TABITHA]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("magma_admin", "magma", [ Species.CAMERUPT ]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)),
|
||||||
@ -1540,9 +1540,9 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
[TrainerType.FLARE_GRUNT]: new TrainerConfig(++t).setHasGenders("Flare Grunt Female").setHasDouble("Flare Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_flare_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene))
|
[TrainerType.FLARE_GRUNT]: new TrainerConfig(++t).setHasGenders("Flare Grunt Female").setHasDouble("Flare Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_flare_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene))
|
||||||
.setSpeciesPools({
|
.setSpeciesPools({
|
||||||
[TrainerPoolTier.COMMON]: [ Species.FLETCHLING, Species.LITLEO, Species.PONYTA, Species.INKAY, Species.HOUNDOUR, Species.SKORUPI, Species.SCRAFTY, Species.CROAGUNK, Species.SCATTERBUG, Species.ESPURR ],
|
[TrainerPoolTier.COMMON]: [ Species.FLETCHLING, Species.LITLEO, Species.PONYTA, Species.INKAY, Species.HOUNDOUR, Species.SKORUPI, Species.SCRAFTY, Species.CROAGUNK, Species.SCATTERBUG, Species.ESPURR ],
|
||||||
[TrainerPoolTier.UNCOMMON]: [ Species.HELIOPTILE, Species.ELECTRIKE, Species.SKRELP, Species.PANCHAM, Species.PURRLOIN, Species.POOCHYENA, Species.BINACLE, Species.CLAUNCHER, Species.PUMPKABOO, Species.PHANTUMP ],
|
[TrainerPoolTier.UNCOMMON]: [ Species.HELIOPTILE, Species.ELECTRIKE, Species.SKRELP, Species.PANCHAM, Species.PURRLOIN, Species.POOCHYENA, Species.BINACLE, Species.CLAUNCHER, Species.PUMPKABOO, Species.PHANTUMP, Species.FOONGUS ],
|
||||||
[TrainerPoolTier.RARE]: [ Species.LITWICK, Species.SNEASEL, Species.PAWNIARD, Species.SLIGGOO ],
|
[TrainerPoolTier.RARE]: [ Species.LITWICK, Species.SNEASEL, Species.PAWNIARD, Species.SLIGGOO ],
|
||||||
[TrainerPoolTier.SUPER_RARE]: [ Species.NOIVERN, Species.HISUI_SLIGGOO, Species.HISUI_AVALUGG ]
|
[TrainerPoolTier.SUPER_RARE]: [ Species.NOIBAT, Species.HISUI_SLIGGOO, Species.HISUI_AVALUGG ]
|
||||||
}),
|
}),
|
||||||
[TrainerType.BRYONY]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("flare_admin_female", "flare", [ Species.LIEPARD ]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_flare_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)),
|
[TrainerType.BRYONY]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("flare_admin_female", "flare", [ Species.LIEPARD ]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_flare_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)),
|
||||||
[TrainerType.XEROSIC]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("flare_admin", "flare", [ Species.MALAMAR ]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_flare_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)),
|
[TrainerType.XEROSIC]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("flare_admin", "flare", [ Species.MALAMAR ]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_flare_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)),
|
||||||
@ -1893,7 +1893,10 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
[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")
|
[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, Species.ALOLA_PERSIAN ]))
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.PERSIAN, Species.ALOLA_PERSIAN ], TrainerSlot.TRAINER, true, p => {
|
||||||
|
p.generateAndPopulateMoveset();
|
||||||
|
p.gender = Gender.MALE;
|
||||||
|
}))
|
||||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.DUGTRIO, Species.ALOLA_DUGTRIO ]))
|
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.DUGTRIO, Species.ALOLA_DUGTRIO ]))
|
||||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.HONCHKROW ]))
|
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.HONCHKROW ]))
|
||||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.NIDOKING, Species.NIDOQUEEN ]))
|
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.NIDOKING, Species.NIDOQUEEN ]))
|
||||||
@ -1945,6 +1948,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
p.formIndex = 1; // Mega Camerupt
|
p.formIndex = 1; // Mega Camerupt
|
||||||
p.generateName();
|
p.generateName();
|
||||||
|
p.gender = Gender.MALE;
|
||||||
})),
|
})),
|
||||||
[TrainerType.MAXIE_2]: new TrainerConfig(++t).setName("Maxie").initForEvilTeamLeader("Magma Boss", [], true).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma")
|
[TrainerType.MAXIE_2]: new TrainerConfig(++t).setName("Maxie").initForEvilTeamLeader("Magma Boss", [], true).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma")
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SOLROCK, Species.TYPHLOSION ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SOLROCK, Species.TYPHLOSION ], TrainerSlot.TRAINER, true, p => {
|
||||||
@ -1967,6 +1971,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
p.formIndex = 1; // Mega Camerupt
|
p.formIndex = 1; // Mega Camerupt
|
||||||
p.generateName();
|
p.generateName();
|
||||||
|
p.gender = Gender.MALE;
|
||||||
}))
|
}))
|
||||||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.GROUDON ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.GROUDON ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
@ -1985,6 +1990,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
p.formIndex = 1; // Mega Sharpedo
|
p.formIndex = 1; // Mega Sharpedo
|
||||||
p.generateName();
|
p.generateName();
|
||||||
|
p.gender = Gender.MALE;
|
||||||
})),
|
})),
|
||||||
[TrainerType.ARCHIE_2]: new TrainerConfig(++t).setName("Archie").initForEvilTeamLeader("Aqua Boss", [], true).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma")
|
[TrainerType.ARCHIE_2]: new TrainerConfig(++t).setName("Archie").initForEvilTeamLeader("Aqua Boss", [], true).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma")
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.EMPOLEON, Species.LUDICOLO ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.EMPOLEON, Species.LUDICOLO ], TrainerSlot.TRAINER, true, p => {
|
||||||
@ -2010,6 +2016,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
p.formIndex = 1; // Mega Sharpedo
|
p.formIndex = 1; // Mega Sharpedo
|
||||||
p.generateName();
|
p.generateName();
|
||||||
|
p.gender = Gender.MALE;
|
||||||
}))
|
}))
|
||||||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.KYOGRE ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.KYOGRE ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
@ -2031,6 +2038,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
|
p.gender = Gender.MALE;
|
||||||
})),
|
})),
|
||||||
[TrainerType.CYRUS_2]: new TrainerConfig(++t).setName("Cyrus").initForEvilTeamLeader("Galactic Boss", [], true).setMixedBattleBgm("battle_galactic_boss").setVictoryBgm("victory_team_plasma")
|
[TrainerType.CYRUS_2]: new TrainerConfig(++t).setName("Cyrus").initForEvilTeamLeader("Galactic Boss", [], true).setMixedBattleBgm("battle_galactic_boss").setVictoryBgm("victory_team_plasma")
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.AZELF, Species.UXIE, Species.MESPRIT ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.AZELF, Species.UXIE, Species.MESPRIT ], TrainerSlot.TRAINER, true, p => {
|
||||||
@ -2049,6 +2057,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
|
p.gender = Gender.MALE;
|
||||||
}))
|
}))
|
||||||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.DARKRAI ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.DARKRAI ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
@ -2065,6 +2074,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
|
p.gender = Gender.MALE;
|
||||||
})),
|
})),
|
||||||
[TrainerType.GHETSIS_2]: new TrainerConfig(++t).setName("Ghetsis").initForEvilTeamLeader("Plasma Boss", [], true).setMixedBattleBgm("battle_plasma_boss").setVictoryBgm("victory_team_plasma")
|
[TrainerType.GHETSIS_2]: new TrainerConfig(++t).setName("Ghetsis").initForEvilTeamLeader("Plasma Boss", [], true).setMixedBattleBgm("battle_plasma_boss").setVictoryBgm("victory_team_plasma")
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GENESECT ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GENESECT ], TrainerSlot.TRAINER, true, p => {
|
||||||
@ -2084,6 +2094,11 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
|
if (p.species.speciesId === Species.HYDREIGON) {
|
||||||
|
p.gender = Gender.MALE;
|
||||||
|
} else if (p.species.speciesId === Species.IRON_JUGULIS) {
|
||||||
|
p.gender = Gender.GENDERLESS;
|
||||||
|
}
|
||||||
}))
|
}))
|
||||||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.KYUREM ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.KYUREM ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
@ -2105,6 +2120,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
p.formIndex = 1; // Mega Gyarados
|
p.formIndex = 1; // Mega Gyarados
|
||||||
p.generateName();
|
p.generateName();
|
||||||
|
p.gender = Gender.MALE;
|
||||||
})),
|
})),
|
||||||
[TrainerType.LYSANDRE_2]: new TrainerConfig(++t).setName("Lysandre").initForEvilTeamLeader("Flare Boss", [], true).setMixedBattleBgm("battle_flare_boss").setVictoryBgm("victory_team_plasma")
|
[TrainerType.LYSANDRE_2]: new TrainerConfig(++t).setName("Lysandre").initForEvilTeamLeader("Flare Boss", [], true).setMixedBattleBgm("battle_flare_boss").setVictoryBgm("victory_team_plasma")
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SCREAM_TAIL, Species.FLUTTER_MANE ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SCREAM_TAIL, Species.FLUTTER_MANE ], TrainerSlot.TRAINER, true, p => {
|
||||||
@ -2124,6 +2140,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
p.formIndex = 1; // Mega Gyardos
|
p.formIndex = 1; // Mega Gyardos
|
||||||
p.generateName();
|
p.generateName();
|
||||||
|
p.gender = Gender.MALE;
|
||||||
}))
|
}))
|
||||||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.YVELTAL ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.YVELTAL ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
@ -2131,7 +2148,10 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.pokeball = PokeballType.MASTER_BALL;
|
p.pokeball = PokeballType.MASTER_BALL;
|
||||||
})),
|
})),
|
||||||
[TrainerType.LUSAMINE]: new TrainerConfig(++t).setName("Lusamine").initForEvilTeamLeader("Aether Boss", []).setMixedBattleBgm("battle_aether_boss").setVictoryBgm("victory_team_plasma")
|
[TrainerType.LUSAMINE]: new TrainerConfig(++t).setName("Lusamine").initForEvilTeamLeader("Aether Boss", []).setMixedBattleBgm("battle_aether_boss").setVictoryBgm("victory_team_plasma")
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.CLEFABLE ]))
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.CLEFABLE ], TrainerSlot.TRAINER, true, p => {
|
||||||
|
p.generateAndPopulateMoveset();
|
||||||
|
p.gender = Gender.FEMALE;
|
||||||
|
}))
|
||||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.LILLIGANT, Species.HISUI_LILLIGANT ]))
|
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.LILLIGANT, Species.HISUI_LILLIGANT ]))
|
||||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.MILOTIC, Species.PRIMARINA ]))
|
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.MILOTIC, Species.PRIMARINA ]))
|
||||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GALAR_SLOWBRO, Species.GALAR_SLOWKING ]))
|
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GALAR_SLOWBRO, Species.GALAR_SLOWKING ]))
|
||||||
@ -2148,7 +2168,10 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.pokeball = PokeballType.ROGUE_BALL;
|
p.pokeball = PokeballType.ROGUE_BALL;
|
||||||
}))
|
}))
|
||||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.MILOTIC, Species.PRIMARINA ]))
|
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.MILOTIC, Species.PRIMARINA ]))
|
||||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.CLEFABLE ]))
|
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.CLEFABLE ], TrainerSlot.TRAINER, true, p => {
|
||||||
|
p.generateAndPopulateMoveset();
|
||||||
|
p.gender = Gender.FEMALE;
|
||||||
|
}))
|
||||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.STAKATAKA, Species.CELESTEELA, Species.GUZZLORD ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.STAKATAKA, Species.CELESTEELA, Species.GUZZLORD ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.pokeball = PokeballType.ROGUE_BALL;
|
p.pokeball = PokeballType.ROGUE_BALL;
|
||||||
@ -2191,6 +2214,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.GOLISOPOD ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.GOLISOPOD ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
|
p.gender = Gender.MALE;
|
||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
})),
|
})),
|
||||||
[TrainerType.GUZMA_2]: new TrainerConfig(++t).setName("Guzma").initForEvilTeamLeader("Skull Boss", [], true).setMixedBattleBgm("battle_skull_boss").setVictoryBgm("victory_team_plasma")
|
[TrainerType.GUZMA_2]: new TrainerConfig(++t).setName("Guzma").initForEvilTeamLeader("Skull Boss", [], true).setMixedBattleBgm("battle_skull_boss").setVictoryBgm("victory_team_plasma")
|
||||||
@ -2198,6 +2222,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.abilityIndex = 2; //Anticipation
|
p.abilityIndex = 2; //Anticipation
|
||||||
|
p.gender = Gender.MALE;
|
||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
}))
|
}))
|
||||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.SCIZOR, Species.KLEAVOR ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.SCIZOR, Species.KLEAVOR ], TrainerSlot.TRAINER, true, p => {
|
||||||
@ -2239,6 +2264,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.formIndex = 1; // G-Max Copperajah
|
p.formIndex = 1; // G-Max Copperajah
|
||||||
p.generateName();
|
p.generateName();
|
||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
|
p.gender = Gender.FEMALE;
|
||||||
})),
|
})),
|
||||||
[TrainerType.ROSE_2]: new TrainerConfig(++t).setName("Rose").initForEvilTeamLeader("Macro Boss", [], true).setMixedBattleBgm("battle_macro_boss").setVictoryBgm("victory_team_plasma")
|
[TrainerType.ROSE_2]: new TrainerConfig(++t).setName("Rose").initForEvilTeamLeader("Macro Boss", [], true).setMixedBattleBgm("battle_macro_boss").setVictoryBgm("victory_team_plasma")
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.ARCHALUDON ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.ARCHALUDON ], TrainerSlot.TRAINER, true, p => {
|
||||||
@ -2262,6 +2288,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.formIndex = 1; // G-Max Copperajah
|
p.formIndex = 1; // G-Max Copperajah
|
||||||
p.generateName();
|
p.generateName();
|
||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
|
p.gender = Gender.FEMALE;
|
||||||
})),
|
})),
|
||||||
[TrainerType.PENNY]: new TrainerConfig(++t).setName("Cassiopeia").initForEvilTeamLeader("Star Boss", []).setMixedBattleBgm("battle_star_boss").setVictoryBgm("victory_team_plasma")
|
[TrainerType.PENNY]: new TrainerConfig(++t).setName("Cassiopeia").initForEvilTeamLeader("Star Boss", []).setMixedBattleBgm("battle_star_boss").setVictoryBgm("victory_team_plasma")
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.VAPOREON, Species.JOLTEON, Species.FLAREON ]))
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.VAPOREON, Species.JOLTEON, Species.FLAREON ]))
|
||||||
@ -2275,8 +2302,9 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.formIndex = Utils.randSeedInt(5, 1); // Heat, Wash, Frost, Fan, or Mow
|
p.formIndex = Utils.randSeedInt(5, 1); // Heat, Wash, Frost, Fan, or Mow
|
||||||
}))
|
}))
|
||||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.SYLVEON ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.SYLVEON ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.generateAndPopulateMoveset();
|
|
||||||
p.abilityIndex = 2; // Pixilate
|
p.abilityIndex = 2; // Pixilate
|
||||||
|
p.generateAndPopulateMoveset();
|
||||||
|
p.gender = Gender.FEMALE;
|
||||||
}))
|
}))
|
||||||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.EEVEE ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.EEVEE ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
@ -2290,20 +2318,21 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ]; //TODO: is the bang correct?
|
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ]; //TODO: is the bang correct?
|
||||||
}),
|
}),
|
||||||
[TrainerType.PENNY_2]: new TrainerConfig(++t).setName("Cassiopeia").initForEvilTeamLeader("Star Boss", [], true).setMixedBattleBgm("battle_star_boss").setVictoryBgm("victory_team_plasma")
|
[TrainerType.PENNY_2]: new TrainerConfig(++t).setName("Cassiopeia").initForEvilTeamLeader("Star Boss", [], true).setMixedBattleBgm("battle_star_boss").setVictoryBgm("victory_team_plasma")
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.REVAVROOM ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SYLVEON ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
p.formIndex = Utils.randSeedInt(5, 1); //Random Starmobile form
|
p.abilityIndex = 2; // Pixilate
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.gender = Gender.FEMALE;
|
||||||
}))
|
}))
|
||||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.ENTEI, Species.RAIKOU, Species.SUICUNE ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.ENTEI, Species.RAIKOU, Species.SUICUNE ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
}))
|
}))
|
||||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.WALKING_WAKE, Species.GOUGING_FIRE, Species.RAGING_BOLT ]))
|
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.WALKING_WAKE, Species.GOUGING_FIRE, Species.RAGING_BOLT ]))
|
||||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.SYLVEON ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.REVAVROOM ], TrainerSlot.TRAINER, true, p => {
|
||||||
|
p.formIndex = Utils.randSeedInt(5, 1); //Random Starmobile form
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.abilityIndex = 2; // Pixilate
|
p.pokeball = PokeballType.ROGUE_BALL;
|
||||||
}))
|
}))
|
||||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.EEVEE ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.EEVEE ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
@ -2318,7 +2347,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.pokeball = PokeballType.MASTER_BALL;
|
p.pokeball = PokeballType.MASTER_BALL;
|
||||||
}))
|
}))
|
||||||
.setGenModifiersFunc(party => {
|
.setGenModifiersFunc(party => {
|
||||||
const teraPokemon = party[3];
|
const teraPokemon = party[0];
|
||||||
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ]; //TODO: is the bang correct?
|
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ]; //TODO: is the bang correct?
|
||||||
}),
|
}),
|
||||||
[TrainerType.BUCK]: new TrainerConfig(++t).setName("Buck").initForStatTrainer([], true)
|
[TrainerType.BUCK]: new TrainerConfig(++t).setName("Buck").initForStatTrainer([], true)
|
||||||
|
@ -80,6 +80,7 @@ export enum BattlerTagType {
|
|||||||
DOUBLE_SHOCKED = "DOUBLE_SHOCKED",
|
DOUBLE_SHOCKED = "DOUBLE_SHOCKED",
|
||||||
AUTOTOMIZED = "AUTOTOMIZED",
|
AUTOTOMIZED = "AUTOTOMIZED",
|
||||||
MYSTERY_ENCOUNTER_POST_SUMMON = "MYSTERY_ENCOUNTER_POST_SUMMON",
|
MYSTERY_ENCOUNTER_POST_SUMMON = "MYSTERY_ENCOUNTER_POST_SUMMON",
|
||||||
|
POWER_TRICK = "POWER_TRICK",
|
||||||
HEAL_BLOCK = "HEAL_BLOCK",
|
HEAL_BLOCK = "HEAL_BLOCK",
|
||||||
TORMENT = "TORMENT",
|
TORMENT = "TORMENT",
|
||||||
TAUNT = "TAUNT",
|
TAUNT = "TAUNT",
|
||||||
|
@ -19,7 +19,7 @@ import { initMoveAnim, loadMoveAnimAssets } from "#app/data/battle-anims";
|
|||||||
import { Status, StatusEffect, getRandomStatus } from "#app/data/status-effect";
|
import { Status, StatusEffect, getRandomStatus } from "#app/data/status-effect";
|
||||||
import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEvolutionCondition, FusionSpeciesFormEvolution } from "#app/data/balance/pokemon-evolutions";
|
import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEvolutionCondition, FusionSpeciesFormEvolution } from "#app/data/balance/pokemon-evolutions";
|
||||||
import { reverseCompatibleTms, tmSpecies, tmPoolTiers } from "#app/data/balance/tms";
|
import { reverseCompatibleTms, tmSpecies, tmPoolTiers } from "#app/data/balance/tms";
|
||||||
import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, SubstituteTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag, MoveRestrictionBattlerTag, ExposedTag, DragonCheerTag, CritBoostTag, TrappedTag, TarShotTag, AutotomizedTag } from "../data/battler-tags";
|
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 "#app/data/weather";
|
import { WeatherType } from "#app/data/weather";
|
||||||
import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "#app/data/arena-tag";
|
import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "#app/data/arena-tag";
|
||||||
import { Ability, AbAttr, StatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatStagesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, 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 } from "#app/data/ability";
|
import { Ability, AbAttr, StatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatStagesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, 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 } from "#app/data/ability";
|
||||||
@ -3048,6 +3048,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tag instanceof PowerTrickTag) {
|
||||||
|
tag.swapStat(this);
|
||||||
|
}
|
||||||
|
|
||||||
this.summonData.tags.push(tag);
|
this.summonData.tags.push(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3062,8 +3066,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
*
|
*
|
||||||
* @see {@linkcode MoveRestrictionBattlerTag}
|
* @see {@linkcode MoveRestrictionBattlerTag}
|
||||||
*/
|
*/
|
||||||
isMoveRestricted(moveId: Moves): boolean {
|
public isMoveRestricted(moveId: Moves, pokemon?: Pokemon): boolean {
|
||||||
return this.getRestrictingTag(moveId) !== null;
|
return this.getRestrictingTag(moveId, pokemon) !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -3096,7 +3100,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
*/
|
*/
|
||||||
getRestrictingTag(moveId: Moves, user?: Pokemon, target?: Pokemon): MoveRestrictionBattlerTag | null {
|
getRestrictingTag(moveId: Moves, user?: Pokemon, target?: Pokemon): MoveRestrictionBattlerTag | null {
|
||||||
for (const tag of this.findTags(t => t instanceof MoveRestrictionBattlerTag)) {
|
for (const tag of this.findTags(t => t instanceof MoveRestrictionBattlerTag)) {
|
||||||
if ((tag as MoveRestrictionBattlerTag).isMoveRestricted(moveId)) {
|
if ((tag as MoveRestrictionBattlerTag).isMoveRestricted(moveId, user)) {
|
||||||
return tag as MoveRestrictionBattlerTag;
|
return tag as MoveRestrictionBattlerTag;
|
||||||
} else if (user && target && (tag as MoveRestrictionBattlerTag).isMoveTargetRestricted(moveId, user, target)) {
|
} else if (user && target && (tag as MoveRestrictionBattlerTag).isMoveTargetRestricted(moveId, user, target)) {
|
||||||
return tag as MoveRestrictionBattlerTag;
|
return tag as MoveRestrictionBattlerTag;
|
||||||
@ -5139,7 +5143,7 @@ export class PokemonMove {
|
|||||||
* @returns `true` if the move can be selected and used by the Pokemon, otherwise `false`.
|
* @returns `true` if the move can be selected and used by the Pokemon, otherwise `false`.
|
||||||
*/
|
*/
|
||||||
isUsable(pokemon: Pokemon, ignorePp: boolean = false, ignoreRestrictionTags: boolean = false): boolean {
|
isUsable(pokemon: Pokemon, ignorePp: boolean = false, ignoreRestrictionTags: boolean = false): boolean {
|
||||||
if (this.moveId && !ignoreRestrictionTags && pokemon.isMoveRestricted(this.moveId)) {
|
if (this.moveId && !ignoreRestrictionTags && pokemon.isMoveRestricted(this.moveId, pokemon)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,7 +383,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
|||||||
const battle = this.scene.currentBattle;
|
const battle = this.scene.currentBattle;
|
||||||
const template = this.getPartyTemplate();
|
const template = this.getPartyTemplate();
|
||||||
|
|
||||||
let species: PokemonSpecies;
|
let baseSpecies: PokemonSpecies;
|
||||||
if (this.config.speciesPools) {
|
if (this.config.speciesPools) {
|
||||||
const tierValue = Utils.randSeedInt(512);
|
const tierValue = Utils.randSeedInt(512);
|
||||||
let tier = tierValue >= 156 ? TrainerPoolTier.COMMON : tierValue >= 32 ? TrainerPoolTier.UNCOMMON : tierValue >= 6 ? TrainerPoolTier.RARE : tierValue >= 1 ? TrainerPoolTier.SUPER_RARE : TrainerPoolTier.ULTRA_RARE;
|
let tier = tierValue >= 156 ? TrainerPoolTier.COMMON : tierValue >= 32 ? TrainerPoolTier.UNCOMMON : tierValue >= 6 ? TrainerPoolTier.RARE : tierValue >= 1 ? TrainerPoolTier.SUPER_RARE : TrainerPoolTier.ULTRA_RARE;
|
||||||
@ -393,17 +393,17 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
|||||||
tier--;
|
tier--;
|
||||||
}
|
}
|
||||||
const tierPool = this.config.speciesPools[tier];
|
const tierPool = this.config.speciesPools[tier];
|
||||||
species = getPokemonSpecies(Utils.randSeedItem(tierPool));
|
baseSpecies = getPokemonSpecies(Utils.randSeedItem(tierPool));
|
||||||
} else {
|
} else {
|
||||||
species = this.scene.randomSpecies(battle.waveIndex, level, false, this.config.speciesFilter);
|
baseSpecies = this.scene.randomSpecies(battle.waveIndex, level, false, this.config.speciesFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ret = getPokemonSpecies(species.getTrainerSpeciesForLevel(level, true, strength, this.scene.currentBattle.waveIndex));
|
let ret = getPokemonSpecies(baseSpecies.getTrainerSpeciesForLevel(level, true, strength, this.scene.currentBattle.waveIndex));
|
||||||
let retry = false;
|
let retry = false;
|
||||||
|
|
||||||
console.log(ret.getName());
|
console.log(ret.getName());
|
||||||
|
|
||||||
if (pokemonPrevolutions.hasOwnProperty(species.speciesId) && ret.speciesId !== species.speciesId) {
|
if (pokemonPrevolutions.hasOwnProperty(baseSpecies.speciesId) && ret.speciesId !== baseSpecies.speciesId) {
|
||||||
retry = true;
|
retry = true;
|
||||||
} else if (template.isBalanced(battle.enemyParty.length)) {
|
} else if (template.isBalanced(battle.enemyParty.length)) {
|
||||||
const partyMemberTypes = battle.enemyParty.map(p => p.getTypes(true)).flat();
|
const partyMemberTypes = battle.enemyParty.map(p => p.getTypes(true)).flat();
|
||||||
@ -417,7 +417,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
|||||||
console.log("Attempting reroll of species evolution to fit specialty type...");
|
console.log("Attempting reroll of species evolution to fit specialty type...");
|
||||||
let evoAttempt = 0;
|
let evoAttempt = 0;
|
||||||
while (retry && evoAttempt++ < 10) {
|
while (retry && evoAttempt++ < 10) {
|
||||||
ret = getPokemonSpecies(species.getTrainerSpeciesForLevel(level, true, strength, this.scene.currentBattle.waveIndex));
|
ret = getPokemonSpecies(baseSpecies.getTrainerSpeciesForLevel(level, true, strength, this.scene.currentBattle.waveIndex));
|
||||||
console.log(ret.name);
|
console.log(ret.name);
|
||||||
if (this.config.specialtyTypes.find(t => ret.isOfType(t))) {
|
if (this.config.specialtyTypes.find(t => ret.isOfType(t))) {
|
||||||
retry = false;
|
retry = false;
|
||||||
@ -426,7 +426,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Prompts reroll of party member species if species already present in the enemy party
|
// Prompts reroll of party member species if species already present in the enemy party
|
||||||
if (this.checkDuplicateSpecies(ret)) {
|
if (this.checkDuplicateSpecies(ret, baseSpecies)) {
|
||||||
console.log("Duplicate species detected, prompting reroll...");
|
console.log("Duplicate species detected, prompting reroll...");
|
||||||
retry = true;
|
retry = true;
|
||||||
}
|
}
|
||||||
@ -442,13 +442,16 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
|||||||
/**
|
/**
|
||||||
* Checks if the enemy trainer already has the Pokemon species in their party
|
* Checks if the enemy trainer already has the Pokemon species in their party
|
||||||
* @param {PokemonSpecies} species {@linkcode PokemonSpecies}
|
* @param {PokemonSpecies} species {@linkcode PokemonSpecies}
|
||||||
|
* @param {PokemonSpecies} baseSpecies {@linkcode PokemonSpecies} - baseSpecies of the Pokemon if species is forced to evolve
|
||||||
* @returns `true` if the species is already present in the party
|
* @returns `true` if the species is already present in the party
|
||||||
*/
|
*/
|
||||||
checkDuplicateSpecies(species: PokemonSpecies): boolean {
|
checkDuplicateSpecies(species: PokemonSpecies, baseSpecies: PokemonSpecies): boolean {
|
||||||
|
const staticPartyPokemon = (signatureSpecies[TrainerType[this.config.trainerType]] ?? []).flat(1);
|
||||||
|
|
||||||
const currentPartySpecies = this.scene.getEnemyParty().map(p => {
|
const currentPartySpecies = this.scene.getEnemyParty().map(p => {
|
||||||
return p.species.speciesId;
|
return p.species.speciesId;
|
||||||
});
|
});
|
||||||
return currentPartySpecies.includes(species.speciesId);
|
return currentPartySpecies.includes(species.speciesId) || staticPartyPokemon.includes(baseSpecies.speciesId);
|
||||||
}
|
}
|
||||||
|
|
||||||
getPartyMemberMatchupScores(trainerSlot: TrainerSlot = TrainerSlot.NONE, forSwitch: boolean = false): [integer, integer][] {
|
getPartyMemberMatchupScores(trainerSlot: TrainerSlot = TrainerSlot.NONE, forSwitch: boolean = false): [integer, integer][] {
|
||||||
|
@ -114,8 +114,8 @@ export class CommandPhase extends FieldPhase {
|
|||||||
|
|
||||||
// Decides between a Disabled, Not Implemented, or No PP translation message
|
// Decides between a Disabled, Not Implemented, or No PP translation message
|
||||||
const errorMessage =
|
const errorMessage =
|
||||||
playerPokemon.isMoveRestricted(move.moveId)
|
playerPokemon.isMoveRestricted(move.moveId, playerPokemon)
|
||||||
? playerPokemon.getRestrictingTag(move.moveId)!.selectionDeniedText(playerPokemon, move.moveId)
|
? playerPokemon.getRestrictingTag(move.moveId, playerPokemon)!.selectionDeniedText(playerPokemon, move.moveId)
|
||||||
: move.getName().endsWith(" (N)") ? "battle:moveNotImplemented" : "battle:moveNoPP";
|
: move.getName().endsWith(" (N)") ? "battle:moveNotImplemented" : "battle:moveNoPP";
|
||||||
const moveName = move.getName().replace(" (N)", ""); // Trims off the indicator
|
const moveName = move.getName().replace(" (N)", ""); // Trims off the indicator
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ export class EggLapsePhase extends Phase {
|
|||||||
if (eggsToHatchCount > 0) {
|
if (eggsToHatchCount > 0) {
|
||||||
if (eggsToHatchCount >= this.minEggsToSkip && this.scene.eggSkipPreference === 1) {
|
if (eggsToHatchCount >= this.minEggsToSkip && this.scene.eggSkipPreference === 1) {
|
||||||
this.scene.ui.showText(i18next.t("battle:eggHatching"), 0, () => {
|
this.scene.ui.showText(i18next.t("battle:eggHatching"), 0, () => {
|
||||||
// show prompt for skip
|
// show prompt for skip, blocking inputs for 1 second
|
||||||
this.scene.ui.showText(i18next.t("battle:eggSkipPrompt"), 0);
|
this.scene.ui.showText(i18next.t("battle:eggSkipPrompt"), 0);
|
||||||
this.scene.ui.setModeWithoutClear(Mode.CONFIRM, () => {
|
this.scene.ui.setModeWithoutClear(Mode.CONFIRM, () => {
|
||||||
this.hatchEggsSkipped(eggsToHatch);
|
this.hatchEggsSkipped(eggsToHatch);
|
||||||
@ -41,7 +41,8 @@ export class EggLapsePhase extends Phase {
|
|||||||
}, () => {
|
}, () => {
|
||||||
this.hatchEggsRegular(eggsToHatch);
|
this.hatchEggsRegular(eggsToHatch);
|
||||||
this.end();
|
this.end();
|
||||||
}
|
},
|
||||||
|
null, null, null, 1000, true
|
||||||
);
|
);
|
||||||
}, 100, true);
|
}, 100, true);
|
||||||
} else if (eggsToHatchCount >= this.minEggsToSkip && this.scene.eggSkipPreference === 2) {
|
} else if (eggsToHatchCount >= this.minEggsToSkip && this.scene.eggSkipPreference === 2) {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import BattleScene from "#app/battle-scene";
|
import BattleScene from "#app/battle-scene";
|
||||||
import { Phase } from "#app/phase";
|
import { Phase } from "#app/phase";
|
||||||
import { Mode } from "#app/ui/ui";
|
import { Mode } from "#app/ui/ui";
|
||||||
import EggHatchSceneHandler from "#app/ui/egg-hatch-scene-handler";
|
|
||||||
import { EggHatchData } from "#app/data/egg-hatch-data";
|
import { EggHatchData } from "#app/data/egg-hatch-data";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -11,7 +10,6 @@ import { EggHatchData } from "#app/data/egg-hatch-data";
|
|||||||
*/
|
*/
|
||||||
export class EggSummaryPhase extends Phase {
|
export class EggSummaryPhase extends Phase {
|
||||||
private eggHatchData: EggHatchData[];
|
private eggHatchData: EggHatchData[];
|
||||||
private eggHatchHandler: EggHatchSceneHandler;
|
|
||||||
|
|
||||||
constructor(scene: BattleScene, eggHatchData: EggHatchData[]) {
|
constructor(scene: BattleScene, eggHatchData: EggHatchData[]) {
|
||||||
super(scene);
|
super(scene);
|
||||||
@ -26,7 +24,6 @@ export class EggSummaryPhase extends Phase {
|
|||||||
if (i >= this.eggHatchData.length) {
|
if (i >= this.eggHatchData.length) {
|
||||||
this.scene.ui.setModeForceTransition(Mode.EGG_HATCH_SUMMARY, this.eggHatchData).then(() => {
|
this.scene.ui.setModeForceTransition(Mode.EGG_HATCH_SUMMARY, this.eggHatchData).then(() => {
|
||||||
this.scene.fadeOutBgm(undefined, false);
|
this.scene.fadeOutBgm(undefined, false);
|
||||||
this.eggHatchHandler = this.scene.ui.getHandler() as EggHatchSceneHandler;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -129,7 +129,9 @@ export class MovePhase extends BattlePhase {
|
|||||||
|
|
||||||
this.lapsePreMoveAndMoveTags();
|
this.lapsePreMoveAndMoveTags();
|
||||||
|
|
||||||
this.resolveFinalPreMoveCancellationChecks();
|
if (!(this.failed || this.cancelled)) {
|
||||||
|
this.resolveFinalPreMoveCancellationChecks();
|
||||||
|
}
|
||||||
|
|
||||||
if (this.cancelled || this.failed) {
|
if (this.cancelled || this.failed) {
|
||||||
this.handlePreMoveFailures();
|
this.handlePreMoveFailures();
|
||||||
|
@ -139,4 +139,58 @@ describe("Moves - Dragon Tail", () => {
|
|||||||
|
|
||||||
expect(enemy.isFullHp()).toBe(false);
|
expect(enemy.isFullHp()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should force a switch upon fainting an opponent normally", async () => {
|
||||||
|
game.override.startingWave(5)
|
||||||
|
.startingLevel(1000); // To make sure Dragon Tail KO's the opponent
|
||||||
|
await game.classicMode.startBattle([ Species.DRATINI ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.DRAGON_TAIL);
|
||||||
|
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
// Make sure the enemy switched to a healthy Pokemon
|
||||||
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
|
expect(enemy).toBeDefined();
|
||||||
|
expect(enemy.isFullHp()).toBe(true);
|
||||||
|
|
||||||
|
// Make sure the enemy has a fainted Pokemon in their party and not on the field
|
||||||
|
const faintedEnemy = game.scene.getEnemyParty().find(p => !p.isAllowedInBattle());
|
||||||
|
expect(faintedEnemy).toBeDefined();
|
||||||
|
expect(game.scene.getEnemyField().length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not cause a softlock when activating an opponent trainer's reviver seed", async () => {
|
||||||
|
game.override.startingWave(5)
|
||||||
|
.enemyHeldItems([{ name: "REVIVER_SEED" }])
|
||||||
|
.startingLevel(1000); // To make sure Dragon Tail KO's the opponent
|
||||||
|
await game.classicMode.startBattle([ Species.DRATINI ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.DRAGON_TAIL);
|
||||||
|
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
// Make sure the enemy field is not empty and has a revived Pokemon
|
||||||
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
|
expect(enemy).toBeDefined();
|
||||||
|
expect(enemy.hp).toBe(Math.floor(enemy.getMaxHp() / 2));
|
||||||
|
expect(game.scene.getEnemyField().length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not cause a softlock when activating a player's reviver seed", async () => {
|
||||||
|
game.override.startingHeldItems([{ name: "REVIVER_SEED" }])
|
||||||
|
.enemyMoveset(Moves.DRAGON_TAIL)
|
||||||
|
.enemyLevel(1000); // To make sure Dragon Tail KO's the player
|
||||||
|
await game.classicMode.startBattle([ Species.DRATINI, Species.BULBASAUR ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
// Make sure the player's field is not empty and has a revived Pokemon
|
||||||
|
const dratini = game.scene.getPlayerPokemon()!;
|
||||||
|
expect(dratini).toBeDefined();
|
||||||
|
expect(dratini.hp).toBe(Math.floor(dratini.getMaxHp() / 2));
|
||||||
|
expect(game.scene.getPlayerField().length).toBe(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
113
src/test/moves/power_trick.test.ts
Normal file
113
src/test/moves/power_trick.test.ts
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import GameManager from "#app/test/utils/gameManager";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Stat } from "#enums/stat";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import { TurnEndPhase } from "#app/phases/turn-end-phase";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
|
|
||||||
|
describe("Moves - Power Trick", () => {
|
||||||
|
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
|
||||||
|
.battleType("single")
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset(Moves.SPLASH)
|
||||||
|
.enemySpecies(Species.MEW)
|
||||||
|
.enemyLevel(200)
|
||||||
|
.moveset([ Moves.POWER_TRICK ])
|
||||||
|
.ability(Abilities.BALL_FETCH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("swaps the user's ATK and DEF stats", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.SHUCKLE ]);
|
||||||
|
|
||||||
|
const player = game.scene.getPlayerPokemon()!;
|
||||||
|
const baseATK = player.getStat(Stat.ATK, false);
|
||||||
|
const baseDEF = player.getStat(Stat.DEF, false);
|
||||||
|
|
||||||
|
game.move.select(Moves.POWER_TRICK);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to(TurnEndPhase);
|
||||||
|
|
||||||
|
expect(player.getStat(Stat.ATK, false)).toBe(baseDEF);
|
||||||
|
expect(player.getStat(Stat.DEF, false)).toBe(baseATK);
|
||||||
|
expect(player.getTag(BattlerTagType.POWER_TRICK)).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("resets initial ATK and DEF stat swap when used consecutively", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.SHUCKLE ]);
|
||||||
|
|
||||||
|
const player = game.scene.getPlayerPokemon()!;
|
||||||
|
const baseATK = player.getStat(Stat.ATK, false);
|
||||||
|
const baseDEF = player.getStat(Stat.DEF, false);
|
||||||
|
|
||||||
|
game.move.select(Moves.POWER_TRICK);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to(TurnEndPhase);
|
||||||
|
|
||||||
|
game.move.select(Moves.POWER_TRICK);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to(TurnEndPhase);
|
||||||
|
|
||||||
|
expect(player.getStat(Stat.ATK, false)).toBe(baseATK);
|
||||||
|
expect(player.getStat(Stat.DEF, false)).toBe(baseDEF);
|
||||||
|
expect(player.getTag(BattlerTagType.POWER_TRICK)).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should pass effect when using BATON_PASS", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.SHUCKLE, Species.SHUCKLE ]);
|
||||||
|
await game.override.moveset([ Moves.POWER_TRICK, Moves.BATON_PASS ]);
|
||||||
|
|
||||||
|
const player = game.scene.getPlayerPokemon()!;
|
||||||
|
player.addTag(BattlerTagType.POWER_TRICK);
|
||||||
|
|
||||||
|
game.move.select(Moves.BATON_PASS);
|
||||||
|
game.doSelectPartyPokemon(1);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to(TurnEndPhase);
|
||||||
|
|
||||||
|
const switchedPlayer = game.scene.getPlayerPokemon()!;
|
||||||
|
const baseATK = switchedPlayer.getStat(Stat.ATK);
|
||||||
|
const baseDEF = switchedPlayer.getStat(Stat.DEF);
|
||||||
|
|
||||||
|
expect(switchedPlayer.getStat(Stat.ATK, false)).toBe(baseDEF);
|
||||||
|
expect(switchedPlayer.getStat(Stat.DEF, false)).toBe(baseATK);
|
||||||
|
expect(switchedPlayer.getTag(BattlerTagType.POWER_TRICK)).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should remove effect after using Transform", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.SHUCKLE, Species.SHUCKLE ]);
|
||||||
|
await game.override.moveset([ Moves.POWER_TRICK, Moves.TRANSFORM ]);
|
||||||
|
|
||||||
|
const player = game.scene.getPlayerPokemon()!;
|
||||||
|
player.addTag(BattlerTagType.POWER_TRICK);
|
||||||
|
|
||||||
|
game.move.select(Moves.TRANSFORM);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to(TurnEndPhase);
|
||||||
|
|
||||||
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
|
const baseATK = enemy.getStat(Stat.ATK);
|
||||||
|
const baseDEF = enemy.getStat(Stat.DEF);
|
||||||
|
|
||||||
|
expect(player.getStat(Stat.ATK, false)).toBe(baseATK);
|
||||||
|
expect(player.getStat(Stat.DEF, false)).toBe(baseDEF);
|
||||||
|
expect(player.getTag(BattlerTagType.POWER_TRICK)).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
@ -96,4 +96,23 @@ describe("Moves - U-turn", () => {
|
|||||||
expect(game.scene.getEnemyPokemon()!.battleData.abilityRevealed).toBe(true); // proxy for asserting ability activated
|
expect(game.scene.getEnemyPokemon()!.battleData.abilityRevealed).toBe(true); // proxy for asserting ability activated
|
||||||
expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase");
|
expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase");
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
|
it("still forces a switch if u-turn KO's the opponent", async () => {
|
||||||
|
game.override.startingLevel(1000); // Ensure that U-Turn KO's the opponent
|
||||||
|
await game.classicMode.startBattle([
|
||||||
|
Species.RAICHU,
|
||||||
|
Species.SHUCKLE
|
||||||
|
]);
|
||||||
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
// KO the opponent with U-Turn
|
||||||
|
game.move.select(Moves.U_TURN);
|
||||||
|
game.doSelectPartyPokemon(1);
|
||||||
|
await game.phaseInterceptor.to(TurnEndPhase);
|
||||||
|
expect(enemy.isFainted()).toBe(true);
|
||||||
|
|
||||||
|
// Check that U-Turn forced a switch
|
||||||
|
expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase");
|
||||||
|
expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.SHUCKLE);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -165,6 +165,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
|
|||||||
if (this.config.delay) {
|
if (this.config.delay) {
|
||||||
this.blockInput = true;
|
this.blockInput = true;
|
||||||
this.optionSelectText.setAlpha(0.5);
|
this.optionSelectText.setAlpha(0.5);
|
||||||
|
this.cursorObj?.setAlpha(0.8);
|
||||||
this.scene.time.delayedCall(Utils.fixedInt(this.config.delay), () => this.unblockInput());
|
this.scene.time.delayedCall(Utils.fixedInt(this.config.delay), () => this.unblockInput());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,6 +257,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
|
|||||||
|
|
||||||
this.blockInput = false;
|
this.blockInput = false;
|
||||||
this.optionSelectText.setAlpha(1);
|
this.optionSelectText.setAlpha(1);
|
||||||
|
this.cursorObj?.setAlpha(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
getOptionsWithScroll(): OptionSelectItem[] {
|
getOptionsWithScroll(): OptionSelectItem[] {
|
||||||
|
@ -76,7 +76,8 @@ export default class ConfirmUiHandler extends AbstractOptionSelectUiHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
delay: args.length >= 6 && args[5] !== null ? args[5] as integer : 0
|
delay: args.length >= 6 && args[5] !== null ? args[5] as number : 0,
|
||||||
|
noCancel: args.length >= 7 && args[6] !== null ? args[6] as boolean : false,
|
||||||
};
|
};
|
||||||
|
|
||||||
super.show([ config ]);
|
super.show([ config ]);
|
||||||
@ -96,7 +97,7 @@ export default class ConfirmUiHandler extends AbstractOptionSelectUiHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
processInput(button: Button): boolean {
|
processInput(button: Button): boolean {
|
||||||
if (button === Button.CANCEL && this.blockInput) {
|
if (button === Button.CANCEL && this.blockInput && !this.config?.noCancel) {
|
||||||
this.unblockInput();
|
this.unblockInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,9 @@ export default class EggSummaryUiHandler extends MessageUiHandler {
|
|||||||
private scrollGridHandler : ScrollableGridUiHandler;
|
private scrollGridHandler : ScrollableGridUiHandler;
|
||||||
private cursorObj: Phaser.GameObjects.Image;
|
private cursorObj: Phaser.GameObjects.Image;
|
||||||
|
|
||||||
|
/** used to add a delay before which it is not possible to exit the summary */
|
||||||
|
private blockExit: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows subscribers to listen for events
|
* Allows subscribers to listen for events
|
||||||
*
|
*
|
||||||
@ -168,6 +171,13 @@ export default class EggSummaryUiHandler extends MessageUiHandler {
|
|||||||
this.setCursor(0);
|
this.setCursor(0);
|
||||||
|
|
||||||
this.scene.playSoundWithoutBgm("evolution_fanfare");
|
this.scene.playSoundWithoutBgm("evolution_fanfare");
|
||||||
|
|
||||||
|
// Prevent exiting the egg summary for 2 seconds if the egg hatching
|
||||||
|
// was skipped automatically and for 1 second otherwise
|
||||||
|
const exitBlockingDuration = (this.scene.eggSkipPreference === 2) ? 2000 : 1000;
|
||||||
|
this.blockExit = true;
|
||||||
|
this.scene.time.delayedCall(exitBlockingDuration, () => this.blockExit = false);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,13 +213,17 @@ export default class EggSummaryUiHandler extends MessageUiHandler {
|
|||||||
const ui = this.getUi();
|
const ui = this.getUi();
|
||||||
|
|
||||||
let success = false;
|
let success = false;
|
||||||
const error = false;
|
let error = false;
|
||||||
if (button === Button.CANCEL) {
|
if (button === Button.CANCEL) {
|
||||||
const phase = this.scene.getCurrentPhase();
|
if (!this.blockExit) {
|
||||||
if (phase instanceof EggSummaryPhase) {
|
const phase = this.scene.getCurrentPhase();
|
||||||
phase.end();
|
if (phase instanceof EggSummaryPhase) {
|
||||||
|
phase.end();
|
||||||
|
}
|
||||||
|
success = true;
|
||||||
|
} else {
|
||||||
|
error = true;
|
||||||
}
|
}
|
||||||
success = true;
|
|
||||||
} else {
|
} else {
|
||||||
this.scrollGridHandler.processInput(button);
|
this.scrollGridHandler.processInput(button);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user