Compare commits

..

No commits in common. "d052d444b6e812dd5f01de0c0c85d1af73a057ff" and "99e17c94ebb206935a050ae06b55f3028f1ade05" have entirely different histories.

48 changed files with 68 additions and 640 deletions

View File

@ -4,9 +4,6 @@ on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
pages:
@ -36,7 +33,6 @@ jobs:
node-version: 20
- name: Checkout repository for Github Pages
if: github.event_name == 'push'
uses: actions/checkout@v3
with:
path: pokerogue_gh
@ -56,7 +52,6 @@ jobs:
npx typedoc --out /tmp/docs --githubPages false --entryPoints ./src/
- name: Commit & Push docs
if: github.event_name == 'push'
run: |
cd pokerogue_gh
git config user.email "github-actions[bot]@users.noreply.github.com"

View File

@ -7400,49 +7400,7 @@
"w": 16,
"h": 16
}
},
{
"filename": "toxic_orb",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 32,
"h": 32
},
"spriteSourceSize": {
"x": 7,
"y": 7,
"w": 18,
"h": 18
},
"frame": {
"x": 379,
"y": 274,
"w": 18,
"h": 18
}
},
{
"filename": "flame_orb",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 32,
"h": 32
},
"spriteSourceSize": {
"x": 7,
"y": 7,
"w": 18,
"h": 18
},
"frame": {
"x": 379,
"y": 292,
"w": 18,
"h": 18
}
}
}
]
}
],

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 367 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 408 B

View File

@ -1332,27 +1332,6 @@
"h": 24
}
},
{
"filename": "173_2",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 40,
"h": 30
},
"spriteSourceSize": {
"x": 11,
"y": 11,
"w": 18,
"h": 18
},
"frame": {
"x": 174,
"y": 253,
"w": 18,
"h": 18
}
},
{
"filename": "173_3",
"rotated": false,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -1,41 +0,0 @@
{
"textures": [
{
"image": "firebreather.png",
"format": "RGBA8888",
"size": {
"w": 80,
"h": 72
},
"scale": 1,
"frames": [
{
"filename": "0001.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 80,
"h": 72
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 80,
"h": 72
},
"frame": {
"x": 0,
"y": 0,
"w": 80,
"h": 72
}
}
]
}
],
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:f692676a166fc1915532cd94d5799af4:fb833f76fb6797474657726bb59a7eee:aeb55e30992938f494b6cd2420158dda$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -55,22 +55,8 @@ export class Ability implements Localizable {
this.description = this.id ? i18next.t(`ability:${i18nKey}.description`) as string : "";
}
/**
* Get all ability attributes that match `attrType`
* @param attrType any attribute that extends {@linkcode AbAttr}
* @returns Array of attributes that match `attrType`, Empty Array if none match.
*/
getAttrs<T extends AbAttr>(attrType: new(...args: any[]) => T ): T[] {
return this.attrs.filter((a): a is T => a instanceof attrType);
}
/**
* Check if an ability has an attribute that matches `attrType`
* @param attrType any attribute that extends {@linkcode AbAttr}
* @returns true if the ability has attribute `attrType`
*/
hasAttr<T extends AbAttr>(attrType: new(...args: any[]) => T): boolean {
return this.attrs.some((attr) => attr instanceof attrType);
getAttrs(attrType: { new(...args: any[]): AbAttr }): AbAttr[] {
return this.attrs.filter(a => a instanceof attrType);
}
attr<T extends new (...args: any[]) => AbAttr>(AttrType: T, ...args: ConstructorParameters<T>): Ability {
@ -88,6 +74,10 @@ export class Ability implements Localizable {
return this;
}
hasAttr(attrType: { new(...args: any[]): AbAttr }): boolean {
return !!this.getAttrs(attrType).length;
}
bypassFaint(): Ability {
this.isBypassFaint = true;
return this;
@ -351,7 +341,7 @@ export class TypeImmunityAbAttr extends PreDefendAbAttr {
}
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean {
if ((move.getMove() instanceof AttackMove || move.getMove().getAttrs(StatusMoveTypeImmunityAttr).find(attr => attr.immuneType === this.immuneType)) && move.getMove().type === this.immuneType) {
if ((move.getMove() instanceof AttackMove || move.getMove().getAttrs(StatusMoveTypeImmunityAttr).find(attr => (attr as StatusMoveTypeImmunityAttr).immuneType === this.immuneType)) && move.getMove().type === this.immuneType) {
(args[0] as Utils.NumberHolder).value = 0;
return true;
}
@ -578,7 +568,7 @@ export class MoveImmunityStatChangeAbAttr extends MoveImmunityAbAttr {
export class ReverseDrainAbAttr extends PostDefendAbAttr {
applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean {
if (move.getMove().hasAttr(HitHealAttr) || move.getMove().hasAttr(StrengthSapHealAttr) ) {
if (!!move.getMove().getAttrs(HitHealAttr).length || !!move.getMove().getAttrs(StrengthSapHealAttr).length ) {
pokemon.scene.queueMessage(getPokemonMessage(attacker, " sucked up the liquid ooze!"));
return true;
}
@ -2204,7 +2194,7 @@ function getAnticipationCondition(): AbAttrCondition {
return true;
}
// move is a OHKO
if (move.getMove().hasAttr(OneHitKOAttr)) {
if (move.getMove().findAttr(attr => attr instanceof OneHitKOAttr)) {
return true;
}
// edge case for hidden power, type is computed
@ -2258,7 +2248,7 @@ export class ForewarnAbAttr extends PostSummonAbAttr {
for (const move of opponent.moveset) {
if (move.getMove() instanceof StatusMove) {
movePower = 1;
} else if (move.getMove().hasAttr(OneHitKOAttr)) {
} else if (move.getMove().findAttr(attr => attr instanceof OneHitKOAttr)) {
movePower = 150;
} else if (move.getMove().id === Moves.COUNTER || move.getMove().id === Moves.MIRROR_COAT || move.getMove().id === Moves.METAL_BURST) {
movePower = 120;
@ -3335,7 +3325,7 @@ function applyAbAttrsInternal<TAttr extends AbAttr>(attrType: { new(...args: any
}
const ability = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility());
const attrs = ability.getAttrs(attrType);
const attrs = ability.getAttrs(attrType) as TAttr[];
const clearSpliceQueueAndResolve = () => {
pokemon.scene.clearPhaseQueueSplice();
@ -3534,7 +3524,7 @@ export const allAbilities = [ new Ability(Abilities.NONE, 3) ];
export function initAbilities() {
allAbilities.push(
new Ability(Abilities.STENCH, 3)
.attr(PostAttackApplyBattlerTagAbAttr, false, (user, target, move) => (move.getMove().category !== MoveCategory.STATUS && !move.getMove().hasAttr(FlinchAttr)) ? 10 : 0, BattlerTagType.FLINCHED),
.attr(PostAttackApplyBattlerTagAbAttr, false, (user, target, move) => (move.getMove().category !== MoveCategory.STATUS && !move.getMove().findAttr(attr => attr instanceof FlinchAttr)) ? 10 : 0, BattlerTagType.FLINCHED),
new Ability(Abilities.DRIZZLE, 3)
.attr(PostSummonWeatherChangeAbAttr, WeatherType.RAIN)
.attr(PostBiomeChangeWeatherChangeAbAttr, WeatherType.RAIN),
@ -3726,9 +3716,9 @@ export function initAbilities() {
.conditionalAttr(pokemon => !Utils.randSeedInt(3), PostTurnResetStatusAbAttr),
new Ability(Abilities.GUTS, 3)
.attr(BypassBurnDamageReductionAbAttr)
.conditionalAttr(pokemon => !!pokemon.status || pokemon.hasAbility(Abilities.COMATOSE), BattleStatMultiplierAbAttr, BattleStat.ATK, 1.5),
.conditionalAttr(pokemon => !!pokemon.status, BattleStatMultiplierAbAttr, BattleStat.ATK, 1.5),
new Ability(Abilities.MARVEL_SCALE, 3)
.conditionalAttr(pokemon => !!pokemon.status || pokemon.hasAbility(Abilities.COMATOSE), BattleStatMultiplierAbAttr, BattleStat.DEF, 1.5)
.conditionalAttr(pokemon => !!pokemon.status, BattleStatMultiplierAbAttr, BattleStat.DEF, 1.5)
.ignorable(),
new Ability(Abilities.LIQUID_OOZE, 3)
.attr(ReverseDrainAbAttr),
@ -3823,7 +3813,7 @@ export function initAbilities() {
.condition(getWeatherCondition(WeatherType.SUNNY, WeatherType.HARSH_SUN)),
new Ability(Abilities.QUICK_FEET, 4)
.conditionalAttr(pokemon => pokemon.status ? pokemon.status.effect === StatusEffect.PARALYSIS : false, BattleStatMultiplierAbAttr, BattleStat.SPD, 2)
.conditionalAttr(pokemon => !!pokemon.status || pokemon.hasAbility(Abilities.COMATOSE), BattleStatMultiplierAbAttr, BattleStat.SPD, 1.5),
.conditionalAttr(pokemon => !!pokemon.status, BattleStatMultiplierAbAttr, BattleStat.SPD, 1.5),
new Ability(Abilities.NORMALIZE, 4)
.attr(MoveTypeChangeAttr, Type.NORMAL, 1.2, (user, target, move) => move.id !== Moves.HIDDEN_POWER && move.id !== Moves.WEATHER_BALL &&
move.id !== Moves.NATURAL_GIFT && move.id !== Moves.JUDGMENT && move.id !== Moves.TECHNO_BLAST),

View File

@ -468,7 +468,7 @@ export function initMoveAnim(scene: BattleScene, move: Moves): Promise<void> {
} else {
const loadedCheckTimer = setInterval(() => {
if (moveAnims.get(move) !== null) {
const chargeAttr = allMoves[move].getAttrs(ChargeAttr)[0] || allMoves[move].getAttrs(DelayedAttackAttr)[0];
const chargeAttr = allMoves[move].getAttrs(ChargeAttr).find(() => true) as ChargeAttr || allMoves[move].getAttrs(DelayedAttackAttr).find(() => true) as DelayedAttackAttr;
if (chargeAttr && chargeAnims.get(chargeAttr.chargeAnim) === null) {
return;
}
@ -498,7 +498,7 @@ export function initMoveAnim(scene: BattleScene, move: Moves): Promise<void> {
} else {
populateMoveAnim(move, ba);
}
const chargeAttr = allMoves[move].getAttrs(ChargeAttr)[0] || allMoves[move].getAttrs(DelayedAttackAttr)[0];
const chargeAttr = allMoves[move].getAttrs(ChargeAttr).find(() => true) as ChargeAttr || allMoves[move].getAttrs(DelayedAttackAttr).find(() => true) as DelayedAttackAttr;
if (chargeAttr) {
initMoveChargeAnim(scene, chargeAttr.chargeAnim).then(() => resolve());
} else {
@ -569,7 +569,7 @@ export function loadMoveAnimAssets(scene: BattleScene, moveIds: Moves[], startLo
return new Promise(resolve => {
const moveAnimations = moveIds.map(m => moveAnims.get(m) as AnimConfig).flat();
for (const moveId of moveIds) {
const chargeAttr = allMoves[moveId].getAttrs(ChargeAttr)[0] || allMoves[moveId].getAttrs(DelayedAttackAttr)[0];
const chargeAttr = allMoves[moveId].getAttrs(ChargeAttr).find(() => true) as ChargeAttr || allMoves[moveId].getAttrs(DelayedAttackAttr).find(() => true) as DelayedAttackAttr;
if (chargeAttr) {
const moveChargeAnims = chargeAnims.get(chargeAttr.chargeAnim);
moveAnimations.push(moveChargeAnims instanceof AnimConfig ? moveChargeAnims : moveChargeAnims[0]);

View File

@ -509,7 +509,7 @@ export class EncoreTag extends BattlerTag {
return false;
}
if (allMoves[repeatableMove.move].hasAttr(ChargeAttr) && repeatableMove.result === MoveResult.OTHER) {
if (allMoves[repeatableMove.move].getAttrs(ChargeAttr).length && repeatableMove.result === MoveResult.OTHER) {
return false;
}

View File

@ -1823,7 +1823,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.VOLCANO]: {
[BiomePoolTier.COMMON]: [ TrainerType.FIREBREATHER ],
[BiomePoolTier.COMMON]: [],
[BiomePoolTier.UNCOMMON]: [],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
@ -7304,10 +7304,6 @@ export function initBiomes() {
[ Biome.GRAVEYARD, BiomePoolTier.UNCOMMON ]
]
],
[ TrainerType.FIREBREATHER, [
[ Biome.VOLCANO, BiomePoolTier.COMMON ]
]
],
[ TrainerType.BROCK, [
[ Biome.CAVE, BiomePoolTier.BOSS ]
]

View File

@ -421,20 +421,6 @@ export const trainerTypeDialogue: TrainerTypeDialogue = {
]
}
],
[TrainerType.FIREBREATHER]: [
{
encounter: [
"dialogue:firebreather.encounter.1",
"dialogue:firebreather.encounter.2",
"dialogue:firebreather.encounter.3",
],
victory: [
"dialogue:firebreather.victory.1",
"dialogue:firebreather.victory.2",
"dialogue:firebreather.victory.3",
]
}
],
[TrainerType.BROCK]: {
encounter: [
"dialogue:brock.encounter.1",

View File

@ -16,7 +16,6 @@ export enum TrainerType {
DANCER,
DEPOT_AGENT,
DOCTOR,
FIREBREATHER,
FISHERMAN,
GUITARIST,
HARLEQUIN,

View File

@ -148,22 +148,8 @@ export default class Move implements Localizable {
this.effect = this.id ? `${i18next.t(`move:${i18nKey}.effect`)}${this.nameAppend}` : "";
}
/**
* Get all move attributes that match `attrType`
* @param attrType any attribute that extends {@linkcode MoveAttr}
* @returns Array of attributes that match `attrType`, Empty Array if none match.
*/
getAttrs<T extends MoveAttr>(attrType: new(...args: any[]) => T): T[] {
return this.attrs.filter((a): a is T => a instanceof attrType);
}
/**
* Check if a move has an attribute that matches `attrType`
* @param attrType any attribute that extends {@linkcode MoveAttr}
* @returns true if the move has attribute `attrType`
*/
hasAttr<T extends MoveAttr>(attrType: new(...args: any[]) => T): boolean {
return this.attrs.some((attr) => attr instanceof attrType);
getAttrs(attrType: { new(...args: any[]): MoveAttr }): MoveAttr[] {
return this.attrs.filter(a => a instanceof attrType);
}
findAttr(attrPredicate: (attr: MoveAttr) => boolean): MoveAttr {
@ -3712,7 +3698,7 @@ export class ProtectAttr extends AddBattlerTagAttr {
while (moveHistory.length) {
turnMove = moveHistory.shift();
if (!allMoves[turnMove.move].hasAttr(ProtectAttr) || turnMove.result !== MoveResult.SUCCESS) {
if (!allMoves[turnMove.move].getAttrs(ProtectAttr).length || turnMove.result !== MoveResult.SUCCESS) {
break;
}
timesUsed++;
@ -4494,7 +4480,7 @@ const lastMoveCopiableCondition: MoveConditionFunc = (user, target, move) => {
return false;
}
if (allMoves[copiableMove].hasAttr(ChargeAttr)) {
if (allMoves[copiableMove].getAttrs(ChargeAttr).length) {
return false;
}
@ -4584,7 +4570,7 @@ const targetMoveCopiableCondition: MoveConditionFunc = (user, target, move) => {
return false;
}
if (allMoves[copiableMove.move].hasAttr(ChargeAttr) && copiableMove.result === MoveResult.OTHER) {
if (allMoves[copiableMove.move].getAttrs(ChargeAttr).length && copiableMove.result === MoveResult.OTHER) {
return false;
}
@ -5001,7 +4987,7 @@ export function getMoveTargets(user: Pokemon, move: Moves): MoveTargetSet {
const variableTarget = new Utils.NumberHolder(0);
user.getOpponents().forEach(p => applyMoveAttrs(VariableTargetAttr, user, p, allMoves[move], variableTarget));
const moveTarget = allMoves[move].hasAttr(VariableTargetAttr) ? variableTarget.value : move ? allMoves[move].moveTarget : move === undefined ? MoveTarget.NEAR_ENEMY : [];
const moveTarget = allMoves[move].getAttrs(VariableTargetAttr).length ? variableTarget.value : move ? allMoves[move].moveTarget : move === undefined ? MoveTarget.NEAR_ENEMY : [];
const opponents = user.getOpponents();
let set: Pokemon[] = [];

View File

@ -56,7 +56,7 @@ export class Terrain {
isMoveTerrainCancelled(user: Pokemon, targets: BattlerIndex[], move: Move): boolean {
switch (this.terrainType) {
case TerrainType.PSYCHIC:
if (!move.hasAttr(ProtectAttr)) {
if (!move.getAttrs(ProtectAttr).length) {
const priority = new Utils.IntegerHolder(move.priority);
applyAbAttrs(IncrementMovePriorityAbAttr, user, null, move, priority);
return priority.value > 0 && user.getOpponents().filter(o => targets.includes(o.getBattlerIndex())).length > 0;

View File

@ -989,8 +989,6 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerType.DEPOT_AGENT]: new TrainerConfig(++t).setMoneyMultiplier(1.45).setEncounterBgm(TrainerType.CLERK),
[TrainerType.DOCTOR]: new TrainerConfig(++t).setHasGenders("Nurse", "lass").setHasDouble("Medical Team").setMoneyMultiplier(3).setEncounterBgm(TrainerType.CLERK)
.setSpeciesFilter(s => !!s.getLevelMoves().find(plm => plm[1] === Moves.HEAL_PULSE)),
[TrainerType.FIREBREATHER]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setEncounterBgm(TrainerType.ROUGHNECK)
.setSpeciesFilter(s => !!s.getLevelMoves().find(plm => plm[1] === Moves.SMOG) || s.isOfType(Type.FIRE)),
[TrainerType.FISHERMAN]: new TrainerConfig(++t).setMoneyMultiplier(1.25).setEncounterBgm(TrainerType.BACKPACKER).setSpecialtyTypes(Type.WATER)
.setPartyTemplates(trainerPartyTemplates.TWO_WEAK_SAME_ONE_AVG, trainerPartyTemplates.ONE_AVG, trainerPartyTemplates.THREE_WEAK_SAME, trainerPartyTemplates.ONE_STRONG, trainerPartyTemplates.SIX_WEAKER)
.setSpeciesPools({

View File

@ -36,7 +36,6 @@ const trainerNameConfigs: TrainerNameConfigs = {
[TrainerType.DANCER]: new TrainerNameConfig(TrainerType.DANCER),
[TrainerType.DEPOT_AGENT]: new TrainerNameConfig(TrainerType.DEPOT_AGENT),
[TrainerType.DOCTOR]: new TrainerNameConfig(TrainerType.DOCTOR).hasGenderVariant("Nurse"),
[TrainerType.FIREBREATHER]: new TrainerNameConfig(TrainerType.FIREBREATHER),
[TrainerType.FISHERMAN]: new TrainerNameConfig(TrainerType.FISHERMAN),
[TrainerType.GUITARIST]: new TrainerNameConfig(TrainerType.GUITARIST),
[TrainerType.HARLEQUIN]: new TrainerNameConfig(TrainerType.HARLEQUIN),
@ -88,7 +87,6 @@ export const trainerNamePools = {
[TrainerType.DANCER]: ["Brian","Davey","Dirk","Edmond","Mickey","Raymond","Cara","Julia","Maika","Mireille","Ronda","Zoe"],
[TrainerType.DEPOT_AGENT]: ["Josh","Hank","Vincent"],
[TrainerType.DOCTOR]: [["Hank","Jerry","Jules","Logan","Wayne","Braid","Derek","Heath","Julius","Kit","Graham"],["Kirsten","Sachiko","Shery","Carol","Dixie","Mariah"]],
[TrainerType.FIREBREATHER]: ["Bill","Burt","Cliff","Dick","Lyle","Ned","Otis","Ray","Richard","Walt"],
[TrainerType.FISHERMAN]: ["Andre","Arnold","Barney","Chris","Edgar","Henry","Jonah","Justin","Kyle","Martin","Marvin","Ralph","Raymond","Scott","Stephen","Wilton","Tully","Andrew","Barny","Carter","Claude","Dale","Elliot","Eugene","Ivan","Ned","Nolan","Roger","Ronald","Wade","Wayne","Darian","Kai","Chip","Hank","Kaden","Tommy","Tylor","Alec","Brett","Cameron","Cody","Cole","Cory","Erick","George","Joseph","Juan","Kenneth","Luc","Miguel","Travis","Walter","Zachary","Josh","Gideon","Kyler","Liam","Murphy","Bruce","Damon","Devon","Hubert","Jones","Lydon","Mick","Pete","Sean","Sid","Vince","Bucky","Dean","Eustace","Kenzo","Leroy","Mack","Ryder","Ewan","Finn","Murray","Seward","Shad","Wharton","Finley","Fisher","Fisk","River","Sheaffer","Timin","Carl","Ernest","Hal","Herbert","Hisato","Mike","Vernon","Harriet","Marina","Chase"],
[TrainerType.GUITARIST]: ["Anna","Beverly","January","Tina","Alicia","Claudia","Julia","Lidia","Mireia","Noelia","Sara","Sheila","Tatiana"],
[TrainerType.HARLEQUIN]: ["Charley","Ian","Jack","Kerry","Louis","Pat","Paul","Rick","Anders","Clarence","Gary"],

View File

@ -114,9 +114,9 @@ export class Weather {
const field = scene.getField(true);
for (const pokemon of field) {
let suppressWeatherEffectAbAttr = pokemon.getAbility().getAttrs(SuppressWeatherEffectAbAttr)[0];
let suppressWeatherEffectAbAttr = pokemon.getAbility().getAttrs(SuppressWeatherEffectAbAttr).find(() => true) as SuppressWeatherEffectAbAttr;
if (!suppressWeatherEffectAbAttr) {
suppressWeatherEffectAbAttr = pokemon.hasPassive() ? pokemon.getPassiveAbility().getAttrs(SuppressWeatherEffectAbAttr)[0] : null;
suppressWeatherEffectAbAttr = pokemon.hasPassive() ? pokemon.getPassiveAbility().getAttrs(SuppressWeatherEffectAbAttr).find(() => true) as SuppressWeatherEffectAbAttr : null;
}
if (suppressWeatherEffectAbAttr && (!this.isImmutable() || suppressWeatherEffectAbAttr.affectsImmutable)) {
return true;

View File

@ -14,51 +14,30 @@ import { EggTier } from "./data/enums/egg-type";
import PokemonInfoContainer from "./ui/pokemon-info-container";
import EggsToHatchCountContainer from "./ui/eggs-to-hatch-count-container";
/**
* Class that represents egg hatching
*/
export class EggHatchPhase extends Phase {
/** The egg that is hatching */
private egg: Egg;
/** The number of eggs that are hatching */
private eggsToHatchCount: integer;
/** The container that lists how many eggs are hatching */
private eggsToHatchCountContainer: EggsToHatchCountContainer;
/** The scene handler for egg hatching */
private eggHatchHandler: EggHatchSceneHandler;
/** The phaser gameobject container that holds everything */
private eggHatchContainer: Phaser.GameObjects.Container;
/** The phaser image that is the background */
private eggHatchBg: Phaser.GameObjects.Image;
/** The phaser rectangle that overlays during the scene */
private eggHatchOverlay: Phaser.GameObjects.Rectangle;
/** The phaser container that holds the egg */
private eggContainer: Phaser.GameObjects.Container;
/** The phaser sprite of the egg */
private eggSprite: Phaser.GameObjects.Sprite;
/** The phaser sprite of the cracks in an egg */
private eggCrackSprite: Phaser.GameObjects.Sprite;
/** The phaser sprite that represents the overlaid light rays */
private eggLightraysOverlay: Phaser.GameObjects.Sprite;
/** The phaser sprite of the hatched Pokemon */
private pokemonSprite: Phaser.GameObjects.Sprite;
/** The phaser sprite for shiny sparkles */
private pokemonShinySparkle: Phaser.GameObjects.Sprite;
/** The {@link PokemonInfoContainer} of the newly hatched Pokemon */
private infoContainer: PokemonInfoContainer;
/** The newly hatched {@link PlayerPokemon} */
private pokemon: PlayerPokemon;
/** The index of which egg move is unlocked. 0-2 is common, 3 is rare */
private eggMoveIndex: integer;
/** Internal booleans representing if the egg is hatched, able to be skipped, or skipped */
private hatched: boolean;
private canSkip: boolean;
private skipped: boolean;
/** The sound effect being played when the egg is hatched */
private evolutionBgm: AnySound;
constructor(scene: BattleScene, egg: Egg, eggsToHatchCount: integer) {
@ -138,7 +117,6 @@ export class EggHatchPhase extends Phase {
this.eggHatchContainer.add(this.infoContainer);
// The game will try to unfuse any Pokemon even though eggs should not generate fused Pokemon in the first place
const pokemon = this.generatePokemon();
if (pokemon.fusionSpecies) {
pokemon.clearFusionSpecies();
@ -209,13 +187,6 @@ export class EggHatchPhase extends Phase {
super.end();
}
/**
* Function that animates egg shaking
* @param intensity of horizontal shaking. Doubled on the first call (where count is 0)
* @param repeatCount the number of times this function should be called (asynchronous recursion?!?)
* @param count the current number of times this function has been called.
* @returns nothing since it's a Promise<void>
*/
doEggShake(intensity: number, repeatCount?: integer, count?: integer): Promise<void> {
return new Promise(resolve => {
if (repeatCount === undefined) {
@ -255,10 +226,6 @@ export class EggHatchPhase extends Phase {
});
}
/**
* Tries to skip the hatching animation
* @returns false if cannot be skipped or already skipped. True otherwise
*/
trySkip(): boolean {
if (!this.canSkip || this.skipped) {
return false;
@ -272,9 +239,6 @@ export class EggHatchPhase extends Phase {
return true;
}
/**
* Plays the animation of an egg hatch
*/
doHatch(): void {
this.canSkip = false;
this.hatched = true;
@ -304,9 +268,6 @@ export class EggHatchPhase extends Phase {
});
}
/**
* Function to do the logic and animation of completing a hatch and revealing the Pokemon
*/
doReveal(): void {
// Update/reduce count of hatching eggs when revealed if count is at least 1
// If count is 0, hide eggsToHatchCountContainer instead
@ -372,21 +333,10 @@ export class EggHatchPhase extends Phase {
});
}
/**
* Helper function to generate sine. (Why is this not a Utils?!?)
* @param index random number from 0-7 being passed in to scale pi/128
* @param amplitude Scaling
* @returns a number
*/
sin(index: integer, amplitude: integer): number {
return amplitude * Math.sin(index * (Math.PI / 128));
}
/**
* Animates spraying
* @param intensity number of times this is repeated (this is a badly named variable)
* @param offsetY how much to offset the Y coordinates
*/
doSpray(intensity: integer, offsetY?: number) {
this.scene.tweens.addCounter({
repeat: intensity,
@ -397,11 +347,6 @@ export class EggHatchPhase extends Phase {
});
}
/**
* Animates a particle used in the spray animation
* @param trigIndex Used to modify the particle's vertical speed, is a random number from 0-7
* @param offsetY how much to offset the Y coordinate
*/
doSprayParticle(trigIndex: integer, offsetY: number) {
const initialX = this.eggHatchBg.displayWidth / 2;
const initialY = this.eggHatchBg.displayHeight / 2 + offsetY;
@ -442,22 +387,12 @@ export class EggHatchPhase extends Phase {
updateParticle();
}
/**
* Generates a Pokemon to be hatched by the egg
* @returns the hatched PlayerPokemon
*/
generatePokemon(): PlayerPokemon {
let ret: PlayerPokemon;
let speciesOverride: Species; // SpeciesOverride should probably be a passed in parameter for future species-eggs
let speciesOverride: Species;
this.scene.executeWithSeedOffset(() => {
/**
* Manaphy eggs have a 1/8 chance of being Manaphy and 7/8 chance of being Phione
* Legendary eggs pulled from the legendary gacha have a 50% of being converted into
* the species that was the legendary focus at the time
*/
if (this.egg.isManaphyEgg()) {
const rand = Utils.randSeedInt(8);
@ -502,18 +437,6 @@ export class EggHatchPhase extends Phase {
.map(s => parseInt(s) as Species)
.filter(s => !pokemonPrevolutions.hasOwnProperty(s) && getPokemonSpecies(s).isObtainable() && ignoredSpecies.indexOf(s) === -1);
/**
* Pokemon that are cheaper in their tier get a weight boost. Regionals get a weight penalty
* 1 cost mons get 2x
* 2 cost mons get 1.5x
* 4, 6, 8 cost mons get 1.75x
* 3, 5, 7, 9 cost mons get 1x
* Alolan, Galarian, and Paldean mons get 0.5x
* Hisui mons get 0.125x
*
* The total weight is also being calculated EACH time there is an egg hatch instead of being generated once
* and being the same each time
*/
let totalWeight = 0;
const speciesWeights = [];
for (const speciesId of speciesPool) {
@ -541,16 +464,6 @@ export class EggHatchPhase extends Phase {
ret = this.scene.addPlayerPokemon(pokemonSpecies, 1, undefined, undefined, undefined, false);
}
/**
* Non Shiny gacha Pokemon have a 1/128 chance of being shiny
* Shiny gacha Pokemon have a 1/64 chance of being shiny
* IVs are rolled twice and the higher of each stat's IV is taken
* The egg move gacha doubles the rate of rare egg moves but the base rates are
* Common: 1/48
* Rare: 1/24
* Epic: 1/12
* Legendary: 1/6
*/
ret.trySetShiny(this.egg.gachaType === GachaType.SHINY ? 1024 : 512);
ret.variant = ret.shiny ? ret.generateVariant() : 0;

View File

@ -1,77 +0,0 @@
import { ArenaTagSide } from "#app/data/arena-tag.js";
import { ArenaTagType } from "#app/data/enums/arena-tag-type.js";
import { TerrainType } from "#app/data/terrain.js";
import { WeatherType } from "#app/data/weather.js";
/** Alias for all {@linkcode ArenaEvent} type strings */
export enum ArenaEventType {
/** Triggers when a {@linkcode WeatherType} is added, overlapped, or removed */
WEATHER_CHANGED = "onWeatherChanged",
/** Triggers when a {@linkcode TerrainType} is added, overlapped, or removed */
TERRAIN_CHANGED = "onTerrainChanged",
/** Triggers when a {@linkcode ArenaTagType} is added or removed */
TAG_CHANGED = "onTagChanged",
}
/**
* Base container class for all {@linkcode ArenaEventType} events
* @extends Event
*/
export class ArenaEvent extends Event {
/** The total duration of the {@linkcode ArenaEventType} */
public duration: number;
constructor(eventType: ArenaEventType, duration: number) {
super(eventType);
this.duration = duration;
}
}
/**
* Container class for {@linkcode ArenaEventType.WEATHER_CHANGED} events
* @extends ArenaEvent
*/
export class WeatherChangedEvent extends ArenaEvent {
/** The {@linkcode WeatherType} being overridden */
public oldWeatherType: WeatherType;
/** The {@linkcode WeatherType} being set */
public newWeatherType: WeatherType;
constructor(oldWeatherType: WeatherType, newWeatherType: WeatherType, duration: number) {
super(ArenaEventType.WEATHER_CHANGED, duration);
this.oldWeatherType = oldWeatherType;
this.newWeatherType = newWeatherType;
}
}
/**
* Container class for {@linkcode ArenaEventType.TERRAIN_CHANGED} events
* @extends ArenaEvent
*/
export class TerrainChangedEvent extends ArenaEvent {
/** The {@linkcode TerrainType} being overridden */
public oldTerrainType: TerrainType;
/** The {@linkcode TerrainType} being set */
public newTerrainType: TerrainType;
constructor(oldTerrainType: TerrainType, newTerrainType: TerrainType, duration: number) {
super(ArenaEventType.TERRAIN_CHANGED, duration);
this.oldTerrainType = oldTerrainType;
this.newTerrainType = newTerrainType;
}
}
/**
* Container class for {@linkcode ArenaEventType.TAG_CHANGED} events
* @extends ArenaEvent
*/
export class TagChangedEvent extends ArenaEvent {
/** The {@linkcode ArenaTagType} being set */
public arenaTagType: ArenaTagType;
/** The {@linkcode ArenaTagSide} the tag is being placed on */
public arenaTagSide: ArenaTagSide;
constructor(arenaTagType: ArenaTagType, arenaTagSide: ArenaTagSide, duration: number) {
super(ArenaEventType.TAG_CHANGED, duration);
this.arenaTagType = arenaTagType;
this.arenaTagSide = arenaTagSide;
}
}

View File

@ -19,7 +19,6 @@ import { Terrain, TerrainType } from "../data/terrain";
import { PostTerrainChangeAbAttr, PostWeatherChangeAbAttr, applyPostTerrainChangeAbAttrs, applyPostWeatherChangeAbAttrs } from "../data/ability";
import Pokemon from "./pokemon";
import * as Overrides from "../overrides";
import { WeatherChangedEvent, TerrainChangedEvent, TagChangedEvent } from "./arena-events";
export class Arena {
public scene: BattleScene;
@ -35,8 +34,6 @@ export class Arena {
private pokemonPool: PokemonPools;
private trainerPool: BiomeTierTrainerPools;
public readonly eventTarget: EventTarget = new EventTarget();
constructor(scene: BattleScene, biome: Biome, bgm: string) {
this.scene = scene;
this.biomeType = biome;
@ -303,7 +300,6 @@ export class Arena {
const oldWeatherType = this.weather?.weatherType || WeatherType.NONE;
this.weather = weather ? new Weather(weather, hasPokemonSource ? 5 : 0) : null;
this.eventTarget.dispatchEvent(new WeatherChangedEvent(oldWeatherType, this.weather?.weatherType, this.weather?.turnsLeft));
if (this.weather) {
this.scene.unshiftPhase(new CommonAnimPhase(this.scene, undefined, undefined, CommonAnim.SUNNY + (weather - 1)));
@ -328,7 +324,6 @@ export class Arena {
const oldTerrainType = this.terrain?.terrainType || TerrainType.NONE;
this.terrain = terrain ? new Terrain(terrain, hasPokemonSource ? 5 : 0) : null;
this.eventTarget.dispatchEvent(new TerrainChangedEvent(oldTerrainType,this.terrain?.terrainType, this.terrain?.turnsLeft));
if (this.terrain) {
if (!ignoreAnim) {
@ -550,8 +545,6 @@ export class Arena {
this.tags.push(newTag);
newTag.onAdd(this);
this.eventTarget.dispatchEvent(new TagChangedEvent(newTag.tagType, newTag.side, newTag.turnCount));
return true;
}

View File

@ -978,7 +978,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
if (this.isOnField() && !ability.hasAttr(SuppressFieldAbilitiesAbAttr)) {
const suppressed = new Utils.BooleanHolder(false);
this.scene.getField(true).filter(p => p !== this).map(p => {
this.scene.getField(true).map(p => {
if (p.getAbility().hasAttr(SuppressFieldAbilitiesAbAttr) && p.canApplyAbility()) {
p.getAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, false, suppressed, [ability]));
}
@ -1058,7 +1058,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
getAttackMoveEffectiveness(source: Pokemon, move: PokemonMove): TypeDamageMultiplier {
const typeless = move.getMove().hasAttr(TypelessAttr);
const typeless = !!move.getMove().getAttrs(TypelessAttr).length;
const typeMultiplier = new Utils.NumberHolder(this.getAttackTypeEffectiveness(move.getMove().type, source));
const cancelled = new Utils.BooleanHolder(false);
if (!typeless) {
@ -1424,19 +1424,19 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
if (this.isBoss()) { // Bosses never get self ko moves
movePool = movePool.filter(m => !allMoves[m[0]].hasAttr(SacrificialAttr));
movePool = movePool.filter(m => !allMoves[m[0]].getAttrs(SacrificialAttr).length);
}
movePool = movePool.filter(m => !allMoves[m[0]].hasAttr(SacrificialAttrOnHit));
movePool = movePool.filter(m => !allMoves[m[0]].getAttrs(SacrificialAttrOnHit).length);
if (this.hasTrainer()) {
// Trainers never get OHKO moves
movePool = movePool.filter(m => !allMoves[m[0]].hasAttr(OneHitKOAttr));
movePool = movePool.filter(m => !allMoves[m[0]].getAttrs(OneHitKOAttr).length);
// Half the weight of self KO moves
movePool = movePool.map(m => [m[0], m[1] * (!!allMoves[m[0]].hasAttr(SacrificialAttr) ? 0.5 : 1)]);
movePool = movePool.map(m => [m[0], m[1] * (!!allMoves[m[0]].hasAttr(SacrificialAttrOnHit) ? 0.5 : 1)]);
movePool = movePool.map(m => [m[0], m[1] * (!!allMoves[m[0]].getAttrs(SacrificialAttr).length ? 0.5 : 1)]);
movePool = movePool.map(m => [m[0], m[1] * (!!allMoves[m[0]].getAttrs(SacrificialAttrOnHit).length ? 0.5 : 1)]);
// Trainers get a weight bump to stat buffing moves
movePool = movePool.map(m => [m[0], m[1] * (allMoves[m[0]].getAttrs(StatChangeAttr).some(a => a.levels > 1 && a.selfTarget) ? 1.25 : 1)]);
movePool = movePool.map(m => [m[0], m[1] * (allMoves[m[0]].getAttrs(StatChangeAttr).some(a => (a as StatChangeAttr).levels > 1 && (a as StatChangeAttr).selfTarget) ? 1.25 : 1)]);
// Trainers get a weight decrease to multiturn moves
movePool = movePool.map(m => [m[0], m[1] * (!!allMoves[m[0]].hasAttr(ChargeAttr) || !!allMoves[m[0]].hasAttr(RechargeAttr) ? 0.7 : 1)]);
movePool = movePool.map(m => [m[0], m[1] * (!!allMoves[m[0]].getAttrs(ChargeAttr).length || !!allMoves[m[0]].getAttrs(RechargeAttr).length ? 0.7 : 1)]);
}
// Weight towards higher power moves, by reducing the power of moves below the highest power.
@ -1627,8 +1627,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const types = this.getTypes(true, true);
const cancelled = new Utils.BooleanHolder(false);
const typeless = move.hasAttr(TypelessAttr);
const typeMultiplier = new Utils.NumberHolder(!typeless && (moveCategory !== MoveCategory.STATUS || move.getAttrs(StatusMoveTypeImmunityAttr).find(attr => types.includes(attr.immuneType)))
const typeless = !!move.getAttrs(TypelessAttr).length;
const typeMultiplier = new Utils.NumberHolder(!typeless && (moveCategory !== MoveCategory.STATUS || move.getAttrs(StatusMoveTypeImmunityAttr).find(attr => types.includes((attr as StatusMoveTypeImmunityAttr).immuneType)))
? this.getAttackTypeEffectiveness(type, source)
: 1);
applyMoveAttrs(VariableMoveTypeMultiplierAttr, source, this, move, typeMultiplier);
@ -1654,7 +1654,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const isPhysical = moveCategory === MoveCategory.PHYSICAL;
const power = new Utils.NumberHolder(move.power);
const sourceTeraType = source.getTeraType();
if (sourceTeraType !== Type.UNKNOWN && sourceTeraType === type && power.value < 60 && move.priority <= 0 && !move.hasAttr(MultiHitAttr) && !this.scene.findModifier(m => m instanceof PokemonMultiHitModifier && m.pokemonId === source.id)) {
if (sourceTeraType !== Type.UNKNOWN && sourceTeraType === type && power.value < 60 && move.priority <= 0 && !move.getAttrs(MultiHitAttr).length && !this.scene.findModifier(m => m instanceof PokemonMultiHitModifier && m.pokemonId === source.id)) {
power.value = 60;
}
applyPreAttackAbAttrs(VariableMovePowerAbAttr, source, this, battlerMove, power);
@ -1756,7 +1756,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (!isTypeImmune) {
damage.value = Math.ceil(((((2 * source.level / 5 + 2) * power.value * sourceAtk.value / targetDef.value) / 50) + 2) * stabMultiplier.value * typeMultiplier.value * arenaAttackTypeMultiplier.value * screenMultiplier.value * ((this.scene.randBattleSeedInt(15) + 85) / 100) * criticalMultiplier.value);
if (isPhysical && source.status && source.status.effect === StatusEffect.BURN) {
if (!move.hasAttr(BypassBurnDamageReductionAttr)) {
if (!move.getAttrs(BypassBurnDamageReductionAttr).length) {
const burnDamageReductionCancelled = new Utils.BooleanHolder(false);
applyAbAttrs(BypassBurnDamageReductionAbAttr, source, burnDamageReductionCancelled);
if (!burnDamageReductionCancelled.value) {
@ -1768,12 +1768,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
applyPreAttackAbAttrs(DamageBoostAbAttr, source, this, battlerMove, damage);
/**
* For each {@link HitsTagAttr} the move has, doubles the damage of the move if:
* The target has a {@link BattlerTagType} that this move interacts with
* AND
* The move doubles damage when used against that tag
*/
move.getAttrs(HitsTagAttr).filter(hta => hta.doubleDamage).forEach(hta => {
* For each {@link HitsTagAttr} the move has, doubles the damage of the move if:
* The target has a {@link BattlerTagType} that this move interacts with
* AND
* The move doubles damage when used against that tag
* */
move.getAttrs(HitsTagAttr).map(hta => hta as HitsTagAttr).filter(hta => hta.doubleDamage).forEach(hta => {
if (this.getTag(hta.tagType)) {
damage.value *= 2;
}
@ -3454,7 +3454,7 @@ export class EnemyPokemon extends Pokemon {
if (!sortedBenefitScores.length) {
// Set target to BattlerIndex.ATTACKER when using a counter move
// This is the same as when the player does so
if (move.hasAttr(CounterDamageAttr)) {
if (!!move.findAttr(attr => attr instanceof CounterDamageAttr)) {
return [BattlerIndex.ATTACKER];
}

View File

@ -367,18 +367,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: "Ich werde für das nächste Rennen tunen."
},
},
"firebreather": {
"encounter": {
1: "My flames shall devour you!",
2: "My soul is on fire. I'll show you how hot it burns!",
3: "Step right up and take a look!"
},
"victory": {
1: "I burned down to ashes...",
2: "Yow! That's hot!",
3: "Ow! I scorched the tip of my nose!"
},
},
"brock": {
"encounter": {
1: "Meine Expertise in Bezug auf Gesteins-Pokémon wird dich besiegen! Komm schon!",

View File

@ -48,7 +48,6 @@ export const trainerClasses: SimpleTranslationEntries = {
"depot_agent": "Bahnangestellter",
"doctor": "Arzt",
"doctor_female": "Ärztin",
"firebreather": "Feuerspucker",
"fisherman": "Angler",
"fisherman_female": "Angler", // Seems to be the same in german but exists in other languages like italian
"gentleman": "Gentleman",

View File

@ -359,18 +359,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: "I'll tune up for the next race."
},
},
"firebreather": {
"encounter": {
1: "My flames shall devour you!",
2: "My soul is on fire. I'll show you how hot it burns!",
3: "Step right up and take a look!"
},
"victory": {
1: "I burned down to ashes...",
2: "Yow! That's hot!",
3: "Ow! I scorched the tip of my nose!"
},
},
"brock": {
"encounter": {
1: "My expertise on Rock-type Pokémon will take you down! Come on!",

View File

@ -209,9 +209,6 @@ export const modifierType: ModifierTypeTranslationEntries = {
"LEFTOVERS": { name: "Leftovers", description: "Heals 1/16 of a Pokémon's maximum HP every turn" },
"SHELL_BELL": { name: "Shell Bell", description: "Heals 1/8 of a Pokémon's dealt damage" },
"TOXIC_ORB": { name: "Toxic Orb", description: "Badly poisons its holder at the end of the turn if they do not have a status condition already" },
"FLAME_ORB": { name: "Flame Orb", description: "Burns its holder at the end of the turn if they do not have a status condition already" },
"BATON": { name: "Baton", description: "Allows passing along effects when switching Pokémon, which also bypasses traps" },
"SHINY_CHARM": { name: "Shiny Charm", description: "Dramatically increases the chance of a wild Pokémon being Shiny" },

View File

@ -48,7 +48,6 @@ export const trainerClasses: SimpleTranslationEntries = {
"depot_agent": "Depot Agent",
"doctor": "Doctor",
"doctor_female": "Doctor",
"firebreather": "Firebreather",
"fisherman": "Fisherman",
"fisherman_female": "Fisherman",
"gentleman": "Gentleman",

View File

@ -359,18 +359,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: "I'll tune up for the next race."
},
},
"firebreather": {
"encounter": {
1: "My flames shall devour you!",
2: "My soul is on fire. I'll show you how hot it burns!",
3: "Step right up and take a look!"
},
"victory": {
1: "I burned down to ashes...",
2: "Yow! That's hot!",
3: "Ow! I scorched the tip of my nose!"
},
},
"brock": {
"encounter": {
1: "My expertise on Rock-type Pokémon will take you down! Come on!",

View File

@ -48,7 +48,6 @@ export const trainerClasses: SimpleTranslationEntries = {
"depot_agent": "Ferroviario",
"doctor": "Enfermero",
"doctor_female": "Enfermera",
"firebreather": "Comefuegos",
"fisherman": "Pescador",
"fisherman_female": "Pescadora",
"gentleman": "Aristócrata",

View File

@ -359,18 +359,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: "I'll tune up for the next race."
},
},
"firebreather": {
"encounter": {
1: "My flames shall devour you!",
2: "My soul is on fire. I'll show you how hot it burns!",
3: "Step right up and take a look!"
},
"victory": {
1: "I burned down to ashes...",
2: "Yow! That's hot!",
3: "Ow! I scorched the tip of my nose!"
},
},
"brock": {
"encounter": {
1: "My expertise on Rock-type Pokémon will take you down! Come on!",

View File

@ -48,7 +48,6 @@ export const trainerClasses: SimpleTranslationEntries = {
"depot_agent": "Cheminot",
"doctor": "Docteur",
"doctor_female": "Docteure",
"firebreather": "Firebreather",
"fisherman": "Pêcheur",
"fisherman_female": "Pêcheuse",
"gentleman": "Gentleman",

View File

@ -359,18 +359,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: "I'll tune up for the next race."
},
},
"firebreather": {
"encounter": {
1: "My flames shall devour you!",
2: "My soul is on fire. I'll show you how hot it burns!",
3: "Step right up and take a look!"
},
"victory": {
1: "I burned down to ashes...",
2: "Yow! That's hot!",
3: "Ow! I scorched the tip of my nose!"
},
},
"brock": {
"encounter": {
1: "My expertise on Rock-type Pokémon will take you down! Come on!",

View File

@ -48,7 +48,6 @@ export const trainerClasses: SimpleTranslationEntries = {
"depot_agent": "Depot Agent",
"doctor": "Doctor",
"doctor_female": "Doctor",
"firebreather": "Firebreather",
"fisherman": "Fisherman",
"fisherman_female": "Fisherman",
"gentleman": "Gentleman",

View File

@ -359,18 +359,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: "I'll tune up for the next race."
},
},
"firebreather": {
"encounter": {
1: "My flames shall devour you!",
2: "My soul is on fire. I'll show you how hot it burns!",
3: "Step right up and take a look!"
},
"victory": {
1: "I burned down to ashes...",
2: "Yow! That's hot!",
3: "Ow! I scorched the tip of my nose!"
},
},
"brock": {
"encounter": {
1: "My expertise on Rock-type Pokémon will take you down! Come on!",

View File

@ -48,7 +48,6 @@ export const trainerClasses: SimpleTranslationEntries = {
"depot_agent": "역무원",
"doctor": "의사",
"doctor_female": "간호사", // doctor_f.png 파일이 간호사
"firebreather": "Firebreather",
"fisherman": "낚시꾼",
"fisherman_female": "낚시꾼",
"gentleman": "신사",

View File

@ -359,18 +359,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: "I'll tune up for the next race."
},
},
"firebreather": {
"encounter": {
1: "My flames shall devour you!",
2: "My soul is on fire. I'll show you how hot it burns!",
3: "Step right up and take a look!"
},
"victory": {
1: "I burned down to ashes...",
2: "Yow! That's hot!",
3: "Ow! I scorched the tip of my nose!"
},
},
"brock": {
"encounter": {
1: "My expertise on Rock-type Pokémon will take you down! Come on!",

View File

@ -48,7 +48,6 @@ export const trainerClasses: SimpleTranslationEntries = {
"depot_agent": "Ferroviário",
"doctor": "Doutor",
"doctor_female": "Doutora",
"firebreather": "Firebreather",
"fishermen": "Pescador",
"fishermen_female": "Pescadora",
"gentleman": "Cavalheiro",

View File

@ -359,18 +359,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: "I'll tune up for the next race."
},
},
"firebreather": {
"encounter": {
1: "My flames shall devour you!",
2: "My soul is on fire. I'll show you how hot it burns!",
3: "Step right up and take a look!"
},
"victory": {
1: "I burned down to ashes...",
2: "Yow! That's hot!",
3: "Ow! I scorched the tip of my nose!"
},
},
"brock": {
"encounter": {
1: "My expertise on Rock-type Pokémon will take you down! Come on!",

View File

@ -48,7 +48,6 @@ export const trainerClasses: SimpleTranslationEntries = {
"depot_agent": "铁路员工",
"doctor": "医生",
"doctor_female": "医生",
"firebreather": "Firebreather",
"fisherman": "垂钓者",
"fisherman_female": "垂钓者",
"gentleman": "绅士",

View File

@ -359,18 +359,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: "I'll tune up for the next race."
},
},
"firebreather": {
"encounter": {
1: "My flames shall devour you!",
2: "My soul is on fire. I'll show you how hot it burns!",
3: "Step right up and take a look!"
},
"victory": {
1: "I burned down to ashes...",
2: "Yow! That's hot!",
3: "Ow! I scorched the tip of my nose!"
},
},
"brock": {
"encounter": {
1: "My expertise on Rock-type Pokémon will take you down! Come on!",

View File

@ -48,7 +48,6 @@ export const trainerClasses: SimpleTranslationEntries = {
"depot_agent": "鐵路員工",
"doctor": "醫生",
"doctor_female": "醫生",
"firebreather": "Firebreather",
"fisherman": "垂釣者",
"fisherman_female": "垂釣者",
"gentleman": "紳士",

View File

@ -1,7 +1,6 @@
import * as Modifiers from "./modifier";
import { AttackMove, allMoves } from "../data/move";
import { Moves } from "../data/enums/moves";
import { Abilities } from "../data/enums/abilities";
import { PokeballType, getPokeballCatchMultiplier, getPokeballName } from "../data/pokeball";
import Pokemon, { EnemyPokemon, PlayerPokemon, PokemonMove } from "../field/pokemon";
import { EvolutionItem, pokemonEvolutions } from "../data/pokemon-evolutions";
@ -757,23 +756,14 @@ export class EvolutionItemModifierType extends PokemonModifierType implements Ge
}
}
/**
* Class that represents form changing items
*/
export class FormChangeItemModifierType extends PokemonModifierType implements GeneratedPersistentModifierType {
public formChangeItem: FormChangeItem;
constructor(formChangeItem: FormChangeItem) {
super("", FormChangeItem[formChangeItem].toLowerCase(), (_type, args) => new Modifiers.PokemonFormChangeItemModifier(this, (args[0] as PlayerPokemon).id, formChangeItem, true),
(pokemon: PlayerPokemon) => {
// Make sure the Pokemon has alternate forms
if (pokemonFormChanges.hasOwnProperty(pokemon.species.speciesId)
// Get all form changes for this species with an item trigger, including any compound triggers
&& pokemonFormChanges[pokemon.species.speciesId].filter(fc => fc.trigger.hasTriggerType(SpeciesFormChangeItemTrigger))
// Returns true if any form changes match this item
.map(fc => fc.findTrigger(SpeciesFormChangeItemTrigger) as SpeciesFormChangeItemTrigger)
.flat().flatMap(fc => fc.item).includes(this.formChangeItem)
) {
if (pokemonFormChanges.hasOwnProperty(pokemon.species.speciesId) && !!pokemonFormChanges[pokemon.species.speciesId].find(fc => fc.trigger.hasTriggerType(SpeciesFormChangeItemTrigger)
&& (fc.trigger as SpeciesFormChangeItemTrigger).item === this.formChangeItem)) {
return null;
}
@ -1192,9 +1182,6 @@ export const modifierTypes = {
LEFTOVERS: () => new PokemonHeldItemModifierType("modifierType:ModifierType.LEFTOVERS", "leftovers", (type, args) => new Modifiers.TurnHealModifier(type, (args[0] as Pokemon).id)),
SHELL_BELL: () => new PokemonHeldItemModifierType("modifierType:ModifierType.SHELL_BELL", "shell_bell", (type, args) => new Modifiers.HitHealModifier(type, (args[0] as Pokemon).id)),
TOXIC_ORB: () => new PokemonHeldItemModifierType("modifierType:ModifierType.TOXIC_ORB", "toxic_orb", (type, args) => new Modifiers.TurnStatusEffectModifier(type, (args[0] as Pokemon).id)),
FLAME_ORB: () => new PokemonHeldItemModifierType("modifierType:ModifierType.FLAME_ORB", "flame_orb", (type, args) => new Modifiers.TurnStatusEffectModifier(type, (args[0] as Pokemon).id)),
BATON: () => new PokemonHeldItemModifierType("modifierType:ModifierType.BATON", "stick", (type, args) => new Modifiers.SwitchEffectTransferModifier(type, (args[0] as Pokemon).id)),
SHINY_CHARM: () => new ModifierType("modifierType:ModifierType.SHINY_CHARM", "shiny_charm", (type, _args) => new Modifiers.ShinyRateBoosterModifier(type)),
@ -1260,12 +1247,7 @@ const modifierPool: ModifierPool = {
[ModifierTier.GREAT]: [
new WeightedModifierType(modifierTypes.GREAT_BALL, 6),
new WeightedModifierType(modifierTypes.FULL_HEAL, (party: Pokemon[]) => {
const statusEffectPartyMemberCount = Math.min(party.filter(p => p.hp && !!p.status && !p.getHeldItems().some(i => {
if (i instanceof Modifiers.TurnStatusEffectModifier) {
return (i as Modifiers.TurnStatusEffectModifier).getStatusEffect() === p.status.effect;
}
return false;
})).length, 3);
const statusEffectPartyMemberCount = Math.min(party.filter(p => p.hp && !!p.status).length, 3);
return statusEffectPartyMemberCount * 6;
}, 18),
new WeightedModifierType(modifierTypes.REVIVE, (party: Pokemon[]) => {
@ -1288,12 +1270,7 @@ const modifierPool: ModifierPool = {
return thresholdPartyMemberCount;
}, 3),
new WeightedModifierType(modifierTypes.FULL_RESTORE, (party: Pokemon[]) => {
const statusEffectPartyMemberCount = Math.min(party.filter(p => p.hp && !!p.status && !p.getHeldItems().some(i => {
if (i instanceof Modifiers.TurnStatusEffectModifier) {
return (i as Modifiers.TurnStatusEffectModifier).getStatusEffect() === p.status.effect;
}
return false;
})).length, 3);
const statusEffectPartyMemberCount = Math.min(party.filter(p => p.hp && !!p.status).length, 3);
const thresholdPartyMemberCount = Math.floor((Math.min(party.filter(p => (p.getInverseHp() >= 150 || p.getHpRatio() <= 0.5) && !p.isFainted()).length, 3) + statusEffectPartyMemberCount) / 2);
return thresholdPartyMemberCount;
}, 3),
@ -1335,40 +1312,6 @@ const modifierPool: ModifierPool = {
new WeightedModifierType(modifierTypes.MINT, 4),
new WeightedModifierType(modifierTypes.RARE_EVOLUTION_ITEM, (party: Pokemon[]) => Math.min(Math.ceil(party[0].scene.currentBattle.waveIndex / 15) * 4, 32), 32),
new WeightedModifierType(modifierTypes.AMULET_COIN, 3),
new WeightedModifierType(modifierTypes.TOXIC_ORB, (party: Pokemon[]) => {
let weight = 0;
const filteredParty = party.filter(p => (p.status?.effect === StatusEffect.TOXIC || p.canSetStatus(StatusEffect.TOXIC, true, true))
&& !p.hasAbility(Abilities.FLARE_BOOST)
&& !p.getHeldItems().some(i => i instanceof Modifiers.TurnStatusEffectModifier));
if (filteredParty.some(p => p.hasAbility(Abilities.TOXIC_BOOST) || p.hasAbility(Abilities.POISON_HEAL))) {
weight = 4;
} else if (filteredParty.some(p => p.hasAbility(Abilities.GUTS) || p.hasAbility(Abilities.QUICK_FEET) || p.hasAbility(Abilities.MARVEL_SCALE))) {
weight = 2;
} else {
const moveList = [Moves.FACADE, Moves.TRICK, Moves.FLING, Moves.SWITCHEROO, Moves.PSYCHO_SHIFT];
if (filteredParty.some(p => p.getMoveset().some(m => moveList.includes(m.moveId)))) {
weight = 1;
}
}
return Math.min(Math.ceil(party[0].scene.currentBattle.waveIndex / 15) * weight, 8 * weight);
}, 32),
new WeightedModifierType(modifierTypes.FLAME_ORB, (party: Pokemon[]) => {
let weight = 0;
const filteredParty = party.filter(p => (p.status?.effect === StatusEffect.BURN || p.canSetStatus(StatusEffect.BURN, true, true))
&& !p.hasAbility(Abilities.TOXIC_BOOST) && !p.hasAbility(Abilities.POISON_HEAL)
&& !p.getHeldItems().some(i => i instanceof Modifiers.TurnStatusEffectModifier));
if (filteredParty.some(p => p.hasAbility(Abilities.FLARE_BOOST))) {
weight = 4;
} else if (filteredParty.some(p => p.hasAbility(Abilities.GUTS) || p.hasAbility(Abilities.QUICK_FEET) || p.hasAbility(Abilities.MARVEL_SCALE))) {
weight = 2;
} else {
const moveList = [Moves.FACADE, Moves.TRICK, Moves.FLING, Moves.SWITCHEROO, Moves.PSYCHO_SHIFT];
if (filteredParty.some(p => p.getMoveset().some(m => moveList.includes(m.moveId)))) {
weight = 1;
}
}
return Math.min(Math.ceil(party[0].scene.currentBattle.waveIndex / 15) * weight, 8 * weight);
}, 32),
new WeightedModifierType(modifierTypes.REVIVER_SEED, 4),
new WeightedModifierType(modifierTypes.CANDY_JAR, 5),
new WeightedModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, 10),

View File

@ -851,66 +851,6 @@ export class TurnHealModifier extends PokemonHeldItemModifier {
}
}
/**
* Modifier used for held items, namely Toxic Orb and Flame Orb, that apply a
* set {@linkcode StatusEffect} at the end of a turn.
* @extends PokemonHeldItemModifier
* @see {@linkcode apply}
*/
export class TurnStatusEffectModifier extends PokemonHeldItemModifier {
/** The status effect to be applied by the held item */
private effect: StatusEffect;
constructor (type: ModifierType, pokemonId: integer, stackCount?: integer) {
super(type, pokemonId, stackCount);
switch (type.id) {
case "TOXIC_ORB":
this.effect = StatusEffect.TOXIC;
break;
case "FLAME_ORB":
this.effect = StatusEffect.BURN;
break;
}
}
/**
* Checks if {@linkcode modifier} is an instance of this class,
* intentionally ignoring potentially different {@linkcode effect}s
* to prevent held item stockpiling since the item obtained first
* would be the only item able to {@linkcode apply} successfully.
* @override
* @param modifier {@linkcode Modifier} being type tested
* @return true if {@linkcode modifier} is an instance of
* TurnStatusEffectModifier, false otherwise
*/
matchType(modifier: Modifier): boolean {
return modifier instanceof TurnStatusEffectModifier;
}
clone() {
return new TurnStatusEffectModifier(this.type, this.pokemonId, this.stackCount);
}
/**
* Tries to inflicts the holder with the associated {@linkcode StatusEffect}.
* @param args [0] {@linkcode Pokemon} that holds the held item
* @returns true if the status effect was applied successfully, false if
* otherwise
*/
apply(args: any[]): boolean {
return (args[0] as Pokemon).trySetStatus(this.effect, true, undefined, undefined, this.type.name);
}
getMaxHeldItemCount(pokemon: Pokemon): integer {
return 1;
}
getStatusEffect(): StatusEffect {
return this.effect;
}
}
export class HitHealModifier extends PokemonHeldItemModifier {
constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) {
super(type, pokemonId, stackCount);

View File

@ -14,7 +14,6 @@ import { PokeballType } from "./data/pokeball";
import {TimeOfDay} from "#app/data/enums/time-of-day";
import { Gender } from "./data/gender";
import { StatusEffect } from "./data/status-effect";
import { modifierTypes } from "./modifier/modifier-type";
/**
* Overrides for testing different in game situations
@ -101,7 +100,7 @@ export const OPP_VARIANT_OVERRIDE: Variant = 0;
* - BerryType is for BERRY
*/
interface ModifierOverride {
name: keyof typeof modifierTypes & string,
name: string,
count?: integer
type?: TempBattleStat|Stat|Nature|Type|BerryType
}

View File

@ -6,7 +6,7 @@ import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMov
import { Mode } from "./ui/ui";
import { Command } from "./ui/command-ui-handler";
import { Stat } from "./data/pokemon-stat";
import { BerryModifier, ContactHeldItemTransferChanceModifier, EnemyAttackStatusEffectChanceModifier, EnemyPersistentModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, HealingBoosterModifier, HitHealModifier, LapsingPersistentModifier, MapModifier, Modifier, MultipleParticipantExpBonusModifier, PersistentModifier, PokemonExpBoosterModifier, PokemonHeldItemModifier, PokemonInstantReviveModifier, SwitchEffectTransferModifier, TempBattleStatBoosterModifier, TurnHealModifier, TurnHeldItemTransferModifier, MoneyMultiplierModifier, MoneyInterestModifier, IvScannerModifier, LapsingPokemonHeldItemModifier, PokemonMultiHitModifier, PokemonMoveAccuracyBoosterModifier, overrideModifiers, overrideHeldItems, BypassSpeedChanceModifier, TurnStatusEffectModifier } from "./modifier/modifier";
import { BerryModifier, ContactHeldItemTransferChanceModifier, EnemyAttackStatusEffectChanceModifier, EnemyPersistentModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, HealingBoosterModifier, HitHealModifier, LapsingPersistentModifier, MapModifier, Modifier, MultipleParticipantExpBonusModifier, PersistentModifier, PokemonExpBoosterModifier, PokemonHeldItemModifier, PokemonInstantReviveModifier, SwitchEffectTransferModifier, TempBattleStatBoosterModifier, TurnHealModifier, TurnHeldItemTransferModifier, MoneyMultiplierModifier, MoneyInterestModifier, IvScannerModifier, LapsingPokemonHeldItemModifier, PokemonMultiHitModifier, PokemonMoveAccuracyBoosterModifier, overrideModifiers, overrideHeldItems, BypassSpeedChanceModifier } from "./modifier/modifier";
import PartyUiHandler, { PartyOption, PartyUiMode } from "./ui/party-ui-handler";
import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getPokeballTintColor, PokeballType } from "./data/pokeball";
import { CommonAnim, CommonBattleAnim, MoveAnim, initMoveAnim, loadMoveAnimAssets } from "./data/battle-anims";
@ -1553,7 +1553,7 @@ export class SwitchSummonPhase extends SummonPhase {
const lastUsedMove = moveId ? allMoves[moveId] : undefined;
const currentCommand = pokemon.scene.currentBattle.turnCommands[this.fieldIndex]?.command;
const lastPokemonIsForceSwitchedAndNotFainted = lastUsedMove?.hasAttr(ForceSwitchOutAttr) && !this.lastPokemon.isFainted();
const lastPokemonIsForceSwitchedAndNotFainted = !!lastUsedMove?.findAttr(attr => attr instanceof ForceSwitchOutAttr) && !this.lastPokemon.isFainted();
// Compensate for turn spent summoning
// Or compensate for force switch move if switched out pokemon is not fainted
@ -2289,8 +2289,6 @@ export class TurnEndPhase extends FieldPhase {
applyPostTurnAbAttrs(PostTurnAbAttr, pokemon);
this.scene.applyModifiers(TurnStatusEffectModifier, pokemon.isPlayer(), pokemon);
this.scene.applyModifiers(TurnHeldItemTransferModifier, pokemon.isPlayer(), pokemon);
pokemon.battleSummonData.turnCount++;
@ -2459,9 +2457,9 @@ export class MovePhase extends BattlePhase {
const oldTarget = moveTarget.value;
this.scene.getField(true).filter(p => p !== this.pokemon).forEach(p => applyAbAttrs(RedirectMoveAbAttr, p, null, this.move.moveId, moveTarget));
//Check if this move is immune to being redirected, and restore its target to the intended target if it is.
if ((this.pokemon.hasAbilityWithAttr(BlockRedirectAbAttr) || this.move.getMove().hasAttr(BypassRedirectAttr))) {
if ((this.pokemon.hasAbilityWithAttr(BlockRedirectAbAttr) || this.move.getMove().getAttrs(BypassRedirectAttr).length)) {
//If an ability prevented this move from being redirected, display its ability pop up.
if ((this.pokemon.hasAbilityWithAttr(BlockRedirectAbAttr) && !this.move.getMove().hasAttr(BypassRedirectAttr)) && oldTarget !== moveTarget.value) {
if ((this.pokemon.hasAbilityWithAttr(BlockRedirectAbAttr) && !this.move.getMove().getAttrs(BypassRedirectAttr).length) && oldTarget !== moveTarget.value) {
this.scene.unshiftPhase(new ShowAbilityPhase(this.scene, this.pokemon.getBattlerIndex(), this.pokemon.getPassiveAbility().hasAttr(BlockRedirectAbAttr)));
}
moveTarget.value = oldTarget;
@ -2551,7 +2549,7 @@ export class MovePhase extends BattlePhase {
this.scene.eventTarget.dispatchEvent(new MoveUsedEvent(this.pokemon?.id, this.move.getMove(), ppUsed));
}
if (!allMoves[this.move.moveId].hasAttr(CopyMoveAttr)) {
if (!allMoves[this.move.moveId].getAttrs(CopyMoveAttr).length) {
this.scene.currentBattle.lastMove = this.move.moveId;
}
@ -2635,7 +2633,7 @@ export class MovePhase extends BattlePhase {
}
showMoveText(): void {
if (this.move.getMove().hasAttr(ChargeAttr)) {
if (this.move.getMove().getAttrs(ChargeAttr).length) {
const lastMove = this.pokemon.getLastXMoves() as TurnMove[];
if (!lastMove.length || lastMove[0].move !== this.move.getMove().id || lastMove[0].result !== MoveResult.OTHER) {
this.scene.queueMessage(getPokemonMessage(this.pokemon, ` used\n${this.move.getName()}!`), 500);
@ -2706,7 +2704,7 @@ export class MoveEffectPhase extends PokemonPhase {
const hitCount = new Utils.IntegerHolder(1);
// Assume single target for multi hit
applyMoveAttrs(MultiHitAttr, user, this.getTarget(), this.move.getMove(), hitCount);
if (this.move.getMove() instanceof AttackMove && !this.move.getMove().hasAttr(FixedDamageAttr)) {
if (this.move.getMove() instanceof AttackMove && !this.move.getMove().getAttrs(FixedDamageAttr).length) {
this.scene.applyModifiers(PokemonMultiHitModifier, user.isPlayer(), user, hitCount, new Utils.IntegerHolder(0));
}
user.turnData.hitsLeft = user.turnData.hitCount = hitCount.value;
@ -2717,7 +2715,7 @@ export class MoveEffectPhase extends PokemonPhase {
const targetHitChecks = Object.fromEntries(targets.map(p => [ p.getBattlerIndex(), this.hitCheck(p) ]));
const activeTargets = targets.map(t => t.isActive(true));
if (!activeTargets.length || (!this.move.getMove().hasAttr(VariableTargetAttr) && !this.move.getMove().isMultiTarget() && !targetHitChecks[this.targets[0]])) {
if (!activeTargets.length || (!this.move.getMove().getAttrs(VariableTargetAttr).length && !this.move.getMove().isMultiTarget() && !targetHitChecks[this.targets[0]])) {
user.turnData.hitCount = 1;
user.turnData.hitsLeft = 1;
if (activeTargets.length) {
@ -2761,7 +2759,7 @@ export class MoveEffectPhase extends PokemonPhase {
applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).trigger === MoveEffectTrigger.PRE_APPLY && (!attr.firstHitOnly || firstHit),
user, target, this.move.getMove()).then(() => {
if (hitResult !== HitResult.FAIL) {
const chargeEffect = !!this.move.getMove().getAttrs(ChargeAttr).find(ca => ca.usedChargeEffect(user, this.getTarget(), this.move.getMove()));
const chargeEffect = !!this.move.getMove().getAttrs(ChargeAttr).find(ca => (ca as ChargeAttr).usedChargeEffect(user, this.getTarget(), this.move.getMove()));
// Charge attribute with charge effect takes all effect attributes and applies them to charge stage, so ignore them if this is present
Utils.executeIf(!chargeEffect, () => applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).trigger === MoveEffectTrigger.POST_APPLY
&& (attr as MoveEffectAttr).selfTarget && (!attr.firstHitOnly || firstHit), user, target, this.move.getMove())).then(() => {
@ -2861,7 +2859,7 @@ export class MoveEffectPhase extends PokemonPhase {
}
const hiddenTag = target.getTag(HiddenTag);
if (hiddenTag && !this.move.getMove().getAttrs(HitsTagAttr).some(hta => hta.tagType === hiddenTag.tagType)) {
if (hiddenTag && !this.move.getMove().getAttrs(HitsTagAttr).filter(hta => (hta as HitsTagAttr).tagType === hiddenTag.tagType).length) {
return false;
}
@ -2873,7 +2871,7 @@ export class MoveEffectPhase extends PokemonPhase {
return true;
}
const isOhko = this.move.getMove().hasAttr(OneHitKOAccuracyAttr);
const isOhko = !!this.move.getMove().getAttrs(OneHitKOAccuracyAttr).length;
if (!isOhko) {
user.scene.applyModifiers(PokemonMoveAccuracyBoosterModifier, user.isPlayer(), user, moveAccuracy);
@ -3534,7 +3532,7 @@ export class FaintPhase extends PokemonPhase {
if (defeatSource?.isOnField()) {
applyPostVictoryAbAttrs(PostVictoryAbAttr, defeatSource);
const pvmove = allMoves[pokemon.turnData.attacksReceived[0].move];
const pvattrs = pvmove.getAttrs(PostVictoryStatChangeAttr);
const pvattrs = pvmove.getAttrs(PostVictoryStatChangeAttr) as PostVictoryStatChangeAttr[];
if (pvattrs.length) {
for (const pvattr of pvattrs) {
pvattr.applyPostVictory(defeatSource, defeatSource, pvmove);

View File

@ -30,7 +30,6 @@ import { allMoves } from "../data/move";
import { TrainerVariant } from "../field/trainer";
import { OutdatedPhase, ReloadSessionPhase } from "#app/phases";
import { Variant, variantData } from "#app/data/variant";
import { TerrainChangedEvent, WeatherChangedEvent } from "#app/field/arena-events.js";
const saveKey = "x0i2O7WRiANTqPmZ"; // Temporary; secure encryption is not yet necessary
@ -741,10 +740,6 @@ export class GameData {
});
scene.arena.weather = sessionData.arena.weather;
scene.arena.eventTarget.dispatchEvent(new WeatherChangedEvent(null, scene.arena.weather?.weatherType, scene.arena.weather?.turnsLeft));
scene.arena.terrain = sessionData.arena.terrain;
scene.arena.eventTarget.dispatchEvent(new TerrainChangedEvent(null, scene.arena.terrain?.terrainType, scene.arena.terrain?.turnsLeft));
// TODO
//scene.arena.tags = sessionData.arena.tags;