mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-19 22:09:27 +02:00
Compare commits
3 Commits
0fedc971b5
...
0afc4e5fe0
Author | SHA1 | Date | |
---|---|---|---|
|
0afc4e5fe0 | ||
|
0da37a0f0c | ||
|
05584be564 |
@ -81,7 +81,7 @@ For example, here is how you could test a scenario where the player Pokemon has
|
|||||||
```typescript
|
```typescript
|
||||||
const overrides = {
|
const overrides = {
|
||||||
ABILITY_OVERRIDE: AbilityId.DROUGHT,
|
ABILITY_OVERRIDE: AbilityId.DROUGHT,
|
||||||
OPP_MOVESET_OVERRIDE: MoveId.WATER_GUN,
|
ENEMY_MOVESET_OVERRIDE: MoveId.WATER_GUN,
|
||||||
} satisfies Partial<InstanceType<typeof DefaultOverrides>>;
|
} satisfies Partial<InstanceType<typeof DefaultOverrides>>;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1,13 +1,24 @@
|
|||||||
|
import type { Pokemon } from "#field/pokemon";
|
||||||
import type {
|
import type {
|
||||||
AttackMove,
|
AttackMove,
|
||||||
ChargingAttackMove,
|
ChargingAttackMove,
|
||||||
ChargingSelfStatusMove,
|
ChargingSelfStatusMove,
|
||||||
|
Move,
|
||||||
MoveAttr,
|
MoveAttr,
|
||||||
MoveAttrConstructorMap,
|
MoveAttrConstructorMap,
|
||||||
SelfStatusMove,
|
SelfStatusMove,
|
||||||
StatusMove,
|
StatusMove,
|
||||||
} from "#moves/move";
|
} from "#moves/move";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A generic function producing a message during a Move's execution.
|
||||||
|
* @param user - The {@linkcode Pokemon} using the move
|
||||||
|
* @param target - The {@linkcode Pokemon} targeted by the move
|
||||||
|
* @param move - The {@linkcode Move} being used
|
||||||
|
* @returns a string
|
||||||
|
*/
|
||||||
|
export type MoveMessageFunc = (user: Pokemon, target: Pokemon, move: Move) => string;
|
||||||
|
|
||||||
export type MoveAttrFilter = (attr: MoveAttr) => boolean;
|
export type MoveAttrFilter = (attr: MoveAttr) => boolean;
|
||||||
|
|
||||||
export type * from "#moves/move";
|
export type * from "#moves/move";
|
||||||
|
@ -943,17 +943,17 @@ export class BattleScene extends SceneBase {
|
|||||||
dataSource?: PokemonData,
|
dataSource?: PokemonData,
|
||||||
postProcess?: (enemyPokemon: EnemyPokemon) => void,
|
postProcess?: (enemyPokemon: EnemyPokemon) => void,
|
||||||
): EnemyPokemon {
|
): EnemyPokemon {
|
||||||
if (Overrides.OPP_LEVEL_OVERRIDE > 0) {
|
if (Overrides.ENEMY_LEVEL_OVERRIDE > 0) {
|
||||||
level = Overrides.OPP_LEVEL_OVERRIDE;
|
level = Overrides.ENEMY_LEVEL_OVERRIDE;
|
||||||
}
|
}
|
||||||
if (Overrides.OPP_SPECIES_OVERRIDE) {
|
if (Overrides.ENEMY_SPECIES_OVERRIDE) {
|
||||||
species = getPokemonSpecies(Overrides.OPP_SPECIES_OVERRIDE);
|
species = getPokemonSpecies(Overrides.ENEMY_SPECIES_OVERRIDE);
|
||||||
// The fact that a Pokemon is a boss or not can change based on its Species and level
|
// The fact that a Pokemon is a boss or not can change based on its Species and level
|
||||||
boss = this.getEncounterBossSegments(this.currentBattle.waveIndex, level, species) > 1;
|
boss = this.getEncounterBossSegments(this.currentBattle.waveIndex, level, species) > 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pokemon = new EnemyPokemon(species, level, trainerSlot, boss, shinyLock, dataSource);
|
const pokemon = new EnemyPokemon(species, level, trainerSlot, boss, shinyLock, dataSource);
|
||||||
if (Overrides.OPP_FUSION_OVERRIDE) {
|
if (Overrides.ENEMY_FUSION_OVERRIDE) {
|
||||||
pokemon.generateFusionSpecies();
|
pokemon.generateFusionSpecies();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1764,10 +1764,10 @@ export class BattleScene extends SceneBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getEncounterBossSegments(waveIndex: number, level: number, species?: PokemonSpecies, forceBoss = false): number {
|
getEncounterBossSegments(waveIndex: number, level: number, species?: PokemonSpecies, forceBoss = false): number {
|
||||||
if (Overrides.OPP_HEALTH_SEGMENTS_OVERRIDE > 1) {
|
if (Overrides.ENEMY_HEALTH_SEGMENTS_OVERRIDE > 1) {
|
||||||
return Overrides.OPP_HEALTH_SEGMENTS_OVERRIDE;
|
return Overrides.ENEMY_HEALTH_SEGMENTS_OVERRIDE;
|
||||||
}
|
}
|
||||||
if (Overrides.OPP_HEALTH_SEGMENTS_OVERRIDE === 1) {
|
if (Overrides.ENEMY_HEALTH_SEGMENTS_OVERRIDE === 1) {
|
||||||
// The rest of the code expects to be returned 0 and not 1 if the enemy is not a boss
|
// The rest of the code expects to be returned 0 and not 1 if the enemy is not a boss
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1670,6 +1670,7 @@ export class MoveTypeChangeAbAttr extends PreAttackAbAttr {
|
|||||||
constructor(
|
constructor(
|
||||||
private newType: PokemonType,
|
private newType: PokemonType,
|
||||||
private powerMultiplier: number,
|
private powerMultiplier: number,
|
||||||
|
// TODO: all moves with this attr solely check the move being used...
|
||||||
private condition?: PokemonAttackCondition,
|
private condition?: PokemonAttackCondition,
|
||||||
) {
|
) {
|
||||||
super(false);
|
super(false);
|
||||||
|
@ -86,7 +86,7 @@ import { PokemonHealPhase } from "#phases/pokemon-heal-phase";
|
|||||||
import { SwitchSummonPhase } from "#phases/switch-summon-phase";
|
import { SwitchSummonPhase } from "#phases/switch-summon-phase";
|
||||||
import type { AttackMoveResult } from "#types/attack-move-result";
|
import type { AttackMoveResult } from "#types/attack-move-result";
|
||||||
import type { Localizable } from "#types/locales";
|
import type { Localizable } from "#types/locales";
|
||||||
import type { ChargingMove, MoveAttrMap, MoveAttrString, MoveClassMap, MoveKindString } from "#types/move-types";
|
import type { ChargingMove, MoveAttrMap, MoveAttrString, MoveClassMap, MoveKindString, MoveMessageFunc } from "#types/move-types";
|
||||||
import type { TurnMove } from "#types/turn-move";
|
import type { TurnMove } from "#types/turn-move";
|
||||||
import { BooleanHolder, type Constructor, isNullOrUndefined, NumberHolder, randSeedFloat, randSeedInt, randSeedItem, toDmgValue } from "#utils/common";
|
import { BooleanHolder, type Constructor, isNullOrUndefined, NumberHolder, randSeedFloat, randSeedInt, randSeedItem, toDmgValue } from "#utils/common";
|
||||||
import { getEnumValues } from "#utils/enums";
|
import { getEnumValues } from "#utils/enums";
|
||||||
@ -1357,20 +1357,20 @@ export class MoveHeaderAttr extends MoveAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Header attribute to queue a message at the beginning of a turn.
|
* Header attribute to queue a message at the beginning of a turn.
|
||||||
* @see {@link MoveHeaderAttr}
|
|
||||||
*/
|
*/
|
||||||
export class MessageHeaderAttr extends MoveHeaderAttr {
|
export class MessageHeaderAttr extends MoveHeaderAttr {
|
||||||
private message: string | ((user: Pokemon, move: Move) => string);
|
/** The message to display, or a function producing one. */
|
||||||
|
private message: string | MoveMessageFunc;
|
||||||
|
|
||||||
constructor(message: string | ((user: Pokemon, move: Move) => string)) {
|
constructor(message: string | MoveMessageFunc) {
|
||||||
super();
|
super();
|
||||||
this.message = message;
|
this.message = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move): boolean {
|
||||||
const message = typeof this.message === "string"
|
const message = typeof this.message === "string"
|
||||||
? this.message
|
? this.message
|
||||||
: this.message(user, move);
|
: this.message(user, target, move);
|
||||||
|
|
||||||
if (message) {
|
if (message) {
|
||||||
globalScene.phaseManager.queueMessage(message);
|
globalScene.phaseManager.queueMessage(message);
|
||||||
@ -1418,21 +1418,21 @@ export class BeakBlastHeaderAttr extends AddBattlerTagHeaderAttr {
|
|||||||
*/
|
*/
|
||||||
export class PreMoveMessageAttr extends MoveAttr {
|
export class PreMoveMessageAttr extends MoveAttr {
|
||||||
/** The message to display or a function returning one */
|
/** The message to display or a function returning one */
|
||||||
private message: string | ((user: Pokemon, target: Pokemon, move: Move) => string | undefined);
|
private message: string | MoveMessageFunc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@linkcode PreMoveMessageAttr} to display a message before move execution.
|
* Create a new {@linkcode PreMoveMessageAttr} to display a message before move execution.
|
||||||
* @param message - The message to display before move use, either as a string or a function producing one.
|
* @param message - The message to display before move use, either` a literal string or a function producing one.
|
||||||
* @remarks
|
* @remarks
|
||||||
* If {@linkcode message} evaluates to an empty string (`''`), no message will be displayed
|
* If {@linkcode message} evaluates to an empty string (`""`), no message will be displayed
|
||||||
* (though the move will still succeed).
|
* (though the move will still succeed).
|
||||||
*/
|
*/
|
||||||
constructor(message: string | ((user: Pokemon, target: Pokemon, move: Move) => string)) {
|
constructor(message: string | MoveMessageFunc) {
|
||||||
super();
|
super();
|
||||||
this.message = message;
|
this.message = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, _args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move): boolean {
|
||||||
const message = typeof this.message === "function"
|
const message = typeof this.message === "function"
|
||||||
? this.message(user, target, move)
|
? this.message(user, target, move)
|
||||||
: this.message;
|
: this.message;
|
||||||
@ -1453,18 +1453,17 @@ export class PreMoveMessageAttr extends MoveAttr {
|
|||||||
* @extends MoveAttr
|
* @extends MoveAttr
|
||||||
*/
|
*/
|
||||||
export class PreUseInterruptAttr extends MoveAttr {
|
export class PreUseInterruptAttr extends MoveAttr {
|
||||||
protected message?: string | ((user: Pokemon, target: Pokemon, move: Move) => string);
|
protected message: string | MoveMessageFunc;
|
||||||
protected overridesFailedMessage: boolean;
|
|
||||||
protected conditionFunc: MoveConditionFunc;
|
protected conditionFunc: MoveConditionFunc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new MoveInterruptedMessageAttr.
|
* Create a new MoveInterruptedMessageAttr.
|
||||||
* @param message The message to display when the move is interrupted, or a function that formats the message based on the user, target, and move.
|
* @param message The message to display when the move is interrupted, or a function that formats the message based on the user, target, and move.
|
||||||
*/
|
*/
|
||||||
constructor(message?: string | ((user: Pokemon, target: Pokemon, move: Move) => string), conditionFunc?: MoveConditionFunc) {
|
constructor(message: string | MoveMessageFunc, conditionFunc: MoveConditionFunc) {
|
||||||
super();
|
super();
|
||||||
this.message = message;
|
this.message = message;
|
||||||
this.conditionFunc = conditionFunc ?? (() => true);
|
this.conditionFunc = conditionFunc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1485,11 +1484,9 @@ export class PreUseInterruptAttr extends MoveAttr {
|
|||||||
*/
|
*/
|
||||||
override getFailedText(user: Pokemon, target: Pokemon, move: Move): string | undefined {
|
override getFailedText(user: Pokemon, target: Pokemon, move: Move): string | undefined {
|
||||||
if (this.message && this.conditionFunc(user, target, move)) {
|
if (this.message && this.conditionFunc(user, target, move)) {
|
||||||
const message =
|
return typeof this.message === "string"
|
||||||
typeof this.message === "string"
|
? this.message
|
||||||
? (this.message as string)
|
|
||||||
: this.message(user, target, move);
|
: this.message(user, target, move);
|
||||||
return message;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1694,17 +1691,30 @@ export class SurviveDamageAttr extends ModifiedDamageAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SplashAttr extends MoveEffectAttr {
|
/**
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
* Move attribute to display arbitrary text during a move's execution.
|
||||||
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:splash"));
|
*/
|
||||||
|
export class MessageAttr extends MoveEffectAttr {
|
||||||
|
/** The message to display, either as a string or a function returning one. */
|
||||||
|
private message: string | MoveMessageFunc;
|
||||||
|
|
||||||
|
constructor(message: string | MoveMessageFunc, options?: MoveEffectAttrOptions) {
|
||||||
|
// TODO: Do we need to respect `selfTarget` if we're just displaying text?
|
||||||
|
super(false, options)
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
override apply(user: Pokemon, target: Pokemon, move: Move): boolean {
|
||||||
|
const message = typeof this.message === "function"
|
||||||
|
? this.message(user, target, move)
|
||||||
|
: this.message;
|
||||||
|
|
||||||
|
// TODO: Consider changing if/when MoveAttr `apply` return values become significant
|
||||||
|
if (message) {
|
||||||
|
globalScene.phaseManager.queueMessage(message, 500);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
return false;
|
||||||
|
|
||||||
export class CelebrateAttr extends MoveEffectAttr {
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
|
||||||
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:celebrate", { playerName: loggedInUser?.username }));
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5931,38 +5941,6 @@ export class ProtectAttr extends AddBattlerTagAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class IgnoreAccuracyAttr extends AddBattlerTagAttr {
|
|
||||||
constructor() {
|
|
||||||
super(BattlerTagType.IGNORE_ACCURACY, true, false, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
|
||||||
if (!super.apply(user, target, move, args)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:tookAimAtTarget", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target) }));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class FaintCountdownAttr extends AddBattlerTagAttr {
|
|
||||||
constructor() {
|
|
||||||
super(BattlerTagType.PERISH_SONG, false, true, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
|
||||||
if (!super.apply(user, target, move, args)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:faintCountdown", { pokemonName: getPokemonNameWithAffix(target), turnCount: this.turnCountMin - 1 }));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attribute to remove all Substitutes from the field.
|
* Attribute to remove all Substitutes from the field.
|
||||||
* @extends MoveEffectAttr
|
* @extends MoveEffectAttr
|
||||||
@ -6603,8 +6581,10 @@ export class ChillyReceptionAttr extends ForceSwitchOutAttr {
|
|||||||
return (user, target, move) => globalScene.arena.weather?.weatherType !== WeatherType.SNOW || super.getSwitchOutCondition()(user, target, move);
|
return (user, target, move) => globalScene.arena.weather?.weatherType !== WeatherType.SNOW || super.getSwitchOutCondition()(user, target, move);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RemoveTypeAttr extends MoveEffectAttr {
|
export class RemoveTypeAttr extends MoveEffectAttr {
|
||||||
|
|
||||||
|
// TODO: Remove the message callback
|
||||||
private removedType: PokemonType;
|
private removedType: PokemonType;
|
||||||
private messageCallback: ((user: Pokemon) => void) | undefined;
|
private messageCallback: ((user: Pokemon) => void) | undefined;
|
||||||
|
|
||||||
@ -8299,8 +8279,6 @@ const MoveAttrs = Object.freeze({
|
|||||||
RandomLevelDamageAttr,
|
RandomLevelDamageAttr,
|
||||||
ModifiedDamageAttr,
|
ModifiedDamageAttr,
|
||||||
SurviveDamageAttr,
|
SurviveDamageAttr,
|
||||||
SplashAttr,
|
|
||||||
CelebrateAttr,
|
|
||||||
RecoilAttr,
|
RecoilAttr,
|
||||||
SacrificialAttr,
|
SacrificialAttr,
|
||||||
SacrificialAttrOnHit,
|
SacrificialAttrOnHit,
|
||||||
@ -8443,8 +8421,7 @@ const MoveAttrs = Object.freeze({
|
|||||||
RechargeAttr,
|
RechargeAttr,
|
||||||
TrapAttr,
|
TrapAttr,
|
||||||
ProtectAttr,
|
ProtectAttr,
|
||||||
IgnoreAccuracyAttr,
|
MessageAttr,
|
||||||
FaintCountdownAttr,
|
|
||||||
RemoveAllSubstitutesAttr,
|
RemoveAllSubstitutesAttr,
|
||||||
HitsTagAttr,
|
HitsTagAttr,
|
||||||
HitsTagForDoubleDamageAttr,
|
HitsTagForDoubleDamageAttr,
|
||||||
@ -8938,7 +8915,7 @@ export function initMoves() {
|
|||||||
new AttackMove(MoveId.PSYWAVE, PokemonType.PSYCHIC, MoveCategory.SPECIAL, -1, 100, 15, -1, 0, 1)
|
new AttackMove(MoveId.PSYWAVE, PokemonType.PSYCHIC, MoveCategory.SPECIAL, -1, 100, 15, -1, 0, 1)
|
||||||
.attr(RandomLevelDamageAttr),
|
.attr(RandomLevelDamageAttr),
|
||||||
new SelfStatusMove(MoveId.SPLASH, PokemonType.NORMAL, -1, 40, -1, 0, 1)
|
new SelfStatusMove(MoveId.SPLASH, PokemonType.NORMAL, -1, 40, -1, 0, 1)
|
||||||
.attr(SplashAttr)
|
.attr(MessageAttr, i18next.t("moveTriggers:splash"))
|
||||||
.condition(failOnGravityCondition),
|
.condition(failOnGravityCondition),
|
||||||
new SelfStatusMove(MoveId.ACID_ARMOR, PokemonType.POISON, -1, 20, -1, 0, 1)
|
new SelfStatusMove(MoveId.ACID_ARMOR, PokemonType.POISON, -1, 20, -1, 0, 1)
|
||||||
.attr(StatStageChangeAttr, [ Stat.DEF ], 2, true),
|
.attr(StatStageChangeAttr, [ Stat.DEF ], 2, true),
|
||||||
@ -9000,7 +8977,10 @@ export function initMoves() {
|
|||||||
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, true, 1)
|
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, true, 1)
|
||||||
.reflectable(),
|
.reflectable(),
|
||||||
new StatusMove(MoveId.MIND_READER, PokemonType.NORMAL, -1, 5, -1, 0, 2)
|
new StatusMove(MoveId.MIND_READER, PokemonType.NORMAL, -1, 5, -1, 0, 2)
|
||||||
.attr(IgnoreAccuracyAttr),
|
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_ACCURACY, true, false, 2)
|
||||||
|
.attr(MessageAttr, (user, target) =>
|
||||||
|
i18next.t("moveTriggers:tookAimAtTarget", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target) })
|
||||||
|
),
|
||||||
new StatusMove(MoveId.NIGHTMARE, PokemonType.GHOST, 100, 15, -1, 0, 2)
|
new StatusMove(MoveId.NIGHTMARE, PokemonType.GHOST, 100, 15, -1, 0, 2)
|
||||||
.attr(AddBattlerTagAttr, BattlerTagType.NIGHTMARE)
|
.attr(AddBattlerTagAttr, BattlerTagType.NIGHTMARE)
|
||||||
.condition(targetSleptOrComatoseCondition),
|
.condition(targetSleptOrComatoseCondition),
|
||||||
@ -9088,7 +9068,9 @@ export function initMoves() {
|
|||||||
return lastTurnMove.length === 0 || lastTurnMove[0].move !== move.id || lastTurnMove[0].result !== MoveResult.SUCCESS;
|
return lastTurnMove.length === 0 || lastTurnMove[0].move !== move.id || lastTurnMove[0].result !== MoveResult.SUCCESS;
|
||||||
}),
|
}),
|
||||||
new StatusMove(MoveId.PERISH_SONG, PokemonType.NORMAL, -1, 5, -1, 0, 2)
|
new StatusMove(MoveId.PERISH_SONG, PokemonType.NORMAL, -1, 5, -1, 0, 2)
|
||||||
.attr(FaintCountdownAttr)
|
.attr(AddBattlerTagAttr, BattlerTagType.PERISH_SONG, false, true, 4)
|
||||||
|
.attr(MessageAttr, (_user, target) =>
|
||||||
|
i18next.t("moveTriggers:faintCountdown", { pokemonName: getPokemonNameWithAffix(target), turnCount: 3 }))
|
||||||
.ignoresProtect()
|
.ignoresProtect()
|
||||||
.soundBased()
|
.soundBased()
|
||||||
.condition(failOnBossCondition)
|
.condition(failOnBossCondition)
|
||||||
@ -9104,7 +9086,10 @@ export function initMoves() {
|
|||||||
.attr(MultiHitAttr)
|
.attr(MultiHitAttr)
|
||||||
.makesContact(false),
|
.makesContact(false),
|
||||||
new StatusMove(MoveId.LOCK_ON, PokemonType.NORMAL, -1, 5, -1, 0, 2)
|
new StatusMove(MoveId.LOCK_ON, PokemonType.NORMAL, -1, 5, -1, 0, 2)
|
||||||
.attr(IgnoreAccuracyAttr),
|
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_ACCURACY, true, false, 2)
|
||||||
|
.attr(MessageAttr, (user, target) =>
|
||||||
|
i18next.t("moveTriggers:tookAimAtTarget", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target) })
|
||||||
|
),
|
||||||
new AttackMove(MoveId.OUTRAGE, PokemonType.DRAGON, MoveCategory.PHYSICAL, 120, 100, 10, -1, 0, 2)
|
new AttackMove(MoveId.OUTRAGE, PokemonType.DRAGON, MoveCategory.PHYSICAL, 120, 100, 10, -1, 0, 2)
|
||||||
.attr(FrenzyAttr)
|
.attr(FrenzyAttr)
|
||||||
.attr(MissEffectAttr, frenzyMissFunc)
|
.attr(MissEffectAttr, frenzyMissFunc)
|
||||||
@ -9331,8 +9316,8 @@ export function initMoves() {
|
|||||||
&& (user.status.effect === StatusEffect.BURN || user.status.effect === StatusEffect.POISON || user.status.effect === StatusEffect.TOXIC || user.status.effect === StatusEffect.PARALYSIS) ? 2 : 1)
|
&& (user.status.effect === StatusEffect.BURN || user.status.effect === StatusEffect.POISON || user.status.effect === StatusEffect.TOXIC || user.status.effect === StatusEffect.PARALYSIS) ? 2 : 1)
|
||||||
.attr(BypassBurnDamageReductionAttr),
|
.attr(BypassBurnDamageReductionAttr),
|
||||||
new AttackMove(MoveId.FOCUS_PUNCH, PokemonType.FIGHTING, MoveCategory.PHYSICAL, 150, 100, 20, -1, -3, 3)
|
new AttackMove(MoveId.FOCUS_PUNCH, PokemonType.FIGHTING, MoveCategory.PHYSICAL, 150, 100, 20, -1, -3, 3)
|
||||||
.attr(MessageHeaderAttr, (user, move) => i18next.t("moveTriggers:isTighteningFocus", { pokemonName: getPokemonNameWithAffix(user) }))
|
.attr(MessageHeaderAttr, (user) => i18next.t("moveTriggers:isTighteningFocus", { pokemonName: getPokemonNameWithAffix(user) }))
|
||||||
.attr(PreUseInterruptAttr, (user, target, move) => i18next.t("moveTriggers:lostFocus", { pokemonName: getPokemonNameWithAffix(user) }), user => !!user.turnData.attacksReceived.find(r => r.damage))
|
.attr(PreUseInterruptAttr, (user) => i18next.t("moveTriggers:lostFocus", { pokemonName: getPokemonNameWithAffix(user) }), user => user.turnData.attacksReceived.some(r => r.damage > 0))
|
||||||
.punchingMove(),
|
.punchingMove(),
|
||||||
new AttackMove(MoveId.SMELLING_SALTS, PokemonType.NORMAL, MoveCategory.PHYSICAL, 70, 100, 10, -1, 0, 3)
|
new AttackMove(MoveId.SMELLING_SALTS, PokemonType.NORMAL, MoveCategory.PHYSICAL, 70, 100, 10, -1, 0, 3)
|
||||||
.attr(MovePowerMultiplierAttr, (user, target, move) => target.status?.effect === StatusEffect.PARALYSIS ? 2 : 1)
|
.attr(MovePowerMultiplierAttr, (user, target, move) => target.status?.effect === StatusEffect.PARALYSIS ? 2 : 1)
|
||||||
@ -10433,7 +10418,8 @@ export function initMoves() {
|
|||||||
new AttackMove(MoveId.DAZZLING_GLEAM, PokemonType.FAIRY, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 6)
|
new AttackMove(MoveId.DAZZLING_GLEAM, PokemonType.FAIRY, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 6)
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
new SelfStatusMove(MoveId.CELEBRATE, PokemonType.NORMAL, -1, 40, -1, 0, 6)
|
new SelfStatusMove(MoveId.CELEBRATE, PokemonType.NORMAL, -1, 40, -1, 0, 6)
|
||||||
.attr(CelebrateAttr),
|
// NB: This needs a lambda function as the user will not be logged in by the time the moves are initialized
|
||||||
|
.attr(MessageAttr, () => i18next.t("moveTriggers:celebrate", { playerName: loggedInUser?.username })),
|
||||||
new StatusMove(MoveId.HOLD_HANDS, PokemonType.NORMAL, -1, 40, -1, 0, 6)
|
new StatusMove(MoveId.HOLD_HANDS, PokemonType.NORMAL, -1, 40, -1, 0, 6)
|
||||||
.ignoresSubstitute()
|
.ignoresSubstitute()
|
||||||
.target(MoveTarget.NEAR_ALLY),
|
.target(MoveTarget.NEAR_ALLY),
|
||||||
@ -10608,7 +10594,12 @@ export function initMoves() {
|
|||||||
.attr(StatStageChangeAttr, [ Stat.SPD ], -1)
|
.attr(StatStageChangeAttr, [ Stat.SPD ], -1)
|
||||||
.reflectable(),
|
.reflectable(),
|
||||||
new SelfStatusMove(MoveId.LASER_FOCUS, PokemonType.NORMAL, -1, 30, -1, 0, 7)
|
new SelfStatusMove(MoveId.LASER_FOCUS, PokemonType.NORMAL, -1, 30, -1, 0, 7)
|
||||||
.attr(AddBattlerTagAttr, BattlerTagType.ALWAYS_CRIT, true, false),
|
.attr(AddBattlerTagAttr, BattlerTagType.ALWAYS_CRIT, true, false)
|
||||||
|
.attr(MessageAttr, (user) =>
|
||||||
|
i18next.t("battlerTags:laserFocusOnAdd", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(user),
|
||||||
|
}),
|
||||||
|
),
|
||||||
new StatusMove(MoveId.GEAR_UP, PokemonType.STEEL, -1, 20, -1, 0, 7)
|
new StatusMove(MoveId.GEAR_UP, PokemonType.STEEL, -1, 20, -1, 0, 7)
|
||||||
.attr(StatStageChangeAttr, [ Stat.ATK, Stat.SPATK ], 1, false, { condition: (user, target, move) => !![ AbilityId.PLUS, AbilityId.MINUS ].find(a => target.hasAbility(a, false)) })
|
.attr(StatStageChangeAttr, [ Stat.ATK, Stat.SPATK ], 1, false, { condition: (user, target, move) => !![ AbilityId.PLUS, AbilityId.MINUS ].find(a => target.hasAbility(a, false)) })
|
||||||
.ignoresSubstitute()
|
.ignoresSubstitute()
|
||||||
|
@ -1825,7 +1825,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
// Overrides moveset based on arrays specified in overrides.ts
|
// Overrides moveset based on arrays specified in overrides.ts
|
||||||
let overrideArray: MoveId | Array<MoveId> = this.isPlayer()
|
let overrideArray: MoveId | Array<MoveId> = this.isPlayer()
|
||||||
? Overrides.MOVESET_OVERRIDE
|
? Overrides.MOVESET_OVERRIDE
|
||||||
: Overrides.OPP_MOVESET_OVERRIDE;
|
: Overrides.ENEMY_MOVESET_OVERRIDE;
|
||||||
overrideArray = coerceArray(overrideArray);
|
overrideArray = coerceArray(overrideArray);
|
||||||
if (overrideArray.length > 0) {
|
if (overrideArray.length > 0) {
|
||||||
if (!this.isPlayer()) {
|
if (!this.isPlayer()) {
|
||||||
@ -2030,8 +2030,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
if (Overrides.ABILITY_OVERRIDE && this.isPlayer()) {
|
if (Overrides.ABILITY_OVERRIDE && this.isPlayer()) {
|
||||||
return allAbilities[Overrides.ABILITY_OVERRIDE];
|
return allAbilities[Overrides.ABILITY_OVERRIDE];
|
||||||
}
|
}
|
||||||
if (Overrides.OPP_ABILITY_OVERRIDE && this.isEnemy()) {
|
if (Overrides.ENEMY_ABILITY_OVERRIDE && this.isEnemy()) {
|
||||||
return allAbilities[Overrides.OPP_ABILITY_OVERRIDE];
|
return allAbilities[Overrides.ENEMY_ABILITY_OVERRIDE];
|
||||||
}
|
}
|
||||||
if (this.isFusion()) {
|
if (this.isFusion()) {
|
||||||
if (!isNullOrUndefined(this.fusionCustomPokemonData?.ability) && this.fusionCustomPokemonData.ability !== -1) {
|
if (!isNullOrUndefined(this.fusionCustomPokemonData?.ability) && this.fusionCustomPokemonData.ability !== -1) {
|
||||||
@ -2060,8 +2060,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
if (Overrides.PASSIVE_ABILITY_OVERRIDE && this.isPlayer()) {
|
if (Overrides.PASSIVE_ABILITY_OVERRIDE && this.isPlayer()) {
|
||||||
return allAbilities[Overrides.PASSIVE_ABILITY_OVERRIDE];
|
return allAbilities[Overrides.PASSIVE_ABILITY_OVERRIDE];
|
||||||
}
|
}
|
||||||
if (Overrides.OPP_PASSIVE_ABILITY_OVERRIDE && this.isEnemy()) {
|
if (Overrides.ENEMY_PASSIVE_ABILITY_OVERRIDE && this.isEnemy()) {
|
||||||
return allAbilities[Overrides.OPP_PASSIVE_ABILITY_OVERRIDE];
|
return allAbilities[Overrides.ENEMY_PASSIVE_ABILITY_OVERRIDE];
|
||||||
}
|
}
|
||||||
if (!isNullOrUndefined(this.customPokemonData.passive) && this.customPokemonData.passive !== -1) {
|
if (!isNullOrUndefined(this.customPokemonData.passive) && this.customPokemonData.passive !== -1) {
|
||||||
return allAbilities[this.customPokemonData.passive];
|
return allAbilities[this.customPokemonData.passive];
|
||||||
@ -2128,14 +2128,14 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
// returns override if valid for current case
|
// returns override if valid for current case
|
||||||
if (
|
if (
|
||||||
(Overrides.HAS_PASSIVE_ABILITY_OVERRIDE === false && this.isPlayer()) ||
|
(Overrides.HAS_PASSIVE_ABILITY_OVERRIDE === false && this.isPlayer()) ||
|
||||||
(Overrides.OPP_HAS_PASSIVE_ABILITY_OVERRIDE === false && this.isEnemy())
|
(Overrides.ENEMY_HAS_PASSIVE_ABILITY_OVERRIDE === false && this.isEnemy())
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
((Overrides.PASSIVE_ABILITY_OVERRIDE !== AbilityId.NONE || Overrides.HAS_PASSIVE_ABILITY_OVERRIDE) &&
|
((Overrides.PASSIVE_ABILITY_OVERRIDE !== AbilityId.NONE || Overrides.HAS_PASSIVE_ABILITY_OVERRIDE) &&
|
||||||
this.isPlayer()) ||
|
this.isPlayer()) ||
|
||||||
((Overrides.OPP_PASSIVE_ABILITY_OVERRIDE !== AbilityId.NONE || Overrides.OPP_HAS_PASSIVE_ABILITY_OVERRIDE) &&
|
((Overrides.ENEMY_PASSIVE_ABILITY_OVERRIDE !== AbilityId.NONE || Overrides.ENEMY_HAS_PASSIVE_ABILITY_OVERRIDE) &&
|
||||||
this.isEnemy())
|
this.isEnemy())
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
@ -3001,8 +3001,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
if (forStarter && this.isPlayer() && Overrides.STARTER_FUSION_SPECIES_OVERRIDE) {
|
if (forStarter && this.isPlayer() && Overrides.STARTER_FUSION_SPECIES_OVERRIDE) {
|
||||||
fusionOverride = getPokemonSpecies(Overrides.STARTER_FUSION_SPECIES_OVERRIDE);
|
fusionOverride = getPokemonSpecies(Overrides.STARTER_FUSION_SPECIES_OVERRIDE);
|
||||||
} else if (this.isEnemy() && Overrides.OPP_FUSION_SPECIES_OVERRIDE) {
|
} else if (this.isEnemy() && Overrides.ENEMY_FUSION_SPECIES_OVERRIDE) {
|
||||||
fusionOverride = getPokemonSpecies(Overrides.OPP_FUSION_SPECIES_OVERRIDE);
|
fusionOverride = getPokemonSpecies(Overrides.ENEMY_FUSION_SPECIES_OVERRIDE);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fusionSpecies =
|
this.fusionSpecies =
|
||||||
@ -6241,22 +6241,22 @@ export class EnemyPokemon extends Pokemon {
|
|||||||
this.setBoss(boss, dataSource?.bossSegments);
|
this.setBoss(boss, dataSource?.bossSegments);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Overrides.OPP_STATUS_OVERRIDE) {
|
if (Overrides.ENEMY_STATUS_OVERRIDE) {
|
||||||
this.status = new Status(Overrides.OPP_STATUS_OVERRIDE, 0, 4);
|
this.status = new Status(Overrides.ENEMY_STATUS_OVERRIDE, 0, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Overrides.OPP_GENDER_OVERRIDE !== null) {
|
if (Overrides.ENEMY_GENDER_OVERRIDE !== null) {
|
||||||
this.gender = Overrides.OPP_GENDER_OVERRIDE;
|
this.gender = Overrides.ENEMY_GENDER_OVERRIDE;
|
||||||
}
|
}
|
||||||
|
|
||||||
const speciesId = this.species.speciesId;
|
const speciesId = this.species.speciesId;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
speciesId in Overrides.OPP_FORM_OVERRIDES &&
|
speciesId in Overrides.ENEMY_FORM_OVERRIDES &&
|
||||||
!isNullOrUndefined(Overrides.OPP_FORM_OVERRIDES[speciesId]) &&
|
!isNullOrUndefined(Overrides.ENEMY_FORM_OVERRIDES[speciesId]) &&
|
||||||
this.species.forms[Overrides.OPP_FORM_OVERRIDES[speciesId]]
|
this.species.forms[Overrides.ENEMY_FORM_OVERRIDES[speciesId]]
|
||||||
) {
|
) {
|
||||||
this.formIndex = Overrides.OPP_FORM_OVERRIDES[speciesId];
|
this.formIndex = Overrides.ENEMY_FORM_OVERRIDES[speciesId];
|
||||||
} else if (globalScene.gameMode.isDaily && globalScene.gameMode.isWaveFinal(globalScene.currentBattle.waveIndex)) {
|
} else if (globalScene.gameMode.isDaily && globalScene.gameMode.isWaveFinal(globalScene.currentBattle.waveIndex)) {
|
||||||
const eventBoss = getDailyEventSeedBoss(globalScene.seed);
|
const eventBoss = getDailyEventSeedBoss(globalScene.seed);
|
||||||
if (!isNullOrUndefined(eventBoss)) {
|
if (!isNullOrUndefined(eventBoss)) {
|
||||||
@ -6266,21 +6266,21 @@ export class EnemyPokemon extends Pokemon {
|
|||||||
|
|
||||||
if (!dataSource) {
|
if (!dataSource) {
|
||||||
this.generateAndPopulateMoveset();
|
this.generateAndPopulateMoveset();
|
||||||
if (shinyLock || Overrides.OPP_SHINY_OVERRIDE === false) {
|
if (shinyLock || Overrides.ENEMY_SHINY_OVERRIDE === false) {
|
||||||
this.shiny = false;
|
this.shiny = false;
|
||||||
} else {
|
} else {
|
||||||
this.trySetShiny();
|
this.trySetShiny();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.shiny && Overrides.OPP_SHINY_OVERRIDE) {
|
if (!this.shiny && Overrides.ENEMY_SHINY_OVERRIDE) {
|
||||||
this.shiny = true;
|
this.shiny = true;
|
||||||
this.initShinySparkle();
|
this.initShinySparkle();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.shiny) {
|
if (this.shiny) {
|
||||||
this.variant = this.generateShinyVariant();
|
this.variant = this.generateShinyVariant();
|
||||||
if (Overrides.OPP_VARIANT_OVERRIDE !== null) {
|
if (Overrides.ENEMY_VARIANT_OVERRIDE !== null) {
|
||||||
this.variant = Overrides.OPP_VARIANT_OVERRIDE;
|
this.variant = Overrides.ENEMY_VARIANT_OVERRIDE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3755,7 +3755,7 @@ export class EnemyFusionChanceModifier extends EnemyPersistentModifier {
|
|||||||
export function overrideModifiers(isPlayer = true): void {
|
export function overrideModifiers(isPlayer = true): void {
|
||||||
const modifiersOverride: ModifierOverride[] = isPlayer
|
const modifiersOverride: ModifierOverride[] = isPlayer
|
||||||
? Overrides.STARTING_MODIFIER_OVERRIDE
|
? Overrides.STARTING_MODIFIER_OVERRIDE
|
||||||
: Overrides.OPP_MODIFIER_OVERRIDE;
|
: Overrides.ENEMY_MODIFIER_OVERRIDE;
|
||||||
if (!modifiersOverride || modifiersOverride.length === 0 || !globalScene) {
|
if (!modifiersOverride || modifiersOverride.length === 0 || !globalScene) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -3797,7 +3797,7 @@ export function overrideModifiers(isPlayer = true): void {
|
|||||||
export function overrideHeldItems(pokemon: Pokemon, isPlayer = true): void {
|
export function overrideHeldItems(pokemon: Pokemon, isPlayer = true): void {
|
||||||
const heldItemsOverride: ModifierOverride[] = isPlayer
|
const heldItemsOverride: ModifierOverride[] = isPlayer
|
||||||
? Overrides.STARTING_HELD_ITEMS_OVERRIDE
|
? Overrides.STARTING_HELD_ITEMS_OVERRIDE
|
||||||
: Overrides.OPP_HELD_ITEMS_OVERRIDE;
|
: Overrides.ENEMY_HELD_ITEMS_OVERRIDE;
|
||||||
if (!heldItemsOverride || heldItemsOverride.length === 0 || !globalScene) {
|
if (!heldItemsOverride || heldItemsOverride.length === 0 || !globalScene) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -179,25 +179,24 @@ class DefaultOverrides {
|
|||||||
// --------------------------
|
// --------------------------
|
||||||
// OPPONENT / ENEMY OVERRIDES
|
// OPPONENT / ENEMY OVERRIDES
|
||||||
// --------------------------
|
// --------------------------
|
||||||
// TODO: rename `OPP_` to `ENEMY_`
|
readonly ENEMY_SPECIES_OVERRIDE: SpeciesId | number = 0;
|
||||||
readonly OPP_SPECIES_OVERRIDE: SpeciesId | number = 0;
|
|
||||||
/**
|
/**
|
||||||
* This will make all opponents fused Pokemon
|
* This will make all opponents fused Pokemon
|
||||||
*/
|
*/
|
||||||
readonly OPP_FUSION_OVERRIDE: boolean = false;
|
readonly ENEMY_FUSION_OVERRIDE: boolean = false;
|
||||||
/**
|
/**
|
||||||
* This will override the species of the fusion only when the opponent is already a fusion
|
* This will override the species of the fusion only when the opponent is already a fusion
|
||||||
*/
|
*/
|
||||||
readonly OPP_FUSION_SPECIES_OVERRIDE: SpeciesId | number = 0;
|
readonly ENEMY_FUSION_SPECIES_OVERRIDE: SpeciesId | number = 0;
|
||||||
readonly OPP_LEVEL_OVERRIDE: number = 0;
|
readonly ENEMY_LEVEL_OVERRIDE: number = 0;
|
||||||
readonly OPP_ABILITY_OVERRIDE: AbilityId = AbilityId.NONE;
|
readonly ENEMY_ABILITY_OVERRIDE: AbilityId = AbilityId.NONE;
|
||||||
readonly OPP_PASSIVE_ABILITY_OVERRIDE: AbilityId = AbilityId.NONE;
|
readonly ENEMY_PASSIVE_ABILITY_OVERRIDE: AbilityId = AbilityId.NONE;
|
||||||
readonly OPP_HAS_PASSIVE_ABILITY_OVERRIDE: boolean | null = null;
|
readonly ENEMY_HAS_PASSIVE_ABILITY_OVERRIDE: boolean | null = null;
|
||||||
readonly OPP_STATUS_OVERRIDE: StatusEffect = StatusEffect.NONE;
|
readonly ENEMY_STATUS_OVERRIDE: StatusEffect = StatusEffect.NONE;
|
||||||
readonly OPP_GENDER_OVERRIDE: Gender | null = null;
|
readonly ENEMY_GENDER_OVERRIDE: Gender | null = null;
|
||||||
readonly OPP_MOVESET_OVERRIDE: MoveId | Array<MoveId> = [];
|
readonly ENEMY_MOVESET_OVERRIDE: MoveId | Array<MoveId> = [];
|
||||||
readonly OPP_SHINY_OVERRIDE: boolean | null = null;
|
readonly ENEMY_SHINY_OVERRIDE: boolean | null = null;
|
||||||
readonly OPP_VARIANT_OVERRIDE: Variant | null = null;
|
readonly ENEMY_VARIANT_OVERRIDE: Variant | null = null;
|
||||||
/**
|
/**
|
||||||
* Overrides the IVs of enemy pokemon. Values must never be outside the range `0` to `31`!
|
* Overrides the IVs of enemy pokemon. Values must never be outside the range `0` to `31`!
|
||||||
* - If set to a number between `0` and `31`, set all IVs of all enemy pokemon to that number.
|
* - If set to a number between `0` and `31`, set all IVs of all enemy pokemon to that number.
|
||||||
@ -207,7 +206,7 @@ class DefaultOverrides {
|
|||||||
readonly ENEMY_IVS_OVERRIDE: number | number[] | null = null;
|
readonly ENEMY_IVS_OVERRIDE: number | number[] | null = null;
|
||||||
/** Override the nature of all enemy pokemon to the specified nature. Disabled if `null`. */
|
/** Override the nature of all enemy pokemon to the specified nature. Disabled if `null`. */
|
||||||
readonly ENEMY_NATURE_OVERRIDE: Nature | null = null;
|
readonly ENEMY_NATURE_OVERRIDE: Nature | null = null;
|
||||||
readonly OPP_FORM_OVERRIDES: Partial<Record<SpeciesId, number>> = {};
|
readonly ENEMY_FORM_OVERRIDES: Partial<Record<SpeciesId, number>> = {};
|
||||||
/**
|
/**
|
||||||
* Override to give the enemy Pokemon a given amount of health segments
|
* Override to give the enemy Pokemon a given amount of health segments
|
||||||
*
|
*
|
||||||
@ -215,7 +214,7 @@ class DefaultOverrides {
|
|||||||
* 1: the Pokemon will have a single health segment and therefore will not be a boss
|
* 1: the Pokemon will have a single health segment and therefore will not be a boss
|
||||||
* 2+: the Pokemon will be a boss with the given number of health segments
|
* 2+: the Pokemon will be a boss with the given number of health segments
|
||||||
*/
|
*/
|
||||||
readonly OPP_HEALTH_SEGMENTS_OVERRIDE: number = 0;
|
readonly ENEMY_HEALTH_SEGMENTS_OVERRIDE: number = 0;
|
||||||
|
|
||||||
// -------------
|
// -------------
|
||||||
// EGG OVERRIDES
|
// EGG OVERRIDES
|
||||||
@ -277,12 +276,12 @@ class DefaultOverrides {
|
|||||||
*
|
*
|
||||||
* Note that any previous modifiers are cleared.
|
* Note that any previous modifiers are cleared.
|
||||||
*/
|
*/
|
||||||
readonly OPP_MODIFIER_OVERRIDE: ModifierOverride[] = [];
|
readonly ENEMY_MODIFIER_OVERRIDE: ModifierOverride[] = [];
|
||||||
|
|
||||||
/** Override array of {@linkcode ModifierOverride}s used to provide held items to first party member when starting a new game. */
|
/** Override array of {@linkcode ModifierOverride}s used to provide held items to first party member when starting a new game. */
|
||||||
readonly STARTING_HELD_ITEMS_OVERRIDE: ModifierOverride[] = [];
|
readonly STARTING_HELD_ITEMS_OVERRIDE: ModifierOverride[] = [];
|
||||||
/** Override array of {@linkcode ModifierOverride}s used to provide held items to enemies on spawn. */
|
/** Override array of {@linkcode ModifierOverride}s used to provide held items to enemies on spawn. */
|
||||||
readonly OPP_HELD_ITEMS_OVERRIDE: ModifierOverride[] = [];
|
readonly ENEMY_HELD_ITEMS_OVERRIDE: ModifierOverride[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override array of {@linkcode ModifierOverride}s used to replace the generated item rolls after a wave.
|
* Override array of {@linkcode ModifierOverride}s used to replace the generated item rolls after a wave.
|
||||||
|
@ -229,7 +229,7 @@ export class EncounterPhase extends BattlePhase {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const overridedBossSegments = Overrides.OPP_HEALTH_SEGMENTS_OVERRIDE > 1;
|
const overridedBossSegments = Overrides.ENEMY_HEALTH_SEGMENTS_OVERRIDE > 1;
|
||||||
// for double battles, reduce the health segments for boss Pokemon unless there is an override
|
// for double battles, reduce the health segments for boss Pokemon unless there is an override
|
||||||
if (!overridedBossSegments && battle.enemyParty.filter(p => p.isBoss()).length > 1) {
|
if (!overridedBossSegments && battle.enemyParty.filter(p => p.isBoss()).length > 1) {
|
||||||
for (const enemyPokemon of battle.enemyParty) {
|
for (const enemyPokemon of battle.enemyParty) {
|
||||||
|
2
test/@types/vitest.d.ts
vendored
2
test/@types/vitest.d.ts
vendored
@ -130,7 +130,7 @@ declare module "vitest" {
|
|||||||
* @param ppUsed - The numerical amount of PP that should have been consumed,
|
* @param ppUsed - The numerical amount of PP that should have been consumed,
|
||||||
* or `all` to indicate the move should be _out_ of PP
|
* or `all` to indicate the move should be _out_ of PP
|
||||||
* @remarks
|
* @remarks
|
||||||
* If the Pokemon's moveset has been set via {@linkcode Overrides.MOVESET_OVERRIDE}/{@linkcode Overrides.OPP_MOVESET_OVERRIDE},
|
* If the Pokemon's moveset has been set via {@linkcode Overrides.MOVESET_OVERRIDE}/{@linkcode Overrides.ENEMY_MOVESET_OVERRIDE},
|
||||||
* does not contain {@linkcode expectedMove}
|
* does not contain {@linkcode expectedMove}
|
||||||
* or contains the desired move more than once, this will fail the test.
|
* or contains the desired move more than once, this will fail the test.
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { globalScene } from "#app/global-scene";
|
|
||||||
import { Status } from "#data/status-effect";
|
import { Status } from "#data/status-effect";
|
||||||
import { AbilityId } from "#enums/ability-id";
|
import { AbilityId } from "#enums/ability-id";
|
||||||
import { BattleType } from "#enums/battle-type";
|
import { BattleType } from "#enums/battle-type";
|
||||||
@ -179,18 +178,13 @@ describe("Moves - Whirlwind", () => {
|
|||||||
const eligibleEnemy = enemyParty.filter(p => p.hp > 0 && p.isAllowedInBattle());
|
const eligibleEnemy = enemyParty.filter(p => p.hp > 0 && p.isAllowedInBattle());
|
||||||
expect(eligibleEnemy.length).toBe(1);
|
expect(eligibleEnemy.length).toBe(1);
|
||||||
|
|
||||||
// Spy on the queueMessage function
|
|
||||||
const queueSpy = vi.spyOn(globalScene.phaseManager, "queueMessage");
|
|
||||||
|
|
||||||
// Player uses Whirlwind; opponent uses Splash
|
// Player uses Whirlwind; opponent uses Splash
|
||||||
game.move.select(MoveId.WHIRLWIND);
|
game.move.select(MoveId.WHIRLWIND);
|
||||||
await game.move.selectEnemyMove(MoveId.SPLASH);
|
await game.move.selectEnemyMove(MoveId.SPLASH);
|
||||||
await game.toNextTurn();
|
await game.toNextTurn();
|
||||||
|
|
||||||
// Verify that the failure message is displayed for Whirlwind
|
const player = game.field.getPlayerPokemon();
|
||||||
expect(queueSpy).toHaveBeenCalledWith(expect.stringContaining("But it failed"));
|
expect(player).toHaveUsedMove({ move: MoveId.WHIRLWIND, result: MoveResult.FAIL });
|
||||||
// Verify the opponent's Splash message
|
|
||||||
expect(queueSpy).toHaveBeenCalledWith(expect.stringContaining("But nothing happened!"));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not pull in the other trainer's pokemon in a partner trainer battle", async () => {
|
it("should not pull in the other trainer's pokemon in a partner trainer battle", async () => {
|
||||||
|
@ -224,7 +224,7 @@ export class GameManager {
|
|||||||
// This will consider all battle entry dialog as seens and skip them
|
// This will consider all battle entry dialog as seens and skip them
|
||||||
vi.spyOn(this.scene.ui, "shouldSkipDialogue").mockReturnValue(true);
|
vi.spyOn(this.scene.ui, "shouldSkipDialogue").mockReturnValue(true);
|
||||||
|
|
||||||
if (overrides.OPP_HELD_ITEMS_OVERRIDE.length === 0) {
|
if (overrides.ENEMY_HELD_ITEMS_OVERRIDE.length === 0) {
|
||||||
this.removeEnemyHeldItems();
|
this.removeEnemyHeldItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ export class ChallengeModeHelper extends GameManagerHelper {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await this.game.phaseInterceptor.run(EncounterPhase);
|
await this.game.phaseInterceptor.run(EncounterPhase);
|
||||||
if (overrides.OPP_HELD_ITEMS_OVERRIDE.length === 0 && this.game.override.removeEnemyStartingItems) {
|
if (overrides.ENEMY_HELD_ITEMS_OVERRIDE.length === 0 && this.game.override.removeEnemyStartingItems) {
|
||||||
this.game.removeEnemyHeldItems();
|
this.game.removeEnemyHeldItems();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ export class ClassicModeHelper extends GameManagerHelper {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await this.game.phaseInterceptor.to(EncounterPhase);
|
await this.game.phaseInterceptor.to(EncounterPhase);
|
||||||
if (overrides.OPP_HELD_ITEMS_OVERRIDE.length === 0 && this.game.override.removeEnemyStartingItems) {
|
if (overrides.ENEMY_HELD_ITEMS_OVERRIDE.length === 0 && this.game.override.removeEnemyStartingItems) {
|
||||||
this.game.removeEnemyHeldItems();
|
this.game.removeEnemyHeldItems();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ export class DailyModeHelper extends GameManagerHelper {
|
|||||||
|
|
||||||
await this.game.phaseInterceptor.to(EncounterPhase);
|
await this.game.phaseInterceptor.to(EncounterPhase);
|
||||||
|
|
||||||
if (overrides.OPP_HELD_ITEMS_OVERRIDE.length === 0 && this.game.override.removeEnemyStartingItems) {
|
if (overrides.ENEMY_HELD_ITEMS_OVERRIDE.length === 0 && this.game.override.removeEnemyStartingItems) {
|
||||||
this.game.removeEnemyHeldItems();
|
this.game.removeEnemyHeldItems();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,8 +228,8 @@ export class MoveHelper extends GameManagerHelper {
|
|||||||
console.warn("Player moveset override disabled due to use of `game.move.changeMoveset`!");
|
console.warn("Player moveset override disabled due to use of `game.move.changeMoveset`!");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (coerceArray(Overrides.OPP_MOVESET_OVERRIDE).length > 0) {
|
if (coerceArray(Overrides.ENEMY_MOVESET_OVERRIDE).length > 0) {
|
||||||
vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([]);
|
vi.spyOn(Overrides, "ENEMY_MOVESET_OVERRIDE", "get").mockReturnValue([]);
|
||||||
console.warn("Enemy moveset override disabled due to use of `game.move.changeMoveset`!");
|
console.warn("Enemy moveset override disabled due to use of `game.move.changeMoveset`!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -302,8 +302,8 @@ export class MoveHelper extends GameManagerHelper {
|
|||||||
(this.game.scene.phaseManager.getCurrentPhase() as EnemyCommandPhase).getFieldIndex()
|
(this.game.scene.phaseManager.getCurrentPhase() as EnemyCommandPhase).getFieldIndex()
|
||||||
];
|
];
|
||||||
|
|
||||||
if ([Overrides.OPP_MOVESET_OVERRIDE].flat().length > 0) {
|
if ([Overrides.ENEMY_MOVESET_OVERRIDE].flat().length > 0) {
|
||||||
vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([]);
|
vi.spyOn(Overrides, "ENEMY_MOVESET_OVERRIDE", "get").mockReturnValue([]);
|
||||||
console.warn(
|
console.warn(
|
||||||
"Warning: `forceEnemyMove` overwrites the Pokemon's moveset and disables the enemy moveset override!",
|
"Warning: `forceEnemyMove` overwrites the Pokemon's moveset and disables the enemy moveset override!",
|
||||||
);
|
);
|
||||||
|
@ -406,7 +406,7 @@ export class OverridesHelper extends GameManagerHelper {
|
|||||||
* @returns `this`
|
* @returns `this`
|
||||||
*/
|
*/
|
||||||
public enemySpecies(species: SpeciesId | number): this {
|
public enemySpecies(species: SpeciesId | number): this {
|
||||||
vi.spyOn(Overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(species);
|
vi.spyOn(Overrides, "ENEMY_SPECIES_OVERRIDE", "get").mockReturnValue(species);
|
||||||
this.log(`Enemy Pokemon species set to ${SpeciesId[species]} (=${species})!`);
|
this.log(`Enemy Pokemon species set to ${SpeciesId[species]} (=${species})!`);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -416,7 +416,7 @@ export class OverridesHelper extends GameManagerHelper {
|
|||||||
* @returns `this`
|
* @returns `this`
|
||||||
*/
|
*/
|
||||||
public enableEnemyFusion(): this {
|
public enableEnemyFusion(): this {
|
||||||
vi.spyOn(Overrides, "OPP_FUSION_OVERRIDE", "get").mockReturnValue(true);
|
vi.spyOn(Overrides, "ENEMY_FUSION_OVERRIDE", "get").mockReturnValue(true);
|
||||||
this.log("Enemy Pokemon is a random fusion!");
|
this.log("Enemy Pokemon is a random fusion!");
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -427,7 +427,7 @@ export class OverridesHelper extends GameManagerHelper {
|
|||||||
* @returns `this`
|
* @returns `this`
|
||||||
*/
|
*/
|
||||||
public enemyFusionSpecies(species: SpeciesId | number): this {
|
public enemyFusionSpecies(species: SpeciesId | number): this {
|
||||||
vi.spyOn(Overrides, "OPP_FUSION_SPECIES_OVERRIDE", "get").mockReturnValue(species);
|
vi.spyOn(Overrides, "ENEMY_FUSION_SPECIES_OVERRIDE", "get").mockReturnValue(species);
|
||||||
this.log(`Enemy Pokemon fusion species set to ${SpeciesId[species]} (=${species})!`);
|
this.log(`Enemy Pokemon fusion species set to ${SpeciesId[species]} (=${species})!`);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -438,7 +438,7 @@ export class OverridesHelper extends GameManagerHelper {
|
|||||||
* @returns `this`
|
* @returns `this`
|
||||||
*/
|
*/
|
||||||
public enemyAbility(ability: AbilityId): this {
|
public enemyAbility(ability: AbilityId): this {
|
||||||
vi.spyOn(Overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(ability);
|
vi.spyOn(Overrides, "ENEMY_ABILITY_OVERRIDE", "get").mockReturnValue(ability);
|
||||||
this.log(`Enemy Pokemon ability set to ${AbilityId[ability]} (=${ability})!`);
|
this.log(`Enemy Pokemon ability set to ${AbilityId[ability]} (=${ability})!`);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -449,7 +449,7 @@ export class OverridesHelper extends GameManagerHelper {
|
|||||||
* @returns `this`
|
* @returns `this`
|
||||||
*/
|
*/
|
||||||
public enemyPassiveAbility(passiveAbility: AbilityId): this {
|
public enemyPassiveAbility(passiveAbility: AbilityId): this {
|
||||||
vi.spyOn(Overrides, "OPP_PASSIVE_ABILITY_OVERRIDE", "get").mockReturnValue(passiveAbility);
|
vi.spyOn(Overrides, "ENEMY_PASSIVE_ABILITY_OVERRIDE", "get").mockReturnValue(passiveAbility);
|
||||||
this.log(`Enemy Pokemon PASSIVE ability set to ${AbilityId[passiveAbility]} (=${passiveAbility})!`);
|
this.log(`Enemy Pokemon PASSIVE ability set to ${AbilityId[passiveAbility]} (=${passiveAbility})!`);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -460,7 +460,7 @@ export class OverridesHelper extends GameManagerHelper {
|
|||||||
* @returns `this`
|
* @returns `this`
|
||||||
*/
|
*/
|
||||||
public enemyHasPassiveAbility(hasPassiveAbility: boolean | null): this {
|
public enemyHasPassiveAbility(hasPassiveAbility: boolean | null): this {
|
||||||
vi.spyOn(Overrides, "OPP_HAS_PASSIVE_ABILITY_OVERRIDE", "get").mockReturnValue(hasPassiveAbility);
|
vi.spyOn(Overrides, "ENEMY_HAS_PASSIVE_ABILITY_OVERRIDE", "get").mockReturnValue(hasPassiveAbility);
|
||||||
if (hasPassiveAbility === null) {
|
if (hasPassiveAbility === null) {
|
||||||
this.log("Enemy Pokemon PASSIVE ability no longer force enabled or disabled!");
|
this.log("Enemy Pokemon PASSIVE ability no longer force enabled or disabled!");
|
||||||
} else {
|
} else {
|
||||||
@ -475,7 +475,7 @@ export class OverridesHelper extends GameManagerHelper {
|
|||||||
* @returns `this`
|
* @returns `this`
|
||||||
*/
|
*/
|
||||||
public enemyMoveset(moveset: MoveId | MoveId[]): this {
|
public enemyMoveset(moveset: MoveId | MoveId[]): this {
|
||||||
vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue(moveset);
|
vi.spyOn(Overrides, "ENEMY_MOVESET_OVERRIDE", "get").mockReturnValue(moveset);
|
||||||
moveset = coerceArray(moveset);
|
moveset = coerceArray(moveset);
|
||||||
const movesetStr = moveset.map(moveId => MoveId[moveId]).join(", ");
|
const movesetStr = moveset.map(moveId => MoveId[moveId]).join(", ");
|
||||||
this.log(`Enemy Pokemon moveset set to ${movesetStr} (=[${moveset.join(", ")}])!`);
|
this.log(`Enemy Pokemon moveset set to ${movesetStr} (=[${moveset.join(", ")}])!`);
|
||||||
@ -488,7 +488,7 @@ export class OverridesHelper extends GameManagerHelper {
|
|||||||
* @returns `this`
|
* @returns `this`
|
||||||
*/
|
*/
|
||||||
public enemyLevel(level: number): this {
|
public enemyLevel(level: number): this {
|
||||||
vi.spyOn(Overrides, "OPP_LEVEL_OVERRIDE", "get").mockReturnValue(level);
|
vi.spyOn(Overrides, "ENEMY_LEVEL_OVERRIDE", "get").mockReturnValue(level);
|
||||||
this.log(`Enemy Pokemon level set to ${level}!`);
|
this.log(`Enemy Pokemon level set to ${level}!`);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -499,7 +499,7 @@ export class OverridesHelper extends GameManagerHelper {
|
|||||||
* @returns `this`
|
* @returns `this`
|
||||||
*/
|
*/
|
||||||
public enemyStatusEffect(statusEffect: StatusEffect): this {
|
public enemyStatusEffect(statusEffect: StatusEffect): this {
|
||||||
vi.spyOn(Overrides, "OPP_STATUS_OVERRIDE", "get").mockReturnValue(statusEffect);
|
vi.spyOn(Overrides, "ENEMY_STATUS_OVERRIDE", "get").mockReturnValue(statusEffect);
|
||||||
this.log(`Enemy Pokemon status-effect set to ${StatusEffect[statusEffect]} (=${statusEffect})!`);
|
this.log(`Enemy Pokemon status-effect set to ${StatusEffect[statusEffect]} (=${statusEffect})!`);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -510,7 +510,7 @@ export class OverridesHelper extends GameManagerHelper {
|
|||||||
* @returns `this`
|
* @returns `this`
|
||||||
*/
|
*/
|
||||||
public enemyHeldItems(items: ModifierOverride[]): this {
|
public enemyHeldItems(items: ModifierOverride[]): this {
|
||||||
vi.spyOn(Overrides, "OPP_HELD_ITEMS_OVERRIDE", "get").mockReturnValue(items);
|
vi.spyOn(Overrides, "ENEMY_HELD_ITEMS_OVERRIDE", "get").mockReturnValue(items);
|
||||||
this.log("Enemy Pokemon held items set to:", items);
|
this.log("Enemy Pokemon held items set to:", items);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -571,7 +571,7 @@ export class OverridesHelper extends GameManagerHelper {
|
|||||||
* @param variant - (Optional) The enemy's shiny {@linkcode Variant}.
|
* @param variant - (Optional) The enemy's shiny {@linkcode Variant}.
|
||||||
*/
|
*/
|
||||||
enemyShiny(shininess: boolean | null, variant?: Variant): this {
|
enemyShiny(shininess: boolean | null, variant?: Variant): this {
|
||||||
vi.spyOn(Overrides, "OPP_SHINY_OVERRIDE", "get").mockReturnValue(shininess);
|
vi.spyOn(Overrides, "ENEMY_SHINY_OVERRIDE", "get").mockReturnValue(shininess);
|
||||||
if (shininess === null) {
|
if (shininess === null) {
|
||||||
this.log("Disabled enemy Pokemon shiny override!");
|
this.log("Disabled enemy Pokemon shiny override!");
|
||||||
} else {
|
} else {
|
||||||
@ -579,7 +579,7 @@ export class OverridesHelper extends GameManagerHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (variant !== undefined) {
|
if (variant !== undefined) {
|
||||||
vi.spyOn(Overrides, "OPP_VARIANT_OVERRIDE", "get").mockReturnValue(variant);
|
vi.spyOn(Overrides, "ENEMY_VARIANT_OVERRIDE", "get").mockReturnValue(variant);
|
||||||
this.log(`Set enemy shiny variant to be ${variant}!`);
|
this.log(`Set enemy shiny variant to be ${variant}!`);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
@ -594,7 +594,7 @@ export class OverridesHelper extends GameManagerHelper {
|
|||||||
* @returns `this`
|
* @returns `this`
|
||||||
*/
|
*/
|
||||||
public enemyHealthSegments(healthSegments: number): this {
|
public enemyHealthSegments(healthSegments: number): this {
|
||||||
vi.spyOn(Overrides, "OPP_HEALTH_SEGMENTS_OVERRIDE", "get").mockReturnValue(healthSegments);
|
vi.spyOn(Overrides, "ENEMY_HEALTH_SEGMENTS_OVERRIDE", "get").mockReturnValue(healthSegments);
|
||||||
this.log("Enemy Pokemon health segments set to:", healthSegments);
|
this.log("Enemy Pokemon health segments set to:", healthSegments);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ export function toHaveUsedPP(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const override = received.isPlayer() ? Overrides.MOVESET_OVERRIDE : Overrides.OPP_MOVESET_OVERRIDE;
|
const override = received.isPlayer() ? Overrides.MOVESET_OVERRIDE : Overrides.ENEMY_MOVESET_OVERRIDE;
|
||||||
if (coerceArray(override).length > 0) {
|
if (coerceArray(override).length > 0) {
|
||||||
return {
|
return {
|
||||||
pass: false,
|
pass: false,
|
||||||
|
Loading…
Reference in New Issue
Block a user