From 6881246d17c352a4201eb3ec4b9469eee7774efb Mon Sep 17 00:00:00 2001 From: Xavion3 Date: Mon, 15 Apr 2024 15:03:50 +1000 Subject: [PATCH 1/6] Implement check functions for abilities --- src/data/battler-tags.ts | 4 ++-- src/data/move.ts | 10 +++++----- src/data/pokemon-forms.ts | 4 ++-- src/data/weather.ts | 2 +- src/field/pokemon.ts | 24 ++++++++++++++++++++---- src/phases.ts | 2 +- 6 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 20946c784cb..a45522b5e1e 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -799,7 +799,7 @@ export class TruantTag extends AbilityBattlerTag { } lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { - if ((!pokemon.canApplyAbility() || pokemon.getAbility().id !== Abilities.TRUANT) && (!pokemon.canApplyAbility(true) || pokemon.getPassiveAbility().id !== Abilities.TRUANT)) + if (!pokemon.hasAbility(Abilities.TRUANT)) return super.lapse(pokemon, lapseType); const passive = pokemon.getAbility().id !== Abilities.TRUANT; @@ -827,7 +827,7 @@ export class SlowStartTag extends AbilityBattlerTag { } lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { - if ((!pokemon.canApplyAbility() || pokemon.getAbility().id !== this.ability) && (!pokemon.canApplyAbility(true) || pokemon.getPassiveAbility().id !== this.ability)) + if (!pokemon.hasAbility(this.ability)) this.turnCount = 1; return super.lapse(pokemon, lapseType); diff --git a/src/data/move.ts b/src/data/move.ts index 841327b42f3..de749ba3ad8 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -275,7 +275,7 @@ export default class Move { checkFlag(flag: MoveFlags, user: Pokemon, target: Pokemon): boolean { switch (flag) { case MoveFlags.MAKES_CONTACT: - if ((user.canApplyAbility() && user.getAbility().hasAttr(IgnoreContactAbAttr)) || (user.canApplyAbility(true) && user.getPassiveAbility().hasAttr(IgnoreContactAbAttr))) + if (user.hasAbilityWithAttr(IgnoreContactAbAttr)) return false; break; } @@ -4849,9 +4849,9 @@ export function initMoves() { .attr(StatChangeAttr, [ BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 2, true) .ignoresVirtual(), new StatusMove(Moves.MAGNETIC_FLUX, "Magnetic Flux", Type.ELECTRIC, -1, 20, "The user manipulates magnetic fields, which raises the Defense and Sp. Def stats of ally Pokémon with the Plus or Minus Ability.", -1, 0, 6) - .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], 1, false, (user, target, move) => !![ Abilities.PLUS, Abilities.MINUS].find(a => a === user.getAbility().id || (user.canApplyPassive() && a === user.getPassiveAbility().id))) + .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], 1, false, (user, target, move) => !![ Abilities.PLUS, Abilities.MINUS].find(a => target.hasAbility(a, false))) .target(MoveTarget.USER_AND_ALLIES) - .condition((user, target, move) => !![ user, user.getAlly() ].filter(p => p?.isActive()).find(p => !![ Abilities.PLUS, Abilities.MINUS].find(a => a === p.getAbility().id || (user.canApplyPassive() && a === user.getPassiveAbility().id)))), + .condition((user, target, move) => !![ user, user.getAlly() ].filter(p => p?.isActive()).find(p => !![ Abilities.PLUS, Abilities.MINUS].find(a => p.hasAbility(a, false)))), new StatusMove(Moves.HAPPY_HOUR, "Happy Hour (N)", Type.NORMAL, -1, 30, "Using Happy Hour doubles the amount of prize money received after battle.", -1, 0, 6) // No animation .target(MoveTarget.USER_SIDE), new StatusMove(Moves.ELECTRIC_TERRAIN, "Electric Terrain", Type.ELECTRIC, -1, 10, "The user electrifies the ground for five turns, powering up Electric-type moves. Pokémon on the ground no longer fall asleep.", -1, 0, 6) @@ -4979,9 +4979,9 @@ export function initMoves() { new SelfStatusMove(Moves.LASER_FOCUS, "Laser Focus", Type.NORMAL, -1, 30, "The user concentrates intensely. The attack on the next turn always results in a critical hit.", -1, 0, 7) .attr(AddBattlerTagAttr, BattlerTagType.ALWAYS_CRIT, true, false), new StatusMove(Moves.GEAR_UP, "Gear Up", Type.STEEL, -1, 20, "The user engages its gears to raise the Attack and Sp. Atk stats of ally Pokémon with the Plus or Minus Ability.", -1, 0, 7) - .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], 1, false, (user, target, move) => [ Abilities.PLUS, Abilities.MINUS ].includes(target.getAbility().id) || (target.canApplyPassive() && [ Abilities.PLUS, Abilities.MINUS ].includes(target.getPassiveAbility().id))) + .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], 1, false, (user, target, move) => !![ Abilities.PLUS, Abilities.MINUS].find(a => target.hasAbility(a, false))) .target(MoveTarget.USER_AND_ALLIES) - .condition((user, target, move) => !![ user, user.getAlly() ].find(p => p && [ Abilities.PLUS, Abilities.MINUS ].includes(p.getAbility().id) || (target.canApplyPassive() && [ Abilities.PLUS, Abilities.MINUS ].includes(target.getPassiveAbility().id)))), + .condition((user, target, move) => !![ user, user.getAlly() ].filter(p => p?.isActive()).find(p => !![ Abilities.PLUS, Abilities.MINUS].find(a => p.hasAbility(a, false)))), new AttackMove(Moves.THROAT_CHOP, "Throat Chop (P)", Type.DARK, MoveCategory.PHYSICAL, 80, 100, 15, "The user attacks the target's throat, and the resultant suffering prevents the target from using moves that emit sound for two turns.", 100, 0, 7), new AttackMove(Moves.POLLEN_PUFF, "Pollen Puff (P)", Type.BUG, MoveCategory.SPECIAL, 90, 100, 15, "The user attacks the enemy with a pollen puff that explodes. If the target is an ally, it gives the ally a pollen puff that restores its HP instead.", -1, 0, 7) .ballBombMove(), diff --git a/src/data/pokemon-forms.ts b/src/data/pokemon-forms.ts index 2d2d491bf31..bb22f985976 100644 --- a/src/data/pokemon-forms.ts +++ b/src/data/pokemon-forms.ts @@ -535,8 +535,8 @@ export const pokemonFormChanges: PokemonFormChanges = { new SpeciesFormChange(Species.MELOETTA, 'pirouette', 'aria', new SpeciesFormChangeActiveTrigger(false), true) ], [Species.AEGISLASH]: [ - new SpeciesFormChange(Species.AEGISLASH, 'blade', 'shield', new SpeciesFormChangePreMoveTrigger(Moves.KINGS_SHIELD), true, new SpeciesFormChangeCondition(p => p.getAbility().id === Abilities.STANCE_CHANGE)), - new SpeciesFormChange(Species.AEGISLASH, 'shield', 'blade', new SpeciesFormChangePreMoveTrigger(m => allMoves[m].category !== MoveCategory.STATUS), true, new SpeciesFormChangeCondition(p => p.getAbility().id === Abilities.STANCE_CHANGE)), + new SpeciesFormChange(Species.AEGISLASH, 'blade', 'shield', new SpeciesFormChangePreMoveTrigger(Moves.KINGS_SHIELD), true, new SpeciesFormChangeCondition(p => p.hasAbility(Abilities.STANCE_CHANGE))), + new SpeciesFormChange(Species.AEGISLASH, 'shield', 'blade', new SpeciesFormChangePreMoveTrigger(m => allMoves[m].category !== MoveCategory.STATUS), true, new SpeciesFormChangeCondition(p => p.hasAbility(Abilities.STANCE_CHANGE))), new SpeciesFormChange(Species.AEGISLASH, 'blade', 'shield', new SpeciesFormChangeActiveTrigger(false), true) ], [Species.DIANCIE]: [ diff --git a/src/data/weather.ts b/src/data/weather.ts index b3a59f34b98..b2881598450 100644 --- a/src/data/weather.ts +++ b/src/data/weather.ts @@ -108,7 +108,7 @@ export class Weather { for (let pokemon of field) { let suppressWeatherEffectAbAttr = pokemon.getAbility().getAttrs(SuppressWeatherEffectAbAttr).find(() => true) as SuppressWeatherEffectAbAttr; if (!suppressWeatherEffectAbAttr) - suppressWeatherEffectAbAttr = pokemon.canApplyPassive() ? pokemon.getPassiveAbility().getAttrs(SuppressWeatherEffectAbAttr).find(() => true) as SuppressWeatherEffectAbAttr : null; + suppressWeatherEffectAbAttr = pokemon.hasPassive() ? pokemon.getPassiveAbility().getAttrs(SuppressWeatherEffectAbAttr).find(() => true) as SuppressWeatherEffectAbAttr : null; if (suppressWeatherEffectAbAttr && (!this.isImmutable() || suppressWeatherEffectAbAttr.affectsImmutable)) return true; } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 16e695769e7..9181be78edf 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -25,7 +25,7 @@ import { TempBattleStat } from '../data/temp-battle-stat'; import { ArenaTagSide, WeakenMoveScreenTag, WeakenMoveTypeTag } from '../data/arena-tag'; import { ArenaTagType } from "../data/enums/arena-tag-type"; import { Biome } from "../data/enums/biome"; -import { Ability, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs } from '../data/ability'; +import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs } from '../data/ability'; import { Abilities } from "#app/data/enums/abilities"; import PokemonData from '../system/pokemon-data'; import { BattlerIndex } from '../battle'; @@ -561,7 +561,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { let value = Math.floor(((2 * baseStat + this.ivs[s]) * this.level) * 0.01); if (isHp) { value = value + this.level + 10; - if ((this.canApplyAbility() && this.getAbility().hasAttr(NonSuperEffectiveImmunityAbAttr)) || (this.canApplyAbility(true) && this.getPassiveAbility().hasAttr(NonSuperEffectiveImmunityAbAttr))) + if (this.hasAbility(Abilities.WONDER_GUARD, false, true)) value = 1; if (this.hp > value || this.hp === undefined) this.hp = value; @@ -730,12 +730,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return allAbilities[starterPassiveAbilities[starterSpeciesId]]; } - canApplyPassive(): boolean { + hasPassive(): boolean { return this.passive || this.isBoss(); } canApplyAbility(passive: boolean = false): boolean { - if (passive && !this.canApplyPassive()) + if (passive && !this.hasPassive()) return false; const ability = (!passive ? this.getAbility() : this.getPassiveAbility()); if (ability.isIgnorable && this.scene.arena.ignoreAbilities) @@ -743,6 +743,22 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return (this.hp || ability.isBypassFaint) && !ability.conditions.find(condition => !condition(this)); } + hasAbility(ability: Abilities, canApply: boolean = true, ignoreOverride?: boolean): boolean { + if ((!canApply || this.canApplyAbility()) && this.getAbility(ignoreOverride).id === ability) + return true; + if (this.hasPassive() && (!canApply || this.canApplyAbility(true)) && this.getPassiveAbility().id === ability) + return true; + return false; + } + + hasAbilityWithAttr(attrType: { new(...args: any[]): AbAttr }, canApply: boolean = true, ignoreOverride?: boolean): boolean { + if ((!canApply || this.canApplyAbility()) && this.getAbility(ignoreOverride).hasAttr(attrType)) + return true; + if (this.hasPassive() && (!canApply || this.canApplyAbility(true)) && this.getPassiveAbility().hasAttr(attrType)) + return true; + return false; + } + getWeight(): number { const weight = new Utils.NumberHolder(this.species.weight); // This will trigger the ability overlay so only call this function when necessary diff --git a/src/phases.ts b/src/phases.ts index ff2f62c3eb9..58490e24cc8 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -2190,7 +2190,7 @@ export class MovePhase extends BattlePhase { for (let opponent of targetedOpponents) { if (this.move.ppUsed === this.move.getMove().pp) break; - if ((opponent.canApplyAbility() && opponent.getAbility().hasAttr(IncreasePpAbAttr)) || (opponent.canApplyAbility(true) && opponent.getPassiveAbility().hasAttr(IncreasePpAbAttr))) + if (opponent.hasAbilityWithAttr(IncreasePpAbAttr)) this.move.ppUsed = Math.min(this.move.ppUsed + 1, this.move.getMovePp()); } } From 6e59b4dd77e6e1451d80de8c002083032f0307e3 Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Mon, 15 Apr 2024 10:09:51 -0400 Subject: [PATCH 2/6] Prevent saving on an outdated client --- package.json | 2 +- src/phases.ts | 10 ++++++ src/system/game-data.ts | 5 +++ src/ui/outdated-modal-ui-handler.ts | 47 +++++++++++++++++++++++++++++ src/ui/ui.ts | 10 ++++-- 5 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 src/ui/outdated-modal-ui-handler.ts diff --git a/package.json b/package.json index fd189fd4d89..0765a180c7e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pokemon-rogue-battle", "private": true, - "version": "1.0.0", + "version": "1.0.1", "type": "module", "scripts": { "start": "vite", diff --git a/src/phases.ts b/src/phases.ts index 58490e24cc8..f668278d273 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -379,6 +379,16 @@ export class UnavailablePhase extends Phase { } } +export class OutdatedPhase extends Phase { + constructor(scene: BattleScene) { + super(scene); + } + + start(): void { + this.scene.ui.setMode(Mode.OUTDATED); + } +} + export class SelectGenderPhase extends Phase { constructor(scene: BattleScene) { super(scene); diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 78ed699e954..e267608e8f8 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -27,6 +27,7 @@ import { Moves } from "../data/enums/moves"; import { speciesEggMoves } from "../data/egg-moves"; import { allMoves } from "../data/move"; import { TrainerVariant } from "../field/trainer"; +import { OutdatedPhase, UnavailablePhase } from "#app/phases"; const saveKey = 'x0i2O7WRiANTqPmZ'; // Temporary; secure encryption is not yet necessary @@ -269,6 +270,10 @@ export class GameData { .then(error => { this.scene.ui.savingIcon.hide(); if (error) { + if (error.startsWith('client version out of date')) { + this.scene.clearPhaseQueue(); + this.scene.unshiftPhase(new OutdatedPhase(this.scene)); + } console.error(error); return resolve(false); } diff --git a/src/ui/outdated-modal-ui-handler.ts b/src/ui/outdated-modal-ui-handler.ts new file mode 100644 index 00000000000..53243c42bbe --- /dev/null +++ b/src/ui/outdated-modal-ui-handler.ts @@ -0,0 +1,47 @@ +import BattleScene from "../battle-scene"; +import { ModalConfig, ModalUiHandler } from "./modal-ui-handler"; +import { addTextObject, TextStyle } from "./text"; +import { Mode } from "./ui"; + +export default class OutdatedModalUiHandler extends ModalUiHandler { + constructor(scene: BattleScene, mode?: Mode) { + super(scene, mode); + } + + getModalTitle(): string { + return ''; + } + + getWidth(): number { + return 160; + } + + getHeight(): number { + return 64; + } + + getMargin(): [number, number, number, number] { + return [ 0, 0, 48, 0 ]; + } + + getButtonLabels(): string[] { + return [ ]; + } + + setup(): void { + super.setup(); + + const label = addTextObject(this.scene, this.getWidth() / 2, this.getHeight() / 2, 'Your client is currently outdated.\nPlease reload to update the game.\n\nIf this error persists, please clear your browser cache.', TextStyle.WINDOW, { fontSize: '48px', align: 'center' }); + label.setOrigin(0.5, 0.5); + + this.modalContainer.add(label); + } + + show(args: any[]): boolean { + const config: ModalConfig = { + buttonActions: [] + }; + + return super.show([ config ]); + } +} \ No newline at end of file diff --git a/src/ui/ui.ts b/src/ui/ui.ts index 422a0ab3e10..82eead45eb4 100644 --- a/src/ui/ui.ts +++ b/src/ui/ui.ts @@ -34,6 +34,7 @@ import SaveSlotSelectUiHandler from './save-slot-select-ui-handler'; import TitleUiHandler from './title-ui-handler'; import SavingIconHandler from './saving-icon-handler'; import UnavailableModalUiHandler from './unavailable-modal-ui-handler'; +import OutdatedModalUiHandler from './outdated-modal-ui-handler'; export enum Mode { MESSAGE, @@ -63,7 +64,8 @@ export enum Mode { LOGIN_FORM, REGISTRATION_FORM, LOADING, - UNAVAILABLE + UNAVAILABLE, + OUTDATED }; const transitionModes = [ @@ -90,7 +92,8 @@ const noTransitionModes = [ Mode.LOGIN_FORM, Mode.REGISTRATION_FORM, Mode.LOADING, - Mode.UNAVAILABLE + Mode.UNAVAILABLE, + Mode.OUTDATED ]; export default class UI extends Phaser.GameObjects.Container { @@ -141,7 +144,8 @@ export default class UI extends Phaser.GameObjects.Container { new LoginFormUiHandler(scene), new RegistrationFormUiHandler(scene), new LoadingModalUiHandler(scene), - new UnavailableModalUiHandler(scene) + new UnavailableModalUiHandler(scene), + new OutdatedModalUiHandler(scene) ]; } From 398f2c5be067a903429401b40d191302b226155f Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Mon, 15 Apr 2024 10:35:57 -0400 Subject: [PATCH 3/6] Fix being able to overwrite data without a confirmation --- src/ui/save-slot-select-ui-handler.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ui/save-slot-select-ui-handler.ts b/src/ui/save-slot-select-ui-handler.ts index 054bb1ab9f9..21865045141 100644 --- a/src/ui/save-slot-select-ui-handler.ts +++ b/src/ui/save-slot-select-ui-handler.ts @@ -114,8 +114,10 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { ui.showText(null, 0); }, false, 0, 19, 2000); }); - } else + } else if (this.sessionSlots[this.cursor].hasData === false) saveAndCallback(); + else + return false; break; } success = true; @@ -210,7 +212,6 @@ class SessionSlot extends Phaser.GameObjects.Container { super(scene, 0, slotId * 56); this.slotId = slotId; - this.hasData = false; this.setup(); } @@ -282,6 +283,7 @@ class SessionSlot extends Phaser.GameObjects.Container { return new Promise(resolve => { this.scene.gameData.getSession(this.slotId).then(async sessionData => { if (!sessionData) { + this.hasData = false; this.loadingLabel.setText('Empty'); resolve(false); return; From 9d92ec2a72661e7e6b22826185b6b68637c70527 Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Mon, 15 Apr 2024 10:45:40 -0400 Subject: [PATCH 4/6] Fix nature power using wrong syntax for switch case --- src/data/move.ts | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index de749ba3ad8..db0c062e2e8 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -2830,44 +2830,44 @@ export class NaturePowerAttr extends OverrideMoveEffectAttr { case Biome.TOWN: moveId = Moves.TRI_ATTACK; break; - case Biome.PLAINS - || Biome.GRASS - || Biome.TALL_GRASS - || Biome.MEADOW - || Biome.FOREST - || Biome.JUNGLE: + case Biome.PLAINS: + case Biome.GRASS: + case Biome.TALL_GRASS: + case Biome.MEADOW: + case Biome.FOREST: + case Biome.JUNGLE: moveId = Moves.ENERGY_BALL; break; - case Biome.SEA - || Biome.SWAMP - || Biome.BEACH - || Biome.LAKE - || Biome.SEABED - || Biome.ISLAND: + case Biome.SEA: + case Biome.SWAMP: + case Biome.BEACH: + case Biome.LAKE: + case Biome.SEABED: + case Biome.ISLAND: moveId = Moves.HYDRO_PUMP; break; case Biome.MOUNTAIN: moveId = Moves.AIR_SLASH; break; - case Biome.BADLANDS - || Biome.DESERT - || Biome.WASTELAND - || Biome.CONSTRUCTION_SITE: + case Biome.BADLANDS: + case Biome.DESERT: + case Biome.WASTELAND: + case Biome.CONSTRUCTION_SITE: moveId = Moves.EARTH_POWER; break; case Biome.CAVE: moveId = Moves.POWER_GEM; break; - case Biome.ICE_CAVE - || Biome.SNOWY_FOREST: + case Biome.ICE_CAVE: + case Biome.SNOWY_FOREST: moveId = Moves.ICE_BEAM; break; case Biome.VOLCANO: moveId = Moves.FLAMETHROWER; break; - case Biome.GRAVEYARD - || Biome.RUINS - || Biome.TEMPLE: + case Biome.GRAVEYARD: + case Biome.RUINS: + case Biome.TEMPLE: moveId = Moves.SHADOW_BALL; break; case Biome.DOJO: @@ -2876,11 +2876,13 @@ export class NaturePowerAttr extends OverrideMoveEffectAttr { case Biome.FAIRY_CAVE: moveId = Moves.MOONBLAST; break; - case Biome.ABYSS - || Biome.SPACE - || Biome.END: + case Biome.ABYSS: + case Biome.SPACE: moveId = Moves.DARK_PULSE; break; + case Biome.END: + moveId = Moves.ETERNABEAM; + break; } break; case TerrainType.MISTY: From 76edb00e312d571b9e85b5e425e949dbec4d6812 Mon Sep 17 00:00:00 2001 From: AJ Fontaine <36677462+Fontbane@users.noreply.github.com> Date: Mon, 15 Apr 2024 12:14:31 -0400 Subject: [PATCH 5/6] Thermal Exchange --- src/data/ability.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index 7cb03d7e7e3..e48003871f1 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -2813,7 +2813,8 @@ export function initAbilities() { .bypassFaint(), new Ability(Abilities.SEED_SOWER, "Seed Sower", "Turns the ground into Grassy Terrain when the Pokémon is hit by an attack.", 9) .attr(PostDefendTerrainChangeAbAttr, TerrainType.GRASSY), - new Ability(Abilities.THERMAL_EXCHANGE, "Thermal Exchange (P)", "Boosts the Attack stat when the Pokémon is hit by a Fire-type move. The Pokémon also cannot be burned.", 9) + new Ability(Abilities.THERMAL_EXCHANGE, "Thermal Exchange", "Boosts the Attack stat when the Pokémon is hit by a Fire-type move. The Pokémon also cannot be burned.", 9) + .attr(PostDefendStatChangeAbAttr, (target, user, move) => move.type === Type.FIRE, BattleStat.ATK, 1) .attr(StatusEffectImmunityAbAttr, StatusEffect.BURN) .ignorable(), new Ability(Abilities.ANGER_SHELL, "Anger Shell (N)", "When an attack causes its HP to drop to half or less, the Pokémon gets angry. This lowers its Defense and Sp. Def stats but boosts its Attack, Sp. Atk, and Speed stats.", 9), From 39eed2a2754c139d081499bb43ba97993da2ae91 Mon Sep 17 00:00:00 2001 From: serif <42188588+Natsumi-chanFE@users.noreply.github.com> Date: Mon, 15 Apr 2024 12:20:15 -0400 Subject: [PATCH 6/6] Update move.ts adds the rest of the biomes --- src/data/move.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/data/move.ts b/src/data/move.ts index db0c062e2e8..73a5ca42302 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -2828,6 +2828,8 @@ export class NaturePowerAttr extends OverrideMoveEffectAttr { case TerrainType.NONE: switch (user.scene.arena.biomeType) { case Biome.TOWN: + case Biome.METROPOLIS: + case Biome.SLUM: moveId = Moves.TRI_ATTACK; break; case Biome.PLAINS: @@ -2880,6 +2882,13 @@ export class NaturePowerAttr extends OverrideMoveEffectAttr { case Biome.SPACE: moveId = Moves.DARK_PULSE; break; + case Biome.FACTORY: + case Biome.LABORATORY: + moveId = Moves.FLASH_CANNON; + break; + case Biome.POWER_PLANT: + moveId = Moves.THUNDERBOLT; + break; case Biome.END: moveId = Moves.ETERNABEAM; break;