Compare commits

...

13 Commits

Author SHA1 Message Date
Jakub Hanko
caeb22c26b
Implement Honey Gather (#1360)
* Implement Honey Gather

* Updated Ability Description

---------

Co-authored-by: Benjamin Odom <bennybroseph@gmail.com>
2024-05-25 08:01:08 -05:00
Jannik Tappert
aaa96ebe0e
Adding the option to have named trainers be able to have a double battle together (#1318)
* WIP: Adding the option to have named trainers be able to have a double battle together

* The team generation now works.
Also changed it so the special pools are now seperatly defined so we can access it for the team generation of the doubles.

They will happen at a 33% chance.

TODO: Option for seperate double dialogue (because for example the dialogue for tate and liza dont make sense since they reference their other sibling not beeing there...)

* Obviously didnt mean to push changes to battle.ts... (I made this change for a test)

* The doubles now have victory and encounter dialogue (the dialogue itself isnt THAT good since english isnt my first language)

* Changed signatureSpecies for the new galar elite 4

* Added Marnie & Piers as a double

* ESLint

---------

Co-authored-by: Benjamin Odom <bennybroseph@gmail.com>
2024-05-25 07:47:18 -05:00
Tempoanon
49c365f154
Make iv scanner check against baby form IVs (#1214) 2024-05-25 06:47:26 -05:00
Jannik Tappert
b524be1db1
Issue #1118 Added Galar Elite 4 (#1246)
Co-authored-by: Benjamin Odom <bennybroseph@gmail.com>
2024-05-25 06:38:59 -05:00
td76099
c4c4774528
Beat Up checks the user's party instead of always checking player's party (#1268) 2024-05-25 06:31:04 -05:00
innerthunder
4ffff8e1ee
Implement Quick Guard and other conditional team protection moves (#1275)
* Implement conditional protection arena tag

Affected moves:
- Quick Guard
- Wide Guard
- Mat Block
- Crafty Shield
- Feint (updated)

* Add support for moves that ignore Protect to conditional protection moves

* Comments for protect arena tags

* ESLint

---------

Co-authored-by: Benjamin Odom <bennybroseph@gmail.com>
2024-05-25 06:22:10 -05:00
ReneGV
5c327e347a
Implement Purify (#1291)
* Implement purify

* Code review fixes

* Remove vitest import

* Update status-effect.ts

* Update status-effect.ts

---------

Co-authored-by: Benjamin Odom <bennybroseph@gmail.com>
2024-05-25 06:01:23 -05:00
神龟
79f69ddfe0
Update move.ts (#1359) 2024-05-25 05:43:42 -05:00
LaukkaE
0da469d7a3
Fix Wind Rider (#607)
Fix Wind Rider
2024-05-25 05:32:32 -05:00
arColm
ae2928e1c9
Implement Poison Puppeteer (#320)
Co-authored-by: Benjamin Odom <bennybroseph@gmail.com>
2024-05-25 04:51:36 -05:00
Franck TROUILLEZ
37ebbd28d5
Apply offset to baseY as well during Pokemon#setMini (#1357)
This fixes an issue where this.baseY and this.y were not sync anymore, leading to unexpected behavior while using both values, especially during the selectTargetPhase, where the UI was not working for the first player pokemon.
2024-05-25 04:45:47 -05:00
Tempoanon
d71451fc23
Players win if classic and past floor 200 (#1348)
* Players win if classic and past floor 200

* isClassic

* no need to handle game over twice
2024-05-25 04:36:30 -05:00
Jannik Tappert
34474fb10e
German Loc for the menu.ts change (#1354) 2024-05-25 04:36:14 -05:00
33 changed files with 1247 additions and 333 deletions

View File

@ -11,6 +11,7 @@ import { BattleSpec } from "./enums/battle-spec";
import { PlayerGender } from "./system/game-data"; import { PlayerGender } from "./system/game-data";
import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier"; import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier";
import { PokeballType } from "./data/pokeball"; import { PokeballType } from "./data/pokeball";
import {trainerConfigs} from "#app/data/trainer-config";
export enum BattleType { export enum BattleType {
WILD, WILD,
@ -309,6 +310,10 @@ function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[]): Get
: trainerPoolEntry; : trainerPoolEntry;
trainerTypes.push(trainerType); trainerTypes.push(trainerType);
} }
// If the trainer type has a double variant, there's a 33% chance of it being a double battle
if (trainerConfigs[trainerTypes[rand]].trainerTypeDouble) {
return new Trainer(scene, trainerTypes[rand], Utils.randSeedInt(3) ? TrainerVariant.DOUBLE : TrainerVariant.DEFAULT);
}
return new Trainer(scene, trainerTypes[rand], TrainerVariant.DEFAULT); return new Trainer(scene, trainerTypes[rand], TrainerVariant.DEFAULT);
}; };
} }
@ -331,15 +336,15 @@ export const fixedBattles: FixedBattleConfigs = {
[145]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) [145]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_5, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)), .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_5, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
[182]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) [182]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.LORELEI, TrainerType.WILL, TrainerType.SIDNEY, TrainerType.AARON, TrainerType.SHAUNTAL, TrainerType.MALVA, [ TrainerType.HALA, TrainerType.MOLAYNE ], TrainerType.RIKA, TrainerType.CRISPIN ])), .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.LORELEI, TrainerType.WILL, TrainerType.SIDNEY, TrainerType.AARON, TrainerType.SHAUNTAL, TrainerType.MALVA, [ TrainerType.HALA, TrainerType.MOLAYNE ],TrainerType.MARNIE_ELITE, TrainerType.RIKA, TrainerType.CRISPIN ])),
[184]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182) [184]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182)
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.BRUNO, TrainerType.KOGA, TrainerType.PHOEBE, TrainerType.BERTHA, TrainerType.MARSHAL, TrainerType.SIEBOLD, TrainerType.OLIVIA, TrainerType.POPPY, TrainerType.AMARYS ])), .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.BRUNO, TrainerType.KOGA, TrainerType.PHOEBE, TrainerType.BERTHA, TrainerType.MARSHAL, TrainerType.SIEBOLD, TrainerType.OLIVIA, TrainerType.NESSA_ELITE, TrainerType.POPPY, TrainerType.AMARYS ])),
[186]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182) [186]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182)
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.AGATHA, TrainerType.BRUNO, TrainerType.GLACIA, TrainerType.FLINT, TrainerType.GRIMSLEY, TrainerType.WIKSTROM, TrainerType.ACEROLA, TrainerType.LARRY_ELITE, TrainerType.LACEY ])), .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.AGATHA, TrainerType.BRUNO, TrainerType.GLACIA, TrainerType.FLINT, TrainerType.GRIMSLEY, TrainerType.WIKSTROM, TrainerType.ACEROLA, [TrainerType.BEA_ELITE,TrainerType.ALLISTER_ELITE], TrainerType.LARRY_ELITE, TrainerType.LACEY ])),
[188]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182) [188]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182)
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.LANCE, TrainerType.KAREN, TrainerType.DRAKE, TrainerType.LUCIAN, TrainerType.CAITLIN, TrainerType.DRASNA, TrainerType.KAHILI, TrainerType.HASSEL, TrainerType.DRAYTON ])), .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.LANCE, TrainerType.KAREN, TrainerType.DRAKE, TrainerType.LUCIAN, TrainerType.CAITLIN, TrainerType.DRASNA, TrainerType.KAHILI,TrainerType.RAIHAN_ELITE, TrainerType.HASSEL, TrainerType.DRAYTON ])),
[190]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182) [190]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182)
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.BLUE, [ TrainerType.RED, TrainerType.LANCE_CHAMPION ], [ TrainerType.STEVEN, TrainerType.WALLACE ], TrainerType.CYNTHIA, [ TrainerType.ALDER, TrainerType.IRIS ], TrainerType.DIANTHA, TrainerType.HAU, [ TrainerType.GEETA, TrainerType.NEMONA ], TrainerType.KIERAN, TrainerType.LEON ])), .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.BLUE, [ TrainerType.RED, TrainerType.LANCE_CHAMPION ], [ TrainerType.STEVEN, TrainerType.WALLACE ], TrainerType.CYNTHIA, [ TrainerType.ALDER, TrainerType.IRIS ], TrainerType.DIANTHA, TrainerType.HAU,TrainerType.LEON, [ TrainerType.GEETA, TrainerType.NEMONA ], TrainerType.KIERAN])),
[195]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) [195]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_6, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)) .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_6, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
}; };

View File

@ -20,8 +20,9 @@ import { SpeciesFormChangeManualTrigger } from "./pokemon-forms";
import { Abilities } from "./enums/abilities"; import { Abilities } from "./enums/abilities";
import i18next, { Localizable } from "#app/plugins/i18n.js"; import i18next, { Localizable } from "#app/plugins/i18n.js";
import { Command } from "../ui/command-ui-handler"; import { Command } from "../ui/command-ui-handler";
import { getPokeballName } from "./pokeball";
import { BerryModifierType } from "#app/modifier/modifier-type"; import { BerryModifierType } from "#app/modifier/modifier-type";
import { getPokeballName } from "./pokeball";
import { Species } from "./enums/species";
import {BattlerIndex} from "#app/battle"; import {BattlerIndex} from "#app/battle";
export class Ability implements Localizable { export class Ability implements Localizable {
@ -555,8 +556,11 @@ export class MoveImmunityStatChangeAbAttr extends MoveImmunityAbAttr {
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean { applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean {
const ret = super.applyPreDefend(pokemon, passive, attacker, move, cancelled, args); const ret = super.applyPreDefend(pokemon, passive, attacker, move, cancelled, args);
if (ret) { if (ret) {
const simulated = args.length > 1 && args[1];
if (!simulated) {
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ this.stat ], this.levels)); pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ this.stat ], this.levels));
} }
}
return ret; return ret;
} }
@ -1778,6 +1782,39 @@ export class ProtectStatAbAttr extends PreStatChangeAbAttr {
} }
} }
/**
* This attribute applies confusion to the target whenever the user
* directly poisons them with a move, e.g. Poison Puppeteer.
* Called in {@linkcode StatusEffectAttr}.
* @extends PostAttackAbAttr
* @see {@linkcode applyPostAttack}
*/
export class ConfusionOnStatusEffectAbAttr extends PostAttackAbAttr {
/** List of effects to apply confusion after */
private effects: StatusEffect[];
constructor(...effects: StatusEffect[]) {
super();
this.effects = effects;
}
/**
* Applies confusion to the target pokemon.
* @param pokemon {@link Pokemon} attacking
* @param passive N/A
* @param defender {@link Pokemon} defending
* @param move {@link Move} used to apply status effect and confusion
* @param hitResult N/A
* @param args [0] {@linkcode StatusEffect} applied by move
* @returns true if defender is confused
*/
applyPostAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean {
if (this.effects.indexOf(args[0]) > -1 && !defender.isFainted()) {
return defender.addTag(BattlerTagType.CONFUSED, pokemon.randSeedInt(3,2), move.moveId, defender.id);
}
return false;
}
}
export class PreSetStatusAbAttr extends AbAttr { export class PreSetStatusAbAttr extends AbAttr {
applyPreSetStatus(pokemon: Pokemon, passive: boolean, effect: StatusEffect, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise<boolean> { applyPreSetStatus(pokemon: Pokemon, passive: boolean, effect: StatusEffect, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise<boolean> {
return false; return false;
@ -2975,6 +3012,29 @@ export class IgnoreTypeStatusEffectImmunityAbAttr extends AbAttr {
} }
} }
/**
* Gives money to the user after the battle.
*
* @extends PostBattleAbAttr
* @see {@linkcode applyPostBattle}
*/
export class MoneyAbAttr extends PostBattleAbAttr {
constructor() {
super();
}
/**
* @param pokemon {@linkcode Pokemon} that is the user of this ability.
* @param passive N/A
* @param args N/A
* @returns true
*/
applyPostBattle(pokemon: Pokemon, passive: boolean, args: any[]): boolean {
pokemon.scene.currentBattle.moneyScattered += pokemon.scene.getWaveMoneyAmount(0.2);
return true;
}
}
function applyAbAttrsInternal<TAttr extends AbAttr>(attrType: { new(...args: any[]): TAttr }, function applyAbAttrsInternal<TAttr extends AbAttr>(attrType: { new(...args: any[]): TAttr },
pokemon: Pokemon, applyFunc: AbAttrApplyFunc<TAttr>, args: any[], isAsync: boolean = false, showAbilityInstant: boolean = false, quiet: boolean = false, passive: boolean = false): Promise<void> { pokemon: Pokemon, applyFunc: AbAttrApplyFunc<TAttr>, args: any[], isAsync: boolean = false, showAbilityInstant: boolean = false, quiet: boolean = false, passive: boolean = false): Promise<void> {
return new Promise(resolve => { return new Promise(resolve => {
@ -3520,7 +3580,7 @@ export function initAbilities() {
.attr(PostSummonWeatherChangeAbAttr, WeatherType.SNOW) .attr(PostSummonWeatherChangeAbAttr, WeatherType.SNOW)
.attr(PostBiomeChangeWeatherChangeAbAttr, WeatherType.SNOW), .attr(PostBiomeChangeWeatherChangeAbAttr, WeatherType.SNOW),
new Ability(Abilities.HONEY_GATHER, 4) new Ability(Abilities.HONEY_GATHER, 4)
.unimplemented(), .attr(MoneyAbAttr),
new Ability(Abilities.FRISK, 4) new Ability(Abilities.FRISK, 4)
.attr(FriskAbAttr), .attr(FriskAbAttr),
new Ability(Abilities.RECKLESS, 4) new Ability(Abilities.RECKLESS, 4)
@ -4155,6 +4215,6 @@ export function initAbilities() {
new Ability(Abilities.POISON_PUPPETEER, 9) new Ability(Abilities.POISON_PUPPETEER, 9)
.attr(UncopiableAbilityAbAttr) .attr(UncopiableAbilityAbAttr)
.attr(UnswappableAbilityAbAttr) .attr(UnswappableAbilityAbAttr)
.unimplemented(), .conditionalAttr(pokemon => pokemon.species.speciesId===Species.PECHARUNT,ConfusionOnStatusEffectAbAttr,StatusEffect.POISON,StatusEffect.TOXIC)
); );
} }

View File

@ -1,7 +1,7 @@
import { Arena } from "../field/arena"; import { Arena } from "../field/arena";
import { Type } from "./type"; import { Type } from "./type";
import * as Utils from "../utils"; import * as Utils from "../utils";
import { MoveCategory, allMoves } from "./move"; import { MoveCategory, allMoves, MoveTarget } from "./move";
import { getPokemonMessage } from "../messages"; import { getPokemonMessage } from "../messages";
import Pokemon, { HitResult, PokemonMove } from "../field/pokemon"; import Pokemon, { HitResult, PokemonMove } from "../field/pokemon";
import { MoveEffectPhase, PokemonHealPhase, StatChangePhase} from "../phases"; import { MoveEffectPhase, PokemonHealPhase, StatChangePhase} from "../phases";
@ -11,6 +11,7 @@ import { Moves } from "./enums/moves";
import { ArenaTagType } from "./enums/arena-tag-type"; import { ArenaTagType } from "./enums/arena-tag-type";
import { BlockNonDirectDamageAbAttr, ProtectStatAbAttr, applyAbAttrs } from "./ability"; import { BlockNonDirectDamageAbAttr, ProtectStatAbAttr, applyAbAttrs } from "./ability";
import { BattleStat } from "./battle-stat"; import { BattleStat } from "./battle-stat";
import { CommonAnim, CommonBattleAnim } from "./battle-anims";
export enum ArenaTagSide { export enum ArenaTagSide {
BOTH, BOTH,
@ -146,6 +147,128 @@ class AuroraVeilTag extends WeakenMoveScreenTag {
} }
} }
type ProtectConditionFunc = (...args: any[]) => boolean;
/**
* Abstract class to implement conditional team protection
* applies protection based on the attributes of incoming moves
* @param protectConditionFunc: The function determining if an incoming move is negated
*/
abstract class ConditionalProtectTag extends ArenaTag {
protected protectConditionFunc: ProtectConditionFunc;
constructor(tagType: ArenaTagType, sourceMove: Moves, sourceId: integer, side: ArenaTagSide, condition: ProtectConditionFunc) {
super(tagType, 1, sourceMove, sourceId, side);
this.protectConditionFunc = condition;
}
onAdd(arena: Arena): void {
arena.scene.queueMessage(`${super.getMoveName()} protected${this.side === ArenaTagSide.PLAYER ? " your" : this.side === ArenaTagSide.ENEMY ? " the\nopposing" : ""} team!`);
}
// Removes default message for effect removal
onRemove(arena: Arena): void { }
/**
* apply(): Checks incoming moves against the condition function
* and protects the target if conditions are met
* @param arena The arena containing this tag
* @param args[0] (Utils.BooleanHolder) Signals if the move is cancelled
* @param args[1] (Pokemon) The intended target of the move
* @param args[2...] (any[]) The parameters to the condition function
* @returns
*/
apply(arena: Arena, args: any[]): boolean {
if ((args[0] as Utils.BooleanHolder).value) {
return false;
}
const target = args[1] as Pokemon;
if ((this.side === ArenaTagSide.PLAYER) === target.isPlayer()
&& this.protectConditionFunc(...args.slice(2))) {
(args[0] as Utils.BooleanHolder).value = true;
new CommonBattleAnim(CommonAnim.PROTECT, target).play(arena.scene);
arena.scene.queueMessage(`${super.getMoveName()} protected ${getPokemonMessage(target, "!")}`);
return true;
}
return false;
}
}
/**
* Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Quick_Guard_(move) Quick Guard}
* Condition: The incoming move has increased priority.
*/
class QuickGuardTag extends ConditionalProtectTag {
constructor(sourceId: integer, side: ArenaTagSide) {
super(ArenaTagType.QUICK_GUARD, Moves.QUICK_GUARD, sourceId, side,
(priority: integer) : boolean => {
return priority > 0;
}
);
}
}
/**
* Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Wide_Guard_(move) Wide Guard}
* Condition: The incoming move can target multiple Pokemon. The move's source
* can be an ally or enemy.
*/
class WideGuardTag extends ConditionalProtectTag {
constructor(sourceId: integer, side: ArenaTagSide) {
super(ArenaTagType.WIDE_GUARD, Moves.WIDE_GUARD, sourceId, side,
(moveTarget: MoveTarget) : boolean => {
switch (moveTarget) {
case MoveTarget.ALL_ENEMIES:
case MoveTarget.ALL_NEAR_ENEMIES:
case MoveTarget.ALL_OTHERS:
case MoveTarget.ALL_NEAR_OTHERS:
return true;
}
return false;
}
);
}
}
/**
* Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Mat_Block_(move) Mat Block}
* Condition: The incoming move is a Physical or Special attack move.
*/
class MatBlockTag extends ConditionalProtectTag {
constructor(sourceId: integer, side: ArenaTagSide) {
super(ArenaTagType.MAT_BLOCK, Moves.MAT_BLOCK, sourceId, side,
(moveCategory: MoveCategory) : boolean => {
return moveCategory !== MoveCategory.STATUS;
}
);
}
onAdd(arena: Arena) {
const source = arena.scene.getPokemonById(this.sourceId);
arena.scene.queueMessage(getPokemonMessage(source, " intends to flip up a mat\nand block incoming attacks!"));
}
}
/**
* Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Crafty_Shield_(move) Crafty Shield}
* Condition: The incoming move is a Status move, is not a hazard, and does
* not target all Pokemon or sides of the field.
*/
class CraftyShieldTag extends ConditionalProtectTag {
constructor(sourceId: integer, side: ArenaTagSide) {
super(ArenaTagType.CRAFTY_SHIELD, Moves.CRAFTY_SHIELD, sourceId, side,
(moveCategory: MoveCategory, moveTarget: MoveTarget) : boolean => {
return moveCategory === MoveCategory.STATUS
&& moveTarget !== MoveTarget.ENEMY_SIDE
&& moveTarget !== MoveTarget.BOTH_SIDES
&& moveTarget !== MoveTarget.ALL;
}
);
}
}
class WishTag extends ArenaTag { class WishTag extends ArenaTag {
private battlerIndex: BattlerIndex; private battlerIndex: BattlerIndex;
private triggerMessage: string; private triggerMessage: string;
@ -513,6 +636,14 @@ export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMov
switch (tagType) { switch (tagType) {
case ArenaTagType.MIST: case ArenaTagType.MIST:
return new MistTag(turnCount, sourceId, side); return new MistTag(turnCount, sourceId, side);
case ArenaTagType.QUICK_GUARD:
return new QuickGuardTag(sourceId, side);
case ArenaTagType.WIDE_GUARD:
return new WideGuardTag(sourceId, side);
case ArenaTagType.MAT_BLOCK:
return new MatBlockTag(sourceId, side);
case ArenaTagType.CRAFTY_SHIELD:
return new CraftyShieldTag(sourceId, side);
case ArenaTagType.MUD_SPORT: case ArenaTagType.MUD_SPORT:
return new MudSportTag(turnCount, sourceId); return new MudSportTag(turnCount, sourceId);
case ArenaTagType.WATER_SPORT: case ArenaTagType.WATER_SPORT:

View File

@ -2074,6 +2074,76 @@ export const trainerTypeDialogue = {
"Things didn't heat up for you.", "Things didn't heat up for you.",
] ]
}, },
[TrainerType.MARNIE_ELITE]: {
encounter: [
"You've made it this far, huh? Let's see if you can handle my Pokémon!",
"I'll give it my best shot, but don't think I'll go easy on you!",
],
victory: [
"I can't believe I lost... But you deserved that win. Well done!",
"Looks like I've still got a lot to learn. Great battle, though!",
],
defeat: [
"You put up a good fight, but I've got the edge! Better luck next time!",
"Seems like my training's paid off. Thanks for the battle!",
]
},
[TrainerType.NESSA_ELITE]: {
encounter: [
"The tides are turning in my favor. Ready to get swept away?",
"Let's make some waves with this battle! I hope you're prepared!",
],
victory: [
"You navigated those waters perfectly... Well done!",
"Looks like my currents were no match for you. Great job!",
],
defeat: [
"Water always finds a way. That was a refreshing battle!",
"You fought well, but the ocean's power is unstoppable!",
]
},
[TrainerType.BEA_ELITE]: {
encounter: [
"Prepare yourself! My fighting spirit burns bright!",
"Let's see if you can keep up with my relentless pace!",
],
victory: [
"Your strength... It's impressive. You truly deserve this win.",
"I've never felt this intensity before. Amazing job!",
],
defeat: [
"Another victory for my intense training regimen! Well done!",
"You've got strength, but I trained harder. Great battle!",
]
},
[TrainerType.ALLISTER_ELITE]: {
encounter: [
"Shadows fall... Are you ready to face your fears?",
"Let's see if you can handle the darkness that I command.",
],
victory: [
"You've dispelled the shadows... For now. Well done.",
"Your light pierced through my darkness. Great job.",
],
defeat: [
"The shadows have spoken... Your strength isn't enough.",
"Darkness triumphs... Maybe next time you'll see the light.",
]
},
[TrainerType.RAIHAN_ELITE]: {
encounter: [
"Storm's brewing! Let's see if you can weather this fight!",
"Get ready to face the eye of the storm!",
],
victory: [
"You've bested the storm... Incredible job!",
"You rode the winds perfectly... Great battle!",
],
defeat: [
"Another storm weathered, another victory claimed! Well fought!",
"You got caught in my storm! Better luck next time!",
]
},
[TrainerType.RIVAL]: [ [TrainerType.RIVAL]: [
{ {
encounter: [ encounter: [
@ -2276,6 +2346,124 @@ export const trainerTypeDialogue = {
] ]
}; };
export const doubleBattleDialogue = {
"blue_red_double": {
encounter: [
`Blue: Hey Red, let's show them what we're made of!
$Red: ...
$Blue: This is Pallet Town Power!`,
],
victory: [
`Blue: That was a great battle!
$Red: ...`,
]
},
"red_blue_double": {
encounter: [
`Red: ...!
$Blue: He never talks much.
$Blue: But dont let that fool you! He is a champ after all!`,
],
victory: [
`Red: ...!
$Blue: Next time we will beat you!`,]
},
"tate_liza_double": {
encounter: [
`Tate: Are you suprised?
$Liza: We are two gym leaders at once!
$Tate: We are twins!
$Liza: We dont need to talk to understand each other!
$Tate: Twice the power...
$Liza: Can you handle it?`,
],
victory: [
`Tate: What? Our combination was perfect!
$Liza: Looks like we need to train more...`,
]
},
"liza_tate_double": {
encounter: [
`Liza: Hihihi... Are you suprised?
$Tate: Yes, we are really two gym leaders at once!
$Liza: This is my twin brother Tate!
$Tate: And this is my twin sister Liza!
$Liza: Don't you think we are a perfect combination?`
],
victory: [
`Liza: Are we...
$Tate: ...not as strong as we thought?`,
]
},
"wallace_steven_double": {
encounter: [
`Steven: Wallace, let's show them the power of the champions!
$Wallace: We will show you the power of Hoenn!
$Steven: Let's go!`,
],
victory: [
`Steven: That was a great battle!
$Wallace: We will win next time!`,
]
},
"steven_wallace_double": {
encounter: [
`Steven: Do you have any rare pokémon?
$Wallace: Steven... We are here for a battle, not to show off our pokémon.
$Steven: Oh... I see... Let's go then!`,
],
victory: [
`Steven: Now that we are done with the battle, let's show off our pokémon!
$Wallace: Steven...`,
]
},
"alder_iris_double": {
encounter: [
`Alder: We are the strongest trainers in Unova!
$Iris: Fights against strong trainers are the best!`,
],
victory: [
`Alder: Wow! You are super strong!
$Iris: We will win next time!`,
]
},
"iris_alder_double": {
encounter: [
`Iris: Welcome Challenger! I am THE Unova Champion!
$Alder: Iris, aren't you a bit too excited?`,
],
victory: [
`Iris: A loss like this is not easy to take...
$Alder: But we will only get stronger with every loss!`,
]
},
"marnie_piers_double": {
encounter: [
`Marnie: Brother, let's show them the power of Spikemuth!
$Piers: We bring darkness!`,
],
victory: [
`Marnie: You brought light to our darkness!
$Piers: Its too bright...`,
]
},
"piers_marnie_double": {
encounter: [
`Piers: Ready for a concert?
$Marnie: Brother... They are here to fight, not to sing...`,
],
victory: [
`Piers: Now that was a great concert!
$Marnie: Brother...`,
]
},
};
export const battleSpecDialogue = { export const battleSpecDialogue = {
[BattleSpec.FINAL_BOSS]: { [BattleSpec.FINAL_BOSS]: {
encounter: `It appears the time has finally come once again.\nYou know why you have come here, do you not? encounter: `It appears the time has finally come once again.\nYou know why you have come here, do you not?

View File

@ -16,5 +16,9 @@ export enum ArenaTagType {
REFLECT = "REFLECT", REFLECT = "REFLECT",
LIGHT_SCREEN = "LIGHT_SCREEN", LIGHT_SCREEN = "LIGHT_SCREEN",
AURORA_VEIL = "AURORA_VEIL", AURORA_VEIL = "AURORA_VEIL",
QUICK_GUARD = "QUICK_GUARD",
WIDE_GUARD = "WIDE_GUARD",
MAT_BLOCK = "MAT_BLOCK",
CRAFTY_SHIELD = "CRAFTY_SHIELD",
TAILWIND = "TAILWIND" TAILWIND = "TAILWIND"
} }

View File

@ -153,6 +153,11 @@ export enum TrainerType {
OLIVIA, OLIVIA,
ACEROLA, ACEROLA,
KAHILI, KAHILI,
MARNIE_ELITE,
NESSA_ELITE,
BEA_ELITE,
ALLISTER_ELITE,
RAIHAN_ELITE,
RIKA, RIKA,
POPPY, POPPY,
LARRY_ELITE, LARRY_ELITE,

77
src/data/move.ts Normal file → Executable file
View File

@ -6,13 +6,13 @@ import { EncoreTag } from "./battler-tags";
import { BattlerTagType } from "./enums/battler-tag-type"; import { BattlerTagType } from "./enums/battler-tag-type";
import { getPokemonMessage } from "../messages"; import { getPokemonMessage } from "../messages";
import Pokemon, { AttackMoveResult, EnemyPokemon, HitResult, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "../field/pokemon"; import Pokemon, { AttackMoveResult, EnemyPokemon, HitResult, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "../field/pokemon";
import { StatusEffect, getStatusEffectHealText } from "./status-effect"; import { StatusEffect, getStatusEffectHealText, isNonVolatileStatusEffect, getNonVolatileStatusEffects} from "./status-effect";
import { Type } from "./type"; import { Type } from "./type";
import * as Utils from "../utils"; import * as Utils from "../utils";
import { WeatherType } from "./weather"; import { WeatherType } from "./weather";
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag"; import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
import { ArenaTagType } from "./enums/arena-tag-type"; import { ArenaTagType } from "./enums/arena-tag-type";
import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr, MoveAbilityBypassAbAttr, ReverseDrainAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr, BlockItemTheftAbAttr } from "./ability"; import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr, MoveAbilityBypassAbAttr, ReverseDrainAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr, BlockItemTheftAbAttr, applyPostAttackAbAttrs, ConfusionOnStatusEffectAbAttr } from "./ability";
import { Abilities } from "./enums/abilities"; import { Abilities } from "./enums/abilities";
import { allAbilities } from "./ability"; import { allAbilities } from "./ability";
import { PokemonHeldItemModifier, BerryModifier, PreserveBerryModifier } from "../modifier/modifier"; import { PokemonHeldItemModifier, BerryModifier, PreserveBerryModifier } from "../modifier/modifier";
@ -204,6 +204,19 @@ export default class Move implements Localizable {
return false; return false;
} }
isAllyTarget(): boolean {
switch (this.moveTarget) {
case MoveTarget.USER:
case MoveTarget.NEAR_ALLY:
case MoveTarget.ALLY:
case MoveTarget.USER_OR_NEAR_ALLY:
case MoveTarget.USER_AND_ALLIES:
case MoveTarget.USER_SIDE:
return true;
}
return false;
}
isTypeImmune(type: Type): boolean { isTypeImmune(type: Type): boolean {
switch (type) { switch (type) {
case Type.GRASS: case Type.GRASS:
@ -1307,8 +1320,9 @@ export class MultiHitAttr extends MoveAttr {
} }
break; break;
case MultiHitType.BEAT_UP: case MultiHitType.BEAT_UP:
const party = user.isPlayer() ? user.scene.getParty() : user.scene.getEnemyParty();
// No status means the ally pokemon can contribute to Beat Up // No status means the ally pokemon can contribute to Beat Up
hitTimes = user.scene.getParty().reduce((total, pokemon) => { hitTimes = party.reduce((total, pokemon) => {
return total + (pokemon.id === user.id ? 1 : pokemon?.status && pokemon.status.effect !== StatusEffect.NONE ? 0 : 1); return total + (pokemon.id === user.id ? 1 : pokemon?.status && pokemon.status.effect !== StatusEffect.NONE ? 0 : 1);
}, 0); }, 0);
} }
@ -1362,8 +1376,10 @@ export class StatusEffectAttr extends MoveEffectAttr {
return false; return false;
} }
} }
if (!pokemon.status || (pokemon.status.effect === this.effect && move.chance < 0)) { if ((!pokemon.status || (pokemon.status.effect === this.effect && move.chance < 0))
return pokemon.trySetStatus(this.effect, true, user, this.cureTurn); && pokemon.trySetStatus(this.effect, true, user, this.cureTurn)) {
applyPostAttackAbAttrs(ConfusionOnStatusEffectAbAttr, user, target, new PokemonMove(move.id), null,this.effect);
return true;
} }
} }
return false; return false;
@ -2308,7 +2324,7 @@ export class MovePowerMultiplierAttr extends VariablePowerAttr {
* @returns The base power of the Beat Up hit. * @returns The base power of the Beat Up hit.
*/ */
const beatUpFunc = (user: Pokemon, allyIndex: number): number => { const beatUpFunc = (user: Pokemon, allyIndex: number): number => {
const party = user.scene.getParty(); const party = user.isPlayer() ? user.scene.getParty() : user.scene.getEnemyParty();
for (let i = allyIndex; i < party.length; i++) { for (let i = allyIndex; i < party.length; i++) {
const pokemon = party[i]; const pokemon = party[i];
@ -3718,6 +3734,37 @@ export class AddArenaTagAttr extends MoveEffectAttr {
} }
} }
/**
* Generic class for removing arena tags
* @param tagTypes: The types of tags that can be removed
* @param selfSideTarget: Is the user removing tags from its own side?
*/
export class RemoveArenaTagsAttr extends MoveEffectAttr {
public tagTypes: ArenaTagType[];
public selfSideTarget: boolean;
constructor(tagTypes: ArenaTagType[], selfSideTarget: boolean) {
super(true, MoveEffectTrigger.POST_APPLY);
this.tagTypes = tagTypes;
this.selfSideTarget = selfSideTarget;
}
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (!super.apply(user, target, move, args)) {
return false;
}
const side = (this.selfSideTarget ? user : target).isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
for (const tagType of this.tagTypes) {
user.scene.arena.removeTagOnSide(tagType, side);
}
return true;
}
}
export class AddArenaTrapTagAttr extends AddArenaTagAttr { export class AddArenaTrapTagAttr extends AddArenaTagAttr {
getCondition(): MoveConditionFunc { getCondition(): MoveConditionFunc {
return (user, target, move) => { return (user, target, move) => {
@ -5907,6 +5954,7 @@ export function initMoves() {
.unimplemented(), .unimplemented(),
new AttackMove(Moves.FEINT, Type.NORMAL, MoveCategory.PHYSICAL, 30, 100, 10, -1, 2, 4) new AttackMove(Moves.FEINT, Type.NORMAL, MoveCategory.PHYSICAL, 30, 100, 10, -1, 2, 4)
.attr(RemoveBattlerTagAttr, [ BattlerTagType.PROTECTED ]) .attr(RemoveBattlerTagAttr, [ BattlerTagType.PROTECTED ])
.attr(RemoveArenaTagsAttr, [ ArenaTagType.QUICK_GUARD, ArenaTagType.WIDE_GUARD, ArenaTagType.MAT_BLOCK, ArenaTagType.CRAFTY_SHIELD ], false)
.makesContact(false) .makesContact(false)
.ignoresProtect(), .ignoresProtect(),
new AttackMove(Moves.PLUCK, Type.FLYING, MoveCategory.PHYSICAL, 60, 100, 20, -1, 0, 4) new AttackMove(Moves.PLUCK, Type.FLYING, MoveCategory.PHYSICAL, 60, 100, 20, -1, 0, 4)
@ -6196,7 +6244,7 @@ export function initMoves() {
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.ACC ], 1, true), .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.ACC ], 1, true),
new StatusMove(Moves.WIDE_GUARD, Type.ROCK, -1, 10, -1, 3, 5) new StatusMove(Moves.WIDE_GUARD, Type.ROCK, -1, 10, -1, 3, 5)
.target(MoveTarget.USER_SIDE) .target(MoveTarget.USER_SIDE)
.unimplemented(), .attr(AddArenaTagAttr, ArenaTagType.WIDE_GUARD, 1, true, true),
new StatusMove(Moves.GUARD_SPLIT, Type.PSYCHIC, -1, 10, -1, 0, 5) new StatusMove(Moves.GUARD_SPLIT, Type.PSYCHIC, -1, 10, -1, 0, 5)
.unimplemented(), .unimplemented(),
new StatusMove(Moves.POWER_SPLIT, Type.PSYCHIC, -1, 10, -1, 0, 5) new StatusMove(Moves.POWER_SPLIT, Type.PSYCHIC, -1, 10, -1, 0, 5)
@ -6284,7 +6332,7 @@ export function initMoves() {
.attr(StatChangeCountPowerAttr), .attr(StatChangeCountPowerAttr),
new StatusMove(Moves.QUICK_GUARD, Type.FIGHTING, -1, 15, -1, 3, 5) new StatusMove(Moves.QUICK_GUARD, Type.FIGHTING, -1, 15, -1, 3, 5)
.target(MoveTarget.USER_SIDE) .target(MoveTarget.USER_SIDE)
.unimplemented(), .attr(AddArenaTagAttr, ArenaTagType.QUICK_GUARD, 1, true, true),
new SelfStatusMove(Moves.ALLY_SWITCH, Type.PSYCHIC, -1, 15, -1, 2, 5) new SelfStatusMove(Moves.ALLY_SWITCH, Type.PSYCHIC, -1, 15, -1, 2, 5)
.ignoresProtect() .ignoresProtect()
.unimplemented(), .unimplemented(),
@ -6450,7 +6498,9 @@ export function initMoves() {
.attr(HitsTagAttr, BattlerTagType.MINIMIZED, true) .attr(HitsTagAttr, BattlerTagType.MINIMIZED, true)
.condition(failOnGravityCondition), .condition(failOnGravityCondition),
new StatusMove(Moves.MAT_BLOCK, Type.FIGHTING, -1, 10, -1, 0, 6) new StatusMove(Moves.MAT_BLOCK, Type.FIGHTING, -1, 10, -1, 0, 6)
.unimplemented(), .target(MoveTarget.USER_SIDE)
.attr(AddArenaTagAttr, ArenaTagType.MAT_BLOCK, 1, true, true)
.condition(new FirstMoveCondition()),
new AttackMove(Moves.BELCH, Type.POISON, MoveCategory.SPECIAL, 120, 90, 10, -1, 0, 6) new AttackMove(Moves.BELCH, Type.POISON, MoveCategory.SPECIAL, 120, 90, 10, -1, 0, 6)
.condition((user, target, move) => user.battleData.berriesEaten.length > 0), .condition((user, target, move) => user.battleData.berriesEaten.length > 0),
new StatusMove(Moves.ROTOTILLER, Type.GROUND, -1, 10, 100, 0, 6) new StatusMove(Moves.ROTOTILLER, Type.GROUND, -1, 10, 100, 0, 6)
@ -6503,7 +6553,7 @@ export function initMoves() {
.triageMove(), .triageMove(),
new StatusMove(Moves.CRAFTY_SHIELD, Type.FAIRY, -1, 10, -1, 3, 6) new StatusMove(Moves.CRAFTY_SHIELD, Type.FAIRY, -1, 10, -1, 3, 6)
.target(MoveTarget.USER_SIDE) .target(MoveTarget.USER_SIDE)
.unimplemented(), .attr(AddArenaTagAttr, ArenaTagType.CRAFTY_SHIELD, 1, true, true),
new StatusMove(Moves.FLOWER_SHIELD, Type.FAIRY, -1, 10, 100, 0, 6) new StatusMove(Moves.FLOWER_SHIELD, Type.FAIRY, -1, 10, 100, 0, 6)
.target(MoveTarget.ALL) .target(MoveTarget.ALL)
.unimplemented(), .unimplemented(),
@ -6811,8 +6861,11 @@ export function initMoves() {
.unimplemented(), .unimplemented(),
new AttackMove(Moves.SMART_STRIKE, Type.STEEL, MoveCategory.PHYSICAL, 70, -1, 10, -1, 0, 7), new AttackMove(Moves.SMART_STRIKE, Type.STEEL, MoveCategory.PHYSICAL, 70, -1, 10, -1, 0, 7),
new StatusMove(Moves.PURIFY, Type.POISON, -1, 20, -1, 0, 7) new StatusMove(Moves.PURIFY, Type.POISON, -1, 20, -1, 0, 7)
.triageMove() .condition(
.unimplemented(), (user: Pokemon, target: Pokemon, move: Move) => isNonVolatileStatusEffect(user.status?.effect))
.attr(HealAttr, 0.5)
.attr(HealStatusEffectAttr, true, ...getNonVolatileStatusEffects())
.triageMove(),
new AttackMove(Moves.REVELATION_DANCE, Type.NORMAL, MoveCategory.SPECIAL, 90, 100, 15, -1, 0, 7) new AttackMove(Moves.REVELATION_DANCE, Type.NORMAL, MoveCategory.SPECIAL, 90, 100, 15, -1, 0, 7)
.danceMove() .danceMove()
.attr(MatchUserTypeAttr), .attr(MatchUserTypeAttr),

View File

@ -27,6 +27,11 @@ export enum Region {
} }
export function getPokemonSpecies(species: Species): PokemonSpecies { export function getPokemonSpecies(species: Species): PokemonSpecies {
// If a special pool (named trainers) is used here it CAN happen that they have a array as species (which means choose one of those two). So we catch that with this code block
if (Array.isArray(species)) {
// Pick a random species from the list
species = species[Math.floor(Math.random() * species.length)];
}
if (species >= 2000) { if (species >= 2000) {
return allSpecies.find(s => s.speciesId === species); return allSpecies.find(s => s.speciesId === species);
} }
@ -149,6 +154,13 @@ export abstract class PokemonSpeciesForm {
this.genderDiffs = genderDiffs; this.genderDiffs = genderDiffs;
} }
/**
* Method to get the root species id of a Pokemon.
* Magmortar.getRootSpeciesId(true) => Magmar
* Magmortar.getRootSpeciesId(false) => Magby
* @param forStarter boolean to get the nonbaby form of a starter
* @returns The species
*/
getRootSpeciesId(forStarter: boolean = false): Species { getRootSpeciesId(forStarter: boolean = false): Species {
let ret = this.speciesId; let ret = this.speciesId;
while (pokemonPrevolutions.hasOwnProperty(ret) && (!forStarter || !speciesStarters.hasOwnProperty(ret))) { while (pokemonPrevolutions.hasOwnProperty(ret) && (!forStarter || !speciesStarters.hasOwnProperty(ret))) {

View File

@ -175,3 +175,27 @@ export function getRandomStatus(statusA: Status, statusB: Status): Status {
return Utils.randIntRange(0, 2) ? statusA : statusB; return Utils.randIntRange(0, 2) ? statusA : statusB;
} }
/**
* Gets all non volatile status effects
* @returns A list containing all non volatile status effects
*/
export function getNonVolatileStatusEffects():Array<StatusEffect> {
return [
StatusEffect.POISON,
StatusEffect.TOXIC,
StatusEffect.PARALYSIS,
StatusEffect.SLEEP,
StatusEffect.FREEZE,
StatusEffect.BURN
];
}
/**
* Returns whether a statuss effect is non volatile.
* Non-volatile status condition is a status that remains after being switched out.
* @param status The status to check
*/
export function isNonVolatileStatusEffect(status: StatusEffect): boolean {
return getNonVolatileStatusEffects().includes(status);
}

View File

@ -6,10 +6,11 @@ import {TrainerType} from "./enums/trainer-type";
import {Moves} from "./enums/moves"; import {Moves} from "./enums/moves";
import {PokeballType} from "./pokeball"; import {PokeballType} from "./pokeball";
import {pokemonEvolutions, pokemonPrevolutions} from "./pokemon-evolutions"; import {pokemonEvolutions, pokemonPrevolutions} from "./pokemon-evolutions";
import PokemonSpecies, {PokemonSpeciesFilter, getPokemonSpecies} from "./pokemon-species"; import PokemonSpecies, {getPokemonSpecies, PokemonSpeciesFilter} from "./pokemon-species";
import {Species} from "./enums/species"; import {Species} from "./enums/species";
import {tmSpecies} from "./tms"; import {tmSpecies} from "./tms";
import {Type} from "./type"; import {Type} from "./type";
import {doubleBattleDialogue} from "./dialogue";
import {PersistentModifier} from "../modifier/modifier"; import {PersistentModifier} from "../modifier/modifier";
import {TrainerVariant} from "../field/trainer"; import {TrainerVariant} from "../field/trainer";
import {PartyMemberStrength} from "./enums/party-member-strength"; import {PartyMemberStrength} from "./enums/party-member-strength";
@ -172,10 +173,12 @@ export interface PartyMemberFuncs {
export class TrainerConfig { export class TrainerConfig {
public trainerType: TrainerType; public trainerType: TrainerType;
public trainerTypeDouble: TrainerType;
public name: string; public name: string;
public nameFemale: string; public nameFemale: string;
public nameDouble: string; public nameDouble: string;
public title: string; public title: string;
public titleDouble: string;
public hasGenders: boolean = false; public hasGenders: boolean = false;
public hasDouble: boolean = false; public hasDouble: boolean = false;
public hasCharSprite: boolean = false; public hasCharSprite: boolean = false;
@ -228,6 +231,10 @@ export class TrainerConfig {
if (this.hasGenders) { if (this.hasGenders) {
ret += `_${female ? "f" : "m"}`; ret += `_${female ? "f" : "m"}`;
} }
// If a special double trainer class was set, set it as the sprite key
if (this.trainerTypeDouble && female) {
ret = TrainerType[this.trainerTypeDouble].toString().toLowerCase();
}
return ret; return ret;
} }
@ -263,6 +270,8 @@ export class TrainerConfig {
return this; return this;
} }
getDerivedType(): TrainerType { getDerivedType(): TrainerType {
let trainerType = this.trainerType; let trainerType = this.trainerType;
switch (trainerType) { switch (trainerType) {
@ -279,6 +288,21 @@ export class TrainerConfig {
case TrainerType.LARRY_ELITE: case TrainerType.LARRY_ELITE:
trainerType = TrainerType.LARRY; trainerType = TrainerType.LARRY;
break; break;
case TrainerType.MARNIE_ELITE:
trainerType = TrainerType.MARNIE;
break;
case TrainerType.NESSA_ELITE:
trainerType = TrainerType.NESSA;
break;
case TrainerType.BEA_ELITE:
trainerType = TrainerType.BEA;
break;
case TrainerType.ALLISTER_ELITE:
trainerType = TrainerType.ALLISTER;
break;
case TrainerType.RAIHAN_ELITE:
trainerType = TrainerType.RAIHAN;
break;
} }
return trainerType; return trainerType;
@ -321,6 +345,12 @@ export class TrainerConfig {
return this; return this;
} }
/**
* Sets the configuration for trainers with double battles, including the name of the double trainer and the encounter BGM.
* @param nameDouble - The name of the double trainer (e.g., "Ace Duo" for Trainer Class Doubles or "red_blue_double" for NAMED trainer doubles).
* @param doubleEncounterBgm - The encounter BGM for the double trainer, which can be a TrainerType or a string.
* @returns {TrainerConfig} - The updated TrainerConfig instance.
*/
setHasDouble(nameDouble: string, doubleEncounterBgm?: TrainerType | string): TrainerConfig { setHasDouble(nameDouble: string, doubleEncounterBgm?: TrainerType | string): TrainerConfig {
this.hasDouble = true; this.hasDouble = true;
this.nameDouble = nameDouble; this.nameDouble = nameDouble;
@ -330,6 +360,50 @@ export class TrainerConfig {
return this; return this;
} }
/**
* Sets the trainer type for double battles.
* @param trainerTypeDouble - The TrainerType of the partner in a double battle.
* @returns {TrainerConfig} - The updated TrainerConfig instance.
*/
setDoubleTrainerType(trainerTypeDouble: TrainerType): TrainerConfig {
this.trainerTypeDouble = trainerTypeDouble;
this.setDoubleMessages(this.nameDouble);
return this;
}
/**
* Sets the encounter and victory messages for double trainers.
* @param nameDouble - The name of the pair (e.g. "red_blue_double").
*/
setDoubleMessages(nameDouble: string) {
// Check if there is double battle dialogue for this trainer
if (doubleBattleDialogue[nameDouble]) {
// Set encounter and victory messages for double trainers
this.doubleEncounterMessages = doubleBattleDialogue[nameDouble].encounter;
this.doubleVictoryMessages = doubleBattleDialogue[nameDouble].victory;
}
}
/**
* Sets the title for double trainers
* @param titleDouble - the key for the title in the i18n file. (e.g., "champion_double").
* @returns {TrainerConfig} - The updated TrainerConfig instance.
*/
setDoubleTitle(titleDouble: string): TrainerConfig {
// First check if i18n is initialized
if (!getIsInitialized()) {
initI18n();
}
// Make the title lowercase and replace spaces with underscores
titleDouble = titleDouble.toLowerCase().replace(/\s/g, "_");
// Get the title from the i18n file
this.titleDouble = i18next.t(`titles:${titleDouble}`);
return this;
}
setHasCharSprite(): TrainerConfig { setHasCharSprite(): TrainerConfig {
this.hasCharSprite = true; this.hasCharSprite = true;
return this; return this;
@ -558,6 +632,7 @@ export class TrainerConfig {
// Set the title to "champion". (this is the key in the i18n file) // Set the title to "champion". (this is the key in the i18n file)
this.setTitle("champion"); this.setTitle("champion");
// Configure various properties for the Champion. // Configure various properties for the Champion.
this.setMoneyMultiplier(10); this.setMoneyMultiplier(10);
this.setBoss(); this.setBoss();
@ -699,6 +774,147 @@ function getRandomTeraModifiers(party: EnemyPokemon[], count: integer, types?: T
return ret; return ret;
} }
type SignatureSpecies = {
[key in string]: (Species | Species[])[];
};
/*
* The signature species for each Gym Leader, Elite Four member, and Champion.
* The key is the trainer type, and the value is an array of Species or Species arrays.
* This is in a separate const so it can be accessed from other places and not just the trainerConfigs
*/
export const signatureSpecies: SignatureSpecies = {
BROCK: [Species.GEODUDE, Species.ONIX],
MISTY: [Species.STARYU, Species.PSYDUCK],
LT_SURGE: [Species.VOLTORB, Species.PIKACHU, Species.ELECTABUZZ],
ERIKA: [Species.ODDISH, Species.BELLSPROUT, Species.TANGELA, Species.HOPPIP],
JANINE: [Species.VENONAT, Species.SPINARAK, Species.ZUBAT],
SABRINA: [Species.ABRA, Species.MR_MIME, Species.ESPEON],
BLAINE: [Species.GROWLITHE, Species.PONYTA, Species.MAGMAR],
GIOVANNI: [Species.SANDILE, Species.MURKROW, Species.NIDORAN_M, Species.NIDORAN_F],
FALKNER: [Species.PIDGEY, Species.HOOTHOOT, Species.DODUO],
BUGSY: [Species.SCYTHER, Species.HERACROSS, Species.SHUCKLE, Species.PINSIR],
WHITNEY: [Species.GIRAFARIG, Species.MILTANK],
MORTY: [Species.GASTLY, Species.MISDREAVUS, Species.SABLEYE],
CHUCK: [Species.POLIWRATH, Species.MANKEY],
JASMINE: [Species.MAGNEMITE, Species.STEELIX],
PRYCE: [Species.SEEL, Species.SWINUB],
CLAIR: [Species.DRATINI, Species.HORSEA, Species.GYARADOS],
ROXANNE: [Species.GEODUDE, Species.NOSEPASS],
BRAWLY: [Species.MACHOP, Species.MAKUHITA],
WATTSON: [Species.MAGNEMITE, Species.VOLTORB, Species.ELECTRIKE],
FLANNERY: [Species.SLUGMA, Species.TORKOAL, Species.NUMEL],
NORMAN: [Species.SLAKOTH, Species.SPINDA, Species.CHANSEY, Species.KANGASKHAN],
WINONA: [Species.SWABLU, Species.WINGULL, Species.TROPIUS, Species.SKARMORY],
TATE: [Species.SOLROCK, Species.NATU, Species.CHIMECHO, Species.GALLADE],
LIZA: [Species.LUNATONE, Species.SPOINK, Species.BALTOY, Species.GARDEVOIR],
JUAN: [Species.HORSEA, Species.BARBOACH, Species.SPHEAL, Species.RELICANTH],
ROARK: [Species.CRANIDOS, Species.LARVITAR, Species.GEODUDE],
GARDENIA: [Species.ROSELIA, Species.TANGELA, Species.TURTWIG],
MAYLENE: [Species.LUCARIO, Species.MEDITITE, Species.CHIMCHAR],
CRASHER_WAKE: [Species.BUIZEL, Species.MAGIKARP, Species.PIPLUP],
FANTINA: [Species.MISDREAVUS, Species.DRIFLOON, Species.SPIRITOMB],
BYRON: [Species.SHIELDON, Species.BRONZOR, Species.AGGRON],
CANDICE: [Species.SNEASEL, Species.SNOVER, Species.SNORUNT],
VOLKNER: [Species.SHINX, Species.CHINCHOU, Species.ROTOM],
CILAN: [Species.PANSAGE, Species.COTTONEE, Species.PETILIL],
CHILI: [Species.PANSEAR, Species.DARUMAKA, Species.HEATMOR],
CRESS: [Species.PANPOUR, Species.BASCULIN, Species.TYMPOLE],
CHEREN: [Species.LILLIPUP, Species.MINCCINO, Species.PATRAT],
LENORA: [Species.KANGASKHAN, Species.DEERLING, Species.AUDINO],
ROXIE: [Species.VENIPEDE, Species.TRUBBISH, Species.SKORUPI],
BURGH: [Species.SEWADDLE, Species.SHELMET, Species.KARRABLAST],
ELESA: [Species.EMOLGA, Species.BLITZLE, Species.JOLTIK],
CLAY: [Species.DRILBUR, Species.SANDILE, Species.GOLETT],
SKYLA: [Species.DUCKLETT, Species.WOOBAT, Species.RUFFLET],
BRYCEN: [Species.CRYOGONAL, Species.VANILLITE, Species.CUBCHOO],
DRAYDEN: [Species.DRUDDIGON, Species.AXEW, Species.DEINO],
MARLON: [Species.WAILMER, Species.FRILLISH, Species.TIRTOUGA],
VIOLA: [Species.SURSKIT, Species.SCATTERBUG],
GRANT: [Species.AMAURA, Species.TYRUNT],
KORRINA: [Species.HAWLUCHA, Species.LUCARIO, Species.MIENFOO],
RAMOS: [Species.SKIDDO, Species.HOPPIP, Species.BELLSPROUT],
CLEMONT: [Species.HELIOPTILE, Species.MAGNEMITE, Species.EMOLGA],
VALERIE: [Species.SYLVEON, Species.MAWILE, Species.MR_MIME],
OLYMPIA: [Species.ESPURR, Species.SIGILYPH, Species.SLOWKING],
WULFRIC: [Species.BERGMITE, Species.SNOVER, Species.CRYOGONAL],
MILO: [Species.GOSSIFLEUR, Species.APPLIN, Species.BOUNSWEET],
NESSA: [Species.CHEWTLE, Species.ARROKUDA, Species.WIMPOD],
KABU: [Species.SIZZLIPEDE, Species.VULPIX, Species.TORKOAL],
BEA: [Species.GALAR_FARFETCHD, Species.MACHOP, Species.CLOBBOPUS],
ALLISTER: [Species.GALAR_YAMASK, Species.GALAR_CORSOLA, Species.GASTLY],
OPAL: [Species.MILCERY, Species.TOGETIC, Species.GALAR_WEEZING],
BEDE: [Species.HATENNA, Species.GALAR_PONYTA, Species.GARDEVOIR],
GORDIE: [Species.ROLYCOLY, Species.STONJOURNER, Species.BINACLE],
MELONY: [Species.SNOM, Species.GALAR_DARUMAKA, Species.GALAR_MR_MIME],
PIERS: [Species.GALAR_ZIGZAGOON, Species.SCRAGGY, Species.INKAY],
MARNIE: [Species.IMPIDIMP, Species.PURRLOIN, Species.MORPEKO],
RAIHAN: [Species.DURALUDON, Species.TURTONATOR, Species.GOOMY],
KATY: [Species.NYMBLE, Species.TAROUNTULA, Species.HERACROSS],
BRASSIUS: [Species.SMOLIV, Species.SHROOMISH, Species.ODDISH],
IONO: [Species.TADBULB, Species.WATTREL, Species.VOLTORB],
KOFU: [Species.VELUZA, Species.WIGLETT, Species.WINGULL],
LARRY: [Species.STARLY, Species.DUNSPARCE, Species.KOMALA],
RYME: [Species.GREAVARD, Species.SHUPPET, Species.MIMIKYU],
TULIP: [Species.GIRAFARIG, Species.FLITTLE, Species.RALTS],
GRUSHA: [Species.CETODDLE, Species.ALOLA_VULPIX, Species.CUBCHOO],
LORELEI: [Species.SLOWBRO, Species.LAPRAS, Species.DEWGONG, Species.ALOLA_SANDSLASH],
BRUNO: [Species.ONIX, Species.HITMONCHAN, Species.HITMONLEE, Species.ALOLA_GOLEM],
AGATHA: [Species.GENGAR, Species.ARBOK, Species.CROBAT, Species.ALOLA_MAROWAK],
LANCE: [Species.DRAGONITE, Species.GYARADOS, Species.AERODACTYL, Species.ALOLA_EXEGGUTOR],
WILL: [Species.XATU, Species.JYNX, Species.SLOWBRO, Species.EXEGGUTOR],
KOGA: [Species.WEEZING, Species.VENOMOTH, Species.CROBAT, Species.TENTACRUEL],
KAREN: [Species.UMBREON, Species.HONCHKROW, Species.HOUNDOOM, Species.WEAVILE],
SIDNEY: [Species.SHIFTRY, Species.SHARPEDO, Species.ABSOL, Species.ZOROARK],
PHOEBE: [Species.SABLEYE, Species.DUSKNOIR, Species.BANETTE, Species.CHANDELURE],
GLACIA: [Species.GLALIE, Species.WALREIN, Species.FROSLASS, Species.ABOMASNOW],
DRAKE: [Species.ALTARIA, Species.SALAMENCE, Species.FLYGON, Species.KINGDRA],
AARON: [Species.SCIZOR, Species.HERACROSS, Species.VESPIQUEN, Species.DRAPION],
BERTHA: [Species.WHISCASH, Species.HIPPOWDON, Species.GLISCOR, Species.RHYPERIOR],
FLINT: [Species.FLAREON, Species.HOUNDOOM, Species.RAPIDASH, Species.INFERNAPE],
LUCIAN: [Species.MR_MIME, Species.GALLADE, Species.BRONZONG, Species.ALAKAZAM],
SHAUNTAL: [Species.COFAGRIGUS, Species.CHANDELURE, Species.GOLURK, Species.DRIFBLIM],
MARSHAL: [Species.TIMBURR, Species.MIENFOO, Species.THROH, Species.SAWK],
GRIMSLEY: [Species.LIEPARD, Species.KINGAMBIT, Species.SCRAFTY, Species.KROOKODILE],
CAITLIN: [Species.MUSHARNA, Species.GOTHITELLE, Species.SIGILYPH, Species.REUNICLUS],
MALVA: [Species.PYROAR, Species.TORKOAL, Species.CHANDELURE, Species.TALONFLAME],
SIEBOLD: [Species.CLAWITZER, Species.GYARADOS, Species.BARBARACLE, Species.STARMIE],
WIKSTROM: [Species.KLEFKI, Species.PROBOPASS, Species.SCIZOR, Species.AEGISLASH],
DRASNA: [Species.DRAGALGE, Species.DRUDDIGON, Species.ALTARIA, Species.NOIVERN],
HALA: [Species.HARIYAMA, Species.BEWEAR, Species.CRABOMINABLE, Species.POLIWRATH],
MOLAYNE: [Species.KLEFKI, Species.MAGNEZONE, Species.METAGROSS, Species.ALOLA_DUGTRIO],
OLIVIA: [Species.ARMALDO, Species.CRADILY, Species.ALOLA_GOLEM, Species.LYCANROC],
ACEROLA: [Species.BANETTE, Species.DRIFBLIM, Species.DHELMISE, Species.PALOSSAND],
KAHILI: [Species.BRAVIARY, Species.HAWLUCHA, Species.ORICORIO, Species.TOUCANNON],
MARNIE_ELITE: [ Species.MORPEKO, Species.LIEPARD, Species.TOXICROAK,Species.SCRAFTY, Species.GRIMMSNARL],
NESSA_ELITE: [ Species.GOLISOPOD,Species.PELIPPER,Species.QUAGSIRE,Species.TOXAPEX,Species.DREDNAW],
BEA_ELITE: [ Species.HAWLUCHA,Species.GRAPPLOCT,Species.SIRFETCHD,Species.FALINKS,Species.MACHAMP],
ALLISTER_ELITE:[ Species.DUSKNOIR,Species.CHANDELURE,Species.CURSOLA,Species.RUNERIGUS,Species.GENGAR],
RAIHAN_ELITE: [ Species.TORKOAL,Species.GOODRA,Species.TURTONATOR,Species.FLYGON,Species.DURALUDON],
RIKA: [Species.WHISCASH, Species.DONPHAN, Species.CAMERUPT, Species.CLODSIRE],
POPPY: [Species.COPPERAJAH, Species.BRONZONG, Species.CORVIKNIGHT, Species.TINKATON],
LARRY_ELITE: [Species.STARAPTOR, Species.FLAMIGO, Species.ALTARIA, Species.TROPIUS],
HASSEL: [Species.NOIVERN, Species.HAXORUS, Species.DRAGALGE, Species.BAXCALIBUR],
CRISPIN: [Species.TALONFLAME, Species.CAMERUPT, Species.MAGMORTAR, Species.BLAZIKEN],
AMARYS: [Species.SKARMORY, Species.EMPOLEON, Species.SCIZOR, Species.METAGROSS],
LACEY: [Species.EXCADRILL, Species.PRIMARINA, Species.ALCREMIE, Species.GALAR_SLOWBRO],
DRAYTON: [Species.DRAGONITE, Species.ARCHALUDON, Species.FLYGON, Species.SCEPTILE],
BLUE: [Species.GYARADOS, Species.MEWTWO, Species.ARCANINE, Species.ALAKAZAM, Species.PIDGEOT],
RED: [Species.CHARIZARD, [Species.LUGIA, Species.HO_OH], Species.SNORLAX, Species.RAICHU, Species.ESPEON],
LANCE_CHAMPION: [Species.DRAGONITE, Species.ZYGARDE, Species.AERODACTYL, Species.KINGDRA, Species.ALOLA_EXEGGUTOR],
STEVEN: [Species.METAGROSS, [Species.DIALGA, Species.PALKIA], Species.SKARMORY, Species.AGGRON, Species.CARBINK],
WALLACE: [Species.MILOTIC, Species.KYOGRE, Species.WHISCASH, Species.WALREIN, Species.LUDICOLO],
CYNTHIA: [Species.SPIRITOMB, Species.GIRATINA, Species.GARCHOMP, Species.MILOTIC, Species.LUCARIO, Species.TOGEKISS],
ALDER: [Species.VOLCARONA, Species.GROUDON, Species.BOUFFALANT, Species.ACCELGOR, Species.CONKELDURR],
IRIS: [Species.HAXORUS, Species.YVELTAL, Species.DRUDDIGON, Species.ARON, Species.LAPRAS],
DIANTHA: [Species.HAWLUCHA, Species.XERNEAS, Species.GOURGEIST, Species.GOODRA, Species.GARDEVOIR],
HAU: [Species.ALOLA_RAICHU, [Species.SOLGALEO, Species.LUNALA], Species.NOIVERN, [Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA], Species.CRABOMINABLE],
GEETA: [Species.GLIMMORA, Species.MIRAIDON, Species.ESPATHRA, Species.VELUZA, Species.KINGAMBIT],
NEMONA: [Species.LYCANROC, Species.KORAIDON, Species.KOMMO_O, Species.PAWMOT, Species.DUSKNOIR],
KIERAN: [Species.POLITOED, [Species.OGERPON, Species.TERAPAGOS], Species.HYDRAPPLE, Species.PORYGON_Z, Species.GRIMMSNARL],
LEON: [Species.DRAGAPULT, [Species.ZACIAN, Species.ZAMAZENTA], Species.SEISMITOAD, Species.AEGISLASH, Species.CHARIZARD],
};
export const trainerConfigs: TrainerConfigs = { export const trainerConfigs: TrainerConfigs = {
[TrainerType.UNKNOWN]: new TrainerConfig(0).setHasGenders(), [TrainerType.UNKNOWN]: new TrainerConfig(0).setHasGenders(),
[TrainerType.ACE_TRAINER]: new TrainerConfig(++t).setHasGenders("Ace Trainer Female").setHasDouble("Ace Duo").setMoneyMultiplier(2.25).setEncounterBgm(TrainerType.ACE_TRAINER) [TrainerType.ACE_TRAINER]: new TrainerConfig(++t).setHasGenders("Ace Trainer Female").setHasDouble("Ace Duo").setMoneyMultiplier(2.25).setEncounterBgm(TrainerType.ACE_TRAINER)
@ -859,132 +1075,137 @@ export const trainerConfigs: TrainerConfigs = {
.setSpeciesPools( .setSpeciesPools(
[Species.CATERPIE, Species.WEEDLE, Species.RATTATA, Species.SENTRET, Species.POOCHYENA, Species.ZIGZAGOON, Species.WURMPLE, Species.BIDOOF, Species.PATRAT, Species.LILLIPUP] [Species.CATERPIE, Species.WEEDLE, Species.RATTATA, Species.SENTRET, Species.POOCHYENA, Species.ZIGZAGOON, Species.WURMPLE, Species.BIDOOF, Species.PATRAT, Species.LILLIPUP]
), ),
[TrainerType.BROCK]: new TrainerConfig((t = TrainerType.BROCK)).initForGymLeader([ Species.GEODUDE, Species.ONIX ], Type.ROCK).setBattleBgm("battle_kanto_gym"), [TrainerType.BROCK]: new TrainerConfig((t = TrainerType.BROCK)).initForGymLeader(signatureSpecies["BROCK"], Type.ROCK).setBattleBgm("battle_kanto_gym"),
[TrainerType.MISTY]: new TrainerConfig(++t).initForGymLeader([ Species.STARYU, Species.PSYDUCK ], Type.WATER).setBattleBgm("battle_kanto_gym"), [TrainerType.MISTY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MISTY"], Type.WATER).setBattleBgm("battle_kanto_gym"),
[TrainerType.LT_SURGE]: new TrainerConfig(++t).initForGymLeader([ Species.VOLTORB, Species.PIKACHU, Species.ELECTABUZZ ], Type.ELECTRIC).setBattleBgm("battle_kanto_gym"), [TrainerType.LT_SURGE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["LT_SURGE"], Type.ELECTRIC).setBattleBgm("battle_kanto_gym"),
[TrainerType.ERIKA]: new TrainerConfig(++t).initForGymLeader([ Species.ODDISH, Species.BELLSPROUT, Species.TANGELA, Species.HOPPIP ], Type.GRASS).setBattleBgm("battle_kanto_gym"), [TrainerType.ERIKA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ERIKA"], Type.GRASS).setBattleBgm("battle_kanto_gym"),
[TrainerType.JANINE]: new TrainerConfig(++t).initForGymLeader([ Species.VENONAT, Species.SPINARAK, Species.ZUBAT ], Type.POISON).setBattleBgm("battle_kanto_gym"), [TrainerType.JANINE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["JANINE"], Type.POISON).setBattleBgm("battle_kanto_gym"),
[TrainerType.SABRINA]: new TrainerConfig(++t).initForGymLeader([ Species.ABRA, Species.MR_MIME, Species.ESPEON ], Type.PSYCHIC).setBattleBgm("battle_kanto_gym"), [TrainerType.SABRINA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["SABRINA"], Type.PSYCHIC).setBattleBgm("battle_kanto_gym"),
[TrainerType.BLAINE]: new TrainerConfig(++t).initForGymLeader([ Species.GROWLITHE, Species.PONYTA, Species.MAGMAR ], Type.FIRE).setBattleBgm("battle_kanto_gym"), [TrainerType.BLAINE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BLAINE"], Type.FIRE).setBattleBgm("battle_kanto_gym"),
[TrainerType.GIOVANNI]: new TrainerConfig(++t).initForGymLeader([ Species.SANDILE, Species.MURKROW, Species.NIDORAN_M, Species.NIDORAN_F ], Type.DARK).setBattleBgm("battle_kanto_gym"), [TrainerType.GIOVANNI]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GIOVANNI"], Type.DARK).setBattleBgm("battle_kanto_gym"),
[TrainerType.FALKNER]: new TrainerConfig(++t).initForGymLeader([ Species.PIDGEY, Species.HOOTHOOT, Species.DODUO ], Type.FLYING).setBattleBgm("battle_johto_gym"), [TrainerType.FALKNER]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["FALKNER"], Type.FLYING).setBattleBgm("battle_johto_gym"),
[TrainerType.BUGSY]: new TrainerConfig(++t).initForGymLeader([ Species.SCYTHER, Species.HERACROSS, Species.SHUCKLE, Species.PINSIR ], Type.BUG).setBattleBgm("battle_johto_gym"), [TrainerType.BUGSY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BUGSY"], Type.BUG).setBattleBgm("battle_johto_gym"),
[TrainerType.WHITNEY]: new TrainerConfig(++t).initForGymLeader([ Species.GIRAFARIG, Species.MILTANK ], Type.NORMAL).setBattleBgm("battle_johto_gym"), [TrainerType.WHITNEY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["WHITNEY"], Type.NORMAL).setBattleBgm("battle_johto_gym"),
[TrainerType.MORTY]: new TrainerConfig(++t).initForGymLeader([ Species.GASTLY, Species.MISDREAVUS, Species.SABLEYE ], Type.GHOST).setBattleBgm("battle_johto_gym"), [TrainerType.MORTY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MORTY"], Type.GHOST).setBattleBgm("battle_johto_gym"),
[TrainerType.CHUCK]: new TrainerConfig(++t).initForGymLeader([ Species.POLIWRATH, Species.MANKEY ], Type.FIGHTING).setBattleBgm("battle_johto_gym"), [TrainerType.CHUCK]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CHUCK"], Type.FIGHTING).setBattleBgm("battle_johto_gym"),
[TrainerType.JASMINE]: new TrainerConfig(++t).initForGymLeader([ Species.MAGNEMITE, Species.STEELIX ], Type.STEEL).setBattleBgm("battle_johto_gym"), [TrainerType.JASMINE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["JASMINE"], Type.STEEL).setBattleBgm("battle_johto_gym"),
[TrainerType.PRYCE]: new TrainerConfig(++t).initForGymLeader([ Species.SEEL, Species.SWINUB ], Type.ICE).setBattleBgm("battle_johto_gym"), [TrainerType.PRYCE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["PRYCE"], Type.ICE).setBattleBgm("battle_johto_gym"),
[TrainerType.CLAIR]: new TrainerConfig(++t).initForGymLeader([ Species.DRATINI, Species.HORSEA, Species.GYARADOS ], Type.DRAGON).setBattleBgm("battle_johto_gym"), [TrainerType.CLAIR]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CLAIR"], Type.DRAGON).setBattleBgm("battle_johto_gym"),
[TrainerType.ROXANNE]: new TrainerConfig(++t).initForGymLeader([ Species.GEODUDE, Species.NOSEPASS ], Type.ROCK).setBattleBgm("battle_hoenn_gym"), [TrainerType.ROXANNE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ROXANNE"], Type.ROCK).setBattleBgm("battle_hoenn_gym"),
[TrainerType.BRAWLY]: new TrainerConfig(++t).initForGymLeader([ Species.MACHOP, Species.MAKUHITA ], Type.FIGHTING).setBattleBgm("battle_hoenn_gym"), [TrainerType.BRAWLY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BRAWLY"], Type.FIGHTING).setBattleBgm("battle_hoenn_gym"),
[TrainerType.WATTSON]: new TrainerConfig(++t).initForGymLeader([ Species.MAGNEMITE, Species.VOLTORB, Species.ELECTRIKE ], Type.ELECTRIC).setBattleBgm("battle_hoenn_gym"), [TrainerType.WATTSON]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["WATTSON"], Type.ELECTRIC).setBattleBgm("battle_hoenn_gym"),
[TrainerType.FLANNERY]: new TrainerConfig(++t).initForGymLeader([ Species.SLUGMA, Species.TORKOAL, Species.NUMEL ], Type.FIRE).setBattleBgm("battle_hoenn_gym"), [TrainerType.FLANNERY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["FLANNERY"], Type.FIRE).setBattleBgm("battle_hoenn_gym"),
[TrainerType.NORMAN]: new TrainerConfig(++t).initForGymLeader([ Species.SLAKOTH, Species.SPINDA, Species.CHANSEY, Species.KANGASKHAN ], Type.NORMAL).setBattleBgm("battle_hoenn_gym"), [TrainerType.NORMAN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["NORMAN"], Type.NORMAL).setBattleBgm("battle_hoenn_gym"),
[TrainerType.WINONA]: new TrainerConfig(++t).initForGymLeader([ Species.SWABLU, Species.WINGULL, Species.TROPIUS, Species.SKARMORY ], Type.FLYING).setBattleBgm("battle_hoenn_gym"), [TrainerType.WINONA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["WINONA"], Type.FLYING).setBattleBgm("battle_hoenn_gym"),
[TrainerType.TATE]: new TrainerConfig(++t).initForGymLeader([ Species.SOLROCK, Species.NATU, Species.CHIMECHO, Species.GALLADE ], Type.PSYCHIC).setBattleBgm("battle_hoenn_gym"), [TrainerType.TATE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["TATE"], Type.PSYCHIC).setBattleBgm("battle_hoenn_gym").setHasDouble("tate_liza_double").setDoubleTrainerType(TrainerType.LIZA).setDoubleTitle("gym_leader_double"),
[TrainerType.LIZA]: new TrainerConfig(++t).initForGymLeader([ Species.LUNATONE, Species.SPOINK, Species.BALTOY, Species.GARDEVOIR ], Type.PSYCHIC).setBattleBgm("battle_hoenn_gym"), [TrainerType.LIZA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["LIZA"], Type.PSYCHIC).setBattleBgm("battle_hoenn_gym").setHasDouble("liza_tate_double").setDoubleTrainerType(TrainerType.TATE).setDoubleTitle("gym_leader_double"),
[TrainerType.JUAN]: new TrainerConfig(++t).initForGymLeader([ Species.HORSEA, Species.BARBOACH, Species.SPHEAL, Species.RELICANTH ], Type.WATER).setBattleBgm("battle_hoenn_gym"), [TrainerType.JUAN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["JUAN"], Type.WATER).setBattleBgm("battle_hoenn_gym"),
[TrainerType.ROARK]: new TrainerConfig(++t).initForGymLeader([ Species.CRANIDOS, Species.LARVITAR, Species.GEODUDE ], Type.ROCK).setBattleBgm("battle_sinnoh_gym"), [TrainerType.ROARK]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ROARK"], Type.ROCK).setBattleBgm("battle_sinnoh_gym"),
[TrainerType.GARDENIA]: new TrainerConfig(++t).initForGymLeader([ Species.ROSELIA, Species.TANGELA, Species.TURTWIG ], Type.GRASS).setBattleBgm("battle_sinnoh_gym"), [TrainerType.GARDENIA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GARDENIA"], Type.GRASS).setBattleBgm("battle_sinnoh_gym"),
[TrainerType.MAYLENE]: new TrainerConfig(++t).initForGymLeader([ Species.LUCARIO, Species.MEDITITE, Species.CHIMCHAR ], Type.FIGHTING).setBattleBgm("battle_sinnoh_gym"), [TrainerType.MAYLENE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MAYLENE"], Type.FIGHTING).setBattleBgm("battle_sinnoh_gym"),
[TrainerType.CRASHER_WAKE]: new TrainerConfig(++t).initForGymLeader([ Species.BUIZEL, Species.MAGIKARP, Species.PIPLUP ], Type.WATER).setBattleBgm("battle_sinnoh_gym"), [TrainerType.CRASHER_WAKE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CRASHER_WAKE"], Type.WATER).setBattleBgm("battle_sinnoh_gym"),
[TrainerType.FANTINA]: new TrainerConfig(++t).initForGymLeader([ Species.MISDREAVUS, Species.DRIFLOON, Species.SPIRITOMB ], Type.GHOST).setBattleBgm("battle_sinnoh_gym"), [TrainerType.FANTINA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["FANTINA"], Type.GHOST).setBattleBgm("battle_sinnoh_gym"),
[TrainerType.BYRON]: new TrainerConfig(++t).initForGymLeader([ Species.SHIELDON, Species.BRONZOR, Species.AGGRON ], Type.STEEL).setBattleBgm("battle_sinnoh_gym"), [TrainerType.BYRON]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BYRON"], Type.STEEL).setBattleBgm("battle_sinnoh_gym"),
[TrainerType.CANDICE]: new TrainerConfig(++t).initForGymLeader([ Species.SNEASEL, Species.SNOVER, Species.SNORUNT ], Type.ICE).setBattleBgm("battle_sinnoh_gym"), [TrainerType.CANDICE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CANDICE"], Type.ICE).setBattleBgm("battle_sinnoh_gym"),
[TrainerType.VOLKNER]: new TrainerConfig(++t).initForGymLeader([ Species.SHINX, Species.CHINCHOU, Species.ROTOM ], Type.ELECTRIC).setBattleBgm("battle_sinnoh_gym"), [TrainerType.VOLKNER]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["VOLKNER"], Type.ELECTRIC).setBattleBgm("battle_sinnoh_gym"),
[TrainerType.CILAN]: new TrainerConfig(++t).initForGymLeader([ Species.PANSAGE, Species.COTTONEE, Species.PETILIL ], Type.GRASS), [TrainerType.CILAN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CILAN"], Type.GRASS),
[TrainerType.CHILI]: new TrainerConfig(++t).initForGymLeader([ Species.PANSEAR, Species.DARUMAKA, Species.HEATMOR ], Type.FIRE), [TrainerType.CHILI]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CHILI"], Type.FIRE),
[TrainerType.CRESS]: new TrainerConfig(++t).initForGymLeader([ Species.PANPOUR, Species.BASCULIN, Species.TYMPOLE ], Type.WATER), [TrainerType.CRESS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CRESS"], Type.WATER),
[TrainerType.CHEREN]: new TrainerConfig(++t).initForGymLeader([ Species.LILLIPUP, Species.MINCCINO, Species.PATRAT ], Type.NORMAL), [TrainerType.CHEREN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CHEREN"], Type.NORMAL),
[TrainerType.LENORA]: new TrainerConfig(++t).initForGymLeader([ Species.KANGASKHAN, Species.DEERLING, Species.AUDINO ], Type.NORMAL), [TrainerType.LENORA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["LENORA"], Type.NORMAL),
[TrainerType.ROXIE]: new TrainerConfig(++t).initForGymLeader([ Species.VENIPEDE, Species.TRUBBISH, Species.SKORUPI ], Type.POISON), [TrainerType.ROXIE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ROXIE"], Type.POISON),
[TrainerType.BURGH]: new TrainerConfig(++t).initForGymLeader([ Species.SEWADDLE, Species.SHELMET, Species.KARRABLAST ], Type.BUG), [TrainerType.BURGH]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BURGH"], Type.BUG),
[TrainerType.ELESA]: new TrainerConfig(++t).initForGymLeader([ Species.EMOLGA, Species.BLITZLE, Species.JOLTIK ], Type.ELECTRIC), [TrainerType.ELESA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ELESA"], Type.ELECTRIC),
[TrainerType.CLAY]: new TrainerConfig(++t).initForGymLeader([ Species.DRILBUR, Species.SANDILE, Species.GOLETT ], Type.GROUND), [TrainerType.CLAY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CLAY"], Type.GROUND),
[TrainerType.SKYLA]: new TrainerConfig(++t).initForGymLeader([ Species.DUCKLETT, Species.WOOBAT, Species.RUFFLET ], Type.FLYING), [TrainerType.SKYLA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["SKYLA"], Type.FLYING),
[TrainerType.BRYCEN]: new TrainerConfig(++t).initForGymLeader([ Species.CRYOGONAL, Species.VANILLITE, Species.CUBCHOO ], Type.ICE), [TrainerType.BRYCEN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BRYCEN"], Type.ICE),
[TrainerType.DRAYDEN]: new TrainerConfig(++t).initForGymLeader([ Species.DRUDDIGON, Species.AXEW, Species.DEINO ], Type.DRAGON), [TrainerType.DRAYDEN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["DRAYDEN"], Type.DRAGON),
[TrainerType.MARLON]: new TrainerConfig(++t).initForGymLeader([ Species.WAILMER, Species.FRILLISH, Species.TIRTOUGA ], Type.WATER), [TrainerType.MARLON]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MARLON"], Type.WATER),
[TrainerType.VIOLA]: new TrainerConfig(++t).initForGymLeader([ Species.SURSKIT, Species.SCATTERBUG ], Type.BUG), [TrainerType.VIOLA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["VIOLA"], Type.BUG),
[TrainerType.GRANT]: new TrainerConfig(++t).initForGymLeader([ Species.AMAURA, Species.TYRUNT ], Type.ROCK), [TrainerType.GRANT]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GRANT"], Type.ROCK),
[TrainerType.KORRINA]: new TrainerConfig(++t).initForGymLeader([ Species.HAWLUCHA, Species.LUCARIO, Species.MIENFOO ], Type.FIGHTING), [TrainerType.KORRINA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KORRINA"], Type.FIGHTING),
[TrainerType.RAMOS]: new TrainerConfig(++t).initForGymLeader([ Species.SKIDDO, Species.HOPPIP, Species.BELLSPROUT ], Type.GRASS), [TrainerType.RAMOS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["RAMOS"], Type.GRASS),
[TrainerType.CLEMONT]: new TrainerConfig(++t).initForGymLeader([ Species.HELIOPTILE, Species.MAGNEMITE, Species.EMOLGA ], Type.ELECTRIC), [TrainerType.CLEMONT]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CLEMONT"], Type.ELECTRIC),
[TrainerType.VALERIE]: new TrainerConfig(++t).initForGymLeader([ Species.SYLVEON, Species.MAWILE, Species.MR_MIME ], Type.FAIRY), [TrainerType.VALERIE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["VALERIE"], Type.FAIRY),
[TrainerType.OLYMPIA]: new TrainerConfig(++t).initForGymLeader([ Species.ESPURR, Species.SIGILYPH, Species.SLOWKING ], Type.PSYCHIC), [TrainerType.OLYMPIA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["OLYMPIA"], Type.PSYCHIC),
[TrainerType.WULFRIC]: new TrainerConfig(++t).initForGymLeader([ Species.BERGMITE, Species.SNOVER, Species.CRYOGONAL ], Type.ICE), [TrainerType.WULFRIC]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["WULFRIC"], Type.ICE),
[TrainerType.MILO]: new TrainerConfig(++t).initForGymLeader([ Species.GOSSIFLEUR, Species.APPLIN, Species.BOUNSWEET ], Type.GRASS), [TrainerType.MILO]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MILO"], Type.GRASS),
[TrainerType.NESSA]: new TrainerConfig(++t).initForGymLeader([ Species.CHEWTLE, Species.ARROKUDA, Species.WIMPOD ], Type.WATER), [TrainerType.NESSA]: new TrainerConfig(++t).setName("Nessa").initForGymLeader(signatureSpecies["NESSA"], Type.WATER),
[TrainerType.KABU]: new TrainerConfig(++t).initForGymLeader([ Species.SIZZLIPEDE, Species.VULPIX, Species.TORKOAL ], Type.FIRE), [TrainerType.KABU]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KABU"], Type.FIRE),
[TrainerType.BEA]: new TrainerConfig(++t).initForGymLeader([ Species.GALAR_FARFETCHD, Species.MACHOP, Species.CLOBBOPUS ], Type.FIGHTING), [TrainerType.BEA]: new TrainerConfig(++t).setName("Bea").initForGymLeader(signatureSpecies["BEA"], Type.FIGHTING),
[TrainerType.ALLISTER]: new TrainerConfig(++t).initForGymLeader([ Species.GALAR_YAMASK, Species.GALAR_CORSOLA, Species.GASTLY ], Type.GHOST), [TrainerType.ALLISTER]: new TrainerConfig(++t).setName("Allister").initForGymLeader(signatureSpecies["ALLISTER"], Type.GHOST),
[TrainerType.OPAL]: new TrainerConfig(++t).initForGymLeader([ Species.MILCERY, Species.TOGETIC, Species.GALAR_WEEZING ], Type.FAIRY), [TrainerType.OPAL]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["OPAL"], Type.FAIRY),
[TrainerType.BEDE]: new TrainerConfig(++t).initForGymLeader([ Species.HATENNA, Species.GALAR_PONYTA, Species.GARDEVOIR ], Type.FAIRY), [TrainerType.BEDE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BEDE"], Type.FAIRY),
[TrainerType.GORDIE]: new TrainerConfig(++t).initForGymLeader([ Species.ROLYCOLY, Species.STONJOURNER, Species.BINACLE ], Type.ROCK), [TrainerType.GORDIE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GORDIE"], Type.ROCK),
[TrainerType.MELONY]: new TrainerConfig(++t).initForGymLeader([ Species.SNOM, Species.GALAR_DARUMAKA, Species.GALAR_MR_MIME ], Type.ICE), [TrainerType.MELONY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MELONY"], Type.ICE),
[TrainerType.PIERS]: new TrainerConfig(++t).initForGymLeader([ Species.GALAR_ZIGZAGOON, Species.SCRAGGY, Species.INKAY ], Type.DARK), [TrainerType.PIERS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["PIERS"], Type.DARK).setHasDouble("piers_marnie_double").setDoubleTrainerType(TrainerType.MARNIE).setDoubleTitle("gym_leader_double"),
[TrainerType.MARNIE]: new TrainerConfig(++t).initForGymLeader([ Species.IMPIDIMP, Species.PURRLOIN, Species.MORPEKO ], Type.DARK), [TrainerType.MARNIE]: new TrainerConfig(++t).setName("Marnie").initForGymLeader(signatureSpecies["MARNIE"], Type.DARK).setHasDouble("marnie_piers_double").setDoubleTrainerType(TrainerType.PIERS).setDoubleTitle("gym_leader_double"),
[TrainerType.RAIHAN]: new TrainerConfig(++t).initForGymLeader([ Species.DURALUDON, Species.TURTONATOR, Species.GOOMY ], Type.DRAGON), [TrainerType.RAIHAN]: new TrainerConfig(++t).setName("Raihan").initForGymLeader(signatureSpecies["RAIHAN"], Type.DRAGON),
[TrainerType.KATY]: new TrainerConfig(++t).initForGymLeader([ Species.NYMBLE, Species.TAROUNTULA, Species.HERACROSS ], Type.BUG), [TrainerType.KATY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KATY"], Type.BUG),
[TrainerType.BRASSIUS]: new TrainerConfig(++t).initForGymLeader([ Species.SMOLIV, Species.SHROOMISH, Species.ODDISH ], Type.GRASS), [TrainerType.BRASSIUS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BRASSIUS"], Type.GRASS),
[TrainerType.IONO]: new TrainerConfig(++t).initForGymLeader([ Species.TADBULB, Species.WATTREL, Species.VOLTORB ], Type.ELECTRIC), [TrainerType.IONO]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["IONO"], Type.ELECTRIC),
[TrainerType.KOFU]: new TrainerConfig(++t).initForGymLeader([ Species.VELUZA, Species.WIGLETT, Species.WINGULL ], Type.WATER), [TrainerType.KOFU]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KOFU"], Type.WATER),
[TrainerType.LARRY]: new TrainerConfig(++t).setName("Larry").initForGymLeader([ Species.STARLY, Species.DUNSPARCE, Species.KOMALA ], Type.NORMAL), [TrainerType.LARRY]: new TrainerConfig(++t).setName("Larry").initForGymLeader(signatureSpecies["LARRY"], Type.NORMAL),
[TrainerType.RYME]: new TrainerConfig(++t).initForGymLeader([ Species.GREAVARD, Species.SHUPPET, Species.MIMIKYU ], Type.GHOST), [TrainerType.RYME]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["RYME"], Type.GHOST),
[TrainerType.TULIP]: new TrainerConfig(++t).initForGymLeader([ Species.GIRAFARIG, Species.FLITTLE, Species.RALTS ], Type.PSYCHIC), [TrainerType.TULIP]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["TULIP"], Type.PSYCHIC),
[TrainerType.GRUSHA]: new TrainerConfig(++t).initForGymLeader([ Species.CETODDLE, Species.ALOLA_VULPIX, Species.CUBCHOO ], Type.ICE), [TrainerType.GRUSHA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GRUSHA"], Type.ICE),
[TrainerType.LORELEI]: new TrainerConfig((t = TrainerType.LORELEI)).initForEliteFour([ Species.SLOWBRO, Species.LAPRAS, Species.DEWGONG, Species.ALOLA_SANDSLASH ], Type.ICE), [TrainerType.LORELEI]: new TrainerConfig((t = TrainerType.LORELEI)).initForEliteFour(signatureSpecies["LORELEI"], Type.ICE),
[TrainerType.BRUNO]: new TrainerConfig(++t).initForEliteFour([ Species.ONIX, Species.HITMONCHAN, Species.HITMONLEE, Species.ALOLA_GOLEM ], Type.FIGHTING), [TrainerType.BRUNO]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["BRUNO"], Type.FIGHTING),
[TrainerType.AGATHA]: new TrainerConfig(++t).initForEliteFour([ Species.GENGAR, Species.ARBOK, Species.CROBAT, Species.ALOLA_MAROWAK ], Type.GHOST), [TrainerType.AGATHA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["AGATHA"], Type.GHOST),
[TrainerType.LANCE]: new TrainerConfig(++t).setName("Lance").initForEliteFour([ Species.DRAGONITE, Species.GYARADOS, Species.AERODACTYL, Species.ALOLA_EXEGGUTOR ], Type.DRAGON), [TrainerType.LANCE]: new TrainerConfig(++t).setName("Lance").initForEliteFour(signatureSpecies["LANCE"], Type.DRAGON),
[TrainerType.WILL]: new TrainerConfig(++t).initForEliteFour([ Species.XATU, Species.JYNX, Species.SLOWBRO, Species.EXEGGUTOR ], Type.PSYCHIC), [TrainerType.WILL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["WILL"], Type.PSYCHIC),
[TrainerType.KOGA]: new TrainerConfig(++t).initForEliteFour([ Species.WEEZING, Species.VENOMOTH, Species.CROBAT, Species.TENTACRUEL ], Type.POISON), [TrainerType.KOGA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["KOGA"], Type.POISON),
[TrainerType.KAREN]: new TrainerConfig(++t).initForEliteFour([ Species.UMBREON, Species.HONCHKROW, Species.HOUNDOOM, Species.WEAVILE ], Type.DARK), [TrainerType.KAREN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["KAREN"], Type.DARK),
[TrainerType.SIDNEY]: new TrainerConfig(++t).initForEliteFour([ Species.SHIFTRY, Species.SHARPEDO, Species.ABSOL, Species.ZOROARK ], Type.DARK), [TrainerType.SIDNEY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["SIDNEY"], Type.DARK),
[TrainerType.PHOEBE]: new TrainerConfig(++t).initForEliteFour([ Species.SABLEYE, Species.DUSKNOIR, Species.BANETTE, Species.CHANDELURE ], Type.GHOST), [TrainerType.PHOEBE]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["PHOEBE"], Type.GHOST),
[TrainerType.GLACIA]: new TrainerConfig(++t).initForEliteFour([ Species.GLALIE, Species.WALREIN, Species.FROSLASS, Species.ABOMASNOW ], Type.ICE), [TrainerType.GLACIA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["GLACIA"], Type.ICE),
[TrainerType.DRAKE]: new TrainerConfig(++t).initForEliteFour([ Species.ALTARIA, Species.SALAMENCE, Species.FLYGON, Species.KINGDRA ], Type.DRAGON), [TrainerType.DRAKE]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["DRAKE"], Type.DRAGON),
[TrainerType.AARON]: new TrainerConfig(++t).initForEliteFour([ Species.SCIZOR, Species.HERACROSS, Species.VESPIQUEN, Species.DRAPION ], Type.BUG), [TrainerType.AARON]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["AARON"], Type.BUG),
[TrainerType.BERTHA]: new TrainerConfig(++t).initForEliteFour([ Species.WHISCASH, Species.HIPPOWDON, Species.GLISCOR, Species.RHYPERIOR ], Type.GROUND), [TrainerType.BERTHA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["BERTHA"], Type.GROUND),
[TrainerType.FLINT]: new TrainerConfig(++t).initForEliteFour([ Species.FLAREON, Species.HOUNDOOM, Species.RAPIDASH, Species.INFERNAPE ], Type.FIRE), [TrainerType.FLINT]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["FLINT"], Type.FIRE),
[TrainerType.LUCIAN]: new TrainerConfig(++t).initForEliteFour([ Species.MR_MIME, Species.GALLADE, Species.BRONZONG, Species.ALAKAZAM ], Type.PSYCHIC), [TrainerType.LUCIAN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["LUCIAN"], Type.PSYCHIC),
[TrainerType.SHAUNTAL]: new TrainerConfig(++t).initForEliteFour([ Species.COFAGRIGUS, Species.CHANDELURE, Species.GOLURK, Species.DRIFBLIM ], Type.GHOST), [TrainerType.SHAUNTAL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["SHAUNTAL"], Type.GHOST),
[TrainerType.MARSHAL]: new TrainerConfig(++t).initForEliteFour([ Species.TIMBURR, Species.MIENFOO, Species.THROH, Species.SAWK ], Type.FIGHTING), [TrainerType.MARSHAL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["MARSHAL"], Type.FIGHTING),
[TrainerType.GRIMSLEY]: new TrainerConfig(++t).initForEliteFour([ Species.LIEPARD, Species.KINGAMBIT, Species.SCRAFTY, Species.KROOKODILE ], Type.DARK), [TrainerType.GRIMSLEY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["GRIMSLEY"], Type.DARK),
[TrainerType.CAITLIN]: new TrainerConfig(++t).initForEliteFour([ Species.MUSHARNA, Species.GOTHITELLE, Species.SIGILYPH, Species.REUNICLUS ], Type.PSYCHIC), [TrainerType.CAITLIN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["CAITLIN"], Type.PSYCHIC),
[TrainerType.MALVA]: new TrainerConfig(++t).initForEliteFour([ Species.PYROAR, Species.TORKOAL, Species.CHANDELURE, Species.TALONFLAME ], Type.FIRE), [TrainerType.MALVA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["MALVA"], Type.FIRE),
[TrainerType.SIEBOLD]: new TrainerConfig(++t).initForEliteFour([ Species.CLAWITZER, Species.GYARADOS, Species.BARBARACLE, Species.STARMIE ], Type.WATER), [TrainerType.SIEBOLD]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["SIEBOLD"], Type.WATER),
[TrainerType.WIKSTROM]: new TrainerConfig(++t).initForEliteFour([ Species.KLEFKI, Species.PROBOPASS, Species.SCIZOR, Species.AEGISLASH ], Type.STEEL), [TrainerType.WIKSTROM]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["WIKSTROM"], Type.STEEL),
[TrainerType.DRASNA]: new TrainerConfig(++t).initForEliteFour([ Species.DRAGALGE, Species.DRUDDIGON, Species.ALTARIA, Species.NOIVERN ], Type.DRAGON), [TrainerType.DRASNA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["DRASNA"], Type.DRAGON),
[TrainerType.HALA]: new TrainerConfig(++t).initForEliteFour([ Species.HARIYAMA, Species.BEWEAR, Species.CRABOMINABLE, Species.POLIWRATH ], Type.FIGHTING), [TrainerType.HALA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["HALA"], Type.FIGHTING),
[TrainerType.MOLAYNE]: new TrainerConfig(++t).initForEliteFour([ Species.KLEFKI, Species.MAGNEZONE, Species.METAGROSS, Species.ALOLA_DUGTRIO ], Type.STEEL), [TrainerType.MOLAYNE]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["MOLAYNE"], Type.STEEL),
[TrainerType.OLIVIA]: new TrainerConfig(++t).initForEliteFour([ Species.ARMALDO, Species.CRADILY, Species.ALOLA_GOLEM, Species.LYCANROC ], Type.ROCK), [TrainerType.OLIVIA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["OLIVIA"], Type.ROCK),
[TrainerType.ACEROLA]: new TrainerConfig(++t).initForEliteFour([ Species.BANETTE, Species.DRIFBLIM, Species.DHELMISE, Species.PALOSSAND ], Type.GHOST), [TrainerType.ACEROLA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["ACEROLA"], Type.GHOST),
[TrainerType.KAHILI]: new TrainerConfig(++t).initForEliteFour([ Species.BRAVIARY, Species.HAWLUCHA, Species.ORICORIO, Species.TOUCANNON ], Type.FLYING), [TrainerType.KAHILI]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["KAHILI"], Type.FLYING),
[TrainerType.RIKA]: new TrainerConfig(++t).initForEliteFour([ Species. WHISCASH, Species.DONPHAN, Species.CAMERUPT, Species.CLODSIRE ], Type.GROUND), [TrainerType.MARNIE_ELITE]: new TrainerConfig(++t).setName("Marnie").initForEliteFour(signatureSpecies["MARNIE_ELITE"], Type.DARK),
[TrainerType.POPPY]: new TrainerConfig(++t).initForEliteFour([ Species.COPPERAJAH, Species.BRONZONG, Species.CORVIKNIGHT, Species.TINKATON ], Type.STEEL), [TrainerType.NESSA_ELITE]: new TrainerConfig(++t).setName("Nessa").initForEliteFour(signatureSpecies["NESSA_ELITE"], Type.WATER),
[TrainerType.LARRY_ELITE]: new TrainerConfig(++t).setName("Larry").initForEliteFour([ Species.STARAPTOR, Species.FLAMIGO, Species.ALTARIA, Species.TROPIUS ], Type.NORMAL, Type.FLYING), [TrainerType.BEA_ELITE]: new TrainerConfig(++t).setName("Bea").initForEliteFour(signatureSpecies["BEA_ELITE"], Type.FIGHTING),
[TrainerType.HASSEL]: new TrainerConfig(++t).initForEliteFour([ Species.NOIVERN, Species.HAXORUS, Species.DRAGALGE, Species.BAXCALIBUR ], Type.DRAGON), [TrainerType.ALLISTER_ELITE]: new TrainerConfig(++t).setName("Allister").initForEliteFour(signatureSpecies["ALLISTER_ELITE"], Type.GHOST),
[TrainerType.CRISPIN]: new TrainerConfig(++t).initForEliteFour([ Species.TALONFLAME, Species.CAMERUPT, Species.MAGMORTAR, Species.BLAZIKEN ], Type.FIRE), [TrainerType.RAIHAN_ELITE]: new TrainerConfig(++t).setName("Raihan").initForEliteFour(signatureSpecies["RAIHAN_ELITE"], Type.DRAGON),
[TrainerType.AMARYS]: new TrainerConfig(++t).initForEliteFour([ Species.SKARMORY, Species.EMPOLEON, Species.SCIZOR, Species.METAGROSS ], Type.STEEL), [TrainerType.RIKA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["RIKA"], Type.GROUND),
[TrainerType.LACEY]: new TrainerConfig(++t).initForEliteFour([ Species.EXCADRILL, Species.PRIMARINA, Species.ALCREMIE, Species.GALAR_SLOWBRO ], Type.FAIRY), [TrainerType.POPPY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["POPPY"], Type.STEEL),
[TrainerType.DRAYTON]: new TrainerConfig(++t).initForEliteFour([ Species.DRAGONITE, Species.ARCHALUDON, Species.FLYGON, Species.SCEPTILE ], Type.DRAGON), [TrainerType.LARRY_ELITE]: new TrainerConfig(++t).setName("Larry").initForEliteFour(signatureSpecies["LARRY_ELITE"], Type.NORMAL, Type.FLYING),
[TrainerType.HASSEL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["HASSEL"], Type.DRAGON),
[TrainerType.CRISPIN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["CRISPIN"], Type.FIRE),
[TrainerType.AMARYS]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["AMARYS"], Type.STEEL),
[TrainerType.LACEY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["LACEY"], Type.FAIRY),
[TrainerType.DRAYTON]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["DRAYTON"], Type.DRAGON),
[TrainerType.BLUE]: new TrainerConfig((t = TrainerType.BLUE)).initForChampion([ Species.GYARADOS, Species.MEWTWO, Species.ARCANINE, Species.ALAKAZAM, Species.PIDGEOT ]).setBattleBgm("battle_kanto_champion"), [TrainerType.BLUE]: new TrainerConfig((t = TrainerType.BLUE)).initForChampion(signatureSpecies["BLUE"]).setBattleBgm("battle_kanto_champion").setHasDouble("blue_red_double").setDoubleTrainerType(TrainerType.RED).setDoubleTitle("champion_double"),
[TrainerType.RED]: new TrainerConfig(++t).initForChampion([ Species.CHARIZARD, [ Species.LUGIA, Species.HO_OH ], Species.SNORLAX, Species.RAICHU, Species.ESPEON ]).setBattleBgm("battle_johto_champion"), [TrainerType.RED]: new TrainerConfig(++t).initForChampion(signatureSpecies["RED"]).setBattleBgm("battle_johto_champion").setHasDouble("red_blue_double").setDoubleTrainerType(TrainerType.BLUE).setDoubleTitle("champion_double"),
[TrainerType.LANCE_CHAMPION]: new TrainerConfig(++t).setName("Lance").initForChampion([ Species.DRAGONITE, Species.ZYGARDE, Species.AERODACTYL, Species.KINGDRA, Species.ALOLA_EXEGGUTOR ]).setBattleBgm("battle_johto_champion"), [TrainerType.LANCE_CHAMPION]: new TrainerConfig(++t).setName("Lance").initForChampion(signatureSpecies["LANCE_CHAMPION"]).setBattleBgm("battle_johto_champion"),
[TrainerType.STEVEN]: new TrainerConfig(++t).initForChampion([ Species.METAGROSS, [ Species.DIALGA, Species.PALKIA ], Species.SKARMORY, Species.AGGRON, Species.CARBINK ]).setBattleBgm("battle_hoenn_champion"), [TrainerType.STEVEN]: new TrainerConfig(++t).initForChampion(signatureSpecies["STEVEN"]).setBattleBgm("battle_hoenn_champion").setHasDouble("steven_wallace_double").setDoubleTrainerType(TrainerType.WALLACE).setDoubleTitle("champion_double"),
[TrainerType.WALLACE]: new TrainerConfig(++t).initForChampion([ Species.MILOTIC, Species.KYOGRE, Species.WHISCASH, Species.WALREIN, Species.LUDICOLO ]).setBattleBgm("battle_hoenn_champion"), [TrainerType.WALLACE]: new TrainerConfig(++t).initForChampion(signatureSpecies["WALLACE"]).setBattleBgm("battle_hoenn_champion").setHasDouble("wallace_steven_double").setDoubleTrainerType(TrainerType.STEVEN).setDoubleTitle("champion_double"),
[TrainerType.CYNTHIA]: new TrainerConfig(++t).initForChampion([ Species.SPIRITOMB, Species.GIRATINA, Species.GARCHOMP, Species.MILOTIC, Species.LUCARIO, Species.TOGEKISS ]).setBattleBgm("battle_sinnoh_champion"), [TrainerType.CYNTHIA]: new TrainerConfig(++t).initForChampion(signatureSpecies["CYNTHIA"]).setBattleBgm("battle_sinnoh_champion"),
[TrainerType.ALDER]: new TrainerConfig(++t).initForChampion([ Species.VOLCARONA, Species.GROUDON, Species.BOUFFALANT, Species.ACCELGOR, Species.CONKELDURR ]), [TrainerType.ALDER]: new TrainerConfig(++t).initForChampion(signatureSpecies["ALDER"]).setHasDouble("alder_iris_double").setDoubleTrainerType(TrainerType.IRIS).setDoubleTitle("champion_double").setBattleBgm("battle_unova_champion"),
[TrainerType.IRIS]: new TrainerConfig(++t).initForChampion([ Species.HAXORUS, Species.YVELTAL, Species.DRUDDIGON, Species.ARON, Species.LAPRAS ]).setBattleBgm("battle_champion_iris"), [TrainerType.IRIS]: new TrainerConfig(++t).initForChampion(signatureSpecies["IRIS"]).setBattleBgm("battle_champion_iris").setHasDouble("iris_alder_double").setDoubleTrainerType(TrainerType.ALDER).setDoubleTitle("champion_double"),
[TrainerType.DIANTHA]: new TrainerConfig(++t).initForChampion([ Species.HAWLUCHA, Species.XERNEAS, Species.GOURGEIST, Species.GOODRA, Species.GARDEVOIR ]), [TrainerType.DIANTHA]: new TrainerConfig(++t).initForChampion(signatureSpecies["DIANTHA"]),
[TrainerType.HAU]: new TrainerConfig(++t).initForChampion([ Species.ALOLA_RAICHU, [ Species.SOLGALEO, Species.LUNALA ], Species.NOIVERN, [ Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA ], Species.CRABOMINABLE ]), [TrainerType.HAU]: new TrainerConfig(++t).initForChampion(signatureSpecies["HAU"]),
[TrainerType.GEETA]: new TrainerConfig(++t).initForChampion([ Species.GLIMMORA, Species.MIRAIDON, Species.ESPATHRA, Species.VELUZA, Species.KINGAMBIT ]), [TrainerType.GEETA]: new TrainerConfig(++t).initForChampion(signatureSpecies["GEETA"]),
[TrainerType.NEMONA]: new TrainerConfig(++t).initForChampion([ Species.LYCANROC, Species.KORAIDON, Species.KOMMO_O, Species.PAWMOT, Species.DUSKNOIR ]), [TrainerType.NEMONA]: new TrainerConfig(++t).initForChampion(signatureSpecies["NEMONA"]),
[TrainerType.KIERAN]: new TrainerConfig(++t).initForChampion([ Species.POLITOED, [ Species.OGERPON, Species.TERAPAGOS ], Species.HYDRAPPLE, Species.PORYGON_Z, Species.GRIMMSNARL ]), [TrainerType.KIERAN]: new TrainerConfig(++t).initForChampion(signatureSpecies["KIERAN"]),
[TrainerType.LEON]: new TrainerConfig(++t).initForChampion([ Species.DRAGAPULT, [ Species.ZACIAN, Species.ZAMAZENTA ], Species.SEISMITOAD, Species.AEGISLASH, Species.CHARIZARD ]), [TrainerType.LEON]: new TrainerConfig(++t).initForChampion(signatureSpecies["LEON"]),
[TrainerType.RIVAL]: new TrainerConfig((t = TrainerType.RIVAL)).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setStaticParty().setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival").setPartyTemplates(trainerPartyTemplates.RIVAL) [TrainerType.RIVAL]: new TrainerConfig((t = TrainerType.RIVAL)).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setStaticParty().setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival").setPartyTemplates(trainerPartyTemplates.RIVAL)
.setModifierRewardFuncs(() => modifierTypes.SUPER_EXP_CHARM, () => modifierTypes.EXP_SHARE) .setModifierRewardFuncs(() => modifierTypes.SUPER_EXP_CHARM, () => modifierTypes.EXP_SHARE)

View File

@ -4,7 +4,7 @@ import { Variant, VariantSet, variantColorCache } from "#app/data/variant";
import { variantData } from "#app/data/variant"; import { variantData } from "#app/data/variant";
import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from "../ui/battle-info"; import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from "../ui/battle-info";
import { Moves } from "../data/enums/moves"; import { Moves } from "../data/enums/moves";
import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, VariablePowerAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, MultiHitAttr, StatusMoveTypeImmunityAttr, MoveTarget, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatChangesAttr, SacrificialAttr, VariableMoveTypeAttr, VariableMoveCategoryAttr, CounterDamageAttr, StatChangeAttr, RechargeAttr, ChargeAttr, IgnoreWeatherTypeDebuffAttr, BypassBurnDamageReductionAttr, SacrificialAttrOnHit } from "../data/move"; import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, VariablePowerAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, MultiHitAttr, StatusMoveTypeImmunityAttr, MoveTarget, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatChangesAttr, SacrificialAttr, VariableMoveTypeAttr, VariableMoveCategoryAttr, CounterDamageAttr, StatChangeAttr, RechargeAttr, ChargeAttr, IgnoreWeatherTypeDebuffAttr, BypassBurnDamageReductionAttr, SacrificialAttrOnHit, MoveFlags } from "../data/move";
import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities } from "../data/pokemon-species"; import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities } from "../data/pokemon-species";
import * as Utils from "../utils"; import * as Utils from "../utils";
import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from "../data/type"; import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from "../data/type";
@ -1613,6 +1613,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
typeMultiplier.value = 0; typeMultiplier.value = 0;
} }
// Apply arena tags for conditional protection
if (!move.hasFlag(MoveFlags.IGNORE_PROTECT) && !move.isAllyTarget()) {
const defendingSide = this.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
this.scene.arena.applyTagsForSide(ArenaTagType.QUICK_GUARD, defendingSide, cancelled, this, move.priority);
this.scene.arena.applyTagsForSide(ArenaTagType.WIDE_GUARD, defendingSide, cancelled, this, move.moveTarget);
this.scene.arena.applyTagsForSide(ArenaTagType.MAT_BLOCK, defendingSide, cancelled, this, move.category);
this.scene.arena.applyTagsForSide(ArenaTagType.CRAFTY_SHIELD, defendingSide, cancelled, this, move.category, move.moveTarget);
}
switch (moveCategory) { switch (moveCategory) {
case MoveCategory.PHYSICAL: case MoveCategory.PHYSICAL:
case MoveCategory.SPECIAL: case MoveCategory.SPECIAL:

View File

@ -1,7 +1,16 @@
import BattleScene from "../battle-scene"; import BattleScene from "../battle-scene";
import {pokemonPrevolutions} from "../data/pokemon-evolutions"; import {pokemonPrevolutions} from "../data/pokemon-evolutions";
import PokemonSpecies, {getPokemonSpecies} from "../data/pokemon-species"; import PokemonSpecies, {getPokemonSpecies} from "../data/pokemon-species";
import { TrainerConfig, TrainerPartyCompoundTemplate, TrainerPartyTemplate, TrainerPoolTier, TrainerSlot, trainerConfigs, trainerPartyTemplates } from "../data/trainer-config"; import {
TrainerConfig,
TrainerPartyCompoundTemplate,
TrainerPartyTemplate,
TrainerPoolTier,
TrainerSlot,
trainerConfigs,
trainerPartyTemplates,
signatureSpecies
} from "../data/trainer-config";
import {PartyMemberStrength} from "../data/enums/party-member-strength"; import {PartyMemberStrength} from "../data/enums/party-member-strength";
import {TrainerType} from "../data/enums/trainer-type"; import {TrainerType} from "../data/enums/trainer-type";
import {EnemyPokemon} from "./pokemon"; import {EnemyPokemon} from "./pokemon";
@ -142,6 +151,11 @@ export default class Trainer extends Phaser.GameObjects.Container {
} }
} }
if (this.config.titleDouble && this.variant === TrainerVariant.DOUBLE && !this.config.doubleOnly) {
title = this.config.titleDouble;
name = i18next.t(`trainerNames:${this.config.nameDouble.toLowerCase().replace(/\s/g, "_")}`);
}
// Return the formatted name, including the title if it is set. // Return the formatted name, including the title if it is set.
return title ? `${title} ${name}` : name; return title ? `${title} ${name}` : name;
} }
@ -236,6 +250,10 @@ export default class Trainer extends Phaser.GameObjects.Container {
const template = this.getPartyTemplate(); const template = this.getPartyTemplate();
const strength: PartyMemberStrength = template.getStrength(index); const strength: PartyMemberStrength = template.getStrength(index);
// If the battle is not one of the named trainer doubles
if (!(this.config.trainerTypeDouble && this.isDouble() && !this.config.doubleOnly)) {
if (this.config.partyMemberFuncs.hasOwnProperty(index)) { if (this.config.partyMemberFuncs.hasOwnProperty(index)) {
ret = this.config.partyMemberFuncs[index](this.scene, level, strength); ret = this.config.partyMemberFuncs[index](this.scene, level, strength);
return; return;
@ -244,7 +262,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
ret = this.config.partyMemberFuncs[index - template.size](this.scene, level, template.getStrength(index)); ret = this.config.partyMemberFuncs[index - template.size](this.scene, level, template.getStrength(index));
return; return;
} }
}
let offset = 0; let offset = 0;
if (template instanceof TrainerPartyCompoundTemplate) { if (template instanceof TrainerPartyCompoundTemplate) {
@ -256,7 +274,63 @@ export default class Trainer extends Phaser.GameObjects.Container {
} }
} }
const species = template.isSameSpecies(index) && index > offset // Create an empty species pool (which will be set to one of the species pools based on the index)
let newSpeciesPool = [];
let useNewSpeciesPool = false;
// If we are in a double battle of named trainers, we need to use alternate species pools (generate half the party from each trainer)
if (this.config.trainerTypeDouble && this.isDouble() && !this.config.doubleOnly) {
// Use the new species pool for this party generation
useNewSpeciesPool = true;
// Get the species pool for the partner trainer and the current trainer
const speciesPoolPartner = signatureSpecies[TrainerType[this.config.trainerTypeDouble]];
const speciesPool = signatureSpecies[TrainerType[this.config.trainerType]];
// Get the species that are already in the enemy party so we dont generate the same species twice
const AlreadyUsedSpecies = battle.enemyParty.map(p => p.species.speciesId);
// Filter out the species that are already in the enemy party from the main trainer species pool
const speciesPoolFiltered = speciesPool.filter(species => {
// Since some species pools have arrays in them (use either of those species), we need to check if one of the species is already in the party and filter the whole array if it is
if (Array.isArray(species)) {
return !species.some(s => AlreadyUsedSpecies.includes(s));
}
return !AlreadyUsedSpecies.includes(species);
});
// Filter out the species that are already in the enemy party from the partner trainer species pool
const speciesPoolPartnerFiltered = speciesPoolPartner.filter(species => {
// Since some species pools have arrays in them (use either of those species), we need to check if one of the species is already in the party and filter the whole array if it is
if (Array.isArray(species)) {
return !species.some(s => AlreadyUsedSpecies.includes(s));
}
return !AlreadyUsedSpecies.includes(species);
});
// If the index is even, use the species pool for the main trainer (that way he only uses his own pokemon in battle)
if (!(index % 2)) {
newSpeciesPool = speciesPoolFiltered;
} else {
// If the index is odd, use the species pool for the partner trainer (that way he only uses his own pokemon in battle)
newSpeciesPool = speciesPoolPartnerFiltered;
}
// Fallback for when the species pool is empty
if (newSpeciesPool.length === 0) {
// If all pokemon from this pool are already in the party, generate a random species
useNewSpeciesPool = false;
}
}
// If useNewSpeciesPool is true, we need to generate a new species from the new species pool, otherwise we generate a random species
const species = useNewSpeciesPool
? getPokemonSpecies(newSpeciesPool[Math.floor(Math.random() * newSpeciesPool.length)])
: template.isSameSpecies(index) && index > offset
? getPokemonSpecies(battle.enemyParty[offset].species.getTrainerSpeciesForLevel(level, false, template.getStrength(offset))) ? getPokemonSpecies(battle.enemyParty[offset].species.getTrainerSpeciesForLevel(level, false, template.getStrength(offset)))
: this.genNewPartyMemberSpecies(level, strength); : this.genNewPartyMemberSpecies(level, strength);
@ -266,6 +340,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
return ret; return ret;
} }
genNewPartyMemberSpecies(level: integer, strength: PartyMemberStrength, attempt?: integer): PokemonSpecies { genNewPartyMemberSpecies(level: integer, strength: PartyMemberStrength, attempt?: integer): PokemonSpecies {
const battle = this.scene.currentBattle; const battle = this.scene.currentBattle;
const template = this.getPartyTemplate(); const template = this.getPartyTemplate();

View File

@ -471,7 +471,7 @@ export const ability: AbilityTranslationEntries = {
}, },
honeyGather: { honeyGather: {
name: "Honigmaul", name: "Honigmaul",
description: "Das Pokémon sammelt nach Kämpfen eventuell Honig auf.", description: "The Pokémon gathers Honey after a battle. The Honey is then sold for money.",
}, },
frisk: { frisk: {
name: "Schnüffler", name: "Schnüffler",

View File

@ -29,7 +29,7 @@ export const menu: SimpleTranslationEntries = {
"confirmPassword": "Bestätige Passwort", "confirmPassword": "Bestätige Passwort",
"registrationAgeWarning": "Mit der Registrierung bestätigen Sie, dass Sie 13 Jahre oder älter sind.", "registrationAgeWarning": "Mit der Registrierung bestätigen Sie, dass Sie 13 Jahre oder älter sind.",
"backToLogin": "Zurück zur Anmeldung", "backToLogin": "Zurück zur Anmeldung",
"failedToLoadSaveData": "Speicherdaten konnten nicht geladen werden. Bitte laden Sie die Seite neu.\nWenn dies weiterhin der Fall ist, wenden Sie sich bitte an den Administrator.", "failedToLoadSaveData": "Speicherdaten konnten nicht geladen werden. Bitte laden Sie die Seite neu.\nÜberprüfe den #announcements-Kanal im Discord bei anhaltenden Problemen",
"sessionSuccess": "Sitzung erfolgreich geladen.", "sessionSuccess": "Sitzung erfolgreich geladen.",
"failedToLoadSession": "Ihre Sitzungsdaten konnten nicht geladen werden.\nSie könnten beschädigt sein.", "failedToLoadSession": "Ihre Sitzungsdaten konnten nicht geladen werden.\nSie könnten beschädigt sein.",
"boyOrGirl": "Bist du ein Junge oder ein Mädchen?", "boyOrGirl": "Bist du ein Junge oder ein Mädchen?",

View File

@ -5,7 +5,9 @@ export const titles: SimpleTranslationEntries = {
"elite_four": "Top Vier", "elite_four": "Top Vier",
"gym_leader": "Arenaleiter", "gym_leader": "Arenaleiter",
"gym_leader_female": "Arenaleiterin", "gym_leader_female": "Arenaleiterin",
"gym_leader_double": "Arenaleiter-Duo",
"champion": "Champion", "champion": "Champion",
"champion_double": "Champion-Duo",
"rival": "Rivale", "rival": "Rivale",
"professor": "Professor", "professor": "Professor",
"frontier_brain": "Kampfkoryphäen", "frontier_brain": "Kampfkoryphäen",
@ -241,4 +243,16 @@ export const trainerNames: SimpleTranslationEntries = {
"leon": "Delion", "leon": "Delion",
"rival": "Finn", "rival": "Finn",
"rival_female": "Ivy", "rival_female": "Ivy",
// Double Names
"blue_red_double": "Blau & Rot",
"red_blue_double": "Rot & Blau",
"tate_liza_double": "Ben & Svenja",
"liza_tate_double": "Svenja & Ben",
"steven_wallace_double": "Troy & Wassili",
"wallace_steven_double": "Wassili & Troy",
"alder_iris_double": "Lauro & Lilia",
"iris_alder_double": "Lilia & Lauro",
"piers_marnie_double": "Nezz & Mary",
"marnie_piers_double": "Mary & Nezz",
} as const; } as const;

View File

@ -471,7 +471,7 @@ export const ability: AbilityTranslationEntries = {
}, },
honeyGather: { honeyGather: {
name: "Honey Gather", name: "Honey Gather",
description: "The Pokémon may gather Honey after a battle.", description: "The Pokémon gathers Honey after a battle. The Honey is then sold for money.",
}, },
frisk: { frisk: {
name: "Frisk", name: "Frisk",

View File

@ -5,7 +5,9 @@ export const titles: SimpleTranslationEntries = {
"elite_four": "Elite Four", "elite_four": "Elite Four",
"gym_leader": "Gym Leader", "gym_leader": "Gym Leader",
"gym_leader_female": "Gym Leader", "gym_leader_female": "Gym Leader",
"gym_leader_double": "Gym Leader Duo",
"champion": "Champion", "champion": "Champion",
"champion_double": "Champion Duo",
"rival": "Rival", "rival": "Rival",
"professor": "Professor", "professor": "Professor",
"frontier_brain": "Frontier Brain", "frontier_brain": "Frontier Brain",
@ -241,4 +243,16 @@ export const trainerNames: SimpleTranslationEntries = {
"leon": "Leon", "leon": "Leon",
"rival": "Finn", "rival": "Finn",
"rival_female": "Ivy", "rival_female": "Ivy",
// Double Names
"blue_red_double": "Blue & Red",
"red_blue_double": "Red & Blue",
"tate_liza_double": "Tate & Liza",
"liza_tate_double": "Liza & Tate",
"steven_wallace_double": "Steven & Wallace",
"wallace_steven_double": "Wallace & Steven",
"alder_iris_double": "Alder & Iris",
"iris_alder_double": "Iris & Alder",
"marnie_piers_double": "Marnie & Piers",
"piers_marnie_double": "Piers & Marnie",
} as const; } as const;

View File

@ -471,7 +471,7 @@ export const ability: AbilityTranslationEntries = {
}, },
"honeyGather": { "honeyGather": {
name: "Recogemiel", name: "Recogemiel",
description: "Puede que encuentre Miel una vez concluido el combate." description: "The Pokémon gathers Honey after a battle. The Honey is then sold for money."
}, },
"frisk": { "frisk": {
name: "Cacheo", name: "Cacheo",

View File

@ -5,7 +5,9 @@ export const titles: SimpleTranslationEntries = {
"elite_four": "Elite Four", "elite_four": "Elite Four",
"gym_leader": "Gym Leader", "gym_leader": "Gym Leader",
"gym_leader_female": "Gym Leader", "gym_leader_female": "Gym Leader",
"gym_leader_double": "Gym Leader Duo",
"champion": "Champion", "champion": "Champion",
"champion_double": "Champion Duo",
"rival": "Rival", "rival": "Rival",
"professor": "Professor", "professor": "Professor",
"frontier_brain": "Frontier Brain", "frontier_brain": "Frontier Brain",
@ -240,4 +242,16 @@ export const trainerNames: SimpleTranslationEntries = {
"leon": "Leon", "leon": "Leon",
"rival": "Finn", "rival": "Finn",
"rival_female": "Ivy", "rival_female": "Ivy",
// Double Names
"blue_red_double": "Blue & Red",
"red_blue_double": "Red & Blue",
"tate_liza_double": "Tate & Liza",
"liza_tate_double": "Liza & Tate",
"steven_wallace_double": "Steven & Wallace",
"wallace_steven_double": "Wallace & Steven",
"alder_iris_double": "Alder & Iris",
"iris_alder_double": "Iris & Alder",
"marnie_piers_double": "Marnie & Piers",
"piers_marnie_double": "Piers & Marnie",
} as const; } as const;

View File

@ -471,7 +471,7 @@ export const ability: AbilityTranslationEntries = {
}, },
honeyGather: { honeyGather: {
name: "Cherche Miel", name: "Cherche Miel",
description: "Le Pokémon peut parfois trouver du Miel après un combat.", description: "The Pokémon gathers Honey after a battle. The Honey is then sold for money.",
}, },
frisk: { frisk: {
name: "Fouille", name: "Fouille",

View File

@ -5,7 +5,9 @@ export const titles: SimpleTranslationEntries = {
"elite_four": "Conseil 4", "elite_four": "Conseil 4",
"gym_leader": "Champion dArène", "gym_leader": "Champion dArène",
"gym_leader_female": "Championne dArène", "gym_leader_female": "Championne dArène",
"gym_leader_double": "Gym Leader Duo",
"champion": "Maitre·esse", //Written in gender-inclusive language in wait of a potential split of the entry "champion": "Maitre·esse", //Written in gender-inclusive language in wait of a potential split of the entry
"champion_double": "Champion Duo",
"rival": "Rival·e", //Written in gender-inclusive language in wait of a potential split of the entry "rival": "Rival·e", //Written in gender-inclusive language in wait of a potential split of the entry
"professor": "Professeur·e", //Written in gender-inclusive language in wait of a potential split of the entry "professor": "Professeur·e", //Written in gender-inclusive language in wait of a potential split of the entry
"frontier_brain": "Meneur·euse de Zone", //Written in gender-inclusive language in wait of a potential split of the entry "frontier_brain": "Meneur·euse de Zone", //Written in gender-inclusive language in wait of a potential split of the entry
@ -241,4 +243,17 @@ export const trainerNames: SimpleTranslationEntries = {
"leon": "Tarak", "leon": "Tarak",
"rival": "Gwenaël", //Male breton name, a celtic language spoken in Brittany (France) and related to the word for "white" (gwenn). Finn meaning is also "white" in irish/goidelic which are also celtic languages. "rival": "Gwenaël", //Male breton name, a celtic language spoken in Brittany (France) and related to the word for "white" (gwenn). Finn meaning is also "white" in irish/goidelic which are also celtic languages.
"rival_female": "Papina", //Litteral translation of ivy, also used as Female name in a North-American indigenous language "rival_female": "Papina", //Litteral translation of ivy, also used as Female name in a North-American indigenous language
// Double Names
"blue_red_double": "Blue & Red",
"red_blue_double": "Red & Blue",
"tate_liza_double": "Tate & Liza",
"liza_tate_double": "Liza & Tate",
"steven_wallace_double": "Steven & Wallace",
"wallace_steven_double": "Wallace & Steven",
"alder_iris_double": "Alder & Iris",
"iris_alder_double": "Iris & Alder",
"marnie_piers_double": "Marnie & Piers",
"piers_marnie_double": "Piers & Marnie",
} as const; } as const;

View File

@ -471,7 +471,7 @@ export const ability: AbilityTranslationEntries = {
}, },
honeyGather: { honeyGather: {
name: "Mielincetta", name: "Mielincetta",
description: "Il Pokémon può raccogliere del Miele alla fine della lotta.", description: "The Pokémon gathers Honey after a battle. The Honey is then sold for money.",
}, },
frisk: { frisk: {
name: "Indagine", name: "Indagine",

View File

@ -5,7 +5,9 @@ export const titles: SimpleTranslationEntries = {
"elite_four": "Superquattro", "elite_four": "Superquattro",
"gym_leader": "Capopalestra", "gym_leader": "Capopalestra",
"gym_leader_female": "Capopalestra", "gym_leader_female": "Capopalestra",
"gym_leader_double": "Gym Leader Duo",
"champion": "Campione", "champion": "Campione",
"champion_double": "Champion Duo",
"rival": "Rivale", "rival": "Rivale",
"professor": "Professore", "professor": "Professore",
"frontier_brain": "Asso Lotta", "frontier_brain": "Asso Lotta",
@ -241,4 +243,17 @@ export const trainerNames: SimpleTranslationEntries = {
"leon": "Leon", "leon": "Leon",
"rival": "Finn", "rival": "Finn",
"rival_female": "Ivy", "rival_female": "Ivy",
// Double Names
"blue_red_double": "Blue & Red",
"red_blue_double": "Red & Blue",
"tate_liza_double": "Tate & Liza",
"liza_tate_double": "Liza & Tate",
"steven_wallace_double": "Steven & Wallace",
"wallace_steven_double": "Wallace & Steven",
"alder_iris_double": "Alder & Iris",
"iris_alder_double": "Iris & Alder",
"marnie_piers_double": "Marnie & Piers",
"piers_marnie_double": "Piers & Marnie",
} as const; } as const;

View File

@ -471,7 +471,7 @@ export const ability: AbilityTranslationEntries = {
}, },
honeyGather: { honeyGather: {
name: "Honey Gather", name: "Honey Gather",
description: "O Pokémon pode coletar Mel ao final de uma batalha.", description: "The Pokémon gathers Honey after a battle. The Honey is then sold for money.",
}, },
frisk: { frisk: {
name: "Frisk", name: "Frisk",

View File

@ -5,7 +5,9 @@ export const titles: SimpleTranslationEntries = {
"elite_four": "Elite dos Quatro", "elite_four": "Elite dos Quatro",
"gym_leader": "Líder de Ginásio", "gym_leader": "Líder de Ginásio",
"gym_leader_female": "Líder de Ginásio", "gym_leader_female": "Líder de Ginásio",
"gym_leader_double": "Gym Leader Duo",
"champion": "Campeão", "champion": "Campeão",
"champion_double": "Champion Duo",
"rival": "Rival", "rival": "Rival",
"professor": "Professor", "professor": "Professor",
"frontier_brain": "Cérebro da Fronteira", "frontier_brain": "Cérebro da Fronteira",
@ -241,4 +243,16 @@ export const trainerNames: SimpleTranslationEntries = {
"leon": "Leon", "leon": "Leon",
"rival": "Finn", "rival": "Finn",
"rival_female": "Ivy", "rival_female": "Ivy",
// Double Names
"blue_red_double": "Blue & Red",
"red_blue_double": "Red & Blue",
"tate_liza_double": "Tate & Liza",
"liza_tate_double": "Liza & Tate",
"steven_wallace_double": "Steven & Wallace",
"wallace_steven_double": "Wallace & Steven",
"alder_iris_double": "Alder & Iris",
"iris_alder_double": "Iris & Alder",
"marnie_piers_double": "Marnie & Piers",
"piers_marnie_double": "Piers & Marnie",
} as const; } as const;

View File

@ -471,7 +471,7 @@ export const ability: AbilityTranslationEntries = {
}, },
honeyGather: { honeyGather: {
name: "采蜜", name: "采蜜",
description: "战斗结束时,有时候会捡来\n甜甜蜜。", description: "The Pokémon gathers Honey after a battle. The Honey is then sold for money.",
}, },
frisk: { frisk: {
name: "察觉", name: "察觉",

View File

@ -5,7 +5,9 @@ export const titles: SimpleTranslationEntries = {
"elite_four": "四天王", "elite_four": "四天王",
"gym_leader": "道馆馆主", "gym_leader": "道馆馆主",
"gym_leader_female": "道馆馆主", "gym_leader_female": "道馆馆主",
"gym_leader_double": "Gym Leader Duo",
"champion": "冠军", "champion": "冠军",
"champion_double": "Champion Duo",
"rival": "劲敌", "rival": "劲敌",
"professor": "博士", "professor": "博士",
"frontier_brain": "开拓头脑", "frontier_brain": "开拓头脑",
@ -297,4 +299,17 @@ export const trainerNames: SimpleTranslationEntries = {
// 劲敌 rival // 劲敌 rival
"rival": "芬恩", "rival": "芬恩",
"rival_female": "艾薇", "rival_female": "艾薇",
// Double Names
"blue_red_double": "Blue & Red",
"red_blue_double": "Red & Blue",
"tate_liza_double": "Tate & Liza",
"liza_tate_double": "Liza & Tate",
"steven_wallace_double": "Steven & Wallace",
"wallace_steven_double": "Wallace & Steven",
"alder_iris_double": "Alder & Iris",
"iris_alder_double": "Iris & Alder",
"marnie_piers_double": "Marnie & Piers",
"piers_marnie_double": "Piers & Marnie",
} as const; } as const;

View File

@ -418,7 +418,7 @@ export const ability: AbilityTranslationEntries = {
snowWarning: { name: "降雪", description: "出場時,會將天氣變爲下雪。" }, snowWarning: { name: "降雪", description: "出場時,會將天氣變爲下雪。" },
honeyGather: { honeyGather: {
name: "採蜜", name: "採蜜",
description: "戰鬥結束時,有時候會撿來\n甜甜蜜。", description: "The Pokémon gathers Honey after a battle. The Honey is then sold for money.",
}, },
frisk: { frisk: {
name: "察覺", name: "察覺",

View File

@ -34,8 +34,8 @@ export const move: MoveTranslationEntries = {
scratch: { name: "抓", effect: "用堅硬且無比鋒利的爪子抓\n對手進行攻擊" }, scratch: { name: "抓", effect: "用堅硬且無比鋒利的爪子抓\n對手進行攻擊" },
viseGrip: { name: "夾住", effect: "將對手從兩側夾住,給予傷\n害" }, viseGrip: { name: "夾住", effect: "將對手從兩側夾住,給予傷\n害" },
guillotine: { guillotine: {
name: "極落鉗", name: "斷頭鉗",
effect: "用大鉗子或剪刀等夾斷對手\n進行攻擊。只要命中就會一\n擊昏厥", effect: "用大鉗子或剪刀等夾斷對手\n進行攻擊。只要命中就會一\n擊瀕死",
}, },
razorWind: { razorWind: {
name: "旋風刀", name: "旋風刀",
@ -45,7 +45,7 @@ export const move: MoveTranslationEntries = {
name: "劍舞", name: "劍舞",
effect: "激烈地跳起戰舞提高氣勢。\n大幅提高自己的攻擊", effect: "激烈地跳起戰舞提高氣勢。\n大幅提高自己的攻擊",
}, },
cut: { name: "居合", effect: "用鐮刀或爪子等切斬對手進\n行攻擊" }, cut: { name: "居合", effect: "用鐮刀或爪子等切斬對手進\n行攻擊" },
gust: { name: "起風", effect: "用翅膀將颳起的狂風襲向對\n手進行攻擊" }, gust: { name: "起風", effect: "用翅膀將颳起的狂風襲向對\n手進行攻擊" },
wingAttack: { wingAttack: {
name: "翅膀攻擊", name: "翅膀攻擊",
@ -217,7 +217,7 @@ export const move: MoveTranslationEntries = {
effect: "一邊旋轉,一邊將尖喙刺入\n對手進行攻擊", effect: "一邊旋轉,一邊將尖喙刺入\n對手進行攻擊",
}, },
submission: { submission: {
name: "深淵翻滾", name: "地獄翻滾",
effect: "將對手連同自己一起摔向地\n面進行攻擊。自己也會受到\n少許傷害", effect: "將對手連同自己一起摔向地\n面進行攻擊。自己也會受到\n少許傷害",
}, },
lowKick: { lowKick: {
@ -305,7 +305,7 @@ export const move: MoveTranslationEntries = {
}, },
fissure: { fissure: {
name: "地裂", name: "地裂",
effect: "讓對手掉落於地裂的裂縫中\n進行攻擊。只要命中就會一\n擊昏厥", effect: "讓對手掉落於地裂的裂縫中\n進行攻擊。只要命中就會一\n擊瀕死",
}, },
dig: { name: "挖洞", effect: "第1回合鑽入地底,第2回\n合攻擊對手" }, dig: { name: "挖洞", effect: "第1回合鑽入地底,第2回\n合攻擊對手" },
toxic: { toxic: {
@ -421,8 +421,8 @@ export const move: MoveTranslationEntries = {
effect: "模仿對手使用的招式,自己\n也使用相同招式", effect: "模仿對手使用的招式,自己\n也使用相同招式",
}, },
selfDestruct: { selfDestruct: {
name: "玉石俱碎", name: "自爆",
effect: "引發爆炸,攻擊自己周圍所\n有的寶可夢。使用後陷入昏\n厥", effect: "引發爆炸,攻擊自己周圍所\n有的寶可夢。使用後陷入瀕\n死",
}, },
eggBomb: { name: "炸蛋", effect: "向對手用力投擲大大的蛋進\n行攻擊" }, eggBomb: { name: "炸蛋", effect: "向對手用力投擲大大的蛋進\n行攻擊" },
lick: { lick: {
@ -548,7 +548,7 @@ export const move: MoveTranslationEntries = {
}, },
explosion: { explosion: {
name: "大爆炸", name: "大爆炸",
effect: "引發大爆炸,攻擊自己周圍\n所有的寶可夢。使用後自己\n會陷入昏厥", effect: "引發大爆炸,攻擊自己周圍\n所有的寶可夢。使用後自己\n會陷入瀕死",
}, },
furySwipes: { furySwipes: {
name: "亂抓", name: "亂抓",
@ -563,15 +563,15 @@ export const move: MoveTranslationEntries = {
effect: "連續睡上2回合。回覆自己\n的全部以及治癒所有異\n常狀態", effect: "連續睡上2回合。回覆自己\n的全部以及治癒所有異\n常狀態",
}, },
rockSlide: { rockSlide: {
name: "崩", name: "崩",
effect: "將大岩石猛烈地撞向對手進\n行攻擊。有時會使對手畏縮", effect: "將大岩石猛烈地撞向對手進\n行攻擊。有時會使對手畏縮",
}, },
hyperFang: { hyperFang: {
name: "終結門牙", name: "必殺門牙",
effect: "用鋒利的門牙牢牢地咬住對\n手進行攻擊。有時會使對手\n畏縮", effect: "用鋒利的門牙牢牢地咬住對\n手進行攻擊。有時會使對手\n畏縮",
}, },
sharpen: { sharpen: {
name: "角化", name: "角化",
effect: "增加身體的角,變得棱棱角\n角從而提高自己的攻擊", effect: "增加身體的角,變得棱棱角\n角從而提高自己的攻擊",
}, },
conversion: { conversion: {
@ -651,7 +651,7 @@ export const move: MoveTranslationEntries = {
effect: "將棉花般柔軟的孢子緊貼對\n手從而大幅降低對手的速\n度", effect: "將棉花般柔軟的孢子緊貼對\n手從而大幅降低對手的速\n度",
}, },
reversal: { reversal: {
name: "絕處逢生", name: "起死回生",
effect: "竭盡全力進行攻擊。自己的\n越少招式的威力越大", effect: "竭盡全力進行攻擊。自己的\n越少招式的威力越大",
}, },
spite: { spite: {
@ -671,7 +671,7 @@ export const move: MoveTranslationEntries = {
effect: "以迅雷不及掩耳之勢出拳。\n必定能夠先制攻擊", effect: "以迅雷不及掩耳之勢出拳。\n必定能夠先制攻擊",
}, },
scaryFace: { scaryFace: {
name: "可怕面孔", name: "鬼面",
effect: "用恐怖的表情瞪着對手,使\n其害怕從而大幅降低對手\n的速度", effect: "用恐怖的表情瞪着對手,使\n其害怕從而大幅降低對手\n的速度",
}, },
feintAttack: { feintAttack: {
@ -712,11 +712,11 @@ export const move: MoveTranslationEntries = {
}, },
destinyBond: { destinyBond: {
name: "同命", name: "同命",
effect: "使出招式後,當受到對手攻\n擊陷入昏厥時,對手也會一\n同昏厥。連續使出則會失敗", effect: "使出招式後,當受到對手攻\n擊陷入瀕死時,對手也會一\n同瀕死。連續使出則會失敗",
}, },
perishSong: { perishSong: {
name: "終焉之歌", name: "滅亡之歌",
effect: "傾聽歌聲的寶可夢經過3回\n合陷入昏厥。替換後效果消\n失", effect: "傾聽歌聲的寶可夢經過3回\n合陷入瀕死。替換後效果消\n失",
}, },
icyWind: { icyWind: {
name: "冰凍之風", name: "冰凍之風",
@ -922,7 +922,7 @@ export const move: MoveTranslationEntries = {
effect: "在使用招式2回合後,向對\n手發送一團念力進行攻擊", effect: "在使用招式2回合後,向對\n手發送一團念力進行攻擊",
}, },
rockSmash: { rockSmash: {
name: "碎", name: "碎",
effect: "用拳頭進行攻擊。有時會降\n低對手的防禦", effect: "用拳頭進行攻擊。有時會降\n低對手的防禦",
}, },
whirlpool: { whirlpool: {
@ -970,7 +970,7 @@ export const move: MoveTranslationEntries = {
effect: "吹捧對手,使其混亂。同時\n還會提高對手的特攻", effect: "吹捧對手,使其混亂。同時\n還會提高對手的特攻",
}, },
willOWisp: { willOWisp: {
name: "火", name: "火",
effect: "放出怪異的火焰,從而讓對\n手陷入灼傷狀態", effect: "放出怪異的火焰,從而讓對\n手陷入灼傷狀態",
}, },
memento: { memento: {
@ -1023,8 +1023,8 @@ export const move: MoveTranslationEntries = {
effect: "向同伴緊急求助,從我方寶\n可夢已學會的招式中隨機使\n用個", effect: "向同伴緊急求助,從我方寶\n可夢已學會的招式中隨機使\n用個",
}, },
ingrain: { ingrain: {
name: "根", name: "根",
effect: "在大地上紮根,每回合回覆\n自己的。因爲紮根了,\n所以不能替換寶可夢", effect: "在大地上扎根,每回合回覆\n自己的。因爲扎根了,\n所以不能替換寶可夢",
}, },
superpower: { superpower: {
name: "蠻力", name: "蠻力",
@ -1201,8 +1201,8 @@ export const move: MoveTranslationEntries = {
effect: "讓對手聽舒適的笛聲,從而\n陷入睡眠狀態", effect: "讓對手聽舒適的笛聲,從而\n陷入睡眠狀態",
}, },
tickle: { tickle: {
name: "癢", name: "癢",
effect: "給對手癢,使其發笑,從\n而降低對手的攻擊和防禦", effect: "給對手癢,使其發笑,從\n而降低對手的攻擊和防禦",
}, },
cosmicPower: { cosmicPower: {
name: "宇宙力量", name: "宇宙力量",
@ -1222,16 +1222,16 @@ export const move: MoveTranslationEntries = {
effect: "發出看不見的神奇力量進行\n攻擊。有時會使對手畏縮", effect: "發出看不見的神奇力量進行\n攻擊。有時會使對手畏縮",
}, },
skyUppercut: { skyUppercut: {
name: "天拳", name: "天拳",
effect: "用衝向天空般高高的上勾拳\n頂起對手進行攻擊", effect: "用衝向天空般高高的上勾拳\n頂起對手進行攻擊",
}, },
sandTomb: { sandTomb: {
name: "流沙深淵", name: "流沙地獄",
effect: "將對手困在鋪天蓋地的沙暴\n中回合內進行攻\n擊", effect: "將對手困在鋪天蓋地的沙暴\n中回合內進行攻\n擊",
}, },
sheerCold: { sheerCold: {
name: "絕對零度", name: "絕對零度",
effect: "給對手一擊昏厥。如果是冰\n屬性以外的寶可夢使用就\n會難以打中", effect: "給對手一擊瀕死。如果是冰\n屬性以外的寶可夢使用就\n會難以打中",
}, },
muddyWater: { muddyWater: {
name: "濁流", name: "濁流",
@ -1353,7 +1353,7 @@ export const move: MoveTranslationEntries = {
}, },
healingWish: { healingWish: {
name: "治癒之願", name: "治癒之願",
effect: "雖然自己陷入昏厥,但可以\n治癒後備上場的寶可夢的異\n常狀態以及回覆", effect: "雖然自己陷入瀕死,但可以\n治癒後備上場的寶可夢的異\n常狀態以及回覆",
}, },
brine: { brine: {
name: "鹽水", name: "鹽水",
@ -1519,7 +1519,7 @@ export const move: MoveTranslationEntries = {
effect: "將外殼堅硬的大種子,從上\n方砸下攻擊對手", effect: "將外殼堅硬的大種子,從上\n方砸下攻擊對手",
}, },
airSlash: { airSlash: {
name: "空氣之刃", name: "空氣",
effect: "用連天空也能劈開的空氣之\n刃進行攻擊。有時會使對手\n畏縮", effect: "用連天空也能劈開的空氣之\n刃進行攻擊。有時會使對手\n畏縮",
}, },
xScissor: { xScissor: {
@ -1630,7 +1630,7 @@ export const move: MoveTranslationEntries = {
effect: "將身體的光芒聚集在一點釋\n放出去。有時會降低對手的\n特防", effect: "將身體的光芒聚集在一點釋\n放出去。有時會降低對手的\n特防",
}, },
rockClimb: { rockClimb: {
name: "攀", name: "攀",
effect: "發動猛撞攻擊,有時會使對\n手混亂。是寶可表的祕傳招\n式之一", effect: "發動猛撞攻擊,有時會使對\n手混亂。是寶可表的祕傳招\n式之一",
}, },
defog: { defog: {
@ -1642,7 +1642,7 @@ export const move: MoveTranslationEntries = {
effect: "製造出離奇的空間。在5回\n合內速度慢的寶可夢可以先\n行動", effect: "製造出離奇的空間。在5回\n合內速度慢的寶可夢可以先\n行動",
}, },
dracoMeteor: { dracoMeteor: {
name: "流星", name: "流星",
effect: "從天空中向對手落下隕石。\n使用之後因爲反作用力自\n己的特攻會大幅降低", effect: "從天空中向對手落下隕石。\n使用之後因爲反作用力自\n己的特攻會大幅降低",
}, },
discharge: { discharge: {
@ -1690,7 +1690,7 @@ export const move: MoveTranslationEntries = {
effect: "♂誘惑♀或♀誘惑♂,從而\n大幅降低對手的特攻", effect: "♂誘惑♀或♀誘惑♂,從而\n大幅降低對手的特攻",
}, },
stealthRock: { stealthRock: {
name: "隱形", name: "隱形",
effect: "將無數岩石懸浮在對手的周\n圍從而對替換出場的對手\n的寶可夢給予傷害", effect: "將無數岩石懸浮在對手的周\n圍從而對替換出場的對手\n的寶可夢給予傷害",
}, },
grassKnot: { grassKnot: {
@ -1893,7 +1893,7 @@ export const move: MoveTranslationEntries = {
effect: "用歌聲攻擊對手。大家一起\n輪唱便可以接連使出威力\n也會提高", effect: "用歌聲攻擊對手。大家一起\n輪唱便可以接連使出威力\n也會提高",
}, },
echoedVoice: { echoedVoice: {
name: "聲", name: "聲",
effect: "用回聲攻擊對手。如果每回\n合都有寶可夢接着使用該招\n式威力就會提高", effect: "用回聲攻擊對手。如果每回\n合都有寶可夢接着使用該招\n式威力就會提高",
}, },
chipAway: { chipAway: {
@ -1945,7 +1945,7 @@ export const move: MoveTranslationEntries = {
effect: "扔飛對手,強制拉後備寶可\n夢上場。如果對手爲野生寶\n可夢戰鬥將直接結束", effect: "扔飛對手,強制拉後備寶可\n夢上場。如果對手爲野生寶\n可夢戰鬥將直接結束",
}, },
incinerate: { incinerate: {
name: "燒", name: "燒",
effect: "用火焰攻擊對手。對手攜帶\n樹果等時會燒掉使其不\n能使用", effect: "用火焰攻擊對手。對手攜帶\n樹果等時會燒掉使其不\n能使用",
}, },
quash: { quash: {
@ -1972,8 +1972,8 @@ export const move: MoveTranslationEntries = {
effect: "當對手未攜帶道具時,能夠\n將自己攜帶的道具交給對手", effect: "當對手未攜帶道具時,能夠\n將自己攜帶的道具交給對手",
}, },
inferno: { inferno: {
name: "烈火深淵", name: "煉獄",
effect: "用烈焰包裹住對手進行攻擊。\n讓對手陷入灼傷狀態", effect: "用猛烈的火焰包圍對手進行\n攻擊。讓對手陷入灼傷狀態",
}, },
waterPledge: { waterPledge: {
name: "水之誓約", name: "水之誓約",

View File

@ -5,7 +5,9 @@ export const titles: SimpleTranslationEntries = {
"elite_four": "四天王", "elite_four": "四天王",
"gym_leader": "道館館主", "gym_leader": "道館館主",
"gym_leader_female": "道館館主", "gym_leader_female": "道館館主",
"gym_leader_double": "Gym Leader Duo",
"champion": "冠軍", "champion": "冠軍",
"champion_double": "Champion Duo",
"rival": "勁敵", "rival": "勁敵",
"professor": "博士", "professor": "博士",
"frontier_brain": "開拓頭腦", "frontier_brain": "開拓頭腦",
@ -296,5 +298,17 @@ export const trainerNames: SimpleTranslationEntries = {
// 勁敵 Rival // 勁敵 Rival
"rival": "芬恩", "rival": "芬恩",
"rival_female": "艾薇" "rival_female": "艾薇",
// Double Names
"blue_red_double": "Blue & Red",
"red_blue_double": "Red & Blue",
"tate_liza_double": "Tate & Liza",
"liza_tate_double": "Liza & Tate",
"steven_wallace_double": "Steven & Wallace",
"wallace_steven_double": "Wallace & Steven",
"alder_iris_double": "Alder & Iris",
"iris_alder_double": "Iris & Alder",
"marnie_piers_double": "Marnie & Piers",
"piers_marnie_double": "Piers & Marnie",
} as const; } as const;

View File

@ -729,6 +729,11 @@ export class EncounterPhase extends BattlePhase {
this.scene.initSession(); this.scene.initSession();
// Failsafe if players somehow skip floor 200 in classic mode
if (this.scene.gameMode.isClassic && this.scene.currentBattle.waveIndex > 200) {
this.scene.unshiftPhase(new GameOverPhase(this.scene));
}
const loadEnemyAssets = []; const loadEnemyAssets = [];
const battle = this.scene.currentBattle; const battle = this.scene.currentBattle;
@ -2296,9 +2301,6 @@ export class BattleEndPhase extends BattlePhase {
super.start(); super.start();
this.scene.currentBattle.addBattleScore(this.scene); this.scene.currentBattle.addBattleScore(this.scene);
if (this.scene.currentBattle.moneyScattered) {
this.scene.currentBattle.pickUpScatteredMoney(this.scene);
}
this.scene.gameData.gameStats.battles++; this.scene.gameData.gameStats.battles++;
if (this.scene.currentBattle.trainer) { if (this.scene.currentBattle.trainer) {
@ -2318,6 +2320,10 @@ export class BattleEndPhase extends BattlePhase {
applyPostBattleAbAttrs(PostBattleAbAttr, pokemon); applyPostBattleAbAttrs(PostBattleAbAttr, pokemon);
} }
if (this.scene.currentBattle.moneyScattered) {
this.scene.currentBattle.pickUpScatteredMoney(this.scene);
}
this.scene.clearEnemyHeldItemModifiers(); this.scene.clearEnemyHeldItemModifiers();
const lapsingModifiers = this.scene.findModifiers(m => m instanceof LapsingPersistentModifier || m instanceof LapsingPokemonHeldItemModifier) as (LapsingPersistentModifier | LapsingPokemonHeldItemModifier)[]; const lapsingModifiers = this.scene.findModifiers(m => m instanceof LapsingPersistentModifier || m instanceof LapsingPokemonHeldItemModifier) as (LapsingPersistentModifier | LapsingPokemonHeldItemModifier)[];
@ -3862,6 +3868,11 @@ export class GameOverPhase extends BattlePhase {
start() { start() {
super.start(); super.start();
// Failsafe if players somehow skip floor 200 in classic mode
if (this.scene.gameMode.isClassic && this.scene.currentBattle.waveIndex > 200) {
this.victory = true;
}
if (this.victory || !this.scene.enableRetries) { if (this.victory || !this.scene.enableRetries) {
this.handleGameOver(); this.handleGameOver();
} else { } else {

View File

@ -380,6 +380,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
if (this.player) { if (this.player) {
this.y -= 12 * (mini ? 1 : -1); this.y -= 12 * (mini ? 1 : -1);
this.baseY = this.y;
} }
const offsetElements = [ this.nameText, this.genderText, this.teraIcon, this.splicedIcon, this.shinyIcon, this.statusIndicator, this.levelContainer ]; const offsetElements = [ this.nameText, this.genderText, this.teraIcon, this.splicedIcon, this.shinyIcon, this.statusIndicator, this.levelContainer ];

View File

@ -166,7 +166,7 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container {
this.pokemonFusionShinyIcon.setTint(getVariantTint(pokemon.fusionVariant)); this.pokemonFusionShinyIcon.setTint(getVariantTint(pokemon.fusionVariant));
} }
const starterSpeciesId = pokemon.species.getRootSpeciesId(true); const starterSpeciesId = pokemon.species.getRootSpeciesId();
const originalIvs: integer[] = this.scene.gameData.dexData[starterSpeciesId].caughtAttr const originalIvs: integer[] = this.scene.gameData.dexData[starterSpeciesId].caughtAttr
? this.scene.gameData.dexData[starterSpeciesId].ivs ? this.scene.gameData.dexData[starterSpeciesId].ivs
: null; : null;