From 433d4b4fc93a27579a36ab2cf6e8a20d20385d3e Mon Sep 17 00:00:00 2001 From: Moka <54149968+MokaStitcher@users.noreply.github.com> Date: Tue, 5 Nov 2024 02:24:17 +0100 Subject: [PATCH 01/75] [P3][UI][QoL] Fix tooltips going out of screen on mobile & other improvements (#4792) * [ui] Fix tooltip placement when using touchscreen * [ui] make candy friendship tooltip hitbox bigger --- src/ui/starter-select-ui-handler.ts | 79 ++++++++++++++--------------- src/ui/summary-ui-handler.ts | 4 +- src/ui/ui.ts | 35 ++++++++++--- 3 files changed, 68 insertions(+), 50 deletions(-) diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 3a29f9431e7..bb4dc74d44e 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -242,6 +242,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { private pokemonEggMoveContainers: Phaser.GameObjects.Container[]; private pokemonEggMoveBgs: Phaser.GameObjects.NineSlice[]; private pokemonEggMoveLabels: Phaser.GameObjects.Text[]; + private pokemonCandyContainer: Phaser.GameObjects.Container; private pokemonCandyIcon: Phaser.GameObjects.Sprite; private pokemonCandyDarknessOverlay: Phaser.GameObjects.Sprite; private pokemonCandyOverlayIcon: Phaser.GameObjects.Sprite; @@ -686,31 +687,36 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonLuckText.setOrigin(0, 0); this.starterSelectContainer.add(this.pokemonLuckText); - this.pokemonCandyIcon = this.scene.add.sprite(4.5, 18, "candy"); + // Candy icon and count + this.pokemonCandyContainer = this.scene.add.container(4.5, 18); + + this.pokemonCandyIcon = this.scene.add.sprite(0, 0, "candy"); this.pokemonCandyIcon.setScale(0.5); this.pokemonCandyIcon.setOrigin(0, 0); - this.starterSelectContainer.add(this.pokemonCandyIcon); + this.pokemonCandyContainer.add(this.pokemonCandyIcon); - this.pokemonFormText = addTextObject(this.scene, 6, 42, "Form", TextStyle.WINDOW_ALT, { fontSize: "42px" }); - this.pokemonFormText.setOrigin(0, 0); - this.starterSelectContainer.add(this.pokemonFormText); - - this.pokemonCandyOverlayIcon = this.scene.add.sprite(4.5, 18, "candy_overlay"); + this.pokemonCandyOverlayIcon = this.scene.add.sprite(0, 0, "candy_overlay"); this.pokemonCandyOverlayIcon.setScale(0.5); this.pokemonCandyOverlayIcon.setOrigin(0, 0); - this.starterSelectContainer.add(this.pokemonCandyOverlayIcon); + this.pokemonCandyContainer.add(this.pokemonCandyOverlayIcon); - this.pokemonCandyDarknessOverlay = this.scene.add.sprite(4.5, 18, "candy"); + this.pokemonCandyDarknessOverlay = this.scene.add.sprite(0, 0, "candy"); this.pokemonCandyDarknessOverlay.setScale(0.5); this.pokemonCandyDarknessOverlay.setOrigin(0, 0); this.pokemonCandyDarknessOverlay.setTint(0x000000); this.pokemonCandyDarknessOverlay.setAlpha(0.50); - this.pokemonCandyDarknessOverlay.setInteractive(new Phaser.Geom.Rectangle(0, 0, 16, 16), Phaser.Geom.Rectangle.Contains); - this.starterSelectContainer.add(this.pokemonCandyDarknessOverlay); + this.pokemonCandyContainer.add(this.pokemonCandyDarknessOverlay); - this.pokemonCandyCountText = addTextObject(this.scene, 14, 18, "x0", TextStyle.WINDOW_ALT, { fontSize: "56px" }); + this.pokemonCandyCountText = addTextObject(this.scene, 9.5, 0, "x0", TextStyle.WINDOW_ALT, { fontSize: "56px" }); this.pokemonCandyCountText.setOrigin(0, 0); - this.starterSelectContainer.add(this.pokemonCandyCountText); + this.pokemonCandyContainer.add(this.pokemonCandyCountText); + + this.pokemonCandyContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, 30, 20), Phaser.Geom.Rectangle.Contains); + this.starterSelectContainer.add(this.pokemonCandyContainer); + + this.pokemonFormText = addTextObject(this.scene, 6, 42, "Form", TextStyle.WINDOW_ALT, { fontSize: "42px" }); + this.pokemonFormText.setOrigin(0, 0); + this.starterSelectContainer.add(this.pokemonFormText); this.pokemonCaughtHatchedContainer = this.scene.add.container(2, 25); this.pokemonCaughtHatchedContainer.setScale(0.5); @@ -2822,10 +2828,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonShinyIcon.setY(135); this.pokemonShinyIcon.setFrame(getVariantIcon(variant)); [ - this.pokemonCandyIcon, - this.pokemonCandyOverlayIcon, - this.pokemonCandyDarknessOverlay, - this.pokemonCandyCountText, + this.pokemonCandyContainer, this.pokemonHatchedIcon, this.pokemonHatchedCountText ].map(c => c.setVisible(false)); @@ -2834,31 +2837,26 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonCaughtHatchedContainer.setY(25); this.pokemonShinyIcon.setY(117); this.pokemonCandyIcon.setTint(argbFromRgba(rgbHexToRgba(colorScheme[0]))); - this.pokemonCandyIcon.setVisible(true); this.pokemonCandyOverlayIcon.setTint(argbFromRgba(rgbHexToRgba(colorScheme[1]))); - this.pokemonCandyOverlayIcon.setVisible(true); - this.pokemonCandyDarknessOverlay.setVisible(true); this.pokemonCandyCountText.setText(`x${this.scene.gameData.starterData[species.speciesId].candyCount}`); - this.pokemonCandyCountText.setVisible(true); + this.pokemonCandyContainer.setVisible(true); this.pokemonFormText.setY(42); this.pokemonHatchedIcon.setVisible(true); this.pokemonHatchedCountText.setVisible(true); const { currentFriendship, friendshipCap } = this.getFriendship(this.lastSpecies.speciesId); const candyCropY = 16 - (16 * (currentFriendship / friendshipCap)); - - if (this.pokemonCandyDarknessOverlay.visible) { - this.pokemonCandyDarknessOverlay.on("pointerover", () => { - this.scene.ui.showTooltip("", `${currentFriendship}/${friendshipCap}`, true); - this.activeTooltip = "CANDY"; - }); - this.pokemonCandyDarknessOverlay.on("pointerout", () => { - this.scene.ui.hideTooltip(); - this.activeTooltip = undefined; - }); - } - this.pokemonCandyDarknessOverlay.setCrop(0, 0, 16, candyCropY); + + this.pokemonCandyContainer.on("pointerover", () => { + this.scene.ui.showTooltip("", `${currentFriendship}/${friendshipCap}`, true); + this.activeTooltip = "CANDY"; + }); + this.pokemonCandyContainer.on("pointerout", () => { + this.scene.ui.hideTooltip(); + this.activeTooltip = undefined; + }); + } @@ -2934,10 +2932,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonPassiveLabelText.setVisible(false); this.pokemonNatureLabelText.setVisible(false); this.pokemonCaughtHatchedContainer.setVisible(false); - this.pokemonCandyIcon.setVisible(false); - this.pokemonCandyOverlayIcon.setVisible(false); - this.pokemonCandyDarknessOverlay.setVisible(false); - this.pokemonCandyCountText.setVisible(false); + this.pokemonCandyContainer.setVisible(false); this.pokemonFormText.setVisible(false); const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species, true, true); @@ -2971,10 +2966,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonPassiveLabelText.setVisible(false); this.pokemonNatureLabelText.setVisible(false); this.pokemonCaughtHatchedContainer.setVisible(false); - this.pokemonCandyIcon.setVisible(false); - this.pokemonCandyOverlayIcon.setVisible(false); - this.pokemonCandyDarknessOverlay.setVisible(false); - this.pokemonCandyCountText.setVisible(false); + this.pokemonCandyContainer.setVisible(false); this.pokemonFormText.setVisible(false); this.setSpeciesDetails(species!, { // TODO: is this bang correct? @@ -3005,7 +2997,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { || !isNullOrUndefined(formIndex) || !isNullOrUndefined(shiny) || !isNullOrUndefined(variant); if (this.activeTooltip === "CANDY") { - if (this.lastSpecies) { + if (this.lastSpecies && this.pokemonCandyContainer.visible) { const { currentFriendship, friendshipCap } = this.getFriendship(this.lastSpecies.speciesId); this.scene.ui.editTooltip("", `${currentFriendship}/${friendshipCap}`); } else { @@ -3230,6 +3222,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonPassiveLockedIcon.setVisible(!isUnlocked); this.pokemonPassiveLockedIcon.setPosition(iconPosition.x, iconPosition.y); + } else if (this.activeTooltip === "PASSIVE") { + // No passive and passive tooltip is active > hide it + this.scene.ui.hideTooltip(); } this.pokemonNatureText.setText(getNatureName(natureIndex as unknown as Nature, true, true, false, this.scene.uiTheme)); diff --git a/src/ui/summary-ui-handler.ts b/src/ui/summary-ui-handler.ts index 9a61dd0f688..4b36867571e 100644 --- a/src/ui/summary-ui-handler.ts +++ b/src/ui/summary-ui-handler.ts @@ -184,7 +184,7 @@ export default class SummaryUiHandler extends UiHandler { this.candyShadow.setTint(0x000000); this.candyShadow.setAlpha(0.50); this.candyShadow.setScale(0.8); - this.candyShadow.setInteractive(new Phaser.Geom.Rectangle(0, 0, 16, 16), Phaser.Geom.Rectangle.Contains); + this.candyShadow.setInteractive(new Phaser.Geom.Rectangle(0, 0, 30, 16), Phaser.Geom.Rectangle.Contains); this.summaryContainer.add(this.candyShadow); this.candyCountText = addTextObject(this.scene, 20, -146, "x0", TextStyle.WINDOW_ALT, { fontSize: "76px" }); @@ -203,7 +203,7 @@ export default class SummaryUiHandler extends UiHandler { this.friendshipShadow.setTint(0x000000); this.friendshipShadow.setAlpha(0.50); this.friendshipShadow.setScale(0.8); - this.friendshipShadow.setInteractive(new Phaser.Geom.Rectangle(0, 0, 16, 16), Phaser.Geom.Rectangle.Contains); + this.friendshipShadow.setInteractive(new Phaser.Geom.Rectangle(0, 0, 50, 16), Phaser.Geom.Rectangle.Contains); this.summaryContainer.add(this.friendshipShadow); this.friendshipText = addTextObject(this.scene, 20, -66, "x0", TextStyle.WINDOW_ALT, { fontSize: "76px" }); diff --git a/src/ui/ui.ts b/src/ui/ui.ts index 63cd48ab1cd..fc8fa94c848 100644 --- a/src/ui/ui.ts +++ b/src/ui/ui.ts @@ -391,6 +391,7 @@ export default class UI extends Phaser.GameObjects.Container { this.tooltipContent.y = title ? 16 : 4; this.tooltipBg.width = Math.min(Math.max(this.tooltipTitle.displayWidth, this.tooltipContent.displayWidth) + 12, 838); this.tooltipBg.height = (title ? 31 : 19) + 10.5 * (wrappedContent.split("\n").length - 1); + this.tooltipTitle.x = this.tooltipBg.width / 2; } hideTooltip(): void { @@ -400,12 +401,34 @@ export default class UI extends Phaser.GameObjects.Container { update(): void { if (this.tooltipContainer.visible) { - const xReverse = this.scene.game.input.mousePointer && this.scene.game.input.mousePointer.x >= this.scene.game.canvas.width - this.tooltipBg.width * 6 - 12; - const yReverse = this.scene.game.input.mousePointer && this.scene.game.input.mousePointer.y >= this.scene.game.canvas.height - this.tooltipBg.height * 6 - 12; - this.tooltipContainer.setPosition( - !xReverse ? this.scene.game.input.mousePointer!.x / 6 + 2 : this.scene.game.input.mousePointer!.x / 6 - this.tooltipBg.width - 2, - !yReverse ? this.scene.game.input.mousePointer!.y / 6 + 2 : this.scene.game.input.mousePointer!.y / 6 - this.tooltipBg.height - 2, - ); + const isTouch = (this.scene as BattleScene).inputMethod === "touch"; + const pointerX = this.scene.game.input.activePointer.x; + const pointerY = this.scene.game.input.activePointer.y; + const tooltipWidth = this.tooltipBg.width; + const tooltipHeight = this.tooltipBg.height; + const padding = 2; + + // Default placement is top left corner of the screen on mobile. Otherwise below the cursor, to the right + let x = isTouch ? padding : pointerX / 6 + padding; + let y = isTouch ? padding : pointerY / 6 + padding; + + if (isTouch) { + // If we are in the top left quadrant on mobile, move the tooltip to the top right corner + if (pointerX <= this.scene.game.canvas.width / 2 && pointerY <= this.scene.game.canvas.height / 2) { + x = this.scene.game.canvas.width / 6 - tooltipWidth - padding; + } + } else { + // If the tooltip would go offscreen on the right, or is close to it, move to the left of the cursor + if (x + tooltipWidth + padding > this.scene.game.canvas.width / 6) { + x = Math.max(padding, pointerX / 6 - tooltipWidth - padding); + } + // If the tooltip would go offscreen at the bottom, or is close to it, move above the cursor + if (y + tooltipHeight + padding > this.scene.game.canvas.height / 6) { + y = Math.max(padding, pointerY / 6 - tooltipHeight - padding); + } + } + + this.tooltipContainer.setPosition(x, y); } } From ab6d15ee8a31bfdeacf92ab9fc2624b31c7eb527 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Mon, 4 Nov 2024 18:31:40 -0800 Subject: [PATCH 02/75] [Move] Improve Future Sight & Doom Desire (still partial) (#4545) * Fix behavior of Future Sight and Doom Desire Add test for Future Sight Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Prevent crash if Future Sight target is missing Co-authored-by: PigeonBar <56974298+PigeonBar@users.noreply.github.com> * Add `partial()` comments, update `DelayedAttackAttr` return --------- Co-authored-by: Gianluca Fuoco Co-authored-by: PigeonBar <56974298+PigeonBar@users.noreply.github.com> Co-authored-by: Tempoanon <163687446+Tempo-anon@users.noreply.github.com> --- src/data/arena-tag.ts | 9 ++--- src/data/move.ts | 24 ++++++++++--- src/phases/move-effect-phase.ts | 18 ++++++---- src/phases/move-phase.ts | 55 +++++++++++++++++++++++++++-- src/test/moves/future_sight.test.ts | 45 +++++++++++++++++++++++ 5 files changed, 134 insertions(+), 17 deletions(-) create mode 100644 src/test/moves/future_sight.test.ts diff --git a/src/data/arena-tag.ts b/src/data/arena-tag.ts index 3dd526676a0..73f8e16d573 100644 --- a/src/data/arena-tag.ts +++ b/src/data/arena-tag.ts @@ -780,13 +780,14 @@ class ToxicSpikesTag extends ArenaTrapTag { * Delays the attack's effect by a set amount of turns, usually 3 (including the turn the move is used), * and deals damage after the turn count is reached. */ -class DelayedAttackTag extends ArenaTag { +export class DelayedAttackTag extends ArenaTag { public targetIndex: BattlerIndex; - constructor(tagType: ArenaTagType, sourceMove: Moves | undefined, sourceId: number, targetIndex: BattlerIndex) { - super(tagType, 3, sourceMove, sourceId); + constructor(tagType: ArenaTagType, sourceMove: Moves | undefined, sourceId: number, targetIndex: BattlerIndex, side: ArenaTagSide = ArenaTagSide.BOTH) { + super(tagType, 3, sourceMove, sourceId, side); this.targetIndex = targetIndex; + this.side = side; } lapse(arena: Arena): boolean { @@ -1250,7 +1251,7 @@ export function getArenaTag(tagType: ArenaTagType, turnCount: number, sourceMove return new ToxicSpikesTag(sourceId, side); case ArenaTagType.FUTURE_SIGHT: case ArenaTagType.DOOM_DESIRE: - return new DelayedAttackTag(tagType, sourceMove, sourceId, targetIndex!); // TODO:questionable bang + return new DelayedAttackTag(tagType, sourceMove, sourceId, targetIndex!, side); // TODO:questionable bang case ArenaTagType.WISH: return new WishTag(turnCount, sourceId, side); case ArenaTagType.STEALTH_ROCK: diff --git a/src/data/move.ts b/src/data/move.ts index 6e350315e65..5ae37c3b092 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -2785,6 +2785,14 @@ export class OverrideMoveEffectAttr extends MoveAttr { } } +/** + * Attack Move that doesn't hit the turn it is played and doesn't allow for multiple + * uses on the same target. Examples are Future Sight or Doom Desire. + * @extends OverrideMoveEffectAttr + * @param tagType The {@linkcode ArenaTagType} that will be placed on the field when the move is used + * @param chargeAnim The {@linkcode ChargeAnim | Charging Animation} used for the move + * @param chargeText The text to display when the move is used + */ export class DelayedAttackAttr extends OverrideMoveEffectAttr { public tagType: ArenaTagType; public chargeAnim: ChargeAnim; @@ -2799,13 +2807,18 @@ export class DelayedAttackAttr extends OverrideMoveEffectAttr { } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise { + // Edge case for the move applied on a pokemon that has fainted + if (!target) { + return Promise.resolve(true); + } + const side = target.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; return new Promise(resolve => { if (args.length < 2 || !args[1]) { new MoveChargeAnim(this.chargeAnim, move.id, user).play(user.scene, false, () => { (args[0] as Utils.BooleanHolder).value = true; user.scene.queueMessage(this.chargeText.replace("{TARGET}", getPokemonNameWithAffix(target)).replace("{USER}", getPokemonNameWithAffix(user))); user.pushMoveHistory({ move: move.id, targets: [ target.getBattlerIndex() ], result: MoveResult.OTHER }); - user.scene.arena.addTag(this.tagType, 3, move.id, user.id, ArenaTagSide.BOTH, false, target.getBattlerIndex()); + user.scene.arena.addTag(this.tagType, 3, move.id, user.id, side, false, target.getBattlerIndex()); resolve(true); }); @@ -5534,7 +5547,8 @@ export class AddArenaTagAttr extends MoveEffectAttr { } if ((move.chance < 0 || move.chance === 100 || user.randSeedInt(100) < move.chance) && user.getLastXMoves(1)[0]?.result === MoveResult.SUCCESS) { - user.scene.arena.addTag(this.tagType, this.turnCount, move.id, user.id, (this.selfSideTarget ? user : target).isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY); + const side = (this.selfSideTarget ? user : target).isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; + user.scene.arena.addTag(this.tagType, this.turnCount, move.id, user.id, side); return true; } @@ -8297,7 +8311,8 @@ export function initMoves() { .attr(StatStageChangeAttr, [ Stat.SPDEF ], -1) .ballBombMove(), new AttackMove(Moves.FUTURE_SIGHT, Type.PSYCHIC, MoveCategory.SPECIAL, 120, 100, 10, -1, 0, 2) - .partial() // Complete buggy mess + .partial() // cannot be used on multiple Pokemon on the same side in a double battle, hits immediately when called by Metronome/etc + .ignoresProtect() .attr(DelayedAttackAttr, ArenaTagType.FUTURE_SIGHT, ChargeAnim.FUTURE_SIGHT_CHARGING, i18next.t("moveTriggers:foresawAnAttack", { pokemonName: "{USER}" })), new AttackMove(Moves.ROCK_SMASH, Type.FIGHTING, MoveCategory.PHYSICAL, 40, 100, 15, 50, 0, 2) .attr(StatStageChangeAttr, [ Stat.DEF ], -1), @@ -8604,7 +8619,8 @@ export function initMoves() { .attr(ConfuseAttr) .pulseMove(), new AttackMove(Moves.DOOM_DESIRE, Type.STEEL, MoveCategory.SPECIAL, 140, 100, 5, -1, 0, 3) - .partial() // Complete buggy mess + .partial() // cannot be used on multiple Pokemon on the same side in a double battle, hits immediately when called by Metronome/etc + .ignoresProtect() .attr(DelayedAttackAttr, ArenaTagType.DOOM_DESIRE, ChargeAnim.DOOM_DESIRE_CHARGING, i18next.t("moveTriggers:choseDoomDesireAsDestiny", { pokemonName: "{USER}" })), new AttackMove(Moves.PSYCHO_BOOST, Type.PSYCHIC, MoveCategory.SPECIAL, 140, 90, 5, -1, 0, 3) .attr(StatStageChangeAttr, [ Stat.SPATK ], -2, true), diff --git a/src/phases/move-effect-phase.ts b/src/phases/move-effect-phase.ts index 4c813a881d3..62ece3769b5 100644 --- a/src/phases/move-effect-phase.ts +++ b/src/phases/move-effect-phase.ts @@ -25,6 +25,7 @@ import { applyFilteredMoveAttrs, applyMoveAttrs, AttackMove, + DelayedAttackAttr, FixedDamageAttr, HitsTagAttr, MissEffectAttr, @@ -85,8 +86,13 @@ export class MoveEffectPhase extends PokemonPhase { /** All Pokemon targeted by this phase's invoked move */ const targets = this.getTargets(); - /** If the user was somehow removed from the field, end this phase */ - if (!user?.isOnField()) { + if (!user) { + return super.end(); + } + + const isDelayedAttack = this.move.getMove().hasAttr(DelayedAttackAttr); + /** If the user was somehow removed from the field and it's not a delayed attack, end this phase */ + if (!user.isOnField() && !isDelayedAttack) { return super.end(); } @@ -142,9 +148,9 @@ export class MoveEffectPhase extends PokemonPhase { const hasActiveTargets = targets.some(t => t.isActive(true)); /** Check if the target is immune via ability to the attacking move, and NOT in semi invulnerable state */ - const isImmune = targets[0].hasAbilityWithAttr(TypeImmunityAbAttr) - && (targets[0].getAbility()?.getAttrs(TypeImmunityAbAttr)?.[0]?.getImmuneType() === user.getMoveType(move)) - && !targets[0].getTag(SemiInvulnerableTag); + const isImmune = targets[0]?.hasAbilityWithAttr(TypeImmunityAbAttr) + && (targets[0]?.getAbility()?.getAttrs(TypeImmunityAbAttr)?.[0]?.getImmuneType() === user.getMoveType(move)) + && !targets[0]?.getTag(SemiInvulnerableTag); /** * If no targets are left for the move to hit (FAIL), or the invoked move is single-target @@ -156,7 +162,7 @@ export class MoveEffectPhase extends PokemonPhase { if (hasActiveTargets) { this.scene.queueMessage(i18next.t("battle:attackMissed", { pokemonNameWithAffix: this.getFirstTarget() ? getPokemonNameWithAffix(this.getFirstTarget()!) : "" })); moveHistoryEntry.result = MoveResult.MISS; - applyMoveAttrs(MissEffectAttr, user, null, move); + applyMoveAttrs(MissEffectAttr, user, null, this.move.getMove()); } else { this.scene.queueMessage(i18next.t("battle:attackFailed")); moveHistoryEntry.result = MoveResult.FAIL; diff --git a/src/phases/move-phase.ts b/src/phases/move-phase.ts index 5c6c339ffa5..b11a7d9b711 100644 --- a/src/phases/move-phase.ts +++ b/src/phases/move-phase.ts @@ -1,9 +1,31 @@ import { BattlerIndex } from "#app/battle"; import BattleScene from "#app/battle-scene"; -import { applyAbAttrs, applyPostMoveUsedAbAttrs, applyPreAttackAbAttrs, BlockRedirectAbAttr, IncreasePpAbAttr, PokemonTypeChangeAbAttr, PostMoveUsedAbAttr, RedirectMoveAbAttr, ReduceStatusEffectDurationAbAttr } from "#app/data/ability"; +import { + applyAbAttrs, + applyPostMoveUsedAbAttrs, + applyPreAttackAbAttrs, + BlockRedirectAbAttr, + IncreasePpAbAttr, + PokemonTypeChangeAbAttr, + PostMoveUsedAbAttr, + RedirectMoveAbAttr, + ReduceStatusEffectDurationAbAttr +} from "#app/data/ability"; +import { DelayedAttackTag } from "#app/data/arena-tag"; import { CommonAnim } from "#app/data/battle-anims"; import { BattlerTagLapseType, CenterOfAttentionTag } from "#app/data/battler-tags"; -import { allMoves, applyMoveAttrs, BypassRedirectAttr, BypassSleepAttr, CopyMoveAttr, frenzyMissFunc, HealStatusEffectAttr, MoveFlags, PreMoveMessageAttr } from "#app/data/move"; +import { + allMoves, + applyMoveAttrs, + BypassRedirectAttr, + BypassSleepAttr, + CopyMoveAttr, + DelayedAttackAttr, + frenzyMissFunc, + HealStatusEffectAttr, + MoveFlags, + PreMoveMessageAttr +} from "#app/data/move"; import { SpeciesFormChangePreMoveTrigger } from "#app/data/pokemon-forms"; import { getStatusEffectActivationText, getStatusEffectHealText } from "#app/data/status-effect"; import { Type } from "#app/data/type"; @@ -14,16 +36,17 @@ import { getPokemonNameWithAffix } from "#app/messages"; import Overrides from "#app/overrides"; import { BattlePhase } from "#app/phases/battle-phase"; import { CommonAnimPhase } from "#app/phases/common-anim-phase"; +import { MoveChargePhase } from "#app/phases/move-charge-phase"; import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { MoveEndPhase } from "#app/phases/move-end-phase"; import { ShowAbilityPhase } from "#app/phases/show-ability-phase"; import { BooleanHolder, NumberHolder } from "#app/utils"; import { Abilities } from "#enums/abilities"; +import { ArenaTagType } from "#enums/arena-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type"; import { Moves } from "#enums/moves"; import { StatusEffect } from "#enums/status-effect"; import i18next from "i18next"; -import { MoveChargePhase } from "#app/phases/move-charge-phase"; export class MovePhase extends BattlePhase { protected _pokemon: Pokemon; @@ -227,6 +250,32 @@ export class MovePhase extends BattlePhase { // form changes happen even before we know that the move wll execute. this.scene.triggerPokemonFormChange(this.pokemon, SpeciesFormChangePreMoveTrigger); + const isDelayedAttack = this.move.getMove().hasAttr(DelayedAttackAttr); + if (isDelayedAttack) { + // Check the player side arena if future sight is active + const futureSightTags = this.scene.arena.findTags(t => t.tagType === ArenaTagType.FUTURE_SIGHT); + const doomDesireTags = this.scene.arena.findTags(t => t.tagType === ArenaTagType.DOOM_DESIRE); + let fail = false; + const currentTargetIndex = targets[0].getBattlerIndex(); + for (const tag of futureSightTags) { + if ((tag as DelayedAttackTag).targetIndex === currentTargetIndex) { + fail = true; + break; + } + } + for (const tag of doomDesireTags) { + if ((tag as DelayedAttackTag).targetIndex === currentTargetIndex) { + fail = true; + break; + } + } + if (fail) { + this.showMoveText(); + this.showFailedText(); + return this.end(); + } + } + this.showMoveText(); if (moveQueue.length > 0) { diff --git a/src/test/moves/future_sight.test.ts b/src/test/moves/future_sight.test.ts new file mode 100644 index 00000000000..d0110a87202 --- /dev/null +++ b/src/test/moves/future_sight.test.ts @@ -0,0 +1,45 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Moves - Future Sight", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .startingLevel(50) + .moveset([ Moves.FUTURE_SIGHT, Moves.SPLASH ]) + .battleType("single") + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.STURDY) + .enemyMoveset(Moves.SPLASH); + }); + + it("hits 2 turns after use, ignores user switch out", async () => { + await game.classicMode.startBattle([ Species.FEEBAS, Species.MILOTIC ]); + + game.move.select(Moves.FUTURE_SIGHT); + await game.toNextTurn(); + game.doSwitchPokemon(1); + await game.toNextTurn(); + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + expect(game.scene.getEnemyPokemon()!.isFullHp()).toBe(false); + }); +}); From 13841765f177a2e6626683967457adcfc965b631 Mon Sep 17 00:00:00 2001 From: AJ Fontaine <36677462+Fontbane@users.noreply.github.com> Date: Mon, 4 Nov 2024 21:33:15 -0500 Subject: [PATCH 03/75] [Dev] Update test save with everything unlocked (#4137) * Add test save with all egg moves unlocked * Move to everything.prsv --------- Co-authored-by: Lugiad Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com> Co-authored-by: Moka <54149968+MokaStitcher@users.noreply.github.com> --- src/test/utils/saves/everything.prsv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/utils/saves/everything.prsv b/src/test/utils/saves/everything.prsv index 1985a6649ca..f9106ce0e35 100644 --- a/src/test/utils/saves/everything.prsv +++ b/src/test/utils/saves/everything.prsv @@ -1 +1 @@ -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 \ No newline at end of file +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 From 543a97076bc2ccb32f6978e9e26b17877a309414 Mon Sep 17 00:00:00 2001 From: PigeonBar <56974298+PigeonBar@users.noreply.github.com> Date: Tue, 5 Nov 2024 09:19:20 -0500 Subject: [PATCH 04/75] [P1][Beta] Fix FormChangePhase being broken by EvolutionPhase refactor (#4795) * [P1][Beta] Fix FormChangePhase being broken by EvolutionPhase refactor * Apply suggested changes to added test --- src/phases/evolution-phase.ts | 11 ++-- src/test/phases/form-change-phase.test.ts | 60 +++++++++++++++++++++ src/test/utils/helpers/classicModeHelper.ts | 2 +- src/test/utils/phaseInterceptor.ts | 19 +++++-- 4 files changed, 79 insertions(+), 13 deletions(-) create mode 100644 src/test/phases/form-change-phase.test.ts diff --git a/src/phases/evolution-phase.ts b/src/phases/evolution-phase.ts index dec65e2c945..01994263688 100644 --- a/src/phases/evolution-phase.ts +++ b/src/phases/evolution-phase.ts @@ -39,8 +39,6 @@ export class EvolutionPhase extends Phase { this.pokemon = pokemon; this.evolution = evolution; this.lastLevel = lastLevel; - this.evolutionBgm = this.scene.playSoundWithoutBgm("evolution"); - this.preEvolvedPokemonName = getPokemonNameWithAffix(this.pokemon); } validate(): boolean { @@ -62,9 +60,9 @@ export class EvolutionPhase extends Phase { this.scene.fadeOutBgm(undefined, false); - const evolutionHandler = this.scene.ui.getHandler() as EvolutionSceneHandler; + this.evolutionHandler = this.scene.ui.getHandler() as EvolutionSceneHandler; - this.evolutionContainer = evolutionHandler.evolutionContainer; + this.evolutionContainer = this.evolutionHandler.evolutionContainer; this.evolutionBaseBg = this.scene.add.image(0, 0, "default_bg"); this.evolutionBaseBg.setOrigin(0, 0); @@ -117,14 +115,12 @@ export class EvolutionPhase extends Phase { sprite.pipelineData[k] = this.pokemon.getSprite().pipelineData[k]; }); }); - + this.preEvolvedPokemonName = getPokemonNameWithAffix(this.pokemon); this.doEvolution(); }); } doEvolution(): void { - this.evolutionHandler = this.scene.ui.getHandler() as EvolutionSceneHandler; - this.scene.ui.showText(i18next.t("menu:evolving", { pokemonName: this.preEvolvedPokemonName }), null, () => { this.pokemon.cry(); @@ -145,6 +141,7 @@ export class EvolutionPhase extends Phase { }); this.scene.time.delayedCall(1000, () => { + this.evolutionBgm = this.scene.playSoundWithoutBgm("evolution"); this.scene.tweens.add({ targets: this.evolutionBgOverlay, alpha: 1, diff --git a/src/test/phases/form-change-phase.test.ts b/src/test/phases/form-change-phase.test.ts new file mode 100644 index 00000000000..70ca429672f --- /dev/null +++ b/src/test/phases/form-change-phase.test.ts @@ -0,0 +1,60 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { Type } from "#app/data/type"; +import { generateModifierType } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; +import { modifierTypes } from "#app/modifier/modifier-type"; + +describe("Form Change Phase", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([ Moves.SPLASH ]) + .ability(Abilities.BALL_FETCH) + .battleType("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("Zacian should successfully change into Crowned form", async () => { + await game.classicMode.startBattle([ Species.ZACIAN ]); + + // Before the form change: Should be Hero form + const zacian = game.scene.getPlayerParty()[0]; + expect(zacian.getFormKey()).toBe("hero-of-many-battles"); + expect(zacian.getTypes()).toStrictEqual([ Type.FAIRY ]); + expect(zacian.calculateBaseStats()).toStrictEqual([ 92, 120, 115, 80, 115, 138 ]); + + // Give Zacian a Rusted Sword + const rustedSwordType = generateModifierType(game.scene, modifierTypes.RARE_FORM_CHANGE_ITEM)!; + const rustedSword = rustedSwordType.newModifier(zacian); + await game.scene.addModifier(rustedSword); + + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + // After the form change: Should be Crowned form + expect(game.phaseInterceptor.log.includes("FormChangePhase")).toBe(true); + expect(zacian.getFormKey()).toBe("crowned"); + expect(zacian.getTypes()).toStrictEqual([ Type.FAIRY, Type.STEEL ]); + expect(zacian.calculateBaseStats()).toStrictEqual([ 92, 150, 115, 80, 115, 148 ]); + }); +}); diff --git a/src/test/utils/helpers/classicModeHelper.ts b/src/test/utils/helpers/classicModeHelper.ts index 80d0b86de7b..41a21a52b72 100644 --- a/src/test/utils/helpers/classicModeHelper.ts +++ b/src/test/utils/helpers/classicModeHelper.ts @@ -35,7 +35,7 @@ export class ClassicModeHelper extends GameManagerHelper { selectStarterPhase.initBattle(starters); }); - await this.game.phaseInterceptor.run(EncounterPhase); + await this.game.phaseInterceptor.to(EncounterPhase); if (overrides.OPP_HELD_ITEMS_OVERRIDE.length === 0 && this.game.override.removeEnemyStartingItems) { this.game.removeEnemyHeldItems(); } diff --git a/src/test/utils/phaseInterceptor.ts b/src/test/utils/phaseInterceptor.ts index ec9309e2405..17b6c7a6c81 100644 --- a/src/test/utils/phaseInterceptor.ts +++ b/src/test/utils/phaseInterceptor.ts @@ -12,6 +12,7 @@ import { EndEvolutionPhase } from "#app/phases/end-evolution-phase"; import { EnemyCommandPhase } from "#app/phases/enemy-command-phase"; import { EvolutionPhase } from "#app/phases/evolution-phase"; import { FaintPhase } from "#app/phases/faint-phase"; +import { FormChangePhase } from "#app/phases/form-change-phase"; import { LearnMovePhase } from "#app/phases/learn-move-phase"; import { LevelCapPhase } from "#app/phases/level-cap-phase"; import { LoginPhase } from "#app/phases/login-phase"; @@ -67,7 +68,6 @@ type PhaseClass = | typeof LoginPhase | typeof TitlePhase | typeof SelectGenderPhase - | typeof EncounterPhase | typeof NewBiomeEncounterPhase | typeof SelectStarterPhase | typeof PostSummonPhase @@ -102,6 +102,7 @@ type PhaseClass = | typeof SwitchPhase | typeof SwitchSummonPhase | typeof PartyHealPhase + | typeof FormChangePhase | typeof EvolutionPhase | typeof EndEvolutionPhase | typeof LevelCapPhase @@ -114,13 +115,13 @@ type PhaseClass = | typeof PostMysteryEncounterPhase | typeof ModifierRewardPhase | typeof PartyExpPhase - | typeof ExpPhase; + | typeof ExpPhase + | typeof EncounterPhase; type PhaseString = | "LoginPhase" | "TitlePhase" | "SelectGenderPhase" - | "EncounterPhase" | "NewBiomeEncounterPhase" | "SelectStarterPhase" | "PostSummonPhase" @@ -155,6 +156,7 @@ type PhaseString = | "SwitchPhase" | "SwitchSummonPhase" | "PartyHealPhase" + | "FormChangePhase" | "EvolutionPhase" | "EndEvolutionPhase" | "LevelCapPhase" @@ -167,7 +169,8 @@ type PhaseString = | "PostMysteryEncounterPhase" | "ModifierRewardPhase" | "PartyExpPhase" - | "ExpPhase"; + | "ExpPhase" + | "EncounterPhase"; type PhaseInterceptorPhase = PhaseClass | PhaseString; @@ -187,12 +190,16 @@ export default class PhaseInterceptor { /** * List of phases with their corresponding start methods. + * + * CAUTION: If a phase and its subclasses (if any) both appear in this list, + * make sure that this list contains said phase AFTER all of its subclasses. + * This way, the phase's `prototype.start` is properly preserved during + * `initPhases()` so that its subclasses can use `super.start()` properly. */ private PHASES = [ [ LoginPhase, this.startPhase ], [ TitlePhase, this.startPhase ], [ SelectGenderPhase, this.startPhase ], - [ EncounterPhase, this.startPhase ], [ NewBiomeEncounterPhase, this.startPhase ], [ SelectStarterPhase, this.startPhase ], [ PostSummonPhase, this.startPhase ], @@ -227,6 +234,7 @@ export default class PhaseInterceptor { [ SwitchPhase, this.startPhase ], [ SwitchSummonPhase, this.startPhase ], [ PartyHealPhase, this.startPhase ], + [ FormChangePhase, this.startPhase ], [ EvolutionPhase, this.startPhase ], [ EndEvolutionPhase, this.startPhase ], [ LevelCapPhase, this.startPhase ], @@ -240,6 +248,7 @@ export default class PhaseInterceptor { [ ModifierRewardPhase, this.startPhase ], [ PartyExpPhase, this.startPhase ], [ ExpPhase, this.startPhase ], + [ EncounterPhase, this.startPhase ], ]; private endBySetMode = [ From 88789c685e376e810f590713890c79bc1c2fd3ba Mon Sep 17 00:00:00 2001 From: "Adrian T." <68144167+torranx@users.noreply.github.com> Date: Wed, 6 Nov 2024 00:08:55 +0800 Subject: [PATCH 05/75] [Documentation] Flag Gulp Missile with edge case (#4800) --- 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 8eeb5af52b8..e8a242ae3ea 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -6099,7 +6099,8 @@ export function initAbilities() { .attr(NoFusionAbilityAbAttr) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) - .bypassFaint(), + .bypassFaint() + .edgeCase(), // Soft-locks the game if a form-changed Cramorant and its attacker both faint at the same time (ex. using Self-Destruct) new Ability(Abilities.STALWART, 8) .attr(BlockRedirectAbAttr), new Ability(Abilities.STEAM_ENGINE, 8) From 6fd3ba284c0df0926460b81855c68e4c380685f6 Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Tue, 5 Nov 2024 09:35:43 -0800 Subject: [PATCH 06/75] [Move][Ability] Implement Commander and Order Up (#4670) * Implement Order Up (mostly untested) * Commander unit tests + bug fixes * Implement Order Up (misnamed the other commit...) * Order Up unit tests * applying Temp's suggestions + other bugfixes * add TODO comment * Reviver Seed reapplies Commander * ESLint woes * Some animation fixes * Update locales * Order Up now uses attr option * Prevent semi-invulnerability lapsing out while Commanding * semi-invulnerability test * Add `edgeCase` --- src/battle-scene.ts | 3 + src/data/ability.ts | 42 +++- src/data/battler-tags.ts | 33 +++ src/data/move.ts | 57 ++++- .../the-winstrate-challenge-encounter.ts | 2 + src/enums/battler-tag-type.ts | 3 +- src/enums/pokemon-anim-type.ts | 12 +- src/field/pokemon.ts | 7 + src/modifier/modifier.ts | 7 + src/phases/command-phase.ts | 16 +- src/phases/encounter-phase.ts | 2 + src/phases/enemy-command-phase.ts | 7 + src/phases/move-effect-phase.ts | 5 +- src/phases/mystery-encounter-phases.ts | 1 + src/phases/pokemon-anim-phase.ts | 132 ++++++++++- src/phases/post-summon-phase.ts | 5 +- src/test/abilities/commander.test.ts | 224 ++++++++++++++++++ src/test/moves/order_up.test.ts | 85 +++++++ 18 files changed, 623 insertions(+), 20 deletions(-) create mode 100644 src/test/abilities/commander.test.ts create mode 100644 src/test/moves/order_up.test.ts diff --git a/src/battle-scene.ts b/src/battle-scene.ts index d82acec1c20..d17c62c6e0e 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -96,6 +96,7 @@ import { ExpPhase } from "#app/phases/exp-phase"; import { ShowPartyExpBarPhase } from "#app/phases/show-party-exp-bar-phase"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; import { ExpGainsSpeed } from "#enums/exp-gains-speed"; +import { BattlerTagType } from "#enums/battler-tag-type"; import { FRIENDSHIP_GAIN_FROM_BATTLE } from "#app/data/balance/starters"; export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1"; @@ -1278,6 +1279,8 @@ export default class BattleScene extends SceneBase { if (resetArenaState) { this.arena.resetArenaEffects(); + playerField.forEach((pokemon) => pokemon.lapseTag(BattlerTagType.COMMANDED)); + playerField.forEach((pokemon, p) => { if (pokemon.isOnField()) { this.pushPhase(new ReturnPhase(this, p)); diff --git a/src/data/ability.ts b/src/data/ability.ts index e8a242ae3ea..7d54459d7d4 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -4,7 +4,7 @@ import { Constructor } from "#app/utils"; import * as Utils from "../utils"; import { getPokemonNameWithAffix } from "../messages"; import { Weather, WeatherType } from "./weather"; -import { BattlerTag, GroundedTag } from "./battler-tags"; +import { BattlerTag, BattlerTagLapseType, GroundedTag } from "./battler-tags"; import { StatusEffect, getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect"; import { Gender } from "./gender"; import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, MoveAttr, MultiHitAttr, SacrificialAttr, SacrificialAttrOnHit, NeutralDamageAgainstFlyingTypeMultiplierAttr, FixedDamageAttr } from "./move"; @@ -35,6 +35,7 @@ import { SwitchSummonPhase } from "#app/phases/switch-summon-phase"; import { BattleEndPhase } from "#app/phases/battle-end-phase"; import { NewBattlePhase } from "#app/phases/new-battle-phase"; import { MoveEndPhase } from "#app/phases/move-end-phase"; +import { PokemonAnimType } from "#enums/pokemon-anim-type"; export class Ability implements Localizable { public id: Abilities; @@ -2591,6 +2592,42 @@ export class PostSummonFormChangeByWeatherAbAttr extends PostSummonAbAttr { } } +/** + * Attribute implementing the effects of {@link https://bulbapedia.bulbagarden.net/wiki/Commander_(Ability) | Commander}. + * When the source of an ability with this attribute detects a Dondozo as their active ally, the source "jumps + * into the Dondozo's mouth," sharply boosting the Dondozo's stats, cancelling the source's moves, and + * causing attacks that target the source to always miss. + */ +export class CommanderAbAttr extends AbAttr { + constructor() { + super(true); + } + + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: null, args: any[]): boolean { + // TODO: Should this work with X + Dondozo fusions? + if (pokemon.scene.currentBattle?.double && pokemon.getAlly()?.species.speciesId === Species.DONDOZO) { + // If the ally Dondozo is fainted or was previously "commanded" by + // another Pokemon, this effect cannot apply. + if (pokemon.getAlly().isFainted() || pokemon.getAlly().getTag(BattlerTagType.COMMANDED)) { + return false; + } + + if (!simulated) { + // Lapse the source's semi-invulnerable tags (to avoid visual inconsistencies) + pokemon.lapseTags(BattlerTagLapseType.MOVE_EFFECT); + // Play an animation of the source jumping into the ally Dondozo's mouth + pokemon.scene.triggerPokemonBattleAnim(pokemon, PokemonAnimType.COMMANDER_APPLY); + // Apply boosts from this effect to the ally Dondozo + pokemon.getAlly().addTag(BattlerTagType.COMMANDED, 0, Moves.NONE, pokemon.id); + // Cancel the source Pokemon's next move (if a move is queued) + pokemon.scene.tryRemovePhase((phase) => phase instanceof MovePhase && phase.pokemon === pokemon); + } + return true; + } + return false; + } +} + export class PreSwitchOutAbAttr extends AbAttr { constructor() { super(true); @@ -6243,9 +6280,10 @@ export function initAbilities() { .attr(PreSwitchOutFormChangeAbAttr, (pokemon) => !pokemon.isFainted() ? 1 : pokemon.formIndex) .bypassFaint(), new Ability(Abilities.COMMANDER, 9) + .attr(CommanderAbAttr) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) - .unimplemented(), + .edgeCase(), // Encore, Frenzy, and other non-`TURN_END` tags don't lapse correctly on the commanding Pokemon. new Ability(Abilities.ELECTROMORPHOSIS, 9) .attr(PostDefendApplyBattlerTagAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, BattlerTagType.CHARGED), new Ability(Abilities.PROTOSYNTHESIS, 9) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 15bc745ec9d..2012c4330cc 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -2091,6 +2091,37 @@ export class IceFaceBlockDamageTag extends FormBlockDamageTag { } } +/** + * Battler tag indicating a Tatsugiri with {@link https://bulbapedia.bulbagarden.net/wiki/Commander_(Ability) | Commander} + * has entered the tagged Pokemon's mouth. + */ +export class CommandedTag extends BattlerTag { + private _tatsugiriFormKey: string; + + constructor(sourceId: number) { + super(BattlerTagType.COMMANDED, BattlerTagLapseType.CUSTOM, 0, Moves.NONE, sourceId); + } + + public get tatsugiriFormKey(): string { + return this._tatsugiriFormKey; + } + + /** Caches the Tatsugiri's form key and sharply boosts the tagged Pokemon's stats */ + override onAdd(pokemon: Pokemon): void { + this._tatsugiriFormKey = this.getSourcePokemon(pokemon.scene)?.getFormKey() ?? "curly"; + pokemon.scene.unshiftPhase(new StatStageChangePhase( + pokemon.scene, pokemon.getBattlerIndex(), true, [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD ], 2 + )); + } + + /** Triggers an {@linkcode PokemonAnimType | animation} of the tagged Pokemon "spitting out" Tatsugiri */ + override onRemove(pokemon: Pokemon): void { + if (this.getSourcePokemon(pokemon.scene)?.isActive(true)) { + pokemon.scene.triggerPokemonBattleAnim(pokemon, PokemonAnimType.COMMANDER_REMOVE); + } + } +} + /** * Battler tag enabling the Stockpile mechanic. This tag handles: * - Stack tracking, including max limit enforcement (which is replicated in Stockpile for redundancy). @@ -2932,6 +2963,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source return new IceFaceBlockDamageTag(tagType); case BattlerTagType.DISGUISE: return new FormBlockDamageTag(tagType); + case BattlerTagType.COMMANDED: + return new CommandedTag(sourceId); case BattlerTagType.STOCKPILING: return new StockpilingTag(sourceMove); case BattlerTagType.OCTOLOCK: diff --git a/src/data/move.ts b/src/data/move.ts index 5ae37c3b092..c97749e0357 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1,5 +1,5 @@ import { ChargeAnim, initMoveAnim, loadMoveAnimAssets, MoveChargeAnim } from "./battle-anims"; -import { EncoreTag, GulpMissileTag, HelpingHandTag, SemiInvulnerableTag, ShellTrapTag, StockpilingTag, SubstituteTag, TrappedTag, TypeBoostTag } from "./battler-tags"; +import { CommandedTag, EncoreTag, GulpMissileTag, HelpingHandTag, SemiInvulnerableTag, ShellTrapTag, StockpilingTag, SubstituteTag, TrappedTag, TypeBoostTag } from "./battler-tags"; import { getPokemonNameWithAffix } from "../messages"; import Pokemon, { AttackMoveResult, EnemyPokemon, HitResult, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "../field/pokemon"; import { getNonVolatileStatusEffects, getStatusEffectHealText, isNonVolatileStatusEffect, StatusEffect } from "./status-effect"; @@ -714,6 +714,10 @@ export default class Move implements Localizable { getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer { let score = 0; + if (target.getAlly()?.getTag(BattlerTagType.COMMANDED)?.getSourcePokemon(target.scene) === target) { + return 20 * (target.isPlayer() === user.isPlayer() ? -1 : 1); // always -20 with how the AI handles this score + } + for (const attr of this.attrs) { // conditionals to check if the move is self targeting (if so then you are applying the move to yourself, not the target) score += attr.getTargetBenefitScore(user, !attr.selfTarget ? target : user, move) * (target !== user && attr.selfTarget ? -1 : 1); @@ -3245,6 +3249,41 @@ export class CutHpStatStageBoostAttr extends StatStageChangeAttr { } } +/** + * Attribute implementing the stat boosting effect of {@link https://bulbapedia.bulbagarden.net/wiki/Order_Up_(move) | Order Up}. + * If the user has a Pokemon with {@link https://bulbapedia.bulbagarden.net/wiki/Commander_(Ability) | Commander} in their mouth, + * one of the user's stats are increased by 1 stage, depending on the "commanding" Pokemon's form. This effect does not respect + * effect chance, but Order Up itself may be boosted by Sheer Force. + */ +export class OrderUpStatBoostAttr extends MoveEffectAttr { + constructor() { + super(true, { trigger: MoveEffectTrigger.HIT }); + } + + override apply(user: Pokemon, target: Pokemon, move: Move, args?: any[]): boolean { + const commandedTag = user.getTag(CommandedTag); + if (!commandedTag) { + return false; + } + + let increasedStat: EffectiveStat = Stat.ATK; + switch (commandedTag.tatsugiriFormKey) { + case "curly": + increasedStat = Stat.ATK; + break; + case "droopy": + increasedStat = Stat.DEF; + break; + case "stretchy": + increasedStat = Stat.SPD; + break; + } + + user.scene.unshiftPhase(new StatStageChangePhase(user.scene, user.getBattlerIndex(), this.selfTarget, [ increasedStat ], 1)); + return true; + } +} + export class CopyStatsAttr extends MoveEffectAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if (!super.apply(user, target, move, args)) { @@ -5852,7 +5891,13 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { return false; } + /** The {@linkcode Pokemon} to be switched out with this effect */ const switchOutTarget = this.selfSwitch ? user : target; + + // If the switch-out target is a Dondozo with a Tatsugiri in its mouth + // (e.g. when it uses Flip Turn), make it spit out the Tatsugiri before switching out. + switchOutTarget.lapseTag(BattlerTagType.COMMANDED); + if (switchOutTarget instanceof PlayerPokemon) { /** * Check if Wimp Out/Emergency Exit activates due to being hit by U-turn or Volt Switch @@ -5955,6 +6000,12 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { return false; } + // Dondozo with an allied Tatsugiri in its mouth cannot be forced out + const commandedTag = switchOutTarget.getTag(BattlerTagType.COMMANDED); + if (commandedTag?.getSourcePokemon(switchOutTarget.scene)?.isActive(true)) { + return false; + } + if (!player && user.scene.currentBattle.isBattleMysteryEncounter() && !user.scene.currentBattle.mysteryEncounter?.fleeAllowed) { // Don't allow wild opponents to be force switched during MEs with flee disabled return false; @@ -10300,8 +10351,8 @@ export function initMoves() { new AttackMove(Moves.LUMINA_CRASH, Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 10, 100, 0, 9) .attr(StatStageChangeAttr, [ Stat.SPDEF ], -2), new AttackMove(Moves.ORDER_UP, Type.DRAGON, MoveCategory.PHYSICAL, 80, 100, 10, 100, 0, 9) - .makesContact(false) - .partial(), // No effect implemented (requires Commander) + .attr(OrderUpStatBoostAttr) + .makesContact(false), new AttackMove(Moves.JET_PUNCH, Type.WATER, MoveCategory.PHYSICAL, 60, 100, 15, -1, 1, 9) .punchingMove(), new StatusMove(Moves.SPICY_EXTRACT, Type.GRASS, -1, 15, -1, 0, 9) diff --git a/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts b/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts index 7d9b531c9ab..5c1af43c426 100644 --- a/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts @@ -23,6 +23,7 @@ import { ReturnPhase } from "#app/phases/return-phase"; import i18next from "i18next"; import { ModifierTier } from "#app/modifier/modifier-tier"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { BattlerTagType } from "#enums/battler-tag-type"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounters/theWinstrateChallenge"; @@ -187,6 +188,7 @@ function endTrainerBattleAndShowDialogue(scene: BattleScene): Promise { } else { scene.arena.resetArenaEffects(); const playerField = scene.getPlayerField(); + playerField.forEach((pokemon) => pokemon.lapseTag(BattlerTagType.COMMANDED)); playerField.forEach((_, p) => scene.unshiftPhase(new ReturnPhase(scene, p))); for (const pokemon of scene.getPlayerParty()) { diff --git a/src/enums/battler-tag-type.ts b/src/enums/battler-tag-type.ts index 0eace9a1607..c53157c68d4 100644 --- a/src/enums/battler-tag-type.ts +++ b/src/enums/battler-tag-type.ts @@ -88,5 +88,6 @@ export enum BattlerTagType { IMPRISON = "IMPRISON", SYRUP_BOMB = "SYRUP_BOMB", ELECTRIFIED = "ELECTRIFIED", - TELEKINESIS = "TELEKINESIS" + TELEKINESIS = "TELEKINESIS", + COMMANDED = "COMMANDED" } diff --git a/src/enums/pokemon-anim-type.ts b/src/enums/pokemon-anim-type.ts index 5a0a0c2f622..b153fb2e652 100644 --- a/src/enums/pokemon-anim-type.ts +++ b/src/enums/pokemon-anim-type.ts @@ -12,5 +12,15 @@ export enum PokemonAnimType { * Removes a Pokemon's Substitute doll from the field. * The Pokemon then moves back to its original position. */ - SUBSTITUTE_REMOVE + SUBSTITUTE_REMOVE, + /** + * Brings Tatsugiri and Dondozo to the center of the field, with + * Tatsugiri jumping into the Dondozo's mouth + */ + COMMANDER_APPLY, + /** + * Dondozo "spits out" Tatsugiri, moving Tatsugiri back to its original + * field position. + */ + COMMANDER_REMOVE } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 78f82e929de..77881d36c56 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1563,6 +1563,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @returns `true` if the pokemon is trapped */ public isTrapped(trappedAbMessages: string[] = [], simulated: boolean = true): boolean { + const commandedTag = this.getTag(BattlerTagType.COMMANDED); + if (commandedTag?.getSourcePokemon(this.scene)?.isActive(true)) { + return true; + } + if (this.isOfType(Type.GHOST)) { return false; } @@ -2914,6 +2919,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.scene.unshiftPhase(new FaintPhase(this.scene, this.getBattlerIndex(), isOneHitKo)); } this.destroySubstitute(); + this.lapseTag(BattlerTagType.COMMANDED); this.resetSummonData(); } @@ -2962,6 +2968,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.scene.setPhaseQueueSplice(); this.scene.unshiftPhase(new FaintPhase(this.scene, this.getBattlerIndex(), preventEndure)); this.destroySubstitute(); + this.lapseTag(BattlerTagType.COMMANDED); this.resetSummonData(); } return damage; diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 0891262649c..c3b1f15fab4 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -31,6 +31,7 @@ import i18next from "i18next"; import { type DoubleBattleChanceBoosterModifierType, type EvolutionItemModifierType, type FormChangeItemModifierType, type ModifierOverride, type ModifierType, type PokemonBaseStatTotalModifierType, type PokemonExpBoosterModifierType, type PokemonFriendshipBoosterModifierType, type PokemonMoveAccuracyBoosterModifierType, type PokemonMultiHitModifierType, type TerastallizeModifierType, type TmModifierType, getModifierType, ModifierPoolType, ModifierTypeGenerator, modifierTypes, PokemonHeldItemModifierType } from "./modifier-type"; import { Color, ShadowColor } from "#enums/color"; import { FRIENDSHIP_GAIN_FROM_RARE_CANDY } from "#app/data/balance/starters"; +import { applyAbAttrs, CommanderAbAttr } from "#app/data/ability"; export type ModifierPredicate = (modifier: Modifier) => boolean; @@ -1937,10 +1938,16 @@ export class PokemonInstantReviveModifier extends PokemonHeldItemModifier { * @returns always `true` */ override apply(pokemon: Pokemon): boolean { + // Restore the Pokemon to half HP pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(), toDmgValue(pokemon.getMaxHp() / 2), i18next.t("modifier:pokemonInstantReviveApply", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), typeName: this.type.name }), false, false, true)); + // Remove the Pokemon's FAINT status pokemon.resetStatus(true, false, true); + + // Reapply Commander on the Pokemon's side of the field, if applicable + const field = pokemon.isPlayer() ? pokemon.scene.getPlayerField() : pokemon.scene.getEnemyField(); + field.forEach((p) => applyAbAttrs(CommanderAbAttr, p, null, false)); return true; } diff --git a/src/phases/command-phase.ts b/src/phases/command-phase.ts index c1d38815c2f..b99eb8d1b2e 100644 --- a/src/phases/command-phase.ts +++ b/src/phases/command-phase.ts @@ -54,6 +54,11 @@ export class CommandPhase extends FieldPhase { } } + // If the Pokemon has applied Commander's effects to its ally, skip this command + if (this.scene.currentBattle?.double && this.getPokemon().getAlly()?.getTag(BattlerTagType.COMMANDED)?.getSourcePokemon(this.scene) === this.getPokemon()) { + this.scene.currentBattle.turnCommands[this.fieldIndex] = { command: Command.FIGHT, move: { move: Moves.NONE, targets: []}, skip: true }; + } + if (this.scene.currentBattle.turnCommands[this.fieldIndex]?.skip) { return this.end(); } @@ -92,7 +97,7 @@ export class CommandPhase extends FieldPhase { handleCommand(command: Command, cursor: integer, ...args: any[]): boolean { const playerPokemon = this.scene.getPlayerField()[this.fieldIndex]; - let success: boolean; + let success: boolean = false; switch (command) { case Command.FIGHT: @@ -232,11 +237,8 @@ export class CommandPhase extends FieldPhase { const trapTag = playerPokemon.getTag(TrappedTag); const fairyLockTag = playerPokemon.scene.arena.getTagOnSide(ArenaTagType.FAIRY_LOCK, ArenaTagSide.PLAYER); - // trapTag should be defined at this point, but just in case... if (!trapTag && !fairyLockTag) { - currentBattle.turnCommands[this.fieldIndex] = isSwitch - ? { command: Command.POKEMON, cursor: cursor, args: args } - : { command: Command.RUN }; + i18next.t(`battle:noEscape${isSwitch ? "Switch" : "Flee"}`); break; } if (!isSwitch) { @@ -272,11 +274,11 @@ export class CommandPhase extends FieldPhase { break; } - if (success!) { // TODO: is the bang correct? + if (success) { this.end(); } - return success!; // TODO: is the bang correct? + return success; } cancel() { diff --git a/src/phases/encounter-phase.ts b/src/phases/encounter-phase.ts index c4d919c0325..123f9ded9fc 100644 --- a/src/phases/encounter-phase.ts +++ b/src/phases/encounter-phase.ts @@ -36,6 +36,7 @@ import { PlayerGender } from "#enums/player-gender"; import { Species } from "#enums/species"; import i18next from "i18next"; import { WEIGHT_INCREMENT_ON_SPAWN_MISS } from "#app/data/mystery-encounters/mystery-encounters"; +import { BattlerTagType } from "#enums/battler-tag-type"; export class EncounterPhase extends BattlePhase { private loaded: boolean; @@ -482,6 +483,7 @@ export class EncounterPhase extends BattlePhase { } } else { if (availablePartyMembers.length > 1 && availablePartyMembers[1].isOnField()) { + this.scene.getPlayerField().forEach((pokemon) => pokemon.lapseTag(BattlerTagType.COMMANDED)); this.scene.pushPhase(new ReturnPhase(this.scene, 1)); } this.scene.pushPhase(new ToggleDoublePositionPhase(this.scene, false)); diff --git a/src/phases/enemy-command-phase.ts b/src/phases/enemy-command-phase.ts index 3647a237ef1..83a85009ae0 100644 --- a/src/phases/enemy-command-phase.ts +++ b/src/phases/enemy-command-phase.ts @@ -2,6 +2,8 @@ import BattleScene from "#app/battle-scene"; import { BattlerIndex } from "#app/battle"; import { Command } from "#app/ui/command-ui-handler"; import { FieldPhase } from "./field-phase"; +import { Abilities } from "#enums/abilities"; +import { BattlerTagType } from "#enums/battler-tag-type"; /** * Phase for determining an enemy AI's action for the next turn. @@ -34,6 +36,11 @@ export class EnemyCommandPhase extends FieldPhase { const trainer = battle.trainer; + if (battle.double && enemyPokemon.hasAbility(Abilities.COMMANDER) + && enemyPokemon.getAlly().getTag(BattlerTagType.COMMANDED)) { + this.skipTurn = true; + } + /** * If the enemy has a trainer, decide whether or not the enemy should switch * to another member in its party. diff --git a/src/phases/move-effect-phase.ts b/src/phases/move-effect-phase.ts index 62ece3769b5..48150ffaf05 100644 --- a/src/phases/move-effect-phase.ts +++ b/src/phases/move-effect-phase.ts @@ -211,11 +211,14 @@ export class MoveEffectPhase extends PokemonPhase { && (target.getAbility()?.getAttrs(TypeImmunityAbAttr)?.[0]?.getImmuneType() === user.getMoveType(move)) && !target.getTag(SemiInvulnerableTag); + /** Is the target hidden by the effects of its Commander ability? */ + const isCommanding = this.scene.currentBattle.double && target.getAlly()?.getTag(BattlerTagType.COMMANDED)?.getSourcePokemon(this.scene) === target; + /** * If the move missed a target, stop all future hits against that target * and move on to the next target (if there is one). */ - if (!isImmune && !isProtected && !targetHitChecks[target.getBattlerIndex()]) { + if (isCommanding || (!isImmune && !isProtected && !targetHitChecks[target.getBattlerIndex()])) { this.stopMultiHit(target); this.scene.queueMessage(i18next.t("battle:attackMissed", { pokemonNameWithAffix: getPokemonNameWithAffix(target) })); if (moveHistoryEntry.result === MoveResult.PENDING) { diff --git a/src/phases/mystery-encounter-phases.ts b/src/phases/mystery-encounter-phases.ts index e7d1f7e9074..2d1c3c4ae31 100644 --- a/src/phases/mystery-encounter-phases.ts +++ b/src/phases/mystery-encounter-phases.ts @@ -417,6 +417,7 @@ export class MysteryEncounterBattlePhase extends Phase { } } else { if (availablePartyMembers.length > 1 && availablePartyMembers[1].isOnField()) { + scene.getPlayerField().forEach((pokemon) => pokemon.lapseTag(BattlerTagType.COMMANDED)); scene.pushPhase(new ReturnPhase(scene, 1)); } scene.pushPhase(new ToggleDoublePositionPhase(scene, false)); diff --git a/src/phases/pokemon-anim-phase.ts b/src/phases/pokemon-anim-phase.ts index 26ae11d1026..e9e1129f158 100644 --- a/src/phases/pokemon-anim-phase.ts +++ b/src/phases/pokemon-anim-phase.ts @@ -3,6 +3,7 @@ import { SubstituteTag } from "#app/data/battler-tags"; import { PokemonAnimType } from "#enums/pokemon-anim-type"; import Pokemon from "#app/field/pokemon"; import { BattlePhase } from "#app/phases/battle-phase"; +import { Species } from "#enums/species"; export class PokemonAnimPhase extends BattlePhase { @@ -37,12 +38,18 @@ export class PokemonAnimPhase extends BattlePhase { case PokemonAnimType.SUBSTITUTE_REMOVE: this.doSubstituteRemoveAnim(); break; + case PokemonAnimType.COMMANDER_APPLY: + this.doCommanderApplyAnim(); + break; + case PokemonAnimType.COMMANDER_REMOVE: + this.doCommanderRemoveAnim(); + break; default: this.end(); } } - doSubstituteAddAnim(): void { + private doSubstituteAddAnim(): void { const substitute = this.pokemon.getTag(SubstituteTag); if (substitute === null) { return this.end(); @@ -106,7 +113,7 @@ export class PokemonAnimPhase extends BattlePhase { }); } - doSubstitutePreMoveAnim(): void { + private doSubstitutePreMoveAnim(): void { if (this.fieldAssets.length !== 1) { return this.end(); } @@ -135,7 +142,7 @@ export class PokemonAnimPhase extends BattlePhase { }); } - doSubstitutePostMoveAnim(): void { + private doSubstitutePostMoveAnim(): void { if (this.fieldAssets.length !== 1) { return this.end(); } @@ -164,7 +171,7 @@ export class PokemonAnimPhase extends BattlePhase { }); } - doSubstituteRemoveAnim(): void { + private doSubstituteRemoveAnim(): void { if (this.fieldAssets.length !== 1) { return this.end(); } @@ -233,4 +240,121 @@ export class PokemonAnimPhase extends BattlePhase { } }); } + + private doCommanderApplyAnim(): void { + if (!this.scene.currentBattle?.double) { + return this.end(); + } + const dondozo = this.pokemon.getAlly(); + + if (dondozo?.species?.speciesId !== Species.DONDOZO) { + return this.end(); + } + + const tatsugiriX = this.pokemon.x + this.pokemon.getSprite().x; + const tatsugiriY = this.pokemon.y + this.pokemon.getSprite().y; + + const getSourceSprite = () => { + const sprite = this.scene.addPokemonSprite(this.pokemon, tatsugiriX, tatsugiriY, this.pokemon.getSprite().texture, this.pokemon.getSprite()!.frame.name, true); + [ "spriteColors", "fusionSpriteColors" ].map(k => sprite.pipelineData[k] = this.pokemon.getSprite().pipelineData[k]); + sprite.setPipelineData("spriteKey", this.pokemon.getBattleSpriteKey()); + sprite.setPipelineData("shiny", this.pokemon.shiny); + sprite.setPipelineData("variant", this.pokemon.variant); + sprite.setPipelineData("ignoreFieldPos", true); + sprite.setOrigin(0.5, 1); + this.pokemon.getSprite().on("animationupdate", (_anim, frame) => sprite.setFrame(frame.textureFrame)); + this.scene.field.add(sprite); + return sprite; + }; + + const sourceSprite = getSourceSprite(); + + this.pokemon.setVisible(false); + + const sourceFpOffset = this.pokemon.getFieldPositionOffset(); + const dondozoFpOffset = dondozo.getFieldPositionOffset(); + + this.scene.playSound("se/pb_throw"); + + this.scene.tweens.add({ + targets: sourceSprite, + duration: 375, + scale: 0.5, + x: { value: tatsugiriX + (dondozoFpOffset[0] - sourceFpOffset[0]) / 2, ease: "Linear" }, + y: { value: (this.pokemon.isPlayer() ? 100 : 65) + sourceFpOffset[1], ease: "Sine.easeOut" }, + onComplete: () => { + this.scene.field.bringToTop(dondozo); + this.scene.tweens.add({ + targets: sourceSprite, + duration: 375, + scale: 0.01, + x: { value: dondozo.x, ease: "Linear" }, + y: { value: dondozo.y + dondozo.height / 2, ease: "Sine.easeIn" }, + onComplete: () => { + sourceSprite.destroy(); + this.scene.playSound("battle_anims/PRSFX- Liquidation1.wav"); + this.scene.tweens.add({ + targets: dondozo, + duration: 250, + ease: "Sine.easeInOut", + scale: 0.85, + yoyo: true, + onComplete: () => this.end() + }); + } + }); + } + }); + } + + private doCommanderRemoveAnim(): void { + // Note: unlike the other Commander animation, this is played through the + // Dondozo instead of the Tatsugiri. + const tatsugiri = this.pokemon.getAlly(); + + const tatsuSprite = this.scene.addPokemonSprite( + tatsugiri, + this.pokemon.x + this.pokemon.getSprite().x, + this.pokemon.y + this.pokemon.getSprite().y + this.pokemon.height / 2, + tatsugiri.getSprite().texture, + tatsugiri.getSprite()!.frame.name, + true + ); + [ "spriteColors", "fusionSpriteColors" ].map(k => tatsuSprite.pipelineData[k] = tatsugiri.getSprite().pipelineData[k]); + tatsuSprite.setPipelineData("spriteKey", tatsugiri.getBattleSpriteKey()); + tatsuSprite.setPipelineData("shiny", tatsugiri.shiny); + tatsuSprite.setPipelineData("variant", tatsugiri.variant); + tatsuSprite.setPipelineData("ignoreFieldPos", true); + this.pokemon.getSprite().on("animationupdate", (_anim, frame) => tatsuSprite.setFrame(frame.textureFrame)); + + tatsuSprite.setOrigin(0.5, 1); + tatsuSprite.setScale(0.01); + + this.scene.field.add(tatsuSprite); + this.scene.field.bringToTop(this.pokemon); + tatsuSprite.setVisible(true); + + this.scene.tweens.add({ + targets: this.pokemon, + duration: 250, + ease: "Sine.easeInOut", + scale: 1.15, + yoyo: true, + onComplete: () => { + this.scene.playSound("battle_anims/PRSFX- Liquidation4.wav"); + this.scene.tweens.add({ + targets: tatsuSprite, + duration: 500, + scale: 1, + x: { value: tatsugiri.x + tatsugiri.getSprite().x, ease: "Linear" }, + y: { value: tatsugiri.y + tatsugiri.getSprite().y, ease: "Sine.easeIn" }, + onComplete: () => { + tatsugiri.setVisible(true); + tatsuSprite.destroy(); + this.end(); + } + }); + } + }); + } } diff --git a/src/phases/post-summon-phase.ts b/src/phases/post-summon-phase.ts index 3db98d9926c..644a6235a42 100644 --- a/src/phases/post-summon-phase.ts +++ b/src/phases/post-summon-phase.ts @@ -1,6 +1,6 @@ import BattleScene from "#app/battle-scene"; import { BattlerIndex } from "#app/battle"; -import { applyPostSummonAbAttrs, PostSummonAbAttr } from "#app/data/ability"; +import { applyAbAttrs, applyPostSummonAbAttrs, CommanderAbAttr, PostSummonAbAttr } from "#app/data/ability"; import { ArenaTrapTag } from "#app/data/arena-tag"; import { StatusEffect } from "#app/enums/status-effect"; import { PokemonPhase } from "./pokemon-phase"; @@ -28,5 +28,8 @@ export class PostSummonPhase extends PokemonPhase { } applyPostSummonAbAttrs(PostSummonAbAttr, pokemon).then(() => this.end()); + + const field = pokemon.isPlayer() ? this.scene.getPlayerField() : this.scene.getEnemyField(); + field.forEach((p) => applyAbAttrs(CommanderAbAttr, p, null, false)); } } diff --git a/src/test/abilities/commander.test.ts b/src/test/abilities/commander.test.ts new file mode 100644 index 00000000000..99b3d50797c --- /dev/null +++ b/src/test/abilities/commander.test.ts @@ -0,0 +1,224 @@ +import { BattlerIndex } from "#app/battle"; +import { BattlerTagType } from "#enums/battler-tag-type"; +import { PokemonAnimType } from "#enums/pokemon-anim-type"; +import { EffectiveStat, Stat } from "#enums/stat"; +import { StatusEffect } from "#enums/status-effect"; +import { WeatherType } from "#enums/weather-type"; +import { MoveResult } from "#app/field/pokemon"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; + +describe("Abilities - Commander", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .startingLevel(100) + .enemyLevel(100) + .moveset([ Moves.LIQUIDATION, Moves.MEMENTO, Moves.SPLASH, Moves.FLIP_TURN ]) + .ability(Abilities.COMMANDER) + .battleType("double") + .disableCrits() + .enemySpecies(Species.SNORLAX) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.TACKLE); + + vi.spyOn(game.scene, "triggerPokemonBattleAnim").mockReturnValue(true); + }); + + it("causes the source to jump into Dondozo's mouth, granting a stat boost and hiding the source", async () => { + await game.classicMode.startBattle([ Species.TATSUGIRI, Species.DONDOZO ]); + + const [ tatsugiri, dondozo ] = game.scene.getPlayerField(); + + const affectedStats: EffectiveStat[] = [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD ]; + + expect(game.scene.triggerPokemonBattleAnim).toHaveBeenLastCalledWith(tatsugiri, PokemonAnimType.COMMANDER_APPLY); + expect(dondozo.getTag(BattlerTagType.COMMANDED)).toBeDefined(); + affectedStats.forEach((stat) => expect(dondozo.getStatStage(stat)).toBe(2)); + + game.move.select(Moves.SPLASH, 1); + + expect(game.scene.currentBattle.turnCommands[0]?.skip).toBeTruthy(); + + // Force both enemies to target the Tatsugiri + await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); + await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); + + await game.phaseInterceptor.to("BerryPhase", false); + game.scene.getEnemyField().forEach(enemy => expect(enemy.getLastXMoves(1)[0].result).toBe(MoveResult.MISS)); + expect(tatsugiri.isFullHp()).toBeTruthy(); + }); + + it("should activate when a Dondozo switches in and cancel the source's move", async () => { + game.override.enemyMoveset(Moves.SPLASH); + + await game.classicMode.startBattle([ Species.TATSUGIRI, Species.MAGIKARP, Species.DONDOZO ]); + + const tatsugiri = game.scene.getPlayerField()[0]; + + game.move.select(Moves.LIQUIDATION, 0, BattlerIndex.ENEMY); + game.doSwitchPokemon(2); + + await game.phaseInterceptor.to("MovePhase", false); + expect(game.scene.triggerPokemonBattleAnim).toHaveBeenCalledWith(tatsugiri, PokemonAnimType.COMMANDER_APPLY); + + const dondozo = game.scene.getPlayerField()[1]; + expect(dondozo.getTag(BattlerTagType.COMMANDED)).toBeDefined(); + + await game.phaseInterceptor.to("BerryPhase", false); + expect(tatsugiri.getMoveHistory()).toHaveLength(0); + expect(game.scene.getEnemyField()[0].isFullHp()).toBeTruthy(); + }); + + it("source should reenter the field when Dondozo faints", async () => { + await game.classicMode.startBattle([ Species.TATSUGIRI, Species.DONDOZO ]); + + const [ tatsugiri, dondozo ] = game.scene.getPlayerField(); + + expect(game.scene.triggerPokemonBattleAnim).toHaveBeenLastCalledWith(tatsugiri, PokemonAnimType.COMMANDER_APPLY); + expect(dondozo.getTag(BattlerTagType.COMMANDED)).toBeDefined(); + + game.move.select(Moves.MEMENTO, 1, BattlerIndex.ENEMY); + + expect(game.scene.currentBattle.turnCommands[0]?.skip).toBeTruthy(); + + await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); + await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); + + await game.setTurnOrder([ BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER ]); + + await game.phaseInterceptor.to("FaintPhase", false); + expect(dondozo.getTag(BattlerTagType.COMMANDED)).toBeUndefined(); + expect(game.scene.triggerPokemonBattleAnim).toHaveBeenLastCalledWith(dondozo, PokemonAnimType.COMMANDER_REMOVE); + + await game.phaseInterceptor.to("BerryPhase", false); + expect(tatsugiri.isFullHp()).toBeFalsy(); + }); + + it("source should still take damage from Poison while hidden", async () => { + game.override + .statusEffect(StatusEffect.POISON) + .enemyMoveset(Moves.SPLASH); + + await game.classicMode.startBattle([ Species.TATSUGIRI, Species.DONDOZO ]); + + const [ tatsugiri, dondozo ] = game.scene.getPlayerField(); + + expect(game.scene.triggerPokemonBattleAnim).toHaveBeenLastCalledWith(tatsugiri, PokemonAnimType.COMMANDER_APPLY); + expect(dondozo.getTag(BattlerTagType.COMMANDED)).toBeDefined(); + + game.move.select(Moves.SPLASH, 1); + + expect(game.scene.currentBattle.turnCommands[0]?.skip).toBeTruthy(); + + await game.phaseInterceptor.to("TurnEndPhase"); + expect(tatsugiri.isFullHp()).toBeFalsy(); + }); + + it("source should still take damage from Salt Cure while hidden", async () => { + game.override.enemyMoveset(Moves.SPLASH); + + await game.classicMode.startBattle([ Species.TATSUGIRI, Species.DONDOZO ]); + + const [ tatsugiri, dondozo ] = game.scene.getPlayerField(); + + expect(game.scene.triggerPokemonBattleAnim).toHaveBeenLastCalledWith(tatsugiri, PokemonAnimType.COMMANDER_APPLY); + expect(dondozo.getTag(BattlerTagType.COMMANDED)).toBeDefined(); + + tatsugiri.addTag(BattlerTagType.SALT_CURED, 0, Moves.NONE, game.scene.getField()[BattlerIndex.ENEMY].id); + + game.move.select(Moves.SPLASH, 1); + + expect(game.scene.currentBattle.turnCommands[0]?.skip).toBeTruthy(); + + await game.phaseInterceptor.to("TurnEndPhase"); + expect(tatsugiri.isFullHp()).toBeFalsy(); + }); + + it("source should still take damage from Sandstorm while hidden", async () => { + game.override + .weather(WeatherType.SANDSTORM) + .enemyMoveset(Moves.SPLASH); + + await game.classicMode.startBattle([ Species.TATSUGIRI, Species.DONDOZO ]); + + const [ tatsugiri, dondozo ] = game.scene.getPlayerField(); + + expect(game.scene.triggerPokemonBattleAnim).toHaveBeenLastCalledWith(tatsugiri, PokemonAnimType.COMMANDER_APPLY); + expect(dondozo.getTag(BattlerTagType.COMMANDED)).toBeDefined(); + + game.move.select(Moves.SPLASH, 1); + + expect(game.scene.currentBattle.turnCommands[0]?.skip).toBeTruthy(); + + await game.phaseInterceptor.to("TurnEndPhase"); + expect(tatsugiri.isFullHp()).toBeFalsy(); + }); + + it("should make Dondozo immune to being forced out", async () => { + game.override.enemyMoveset([ Moves.SPLASH, Moves.WHIRLWIND ]); + + await game.classicMode.startBattle([ Species.TATSUGIRI, Species.DONDOZO ]); + + const [ tatsugiri, dondozo ] = game.scene.getPlayerField(); + + expect(game.scene.triggerPokemonBattleAnim).toHaveBeenLastCalledWith(tatsugiri, PokemonAnimType.COMMANDER_APPLY); + expect(dondozo.getTag(BattlerTagType.COMMANDED)).toBeDefined(); + + game.move.select(Moves.SPLASH, 1); + + expect(game.scene.currentBattle.turnCommands[0]?.skip).toBeTruthy(); + + await game.forceEnemyMove(Moves.WHIRLWIND, BattlerIndex.PLAYER_2); + await game.forceEnemyMove(Moves.SPLASH); + + // Test may time out here if Whirlwind forced out a Pokemon + await game.phaseInterceptor.to("TurnEndPhase"); + expect(dondozo.isActive(true)).toBeTruthy(); + }); + + it("should interrupt the source's semi-invulnerability", async () => { + game.override + .moveset([ Moves.SPLASH, Moves.DIVE ]) + .enemyMoveset(Moves.SPLASH); + + await game.classicMode.startBattle([ Species.TATSUGIRI, Species.MAGIKARP, Species.DONDOZO ]); + + const tatsugiri = game.scene.getPlayerField()[0]; + + game.move.select(Moves.DIVE, 0, BattlerIndex.ENEMY); + game.move.select(Moves.SPLASH, 1); + + await game.phaseInterceptor.to("CommandPhase"); + await game.toNextTurn(); + + expect(tatsugiri.getTag(BattlerTagType.UNDERWATER)).toBeDefined(); + game.doSwitchPokemon(2); + + await game.phaseInterceptor.to("MovePhase", false); + const dondozo = game.scene.getPlayerField()[1]; + expect(tatsugiri.getTag(BattlerTagType.UNDERWATER)).toBeUndefined(); + expect(dondozo.getTag(BattlerTagType.COMMANDED)).toBeDefined(); + + await game.toNextTurn(); + const enemy = game.scene.getEnemyField()[0]; + expect(enemy.isFullHp()).toBeTruthy(); + }); +}); diff --git a/src/test/moves/order_up.test.ts b/src/test/moves/order_up.test.ts new file mode 100644 index 00000000000..d0b52dc1a9d --- /dev/null +++ b/src/test/moves/order_up.test.ts @@ -0,0 +1,85 @@ +import { BattlerIndex } from "#app/battle"; +import { BattlerTagType } from "#enums/battler-tag-type"; +import { PokemonAnimType } from "#enums/pokemon-anim-type"; +import { EffectiveStat, Stat } from "#enums/stat"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; + +describe("Moves - Order Up", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset(Moves.ORDER_UP) + .ability(Abilities.COMMANDER) + .battleType("double") + .disableCrits() + .enemySpecies(Species.SNORLAX) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH) + .startingLevel(100) + .enemyLevel(100); + + vi.spyOn(game.scene, "triggerPokemonBattleAnim").mockReturnValue(true); + }); + + it.each([ + { formIndex: 0, formName: "Curly", stat: Stat.ATK, statName: "Attack" }, + { formIndex: 1, formName: "Droopy", stat: Stat.DEF, statName: "Defense" }, + { formIndex: 2, formName: "Stretchy", stat: Stat.SPD, statName: "Speed" } + ])("should raise the user's $statName when the user is commanded by a $formName Tatsugiri", async ({ formIndex, stat }) => { + game.override.starterForms({ [Species.TATSUGIRI]: formIndex }); + + await game.classicMode.startBattle([ Species.TATSUGIRI, Species.DONDOZO ]); + + const [ tatsugiri, dondozo ] = game.scene.getPlayerField(); + + expect(game.scene.triggerPokemonBattleAnim).toHaveBeenLastCalledWith(tatsugiri, PokemonAnimType.COMMANDER_APPLY); + expect(dondozo.getTag(BattlerTagType.COMMANDED)).toBeDefined(); + + game.move.select(Moves.ORDER_UP, 1, BattlerIndex.ENEMY); + expect(game.scene.currentBattle.turnCommands[0]?.skip).toBeTruthy(); + + await game.phaseInterceptor.to("BerryPhase", false); + + const affectedStats: EffectiveStat[] = [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD ]; + affectedStats.forEach(st => expect(dondozo.getStatStage(st)).toBe(st === stat ? 3 : 2)); + }); + + it("should be boosted by Sheer Force while still applying a stat boost", async () => { + game.override + .passiveAbility(Abilities.SHEER_FORCE) + .starterForms({ [Species.TATSUGIRI]: 0 }); + + await game.classicMode.startBattle([ Species.TATSUGIRI, Species.DONDOZO ]); + + const [ tatsugiri, dondozo ] = game.scene.getPlayerField(); + + expect(game.scene.triggerPokemonBattleAnim).toHaveBeenLastCalledWith(tatsugiri, PokemonAnimType.COMMANDER_APPLY); + expect(dondozo.getTag(BattlerTagType.COMMANDED)).toBeDefined(); + + game.move.select(Moves.ORDER_UP, 1, BattlerIndex.ENEMY); + expect(game.scene.currentBattle.turnCommands[0]?.skip).toBeTruthy(); + + await game.phaseInterceptor.to("BerryPhase", false); + + expect(dondozo.battleData.abilitiesApplied.includes(Abilities.SHEER_FORCE)).toBeTruthy(); + expect(dondozo.getStatStage(Stat.ATK)).toBe(3); + }); +}); From 198d3ce2a6bce6d25748bd961b7cab1659b78d27 Mon Sep 17 00:00:00 2001 From: geeilhan <107366005+geeilhan@users.noreply.github.com> Date: Tue, 5 Nov 2024 18:37:47 +0100 Subject: [PATCH 07/75] [P2] Fixing Incorrect Freeze Dry Interaction With Soaked Wonder Guard Target (#4798) * [Bug] fixed interaction between freeze dry and soaked wonder guard target * added automated test for freeze dry interaction with soaked wonder guard target * using parameter instead of function to get typeMultiplier --- src/data/ability.ts | 6 +++++- src/test/moves/freeze_dry.test.ts | 25 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index 7d54459d7d4..6a3e8da3cd4 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -512,7 +512,11 @@ export class NonSuperEffectiveImmunityAbAttr extends TypeImmunityAbAttr { } applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { - if (move instanceof AttackMove && pokemon.getAttackTypeEffectiveness(attacker.getMoveType(move), attacker) < 2) { + const modifierValue = args.length > 0 + ? (args[0] as Utils.NumberHolder).value + : pokemon.getAttackTypeEffectiveness(attacker.getMoveType(move), attacker); + + if (move instanceof AttackMove && modifierValue < 2) { cancelled.value = true; // Suppresses "No Effect" message (args[0] as Utils.NumberHolder).value = 0; return true; diff --git a/src/test/moves/freeze_dry.test.ts b/src/test/moves/freeze_dry.test.ts index c09d12fa597..f766ed41a82 100644 --- a/src/test/moves/freeze_dry.test.ts +++ b/src/test/moves/freeze_dry.test.ts @@ -72,6 +72,31 @@ describe("Moves - Freeze-Dry", () => { expect(enemy.getMoveEffectiveness).toHaveReturnedWith(1); }); + /** + * Freeze drys forced super effectiveness should overwrite wonder guard + */ + it("should deal 2x dmg against soaked wonder guard target", async () => { + game.override + .enemySpecies(Species.SHEDINJA) + .enemyMoveset(Moves.SPLASH) + .starterSpecies(Species.MAGIKARP) + .moveset([ Moves.SOAK, Moves.FREEZE_DRY ]); + await game.classicMode.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + vi.spyOn(enemy, "getMoveEffectiveness"); + + game.move.select(Moves.SOAK); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await game.toNextTurn(); + + game.move.select(Moves.FREEZE_DRY); + await game.phaseInterceptor.to("MoveEffectPhase"); + + expect(enemy.getMoveEffectiveness).toHaveReturnedWith(2); + expect(enemy.hp).toBeLessThan(enemy.getMaxHp()); + }); + // enable if this is ever fixed (lol) it.todo("should deal 2x damage to water types under Normalize", async () => { game.override.ability(Abilities.NORMALIZE); From b79b643b317e898b35b84c2e368b24d22f865346 Mon Sep 17 00:00:00 2001 From: Moka <54149968+MokaStitcher@users.noreply.github.com> Date: Tue, 5 Nov 2024 18:42:04 +0100 Subject: [PATCH 08/75] [P2][ME] Fix GTS not getting proper item tier when trading items (#4802) --- .../encounters/global-trade-system-encounter.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts b/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts index 90f6ee942be..720e904ecdb 100644 --- a/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts +++ b/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts @@ -367,10 +367,11 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = }) .withOptionPhase(async (scene: BattleScene) => { const encounter = scene.currentBattle.mysteryEncounter!; - const modifier = encounter.misc.chosenModifier; + const modifier = encounter.misc.chosenModifier as PokemonHeldItemModifier; + const party = scene.getPlayerParty(); // Check tier of the traded item, the received item will be one tier up - const type = modifier.type.withTierFromPool(); + const type = modifier.type.withTierFromPool(ModifierPoolType.PLAYER, party); let tier = type.tier ?? ModifierTier.GREAT; // Eggs and White Herb are not in the pool if (type.id === "WHITE_HERB") { @@ -385,11 +386,11 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = tier++; } - regenerateModifierPoolThresholds(scene.getPlayerParty(), ModifierPoolType.PLAYER, 0); + regenerateModifierPoolThresholds(party, ModifierPoolType.PLAYER, 0); let item: ModifierTypeOption | null = null; // TMs excluded from possible rewards while (!item || item.type.id.includes("TM_")) { - item = getPlayerModifierTypeOptions(1, scene.getPlayerParty(), [], { guaranteedModifierTiers: [ tier ], allowLuckUpgrades: false })[0]; + item = getPlayerModifierTypeOptions(1, party, [], { guaranteedModifierTiers: [ tier ], allowLuckUpgrades: false })[0]; } encounter.setDialogueToken("itemName", item.type.name); From eb32545772da2d6a0cf133989ff1424cf1527a4d Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Tue, 5 Nov 2024 11:23:22 -0800 Subject: [PATCH 09/75] [Balance][Beta] Commander now increases double battle chance (#4803) --- src/data/ability.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/data/ability.ts b/src/data/ability.ts index 6a3e8da3cd4..4752217da19 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -6285,6 +6285,7 @@ export function initAbilities() { .bypassFaint(), new Ability(Abilities.COMMANDER, 9) .attr(CommanderAbAttr) + .attr(DoubleBattleChanceAbAttr) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) .edgeCase(), // Encore, Frenzy, and other non-`TURN_END` tags don't lapse correctly on the commanding Pokemon. From 4f733796c5394c8060f8736b065d5929162384f6 Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Tue, 5 Nov 2024 18:32:07 -0800 Subject: [PATCH 10/75] [Move] Implement Grudge (#4794) * some work * slay dnr * Fixed up move mechanics * bahhh * yawn * updated lapse type to correctness * Test + documentation * yattt * Remove some redundant code * Apply suggestions from code review Co-authored-by: innerthunder <168692175+innerthunder@users.noreply.github.com> * Update battler-tags.ts * Fix `PokemonAnimPhase` --------- Co-authored-by: frutescens Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> Co-authored-by: innerthunder <168692175+innerthunder@users.noreply.github.com> --- src/data/battler-tags.ts | 41 +++++++++++++++ src/data/move.ts | 2 +- src/enums/battler-tag-type.ts | 3 +- src/field/pokemon.ts | 19 +++---- src/phases/faint-phase.ts | 18 +++++-- src/phases/pokemon-anim-phase.ts | 5 +- src/test/moves/grudge.test.ts | 90 ++++++++++++++++++++++++++++++++ 7 files changed, 159 insertions(+), 19 deletions(-) create mode 100644 src/test/moves/grudge.test.ts diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 2012c4330cc..473974048c9 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -2827,6 +2827,45 @@ export class PowerTrickTag extends BattlerTag { } } +/** + * Tag associated with the move Grudge. + * If this tag is active when the bearer faints from an opponent's move, the tag reduces that move's PP to 0. + * Otherwise, it lapses when the bearer makes another move. + */ +export class GrudgeTag extends BattlerTag { + constructor() { + super(BattlerTagType.GRUDGE, [ BattlerTagLapseType.CUSTOM, BattlerTagLapseType.PRE_MOVE ], 1, Moves.GRUDGE); + } + + onAdd(pokemon: Pokemon) { + super.onAdd(pokemon); + pokemon.scene.queueMessage(i18next.t("battlerTags:grudgeOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })); + } + + /** + * Activates Grudge's special effect on the attacking Pokemon and lapses the tag. + * @param pokemon + * @param lapseType + * @param sourcePokemon {@linkcode Pokemon} the source of the move that fainted the tag's bearer + * @returns `false` if Grudge activates its effect or lapses + */ + override lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType, sourcePokemon?: Pokemon): boolean { + if (lapseType === BattlerTagLapseType.CUSTOM && sourcePokemon) { + if (sourcePokemon.isActive() && pokemon.isOpponent(sourcePokemon)) { + const lastMove = pokemon.turnData.attacksReceived[0]; + const lastMoveData = sourcePokemon.getMoveset().find(m => m?.moveId === lastMove.move); + if (lastMoveData && lastMove.move !== Moves.STRUGGLE) { + lastMoveData.ppUsed = lastMoveData.getMovePp(); + pokemon.scene.queueMessage(i18next.t("battlerTags:grudgeLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: lastMoveData.getName() })); + } + } + return false; + } else { + return super.lapse(pokemon, lapseType); + } + } +} + /** * Retrieves a {@linkcode BattlerTag} based on the provided tag type, turn count, source move, and source ID. * @param sourceId - The ID of the pokemon adding the tag @@ -3008,6 +3047,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source return new TelekinesisTag(sourceMove); case BattlerTagType.POWER_TRICK: return new PowerTrickTag(sourceMove, sourceId); + case BattlerTagType.GRUDGE: + return new GrudgeTag(); case BattlerTagType.NONE: default: return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId); diff --git a/src/data/move.ts b/src/data/move.ts index c97749e0357..fb09d822a1d 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -8489,7 +8489,7 @@ export function initMoves() { .attr(HealStatusEffectAttr, true, StatusEffect.PARALYSIS, StatusEffect.POISON, StatusEffect.TOXIC, StatusEffect.BURN) .condition((user, target, move) => !!user.status && (user.status.effect === StatusEffect.PARALYSIS || user.status.effect === StatusEffect.POISON || user.status.effect === StatusEffect.TOXIC || user.status.effect === StatusEffect.BURN)), new SelfStatusMove(Moves.GRUDGE, Type.GHOST, -1, 5, -1, 0, 3) - .unimplemented(), + .attr(AddBattlerTagAttr, BattlerTagType.GRUDGE, true, undefined, 1), new SelfStatusMove(Moves.SNATCH, Type.DARK, -1, 10, -1, 4, 3) .unimplemented(), new AttackMove(Moves.SECRET_POWER, Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 20, 30, 0, 3) diff --git a/src/enums/battler-tag-type.ts b/src/enums/battler-tag-type.ts index c53157c68d4..660a47e0d68 100644 --- a/src/enums/battler-tag-type.ts +++ b/src/enums/battler-tag-type.ts @@ -89,5 +89,6 @@ export enum BattlerTagType { SYRUP_BOMB = "SYRUP_BOMB", ELECTRIFIED = "ELECTRIFIED", TELEKINESIS = "TELEKINESIS", - COMMANDED = "COMMANDED" + COMMANDED = "COMMANDED", + GRUDGE = "GRUDGE" } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 77881d36c56..25a771c9281 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -7,7 +7,7 @@ import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, Varia import { default as PokemonSpecies, PokemonSpeciesForm, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species"; import { CLASSIC_CANDY_FRIENDSHIP_MULTIPLIER, getStarterValueFriendshipCap, speciesStarterCosts } from "#app/data/balance/starters"; import { starterPassiveAbilities } from "#app/data/balance/passives"; -import { Constructor, isNullOrUndefined, randSeedInt } from "#app/utils"; +import { Constructor, isNullOrUndefined, randSeedInt, type nil } from "#app/utils"; import * as Utils from "#app/utils"; import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from "#app/data/type"; import { getLevelTotalExp } from "#app/data/exp"; @@ -2841,6 +2841,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { // In case of fatal damage, this tag would have gotten cleared before we could lapse it. const destinyTag = this.getTag(BattlerTagType.DESTINY_BOND); + const grudgeTag = this.getTag(BattlerTagType.GRUDGE); const isOneHitKo = result === HitResult.ONE_HIT_KO; @@ -2912,12 +2913,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (this.isFainted()) { // set splice index here, so future scene queues happen before FaintedPhase this.scene.setPhaseQueueSplice(); - if (!isNullOrUndefined(destinyTag) && dmg) { - // Destiny Bond will activate during FaintPhase - this.scene.unshiftPhase(new FaintPhase(this.scene, this.getBattlerIndex(), isOneHitKo, destinyTag, source)); - } else { - this.scene.unshiftPhase(new FaintPhase(this.scene, this.getBattlerIndex(), isOneHitKo)); - } + this.scene.unshiftPhase(new FaintPhase(this.scene, this.getBattlerIndex(), isOneHitKo, destinyTag, grudgeTag, source)); + this.destroySubstitute(); this.lapseTag(BattlerTagType.COMMANDED); this.resetSummonData(); @@ -3051,19 +3048,19 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } /** @overload */ - getTag(tagType: BattlerTagType): BattlerTag | null; + getTag(tagType: BattlerTagType): BattlerTag | nil; /** @overload */ - getTag(tagType: Constructor): T | null; + getTag(tagType: Constructor): T | nil; - getTag(tagType: BattlerTagType | Constructor): BattlerTag | null { + getTag(tagType: BattlerTagType | Constructor): BattlerTag | nil { if (!this.summonData) { return null; } return (tagType instanceof Function ? this.summonData.tags.find(t => t instanceof tagType) : this.summonData.tags.find(t => t.tagType === tagType) - )!; // TODO: is this bang correct? + ); } findTag(tagFilter: ((tag: BattlerTag) => boolean)) { diff --git a/src/phases/faint-phase.ts b/src/phases/faint-phase.ts index 3e90233a38c..d66c5b66144 100644 --- a/src/phases/faint-phase.ts +++ b/src/phases/faint-phase.ts @@ -1,7 +1,7 @@ import { BattlerIndex, BattleType } from "#app/battle"; import BattleScene from "#app/battle-scene"; import { applyPostFaintAbAttrs, applyPostKnockOutAbAttrs, applyPostVictoryAbAttrs, PostFaintAbAttr, PostKnockOutAbAttr, PostVictoryAbAttr } from "#app/data/ability"; -import { BattlerTagLapseType, DestinyBondTag } from "#app/data/battler-tags"; +import { BattlerTagLapseType, DestinyBondTag, GrudgeTag } from "#app/data/battler-tags"; import { battleSpecDialogue } from "#app/data/dialogue"; import { allMoves, PostVictoryStatStageChangeAttr } from "#app/data/move"; import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms"; @@ -31,18 +31,24 @@ export class FaintPhase extends PokemonPhase { /** * Destiny Bond tag belonging to the currently fainting Pokemon, if applicable */ - private destinyTag?: DestinyBondTag; + private destinyTag?: DestinyBondTag | null; /** - * The source Pokemon that dealt fatal damage and should get KO'd by Destiny Bond, if applicable + * Grudge tag belonging to the currently fainting Pokemon, if applicable + */ + private grudgeTag?: GrudgeTag | null; + + /** + * The source Pokemon that dealt fatal damage */ private source?: Pokemon; - constructor(scene: BattleScene, battlerIndex: BattlerIndex, preventEndure: boolean = false, destinyTag?: DestinyBondTag, source?: Pokemon) { + constructor(scene: BattleScene, battlerIndex: BattlerIndex, preventEndure: boolean = false, destinyTag?: DestinyBondTag | null, grudgeTag?: GrudgeTag | null, source?: Pokemon) { super(scene, battlerIndex); this.preventEndure = preventEndure; this.destinyTag = destinyTag; + this.grudgeTag = grudgeTag; this.source = source; } @@ -53,6 +59,10 @@ export class FaintPhase extends PokemonPhase { this.destinyTag.lapse(this.source, BattlerTagLapseType.CUSTOM); } + if (!isNullOrUndefined(this.grudgeTag) && !isNullOrUndefined(this.source)) { + this.grudgeTag.lapse(this.getPokemon(), BattlerTagLapseType.CUSTOM, this.source); + } + if (!this.preventEndure) { const instantReviveModifier = this.scene.applyModifier(PokemonInstantReviveModifier, this.player, this.getPokemon()) as PokemonInstantReviveModifier; diff --git a/src/phases/pokemon-anim-phase.ts b/src/phases/pokemon-anim-phase.ts index e9e1129f158..ad0be34af7d 100644 --- a/src/phases/pokemon-anim-phase.ts +++ b/src/phases/pokemon-anim-phase.ts @@ -1,8 +1,9 @@ import BattleScene from "#app/battle-scene"; import { SubstituteTag } from "#app/data/battler-tags"; -import { PokemonAnimType } from "#enums/pokemon-anim-type"; import Pokemon from "#app/field/pokemon"; import { BattlePhase } from "#app/phases/battle-phase"; +import { isNullOrUndefined } from "#app/utils"; +import { PokemonAnimType } from "#enums/pokemon-anim-type"; import { Species } from "#enums/species"; @@ -51,7 +52,7 @@ export class PokemonAnimPhase extends BattlePhase { private doSubstituteAddAnim(): void { const substitute = this.pokemon.getTag(SubstituteTag); - if (substitute === null) { + if (isNullOrUndefined(substitute)) { return this.end(); } diff --git a/src/test/moves/grudge.test.ts b/src/test/moves/grudge.test.ts new file mode 100644 index 00000000000..340808929ab --- /dev/null +++ b/src/test/moves/grudge.test.ts @@ -0,0 +1,90 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import { BattlerIndex } from "#app/battle"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Moves - Grudge", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([ Moves.EMBER, Moves.SPLASH ]) + .ability(Abilities.BALL_FETCH) + .battleType("single") + .disableCrits() + .enemySpecies(Species.SHEDINJA) + .enemyAbility(Abilities.WONDER_GUARD) + .enemyMoveset([ Moves.GRUDGE, Moves.SPLASH ]); + }); + + it("should reduce the PP of the Pokemon's move to 0 when the user has fainted", async () => { + await game.classicMode.startBattle([ Species.FEEBAS ]); + + const playerPokemon = game.scene.getPlayerPokemon(); + game.move.select(Moves.EMBER); + await game.forceEnemyMove(Moves.GRUDGE); + await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]); + await game.phaseInterceptor.to("BerryPhase"); + + const playerMove = playerPokemon?.getMoveset().find(m => m?.moveId === Moves.EMBER); + + expect(playerMove?.getPpRatio()).toBe(0); + }); + + it("should remain in effect until the user's next move", async () => { + await game.classicMode.startBattle([ Species.FEEBAS ]); + + const playerPokemon = game.scene.getPlayerPokemon(); + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.GRUDGE); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await game.toNextTurn(); + + game.move.select(Moves.EMBER); + await game.forceEnemyMove(Moves.SPLASH); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await game.phaseInterceptor.to("BerryPhase"); + + const playerMove = playerPokemon?.getMoveset().find(m => m?.moveId === Moves.EMBER); + + expect(playerMove?.getPpRatio()).toBe(0); + }); + + it("should not reduce the opponent's PP if the user dies to weather/indirect damage", async () => { + // Opponent will be reduced to 1 HP by False Swipe, then faint to Sandstorm + game.override + .moveset([ Moves.FALSE_SWIPE ]) + .startingLevel(100) + .ability(Abilities.SAND_STREAM) + .enemySpecies(Species.RATTATA); + await game.classicMode.startBattle([ Species.GEODUDE ]); + + const enemyPokemon = game.scene.getEnemyPokemon(); + const playerPokemon = game.scene.getPlayerPokemon(); + + game.move.select(Moves.FALSE_SWIPE); + await game.forceEnemyMove(Moves.GRUDGE); + await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemyPokemon?.isFainted()).toBe(true); + + const playerMove = playerPokemon?.getMoveset().find(m => m?.moveId === Moves.FALSE_SWIPE); + expect(playerMove?.getPpRatio()).toBeGreaterThan(0); + }); +}); From 6b7efb444b4b774fdb0dc892caa3f9e4b22967ae Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Wed, 6 Nov 2024 08:29:24 -0800 Subject: [PATCH 11/75] [Ability] Fully implement Synchronize (#4785) Co-authored-by: frutescens Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/data/ability.ts | 5 ++- src/data/battler-tags.ts | 26 +++++++++++++- src/data/move.ts | 20 ++++++----- src/enums/battler-tag-type.ts | 3 +- src/test/abilities/corrosion.test.ts | 46 ++++++++++++++++++++++++ src/test/abilities/synchronize.test.ts | 12 ------- src/test/moves/psycho_shift.test.ts | 49 ++++++++++++++++++++++++++ 7 files changed, 135 insertions(+), 26 deletions(-) create mode 100644 src/test/abilities/corrosion.test.ts create mode 100644 src/test/moves/psycho_shift.test.ts diff --git a/src/data/ability.ts b/src/data/ability.ts index 4752217da19..2b65ff79d56 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -5433,8 +5433,7 @@ export function initAbilities() { .attr(EffectSporeAbAttr), new Ability(Abilities.SYNCHRONIZE, 3) .attr(SyncEncounterNatureAbAttr) - .attr(SynchronizeStatusAbAttr) - .partial(), // interaction with psycho shift needs work, keeping to old Gen interaction for now + .attr(SynchronizeStatusAbAttr), new Ability(Abilities.CLEAR_BODY, 3) .attr(ProtectStatAbAttr) .ignorable(), @@ -6036,7 +6035,7 @@ export function initAbilities() { .bypassFaint(), new Ability(Abilities.CORROSION, 7) .attr(IgnoreTypeStatusEffectImmunityAbAttr, [ StatusEffect.POISON, StatusEffect.TOXIC ], [ Type.STEEL, Type.POISON ]) - .edgeCase(), // Should interact correctly with magic coat/bounce (not yet implemented), fling with toxic orb (not implemented yet), and synchronize (not fully implemented yet) + .edgeCase(), // Should interact correctly with magic coat/bounce (not yet implemented) + fling with toxic orb (not implemented yet) new Ability(Abilities.COMATOSE, 7) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 473974048c9..ebbab7bfa4a 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -18,7 +18,7 @@ import Move, { StatusCategoryOnAllyAttr } from "#app/data/move"; import { SpeciesFormChangeManualTrigger } from "#app/data/pokemon-forms"; -import { StatusEffect } from "#app/data/status-effect"; +import { getStatusEffectHealText, StatusEffect } from "#app/data/status-effect"; import { TerrainType } from "#app/data/terrain"; import { Type } from "#app/data/type"; import { WeatherType } from "#app/data/weather"; @@ -2866,6 +2866,28 @@ export class GrudgeTag extends BattlerTag { } } +/** + * Tag used to heal the user of Psycho Shift of its status effect if Psycho Shift succeeds in transferring its status effect to the target Pokemon + */ +export class PsychoShiftTag extends BattlerTag { + constructor() { + super(BattlerTagType.PSYCHO_SHIFT, BattlerTagLapseType.AFTER_MOVE, 1, Moves.PSYCHO_SHIFT); + } + + /** + * Heals Psycho Shift's user of its status effect after it uses a move + * @returns `false` to expire the tag immediately + */ + override lapse(pokemon: Pokemon, _lapseType: BattlerTagLapseType): boolean { + if (pokemon.status && pokemon.isActive(true)) { + pokemon.scene.queueMessage(getStatusEffectHealText(pokemon.status.effect, getPokemonNameWithAffix(pokemon))); + pokemon.resetStatus(); + pokemon.updateInfo(); + } + return false; + } +} + /** * Retrieves a {@linkcode BattlerTag} based on the provided tag type, turn count, source move, and source ID. * @param sourceId - The ID of the pokemon adding the tag @@ -3049,6 +3071,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source return new PowerTrickTag(sourceMove, sourceId); case BattlerTagType.GRUDGE: return new GrudgeTag(); + case BattlerTagType.PSYCHO_SHIFT: + return new PsychoShiftTag(); case BattlerTagType.NONE: default: return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId); diff --git a/src/data/move.ts b/src/data/move.ts index fb09d822a1d..9964409df7a 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -2270,24 +2270,26 @@ export class PsychoShiftEffectAttr extends MoveEffectAttr { super(false, { trigger: MoveEffectTrigger.HIT }); } - apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + /** + * Applies the effect of Psycho Shift to its target + * Psycho Shift takes the user's status effect and passes it onto the target. The user is then healed after the move has been successfully executed. + * @returns `true` if Psycho Shift's effect is able to be applied to the target + */ + apply(user: Pokemon, target: Pokemon, _move: Move, _args: any[]): boolean { const statusToApply: StatusEffect | undefined = user.status?.effect ?? (user.hasAbility(Abilities.COMATOSE) ? StatusEffect.SLEEP : undefined); if (target.status) { return false; } else { const canSetStatus = target.canSetStatus(statusToApply, true, false, user); + const trySetStatus = canSetStatus ? target.trySetStatus(statusToApply, true, user) : false; - if (canSetStatus) { - if (user.status) { - user.scene.queueMessage(getStatusEffectHealText(user.status.effect, getPokemonNameWithAffix(user))); - } - user.resetStatus(); - user.updateInfo(); - target.trySetStatus(statusToApply, true, user); + if (trySetStatus && user.status) { + // PsychoShiftTag is added to the user if move succeeds so that the user is healed of its status effect after its move + user.addTag(BattlerTagType.PSYCHO_SHIFT); } - return canSetStatus; + return trySetStatus; } } diff --git a/src/enums/battler-tag-type.ts b/src/enums/battler-tag-type.ts index 660a47e0d68..b2bbc1e6189 100644 --- a/src/enums/battler-tag-type.ts +++ b/src/enums/battler-tag-type.ts @@ -90,5 +90,6 @@ export enum BattlerTagType { ELECTRIFIED = "ELECTRIFIED", TELEKINESIS = "TELEKINESIS", COMMANDED = "COMMANDED", - GRUDGE = "GRUDGE" + GRUDGE = "GRUDGE", + PSYCHO_SHIFT = "PSYCHO_SHIFT", } diff --git a/src/test/abilities/corrosion.test.ts b/src/test/abilities/corrosion.test.ts new file mode 100644 index 00000000000..e607e85defb --- /dev/null +++ b/src/test/abilities/corrosion.test.ts @@ -0,0 +1,46 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Abilities - Corrosion", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([ Moves.SPLASH ]) + .battleType("single") + .disableCrits() + .enemySpecies(Species.GRIMER) + .enemyAbility(Abilities.CORROSION) + .enemyMoveset(Moves.TOXIC); + }); + + it("If a Poison- or Steel-type Pokémon with this Ability poisons a target with Synchronize, Synchronize does not gain the ability to poison Poison- or Steel-type Pokémon.", async () => { + game.override.ability(Abilities.SYNCHRONIZE); + await game.classicMode.startBattle([ Species.FEEBAS ]); + + const playerPokemon = game.scene.getPlayerPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon(); + expect(playerPokemon!.status).toBeUndefined(); + + game.move.select(Moves.SPLASH); + await game.phaseInterceptor.to("BerryPhase"); + expect(playerPokemon!.status).toBeDefined(); + expect(enemyPokemon!.status).toBeUndefined(); + }); +}); diff --git a/src/test/abilities/synchronize.test.ts b/src/test/abilities/synchronize.test.ts index d34b5631271..f30ab9d3db4 100644 --- a/src/test/abilities/synchronize.test.ts +++ b/src/test/abilities/synchronize.test.ts @@ -94,16 +94,4 @@ describe("Abilities - Synchronize", () => { expect(game.scene.getEnemyPokemon()!.status?.effect).toBe(StatusEffect.PARALYSIS); expect(game.phaseInterceptor.log).toContain("ShowAbilityPhase"); }); - - it("should activate with Psycho Shift after the move clears the status", async () => { - game.override.statusEffect(StatusEffect.PARALYSIS); - await game.classicMode.startBattle(); - - game.move.select(Moves.PSYCHO_SHIFT); - await game.phaseInterceptor.to("BerryPhase"); - - expect(game.scene.getPlayerPokemon()!.status?.effect).toBe(StatusEffect.PARALYSIS); // keeping old gen < V impl for now since it's buggy otherwise - expect(game.scene.getEnemyPokemon()!.status?.effect).toBe(StatusEffect.PARALYSIS); - expect(game.phaseInterceptor.log).toContain("ShowAbilityPhase"); - }); }); diff --git a/src/test/moves/psycho_shift.test.ts b/src/test/moves/psycho_shift.test.ts new file mode 100644 index 00000000000..448a8c99ef0 --- /dev/null +++ b/src/test/moves/psycho_shift.test.ts @@ -0,0 +1,49 @@ +import { StatusEffect } from "#app/enums/status-effect"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Moves - Psycho Shift", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([ Moves.PSYCHO_SHIFT ]) + .ability(Abilities.BALL_FETCH) + .statusEffect(StatusEffect.POISON) + .battleType("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyLevel(20) + .enemyAbility(Abilities.SYNCHRONIZE) + .enemyMoveset(Moves.SPLASH); + }); + + it("If Psycho Shift is used on a Pokémon with Synchronize, the user of Psycho Shift will already be afflicted with a status condition when Synchronize activates", async () => { + await game.classicMode.startBattle([ Species.FEEBAS ]); + + const playerPokemon = game.scene.getPlayerPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon(); + expect(enemyPokemon?.status).toBeUndefined(); + + game.move.select(Moves.PSYCHO_SHIFT); + await game.phaseInterceptor.to("TurnEndPhase"); + expect(playerPokemon?.status).toBeNull(); + expect(enemyPokemon?.status).toBeDefined(); + }); +}); From 9dae28f26413bd2ffb409bec5132c48b2e5ab8ac Mon Sep 17 00:00:00 2001 From: ThePsychedelicSeal <116048497+ThePsychedelicSeal@users.noreply.github.com> Date: Wed, 6 Nov 2024 09:42:39 -0700 Subject: [PATCH 12/75] [Misc] Adding Type, Current HP, Max HP, & Status to updateGameInfo() (#4756) * Adding to window.gameInfo Added type -> not working currentHP -> not working maxHP status * Adding to updateGameInfo() * Update pokemon.ts * Modifying battle-scene.ts Added code to get Form and Tera Type Typo fixed in pokemon.ts * Output type names/etc instead of numbers --------- Co-authored-by: ThePsychedelicSeal Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com> --- src/battle-scene.ts | 20 +++++++++++++++----- src/phases/command-phase.ts | 2 ++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index d17c62c6e0e..d1d520f5f9d 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -38,7 +38,7 @@ import PokemonData from "#app/system/pokemon-data"; import { Nature } from "#app/data/nature"; import { FormChangeItem, pokemonFormChanges, SpeciesFormChange, SpeciesFormChangeManualTrigger, SpeciesFormChangeTimeOfDayTrigger, SpeciesFormChangeTrigger } from "#app/data/pokemon-forms"; import { FormChangePhase } from "#app/phases/form-change-phase"; -import { getTypeRgb } from "#app/data/type"; +import { getTypeRgb, Type } from "#app/data/type"; import PokemonSpriteSparkleHandler from "#app/field/pokemon-sprite-sparkle-handler"; import CharSprite from "#app/ui/char-sprite"; import DamageNumberHandler from "#app/field/damage-number-handler"; @@ -98,6 +98,7 @@ import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; import { ExpGainsSpeed } from "#enums/exp-gains-speed"; import { BattlerTagType } from "#enums/battler-tag-type"; import { FRIENDSHIP_GAIN_FROM_BATTLE } from "#app/data/balance/starters"; +import { StatusEffect } from "#enums/status-effect"; export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1"; @@ -2982,12 +2983,21 @@ export default class BattleScene extends SceneBase { updateGameInfo(): void { const gameInfo = { - playTime: this.sessionPlayTime ? this.sessionPlayTime : 0, + playTime: this.sessionPlayTime ?? 0, gameMode: this.currentBattle ? this.gameMode.getName() : "Title", biome: this.currentBattle ? getBiomeName(this.arena.biomeType) : "", - wave: this.currentBattle?.waveIndex || 0, - party: this.party ? this.party.map(p => { - return { name: p.name, level: p.level }; + wave: this.currentBattle?.waveIndex ?? 0, + party: this.party ? this.party.map((p) => { + return { + name: p.name, + form: p.getFormKey(), + types: p.getTypes().map((type) => Type[type]), + teraType: p.getTeraType() !== Type.UNKNOWN ? Type[p.getTeraType()] : "", + level: p.level, + currentHP: p.hp, + maxHP: p.getMaxHp(), + status: p.status?.effect ? StatusEffect[p.status.effect] : "" + }; }) : [], modeChain: this.ui?.getModeChain() ?? [], }; diff --git a/src/phases/command-phase.ts b/src/phases/command-phase.ts index b99eb8d1b2e..547805ec1d1 100644 --- a/src/phases/command-phase.ts +++ b/src/phases/command-phase.ts @@ -32,6 +32,8 @@ export class CommandPhase extends FieldPhase { start() { super.start(); + this.scene.updateGameInfo(); + const commandUiHandler = this.scene.ui.handlers[Mode.COMMAND]; if (commandUiHandler) { if (this.scene.currentBattle.turn === 1 || commandUiHandler.getCursor() === Command.POKEMON) { From 1f6dab069d01809e5b333a4b9c0986cbd17d94aa Mon Sep 17 00:00:00 2001 From: AJ Fontaine <36677462+Fontbane@users.noreply.github.com> Date: Wed, 6 Nov 2024 21:25:27 -0500 Subject: [PATCH 13/75] [Feature][Balance] Add critical captures, update shake probability to match gen 6 (#4791) * Change shake probability to match Gen 6 * Add critical captures, update shake probability to gen 6 * Change IntegerHolder to NumberHolder * Adjust dex count thresholds for multiplier * Disable critical captures in fresh start runs * Skip first shake check for critical captures * Move shake check for crit captures to after first shake * Use less insane catch formula * Integer to number in bounceanim signature * Use max crit catch dex multiplier in daily runs * Adjust crit capture animation --------- Co-authored-by: innerthunder <168692175+innerthunder@users.noreply.github.com> Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/data/pokeball.ts | 67 ++++++++++++++++++++++++++++- src/phases/attempt-capture-phase.ts | 31 +++++++++---- 2 files changed, 87 insertions(+), 11 deletions(-) diff --git a/src/data/pokeball.ts b/src/data/pokeball.ts index 57a78e2cd61..447095b0468 100644 --- a/src/data/pokeball.ts +++ b/src/data/pokeball.ts @@ -1,3 +1,4 @@ +import { NumberHolder } from "#app/utils"; import { PokeballType } from "#enums/pokeball"; import BattleScene from "../battle-scene"; import i18next from "i18next"; @@ -82,11 +83,38 @@ export function getPokeballTintColor(type: PokeballType): number { } } -export function doPokeballBounceAnim(scene: BattleScene, pokeball: Phaser.GameObjects.Sprite, y1: number, y2: number, baseBounceDuration: integer, callback: Function) { +/** + * Gets the critical capture chance based on number of mons registered in Dex and modified {@link https://bulbapedia.bulbagarden.net/wiki/Catch_rate Catch rate} + * Formula from {@link https://www.dragonflycave.com/mechanics/gen-vi-vii-capturing Dragonfly Cave Gen 6 Capture Mechanics page} + * @param scene {@linkcode BattleScene} current BattleScene + * @param modifiedCatchRate the modified catch rate as calculated in {@linkcode AttemptCapturePhase} + * @returns the chance of getting a critical capture, out of 256 + */ +export function getCriticalCaptureChance(scene: BattleScene, modifiedCatchRate: number): number { + if (scene.gameMode.isFreshStartChallenge()) { + return 0; + } + const dexCount = scene.gameData.getSpeciesCount(d => !!d.caughtAttr); + const catchingCharmMultiplier = new NumberHolder(1); + //scene.findModifier(m => m instanceof CriticalCatchChanceBoosterModifier)?.apply(catchingCharmMultiplier); + const dexMultiplier = scene.gameMode.isDaily || dexCount > 800 ? 2.5 + : dexCount > 600 ? 2 + : dexCount > 400 ? 1.5 + : dexCount > 200 ? 1 + : dexCount > 100 ? 0.5 + : 0; + return Math.floor(catchingCharmMultiplier.value * dexMultiplier * Math.min(255, modifiedCatchRate) / 6); +} + +export function doPokeballBounceAnim(scene: BattleScene, pokeball: Phaser.GameObjects.Sprite, y1: number, y2: number, baseBounceDuration: number, callback: Function, isCritical: boolean = false) { let bouncePower = 1; let bounceYOffset = y1; let bounceY = y2; const yd = y2 - y1; + const x0 = pokeball.x; + const x1 = x0 + 3; + const x2 = x0 - 3; + let critShakes = 4; const doBounce = () => { scene.tweens.add({ @@ -117,5 +145,40 @@ export function doPokeballBounceAnim(scene: BattleScene, pokeball: Phaser.GameOb }); }; - doBounce(); + const doCritShake = () => { + scene.tweens.add({ + targets: pokeball, + x: x2, + duration: 125, + ease: "Linear", + onComplete: () => { + scene.tweens.add({ + targets: pokeball, + x: x1, + duration: 125, + ease: "Linear", + onComplete: () => { + critShakes--; + if (critShakes > 0) { + doCritShake(); + } else { + scene.tweens.add({ + targets: pokeball, + x: x0, + duration: 60, + ease: "Linear", + onComplete: () => scene.time.delayedCall(500, doBounce) + }); + } + } + }); + } + }); + }; + + if (isCritical) { + scene.time.delayedCall(500, doCritShake); + } else { + doBounce(); + } } diff --git a/src/phases/attempt-capture-phase.ts b/src/phases/attempt-capture-phase.ts index 483e6eac943..de10d1eca45 100644 --- a/src/phases/attempt-capture-phase.ts +++ b/src/phases/attempt-capture-phase.ts @@ -2,7 +2,7 @@ import { BattlerIndex } from "#app/battle"; import BattleScene from "#app/battle-scene"; import { PLAYER_PARTY_MAX_SIZE } from "#app/constants"; import { SubstituteTag } from "#app/data/battler-tags"; -import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getPokeballTintColor } from "#app/data/pokeball"; +import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getPokeballTintColor, getCriticalCaptureChance } from "#app/data/pokeball"; import { getStatusEffectCatchRateMultiplier } from "#app/data/status-effect"; import { addPokeballCaptureStars, addPokeballOpenParticles } from "#app/field/anims"; import { EnemyPokemon } from "#app/field/pokemon"; @@ -52,8 +52,10 @@ export class AttemptCapturePhase extends PokemonPhase { const catchRate = pokemon.species.catchRate; const pokeballMultiplier = getPokeballCatchMultiplier(this.pokeballType); const statusMultiplier = pokemon.status ? getStatusEffectCatchRateMultiplier(pokemon.status.effect) : 1; - const x = Math.round((((_3m - _2h) * catchRate * pokeballMultiplier) / _3m) * statusMultiplier); - const y = Math.round(65536 / Math.sqrt(Math.sqrt(255 / x))); + const modifiedCatchRate = Math.round((((_3m - _2h) * catchRate * pokeballMultiplier) / _3m) * statusMultiplier); + const shakeProbability = Math.round(65536 / Math.pow((255 / modifiedCatchRate), 0.1875)); // Formula taken from gen 6 + const criticalCaptureChance = getCriticalCaptureChance(this.scene, modifiedCatchRate); + const isCritical = pokemon.randSeedInt(256) < criticalCaptureChance; const fpOffset = pokemon.getFieldPositionOffset(); const pokeballAtlasKey = getPokeballAtlasKey(this.pokeballType); @@ -61,17 +63,19 @@ export class AttemptCapturePhase extends PokemonPhase { this.pokeball.setOrigin(0.5, 0.625); this.scene.field.add(this.pokeball); - this.scene.playSound("se/pb_throw"); + this.scene.playSound("se/pb_throw", isCritical ? { rate: 0.2 } : undefined); // Crit catch throws are higher pitched this.scene.time.delayedCall(300, () => { this.scene.field.moveBelow(this.pokeball as Phaser.GameObjects.GameObject, pokemon); }); this.scene.tweens.add({ + // Throw animation targets: this.pokeball, x: { value: 236 + fpOffset[0], ease: "Linear" }, y: { value: 16 + fpOffset[1], ease: "Cubic.easeOut" }, duration: 500, onComplete: () => { + // Ball opens this.pokeball.setTexture("pb", `${pokeballAtlasKey}_opening`); this.scene.time.delayedCall(17, () => this.pokeball.setTexture("pb", `${pokeballAtlasKey}_open`)); this.scene.playSound("se/pb_rel"); @@ -80,30 +84,33 @@ export class AttemptCapturePhase extends PokemonPhase { addPokeballOpenParticles(this.scene, this.pokeball.x, this.pokeball.y, this.pokeballType); this.scene.tweens.add({ + // Mon enters ball targets: pokemon, duration: 500, ease: "Sine.easeIn", scale: 0.25, y: 20, onComplete: () => { + // Ball closes this.pokeball.setTexture("pb", `${pokeballAtlasKey}_opening`); pokemon.setVisible(false); this.scene.playSound("se/pb_catch"); this.scene.time.delayedCall(17, () => this.pokeball.setTexture("pb", `${pokeballAtlasKey}`)); const doShake = () => { + // After the overall catch rate check, the game does 3 shake checks before confirming the catch. let shakeCount = 0; const pbX = this.pokeball.x; const shakeCounter = this.scene.tweens.addCounter({ from: 0, to: 1, - repeat: 4, + repeat: isCritical ? 2 : 4, // Critical captures only perform 1 shake check yoyo: true, ease: "Cubic.easeOut", duration: 250, repeatDelay: 500, onUpdate: t => { - if (shakeCount && shakeCount < 4) { + if (shakeCount && shakeCount < (isCritical ? 2 : 4)) { const value = t.getValue(); const directionMultiplier = shakeCount % 2 === 1 ? 1 : -1; this.pokeball.setX(pbX + value * 4 * directionMultiplier); @@ -114,13 +121,18 @@ export class AttemptCapturePhase extends PokemonPhase { if (!pokemon.species.isObtainable()) { shakeCounter.stop(); this.failCatch(shakeCount); - } else if (shakeCount++ < 3) { - if (pokeballMultiplier === -1 || pokemon.randSeedInt(65536) < y) { + } else if (shakeCount++ < (isCritical ? 1 : 3)) { + // Shake check (skip check for critical or guaranteed captures, but still play the sound) + if (pokeballMultiplier === -1 || isCritical || modifiedCatchRate >= 255 || pokemon.randSeedInt(65536) < shakeProbability) { this.scene.playSound("se/pb_move"); } else { shakeCounter.stop(); this.failCatch(shakeCount); } + } else if (isCritical && pokemon.randSeedInt(65536) >= shakeProbability) { + // Above, perform the one shake check for critical captures after the ball shakes once + shakeCounter.stop(); + this.failCatch(shakeCount); } else { this.scene.playSound("se/pb_lock"); addPokeballCaptureStars(this.scene, this.pokeball); @@ -153,7 +165,8 @@ export class AttemptCapturePhase extends PokemonPhase { }); }; - this.scene.time.delayedCall(250, () => doPokeballBounceAnim(this.scene, this.pokeball, 16, 72, 350, doShake)); + // Ball bounces (handled in pokemon.ts) + this.scene.time.delayedCall(250, () => doPokeballBounceAnim(this.scene, this.pokeball, 16, 72, 350, doShake, isCritical)); } }); } From 4c5b83612b570df41decad27002173ca24b05918 Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Thu, 7 Nov 2024 07:36:25 -0800 Subject: [PATCH 14/75] [P2] END biome transition now properly uses seeded RNG (#4809) Co-authored-by: frutescens --- src/data/balance/biomes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/balance/biomes.ts b/src/data/balance/biomes.ts index 2ce693c360b..0edc8f6c3da 100644 --- a/src/data/balance/biomes.ts +++ b/src/data/balance/biomes.ts @@ -7666,7 +7666,7 @@ export function initBiomes() { if (biome === Biome.END) { const biomeList = Object.keys(Biome).filter(key => !isNaN(Number(key))); biomeList.pop(); // Removes Biome.END from the list - const randIndex = Utils.randInt(biomeList.length, 1); // Will never be Biome.TOWN + const randIndex = Utils.randSeedInt(biomeList.length, 1); // Will never be Biome.TOWN biome = Biome[biomeList[randIndex]]; } const linkedBiomes: (Biome | [ Biome, integer ])[] = Array.isArray(biomeLinks[biome]) From 5601bb14ecc25d8489ea4dd4a334ee70cd1984f1 Mon Sep 17 00:00:00 2001 From: Frederico Santos Date: Thu, 7 Nov 2024 21:21:30 +0000 Subject: [PATCH 15/75] Locales update --- public/locales | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/locales b/public/locales index fc4a1effd51..d600913dbf1 160000 --- a/public/locales +++ b/public/locales @@ -1 +1 @@ -Subproject commit fc4a1effd5170def3c8314208a52cd0d8e6913ef +Subproject commit d600913dbf1f8b47dae8dccbd8296df78f1c51b5 From b2fdb9fcd1ac5e50ebcd911f64bc6509c85431d3 Mon Sep 17 00:00:00 2001 From: AJ Fontaine <36677462+Fontbane@users.noreply.github.com> Date: Thu, 7 Nov 2024 16:33:25 -0500 Subject: [PATCH 16/75] [P2] Fix Cosmoem requirng an evolution level (#4812) --- src/data/balance/pokemon-evolutions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/balance/pokemon-evolutions.ts b/src/data/balance/pokemon-evolutions.ts index 8f22b288f45..0511efb564d 100644 --- a/src/data/balance/pokemon-evolutions.ts +++ b/src/data/balance/pokemon-evolutions.ts @@ -1005,8 +1005,8 @@ export const pokemonEvolutions: PokemonEvolutions = { new SpeciesEvolution(Species.COSMOEM, 23, null, null) ], [Species.COSMOEM]: [ - new SpeciesEvolution(Species.SOLGALEO, 53, EvolutionItem.SUN_FLUTE, null, SpeciesWildEvolutionDelay.VERY_LONG), - new SpeciesEvolution(Species.LUNALA, 53, EvolutionItem.MOON_FLUTE, null, SpeciesWildEvolutionDelay.VERY_LONG) + new SpeciesEvolution(Species.SOLGALEO, 1, EvolutionItem.SUN_FLUTE, null, SpeciesWildEvolutionDelay.VERY_LONG), + new SpeciesEvolution(Species.LUNALA, 1, EvolutionItem.MOON_FLUTE, null, SpeciesWildEvolutionDelay.VERY_LONG) ], [Species.MELTAN]: [ new SpeciesEvolution(Species.MELMETAL, 48, null, null) From 2b91d9d259516aa33a0a143888ce80c9e2bf30c9 Mon Sep 17 00:00:00 2001 From: Moka <54149968+MokaStitcher@users.noreply.github.com> Date: Fri, 8 Nov 2024 00:30:49 +0100 Subject: [PATCH 17/75] [Dev] Remove logging for api requests outside of dev (#4804) --- src/plugins/api/api-base.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/api/api-base.ts b/src/plugins/api/api-base.ts index 0740de4e675..5c1a30ff3ab 100644 --- a/src/plugins/api/api-base.ts +++ b/src/plugins/api/api-base.ts @@ -69,7 +69,9 @@ export abstract class ApiBase { "Content-Type": config.headers?.["Content-Type"] ?? "application/json", }; - console.log(`Sending ${config.method ?? "GET"} request to: `, this.base + path, config); + if (import.meta.env.DEV) { + console.log(`Sending ${config.method ?? "GET"} request to: `, this.base + path, config); + } return await fetch(this.base + path, config); } From aa2c794910aaef68f95001eacc3735091098e279 Mon Sep 17 00:00:00 2001 From: Daniel Pochert Date: Fri, 8 Nov 2024 05:09:25 +0100 Subject: [PATCH 18/75] [Balance/Bug] Boss segments properly heal (#4819) --- src/field/pokemon.ts | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 25a771c9281..45c9caf7477 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -5079,26 +5079,6 @@ export class EnemyPokemon extends Pokemon { } } - heal(amount: integer): integer { - if (this.isBoss()) { - const amountRatio = amount / this.getMaxHp(); - const segmentBypassCount = Math.floor(amountRatio / (1 / this.bossSegments)); - const segmentSize = this.getMaxHp() / this.bossSegments; - for (let s = 1; s < this.bossSegments; s++) { - const hpThreshold = segmentSize * s; - if (this.hp <= Math.round(hpThreshold)) { - const healAmount = Math.min(amount, this.getMaxHp() - this.hp, Math.round(hpThreshold + (segmentSize * segmentBypassCount) - this.hp)); - this.hp += healAmount; - return healAmount; - } else if (s >= this.bossSegmentIndex) { - return super.heal(amount); - } - } - } - - return super.heal(amount); - } - getFieldIndex(): integer { return this.scene.getEnemyField().indexOf(this); } From 4821df68f2829c0ed98ddc382c3ddf1a0ba11c03 Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Thu, 7 Nov 2024 20:10:46 -0800 Subject: [PATCH 19/75] [P1] Prevents crash from using Sketch against a lost turn (#4806) * Added check to make sure that Sketch does not copy a failed move. * Added check for Struggle. * Added a revised check. * Added test + change to valid move finding conditional. * Made revision to .find target * Reverting previous commit, whoops. * Add moveset checks to Sketch tests --------- Co-authored-by: frutescens Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/data/move.ts | 3 ++- src/test/moves/sketch.test.ts | 46 +++++++++++++++++++++++++++-------- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index 9964409df7a..2eb2f792ef9 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -6748,7 +6748,8 @@ export class SketchAttr extends MoveEffectAttr { return false; } - const targetMove = target.getMoveHistory().filter(m => !m.virtual).at(-1); + const targetMove = target.getLastXMoves(target.battleSummonData.turnCount) + .find(m => m.move !== Moves.NONE && m.move !== Moves.STRUGGLE && !m.virtual); if (!targetMove) { return false; } diff --git a/src/test/moves/sketch.test.ts b/src/test/moves/sketch.test.ts index 2e3eb97a76c..4386ce5868e 100644 --- a/src/test/moves/sketch.test.ts +++ b/src/test/moves/sketch.test.ts @@ -1,10 +1,12 @@ import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; -import { MoveResult } from "#app/field/pokemon"; +import { MoveResult, PokemonMove } from "#app/field/pokemon"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { StatusEffect } from "#app/enums/status-effect"; +import { BattlerIndex } from "#app/battle"; describe("Moves - Sketch", () => { let phaserGame: Phaser.Game; @@ -32,22 +34,46 @@ describe("Moves - Sketch", () => { }); it("Sketch should not fail even if a previous Sketch failed to retrieve a valid move and ran out of PP", async () => { - game.override.moveset([ Moves.SKETCH, Moves.SKETCH ]); - await game.classicMode.startBattle([ Species.REGIELEKI ]); - const playerPokemon = game.scene.getPlayerPokemon(); + const playerPokemon = game.scene.getPlayerPokemon()!; + // can't use normal moveset override because we need to check moveset changes + playerPokemon.moveset = [ new PokemonMove(Moves.SKETCH), new PokemonMove(Moves.SKETCH) ]; game.move.select(Moves.SKETCH); await game.phaseInterceptor.to("TurnEndPhase"); - expect(playerPokemon?.getLastXMoves()[0].result).toBe(MoveResult.FAIL); - const moveSlot0 = playerPokemon?.getMoveset()[0]; - expect(moveSlot0?.moveId).toBe(Moves.SKETCH); - expect(moveSlot0?.getPpRatio()).toBe(0); + expect(playerPokemon.getLastXMoves()[0].result).toBe(MoveResult.FAIL); + const moveSlot0 = playerPokemon.getMoveset()[0]!; + expect(moveSlot0.moveId).toBe(Moves.SKETCH); + expect(moveSlot0.getPpRatio()).toBe(0); await game.toNextTurn(); game.move.select(Moves.SKETCH); await game.phaseInterceptor.to("TurnEndPhase"); - expect(playerPokemon?.getLastXMoves()[0].result).toBe(MoveResult.SUCCESS); - // Can't verify if the player Pokemon's moveset was successfully changed because of overrides. + expect(playerPokemon.getLastXMoves()[0].result).toBe(MoveResult.SUCCESS); + expect(playerPokemon.moveset[0]?.moveId).toBe(Moves.SPLASH); + expect(playerPokemon.moveset[1]?.moveId).toBe(Moves.SKETCH); + }); + + it("Sketch should retrieve the most recent valid move from its target history", async () => { + game.override.enemyStatusEffect(StatusEffect.PARALYSIS); + await game.classicMode.startBattle([ Species.REGIELEKI ]); + const playerPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; + playerPokemon.moveset = [ new PokemonMove(Moves.SKETCH), new PokemonMove(Moves.GROWL) ]; + + game.move.select(Moves.GROWL); + await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]); + await game.move.forceStatusActivation(false); + await game.phaseInterceptor.to("TurnEndPhase"); + expect(enemyPokemon.getLastXMoves()[0].result).toBe(MoveResult.SUCCESS); + + await game.toNextTurn(); + game.move.select(Moves.SKETCH); + await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]); + await game.move.forceStatusActivation(true); + await game.phaseInterceptor.to("TurnEndPhase"); + expect(playerPokemon.getLastXMoves()[0].result).toBe(MoveResult.SUCCESS); + expect(playerPokemon.moveset[0]?.moveId).toBe(Moves.SPLASH); + expect(playerPokemon.moveset[1]?.moveId).toBe(Moves.GROWL); }); }); From 625b98a6fee1636e26f86aff0638fa22dd9df842 Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Fri, 8 Nov 2024 07:50:23 -0800 Subject: [PATCH 20/75] [Move][Refactor] Create `Move.getPriority` + Fully Implement Upper Hand (#4789) * Fully Implement Upper Hand * doc for UpperHandCondition * New Upper Hand tests + some nit fixes * Use Fake Out over mocked Tackle in test --- src/data/ability.ts | 8 +-- src/data/arena-tag.ts | 10 ++- src/data/move.ts | 35 +++++++++- src/data/terrain.ts | 6 +- src/phases/turn-start-phase.ts | 22 +++---- src/test/moves/upper_hand.test.ts | 103 ++++++++++++++++++++++++++++++ 6 files changed, 151 insertions(+), 33 deletions(-) create mode 100644 src/test/moves/upper_hand.test.ts diff --git a/src/data/ability.ts b/src/data/ability.ts index 2b65ff79d56..c24369b07eb 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -7,7 +7,7 @@ import { Weather, WeatherType } from "./weather"; import { BattlerTag, BattlerTagLapseType, GroundedTag } from "./battler-tags"; import { StatusEffect, getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect"; import { Gender } from "./gender"; -import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, MoveAttr, MultiHitAttr, SacrificialAttr, SacrificialAttrOnHit, NeutralDamageAgainstFlyingTypeMultiplierAttr, FixedDamageAttr } from "./move"; +import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, MoveAttr, MultiHitAttr, SacrificialAttr, SacrificialAttrOnHit, NeutralDamageAgainstFlyingTypeMultiplierAttr, FixedDamageAttr } from "./move"; import { ArenaTagSide, ArenaTrapTag } from "./arena-tag"; import { BerryModifier, HitHealModifier, PokemonHeldItemModifier } from "../modifier/modifier"; import { TerrainType } from "./terrain"; @@ -583,15 +583,11 @@ export class PostDefendAbAttr extends AbAttr { export class FieldPriorityMoveImmunityAbAttr extends PreDefendAbAttr { applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { - const attackPriority = new Utils.IntegerHolder(move.priority); - applyMoveAttrs(IncrementMovePriorityAttr, attacker, null, move, attackPriority); - applyAbAttrs(ChangeMovePriorityAbAttr, attacker, null, simulated, move, attackPriority); - if (move.moveTarget === MoveTarget.USER || move.moveTarget === MoveTarget.NEAR_ALLY) { return false; } - if (attackPriority.value > 0 && !move.isMultiTarget()) { + if (move.getPriority(attacker) > 0 && !move.isMultiTarget()) { cancelled.value = true; return true; } diff --git a/src/data/arena-tag.ts b/src/data/arena-tag.ts index 73f8e16d573..d70a865f4a4 100644 --- a/src/data/arena-tag.ts +++ b/src/data/arena-tag.ts @@ -2,12 +2,12 @@ import { Arena } from "#app/field/arena"; import BattleScene from "#app/battle-scene"; import { Type } from "#app/data/type"; import { BooleanHolder, NumberHolder, toDmgValue } from "#app/utils"; -import { MoveCategory, allMoves, MoveTarget, IncrementMovePriorityAttr, applyMoveAttrs } from "#app/data/move"; +import { MoveCategory, allMoves, MoveTarget } from "#app/data/move"; import { getPokemonNameWithAffix } from "#app/messages"; import Pokemon, { HitResult, PokemonMove } from "#app/field/pokemon"; import { StatusEffect } from "#app/data/status-effect"; import { BattlerIndex } from "#app/battle"; -import { BlockNonDirectDamageAbAttr, ChangeMovePriorityAbAttr, InfiltratorAbAttr, ProtectStatAbAttr, applyAbAttrs } from "#app/data/ability"; +import { BlockNonDirectDamageAbAttr, InfiltratorAbAttr, ProtectStatAbAttr, applyAbAttrs } from "#app/data/ability"; import { Stat } from "#enums/stat"; import { CommonAnim, CommonBattleAnim } from "#app/data/battle-anims"; import i18next from "i18next"; @@ -318,17 +318,15 @@ export class ConditionalProtectTag extends ArenaTag { */ const QuickGuardConditionFunc: ProtectConditionFunc = (arena, moveId) => { const move = allMoves[moveId]; - const priority = new NumberHolder(move.priority); const effectPhase = arena.scene.getCurrentPhase(); if (effectPhase instanceof MoveEffectPhase) { const attacker = effectPhase.getUserPokemon(); - applyMoveAttrs(IncrementMovePriorityAttr, attacker, null, move, priority); if (attacker) { - applyAbAttrs(ChangeMovePriorityAbAttr, attacker, null, false, move, priority); + return move.getPriority(attacker) > 0; } } - return priority.value > 0; + return move.priority > 0; }; /** diff --git a/src/data/move.ts b/src/data/move.ts index 2eb2f792ef9..07dcf013206 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -8,7 +8,7 @@ import { Constructor, NumberHolder } from "#app/utils"; import * as Utils from "../utils"; import { WeatherType } from "./weather"; import { ArenaTagSide, ArenaTrapTag, WeakenMoveTypeTag } from "./arena-tag"; -import { allAbilities, AllyMoveCategoryPowerBoostAbAttr, applyAbAttrs, applyPostAttackAbAttrs, applyPostItemLostAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, BlockItemTheftAbAttr, BlockNonDirectDamageAbAttr, BlockOneHitKOAbAttr, BlockRecoilDamageAttr, ConfusionOnStatusEffectAbAttr, FieldMoveTypePowerBoostAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr, HealFromBerryUseAbAttr, IgnoreContactAbAttr, IgnoreMoveEffectsAbAttr, IgnoreProtectOnContactAbAttr, InfiltratorAbAttr, MaxMultiHitAbAttr, MoveAbilityBypassAbAttr, MoveEffectChanceMultiplierAbAttr, MoveTypeChangeAbAttr, PostDamageForceSwitchAbAttr, PostItemLostAbAttr, ReverseDrainAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, UnswappableAbilityAbAttr, UserFieldMoveTypePowerBoostAbAttr, VariableMovePowerAbAttr, WonderSkinAbAttr } from "./ability"; +import { allAbilities, AllyMoveCategoryPowerBoostAbAttr, applyAbAttrs, applyPostAttackAbAttrs, applyPostItemLostAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, BlockItemTheftAbAttr, BlockNonDirectDamageAbAttr, BlockOneHitKOAbAttr, BlockRecoilDamageAttr, ChangeMovePriorityAbAttr, ConfusionOnStatusEffectAbAttr, FieldMoveTypePowerBoostAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr, HealFromBerryUseAbAttr, IgnoreContactAbAttr, IgnoreMoveEffectsAbAttr, IgnoreProtectOnContactAbAttr, InfiltratorAbAttr, MaxMultiHitAbAttr, MoveAbilityBypassAbAttr, MoveEffectChanceMultiplierAbAttr, MoveTypeChangeAbAttr, PostDamageForceSwitchAbAttr, PostItemLostAbAttr, ReverseDrainAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, UnswappableAbilityAbAttr, UserFieldMoveTypePowerBoostAbAttr, VariableMovePowerAbAttr, WonderSkinAbAttr } from "./ability"; import { AttackTypeBoosterModifier, BerryModifier, PokemonHeldItemModifier, PokemonMoveAccuracyBoosterModifier, PokemonMultiHitModifier, PreserveBerryModifier } from "../modifier/modifier"; import { BattlerIndex, BattleType } from "../battle"; import { TerrainType } from "./terrain"; @@ -829,6 +829,15 @@ export default class Move implements Localizable { return power.value; } + + getPriority(user: Pokemon, simulated: boolean = true) { + const priority = new Utils.NumberHolder(this.priority); + + applyMoveAttrs(IncrementMovePriorityAttr, user, null, this, priority); + applyAbAttrs(ChangeMovePriorityAbAttr, user, null, simulated, this, priority); + + return priority.value; + } } export class AttackMove extends Move { @@ -7452,6 +7461,27 @@ export class FirstMoveCondition extends MoveCondition { } } +/** + * Condition used by the move {@link https://bulbapedia.bulbagarden.net/wiki/Upper_Hand_(move) | Upper Hand}. + * Moves with this condition are only successful when the target has selected + * a high-priority attack (after factoring in priority-boosting effects) and + * hasn't moved yet this turn. + */ +export class UpperHandCondition extends MoveCondition { + constructor() { + super((user, target, move) => { + const targetCommand = user.scene.currentBattle.turnCommands[target.getBattlerIndex()]; + + return !!targetCommand + && targetCommand.command === Command.FIGHT + && !target.turnData.acted + && !!targetCommand.move?.move + && allMoves[targetCommand.move.move].category !== MoveCategory.STATUS + && allMoves[targetCommand.move.move].getPriority(target) > 0; + }); + } +} + export class hitsSameTypeAttr extends VariableMoveTypeMultiplierAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const multiplier = args[0] as Utils.NumberHolder; @@ -10569,8 +10599,7 @@ export function initMoves() { .attr(AddBattlerTagAttr, BattlerTagType.HEAL_BLOCK, false, false, 2), new AttackMove(Moves.UPPER_HAND, Type.FIGHTING, MoveCategory.PHYSICAL, 65, 100, 15, 100, 3, 9) .attr(FlinchAttr) - .condition((user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()]?.command === Command.FIGHT && !target.turnData.acted && allMoves[user.scene.currentBattle.turnCommands[target.getBattlerIndex()]?.move?.move!].category !== MoveCategory.STATUS && allMoves[user.scene.currentBattle.turnCommands[target.getBattlerIndex()]?.move?.move!].priority > 0 ) // TODO: is this bang correct? - .partial(), // Should also apply when target move priority increased by ability ex. gale wings + .condition(new UpperHandCondition()), new AttackMove(Moves.MALIGNANT_CHAIN, Type.POISON, MoveCategory.SPECIAL, 100, 100, 5, 50, 0, 9) .attr(StatusEffectAttr, StatusEffect.TOXIC) ); diff --git a/src/data/terrain.ts b/src/data/terrain.ts index d8ee8d67925..0bee1ddc7a9 100644 --- a/src/data/terrain.ts +++ b/src/data/terrain.ts @@ -1,8 +1,6 @@ import Pokemon from "../field/pokemon"; import Move from "./move"; import { Type } from "./type"; -import * as Utils from "../utils"; -import { ChangeMovePriorityAbAttr, applyAbAttrs } from "./ability"; import { ProtectAttr } from "./move"; import { BattlerIndex } from "#app/battle"; import i18next from "i18next"; @@ -58,10 +56,8 @@ export class Terrain { switch (this.terrainType) { case TerrainType.PSYCHIC: if (!move.hasAttr(ProtectAttr)) { - const priority = new Utils.IntegerHolder(move.priority); - applyAbAttrs(ChangeMovePriorityAbAttr, user, null, false, move, priority); // Cancels move if the move has positive priority and targets a Pokemon grounded on the Psychic Terrain - return priority.value > 0 && user.getOpponents().some(o => targets.includes(o.getBattlerIndex()) && o.isGrounded()); + return move.getPriority(user) > 0 && user.getOpponents().some(o => targets.includes(o.getBattlerIndex()) && o.isGrounded()); } } diff --git a/src/phases/turn-start-phase.ts b/src/phases/turn-start-phase.ts index dc3ee3f660a..b48b018a046 100644 --- a/src/phases/turn-start-phase.ts +++ b/src/phases/turn-start-phase.ts @@ -1,6 +1,6 @@ import BattleScene from "#app/battle-scene"; -import { applyAbAttrs, BypassSpeedChanceAbAttr, PreventBypassSpeedChanceAbAttr, ChangeMovePriorityAbAttr } from "#app/data/ability"; -import { allMoves, applyMoveAttrs, IncrementMovePriorityAttr, MoveHeaderAttr } from "#app/data/move"; +import { applyAbAttrs, BypassSpeedChanceAbAttr, PreventBypassSpeedChanceAbAttr } from "#app/data/ability"; +import { allMoves, MoveHeaderAttr } from "#app/data/move"; import { Abilities } from "#app/enums/abilities"; import { Stat } from "#app/enums/stat"; import Pokemon, { PokemonMove } from "#app/field/pokemon"; @@ -98,26 +98,22 @@ export class TurnStartPhase extends FieldPhase { const aMove = allMoves[aCommand.move!.move]; const bMove = allMoves[bCommand!.move!.move]; - // The game now considers priority and applies the relevant move and ability attributes - const aPriority = new Utils.IntegerHolder(aMove.priority); - const bPriority = new Utils.IntegerHolder(bMove.priority); + const aUser = this.scene.getField(true).find(p => p.getBattlerIndex() === a)!; + const bUser = this.scene.getField(true).find(p => p.getBattlerIndex() === b)!; - applyMoveAttrs(IncrementMovePriorityAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a)!, null, aMove, aPriority); - applyMoveAttrs(IncrementMovePriorityAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b)!, null, bMove, bPriority); - - applyAbAttrs(ChangeMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a)!, null, false, aMove, aPriority); - applyAbAttrs(ChangeMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b)!, null, false, bMove, bPriority); + const aPriority = aMove.getPriority(aUser, false); + const bPriority = bMove.getPriority(bUser, false); // The game now checks for differences in priority levels. // If the moves share the same original priority bracket, it can check for differences in battlerBypassSpeed and return the result. // This conditional is used to ensure that Quick Claw can still activate with abilities like Stall and Mycelium Might (attack moves only) // Otherwise, the game returns the user of the move with the highest priority. - const isSameBracket = Math.ceil(aPriority.value) - Math.ceil(bPriority.value) === 0; - if (aPriority.value !== bPriority.value) { + const isSameBracket = Math.ceil(aPriority) - Math.ceil(bPriority) === 0; + if (aPriority !== bPriority) { if (isSameBracket && battlerBypassSpeed[a].value !== battlerBypassSpeed[b].value) { return battlerBypassSpeed[a].value ? -1 : 1; } - return aPriority.value < bPriority.value ? 1 : -1; + return (aPriority < bPriority) ? 1 : -1; } } diff --git a/src/test/moves/upper_hand.test.ts b/src/test/moves/upper_hand.test.ts new file mode 100644 index 00000000000..f94197d3fbd --- /dev/null +++ b/src/test/moves/upper_hand.test.ts @@ -0,0 +1,103 @@ +import { BattlerIndex } from "#app/battle"; +import { MoveResult } from "#app/field/pokemon"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Moves - Upper Hand", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset(Moves.UPPER_HAND) + .ability(Abilities.BALL_FETCH) + .battleType("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.QUICK_ATTACK) + .startingLevel(100) + .enemyLevel(100); + }); + + it("should flinch the opponent before they use a priority attack", async () => { + await game.classicMode.startBattle([ Species.FEEBAS ]); + + const feebas = game.scene.getPlayerPokemon()!; + const magikarp = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.UPPER_HAND); + await game.phaseInterceptor.to("BerryPhase"); + + expect(feebas.getLastXMoves()[0].result).toBe(MoveResult.SUCCESS); + expect(magikarp.isFullHp()).toBeFalsy(); + expect(feebas.isFullHp()).toBeTruthy(); + }); + + it.each([ + { descriptor: "non-priority attack", move: Moves.TACKLE }, + { descriptor: "status move", move: Moves.BABY_DOLL_EYES } + ])("should fail when the opponent selects a $descriptor", async ({ move }) => { + game.override.enemyMoveset(move); + + await game.classicMode.startBattle([ Species.FEEBAS ]); + + const feebas = game.scene.getPlayerPokemon()!; + + game.move.select(Moves.UPPER_HAND); + await game.phaseInterceptor.to("BerryPhase"); + + expect(feebas.getLastXMoves()[0].result).toBe(MoveResult.FAIL); + }); + + it("should flinch the opponent before they use an attack boosted by Gale Wings", async () => { + game.override + .enemyAbility(Abilities.GALE_WINGS) + .enemyMoveset(Moves.GUST); + + await game.classicMode.startBattle([ Species.FEEBAS ]); + + const feebas = game.scene.getPlayerPokemon()!; + const magikarp = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.UPPER_HAND); + await game.phaseInterceptor.to("BerryPhase"); + + expect(feebas.getLastXMoves()[0].result).toBe(MoveResult.SUCCESS); + expect(magikarp.isFullHp()).toBeFalsy(); + expect(feebas.isFullHp()).toBeTruthy(); + }); + + it("should fail if the target has already moved", async () => { + game.override + .enemyMoveset(Moves.FAKE_OUT) + .enemyAbility(Abilities.SHEER_FORCE); + + await game.classicMode.startBattle([ Species.FEEBAS ]); + + const feebas = game.scene.getPlayerPokemon()!; + + game.move.select(Moves.UPPER_HAND); + + await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]); + await game.phaseInterceptor.to("BerryPhase"); + + expect(feebas.getLastXMoves()[0].result).toBe(MoveResult.FAIL); + expect(feebas.isFullHp()).toBeFalsy(); + }); +}); From 58d40b905aa48fd10a1681172eb2ace5ec5b9d02 Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Fri, 8 Nov 2024 09:35:33 -0800 Subject: [PATCH 21/75] [Bug] Fixing Encore's interactions with other Move Restriction moves (#4805) * Converted EncoreTag into a MoveRestrictionBattlerTag * Wrote test and added documentation * Added documentation describing EncoreTag as a whole * Added PRE_MOVE lapse code to handle early tag expiration from PP-less encored move * Replaced PRE_MOVE with CUSTOM for lapsing Encore in situations where the encored move has 0 PP * Add encore tests * fix overrides * Apply suggestions from code review Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update command-phase.ts * Addressed failing eslint test --------- Co-authored-by: frutescens Co-authored-by: innerthunder Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/data/battler-tags.ts | 43 ++++++++++++- src/phases/command-phase.ts | 26 ++------ src/test/moves/encore.test.ts | 116 ++++++++++++++++++++++++++++++++++ src/ui/command-ui-handler.ts | 3 - 4 files changed, 162 insertions(+), 26 deletions(-) create mode 100644 src/test/moves/encore.test.ts diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index ebbab7bfa4a..5726a5d53f3 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -909,11 +909,15 @@ export class FrenzyTag extends BattlerTag { } } -export class EncoreTag extends BattlerTag { +/** + * Applies the effects of the move Encore onto the target Pokemon + * Encore forces the target Pokemon to use its most-recent move for 3 turns + */ +export class EncoreTag extends MoveRestrictionBattlerTag { public moveId: Moves; constructor(sourceId: number) { - super(BattlerTagType.ENCORE, BattlerTagLapseType.AFTER_MOVE, 3, Moves.ENCORE, sourceId); + super(BattlerTagType.ENCORE, [ BattlerTagLapseType.CUSTOM, BattlerTagLapseType.AFTER_MOVE ], 3, Moves.ENCORE, sourceId); } /** @@ -969,6 +973,39 @@ export class EncoreTag extends BattlerTag { } } + /** + * If the encored move has run out of PP, Encore ends early. Otherwise, Encore lapses based on the AFTER_MOVE battler tag lapse type. + * @returns `true` to persist | `false` to end and be removed + */ + override lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { + if (lapseType === BattlerTagLapseType.CUSTOM) { + const encoredMove = pokemon.getMoveset().find(m => m?.moveId === this.moveId); + if (encoredMove && encoredMove?.getPpRatio() > 0) { + return true; + } + return false; + } else { + return super.lapse(pokemon, lapseType); + } + } + + /** + * Checks if the move matches the moveId stored within the tag and returns a boolean value + * @param move {@linkcode Moves} the move selected + * @param user N/A + * @returns `true` if the move does not match with the moveId stored and as a result, restricted + */ + override isMoveRestricted(move: Moves, _user?: Pokemon): boolean { + if (move !== this.moveId) { + return true; + } + return false; + } + + override selectionDeniedText(_pokemon: Pokemon, move: Moves): string { + return i18next.t("battle:moveDisabled", { moveName: allMoves[move].name }); + } + onRemove(pokemon: Pokemon): void { super.onRemove(pokemon); @@ -2360,7 +2397,7 @@ export class HealBlockTag extends MoveRestrictionBattlerTag { } /** - * Uses DisabledTag's selectionDeniedText() message + * Uses its own unique selectionDeniedText() message */ override selectionDeniedText(pokemon: Pokemon, move: Moves): string { return i18next.t("battle:moveDisabledHealBlock", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name, healBlockName: allMoves[Moves.HEAL_BLOCK].name }); diff --git a/src/phases/command-phase.ts b/src/phases/command-phase.ts index 547805ec1d1..6163b428603 100644 --- a/src/phases/command-phase.ts +++ b/src/phases/command-phase.ts @@ -61,6 +61,12 @@ export class CommandPhase extends FieldPhase { this.scene.currentBattle.turnCommands[this.fieldIndex] = { command: Command.FIGHT, move: { move: Moves.NONE, targets: []}, skip: true }; } + // Checks if the Pokemon is under the effects of Encore. If so, Encore can end early if the encored move has no more PP. + const encoreTag = this.getPokemon().getTag(BattlerTagType.ENCORE) as EncoreTag; + if (encoreTag) { + this.getPokemon().lapseTag(BattlerTagType.ENCORE); + } + if (this.scene.currentBattle.turnCommands[this.fieldIndex]?.skip) { return this.end(); } @@ -291,26 +297,6 @@ export class CommandPhase extends FieldPhase { } } - checkFightOverride(): boolean { - const pokemon = this.getPokemon(); - - const encoreTag = pokemon.getTag(EncoreTag) as EncoreTag; - - if (!encoreTag) { - return false; - } - - const moveIndex = pokemon.getMoveset().findIndex(m => m?.moveId === encoreTag.moveId); - - if (moveIndex === -1 || !pokemon.getMoveset()[moveIndex]!.isUsable(pokemon)) { // TODO: is this bang correct? - return false; - } - - this.handleCommand(Command.FIGHT, moveIndex, false); - - return true; - } - getFieldIndex(): integer { return this.fieldIndex; } diff --git a/src/test/moves/encore.test.ts b/src/test/moves/encore.test.ts new file mode 100644 index 00000000000..7d8dc9658bf --- /dev/null +++ b/src/test/moves/encore.test.ts @@ -0,0 +1,116 @@ +import { BattlerTagType } from "#enums/battler-tag-type"; +import { BattlerIndex } from "#app/battle"; +import { MoveResult } from "#app/field/pokemon"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Moves - Encore", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([ Moves.SPLASH, Moves.ENCORE ]) + .ability(Abilities.BALL_FETCH) + .battleType("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset([ Moves.SPLASH, Moves.TACKLE ]) + .startingLevel(100) + .enemyLevel(100); + }); + + it("should prevent the target from using any move except the last used move", async () => { + await game.classicMode.startBattle([ Species.SNORLAX ]); + + const enemyPokemon = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.ENCORE); + await game.forceEnemyMove(Moves.SPLASH); + + await game.toNextTurn(); + expect(enemyPokemon.getTag(BattlerTagType.ENCORE)).toBeDefined(); + + game.move.select(Moves.SPLASH); + // The enemy AI would normally be inclined to use Tackle, but should be + // forced into using Splash. + await game.phaseInterceptor.to("BerryPhase", false); + + expect(enemyPokemon.getLastXMoves().every(turnMove => turnMove.move === Moves.SPLASH)).toBeTruthy(); + }); + + describe("should fail against the following moves:", () => { + it.each([ + { moveId: Moves.TRANSFORM, name: "Transform", delay: false }, + { moveId: Moves.MIMIC, name: "Mimic", delay: true }, + { moveId: Moves.SKETCH, name: "Sketch", delay: true }, + { moveId: Moves.ENCORE, name: "Encore", delay: false }, + { moveId: Moves.STRUGGLE, name: "Struggle", delay: false } + ])("$name", async ({ moveId, delay }) => { + game.override.enemyMoveset(moveId); + + await game.classicMode.startBattle([ Species.SNORLAX ]); + + const playerPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; + + if (delay) { + game.move.select(Moves.SPLASH); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await game.toNextTurn(); + } + + game.move.select(Moves.ENCORE); + + const turnOrder = delay + ? [ BattlerIndex.PLAYER, BattlerIndex.ENEMY ] + : [ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]; + await game.setTurnOrder(turnOrder); + + await game.phaseInterceptor.to("BerryPhase", false); + expect(playerPokemon.getLastXMoves(1)[0].result).toBe(MoveResult.FAIL); + expect(enemyPokemon.getTag(BattlerTagType.ENCORE)).toBeUndefined(); + }); + }); + + it("Pokemon under both Encore and Torment should alternate between Struggle and restricted move", async () => { + const turnOrder = [ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]; + game.override.moveset([ Moves.ENCORE, Moves.TORMENT, Moves.SPLASH ]); + await game.classicMode.startBattle([ Species.FEEBAS ]); + + const enemyPokemon = game.scene.getEnemyPokemon(); + game.move.select(Moves.ENCORE); + await game.setTurnOrder(turnOrder); + await game.phaseInterceptor.to("BerryPhase"); + expect(enemyPokemon?.getTag(BattlerTagType.ENCORE)).toBeDefined(); + + await game.toNextTurn(); + game.move.select(Moves.TORMENT); + await game.setTurnOrder(turnOrder); + await game.phaseInterceptor.to("BerryPhase"); + expect(enemyPokemon?.getTag(BattlerTagType.TORMENT)).toBeDefined(); + + await game.toNextTurn(); + game.move.select(Moves.SPLASH); + await game.setTurnOrder(turnOrder); + await game.phaseInterceptor.to("BerryPhase"); + const lastMove = enemyPokemon?.getLastXMoves()[0]; + expect(lastMove?.move).toBe(Moves.STRUGGLE); + }); +}); diff --git a/src/ui/command-ui-handler.ts b/src/ui/command-ui-handler.ts index 0f5edc28675..0dacacc7b70 100644 --- a/src/ui/command-ui-handler.ts +++ b/src/ui/command-ui-handler.ts @@ -90,9 +90,6 @@ export default class CommandUiHandler extends UiHandler { switch (cursor) { // Fight case Command.FIGHT: - if ((this.scene.getCurrentPhase() as CommandPhase).checkFightOverride()) { - return true; - } ui.setMode(Mode.FIGHT, (this.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); success = true; break; From 00f7fd47dfeb47778c071a0f5d2da5adf11c12d5 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Fri, 8 Nov 2024 14:44:34 -0800 Subject: [PATCH 22/75] [Refactor] Remove unnecessary re-exports (#4818) * Remove unnecessary re-exports * Move `Type` enum to `src/enums/type.ts` * Remove import style change from `modifier-type.ts` --- src/battle-scene.ts | 7 +++--- src/battle.ts | 2 +- src/data/ability.ts | 8 ++++--- src/data/arena-tag.ts | 4 ++-- src/data/balance/biomes.ts | 2 +- src/data/balance/pokemon-evolutions.ts | 8 +++---- src/data/battler-tags.ts | 7 +++--- src/data/challenge.ts | 4 ++-- src/data/custom-pokemon-data.ts | 2 +- src/data/move.ts | 8 ++++--- .../encounters/absolute-avarice-encounter.ts | 2 +- .../encounters/bug-type-superfan-encounter.ts | 2 +- .../encounters/clowning-around-encounter.ts | 2 +- .../encounters/dark-deal-encounter.ts | 2 +- .../encounters/fiery-fallout-encounter.ts | 6 ++--- .../global-trade-system-encounter.ts | 3 ++- .../encounters/safari-zone-encounter.ts | 2 +- .../slumbering-snorlax-encounter.ts | 2 +- .../teleporting-hijinks-encounter.ts | 2 +- .../the-expert-pokemon-breeder-encounter.ts | 2 +- .../the-pokemon-salesman-encounter.ts | 2 +- .../encounters/the-strong-stuff-encounter.ts | 2 +- .../the-winstrate-challenge-encounter.ts | 2 +- .../encounters/training-session-encounter.ts | 3 ++- .../encounters/weird-dream-encounter.ts | 2 +- .../mystery-encounter-option.ts | 2 +- .../mystery-encounter-requirements.ts | 8 +++---- .../mystery-encounters/mystery-encounter.ts | 2 +- .../utils/encounter-phase-utils.ts | 5 ++-- .../utils/encounter-pokemon-utils.ts | 8 ++++--- src/data/nature.ts | 4 +--- src/data/pokeball.ts | 2 -- src/data/pokemon-forms.ts | 6 ++--- src/data/pokemon-species.ts | 2 +- src/data/status-effect.ts | 2 -- src/data/terrain.ts | 2 +- src/data/trainer-config.ts | 4 ++-- src/data/type.ts | 23 +------------------ src/data/weather.ts | 3 +-- src/enums/type.ts | 22 ++++++++++++++++++ src/events/arena.ts | 2 +- src/field/anims.ts | 2 +- src/field/arena.ts | 5 ++-- src/field/pokemon.ts | 13 +++++++---- src/modifier/modifier-type.ts | 19 +++++++-------- src/modifier/modifier.ts | 2 +- src/phases/command-phase.ts | 2 +- src/phases/move-effect-phase.ts | 2 +- src/phases/move-phase.ts | 2 +- src/system/game-data.ts | 4 ++-- src/system/pokemon-data.ts | 4 ++-- src/test/abilities/battle_bond.test.ts | 3 ++- src/test/abilities/disguise.test.ts | 2 +- src/test/abilities/flash_fire.test.ts | 2 +- src/test/abilities/galvanize.test.ts | 2 +- src/test/abilities/libero.test.ts | 5 ++-- src/test/abilities/magic_guard.test.ts | 5 ++-- src/test/abilities/mimicry.test.ts | 2 +- src/test/abilities/parental_bond.test.ts | 6 ++--- src/test/abilities/pastel_veil.test.ts | 2 +- src/test/abilities/power_construct.test.ts | 3 ++- src/test/abilities/protean.test.ts | 5 ++-- src/test/abilities/sand_veil.test.ts | 4 ++-- src/test/abilities/schooling.test.ts | 3 ++- src/test/abilities/shields_down.test.ts | 3 ++- src/test/abilities/synchronize.test.ts | 2 +- src/test/abilities/zen_mode.test.ts | 3 ++- src/test/abilities/zero_to_hero.test.ts | 3 ++- src/test/arena/weather_fog.test.ts | 2 +- src/test/arena/weather_hail.test.ts | 4 ++-- src/test/arena/weather_sandstorm.test.ts | 2 +- src/test/battle/double_battle.test.ts | 3 ++- src/test/battle/inverse_battle.test.ts | 2 +- src/test/data/status-effect.test.ts | 2 +- src/test/field/pokemon.test.ts | 2 +- src/test/final_boss.test.ts | 12 +++++----- src/test/items/toxic_orb.test.ts | 2 +- src/test/moves/aurora_veil.test.ts | 4 ++-- src/test/moves/camouflage.test.ts | 2 +- src/test/moves/dragon_cheer.test.ts | 2 +- src/test/moves/dragon_rage.test.ts | 2 +- src/test/moves/effectiveness.test.ts | 2 +- src/test/moves/electrify.test.ts | 2 +- src/test/moves/flower_shield.test.ts | 2 +- src/test/moves/forests_curse.test.ts | 2 +- src/test/moves/fusion_flare.test.ts | 2 +- src/test/moves/heal_block.test.ts | 2 +- src/test/moves/nightmare.test.ts | 2 +- src/test/moves/plasma_fists.test.ts | 2 +- src/test/moves/pledge_moves.test.ts | 2 +- src/test/moves/purify.test.ts | 3 ++- src/test/moves/reflect_type.test.ts | 2 +- src/test/moves/relic_song.test.ts | 2 +- src/test/moves/roost.test.ts | 2 +- src/test/moves/substitute.test.ts | 12 +++++----- src/test/moves/tar_shot.test.ts | 2 +- src/test/moves/tera_blast.test.ts | 2 +- src/test/moves/tera_starstorm.test.ts | 2 +- src/test/moves/thunder_wave.test.ts | 4 ++-- src/test/moves/toxic_spikes.test.ts | 2 +- src/test/moves/trick_or_treat.test.ts | 2 +- .../mystery-encounter/encounter-test-utils.ts | 23 ++++++++++--------- .../clowning-around-encounter.test.ts | 2 +- .../fiery-fallout-encounter.test.ts | 13 ++++++----- .../the-strong-stuff-encounter.test.ts | 12 +++++----- .../the-winstrate-challenge-encounter.test.ts | 11 +++++---- .../mystery-encounter-utils.test.ts | 20 ++++++++-------- src/test/phases/form-change-phase.test.ts | 2 +- src/test/ui/starter-select.test.ts | 2 +- src/test/utils/helpers/overridesHelper.ts | 19 +++++++-------- src/ui/arena-flyout.ts | 2 +- src/ui/battle-info.ts | 5 ++-- src/ui/fight-ui-handler.ts | 3 ++- src/ui/modifier-select-ui-handler.ts | 3 ++- src/ui/move-info-overlay.ts | 2 +- src/ui/party-ui-handler.ts | 2 +- src/ui/pokemon-hatch-info-container.ts | 2 +- src/ui/pokemon-info-container.ts | 2 +- src/ui/run-info-ui-handler.ts | 3 ++- src/ui/starter-select-ui-handler.ts | 5 ++-- src/ui/summary-ui-handler.ts | 8 ++++--- 121 files changed, 281 insertions(+), 249 deletions(-) create mode 100644 src/enums/type.ts diff --git a/src/battle-scene.ts b/src/battle-scene.ts index d1d520f5f9d..ed8a79125bc 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -5,7 +5,7 @@ import PokemonSpecies, { allSpecies, getPokemonSpecies, PokemonSpeciesFilter } f import { Constructor, isNullOrUndefined, randSeedInt } from "#app/utils"; import * as Utils from "#app/utils"; import { ConsumableModifier, ConsumablePokemonModifier, DoubleBattleChanceBoosterModifier, ExpBalanceModifier, ExpShareModifier, FusePokemonModifier, HealingBoosterModifier, Modifier, ModifierBar, ModifierPredicate, MultipleParticipantExpBonusModifier, overrideHeldItems, overrideModifiers, PersistentModifier, PokemonExpBoosterModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier, PokemonHpRestoreModifier, PokemonIncrementingStatModifier, RememberMoveModifier, TerastallizeModifier, TurnHeldItemTransferModifier } from "./modifier/modifier"; -import { PokeballType } from "#app/data/pokeball"; +import { PokeballType } from "#enums/pokeball"; import { initCommonAnims, initMoveAnim, loadCommonAnimAssets, loadMoveAnimAssets, populateAnims } from "#app/data/battle-anims"; import { Phase } from "#app/phase"; import { initGameSpeed } from "#app/system/game-speed"; @@ -35,10 +35,11 @@ import { Gender } from "#app/data/gender"; import UIPlugin from "phaser3-rex-plugins/templates/ui/ui-plugin"; import { addUiThemeOverrides } from "#app/ui/ui-theme"; import PokemonData from "#app/system/pokemon-data"; -import { Nature } from "#app/data/nature"; +import { Nature } from "#enums/nature"; import { FormChangeItem, pokemonFormChanges, SpeciesFormChange, SpeciesFormChangeManualTrigger, SpeciesFormChangeTimeOfDayTrigger, SpeciesFormChangeTrigger } from "#app/data/pokemon-forms"; import { FormChangePhase } from "#app/phases/form-change-phase"; -import { getTypeRgb, Type } from "#app/data/type"; +import { getTypeRgb } from "#app/data/type"; +import { Type } from "#enums/type"; import PokemonSpriteSparkleHandler from "#app/field/pokemon-sprite-sparkle-handler"; import CharSprite from "#app/ui/char-sprite"; import DamageNumberHandler from "#app/field/damage-number-handler"; diff --git a/src/battle.ts b/src/battle.ts index 0356772bb07..75f0dff2534 100644 --- a/src/battle.ts +++ b/src/battle.ts @@ -4,7 +4,7 @@ import * as Utils from "./utils"; import Trainer, { TrainerVariant } from "./field/trainer"; import { GameMode } from "./game-mode"; import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier"; -import { PokeballType } from "./data/pokeball"; +import { PokeballType } from "#enums/pokeball"; import { trainerConfigs } from "#app/data/trainer-config"; import { SpeciesFormKey } from "#enums/species-form-key"; import Pokemon, { EnemyPokemon, PlayerPokemon, QueuedMove } from "#app/field/pokemon"; diff --git a/src/data/ability.ts b/src/data/ability.ts index c24369b07eb..08dc1ed27a4 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -1,11 +1,11 @@ import Pokemon, { EnemyPokemon, HitResult, MoveResult, PlayerPokemon, PokemonMove } from "../field/pokemon"; -import { Type } from "./type"; +import { Type } from "#enums/type"; import { Constructor } from "#app/utils"; import * as Utils from "../utils"; import { getPokemonNameWithAffix } from "../messages"; -import { Weather, WeatherType } from "./weather"; +import { Weather } from "#app/data/weather"; import { BattlerTag, BattlerTagLapseType, GroundedTag } from "./battler-tags"; -import { StatusEffect, getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect"; +import { getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "#app/data/status-effect"; import { Gender } from "./gender"; import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, MoveAttr, MultiHitAttr, SacrificialAttr, SacrificialAttrOnHit, NeutralDamageAgainstFlyingTypeMultiplierAttr, FixedDamageAttr } from "./move"; import { ArenaTagSide, ArenaTrapTag } from "./arena-tag"; @@ -36,6 +36,8 @@ import { BattleEndPhase } from "#app/phases/battle-end-phase"; import { NewBattlePhase } from "#app/phases/new-battle-phase"; import { MoveEndPhase } from "#app/phases/move-end-phase"; import { PokemonAnimType } from "#enums/pokemon-anim-type"; +import { StatusEffect } from "#enums/status-effect"; +import { WeatherType } from "#enums/weather-type"; export class Ability implements Localizable { public id: Abilities; diff --git a/src/data/arena-tag.ts b/src/data/arena-tag.ts index d70a865f4a4..2f57650c65d 100644 --- a/src/data/arena-tag.ts +++ b/src/data/arena-tag.ts @@ -1,11 +1,11 @@ import { Arena } from "#app/field/arena"; import BattleScene from "#app/battle-scene"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { BooleanHolder, NumberHolder, toDmgValue } from "#app/utils"; import { MoveCategory, allMoves, MoveTarget } from "#app/data/move"; import { getPokemonNameWithAffix } from "#app/messages"; import Pokemon, { HitResult, PokemonMove } from "#app/field/pokemon"; -import { StatusEffect } from "#app/data/status-effect"; +import { StatusEffect } from "#enums/status-effect"; import { BattlerIndex } from "#app/battle"; import { BlockNonDirectDamageAbAttr, InfiltratorAbAttr, ProtectStatAbAttr, applyAbAttrs } from "#app/data/ability"; import { Stat } from "#enums/stat"; diff --git a/src/data/balance/biomes.ts b/src/data/balance/biomes.ts index 0edc8f6c3da..0f4926cf7c7 100644 --- a/src/data/balance/biomes.ts +++ b/src/data/balance/biomes.ts @@ -1,4 +1,4 @@ -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import * as Utils from "#app/utils"; import { pokemonEvolutions, SpeciesFormEvolution } from "#app/data/balance/pokemon-evolutions"; import i18next from "i18next"; diff --git a/src/data/balance/pokemon-evolutions.ts b/src/data/balance/pokemon-evolutions.ts index 0511efb564d..9e86ea7397b 100644 --- a/src/data/balance/pokemon-evolutions.ts +++ b/src/data/balance/pokemon-evolutions.ts @@ -1,10 +1,10 @@ import { Gender } from "#app/data/gender"; -import { PokeballType } from "#app/data/pokeball"; +import { PokeballType } from "#enums/pokeball"; import Pokemon from "#app/field/pokemon"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import * as Utils from "#app/utils"; -import { WeatherType } from "#app/data/weather"; -import { Nature } from "#app/data/nature"; +import { WeatherType } from "#enums/weather-type"; +import { Nature } from "#enums/nature"; import { Biome } from "#enums/biome"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 5726a5d53f3..25d65fbc372 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -18,10 +18,9 @@ import Move, { StatusCategoryOnAllyAttr } from "#app/data/move"; import { SpeciesFormChangeManualTrigger } from "#app/data/pokemon-forms"; -import { getStatusEffectHealText, StatusEffect } from "#app/data/status-effect"; +import { getStatusEffectHealText } from "#app/data/status-effect"; import { TerrainType } from "#app/data/terrain"; -import { Type } from "#app/data/type"; -import { WeatherType } from "#app/data/weather"; +import { Type } from "#enums/type"; import Pokemon, { HitResult, MoveResult } from "#app/field/pokemon"; import { getPokemonNameWithAffix } from "#app/messages"; import { CommonAnimPhase } from "#app/phases/common-anim-phase"; @@ -38,6 +37,8 @@ import { Moves } from "#enums/moves"; import { PokemonAnimType } from "#enums/pokemon-anim-type"; import { Species } from "#enums/species"; import { EFFECTIVE_STATS, getStatKey, Stat, type BattleStat, type EffectiveStat } from "#enums/stat"; +import { StatusEffect } from "#enums/status-effect"; +import { WeatherType } from "#enums/weather-type"; export enum BattlerTagLapseType { FAINT, diff --git a/src/data/challenge.ts b/src/data/challenge.ts index a64a90e5d14..af6bbf5b00f 100644 --- a/src/data/challenge.ts +++ b/src/data/challenge.ts @@ -7,11 +7,11 @@ import Pokemon, { PokemonMove } from "#app/field/pokemon"; import { BattleType, FixedBattleConfig } from "#app/battle"; import Trainer, { TrainerVariant } from "#app/field/trainer"; import { GameMode } from "#app/game-mode"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { Challenges } from "#enums/challenges"; import { Species } from "#enums/species"; import { TrainerType } from "#enums/trainer-type"; -import { Nature } from "#app/data/nature"; +import { Nature } from "#enums/nature"; import { Moves } from "#enums/moves"; import { TypeColor, TypeShadow } from "#enums/color"; import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; diff --git a/src/data/custom-pokemon-data.ts b/src/data/custom-pokemon-data.ts index 2e94123fc84..7bc884cff50 100644 --- a/src/data/custom-pokemon-data.ts +++ b/src/data/custom-pokemon-data.ts @@ -1,5 +1,5 @@ import { Abilities } from "#enums/abilities"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { isNullOrUndefined } from "#app/utils"; import { Nature } from "#enums/nature"; diff --git a/src/data/move.ts b/src/data/move.ts index 07dcf013206..071d7fa1e65 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -2,11 +2,12 @@ import { ChargeAnim, initMoveAnim, loadMoveAnimAssets, MoveChargeAnim } from "./ import { CommandedTag, EncoreTag, GulpMissileTag, HelpingHandTag, SemiInvulnerableTag, ShellTrapTag, StockpilingTag, SubstituteTag, TrappedTag, TypeBoostTag } from "./battler-tags"; import { getPokemonNameWithAffix } from "../messages"; import Pokemon, { AttackMoveResult, EnemyPokemon, HitResult, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "../field/pokemon"; -import { getNonVolatileStatusEffects, getStatusEffectHealText, isNonVolatileStatusEffect, StatusEffect } from "./status-effect"; -import { getTypeDamageMultiplier, Type } from "./type"; +import { getNonVolatileStatusEffects, getStatusEffectHealText, isNonVolatileStatusEffect } from "./status-effect"; +import { getTypeDamageMultiplier } from "./type"; +import { Type } from "#enums/type"; import { Constructor, NumberHolder } from "#app/utils"; import * as Utils from "../utils"; -import { WeatherType } from "./weather"; +import { WeatherType } from "#enums/weather-type"; import { ArenaTagSide, ArenaTrapTag, WeakenMoveTypeTag } from "./arena-tag"; import { allAbilities, AllyMoveCategoryPowerBoostAbAttr, applyAbAttrs, applyPostAttackAbAttrs, applyPostItemLostAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, BlockItemTheftAbAttr, BlockNonDirectDamageAbAttr, BlockOneHitKOAbAttr, BlockRecoilDamageAttr, ChangeMovePriorityAbAttr, ConfusionOnStatusEffectAbAttr, FieldMoveTypePowerBoostAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr, HealFromBerryUseAbAttr, IgnoreContactAbAttr, IgnoreMoveEffectsAbAttr, IgnoreProtectOnContactAbAttr, InfiltratorAbAttr, MaxMultiHitAbAttr, MoveAbilityBypassAbAttr, MoveEffectChanceMultiplierAbAttr, MoveTypeChangeAbAttr, PostDamageForceSwitchAbAttr, PostItemLostAbAttr, ReverseDrainAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, UnswappableAbilityAbAttr, UserFieldMoveTypePowerBoostAbAttr, VariableMovePowerAbAttr, WonderSkinAbAttr } from "./ability"; import { AttackTypeBoosterModifier, BerryModifier, PokemonHeldItemModifier, PokemonMoveAccuracyBoosterModifier, PokemonMultiHitModifier, PreserveBerryModifier } from "../modifier/modifier"; @@ -38,6 +39,7 @@ import { SpeciesFormChangeRevertWeatherFormTrigger } from "./pokemon-forms"; import { GameMode } from "#app/game-mode"; import { applyChallenges, ChallengeType } from "./challenge"; import { SwitchType } from "#enums/switch-type"; +import { StatusEffect } from "enums/status-effect"; export enum MoveCategory { PHYSICAL, diff --git a/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts b/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts index fa8e1aed1c7..9c00148fbac 100644 --- a/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts +++ b/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts @@ -18,7 +18,7 @@ import { randInt } from "#app/utils"; import { BattlerIndex } from "#app/battle"; import { applyModifierTypeToPlayerPokemon, catchPokemon, getHighestLevelPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { TrainerSlot } from "#app/data/trainer-config"; -import { PokeballType } from "#app/data/pokeball"; +import { PokeballType } from "#enums/pokeball"; import HeldModifierConfig from "#app/interfaces/held-modifier-config"; import { BerryType } from "#enums/berry-type"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; diff --git a/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts b/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts index f2605795955..7a03e6efdd2 100644 --- a/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts +++ b/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts @@ -36,7 +36,7 @@ import { HeldItemRequirement, TypeRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { AttackTypeBoosterModifierType, ModifierTypeOption, modifierTypes } from "#app/modifier/modifier-type"; import { AttackTypeBoosterModifier, diff --git a/src/data/mystery-encounters/encounters/clowning-around-encounter.ts b/src/data/mystery-encounters/encounters/clowning-around-encounter.ts index 5502cc7b53a..ae6cabd4dae 100644 --- a/src/data/mystery-encounters/encounters/clowning-around-encounter.ts +++ b/src/data/mystery-encounters/encounters/clowning-around-encounter.ts @@ -12,7 +12,7 @@ import { TrainerType } from "#enums/trainer-type"; import { getPokemonSpecies } from "#app/data/pokemon-species"; import { Abilities } from "#enums/abilities"; import { applyAbilityOverrideToPokemon, applyModifierTypeToPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { randSeedInt, randSeedShuffle } from "#app/utils"; diff --git a/src/data/mystery-encounters/encounters/dark-deal-encounter.ts b/src/data/mystery-encounters/encounters/dark-deal-encounter.ts index 8a814b58248..2b801d70f61 100644 --- a/src/data/mystery-encounters/encounters/dark-deal-encounter.ts +++ b/src/data/mystery-encounters/encounters/dark-deal-encounter.ts @@ -1,4 +1,4 @@ -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { isNullOrUndefined, randSeedInt } from "#app/utils"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Species } from "#enums/species"; diff --git a/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts b/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts index 5794277ffe1..bbc979e844e 100644 --- a/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts +++ b/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts @@ -8,14 +8,14 @@ import { AbilityRequirement, CombinationPokemonRequirement, TypeRequirement } fr import { Species } from "#enums/species"; import { getPokemonSpecies } from "#app/data/pokemon-species"; import { Gender } from "#app/data/gender"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { BattlerIndex } from "#app/battle"; import Pokemon, { PokemonMove } from "#app/field/pokemon"; import { Moves } from "#enums/moves"; import { EncounterBattleAnim } from "#app/data/battle-anims"; -import { WeatherType } from "#app/data/weather"; +import { WeatherType } from "#enums/weather-type"; import { isNullOrUndefined, randSeedInt } from "#app/utils"; -import { StatusEffect } from "#app/data/status-effect"; +import { StatusEffect } from "#enums/status-effect"; import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { applyAbilityOverrideToPokemon, applyDamageToPokemon, applyModifierTypeToPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; diff --git a/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts b/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts index 720e904ecdb..b0d547e36cf 100644 --- a/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts +++ b/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts @@ -21,11 +21,12 @@ import PokemonData from "#app/system/pokemon-data"; import i18next from "i18next"; import { Gender, getGenderSymbol } from "#app/data/gender"; import { getNatureName } from "#app/data/nature"; -import { getPokeballAtlasKey, getPokeballTintColor, PokeballType } from "#app/data/pokeball"; +import { getPokeballAtlasKey, getPokeballTintColor } from "#app/data/pokeball"; import { getEncounterText, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { trainerNamePools } from "#app/data/trainer-names"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { addPokemonDataToDexAndValidateAchievements } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; +import type { PokeballType } from "#enums/pokeball"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounters/globalTradeSystem"; diff --git a/src/data/mystery-encounters/encounters/safari-zone-encounter.ts b/src/data/mystery-encounters/encounters/safari-zone-encounter.ts index 0ee3c57b0a2..0353d52a592 100644 --- a/src/data/mystery-encounters/encounters/safari-zone-encounter.ts +++ b/src/data/mystery-encounters/encounters/safari-zone-encounter.ts @@ -6,7 +6,7 @@ import MysteryEncounterOption, { MysteryEncounterOptionBuilder } from "#app/data import { TrainerSlot } from "#app/data/trainer-config"; import { HiddenAbilityRateBoosterModifier, IvScannerModifier } from "#app/modifier/modifier"; import { EnemyPokemon } from "#app/field/pokemon"; -import { PokeballType } from "#app/data/pokeball"; +import { PokeballType } from "#enums/pokeball"; import { PlayerGender } from "#enums/player-gender"; import { IntegerHolder, randSeedInt } from "#app/utils"; import { getPokemonSpecies } from "#app/data/pokemon-species"; diff --git a/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts b/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts index 8ea19e1225b..3fb502be545 100644 --- a/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts +++ b/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts @@ -3,7 +3,7 @@ import { modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifi import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Species } from "#enums/species"; import BattleScene from "#app/battle-scene"; -import { StatusEffect } from "#app/data/status-effect"; +import { StatusEffect } from "#enums/status-effect"; import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter"; import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; import { MoveRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements"; diff --git a/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts b/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts index faeba95f358..042e9278673 100644 --- a/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts +++ b/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts @@ -12,7 +12,7 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { Biome } from "#enums/biome"; import { getBiomeKey } from "#app/field/arena"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { getPartyLuckValue, modifierTypes } from "#app/modifier/modifier-type"; import { TrainerSlot } from "#app/data/trainer-config"; import { BattlerTagType } from "#enums/battler-tag-type"; diff --git a/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts b/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts index 7c904bd047a..6a4c6592fda 100644 --- a/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts @@ -23,7 +23,7 @@ import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/myst import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { achvs } from "#app/system/achv"; import { modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { getPokeballTintColor } from "#app/data/pokeball"; import { PokemonHeldItemModifier } from "#app/modifier/modifier"; diff --git a/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts b/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts index 95f359547e4..77d92e3749e 100644 --- a/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts @@ -8,7 +8,7 @@ import { catchPokemon, getRandomSpeciesByStarterTier, getSpriteKeysFromPokemon } import { getPokemonSpecies } from "#app/data/pokemon-species"; import { speciesStarterCosts } from "#app/data/balance/starters"; import { Species } from "#enums/species"; -import { PokeballType } from "#app/data/pokeball"; +import { PokeballType } from "#enums/pokeball"; import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; import { showEncounterDialogue } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; diff --git a/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts b/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts index b1ef6cedb21..754632aedea 100644 --- a/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts @@ -5,7 +5,7 @@ import BattleScene from "#app/battle-scene"; import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter"; import { getPokemonSpecies } from "#app/data/pokemon-species"; import { Species } from "#enums/species"; -import { Nature } from "#app/data/nature"; +import { Nature } from "#enums/nature"; import Pokemon, { PokemonMove } from "#app/field/pokemon"; import { queueEncounterMessage, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { modifyPlayerPokemonBST } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; diff --git a/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts b/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts index 5c1af43c426..f4446241873 100644 --- a/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts @@ -10,7 +10,7 @@ import { Abilities } from "#enums/abilities"; import { getPokemonSpecies } from "#app/data/pokemon-species"; import { Moves } from "#enums/moves"; import { Nature } from "#enums/nature"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { BerryType } from "#enums/berry-type"; import { Stat } from "#enums/stat"; import { SpeciesFormChangeManualTrigger } from "#app/data/pokemon-forms"; diff --git a/src/data/mystery-encounters/encounters/training-session-encounter.ts b/src/data/mystery-encounters/encounters/training-session-encounter.ts index 8814eb0d8cf..4a0a91bf751 100644 --- a/src/data/mystery-encounters/encounters/training-session-encounter.ts +++ b/src/data/mystery-encounters/encounters/training-session-encounter.ts @@ -1,6 +1,6 @@ import { Ability, allAbilities } from "#app/data/ability"; import { EnemyPartyConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, selectPokemonForOption, setEncounterRewards, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; -import { getNatureName, Nature } from "#app/data/nature"; +import { getNatureName } from "#app/data/nature"; import { speciesStarterCosts } from "#app/data/balance/starters"; import Pokemon, { PlayerPokemon } from "#app/field/pokemon"; import { PokemonHeldItemModifier } from "#app/modifier/modifier"; @@ -21,6 +21,7 @@ import i18next from "i18next"; import { getStatKey } from "#enums/stat"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { isPokemonValidForEncounterOptionSelection } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; +import type { Nature } from "#enums/nature"; /** The i18n namespace for the encounter */ const namespace = "mysteryEncounters/trainingSession"; diff --git a/src/data/mystery-encounters/encounters/weird-dream-encounter.ts b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts index c05e707ed4d..3c541e20bf4 100644 --- a/src/data/mystery-encounters/encounters/weird-dream-encounter.ts +++ b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts @@ -1,4 +1,4 @@ -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Species } from "#enums/species"; import BattleScene from "#app/battle-scene"; diff --git a/src/data/mystery-encounters/mystery-encounter-option.ts b/src/data/mystery-encounters/mystery-encounter-option.ts index c674ebdc46e..4ff8fd95f85 100644 --- a/src/data/mystery-encounters/mystery-encounter-option.ts +++ b/src/data/mystery-encounters/mystery-encounter-option.ts @@ -2,7 +2,7 @@ import { OptionTextDisplay } from "#app/data/mystery-encounters/mystery-encounte import { Moves } from "#app/enums/moves"; import Pokemon, { PlayerPokemon } from "#app/field/pokemon"; import BattleScene from "#app/battle-scene"; -import { Type } from "../type"; +import { Type } from "#enums/type"; import { EncounterPokemonRequirement, EncounterSceneRequirement, MoneyRequirement, TypeRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements"; import { CanLearnMoveRequirement, CanLearnMoveRequirementOptions } from "./requirements/can-learn-move-requirement"; import { isNullOrUndefined, randSeedInt } from "#app/utils"; diff --git a/src/data/mystery-encounters/mystery-encounter-requirements.ts b/src/data/mystery-encounters/mystery-encounter-requirements.ts index 1358c465d17..811b622de76 100644 --- a/src/data/mystery-encounters/mystery-encounter-requirements.ts +++ b/src/data/mystery-encounters/mystery-encounter-requirements.ts @@ -1,11 +1,11 @@ import BattleScene from "#app/battle-scene"; import { allAbilities } from "#app/data/ability"; import { EvolutionItem, pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; -import { Nature } from "#app/data/nature"; +import { Nature } from "#enums/nature"; import { FormChangeItem, pokemonFormChanges, SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms"; -import { StatusEffect } from "#app/data/status-effect"; -import { Type } from "#app/data/type"; -import { WeatherType } from "#app/data/weather"; +import { StatusEffect } from "#enums/status-effect"; +import { Type } from "#enums/type"; +import { WeatherType } from "#enums/weather-type"; import { PlayerPokemon } from "#app/field/pokemon"; import { AttackTypeBoosterModifier } from "#app/modifier/modifier"; import { AttackTypeBoosterModifierType } from "#app/modifier/modifier-type"; diff --git a/src/data/mystery-encounters/mystery-encounter.ts b/src/data/mystery-encounters/mystery-encounter.ts index badbfcf7a56..e341da4e435 100644 --- a/src/data/mystery-encounters/mystery-encounter.ts +++ b/src/data/mystery-encounters/mystery-encounter.ts @@ -5,7 +5,7 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "#app/battle-scene"; import MysteryEncounterIntroVisuals, { MysteryEncounterSpriteConfig } from "#app/field/mystery-encounter-intro"; import * as Utils from "#app/utils"; -import { StatusEffect } from "../status-effect"; +import { StatusEffect } from "#enums/status-effect"; import MysteryEncounterDialogue, { OptionTextDisplay } from "./mystery-encounter-dialogue"; import MysteryEncounterOption, { MysteryEncounterOptionBuilder, OptionPhaseCallback } from "./mystery-encounter-option"; import { EncounterPokemonRequirement, EncounterSceneRequirement, HealthRatioRequirement, PartySizeRequirement, StatusEffectRequirement, WaveRangeRequirement } from "./mystery-encounter-requirements"; diff --git a/src/data/mystery-encounters/utils/encounter-phase-utils.ts b/src/data/mystery-encounters/utils/encounter-phase-utils.ts index 429b6bfa292..c6dda134346 100644 --- a/src/data/mystery-encounters/utils/encounter-phase-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-phase-utils.ts @@ -19,11 +19,11 @@ import i18next from "i18next"; import BattleScene from "#app/battle-scene"; import Trainer, { TrainerVariant } from "#app/field/trainer"; import { Gender } from "#app/data/gender"; -import { Nature } from "#app/data/nature"; +import { Nature } from "#enums/nature"; import { Moves } from "#enums/moves"; import { initMoveAnim, loadMoveAnimAssets } from "#app/data/battle-anims"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; -import { Status, StatusEffect } from "#app/data/status-effect"; +import { Status } from "#app/data/status-effect"; import { TrainerConfig, trainerConfigs, TrainerSlot } from "#app/data/trainer-config"; import PokemonSpecies from "#app/data/pokemon-species"; import { Egg, IEggOptions } from "#app/data/egg"; @@ -37,6 +37,7 @@ import { GameOverPhase } from "#app/phases/game-over-phase"; import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; import { PartyExpPhase } from "#app/phases/party-exp-phase"; import { Variant } from "#app/data/variant"; +import { StatusEffect } from "#enums/status-effect"; /** * Animates exclamation sprite over trainer's head at start of encounter diff --git a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts index dd42cc9ce55..fc85754bdde 100644 --- a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts @@ -3,15 +3,15 @@ import i18next from "i18next"; import { isNullOrUndefined, randSeedInt } from "#app/utils"; import { PokemonHeldItemModifier } from "#app/modifier/modifier"; import Pokemon, { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; -import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getPokeballTintColor, PokeballType } from "#app/data/pokeball"; +import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getPokeballTintColor } from "#app/data/pokeball"; import { PlayerGender } from "#enums/player-gender"; import { addPokeballCaptureStars, addPokeballOpenParticles } from "#app/field/anims"; -import { getStatusEffectCatchRateMultiplier, StatusEffect } from "#app/data/status-effect"; +import { getStatusEffectCatchRateMultiplier } from "#app/data/status-effect"; import { achvs } from "#app/system/achv"; import { Mode } from "#app/ui/ui"; import { PartyOption, PartyUiMode } from "#app/ui/party-ui-handler"; import { Species } from "#enums/species"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import PokemonSpecies, { getPokemonSpecies } from "#app/data/pokemon-species"; import { speciesStarterCosts } from "#app/data/balance/starters"; import { getEncounterText, queueEncounterMessage, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; @@ -23,6 +23,8 @@ import { VictoryPhase } from "#app/phases/victory-phase"; import { SummaryUiMode } from "#app/ui/summary-ui-handler"; import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import { Abilities } from "#enums/abilities"; +import type { PokeballType } from "#enums/pokeball"; +import { StatusEffect } from "#enums/status-effect"; /** Will give +1 level every 10 waves */ export const STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER = 1; diff --git a/src/data/nature.ts b/src/data/nature.ts index edac06f1a4f..b90047ce6f0 100644 --- a/src/data/nature.ts +++ b/src/data/nature.ts @@ -3,9 +3,7 @@ import { TextStyle, getBBCodeFrag } from "../ui/text"; import { Nature } from "#enums/nature"; import { UiTheme } from "#enums/ui-theme"; import i18next from "i18next"; -import { Stat, EFFECTIVE_STATS, getShortenedStatKey } from "#app/enums/stat"; - -export { Nature }; +import { Stat, EFFECTIVE_STATS, getShortenedStatKey } from "#enums/stat"; export function getNatureName(nature: Nature, includeStatEffects: boolean = false, forStarterSelect: boolean = false, ignoreBBCode: boolean = false, uiTheme: UiTheme = UiTheme.DEFAULT): string { let ret = Utils.toReadableString(Nature[nature]); diff --git a/src/data/pokeball.ts b/src/data/pokeball.ts index 447095b0468..49cb0d1bf72 100644 --- a/src/data/pokeball.ts +++ b/src/data/pokeball.ts @@ -3,8 +3,6 @@ import { PokeballType } from "#enums/pokeball"; import BattleScene from "../battle-scene"; import i18next from "i18next"; -export { PokeballType }; - export const MAX_PER_TYPE_POKEBALLS: integer = 99; export function getPokeballAtlasKey(type: PokeballType): string { diff --git a/src/data/pokemon-forms.ts b/src/data/pokemon-forms.ts index 7cc20d50fb9..2db0ed54294 100644 --- a/src/data/pokemon-forms.ts +++ b/src/data/pokemon-forms.ts @@ -1,8 +1,8 @@ import { PokemonFormChangeItemModifier, TerastallizeModifier } from "../modifier/modifier"; import Pokemon from "../field/pokemon"; -import { StatusEffect } from "./status-effect"; +import { StatusEffect } from "#enums/status-effect"; import { MoveCategory, allMoves } from "./move"; -import { Type } from "./type"; +import { Type } from "#enums/type"; import { Constructor, nil } from "#app/utils"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; @@ -10,7 +10,7 @@ import { Species } from "#enums/species"; import { TimeOfDay } from "#enums/time-of-day"; import { getPokemonNameWithAffix } from "#app/messages"; import i18next from "i18next"; -import { WeatherType } from "./weather"; +import { WeatherType } from "#enums/weather-type"; import { Challenges } from "#app/enums/challenges"; import { SpeciesFormKey } from "#enums/species-form-key"; diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index 0cdeef10d9e..e7fe902956c 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -12,7 +12,7 @@ import { uncatchableSpecies } from "#app/data/balance/biomes"; import { speciesEggMoves } from "#app/data/balance/egg-moves"; import { GrowthRate } from "#app/data/exp"; import { EvolutionLevel, SpeciesWildEvolutionDelay, pokemonEvolutions, pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { LevelMoves, pokemonFormLevelMoves, pokemonFormLevelMoves as pokemonSpeciesFormLevelMoves, pokemonSpeciesLevelMoves } from "#app/data/balance/pokemon-level-moves"; import { Stat } from "#enums/stat"; import { Variant, VariantSet, variantColorCache, variantData } from "#app/data/variant"; diff --git a/src/data/status-effect.ts b/src/data/status-effect.ts index 56e754ac407..6b4e1d546df 100644 --- a/src/data/status-effect.ts +++ b/src/data/status-effect.ts @@ -2,8 +2,6 @@ import { randIntRange } from "#app/utils"; import { StatusEffect } from "#enums/status-effect"; import i18next, { ParseKeys } from "i18next"; -export { StatusEffect }; - export class Status { public effect: StatusEffect; /** Toxic damage is `1/16 max HP * toxicTurnCount` */ diff --git a/src/data/terrain.ts b/src/data/terrain.ts index 0bee1ddc7a9..6ba9acfd166 100644 --- a/src/data/terrain.ts +++ b/src/data/terrain.ts @@ -1,6 +1,6 @@ import Pokemon from "../field/pokemon"; import Move from "./move"; -import { Type } from "./type"; +import { Type } from "#enums/type"; import { ProtectAttr } from "./move"; import { BattlerIndex } from "#app/battle"; import i18next from "i18next"; diff --git a/src/data/trainer-config.ts b/src/data/trainer-config.ts index 18bcec1f928..d82d568ecc6 100644 --- a/src/data/trainer-config.ts +++ b/src/data/trainer-config.ts @@ -2,11 +2,11 @@ import BattleScene, { startingWave } from "#app/battle-scene"; import { ModifierTypeFunc, modifierTypes } from "#app/modifier/modifier-type"; import { EnemyPokemon, PokemonMove } from "#app/field/pokemon"; import * as Utils from "#app/utils"; -import { PokeballType } from "#app/data/pokeball"; +import { PokeballType } from "#enums/pokeball"; import { pokemonEvolutions, pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions"; import PokemonSpecies, { getPokemonSpecies, PokemonSpeciesFilter } from "#app/data/pokemon-species"; import { tmSpecies } from "#app/data/balance/tms"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { doubleBattleDialogue } from "#app/data/dialogue"; import { PersistentModifier } from "#app/modifier/modifier"; import { TrainerVariant } from "#app/field/trainer"; diff --git a/src/data/type.ts b/src/data/type.ts index 483ec068d3c..6170eadc91e 100644 --- a/src/data/type.ts +++ b/src/data/type.ts @@ -1,25 +1,4 @@ -export enum Type { - UNKNOWN = -1, - NORMAL = 0, - FIGHTING, - FLYING, - POISON, - GROUND, - ROCK, - BUG, - GHOST, - STEEL, - FIRE, - WATER, - GRASS, - ELECTRIC, - PSYCHIC, - ICE, - DRAGON, - DARK, - FAIRY, - STELLAR -} +import { Type } from "#enums/type"; export type TypeDamageMultiplier = 0 | 0.125 | 0.25 | 0.5 | 1 | 2 | 4 | 8; diff --git a/src/data/weather.ts b/src/data/weather.ts index 20c03af77c8..0a76a015402 100644 --- a/src/data/weather.ts +++ b/src/data/weather.ts @@ -2,7 +2,7 @@ import { Biome } from "#enums/biome"; import { WeatherType } from "#enums/weather-type"; import { getPokemonNameWithAffix } from "../messages"; import Pokemon from "../field/pokemon"; -import { Type } from "./type"; +import { Type } from "#enums/type"; import Move, { AttackMove } from "./move"; import * as Utils from "../utils"; import BattleScene from "../battle-scene"; @@ -10,7 +10,6 @@ import { SuppressWeatherEffectAbAttr } from "./ability"; import { TerrainType, getTerrainName } from "./terrain"; import i18next from "i18next"; -export { WeatherType }; export class Weather { public weatherType: WeatherType; public turnsLeft: integer; diff --git a/src/enums/type.ts b/src/enums/type.ts new file mode 100644 index 00000000000..a04849c2ca3 --- /dev/null +++ b/src/enums/type.ts @@ -0,0 +1,22 @@ +export enum Type { + UNKNOWN = -1, + NORMAL = 0, + FIGHTING, + FLYING, + POISON, + GROUND, + ROCK, + BUG, + GHOST, + STEEL, + FIRE, + WATER, + GRASS, + ELECTRIC, + PSYCHIC, + ICE, + DRAGON, + DARK, + FAIRY, + STELLAR +} diff --git a/src/events/arena.ts b/src/events/arena.ts index c05e67d353c..b1126e5c03d 100644 --- a/src/events/arena.ts +++ b/src/events/arena.ts @@ -1,7 +1,7 @@ import { ArenaTagSide } from "#app/data/arena-tag"; import { ArenaTagType } from "#enums/arena-tag-type"; import { TerrainType } from "#app/data/terrain"; -import { WeatherType } from "#app/data/weather"; +import { WeatherType } from "#enums/weather-type"; /** Alias for all {@linkcode ArenaEvent} type strings */ export enum ArenaEventType { diff --git a/src/field/anims.ts b/src/field/anims.ts index c73c52027c5..dddf38e4a7e 100644 --- a/src/field/anims.ts +++ b/src/field/anims.ts @@ -1,5 +1,5 @@ import BattleScene from "../battle-scene"; -import { PokeballType } from "../data/pokeball"; +import { PokeballType } from "#enums/pokeball"; import * as Utils from "../utils"; export function addPokeballOpenParticles(scene: BattleScene, x: number, y: number, pokeballType: PokeballType): void { diff --git a/src/field/arena.ts b/src/field/arena.ts index abc2b89569c..da74063ac06 100644 --- a/src/field/arena.ts +++ b/src/field/arena.ts @@ -3,9 +3,9 @@ import { biomePokemonPools, BiomePoolTier, BiomeTierTrainerPools, biomeTrainerPo import { Constructor } from "#app/utils"; import * as Utils from "#app/utils"; import PokemonSpecies, { getPokemonSpecies } from "#app/data/pokemon-species"; -import { getTerrainClearMessage, getTerrainStartMessage, getWeatherClearMessage, getWeatherStartMessage, Weather, WeatherType } from "#app/data/weather"; +import { getTerrainClearMessage, getTerrainStartMessage, getWeatherClearMessage, getWeatherStartMessage, Weather } from "#app/data/weather"; import { CommonAnim } from "#app/data/battle-anims"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import Move from "#app/data/move"; import { ArenaTag, ArenaTagSide, ArenaTrapTag, getArenaTag } from "#app/data/arena-tag"; import { BattlerIndex } from "#app/battle"; @@ -31,6 +31,7 @@ import { Abilities } from "#enums/abilities"; import { SpeciesFormChangeRevertWeatherFormTrigger, SpeciesFormChangeWeatherTrigger } from "#app/data/pokemon-forms"; import { CommonAnimPhase } from "#app/phases/common-anim-phase"; import { ShowAbilityPhase } from "#app/phases/show-ability-phase"; +import { WeatherType } from "#enums/weather-type"; export class Arena { public scene: BattleScene; diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 45c9caf7477..e0b7bf1094f 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -9,18 +9,19 @@ import { CLASSIC_CANDY_FRIENDSHIP_MULTIPLIER, getStarterValueFriendshipCap, spec import { starterPassiveAbilities } from "#app/data/balance/passives"; import { Constructor, isNullOrUndefined, randSeedInt, type nil } from "#app/utils"; import * as Utils from "#app/utils"; -import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from "#app/data/type"; +import { TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from "#app/data/type"; +import { Type } from "#enums/type"; import { getLevelTotalExp } from "#app/data/exp"; import { Stat, type PermanentStat, type BattleStat, type EffectiveStat, PERMANENT_STATS, BATTLE_STATS, EFFECTIVE_STATS } from "#enums/stat"; import { DamageMoneyRewardModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, HiddenAbilityRateBoosterModifier, BaseStatModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonNatureWeightModifier, ShinyRateBoosterModifier, SurviveDamageModifier, TempStatStageBoosterModifier, TempCritBoosterModifier, StatBoosterModifier, CritBoosterModifier, TerastallizeModifier, PokemonBaseStatFlatModifier, PokemonBaseStatTotalModifier, PokemonIncrementingStatModifier, EvoTrackerModifier, PokemonMultiHitModifier } from "#app/modifier/modifier"; -import { PokeballType } from "#app/data/pokeball"; +import { PokeballType } from "#enums/pokeball"; import { Gender } from "#app/data/gender"; import { initMoveAnim, loadMoveAnimAssets } from "#app/data/battle-anims"; -import { Status, StatusEffect, getRandomStatus } from "#app/data/status-effect"; +import { Status, getRandomStatus } from "#app/data/status-effect"; import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEvolutionCondition, FusionSpeciesFormEvolution } from "#app/data/balance/pokemon-evolutions"; import { reverseCompatibleTms, tmSpecies, tmPoolTiers } from "#app/data/balance/tms"; import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, SubstituteTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag, MoveRestrictionBattlerTag, ExposedTag, DragonCheerTag, CritBoostTag, TrappedTag, TarShotTag, AutotomizedTag, PowerTrickTag } from "../data/battler-tags"; -import { WeatherType } from "#app/data/weather"; +import { WeatherType } from "#enums/weather-type"; import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "#app/data/arena-tag"; import { Ability, AbAttr, StatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatStagesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldStatMultiplierAbAttrs, FieldMultiplyStatAbAttr, AddSecondStrikeAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr, FullHpResistTypeAbAttr, applyCheckTrappedAbAttrs, CheckTrappedAbAttr, PostSetStatusAbAttr, applyPostSetStatusAbAttrs, InfiltratorAbAttr, AlliedFieldDamageReductionAbAttr, PostDamageAbAttr, applyPostDamageAbAttrs, PostDamageForceSwitchAbAttr } from "#app/data/ability"; import PokemonData from "#app/system/pokemon-data"; @@ -32,7 +33,7 @@ import { LevelMoves } from "#app/data/balance/pokemon-level-moves"; import { DamageAchv, achvs } from "#app/system/achv"; import { DexAttr, StarterDataEntry, StarterMoveset } from "#app/system/game-data"; import { QuantizerCelebi, argbFromRgba, rgbaFromArgb } from "@material/material-color-utilities"; -import { Nature, getNatureStatMultiplier } from "#app/data/nature"; +import { getNatureStatMultiplier } from "#app/data/nature"; import { SpeciesFormChange, SpeciesFormChangeActiveTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangeStatusEffectTrigger } from "#app/data/pokemon-forms"; import { TerrainType } from "#app/data/terrain"; import { TrainerSlot } from "#app/data/trainer-config"; @@ -66,6 +67,8 @@ import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import { SwitchType } from "#enums/switch-type"; import { SpeciesFormKey } from "#enums/species-form-key"; import { BASE_HIDDEN_ABILITY_CHANCE, BASE_SHINY_CHANCE, SHINY_EPIC_CHANCE, SHINY_VARIANT_CHANCE } from "#app/data/balance/rates"; +import { Nature } from "#enums/nature"; +import { StatusEffect } from "#enums/status-effect"; export enum FieldPosition { CENTER, diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index dfa46ce3667..571c54d76e9 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -3,30 +3,31 @@ import { EvolutionItem, pokemonEvolutions } from "#app/data/balance/pokemon-evol import { tmPoolTiers, tmSpecies } from "#app/data/balance/tms"; import { getBerryEffectDescription, getBerryName } from "#app/data/berry"; import { allMoves, AttackMove, selfStatLowerMoves } from "#app/data/move"; -import { getNatureName, getNatureStatMultiplier, Nature } from "#app/data/nature"; -import { getPokeballCatchMultiplier, getPokeballName, MAX_PER_TYPE_POKEBALLS, PokeballType } from "#app/data/pokeball"; +import { getNatureName, getNatureStatMultiplier } from "#app/data/nature"; +import { getPokeballCatchMultiplier, getPokeballName, MAX_PER_TYPE_POKEBALLS } from "#app/data/pokeball"; import { FormChangeItem, pokemonFormChanges, SpeciesFormChangeCondition, SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms"; -import { getStatusEffectDescriptor, StatusEffect } from "#app/data/status-effect"; -import { Type } from "#app/data/type"; +import { getStatusEffectDescriptor } from "#app/data/status-effect"; +import { Type } from "#enums/type"; import Pokemon, { EnemyPokemon, PlayerPokemon, PokemonMove } from "#app/field/pokemon"; import { getPokemonNameWithAffix } from "#app/messages"; -import { - AddPokeballModifier, AddVoucherModifier, AttackTypeBoosterModifier, BaseStatModifier, BerryModifier, BoostBugSpawnModifier, BypassSpeedChanceModifier, ContactHeldItemTransferChanceModifier, CritBoosterModifier, DamageMoneyRewardModifier, DoubleBattleChanceBoosterModifier, EnemyAttackStatusEffectChanceModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, EvolutionItemModifier, EvolutionStatBoosterModifier, EvoTrackerModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, FusePokemonModifier, GigantamaxAccessModifier, HealingBoosterModifier, HealShopCostModifier, HiddenAbilityRateBoosterModifier, HitHealModifier, IvScannerModifier, LevelIncrementBoosterModifier, LockModifierTiersModifier, MapModifier, MegaEvolutionAccessModifier, MoneyInterestModifier, MoneyMultiplierModifier, MoneyRewardModifier, MultipleParticipantExpBonusModifier, PokemonAllMovePpRestoreModifier, PokemonBaseStatFlatModifier, PokemonBaseStatTotalModifier, PokemonExpBoosterModifier, PokemonFormChangeItemModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonHpRestoreModifier, PokemonIncrementingStatModifier, PokemonInstantReviveModifier, PokemonLevelIncrementModifier, PokemonMoveAccuracyBoosterModifier, PokemonMultiHitModifier, PokemonNatureChangeModifier, PokemonNatureWeightModifier, PokemonPpRestoreModifier, PokemonPpUpModifier, PokemonStatusHealModifier, PreserveBerryModifier, RememberMoveModifier, ResetNegativeStatStageModifier, ShinyRateBoosterModifier, SpeciesCritBoosterModifier, SpeciesStatBoosterModifier, SurviveDamageModifier, SwitchEffectTransferModifier, TempCritBoosterModifier, TempStatStageBoosterModifier, TerastallizeAccessModifier, TerastallizeModifier, TmModifier, TurnHealModifier, TurnHeldItemTransferModifier, TurnStatusEffectModifier, type EnemyPersistentModifier, type Modifier, type PersistentModifier, TempExtraModifierModifier -} from "#app/modifier/modifier"; +import { AddPokeballModifier, AddVoucherModifier, AttackTypeBoosterModifier, BaseStatModifier, BerryModifier, BoostBugSpawnModifier, BypassSpeedChanceModifier, ContactHeldItemTransferChanceModifier, CritBoosterModifier, DamageMoneyRewardModifier, DoubleBattleChanceBoosterModifier, EnemyAttackStatusEffectChanceModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, EvolutionItemModifier, EvolutionStatBoosterModifier, EvoTrackerModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, FusePokemonModifier, GigantamaxAccessModifier, HealingBoosterModifier, HealShopCostModifier, HiddenAbilityRateBoosterModifier, HitHealModifier, IvScannerModifier, LevelIncrementBoosterModifier, LockModifierTiersModifier, MapModifier, MegaEvolutionAccessModifier, MoneyInterestModifier, MoneyMultiplierModifier, MoneyRewardModifier, MultipleParticipantExpBonusModifier, PokemonAllMovePpRestoreModifier, PokemonBaseStatFlatModifier, PokemonBaseStatTotalModifier, PokemonExpBoosterModifier, PokemonFormChangeItemModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonHpRestoreModifier, PokemonIncrementingStatModifier, PokemonInstantReviveModifier, PokemonLevelIncrementModifier, PokemonMoveAccuracyBoosterModifier, PokemonMultiHitModifier, PokemonNatureChangeModifier, PokemonNatureWeightModifier, PokemonPpRestoreModifier, PokemonPpUpModifier, PokemonStatusHealModifier, PreserveBerryModifier, RememberMoveModifier, ResetNegativeStatStageModifier, ShinyRateBoosterModifier, SpeciesCritBoosterModifier, SpeciesStatBoosterModifier, SurviveDamageModifier, SwitchEffectTransferModifier, TempCritBoosterModifier, TempStatStageBoosterModifier, TerastallizeAccessModifier, TerastallizeModifier, TmModifier, TurnHealModifier, TurnHeldItemTransferModifier, TurnStatusEffectModifier, type EnemyPersistentModifier, type Modifier, type PersistentModifier, TempExtraModifierModifier } from "#app/modifier/modifier"; import { ModifierTier } from "#app/modifier/modifier-tier"; import Overrides from "#app/overrides"; import { Unlockables } from "#app/system/unlockables"; import { getVoucherTypeIcon, getVoucherTypeName, VoucherType } from "#app/system/voucher"; import PartyUiHandler, { PokemonMoveSelectFilter, PokemonSelectFilter } from "#app/ui/party-ui-handler"; import { getModifierTierTextTint } from "#app/ui/text"; -import { formatMoney, getEnumKeys, getEnumValues, IntegerHolder, isNullOrUndefined, NumberHolder, padInt, randSeedInt, randSeedItem } from "#app/utils"; +import { formatMoney, getEnumKeys, getEnumValues, isNullOrUndefined, NumberHolder, padInt, randSeedInt, randSeedItem } from "#app/utils"; import { Abilities } from "#enums/abilities"; import { BattlerTagType } from "#enums/battler-tag-type"; import { BerryType } from "#enums/berry-type"; import { Moves } from "#enums/moves"; +import { Nature } from "#enums/nature"; +import { PokeballType } from "#enums/pokeball"; import { Species } from "#enums/species"; import { SpeciesFormKey } from "#enums/species-form-key"; import { getStatKey, PermanentStat, Stat, TEMP_BATTLE_STATS, TempBattleStat } from "#enums/stat"; +import { StatusEffect } from "#enums/status-effect"; import i18next from "i18next"; const outputModifierData = false; @@ -730,7 +731,7 @@ export class MoneyRewardModifierType extends ModifierType { } getDescription(scene: BattleScene): string { - const moneyAmount = new IntegerHolder(scene.getWaveMoneyAmount(this.moneyMultiplier)); + const moneyAmount = new NumberHolder(scene.getWaveMoneyAmount(this.moneyMultiplier)); scene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount); const formattedMoney = formatMoney(scene.moneyFormat, moneyAmount.value); diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index c3b1f15fab4..d2965247826 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -6,7 +6,7 @@ import { allMoves } from "#app/data/move"; import { MAX_PER_TYPE_POKEBALLS } from "#app/data/pokeball"; import { type FormChangeItem, SpeciesFormChangeItemTrigger, SpeciesFormChangeLapseTeraTrigger, SpeciesFormChangeTeraTrigger } from "#app/data/pokemon-forms"; import { getStatusEffectHealText } from "#app/data/status-effect"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import Pokemon, { type PlayerPokemon } from "#app/field/pokemon"; import { getPokemonNameWithAffix } from "#app/messages"; import Overrides from "#app/overrides"; diff --git a/src/phases/command-phase.ts b/src/phases/command-phase.ts index 6163b428603..eab76282908 100644 --- a/src/phases/command-phase.ts +++ b/src/phases/command-phase.ts @@ -7,7 +7,7 @@ import { Abilities } from "#app/enums/abilities"; import { BattlerTagType } from "#app/enums/battler-tag-type"; import { Biome } from "#app/enums/biome"; import { Moves } from "#app/enums/moves"; -import { PokeballType } from "#app/enums/pokeball"; +import { PokeballType } from "#enums/pokeball"; import { FieldPosition, PlayerPokemon } from "#app/field/pokemon"; import { getPokemonNameWithAffix } from "#app/messages"; import { Command } from "#app/ui/command-ui-handler"; diff --git a/src/phases/move-effect-phase.ts b/src/phases/move-effect-phase.ts index 48150ffaf05..ef863d64c50 100644 --- a/src/phases/move-effect-phase.ts +++ b/src/phases/move-effect-phase.ts @@ -43,7 +43,7 @@ import { VariableTargetAttr, } from "#app/data/move"; import { SpeciesFormChangePostMoveTrigger } from "#app/data/pokemon-forms"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import Pokemon, { HitResult, MoveResult, PokemonMove } from "#app/field/pokemon"; import { getPokemonNameWithAffix } from "#app/messages"; import { diff --git a/src/phases/move-phase.ts b/src/phases/move-phase.ts index b11a7d9b711..6bdef281d70 100644 --- a/src/phases/move-phase.ts +++ b/src/phases/move-phase.ts @@ -28,7 +28,7 @@ import { } from "#app/data/move"; import { SpeciesFormChangePreMoveTrigger } from "#app/data/pokemon-forms"; import { getStatusEffectActivationText, getStatusEffectHealText } from "#app/data/status-effect"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { getTerrainBlockMessage } from "#app/data/weather"; import { MoveUsedEvent } from "#app/events/battle-scene"; import Pokemon, { MoveResult, PokemonMove } from "#app/field/pokemon"; diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 4b7eeedfe77..8f179ddb677 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -22,7 +22,7 @@ import { vouchers, VoucherType } from "#app/system/voucher"; import { AES, enc } from "crypto-js"; import { Mode } from "#app/ui/ui"; import { clientSessionId, loggedInUser, updateUserInfo } from "#app/account"; -import { Nature } from "#app/data/nature"; +import { Nature } from "#enums/nature"; import { GameStats } from "#app/system/game-stats"; import { Tutorial } from "#app/tutorial"; import { speciesEggMoves } from "#app/data/balance/egg-moves"; @@ -33,7 +33,7 @@ import { setSettingGamepad, SettingGamepad, settingGamepadDefaults } from "#app/ import { setSettingKeyboard, SettingKeyboard } from "#app/system/settings/settings-keyboard"; import { TagAddedEvent, TerrainChangedEvent, WeatherChangedEvent } from "#app/events/arena"; import * as Modifier from "#app/modifier/modifier"; -import { StatusEffect } from "#app/data/status-effect"; +import { StatusEffect } from "#enums/status-effect"; import ChallengeData from "#app/system/challenge-data"; import { Device } from "#enums/devices"; import { GameDataType } from "#enums/game-data-type"; diff --git a/src/system/pokemon-data.ts b/src/system/pokemon-data.ts index 485c1d90c1d..443382186c7 100644 --- a/src/system/pokemon-data.ts +++ b/src/system/pokemon-data.ts @@ -1,8 +1,8 @@ import { BattleType } from "../battle"; import BattleScene from "../battle-scene"; import { Gender } from "../data/gender"; -import { Nature } from "../data/nature"; -import { PokeballType } from "../data/pokeball"; +import { Nature } from "#enums/nature"; +import { PokeballType } from "#enums/pokeball"; import { getPokemonSpecies } from "../data/pokemon-species"; import { Status } from "../data/status-effect"; import Pokemon, { EnemyPokemon, PokemonMove, PokemonSummonData } from "../field/pokemon"; diff --git a/src/test/abilities/battle_bond.test.ts b/src/test/abilities/battle_bond.test.ts index e9970e1c049..db7ed01e7d9 100644 --- a/src/test/abilities/battle_bond.test.ts +++ b/src/test/abilities/battle_bond.test.ts @@ -1,8 +1,9 @@ import { allMoves, MultiHitAttr, MultiHitType } from "#app/data/move"; -import { Status, StatusEffect } from "#app/data/status-effect"; +import { Status } from "#app/data/status-effect"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; import GameManager from "#test/utils/gameManager"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/src/test/abilities/disguise.test.ts b/src/test/abilities/disguise.test.ts index f44782207cb..07a84bd7a5a 100644 --- a/src/test/abilities/disguise.test.ts +++ b/src/test/abilities/disguise.test.ts @@ -1,10 +1,10 @@ import { BattlerIndex } from "#app/battle"; -import { StatusEffect } from "#app/data/status-effect"; import { toDmgValue } from "#app/utils"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { Stat } from "#enums/stat"; +import { StatusEffect } from "#enums/status-effect"; import GameManager from "#test/utils/gameManager"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/abilities/flash_fire.test.ts b/src/test/abilities/flash_fire.test.ts index f03e1689649..0ca55227ea4 100644 --- a/src/test/abilities/flash_fire.test.ts +++ b/src/test/abilities/flash_fire.test.ts @@ -1,11 +1,11 @@ import { BattlerIndex } from "#app/battle"; -import { StatusEffect } from "#app/data/status-effect"; import { BattlerTagType } from "#app/enums/battler-tag-type"; import { Species } from "#app/enums/species"; import { MovePhase } from "#app/phases/move-phase"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; +import { StatusEffect } from "#enums/status-effect"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/abilities/galvanize.test.ts b/src/test/abilities/galvanize.test.ts index 438f166174d..80e767866ea 100644 --- a/src/test/abilities/galvanize.test.ts +++ b/src/test/abilities/galvanize.test.ts @@ -1,6 +1,6 @@ import { BattlerIndex } from "#app/battle"; import { allMoves } from "#app/data/move"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { Abilities } from "#app/enums/abilities"; import { Moves } from "#app/enums/moves"; import { Species } from "#app/enums/species"; diff --git a/src/test/abilities/libero.test.ts b/src/test/abilities/libero.test.ts index aac1cb16d97..e7bc9eeeb63 100644 --- a/src/test/abilities/libero.test.ts +++ b/src/test/abilities/libero.test.ts @@ -1,6 +1,6 @@ import { allMoves } from "#app/data/move"; -import { Type } from "#app/data/type"; -import { Weather, WeatherType } from "#app/data/weather"; +import { Type } from "#enums/type"; +import { Weather } from "#app/data/weather"; import { PlayerPokemon } from "#app/field/pokemon"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; @@ -8,6 +8,7 @@ import { BattlerTagType } from "#enums/battler-tag-type"; import { Biome } from "#enums/biome"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { WeatherType } from "#enums/weather-type"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; diff --git a/src/test/abilities/magic_guard.test.ts b/src/test/abilities/magic_guard.test.ts index 8075eac66f2..7c038354748 100644 --- a/src/test/abilities/magic_guard.test.ts +++ b/src/test/abilities/magic_guard.test.ts @@ -1,12 +1,13 @@ import { ArenaTagSide, getArenaTag } from "#app/data/arena-tag"; -import { StatusEffect, getStatusEffectCatchRateMultiplier } from "#app/data/status-effect"; -import { WeatherType } from "#app/data/weather"; +import { getStatusEffectCatchRateMultiplier } from "#app/data/status-effect"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { ArenaTagType } from "#enums/arena-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; +import { WeatherType } from "#enums/weather-type"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/abilities/mimicry.test.ts b/src/test/abilities/mimicry.test.ts index 8f22de33061..29aa1d649d3 100644 --- a/src/test/abilities/mimicry.test.ts +++ b/src/test/abilities/mimicry.test.ts @@ -1,7 +1,7 @@ import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/abilities/parental_bond.test.ts b/src/test/abilities/parental_bond.test.ts index 993a5eb8344..d8f952ae6ad 100644 --- a/src/test/abilities/parental_bond.test.ts +++ b/src/test/abilities/parental_bond.test.ts @@ -1,11 +1,11 @@ -import { Stat } from "#enums/stat"; -import { StatusEffect } from "#app/data/status-effect"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { BattlerTagType } from "#app/enums/battler-tag-type"; import { toDmgValue } from "#app/utils"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { Stat } from "#enums/stat"; +import { StatusEffect } from "#enums/status-effect"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/abilities/pastel_veil.test.ts b/src/test/abilities/pastel_veil.test.ts index 6f09fd8ff06..dd8360493a1 100644 --- a/src/test/abilities/pastel_veil.test.ts +++ b/src/test/abilities/pastel_veil.test.ts @@ -1,10 +1,10 @@ import { BattlerIndex } from "#app/battle"; -import { StatusEffect } from "#app/data/status-effect"; import { Abilities } from "#app/enums/abilities"; import { CommandPhase } from "#app/phases/command-phase"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/abilities/power_construct.test.ts b/src/test/abilities/power_construct.test.ts index bb80e9f3ac8..aaab5ddb5c4 100644 --- a/src/test/abilities/power_construct.test.ts +++ b/src/test/abilities/power_construct.test.ts @@ -1,9 +1,10 @@ -import { Status, StatusEffect } from "#app/data/status-effect"; +import { Status } from "#app/data/status-effect"; import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; import GameManager from "#test/utils/gameManager"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; diff --git a/src/test/abilities/protean.test.ts b/src/test/abilities/protean.test.ts index 5f86ec4c6e6..0d7202e3f6d 100644 --- a/src/test/abilities/protean.test.ts +++ b/src/test/abilities/protean.test.ts @@ -1,6 +1,6 @@ import { allMoves } from "#app/data/move"; -import { Type } from "#app/data/type"; -import { Weather, WeatherType } from "#app/data/weather"; +import { Type } from "#enums/type"; +import { Weather } from "#app/data/weather"; import { PlayerPokemon } from "#app/field/pokemon"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; @@ -8,6 +8,7 @@ import { BattlerTagType } from "#enums/battler-tag-type"; import { Biome } from "#enums/biome"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { WeatherType } from "#enums/weather-type"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; diff --git a/src/test/abilities/sand_veil.test.ts b/src/test/abilities/sand_veil.test.ts index c62357f17af..ee8ca450df9 100644 --- a/src/test/abilities/sand_veil.test.ts +++ b/src/test/abilities/sand_veil.test.ts @@ -1,12 +1,12 @@ import { StatMultiplierAbAttr, allAbilities } from "#app/data/ability"; -import { Stat } from "#enums/stat"; -import { WeatherType } from "#app/data/weather"; import { CommandPhase } from "#app/phases/command-phase"; import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { MoveEndPhase } from "#app/phases/move-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { Stat } from "#enums/stat"; +import { WeatherType } from "#enums/weather-type"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; diff --git a/src/test/abilities/schooling.test.ts b/src/test/abilities/schooling.test.ts index 5f953dbf9ab..e1ec58f517e 100644 --- a/src/test/abilities/schooling.test.ts +++ b/src/test/abilities/schooling.test.ts @@ -1,9 +1,10 @@ -import { Status, StatusEffect } from "#app/data/status-effect"; +import { Status } from "#app/data/status-effect"; import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; import GameManager from "#test/utils/gameManager"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; diff --git a/src/test/abilities/shields_down.test.ts b/src/test/abilities/shields_down.test.ts index fbb2e96e463..6100d3e04d9 100644 --- a/src/test/abilities/shields_down.test.ts +++ b/src/test/abilities/shields_down.test.ts @@ -1,9 +1,10 @@ -import { Status, StatusEffect } from "#app/data/status-effect"; +import { Status } from "#app/data/status-effect"; import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; import GameManager from "#test/utils/gameManager"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; diff --git a/src/test/abilities/synchronize.test.ts b/src/test/abilities/synchronize.test.ts index f30ab9d3db4..2ae80ae9c7a 100644 --- a/src/test/abilities/synchronize.test.ts +++ b/src/test/abilities/synchronize.test.ts @@ -1,7 +1,7 @@ -import { StatusEffect } from "#app/data/status-effect"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/abilities/zen_mode.test.ts b/src/test/abilities/zen_mode.test.ts index 74575415788..4ba5e3d5929 100644 --- a/src/test/abilities/zen_mode.test.ts +++ b/src/test/abilities/zen_mode.test.ts @@ -1,5 +1,5 @@ import { BattlerIndex } from "#app/battle"; -import { Status, StatusEffect } from "#app/data/status-effect"; +import { Status } from "#app/data/status-effect"; import { DamagePhase } from "#app/phases/damage-phase"; import { SwitchSummonPhase } from "#app/phases/switch-summon-phase"; import { Mode } from "#app/ui/ui"; @@ -7,6 +7,7 @@ import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { Stat } from "#enums/stat"; +import { StatusEffect } from "#enums/status-effect"; import { SwitchType } from "#enums/switch-type"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; diff --git a/src/test/abilities/zero_to_hero.test.ts b/src/test/abilities/zero_to_hero.test.ts index 160b43abf1e..5702f73e6c4 100644 --- a/src/test/abilities/zero_to_hero.test.ts +++ b/src/test/abilities/zero_to_hero.test.ts @@ -1,9 +1,10 @@ -import { Status, StatusEffect } from "#app/data/status-effect"; +import { Status } from "#app/data/status-effect"; import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; import GameManager from "#test/utils/gameManager"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/arena/weather_fog.test.ts b/src/test/arena/weather_fog.test.ts index db591dda2b8..8c1fcb1e3a4 100644 --- a/src/test/arena/weather_fog.test.ts +++ b/src/test/arena/weather_fog.test.ts @@ -1,9 +1,9 @@ import { allMoves } from "#app/data/move"; -import { WeatherType } from "#app/data/weather"; import { Abilities } from "#app/enums/abilities"; import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { WeatherType } from "#enums/weather-type"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/src/test/arena/weather_hail.test.ts b/src/test/arena/weather_hail.test.ts index b8f4276a3d9..0b267550d75 100644 --- a/src/test/arena/weather_hail.test.ts +++ b/src/test/arena/weather_hail.test.ts @@ -1,10 +1,10 @@ -import { WeatherType } from "#app/data/weather"; +import { BattlerIndex } from "#app/battle"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { WeatherType } from "#enums/weather-type"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { BattlerIndex } from "#app/battle"; describe("Weather - Hail", () => { let phaserGame: Phaser.Game; diff --git a/src/test/arena/weather_sandstorm.test.ts b/src/test/arena/weather_sandstorm.test.ts index 09d0c1d2b77..17ccfdee94b 100644 --- a/src/test/arena/weather_sandstorm.test.ts +++ b/src/test/arena/weather_sandstorm.test.ts @@ -1,8 +1,8 @@ -import { WeatherType } from "#app/data/weather"; import { Abilities } from "#app/enums/abilities"; import { Stat } from "#app/enums/stat"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { WeatherType } from "#enums/weather-type"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/battle/double_battle.test.ts b/src/test/battle/double_battle.test.ts index a7585d55bab..1fc24bfc027 100644 --- a/src/test/battle/double_battle.test.ts +++ b/src/test/battle/double_battle.test.ts @@ -1,8 +1,9 @@ -import { Status, StatusEffect } from "#app/data/status-effect"; +import { Status } from "#app/data/status-effect"; import { BattleEndPhase } from "#app/phases/battle-end-phase"; import { TurnInitPhase } from "#app/phases/turn-init-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/battle/inverse_battle.test.ts b/src/test/battle/inverse_battle.test.ts index 110f92d15b7..0bda678bbd3 100644 --- a/src/test/battle/inverse_battle.test.ts +++ b/src/test/battle/inverse_battle.test.ts @@ -1,5 +1,5 @@ import { BattlerIndex } from "#app/battle"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { Abilities } from "#enums/abilities"; import { ArenaTagType } from "#enums/arena-tag-type"; import { Challenges } from "#enums/challenges"; diff --git a/src/test/data/status-effect.test.ts b/src/test/data/status-effect.test.ts index 1b1a97fc51f..4831e8de5de 100644 --- a/src/test/data/status-effect.test.ts +++ b/src/test/data/status-effect.test.ts @@ -1,6 +1,5 @@ import { Status, - StatusEffect, getStatusEffectActivationText, getStatusEffectDescriptor, getStatusEffectHealText, @@ -11,6 +10,7 @@ import { MoveResult } from "#app/field/pokemon"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; import GameManager from "#test/utils/gameManager"; import { mockI18next } from "#test/utils/testUtils"; import i18next from "i18next"; diff --git a/src/test/field/pokemon.test.ts b/src/test/field/pokemon.test.ts index ce9862e22e4..0bfbd03e9d9 100644 --- a/src/test/field/pokemon.test.ts +++ b/src/test/field/pokemon.test.ts @@ -1,7 +1,7 @@ import { Species } from "#app/enums/species"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import GameManager from "../utils/gameManager"; -import { PokeballType } from "#app/enums/pokeball"; +import { PokeballType } from "#enums/pokeball"; import BattleScene from "#app/battle-scene"; import { Moves } from "#app/enums/moves"; diff --git a/src/test/final_boss.test.ts b/src/test/final_boss.test.ts index de2cddff944..5540d9511e4 100644 --- a/src/test/final_boss.test.ts +++ b/src/test/final_boss.test.ts @@ -1,12 +1,12 @@ -import { StatusEffect } from "#app/data/status-effect"; -import { Abilities } from "#app/enums/abilities"; -import { Biome } from "#app/enums/biome"; -import { Moves } from "#app/enums/moves"; -import { Species } from "#app/enums/species"; import { GameModes } from "#app/game-mode"; import { TurnHeldItemTransferModifier } from "#app/modifier/modifier"; +import { Abilities } from "#enums/abilities"; +import { Biome } from "#enums/biome"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; +import GameManager from "#test/utils/gameManager"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import GameManager from "./utils/gameManager"; const FinalWave = { Classic: 200, diff --git a/src/test/items/toxic_orb.test.ts b/src/test/items/toxic_orb.test.ts index 583e302126c..6918d7f34f0 100644 --- a/src/test/items/toxic_orb.test.ts +++ b/src/test/items/toxic_orb.test.ts @@ -1,8 +1,8 @@ -import { StatusEffect } from "#app/data/status-effect"; import i18next from "#app/plugins/i18n"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/src/test/moves/aurora_veil.test.ts b/src/test/moves/aurora_veil.test.ts index e68117a2f59..2d7484b4eb5 100644 --- a/src/test/moves/aurora_veil.test.ts +++ b/src/test/moves/aurora_veil.test.ts @@ -1,13 +1,13 @@ import { ArenaTagSide } from "#app/data/arena-tag"; import Move, { allMoves } from "#app/data/move"; -import { WeatherType } from "#app/data/weather"; -import { Abilities } from "#app/enums/abilities"; import { ArenaTagType } from "#app/enums/arena-tag-type"; import Pokemon from "#app/field/pokemon"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { NumberHolder } from "#app/utils"; +import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { WeatherType } from "#enums/weather-type"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/moves/camouflage.test.ts b/src/test/moves/camouflage.test.ts index acf37635c47..5773afffcc3 100644 --- a/src/test/moves/camouflage.test.ts +++ b/src/test/moves/camouflage.test.ts @@ -2,7 +2,7 @@ import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { TerrainType } from "#app/data/terrain"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { BattlerIndex } from "#app/battle"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; diff --git a/src/test/moves/dragon_cheer.test.ts b/src/test/moves/dragon_cheer.test.ts index 37b74d44360..750f09214ca 100644 --- a/src/test/moves/dragon_cheer.test.ts +++ b/src/test/moves/dragon_cheer.test.ts @@ -1,5 +1,5 @@ import { BattlerIndex } from "#app/battle"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { Moves } from "#app/enums/moves"; import { Species } from "#app/enums/species"; import { Abilities } from "#enums/abilities"; diff --git a/src/test/moves/dragon_rage.test.ts b/src/test/moves/dragon_rage.test.ts index 595f347a6b5..e8185f013e5 100644 --- a/src/test/moves/dragon_rage.test.ts +++ b/src/test/moves/dragon_rage.test.ts @@ -1,5 +1,5 @@ import { Stat } from "#enums/stat"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { Species } from "#app/enums/species"; import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; import { modifierTypes } from "#app/modifier/modifier-type"; diff --git a/src/test/moves/effectiveness.test.ts b/src/test/moves/effectiveness.test.ts index d1903c79844..829d4533f9b 100644 --- a/src/test/moves/effectiveness.test.ts +++ b/src/test/moves/effectiveness.test.ts @@ -1,7 +1,7 @@ import { allMoves } from "#app/data/move"; import { getPokemonSpecies } from "#app/data/pokemon-species"; import { TrainerSlot } from "#app/data/trainer-config"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { Abilities } from "#app/enums/abilities"; import { Moves } from "#app/enums/moves"; import { Species } from "#app/enums/species"; diff --git a/src/test/moves/electrify.test.ts b/src/test/moves/electrify.test.ts index 5d15a825688..8015dd0a74d 100644 --- a/src/test/moves/electrify.test.ts +++ b/src/test/moves/electrify.test.ts @@ -1,5 +1,5 @@ import { BattlerIndex } from "#app/battle"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; diff --git a/src/test/moves/flower_shield.test.ts b/src/test/moves/flower_shield.test.ts index 1a5cd326fd8..4c03df5212b 100644 --- a/src/test/moves/flower_shield.test.ts +++ b/src/test/moves/flower_shield.test.ts @@ -1,6 +1,6 @@ import { Stat } from "#enums/stat"; import { SemiInvulnerableTag } from "#app/data/battler-tags"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { Biome } from "#app/enums/biome"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; diff --git a/src/test/moves/forests_curse.test.ts b/src/test/moves/forests_curse.test.ts index c49bdab5255..010b00599a5 100644 --- a/src/test/moves/forests_curse.test.ts +++ b/src/test/moves/forests_curse.test.ts @@ -1,7 +1,7 @@ import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/moves/fusion_flare.test.ts b/src/test/moves/fusion_flare.test.ts index 162cefcfb1e..75641c04d02 100644 --- a/src/test/moves/fusion_flare.test.ts +++ b/src/test/moves/fusion_flare.test.ts @@ -1,7 +1,7 @@ -import { StatusEffect } from "#app/data/status-effect"; import { TurnStartPhase } from "#app/phases/turn-start-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/moves/heal_block.test.ts b/src/test/moves/heal_block.test.ts index 252533215a8..25f2076ff3e 100644 --- a/src/test/moves/heal_block.test.ts +++ b/src/test/moves/heal_block.test.ts @@ -1,12 +1,12 @@ import { BattlerIndex } from "#app/battle"; import { ArenaTagSide } from "#app/data/arena-tag"; -import { WeatherType } from "#app/data/weather"; import GameManager from "#app/test/utils/gameManager"; import { Abilities } from "#enums/abilities"; import { ArenaTagType } from "#enums/arena-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { WeatherType } from "#enums/weather-type"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/moves/nightmare.test.ts b/src/test/moves/nightmare.test.ts index f4c485ff1b4..850b0793b1e 100644 --- a/src/test/moves/nightmare.test.ts +++ b/src/test/moves/nightmare.test.ts @@ -1,7 +1,7 @@ -import { StatusEffect } from "#app/data/status-effect"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/moves/plasma_fists.test.ts b/src/test/moves/plasma_fists.test.ts index 24210cd47fa..4075c1ab988 100644 --- a/src/test/moves/plasma_fists.test.ts +++ b/src/test/moves/plasma_fists.test.ts @@ -1,5 +1,5 @@ import { BattlerIndex } from "#app/battle"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; diff --git a/src/test/moves/pledge_moves.test.ts b/src/test/moves/pledge_moves.test.ts index 93fcf57cc60..64d586e7ba4 100644 --- a/src/test/moves/pledge_moves.test.ts +++ b/src/test/moves/pledge_moves.test.ts @@ -2,7 +2,7 @@ import { BattlerIndex } from "#app/battle"; import { allAbilities } from "#app/data/ability"; import { ArenaTagSide } from "#app/data/arena-tag"; import { allMoves, FlinchAttr } from "#app/data/move"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { ArenaTagType } from "#enums/arena-tag-type"; import { Stat } from "#enums/stat"; import { toDmgValue } from "#app/utils"; diff --git a/src/test/moves/purify.test.ts b/src/test/moves/purify.test.ts index 3b07eafd75a..171f94a611a 100644 --- a/src/test/moves/purify.test.ts +++ b/src/test/moves/purify.test.ts @@ -1,9 +1,10 @@ import { BattlerIndex } from "#app/battle"; -import { Status, StatusEffect } from "#app/data/status-effect"; +import { Status } from "#app/data/status-effect"; import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; import { MoveEndPhase } from "#app/phases/move-end-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; diff --git a/src/test/moves/reflect_type.test.ts b/src/test/moves/reflect_type.test.ts index 0e47d4b00fc..50e0fc2fbe6 100644 --- a/src/test/moves/reflect_type.test.ts +++ b/src/test/moves/reflect_type.test.ts @@ -1,7 +1,7 @@ import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/moves/relic_song.test.ts b/src/test/moves/relic_song.test.ts index eb877b6054d..c09514850eb 100644 --- a/src/test/moves/relic_song.test.ts +++ b/src/test/moves/relic_song.test.ts @@ -1,4 +1,4 @@ -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { Challenges } from "#app/enums/challenges"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; diff --git a/src/test/moves/roost.test.ts b/src/test/moves/roost.test.ts index e595f879844..69301dc86cf 100644 --- a/src/test/moves/roost.test.ts +++ b/src/test/moves/roost.test.ts @@ -1,5 +1,5 @@ import { BattlerIndex } from "#app/battle"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { BattlerTagType } from "#app/enums/battler-tag-type"; import { Moves } from "#app/enums/moves"; import { Species } from "#app/enums/species"; diff --git a/src/test/moves/substitute.test.ts b/src/test/moves/substitute.test.ts index 92f66c967c4..14ab4ab5054 100644 --- a/src/test/moves/substitute.test.ts +++ b/src/test/moves/substitute.test.ts @@ -2,7 +2,11 @@ import { BattlerIndex } from "#app/battle"; import { ArenaTagSide } from "#app/data/arena-tag"; import { SubstituteTag, TrappedTag } from "#app/data/battler-tags"; import { allMoves, StealHeldItemChanceAttr } from "#app/data/move"; -import { StatusEffect } from "#app/data/status-effect"; +import { MoveResult } from "#app/field/pokemon"; +import { CommandPhase } from "#app/phases/command-phase"; +import GameManager from "#app/test/utils/gameManager"; +import { Command } from "#app/ui/command-ui-handler"; +import { Mode } from "#app/ui/ui"; import { Abilities } from "#enums/abilities"; import { ArenaTagType } from "#enums/arena-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type"; @@ -10,11 +14,7 @@ import { BerryType } from "#enums/berry-type"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { Stat } from "#enums/stat"; -import { MoveResult } from "#app/field/pokemon"; -import { CommandPhase } from "#app/phases/command-phase"; -import GameManager from "#app/test/utils/gameManager"; -import { Command } from "#app/ui/command-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { StatusEffect } from "#enums/status-effect"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/src/test/moves/tar_shot.test.ts b/src/test/moves/tar_shot.test.ts index 4734da366e4..5fb70abc19c 100644 --- a/src/test/moves/tar_shot.test.ts +++ b/src/test/moves/tar_shot.test.ts @@ -1,5 +1,5 @@ import { BattlerIndex } from "#app/battle"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { Moves } from "#app/enums/moves"; import { Species } from "#app/enums/species"; import { Stat } from "#app/enums/stat"; diff --git a/src/test/moves/tera_blast.test.ts b/src/test/moves/tera_blast.test.ts index 0ce8a552105..311ac0f0d0e 100644 --- a/src/test/moves/tera_blast.test.ts +++ b/src/test/moves/tera_blast.test.ts @@ -1,7 +1,7 @@ import { BattlerIndex } from "#app/battle"; import { Stat } from "#enums/stat"; import { allMoves } from "#app/data/move"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { Abilities } from "#app/enums/abilities"; import { HitResult } from "#app/field/pokemon"; import { Moves } from "#enums/moves"; diff --git a/src/test/moves/tera_starstorm.test.ts b/src/test/moves/tera_starstorm.test.ts index c7b6b66c1ce..22dd5b3c4d1 100644 --- a/src/test/moves/tera_starstorm.test.ts +++ b/src/test/moves/tera_starstorm.test.ts @@ -1,5 +1,5 @@ import { BattlerIndex } from "#app/battle"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; diff --git a/src/test/moves/thunder_wave.test.ts b/src/test/moves/thunder_wave.test.ts index 03e9ebb94f3..5551451e59b 100644 --- a/src/test/moves/thunder_wave.test.ts +++ b/src/test/moves/thunder_wave.test.ts @@ -1,8 +1,8 @@ -import { StatusEffect } from "#app/data/status-effect"; -import { Abilities } from "#app/enums/abilities"; import { EnemyPokemon } from "#app/field/pokemon"; +import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/moves/toxic_spikes.test.ts b/src/test/moves/toxic_spikes.test.ts index a5c63a2652f..bdd59ed0ac8 100644 --- a/src/test/moves/toxic_spikes.test.ts +++ b/src/test/moves/toxic_spikes.test.ts @@ -1,10 +1,10 @@ import { ArenaTagSide, ArenaTrapTag } from "#app/data/arena-tag"; -import { StatusEffect } from "#app/data/status-effect"; import { decrypt, encrypt, GameData, SessionSaveData } from "#app/system/game-data"; import { Abilities } from "#enums/abilities"; import { ArenaTagType } from "#enums/arena-tag-type"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/moves/trick_or_treat.test.ts b/src/test/moves/trick_or_treat.test.ts index 7ecd00ed076..5c85cac05e2 100644 --- a/src/test/moves/trick_or_treat.test.ts +++ b/src/test/moves/trick_or_treat.test.ts @@ -1,7 +1,7 @@ import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/mystery-encounter/encounter-test-utils.ts b/src/test/mystery-encounter/encounter-test-utils.ts index f95a442d4c2..cd2fd2db042 100644 --- a/src/test/mystery-encounter/encounter-test-utils.ts +++ b/src/test/mystery-encounter/encounter-test-utils.ts @@ -1,18 +1,19 @@ -import { Button } from "#app/enums/buttons"; -import { MysteryEncounterBattlePhase, MysteryEncounterOptionSelectedPhase, MysteryEncounterPhase, MysteryEncounterRewardsPhase } from "#app/phases/mystery-encounter-phases"; -import MysteryEncounterUiHandler from "#app/ui/mystery-encounter-ui-handler"; -import { Mode } from "#app/ui/ui"; -import GameManager from "../utils/gameManager"; -import MessageUiHandler from "#app/ui/message-ui-handler"; -import { Status, StatusEffect } from "#app/data/status-effect"; -import { expect, vi } from "vitest"; import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils"; +import { Status } from "#app/data/status-effect"; +import { CommandPhase } from "#app/phases/command-phase"; +import { MessagePhase } from "#app/phases/message-phase"; +import { MysteryEncounterBattlePhase, MysteryEncounterOptionSelectedPhase, MysteryEncounterPhase, MysteryEncounterRewardsPhase } from "#app/phases/mystery-encounter-phases"; +import { VictoryPhase } from "#app/phases/victory-phase"; +import MessageUiHandler from "#app/ui/message-ui-handler"; +import MysteryEncounterUiHandler from "#app/ui/mystery-encounter-ui-handler"; import PartyUiHandler from "#app/ui/party-ui-handler"; import OptionSelectUiHandler from "#app/ui/settings/option-select-ui-handler"; +import { Mode } from "#app/ui/ui"; import { isNullOrUndefined } from "#app/utils"; -import { CommandPhase } from "#app/phases/command-phase"; -import { VictoryPhase } from "#app/phases/victory-phase"; -import { MessagePhase } from "#app/phases/message-phase"; +import { Button } from "#enums/buttons"; +import { StatusEffect } from "#enums/status-effect"; +import GameManager from "#test/utils/gameManager"; +import { expect, vi } from "vitest"; /** * Runs a {@linkcode MysteryEncounter} to either the start of a battle, or to the {@linkcode MysteryEncounterRewardsPhase}, depending on the option selected diff --git a/src/test/mystery-encounter/encounters/clowning-around-encounter.test.ts b/src/test/mystery-encounter/encounters/clowning-around-encounter.test.ts index 7ea1f883bd1..a403a306b3d 100644 --- a/src/test/mystery-encounter/encounters/clowning-around-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/clowning-around-encounter.test.ts @@ -27,7 +27,7 @@ import OptionSelectUiHandler from "#app/ui/settings/option-select-ui-handler"; import { modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type"; import { BerryType } from "#enums/berry-type"; import { PokemonHeldItemModifier } from "#app/modifier/modifier"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { CommandPhase } from "#app/phases/command-phase"; import { MovePhase } from "#app/phases/move-phase"; import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; diff --git a/src/test/mystery-encounter/encounters/fiery-fallout-encounter.test.ts b/src/test/mystery-encounter/encounters/fiery-fallout-encounter.test.ts index 92555e98679..215cab5c65a 100644 --- a/src/test/mystery-encounter/encounters/fiery-fallout-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/fiery-fallout-encounter.test.ts @@ -1,8 +1,8 @@ import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encounters"; -import { Biome } from "#app/enums/biome"; -import { MysteryEncounterType } from "#app/enums/mystery-encounter-type"; -import { Species } from "#app/enums/species"; -import GameManager from "#app/test/utils/gameManager"; +import { Biome } from "#enums/biome"; +import { MysteryEncounterType } from "#enums/mystery-encounter-type"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { FieryFalloutEncounter } from "#app/data/mystery-encounters/encounters/fiery-fallout-encounter"; import { Gender } from "#app/data/gender"; @@ -13,8 +13,8 @@ import { runMysteryEncounterToEnd, runSelectMysteryEncounterOption, skipBattleRu import { Moves } from "#enums/moves"; import BattleScene from "#app/battle-scene"; import { AttackTypeBoosterModifier, PokemonHeldItemModifier } from "#app/modifier/modifier"; -import { Type } from "#app/data/type"; -import { Status, StatusEffect } from "#app/data/status-effect"; +import { Type } from "#enums/type"; +import { Status } from "#app/data/status-effect"; import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; @@ -25,6 +25,7 @@ import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; import { BattlerTagType } from "#enums/battler-tag-type"; import { Abilities } from "#enums/abilities"; import i18next from "i18next"; +import { StatusEffect } from "#enums/status-effect"; const namespace = "mysteryEncounters/fieryFallout"; /** Arcanine and Ninetails for 2 Fire types. Lapras, Gengar, Abra for burnable mon. */ diff --git a/src/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts b/src/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts index be0e6e68b5e..ae725f3480a 100644 --- a/src/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts @@ -1,8 +1,8 @@ import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encounters"; -import { Biome } from "#app/enums/biome"; -import { MysteryEncounterType } from "#app/enums/mystery-encounter-type"; -import { Species } from "#app/enums/species"; -import GameManager from "#app/test/utils/gameManager"; +import { Biome } from "#enums/biome"; +import { MysteryEncounterType } from "#enums/mystery-encounter-type"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { getPokemonSpecies } from "#app/data/pokemon-species"; import * as BattleAnims from "#app/data/battle-anims"; @@ -11,7 +11,7 @@ import { runMysteryEncounterToEnd, skipBattleRunMysteryEncounterRewardsPhase } f import { Moves } from "#enums/moves"; import BattleScene from "#app/battle-scene"; import { TheStrongStuffEncounter } from "#app/data/mystery-encounters/encounters/the-strong-stuff-encounter"; -import { Nature } from "#app/data/nature"; +import { Nature } from "#enums/nature"; import { BerryType } from "#enums/berry-type"; import { BattlerTagType } from "#enums/battler-tag-type"; import { PokemonMove } from "#app/field/pokemon"; @@ -25,7 +25,7 @@ import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import { CommandPhase } from "#app/phases/command-phase"; import { MovePhase } from "#app/phases/move-phase"; import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; -import { Abilities } from "#app/enums/abilities"; +import { Abilities } from "#enums/abilities"; const namespace = "mysteryEncounters/theStrongStuff"; const defaultParty = [ Species.LAPRAS, Species.GENGAR, Species.ABRA ]; diff --git a/src/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts b/src/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts index 2653b76ab7c..701a3c94add 100644 --- a/src/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts @@ -1,9 +1,9 @@ import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encounters"; import { HUMAN_TRANSITABLE_BIOMES } from "#app/data/mystery-encounters/mystery-encounters"; -import { Biome } from "#app/enums/biome"; -import { MysteryEncounterType } from "#app/enums/mystery-encounter-type"; -import { Species } from "#app/enums/species"; -import GameManager from "#app/test/utils/gameManager"; +import { Biome } from "#enums/biome"; +import { MysteryEncounterType } from "#enums/mystery-encounter-type"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { runMysteryEncounterToEnd } from "#test/mystery-encounter/encounter-test-utils"; import BattleScene from "#app/battle-scene"; @@ -19,12 +19,13 @@ import { Nature } from "#enums/nature"; import { Moves } from "#enums/moves"; import { getPokemonSpecies } from "#app/data/pokemon-species"; import { TheWinstrateChallengeEncounter } from "#app/data/mystery-encounters/encounters/the-winstrate-challenge-encounter"; -import { Status, StatusEffect } from "#app/data/status-effect"; +import { Status } from "#app/data/status-effect"; import { MysteryEncounterRewardsPhase } from "#app/phases/mystery-encounter-phases"; import { CommandPhase } from "#app/phases/command-phase"; import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; import { PartyHealPhase } from "#app/phases/party-heal-phase"; import { VictoryPhase } from "#app/phases/victory-phase"; +import { StatusEffect } from "#enums/status-effect"; const namespace = "mysteryEncounters/theWinstrateChallenge"; const defaultParty = [ Species.LAPRAS, Species.GENGAR, Species.ABRA ]; diff --git a/src/test/mystery-encounter/mystery-encounter-utils.test.ts b/src/test/mystery-encounter/mystery-encounter-utils.test.ts index b57a88d5cad..ab2d5f052c0 100644 --- a/src/test/mystery-encounter/mystery-encounter-utils.test.ts +++ b/src/test/mystery-encounter/mystery-encounter-utils.test.ts @@ -1,17 +1,17 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import GameManager from "#app/test/utils/gameManager"; -import Phaser from "phaser"; -import { initSceneWithoutEncounterPhase } from "#test/utils/gameManagerUtils"; -import { Species } from "#enums/species"; import BattleScene from "#app/battle-scene"; -import { StatusEffect } from "#app/data/status-effect"; -import MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; -import { getPokemonSpecies } from "#app/data/pokemon-species"; import { speciesStarterCosts } from "#app/data/balance/starters"; -import { Type } from "#app/data/type"; -import { getHighestLevelPlayerPokemon, getLowestLevelPlayerPokemon, getRandomPlayerPokemon, getRandomSpeciesByStarterTier, koPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; +import MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; import { getEncounterText, queueEncounterMessage, showEncounterDialogue, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; +import { getHighestLevelPlayerPokemon, getLowestLevelPlayerPokemon, getRandomPlayerPokemon, getRandomSpeciesByStarterTier, koPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; +import { getPokemonSpecies } from "#app/data/pokemon-species"; +import { Type } from "#enums/type"; import { MessagePhase } from "#app/phases/message-phase"; +import GameManager from "#app/test/utils/gameManager"; +import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; +import { initSceneWithoutEncounterPhase } from "#test/utils/gameManagerUtils"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; describe("Mystery Encounter Utils", () => { let phaserGame: Phaser.Game; diff --git a/src/test/phases/form-change-phase.test.ts b/src/test/phases/form-change-phase.test.ts index 70ca429672f..3c0016260a3 100644 --- a/src/test/phases/form-change-phase.test.ts +++ b/src/test/phases/form-change-phase.test.ts @@ -4,7 +4,7 @@ import { Species } from "#enums/species"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { generateModifierType } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { modifierTypes } from "#app/modifier/modifier-type"; diff --git a/src/test/ui/starter-select.test.ts b/src/test/ui/starter-select.test.ts index 8f86d62c546..15af3619ed3 100644 --- a/src/test/ui/starter-select.test.ts +++ b/src/test/ui/starter-select.test.ts @@ -1,5 +1,5 @@ import { Gender } from "#app/data/gender"; -import { Nature } from "#app/data/nature"; +import { Nature } from "#enums/nature"; import { allSpecies } from "#app/data/pokemon-species"; import { GameModes } from "#app/game-mode"; import { EncounterPhase } from "#app/phases/encounter-phase"; diff --git a/src/test/utils/helpers/overridesHelper.ts b/src/test/utils/helpers/overridesHelper.ts index 404f5c34a26..02950d497ee 100644 --- a/src/test/utils/helpers/overridesHelper.ts +++ b/src/test/utils/helpers/overridesHelper.ts @@ -1,19 +1,20 @@ -import { StatusEffect } from "#app/data/status-effect"; -import { Weather, WeatherType } from "#app/data/weather"; +import { Variant } from "#app/data/variant"; +import { Weather } from "#app/data/weather"; import { Abilities } from "#app/enums/abilities"; -import { Biome } from "#app/enums/biome"; -import { Moves } from "#app/enums/moves"; -import { Species } from "#app/enums/species"; import * as GameMode from "#app/game-mode"; import { GameModes, getGameMode } from "#app/game-mode"; import { ModifierOverride } from "#app/modifier/modifier-type"; import Overrides from "#app/overrides"; +import { Unlockables } from "#app/system/unlockables"; +import { Biome } from "#enums/biome"; +import { Moves } from "#enums/moves"; +import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; +import { MysteryEncounterType } from "#enums/mystery-encounter-type"; +import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; +import type { WeatherType } from "#enums/weather-type"; import { vi } from "vitest"; import { GameManagerHelper } from "./gameManagerHelper"; -import { Unlockables } from "#app/system/unlockables"; -import { Variant } from "#app/data/variant"; -import { MysteryEncounterType } from "#enums/mystery-encounter-type"; -import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; /** * Helper to handle overrides in tests diff --git a/src/ui/arena-flyout.ts b/src/ui/arena-flyout.ts index a82f97244cd..573cb85db70 100644 --- a/src/ui/arena-flyout.ts +++ b/src/ui/arena-flyout.ts @@ -1,7 +1,7 @@ import { addTextObject, TextStyle } from "./text"; import BattleScene from "#app/battle-scene"; import { ArenaTagSide, ArenaTrapTag } from "#app/data/arena-tag"; -import { WeatherType } from "#app/data/weather"; +import { WeatherType } from "#enums/weather-type"; import { TerrainType } from "#app/data/terrain"; import { addWindow, WindowVariant } from "./ui-theme"; import { ArenaEvent, ArenaEventType, TagAddedEvent, TagRemovedEvent, TerrainChangedEvent, WeatherChangedEvent } from "#app/events/arena"; diff --git a/src/ui/battle-info.ts b/src/ui/battle-info.ts index 1d97998f491..72447988bdd 100644 --- a/src/ui/battle-info.ts +++ b/src/ui/battle-info.ts @@ -3,9 +3,10 @@ import { getLevelTotalExp, getLevelRelExp } from "../data/exp"; import * as Utils from "../utils"; import { addTextObject, TextStyle } from "./text"; import { getGenderSymbol, getGenderColor, Gender } from "../data/gender"; -import { StatusEffect } from "../data/status-effect"; +import { StatusEffect } from "#enums/status-effect"; import BattleScene from "../battle-scene"; -import { Type, getTypeRgb } from "../data/type"; +import { getTypeRgb } from "#app/data/type"; +import { Type } from "#enums/type"; import { getVariantTint } from "#app/data/variant"; import { Stat } from "#enums/stat"; import BattleFlyout from "./battle-flyout"; diff --git a/src/ui/fight-ui-handler.ts b/src/ui/fight-ui-handler.ts index ee6641a1a27..eaf504495d5 100644 --- a/src/ui/fight-ui-handler.ts +++ b/src/ui/fight-ui-handler.ts @@ -1,6 +1,7 @@ import BattleScene, { InfoToggle } from "../battle-scene"; import { addTextObject, TextStyle } from "./text"; -import { getTypeDamageMultiplierColor, Type } from "../data/type"; +import { getTypeDamageMultiplierColor } from "#app/data/type"; +import { Type } from "#enums/type"; import { Command } from "./command-ui-handler"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; diff --git a/src/ui/modifier-select-ui-handler.ts b/src/ui/modifier-select-ui-handler.ts index 3f89ebe415f..a0358b5ca8c 100644 --- a/src/ui/modifier-select-ui-handler.ts +++ b/src/ui/modifier-select-ui-handler.ts @@ -1,6 +1,6 @@ import BattleScene from "../battle-scene"; import { getPlayerShopModifierTypeOptionsForWave, ModifierTypeOption, TmModifierType } from "../modifier/modifier-type"; -import { getPokeballAtlasKey, PokeballType } from "../data/pokeball"; +import { getPokeballAtlasKey } from "#app/data/pokeball"; import { addTextObject, getTextStyleOptions, getModifierTierTextTint, getTextColor, TextStyle } from "./text"; import AwaitableUiHandler from "./awaitable-ui-handler"; import { Mode } from "./ui"; @@ -15,6 +15,7 @@ import i18next from "i18next"; import { ShopCursorTarget } from "#app/enums/shop-cursor-target"; import { IntegerHolder } from "./../utils"; import Phaser from "phaser"; +import type { PokeballType } from "#enums/pokeball"; export const SHOP_OPTIONS_ROW_LIMIT = 7; const SINGLE_SHOP_ROW_YOFFSET = 12; diff --git a/src/ui/move-info-overlay.ts b/src/ui/move-info-overlay.ts index 6c58d32c515..d9c4200ea9b 100644 --- a/src/ui/move-info-overlay.ts +++ b/src/ui/move-info-overlay.ts @@ -3,7 +3,7 @@ import { TextStyle, addTextObject } from "./text"; import { addWindow } from "./ui-theme"; import * as Utils from "../utils"; import Move, { MoveCategory } from "../data/move"; -import { Type } from "../data/type"; +import { Type } from "#enums/type"; import i18next from "i18next"; export interface MoveInfoOverlaySettings { diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index a26aa572ef3..bd3561dd0b4 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -8,7 +8,7 @@ import * as Utils from "#app/utils"; import { PokemonFormChangeItemModifier, PokemonHeldItemModifier, SwitchEffectTransferModifier } from "#app/modifier/modifier"; import { allMoves, ForceSwitchOutAttr } from "#app/data/move"; import { getGenderColor, getGenderSymbol } from "#app/data/gender"; -import { StatusEffect } from "#app/data/status-effect"; +import { StatusEffect } from "#enums/status-effect"; import PokemonIconAnimHandler, { PokemonIconAnimMode } from "#app/ui/pokemon-icon-anim-handler"; import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; import { addWindow } from "#app/ui/ui-theme"; diff --git a/src/ui/pokemon-hatch-info-container.ts b/src/ui/pokemon-hatch-info-container.ts index 146d70522fd..494855d20fa 100644 --- a/src/ui/pokemon-hatch-info-container.ts +++ b/src/ui/pokemon-hatch-info-container.ts @@ -1,7 +1,7 @@ import PokemonInfoContainer from "#app/ui/pokemon-info-container"; import BattleScene from "#app/battle-scene"; import { Gender } from "#app/data/gender"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import * as Utils from "#app/utils"; import { TextStyle, addTextObject } from "#app/ui/text"; import { speciesEggMoves } from "#app/data/balance/egg-moves"; diff --git a/src/ui/pokemon-info-container.ts b/src/ui/pokemon-info-container.ts index 5b11aff43b1..ead24e6d92f 100644 --- a/src/ui/pokemon-info-container.ts +++ b/src/ui/pokemon-info-container.ts @@ -3,7 +3,7 @@ import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext"; import BattleScene from "../battle-scene"; import { Gender, getGenderColor, getGenderSymbol } from "../data/gender"; import { getNatureName } from "../data/nature"; -import { Type } from "../data/type"; +import { Type } from "#enums/type"; import Pokemon from "../field/pokemon"; import i18next from "i18next"; import { DexAttr, DexEntry, StarterDataEntry } from "../system/game-data"; diff --git a/src/ui/run-info-ui-handler.ts b/src/ui/run-info-ui-handler.ts index 4975f05b8a3..82d390016f7 100644 --- a/src/ui/run-info-ui-handler.ts +++ b/src/ui/run-info-ui-handler.ts @@ -15,7 +15,8 @@ import { TrainerVariant } from "../field/trainer"; import { Challenges } from "#enums/challenges"; import { getLuckString, getLuckTextTint } from "../modifier/modifier-type"; import RoundRectangle from "phaser3-rex-plugins/plugins/roundrectangle"; -import { Type, getTypeRgb } from "../data/type"; +import { getTypeRgb } from "#app/data/type"; +import { Type } from "#enums/type"; import { TypeColor, TypeShadow } from "#app/enums/color"; import { getNatureStatMultiplier, getNatureName } from "../data/nature"; import { getVariantTint } from "#app/data/variant"; diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index bb4dc74d44e..a08b7ceaec6 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -10,13 +10,13 @@ import { speciesEggMoves } from "#app/data/balance/egg-moves"; import { GrowthRate, getGrowthRateColor } from "#app/data/exp"; import { Gender, getGenderColor, getGenderSymbol } from "#app/data/gender"; import { allMoves } from "#app/data/move"; -import { Nature, getNatureName } from "#app/data/nature"; +import { getNatureName } from "#app/data/nature"; import { pokemonFormChanges } from "#app/data/pokemon-forms"; import { LevelMoves, pokemonFormLevelMoves, pokemonSpeciesLevelMoves } from "#app/data/balance/pokemon-level-moves"; import PokemonSpecies, { allSpecies, getPokemonSpeciesForm, getPokerusStarters } from "#app/data/pokemon-species"; import { getStarterValueFriendshipCap, speciesStarterCosts, POKERUS_STARTER_COUNT } from "#app/data/balance/starters"; import { starterPassiveAbilities } from "#app/data/balance/passives"; -import { Type } from "#app/data/type"; +import { Type } from "#enums/type"; import { GameModes } from "#app/game-mode"; import { AbilityAttr, DexAttr, DexAttrProps, DexEntry, StarterMoveset, StarterAttributes, StarterPreferences, StarterPrefs } from "#app/system/game-data"; import { Tutorial, handleTutorial } from "#app/tutorial"; @@ -50,6 +50,7 @@ import { TitlePhase } from "#app/phases/title-phase"; import { Abilities } from "#enums/abilities"; import { getPassiveCandyCount, getValueReductionCandyCounts, getSameSpeciesEggCandyCounts } from "#app/data/balance/starters"; import { BooleanHolder, capitalizeString, fixedInt, getLocalizedSpriteKey, isNullOrUndefined, NumberHolder, padInt, randIntRange, rgbHexToRgba, toReadableString } from "#app/utils"; +import type { Nature } from "#enums/nature"; export type StarterSelectCallback = (starters: Starter[]) => void; diff --git a/src/ui/summary-ui-handler.ts b/src/ui/summary-ui-handler.ts index 4b36867571e..2e05f3de4c1 100644 --- a/src/ui/summary-ui-handler.ts +++ b/src/ui/summary-ui-handler.ts @@ -5,16 +5,17 @@ import * as Utils from "#app/utils"; import { PlayerPokemon, PokemonMove } from "#app/field/pokemon"; import { getStarterValueFriendshipCap, speciesStarterCosts } from "#app/data/balance/starters"; import { argbFromRgba } from "@material/material-color-utilities"; -import { Type, getTypeRgb } from "#app/data/type"; +import { getTypeRgb } from "#app/data/type"; +import { Type } from "#enums/type"; import { TextStyle, addBBCodeTextObject, addTextObject, getBBCodeFrag } from "#app/ui/text"; import Move, { MoveCategory } from "#app/data/move"; import { getPokeballAtlasKey } from "#app/data/pokeball"; import { getGenderColor, getGenderSymbol } from "#app/data/gender"; import { getLevelRelExp, getLevelTotalExp } from "#app/data/exp"; import { PokemonHeldItemModifier } from "#app/modifier/modifier"; -import { StatusEffect } from "#app/data/status-effect"; +import { StatusEffect } from "#enums/status-effect"; import { getBiomeName } from "#app/data/balance/biomes"; -import { Nature, getNatureName, getNatureStatMultiplier } from "#app/data/nature"; +import { getNatureName, getNatureStatMultiplier } from "#app/data/nature"; import { loggedInUser } from "#app/account"; import { Variant, getVariantTint } from "#app/data/variant"; import { Button } from "#enums/buttons"; @@ -23,6 +24,7 @@ import i18next from "i18next"; import { modifierSortFunc } from "#app/modifier/modifier"; import { PlayerGender } from "#enums/player-gender"; import { Stat, PERMANENT_STATS, getStatKey } from "#enums/stat"; +import { Nature } from "#enums/nature"; enum Page { PROFILE, From de4ec5e1cb2d550b9ee9c8803faab4c6fbe552d5 Mon Sep 17 00:00:00 2001 From: AJ Fontaine <36677462+Fontbane@users.noreply.github.com> Date: Sat, 9 Nov 2024 01:38:45 -0500 Subject: [PATCH 23/75] [Feature] [Item] Add Catching Charm item (#4811) * Add catching charm item * Add Catching Charm item * Disable catching charm in item pool when dex isn't full enough * Replace catching charm icon --------- Co-authored-by: Madmadness65 <59298170+Madmadness65@users.noreply.github.com> --- public/images/items.png | Bin 58629 -> 59627 bytes public/images/items/catching_charm.png | Bin 454 -> 322 bytes src/data/pokeball.ts | 3 ++- src/modifier/modifier-type.ts | 4 +++- src/modifier/modifier.ts | 32 +++++++++++++++++++++++++ 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/public/images/items.png b/public/images/items.png index cb4f8fa7d065f53b4861bc32eb0867b9eda94b5d..191766f520e852149c71b728781f7feb401f4514 100644 GIT binary patch literal 59627 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 X1m@~7!j6GBz~zy~6ZIN3n^*q_+l|+J delta 58282 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
RY4!*yekQ&gfCG%r@kb`(v^8OaANm<<#%b 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
  • _n(YR4Gokl~ClQ$4;Z#bnwLvU#*=}H89kgbNdPS zu^E1Jci%?JBgm}~i#pe#C>j8`{U?e433~%2mSb$rDfiW?&+(vaV*1SZ_}jV@URdqB zw)f+GFiO3 zz9hr=f-J-Z#l$qkDWfi$MFbtO>C!aV>}PL73~I@iwv9Qv$|4NgK^<}IUE6KZ2r9Lc$+;L`6j(VwfA69p(12Kyx_v6J^^>x4PWE&WlvaEC zMVo=k6<_o3VmU5c>)ISD$7vU8$UQGSoZ}Gb8+>auZgpG-EmA2=MAA{+!YNGWZn@qa z+6+9AgH@E0GRdEw)&LfgeAfLt!G;aE@(&hSo%>@0hX9XkloTHfS7LK-A@L_-yTRI<rH1_C#Sko>A?yXPBxeX8|#y1ERg=HhN1@0O%7u2u^=SV2i9cl$`91iw_K zArGH}PB5iHI6Cd^nve(GU0`q(hON1Sc3oZ6U|Yzlc^$PI-R3e=m2^>5yRD$R*uX05-f7Y??vuTZ`-j0&F1AqO1XVcT;e~x zPM6TleF1NBjL}c)I>#JXw-bX6^x`nF6X?|IPCDh}6c8Yf3cI}d?Dofz^rGd^czB~O zBzcNa&EU+{K9J=DP7m$euH{)L?Xxwc@hr?!NIfXGHQ{>0m(kHN$G;!seNuyZj-xWa zf3zcL>vJ+Cg}2+8UPlwyMfS0uvpVc*q|0k#i?CQNK+mN|Mf`w=gl*{#ejz)bzbmYFIBpL3< zzo?$bg?EFOt)mX}X61_8iXjutvBrOi_XO7v&E5H%YW5#U86UvZ0+W31nz(u?M0)Qr z$soCWQh$Ypak9s7BewD{?OYD%8gDAs~5}P51&2!L_*rokZudu`YQs7!eriC zvW})IDN>Z+>NCnJOp92g*?gLswZB|b%|%Hu(F9oJ6r~K-`6BFWi?bf{yyp=89Y~mF zKBlQtzkCB13hKNK+D2^t z8L8CJSW8MuT1(Qf0;(Wq?|R)rSHQ43Dp((>?D$?BhlDnMz6xGqKTV%Mg7qpfQm}xD zu_g{PfqO0vZV86`#Qi3LKTL1RYrH6lBASrKdidHnEP5&Gp%pL5#jk;=JN{UygTgU(8+{FX; z1<>M4A-fe;6SzPg9QT6QI*r@L!?xzaV-KqKe%VDEZSR%q6^h~wD_i6yI$V16%$ZBT z18itj_{Bx|#U{P2J8^s@!r;k9hz0zi*)8u(Iw#vc>!*Q9(~Wk7^tZCJnWiY76h_Kq zgSbM8l+Pz~r0}e4;1xG)V1bv4dIvCrEp{B21vE4$Ktgc`JHKVgseD}Ga6@q{%v;~5 z9!xflD%x(kRQ0T#oupQ&QmKS0bonQ9{N0pQY>pjEzJqHON|G5X-SpZ%DN!R~gCu5O z#9C9gdoEL5x6Z#$wK94&$?!&_>%@65Ij(q_hXikZL5yta`xn@|kKwU!aS1i}rMnS2n66mRQX zWy=!bCp)18FO|NwRotRr-qTcYsm5B=*95ruMJyW);?|c4Iw?}31hM1oWuxO9{G|1!X8sz!?k8Q=0Nl=IbCl>T*XyCbz~4V-0&{W+@~dv?6n!)Bd~%%k;wy0|&Lmx+?aST8 z5jkP+ku9W3@j4@nfmy)W-JQBlF!HefWw9Rlf|t%N9RY1p_605K)(exn?@mVE>3C&( zhD8NaF|XM0we8Mx5xF0KO4n&+=9tA}n{wg$oqOBjkj`lFM}Zz6UQL)>EOyBUwuWZo z-6y`{I^f4ZW$#VGIohorSJWNn{a)}dtnoXRZzND5!!c5ic!S8 zZ*_F?Y7tqgXWP>!CvS*8#Rr_ejy}%UN%`^I;c}C)SyQVaVyvv2pBz=a|N94LFVJNF z{k;Y-Hu|{mkC@zVN)DbdY;A77{F@fXn^lFw+{QH5qjkiUA<-uH?_=on>Od8b(8)TB zGu@?ZDP&IJ;fx=*h~rFRv5yWdZ+<4Ic+5+~Q2tp#vR}P#WDRyi-XzS;Vaeqx50OWf z?CJlBHF;IoxsOw({13M*pALu+zI2kb8T@UlBD6<~!VUb_ zrf;aNh7UDVES_+*R$sg&O0;M2O917_(q4a)r>1!JIDhx1KufnDkxarKDP?Dk>$RfmmTDG zWBd^{L|jOcXSYvTt2>gzs_-V}cjy##uH1BiIU;XiXR-u@Jxa)rUK6CG4TODSK?=wD zb}9r!Ce}Eqc$J6zqs(b!N>k&^@h`VCcYJkHsjvFGj59HKz4D>?J@4Z@$<)OWs$?8ko zgD-y2qP6(h=!fYDnL3KBzl9PbfO06I(%x0X+o0p1W&&5hXDGx2v|X&+e_Qnf zGnTjNdQm%Y5%zv}o!}LcRztXE!m+eSDdxywpoY-H<7Qs$DaH7PcSmPu zSEcS3HI`$!ByvB3*Z#eZ=%))I82gb&-{b zU-CrBdalme8pxdu$rAf_do;ijSnAaUd_y*8TZFJk2}fckVYnl4a!7OcE%&Xl{g99? zS~#u--|=t&X>8(Dq`O?tQPz5LV%S)e$oTO?l}0Iz(9;l-{ny#dtM#7YDIxPtPYT(= zCxD3-zUbv`j4NDNSSWf1Tyul(zXHvsK|wxKFRTp^QlzO@g1p3?9*LQwzQ=T0Bu}zE zLdGRhQ$2Xjb^})&N6*SG#KPkv<@cE9OA*DGQHv1igR>7h&J7hUkENuYh}F@>Wua4o z)3g*t=6MibPP%$Pd4Ap>+Q|m{$8szZB_$UBU;^I;Umkz9V2vqnT_3ghk&GLJq@?1m zcXR>#yoNv5vFmT%933ec5Cuoma+UsErBSlA=%o2I6@a`BdMBy%IOY3vyDavCl?uX` z$pIOG(C7)L@2tog7;r@r)cd2-fyBZXMQsfY2vnW|#aem?jdKc(U*~=E#J(+q^(|Uz`c~_&srUn?|)w}-joD0x-j!+@Y=v3Q*1n% zlfN zt0~#oDE9njH@*}DEi!!Bqxs&&-tyQbYxD+Yg0JPcDepFOO9HHN5%!rJ4Yib25kA|(IV1e6zYZben}W7hwkbH=p~_^?I%~R$odS$s15f<(V+L4_gn44 zE24i@HdR*B%OCntfp^o`O1$}>`hN*A$th9!H;$rrxjo=BtO?Lwpf5DXyXDdJqr|ro zwDi|e7LuQnaM6eVJUO?@Yxlff5L416l1UHE-@_6}DKK+))#+ok4~7EcI=_#dO0awy z!!LyjXrgbht_;XDozcV-Eu8qIBo64QP7XLErsA`sFv3U}|l3M3pF~fz@rf8yttui;)ml67u4>9tT{{72xra`Ws zKoAz*FJ!cHbMC1`^!5Qw!2@hZqzh;|hdF*>O=UcX~J=)@^vT168>WP@lci^$dYus(&-_R_JEm);l@Wj&pWPm zZ=c+uBGdh#=lOPeC>9#Z%JJ=Tw>yaFd7N7;A)~*H5{f|j<_|W}+3`jGm+v?~-xV@% zIKd1k-O4B-A(5!AO}Hwo$L3ij{-Y-VNbu9y^m>l6v;+a$xiH$iEL^dA=I2`PDYg)$}7_)bV(8^H$U8deN(b)6c5~z{k#0 zD^b`qZBhQ67uGy6_CBWQqw}gzN}qs-D-e&p048$zfvW1g(sL>; zliNPZj*Sdk*{if5B85pBzpwQ>T(ar<7nqSE_EF^flT(Z!3i#i-dnT8UD=PM?yh6L3 zC}f8PNizAHeU=2ly~QDr2Z^{3RcO98=-?3~wvIHTNJ+AdnY{Q9 zNuoRplQARgjWtj%sm=t6j6V_Vac5B9F=W`ONZ;R>!M-(`&zxo4+B0Kj=|pUND_9Dt z6Ye7jtpkMnNJ%$0tEHr>J>RP+{k&^_aW;Yga*fQb-wEw1Qi{Qcd^PRRpNZl@3jTDy zgUWfwdWq&VGNSWJzc4e#&ZH|f$0kCT*%1Bxp|Aot19V6)cPoMXleu&j@8W%|BZsvn zslPJHz3lP3TkvZ<6klRZ!YiF4f}Ys`-tn%$jJtlete0%za8hsCU~g`qdmY zWD+I&wT@!>`z@5lnTb*HOGv5@=0l#*uw#N&vcGlKm|C+lvI|w5@BRKsyY<}-7!bH~ zk*l-yGp)c{e(2!9m_&Q`VRn!xR_sb@u**%0P1Id%K0DKf-|;{{Q(q^Yqmw{`47rJ& zT~j~i*wl)IWcur3LQIQtV8ce&zWwYy*W}Hp- zm}9T&Q~_T=A47-LZ&ov~!&~JzWO(Gt3YgJF^XiDPDv>`rROqU>oR7?sD}Qk`+8?fW z5K|3Nx}S5+2?i#o%gJ=5YPRF#48psG9)r@&10i%TcSY;XAHThH#{h9*I16VM$o;ou zAPxBUKP0bZQ}uxwesQn^{p z2nYxjG?Wz#jXGB8BK0jh9)&Ro%f+AE+2)Y`_!zu35Pz?oaDd3sT7#4#ieYqUh|fC% zJY9Tz-#(8z1Yr6ltMex9UTIV0F^cQeTT2al^~X~SzMl)QQBe|U5m3UEu(uJB@p?}^ zkuqxXO??kP*eF`nzVh1-%=l6^oFka=Ldm*XnpXt16D8X9skK8kxOYJMU$C#{`M}Fh z$rD=*-OF}0`;$ANZE25D?L~Et(=ty?jVdI)?VDsl`3QJ#CT}q3mKP7l%kPQPNT7GnhjH(Q%ujh)tc2&E38Lee?8^-0+*6}eT<)DmpZA5jg1AU&_lmJo^6vuE n>_abDblLA*_FdRrZX8_pGulWwDrXN7fG-V|$I7LO=-2-Tdgeal diff --git a/public/images/items/catching_charm.png b/public/images/items/catching_charm.png index 9d72fe465e3f1322e38b724e6ec333797e79f5fb..c220ff70c03408c81c400f715fa3d94f0da43788 100644 GIT binary patch delta 306 zcmX@ce28g+WIZzj1B1(wu46!ou{g-xiDBJ2nU_G0L4Z$)E09)DP>?F93dzea&lPcwu{-CPI3BF6xtBu@a z%3Bzf_z&qe%u()^7iN-kO;Y%Kk&*Am+o3K{4mBP#dL*U&?A(Ft`Vz;ZO3GEg+&jN{&7wEltcE*VLSL({Q8KJMeW#*{SzFcr lfYx20yZBNgJkxxA8MJ_G4j=}BOTm*tl&7no%Q~loCIAiueS!c0 delta 439 zcmV;o0Z9JB0>%T78Gi-<0047(dh`GQ0gXvSK~z}7?Uubu#4s4f`zLf4hrlTYI@tXd zR~MmUM^_h5C{Aupy83}|c)N&;gNq0v=W^ia=%{1I4i2w*18+%ly*Af0J%<(^C{4-p z%lkz<0Pt3+m74be{~Mt0q5t@RgD!oa)&b}rf13llJuMhUCw~ce!w_)ISp>*DP7Yzw zNpZ~t!Wuw@nA<}{!WjTTkT4Zx>CkJU^&-@ZQB4g3IRmJIQ6tg`KpBXMd8;YVQ{fDt z5b8h}Z54I!kV%=CFAboc63ver_aR`W+O#Ivv5 zm{Nk#K|pJOsvd{mRGK4%3V?-4=GFjZ7mf8Z5#E47G)rOf_ykO8M=VV24z>O40p7;B z&>XdMbtfU1GHB#L8t}q5YXCn8AwEiA?fgb6hcOwihA?BhwgwPl^K~Mn-}jbz8Us{a hG&=$4LOnna@CPb(llSSAz !!d.caughtAttr); const catchingCharmMultiplier = new NumberHolder(1); - //scene.findModifier(m => m instanceof CriticalCatchChanceBoosterModifier)?.apply(catchingCharmMultiplier); + scene.findModifier(m => m instanceof CriticalCatchChanceBoosterModifier)?.apply(catchingCharmMultiplier); const dexMultiplier = scene.gameMode.isDaily || dexCount > 800 ? 2.5 : dexCount > 600 ? 2 : dexCount > 400 ? 1.5 diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 571c54d76e9..3e459f2dc74 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -10,7 +10,7 @@ import { getStatusEffectDescriptor } from "#app/data/status-effect"; import { Type } from "#enums/type"; import Pokemon, { EnemyPokemon, PlayerPokemon, PokemonMove } from "#app/field/pokemon"; import { getPokemonNameWithAffix } from "#app/messages"; -import { AddPokeballModifier, AddVoucherModifier, AttackTypeBoosterModifier, BaseStatModifier, BerryModifier, BoostBugSpawnModifier, BypassSpeedChanceModifier, ContactHeldItemTransferChanceModifier, CritBoosterModifier, DamageMoneyRewardModifier, DoubleBattleChanceBoosterModifier, EnemyAttackStatusEffectChanceModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, EvolutionItemModifier, EvolutionStatBoosterModifier, EvoTrackerModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, FusePokemonModifier, GigantamaxAccessModifier, HealingBoosterModifier, HealShopCostModifier, HiddenAbilityRateBoosterModifier, HitHealModifier, IvScannerModifier, LevelIncrementBoosterModifier, LockModifierTiersModifier, MapModifier, MegaEvolutionAccessModifier, MoneyInterestModifier, MoneyMultiplierModifier, MoneyRewardModifier, MultipleParticipantExpBonusModifier, PokemonAllMovePpRestoreModifier, PokemonBaseStatFlatModifier, PokemonBaseStatTotalModifier, PokemonExpBoosterModifier, PokemonFormChangeItemModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonHpRestoreModifier, PokemonIncrementingStatModifier, PokemonInstantReviveModifier, PokemonLevelIncrementModifier, PokemonMoveAccuracyBoosterModifier, PokemonMultiHitModifier, PokemonNatureChangeModifier, PokemonNatureWeightModifier, PokemonPpRestoreModifier, PokemonPpUpModifier, PokemonStatusHealModifier, PreserveBerryModifier, RememberMoveModifier, ResetNegativeStatStageModifier, ShinyRateBoosterModifier, SpeciesCritBoosterModifier, SpeciesStatBoosterModifier, SurviveDamageModifier, SwitchEffectTransferModifier, TempCritBoosterModifier, TempStatStageBoosterModifier, TerastallizeAccessModifier, TerastallizeModifier, TmModifier, TurnHealModifier, TurnHeldItemTransferModifier, TurnStatusEffectModifier, type EnemyPersistentModifier, type Modifier, type PersistentModifier, TempExtraModifierModifier } from "#app/modifier/modifier"; +import { AddPokeballModifier, AddVoucherModifier, AttackTypeBoosterModifier, BaseStatModifier, BerryModifier, BoostBugSpawnModifier, BypassSpeedChanceModifier, ContactHeldItemTransferChanceModifier, CritBoosterModifier, DamageMoneyRewardModifier, DoubleBattleChanceBoosterModifier, EnemyAttackStatusEffectChanceModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, EvolutionItemModifier, EvolutionStatBoosterModifier, EvoTrackerModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, FusePokemonModifier, GigantamaxAccessModifier, HealingBoosterModifier, HealShopCostModifier, HiddenAbilityRateBoosterModifier, HitHealModifier, IvScannerModifier, LevelIncrementBoosterModifier, LockModifierTiersModifier, MapModifier, MegaEvolutionAccessModifier, MoneyInterestModifier, MoneyMultiplierModifier, MoneyRewardModifier, MultipleParticipantExpBonusModifier, PokemonAllMovePpRestoreModifier, PokemonBaseStatFlatModifier, PokemonBaseStatTotalModifier, PokemonExpBoosterModifier, PokemonFormChangeItemModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonHpRestoreModifier, PokemonIncrementingStatModifier, PokemonInstantReviveModifier, PokemonLevelIncrementModifier, PokemonMoveAccuracyBoosterModifier, PokemonMultiHitModifier, PokemonNatureChangeModifier, PokemonNatureWeightModifier, PokemonPpRestoreModifier, PokemonPpUpModifier, PokemonStatusHealModifier, PreserveBerryModifier, RememberMoveModifier, ResetNegativeStatStageModifier, ShinyRateBoosterModifier, SpeciesCritBoosterModifier, SpeciesStatBoosterModifier, SurviveDamageModifier, SwitchEffectTransferModifier, TempCritBoosterModifier, TempStatStageBoosterModifier, TerastallizeAccessModifier, TerastallizeModifier, TmModifier, TurnHealModifier, TurnHeldItemTransferModifier, TurnStatusEffectModifier, type EnemyPersistentModifier, type Modifier, type PersistentModifier, TempExtraModifierModifier, CriticalCatchChanceBoosterModifier } from "#app/modifier/modifier"; import { ModifierTier } from "#app/modifier/modifier-tier"; import Overrides from "#app/overrides"; import { Unlockables } from "#app/system/unlockables"; @@ -1554,6 +1554,7 @@ export const modifierTypes = { SHINY_CHARM: () => new ModifierType("modifierType:ModifierType.SHINY_CHARM", "shiny_charm", (type, _args) => new ShinyRateBoosterModifier(type)), ABILITY_CHARM: () => new ModifierType("modifierType:ModifierType.ABILITY_CHARM", "ability_charm", (type, _args) => new HiddenAbilityRateBoosterModifier(type)), + CATCHING_CHARM: () => new ModifierType("modifierType:ModifierType.CATCHING_CHARM", "catching_charm", (type, _args) => new CriticalCatchChanceBoosterModifier(type)), IV_SCANNER: () => new ModifierType("modifierType:ModifierType.IV_SCANNER", "scanner", (type, _args) => new IvScannerModifier(type)), @@ -1791,6 +1792,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.BATON, 2), new WeightedModifierType(modifierTypes.SOUL_DEW, 7), //new WeightedModifierType(modifierTypes.OVAL_CHARM, 6), + new WeightedModifierType(modifierTypes.CATCHING_CHARM, (party: Pokemon[]) => !party[0].scene.gameMode.isFreshStartChallenge() && party[0].scene.gameData.getSpeciesCount(d => !!d.caughtAttr) > 100 ? 4 : 0, 4), new WeightedModifierType(modifierTypes.SOOTHE_BELL, (party: Pokemon[]) => party[0].scene.eventManager.isEventActive() ? 0 : 4), new WeightedModifierType(modifierTypes.ABILITY_CHARM, skipInClassicAfterWave(189, 6)), new WeightedModifierType(modifierTypes.FOCUS_BAND, 5), diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index d2965247826..9e97c866718 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -2957,6 +2957,38 @@ export class ShinyRateBoosterModifier extends PersistentModifier { } } +export class CriticalCatchChanceBoosterModifier extends PersistentModifier { + constructor(type: ModifierType, stackCount?: number) { + super(type, stackCount); + } + + match(modifier: Modifier): boolean { + return modifier instanceof CriticalCatchChanceBoosterModifier; + } + + clone(): CriticalCatchChanceBoosterModifier { + return new CriticalCatchChanceBoosterModifier(this.type, this.stackCount); + } + + /** + * Applies {@linkcode CriticalCatchChanceBoosterModifier} + * @param boost {@linkcode NumberHolder} holding the boost value + * @returns always `true` + */ + override apply(boost: NumberHolder): boolean { + // 1 stack: 2x + // 2 stack: 2.5x + // 3 stack: 3x + boost.value *= 1.5 + this.getStackCount() / 2; + + return true; + } + + getMaxStackCount(scene: BattleScene): number { + return 3; + } +} + export class LockModifierTiersModifier extends PersistentModifier { constructor(type: ModifierType, stackCount?: number) { super(type, stackCount); From c6cc187c96e0543a3d7c2b446890e854529f5b57 Mon Sep 17 00:00:00 2001 From: AJ Fontaine <36677462+Fontbane@users.noreply.github.com> Date: Sat, 9 Nov 2024 04:10:49 -0500 Subject: [PATCH 24/75] [Balance] Modify potion and ether weight funcs (#4829) * Adjust for low HP mons --- src/modifier/modifier-type.ts | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 3e459f2dc74..ae1aef3ff88 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -1621,19 +1621,21 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.POKEBALL, (party: Pokemon[]) => (hasMaximumBalls(party, PokeballType.POKEBALL)) ? 0 : 6, 6), new WeightedModifierType(modifierTypes.RARE_CANDY, 2), new WeightedModifierType(modifierTypes.POTION, (party: Pokemon[]) => { - const thresholdPartyMemberCount = Math.min(party.filter(p => (p.getInverseHp() >= 10 || p.getHpRatio() <= 0.875) && !p.isFainted()).length, 3); + const thresholdPartyMemberCount = Math.min(party.filter(p => (p.getInverseHp() >= 10 && p.getHpRatio() <= 0.875) && !p.isFainted()).length, 3); return thresholdPartyMemberCount * 3; }, 9), new WeightedModifierType(modifierTypes.SUPER_POTION, (party: Pokemon[]) => { - const thresholdPartyMemberCount = Math.min(party.filter(p => (p.getInverseHp() >= 25 || p.getHpRatio() <= 0.75) && !p.isFainted()).length, 3); + const thresholdPartyMemberCount = Math.min(party.filter(p => (p.getInverseHp() >= 25 && p.getHpRatio() <= 0.75) && !p.isFainted()).length, 3); return thresholdPartyMemberCount; }, 3), new WeightedModifierType(modifierTypes.ETHER, (party: Pokemon[]) => { - const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && p.getMoveset().filter(m => m?.ppUsed && (m.getMovePp() - m.ppUsed) <= 5 && m.ppUsed >= Math.floor(m.getMovePp() / 2)).length).length, 3); + const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && !p.getHeldItems().some(m => m instanceof BerryModifier && m.berryType === BerryType.LEPPA) + && p.getMoveset().filter(m => m?.ppUsed && (m.getMovePp() - m.ppUsed) <= 5 && m.ppUsed > Math.floor(m.getMovePp() / 2)).length).length, 3); return thresholdPartyMemberCount * 3; }, 9), new WeightedModifierType(modifierTypes.MAX_ETHER, (party: Pokemon[]) => { - const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && p.getMoveset().filter(m => m?.ppUsed && (m.getMovePp() - m.ppUsed) <= 5 && m.ppUsed >= Math.floor(m.getMovePp() / 2)).length).length, 3); + const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && !p.getHeldItems().some(m => m instanceof BerryModifier && m.berryType === BerryType.LEPPA) + && p.getMoveset().filter(m => m?.ppUsed && (m.getMovePp() - m.ppUsed) <= 5 && m.ppUsed > Math.floor(m.getMovePp() / 2)).length).length, 3); return thresholdPartyMemberCount; }, 3), new WeightedModifierType(modifierTypes.LURE, lureWeightFunc(10, 2)), @@ -1667,11 +1669,11 @@ const modifierPool: ModifierPool = { return party.filter(p => p.isFainted()).length >= Math.ceil(party.length / 2) ? 1 : 0; }, 1), new WeightedModifierType(modifierTypes.HYPER_POTION, (party: Pokemon[]) => { - const thresholdPartyMemberCount = Math.min(party.filter(p => (p.getInverseHp() >= 100 || p.getHpRatio() <= 0.625) && !p.isFainted()).length, 3); + const thresholdPartyMemberCount = Math.min(party.filter(p => (p.getInverseHp() >= 100 && p.getHpRatio() <= 0.625) && !p.isFainted()).length, 3); return thresholdPartyMemberCount * 3; }, 9), new WeightedModifierType(modifierTypes.MAX_POTION, (party: Pokemon[]) => { - const thresholdPartyMemberCount = Math.min(party.filter(p => (p.getInverseHp() >= 150 || p.getHpRatio() <= 0.5) && !p.isFainted()).length, 3); + const thresholdPartyMemberCount = Math.min(party.filter(p => (p.getInverseHp() >= 100 && p.getHpRatio() <= 0.5) && !p.isFainted()).length, 3); return thresholdPartyMemberCount; }, 3), new WeightedModifierType(modifierTypes.FULL_RESTORE, (party: Pokemon[]) => { @@ -1681,15 +1683,17 @@ const modifierPool: ModifierPool = { } return false; })).length, 3); - const thresholdPartyMemberCount = Math.floor((Math.min(party.filter(p => (p.getInverseHp() >= 150 || p.getHpRatio() <= 0.5) && !p.isFainted()).length, 3) + statusEffectPartyMemberCount) / 2); + const thresholdPartyMemberCount = Math.floor((Math.min(party.filter(p => (p.getInverseHp() >= 100 && p.getHpRatio() <= 0.5) && !p.isFainted()).length, 3) + statusEffectPartyMemberCount) / 2); return thresholdPartyMemberCount; }, 3), new WeightedModifierType(modifierTypes.ELIXIR, (party: Pokemon[]) => { - const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && p.getMoveset().filter(m => m?.ppUsed && (m.getMovePp() - m.ppUsed) <= 5 && m.ppUsed >= Math.floor(m.getMovePp() / 2)).length).length, 3); + const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && !p.getHeldItems().some(m => m instanceof BerryModifier && m.berryType === BerryType.LEPPA) + && p.getMoveset().filter(m => m?.ppUsed && (m.getMovePp() - m.ppUsed) <= 5 && m.ppUsed > Math.floor(m.getMovePp() / 2)).length).length, 3); return thresholdPartyMemberCount * 3; }, 9), new WeightedModifierType(modifierTypes.MAX_ELIXIR, (party: Pokemon[]) => { - const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && p.getMoveset().filter(m => m?.ppUsed && (m.getMovePp() - m.ppUsed) <= 5 && m.ppUsed >= Math.floor(m.getMovePp() / 2)).length).length, 3); + const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && !p.getHeldItems().some(m => m instanceof BerryModifier && m.berryType === BerryType.LEPPA) + && p.getMoveset().filter(m => m?.ppUsed && (m.getMovePp() - m.ppUsed) <= 5 && m.ppUsed > Math.floor(m.getMovePp() / 2)).length).length, 3); return thresholdPartyMemberCount; }, 3), new WeightedModifierType(modifierTypes.DIRE_HIT, 4), From c54d21c313a6f3aafff9849b12ca772672689f09 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sat, 9 Nov 2024 10:12:22 -0800 Subject: [PATCH 25/75] [Test] Fix flaky Wimp Out test (#4830) --- src/test/abilities/wimp_out.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/abilities/wimp_out.test.ts b/src/test/abilities/wimp_out.test.ts index 6f56a2f4e7e..df965fc340d 100644 --- a/src/test/abilities/wimp_out.test.ts +++ b/src/test/abilities/wimp_out.test.ts @@ -296,7 +296,9 @@ describe("Abilities - Wimp Out", () => { Species.TYRUNT ]); - game.move.select(Moves.SPLASH); + game.scene.getPlayerPokemon()!.hp *= 0.51; + + game.move.select(Moves.ENDURE); await game.phaseInterceptor.to("TurnEndPhase"); confirmNoSwitch(); From 329e43ad48519486125a54e534b7b6e01d4cac05 Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Sat, 9 Nov 2024 10:13:12 -0800 Subject: [PATCH 26/75] [P2] Removed incorrect calls to `resetBattleData` on switchout (#4828) --- src/field/pokemon.ts | 3 +-- src/phases/switch-summon-phase.ts | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index e0b7bf1094f..5478a6e5aaa 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -4029,8 +4029,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.resetTurnData(); if (clearEffects) { this.destroySubstitute(); - this.resetSummonData(); - this.resetBattleData(); + this.resetSummonData(); // this also calls `resetBattleSummonData` } if (hideInfo) { this.hideInfo(); diff --git a/src/phases/switch-summon-phase.ts b/src/phases/switch-summon-phase.ts index 36db8b7a7e7..51d54315165 100644 --- a/src/phases/switch-summon-phase.ts +++ b/src/phases/switch-summon-phase.ts @@ -138,7 +138,6 @@ export class SwitchSummonPhase extends SummonPhase { switchedInPokemon.setAlpha(0.5); } } else { - switchedInPokemon.resetBattleData(); switchedInPokemon.resetSummonData(); } this.summon(); From a763cd173dbdf193d26c3ace9c569c8a62713b7f Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Sat, 9 Nov 2024 10:14:11 -0800 Subject: [PATCH 27/75] [Beta][P1-3] Fix Commander implementation bugs (#4826) --- src/battle-scene.ts | 18 +++++++++++------- src/field/pokemon.ts | 14 ++++++++++++-- src/phases/check-switch-phase.ts | 22 +++++++++++++--------- src/phases/encounter-phase.ts | 2 -- 4 files changed, 36 insertions(+), 20 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index ed8a79125bc..c5acadc8eb6 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -774,7 +774,7 @@ export default class BattleScene extends SceneBase { /** * @returns An array of {@linkcode PlayerPokemon} filtered from the player's party - * that are {@linkcode PlayerPokemon.isAllowedInBattle | allowed in battle}. + * that are {@linkcode Pokemon.isAllowedInBattle | allowed in battle}. */ public getPokemonAllowedInBattle(): PlayerPokemon[] { return this.getPlayerParty().filter(p => p.isAllowedInBattle()); @@ -1243,23 +1243,27 @@ export default class BattleScene extends SceneBase { const lastBattle = this.currentBattle; - if (lastBattle?.double && !newDouble) { - this.tryRemovePhase(p => p instanceof SwitchPhase); - } - const maxExpLevel = this.getMaxExpLevel(); this.lastEnemyTrainer = lastBattle?.trainer ?? null; this.lastMysteryEncounter = lastBattle?.mysteryEncounter; + if (newBattleType === BattleType.MYSTERY_ENCOUNTER) { + // Disable double battle on mystery encounters (it may be re-enabled as part of encounter) + newDouble = false; + } + + if (lastBattle?.double && !newDouble) { + this.tryRemovePhase(p => p instanceof SwitchPhase); + this.getPlayerField().forEach(p => p.lapseTag(BattlerTagType.COMMANDED)); + } + this.executeWithSeedOffset(() => { this.currentBattle = new Battle(this.gameMode, newWaveIndex, newBattleType, newTrainer, newDouble); }, newWaveIndex << 3, this.waveSeed); this.currentBattle.incrementTurn(this); if (newBattleType === BattleType.MYSTERY_ENCOUNTER) { - // Disable double battle on mystery encounters (it may be re-enabled as part of encounter) - this.currentBattle.double = false; // Will generate the actual Mystery Encounter during NextEncounterPhase, to ensure it uses proper biome this.currentBattle.mysteryEncounterType = mysteryEncounterType; } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 5478a6e5aaa..5d77aea248d 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -23,7 +23,7 @@ import { reverseCompatibleTms, tmSpecies, tmPoolTiers } from "#app/data/balance/ import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, SubstituteTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag, MoveRestrictionBattlerTag, ExposedTag, DragonCheerTag, CritBoostTag, TrappedTag, TarShotTag, AutotomizedTag, PowerTrickTag } from "../data/battler-tags"; import { WeatherType } from "#enums/weather-type"; import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "#app/data/arena-tag"; -import { Ability, AbAttr, StatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatStagesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldStatMultiplierAbAttrs, FieldMultiplyStatAbAttr, AddSecondStrikeAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr, FullHpResistTypeAbAttr, applyCheckTrappedAbAttrs, CheckTrappedAbAttr, PostSetStatusAbAttr, applyPostSetStatusAbAttrs, InfiltratorAbAttr, AlliedFieldDamageReductionAbAttr, PostDamageAbAttr, applyPostDamageAbAttrs, PostDamageForceSwitchAbAttr } from "#app/data/ability"; +import { Ability, AbAttr, StatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatStagesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldStatMultiplierAbAttrs, FieldMultiplyStatAbAttr, AddSecondStrikeAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr, FullHpResistTypeAbAttr, applyCheckTrappedAbAttrs, CheckTrappedAbAttr, PostSetStatusAbAttr, applyPostSetStatusAbAttrs, InfiltratorAbAttr, AlliedFieldDamageReductionAbAttr, PostDamageAbAttr, applyPostDamageAbAttrs, PostDamageForceSwitchAbAttr, CommanderAbAttr } from "#app/data/ability"; import PokemonData from "#app/system/pokemon-data"; import { BattlerIndex } from "#app/battle"; import { Mode } from "#app/ui/ui"; @@ -3081,7 +3081,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } lapseTag(tagType: BattlerTagType): boolean { - const tags = this.summonData.tags; + const tags = this.summonData?.tags; + if (isNullOrUndefined(tags)) { + return false; + } const tag = tags.find(t => t.tagType === tagType); if (tag && !(tag.lapse(this, BattlerTagLapseType.CUSTOM))) { tag.onRemove(this); @@ -3646,6 +3649,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.scene.triggerPokemonBattleAnim(this, PokemonAnimType.SUBSTITUTE_ADD); this.getTag(SubstituteTag)!.sourceInFocus = false; } + + // If this Pokemon has Commander and Dondozo as an active ally, hide this Pokemon's sprite. + if (this.hasAbilityWithAttr(CommanderAbAttr) + && this.scene.currentBattle.double + && this.getAlly()?.species.speciesId === Species.DONDOZO) { + this.setVisible(false); + } this.summonDataPrimer = null; } this.updateInfo(); diff --git a/src/phases/check-switch-phase.ts b/src/phases/check-switch-phase.ts index b87dff32f60..acf17c75668 100644 --- a/src/phases/check-switch-phase.ts +++ b/src/phases/check-switch-phase.ts @@ -26,25 +26,29 @@ export class CheckSwitchPhase extends BattlePhase { const pokemon = this.scene.getPlayerField()[this.fieldIndex]; + // End this phase early... + + // ...if the user is playing in Set Mode if (this.scene.battleStyle === BattleStyle.SET) { - super.end(); - return; + return super.end(); } + // ...if the checked Pokemon is somehow not on the field if (this.scene.field.getAll().indexOf(pokemon) === -1) { this.scene.unshiftPhase(new SummonMissingPhase(this.scene, this.fieldIndex)); - super.end(); - return; + return super.end(); } + // ...if there are no other allowed Pokemon in the player's party to switch with if (!this.scene.getPlayerParty().slice(1).filter(p => p.isActive()).length) { - super.end(); - return; + return super.end(); } - if (pokemon.getTag(BattlerTagType.FRENZY)) { - super.end(); - return; + // ...or if any player Pokemon has an effect that prevents the checked Pokemon from switching + if (pokemon.getTag(BattlerTagType.FRENZY) + || pokemon.isTrapped() + || this.scene.getPlayerField().some(p => p.getTag(BattlerTagType.COMMANDED))) { + return super.end(); } this.scene.ui.showText(i18next.t("battle:switchQuestion", { pokemonName: this.useName ? getPokemonNameWithAffix(pokemon) : i18next.t("battle:pokemon") }), null, () => { diff --git a/src/phases/encounter-phase.ts b/src/phases/encounter-phase.ts index 123f9ded9fc..c4d919c0325 100644 --- a/src/phases/encounter-phase.ts +++ b/src/phases/encounter-phase.ts @@ -36,7 +36,6 @@ import { PlayerGender } from "#enums/player-gender"; import { Species } from "#enums/species"; import i18next from "i18next"; import { WEIGHT_INCREMENT_ON_SPAWN_MISS } from "#app/data/mystery-encounters/mystery-encounters"; -import { BattlerTagType } from "#enums/battler-tag-type"; export class EncounterPhase extends BattlePhase { private loaded: boolean; @@ -483,7 +482,6 @@ export class EncounterPhase extends BattlePhase { } } else { if (availablePartyMembers.length > 1 && availablePartyMembers[1].isOnField()) { - this.scene.getPlayerField().forEach((pokemon) => pokemon.lapseTag(BattlerTagType.COMMANDED)); this.scene.pushPhase(new ReturnPhase(this.scene, 1)); } this.scene.pushPhase(new ToggleDoublePositionPhase(this.scene, false)); From 2bf8acea06bd0e536b3ac9c49127fd6f0797a28c Mon Sep 17 00:00:00 2001 From: PigeonBar <56974298+PigeonBar@users.noreply.github.com> Date: Sat, 9 Nov 2024 13:15:24 -0500 Subject: [PATCH 28/75] [Beta][P2] Fix Sketch failing to sketch moves that call other moves virtually (#4823) * [P2][Beta] Fix Sketch failing to sketch Metronome et al * Suggested changes to `getLastXMoves()` * Renamed turnCount to moveCount --- src/data/move.ts | 11 +++- src/field/pokemon.ts | 16 +++++- src/modifier/modifier.ts | 4 +- src/test/abilities/sap_sipper.test.ts | 72 ++++++++++----------------- src/test/moves/sketch.test.ts | 21 +++++++- 5 files changed, 70 insertions(+), 54 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index 071d7fa1e65..ed2b176f54c 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -6373,10 +6373,17 @@ export class RandomMovesetMoveAttr extends OverrideMoveEffectAttr { } export class RandomMoveAttr extends OverrideMoveEffectAttr { + /** + * This function exists solely to allow tests to override the randomly selected move by mocking this function. + */ + public getMoveOverride(): Moves | null { + return null; + } + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise { return new Promise(resolve => { const moveIds = Utils.getEnumValues(Moves).filter(m => !allMoves[m].hasFlag(MoveFlags.IGNORE_VIRTUAL) && !allMoves[m].name.endsWith(" (N)")); - const moveId = moveIds[user.randSeedInt(moveIds.length)]; + const moveId = this.getMoveOverride() ?? moveIds[user.randSeedInt(moveIds.length)]; const moveTargets = getMoveTargets(user, moveId); if (!moveTargets.targets.length) { @@ -6759,7 +6766,7 @@ export class SketchAttr extends MoveEffectAttr { return false; } - const targetMove = target.getLastXMoves(target.battleSummonData.turnCount) + const targetMove = target.getLastXMoves(-1) .find(m => m.move !== Moves.NONE && m.move !== Moves.STRUGGLE && !m.virtual); if (!targetMove) { return false; diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 5d77aea248d..221cc8f818a 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -3226,9 +3226,21 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.getMoveHistory().push(turnMove); } - getLastXMoves(turnCount: integer = 0): TurnMove[] { + /** + * Returns a list of the most recent move entries in this Pokemon's move history. + * The retrieved move entries are sorted in order from NEWEST to OLDEST. + * @param moveCount The number of move entries to retrieve. + * If negative, retrieve the Pokemon's entire move history (equivalent to reversing the output of {@linkcode getMoveHistory()}). + * Default is `1`. + * @returns A list of {@linkcode TurnMove}, as specified above. + */ + getLastXMoves(moveCount: number = 1): TurnMove[] { const moveHistory = this.getMoveHistory(); - return moveHistory.slice(turnCount >= 0 ? Math.max(moveHistory.length - (turnCount || 1), 0) : 0, moveHistory.length).reverse(); + if (moveCount >= 0) { + return moveHistory.slice(Math.max(moveHistory.length - moveCount, 0)).reverse(); + } else { + return moveHistory.slice(0).reverse(); + } } getMoveQueue(): QueuedMove[] { diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 9e97c866718..90336780ba6 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -728,10 +728,10 @@ export abstract class PokemonHeldItemModifier extends PersistentModifier { //Applies to items with chance of activating secondary effects ie Kings Rock getSecondaryChanceMultiplier(pokemon: Pokemon): number { // Temporary quickfix to stop game from freezing when the opponet uses u-turn while holding on to king's rock - if (!pokemon.getLastXMoves(0)[0]) { + if (!pokemon.getLastXMoves()[0]) { return 1; } - const sheerForceAffected = allMoves[pokemon.getLastXMoves(0)[0].move].chance >= 0 && pokemon.hasAbility(Abilities.SHEER_FORCE); + const sheerForceAffected = allMoves[pokemon.getLastXMoves()[0].move].chance >= 0 && pokemon.hasAbility(Abilities.SHEER_FORCE); if (sheerForceAffected) { return 0; diff --git a/src/test/abilities/sap_sipper.test.ts b/src/test/abilities/sap_sipper.test.ts index a4ce0c1b8f6..dc254a54b54 100644 --- a/src/test/abilities/sap_sipper.test.ts +++ b/src/test/abilities/sap_sipper.test.ts @@ -8,7 +8,8 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { allMoves, RandomMoveAttr } from "#app/data/move"; // See also: TypeImmunityAbAttr describe("Abilities - Sap Sipper", () => { @@ -27,20 +28,20 @@ describe("Abilities - Sap Sipper", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); - game.override.disableCrits(); + game.override.battleType("single") + .disableCrits() + .ability(Abilities.SAP_SIPPER) + .enemySpecies(Species.RATTATA) + .enemyAbility(Abilities.SAP_SIPPER) + .enemyMoveset(Moves.SPLASH); }); it("raises ATK stat stage by 1 and block effects when activated against a grass attack", async() => { const moveToUse = Moves.LEAFAGE; - const enemyAbility = Abilities.SAP_SIPPER; - game.override.moveset([ moveToUse ]); - game.override.enemyMoveset(Moves.SPLASH); - game.override.enemySpecies(Species.DUSKULL); - game.override.enemyAbility(enemyAbility); + game.override.moveset(moveToUse); - await game.startBattle(); + await game.classicMode.startBattle([ Species.BULBASAUR ]); const enemyPokemon = game.scene.getEnemyPokemon()!; const initialEnemyHp = enemyPokemon.hp; @@ -55,14 +56,10 @@ describe("Abilities - Sap Sipper", () => { it("raises ATK stat stage by 1 and block effects when activated against a grass status move", async() => { const moveToUse = Moves.SPORE; - const enemyAbility = Abilities.SAP_SIPPER; - game.override.moveset([ moveToUse ]); - game.override.enemyMoveset(Moves.SPLASH); - game.override.enemySpecies(Species.RATTATA); - game.override.enemyAbility(enemyAbility); + game.override.moveset(moveToUse); - await game.startBattle(); + await game.classicMode.startBattle([ Species.BULBASAUR ]); const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -76,14 +73,10 @@ describe("Abilities - Sap Sipper", () => { it("do not activate against status moves that target the field", async () => { const moveToUse = Moves.GRASSY_TERRAIN; - const enemyAbility = Abilities.SAP_SIPPER; - game.override.moveset([ moveToUse ]); - game.override.enemyMoveset(Moves.SPLASH); - game.override.enemySpecies(Species.RATTATA); - game.override.enemyAbility(enemyAbility); + game.override.moveset(moveToUse); - await game.startBattle(); + await game.classicMode.startBattle([ Species.BULBASAUR ]); game.move.select(moveToUse); @@ -96,14 +89,10 @@ describe("Abilities - Sap Sipper", () => { it("activate once against multi-hit grass attacks", async () => { const moveToUse = Moves.BULLET_SEED; - const enemyAbility = Abilities.SAP_SIPPER; - game.override.moveset([ moveToUse ]); - game.override.enemyMoveset(Moves.SPLASH); - game.override.enemySpecies(Species.RATTATA); - game.override.enemyAbility(enemyAbility); + game.override.moveset(moveToUse); - await game.startBattle(); + await game.classicMode.startBattle([ Species.BULBASAUR ]); const enemyPokemon = game.scene.getEnemyPokemon()!; const initialEnemyHp = enemyPokemon.hp; @@ -118,15 +107,10 @@ describe("Abilities - Sap Sipper", () => { it("do not activate against status moves that target the user", async () => { const moveToUse = Moves.SPIKY_SHIELD; - const ability = Abilities.SAP_SIPPER; - game.override.moveset([ moveToUse ]); - game.override.ability(ability); - game.override.enemyMoveset(Moves.SPLASH); - game.override.enemySpecies(Species.RATTATA); - game.override.enemyAbility(Abilities.NONE); + game.override.moveset(moveToUse); - await game.startBattle(); + await game.classicMode.startBattle([ Species.BULBASAUR ]); const playerPokemon = game.scene.getPlayerPokemon()!; @@ -142,18 +126,15 @@ describe("Abilities - Sap Sipper", () => { expect(game.phaseInterceptor.log).not.toContain("ShowAbilityPhase"); }); - // TODO Add METRONOME outcome override - // To run this testcase, manually modify the METRONOME move to always give SAP_SIPPER, then uncomment - it.todo("activate once against multi-hit grass attacks (metronome)", async () => { + it("activate once against multi-hit grass attacks (metronome)", async () => { const moveToUse = Moves.METRONOME; - const enemyAbility = Abilities.SAP_SIPPER; - game.override.moveset([ moveToUse ]); - game.override.enemyMoveset([ Moves.SPLASH, Moves.NONE, Moves.NONE, Moves.NONE ]); - game.override.enemySpecies(Species.RATTATA); - game.override.enemyAbility(enemyAbility); + const randomMoveAttr = allMoves[Moves.METRONOME].findAttr(attr => attr instanceof RandomMoveAttr) as RandomMoveAttr; + vi.spyOn(randomMoveAttr, "getMoveOverride").mockReturnValue(Moves.BULLET_SEED); - await game.startBattle(); + game.override.moveset(moveToUse); + + await game.classicMode.startBattle([ Species.BULBASAUR ]); const enemyPokemon = game.scene.getEnemyPokemon()!; const initialEnemyHp = enemyPokemon.hp; @@ -168,11 +149,8 @@ describe("Abilities - Sap Sipper", () => { it("still activates regardless of accuracy check", async () => { game.override.moveset(Moves.LEAF_BLADE); - game.override.enemyMoveset(Moves.SPLASH); - game.override.enemySpecies(Species.MAGIKARP); - game.override.enemyAbility(Abilities.SAP_SIPPER); - await game.classicMode.startBattle(); + await game.classicMode.startBattle([ Species.BULBASAUR ]); const enemyPokemon = game.scene.getEnemyPokemon()!; diff --git a/src/test/moves/sketch.test.ts b/src/test/moves/sketch.test.ts index 4386ce5868e..f531f44ef0c 100644 --- a/src/test/moves/sketch.test.ts +++ b/src/test/moves/sketch.test.ts @@ -4,9 +4,10 @@ import { Species } from "#enums/species"; import { MoveResult, PokemonMove } from "#app/field/pokemon"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { StatusEffect } from "#app/enums/status-effect"; import { BattlerIndex } from "#app/battle"; +import { allMoves, RandomMoveAttr } from "#app/data/move"; describe("Moves - Sketch", () => { let phaserGame: Phaser.Game; @@ -76,4 +77,22 @@ describe("Moves - Sketch", () => { expect(playerPokemon.moveset[0]?.moveId).toBe(Moves.SPLASH); expect(playerPokemon.moveset[1]?.moveId).toBe(Moves.GROWL); }); + + it("should sketch moves that call other moves", async () => { + const randomMoveAttr = allMoves[Moves.METRONOME].findAttr(attr => attr instanceof RandomMoveAttr) as RandomMoveAttr; + vi.spyOn(randomMoveAttr, "getMoveOverride").mockReturnValue(Moves.FALSE_SWIPE); + + game.override.enemyMoveset([ Moves.METRONOME ]); + await game.classicMode.startBattle([ Species.REGIELEKI ]); + const playerPokemon = game.scene.getPlayerPokemon()!; + playerPokemon.moveset = [ new PokemonMove(Moves.SKETCH) ]; + + // Opponent uses Metronome -> False Swipe, then player uses Sketch, which should sketch Metronome + game.move.select(Moves.SKETCH); + await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]); + await game.phaseInterceptor.to("TurnEndPhase"); + expect(playerPokemon.getLastXMoves()[0].result).toBe(MoveResult.SUCCESS); + expect(playerPokemon.moveset[0]?.moveId).toBe(Moves.METRONOME); + expect(playerPokemon.hp).toBeLessThan(playerPokemon.getMaxHp()); // Make sure opponent actually used False Swipe + }); }); From 198ac2431d11536f20b68d56b06056eecd8c73fa Mon Sep 17 00:00:00 2001 From: damocleas Date: Sat, 9 Nov 2024 17:26:55 -0500 Subject: [PATCH 29/75] Undo Event modifier-type.ts item table changes (#4836) --- src/modifier/modifier-type.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index ae1aef3ff88..4986c1feab1 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -1702,10 +1702,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.EVOLUTION_ITEM, (party: Pokemon[]) => { return Math.min(Math.ceil(party[0].scene.currentBattle.waveIndex / 15), 8); }, 8), - new WeightedModifierType(modifierTypes.MAP, - (party: Pokemon[]) => party[0].scene.gameMode.isClassic && party[0].scene.currentBattle.waveIndex < 180 ? party[0].scene.eventManager.isEventActive() ? 2 : 1 : 0, - (party: Pokemon[]) => party[0].scene.eventManager.isEventActive() ? 2 : 1), - new WeightedModifierType(modifierTypes.SOOTHE_BELL, (party: Pokemon[]) => party[0].scene.eventManager.isEventActive() ? 3 : 0), + new WeightedModifierType(modifierTypes.MAP, (party: Pokemon[]) => party[0].scene.gameMode.isClassic && party[0].scene.currentBattle.waveIndex < 180 ? 1 : 0, 1), new WeightedModifierType(modifierTypes.TM_GREAT, 3), new WeightedModifierType(modifierTypes.MEMORY_MUSHROOM, (party: Pokemon[]) => { if (!party.find(p => p.getLearnableLevelMoves().length)) { @@ -1773,7 +1770,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.CANDY_JAR, skipInLastClassicWaveOrDefault(5)), new WeightedModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, 9), new WeightedModifierType(modifierTypes.TM_ULTRA, 11), - new WeightedModifierType(modifierTypes.RARER_CANDY, (party: Pokemon[]) => party[0].scene.eventManager.isEventActive() ? 6 : 4), + new WeightedModifierType(modifierTypes.RARER_CANDY, 4), new WeightedModifierType(modifierTypes.GOLDEN_PUNCH, skipInLastClassicWaveOrDefault(2)), new WeightedModifierType(modifierTypes.IV_SCANNER, skipInLastClassicWaveOrDefault(4)), new WeightedModifierType(modifierTypes.EXP_CHARM, skipInLastClassicWaveOrDefault(8)), @@ -1797,7 +1794,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.SOUL_DEW, 7), //new WeightedModifierType(modifierTypes.OVAL_CHARM, 6), new WeightedModifierType(modifierTypes.CATCHING_CHARM, (party: Pokemon[]) => !party[0].scene.gameMode.isFreshStartChallenge() && party[0].scene.gameData.getSpeciesCount(d => !!d.caughtAttr) > 100 ? 4 : 0, 4), - new WeightedModifierType(modifierTypes.SOOTHE_BELL, (party: Pokemon[]) => party[0].scene.eventManager.isEventActive() ? 0 : 4), + new WeightedModifierType(modifierTypes.SOOTHE_BELL, 4), new WeightedModifierType(modifierTypes.ABILITY_CHARM, skipInClassicAfterWave(189, 6)), new WeightedModifierType(modifierTypes.FOCUS_BAND, 5), new WeightedModifierType(modifierTypes.KINGS_ROCK, 3), From 265b3cb938a7f8a5685f5279bb6127d37919adf8 Mon Sep 17 00:00:00 2001 From: Payton Rogers Date: Sat, 9 Nov 2024 23:35:16 -0600 Subject: [PATCH 30/75] [P3] Fix visual bug with level text remaining the same when pokemon levels are reduced in weird dream ME (#4837) --- src/data/mystery-encounters/encounters/weird-dream-encounter.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/data/mystery-encounters/encounters/weird-dream-encounter.ts b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts index 3c541e20bf4..3d2e8493d44 100644 --- a/src/data/mystery-encounters/encounters/weird-dream-encounter.ts +++ b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts @@ -312,6 +312,7 @@ export const WeirdDreamEncounter: MysteryEncounter = pokemon.levelExp = 0; pokemon.calculateStats(); + pokemon.getBattleInfo().setLevel(pokemon.level); await pokemon.updateInfo(); } From 44a68a91bac22b5982f98012846e66174ee16d96 Mon Sep 17 00:00:00 2001 From: Moka <54149968+MokaStitcher@users.noreply.github.com> Date: Sun, 10 Nov 2024 06:35:49 +0100 Subject: [PATCH 31/75] [P1] Fix crash when newly aquired Pokemon are sent in battle (#4835) --- .../encounters/fun-and-games-encounter.ts | 2 +- src/field/pokemon.ts | 8 ++++---- src/phases/encounter-phase.ts | 2 +- src/phases/summon-phase.ts | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/data/mystery-encounters/encounters/fun-and-games-encounter.ts b/src/data/mystery-encounters/encounters/fun-and-games-encounter.ts index 7bf48aa5926..c286fffe0de 100644 --- a/src/data/mystery-encounters/encounters/fun-and-games-encounter.ts +++ b/src/data/mystery-encounters/encounters/fun-and-games-encounter.ts @@ -305,7 +305,7 @@ async function showWobbuffetHealthBar(scene: BattleScene) { scene.field.add(wobbuffet); const playerPokemon = scene.getPlayerPokemon() as Pokemon; - if (playerPokemon?.visible) { + if (playerPokemon?.isOnField()) { scene.field.moveBelow(wobbuffet, playerPokemon); } // Show health bar and trigger cry diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 221cc8f818a..daa73164577 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -5113,7 +5113,7 @@ export class EnemyPokemon extends Pokemon { /** * Add a new pokemon to the player's party (at `slotIndex` if set). - * If the first slot is replaced, the new pokemon's visibility will be set to `false`. + * The new pokemon's visibility will be set to `false`. * @param pokeballType the type of pokeball the pokemon was caught with * @param slotIndex an optional index to place the pokemon in the party * @returns the pokemon that was added or null if the pokemon could not be added @@ -5131,14 +5131,14 @@ export class EnemyPokemon extends Pokemon { const newPokemon = this.scene.addPlayerPokemon(this.species, this.level, this.abilityIndex, this.formIndex, this.gender, this.shiny, this.variant, this.ivs, this.nature, this); if (Utils.isBetween(slotIndex, 0, PLAYER_PARTY_MAX_SIZE - 1)) { - if (slotIndex === 0) { - newPokemon.setVisible(false); // Hide if replaced with first pokemon - } party.splice(slotIndex, 0, newPokemon); } else { party.push(newPokemon); } + // Hide the Pokemon since it is not on the field + newPokemon.setVisible(false); + ret = newPokemon; this.scene.triggerPokemonFormChange(newPokemon, SpeciesFormChangeActiveTrigger, true); } diff --git a/src/phases/encounter-phase.ts b/src/phases/encounter-phase.ts index c4d919c0325..fc022ab9647 100644 --- a/src/phases/encounter-phase.ts +++ b/src/phases/encounter-phase.ts @@ -202,7 +202,7 @@ export class EncounterPhase extends BattlePhase { this.scene.field.add(enemyPokemon); battle.seenEnemyPartyMemberIds.add(enemyPokemon.id); const playerPokemon = this.scene.getPlayerPokemon(); - if (playerPokemon?.visible) { + if (playerPokemon?.isOnField()) { this.scene.field.moveBelow(enemyPokemon as Pokemon, playerPokemon); } enemyPokemon.tint(0, 0.5); diff --git a/src/phases/summon-phase.ts b/src/phases/summon-phase.ts index 119e550293c..177e09c4527 100644 --- a/src/phases/summon-phase.ts +++ b/src/phases/summon-phase.ts @@ -140,7 +140,7 @@ export class SummonPhase extends PartyMemberPokemonPhase { this.scene.field.add(pokemon); if (!this.player) { const playerPokemon = this.scene.getPlayerPokemon() as Pokemon; - if (playerPokemon?.visible) { + if (playerPokemon?.isOnField()) { this.scene.field.moveBelow(pokemon, playerPokemon); } this.scene.currentBattle.seenEnemyPartyMemberIds.add(pokemon.id); @@ -193,7 +193,7 @@ export class SummonPhase extends PartyMemberPokemonPhase { this.scene.field.add(pokemon); if (!this.player) { const playerPokemon = this.scene.getPlayerPokemon() as Pokemon; - if (playerPokemon?.visible) { + if (playerPokemon?.isOnField()) { this.scene.field.moveBelow(pokemon, playerPokemon); } this.scene.currentBattle.seenEnemyPartyMemberIds.add(pokemon.id); From b3a94e6a6bebc8c1b948b4196a410b3f4c23f60e Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Sat, 9 Nov 2024 21:37:09 -0800 Subject: [PATCH 32/75] [Telemetry][Misc] Client-Side changes to log run results at the end of runs (#4834) * Added new telemetry-related parameters * Update test with new parameters. * Removing extra parameters. * Cat in front of keyboar d sorry * Changed variable name to isVictory. * Apply suggestions from code review Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Thank you Torranx * Condensed if-else pair to else if statement * Update src/phases/game-over-phase.ts Co-authored-by: Adrian T. <68144167+torranx@users.noreply.github.com> * inhale... exhale... corrected variable name to pass linter --------- Co-authored-by: frutescens Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> Co-authored-by: Adrian T. <68144167+torranx@users.noreply.github.com> --- src/@types/PokerogueSessionSavedataApi.ts | 1 + src/phases/game-over-phase.ts | 50 +++++++++---------- .../pokerogue-session-savedata-api.test.ts | 3 +- 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/@types/PokerogueSessionSavedataApi.ts b/src/@types/PokerogueSessionSavedataApi.ts index 5fcd8575b15..c4650611c4f 100644 --- a/src/@types/PokerogueSessionSavedataApi.ts +++ b/src/@types/PokerogueSessionSavedataApi.ts @@ -8,6 +8,7 @@ export class UpdateSessionSavedataRequest { /** This is **NOT** similar to {@linkcode ClearSessionSavedataRequest} */ export interface NewClearSessionSavedataRequest { slot: number; + isVictory: boolean; clientSessionId: string; } diff --git a/src/phases/game-over-phase.ts b/src/phases/game-over-phase.ts index 84fad257897..26a0c45f449 100644 --- a/src/phases/game-over-phase.ts +++ b/src/phases/game-over-phase.ts @@ -26,13 +26,13 @@ import i18next from "i18next"; import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; export class GameOverPhase extends BattlePhase { - private victory: boolean; + private isVictory: boolean; private firstRibbons: PokemonSpecies[] = []; - constructor(scene: BattleScene, victory?: boolean) { + constructor(scene: BattleScene, isVictory: boolean = false) { super(scene); - this.victory = !!victory; + this.isVictory = isVictory; } start() { @@ -40,22 +40,22 @@ export class GameOverPhase extends BattlePhase { // Failsafe if players somehow skip floor 200 in classic mode if (this.scene.gameMode.isClassic && this.scene.currentBattle.waveIndex > 200) { - this.victory = true; + this.isVictory = true; } // Handle Mystery Encounter special Game Over cases // Situations such as when player lost a battle, but it isn't treated as full Game Over - if (!this.victory && this.scene.currentBattle.mysteryEncounter?.onGameOver && !this.scene.currentBattle.mysteryEncounter.onGameOver(this.scene)) { + if (!this.isVictory && this.scene.currentBattle.mysteryEncounter?.onGameOver && !this.scene.currentBattle.mysteryEncounter.onGameOver(this.scene)) { // Do not end the game return this.end(); } // Otherwise, continue standard Game Over logic - if (this.victory && this.scene.gameMode.isEndless) { + if (this.isVictory && this.scene.gameMode.isEndless) { const genderIndex = this.scene.gameData.gender ?? PlayerGender.UNSET; const genderStr = PlayerGender[genderIndex].toLowerCase(); this.scene.ui.showDialogue(i18next.t("miscDialogue:ending_endless", { context: genderStr }), i18next.t("miscDialogue:ending_name"), 0, () => this.handleGameOver()); - } else if (this.victory || !this.scene.enableRetries) { + } else if (this.isVictory || !this.scene.enableRetries) { this.handleGameOver(); } else { this.scene.ui.showText(i18next.t("battle:retryBattle"), null, () => { @@ -93,7 +93,7 @@ export class GameOverPhase extends BattlePhase { this.scene.disableMenu = true; this.scene.time.delayedCall(1000, () => { let firstClear = false; - if (this.victory && newClear) { + if (this.isVictory && newClear) { if (this.scene.gameMode.isClassic) { firstClear = this.scene.validateAchv(achvs.CLASSIC_VICTORY); this.scene.validateAchv(achvs.UNEVOLVED_CLASSIC_VICTORY); @@ -109,8 +109,8 @@ export class GameOverPhase extends BattlePhase { this.scene.gameData.gameStats.dailyRunSessionsWon++; } } - this.scene.gameData.saveRunHistory(this.scene, this.scene.gameData.getSessionSaveData(this.scene), this.victory); - const fadeDuration = this.victory ? 10000 : 5000; + this.scene.gameData.saveRunHistory(this.scene, this.scene.gameData.getSessionSaveData(this.scene), this.isVictory); + const fadeDuration = this.isVictory ? 10000 : 5000; this.scene.fadeOutBgm(fadeDuration, true); const activeBattlers = this.scene.getField().filter(p => p?.isActive(true)); activeBattlers.map(p => p.hideInfo()); @@ -120,7 +120,7 @@ export class GameOverPhase extends BattlePhase { this.scene.clearPhaseQueue(); this.scene.ui.clearText(); - if (this.victory && this.scene.gameMode.isChallenge) { + if (this.isVictory && this.scene.gameMode.isChallenge) { this.scene.gameMode.challenges.forEach(c => this.scene.validateAchvs(ChallengeAchv, c)); } @@ -128,7 +128,7 @@ export class GameOverPhase extends BattlePhase { if (newClear) { this.handleUnlocks(); } - if (this.victory && newClear) { + if (this.isVictory && newClear) { for (const species of this.firstRibbons) { this.scene.unshiftPhase(new RibbonModifierRewardPhase(this.scene, modifierTypes.VOUCHER_PLUS, species)); } @@ -140,7 +140,7 @@ export class GameOverPhase extends BattlePhase { this.end(); }; - if (this.victory && this.scene.gameMode.isClassic) { + if (this.isVictory && this.scene.gameMode.isClassic) { const dialogueKey = "miscDialogue:ending"; if (!this.scene.ui.shouldSkipDialogue(dialogueKey)) { @@ -173,25 +173,21 @@ export class GameOverPhase extends BattlePhase { }); }; - /* Added a local check to see if the game is running offline on victory + /* Added a local check to see if the game is running offline If Online, execute apiFetch as intended - If Offline, execute offlineNewClear(), a localStorage implementation of newClear daily run checks */ - if (this.victory) { - if (!Utils.isLocal || Utils.isLocalServerConnected) { - pokerogueApi.savedata.session.newclear({ slot: this.scene.sessionSlotId, clientSessionId }) - .then((success) => doGameOver(!!success)); - } else { - this.scene.gameData.offlineNewClear(this.scene).then(result => { - doGameOver(result); - }); - } - } else { - doGameOver(false); + If Offline, execute offlineNewClear() only for victory, a localStorage implementation of newClear daily run checks */ + if (!Utils.isLocal || Utils.isLocalServerConnected) { + pokerogueApi.savedata.session.newclear({ slot: this.scene.sessionSlotId, isVictory: this.isVictory, clientSessionId: clientSessionId }) + .then((success) => doGameOver(!!success)); + } else if (this.isVictory) { + this.scene.gameData.offlineNewClear(this.scene).then(result => { + doGameOver(result); + }); } } handleUnlocks(): void { - if (this.victory && this.scene.gameMode.isClassic) { + if (this.isVictory && this.scene.gameMode.isClassic) { if (!this.scene.gameData.unlocks[Unlockables.ENDLESS_MODE]) { this.scene.unshiftPhase(new UnlockPhase(this.scene, Unlockables.ENDLESS_MODE)); } diff --git a/src/test/plugins/api/pokerogue-session-savedata-api.test.ts b/src/test/plugins/api/pokerogue-session-savedata-api.test.ts index d9f6216c4cf..f453c5edd88 100644 --- a/src/test/plugins/api/pokerogue-session-savedata-api.test.ts +++ b/src/test/plugins/api/pokerogue-session-savedata-api.test.ts @@ -28,7 +28,8 @@ describe("Pokerogue Session Savedata API", () => { describe("Newclear", () => { const params: NewClearSessionSavedataRequest = { clientSessionId: "test-session-id", - slot: 3, + isVictory: true, + slot: 3 }; it("should return true on SUCCESS", async () => { From 2968059814dd714a1a855006adc6016b1f081a1b Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sat, 9 Nov 2024 21:39:05 -0800 Subject: [PATCH 33/75] [P1] Transform and Imposter will now fail when either Pokemon is fused (#4824) * Transform and Imposter will now fail when either Pokemon is fused * Prevent Ditto from being randomly generated as part of a fusion --- src/data/ability.ts | 27 ++++++++++++++++++++++----- src/data/move.ts | 8 +++++--- src/data/pokemon-species.ts | 19 +++++++++++++------ src/field/pokemon.ts | 18 ++++++++++-------- 4 files changed, 50 insertions(+), 22 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index 08dc1ed27a4..736f5862530 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -2463,12 +2463,15 @@ export class PostSummonCopyAllyStatsAbAttr extends PostSummonAbAttr { } } +/** + * Used by Imposter + */ export class PostSummonTransformAbAttr extends PostSummonAbAttr { constructor() { super(true); } - async applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): Promise { + async applyPostSummon(pokemon: Pokemon, _passive: boolean, simulated: boolean, _args: any[]): Promise { const targets = pokemon.getOpponents(); if (simulated || !targets.length) { return simulated; @@ -2477,17 +2480,31 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr { let target: Pokemon; if (targets.length > 1) { - pokemon.scene.executeWithSeedOffset(() => target = Utils.randSeedItem(targets), pokemon.scene.currentBattle.waveIndex); + pokemon.scene.executeWithSeedOffset(() => { + // in a double battle, if one of the opposing pokemon is fused the other one will be chosen + // if both are fused, then Imposter will fail below + if (targets[0].fusionSpecies) { + target = targets[1]; + return; + } else if (targets[1].fusionSpecies) { + target = targets[0]; + return; + } + target = Utils.randSeedItem(targets); + }, pokemon.scene.currentBattle.waveIndex); } else { target = targets[0]; } - target = target!; + + // transforming from or into fusion pokemon causes various problems (including crashes and save corruption) + if (target.fusionSpecies || pokemon.fusionSpecies) { + return false; + } + pokemon.summonData.speciesForm = target.getSpeciesForm(); - pokemon.summonData.fusionSpeciesForm = target.getFusionSpeciesForm(); pokemon.summonData.ability = target.getAbility().id; pokemon.summonData.gender = target.getGender(); - pokemon.summonData.fusionGender = target.getFusionGender(); // Copy all stats (except HP) for (const s of EFFECTIVE_STATS) { diff --git a/src/data/move.ts b/src/data/move.ts index ed2b176f54c..37afe651861 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -6995,6 +6995,9 @@ export class SuppressAbilitiesIfActedAttr extends MoveEffectAttr { } } +/** + * Used by Transform + */ export class TransformAttr extends MoveEffectAttr { async apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise { if (!super.apply(user, target, move, args)) { @@ -7003,10 +7006,8 @@ export class TransformAttr extends MoveEffectAttr { const promises: Promise[] = []; user.summonData.speciesForm = target.getSpeciesForm(); - user.summonData.fusionSpeciesForm = target.getFusionSpeciesForm(); user.summonData.ability = target.getAbility().id; user.summonData.gender = target.getGender(); - user.summonData.fusionGender = target.getFusionGender(); // Power Trick's effect will not preserved after using Transform user.removeTag(BattlerTagType.POWER_TRICK); @@ -8077,7 +8078,8 @@ export function initMoves() { .ignoresVirtual(), new StatusMove(Moves.TRANSFORM, Type.NORMAL, -1, 10, -1, 0, 1) .attr(TransformAttr) - .condition((user, target, move) => !target.getTag(BattlerTagType.SUBSTITUTE)) + // transforming from or into fusion pokemon causes various problems (such as crashes) + .condition((user, target, move) => !target.getTag(BattlerTagType.SUBSTITUTE) && !user.fusionSpecies && !target.fusionSpecies) .ignoresProtect(), new AttackMove(Moves.BUBBLE, Type.WATER, MoveCategory.SPECIAL, 40, 100, 30, 10, 0, 1) .attr(StatStageChangeAttr, [ Stat.SPD ], -1) diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index e7fe902956c..ff53fdb9392 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -888,17 +888,24 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali getCompatibleFusionSpeciesFilter(): PokemonSpeciesFilter { const hasEvolution = pokemonEvolutions.hasOwnProperty(this.speciesId); const hasPrevolution = pokemonPrevolutions.hasOwnProperty(this.speciesId); - const pseudoLegendary = this.subLegendary; + const subLegendary = this.subLegendary; const legendary = this.legendary; const mythical = this.mythical; return species => { - return (pseudoLegendary || legendary || mythical || - (pokemonEvolutions.hasOwnProperty(species.speciesId) === hasEvolution - && pokemonPrevolutions.hasOwnProperty(species.speciesId) === hasPrevolution)) - && species.subLegendary === pseudoLegendary + return ( + subLegendary + || legendary + || mythical + || ( + pokemonEvolutions.hasOwnProperty(species.speciesId) === hasEvolution + && pokemonPrevolutions.hasOwnProperty(species.speciesId) === hasPrevolution + ) + ) + && species.subLegendary === subLegendary && species.legendary === legendary && species.mythical === mythical - && (this.isTrainerForbidden() || !species.isTrainerForbidden()); + && (this.isTrainerForbidden() || !species.isTrainerForbidden()) + && species.speciesId !== Species.DITTO; }; } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index daa73164577..d413e618381 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -2030,15 +2030,17 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const hasHiddenAbility = !Utils.randSeedInt(hiddenAbilityChance.value); const randAbilityIndex = Utils.randSeedInt(2); - const filter = !forStarter ? this.species.getCompatibleFusionSpeciesFilter() - : species => { + const filter = !forStarter ? + this.species.getCompatibleFusionSpeciesFilter() + : (species: PokemonSpecies) => { return pokemonEvolutions.hasOwnProperty(species.speciesId) - && !pokemonPrevolutions.hasOwnProperty(species.speciesId) - && !species.pseudoLegendary - && !species.legendary - && !species.mythical - && !species.isTrainerForbidden() - && species.speciesId !== this.species.speciesId; + && !pokemonPrevolutions.hasOwnProperty(species.speciesId) + && !species.subLegendary + && !species.legendary + && !species.mythical + && !species.isTrainerForbidden() + && species.speciesId !== this.species.speciesId + && species.speciesId !== Species.DITTO; }; let fusionOverride: PokemonSpecies | undefined = undefined; From 63ffab027dcddcca9122e7270242e88845703e25 Mon Sep 17 00:00:00 2001 From: PigeonBar <56974298+PigeonBar@users.noreply.github.com> Date: Sun, 10 Nov 2024 14:21:29 -0500 Subject: [PATCH 34/75] [Beta][P2] Several Unburden bug fixes (#4820) * [P2][Beta] Several Unburden bug fixes * Unburden test adjustments * Some further test cleanup * Add suggested `.bypassFaint()` to Unburden --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/battle-scene.ts | 29 +- src/data/ability.ts | 6 +- src/data/berry.ts | 26 +- src/data/move.ts | 16 +- .../encounters/bug-type-superfan-encounter.ts | 7 +- .../encounters/delibirdy-encounter.ts | 18 +- .../global-trade-system-encounter.ts | 8 +- src/field/pokemon.ts | 28 +- src/phases/berry-phase.ts | 7 +- src/phases/faint-phase.ts | 10 +- src/phases/select-modifier-phase.ts | 2 +- src/phases/stat-stage-change-phase.ts | 5 +- src/phases/switch-summon-phase.ts | 2 +- src/test/abilities/unburden.test.ts | 360 +++++++++++++----- 14 files changed, 346 insertions(+), 178 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index c5acadc8eb6..c30ab2e2912 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -2572,14 +2572,15 @@ export default class BattleScene extends SceneBase { * The quantity to transfer is automatically capped at how much the recepient can take before reaching the maximum stack size for the item. * A transfer that moves a quantity smaller than what is specified in the transferQuantity parameter is still considered successful. * @param itemModifier {@linkcode PokemonHeldItemModifier} item to transfer (represents the whole stack) - * @param target {@linkcode Pokemon} pokemon recepient in this transfer - * @param playSound {boolean} - * @param transferQuantity {@linkcode integer} how many items of the stack to transfer. Optional, defaults to 1 - * @param instant {boolean} - * @param ignoreUpdate {boolean} - * @returns true if the transfer was successful + * @param target {@linkcode Pokemon} recepient in this transfer + * @param playSound `true` to play a sound when transferring the item + * @param transferQuantity How many items of the stack to transfer. Optional, defaults to `1` + * @param instant ??? (Optional) + * @param ignoreUpdate ??? (Optional) + * @param itemLost If `true`, treat the item's current holder as losing the item (for now, this simply enables Unburden). Default is `true`. + * @returns `true` if the transfer was successful */ - tryTransferHeldItemModifier(itemModifier: PokemonHeldItemModifier, target: Pokemon, playSound: boolean, transferQuantity: integer = 1, instant?: boolean, ignoreUpdate?: boolean): Promise { + tryTransferHeldItemModifier(itemModifier: PokemonHeldItemModifier, target: Pokemon, playSound: boolean, transferQuantity: number = 1, instant?: boolean, ignoreUpdate?: boolean, itemLost: boolean = true): Promise { return new Promise(resolve => { const source = itemModifier.pokemonId ? itemModifier.getPokemon(target.scene) : null; const cancelled = new Utils.BooleanHolder(false); @@ -2612,14 +2613,14 @@ export default class BattleScene extends SceneBase { if (!matchingModifier || this.removeModifier(matchingModifier, !target.isPlayer())) { if (target.isPlayer()) { this.addModifier(newItemModifier, ignoreUpdate, playSound, false, instant).then(() => { - if (source) { + if (source && itemLost) { applyPostItemLostAbAttrs(PostItemLostAbAttr, source, false); } resolve(true); }); } else { this.addEnemyModifier(newItemModifier, ignoreUpdate, instant).then(() => { - if (source) { + if (source && itemLost) { applyPostItemLostAbAttrs(PostItemLostAbAttr, source, false); } resolve(true); @@ -2791,7 +2792,15 @@ export default class BattleScene extends SceneBase { }); } - removeModifier(modifier: PersistentModifier, enemy?: boolean): boolean { + /** + * Removes a currently owned item. If the item is stacked, the entire item stack + * gets removed. This function does NOT apply in-battle effects, such as Unburden. + * If in-battle effects are needed, use {@linkcode Pokemon.loseHeldItem} instead. + * @param modifier The item to be removed. + * @param enemy If `true`, remove an item owned by the enemy. If `false`, remove an item owned by the player. Default is `false`. + * @returns `true` if the item exists and was successfully removed, `false` otherwise. + */ + removeModifier(modifier: PersistentModifier, enemy: boolean = false): boolean { const modifiers = !enemy ? this.modifiers : this.enemyModifiers; const modifierIndex = modifiers.indexOf(modifier); if (modifierIndex > -1) { diff --git a/src/data/ability.ts b/src/data/ability.ts index 736f5862530..49763991e0e 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -4152,7 +4152,7 @@ export class PostBattleLootAbAttr extends PostBattleAbAttr { if (!simulated && postBattleLoot.length) { const randItem = Utils.randSeedItem(postBattleLoot); //@ts-ignore - TODO see below - if (pokemon.scene.tryTransferHeldItemModifier(randItem, pokemon, true, 1, true)) { // TODO: fix. This is a promise!? + if (pokemon.scene.tryTransferHeldItemModifier(randItem, pokemon, true, 1, true, undefined, false)) { // TODO: fix. This is a promise!? postBattleLoot.splice(postBattleLoot.indexOf(randItem), 1); pokemon.scene.queueMessage(i18next.t("abilityTriggers:postBattleLoot", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), itemName: randItem.type.name })); return true; @@ -5616,7 +5616,9 @@ export function initAbilities() { new Ability(Abilities.ANGER_POINT, 4) .attr(PostDefendCritStatStageChangeAbAttr, Stat.ATK, 6), new Ability(Abilities.UNBURDEN, 4) - .attr(PostItemLostApplyBattlerTagAbAttr, BattlerTagType.UNBURDEN), + .attr(PostItemLostApplyBattlerTagAbAttr, BattlerTagType.UNBURDEN) + .bypassFaint() // Allows reviver seed to activate Unburden + .edgeCase(), // Should not restore Unburden boost if Pokemon loses then regains Unburden ability new Ability(Abilities.HEATPROOF, 4) .attr(ReceivedTypeDamageMultiplierAbAttr, Type.FIRE, 0.5) .attr(ReduceBurnDamageAbAttr, 0.5) diff --git a/src/data/berry.ts b/src/data/berry.ts index d2bbd0fdd1c..dfd6a7ddcf0 100644 --- a/src/data/berry.ts +++ b/src/data/berry.ts @@ -61,13 +61,13 @@ export function getBerryPredicate(berryType: BerryType): BerryPredicate { } } -export type BerryEffectFunc = (pokemon: Pokemon) => void; +export type BerryEffectFunc = (pokemon: Pokemon, berryOwner?: Pokemon) => void; export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { switch (berryType) { case BerryType.SITRUS: case BerryType.ENIGMA: - return (pokemon: Pokemon) => { + return (pokemon: Pokemon, berryOwner?: Pokemon) => { if (pokemon.battleData) { pokemon.battleData.berriesEaten.push(berryType); } @@ -75,10 +75,10 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, hpHealed); pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(), hpHealed.value, i18next.t("battle:hpHealBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), berryName: getBerryName(berryType) }), true)); - applyPostItemLostAbAttrs(PostItemLostAbAttr, pokemon, false); + applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false); }; case BerryType.LUM: - return (pokemon: Pokemon) => { + return (pokemon: Pokemon, berryOwner?: Pokemon) => { if (pokemon.battleData) { pokemon.battleData.berriesEaten.push(berryType); } @@ -87,14 +87,14 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { } pokemon.resetStatus(true, true); pokemon.updateInfo(); - applyPostItemLostAbAttrs(PostItemLostAbAttr, pokemon, false); + applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false); }; case BerryType.LIECHI: case BerryType.GANLON: case BerryType.PETAYA: case BerryType.APICOT: case BerryType.SALAC: - return (pokemon: Pokemon) => { + return (pokemon: Pokemon, berryOwner?: Pokemon) => { if (pokemon.battleData) { pokemon.battleData.berriesEaten.push(berryType); } @@ -103,18 +103,18 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { const statStages = new Utils.NumberHolder(1); applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, statStages); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ stat ], statStages.value)); - applyPostItemLostAbAttrs(PostItemLostAbAttr, pokemon, false); + applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false); }; case BerryType.LANSAT: - return (pokemon: Pokemon) => { + return (pokemon: Pokemon, berryOwner?: Pokemon) => { if (pokemon.battleData) { pokemon.battleData.berriesEaten.push(berryType); } pokemon.addTag(BattlerTagType.CRIT_BOOST); - applyPostItemLostAbAttrs(PostItemLostAbAttr, pokemon, false); + applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false); }; case BerryType.STARF: - return (pokemon: Pokemon) => { + return (pokemon: Pokemon, berryOwner?: Pokemon) => { if (pokemon.battleData) { pokemon.battleData.berriesEaten.push(berryType); } @@ -122,10 +122,10 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { const stages = new Utils.NumberHolder(2); applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, stages); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ randStat ], stages.value)); - applyPostItemLostAbAttrs(PostItemLostAbAttr, pokemon, false); + applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false); }; case BerryType.LEPPA: - return (pokemon: Pokemon) => { + return (pokemon: Pokemon, berryOwner?: Pokemon) => { if (pokemon.battleData) { pokemon.battleData.berriesEaten.push(berryType); } @@ -133,7 +133,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { if (ppRestoreMove !== undefined) { ppRestoreMove!.ppUsed = Math.max(ppRestoreMove!.ppUsed - 10, 0); pokemon.scene.queueMessage(i18next.t("battle:ppHealBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: ppRestoreMove!.getName(), berryName: getBerryName(berryType) })); - applyPostItemLostAbAttrs(PostItemLostAbAttr, pokemon, false); + applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false); } }; } diff --git a/src/data/move.ts b/src/data/move.ts index 37afe651861..9cd4881488c 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -2417,9 +2417,8 @@ export class RemoveHeldItemAttr extends MoveEffectAttr { const removedItem = heldItems[user.randSeedInt(heldItems.length)]; // Decrease item amount and update icon - !--removedItem.stackCount; + target.loseHeldItem(removedItem); target.scene.updateModifiers(target.isPlayer()); - applyPostItemLostAbAttrs(PostItemLostAbAttr, target, false); if (this.berriesOnly) { @@ -2489,18 +2488,15 @@ export class EatBerryAttr extends MoveEffectAttr { } reduceBerryModifier(target: Pokemon) { - if (this.chosenBerry?.stackCount === 1) { - target.scene.removeModifier(this.chosenBerry, !target.isPlayer()); - } else if (this.chosenBerry !== undefined && this.chosenBerry.stackCount > 1) { - this.chosenBerry.stackCount--; + if (this.chosenBerry) { + target.loseHeldItem(this.chosenBerry); } target.scene.updateModifiers(target.isPlayer()); } - eatBerry(consumer: Pokemon) { - getBerryEffectFunc(this.chosenBerry!.berryType)(consumer); // consumer eats the berry + eatBerry(consumer: Pokemon, berryOwner?: Pokemon) { + getBerryEffectFunc(this.chosenBerry!.berryType)(consumer, berryOwner); // consumer eats the berry applyAbAttrs(HealFromBerryUseAbAttr, consumer, new Utils.BooleanHolder(false)); - applyPostItemLostAbAttrs(PostItemLostAbAttr, consumer, false); } } @@ -2540,7 +2536,7 @@ export class StealEatBerryAttr extends EatBerryAttr { const message = i18next.t("battle:stealEatBerry", { pokemonName: user.name, targetName: target.name, berryName: this.chosenBerry.type.name }); user.scene.queueMessage(message); this.reduceBerryModifier(target); - this.eatBerry(user); + this.eatBerry(user, target); return true; } } diff --git a/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts b/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts index 7a03e6efdd2..ecd6972902b 100644 --- a/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts +++ b/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts @@ -477,12 +477,9 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = .withOptionPhase(async (scene: BattleScene) => { const encounter = scene.currentBattle.mysteryEncounter!; const modifier = encounter.misc.chosenModifier; + const chosenPokemon: PlayerPokemon = encounter.misc.chosenPokemon; - // Remove the modifier if its stacks go to 0 - modifier.stackCount -= 1; - if (modifier.stackCount === 0) { - scene.removeModifier(modifier); - } + chosenPokemon.loseHeldItem(modifier, false); scene.updateModifiers(true, true); const bugNet = generateModifierTypeOption(scene, modifierTypes.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET)!; diff --git a/src/data/mystery-encounters/encounters/delibirdy-encounter.ts b/src/data/mystery-encounters/encounters/delibirdy-encounter.ts index d5a938b9cef..a3a97a01238 100644 --- a/src/data/mystery-encounters/encounters/delibirdy-encounter.ts +++ b/src/data/mystery-encounters/encounters/delibirdy-encounter.ts @@ -8,7 +8,7 @@ import { applyModifierTypeToPlayerPokemon } from "#app/data/mystery-encounters/u import { getPokemonSpecies } from "#app/data/pokemon-species"; import Pokemon, { PlayerPokemon } from "#app/field/pokemon"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; -import { BerryModifier, HealingBoosterModifier, LevelIncrementBoosterModifier, MoneyMultiplierModifier, PokemonHeldItemModifier, PreserveBerryModifier } from "#app/modifier/modifier"; +import { BerryModifier, HealingBoosterModifier, LevelIncrementBoosterModifier, MoneyMultiplierModifier, PokemonHeldItemModifier, PokemonInstantReviveModifier, PreserveBerryModifier } from "#app/modifier/modifier"; import { modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type"; import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase"; import i18next from "#app/plugins/i18n"; @@ -197,7 +197,8 @@ export const DelibirdyEncounter: MysteryEncounter = }) .withOptionPhase(async (scene: BattleScene) => { const encounter = scene.currentBattle.mysteryEncounter!; - const modifier: BerryModifier | HealingBoosterModifier = encounter.misc.chosenModifier; + const modifier: BerryModifier | PokemonInstantReviveModifier = encounter.misc.chosenModifier; + const chosenPokemon: PlayerPokemon = encounter.misc.chosenPokemon; // Give the player a Candy Jar if they gave a Berry, and a Berry Pouch for Reviver Seed if (modifier instanceof BerryModifier) { @@ -228,11 +229,7 @@ export const DelibirdyEncounter: MysteryEncounter = } } - // Remove the modifier if its stacks go to 0 - modifier.stackCount -= 1; - if (modifier.stackCount === 0) { - scene.removeModifier(modifier); - } + chosenPokemon.loseHeldItem(modifier, false); leaveEncounterWithoutBattle(scene, true); }) @@ -292,6 +289,7 @@ export const DelibirdyEncounter: MysteryEncounter = .withOptionPhase(async (scene: BattleScene) => { const encounter = scene.currentBattle.mysteryEncounter!; const modifier = encounter.misc.chosenModifier; + const chosenPokemon: PlayerPokemon = encounter.misc.chosenPokemon; // Check if the player has max stacks of Healing Charm already const existing = scene.findModifier(m => m instanceof HealingBoosterModifier) as HealingBoosterModifier; @@ -306,11 +304,7 @@ export const DelibirdyEncounter: MysteryEncounter = scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.HEALING_CHARM)); } - // Remove the modifier if its stacks go to 0 - modifier.stackCount -= 1; - if (modifier.stackCount === 0) { - scene.removeModifier(modifier); - } + chosenPokemon.loseHeldItem(modifier, false); leaveEncounterWithoutBattle(scene, true); }) diff --git a/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts b/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts index b0d547e36cf..2d569621449 100644 --- a/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts +++ b/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts @@ -345,6 +345,7 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = // Pokemon and item selected encounter.setDialogueToken("chosenItem", modifier.type.name); encounter.misc.chosenModifier = modifier; + encounter.misc.chosenPokemon = pokemon; return true; }, }; @@ -370,6 +371,7 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = const encounter = scene.currentBattle.mysteryEncounter!; const modifier = encounter.misc.chosenModifier as PokemonHeldItemModifier; const party = scene.getPlayerParty(); + const chosenPokemon: PlayerPokemon = encounter.misc.chosenPokemon; // Check tier of the traded item, the received item will be one tier up const type = modifier.type.withTierFromPool(ModifierPoolType.PLAYER, party); @@ -397,11 +399,7 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = encounter.setDialogueToken("itemName", item.type.name); setEncounterRewards(scene, { guaranteedModifierTypeOptions: [ item ], fillRemaining: false }); - // Remove the chosen modifier if its stacks go to 0 - modifier.stackCount -= 1; - if (modifier.stackCount === 0) { - scene.removeModifier(modifier); - } + chosenPokemon.loseHeldItem(modifier, false); await scene.updateModifiers(true, true); // Generate a trainer name diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index d413e618381..d806a9b605c 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -23,7 +23,7 @@ import { reverseCompatibleTms, tmSpecies, tmPoolTiers } from "#app/data/balance/ import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, SubstituteTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag, MoveRestrictionBattlerTag, ExposedTag, DragonCheerTag, CritBoostTag, TrappedTag, TarShotTag, AutotomizedTag, PowerTrickTag } from "../data/battler-tags"; import { WeatherType } from "#enums/weather-type"; import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "#app/data/arena-tag"; -import { Ability, AbAttr, StatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatStagesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldStatMultiplierAbAttrs, FieldMultiplyStatAbAttr, AddSecondStrikeAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr, FullHpResistTypeAbAttr, applyCheckTrappedAbAttrs, CheckTrappedAbAttr, PostSetStatusAbAttr, applyPostSetStatusAbAttrs, InfiltratorAbAttr, AlliedFieldDamageReductionAbAttr, PostDamageAbAttr, applyPostDamageAbAttrs, PostDamageForceSwitchAbAttr, CommanderAbAttr } from "#app/data/ability"; +import { Ability, AbAttr, StatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatStagesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldStatMultiplierAbAttrs, FieldMultiplyStatAbAttr, AddSecondStrikeAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr, FullHpResistTypeAbAttr, applyCheckTrappedAbAttrs, CheckTrappedAbAttr, PostSetStatusAbAttr, applyPostSetStatusAbAttrs, InfiltratorAbAttr, AlliedFieldDamageReductionAbAttr, PostDamageAbAttr, applyPostDamageAbAttrs, PostDamageForceSwitchAbAttr, CommanderAbAttr, applyPostItemLostAbAttrs, PostItemLostAbAttr } from "#app/data/ability"; import PokemonData from "#app/system/pokemon-data"; import { BattlerIndex } from "#app/battle"; import { Mode } from "#app/ui/ui"; @@ -985,7 +985,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (this.status && this.status.effect === StatusEffect.PARALYSIS) { ret >>= 1; } - if (this.getTag(BattlerTagType.UNBURDEN) && !this.scene.getField(true).some(pokemon => pokemon !== this && pokemon.hasAbilityWithAttr(SuppressFieldAbilitiesAbAttr))) { + if (this.getTag(BattlerTagType.UNBURDEN) && this.hasAbility(Abilities.UNBURDEN)) { ret *= 2; } break; @@ -4102,6 +4102,28 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } return false; } + + /** + * Reduces one of this Pokemon's held item stacks by 1, and removes the item if applicable. + * Does nothing if this Pokemon is somehow not the owner of the held item. + * @param heldItem The item stack to be reduced by 1. + * @param forBattle If `false`, do not trigger in-battle effects (such as Unburden) from losing the item. For example, set this to `false` if the Pokemon is giving away the held item for a Mystery Encounter. Default is `true`. + * @returns `true` if the item was removed successfully, `false` otherwise. + */ + public loseHeldItem(heldItem: PokemonHeldItemModifier, forBattle: boolean = true): boolean { + if (heldItem.pokemonId === -1 || heldItem.pokemonId === this.id) { + heldItem.stackCount--; + if (heldItem.stackCount <= 0) { + this.scene.removeModifier(heldItem, !this.isPlayer()); + } + if (forBattle) { + applyPostItemLostAbAttrs(PostItemLostAbAttr, this, false); + } + return true; + } else { + return false; + } + } } export default interface Pokemon { @@ -4544,7 +4566,7 @@ export class PlayerPokemon extends Pokemon { && m.pokemonId === pokemon.id, true) as PokemonHeldItemModifier[]; const transferModifiers: Promise[] = []; for (const modifier of fusedPartyMemberHeldModifiers) { - transferModifiers.push(this.scene.tryTransferHeldItemModifier(modifier, this, false, modifier.getStackCount(), true, true)); + transferModifiers.push(this.scene.tryTransferHeldItemModifier(modifier, this, false, modifier.getStackCount(), true, true, false)); } Promise.allSettled(transferModifiers).then(() => { this.scene.updateModifiers(true, true).then(() => { diff --git a/src/phases/berry-phase.ts b/src/phases/berry-phase.ts index e419aa6692d..5c33ae4b343 100644 --- a/src/phases/berry-phase.ts +++ b/src/phases/berry-phase.ts @@ -31,11 +31,8 @@ export class BerryPhase extends FieldPhase { for (const berryModifier of this.scene.applyModifiers(BerryModifier, pokemon.isPlayer(), pokemon)) { if (berryModifier.consumed) { - if (!--berryModifier.stackCount) { - this.scene.removeModifier(berryModifier); - } else { - berryModifier.consumed = false; - } + berryModifier.consumed = false; + pokemon.loseHeldItem(berryModifier); } this.scene.eventTarget.dispatchEvent(new BerryUsedEvent(berryModifier)); // Announce a berry was used } diff --git a/src/phases/faint-phase.ts b/src/phases/faint-phase.ts index d66c5b66144..1c48bdfb37a 100644 --- a/src/phases/faint-phase.ts +++ b/src/phases/faint-phase.ts @@ -55,21 +55,21 @@ export class FaintPhase extends PokemonPhase { start() { super.start(); + const faintPokemon = this.getPokemon(); + if (!isNullOrUndefined(this.destinyTag) && !isNullOrUndefined(this.source)) { this.destinyTag.lapse(this.source, BattlerTagLapseType.CUSTOM); } if (!isNullOrUndefined(this.grudgeTag) && !isNullOrUndefined(this.source)) { - this.grudgeTag.lapse(this.getPokemon(), BattlerTagLapseType.CUSTOM, this.source); + this.grudgeTag.lapse(faintPokemon, BattlerTagLapseType.CUSTOM, this.source); } if (!this.preventEndure) { - const instantReviveModifier = this.scene.applyModifier(PokemonInstantReviveModifier, this.player, this.getPokemon()) as PokemonInstantReviveModifier; + const instantReviveModifier = this.scene.applyModifier(PokemonInstantReviveModifier, this.player, faintPokemon) as PokemonInstantReviveModifier; if (instantReviveModifier) { - if (!--instantReviveModifier.stackCount) { - this.scene.removeModifier(instantReviveModifier); - } + faintPokemon.loseHeldItem(instantReviveModifier); this.scene.updateModifiers(this.player); return this.end(); } diff --git a/src/phases/select-modifier-phase.ts b/src/phases/select-modifier-phase.ts index 98975e30720..19e1ccc12ae 100644 --- a/src/phases/select-modifier-phase.ts +++ b/src/phases/select-modifier-phase.ts @@ -103,7 +103,7 @@ export class SelectModifierPhase extends BattlePhase { const itemModifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && m.isTransferable && m.pokemonId === party[fromSlotIndex].id) as PokemonHeldItemModifier[]; const itemModifier = itemModifiers[itemIndex]; - this.scene.tryTransferHeldItemModifier(itemModifier, party[toSlotIndex], true, itemQuantity); + this.scene.tryTransferHeldItemModifier(itemModifier, party[toSlotIndex], true, itemQuantity, undefined, undefined, false); } else { this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), this.typeOptions, modifierSelectCallback, this.getRerollCost(this.scene.lockModifierTiers)); } diff --git a/src/phases/stat-stage-change-phase.ts b/src/phases/stat-stage-change-phase.ts index ce6ebea2442..44144f9d047 100644 --- a/src/phases/stat-stage-change-phase.ts +++ b/src/phases/stat-stage-change-phase.ts @@ -125,10 +125,7 @@ export class StatStageChangePhase extends PokemonPhase { const whiteHerb = this.scene.applyModifier(ResetNegativeStatStageModifier, this.player, pokemon) as ResetNegativeStatStageModifier; // If the White Herb was applied, consume it if (whiteHerb) { - whiteHerb.stackCount--; - if (whiteHerb.stackCount <= 0) { - this.scene.removeModifier(whiteHerb); - } + pokemon.loseHeldItem(whiteHerb); this.scene.updateModifiers(this.player); } } diff --git a/src/phases/switch-summon-phase.ts b/src/phases/switch-summon-phase.ts index 51d54315165..a667e17edf1 100644 --- a/src/phases/switch-summon-phase.ts +++ b/src/phases/switch-summon-phase.ts @@ -111,7 +111,7 @@ export class SwitchSummonPhase extends SummonPhase { const batonPassModifier = this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier && (m as SwitchEffectTransferModifier).pokemonId === this.lastPokemon.id) as SwitchEffectTransferModifier; if (batonPassModifier && !this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier && (m as SwitchEffectTransferModifier).pokemonId === switchedInPokemon.id)) { - this.scene.tryTransferHeldItemModifier(batonPassModifier, switchedInPokemon, false); + this.scene.tryTransferHeldItemModifier(batonPassModifier, switchedInPokemon, false, undefined, undefined, undefined, false); } } } diff --git a/src/test/abilities/unburden.test.ts b/src/test/abilities/unburden.test.ts index 7cd69f4a075..ba14c7fdcd0 100644 --- a/src/test/abilities/unburden.test.ts +++ b/src/test/abilities/unburden.test.ts @@ -1,18 +1,35 @@ +import { BattlerIndex } from "#app/battle"; +import { PostItemLostAbAttr } from "#app/data/ability"; +import { allMoves, StealHeldItemChanceAttr } from "#app/data/move"; +import Pokemon from "#app/field/pokemon"; +import type { ContactHeldItemTransferChanceModifier } from "#app/modifier/modifier"; import { Abilities } from "#enums/abilities"; +import { BattlerTagType } from "#enums/battler-tag-type"; +import { BerryType } from "#enums/berry-type"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { Stat } from "#enums/stat"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { Stat } from "#enums/stat"; -import { BerryType } from "#app/enums/berry-type"; -import { allMoves, StealHeldItemChanceAttr } from "#app/data/move"; describe("Abilities - Unburden", () => { let phaserGame: Phaser.Game; let game: GameManager; + /** + * Count the number of held items a Pokemon has, accounting for stacks of multiple items. + */ + function getHeldItemCount(pokemon: Pokemon): number { + const stackCounts = pokemon.getHeldItems().map(m => m.getStackCount()); + if (stackCounts.length) { + return stackCounts.reduce((a, b) => a + b); + } else { + return 0; + } + } + beforeAll(() => { phaserGame = new Phaser.Game({ type: Phaser.HEADLESS, @@ -27,9 +44,9 @@ describe("Abilities - Unburden", () => { game = new GameManager(phaserGame); game.override .battleType("single") - .starterSpecies(Species.TREECKO) .startingLevel(1) - .moveset([ Moves.POPULATION_BOMB, Moves.KNOCK_OFF, Moves.PLUCK, Moves.THIEF ]) + .ability(Abilities.UNBURDEN) + .moveset([ Moves.SPLASH, Moves.KNOCK_OFF, Moves.PLUCK, Moves.FALSE_SWIPE ]) .startingHeldItems([ { name: "BERRY", count: 1, type: BerryType.SITRUS }, { name: "BERRY", count: 2, type: BerryType.APICOT }, @@ -37,209 +54,348 @@ describe("Abilities - Unburden", () => { ]) .enemySpecies(Species.NINJASK) .enemyLevel(100) - .enemyMoveset([ Moves.FALSE_SWIPE ]) + .enemyMoveset(Moves.SPLASH) .enemyAbility(Abilities.UNBURDEN) .enemyPassiveAbility(Abilities.NO_GUARD) .enemyHeldItems([ { name: "BERRY", type: BerryType.SITRUS, count: 1 }, { name: "BERRY", type: BerryType.LUM, count: 1 }, ]); + // For the various tests that use Thief, give it a 100% steal rate + vi.spyOn(allMoves[Moves.THIEF], "attrs", "get").mockReturnValue([ new StealHeldItemChanceAttr(1.0) ]); }); it("should activate when a berry is eaten", async () => { - await game.classicMode.startBattle(); + game.override.enemyMoveset(Moves.FALSE_SWIPE); + await game.classicMode.startBattle([ Species.TREECKO ]); const playerPokemon = game.scene.getPlayerPokemon()!; - playerPokemon.abilityIndex = 2; - const playerHeldItems = playerPokemon.getHeldItems().length; + const playerHeldItems = getHeldItemCount(playerPokemon); const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD); - game.move.select(Moves.FALSE_SWIPE); + // Player gets hit by False Swipe and eats its own Sitrus Berry + game.move.select(Moves.SPLASH); await game.toNextTurn(); - expect(playerPokemon.getHeldItems().length).toBeLessThan(playerHeldItems); - expect(playerPokemon.getEffectiveStat(Stat.SPD)).toBeCloseTo(initialPlayerSpeed * 2); + expect(getHeldItemCount(playerPokemon)).toBeLessThan(playerHeldItems); + expect(playerPokemon.getEffectiveStat(Stat.SPD)).toBe(initialPlayerSpeed * 2); }); - it("should activate when a berry is stolen", async () => { - await game.classicMode.startBattle(); + it("should activate when a berry is eaten, even if Berry Pouch preserves the berry", async () => { + game.override.enemyMoveset(Moves.FALSE_SWIPE) + .startingModifier([{ name: "BERRY_POUCH", count: 5850 }]); + await game.classicMode.startBattle([ Species.TREECKO ]); + const playerPokemon = game.scene.getPlayerPokemon()!; + const playerHeldItems = getHeldItemCount(playerPokemon); + const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD); + + // Player gets hit by False Swipe and eats its own Sitrus Berry + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + expect(getHeldItemCount(playerPokemon)).toBe(playerHeldItems); + expect(playerPokemon.getEffectiveStat(Stat.SPD)).toBe(initialPlayerSpeed * 2); + }); + + it("should activate for the target, and not the stealer, when a berry is stolen", async () => { + await game.classicMode.startBattle([ Species.TREECKO ]); + + const playerPokemon = game.scene.getPlayerPokemon()!; + const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD); const enemyPokemon = game.scene.getEnemyPokemon()!; - const enemyHeldItemCt = enemyPokemon.getHeldItems().length; + const enemyHeldItemCt = getHeldItemCount(enemyPokemon); const initialEnemySpeed = enemyPokemon.getStat(Stat.SPD); + // Player uses Pluck and eats the opponent's berry game.move.select(Moves.PLUCK); await game.toNextTurn(); - expect(enemyPokemon.getHeldItems().length).toBeLessThan(enemyHeldItemCt); - expect(enemyPokemon.getEffectiveStat(Stat.SPD)).toBeCloseTo(initialEnemySpeed * 2); + expect(getHeldItemCount(enemyPokemon)).toBeLessThan(enemyHeldItemCt); + expect(enemyPokemon.getEffectiveStat(Stat.SPD)).toBe(initialEnemySpeed * 2); + expect(playerPokemon.getEffectiveStat(Stat.SPD)).toBe(initialPlayerSpeed); }); it("should activate when an item is knocked off", async () => { - await game.classicMode.startBattle(); + await game.classicMode.startBattle([ Species.TREECKO ]); const enemyPokemon = game.scene.getEnemyPokemon()!; - const enemyHeldItemCt = enemyPokemon.getHeldItems().length; + const enemyHeldItemCt = getHeldItemCount(enemyPokemon); const initialEnemySpeed = enemyPokemon.getStat(Stat.SPD); + // Player uses Knock Off and removes the opponent's item game.move.select(Moves.KNOCK_OFF); await game.toNextTurn(); - expect(enemyPokemon.getHeldItems().length).toBeLessThan(enemyHeldItemCt); - expect(enemyPokemon.getEffectiveStat(Stat.SPD)).toBeCloseTo(initialEnemySpeed * 2); + expect(getHeldItemCount(enemyPokemon)).toBeLessThan(enemyHeldItemCt); + expect(enemyPokemon.getEffectiveStat(Stat.SPD)).toBe(initialEnemySpeed * 2); }); it("should activate when an item is stolen via attacking ability", async () => { game.override .ability(Abilities.MAGICIAN) - .startingHeldItems([ - { name: "MULTI_LENS", count: 3 }, - ]); - await game.classicMode.startBattle(); + .startingHeldItems([]); // Remove player's full stacks of held items so it can steal opponent's held items + await game.classicMode.startBattle([ Species.TREECKO ]); const enemyPokemon = game.scene.getEnemyPokemon()!; - const enemyHeldItemCt = enemyPokemon.getHeldItems().length; + const enemyHeldItemCt = getHeldItemCount(enemyPokemon); const initialEnemySpeed = enemyPokemon.getStat(Stat.SPD); - game.move.select(Moves.POPULATION_BOMB); + // Player steals the opponent's item via ability Magician + game.move.select(Moves.FALSE_SWIPE); await game.toNextTurn(); - expect(enemyPokemon.getHeldItems().length).toBeLessThan(enemyHeldItemCt); - expect(enemyPokemon.getEffectiveStat(Stat.SPD)).toBeCloseTo(initialEnemySpeed * 2); + expect(getHeldItemCount(enemyPokemon)).toBeLessThan(enemyHeldItemCt); + expect(enemyPokemon.getEffectiveStat(Stat.SPD)).toBe(initialEnemySpeed * 2); }); it("should activate when an item is stolen via defending ability", async () => { game.override - .startingLevel(45) .enemyAbility(Abilities.PICKPOCKET) - .startingHeldItems([ - { name: "MULTI_LENS", count: 3 }, - { name: "SOUL_DEW", count: 1 }, - { name: "LUCKY_EGG", count: 1 }, - ]); - await game.classicMode.startBattle(); + .enemyHeldItems([]); // Remove opponent's full stacks of held items so it can steal player's held items + await game.classicMode.startBattle([ Species.TREECKO ]); const playerPokemon = game.scene.getPlayerPokemon()!; - playerPokemon.abilityIndex = 2; - const playerHeldItems = playerPokemon.getHeldItems().length; + const playerHeldItems = getHeldItemCount(playerPokemon); const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD); - game.move.select(Moves.POPULATION_BOMB); + // Player's item gets stolen via ability Pickpocket + game.move.select(Moves.FALSE_SWIPE); await game.toNextTurn(); - expect(playerPokemon.getHeldItems().length).toBeLessThan(playerHeldItems); - expect(playerPokemon.getEffectiveStat(Stat.SPD)).toBeCloseTo(initialPlayerSpeed * 2); + expect(getHeldItemCount(playerPokemon)).toBeLessThan(playerHeldItems); + expect(playerPokemon.getEffectiveStat(Stat.SPD)).toBe(initialPlayerSpeed * 2); }); it("should activate when an item is stolen via move", async () => { - vi.spyOn(allMoves[Moves.THIEF], "attrs", "get").mockReturnValue([ new StealHeldItemChanceAttr(1.0) ]); // give Thief 100% steal rate - game.override.startingHeldItems([ - { name: "MULTI_LENS", count: 3 }, - ]); - await game.classicMode.startBattle(); + game.override.moveset(Moves.THIEF) + .startingHeldItems([]); // Remove player's full stacks of held items so it can steal opponent's held items + await game.classicMode.startBattle([ Species.TREECKO ]); const enemyPokemon = game.scene.getEnemyPokemon()!; - const enemyHeldItemCt = enemyPokemon.getHeldItems().length; + const enemyHeldItemCt = getHeldItemCount(enemyPokemon); const initialEnemySpeed = enemyPokemon.getStat(Stat.SPD); + // Player uses Thief and steals the opponent's item game.move.select(Moves.THIEF); await game.toNextTurn(); - expect(enemyPokemon.getHeldItems().length).toBeLessThan(enemyHeldItemCt); - expect(enemyPokemon.getEffectiveStat(Stat.SPD)).toBeCloseTo(initialEnemySpeed * 2); + expect(getHeldItemCount(enemyPokemon)).toBeLessThan(enemyHeldItemCt); + expect(enemyPokemon.getEffectiveStat(Stat.SPD)).toBe(initialEnemySpeed * 2); }); it("should activate when an item is stolen via grip claw", async () => { game.override - .startingLevel(5) .startingHeldItems([ - { name: "GRIP_CLAW", count: 5 }, - { name: "MULTI_LENS", count: 3 }, - ]) - .enemyHeldItems([ - { name: "SOUL_DEW", count: 1 }, - { name: "LUCKY_EGG", count: 1 }, - { name: "LEFTOVERS", count: 1 }, { name: "GRIP_CLAW", count: 1 }, - { name: "MULTI_LENS", count: 1 }, - { name: "BERRY", type: BerryType.SITRUS, count: 1 }, - { name: "BERRY", type: BerryType.LUM, count: 1 }, ]); - await game.classicMode.startBattle(); - - const enemyPokemon = game.scene.getEnemyPokemon()!; - const enemyHeldItemCt = enemyPokemon.getHeldItems().length; - const initialEnemySpeed = enemyPokemon.getStat(Stat.SPD); - - while (enemyPokemon.getHeldItems().length === enemyHeldItemCt) { - game.move.select(Moves.POPULATION_BOMB); - await game.toNextTurn(); - } - - expect(enemyPokemon.getHeldItems().length).toBeLessThan(enemyHeldItemCt); - expect(enemyPokemon.getEffectiveStat(Stat.SPD)).toBeCloseTo(initialEnemySpeed * 2); - }); - - it("should not activate when a neutralizing ability is present", async () => { - game.override.enemyAbility(Abilities.NEUTRALIZING_GAS); - await game.classicMode.startBattle(); + await game.classicMode.startBattle([ Species.TREECKO ]); const playerPokemon = game.scene.getPlayerPokemon()!; - const playerHeldItems = playerPokemon.getHeldItems().length; - const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD); + const gripClaw = playerPokemon.getHeldItems()[0] as ContactHeldItemTransferChanceModifier; + vi.spyOn(gripClaw, "chance", "get").mockReturnValue(100); + const enemyPokemon = game.scene.getEnemyPokemon()!; + const enemyHeldItemCt = getHeldItemCount(enemyPokemon); + const initialEnemySpeed = enemyPokemon.getStat(Stat.SPD); + + // Player steals the opponent's item using Grip Claw game.move.select(Moves.FALSE_SWIPE); await game.toNextTurn(); - expect(playerPokemon.getHeldItems().length).toBeLessThan(playerHeldItems); - expect(playerPokemon.getEffectiveStat(Stat.SPD)).toBeCloseTo(initialPlayerSpeed); + expect(getHeldItemCount(enemyPokemon)).toBeLessThan(enemyHeldItemCt); + expect(enemyPokemon.getEffectiveStat(Stat.SPD)).toBe(initialEnemySpeed * 2); + }); + + it("should not activate when a neutralizing ability is present", async () => { + game.override.enemyAbility(Abilities.NEUTRALIZING_GAS) + .enemyMoveset(Moves.FALSE_SWIPE); + await game.classicMode.startBattle([ Species.TREECKO ]); + + const playerPokemon = game.scene.getPlayerPokemon()!; + const playerHeldItems = getHeldItemCount(playerPokemon); + const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD); + + // Player gets hit by False Swipe and eats Sitrus Berry, which should not trigger Unburden + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + expect(getHeldItemCount(playerPokemon)).toBeLessThan(playerHeldItems); + expect(playerPokemon.getEffectiveStat(Stat.SPD)).toBe(initialPlayerSpeed); + expect(playerPokemon.getTag(BattlerTagType.UNBURDEN)).toBeUndefined(); }); it("should activate when a move that consumes a berry is used", async () => { - game.override.enemyMoveset([ Moves.STUFF_CHEEKS ]); - await game.classicMode.startBattle(); + game.override.moveset(Moves.STUFF_CHEEKS); + await game.classicMode.startBattle([ Species.TREECKO ]); - const enemyPokemon = game.scene.getEnemyPokemon()!; - const enemyHeldItemCt = enemyPokemon.getHeldItems().length; - const initialEnemySpeed = enemyPokemon.getStat(Stat.SPD); + const playerPokemon = game.scene.getPlayerPokemon()!; + const playerHeldItemCt = getHeldItemCount(playerPokemon); + const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD); + // Player uses Stuff Cheeks and eats its own berry + // Caution: Do not test this using opponent, there is a known issue where opponent can randomly generate with Salac Berry game.move.select(Moves.STUFF_CHEEKS); await game.toNextTurn(); - expect(enemyPokemon.getHeldItems().length).toBeLessThan(enemyHeldItemCt); - expect(enemyPokemon.getEffectiveStat(Stat.SPD)).toBeCloseTo(initialEnemySpeed * 2); + expect(getHeldItemCount(playerPokemon)).toBeLessThan(playerHeldItemCt); + expect(playerPokemon.getEffectiveStat(Stat.SPD)).toBe(initialPlayerSpeed * 2); }); - it("should deactivate when a neutralizing gas user enters the field", async () => { + it("should deactivate temporarily when a neutralizing gas user is on the field", async () => { game.override .battleType("double") - .moveset([ Moves.SPLASH ]); + .ability(Abilities.NONE); // Disable ability override so that we can properly set abilities below await game.classicMode.startBattle([ Species.TREECKO, Species.MEOWTH, Species.WEEZING ]); - const playerPokemon = game.scene.getPlayerParty(); - const treecko = playerPokemon[0]; - const weezing = playerPokemon[2]; - treecko.abilityIndex = 2; - weezing.abilityIndex = 1; - const playerHeldItems = treecko.getHeldItems().length; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [ treecko, _meowth, weezing ] = game.scene.getPlayerParty(); + treecko.abilityIndex = 2; // Treecko has Unburden + weezing.abilityIndex = 1; // Weezing has Neutralizing Gas + const playerHeldItems = getHeldItemCount(treecko); const initialPlayerSpeed = treecko.getStat(Stat.SPD); + // Turn 1: Treecko gets hit by False Swipe and eats Sitrus Berry, activating Unburden game.move.select(Moves.SPLASH); - game.move.select(Moves.SPLASH); + game.move.select(Moves.SPLASH, 1); await game.forceEnemyMove(Moves.FALSE_SWIPE, 0); await game.forceEnemyMove(Moves.FALSE_SWIPE, 0); await game.phaseInterceptor.to("TurnEndPhase"); - expect(treecko.getHeldItems().length).toBeLessThan(playerHeldItems); - expect(treecko.getEffectiveStat(Stat.SPD)).toBeCloseTo(initialPlayerSpeed * 2); + expect(getHeldItemCount(treecko)).toBeLessThan(playerHeldItems); + expect(treecko.getEffectiveStat(Stat.SPD)).toBe(initialPlayerSpeed * 2); + // Turn 2: Switch Meowth to Weezing, activating Neutralizing Gas await game.toNextTurn(); game.move.select(Moves.SPLASH); game.doSwitchPokemon(2); await game.phaseInterceptor.to("TurnEndPhase"); - expect(treecko.getHeldItems().length).toBeLessThan(playerHeldItems); - expect(treecko.getEffectiveStat(Stat.SPD)).toBeCloseTo(initialPlayerSpeed); + expect(getHeldItemCount(treecko)).toBeLessThan(playerHeldItems); + expect(treecko.getEffectiveStat(Stat.SPD)).toBe(initialPlayerSpeed); + + // Turn 3: Switch Weezing to Meowth, deactivating Neutralizing Gas + await game.toNextTurn(); + game.move.select(Moves.SPLASH); + game.doSwitchPokemon(2); + await game.phaseInterceptor.to("TurnEndPhase"); + + expect(getHeldItemCount(treecko)).toBeLessThan(playerHeldItems); + expect(treecko.getEffectiveStat(Stat.SPD)).toBe(initialPlayerSpeed * 2); }); + it("should not activate when passing a baton to a teammate switching in", async () => { + game.override.startingHeldItems([{ name: "BATON" }]) + .moveset(Moves.BATON_PASS); + await game.classicMode.startBattle([ Species.TREECKO, Species.PURRLOIN ]); + + const [ treecko, purrloin ] = game.scene.getPlayerParty(); + const initialTreeckoSpeed = treecko.getStat(Stat.SPD); + const initialPurrloinSpeed = purrloin.getStat(Stat.SPD); + const unburdenAttr = treecko.getAbilityAttrs(PostItemLostAbAttr)[0]; + vi.spyOn(unburdenAttr, "applyPostItemLost"); + + // Player uses Baton Pass, which also passes the Baton item + game.move.select(Moves.BATON_PASS); + game.doSelectPartyPokemon(1); + await game.toNextTurn(); + + expect(getHeldItemCount(treecko)).toBe(0); + expect(getHeldItemCount(purrloin)).toBe(1); + expect(treecko.getEffectiveStat(Stat.SPD)).toBe(initialTreeckoSpeed); + expect(purrloin.getEffectiveStat(Stat.SPD)).toBe(initialPurrloinSpeed); + expect(unburdenAttr.applyPostItemLost).not.toHaveBeenCalled(); + }); + + it("should not speed up a Pokemon after it loses the ability Unburden", async () => { + game.override.enemyMoveset([ Moves.FALSE_SWIPE, Moves.WORRY_SEED ]); + await game.classicMode.startBattle([ Species.PURRLOIN ]); + + const playerPokemon = game.scene.getPlayerPokemon()!; + const playerHeldItems = getHeldItemCount(playerPokemon); + const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD); + + // Turn 1: Get hit by False Swipe and eat Sitrus Berry, activating Unburden + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.FALSE_SWIPE); + await game.toNextTurn(); + + expect(getHeldItemCount(playerPokemon)).toBeLessThan(playerHeldItems); + expect(playerPokemon.getEffectiveStat(Stat.SPD)).toBe(initialPlayerSpeed * 2); + + // Turn 2: Get hit by Worry Seed, deactivating Unburden + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.WORRY_SEED); + await game.toNextTurn(); + + expect(getHeldItemCount(playerPokemon)).toBeLessThan(playerHeldItems); + expect(playerPokemon.getEffectiveStat(Stat.SPD)).toBe(initialPlayerSpeed); + }); + + it("should activate when a reviver seed is used", async () => { + game.override.startingHeldItems([{ name: "REVIVER_SEED" }]) + .enemyMoveset([ Moves.WING_ATTACK ]); + await game.classicMode.startBattle([ Species.TREECKO ]); + + const playerPokemon = game.scene.getPlayerPokemon()!; + const playerHeldItems = getHeldItemCount(playerPokemon); + const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD); + + // Turn 1: Get hit by Wing Attack and faint, activating Reviver Seed + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + expect(getHeldItemCount(playerPokemon)).toBeLessThan(playerHeldItems); + expect(playerPokemon.getEffectiveStat(Stat.SPD)).toBe(initialPlayerSpeed * 2); + }); + + // test for `.bypassFaint()` - singles + it("shouldn't persist when revived normally if activated while fainting", async () => { + game.override.enemyMoveset([ Moves.SPLASH, Moves.THIEF ]); + await game.classicMode.startBattle([ Species.TREECKO, Species.FEEBAS ]); + + const treecko = game.scene.getPlayerPokemon()!; + const treeckoInitialHeldItems = getHeldItemCount(treecko); + const initialSpeed = treecko.getStat(Stat.SPD); + + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.THIEF); + game.doSelectPartyPokemon(1); + await game.toNextTurn(); + + game.doRevivePokemon(1); + game.doSwitchPokemon(1); + await game.forceEnemyMove(Moves.SPLASH); + await game.toNextTurn(); + + expect(game.scene.getPlayerPokemon()!).toBe(treecko); + expect(getHeldItemCount(treecko)).toBeLessThan(treeckoInitialHeldItems); + expect(treecko.getEffectiveStat(Stat.SPD)).toBe(initialSpeed); + }); + + // test for `.bypassFaint()` - doubles + it("shouldn't persist when revived by revival blessing if activated while fainting", async () => { + game.override + .battleType("double") + .enemyMoveset([ Moves.SPLASH, Moves.THIEF ]) + .moveset([ Moves.SPLASH, Moves.REVIVAL_BLESSING ]) + .startingHeldItems([{ name: "WIDE_LENS" }]); + await game.classicMode.startBattle([ Species.TREECKO, Species.FEEBAS, Species.MILOTIC ]); + + const treecko = game.scene.getPlayerField()[0]; + const treeckoInitialHeldItems = getHeldItemCount(treecko); + const initialSpeed = treecko.getStat(Stat.SPD); + + game.move.select(Moves.SPLASH); + game.move.select(Moves.REVIVAL_BLESSING, 1); + await game.forceEnemyMove(Moves.THIEF, BattlerIndex.PLAYER); + await game.forceEnemyMove(Moves.SPLASH); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2 ]); + game.doSelectPartyPokemon(0, "MoveEffectPhase"); + await game.toNextTurn(); + + expect(game.scene.getPlayerField()[0]).toBe(treecko); + expect(getHeldItemCount(treecko)).toBeLessThan(treeckoInitialHeldItems); + expect(treecko.getEffectiveStat(Stat.SPD)).toBe(initialSpeed); + }); }); From f2a2281ff11c5b644698121f6ce33f32830898b0 Mon Sep 17 00:00:00 2001 From: chaosgrimmon <31082757+chaosgrimmon@users.noreply.github.com> Date: Sun, 10 Nov 2024 14:37:21 -0500 Subject: [PATCH 35/75] [Sprite] Implement female icon assets for Meganium and Doduo + Torchic lines (#4841) * [Sprite] Implement more female icons * [Sprite] Add female Doduo/Dodrio icons * [Sprite] Add female Meganium icons * [Sprite] Add female Torchic line icons * [Sprite] Add female Meganium icons * [Sprite] Add female Torchic line icons Identical to male counterpart icons --- public/images/pokemon/icons/2/154-f.png | Bin 0 -> 427 bytes public/images/pokemon/icons/2/154s-f.png | Bin 0 -> 464 bytes public/images/pokemon/icons/3/255-f.png | Bin 0 -> 267 bytes public/images/pokemon/icons/3/255s-f.png | Bin 0 -> 268 bytes public/images/pokemon/icons/3/256-f.png | Bin 0 -> 373 bytes public/images/pokemon/icons/3/256s-f.png | Bin 0 -> 451 bytes public/images/pokemon/icons/3/257-f-mega.png | Bin 0 -> 493 bytes public/images/pokemon/icons/3/257-f.png | Bin 0 -> 451 bytes public/images/pokemon/icons/3/257s-f-mega.png | Bin 0 -> 524 bytes public/images/pokemon/icons/3/257s-f.png | Bin 0 -> 530 bytes public/images/pokemon_icons_1.json | 84 ++++++++++++ public/images/pokemon_icons_2.json | 42 ++++++ public/images/pokemon_icons_3.json | 126 ++++++++++++++++++ src/data/pokemon-species.ts | 6 + 14 files changed, 258 insertions(+) create mode 100644 public/images/pokemon/icons/2/154-f.png create mode 100644 public/images/pokemon/icons/2/154s-f.png create mode 100644 public/images/pokemon/icons/3/255-f.png create mode 100644 public/images/pokemon/icons/3/255s-f.png create mode 100644 public/images/pokemon/icons/3/256-f.png create mode 100644 public/images/pokemon/icons/3/256s-f.png create mode 100644 public/images/pokemon/icons/3/257-f-mega.png create mode 100644 public/images/pokemon/icons/3/257-f.png create mode 100644 public/images/pokemon/icons/3/257s-f-mega.png create mode 100644 public/images/pokemon/icons/3/257s-f.png diff --git a/public/images/pokemon/icons/2/154-f.png b/public/images/pokemon/icons/2/154-f.png new file mode 100644 index 0000000000000000000000000000000000000000..6481cdd8a00bbba52c035ebd8b9867d44a82ef37 GIT binary patch literal 427 zcmV;c0aX5pP)X0004UNklb>!3`Ko}9KmPln9qguG1rl}A06mWOg+BJP{@*(Z> z*U#S8x+pO~00cn7X+CwTv7v{Tg2X20oMx2_ zw1mNw@a3K%Z-Bn!wY4UIghXOU2xsc>W$LpBBwSbzLNWTC9|{e&K{()iav;Q%S#G>jIK2-6 z0WbcEP)X0004(Nkllfr0~AoPrB*0NimODkP2q1r-!7({Tnwl_StlEdCpR>u0nZM`U)rBaMQ_e2=M9gCO(cYSKsaYI&Oy2Wi6fA0 zjq7C!MdDnB&(}lF$keiT2mbEgmMTT)6cICpZTEtlfwtv(%@s%_5<^0uJ&UO5&-48e zRI%nb_yF+_6{r|{jn}^(t|OF4fD`A{cSy9I`hmGBS|GoWJJ6mTcHif10hS9?Z$hG)8|!y91bFN*V(1a)r719vX0002eNkl}K_3|xr&Rb$_)Au<X0002fNkl+%NOFXINQwd!$zv4G=~ z>)W)`AU&>EIw0}|5Z(Mal4s9uXEKP)X0003zNklNN?OW{zzQi@!B`^SD8|W!!j2B2yMMrOhhHT9AJQ~? z?e$%?ZR;UbPFxz9Ug%m&fhO4f(=&5sJV*)Zs@H) z+v$i^IF{g~RCR4moA2EcoLWFK2=AZt(!6GqQRZ};oL}bZk~g!;$jlU zoEtaoY7P`DQXG;Fa^__e0OpJWqs8w-6$OMrNN&tO5@%u3Rk^Rcv!SrlRRASqm%`fV zUoHSviysMz4gpF^0@Vv|cVwlmOd&VBCojbXZiTo2m5-i$_X&W-4e?XY$A4K*f(EN@ Twsxr800000NkvXXu0mjf8iAT> literal 0 HcmV?d00001 diff --git a/public/images/pokemon/icons/3/256s-f.png b/public/images/pokemon/icons/3/256s-f.png new file mode 100644 index 0000000000000000000000000000000000000000..ce6608f7bc5c4a2cb11ca0705cf6b7f442acbe70 GIT binary patch literal 451 zcmV;!0X+VRP)X0004sNklQLj4P1H&kDG(<1EUoLXyy&F zu)Lr5&xXP|S3I+d7oauZt)nbUM@^lZ6i~1K?3Y1+5uaXMgNCk~1&~k@j>ptP0FRr6 z7s1+jfRl5=ngjlx-lKwX0-evbYuEnaJ}+>wedd7QhjkDj0N2jl*T8SlaQN?yM8Jb3GM?*^1jm#V6&2Z$j7aRXzJ z$pB#lVMF*Rz{#c@Lb_dFa>JY=ooN8vM<-VkV%t7se z?h!Uw%|ozB0b_751~JUBa3fb^piB`nK2#W79OaWOS5CHMk0^wMD zRpx646>>TYpoH|zTEKEHA?ZES9E?HILxhr&MaH>#k<@kVrQ3&wH1C6B9vm{xM#vU-`U8!~)f{J@Yb*c&002ovPDHLkV1gct%q#!^ literal 0 HcmV?d00001 diff --git a/public/images/pokemon/icons/3/257-f-mega.png b/public/images/pokemon/icons/3/257-f-mega.png new file mode 100644 index 0000000000000000000000000000000000000000..ed64fe8f41f3cedeca980ad3befcf181ac75f327 GIT binary patch literal 493 zcmVX0005BNkl*MZf5rBvT3fMi{R$gRx5+FvJ0Exi} zhi)5S&TcL)2Ll4BdjM)KtMscI6KHY3wqqvd(7}Uv)yojqF?1Ym@G)zF8)G9cH6DB1 z^Q7?yV!b~Qdo-QaAWs6OBb7KDfbKnx8#%w6>UEk4lSyz6DT6W$AfE8I3dPwIhcG}t zLgvC~R41e1apet!gGR`xFE|IBrK@q{OX0004sNkl zF>b>!3`KK{j=n}lUqM&t*fC?*jv0H6jvh01%~jNp%@ckI*GU1JS|WguV;S+&C;8>w z?m3djFbuUf!y;ULE%hFxt#{eTBY=-?A`K9=h;DFmkbYe!k5Y=?{}@OA-3<~z2MTag z**Cy$kN_IY_w?4_P|xlG2xKa#z0Ba6iUH1MRnfxkr$Yh;oIwMwwHVb*fm1;0t{l#_ zp2izBiOo~4Hex`QT2~0AE?^FQ1>_lpRM1sZ?oeN!9>@1Xo1=;bXHW$7XwL#@*Q=%+ zIKX&0f2@{cK^;bgHRTGq3Lud7Qk09&pqQ$s4Z|jY)J?9EVvV_V(iyGAo9AjpwmF4N z>*xk|n)g2xqf}N^@1CmETWb{YKTaA{q>hQrAOX{$A#O}sW)##p1&|YjPPMfN3m~ea ziX0005gNkl{prMAI1<+7ZrDX+_)QDx!A$CBS3K<MzwOx4 z$j;UE_{-c!oK;a2t0l+50iA($N0w#v9Y#2M1BH8i+!k$+>O(9F2YD<-Y&V5s5YUq}0V7U*QWaFr&)rBs5&L}1|^=pm0xTzrefe(|^FG)f=lAKeqx_ebWexIJGO9wxZF1`}dF3daON(#t{K-jXD9*M3 O0000X0005mNkllc3X0T`H~<9&H5Wj%IRW*uZ?&KG7&#F?_5u!U_6}i z;Uz~R4x_`qUKLfVhs6 zO=A$q&Bf6Oq}EFhkbeBBf0&oUquKkQCy2mYu|873X@MN>+r6-Qjf`-5I2v6VprV>P zSSsWZ?hvFF188%=5>$i(D7rX{gIS8Hf;a{<)bv8p6!5bbArSAY{BZyOZ{`Df1F=YV U=XA_GX#fBK07*qoM6N<$g1^J=Hvj+t literal 0 HcmV?d00001 diff --git a/public/images/pokemon_icons_1.json b/public/images/pokemon_icons_1.json index 49e471514cd..12e26b380a5 100644 --- a/public/images/pokemon_icons_1.json +++ b/public/images/pokemon_icons_1.json @@ -1647,6 +1647,27 @@ "h": 25 } }, + { + "filename": "85-f", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 5, + "y": 3, + "w": 29, + "h": 25 + }, + "frame": { + "x": 55, + "y": 270, + "w": 29, + "h": 25 + } + }, { "filename": "22s", "rotated": false, @@ -1731,6 +1752,27 @@ "h": 25 } }, + { + "filename": "85s-f", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 5, + "y": 3, + "w": 29, + "h": 25 + }, + "frame": { + "x": 56, + "y": 317, + "w": 29, + "h": 25 + } + }, { "filename": "9s", "rotated": false, @@ -6456,6 +6498,27 @@ "h": 18 } }, + { + "filename": "84-f", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 9, + "y": 10, + "w": 21, + "h": 18 + }, + "frame": { + "x": 98, + "y": 712, + "w": 21, + "h": 18 + } + }, { "filename": "107", "rotated": false, @@ -6519,6 +6582,27 @@ "h": 18 } }, + { + "filename": "84s-f", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 9, + "y": 10, + "w": 21, + "h": 18 + }, + "frame": { + "x": 96, + "y": 770, + "w": 21, + "h": 18 + } + }, { "filename": "88", "rotated": false, diff --git a/public/images/pokemon_icons_2.json b/public/images/pokemon_icons_2.json index 5a389362bc0..c5ebfe61487 100644 --- a/public/images/pokemon_icons_2.json +++ b/public/images/pokemon_icons_2.json @@ -786,6 +786,27 @@ "h": 27 } }, + { + "filename": "154-f", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 8, + "y": 1, + "w": 23, + "h": 27 + }, + "frame": { + "x": 29, + "y": 147, + "w": 23, + "h": 27 + } + }, { "filename": "154s", "rotated": false, @@ -807,6 +828,27 @@ "h": 27 } }, + { + "filename": "154s-f", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 8, + "y": 1, + "w": 23, + "h": 27 + }, + "frame": { + "x": 29, + "y": 174, + "w": 23, + "h": 27 + } + }, { "filename": "229-mega", "rotated": false, diff --git a/public/images/pokemon_icons_3.json b/public/images/pokemon_icons_3.json index 220d91f5222..a1aefa0ff0b 100644 --- a/public/images/pokemon_icons_3.json +++ b/public/images/pokemon_icons_3.json @@ -198,6 +198,27 @@ "h": 27 } }, + { + "filename": "257-f-mega", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 4, + "y": 2, + "w": 32, + "h": 27 + }, + "frame": { + "x": 0, + "y": 79, + "w": 32, + "h": 27 + } + }, { "filename": "257s-mega", "rotated": false, @@ -219,6 +240,27 @@ "h": 27 } }, + { + "filename": "257s-f-mega", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 4, + "y": 2, + "w": 32, + "h": 27 + }, + "frame": { + "x": 0, + "y": 106, + "w": 32, + "h": 27 + } + }, { "filename": "323-mega", "rotated": false, @@ -1248,6 +1290,27 @@ "h": 26 } }, + { + "filename": "257-f", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 7, + "y": 2, + "w": 25, + "h": 26 + }, + "frame": { + "x": 28, + "y": 556, + "w": 25, + "h": 26 + } + }, { "filename": "257s", "rotated": false, @@ -1269,6 +1332,27 @@ "h": 26 } }, + { + "filename": "257s-f", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 7, + "y": 2, + "w": 25, + "h": 26 + }, + "frame": { + "x": 28, + "y": 582, + "w": 25, + "h": 26 + } + }, { "filename": "359-mega", "rotated": false, @@ -1605,6 +1689,27 @@ "h": 25 } }, + { + "filename": "256-f", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 8, + "y": 3, + "w": 23, + "h": 25 + }, + "frame": { + "x": 98, + "y": 72, + "w": 23, + "h": 25 + } + }, { "filename": "282s-mega", "rotated": false, @@ -5553,6 +5658,27 @@ "h": 19 } }, + { + "filename": "255-f", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 13, + "y": 9, + "w": 13, + "h": 19 + }, + "frame": { + "x": 204, + "y": 342, + "w": 13, + "h": 19 + } + }, { "filename": "307s", "rotated": false, diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index ff53fdb9392..203e545503a 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -363,6 +363,12 @@ export abstract class PokemonSpeciesForm { } switch (this.speciesId) { + case Species.DODUO: + case Species.DODRIO: + case Species.MEGANIUM: + case Species.TORCHIC: + case Species.COMBUSKEN: + case Species.BLAZIKEN: case Species.HIPPOPOTAS: case Species.HIPPOWDON: case Species.UNFEZANT: From efa9f119a0e803ff13409e67adaa9f1dbef206b0 Mon Sep 17 00:00:00 2001 From: PigeonBar <56974298+PigeonBar@users.noreply.github.com> Date: Mon, 11 Nov 2024 02:18:57 -0500 Subject: [PATCH 36/75] [Beta][P3] Fix shiny Pokemon being displayed before shiny colours are loaded (#4843) --- src/field/pokemon.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index d806a9b605c..9e5103656d3 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -442,7 +442,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { }; if (this.shiny) { const populateVariantColors = (isBackSprite: boolean = false): Promise => { - return new Promise(resolve => { + return new Promise(async resolve => { const battleSpritePath = this.getBattleSpriteAtlasPath(isBackSprite, ignoreOverride).replace("variant/", "").replace(/_[1-3]$/, ""); let config = variantData; const useExpSprite = this.scene.experimentalSprites && this.scene.hasExpSprite(this.getBattleSpriteKey(isBackSprite, ignoreOverride)); @@ -451,7 +451,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (variantSet && variantSet[this.variant] === 1) { const cacheKey = this.getBattleSpriteKey(isBackSprite); if (!variantColorCache.hasOwnProperty(cacheKey)) { - this.populateVariantColorCache(cacheKey, useExpSprite, battleSpritePath); + await this.populateVariantColorCache(cacheKey, useExpSprite, battleSpritePath); } } resolve(); @@ -483,10 +483,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @param battleSpritePath the filename of the sprite * @param optionalParams any additional params to log */ - fallbackVariantColor(cacheKey: string, attemptedSpritePath: string, useExpSprite: boolean, battleSpritePath: string, ...optionalParams: any[]) { + async fallbackVariantColor(cacheKey: string, attemptedSpritePath: string, useExpSprite: boolean, battleSpritePath: string, ...optionalParams: any[]) { console.warn(`Could not load ${attemptedSpritePath}!`, ...optionalParams); if (useExpSprite) { - this.populateVariantColorCache(cacheKey, false, battleSpritePath); + await this.populateVariantColorCache(cacheKey, false, battleSpritePath); } } @@ -497,18 +497,20 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @param useExpSprite should the experimental sprite be used * @param battleSpritePath the filename of the sprite */ - populateVariantColorCache(cacheKey: string, useExpSprite: boolean, battleSpritePath: string) { + async populateVariantColorCache(cacheKey: string, useExpSprite: boolean, battleSpritePath: string) { const spritePath = `./images/pokemon/variant/${useExpSprite ? "exp/" : ""}${battleSpritePath}.json`; - this.scene.cachedFetch(spritePath).then(res => { + return this.scene.cachedFetch(spritePath).then(res => { // Prevent the JSON from processing if it failed to load if (!res.ok) { return this.fallbackVariantColor(cacheKey, res.url, useExpSprite, battleSpritePath, res.status, res.statusText); } return res.json(); }).catch(error => { - this.fallbackVariantColor(cacheKey, spritePath, useExpSprite, battleSpritePath, error); + return this.fallbackVariantColor(cacheKey, spritePath, useExpSprite, battleSpritePath, error); }).then(c => { - variantColorCache[cacheKey] = c; + if (!isNullOrUndefined(c)) { + variantColorCache[cacheKey] = c; + } }); } From 6799594bbb43a8a7a8431a5f7c52062ee917dd3e Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sun, 10 Nov 2024 23:21:06 -0800 Subject: [PATCH 37/75] [Test] Update Zen Mode test (#4845) --- src/test/abilities/zen_mode.test.ts | 87 ++++++++++------------------- 1 file changed, 31 insertions(+), 56 deletions(-) diff --git a/src/test/abilities/zen_mode.test.ts b/src/test/abilities/zen_mode.test.ts index 4ba5e3d5929..e0cc457c4d5 100644 --- a/src/test/abilities/zen_mode.test.ts +++ b/src/test/abilities/zen_mode.test.ts @@ -1,14 +1,8 @@ -import { BattlerIndex } from "#app/battle"; import { Status } from "#app/data/status-effect"; -import { DamagePhase } from "#app/phases/damage-phase"; -import { SwitchSummonPhase } from "#app/phases/switch-summon-phase"; -import { Mode } from "#app/ui/ui"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; -import { Stat } from "#enums/stat"; import { StatusEffect } from "#enums/status-effect"; -import { SwitchType } from "#enums/switch-type"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -34,78 +28,60 @@ describe("Abilities - ZEN MODE", () => { game = new GameManager(phaserGame); game.override .battleType("single") - .enemySpecies(Species.RATTATA) - .enemyAbility(Abilities.HYDRATION) + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyLevel(5) .ability(Abilities.ZEN_MODE) - .startingLevel(100) .moveset(Moves.SPLASH) - .enemyMoveset(Moves.TACKLE); + .enemyMoveset(Moves.SEISMIC_TOSS); }); it("shouldn't change form when taking damage if not dropping below 50% HP", async () => { await game.classicMode.startBattle([ Species.DARMANITAN ]); - const player = game.scene.getPlayerPokemon()!; - player.stats[Stat.HP] = 100; - player.hp = 100; - expect(player.formIndex).toBe(baseForm); + const darmanitan = game.scene.getPlayerPokemon()!; + expect(darmanitan.formIndex).toBe(baseForm); game.move.select(Moves.SPLASH); - await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]); - await game.phaseInterceptor.to("BerryPhase"); + await game.toNextTurn(); - expect(player.hp).toBeLessThan(100); - expect(player.formIndex).toBe(baseForm); + expect(darmanitan.getHpRatio()).toBeLessThan(1); + expect(darmanitan.getHpRatio()).toBeGreaterThan(0.5); + expect(darmanitan.formIndex).toBe(baseForm); }); it("should change form when falling below 50% HP", async () => { await game.classicMode.startBattle([ Species.DARMANITAN ]); - const player = game.scene.getPlayerPokemon()!; - player.stats[Stat.HP] = 1000; - player.hp = 100; - expect(player.formIndex).toBe(baseForm); + const darmanitan = game.scene.getPlayerPokemon()!; + darmanitan.hp = (darmanitan.getMaxHp() / 2) + 1; + expect(darmanitan.formIndex).toBe(baseForm); game.move.select(Moves.SPLASH); + await game.toNextTurn(); - await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]); - await game.phaseInterceptor.to("QuietFormChangePhase"); - await game.phaseInterceptor.to("TurnInitPhase", false); - - expect(player.hp).not.toBe(100); - expect(player.formIndex).toBe(zenForm); + expect(darmanitan.getHpRatio()).toBeLessThan(0.5); + expect(darmanitan.formIndex).toBe(zenForm); }); it("should stay zen mode when fainted", async () => { await game.classicMode.startBattle([ Species.DARMANITAN, Species.CHARIZARD ]); - const player = game.scene.getPlayerPokemon()!; - player.stats[Stat.HP] = 1000; - player.hp = 100; - expect(player.formIndex).toBe(baseForm); + const darmanitan = game.scene.getPlayerPokemon()!; + darmanitan.hp = (darmanitan.getMaxHp() / 2) + 1; + expect(darmanitan.formIndex).toBe(baseForm); game.move.select(Moves.SPLASH); + await game.toNextTurn(); - await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]); - await game.phaseInterceptor.to(DamagePhase, false); - const damagePhase = game.scene.getCurrentPhase() as DamagePhase; - damagePhase.updateAmount(80); - await game.phaseInterceptor.to("QuietFormChangePhase"); + expect(darmanitan.getHpRatio()).toBeLessThan(0.5); + expect(darmanitan.formIndex).toBe(zenForm); - expect(player.hp).not.toBe(100); - expect(player.formIndex).toBe(zenForm); - - await game.killPokemon(player); - expect(player.isFainted()).toBe(true); - - await game.phaseInterceptor.to("TurnStartPhase"); - game.onNextPrompt("SwitchPhase", Mode.PARTY, () => { - game.scene.unshiftPhase(new SwitchSummonPhase(game.scene, SwitchType.SWITCH, 0, 1, false)); - game.scene.ui.setMode(Mode.MESSAGE); - }); - game.onNextPrompt("SwitchPhase", Mode.MESSAGE, () => { - game.endPhase(); - }); - await game.phaseInterceptor.to("PostSummonPhase"); + game.move.select(Moves.SPLASH); + await game.killPokemon(darmanitan); + game.doSelectPartyPokemon(1); + await game.toNextTurn(); + expect(darmanitan.isFainted()).toBe(true); expect(game.scene.getPlayerParty()[1].formIndex).toBe(zenForm); }); @@ -117,7 +93,8 @@ describe("Abilities - ZEN MODE", () => { await game.classicMode.startBattle([ Species.MAGIKARP, Species.DARMANITAN ]); - const darmanitan = game.scene.getPlayerParty().find((p) => p.species.speciesId === Species.DARMANITAN)!; + const darmanitan = game.scene.getPlayerParty()[1]; + darmanitan.hp = 1; expect(darmanitan.formIndex).toBe(zenForm); darmanitan.hp = 0; @@ -126,9 +103,7 @@ describe("Abilities - ZEN MODE", () => { game.move.select(Moves.SPLASH); await game.doKillOpponents(); - await game.phaseInterceptor.to("TurnEndPhase"); - game.doSelectModifier(); - await game.phaseInterceptor.to("QuietFormChangePhase"); + await game.toNextWave(); expect(darmanitan.formIndex).toBe(baseForm); }); From 6feb63484c308d3f376e1f77ed2c05ae760d9fb3 Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Mon, 11 Nov 2024 09:29:20 -0800 Subject: [PATCH 38/75] [P3] Added `failIfSingleBattle` condtion to Doubles-only moves and display failure message when used in singles (#4839) * Added failIfSingleBattle condtion to Helping Hand * Added failIfSingleBattle conditions to Doubles-Only moves * Adjusted canMove failure condition. * Updated moves that failIfSingleBattle * Fixed condtional. --------- Co-authored-by: frutescens --- src/data/move.ts | 11 ++++++++--- src/phases/move-phase.ts | 19 ++++++------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index 9cd4881488c..a79ac386a7e 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -8480,7 +8480,8 @@ export function initMoves() { new StatusMove(Moves.HELPING_HAND, Type.NORMAL, -1, 20, -1, 5, 3) .attr(AddBattlerTagAttr, BattlerTagType.HELPING_HAND) .ignoresSubstitute() - .target(MoveTarget.NEAR_ALLY), + .target(MoveTarget.NEAR_ALLY) + .condition(failIfSingleBattle), new StatusMove(Moves.TRICK, Type.PSYCHIC, 100, 10, -1, 0, 3) .unimplemented(), new StatusMove(Moves.ROLE_PLAY, Type.PSYCHIC, -1, 10, -1, 0, 3) @@ -9172,6 +9173,7 @@ export function initMoves() { .target(MoveTarget.ALL_NEAR_ENEMIES) .attr(RemoveHeldItemAttr, true), new StatusMove(Moves.QUASH, Type.DARK, 100, 15, -1, 0, 5) + .condition(failIfSingleBattle) .unimplemented(), new AttackMove(Moves.ACROBATICS, Type.FLYING, MoveCategory.PHYSICAL, 55, 100, 15, -1, 0, 5) .attr(MovePowerMultiplierAttr, (user, target, move) => Math.max(1, 2 - 0.2 * user.getHeldItems().filter(i => i.isTransferable).reduce((v, m) => v + m.stackCount, 0))), @@ -9459,6 +9461,7 @@ export function initMoves() { new StatusMove(Moves.AROMATIC_MIST, Type.FAIRY, -1, 20, -1, 0, 6) .attr(StatStageChangeAttr, [ Stat.SPDEF ], 1) .ignoresSubstitute() + .condition(failIfSingleBattle) .target(MoveTarget.NEAR_ALLY), new StatusMove(Moves.EERIE_IMPULSE, Type.ELECTRIC, 100, 15, -1, 0, 6) .attr(StatStageChangeAttr, [ Stat.SPATK ], -2), @@ -9687,7 +9690,8 @@ export function initMoves() { new AttackMove(Moves.LEAFAGE, Type.GRASS, MoveCategory.PHYSICAL, 40, 100, 40, -1, 0, 7) .makesContact(false), new StatusMove(Moves.SPOTLIGHT, Type.NORMAL, -1, 15, -1, 3, 7) - .attr(AddBattlerTagAttr, BattlerTagType.CENTER_OF_ATTENTION, false), + .attr(AddBattlerTagAttr, BattlerTagType.CENTER_OF_ATTENTION, false) + .condition(failIfSingleBattle), new StatusMove(Moves.TOXIC_THREAD, Type.POISON, 100, 20, -1, 0, 7) .attr(StatusEffectAttr, StatusEffect.POISON) .attr(StatStageChangeAttr, [ Stat.SPD ], -1), @@ -10144,7 +10148,8 @@ export function initMoves() { .unimplemented(), new StatusMove(Moves.COACHING, Type.FIGHTING, -1, 10, -1, 0, 8) .attr(StatStageChangeAttr, [ Stat.ATK, Stat.DEF ], 1) - .target(MoveTarget.NEAR_ALLY), + .target(MoveTarget.NEAR_ALLY) + .condition(failIfSingleBattle), new AttackMove(Moves.FLIP_TURN, Type.WATER, MoveCategory.PHYSICAL, 60, 100, 20, -1, 0, 8) .attr(ForceSwitchOutAttr, true), new AttackMove(Moves.TRIPLE_AXEL, Type.ICE, MoveCategory.PHYSICAL, 20, 90, 10, -1, 0, 8) diff --git a/src/phases/move-phase.ts b/src/phases/move-phase.ts index 6bdef281d70..7cfa3b12476 100644 --- a/src/phases/move-phase.ts +++ b/src/phases/move-phase.ts @@ -120,13 +120,10 @@ export class MovePhase extends BattlePhase { console.log(Moves[this.move.moveId]); // Check if move is unusable (e.g. because it's out of PP due to a mid-turn Spite). - if (!this.canMove(true)) { - if (this.pokemon.isActive(true) && this.move.ppUsed >= this.move.getMovePp()) { - this.fail(); - this.showMoveText(); - this.showFailedText(); - } - + if (!this.canMove(true) && (this.pokemon.isActive(true) || this.move.ppUsed >= this.move.getMovePp())) { + this.fail(); + this.showMoveText(); + this.showFailedText(); return this.end(); } @@ -378,16 +375,12 @@ export class MovePhase extends BattlePhase { } else { this.pokemon.pushMoveHistory({ move: this.move.moveId, targets: this.targets, result: MoveResult.FAIL, virtual: this.move.virtual }); - let failedText: string | undefined; const failureMessage = move.getFailedText(this.pokemon, targets[0], move, new BooleanHolder(false)); - if (failureMessage) { - failedText = failureMessage; + this.showMoveText(); + this.showFailedText(failureMessage); } - this.showMoveText(); - this.showFailedText(failedText); - // Remove the user from its semi-invulnerable state (if applicable) this.pokemon.lapseTags(BattlerTagLapseType.MOVE_EFFECT); } From e5e392617615ec5023afe5662ceb3cd7c0720f6d Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Mon, 11 Nov 2024 12:13:15 -0800 Subject: [PATCH 39/75] [beta] Fix MovePhase not ending properly. (#4848) Co-authored-by: frutescens --- src/phases/move-phase.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/phases/move-phase.ts b/src/phases/move-phase.ts index 7cfa3b12476..378b72e1f56 100644 --- a/src/phases/move-phase.ts +++ b/src/phases/move-phase.ts @@ -120,10 +120,12 @@ export class MovePhase extends BattlePhase { console.log(Moves[this.move.moveId]); // Check if move is unusable (e.g. because it's out of PP due to a mid-turn Spite). - if (!this.canMove(true) && (this.pokemon.isActive(true) || this.move.ppUsed >= this.move.getMovePp())) { - this.fail(); - this.showMoveText(); - this.showFailedText(); + if (!this.canMove(true)) { + if (this.pokemon.isActive(true)) { + this.fail(); + this.showMoveText(); + this.showFailedText(); + } return this.end(); } From cebedd220bd4259b4bee449bb88cc686853b3474 Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Mon, 11 Nov 2024 14:56:16 -0800 Subject: [PATCH 40/75] [Balance] Rework Multi-Lens (#4831) * Rework Multi-Lens * Multi-Lens integration tests * Apply suggestions from code review Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Fix obsolete tests related to Multi-Lens * Fix flaky unburden tests * maybe fix flaky ceaseless edge test? * Fixed Multi-Lens apply comment * Fix ceaseless edge test for real this time * Update locales * Another locale update --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- public/locales | 2 +- src/data/ability.ts | 61 ++++----------- src/data/move.ts | 38 ++++++++- src/field/pokemon.ts | 9 ++- src/modifier/modifier.ts | 64 +++++++++++----- src/phases/move-effect-phase.ts | 11 +-- src/test/abilities/parental_bond.test.ts | 60 ++------------- src/test/items/multi_lens.test.ts | 98 ++++++++++++++++++++++++ src/test/moves/beat_up.test.ts | 25 ------ src/test/moves/ceaseless_edge.test.ts | 12 +-- src/test/moves/dragon_rage.test.ts | 11 --- src/test/moves/electro_shot.test.ts | 2 +- 12 files changed, 215 insertions(+), 178 deletions(-) create mode 100644 src/test/items/multi_lens.test.ts diff --git a/public/locales b/public/locales index d600913dbf1..5775faa6b31 160000 --- a/public/locales +++ b/public/locales @@ -1 +1 @@ -Subproject commit d600913dbf1f8b47dae8dccbd8296df78f1c51b5 +Subproject commit 5775faa6b3184082df73f6cdb96b253ea7dae3fe diff --git a/src/data/ability.ts b/src/data/ability.ts index 49763991e0e..4194be31405 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -7,7 +7,7 @@ import { Weather } from "#app/data/weather"; import { BattlerTag, BattlerTagLapseType, GroundedTag } from "./battler-tags"; import { getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "#app/data/status-effect"; import { Gender } from "./gender"; -import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, MoveAttr, MultiHitAttr, SacrificialAttr, SacrificialAttrOnHit, NeutralDamageAgainstFlyingTypeMultiplierAttr, FixedDamageAttr } from "./move"; +import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, NeutralDamageAgainstFlyingTypeMultiplierAttr, FixedDamageAttr } from "./move"; import { ArenaTagSide, ArenaTrapTag } from "./arena-tag"; import { BerryModifier, HitHealModifier, PokemonHeldItemModifier } from "../modifier/modifier"; import { TerrainType } from "./terrain"; @@ -1351,65 +1351,30 @@ export class AddSecondStrikeAbAttr extends PreAttackAbAttr { this.damageMultiplier = damageMultiplier; } - /** - * Determines whether this attribute can apply to a given move. - * @param {Move} move the move to which this attribute may apply - * @param numTargets the number of {@linkcode Pokemon} targeted by this move - * @returns true if the attribute can apply to the move, false otherwise - */ - canApplyPreAttack(move: Move, numTargets: integer): boolean { - /** - * Parental Bond cannot apply to multi-hit moves, charging moves, or - * moves that cause the user to faint. - */ - const exceptAttrs: Constructor[] = [ - MultiHitAttr, - SacrificialAttr, - SacrificialAttrOnHit - ]; - - /** Parental Bond cannot apply to these specific moves */ - const exceptMoves: Moves[] = [ - Moves.FLING, - Moves.UPROAR, - Moves.ROLLOUT, - Moves.ICE_BALL, - Moves.ENDEAVOR - ]; - - /** Also check if this move is an Attack move and if it's only targeting one Pokemon */ - return numTargets === 1 - && !move.isChargingMove() - && !exceptAttrs.some(attr => move.hasAttr(attr)) - && !exceptMoves.some(id => move.id === id) - && move.category !== MoveCategory.STATUS; - } - /** * If conditions are met, this doubles the move's hit count (via args[1]) * or multiplies the damage of secondary strikes (via args[2]) - * @param {Pokemon} pokemon the Pokemon using the move + * @param pokemon the {@linkcode Pokemon} using the move * @param passive n/a * @param defender n/a - * @param {Move} move the move used by the ability source - * @param args\[0\] the number of Pokemon this move is targeting - * @param {Utils.IntegerHolder} args\[1\] the number of strikes with this move - * @param {Utils.NumberHolder} args\[2\] the damage multiplier for the current strike + * @param move the {@linkcode Move} used by the ability source + * @param args Additional arguments: + * - `[0]` the number of strikes this move currently has ({@linkcode Utils.NumberHolder}) + * - `[1]` the damage multiplier for the current strike ({@linkcode Utils.NumberHolder}) * @returns */ applyPreAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, args: any[]): boolean { - const numTargets = args[0] as integer; - const hitCount = args[1] as Utils.IntegerHolder; - const multiplier = args[2] as Utils.NumberHolder; + const hitCount = args[0] as Utils.NumberHolder; + const multiplier = args[1] as Utils.NumberHolder; - if (this.canApplyPreAttack(move, numTargets)) { + if (move.canBeMultiStrikeEnhanced(pokemon)) { this.showAbility = !!hitCount?.value; - if (!!hitCount?.value) { - hitCount.value *= 2; + if (hitCount?.value) { + hitCount.value += 1; } - if (!!multiplier?.value && pokemon.turnData.hitsLeft % 2 === 1 && pokemon.turnData.hitsLeft !== pokemon.turnData.hitCount) { - multiplier.value *= this.damageMultiplier; + if (multiplier?.value && pokemon.turnData.hitsLeft === 1) { + multiplier.value = this.damageMultiplier; } return true; } diff --git a/src/data/move.ts b/src/data/move.ts index a79ac386a7e..0de9d9b53a2 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -818,7 +818,7 @@ export default class Move implements Localizable { applyMoveAttrs(VariablePowerAttr, source, target, this, power); - source.scene.applyModifiers(PokemonMultiHitModifier, source.isPlayer(), source, new Utils.IntegerHolder(0), power); + source.scene.applyModifiers(PokemonMultiHitModifier, source.isPlayer(), source, this.id, null, power); if (!this.hasAttr(TypelessAttr)) { source.scene.arena.applyTags(WeakenMoveTypeTag, simulated, this.type, power); @@ -840,6 +840,42 @@ export default class Move implements Localizable { return priority.value; } + + /** + * Returns `true` if this move can be given additional strikes + * by enhancing effects. + * Currently used for {@link https://bulbapedia.bulbagarden.net/wiki/Parental_Bond_(Ability) | Parental Bond} + * and {@linkcode PokemonMultiHitModifier | Multi-Lens}. + */ + canBeMultiStrikeEnhanced(user: Pokemon): boolean { + // Multi-strike enhancers... + + // ...cannot enhance moves that hit multiple targets + const { targets, multiple } = getMoveTargets(user, this.id); + const isMultiTarget = multiple && targets.length > 1; + + // ...cannot enhance multi-hit or sacrificial moves + const exceptAttrs: Constructor[] = [ + MultiHitAttr, + SacrificialAttr, + SacrificialAttrOnHit + ]; + + // ...and cannot enhance these specific moves. + const exceptMoves: Moves[] = [ + Moves.FLING, + Moves.UPROAR, + Moves.ROLLOUT, + Moves.ICE_BALL, + Moves.ENDEAVOR + ]; + + return !isMultiTarget + && !this.isChargingMove() + && !exceptAttrs.some(attr => this.hasAttr(attr)) + && !exceptMoves.some(id => this.id === id) + && this.category !== MoveCategory.STATUS; + } } export class AttackMove extends Move { diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 9e5103656d3..5d912f7d6e6 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -2642,10 +2642,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const numTargets = multiple ? targets.length : 1; const targetMultiplier = (numTargets > 1) ? 0.75 : 1; - /** 0.25x multiplier if this is an added strike from the attacker's Parental Bond */ - const parentalBondMultiplier = new Utils.NumberHolder(1); + /** Multiplier for moves enhanced by Multi-Lens and/or Parental Bond */ + const multiStrikeEnhancementMultiplier = new Utils.NumberHolder(1); + source.scene.applyModifiers(PokemonMultiHitModifier, source.isPlayer(), source, move.id, null, multiStrikeEnhancementMultiplier); if (!ignoreSourceAbility) { - applyPreAttackAbAttrs(AddSecondStrikeAbAttr, source, this, move, simulated, numTargets, new Utils.IntegerHolder(0), parentalBondMultiplier); + applyPreAttackAbAttrs(AddSecondStrikeAbAttr, source, this, move, simulated, null, multiStrikeEnhancementMultiplier); } /** Doubles damage if this Pokemon's last move was Glaive Rush */ @@ -2722,7 +2723,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { damage.value = Utils.toDmgValue( baseDamage * targetMultiplier - * parentalBondMultiplier.value + * multiStrikeEnhancementMultiplier.value * arenaAttackTypeMultiplier.value * glaiveRushMultiplier.value * criticalMultiplier.value diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 90336780ba6..5e60d888072 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -6,7 +6,6 @@ import { allMoves } from "#app/data/move"; import { MAX_PER_TYPE_POKEBALLS } from "#app/data/pokeball"; import { type FormChangeItem, SpeciesFormChangeItemTrigger, SpeciesFormChangeLapseTeraTrigger, SpeciesFormChangeTeraTrigger } from "#app/data/pokemon-forms"; import { getStatusEffectHealText } from "#app/data/status-effect"; -import { Type } from "#enums/type"; import Pokemon, { type PlayerPokemon } from "#app/field/pokemon"; import { getPokemonNameWithAffix } from "#app/messages"; import Overrides from "#app/overrides"; @@ -22,11 +21,13 @@ import { BooleanHolder, hslToHex, isNullOrUndefined, NumberHolder, toDmgValue } import { Abilities } from "#enums/abilities"; import { BattlerTagType } from "#enums/battler-tag-type"; import { BerryType } from "#enums/berry-type"; +import { Moves } from "#enums/moves"; import type { Nature } from "#enums/nature"; import type { PokeballType } from "#enums/pokeball"; import { Species } from "#enums/species"; import { type PermanentStat, type TempBattleStat, BATTLE_STATS, Stat, TEMP_BATTLE_STATS } from "#enums/stat"; import { StatusEffect } from "#enums/status-effect"; +import { Type } from "#enums/type"; import i18next from "i18next"; import { type DoubleBattleChanceBoosterModifierType, type EvolutionItemModifierType, type FormChangeItemModifierType, type ModifierOverride, type ModifierType, type PokemonBaseStatTotalModifierType, type PokemonExpBoosterModifierType, type PokemonFriendshipBoosterModifierType, type PokemonMoveAccuracyBoosterModifierType, type PokemonMultiHitModifierType, type TerastallizeModifierType, type TmModifierType, getModifierType, ModifierPoolType, ModifierTypeGenerator, modifierTypes, PokemonHeldItemModifierType } from "./modifier-type"; import { Color, ShadowColor } from "#enums/color"; @@ -2689,32 +2690,57 @@ export class PokemonMultiHitModifier extends PokemonHeldItemModifier { } /** - * Applies {@linkcode PokemonMultiHitModifier} - * @param _pokemon The {@linkcode Pokemon} using the move - * @param count {@linkcode NumberHolder} holding the number of items - * @param power {@linkcode NumberHolder} holding the power of the move + * For each stack, converts 25 percent of attack damage into an additional strike. + * @param pokemon The {@linkcode Pokemon} using the move + * @param moveId The {@linkcode Moves | identifier} for the move being used + * @param count {@linkcode NumberHolder} holding the move's hit count for this turn + * @param damageMultiplier {@linkcode NumberHolder} holding a damage multiplier applied to a strike of this move * @returns always `true` */ - override apply(_pokemon: Pokemon, count: NumberHolder, power: NumberHolder): boolean { - count.value *= (this.getStackCount() + 1); - - switch (this.getStackCount()) { - case 1: - power.value *= 0.4; - break; - case 2: - power.value *= 0.25; - break; - case 3: - power.value *= 0.175; - break; + override apply(pokemon: Pokemon, moveId: Moves, count: NumberHolder | null = null, damageMultiplier: NumberHolder | null = null): boolean { + const move = allMoves[moveId]; + /** + * The move must meet Parental Bond's restrictions for this item + * to apply. This means + * - Only attacks are boosted + * - Multi-strike moves, charge moves, and self-sacrificial moves are not boosted + * (though Multi-Lens can still affect moves boosted by Parental Bond) + * - Multi-target moves are not boosted *unless* they can only hit a single Pokemon + * - Fling, Uproar, Rollout, Ice Ball, and Endeavor are not boosted + */ + if (!move.canBeMultiStrikeEnhanced(pokemon)) { + return false; } + if (!isNullOrUndefined(count)) { + return this.applyHitCountBoost(count); + } else if (!isNullOrUndefined(damageMultiplier)) { + return this.applyPowerModifier(pokemon, damageMultiplier); + } + + return false; + } + + /** Adds strikes to a move equal to the number of stacked Multi-Lenses */ + private applyHitCountBoost(count: NumberHolder): boolean { + count.value += this.getStackCount(); + return true; + } + + /** + * If applied to the first hit of a move, sets the damage multiplier + * equal to (1 - the number of stacked Multi-Lenses). + * Additional strikes beyond that are given a 0.25x damage multiplier + */ + private applyPowerModifier(pokemon: Pokemon, damageMultiplier: NumberHolder): boolean { + damageMultiplier.value = (pokemon.turnData.hitsLeft === pokemon.turnData.hitCount) + ? (1 - (0.25 * this.getStackCount())) + : 0.25; return true; } getMaxHeldItemCount(pokemon: Pokemon): number { - return 3; + return 2; } } diff --git a/src/phases/move-effect-phase.ts b/src/phases/move-effect-phase.ts index ef863d64c50..24a0b51da96 100644 --- a/src/phases/move-effect-phase.ts +++ b/src/phases/move-effect-phase.ts @@ -26,7 +26,6 @@ import { applyMoveAttrs, AttackMove, DelayedAttackAttr, - FixedDamageAttr, HitsTagAttr, MissEffectAttr, MoveAttr, @@ -122,12 +121,10 @@ export class MoveEffectPhase extends PokemonPhase { const hitCount = new NumberHolder(1); // Assume single target for multi hit applyMoveAttrs(MultiHitAttr, user, this.getFirstTarget() ?? null, move, hitCount); - // If Parental Bond is applicable, double the hit count - applyPreAttackAbAttrs(AddSecondStrikeAbAttr, user, null, move, false, targets.length, hitCount, new NumberHolder(0)); - // If Multi-Lens is applicable, multiply the hit count by 1 + the number of Multi-Lenses held by the user - if (move instanceof AttackMove && !move.hasAttr(FixedDamageAttr)) { - this.scene.applyModifiers(PokemonMultiHitModifier, user.isPlayer(), user, hitCount, new NumberHolder(0)); - } + // If Parental Bond is applicable, add another hit + applyPreAttackAbAttrs(AddSecondStrikeAbAttr, user, null, move, false, hitCount, null); + // If Multi-Lens is applicable, add hits equal to the number of held Multi-Lenses + this.scene.applyModifiers(PokemonMultiHitModifier, user.isPlayer(), user, move.id, hitCount); // Set the user's relevant turnData fields to reflect the final hit count user.turnData.hitCount = hitCount.value; user.turnData.hitsLeft = hitCount.value; diff --git a/src/test/abilities/parental_bond.test.ts b/src/test/abilities/parental_bond.test.ts index d8f952ae6ad..4189941a51e 100644 --- a/src/test/abilities/parental_bond.test.ts +++ b/src/test/abilities/parental_bond.test.ts @@ -274,7 +274,7 @@ describe("Abilities - Parental Bond", () => { ); it( - "Moves boosted by this ability and Multi-Lens should strike 4 times", + "Moves boosted by this ability and Multi-Lens should strike 3 times", async () => { game.override.moveset([ Moves.TACKLE ]); game.override.startingHeldItems([{ name: "MULTI_LENS", count: 1 }]); @@ -287,36 +287,12 @@ describe("Abilities - Parental Bond", () => { await game.phaseInterceptor.to("DamagePhase"); - expect(leadPokemon.turnData.hitCount).toBe(4); + expect(leadPokemon.turnData.hitCount).toBe(3); } ); it( - "Super Fang boosted by this ability and Multi-Lens should strike twice", - async () => { - game.override.moveset([ Moves.SUPER_FANG ]); - game.override.startingHeldItems([{ name: "MULTI_LENS", count: 1 }]); - - await game.classicMode.startBattle([ Species.MAGIKARP ]); - - const leadPokemon = game.scene.getPlayerPokemon()!; - const enemyPokemon = game.scene.getEnemyPokemon()!; - - game.move.select(Moves.SUPER_FANG); - await game.move.forceHit(); - - await game.phaseInterceptor.to("DamagePhase"); - - expect(leadPokemon.turnData.hitCount).toBe(2); - - await game.phaseInterceptor.to("MoveEndPhase", false); - - expect(enemyPokemon.hp).toBe(Math.ceil(enemyPokemon.getMaxHp() * 0.25)); - } - ); - - it( - "Seismic Toss boosted by this ability and Multi-Lens should strike twice", + "Seismic Toss boosted by this ability and Multi-Lens should strike 3 times", async () => { game.override.moveset([ Moves.SEISMIC_TOSS ]); game.override.startingHeldItems([{ name: "MULTI_LENS", count: 1 }]); @@ -333,11 +309,11 @@ describe("Abilities - Parental Bond", () => { await game.phaseInterceptor.to("DamagePhase"); - expect(leadPokemon.turnData.hitCount).toBe(2); + expect(leadPokemon.turnData.hitCount).toBe(3); await game.phaseInterceptor.to("MoveEndPhase", false); - expect(enemyPokemon.hp).toBe(enemyStartingHp - 200); + expect(enemyPokemon.hp).toBe(enemyStartingHp - 300); } ); @@ -494,30 +470,4 @@ describe("Abilities - Parental Bond", () => { expect(enemyPokemon.getStatStage(Stat.SPATK)).toBe(1); } ); - - it( - "should not apply to multi-target moves with Multi-Lens", - async () => { - game.override.battleType("double"); - game.override.moveset([ Moves.EARTHQUAKE, Moves.SPLASH ]); - game.override.passiveAbility(Abilities.LEVITATE); - game.override.startingHeldItems([{ name: "MULTI_LENS", count: 1 }]); - - await game.classicMode.startBattle([ Species.MAGIKARP, Species.FEEBAS ]); - - const enemyPokemon = game.scene.getEnemyField(); - - const enemyStartingHp = enemyPokemon.map(p => p.hp); - - game.move.select(Moves.EARTHQUAKE); - game.move.select(Moves.SPLASH, 1); - - await game.phaseInterceptor.to("DamagePhase"); - const enemyFirstHitDamage = enemyStartingHp.map((hp, i) => hp - enemyPokemon[i].hp); - - await game.phaseInterceptor.to("BerryPhase", false); - - enemyPokemon.forEach((p, i) => expect(enemyStartingHp[i] - p.hp).toBe(2 * enemyFirstHitDamage[i])); - } - ); }); diff --git a/src/test/items/multi_lens.test.ts b/src/test/items/multi_lens.test.ts new file mode 100644 index 00000000000..e4e4ab9863e --- /dev/null +++ b/src/test/items/multi_lens.test.ts @@ -0,0 +1,98 @@ +import { BattlerIndex } from "#app/battle"; +import { Stat } from "#enums/stat"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; + +describe("Items - Multi Lens", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([ Moves.TACKLE, Moves.TRAILBLAZE, Moves.TACHYON_CUTTER ]) + .ability(Abilities.BALL_FETCH) + .startingHeldItems([{ name: "MULTI_LENS" }]) + .battleType("single") + .disableCrits() + .enemySpecies(Species.SNORLAX) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH) + .startingLevel(100) + .enemyLevel(100); + }); + + it.each([ + { stackCount: 1, firstHitDamage: 0.75 }, + { stackCount: 2, firstHitDamage: 0.50 } + ])("$stackCount count: should deal {$firstHitDamage}x damage on the first hit, then hit $stackCount times for 0.25x", + async ({ stackCount, firstHitDamage }) => { + game.override.startingHeldItems([{ name: "MULTI_LENS", count: stackCount }]); + + await game.classicMode.startBattle([ Species.MAGIKARP ]); + + const enemyPokemon = game.scene.getEnemyPokemon()!; + const spy = vi.spyOn(enemyPokemon, "getAttackDamage"); + vi.spyOn(enemyPokemon, "getBaseDamage").mockReturnValue(100); + + game.move.select(Moves.TACKLE); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + + await game.phaseInterceptor.to("MoveEndPhase"); + const damageResults = spy.mock.results.map(result => result.value?.damage); + + expect(damageResults).toHaveLength(1 + stackCount); + expect(damageResults[0]).toBe(firstHitDamage * 100); + damageResults.slice(1).forEach(dmg => expect(dmg).toBe(25)); + }); + + it("should stack additively with Parental Bond", async () => { + game.override.ability(Abilities.PARENTAL_BOND); + + await game.classicMode.startBattle([ Species.MAGIKARP ]); + + const playerPokemon = game.scene.getPlayerPokemon()!; + + game.move.select(Moves.TACKLE); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + + await game.phaseInterceptor.to("MoveEndPhase"); + expect(playerPokemon.turnData.hitCount).toBe(3); + }); + + it("should apply secondary effects on each hit", async () => { + await game.classicMode.startBattle([ Species.MAGIKARP ]); + + const playerPokemon = game.scene.getPlayerPokemon()!; + + game.move.select(Moves.TRAILBLAZE); + + await game.phaseInterceptor.to("BerryPhase", false); + expect(playerPokemon.getStatStage(Stat.SPD)).toBe(2); + }); + + it("should not enhance multi-hit moves", async () => { + await game.classicMode.startBattle([ Species.MAGIKARP ]); + + const playerPokemon = game.scene.getPlayerPokemon()!; + + game.move.select(Moves.TACHYON_CUTTER); + + await game.phaseInterceptor.to("BerryPhase", false); + expect(playerPokemon.turnData.hitCount).toBe(2); + }); +}); diff --git a/src/test/moves/beat_up.test.ts b/src/test/moves/beat_up.test.ts index a0129621f0e..41e5b63471f 100644 --- a/src/test/moves/beat_up.test.ts +++ b/src/test/moves/beat_up.test.ts @@ -74,29 +74,4 @@ describe("Moves - Beat Up", () => { expect(playerPokemon.turnData.hitCount).toBe(5); } ); - - it( - "should hit twice for each player Pokemon if the user has Multi-Lens", - async () => { - game.override.startingHeldItems([{ name: "MULTI_LENS", count: 1 }]); - await game.startBattle([ Species.MAGIKARP, Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE, Species.PIKACHU, Species.EEVEE ]); - - const playerPokemon = game.scene.getPlayerPokemon()!; - const enemyPokemon = game.scene.getEnemyPokemon()!; - let enemyStartingHp = enemyPokemon.hp; - - game.move.select(Moves.BEAT_UP); - - await game.phaseInterceptor.to(MoveEffectPhase); - - expect(playerPokemon.turnData.hitCount).toBe(12); - expect(enemyPokemon.hp).toBeLessThan(enemyStartingHp); - - while (playerPokemon.turnData.hitsLeft > 0) { - enemyStartingHp = enemyPokemon.hp; - await game.phaseInterceptor.to(MoveEffectPhase); - expect(enemyPokemon.hp).toBeLessThan(enemyStartingHp); - } - } - ); }); diff --git a/src/test/moves/ceaseless_edge.test.ts b/src/test/moves/ceaseless_edge.test.ts index 88c8c8cf011..3fbbb7b0aaf 100644 --- a/src/test/moves/ceaseless_edge.test.ts +++ b/src/test/moves/ceaseless_edge.test.ts @@ -34,7 +34,7 @@ describe("Moves - Ceaseless Edge", () => { game.override.startingLevel(100); game.override.enemyLevel(100); game.override.moveset([ Moves.CEASELESS_EDGE, Moves.SPLASH, Moves.ROAR ]); - game.override.enemyMoveset([ Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH ]); + game.override.enemyMoveset(Moves.SPLASH); vi.spyOn(allMoves[Moves.CEASELESS_EDGE], "accuracy", "get").mockReturnValue(100); }); @@ -42,7 +42,7 @@ describe("Moves - Ceaseless Edge", () => { test( "move should hit and apply spikes", async () => { - await game.startBattle([ Species.ILLUMISE ]); + await game.classicMode.startBattle([ Species.ILLUMISE ]); const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -67,7 +67,7 @@ describe("Moves - Ceaseless Edge", () => { "move should hit twice with multi lens and apply two layers of spikes", async () => { game.override.startingHeldItems([{ name: "MULTI_LENS" }]); - await game.startBattle([ Species.ILLUMISE ]); + await game.classicMode.startBattle([ Species.ILLUMISE ]); const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -92,9 +92,9 @@ describe("Moves - Ceaseless Edge", () => { "trainer - move should hit twice, apply two layers of spikes, force switch opponent - opponent takes damage", async () => { game.override.startingHeldItems([{ name: "MULTI_LENS" }]); - game.override.startingWave(5); + game.override.startingWave(25); - await game.startBattle([ Species.ILLUMISE ]); + await game.classicMode.startBattle([ Species.ILLUMISE ]); game.move.select(Moves.CEASELESS_EDGE); await game.phaseInterceptor.to(MoveEffectPhase, false); @@ -102,7 +102,7 @@ describe("Moves - Ceaseless Edge", () => { const tagBefore = game.scene.arena.getTagOnSide(ArenaTagType.SPIKES, ArenaTagSide.ENEMY) as ArenaTrapTag; expect(tagBefore instanceof ArenaTrapTag).toBeFalsy(); - await game.phaseInterceptor.to(TurnEndPhase, false); + await game.toNextTurn(); const tagAfter = game.scene.arena.getTagOnSide(ArenaTagType.SPIKES, ArenaTagSide.ENEMY) as ArenaTrapTag; expect(tagAfter instanceof ArenaTrapTag).toBeTruthy(); expect(tagAfter.layers).toBe(2); diff --git a/src/test/moves/dragon_rage.test.ts b/src/test/moves/dragon_rage.test.ts index e8185f013e5..d5536ff9d2f 100644 --- a/src/test/moves/dragon_rage.test.ts +++ b/src/test/moves/dragon_rage.test.ts @@ -2,7 +2,6 @@ import { Stat } from "#enums/stat"; import { Type } from "#enums/type"; import { Species } from "#app/enums/species"; import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; -import { modifierTypes } from "#app/modifier/modifier-type"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { BattlerTagType } from "#enums/battler-tag-type"; @@ -114,14 +113,4 @@ describe("Moves - Dragon Rage", () => { expect(enemyPokemon.getInverseHp()).toBe(dragonRageDamage); }); - - it("ignores multi hit", async () => { - game.override.disableCrits(); - game.scene.addModifier(modifierTypes.MULTI_LENS().newModifier(partyPokemon), false); - - game.move.select(Moves.DRAGON_RAGE); - await game.phaseInterceptor.to(TurnEndPhase); - - expect(enemyPokemon.getInverseHp()).toBe(dragonRageDamage); - }); }); diff --git a/src/test/moves/electro_shot.test.ts b/src/test/moves/electro_shot.test.ts index 1373b4941eb..283154b3408 100644 --- a/src/test/moves/electro_shot.test.ts +++ b/src/test/moves/electro_shot.test.ts @@ -98,7 +98,7 @@ describe("Moves - Electro Shot", () => { game.move.select(Moves.ELECTRO_SHOT); await game.phaseInterceptor.to("MoveEndPhase"); - expect(playerPokemon.turnData.hitCount).toBe(2); + expect(playerPokemon.turnData.hitCount).toBe(1); expect(playerPokemon.getStatStage(Stat.SPATK)).toBe(1); }); }); From 4802f512ff7925037ecb90bf4d19505d1831d2a4 Mon Sep 17 00:00:00 2001 From: PigeonBar <56974298+PigeonBar@users.noreply.github.com> Date: Mon, 11 Nov 2024 18:22:27 -0500 Subject: [PATCH 41/75] [P1][Beta] Fix softlock when losing a run on local build (#4846) --- src/phases/game-over-phase.ts | 7 ++- src/test/phases/game-over-phase.test.ts | 77 +++++++++++++++++++++++++ src/test/utils/phaseInterceptor.ts | 24 +++++++- 3 files changed, 103 insertions(+), 5 deletions(-) create mode 100644 src/test/phases/game-over-phase.test.ts diff --git a/src/phases/game-over-phase.ts b/src/phases/game-over-phase.ts index 26a0c45f449..84a4a4e8ef9 100644 --- a/src/phases/game-over-phase.ts +++ b/src/phases/game-over-phase.ts @@ -125,10 +125,9 @@ export class GameOverPhase extends BattlePhase { } const clear = (endCardPhase?: EndCardPhase) => { - if (newClear) { - this.handleUnlocks(); - } if (this.isVictory && newClear) { + this.handleUnlocks(); + for (const species of this.firstRibbons) { this.scene.unshiftPhase(new RibbonModifierRewardPhase(this.scene, modifierTypes.VOUCHER_PLUS, species)); } @@ -183,6 +182,8 @@ export class GameOverPhase extends BattlePhase { this.scene.gameData.offlineNewClear(this.scene).then(result => { doGameOver(result); }); + } else { + doGameOver(false); } } diff --git a/src/test/phases/game-over-phase.test.ts b/src/test/phases/game-over-phase.test.ts new file mode 100644 index 00000000000..2e19d5fe954 --- /dev/null +++ b/src/test/phases/game-over-phase.test.ts @@ -0,0 +1,77 @@ +import { Biome } from "#enums/biome"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { achvs } from "#app/system/achv"; +import { Unlockables } from "#app/system/unlockables"; + +describe("Game Over Phase", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([ Moves.MEMENTO, Moves.ICE_BEAM, Moves.SPLASH ]) + .ability(Abilities.BALL_FETCH) + .battleType("single") + .disableCrits() + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH) + .startingWave(200) + .startingBiome(Biome.END) + .startingLevel(10000); + }); + + it("winning a run should give rewards", async () => { + await game.classicMode.startBattle([ Species.BULBASAUR ]); + vi.spyOn(game.scene, "validateAchv"); + + // Note: `game.doKillOpponents()` does not properly handle final boss + // Final boss phase 1 + game.move.select(Moves.ICE_BEAM); + await game.toNextTurn(); + + // Final boss phase 2 + game.move.select(Moves.ICE_BEAM); + await game.phaseInterceptor.to("PostGameOverPhase", false); + + // The game refused to actually give the vouchers during tests, + // so the best we can do is to check that their reward phases occurred. + expect(game.phaseInterceptor.log.includes("GameOverPhase")).toBe(true); + expect(game.phaseInterceptor.log.includes("UnlockPhase")).toBe(true); + expect(game.phaseInterceptor.log.includes("RibbonModifierRewardPhase")).toBe(true); + expect(game.scene.gameData.unlocks[Unlockables.ENDLESS_MODE]).toBe(true); + expect(game.scene.validateAchv).toHaveBeenCalledWith(achvs.CLASSIC_VICTORY); + expect(game.scene.gameData.achvUnlocks[achvs.CLASSIC_VICTORY.id]).toBeTruthy(); + }); + + it("losing a run should not give rewards", async () => { + await game.classicMode.startBattle([ Species.BULBASAUR ]); + vi.spyOn(game.scene, "validateAchv"); + + game.move.select(Moves.MEMENTO); + await game.phaseInterceptor.to("PostGameOverPhase", false); + + expect(game.phaseInterceptor.log.includes("GameOverPhase")).toBe(true); + expect(game.phaseInterceptor.log.includes("UnlockPhase")).toBe(false); + expect(game.phaseInterceptor.log.includes("RibbonModifierRewardPhase")).toBe(false); + expect(game.phaseInterceptor.log.includes("GameOverModifierRewardPhase")).toBe(false); + expect(game.scene.gameData.unlocks[Unlockables.ENDLESS_MODE]).toBe(false); + expect(game.scene.validateAchv).not.toHaveBeenCalledWith(achvs.CLASSIC_VICTORY); + expect(game.scene.gameData.achvUnlocks[achvs.CLASSIC_VICTORY.id]).toBeFalsy(); + }); +}); diff --git a/src/test/utils/phaseInterceptor.ts b/src/test/utils/phaseInterceptor.ts index 17b6c7a6c81..4029e5e168c 100644 --- a/src/test/utils/phaseInterceptor.ts +++ b/src/test/utils/phaseInterceptor.ts @@ -55,6 +55,11 @@ import { import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase"; import { PartyExpPhase } from "#app/phases/party-exp-phase"; import { ExpPhase } from "#app/phases/exp-phase"; +import { GameOverPhase } from "#app/phases/game-over-phase"; +import { RibbonModifierRewardPhase } from "#app/phases/ribbon-modifier-reward-phase"; +import { GameOverModifierRewardPhase } from "#app/phases/game-over-modifier-reward-phase"; +import { UnlockPhase } from "#app/phases/unlock-phase"; +import { PostGameOverPhase } from "#app/phases/post-game-over-phase"; export interface PromptHandler { phaseTarget?: string; @@ -113,10 +118,15 @@ type PhaseClass = | typeof MysteryEncounterBattlePhase | typeof MysteryEncounterRewardsPhase | typeof PostMysteryEncounterPhase + | typeof RibbonModifierRewardPhase + | typeof GameOverModifierRewardPhase | typeof ModifierRewardPhase | typeof PartyExpPhase | typeof ExpPhase - | typeof EncounterPhase; + | typeof EncounterPhase + | typeof GameOverPhase + | typeof UnlockPhase + | typeof PostGameOverPhase; type PhaseString = | "LoginPhase" @@ -167,10 +177,15 @@ type PhaseString = | "MysteryEncounterBattlePhase" | "MysteryEncounterRewardsPhase" | "PostMysteryEncounterPhase" + | "RibbonModifierRewardPhase" + | "GameOverModifierRewardPhase" | "ModifierRewardPhase" | "PartyExpPhase" | "ExpPhase" - | "EncounterPhase"; + | "EncounterPhase" + | "GameOverPhase" + | "UnlockPhase" + | "PostGameOverPhase"; type PhaseInterceptorPhase = PhaseClass | PhaseString; @@ -245,10 +260,15 @@ export default class PhaseInterceptor { [ MysteryEncounterBattlePhase, this.startPhase ], [ MysteryEncounterRewardsPhase, this.startPhase ], [ PostMysteryEncounterPhase, this.startPhase ], + [ RibbonModifierRewardPhase, this.startPhase ], + [ GameOverModifierRewardPhase, this.startPhase ], [ ModifierRewardPhase, this.startPhase ], [ PartyExpPhase, this.startPhase ], [ ExpPhase, this.startPhase ], [ EncounterPhase, this.startPhase ], + [ GameOverPhase, this.startPhase ], + [ UnlockPhase, this.startPhase ], + [ PostGameOverPhase, this.startPhase ], ]; private endBySetMode = [ From 8e26db944d27ee031de891ea834d0c32c426d7a8 Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Mon, 11 Nov 2024 21:13:37 -0800 Subject: [PATCH 42/75] [Balance][Beta] Revert Spread Move Restriction on Multi-Lens (#4851) * Multi-Lens now applies to spread moves * Fix Multi-Lens applying to both damage and power --- src/data/ability.ts | 2 +- src/data/move.ts | 9 +++++---- src/modifier/modifier.ts | 4 ++-- src/test/items/multi_lens.test.ts | 19 +++++++++++++++++++ 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index 4194be31405..d58c6c5c9b9 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -1367,7 +1367,7 @@ export class AddSecondStrikeAbAttr extends PreAttackAbAttr { const hitCount = args[0] as Utils.NumberHolder; const multiplier = args[1] as Utils.NumberHolder; - if (move.canBeMultiStrikeEnhanced(pokemon)) { + if (move.canBeMultiStrikeEnhanced(pokemon, true)) { this.showAbility = !!hitCount?.value; if (hitCount?.value) { hitCount.value += 1; diff --git a/src/data/move.ts b/src/data/move.ts index 0de9d9b53a2..98c679b923e 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -818,8 +818,6 @@ export default class Move implements Localizable { applyMoveAttrs(VariablePowerAttr, source, target, this, power); - source.scene.applyModifiers(PokemonMultiHitModifier, source.isPlayer(), source, this.id, null, power); - if (!this.hasAttr(TypelessAttr)) { source.scene.arena.applyTags(WeakenMoveTypeTag, simulated, this.type, power); source.scene.applyModifiers(AttackTypeBoosterModifier, source.isPlayer(), source, this.type, power); @@ -846,8 +844,11 @@ export default class Move implements Localizable { * by enhancing effects. * Currently used for {@link https://bulbapedia.bulbagarden.net/wiki/Parental_Bond_(Ability) | Parental Bond} * and {@linkcode PokemonMultiHitModifier | Multi-Lens}. + * @param user The {@linkcode Pokemon} using the move + * @param restrictSpread `true` if the enhancing effect + * should not affect multi-target moves (default `false`) */ - canBeMultiStrikeEnhanced(user: Pokemon): boolean { + canBeMultiStrikeEnhanced(user: Pokemon, restrictSpread: boolean = false): boolean { // Multi-strike enhancers... // ...cannot enhance moves that hit multiple targets @@ -870,7 +871,7 @@ export default class Move implements Localizable { Moves.ENDEAVOR ]; - return !isMultiTarget + return (!restrictSpread || !isMultiTarget) && !this.isChargingMove() && !exceptAttrs.some(attr => this.hasAttr(attr)) && !exceptMoves.some(id => this.id === id) diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 5e60d888072..7aa4b9308d1 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -2715,7 +2715,7 @@ export class PokemonMultiHitModifier extends PokemonHeldItemModifier { if (!isNullOrUndefined(count)) { return this.applyHitCountBoost(count); } else if (!isNullOrUndefined(damageMultiplier)) { - return this.applyPowerModifier(pokemon, damageMultiplier); + return this.applyDamageModifier(pokemon, damageMultiplier); } return false; @@ -2732,7 +2732,7 @@ export class PokemonMultiHitModifier extends PokemonHeldItemModifier { * equal to (1 - the number of stacked Multi-Lenses). * Additional strikes beyond that are given a 0.25x damage multiplier */ - private applyPowerModifier(pokemon: Pokemon, damageMultiplier: NumberHolder): boolean { + private applyDamageModifier(pokemon: Pokemon, damageMultiplier: NumberHolder): boolean { damageMultiplier.value = (pokemon.turnData.hitsLeft === pokemon.turnData.hitCount) ? (1 - (0.25 * this.getStackCount())) : 0.25; diff --git a/src/test/items/multi_lens.test.ts b/src/test/items/multi_lens.test.ts index e4e4ab9863e..d389ca70555 100644 --- a/src/test/items/multi_lens.test.ts +++ b/src/test/items/multi_lens.test.ts @@ -95,4 +95,23 @@ describe("Items - Multi Lens", () => { await game.phaseInterceptor.to("BerryPhase", false); expect(playerPokemon.turnData.hitCount).toBe(2); }); + + it("should enhance multi-target moves", async () => { + game.override + .battleType("double") + .moveset([ Moves.SWIFT, Moves.SPLASH ]); + + await game.classicMode.startBattle([ Species.MAGIKARP, Species.FEEBAS ]); + + const [ magikarp, ] = game.scene.getPlayerField(); + + game.move.select(Moves.SWIFT, 0); + game.move.select(Moves.SPLASH, 1); + + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]); + + await game.phaseInterceptor.to("MoveEndPhase"); + + expect(magikarp.turnData.hitCount).toBe(2); + }); }); From 6f3fd0f138c554a21ea3f37a02e4457ae9219815 Mon Sep 17 00:00:00 2001 From: PigeonBar <56974298+PigeonBar@users.noreply.github.com> Date: Tue, 12 Nov 2024 06:29:37 -0500 Subject: [PATCH 43/75] [Beta][P3] Fix failed charge moves not displaying failed text (#4853) --- src/data/move.ts | 4 ++-- src/phases/move-phase.ts | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index 98c679b923e..089bb51bf5e 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -668,12 +668,12 @@ export default class Move implements Localizable { } /** - * Sees if, given the target pokemon, a move fails on it (by looking at each {@linkcode MoveAttr} of this move + * Sees if a move has a custom failure text (by looking at each {@linkcode MoveAttr} of this move) * @param user {@linkcode Pokemon} using the move * @param target {@linkcode Pokemon} receiving the move * @param move {@linkcode Move} using the move * @param cancelled {@linkcode Utils.BooleanHolder} to hold boolean value - * @returns string of the failed text, or null + * @returns string of the custom failure text, or `null` if it uses the default text ("But it failed!") */ getFailedText(user: Pokemon, target: Pokemon, move: Move, cancelled: Utils.BooleanHolder): string | null { for (const attr of this.attrs) { diff --git a/src/phases/move-phase.ts b/src/phases/move-phase.ts index 378b72e1f56..005cdbe1716 100644 --- a/src/phases/move-phase.ts +++ b/src/phases/move-phase.ts @@ -378,10 +378,8 @@ export class MovePhase extends BattlePhase { this.pokemon.pushMoveHistory({ move: this.move.moveId, targets: this.targets, result: MoveResult.FAIL, virtual: this.move.virtual }); const failureMessage = move.getFailedText(this.pokemon, targets[0], move, new BooleanHolder(false)); - if (failureMessage) { - this.showMoveText(); - this.showFailedText(failureMessage); - } + this.showMoveText(); + this.showFailedText(failureMessage ?? undefined); // Remove the user from its semi-invulnerable state (if applicable) this.pokemon.lapseTags(BattlerTagLapseType.MOVE_EFFECT); From b6b756a1620c488557e9c6bf5e2b0990242e138e Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Tue, 12 Nov 2024 03:44:28 -0800 Subject: [PATCH 44/75] [P2] Fix issue with Pokemon not evolving until the next floor and clean up `LevelUpPhase` (#4854) --- src/phases/level-up-phase.ts | 47 +++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/phases/level-up-phase.ts b/src/phases/level-up-phase.ts index a2fa8a16533..4f26abc5af3 100644 --- a/src/phases/level-up-phase.ts +++ b/src/phases/level-up-phase.ts @@ -1,59 +1,66 @@ -import BattleScene from "#app/battle-scene"; +import type BattleScene from "#app/battle-scene"; import { ExpNotification } from "#app/enums/exp-notification"; -import { EvolutionPhase } from "#app/phases/evolution-phase"; -import { PlayerPokemon } from "#app/field/pokemon"; +import type { PlayerPokemon } from "#app/field/pokemon"; import { getPokemonNameWithAffix } from "#app/messages"; +import { EvolutionPhase } from "#app/phases/evolution-phase"; +import { LearnMovePhase } from "#app/phases/learn-move-phase"; +import { PlayerPartyMemberPokemonPhase } from "#app/phases/player-party-member-pokemon-phase"; import { LevelAchv } from "#app/system/achv"; +import { NumberHolder } from "#app/utils"; import i18next from "i18next"; -import * as Utils from "#app/utils"; -import { PlayerPartyMemberPokemonPhase } from "./player-party-member-pokemon-phase"; -import { LearnMovePhase } from "./learn-move-phase"; export class LevelUpPhase extends PlayerPartyMemberPokemonPhase { - private lastLevel: integer; - private level: integer; + protected lastLevel: number; + protected level: number; + protected pokemon: PlayerPokemon = this.getPlayerPokemon(); - constructor(scene: BattleScene, partyMemberIndex: integer, lastLevel: integer, level: integer) { + constructor(scene: BattleScene, partyMemberIndex: number, lastLevel: number, level: number) { super(scene, partyMemberIndex); this.lastLevel = lastLevel; this.level = level; - this.scene = scene; } - start() { + public override start() { super.start(); if (this.level > this.scene.gameData.gameStats.highestLevel) { this.scene.gameData.gameStats.highestLevel = this.level; } - this.scene.validateAchvs(LevelAchv, new Utils.NumberHolder(this.level)); + this.scene.validateAchvs(LevelAchv, new NumberHolder(this.level)); - const pokemon = this.getPokemon(); - const prevStats = pokemon.stats.slice(0); - pokemon.calculateStats(); - pokemon.updateInfo(); + const prevStats = this.pokemon.stats.slice(0); + this.pokemon.calculateStats(); + this.pokemon.updateInfo(); if (this.scene.expParty === ExpNotification.DEFAULT) { this.scene.playSound("level_up_fanfare"); - this.scene.ui.showText(i18next.t("battle:levelUp", { pokemonName: getPokemonNameWithAffix(this.getPokemon()), level: this.level }), null, () => this.scene.ui.getMessageHandler().promptLevelUpStats(this.partyMemberIndex, prevStats, false).then(() => this.end()), null, true); + this.scene.ui.showText( + i18next.t("battle:levelUp", { pokemonName: getPokemonNameWithAffix(this.pokemon), level: this.level }), + null, + () => this.scene.ui.getMessageHandler().promptLevelUpStats(this.partyMemberIndex, prevStats, false) + .then(() => this.end()), null, true); } else if (this.scene.expParty === ExpNotification.SKIP) { this.end(); } else { // we still want to display the stats if activated this.scene.ui.getMessageHandler().promptLevelUpStats(this.partyMemberIndex, prevStats, false).then(() => this.end()); } + } + + public override end() { if (this.lastLevel < 100) { // this feels like an unnecessary optimization const levelMoves = this.getPokemon().getLevelMoves(this.lastLevel + 1); for (const lm of levelMoves) { this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, lm[1])); } } - if (!pokemon.pauseEvolutions) { - const evolution = pokemon.getEvolution(); + if (!this.pokemon.pauseEvolutions) { + const evolution = this.pokemon.getEvolution(); if (evolution) { - this.scene.unshiftPhase(new EvolutionPhase(this.scene, pokemon as PlayerPokemon, evolution, this.lastLevel)); + this.scene.unshiftPhase(new EvolutionPhase(this.scene, this.pokemon, evolution, this.lastLevel)); } } + return super.end(); } } From e45cb42f7ee86899e45d9aa40aa390b65251dd76 Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Tue, 12 Nov 2024 18:42:47 -0800 Subject: [PATCH 45/75] [Balance] Disable King's Rock for moves that can already flinch (#4860) --- src/phases/move-effect-phase.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/phases/move-effect-phase.ts b/src/phases/move-effect-phase.ts index 24a0b51da96..afc8dd0475d 100644 --- a/src/phases/move-effect-phase.ts +++ b/src/phases/move-effect-phase.ts @@ -26,6 +26,7 @@ import { applyMoveAttrs, AttackMove, DelayedAttackAttr, + FlinchAttr, HitsTagAttr, MissEffectAttr, MoveAttr, @@ -502,6 +503,10 @@ export class MoveEffectPhase extends PokemonPhase { */ protected applyHeldItemFlinchCheck(user: Pokemon, target: Pokemon, dealsDamage: boolean) : () => void { return () => { + if (this.move.getMove().hasAttr(FlinchAttr)) { + return; + } + if (dealsDamage && !target.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && !this.move.getMove().hitsSubstitute(user, target)) { const flinched = new BooleanHolder(false); user.scene.applyModifiers(FlinchChanceModifier, user.isPlayer(), user, flinched); From 162eea500dcfaa5e39b06481339a60ebfb2d0c78 Mon Sep 17 00:00:00 2001 From: muscode Date: Wed, 13 Nov 2024 00:28:22 -0600 Subject: [PATCH 46/75] Fixed wild form changes messages, and form-changed Cramorant crashing the game when both sides faint at the same time (#4859) --- src/phases/quiet-form-change-phase.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/phases/quiet-form-change-phase.ts b/src/phases/quiet-form-change-phase.ts index c28cc28b592..6c84c0d1a8a 100644 --- a/src/phases/quiet-form-change-phase.ts +++ b/src/phases/quiet-form-change-phase.ts @@ -29,10 +29,14 @@ export class QuietFormChangePhase extends BattlePhase { const preName = getPokemonNameWithAffix(this.pokemon); - if (!this.pokemon.isOnField() || this.pokemon.getTag(SemiInvulnerableTag)) { - this.pokemon.changeForm(this.formChange).then(() => { - this.scene.ui.showText(getSpeciesFormChangeMessage(this.pokemon, this.formChange, preName), null, () => this.end(), 1500); - }); + if (!this.pokemon.isOnField() || this.pokemon.getTag(SemiInvulnerableTag) || this.pokemon.isFainted()) { + if (this.pokemon.isPlayer() || this.pokemon.isActive()) { + this.pokemon.changeForm(this.formChange).then(() => { + this.scene.ui.showText(getSpeciesFormChangeMessage(this.pokemon, this.formChange, preName), null, () => this.end(), 1500); + }); + } else { + this.end(); + } return; } From 0c521bbe0828746ace0dd7310340fb6340bee6e5 Mon Sep 17 00:00:00 2001 From: geeilhan <107366005+geeilhan@users.noreply.github.com> Date: Wed, 13 Nov 2024 16:41:39 +0100 Subject: [PATCH 47/75] [Move] Implement Freeze Dry type-changed interactions (#4840) * Full implementation of freeze-dry including edge cases such as Normalize and Electrify plus tests * Update comments * renamed WaterSuperEffectTypeMultiplierAttr to FreezeDryAttr * Added test case for freeze dry during inverse battles * cleaned up code making it more general * Added some more documentation * implementing reviewed changes * used getMoveType() instead of move.type * added additional test cases to freeze dry * Revert "used getMoveType() instead of move.type" This reverts commit 03445dfab4db52b0dddbe7abf7d4b4dfa8b9c583. * added reviewed changes without changing public/locales --------- Co-authored-by: ga27lok --- src/data/move.ts | 40 ++++++-- src/test/moves/freeze_dry.test.ts | 163 +++++++++++++++++++++++++++++- 2 files changed, 192 insertions(+), 11 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index 089bb51bf5e..74ac61af884 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -4971,16 +4971,42 @@ export class NeutralDamageAgainstFlyingTypeMultiplierAttr extends VariableMoveTy } } -export class WaterSuperEffectTypeMultiplierAttr extends VariableMoveTypeMultiplierAttr { +/** + * This class forces Freeze-Dry to be super effective against Water Type. + * It considers if target is Mono or Dual Type and calculates the new Multiplier accordingly. + * @see {@linkcode apply} + */ +export class FreezeDryAttr extends VariableMoveTypeMultiplierAttr { + /** + * If the target is Mono Type (Water only) then a 2x Multiplier is always forced. + * If target is Dual Type (containing Water) then only a 2x Multiplier is forced for the Water Type. + * + * Additionally Freeze-Dry's effectiveness against water is always forced during {@linkcode InverseBattleChallenge}. + * The multiplier is recalculated for the non-Water Type in case of Dual Type targets containing Water Type. + * + * @param user The {@linkcode Pokemon} applying the move + * @param target The {@linkcode Pokemon} targeted by the move + * @param move The move used by the user + * @param args `[0]` a {@linkcode Utils.NumberHolder | NumberHolder} containing a type effectiveness multiplier + * @returns `true` if super effectiveness on water type is forced; `false` otherwise + */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const multiplier = args[0] as Utils.NumberHolder; - if (target.isOfType(Type.WATER)) { - const effectivenessAgainstWater = new Utils.NumberHolder(getTypeDamageMultiplier(move.type, Type.WATER)); - applyChallenges(user.scene.gameMode, ChallengeType.TYPE_EFFECTIVENESS, effectivenessAgainstWater); - if (effectivenessAgainstWater.value !== 0) { - multiplier.value *= 2 / effectivenessAgainstWater.value; + if (target.isOfType(Type.WATER) && multiplier.value !== 0) { + const multipleTypes = (target.getTypes().length > 1); + + if (multipleTypes) { + const nonWaterType = target.getTypes().filter(type => type !== Type.WATER)[0]; + const effectivenessAgainstTarget = new Utils.NumberHolder(getTypeDamageMultiplier(user.getMoveType(move), nonWaterType)); + + applyChallenges(user.scene.gameMode, ChallengeType.TYPE_EFFECTIVENESS, effectivenessAgainstTarget); + + multiplier.value = effectivenessAgainstTarget.value * 2; return true; } + + multiplier.value = 2; + return true; } return false; @@ -9422,7 +9448,7 @@ export function initMoves() { .target(MoveTarget.ALL_NEAR_OTHERS), new AttackMove(Moves.FREEZE_DRY, Type.ICE, MoveCategory.SPECIAL, 70, 100, 20, 10, 0, 6) .attr(StatusEffectAttr, StatusEffect.FREEZE) - .attr(WaterSuperEffectTypeMultiplierAttr) + .attr(FreezeDryAttr) .edgeCase(), // This currently just multiplies the move's power instead of changing its effectiveness. It also doesn't account for abilities that modify type effectiveness such as tera shell. new AttackMove(Moves.DISARMING_VOICE, Type.FAIRY, MoveCategory.SPECIAL, 40, -1, 15, -1, 0, 6) .soundBased() diff --git a/src/test/moves/freeze_dry.test.ts b/src/test/moves/freeze_dry.test.ts index f766ed41a82..8bc6717f435 100644 --- a/src/test/moves/freeze_dry.test.ts +++ b/src/test/moves/freeze_dry.test.ts @@ -2,6 +2,7 @@ import { BattlerIndex } from "#app/battle"; import { Abilities } from "#app/enums/abilities"; import { Moves } from "#app/enums/moves"; import { Species } from "#app/enums/species"; +import { Challenges } from "#enums/challenges"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; @@ -97,8 +98,7 @@ describe("Moves - Freeze-Dry", () => { expect(enemy.hp).toBeLessThan(enemy.getMaxHp()); }); - // enable if this is ever fixed (lol) - it.todo("should deal 2x damage to water types under Normalize", async () => { + it("should deal 2x damage to water type under Normalize", async () => { game.override.ability(Abilities.NORMALIZE); await game.classicMode.startBattle(); @@ -112,8 +112,39 @@ describe("Moves - Freeze-Dry", () => { expect(enemy.getMoveEffectiveness).toHaveReturnedWith(2); }); - // enable once Electrify is implemented (and the interaction is fixed, as above) - it.todo("should deal 2x damage to water types under Electrify", async () => { + it("should deal 0.25x damage to rock/steel type under Normalize", async () => { + game.override + .ability(Abilities.NORMALIZE) + .enemySpecies(Species.SHIELDON); + await game.classicMode.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + vi.spyOn(enemy, "getMoveEffectiveness"); + + game.move.select(Moves.FREEZE_DRY); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await game.phaseInterceptor.to("MoveEffectPhase"); + + expect(enemy.getMoveEffectiveness).toHaveReturnedWith(0.25); + }); + + it("should deal 0x damage to water/ghost type under Normalize", async () => { + game.override + .ability(Abilities.NORMALIZE) + .enemySpecies(Species.JELLICENT); + await game.classicMode.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + vi.spyOn(enemy, "getMoveEffectiveness"); + + game.move.select(Moves.FREEZE_DRY); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemy.getMoveEffectiveness).toHaveReturnedWith(0); + }); + + it("should deal 2x damage to water type under Electrify", async () => { game.override.enemyMoveset([ Moves.ELECTRIFY ]); await game.classicMode.startBattle(); @@ -126,4 +157,128 @@ describe("Moves - Freeze-Dry", () => { expect(enemy.getMoveEffectiveness).toHaveReturnedWith(2); }); + + it("should deal 4x damage to water/flying type under Electrify", async () => { + game.override + .enemyMoveset([ Moves.ELECTRIFY ]) + .enemySpecies(Species.GYARADOS); + await game.classicMode.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + vi.spyOn(enemy, "getMoveEffectiveness"); + + game.move.select(Moves.FREEZE_DRY); + await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemy.getMoveEffectiveness).toHaveReturnedWith(4); + }); + + it("should deal 0x damage to water/ground type under Electrify", async () => { + game.override + .enemyMoveset([ Moves.ELECTRIFY ]) + .enemySpecies(Species.BARBOACH); + await game.classicMode.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + vi.spyOn(enemy, "getMoveEffectiveness"); + + game.move.select(Moves.FREEZE_DRY); + await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemy.getMoveEffectiveness).toHaveReturnedWith(0); + }); + + it("should deal 0.25x damage to Grass/Dragon type under Electrify", async () => { + game.override + .enemyMoveset([ Moves.ELECTRIFY ]) + .enemySpecies(Species.FLAPPLE); + await game.classicMode.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + vi.spyOn(enemy, "getMoveEffectiveness"); + + game.move.select(Moves.FREEZE_DRY); + await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemy.getMoveEffectiveness).toHaveReturnedWith(0.25); + }); + + it("should deal 2x damage to Water type during inverse battle", async () => { + game.override + .moveset([ Moves.FREEZE_DRY ]) + .enemySpecies(Species.MAGIKARP); + game.challengeMode.addChallenge(Challenges.INVERSE_BATTLE, 1, 1); + + + await game.challengeMode.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + vi.spyOn(enemy, "getMoveEffectiveness"); + + game.move.select(Moves.FREEZE_DRY); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await game.phaseInterceptor.to("MoveEffectPhase"); + + expect(enemy.getMoveEffectiveness).toHaveLastReturnedWith(2); + }); + + it("should deal 2x damage to Water type during inverse battle under Normalize", async () => { + game.override + .moveset([ Moves.FREEZE_DRY ]) + .ability(Abilities.NORMALIZE) + .enemySpecies(Species.MAGIKARP); + game.challengeMode.addChallenge(Challenges.INVERSE_BATTLE, 1, 1); + + await game.challengeMode.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + vi.spyOn(enemy, "getMoveEffectiveness"); + + game.move.select(Moves.FREEZE_DRY); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await game.phaseInterceptor.to("MoveEffectPhase"); + + expect(enemy.getMoveEffectiveness).toHaveLastReturnedWith(2); + }); + + it("should deal 2x damage to Water type during inverse battle under Electrify", async () => { + game.override + .moveset([ Moves.FREEZE_DRY ]) + .enemySpecies(Species.MAGIKARP) + .enemyMoveset([ Moves.ELECTRIFY ]); + game.challengeMode.addChallenge(Challenges.INVERSE_BATTLE, 1, 1); + + await game.challengeMode.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + vi.spyOn(enemy, "getMoveEffectiveness"); + + game.move.select(Moves.FREEZE_DRY); + await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]); + await game.phaseInterceptor.to("MoveEffectPhase"); + + expect(enemy.getMoveEffectiveness).toHaveLastReturnedWith(2); + }); + + it("should deal 1x damage to water/flying type during inverse battle under Electrify", async () => { + game.override + .enemyMoveset([ Moves.ELECTRIFY ]) + .enemySpecies(Species.GYARADOS); + + game.challengeMode.addChallenge(Challenges.INVERSE_BATTLE, 1, 1); + + await game.challengeMode.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + vi.spyOn(enemy, "getMoveEffectiveness"); + + game.move.select(Moves.FREEZE_DRY); + await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemy.getMoveEffectiveness).toHaveReturnedWith(1); + }); }); From d0d9eb78da7beadb980f32a6c466f521f9e600cf Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Thu, 14 Nov 2024 11:35:13 -0800 Subject: [PATCH 48/75] Set the IVs of default starters to 15. (#4861) Co-authored-by: frutescens --- src/data/challenge.ts | 2 +- src/system/game-data.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/challenge.ts b/src/data/challenge.ts index af6bbf5b00f..4301ea7b375 100644 --- a/src/data/challenge.ts +++ b/src/data/challenge.ts @@ -653,7 +653,7 @@ export class FreshStartChallenge extends Challenge { pokemon.shiny = false; // Not shiny pokemon.variant = 0; // Not shiny pokemon.formIndex = 0; // Froakie should be base form - pokemon.ivs = [ 10, 10, 10, 10, 10, 10 ]; // Default IVs of 10 for all stats + pokemon.ivs = [ 15, 15, 15, 15, 15, 15 ]; // Default IVs of 15 for all stats (Updated to 15 from 10 in 1.2.0) return true; } diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 8f179ddb677..a9726ac0713 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -1540,7 +1540,7 @@ export class GameData { entry.caughtAttr = defaultStarterAttr; entry.natureAttr = 1 << (defaultStarterNatures[ds] + 1); for (const i in entry.ivs) { - entry.ivs[i] = 10; + entry.ivs[i] = 15; } } From 640ac237412dd82863f7ef7e704e8406c2d3c3fe Mon Sep 17 00:00:00 2001 From: PigeonBar <56974298+PigeonBar@users.noreply.github.com> Date: Thu, 14 Nov 2024 14:40:01 -0500 Subject: [PATCH 49/75] [Dev] Add overrides for alternating between single and double battles (#4833) * [Dev] Add overrides for alternating between single and double battles * PR feedback * Add type `DoubleType` * Fixed Gastro Acid test using `game.override.battleType(null)` * Changed new type name to `SingleOrDoubleType` * `SingleOrDoubleType` is now `BattleStyle` * Update src/test/utils/helpers/overridesHelper.ts --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> Co-authored-by: Moka <54149968+MokaStitcher@users.noreply.github.com> --- src/battle-scene.ts | 34 ++++++++++++++---- src/overrides.ts | 15 +++++++- src/test/battle/double_battle.test.ts | 42 ++++++++++++++++++++++- src/test/moves/gastro_acid.test.ts | 2 +- src/test/utils/helpers/overridesHelper.ts | 9 ++--- 5 files changed, 89 insertions(+), 13 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index c30ab2e2912..e659b588208 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1233,12 +1233,34 @@ export default class BattleScene extends SceneBase { newDouble = !!double; } - if (Overrides.BATTLE_TYPE_OVERRIDE === "double") { - newDouble = true; - } - /* Override battles into single only if not fighting with trainers */ - if (newBattleType !== BattleType.TRAINER && Overrides.BATTLE_TYPE_OVERRIDE === "single") { - newDouble = false; + if (!isNullOrUndefined(Overrides.BATTLE_TYPE_OVERRIDE)) { + let doubleOverrideForWave: "single" | "double" | null = null; + + switch (Overrides.BATTLE_TYPE_OVERRIDE) { + case "double": + doubleOverrideForWave = "double"; + break; + case "single": + doubleOverrideForWave = "single"; + break; + case "even-doubles": + doubleOverrideForWave = (newWaveIndex % 2) ? "single" : "double"; + break; + case "odd-doubles": + doubleOverrideForWave = (newWaveIndex % 2) ? "double" : "single"; + break; + } + + if (doubleOverrideForWave === "double") { + newDouble = true; + } + /** + * Override battles into single only if not fighting with trainers. + * @see {@link https://github.com/pagefaultgames/pokerogue/issues/1948 | GitHub Issue #1948} + */ + if (newBattleType !== BattleType.TRAINER && doubleOverrideForWave === "single") { + newDouble = false; + } } const lastBattle = this.currentBattle; diff --git a/src/overrides.ts b/src/overrides.ts index d7a8ee18f15..7b73cd47b03 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -47,7 +47,18 @@ class DefaultOverrides { /** a specific seed (default: a random string of 24 characters) */ readonly SEED_OVERRIDE: string = ""; readonly WEATHER_OVERRIDE: WeatherType = WeatherType.NONE; - readonly BATTLE_TYPE_OVERRIDE: "double" | "single" | null = null; + /** + * If `null`, ignore this override. + * + * If `"single"`, set every non-trainer battle to be a single battle. + * + * If `"double"`, set every battle (including trainer battles) to be a double battle. + * + * If `"even-doubles"`, follow the `"double"` rule on even wave numbers, and follow the `"single"` rule on odd wave numbers. + * + * If `"odd-doubles"`, follow the `"double"` rule on odd wave numbers, and follow the `"single"` rule on even wave numbers. + */ + readonly BATTLE_TYPE_OVERRIDE: BattleStyle | null = null; readonly STARTING_WAVE_OVERRIDE: number = 0; readonly STARTING_BIOME_OVERRIDE: Biome = Biome.TOWN; readonly ARENA_TINT_OVERRIDE: TimeOfDay | null = null; @@ -229,3 +240,5 @@ export default { ...defaultOverrides, ...overrides } satisfies InstanceType; + +export type BattleStyle = "double" | "single" | "even-doubles" | "odd-doubles"; diff --git a/src/test/battle/double_battle.test.ts b/src/test/battle/double_battle.test.ts index 1fc24bfc027..b48f2a96a5b 100644 --- a/src/test/battle/double_battle.test.ts +++ b/src/test/battle/double_battle.test.ts @@ -1,4 +1,6 @@ import { Status } from "#app/data/status-effect"; +import { Abilities } from "#enums/abilities"; +import { GameModes, getGameMode } from "#app/game-mode"; import { BattleEndPhase } from "#app/phases/battle-end-phase"; import { TurnInitPhase } from "#app/phases/turn-init-phase"; import { Moves } from "#enums/moves"; @@ -6,9 +8,11 @@ import { Species } from "#enums/species"; import { StatusEffect } from "#enums/status-effect"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; describe("Double Battles", () => { + const DOUBLE_CHANCE = 8; // Normal chance of double battle is 1/8 + let phaserGame: Phaser.Game; let game: GameManager; @@ -56,4 +60,40 @@ describe("Double Battles", () => { await game.phaseInterceptor.to(TurnInitPhase); expect(game.scene.getPlayerField().filter(p => !p.isFainted())).toHaveLength(2); }, 20000); + + it("randomly chooses between single and double battles if there is no battle type override", async () => { + let rngSweepProgress = 0; // Will simulate RNG rolls by slowly increasing from 0 to 1 + let doubleCount = 0; + let singleCount = 0; + + vi.spyOn(Phaser.Math.RND, "realInRange").mockImplementation((min: number, max: number) => { + return rngSweepProgress * (max - min) + min; + }); + + game.override.enemyMoveset(Moves.SPLASH) + .moveset(Moves.SPLASH) + .enemyAbility(Abilities.BALL_FETCH) + .ability(Abilities.BALL_FETCH); + + // Play through endless, waves 1 to 9, counting number of double battles from waves 2 to 9 + await game.classicMode.startBattle([ Species.BULBASAUR ]); + game.scene.gameMode = getGameMode(GameModes.ENDLESS); + + for (let i = 0; i < DOUBLE_CHANCE; i++) { + rngSweepProgress = (i + 0.5) / DOUBLE_CHANCE; + + game.move.select(Moves.SPLASH); + await game.doKillOpponents(); + await game.toNextWave(); + + if (game.scene.getEnemyParty().length === 1) { + singleCount++; + } else if (game.scene.getEnemyParty().length === 2) { + doubleCount++; + } + } + + expect(doubleCount).toBe(1); + expect(singleCount).toBe(DOUBLE_CHANCE - 1); + }); }); diff --git a/src/test/moves/gastro_acid.test.ts b/src/test/moves/gastro_acid.test.ts index fdd75b90b13..ec9246c855c 100644 --- a/src/test/moves/gastro_acid.test.ts +++ b/src/test/moves/gastro_acid.test.ts @@ -62,7 +62,7 @@ describe("Moves - Gastro Acid", () => { }); it("fails if used on an enemy with an already-suppressed ability", async () => { - game.override.battleType(null); + game.override.battleType("single"); await game.startBattle(); diff --git a/src/test/utils/helpers/overridesHelper.ts b/src/test/utils/helpers/overridesHelper.ts index 02950d497ee..1c05f92a334 100644 --- a/src/test/utils/helpers/overridesHelper.ts +++ b/src/test/utils/helpers/overridesHelper.ts @@ -4,7 +4,7 @@ import { Abilities } from "#app/enums/abilities"; import * as GameMode from "#app/game-mode"; import { GameModes, getGameMode } from "#app/game-mode"; import { ModifierOverride } from "#app/modifier/modifier-type"; -import Overrides from "#app/overrides"; +import Overrides, { BattleStyle } from "#app/overrides"; import { Unlockables } from "#app/system/unlockables"; import { Biome } from "#enums/biome"; import { Moves } from "#enums/moves"; @@ -238,13 +238,14 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Override the battle type (single or double) + * Override the battle type (e.g., single or double). + * @see {@linkcode Overrides.BATTLE_TYPE_OVERRIDE} * @param battleType battle type to set * @returns `this` */ - public battleType(battleType: "single" | "double" | null): this { + public battleType(battleType: BattleStyle | null): this { vi.spyOn(Overrides, "BATTLE_TYPE_OVERRIDE", "get").mockReturnValue(battleType); - this.log(`Battle type set to ${battleType} only!`); + this.log(battleType === null ? "Battle type override disabled!" : `Battle type set to ${battleType}!`); return this; } From 58912db8f1044a8ea5fa23a6f4989bfdc1cc426f Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Thu, 14 Nov 2024 13:16:05 -0800 Subject: [PATCH 50/75] [P2] Telekinesis now sets FloatingTag to 3 turns instead of 5 turns (#4869) Co-authored-by: frutescens --- src/data/battler-tags.ts | 6 +++--- src/data/move.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 25d65fbc372..5c6d9d66b7c 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -1809,8 +1809,8 @@ export class TypeImmuneTag extends BattlerTag { * @see {@link https://bulbapedia.bulbagarden.net/wiki/Telekinesis_(move) | Moves.TELEKINESIS} */ export class FloatingTag extends TypeImmuneTag { - constructor(tagType: BattlerTagType, sourceMove: Moves) { - super(tagType, sourceMove, Type.GROUND, 5); + constructor(tagType: BattlerTagType, sourceMove: Moves, turnCount: number) { + super(tagType, sourceMove, Type.GROUND, turnCount); } onAdd(pokemon: Pokemon): void { @@ -3053,7 +3053,7 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source case BattlerTagType.CHARGED: return new TypeBoostTag(tagType, sourceMove, Type.ELECTRIC, 2, true); case BattlerTagType.FLOATING: - return new FloatingTag(tagType, sourceMove); + return new FloatingTag(tagType, sourceMove, turnCount); case BattlerTagType.MINIMIZED: return new MinimizeTag(); case BattlerTagType.DESTINY_BOND: diff --git a/src/data/move.ts b/src/data/move.ts index 74ac61af884..a288c0e9618 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -8897,7 +8897,7 @@ export function initMoves() { new SelfStatusMove(Moves.AQUA_RING, Type.WATER, -1, 20, -1, 0, 4) .attr(AddBattlerTagAttr, BattlerTagType.AQUA_RING, true, true), new SelfStatusMove(Moves.MAGNET_RISE, Type.ELECTRIC, -1, 10, -1, 0, 4) - .attr(AddBattlerTagAttr, BattlerTagType.FLOATING, true, true) + .attr(AddBattlerTagAttr, BattlerTagType.FLOATING, true, true, 5) .condition((user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY) && [ BattlerTagType.FLOATING, BattlerTagType.IGNORE_FLYING, BattlerTagType.INGRAIN ].every((tag) => !user.getTag(tag))), new AttackMove(Moves.FLARE_BLITZ, Type.FIRE, MoveCategory.PHYSICAL, 120, 100, 15, 10, 0, 4) .attr(RecoilAttr, false, 0.33) From f778bd587700c5def856d038a51b1b25fc42da90 Mon Sep 17 00:00:00 2001 From: Moka <54149968+MokaStitcher@users.noreply.github.com> Date: Fri, 15 Nov 2024 00:01:04 +0100 Subject: [PATCH 51/75] Prevent crash from null dexData attributes (#4871) --- src/system/game-data.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/system/game-data.ts b/src/system/game-data.ts index a9726ac0713..4d01ae9998a 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -679,7 +679,7 @@ export class GameData { return ret; } - return k.endsWith("Attr") && ![ "natureAttr", "abilityAttr", "passiveAttr" ].includes(k) ? BigInt(v) : v; + return k.endsWith("Attr") && ![ "natureAttr", "abilityAttr", "passiveAttr" ].includes(k) ? BigInt(v ?? 0) : v; }) as SystemSaveData; } From b1138c1d70a9428e767539ff64c858bf5dc80f36 Mon Sep 17 00:00:00 2001 From: PigeonBar <56974298+PigeonBar@users.noreply.github.com> Date: Fri, 15 Nov 2024 00:07:19 -0500 Subject: [PATCH 52/75] [P2][Beta] Freeze-dry Re-implementation (#4874) --- src/data/ability.ts | 4 +- src/data/move.ts | 82 ++++++++++++++----------------- src/field/pokemon.ts | 10 ++-- src/test/moves/freeze_dry.test.ts | 68 ++++++++++++++++++++++++- 4 files changed, 113 insertions(+), 51 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index d58c6c5c9b9..b77b18947be 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -516,7 +516,7 @@ export class NonSuperEffectiveImmunityAbAttr extends TypeImmunityAbAttr { applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { const modifierValue = args.length > 0 ? (args[0] as Utils.NumberHolder).value - : pokemon.getAttackTypeEffectiveness(attacker.getMoveType(move), attacker); + : pokemon.getAttackTypeEffectiveness(attacker.getMoveType(move), attacker, undefined, undefined, move); if (move instanceof AttackMove && modifierValue < 2) { cancelled.value = true; // Suppresses "No Effect" message @@ -3180,7 +3180,7 @@ function getAnticipationCondition(): AbAttrCondition { continue; } // the move's base type (not accounting for variable type changes) is super effective - if (move.getMove() instanceof AttackMove && pokemon.getAttackTypeEffectiveness(move.getMove().type, opponent, true) >= 2) { + if (move.getMove() instanceof AttackMove && pokemon.getAttackTypeEffectiveness(move.getMove().type, opponent, true, undefined, move.getMove()) >= 2) { return true; } // move is a OHKO diff --git a/src/data/move.ts b/src/data/move.ts index a288c0e9618..e7cd9d10615 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -897,7 +897,7 @@ export class AttackMove extends Move { let attackScore = 0; - const effectiveness = target.getAttackTypeEffectiveness(this.type, user); + const effectiveness = target.getAttackTypeEffectiveness(this.type, user, undefined, undefined, this); attackScore = Math.pow(effectiveness - 1, 2) * effectiveness < 1 ? -2 : 2; if (attackScore) { if (this.category === MoveCategory.PHYSICAL) { @@ -4971,48 +4971,6 @@ export class NeutralDamageAgainstFlyingTypeMultiplierAttr extends VariableMoveTy } } -/** - * This class forces Freeze-Dry to be super effective against Water Type. - * It considers if target is Mono or Dual Type and calculates the new Multiplier accordingly. - * @see {@linkcode apply} - */ -export class FreezeDryAttr extends VariableMoveTypeMultiplierAttr { - /** - * If the target is Mono Type (Water only) then a 2x Multiplier is always forced. - * If target is Dual Type (containing Water) then only a 2x Multiplier is forced for the Water Type. - * - * Additionally Freeze-Dry's effectiveness against water is always forced during {@linkcode InverseBattleChallenge}. - * The multiplier is recalculated for the non-Water Type in case of Dual Type targets containing Water Type. - * - * @param user The {@linkcode Pokemon} applying the move - * @param target The {@linkcode Pokemon} targeted by the move - * @param move The move used by the user - * @param args `[0]` a {@linkcode Utils.NumberHolder | NumberHolder} containing a type effectiveness multiplier - * @returns `true` if super effectiveness on water type is forced; `false` otherwise - */ - apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const multiplier = args[0] as Utils.NumberHolder; - if (target.isOfType(Type.WATER) && multiplier.value !== 0) { - const multipleTypes = (target.getTypes().length > 1); - - if (multipleTypes) { - const nonWaterType = target.getTypes().filter(type => type !== Type.WATER)[0]; - const effectivenessAgainstTarget = new Utils.NumberHolder(getTypeDamageMultiplier(user.getMoveType(move), nonWaterType)); - - applyChallenges(user.scene.gameMode, ChallengeType.TYPE_EFFECTIVENESS, effectivenessAgainstTarget); - - multiplier.value = effectivenessAgainstTarget.value * 2; - return true; - } - - multiplier.value = 2; - return true; - } - - return false; - } -} - export class IceNoEffectTypeAttr extends VariableMoveTypeMultiplierAttr { /** * Checks to see if the Target is Ice-Type or not. If so, the move will have no effect. @@ -5040,6 +4998,41 @@ export class FlyingTypeMultiplierAttr extends VariableMoveTypeMultiplierAttr { } } +/** + * Attribute for moves which have a custom type chart interaction. + */ +export class VariableMoveTypeChartAttr extends MoveAttr { + /** + * @param user {@linkcode Pokemon} using the move + * @param target {@linkcode Pokemon} target of the move + * @param move {@linkcode Move} with this attribute + * @param args [0] {@linkcode NumberHolder} holding the type effectiveness + * @param args [1] A single defensive type of the target + * + * @returns true if application of the attribute succeeds + */ + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + return false; + } +} + +/** + * This class forces Freeze-Dry to be super effective against Water Type. + */ +export class FreezeDryAttr extends VariableMoveTypeChartAttr { + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + const multiplier = args[0] as Utils.NumberHolder; + const defType = args[1] as Type; + + if (defType === Type.WATER) { + multiplier.value = 2; + return true; + } else { + return false; + } + } +} + export class OneHitKOAccuracyAttr extends VariableAccuracyAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const accuracy = args[0] as Utils.NumberHolder; @@ -9448,8 +9441,7 @@ export function initMoves() { .target(MoveTarget.ALL_NEAR_OTHERS), new AttackMove(Moves.FREEZE_DRY, Type.ICE, MoveCategory.SPECIAL, 70, 100, 20, 10, 0, 6) .attr(StatusEffectAttr, StatusEffect.FREEZE) - .attr(FreezeDryAttr) - .edgeCase(), // This currently just multiplies the move's power instead of changing its effectiveness. It also doesn't account for abilities that modify type effectiveness such as tera shell. + .attr(FreezeDryAttr), new AttackMove(Moves.DISARMING_VOICE, Type.FAIRY, MoveCategory.SPECIAL, 40, -1, 15, -1, 0, 6) .soundBased() .target(MoveTarget.ALL_NEAR_ENEMIES), diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 5d912f7d6e6..bc7e844a290 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -3,7 +3,7 @@ import BattleScene, { AnySound } from "#app/battle-scene"; import { Variant, VariantSet, variantColorCache } from "#app/data/variant"; import { variantData } from "#app/data/variant"; import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from "#app/ui/battle-info"; -import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, VariableMoveTypeAttr, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatStagesAttr, SacrificialAttr, VariableMoveCategoryAttr, CounterDamageAttr, StatStageChangeAttr, RechargeAttr, IgnoreWeatherTypeDebuffAttr, BypassBurnDamageReductionAttr, SacrificialAttrOnHit, OneHitKOAccuracyAttr, RespectAttackTypeImmunityAttr, MoveTarget, CombinedPledgeStabBoostAttr } from "#app/data/move"; +import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, VariableMoveTypeAttr, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatStagesAttr, SacrificialAttr, VariableMoveCategoryAttr, CounterDamageAttr, StatStageChangeAttr, RechargeAttr, IgnoreWeatherTypeDebuffAttr, BypassBurnDamageReductionAttr, SacrificialAttrOnHit, OneHitKOAccuracyAttr, RespectAttackTypeImmunityAttr, MoveTarget, CombinedPledgeStabBoostAttr, VariableMoveTypeChartAttr } from "#app/data/move"; import { default as PokemonSpecies, PokemonSpeciesForm, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species"; import { CLASSIC_CANDY_FRIENDSHIP_MULTIPLIER, getStarterValueFriendshipCap, speciesStarterCosts } from "#app/data/balance/starters"; import { starterPassiveAbilities } from "#app/data/balance/passives"; @@ -1632,7 +1632,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const moveType = source.getMoveType(move); const typeMultiplier = new Utils.NumberHolder((move.category !== MoveCategory.STATUS || move.hasAttr(RespectAttackTypeImmunityAttr)) - ? this.getAttackTypeEffectiveness(moveType, source, false, simulated) + ? this.getAttackTypeEffectiveness(moveType, source, false, simulated, move) : 1); applyMoveAttrs(VariableMoveTypeMultiplierAttr, source, this, move, typeMultiplier); @@ -1684,9 +1684,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @param source {@linkcode Pokemon} the Pokemon using the move * @param ignoreStrongWinds whether or not this ignores strong winds (anticipation, forewarn, stealth rocks) * @param simulated tag to only apply the strong winds effect message when the move is used + * @param move (optional) the move whose type effectiveness is to be checked. Used for applying {@linkcode VariableMoveTypeChartAttr} * @returns a multiplier for the type effectiveness */ - getAttackTypeEffectiveness(moveType: Type, source?: Pokemon, ignoreStrongWinds: boolean = false, simulated: boolean = true): TypeDamageMultiplier { + getAttackTypeEffectiveness(moveType: Type, source?: Pokemon, ignoreStrongWinds: boolean = false, simulated: boolean = true, move?: Move): TypeDamageMultiplier { if (moveType === Type.STELLAR) { return this.isTerastallized() ? 2 : 1; } @@ -1705,6 +1706,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { let multiplier = types.map(defType => { const multiplier = new Utils.NumberHolder(getTypeDamageMultiplier(moveType, defType)); applyChallenges(this.scene.gameMode, ChallengeType.TYPE_EFFECTIVENESS, multiplier); + if (move) { + applyMoveAttrs(VariableMoveTypeChartAttr, null, this, move, multiplier, defType); + } if (source) { const ignoreImmunity = new Utils.BooleanHolder(false); if (source.isActive(true) && source.hasAbilityWithAttr(IgnoreTypeImmunityAbAttr)) { diff --git a/src/test/moves/freeze_dry.test.ts b/src/test/moves/freeze_dry.test.ts index 8bc6717f435..9206a103a35 100644 --- a/src/test/moves/freeze_dry.test.ts +++ b/src/test/moves/freeze_dry.test.ts @@ -2,6 +2,7 @@ import { BattlerIndex } from "#app/battle"; import { Abilities } from "#app/enums/abilities"; import { Moves } from "#app/enums/moves"; import { Species } from "#app/enums/species"; +import { Type } from "#enums/type"; import { Challenges } from "#enums/challenges"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; @@ -29,7 +30,7 @@ describe("Moves - Freeze-Dry", () => { .enemyMoveset(Moves.SPLASH) .starterSpecies(Species.FEEBAS) .ability(Abilities.BALL_FETCH) - .moveset([ Moves.FREEZE_DRY ]); + .moveset([ Moves.FREEZE_DRY, Moves.FORESTS_CURSE, Moves.SOAK ]); }); it("should deal 2x damage to pure water types", async () => { @@ -98,6 +99,71 @@ describe("Moves - Freeze-Dry", () => { expect(enemy.hp).toBeLessThan(enemy.getMaxHp()); }); + it("should deal 8x damage to water/ground/grass type under Forest's Curse", async () => { + game.override.enemySpecies(Species.QUAGSIRE); + await game.classicMode.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + vi.spyOn(enemy, "getMoveEffectiveness"); + + game.move.select(Moves.FORESTS_CURSE); + await game.toNextTurn(); + + game.move.select(Moves.FREEZE_DRY); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await game.phaseInterceptor.to("MoveEffectPhase"); + + expect(enemy.getMoveEffectiveness).toHaveReturnedWith(8); + }); + + it("should deal 2x damage to steel type terastallized into water", async () => { + game.override.enemySpecies(Species.SKARMORY) + .enemyHeldItems([{ name: "TERA_SHARD", type: Type.WATER }]); + await game.classicMode.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + vi.spyOn(enemy, "getMoveEffectiveness"); + + game.move.select(Moves.FREEZE_DRY); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await game.phaseInterceptor.to("MoveEffectPhase"); + + expect(enemy.getMoveEffectiveness).toHaveReturnedWith(2); + }); + + it("should deal 0.5x damage to water type terastallized into fire", async () => { + game.override.enemySpecies(Species.PELIPPER) + .enemyHeldItems([{ name: "TERA_SHARD", type: Type.FIRE }]); + await game.classicMode.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + vi.spyOn(enemy, "getMoveEffectiveness"); + + game.move.select(Moves.FREEZE_DRY); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await game.phaseInterceptor.to("MoveEffectPhase"); + + expect(enemy.getMoveEffectiveness).toHaveReturnedWith(0.5); + }); + + it("should deal 0.5x damage to water type Terapagos with Tera Shell", async () => { + game.override.enemySpecies(Species.TERAPAGOS) + .enemyAbility(Abilities.TERA_SHELL); + await game.classicMode.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + vi.spyOn(enemy, "getMoveEffectiveness"); + + game.move.select(Moves.SOAK); + await game.toNextTurn(); + + game.move.select(Moves.FREEZE_DRY); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await game.phaseInterceptor.to("MoveEffectPhase"); + + expect(enemy.getMoveEffectiveness).toHaveReturnedWith(0.5); + }); + it("should deal 2x damage to water type under Normalize", async () => { game.override.ability(Abilities.NORMALIZE); await game.classicMode.startBattle(); From 6dec84e39c0e1229160af14dddb0b9df6aeedfcb Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Thu, 14 Nov 2024 21:13:23 -0800 Subject: [PATCH 53/75] [Balance] No more double 50x bosses in Endless + cleaning up RNG (#4862) * Added double battle exclusion to Endless bosses. * Brought Endure token RNG in line with game RNG formatting. * Corrected incorrect modulo condition in isEndlessBoss * Moved new doubles conditional to be above overrides. * Fixed bad RNG calls for Covet and Thief too. * Updated unburden test. * Revert "Updated unburden test." This reverts commit 01788d40c2f5c32d89bd0cb899bfc67fc77f881e. * Revert "Fixed bad RNG calls for Covet and Thief too." This reverts commit c7fcfd195de7e98c1e582ec67c829e003663cad0. --------- Co-authored-by: frutescens --- src/battle-scene.ts | 5 +++++ src/game-mode.ts | 2 +- src/modifier/modifier.ts | 8 ++++---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index e659b588208..061fc6e28f2 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1233,6 +1233,11 @@ export default class BattleScene extends SceneBase { newDouble = !!double; } + // Disable double battles on Endless/Endless Spliced Wave 50x boss battles (Introduced 1.2.0) + if (this.gameMode.isEndlessBoss(newWaveIndex)) { + newDouble = false; + } + if (!isNullOrUndefined(Overrides.BATTLE_TYPE_OVERRIDE)) { let doubleOverrideForWave: "single" | "double" | null = null; diff --git a/src/game-mode.ts b/src/game-mode.ts index 8f1bb9356e6..0f997bf651e 100644 --- a/src/game-mode.ts +++ b/src/game-mode.ts @@ -236,7 +236,7 @@ export class GameMode implements GameModeConfig { * @returns true if waveIndex is a multiple of 50 in Endless */ isEndlessBoss(waveIndex: integer): boolean { - return !!(waveIndex % 50) && + return waveIndex % 50 === 0 && (this.modeId === GameModes.ENDLESS || this.modeId === GameModes.SPLICED_ENDLESS); } diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 7aa4b9308d1..ac8dc556b98 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -3631,7 +3631,7 @@ export class EnemyEndureChanceModifier extends EnemyPersistentModifier { super(type, stackCount || 10); //Hardcode temporarily - this.chance = .02; + this.chance = 2; } match(modifier: Modifier) { @@ -3639,11 +3639,11 @@ export class EnemyEndureChanceModifier extends EnemyPersistentModifier { } clone() { - return new EnemyEndureChanceModifier(this.type, this.chance * 100, this.stackCount); + return new EnemyEndureChanceModifier(this.type, this.chance, this.stackCount); } getArgs(): any[] { - return [ this.chance * 100 ]; + return [ this.chance ]; } /** @@ -3652,7 +3652,7 @@ export class EnemyEndureChanceModifier extends EnemyPersistentModifier { * @returns `true` if {@linkcode Pokemon} endured */ override apply(target: Pokemon): boolean { - if (target.battleData.endured || Phaser.Math.RND.realInRange(0, 1) >= (this.chance * this.getStackCount())) { + if (target.battleData.endured || target.randSeedInt(100) >= (this.chance * this.getStackCount())) { return false; } From 8326e3556b90c95379bf7c5c95ed31c33485d2cc Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Fri, 15 Nov 2024 08:29:52 -0800 Subject: [PATCH 54/75] Remove `.edgeCase()` from fully implemented moves (#4876) This includes Sunsteel Strike, Moongeist Beam and Photon Geyser --- src/data/move.ts | 9 ++-- src/test/moves/moongeist_beam.test.ts | 59 +++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 src/test/moves/moongeist_beam.test.ts diff --git a/src/data/move.ts b/src/data/move.ts index e7cd9d10615..ae2ba919b52 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -9876,11 +9876,9 @@ export function initMoves() { .ignoresSubstitute() .partial(), // Does not steal stats new AttackMove(Moves.SUNSTEEL_STRIKE, Type.STEEL, MoveCategory.PHYSICAL, 100, 100, 5, -1, 0, 7) - .ignoresAbilities() - .edgeCase(), // Should not ignore abilities when called virtually (metronome) + .ignoresAbilities(), new AttackMove(Moves.MOONGEIST_BEAM, Type.GHOST, MoveCategory.SPECIAL, 100, 100, 5, -1, 0, 7) - .ignoresAbilities() - .edgeCase(), // Should not ignore abilities when called virtually (metronome) + .ignoresAbilities(), new StatusMove(Moves.TEARFUL_LOOK, Type.NORMAL, -1, 20, -1, 0, 7) .attr(StatStageChangeAttr, [ Stat.ATK, Stat.SPATK ], -1), new AttackMove(Moves.ZING_ZAP, Type.ELECTRIC, MoveCategory.PHYSICAL, 80, 100, 10, 30, 0, 7) @@ -9903,8 +9901,7 @@ export function initMoves() { .punchingMove(), new AttackMove(Moves.PHOTON_GEYSER, Type.PSYCHIC, MoveCategory.SPECIAL, 100, 100, 5, -1, 0, 7) .attr(PhotonGeyserCategoryAttr) - .ignoresAbilities() - .edgeCase(), // Should not ignore abilities when called virtually (metronome) + .ignoresAbilities(), /* Unused */ new AttackMove(Moves.LIGHT_THAT_BURNS_THE_SKY, Type.PSYCHIC, MoveCategory.SPECIAL, 200, -1, 1, -1, 0, 7) .attr(PhotonGeyserCategoryAttr) diff --git a/src/test/moves/moongeist_beam.test.ts b/src/test/moves/moongeist_beam.test.ts new file mode 100644 index 00000000000..216eee482fb --- /dev/null +++ b/src/test/moves/moongeist_beam.test.ts @@ -0,0 +1,59 @@ +import { allMoves, RandomMoveAttr } from "#app/data/move"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; + +describe("Moves - Moongeist Beam", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([ Moves.MOONGEIST_BEAM, Moves.METRONOME ]) + .ability(Abilities.BALL_FETCH) + .startingLevel(200) + .battleType("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.STURDY) + .enemyMoveset(Moves.SPLASH); + }); + + // Also covers Photon Geyser and Sunsteel Strike + it("should ignore enemy abilities", async () => { + await game.classicMode.startBattle([ Species.MILOTIC ]); + + const enemy = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.MOONGEIST_BEAM); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemy.isFainted()).toBe(true); + }); + + // Also covers Photon Geyser and Sunsteel Strike + it("should not ignore enemy abilities when called by another move, such as metronome", async () => { + await game.classicMode.startBattle([ Species.MILOTIC ]); + vi.spyOn(allMoves[Moves.METRONOME].getAttrs(RandomMoveAttr)[0], "getMoveOverride").mockReturnValue(Moves.MOONGEIST_BEAM); + + game.move.select(Moves.METRONOME); + await game.phaseInterceptor.to("BerryPhase"); + + expect(game.scene.getEnemyPokemon()!.isFainted()).toBe(false); + expect(game.scene.getPlayerPokemon()!.getLastXMoves()[0].move).toBe(Moves.MOONGEIST_BEAM); + }); +}); From 9273b4930d929cd9c8fb67466ea2501e8ffb8bf4 Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Fri, 15 Nov 2024 08:56:05 -0800 Subject: [PATCH 55/75] [Beta][P1] Fix crash when resetting Commanded Dondozo before Trainer battles (#4873) * Add failsafe to Commander remove anim * Commanded tag saves Tatsu form on reload --- src/data/battler-tags.ts | 5 +++++ src/phases/pokemon-anim-phase.ts | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 5c6d9d66b7c..28ab5ff2a4f 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -2158,6 +2158,11 @@ export class CommandedTag extends BattlerTag { pokemon.scene.triggerPokemonBattleAnim(pokemon, PokemonAnimType.COMMANDER_REMOVE); } } + + override loadTag(source: BattlerTag | any): void { + super.loadTag(source); + this._tatsugiriFormKey = source._tatsugiriFormKey; + } } /** diff --git a/src/phases/pokemon-anim-phase.ts b/src/phases/pokemon-anim-phase.ts index ad0be34af7d..eb5431cbc56 100644 --- a/src/phases/pokemon-anim-phase.ts +++ b/src/phases/pokemon-anim-phase.ts @@ -312,6 +312,10 @@ export class PokemonAnimPhase extends BattlePhase { // Note: unlike the other Commander animation, this is played through the // Dondozo instead of the Tatsugiri. const tatsugiri = this.pokemon.getAlly(); + if (isNullOrUndefined(tatsugiri)) { + console.warn("Aborting COMMANDER_REMOVE anim: Tatsugiri is undefined"); + return this.end(); + } const tatsuSprite = this.scene.addPokemonSprite( tatsugiri, From ef7d860166136e126973a69bd80450dfd92c1c25 Mon Sep 17 00:00:00 2001 From: AJ Fontaine <36677462+Fontbane@users.noreply.github.com> Date: Fri, 15 Nov 2024 11:57:02 -0500 Subject: [PATCH 56/75] [Balance] Remove from trainers: Pika/Eevee forms before 30, BB Greninja, Rival starter HA (#4863) * Remove Pika/Eevee forms from Trainers before wave 30, and BB Gren * Fix `egg` test * Ban hidden ability from Rival starter --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/battle-scene.ts | 9 +++++++++ src/data/trainer-config.ts | 18 +++++++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 061fc6e28f2..2f062667808 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1424,10 +1424,19 @@ export default class BattleScene extends SceneBase { case Species.PALDEA_TAUROS: return Utils.randSeedInt(species.forms.length); case Species.PIKACHU: + if (this.currentBattle?.battleType === BattleType.TRAINER && this.currentBattle?.waveIndex < 30) { + return 0; // Ban Cosplay and Partner Pika from Trainers before wave 30 + } return Utils.randSeedInt(8); case Species.EEVEE: + if (this.currentBattle?.battleType === BattleType.TRAINER && this.currentBattle?.waveIndex < 30) { + return 0; // No Partner Eevee for Wave 12 Preschoolers + } return Utils.randSeedInt(2); case Species.GRENINJA: + if (this.currentBattle?.battleType === BattleType.TRAINER) { + return 0; // Don't give trainers Battle Bond Greninja + } return Utils.randSeedInt(2); case Species.ZYGARDE: return Utils.randSeedInt(4); diff --git a/src/data/trainer-config.ts b/src/data/trainer-config.ts index d82d568ecc6..5e5f38bd00d 100644 --- a/src/data/trainer-config.ts +++ b/src/data/trainer-config.ts @@ -1841,21 +1841,25 @@ export const trainerConfigs: TrainerConfigs = { [TrainerType.RIVAL]: new TrainerConfig((t = TrainerType.RIVAL)).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setStaticParty().setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival").setMixedBattleBgm("battle_rival").setPartyTemplates(trainerPartyTemplates.RIVAL) .setModifierRewardFuncs(() => modifierTypes.SUPER_EXP_CHARM, () => modifierTypes.EXP_SHARE) .setEventModifierRewardFuncs(() => modifierTypes.SHINY_CHARM, () => modifierTypes.ABILITY_CHARM) - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE, Species.CHIKORITA, Species.CYNDAQUIL, Species.TOTODILE, Species.TREECKO, Species.TORCHIC, Species.MUDKIP, Species.TURTWIG, Species.CHIMCHAR, Species.PIPLUP, Species.SNIVY, Species.TEPIG, Species.OSHAWOTT, Species.CHESPIN, Species.FENNEKIN, Species.FROAKIE, Species.ROWLET, Species.LITTEN, Species.POPPLIO, Species.GROOKEY, Species.SCORBUNNY, Species.SOBBLE, Species.SPRIGATITO, Species.FUECOCO, Species.QUAXLY ], TrainerSlot.TRAINER, true)) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE, Species.CHIKORITA, Species.CYNDAQUIL, Species.TOTODILE, Species.TREECKO, Species.TORCHIC, Species.MUDKIP, Species.TURTWIG, Species.CHIMCHAR, Species.PIPLUP, Species.SNIVY, Species.TEPIG, Species.OSHAWOTT, Species.CHESPIN, Species.FENNEKIN, Species.FROAKIE, Species.ROWLET, Species.LITTEN, Species.POPPLIO, Species.GROOKEY, Species.SCORBUNNY, Species.SOBBLE, Species.SPRIGATITO, Species.FUECOCO, Species.QUAXLY ], TrainerSlot.TRAINER, true, + (p => p.abilityIndex = 0))) .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.PIDGEY, Species.HOOTHOOT, Species.TAILLOW, Species.STARLY, Species.PIDOVE, Species.FLETCHLING, Species.PIKIPEK, Species.ROOKIDEE, Species.WATTREL ], TrainerSlot.TRAINER, true)), [TrainerType.RIVAL_2]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setStaticParty().setMoneyMultiplier(1.25).setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival").setMixedBattleBgm("battle_rival").setPartyTemplates(trainerPartyTemplates.RIVAL_2) .setModifierRewardFuncs(() => modifierTypes.EXP_SHARE) .setEventModifierRewardFuncs(() => modifierTypes.SHINY_CHARM) - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.IVYSAUR, Species.CHARMELEON, Species.WARTORTLE, Species.BAYLEEF, Species.QUILAVA, Species.CROCONAW, Species.GROVYLE, Species.COMBUSKEN, Species.MARSHTOMP, Species.GROTLE, Species.MONFERNO, Species.PRINPLUP, Species.SERVINE, Species.PIGNITE, Species.DEWOTT, Species.QUILLADIN, Species.BRAIXEN, Species.FROGADIER, Species.DARTRIX, Species.TORRACAT, Species.BRIONNE, Species.THWACKEY, Species.RABOOT, Species.DRIZZILE, Species.FLORAGATO, Species.CROCALOR, Species.QUAXWELL ], TrainerSlot.TRAINER, true)) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.IVYSAUR, Species.CHARMELEON, Species.WARTORTLE, Species.BAYLEEF, Species.QUILAVA, Species.CROCONAW, Species.GROVYLE, Species.COMBUSKEN, Species.MARSHTOMP, Species.GROTLE, Species.MONFERNO, Species.PRINPLUP, Species.SERVINE, Species.PIGNITE, Species.DEWOTT, Species.QUILLADIN, Species.BRAIXEN, Species.FROGADIER, Species.DARTRIX, Species.TORRACAT, Species.BRIONNE, Species.THWACKEY, Species.RABOOT, Species.DRIZZILE, Species.FLORAGATO, Species.CROCALOR, Species.QUAXWELL ], TrainerSlot.TRAINER, true, + (p => p.abilityIndex = 0))) .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.PIDGEOTTO, Species.HOOTHOOT, Species.TAILLOW, Species.STARAVIA, Species.TRANQUILL, Species.FLETCHINDER, Species.TRUMBEAK, Species.CORVISQUIRE, Species.WATTREL ], TrainerSlot.TRAINER, true)) .setPartyMemberFunc(2, getSpeciesFilterRandomPartyMemberFunc((species: PokemonSpecies) => !pokemonEvolutions.hasOwnProperty(species.speciesId) && !pokemonPrevolutions.hasOwnProperty(species.speciesId) && species.baseTotal >= 450)), [TrainerType.RIVAL_3]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setStaticParty().setMoneyMultiplier(1.5).setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival").setMixedBattleBgm("battle_rival").setPartyTemplates(trainerPartyTemplates.RIVAL_3) - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE, Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR, Species.SCEPTILE, Species.BLAZIKEN, Species.SWAMPERT, Species.TORTERRA, Species.INFERNAPE, Species.EMPOLEON, Species.SERPERIOR, Species.EMBOAR, Species.SAMUROTT, Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA, Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA, Species.RILLABOOM, Species.CINDERACE, Species.INTELEON, Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL ], TrainerSlot.TRAINER, true)) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE, Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR, Species.SCEPTILE, Species.BLAZIKEN, Species.SWAMPERT, Species.TORTERRA, Species.INFERNAPE, Species.EMPOLEON, Species.SERPERIOR, Species.EMBOAR, Species.SAMUROTT, Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA, Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA, Species.RILLABOOM, Species.CINDERACE, Species.INTELEON, Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL ], TrainerSlot.TRAINER, true, + (p => p.abilityIndex = 0))) .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.PIDGEOT, Species.NOCTOWL, Species.SWELLOW, Species.STARAPTOR, Species.UNFEZANT, Species.TALONFLAME, Species.TOUCANNON, Species.CORVIKNIGHT, Species.KILOWATTREL ], TrainerSlot.TRAINER, true)) .setPartyMemberFunc(2, getSpeciesFilterRandomPartyMemberFunc((species: PokemonSpecies) => !pokemonEvolutions.hasOwnProperty(species.speciesId) && !pokemonPrevolutions.hasOwnProperty(species.speciesId) && species.baseTotal >= 450)) .setSpeciesFilter(species => species.baseTotal >= 540), [TrainerType.RIVAL_4]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setBoss().setStaticParty().setMoneyMultiplier(1.75).setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival_2").setMixedBattleBgm("battle_rival_2").setPartyTemplates(trainerPartyTemplates.RIVAL_4) - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE, Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR, Species.SCEPTILE, Species.BLAZIKEN, Species.SWAMPERT, Species.TORTERRA, Species.INFERNAPE, Species.EMPOLEON, Species.SERPERIOR, Species.EMBOAR, Species.SAMUROTT, Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA, Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA, Species.RILLABOOM, Species.CINDERACE, Species.INTELEON, Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL ], TrainerSlot.TRAINER, true)) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE, Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR, Species.SCEPTILE, Species.BLAZIKEN, Species.SWAMPERT, Species.TORTERRA, Species.INFERNAPE, Species.EMPOLEON, Species.SERPERIOR, Species.EMBOAR, Species.SAMUROTT, Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA, Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA, Species.RILLABOOM, Species.CINDERACE, Species.INTELEON, Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL ], TrainerSlot.TRAINER, true, + (p => p.abilityIndex = 0))) .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.PIDGEOT, Species.NOCTOWL, Species.SWELLOW, Species.STARAPTOR, Species.UNFEZANT, Species.TALONFLAME, Species.TOUCANNON, Species.CORVIKNIGHT, Species.KILOWATTREL ], TrainerSlot.TRAINER, true)) .setPartyMemberFunc(2, getSpeciesFilterRandomPartyMemberFunc((species: PokemonSpecies) => !pokemonEvolutions.hasOwnProperty(species.speciesId) && !pokemonPrevolutions.hasOwnProperty(species.speciesId) && species.baseTotal >= 450)) .setSpeciesFilter(species => species.baseTotal >= 540) @@ -1865,7 +1869,10 @@ export const trainerConfigs: TrainerConfigs = { }), [TrainerType.RIVAL_5]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setBoss().setStaticParty().setMoneyMultiplier(2.25).setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival_3").setMixedBattleBgm("battle_rival_3").setPartyTemplates(trainerPartyTemplates.RIVAL_5) .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE, Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR, Species.SCEPTILE, Species.BLAZIKEN, Species.SWAMPERT, Species.TORTERRA, Species.INFERNAPE, Species.EMPOLEON, Species.SERPERIOR, Species.EMBOAR, Species.SAMUROTT, Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA, Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA, Species.RILLABOOM, Species.CINDERACE, Species.INTELEON, Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL ], TrainerSlot.TRAINER, true, - p => p.setBoss(true, 2))) + p => { + p.setBoss(true, 2); + p.abilityIndex = 0; + })) .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.PIDGEOT, Species.NOCTOWL, Species.SWELLOW, Species.STARAPTOR, Species.UNFEZANT, Species.TALONFLAME, Species.TOUCANNON, Species.CORVIKNIGHT, Species.KILOWATTREL ], TrainerSlot.TRAINER, true)) .setPartyMemberFunc(2, getSpeciesFilterRandomPartyMemberFunc((species: PokemonSpecies) => !pokemonEvolutions.hasOwnProperty(species.speciesId) && !pokemonPrevolutions.hasOwnProperty(species.speciesId) && species.baseTotal >= 450)) .setSpeciesFilter(species => species.baseTotal >= 540) @@ -1883,6 +1890,7 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE, Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR, Species.SCEPTILE, Species.BLAZIKEN, Species.SWAMPERT, Species.TORTERRA, Species.INFERNAPE, Species.EMPOLEON, Species.SERPERIOR, Species.EMBOAR, Species.SAMUROTT, Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA, Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA, Species.RILLABOOM, Species.CINDERACE, Species.INTELEON, Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL ], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 3); + p.abilityIndex = 0; p.generateAndPopulateMoveset(); })) .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.PIDGEOT, Species.NOCTOWL, Species.SWELLOW, Species.STARAPTOR, Species.UNFEZANT, Species.TALONFLAME, Species.TOUCANNON, Species.CORVIKNIGHT, Species.KILOWATTREL ], TrainerSlot.TRAINER, true, From 5ca1fd5cfd8cc8f98c9cfc939a484cea6399a57d Mon Sep 17 00:00:00 2001 From: pom-eranian Date: Fri, 15 Nov 2024 11:58:50 -0500 Subject: [PATCH 57/75] [Sprite] Set default fps to 10 instead of 12 on pokemon animations (#4842) * Set default fps to 10 instead of 12 for pokemon sprites * [Sprite] Set pokemon animation framerate to 10 where assigned --- src/data/pokemon-species.ts | 4 ++-- src/field/mystery-encounter-intro.ts | 2 +- src/field/pokemon.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index 203e545503a..ec104d4d4aa 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -505,11 +505,11 @@ export abstract class PokemonSpeciesForm { scene.anims.create({ key: this.getSpriteKey(female, formIndex, shiny, variant), frames: frameNames, - frameRate: 12, + frameRate: 10, repeat: -1 }); } else { - scene.anims.get(spriteKey).frameRate = 12; + scene.anims.get(spriteKey).frameRate = 10; } let spritePath = this.getSpriteAtlasPath(female, formIndex, shiny, variant).replace("variant/", "").replace(/_[1-3]$/, ""); const useExpSprite = scene.experimentalSprites && scene.hasExpSprite(spriteKey); diff --git a/src/field/mystery-encounter-intro.ts b/src/field/mystery-encounter-intro.ts index 12bcace500c..1577d1157d7 100644 --- a/src/field/mystery-encounter-intro.ts +++ b/src/field/mystery-encounter-intro.ts @@ -212,7 +212,7 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con this.scene.anims.create({ key: config.spriteKey, frames: frameNames, - frameRate: 12, + frameRate: 10, repeat: -1 }); } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index bc7e844a290..30d1aceea4b 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -427,7 +427,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.scene.anims.create({ key: this.getBattleSpriteKey(), frames: battleFrameNames, - frameRate: 12, + frameRate: 10, repeat: -1 }); } @@ -3612,7 +3612,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } this.status = null; if (lastStatus === StatusEffect.SLEEP) { - this.setFrameRate(12); + this.setFrameRate(10); if (this.getTag(BattlerTagType.NIGHTMARE)) { this.lapseTag(BattlerTagType.NIGHTMARE); } From eb3c0d731a38178722636391f175002c9b467f5d Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Fri, 15 Nov 2024 09:17:46 -0800 Subject: [PATCH 58/75] [P2] Lunar Blessing / Jungle Healing now heal Freeze (#4877) * Added Freeze to statuses healed by Jungle Healing / Lunar Blessing * Fixed up documentation. --------- Co-authored-by: frutescens --- src/data/move.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index ae2ba919b52..2ac4d74b712 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -2589,12 +2589,11 @@ export class HealStatusEffectAttr extends MoveEffectAttr { /** * @param selfTarget - Whether this move targets the user - * @param ...effects - List of status effects to cure + * @param effects - status effect or list of status effects to cure */ - constructor(selfTarget: boolean, ...effects: StatusEffect[]) { + constructor(selfTarget: boolean, effects: StatusEffect | StatusEffect[]) { super(selfTarget, { lastHitOnly: true }); - - this.effects = effects; + this.effects = [ effects ].flat(1); } /** @@ -8583,7 +8582,7 @@ export function initMoves() { .attr(AddArenaTagAttr, ArenaTagType.IMPRISON, 1, true, false) .target(MoveTarget.ENEMY_SIDE), new SelfStatusMove(Moves.REFRESH, Type.NORMAL, -1, 20, -1, 0, 3) - .attr(HealStatusEffectAttr, true, StatusEffect.PARALYSIS, StatusEffect.POISON, StatusEffect.TOXIC, StatusEffect.BURN) + .attr(HealStatusEffectAttr, true, [ StatusEffect.PARALYSIS, StatusEffect.POISON, StatusEffect.TOXIC, StatusEffect.BURN ]) .condition((user, target, move) => !!user.status && (user.status.effect === StatusEffect.PARALYSIS || user.status.effect === StatusEffect.POISON || user.status.effect === StatusEffect.TOXIC || user.status.effect === StatusEffect.BURN)), new SelfStatusMove(Moves.GRUDGE, Type.GHOST, -1, 5, -1, 0, 3) .attr(AddBattlerTagAttr, BattlerTagType.GRUDGE, true, undefined, 1), @@ -9792,7 +9791,7 @@ export function initMoves() { .condition( (user: Pokemon, target: Pokemon, move: Move) => isNonVolatileStatusEffect(target.status?.effect!)) // TODO: is this bang correct? .attr(HealAttr, 0.5) - .attr(HealStatusEffectAttr, false, ...getNonVolatileStatusEffects()) + .attr(HealStatusEffectAttr, false, getNonVolatileStatusEffects()) .triageMove(), new AttackMove(Moves.REVELATION_DANCE, Type.NORMAL, MoveCategory.SPECIAL, 90, 100, 15, -1, 0, 7) .danceMove() @@ -10216,7 +10215,7 @@ export function initMoves() { .attr(StatusEffectAttr, StatusEffect.BURN), new StatusMove(Moves.JUNGLE_HEALING, Type.GRASS, -1, 10, -1, 0, 8) .attr(HealAttr, 0.25, true, false) - .attr(HealStatusEffectAttr, false, StatusEffect.PARALYSIS, StatusEffect.POISON, StatusEffect.TOXIC, StatusEffect.BURN, StatusEffect.SLEEP) + .attr(HealStatusEffectAttr, false, getNonVolatileStatusEffects()) .target(MoveTarget.USER_AND_ALLIES), new AttackMove(Moves.WICKED_BLOW, Type.DARK, MoveCategory.PHYSICAL, 75, 100, 5, -1, 0, 8) .attr(CritOnlyAttr) @@ -10320,12 +10319,12 @@ export function initMoves() { .target(MoveTarget.ALL_NEAR_ENEMIES), new StatusMove(Moves.LUNAR_BLESSING, Type.PSYCHIC, -1, 5, -1, 0, 8) .attr(HealAttr, 0.25, true, false) - .attr(HealStatusEffectAttr, false, StatusEffect.PARALYSIS, StatusEffect.POISON, StatusEffect.TOXIC, StatusEffect.BURN, StatusEffect.SLEEP) + .attr(HealStatusEffectAttr, false, getNonVolatileStatusEffects()) .target(MoveTarget.USER_AND_ALLIES) .triageMove(), new SelfStatusMove(Moves.TAKE_HEART, Type.PSYCHIC, -1, 10, -1, 0, 8) .attr(StatStageChangeAttr, [ Stat.SPATK, Stat.SPDEF ], 1, true) - .attr(HealStatusEffectAttr, true, StatusEffect.PARALYSIS, StatusEffect.POISON, StatusEffect.TOXIC, StatusEffect.BURN, StatusEffect.SLEEP), + .attr(HealStatusEffectAttr, true, [ StatusEffect.PARALYSIS, StatusEffect.POISON, StatusEffect.TOXIC, StatusEffect.BURN, StatusEffect.SLEEP ]), /* Unused new AttackMove(Moves.G_MAX_WILDFIRE, Type.FIRE, MoveCategory.PHYSICAL, 10, -1, 10, -1, 0, 8) .target(MoveTarget.ALL_NEAR_ENEMIES) From c535e928d84688b361c54e9bb8992a079f71013d Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Fri, 15 Nov 2024 09:45:21 -0800 Subject: [PATCH 59/75] [Beta][QoL] Improved cursor memory for target selection in Doubles (#4849) * Added more intelligent cursor memory for target selection in Doubles * Added documentation * Fixed variable name. * Apply suggestions from code review Co-authored-by: Moka <54149968+MokaStitcher@users.noreply.github.com> --------- Co-authored-by: frutescens Co-authored-by: Moka <54149968+MokaStitcher@users.noreply.github.com> --- src/ui/target-select-ui-handler.ts | 40 +++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/src/ui/target-select-ui-handler.ts b/src/ui/target-select-ui-handler.ts index ecc15e5985e..249ae7b8b01 100644 --- a/src/ui/target-select-ui-handler.ts +++ b/src/ui/target-select-ui-handler.ts @@ -13,9 +13,11 @@ import { SubstituteTag } from "#app/data/battler-tags"; export type TargetSelectCallback = (targets: BattlerIndex[]) => void; export default class TargetSelectUiHandler extends UiHandler { - private fieldIndex: integer; + private fieldIndex: number; private move: Moves; private targetSelectCallback: TargetSelectCallback; + private cursor0: number; // associated with BattlerIndex.PLAYER + private cursor1: number; // associated with BattlerIndex.PLAYER_2 private isMultipleTargets: boolean = false; private targets: BattlerIndex[]; @@ -42,8 +44,9 @@ export default class TargetSelectUiHandler extends UiHandler { this.fieldIndex = args[0] as integer; this.move = args[1] as Moves; this.targetSelectCallback = args[2] as TargetSelectCallback; + const user = this.scene.getPlayerField()[this.fieldIndex]; - const moveTargets = getMoveTargets(this.scene.getPlayerField()[this.fieldIndex], this.move); + const moveTargets = getMoveTargets(user, this.move); this.targets = moveTargets.targets; this.isMultipleTargets = moveTargets.multiple ?? false; @@ -53,11 +56,29 @@ export default class TargetSelectUiHandler extends UiHandler { this.enemyModifiers = this.scene.getModifierBar(true); - this.setCursor(this.targets.includes(this.cursor) ? this.cursor : this.targets[0]); - + if (this.fieldIndex === BattlerIndex.PLAYER) { + this.resetCursor(this.cursor0, user); + } else if (this.fieldIndex === BattlerIndex.PLAYER_2) { + this.resetCursor(this.cursor1, user); + } return true; } + /** + * Determines what value to assign the main cursor based on the previous turn's target or the user's status + * @param cursorN the cursor associated with the user's field index + * @param user the Pokemon using the move + */ + resetCursor(cursorN: number, user: Pokemon): void { + if (!Utils.isNullOrUndefined(cursorN)) { + if ([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2 ].includes(cursorN) || user.battleSummonData.waveTurnCount === 1) { + // Reset cursor on the first turn of a fight or if an ally was targeted last turn + cursorN = -1; + } + } + this.setCursor(this.targets.includes(cursorN) ? cursorN : this.targets[0]); + } + processInput(button: Button): boolean { const ui = this.getUi(); @@ -67,6 +88,15 @@ export default class TargetSelectUiHandler extends UiHandler { const targetIndexes: BattlerIndex[] = this.isMultipleTargets ? this.targets : [ this.cursor ]; this.targetSelectCallback(button === Button.ACTION ? targetIndexes : []); success = true; + if (this.fieldIndex === BattlerIndex.PLAYER) { + if (Utils.isNullOrUndefined(this.cursor0) || this.cursor0 !== this.cursor) { + this.cursor0 = this.cursor; + } + } else if (this.fieldIndex === BattlerIndex.PLAYER_2) { + if (Utils.isNullOrUndefined(this.cursor1) || this.cursor1 !== this.cursor) { + this.cursor1 = this.cursor; + } + } } else if (this.isMultipleTargets) { success = false; } else { @@ -152,7 +182,6 @@ export default class TargetSelectUiHandler extends UiHandler { yoyo: true })); }); - return ret; } @@ -184,7 +213,6 @@ export default class TargetSelectUiHandler extends UiHandler { } clear() { - this.cursor = -1; super.clear(); this.eraseCursor(); } From 5e7d44abfdabe78157a3641aaa036eb32a033e56 Mon Sep 17 00:00:00 2001 From: AJ Fontaine <36677462+Fontbane@users.noreply.github.com> Date: Fri, 15 Nov 2024 14:07:02 -0500 Subject: [PATCH 60/75] [Balance] Fix Liquidation, Double-Edge, Body Press compatibility (#4879) --- src/data/balance/tms.ts | 124 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/src/data/balance/tms.ts b/src/data/balance/tms.ts index 7b65ae65ec4..4882cf4f652 100644 --- a/src/data/balance/tms.ts +++ b/src/data/balance/tms.ts @@ -3302,11 +3302,23 @@ export const tmSpecies: TmSpecies = { Species.FERALIGATR, Species.SENTRET, Species.FURRET, + Species.HOOTHOOT, Species.NOCTOWL, + Species.LEDYBA, + Species.LEDIAN, + Species.SPINARAK, + Species.ARIADOS, Species.CROBAT, Species.CHINCHOU, Species.LANTURN, + Species.PICHU, + Species.CLEFFA, Species.IGGLYBUFF, + Species.TYROGUE, + Species.TOGEPI, + Species.TOGETIC, + Species.NATU, + Species.XATU, Species.MAREEP, Species.FLAAFFY, Species.AMPHAROS, @@ -3328,6 +3340,7 @@ export const tmSpecies: TmSpecies = { Species.UMBREON, Species.MURKROW, Species.SLOWKING, + Species.MISDREAVUS, Species.GIRAFARIG, Species.PINECO, Species.FORRETRESS, @@ -3338,11 +3351,21 @@ export const tmSpecies: TmSpecies = { Species.GRANBULL, Species.QWILFISH, Species.SCIZOR, + Species.SHUCKLE, Species.HERACROSS, + Species.SNEASEL, Species.TEDDIURSA, Species.URSARING, + Species.SLUGMA, + Species.MAGCARGO, Species.SWINUB, Species.PILOSWINE, + Species.CORSOLA, + Species.REMORAID, + Species.OCTILLERY, + Species.DELIBIRD, + Species.MANTINE, + Species.SKARMORY, Species.HOUNDOUR, Species.HOUNDOOM, Species.KINGDRA, @@ -3350,9 +3373,12 @@ export const tmSpecies: TmSpecies = { Species.DONPHAN, Species.PORYGON2, Species.STANTLER, + Species.TYROGUE, Species.HITMONTOP, + Species.SMOOCHUM, Species.ELEKID, Species.MAGBY, + Species.MILTANK, Species.BLISSEY, Species.RAIKOU, Species.ENTEI, @@ -3362,6 +3388,9 @@ export const tmSpecies: TmSpecies = { Species.TYRANITAR, Species.LUGIA, Species.HO_OH, + Species.CELEBI, + Species.TREECKO, + Species.GROVYLE, Species.SCEPTILE, Species.TORCHIC, Species.COMBUSKEN, @@ -3371,41 +3400,116 @@ export const tmSpecies: TmSpecies = { Species.SWAMPERT, Species.POOCHYENA, Species.MIGHTYENA, + Species.ZIGZAGOON, + Species.LINOONE, + Species.BEAUTIFLY, + Species.DUSTOX, Species.LOTAD, Species.LOMBRE, Species.LUDICOLO, Species.SEEDOT, Species.NUZLEAF, Species.SHIFTRY, + Species.TAILLOW, + Species.SWELLOW, + Species.WINGULL, + Species.PELIPPER, + Species.RALTS, + Species.KIRLIA, + Species.GARDEVOIR, + Species.SURSKIT, + Species.MASQUERAIN, + Species.SHROOMISH, + Species.BRELOOM, Species.VIGOROTH, Species.SLAKING, + Species.NINCADA, + Species.NINJASK, + Species.SHEDINJA, + Species.WHISMUR, + Species.LOUDRED, + Species.EXPLOUD, Species.MAKUHITA, Species.HARIYAMA, + Species.AZURILL, Species.NOSEPASS, + Species.SKITTY, + Species.DELCATTY, + Species.SABLEYE, + Species.MAWILE, + Species.ARON, + Species.LAIRON, + Species.AGGRON, + Species.MEDITITE, + Species.MEDICHAM, + Species.ELECTRIKE, + Species.MANECTRIC, + Species.PLUSLE, + Species.MINUN, Species.VOLBEAT, Species.ILLUMISE, + Species.ROSELIA, + Species.GULPIN, Species.SWALOT, + Species.CARVANHA, + Species.SHARPEDO, + Species.WAILMER, + Species.WAILORD, Species.NUMEL, Species.CAMERUPT, Species.TORKOAL, + Species.SPOINK, + Species.GRUMPIG, + Species.SPINDA, + Species.TRAPINCH, + Species.VIBRAVA, Species.FLYGON, + Species.CACNEA, + Species.CACTURNE, + Species.SWABLU, Species.ALTARIA, Species.ZANGOOSE, Species.SEVIPER, + Species.LUNATONE, + Species.SOLROCK, Species.BARBOACH, Species.WHISCASH, Species.CORPHISH, Species.CRAWDAUNT, + Species.BALTOY, + Species.CLAYDOL, + Species.LILEEP, + Species.CRADILY, + Species.ANORITH, + Species.ARMALDO, Species.FEEBAS, Species.MILOTIC, + Species.CASTFORM, + Species.KECLEON, + Species.SHUPPET, + Species.BANETTE, + Species.DUSKULL, + Species.DUSCLOPS, Species.TROPIUS, Species.CHIMECHO, + Species.ABSOL, + Species.SNORUNT, + Species.GLALIE, + Species.SPHEAL, + Species.SEALEO, + Species.WALREIN, + Species.CLAMPERL, + Species.HUNTAIL, + Species.GOREBYSS, + Species.RELICANTH, + Species.LUVDISC, Species.BAGON, Species.SHELGON, Species.SALAMENCE, Species.METANG, Species.METAGROSS, Species.REGIROCK, + Species.REGICE, Species.REGISTEEL, Species.LATIAS, Species.LATIOS, @@ -3413,6 +3517,7 @@ export const tmSpecies: TmSpecies = { Species.GROUDON, Species.RAYQUAZA, Species.JIRACHI, + Species.DEOXYS, Species.TURTWIG, Species.GROTLE, Species.TORTERRA, @@ -64246,12 +64351,16 @@ export const tmSpecies: TmSpecies = { Species.BLOODMOON_URSALUNA, ], [Moves.LIQUIDATION]: [ + Species.SQUIRTLE, + Species.WARTORTLE, Species.BLASTOISE, Species.PSYDUCK, Species.GOLDUCK, Species.POLIWAG, Species.POLIWHIRL, Species.POLIWRATH, + Species.TENTACOOL, + Species.TENTACRUEL, Species.SLOWPOKE, Species.SLOWBRO, Species.DEWGONG, @@ -64267,7 +64376,11 @@ export const tmSpecies: TmSpecies = { Species.KABUTO, Species.KABUTOPS, Species.MEW, + Species.TOTODILE, + Species.CROCONAW, Species.FERALIGATR, + Species.CHINCHOU, + Species.LANTURN, Species.MARILL, Species.AZUMARILL, Species.POLITOED, @@ -64280,6 +64393,9 @@ export const tmSpecies: TmSpecies = { Species.MANTINE, Species.KINGDRA, Species.SUICUNE, + Species.LUGIA, + Species.MUDKIP, + Species.MARSHTOMP, Species.SWAMPERT, Species.WINGULL, Species.PELIPPER, @@ -64296,6 +64412,8 @@ export const tmSpecies: TmSpecies = { Species.WALREIN, Species.RELICANTH, Species.LUVDISC, + Species.LATIAS, + Species.LATIOS, Species.KYOGRE, Species.PIPLUP, Species.PRINPLUP, @@ -64407,11 +64525,13 @@ export const tmSpecies: TmSpecies = { Species.ONIX, Species.HYPNO, Species.LICKITUNG, + Species.RHYHORN, Species.RHYDON, Species.LAPRAS, Species.SNORLAX, Species.DRAGONITE, Species.MEW, + Species.MEGANIUM, Species.SUDOWOODO, Species.QUAGSIRE, Species.FORRETRESS, @@ -64445,6 +64565,8 @@ export const tmSpecies: TmSpecies = { Species.REGISTEEL, Species.GROUDON, Species.TORTERRA, + Species.RAMPARDOS, + Species.BASTIODON, Species.BRONZONG, Species.HIPPOPOTAS, Species.HIPPOWDON, @@ -64459,6 +64581,7 @@ export const tmSpecies: TmSpecies = { Species.HEATRAN, Species.REGIGIGAS, Species.ARCEUS, + Species.EMBOAR, Species.ROGGENROLA, Species.BOLDORE, Species.GIGALITH, @@ -64471,6 +64594,7 @@ export const tmSpecies: TmSpecies = { Species.CUBCHOO, Species.BEARTIC, Species.GOLURK, + Species.COBALION, Species.RESHIRAM, Species.ZEKROM, Species.KYUREM, From 413f2b80c8ba5bc181c603cd7ae45c5b40ab21f8 Mon Sep 17 00:00:00 2001 From: AJ Fontaine <36677462+Fontbane@users.noreply.github.com> Date: Fri, 15 Nov 2024 14:26:58 -0500 Subject: [PATCH 61/75] [Balance] Increase Gimmighoul's evo counter more with Big Nugget/Relic Gold (#4856) * Increase Gimmighoul's evo counter more with Big Nugget/Relic Gold * Update src/modifier/modifier.ts Co-authored-by: Moka <54149968+MokaStitcher@users.noreply.github.com> --------- Co-authored-by: Moka <54149968+MokaStitcher@users.noreply.github.com> --- src/modifier/modifier.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index ac8dc556b98..6b449c38ada 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -2818,7 +2818,7 @@ export class MoneyRewardModifier extends ConsumableModifier { battleScene.getPlayerParty().map(p => { if (p.species?.speciesId === Species.GIMMIGHOUL || p.fusionSpecies?.speciesId === Species.GIMMIGHOUL) { - p.evoCounter ? p.evoCounter++ : p.evoCounter = 1; + p.evoCounter ? p.evoCounter += Math.min(Math.floor(this.moneyMultiplier), 3) : p.evoCounter = Math.min(Math.floor(this.moneyMultiplier), 3); const modifier = getModifierType(modifierTypes.EVOLUTION_TRACKER_GIMMIGHOUL).newModifier(p) as EvoTrackerModifier; battleScene.addModifier(modifier); } From 360a897ed2f53a0f54dc96f3a16fc5bade166956 Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Fri, 15 Nov 2024 12:11:46 -0800 Subject: [PATCH 62/75] [Balance] Endure Tokens only endure one hit (#4875) * Endure Tokens only endure one hit * Add tests for Endure * Update docs --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/data/battler-tags.ts | 13 +++++-- src/enums/battler-tag-type.ts | 1 + src/field/pokemon.ts | 2 ++ src/modifier/modifier.ts | 6 ++-- src/test/moves/endure.test.ts | 65 +++++++++++++++++++++++++++++++++++ 5 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 src/test/moves/endure.test.ts diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 28ab5ff2a4f..ce25b56157c 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -1502,9 +1502,14 @@ export class ContactBurnProtectedTag extends DamageProtectedTag { } } +/** + * `BattlerTag` class for effects that cause the affected Pokemon to survive lethal attacks at 1 HP. + * Used for {@link https://bulbapedia.bulbagarden.net/wiki/Endure_(move) | Endure} and + * Endure Tokens. + */ export class EnduringTag extends BattlerTag { - constructor(sourceMove: Moves) { - super(BattlerTagType.ENDURING, BattlerTagLapseType.TURN_END, 0, sourceMove); + constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType, sourceMove: Moves) { + super(tagType, lapseType, 0, sourceMove); } onAdd(pokemon: Pokemon): void { @@ -3009,7 +3014,9 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source case BattlerTagType.BURNING_BULWARK: return new ContactBurnProtectedTag(sourceMove); case BattlerTagType.ENDURING: - return new EnduringTag(sourceMove); + return new EnduringTag(tagType, BattlerTagLapseType.TURN_END, sourceMove); + case BattlerTagType.ENDURE_TOKEN: + return new EnduringTag(tagType, BattlerTagLapseType.AFTER_HIT, sourceMove); case BattlerTagType.STURDY: return new SturdyTag(sourceMove); case BattlerTagType.PERISH_SONG: diff --git a/src/enums/battler-tag-type.ts b/src/enums/battler-tag-type.ts index b2bbc1e6189..bb969386630 100644 --- a/src/enums/battler-tag-type.ts +++ b/src/enums/battler-tag-type.ts @@ -92,4 +92,5 @@ export enum BattlerTagType { COMMANDED = "COMMANDED", GRUDGE = "GRUDGE", PSYCHO_SHIFT = "PSYCHO_SHIFT", + ENDURE_TOKEN = "ENDURE_TOKEN", } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 30d1aceea4b..07a958fe27b 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -2955,6 +2955,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { surviveDamage.value = this.lapseTag(BattlerTagType.ENDURING); } else if (this.hp > 1 && this.getTag(BattlerTagType.STURDY)) { surviveDamage.value = this.lapseTag(BattlerTagType.STURDY); + } else if (this.hp >= 1 && this.getTag(BattlerTagType.ENDURE_TOKEN)) { + surviveDamage.value = this.lapseTag(BattlerTagType.ENDURE_TOKEN); } if (!surviveDamage.value) { this.scene.applyModifiers(SurviveDamageModifier, this.isPlayer(), this, surviveDamage); diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 6b449c38ada..4e59d6c01f0 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -3647,8 +3647,8 @@ export class EnemyEndureChanceModifier extends EnemyPersistentModifier { } /** - * Applies {@linkcode EnemyEndureChanceModifier} - * @param target {@linkcode Pokemon} to apply the {@linkcode BattlerTagType.ENDURING} chance to + * Applies a chance of enduring a lethal hit of an attack + * @param target the {@linkcode Pokemon} to apply the {@linkcode BattlerTagType.ENDURING} chance to * @returns `true` if {@linkcode Pokemon} endured */ override apply(target: Pokemon): boolean { @@ -3656,7 +3656,7 @@ export class EnemyEndureChanceModifier extends EnemyPersistentModifier { return false; } - target.addTag(BattlerTagType.ENDURING, 1); + target.addTag(BattlerTagType.ENDURE_TOKEN, 1); target.battleData.endured = true; diff --git a/src/test/moves/endure.test.ts b/src/test/moves/endure.test.ts new file mode 100644 index 00000000000..bde5a26f68e --- /dev/null +++ b/src/test/moves/endure.test.ts @@ -0,0 +1,65 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Moves - Endure", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([ Moves.THUNDER, Moves.BULLET_SEED, Moves.TOXIC ]) + .ability(Abilities.SKILL_LINK) + .startingLevel(100) + .battleType("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.NO_GUARD) + .enemyMoveset(Moves.ENDURE); + }); + + it("should let the pokemon survive with 1 HP", async () => { + await game.classicMode.startBattle([ Species.ARCEUS ]); + + game.move.select(Moves.THUNDER); + await game.phaseInterceptor.to("BerryPhase"); + + expect(game.scene.getEnemyPokemon()!.hp).toBe(1); + }); + + it("should let the pokemon survive with 1 HP when hit with a multihit move", async () => { + await game.classicMode.startBattle([ Species.ARCEUS ]); + + game.move.select(Moves.BULLET_SEED); + await game.phaseInterceptor.to("BerryPhase"); + + expect(game.scene.getEnemyPokemon()!.hp).toBe(1); + }); + + it("shouldn't prevent fainting from indirect damage", async () => { + game.override.enemyLevel(100); + await game.classicMode.startBattle([ Species.ARCEUS ]); + + const enemy = game.scene.getEnemyPokemon()!; + enemy.hp = 2; + + game.move.select(Moves.TOXIC); + await game.phaseInterceptor.to("VictoryPhase"); + + expect(enemy.isFainted()).toBe(true); + }); +}); From 77b94bf45d9b3b92d44fb2c27936a4fd2d8cf390 Mon Sep 17 00:00:00 2001 From: Moka <54149968+MokaStitcher@users.noreply.github.com> Date: Sat, 16 Nov 2024 17:46:02 +0100 Subject: [PATCH 63/75] bump version to 1.2.0 and update locale submodule to latest commit (#4884) --- package-lock.json | 4 ++-- package.json | 2 +- public/locales | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9e512884922..792720200a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pokemon-rogue-battle", - "version": "1.1.6", + "version": "1.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pokemon-rogue-battle", - "version": "1.1.6", + "version": "1.2.0", "hasInstallScript": true, "dependencies": { "@material/material-color-utilities": "^0.2.7", diff --git a/package.json b/package.json index f106fb1a773..3c65fe1a8b9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pokemon-rogue-battle", "private": true, - "version": "1.1.6", + "version": "1.2.0", "type": "module", "scripts": { "start": "vite", diff --git a/public/locales b/public/locales index 5775faa6b31..ed1b1df4776 160000 --- a/public/locales +++ b/public/locales @@ -1 +1 @@ -Subproject commit 5775faa6b3184082df73f6cdb96b253ea7dae3fe +Subproject commit ed1b1df4776ccd4330e8ac1d2f44de611d04c2bc From 4aff2ffa1d4bfe82494b3489f21e46b6a88adc6a Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Sat, 16 Nov 2024 15:30:47 -0800 Subject: [PATCH 64/75] [Dev] Sessions will now sync with the server at the start of every 5 waves (#4808) * Replaced conditional with `true` so that sync-to-server occurs at the start of every wave. * Update src/phases/encounter-phase.ts Co-authored-by: Frederico Santos * Fixed errors from previous commit. * Revised condition to include the first wave of a run. * Apply suggestions from code review Co-authored-by: Moka <54149968+MokaStitcher@users.noreply.github.com> --------- Co-authored-by: frutescens Co-authored-by: Frederico Santos Co-authored-by: Moka <54149968+MokaStitcher@users.noreply.github.com> --- src/phases/encounter-phase.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/phases/encounter-phase.ts b/src/phases/encounter-phase.ts index fc022ab9647..e58500c934e 100644 --- a/src/phases/encounter-phase.ts +++ b/src/phases/encounter-phase.ts @@ -225,7 +225,8 @@ export class EncounterPhase extends BattlePhase { this.scene.ui.setMode(Mode.MESSAGE).then(() => { if (!this.loaded) { this.trySetWeatherIfNewBiome(); // Set weather before session gets saved - this.scene.gameData.saveAll(this.scene, true, battle.waveIndex % 10 === 1 || (this.scene.lastSavePlayTime ?? 0) >= 300).then(success => { + // Game syncs to server on waves X1 and X6 (As of 1.2.0) + this.scene.gameData.saveAll(this.scene, true, battle.waveIndex % 5 === 1 || (this.scene.lastSavePlayTime ?? 0) >= 300).then(success => { this.scene.disableMenu = false; if (!success) { return this.scene.reset(true); From c22b48f9032c2c5930abcc62fe2a593794814a96 Mon Sep 17 00:00:00 2001 From: "Amani H." <109637146+xsn34kzx@users.noreply.github.com> Date: Sat, 16 Nov 2024 18:31:28 -0500 Subject: [PATCH 65/75] [P1] Fix System Data Conversion Failure 3 (#4866) * [P1] Fix System Data Conversion Failure 3 * Use `isNullOrUndefined`, Clean Up Imports * fix pre candy update save data migration for candy * fix pre candy update save data migration for candy part 2... --------- Co-authored-by: Moka --- src/system/game-data.ts | 6 +++--- .../version_migration/versions/v1_0_4.ts | 21 +++++++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 4d01ae9998a..70b0fadf0b0 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -506,9 +506,9 @@ export class GameData { const starterIds = Object.keys(this.starterData).map(s => parseInt(s) as Species); for (const s of starterIds) { - this.starterData[s].candyCount += this.dexData[s].caughtCount; - this.starterData[s].candyCount += this.dexData[s].hatchedCount * 2; - if (this.dexData[s].caughtAttr & DexAttr.SHINY) { + this.starterData[s].candyCount += systemData.dexData[s].caughtCount; + this.starterData[s].candyCount += systemData.dexData[s].hatchedCount * 2; + if (systemData.dexData[s].caughtAttr & DexAttr.SHINY) { this.starterData[s].candyCount += 4; } } diff --git a/src/system/version_migration/versions/v1_0_4.ts b/src/system/version_migration/versions/v1_0_4.ts index f16b6bcb6bb..d6e5baf0c84 100644 --- a/src/system/version_migration/versions/v1_0_4.ts +++ b/src/system/version_migration/versions/v1_0_4.ts @@ -1,6 +1,7 @@ -import { SettingKeys } from "../../settings/settings"; -import { AbilityAttr, defaultStarterSpecies, DexAttr, SystemSaveData, SessionSaveData } from "../../game-data"; -import { allSpecies } from "../../../data/pokemon-species"; +import { SettingKeys } from "#app/system/settings/settings"; +import { AbilityAttr, defaultStarterSpecies, DexAttr, SystemSaveData, SessionSaveData } from "#app/system/game-data"; +import { allSpecies } from "#app/data/pokemon-species"; +import { isNullOrUndefined } from "#app/utils"; export const systemMigrators = [ /** @@ -46,12 +47,14 @@ export const systemMigrators = [ * @param data {@linkcode SystemSaveData} */ function fixStarterData(data: SystemSaveData) { - for (const starterId of defaultStarterSpecies) { - if (data.starterData[starterId]?.abilityAttr) { - data.starterData[starterId].abilityAttr |= AbilityAttr.ABILITY_1; - } - if (data.dexData[starterId]?.caughtAttr) { - data.dexData[starterId].caughtAttr |= DexAttr.FEMALE; + if (!isNullOrUndefined(data.starterData)) { + for (const starterId of defaultStarterSpecies) { + if (data.starterData[starterId]?.abilityAttr) { + data.starterData[starterId].abilityAttr |= AbilityAttr.ABILITY_1; + } + if (data.dexData[starterId]?.caughtAttr) { + data.dexData[starterId].caughtAttr |= DexAttr.FEMALE; + } } } } From c2afac8b02a6ca793263c68dc5a93bf10386b7bc Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Sat, 16 Nov 2024 15:32:05 -0800 Subject: [PATCH 66/75] [Bug] Moved code preventing MBH's transfer to post modifier generation (#4858) * Moved code preventing MBH's transfer to after enemy modifiers were generated. * Removed unnecessary ! * Removed unnecessary ? * Created a new enum and functions for retrieving final bosses. * Moved isBattleClassicFinalBoss to game-mode.ts and reverted battle.ts * Preventing item transfer with tryTransferModifier instead * Added filtering to modifier-retrieve methods. * Revised logic in tryTransferHeldItemModifier * Adding what works to the game even though it's not the best. * Added comments * Removing past changes to files. * Added check for Classic Final Boss. --------- Co-authored-by: frutescens --- src/game-mode.ts | 7 +++++++ src/phases/encounter-phase.ts | 13 +++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/game-mode.ts b/src/game-mode.ts index 0f997bf651e..3f12c5b056e 100644 --- a/src/game-mode.ts +++ b/src/game-mode.ts @@ -230,6 +230,13 @@ export class GameMode implements GameModeConfig { return waveIndex % 10 === 0; } + /** + * @returns `true` if the current battle is against classic mode's final boss + */ + isBattleClassicFinalBoss(waveIndex: number): boolean { + return (this.modeId === GameModes.CLASSIC || this.modeId === GameModes.CHALLENGE) && this.isWaveFinal(waveIndex); + } + /** * Every 50 waves of an Endless mode is a boss * At this time it is paradox pokemon diff --git a/src/phases/encounter-phase.ts b/src/phases/encounter-phase.ts index e58500c934e..03126ba81bb 100644 --- a/src/phases/encounter-phase.ts +++ b/src/phases/encounter-phase.ts @@ -141,10 +141,6 @@ export class EncounterPhase extends BattlePhase { } else if (!(battle.waveIndex % 1000)) { enemyPokemon.formIndex = 1; enemyPokemon.updateScale(); - const bossMBH = this.scene.findModifier(m => m instanceof TurnHeldItemTransferModifier && m.pokemonId === enemyPokemon.id, false) as TurnHeldItemTransferModifier; - this.scene.removeModifier(bossMBH!); - bossMBH?.setTransferrableFalse(); - this.scene.addEnemyModifier(bossMBH!); } } @@ -443,6 +439,15 @@ export class EncounterPhase extends BattlePhase { if (enemyPokemon.isShiny()) { this.scene.unshiftPhase(new ShinySparklePhase(this.scene, BattlerIndex.ENEMY + e)); } + /** This sets Eternatus' held item to be untransferrable, preventing it from being stolen */ + if (enemyPokemon.species.speciesId === Species.ETERNATUS && (this.scene.gameMode.isBattleClassicFinalBoss(this.scene.currentBattle.waveIndex) || this.scene.gameMode.isEndlessMajorBoss(this.scene.currentBattle.waveIndex))) { + const enemyMBH = this.scene.findModifier(m => m instanceof TurnHeldItemTransferModifier, false) as TurnHeldItemTransferModifier; + if (enemyMBH) { + this.scene.removeModifier(enemyMBH, true); + enemyMBH.setTransferrableFalse(); + this.scene.addEnemyModifier(enemyMBH); + } + } }); if (![ BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER ].includes(this.scene.currentBattle.battleType)) { From 7dc4210f711e0cb92ac668b9a217561731b2e83c Mon Sep 17 00:00:00 2001 From: Daniel Pochert Date: Sun, 17 Nov 2024 00:33:14 +0100 Subject: [PATCH 67/75] [Bug] fix training session encounter not applying nature correctly (#4801) * fix training session encounter not applying nature correctly * implement pokemon.setCustomNature + nature unlock utility method(s) * update doc --------- Co-authored-by: Moka <54149968+MokaStitcher@users.noreply.github.com> --- .../shady-vitamin-dealer-encounter.ts | 2 +- .../encounters/training-session-encounter.ts | 4 +-- src/field/pokemon.ts | 5 ++++ src/modifier/modifier.ts | 12 +++------ src/system/game-data.ts | 26 +++++++++++++++++++ 5 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts b/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts index 798e85868f6..3f1ace47b0f 100644 --- a/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts +++ b/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts @@ -138,7 +138,7 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter = newNature = randSeedInt(25) as Nature; } - chosenPokemon.customPokemonData.nature = newNature; + chosenPokemon.setCustomNature(newNature); encounter.setDialogueToken("newNature", getNatureName(newNature)); queueEncounterMessage(scene, `${namespace}:cheap_side_effects`); setEncounterExp(scene, [ chosenPokemon.id ], 100); diff --git a/src/data/mystery-encounters/encounters/training-session-encounter.ts b/src/data/mystery-encounters/encounters/training-session-encounter.ts index 4a0a91bf751..725c4ba79eb 100644 --- a/src/data/mystery-encounters/encounters/training-session-encounter.ts +++ b/src/data/mystery-encounters/encounters/training-session-encounter.ts @@ -226,8 +226,8 @@ export const TrainingSessionEncounter: MysteryEncounter = const onBeforeRewardsPhase = () => { queueEncounterMessage(scene, `${namespace}:option.2.finished`); // Add the pokemon back to party with Nature change - playerPokemon.setNature(encounter.misc.chosenNature); - scene.gameData.setPokemonCaught(playerPokemon, false); + playerPokemon.setCustomNature(encounter.misc.chosenNature); + scene.gameData.unlockSpeciesNature(playerPokemon.species, encounter.misc.chosenNature); // Add pokemon and modifiers back scene.getPlayerParty().push(playerPokemon); diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 07a958fe27b..f9e7d7d1cad 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1072,6 +1072,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.calculateStats(); } + setCustomNature(nature: Nature): void { + this.customPokemonData.nature = nature; + this.calculateStats(); + } + generateNature(naturePool?: Nature[]): void { if (naturePool === undefined) { naturePool = Utils.getEnumValues(Nature); diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 4e59d6c01f0..bbd1763cd84 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -1,5 +1,5 @@ import type BattleScene from "#app/battle-scene"; -import { FusionSpeciesFormEvolution, pokemonEvolutions, pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions"; +import { FusionSpeciesFormEvolution, pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; import { getBerryEffectFunc, getBerryPredicate } from "#app/data/berry"; import { getLevelTotalExp } from "#app/data/exp"; import { allMoves } from "#app/data/move"; @@ -2197,14 +2197,8 @@ export class PokemonNatureChangeModifier extends ConsumablePokemonModifier { * @returns */ override apply(playerPokemon: PlayerPokemon): boolean { - playerPokemon.customPokemonData.nature = this.nature; - let speciesId = playerPokemon.species.speciesId; - playerPokemon.scene.gameData.dexData[speciesId].natureAttr |= 1 << (this.nature + 1); - - while (pokemonPrevolutions.hasOwnProperty(speciesId)) { - speciesId = pokemonPrevolutions[speciesId]; - playerPokemon.scene.gameData.dexData[speciesId].natureAttr |= 1 << (this.nature + 1); - } + playerPokemon.setCustomNature(this.nature); + playerPokemon.scene.gameData.unlockSpeciesNature(playerPokemon.species, this.nature); return true; } diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 70b0fadf0b0..3e3a6ce8f8b 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -1791,6 +1791,32 @@ export class GameData { }); } + /** + * Checks whether the root species of a given {@PokemonSpecies} has been unlocked in the dex + */ + isRootSpeciesUnlocked(species: PokemonSpecies): boolean { + return !!this.dexData[species.getRootSpeciesId()]?.caughtAttr; + } + + /** + * Unlocks the given {@linkcode Nature} for a {@linkcode PokemonSpecies} and its prevolutions. + * Will fail silently if root species has not been unlocked + */ + unlockSpeciesNature(species: PokemonSpecies, nature: Nature): void { + if (!this.isRootSpeciesUnlocked(species)) { + return; + } + + //recursively unlock nature for species and prevolutions + const _unlockSpeciesNature = (speciesId: Species) => { + this.dexData[speciesId].natureAttr |= 1 << (nature + 1); + if (pokemonPrevolutions.hasOwnProperty(speciesId)) { + _unlockSpeciesNature(pokemonPrevolutions[speciesId]); + } + }; + _unlockSpeciesNature(species.speciesId); + } + updateSpeciesDexIvs(speciesId: Species, ivs: integer[]): void { let dexEntry: DexEntry; do { From ae8efeedf8ca520f2beb17ca8093586de5775ca0 Mon Sep 17 00:00:00 2001 From: Moka <54149968+MokaStitcher@users.noreply.github.com> Date: Sun, 17 Nov 2024 00:34:14 +0100 Subject: [PATCH 68/75] [UI] Make ME text legible when using the legacy UI theme (#4847) --- .../utils/encounter-dialogue-utils.ts | 8 ++-- src/ui/mystery-encounter-ui-handler.ts | 4 +- src/ui/run-info-ui-handler.ts | 3 +- src/ui/text.ts | 37 ++++++++++++++++--- 4 files changed, 40 insertions(+), 12 deletions(-) diff --git a/src/data/mystery-encounters/utils/encounter-dialogue-utils.ts b/src/data/mystery-encounters/utils/encounter-dialogue-utils.ts index c4d5e47cb05..acaa7c6244f 100644 --- a/src/data/mystery-encounters/utils/encounter-dialogue-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-dialogue-utils.ts @@ -7,22 +7,22 @@ import i18next from "i18next"; /** * Will inject all relevant dialogue tokens that exist in the {@linkcode BattleScene.currentBattle.mysteryEncounter.dialogueTokens}, into i18n text. * Also adds BBCodeText fragments for colored text, if applicable - * @param scene * @param keyOrString * @param primaryStyle Can define a text style to be applied to the entire string. Must be defined for BBCodeText styles to be applied correctly - * @param uiTheme */ -export function getEncounterText(scene: BattleScene, keyOrString?: string, primaryStyle?: TextStyle, uiTheme: UiTheme = UiTheme.DEFAULT): string | null { +export function getEncounterText(scene: BattleScene, keyOrString?: string, primaryStyle?: TextStyle): string | null { if (isNullOrUndefined(keyOrString)) { return null; } + const uiTheme = scene.uiTheme ?? UiTheme.DEFAULT; + let textString: string | null = getTextWithDialogueTokens(scene, keyOrString); // Can only color the text if a Primary Style is defined // primaryStyle is applied to all text that does not have its own specified style if (primaryStyle && textString) { - textString = getTextWithColors(textString, primaryStyle, uiTheme); + textString = getTextWithColors(textString, primaryStyle, uiTheme, true); } return textString; diff --git a/src/ui/mystery-encounter-ui-handler.ts b/src/ui/mystery-encounter-ui-handler.ts index b568f8b71de..cdb1c9024c5 100644 --- a/src/ui/mystery-encounter-ui-handler.ts +++ b/src/ui/mystery-encounter-ui-handler.ts @@ -369,9 +369,9 @@ export default class MysteryEncounterUiHandler extends UiHandler { let text: string | null; if (option.hasRequirements() && this.optionsMeetsReqs[i] && (option.optionMode === MysteryEncounterOptionMode.DEFAULT_OR_SPECIAL || option.optionMode === MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)) { // Options with special requirements that are met are automatically colored green - text = getEncounterText(this.scene, label, TextStyle.SUMMARY_GREEN); + text = getEncounterText(this.scene, label, TextStyle.ME_OPTION_SPECIAL); } else { - text = getEncounterText(this.scene, label, optionDialogue.style ? optionDialogue.style : TextStyle.WINDOW); + text = getEncounterText(this.scene, label, optionDialogue.style ? optionDialogue.style : TextStyle.ME_OPTION_DEFAULT); } if (text) { diff --git a/src/ui/run-info-ui-handler.ts b/src/ui/run-info-ui-handler.ts index 82d390016f7..ace9d956dd9 100644 --- a/src/ui/run-info-ui-handler.ts +++ b/src/ui/run-info-ui-handler.ts @@ -518,7 +518,8 @@ export default class RunInfoUiHandler extends UiHandler { const runTime = Utils.getPlayTimeString(this.runInfo.playTime); runInfoText.appendText(`${i18next.t("runHistory:runLength")}: ${runTime}`, false); const runMoney = Utils.formatMoney(this.scene.moneyFormat, this.runInfo.money); - runInfoText.appendText(`[color=${getTextColor(TextStyle.MONEY)}]${i18next.t("battleScene:moneyOwned", { formattedMoney : runMoney })}[/color]`); + const moneyTextColor = getTextColor(TextStyle.MONEY_WINDOW, false, this.scene.uiTheme); + runInfoText.appendText(`[color=${moneyTextColor}]${i18next.t("battleScene:moneyOwned", { formattedMoney : runMoney })}[/color]`); runInfoText.setPosition(7, 70); runInfoTextContainer.add(runInfoText); // Luck diff --git a/src/ui/text.ts b/src/ui/text.ts index 069aa8680fc..17ae02be9ef 100644 --- a/src/ui/text.ts +++ b/src/ui/text.ts @@ -22,7 +22,8 @@ export enum TextStyle { SUMMARY_GOLD, SUMMARY_GRAY, SUMMARY_GREEN, - MONEY, + MONEY, // Money default styling (pale yellow) + MONEY_WINDOW, // Money displayed in Windows (needs different colors based on theme) STATS_LABEL, STATS_VALUE, SETTINGS_VALUE, @@ -38,7 +39,9 @@ export enum TextStyle { MOVE_PP_EMPTY, SMALLER_WINDOW_ALT, BGM_BAR, - PERFECT_IV + PERFECT_IV, + ME_OPTION_DEFAULT, // Default style for choices in ME + ME_OPTION_SPECIAL, // Style for choices with special requirements in ME } export interface TextStyleOptions { @@ -139,6 +142,8 @@ export function getTextStyleOptions(style: TextStyle, uiTheme: UiTheme, extraSty case TextStyle.SUMMARY_GREEN: case TextStyle.WINDOW: case TextStyle.WINDOW_ALT: + case TextStyle.ME_OPTION_DEFAULT: + case TextStyle.ME_OPTION_SPECIAL: shadowXpos = 3; shadowYpos = 3; break; @@ -177,6 +182,7 @@ export function getTextStyleOptions(style: TextStyle, uiTheme: UiTheme, extraSty break; case TextStyle.BATTLE_INFO: case TextStyle.MONEY: + case TextStyle.MONEY_WINDOW: case TextStyle.TOOLTIP_TITLE: styleOptions.fontSize = defaultFontSize - 24; shadowXpos = 3.5; @@ -238,13 +244,22 @@ export function getBBCodeFrag(content: string, textStyle: TextStyle, uiTheme: Ui * - "red text" with TextStyle.SUMMARY_RED applied * @param content string with styling that need to be applied for BBCodeTextObject * @param primaryStyle Primary style is required in order to escape BBCode styling properly. - * @param uiTheme + * @param uiTheme the {@linkcode UiTheme} to get TextStyle for + * @param forWindow set to `true` if the text is to be displayed in a window ({@linkcode BattleScene.addWindow}) + * it will replace all instances of the default MONEY TextStyle by {@linkcode TextStyle.MONEY_WINDOW} */ -export function getTextWithColors(content: string, primaryStyle: TextStyle, uiTheme: UiTheme = UiTheme.DEFAULT): string { +export function getTextWithColors(content: string, primaryStyle: TextStyle, uiTheme: UiTheme, forWindow?: boolean): string { // Apply primary styling before anything else let text = getBBCodeFrag(content, primaryStyle, uiTheme) + "[/color][/shadow]"; const primaryStyleString = [ ...text.match(new RegExp(/\[color=[^\[]*\]\[shadow=[^\[]*\]/i))! ][0]; + /* For money text displayed in game windows, we can't use the default {@linkcode TextStyle.MONEY} + * or it will look wrong in legacy mode because of the different window background color + * So, for text to be displayed in windows replace all "@[MONEY]" with "@[MONEY_WINDOW]" */ + if (forWindow) { + text = text.replace(/@\[MONEY\]/g, (_substring: string) => "@[MONEY_WINDOW]"); + } + // Set custom colors text = text.replace(/@\[([^{]*)\]{([^}]*)}/gi, (substring, textStyle: string, textToColor: string) => { return "[/color][/shadow]" + getBBCodeFrag(textToColor, TextStyle[textStyle], uiTheme) + "[/color][/shadow]" + primaryStyleString; @@ -310,7 +325,12 @@ export function getTextColor(textStyle: TextStyle, shadow?: boolean, uiTheme: Ui return !shadow ? "#f89890" : "#984038"; case TextStyle.SUMMARY_GOLD: case TextStyle.MONEY: - return !shadow ? "#e8e8a8" : "#a0a060"; + return !shadow ? "#e8e8a8" : "#a0a060"; // Pale Yellow/Gold + case TextStyle.MONEY_WINDOW: + if (isLegacyTheme) { + return !shadow ? "#f8b050" : "#c07800"; // Gold + } + return !shadow ? "#e8e8a8" : "#a0a060"; // Pale Yellow/Gold case TextStyle.SETTINGS_LOCKED: case TextStyle.SUMMARY_GRAY: return !shadow ? "#a0a0a0" : "#636363"; @@ -332,6 +352,13 @@ export function getTextColor(textStyle: TextStyle, shadow?: boolean, uiTheme: Ui return !shadow ? "#484848" : "#d0d0c8"; case TextStyle.BGM_BAR: return !shadow ? "#f8f8f8" : "#6b5a73"; + case TextStyle.ME_OPTION_DEFAULT: + return !shadow ? "#f8f8f8" : "#6b5a73"; // White + case TextStyle.ME_OPTION_SPECIAL: + if (isLegacyTheme) { + return !shadow ? "#f8b050" : "#c07800"; // Gold + } + return !shadow ? "#78c850" : "#306850"; // Green } } From 07f08877c18a027b9ff6c473476796b3d57b992b Mon Sep 17 00:00:00 2001 From: PigeonBar <56974298+PigeonBar@users.noreply.github.com> Date: Sun, 17 Nov 2024 12:16:54 -0500 Subject: [PATCH 69/75] [Balance] Multi Lens damage reduction on fixed-damage moves (#4896) --- src/field/pokemon.ts | 4 ++++ src/modifier/modifier.ts | 16 +++++++++++---- src/test/abilities/parental_bond.test.ts | 2 +- src/test/items/multi_lens.test.ts | 25 ++++++++++++++++++++++-- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index f9e7d7d1cad..f14fc954c84 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -2622,6 +2622,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const fixedDamage = new Utils.IntegerHolder(0); applyMoveAttrs(FixedDamageAttr, source, this, move, fixedDamage); if (fixedDamage.value) { + const multiLensMultiplier = new Utils.NumberHolder(1); + source.scene.applyModifiers(PokemonMultiHitModifier, source.isPlayer(), source, move.id, null, multiLensMultiplier); + fixedDamage.value = Utils.toDmgValue(fixedDamage.value * multiLensMultiplier.value); + return { cancelled: false, result: HitResult.EFFECTIVE, diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index bbd1763cd84..5e5246269a3 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -2727,10 +2727,18 @@ export class PokemonMultiHitModifier extends PokemonHeldItemModifier { * Additional strikes beyond that are given a 0.25x damage multiplier */ private applyDamageModifier(pokemon: Pokemon, damageMultiplier: NumberHolder): boolean { - damageMultiplier.value = (pokemon.turnData.hitsLeft === pokemon.turnData.hitCount) - ? (1 - (0.25 * this.getStackCount())) - : 0.25; - return true; + if (pokemon.turnData.hitsLeft === pokemon.turnData.hitCount) { + // Reduce first hit by 25% for each stack count + damageMultiplier.value *= 1 - 0.25 * this.getStackCount(); + return true; + } else if (pokemon.turnData.hitCount - pokemon.turnData.hitsLeft !== this.getStackCount() + 1) { + // Deal 25% damage for each remaining Multi Lens hit + damageMultiplier.value *= 0.25; + return true; + } else { + // An extra hit not caused by Multi Lens -- assume it is Parental Bond + return false; + } } getMaxHeldItemCount(pokemon: Pokemon): number { diff --git a/src/test/abilities/parental_bond.test.ts b/src/test/abilities/parental_bond.test.ts index 4189941a51e..10048a774cd 100644 --- a/src/test/abilities/parental_bond.test.ts +++ b/src/test/abilities/parental_bond.test.ts @@ -313,7 +313,7 @@ describe("Abilities - Parental Bond", () => { await game.phaseInterceptor.to("MoveEndPhase", false); - expect(enemyPokemon.hp).toBe(enemyStartingHp - 300); + expect(enemyPokemon.hp).toBe(enemyStartingHp - 200); } ); diff --git a/src/test/items/multi_lens.test.ts b/src/test/items/multi_lens.test.ts index d389ca70555..c5e60c9f9e5 100644 --- a/src/test/items/multi_lens.test.ts +++ b/src/test/items/multi_lens.test.ts @@ -32,8 +32,8 @@ describe("Items - Multi Lens", () => { .enemySpecies(Species.SNORLAX) .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH) - .startingLevel(100) - .enemyLevel(100); + .startingLevel(99) // Check for proper rounding on Seismic Toss damage reduction + .enemyLevel(99); }); it.each([ @@ -114,4 +114,25 @@ describe("Items - Multi Lens", () => { expect(magikarp.turnData.hitCount).toBe(2); }); + + it("should enhance fixed-damage moves while also applying damage reduction", async () => { + game.override.startingHeldItems([{ name: "MULTI_LENS", count: 1 }]) + .moveset(Moves.SEISMIC_TOSS); + + await game.classicMode.startBattle([ Species.MAGIKARP ]); + + const playerPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; + const spy = vi.spyOn(enemyPokemon, "getAttackDamage"); + + game.move.select(Moves.SEISMIC_TOSS); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + + await game.phaseInterceptor.to("MoveEndPhase"); + const damageResults = spy.mock.results.map(result => result.value?.damage); + + expect(damageResults).toHaveLength(2); + expect(damageResults[0]).toBe(Math.floor(playerPokemon.level * 0.75)); + expect(damageResults[1]).toBe(Math.floor(playerPokemon.level * 0.25)); + }); }); From 1867ac4a9e37a49389dd3db6da6c33806258eb77 Mon Sep 17 00:00:00 2001 From: "Amani H." <109637146+xsn34kzx@users.noreply.github.com> Date: Sun, 17 Nov 2024 12:34:41 -0500 Subject: [PATCH 70/75] [Dev] Minor Version Migration Tweaks (#4727) * [P3] Prevent Unintended ME Migration Application * Change Patch Value from 4 to 5 * Bump Game Version * Fix Imports, Use `isNullOrUndefined` --- .../version_migration/version_converter.ts | 2 +- .../version_migration/versions/v1_0_4.ts | 24 +++++++++++++++ .../version_migration/versions/v1_1_0.ts | 29 +------------------ 3 files changed, 26 insertions(+), 29 deletions(-) diff --git a/src/system/version_migration/version_converter.ts b/src/system/version_migration/version_converter.ts index e96afb5cbd4..d0c69dc3213 100644 --- a/src/system/version_migration/version_converter.ts +++ b/src/system/version_migration/version_converter.ts @@ -129,7 +129,7 @@ class SessionVersionConverter extends VersionConverter { if (curMajor === 1) { if (curMinor === 0) { - if (curPatch <= 4) { + if (curPatch <= 5) { console.log("Applying v1.0.4 session data migration!"); this.callMigrators(data, v1_0_4.sessionMigrators); } diff --git a/src/system/version_migration/versions/v1_0_4.ts b/src/system/version_migration/versions/v1_0_4.ts index d6e5baf0c84..95f0337ecdd 100644 --- a/src/system/version_migration/versions/v1_0_4.ts +++ b/src/system/version_migration/versions/v1_0_4.ts @@ -1,6 +1,7 @@ import { SettingKeys } from "#app/system/settings/settings"; import { AbilityAttr, defaultStarterSpecies, DexAttr, SystemSaveData, SessionSaveData } from "#app/system/game-data"; import { allSpecies } from "#app/data/pokemon-species"; +import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import { isNullOrUndefined } from "#app/utils"; export const systemMigrators = [ @@ -134,5 +135,28 @@ export const sessionMigrators = [ m.className = "ResetNegativeStatStageModifier"; } }); + }, + /** + * Converts old Pokemon natureOverride and mysteryEncounterData + * to use the new conjoined {@linkcode Pokemon.customPokemonData} structure instead. + * @param data {@linkcode SessionSaveData} + */ + function migrateCustomPokemonDataAndNatureOverrides(data: SessionSaveData) { + // Fix Pokemon nature overrides and custom data migration + data.party.forEach(pokemon => { + if (pokemon["mysteryEncounterPokemonData"]) { + pokemon.customPokemonData = new CustomPokemonData(pokemon["mysteryEncounterPokemonData"]); + pokemon["mysteryEncounterPokemonData"] = null; + } + if (pokemon["fusionMysteryEncounterPokemonData"]) { + pokemon.fusionCustomPokemonData = new CustomPokemonData(pokemon["fusionMysteryEncounterPokemonData"]); + pokemon["fusionMysteryEncounterPokemonData"] = null; + } + pokemon.customPokemonData = pokemon.customPokemonData ?? new CustomPokemonData(); + if (!isNullOrUndefined(pokemon["natureOverride"]) && pokemon["natureOverride"] >= 0) { + pokemon.customPokemonData.nature = pokemon["natureOverride"]; + pokemon["natureOverride"] = -1; + } + }); } ] as const; diff --git a/src/system/version_migration/versions/v1_1_0.ts b/src/system/version_migration/versions/v1_1_0.ts index aac554c4531..5d6247aeaa2 100644 --- a/src/system/version_migration/versions/v1_1_0.ts +++ b/src/system/version_migration/versions/v1_1_0.ts @@ -1,32 +1,5 @@ -import { SessionSaveData } from "../../game-data"; -import { CustomPokemonData } from "#app/data/custom-pokemon-data"; - export const systemMigrators = [] as const; export const settingsMigrators = [] as const; -export const sessionMigrators = [ - /** - * Converts old Pokemon natureOverride and mysteryEncounterData - * to use the new conjoined {@linkcode Pokemon.customPokemonData} structure instead. - * @param data {@linkcode SessionSaveData} - */ - function migrateCustomPokemonDataAndNatureOverrides(data: SessionSaveData) { - // Fix Pokemon nature overrides and custom data migration - data.party.forEach(pokemon => { - if (pokemon["mysteryEncounterPokemonData"]) { - pokemon.customPokemonData = new CustomPokemonData(pokemon["mysteryEncounterPokemonData"]); - pokemon["mysteryEncounterPokemonData"] = null; - } - if (pokemon["fusionMysteryEncounterPokemonData"]) { - pokemon.fusionCustomPokemonData = new CustomPokemonData(pokemon["fusionMysteryEncounterPokemonData"]); - pokemon["fusionMysteryEncounterPokemonData"] = null; - } - pokemon.customPokemonData = pokemon.customPokemonData ?? new CustomPokemonData(); - if (pokemon["natureOverride"] && pokemon["natureOverride"] >= 0) { - pokemon.customPokemonData.nature = pokemon["natureOverride"]; - pokemon["natureOverride"] = -1; - } - }); - } -] as const; +export const sessionMigrators = [] as const; From 6b58d51ea2d75b29341526a3122659b5415f86ab Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Sun, 17 Nov 2024 12:19:23 -0800 Subject: [PATCH 71/75] Changed conditional to actually consider the wave index. (#4899) Co-authored-by: frutescens --- src/data/ability.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index b77b18947be..0572b041c95 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -4953,7 +4953,7 @@ class ForceSwitchOutHelper { * For wild Pokémon battles, the Pokémon will flee if the conditions are met (waveIndex and double battles). */ } else { - if (!pokemon.scene.currentBattle.waveIndex && pokemon.scene.currentBattle.waveIndex % 10 === 0) { + if (!pokemon.scene.currentBattle.waveIndex || pokemon.scene.currentBattle.waveIndex % 10 === 0) { return false; } From e825e308f9d24eafa0c6b7a0237b01b62863c631 Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Sun, 17 Nov 2024 13:22:11 -0800 Subject: [PATCH 72/75] [Test] Update wimp out test and comment (#4900) * Changed conditional to actually consider the wave index. * Added PigeonBar's test * Added check for MEs + Documentation * Apply suggestions from code review Co-authored-by: PigeonBar <56974298+PigeonBar@users.noreply.github.com> --------- Co-authored-by: frutescens Co-authored-by: PigeonBar <56974298+PigeonBar@users.noreply.github.com> --- src/data/ability.ts | 1 + src/test/abilities/wimp_out.test.ts | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/data/ability.ts b/src/data/ability.ts index 0572b041c95..1697c816902 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -4951,6 +4951,7 @@ class ForceSwitchOutHelper { } /** * For wild Pokémon battles, the Pokémon will flee if the conditions are met (waveIndex and double battles). + * It will not flee if it is a Mystery Encounter with fleeing disabled (checked in `getSwitchOutCondition()`) or if it is a wave 10x wild boss */ } else { if (!pokemon.scene.currentBattle.waveIndex || pokemon.scene.currentBattle.waveIndex % 10 === 0) { diff --git a/src/test/abilities/wimp_out.test.ts b/src/test/abilities/wimp_out.test.ts index df965fc340d..4283386b248 100644 --- a/src/test/abilities/wimp_out.test.ts +++ b/src/test/abilities/wimp_out.test.ts @@ -613,4 +613,23 @@ describe("Abilities - Wimp Out", () => { confirmNoSwitch(); }); + + it("should not activate on wave X0 bosses", async () => { + game.override.enemyAbility(Abilities.WIMP_OUT) + .startingLevel(5850) + .startingWave(10); + await game.classicMode.startBattle([ Species.GOLISOPOD ]); + + const enemyPokemon = game.scene.getEnemyPokemon()!; + + // Use 2 turns of False Swipe due to opponent's health bar shield + game.move.select(Moves.FALSE_SWIPE); + await game.toNextTurn(); + game.move.select(Moves.FALSE_SWIPE); + await game.toNextTurn(); + + const isVisible = enemyPokemon.visible; + const hasFled = enemyPokemon.switchOutStatus; + expect(isVisible && !hasFled).toBe(true); + }); }); From 33d8db73efa74dbb7fe79468eea6aefe20cce3d4 Mon Sep 17 00:00:00 2001 From: Moka <54149968+MokaStitcher@users.noreply.github.com> Date: Sun, 17 Nov 2024 22:35:14 +0100 Subject: [PATCH 73/75] [P1] Fix crash caused by removing arena tags on a new catch (#4888) --- src/field/pokemon.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index f14fc954c84..1dc4972af79 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -3101,10 +3101,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } lapseTag(tagType: BattlerTagType): boolean { - const tags = this.summonData?.tags; - if (isNullOrUndefined(tags)) { + if (!this.summonData) { return false; } + const tags = this.summonData.tags; const tag = tags.find(t => t.tagType === tagType); if (tag && !(tag.lapse(this, BattlerTagLapseType.CUSTOM))) { tag.onRemove(this); @@ -3114,6 +3114,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } lapseTags(lapseType: BattlerTagLapseType): void { + if (!this.summonData) { + return; + } const tags = this.summonData.tags; tags.filter(t => lapseType === BattlerTagLapseType.FAINT || ((t.lapseTypes.some(lType => lType === lapseType)) && !(t.lapse(this, lapseType)))).forEach(t => { t.onRemove(this); @@ -3122,6 +3125,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } removeTag(tagType: BattlerTagType): boolean { + if (!this.summonData) { + return false; + } const tags = this.summonData.tags; const tag = tags.find(t => t.tagType === tagType); if (tag) { From dd904fe7827eb2695c5362f0864e32d58df10c6c Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sun, 17 Nov 2024 18:08:00 -0800 Subject: [PATCH 74/75] [Hotfix] Prevent crash if enemy Future Sight user is caught (#4905) --- package-lock.json | 4 ++-- package.json | 2 +- src/field/pokemon.ts | 7 +++++-- src/phases/move-effect-phase.ts | 10 +++++++--- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 792720200a9..22a55cdfa28 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pokemon-rogue-battle", - "version": "1.2.0", + "version": "1.2.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pokemon-rogue-battle", - "version": "1.2.0", + "version": "1.2.1", "hasInstallScript": true, "dependencies": { "@material/material-color-utilities": "^0.2.7", diff --git a/package.json b/package.json index 3c65fe1a8b9..5aaffc59de1 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pokemon-rogue-battle", "private": true, - "version": "1.2.0", + "version": "1.2.1", "type": "module", "scripts": { "start": "vite", diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 1dc4972af79..217d5fa699b 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -3243,11 +3243,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return null; } - getMoveHistory(): TurnMove[] { + public getMoveHistory(): TurnMove[] { return this.battleSummonData.moveHistory; } - pushMoveHistory(turnMove: TurnMove) { + public pushMoveHistory(turnMove: TurnMove): void { + if (!this.isOnField()) { + return; + } turnMove.turn = this.scene.currentBattle?.turn; this.getMoveHistory().push(turnMove); } diff --git a/src/phases/move-effect-phase.ts b/src/phases/move-effect-phase.ts index afc8dd0475d..3a609f850c6 100644 --- a/src/phases/move-effect-phase.ts +++ b/src/phases/move-effect-phase.ts @@ -92,8 +92,12 @@ export class MoveEffectPhase extends PokemonPhase { const isDelayedAttack = this.move.getMove().hasAttr(DelayedAttackAttr); /** If the user was somehow removed from the field and it's not a delayed attack, end this phase */ - if (!user.isOnField() && !isDelayedAttack) { - return super.end(); + if (!user.isOnField()) { + if (!isDelayedAttack) { + return super.end(); + } else { + user.resetTurnData(); + } } /** @@ -174,7 +178,7 @@ export class MoveEffectPhase extends PokemonPhase { const playOnEmptyField = this.scene.currentBattle?.mysteryEncounter?.hasBattleAnimationsWithoutTargets ?? false; // Move animation only needs one target - new MoveAnim(move.id as Moves, user, this.getFirstTarget()!.getBattlerIndex()!, playOnEmptyField).play(this.scene, move.hitsSubstitute(user, this.getFirstTarget()!), () => { + new MoveAnim(move.id as Moves, user, this.getFirstTarget()!.getBattlerIndex(), playOnEmptyField).play(this.scene, move.hitsSubstitute(user, this.getFirstTarget()!), () => { /** Has the move successfully hit a target (for damage) yet? */ let hasHit: boolean = false; for (const target of targets) { From 0c920ba195c8fa8470694f5a1f4b3157438aa256 Mon Sep 17 00:00:00 2001 From: Moka <54149968+MokaStitcher@users.noreply.github.com> Date: Mon, 18 Nov 2024 19:41:24 +0100 Subject: [PATCH 75/75] [Hotfix] Prevent more Future Sight crash with new catches (#4910) --- package-lock.json | 4 ++-- package.json | 2 +- src/phases/move-effect-phase.ts | 8 ++++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 22a55cdfa28..9d6e2440f44 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pokemon-rogue-battle", - "version": "1.2.1", + "version": "1.2.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pokemon-rogue-battle", - "version": "1.2.1", + "version": "1.2.2", "hasInstallScript": true, "dependencies": { "@material/material-color-utilities": "^0.2.7", diff --git a/package.json b/package.json index 5aaffc59de1..ef2d4938087 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pokemon-rogue-battle", "private": true, - "version": "1.2.1", + "version": "1.2.2", "type": "module", "scripts": { "start": "vite", diff --git a/src/phases/move-effect-phase.ts b/src/phases/move-effect-phase.ts index 3a609f850c6..f7a9b22c396 100644 --- a/src/phases/move-effect-phase.ts +++ b/src/phases/move-effect-phase.ts @@ -96,6 +96,14 @@ export class MoveEffectPhase extends PokemonPhase { if (!isDelayedAttack) { return super.end(); } else { + if (!user.scene) { + /** + * This happens if the Pokemon that used the delayed attack gets caught and released + * on the turn the attack would have triggered. Having access to the global scene + * in the future may solve this entirely, so for now we just cancel the hit + */ + return super.end(); + } user.resetTurnData(); } }