From b7fd719de86aec11e9f28918d939ef65af62061a Mon Sep 17 00:00:00 2001 From: frutescens Date: Tue, 12 Nov 2024 13:45:20 -0800 Subject: [PATCH 01/12] Moved code preventing MBH's transfer to after enemy modifiers were generated. --- src/phases/encounter-phase.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/phases/encounter-phase.ts b/src/phases/encounter-phase.ts index fc022ab9647..42a172ae00e 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!); } } @@ -220,6 +216,18 @@ export class EncounterPhase extends BattlePhase { if (!this.loaded && battle.battleType !== BattleType.MYSTERY_ENCOUNTER) { regenerateModifierPoolThresholds(this.scene.getEnemyField(), battle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD); this.scene.generateEnemyModifiers(); + // This checks if the current battle is an Endless E-Max battle/Classic final boss and sets the MBH held by the boss to untransferrable + if (this.scene.currentBattle.waveIndex % 1000 || battle.battleSpec === BattleSpec.FINAL_BOSS) { + const enemyPokemon = this.scene.getEnemyPokemon(); + if (enemyPokemon) { + const bossMBH = this.scene.findModifier(m => m instanceof TurnHeldItemTransferModifier && m.pokemonId === enemyPokemon.id, false) as TurnHeldItemTransferModifier; + if (bossMBH) { + this.scene.removeModifier(bossMBH!); + bossMBH?.setTransferrableFalse(); + this.scene.addEnemyModifier(bossMBH!); + } + } + } } this.scene.ui.setMode(Mode.MESSAGE).then(() => { From 8cd6b39bac893db3ce77b4a2d7332baf7199c768 Mon Sep 17 00:00:00 2001 From: frutescens Date: Tue, 12 Nov 2024 15:16:43 -0800 Subject: [PATCH 02/12] Removed unnecessary ! --- src/phases/encounter-phase.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/phases/encounter-phase.ts b/src/phases/encounter-phase.ts index 42a172ae00e..f4b4ef1e811 100644 --- a/src/phases/encounter-phase.ts +++ b/src/phases/encounter-phase.ts @@ -222,9 +222,9 @@ export class EncounterPhase extends BattlePhase { if (enemyPokemon) { const bossMBH = this.scene.findModifier(m => m instanceof TurnHeldItemTransferModifier && m.pokemonId === enemyPokemon.id, false) as TurnHeldItemTransferModifier; if (bossMBH) { - this.scene.removeModifier(bossMBH!); + this.scene.removeModifier(bossMBH); bossMBH?.setTransferrableFalse(); - this.scene.addEnemyModifier(bossMBH!); + this.scene.addEnemyModifier(bossMBH); } } } From c983027adbd97bb0003ba530a7c8b339d8482197 Mon Sep 17 00:00:00 2001 From: frutescens Date: Tue, 12 Nov 2024 15:17:42 -0800 Subject: [PATCH 03/12] Removed unnecessary ? --- src/phases/encounter-phase.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/phases/encounter-phase.ts b/src/phases/encounter-phase.ts index f4b4ef1e811..85eaffc3ecb 100644 --- a/src/phases/encounter-phase.ts +++ b/src/phases/encounter-phase.ts @@ -223,7 +223,7 @@ export class EncounterPhase extends BattlePhase { const bossMBH = this.scene.findModifier(m => m instanceof TurnHeldItemTransferModifier && m.pokemonId === enemyPokemon.id, false) as TurnHeldItemTransferModifier; if (bossMBH) { this.scene.removeModifier(bossMBH); - bossMBH?.setTransferrableFalse(); + bossMBH.setTransferrableFalse(); this.scene.addEnemyModifier(bossMBH); } } From 8bd36a73fd05c3dd55156a5b28b649d58fc35700 Mon Sep 17 00:00:00 2001 From: frutescens Date: Tue, 12 Nov 2024 16:01:06 -0800 Subject: [PATCH 04/12] Created a new enum and functions for retrieving final bosses. --- src/battle.ts | 39 ++++++++++++++++++++++++++++++++--- src/phases/encounter-phase.ts | 4 ++-- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/battle.ts b/src/battle.ts index 75f0dff2534..77aeaca0cac 100644 --- a/src/battle.ts +++ b/src/battle.ts @@ -2,7 +2,7 @@ import BattleScene from "./battle-scene"; import { Command } from "./ui/command-ui-handler"; import * as Utils from "./utils"; import Trainer, { TrainerVariant } from "./field/trainer"; -import { GameMode } from "./game-mode"; +import { GameMode, GameModes } from "./game-mode"; import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier"; import { PokeballType } from "#enums/pokeball"; import { trainerConfigs } from "#app/data/trainer-config"; @@ -28,6 +28,13 @@ export enum ClassicFixedBossWaves { EVIL_BOSS_2 = 165, } +export enum EndlessBossType { + STANDARD = 50, + ETERNATUS = 250, + ETERNAMAX = 1000, + NONE +} + export enum BattleType { WILD, TRAINER, @@ -438,6 +445,32 @@ export default class Battle { isBattleMysteryEncounter(): boolean { return this.battleType === BattleType.MYSTERY_ENCOUNTER; } + + /** + * @returns `true` if the current battle is against classic mode's final boss + */ + isBattleClassicFinalBoss(): boolean { + return (this.gameMode.modeId === GameModes.CLASSIC || this.gameMode.modeId === GameModes.CHALLENGE) && this.waveIndex === 200; + } + + /** + * Uses modulos to determine what type of boss is faced by the player in Endless mode. + * @returns the type of Endless boss faced by the player {@linkcode EndlessBossType} + */ + getEndlessBossType(): EndlessBossType { + if (this.gameMode.modeId !== GameModes.ENDLESS && this.gameMode.modeId !== GameModes.SPLICED_ENDLESS) { + return EndlessBossType.NONE; + } else { + if (!(this.waveIndex % EndlessBossType.ETERNAMAX)) { + return EndlessBossType.ETERNAMAX; + } else if (!(this.waveIndex % EndlessBossType.ETERNATUS)) { + return EndlessBossType.ETERNATUS; + } else if (!(this.waveIndex % EndlessBossType.STANDARD)) { + return EndlessBossType.STANDARD; + } + return EndlessBossType.NONE; + } + } } export class FixedBattle extends Battle { @@ -499,7 +532,7 @@ export class FixedBattleConfig { * @param seedOffset the seed offset to use for the random generation of the trainer * @returns the generated trainer */ -function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], randomGender: boolean = false, seedOffset: number = 0): GetTrainerFunc { +function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], randomGender: boolean = false, seedOffset: number = 0): GetTrainerFunc { return (scene: BattleScene) => { const rand = Utils.randSeedInt(trainerPool.length); const trainerTypes: TrainerType[] = []; @@ -531,7 +564,7 @@ function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], rand } export interface FixedBattleConfigs { - [key: number]: FixedBattleConfig + [key: number]: FixedBattleConfig } /** * Youngster/Lass on 5 diff --git a/src/phases/encounter-phase.ts b/src/phases/encounter-phase.ts index 85eaffc3ecb..40aa61bc457 100644 --- a/src/phases/encounter-phase.ts +++ b/src/phases/encounter-phase.ts @@ -1,4 +1,4 @@ -import { BattlerIndex, BattleType } from "#app/battle"; +import { BattlerIndex, BattleType, EndlessBossType } from "#app/battle"; import BattleScene from "#app/battle-scene"; import { PLAYER_PARTY_MAX_SIZE } from "#app/constants"; import { applyAbAttrs, SyncEncounterNatureAbAttr } from "#app/data/ability"; @@ -217,7 +217,7 @@ export class EncounterPhase extends BattlePhase { regenerateModifierPoolThresholds(this.scene.getEnemyField(), battle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD); this.scene.generateEnemyModifiers(); // This checks if the current battle is an Endless E-Max battle/Classic final boss and sets the MBH held by the boss to untransferrable - if (this.scene.currentBattle.waveIndex % 1000 || battle.battleSpec === BattleSpec.FINAL_BOSS) { + if (this.scene.currentBattle.getEndlessBossType() === EndlessBossType.ETERNAMAX || battle.isBattleClassicFinalBoss()) { const enemyPokemon = this.scene.getEnemyPokemon(); if (enemyPokemon) { const bossMBH = this.scene.findModifier(m => m instanceof TurnHeldItemTransferModifier && m.pokemonId === enemyPokemon.id, false) as TurnHeldItemTransferModifier; From 639f958a6386345c28c2cbe5636429632e6e6ad8 Mon Sep 17 00:00:00 2001 From: frutescens Date: Tue, 12 Nov 2024 16:37:19 -0800 Subject: [PATCH 05/12] Moved isBattleClassicFinalBoss to game-mode.ts and reverted battle.ts --- src/battle.ts | 35 +---------------------------------- src/game-mode.ts | 7 +++++++ src/phases/encounter-phase.ts | 4 ++-- 3 files changed, 10 insertions(+), 36 deletions(-) diff --git a/src/battle.ts b/src/battle.ts index 77aeaca0cac..a5f1b830cc7 100644 --- a/src/battle.ts +++ b/src/battle.ts @@ -2,7 +2,7 @@ import BattleScene from "./battle-scene"; import { Command } from "./ui/command-ui-handler"; import * as Utils from "./utils"; import Trainer, { TrainerVariant } from "./field/trainer"; -import { GameMode, GameModes } from "./game-mode"; +import { GameMode } from "./game-mode"; import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier"; import { PokeballType } from "#enums/pokeball"; import { trainerConfigs } from "#app/data/trainer-config"; @@ -28,13 +28,6 @@ export enum ClassicFixedBossWaves { EVIL_BOSS_2 = 165, } -export enum EndlessBossType { - STANDARD = 50, - ETERNATUS = 250, - ETERNAMAX = 1000, - NONE -} - export enum BattleType { WILD, TRAINER, @@ -445,32 +438,6 @@ export default class Battle { isBattleMysteryEncounter(): boolean { return this.battleType === BattleType.MYSTERY_ENCOUNTER; } - - /** - * @returns `true` if the current battle is against classic mode's final boss - */ - isBattleClassicFinalBoss(): boolean { - return (this.gameMode.modeId === GameModes.CLASSIC || this.gameMode.modeId === GameModes.CHALLENGE) && this.waveIndex === 200; - } - - /** - * Uses modulos to determine what type of boss is faced by the player in Endless mode. - * @returns the type of Endless boss faced by the player {@linkcode EndlessBossType} - */ - getEndlessBossType(): EndlessBossType { - if (this.gameMode.modeId !== GameModes.ENDLESS && this.gameMode.modeId !== GameModes.SPLICED_ENDLESS) { - return EndlessBossType.NONE; - } else { - if (!(this.waveIndex % EndlessBossType.ETERNAMAX)) { - return EndlessBossType.ETERNAMAX; - } else if (!(this.waveIndex % EndlessBossType.ETERNATUS)) { - return EndlessBossType.ETERNATUS; - } else if (!(this.waveIndex % EndlessBossType.STANDARD)) { - return EndlessBossType.STANDARD; - } - return EndlessBossType.NONE; - } - } } export class FixedBattle extends Battle { diff --git a/src/game-mode.ts b/src/game-mode.ts index 8f1bb9356e6..fc9bde0da58 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 40aa61bc457..2e6b7e03c11 100644 --- a/src/phases/encounter-phase.ts +++ b/src/phases/encounter-phase.ts @@ -1,4 +1,4 @@ -import { BattlerIndex, BattleType, EndlessBossType } from "#app/battle"; +import { BattlerIndex, BattleType } from "#app/battle"; import BattleScene from "#app/battle-scene"; import { PLAYER_PARTY_MAX_SIZE } from "#app/constants"; import { applyAbAttrs, SyncEncounterNatureAbAttr } from "#app/data/ability"; @@ -217,7 +217,7 @@ export class EncounterPhase extends BattlePhase { regenerateModifierPoolThresholds(this.scene.getEnemyField(), battle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD); this.scene.generateEnemyModifiers(); // This checks if the current battle is an Endless E-Max battle/Classic final boss and sets the MBH held by the boss to untransferrable - if (this.scene.currentBattle.getEndlessBossType() === EndlessBossType.ETERNAMAX || battle.isBattleClassicFinalBoss()) { + if (this.scene.gameMode.isEndlessMajorBoss(this.scene.currentBattle.waveIndex) || this.scene.gameMode.isBattleClassicFinalBoss(this.scene.currentBattle.waveIndex)) { const enemyPokemon = this.scene.getEnemyPokemon(); if (enemyPokemon) { const bossMBH = this.scene.findModifier(m => m instanceof TurnHeldItemTransferModifier && m.pokemonId === enemyPokemon.id, false) as TurnHeldItemTransferModifier; From a144e93ce1491062c703125faa8dd4376ffcc874 Mon Sep 17 00:00:00 2001 From: frutescens Date: Tue, 12 Nov 2024 19:14:44 -0800 Subject: [PATCH 06/12] Preventing item transfer with tryTransferModifier instead --- src/battle-scene.ts | 2 ++ src/phases/encounter-phase.ts | 14 +------------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index c30ab2e2912..194876a2e49 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -2585,6 +2585,8 @@ export default class BattleScene extends SceneBase { const source = itemModifier.pokemonId ? itemModifier.getPokemon(target.scene) : null; const cancelled = new Utils.BooleanHolder(false); Utils.executeIf(!!source && source.isPlayer() !== target.isPlayer(), () => applyAbAttrs(BlockItemTheftAbAttr, source! /* checked in condition*/, cancelled)).then(() => { + // Prevents transfer of Mini Black Hole from opponent to player / player to opponent + cancelled.value = itemModifier instanceof TurnHeldItemTransferModifier ? true : false; if (cancelled.value) { return resolve(false); } diff --git a/src/phases/encounter-phase.ts b/src/phases/encounter-phase.ts index 2e6b7e03c11..9e2ab51fcdc 100644 --- a/src/phases/encounter-phase.ts +++ b/src/phases/encounter-phase.ts @@ -12,7 +12,7 @@ import { getRandomWeatherType } from "#app/data/weather"; import { EncounterPhaseEvent } from "#app/events/battle-scene"; import Pokemon, { FieldPosition } from "#app/field/pokemon"; import { getPokemonNameWithAffix } from "#app/messages"; -import { BoostBugSpawnModifier, IvScannerModifier, TurnHeldItemTransferModifier } from "#app/modifier/modifier"; +import { BoostBugSpawnModifier, IvScannerModifier } from "#app/modifier/modifier"; import { ModifierPoolType, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type"; import Overrides from "#app/overrides"; import { BattlePhase } from "#app/phases/battle-phase"; @@ -216,18 +216,6 @@ export class EncounterPhase extends BattlePhase { if (!this.loaded && battle.battleType !== BattleType.MYSTERY_ENCOUNTER) { regenerateModifierPoolThresholds(this.scene.getEnemyField(), battle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD); this.scene.generateEnemyModifiers(); - // This checks if the current battle is an Endless E-Max battle/Classic final boss and sets the MBH held by the boss to untransferrable - if (this.scene.gameMode.isEndlessMajorBoss(this.scene.currentBattle.waveIndex) || this.scene.gameMode.isBattleClassicFinalBoss(this.scene.currentBattle.waveIndex)) { - const enemyPokemon = this.scene.getEnemyPokemon(); - if (enemyPokemon) { - const bossMBH = this.scene.findModifier(m => m instanceof TurnHeldItemTransferModifier && m.pokemonId === enemyPokemon.id, false) as TurnHeldItemTransferModifier; - if (bossMBH) { - this.scene.removeModifier(bossMBH); - bossMBH.setTransferrableFalse(); - this.scene.addEnemyModifier(bossMBH); - } - } - } } this.scene.ui.setMode(Mode.MESSAGE).then(() => { From b8f9bb0d8f3b6289ee5e83e9b9824c6f81d829d0 Mon Sep 17 00:00:00 2001 From: frutescens Date: Tue, 12 Nov 2024 19:20:51 -0800 Subject: [PATCH 07/12] Added filtering to modifier-retrieve methods. --- src/battle.ts | 4 ++-- src/data/move.ts | 4 ++-- src/modifier/modifier.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/battle.ts b/src/battle.ts index a5f1b830cc7..4085916c310 100644 --- a/src/battle.ts +++ b/src/battle.ts @@ -3,7 +3,7 @@ import { Command } from "./ui/command-ui-handler"; import * as Utils from "./utils"; import Trainer, { TrainerVariant } from "./field/trainer"; import { GameMode } from "./game-mode"; -import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier"; +import { MoneyMultiplierModifier, PokemonHeldItemModifier, TurnHeldItemTransferModifier } from "./modifier/modifier"; import { PokeballType } from "#enums/pokeball"; import { trainerConfigs } from "#app/data/trainer-config"; import { SpeciesFormKey } from "#enums/species-form-key"; @@ -169,7 +169,7 @@ export default class Battle { } addPostBattleLoot(enemyPokemon: EnemyPokemon): void { - this.postBattleLoot.push(...enemyPokemon.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && m.pokemonId === enemyPokemon.id && m.isTransferable, false).map(i => { + this.postBattleLoot.push(...enemyPokemon.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && m.pokemonId === enemyPokemon.id && m.isTransferable && !(m instanceof TurnHeldItemTransferModifier), false).map(i => { const ret = i as PokemonHeldItemModifier; //@ts-ignore - this is awful to fix/change ret.pokemonId = null; diff --git a/src/data/move.ts b/src/data/move.ts index 089bb51bf5e..57f26fcdbe5 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -10,7 +10,7 @@ import * as Utils from "../utils"; 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"; +import { AttackTypeBoosterModifier, BerryModifier, PokemonHeldItemModifier, PokemonMoveAccuracyBoosterModifier, PokemonMultiHitModifier, PreserveBerryModifier, TurnHeldItemTransferModifier } from "../modifier/modifier"; import { BattlerIndex, BattleType } from "../battle"; import { TerrainType } from "./terrain"; import { ModifierPoolType } from "#app/modifier/modifier-type"; @@ -2371,7 +2371,7 @@ export class StealHeldItemChanceAttr extends MoveEffectAttr { if (heldItems.length) { const poolType = target.isPlayer() ? ModifierPoolType.PLAYER : target.hasTrainer() ? ModifierPoolType.TRAINER : ModifierPoolType.WILD; const highestItemTier = heldItems.map(m => m.type.getOrInferTier(poolType)).reduce((highestTier, tier) => Math.max(tier!, highestTier), 0); // TODO: is the bang after tier correct? - const tierHeldItems = heldItems.filter(m => m.type.getOrInferTier(poolType) === highestItemTier); + const tierHeldItems = heldItems.filter(m => m.type.getOrInferTier(poolType) === highestItemTier && !(m instanceof TurnHeldItemTransferModifier)); const stolenItem = tierHeldItems[user.randSeedInt(tierHeldItems.length)]; user.scene.tryTransferHeldItemModifier(stolenItem, user, false).then(success => { if (success) { diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 7aa4b9308d1..75d39b1b377 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -3181,7 +3181,7 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier { const transferredModifierTypes: ModifierType[] = []; const itemModifiers = pokemon.scene.findModifiers(m => m instanceof PokemonHeldItemModifier - && m.pokemonId === targetPokemon.id && m.isTransferable, targetPokemon.isPlayer()) as PokemonHeldItemModifier[]; + && m.pokemonId === targetPokemon.id && m.isTransferable && !(m instanceof TurnHeldItemTransferModifier), targetPokemon.isPlayer()) as PokemonHeldItemModifier[]; let highestItemTier = itemModifiers.map(m => m.type.getOrInferTier(poolType)).reduce((highestTier, tier) => Math.max(tier!, highestTier), 0); // TODO: is this bang correct? let tierItemModifiers = itemModifiers.filter(m => m.type.getOrInferTier(poolType) === highestItemTier); From 3e94a3aa650f8be53a8fb99e8451d358075cb0bd Mon Sep 17 00:00:00 2001 From: frutescens Date: Wed, 13 Nov 2024 12:23:38 -0800 Subject: [PATCH 08/12] Revised logic in tryTransferHeldItemModifier --- src/battle-scene.ts | 123 +++++++++++++++++++++++--------------------- 1 file changed, 64 insertions(+), 59 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 194876a2e49..27ca91b8d0d 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -105,7 +105,7 @@ export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1"; const DEBUG_RNG = false; -const OPP_IVS_OVERRIDE_VALIDATED : integer[] = ( +const OPP_IVS_OVERRIDE_VALIDATED: integer[] = ( Array.isArray(Overrides.OPP_IVS_OVERRIDE) ? Overrides.OPP_IVS_OVERRIDE : new Array(6).fill(Overrides.OPP_IVS_OVERRIDE) @@ -117,18 +117,18 @@ const expSpriteKeys: string[] = []; export let starterColors: StarterColors; interface StarterColors { - [key: string]: [string, string] + [key: string]: [string, string] } export interface PokeballCounts { - [pb: string]: integer; + [pb: string]: integer; } export type AnySound = Phaser.Sound.WebAudioSound | Phaser.Sound.HTML5AudioSound | Phaser.Sound.NoAudioSound; export interface InfoToggle { - toggleInfo(force?: boolean): void; - isActive(): boolean; + toggleInfo(force?: boolean): void; + isActive(): boolean; } export default class BattleScene extends SceneBase { @@ -342,7 +342,7 @@ export default class BattleScene extends SceneBase { if (variant) { atlasPath = atlasPath.replace("variant/", ""); } - this.load.atlas(key, `images/pokemon/${variant ? "variant/" : ""}${experimental ? "exp/" : ""}${atlasPath}.png`, `images/pokemon/${variant ? "variant/" : ""}${experimental ? "exp/" : ""}${atlasPath}.json`); + this.load.atlas(key, `images/pokemon/${variant ? "variant/" : ""}${experimental ? "exp/" : ""}${atlasPath}.png`, `images/pokemon/${variant ? "variant/" : ""}${experimental ? "exp/" : ""}${atlasPath}.json`); } async preload() { @@ -1420,7 +1420,7 @@ export default class BattleScene extends SceneBase { } return 0; case Species.GIMMIGHOUL: - // Chest form can only be found in Mysterious Chest Encounter, if this is a game mode with MEs + // Chest form can only be found in Mysterious Chest Encounter, if this is a game mode with MEs if (this.gameMode.hasMysteryEncounters) { return 1; // Wandering form } else { @@ -1649,7 +1649,7 @@ export default class BattleScene extends SceneBase { const isBoss = !(this.currentBattle.waveIndex % 10); const biomeString: string = getBiomeName(this.arena.biomeType); this.fieldUI.moveAbove(this.biomeWaveText, this.luckText); - this.biomeWaveText.setText( biomeString + " - " + this.currentBattle.waveIndex.toString()); + this.biomeWaveText.setText(biomeString + " - " + this.currentBattle.waveIndex.toString()); this.biomeWaveText.setColor(!isBoss ? "#ffffff" : "#f89890"); this.biomeWaveText.setShadowColor(!isBoss ? "#636363" : "#984038"); this.biomeWaveText.setVisible(true); @@ -1955,8 +1955,8 @@ export default class BattleScene extends SceneBase { case "heal": case "evolution": case "evolution_fanfare": - // These sounds are loaded in as BGM, but played as sound effects - // When these sounds are updated in updateVolume(), they are treated as BGM however because they are placed in the BGM Cache through being called by playSoundWithoutBGM() + // These sounds are loaded in as BGM, but played as sound effects + // When these sounds are updated in updateVolume(), they are treated as BGM however because they are placed in the BGM Cache through being called by playSoundWithoutBGM() config["volume"] *= (this.masterVolume * this.bgmVolume); break; case "battle_anims": @@ -1968,7 +1968,7 @@ export default class BattleScene extends SceneBase { } break; case "ui": - //As of, right now this applies to the "select", "menu_open", "error" sound effects + //As of, right now this applies to the "select", "menu_open", "error" sound effects config["volume"] *= (this.masterVolume * this.uiVolume); break; case "se": @@ -2584,63 +2584,68 @@ export default class BattleScene extends SceneBase { return new Promise(resolve => { const source = itemModifier.pokemonId ? itemModifier.getPokemon(target.scene) : null; const cancelled = new Utils.BooleanHolder(false); - Utils.executeIf(!!source && source.isPlayer() !== target.isPlayer(), () => applyAbAttrs(BlockItemTheftAbAttr, source! /* checked in condition*/, cancelled)).then(() => { - // Prevents transfer of Mini Black Hole from opponent to player / player to opponent - cancelled.value = itemModifier instanceof TurnHeldItemTransferModifier ? true : false; - if (cancelled.value) { - return resolve(false); - } - const newItemModifier = itemModifier.clone() as PokemonHeldItemModifier; - newItemModifier.pokemonId = target.id; - const matchingModifier = target.scene.findModifier(m => m instanceof PokemonHeldItemModifier - && (m as PokemonHeldItemModifier).matchType(itemModifier) && m.pokemonId === target.id, target.isPlayer()) as PokemonHeldItemModifier; - let removeOld = true; - if (matchingModifier) { - const maxStackCount = matchingModifier.getMaxStackCount(target.scene); - if (matchingModifier.stackCount >= maxStackCount) { + if (source && source.isPlayer() !== target.isPlayer()) { + //Check for abilities like Sticky Hold that prevent item transfer between player and opponent + applyAbAttrs(BlockItemTheftAbAttr, source, cancelled).then(() => { + // Check to prevent player-to-opponent/opponent-to-player MBH transfer + if (!cancelled.value) { + cancelled.value = itemModifier instanceof TurnHeldItemTransferModifier; + } + if (cancelled.value) { return resolve(false); } - const countTaken = Math.min(transferQuantity, itemModifier.stackCount, maxStackCount - matchingModifier.stackCount); - itemModifier.stackCount -= countTaken; - newItemModifier.stackCount = matchingModifier.stackCount + countTaken; - removeOld = !itemModifier.stackCount; - } else { - const countTaken = Math.min(transferQuantity, itemModifier.stackCount); - itemModifier.stackCount -= countTaken; - newItemModifier.stackCount = countTaken; + }); + } + const newItemModifier = itemModifier.clone() as PokemonHeldItemModifier; + newItemModifier.pokemonId = target.id; + const matchingModifier = target.scene.findModifier(m => m instanceof PokemonHeldItemModifier + && (m as PokemonHeldItemModifier).matchType(itemModifier) && m.pokemonId === target.id, target.isPlayer()) as PokemonHeldItemModifier; + let removeOld = true; + if (matchingModifier) { + const maxStackCount = matchingModifier.getMaxStackCount(target.scene); + if (matchingModifier.stackCount >= maxStackCount) { + return resolve(false); } + const countTaken = Math.min(transferQuantity, itemModifier.stackCount, maxStackCount - matchingModifier.stackCount); + itemModifier.stackCount -= countTaken; + newItemModifier.stackCount = matchingModifier.stackCount + countTaken; removeOld = !itemModifier.stackCount; - if (!removeOld || !source || this.removeModifier(itemModifier, !source.isPlayer())) { - const addModifier = () => { - if (!matchingModifier || this.removeModifier(matchingModifier, !target.isPlayer())) { - if (target.isPlayer()) { - this.addModifier(newItemModifier, ignoreUpdate, playSound, false, instant).then(() => { - if (source && itemLost) { - applyPostItemLostAbAttrs(PostItemLostAbAttr, source, false); - } - resolve(true); - }); - } else { - this.addEnemyModifier(newItemModifier, ignoreUpdate, instant).then(() => { - if (source && itemLost) { - applyPostItemLostAbAttrs(PostItemLostAbAttr, source, false); - } - resolve(true); - }); - } + } else { + const countTaken = Math.min(transferQuantity, itemModifier.stackCount); + itemModifier.stackCount -= countTaken; + newItemModifier.stackCount = countTaken; + } + removeOld = !itemModifier.stackCount; + if (!removeOld || !source || this.removeModifier(itemModifier, !source.isPlayer())) { + const addModifier = () => { + if (!matchingModifier || this.removeModifier(matchingModifier, !target.isPlayer())) { + if (target.isPlayer()) { + this.addModifier(newItemModifier, ignoreUpdate, playSound, false, instant).then(() => { + if (source && itemLost) { + applyPostItemLostAbAttrs(PostItemLostAbAttr, source, false); + } + resolve(true); + }); } else { - resolve(false); + this.addEnemyModifier(newItemModifier, ignoreUpdate, instant).then(() => { + if (source && itemLost) { + applyPostItemLostAbAttrs(PostItemLostAbAttr, source, false); + } + resolve(true); + }); } - }; - if (source && source.isPlayer() !== target.isPlayer() && !ignoreUpdate) { - this.updateModifiers(source.isPlayer(), instant).then(() => addModifier()); } else { - addModifier(); + resolve(false); } - return; + }; + if (source && source.isPlayer() !== target.isPlayer() && !ignoreUpdate) { + this.updateModifiers(source.isPlayer(), instant).then(() => addModifier()); + } else { + addModifier(); } - resolve(false); - }); + return; + } + resolve(false); }); } From 91526a5410c6d6e71e6862a7536545064fe06bc0 Mon Sep 17 00:00:00 2001 From: frutescens Date: Fri, 15 Nov 2024 10:58:36 -0800 Subject: [PATCH 09/12] Adding what works to the game even though it's not the best. --- src/battle-scene.ts | 167 ++++++++++++++++++++-------------- src/phases/encounter-phase.ts | 10 +- 2 files changed, 107 insertions(+), 70 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 27ca91b8d0d..2f062667808 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -105,7 +105,7 @@ export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1"; const DEBUG_RNG = false; -const OPP_IVS_OVERRIDE_VALIDATED: integer[] = ( +const OPP_IVS_OVERRIDE_VALIDATED : integer[] = ( Array.isArray(Overrides.OPP_IVS_OVERRIDE) ? Overrides.OPP_IVS_OVERRIDE : new Array(6).fill(Overrides.OPP_IVS_OVERRIDE) @@ -117,18 +117,18 @@ const expSpriteKeys: string[] = []; export let starterColors: StarterColors; interface StarterColors { - [key: string]: [string, string] + [key: string]: [string, string] } export interface PokeballCounts { - [pb: string]: integer; + [pb: string]: integer; } export type AnySound = Phaser.Sound.WebAudioSound | Phaser.Sound.HTML5AudioSound | Phaser.Sound.NoAudioSound; export interface InfoToggle { - toggleInfo(force?: boolean): void; - isActive(): boolean; + toggleInfo(force?: boolean): void; + isActive(): boolean; } export default class BattleScene extends SceneBase { @@ -342,7 +342,7 @@ export default class BattleScene extends SceneBase { if (variant) { atlasPath = atlasPath.replace("variant/", ""); } - this.load.atlas(key, `images/pokemon/${variant ? "variant/" : ""}${experimental ? "exp/" : ""}${atlasPath}.png`, `images/pokemon/${variant ? "variant/" : ""}${experimental ? "exp/" : ""}${atlasPath}.json`); + this.load.atlas(key, `images/pokemon/${variant ? "variant/" : ""}${experimental ? "exp/" : ""}${atlasPath}.png`, `images/pokemon/${variant ? "variant/" : ""}${experimental ? "exp/" : ""}${atlasPath}.json`); } async preload() { @@ -1233,14 +1233,41 @@ 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") { + // 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; + + 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; const maxExpLevel = this.getMaxExpLevel(); @@ -1397,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); @@ -1420,7 +1456,7 @@ export default class BattleScene extends SceneBase { } return 0; case Species.GIMMIGHOUL: - // Chest form can only be found in Mysterious Chest Encounter, if this is a game mode with MEs + // Chest form can only be found in Mysterious Chest Encounter, if this is a game mode with MEs if (this.gameMode.hasMysteryEncounters) { return 1; // Wandering form } else { @@ -1649,7 +1685,7 @@ export default class BattleScene extends SceneBase { const isBoss = !(this.currentBattle.waveIndex % 10); const biomeString: string = getBiomeName(this.arena.biomeType); this.fieldUI.moveAbove(this.biomeWaveText, this.luckText); - this.biomeWaveText.setText(biomeString + " - " + this.currentBattle.waveIndex.toString()); + this.biomeWaveText.setText( biomeString + " - " + this.currentBattle.waveIndex.toString()); this.biomeWaveText.setColor(!isBoss ? "#ffffff" : "#f89890"); this.biomeWaveText.setShadowColor(!isBoss ? "#636363" : "#984038"); this.biomeWaveText.setVisible(true); @@ -1955,8 +1991,8 @@ export default class BattleScene extends SceneBase { case "heal": case "evolution": case "evolution_fanfare": - // These sounds are loaded in as BGM, but played as sound effects - // When these sounds are updated in updateVolume(), they are treated as BGM however because they are placed in the BGM Cache through being called by playSoundWithoutBGM() + // These sounds are loaded in as BGM, but played as sound effects + // When these sounds are updated in updateVolume(), they are treated as BGM however because they are placed in the BGM Cache through being called by playSoundWithoutBGM() config["volume"] *= (this.masterVolume * this.bgmVolume); break; case "battle_anims": @@ -1968,7 +2004,7 @@ export default class BattleScene extends SceneBase { } break; case "ui": - //As of, right now this applies to the "select", "menu_open", "error" sound effects + //As of, right now this applies to the "select", "menu_open", "error" sound effects config["volume"] *= (this.masterVolume * this.uiVolume); break; case "se": @@ -2584,68 +2620,61 @@ export default class BattleScene extends SceneBase { return new Promise(resolve => { const source = itemModifier.pokemonId ? itemModifier.getPokemon(target.scene) : null; const cancelled = new Utils.BooleanHolder(false); - if (source && source.isPlayer() !== target.isPlayer()) { - //Check for abilities like Sticky Hold that prevent item transfer between player and opponent - applyAbAttrs(BlockItemTheftAbAttr, source, cancelled).then(() => { - // Check to prevent player-to-opponent/opponent-to-player MBH transfer - if (!cancelled.value) { - cancelled.value = itemModifier instanceof TurnHeldItemTransferModifier; - } - if (cancelled.value) { + Utils.executeIf(!!source && source.isPlayer() !== target.isPlayer(), () => applyAbAttrs(BlockItemTheftAbAttr, source! /* checked in condition*/, cancelled)).then(() => { + if (cancelled.value) { + return resolve(false); + } + const newItemModifier = itemModifier.clone() as PokemonHeldItemModifier; + newItemModifier.pokemonId = target.id; + const matchingModifier = target.scene.findModifier(m => m instanceof PokemonHeldItemModifier + && (m as PokemonHeldItemModifier).matchType(itemModifier) && m.pokemonId === target.id, target.isPlayer()) as PokemonHeldItemModifier; + let removeOld = true; + if (matchingModifier) { + const maxStackCount = matchingModifier.getMaxStackCount(target.scene); + if (matchingModifier.stackCount >= maxStackCount) { return resolve(false); } - }); - } - const newItemModifier = itemModifier.clone() as PokemonHeldItemModifier; - newItemModifier.pokemonId = target.id; - const matchingModifier = target.scene.findModifier(m => m instanceof PokemonHeldItemModifier - && (m as PokemonHeldItemModifier).matchType(itemModifier) && m.pokemonId === target.id, target.isPlayer()) as PokemonHeldItemModifier; - let removeOld = true; - if (matchingModifier) { - const maxStackCount = matchingModifier.getMaxStackCount(target.scene); - if (matchingModifier.stackCount >= maxStackCount) { - return resolve(false); + const countTaken = Math.min(transferQuantity, itemModifier.stackCount, maxStackCount - matchingModifier.stackCount); + itemModifier.stackCount -= countTaken; + newItemModifier.stackCount = matchingModifier.stackCount + countTaken; + removeOld = !itemModifier.stackCount; + } else { + const countTaken = Math.min(transferQuantity, itemModifier.stackCount); + itemModifier.stackCount -= countTaken; + newItemModifier.stackCount = countTaken; } - const countTaken = Math.min(transferQuantity, itemModifier.stackCount, maxStackCount - matchingModifier.stackCount); - itemModifier.stackCount -= countTaken; - newItemModifier.stackCount = matchingModifier.stackCount + countTaken; removeOld = !itemModifier.stackCount; - } else { - const countTaken = Math.min(transferQuantity, itemModifier.stackCount); - itemModifier.stackCount -= countTaken; - newItemModifier.stackCount = countTaken; - } - removeOld = !itemModifier.stackCount; - if (!removeOld || !source || this.removeModifier(itemModifier, !source.isPlayer())) { - const addModifier = () => { - if (!matchingModifier || this.removeModifier(matchingModifier, !target.isPlayer())) { - if (target.isPlayer()) { - this.addModifier(newItemModifier, ignoreUpdate, playSound, false, instant).then(() => { - if (source && itemLost) { - applyPostItemLostAbAttrs(PostItemLostAbAttr, source, false); - } - resolve(true); - }); + if (!removeOld || !source || this.removeModifier(itemModifier, !source.isPlayer())) { + const addModifier = () => { + if (!matchingModifier || this.removeModifier(matchingModifier, !target.isPlayer())) { + if (target.isPlayer()) { + this.addModifier(newItemModifier, ignoreUpdate, playSound, false, instant).then(() => { + if (source && itemLost) { + applyPostItemLostAbAttrs(PostItemLostAbAttr, source, false); + } + resolve(true); + }); + } else { + this.addEnemyModifier(newItemModifier, ignoreUpdate, instant).then(() => { + if (source && itemLost) { + applyPostItemLostAbAttrs(PostItemLostAbAttr, source, false); + } + resolve(true); + }); + } } else { - this.addEnemyModifier(newItemModifier, ignoreUpdate, instant).then(() => { - if (source && itemLost) { - applyPostItemLostAbAttrs(PostItemLostAbAttr, source, false); - } - resolve(true); - }); + resolve(false); } + }; + if (source && source.isPlayer() !== target.isPlayer() && !ignoreUpdate) { + this.updateModifiers(source.isPlayer(), instant).then(() => addModifier()); } else { - resolve(false); + addModifier(); } - }; - if (source && source.isPlayer() !== target.isPlayer() && !ignoreUpdate) { - this.updateModifiers(source.isPlayer(), instant).then(() => addModifier()); - } else { - addModifier(); + return; } - return; - } - resolve(false); + resolve(false); + }); }); } diff --git a/src/phases/encounter-phase.ts b/src/phases/encounter-phase.ts index 9e2ab51fcdc..ca8ed3c3fc4 100644 --- a/src/phases/encounter-phase.ts +++ b/src/phases/encounter-phase.ts @@ -12,7 +12,7 @@ import { getRandomWeatherType } from "#app/data/weather"; import { EncounterPhaseEvent } from "#app/events/battle-scene"; import Pokemon, { FieldPosition } from "#app/field/pokemon"; import { getPokemonNameWithAffix } from "#app/messages"; -import { BoostBugSpawnModifier, IvScannerModifier } from "#app/modifier/modifier"; +import { BoostBugSpawnModifier, IvScannerModifier, TurnHeldItemTransferModifier } from "#app/modifier/modifier"; import { ModifierPoolType, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type"; import Overrides from "#app/overrides"; import { BattlePhase } from "#app/phases/battle-phase"; @@ -438,6 +438,14 @@ export class EncounterPhase extends BattlePhase { if (enemyPokemon.isShiny()) { this.scene.unshiftPhase(new ShinySparklePhase(this.scene, BattlerIndex.ENEMY + e)); } + if (enemyPokemon.species.speciesId === Species.ETERNATUS && 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 eee3d4f191d160a8094cc42c73034d9ef078f720 Mon Sep 17 00:00:00 2001 From: frutescens Date: Fri, 15 Nov 2024 10:59:27 -0800 Subject: [PATCH 10/12] Added comments --- src/phases/encounter-phase.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/phases/encounter-phase.ts b/src/phases/encounter-phase.ts index ca8ed3c3fc4..6de0a3863f3 100644 --- a/src/phases/encounter-phase.ts +++ b/src/phases/encounter-phase.ts @@ -438,6 +438,7 @@ 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.isEndlessMajorBoss(this.scene.currentBattle.waveIndex)) { const enemyMBH = this.scene.findModifier(m => m instanceof TurnHeldItemTransferModifier, false) as TurnHeldItemTransferModifier; if (enemyMBH) { From 3720a625bbf1c6af05abcac298f5c28d806cf648 Mon Sep 17 00:00:00 2001 From: frutescens Date: Fri, 15 Nov 2024 11:06:00 -0800 Subject: [PATCH 11/12] Removing past changes to files. --- src/battle.ts | 8 ++++---- src/data/move.ts | 4 ++-- src/modifier/modifier.ts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/battle.ts b/src/battle.ts index 4085916c310..75f0dff2534 100644 --- a/src/battle.ts +++ b/src/battle.ts @@ -3,7 +3,7 @@ import { Command } from "./ui/command-ui-handler"; import * as Utils from "./utils"; import Trainer, { TrainerVariant } from "./field/trainer"; import { GameMode } from "./game-mode"; -import { MoneyMultiplierModifier, PokemonHeldItemModifier, TurnHeldItemTransferModifier } from "./modifier/modifier"; +import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier"; import { PokeballType } from "#enums/pokeball"; import { trainerConfigs } from "#app/data/trainer-config"; import { SpeciesFormKey } from "#enums/species-form-key"; @@ -169,7 +169,7 @@ export default class Battle { } addPostBattleLoot(enemyPokemon: EnemyPokemon): void { - this.postBattleLoot.push(...enemyPokemon.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && m.pokemonId === enemyPokemon.id && m.isTransferable && !(m instanceof TurnHeldItemTransferModifier), false).map(i => { + this.postBattleLoot.push(...enemyPokemon.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && m.pokemonId === enemyPokemon.id && m.isTransferable, false).map(i => { const ret = i as PokemonHeldItemModifier; //@ts-ignore - this is awful to fix/change ret.pokemonId = null; @@ -499,7 +499,7 @@ export class FixedBattleConfig { * @param seedOffset the seed offset to use for the random generation of the trainer * @returns the generated trainer */ -function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], randomGender: boolean = false, seedOffset: number = 0): GetTrainerFunc { +function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], randomGender: boolean = false, seedOffset: number = 0): GetTrainerFunc { return (scene: BattleScene) => { const rand = Utils.randSeedInt(trainerPool.length); const trainerTypes: TrainerType[] = []; @@ -531,7 +531,7 @@ function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], rand } export interface FixedBattleConfigs { - [key: number]: FixedBattleConfig + [key: number]: FixedBattleConfig } /** * Youngster/Lass on 5 diff --git a/src/data/move.ts b/src/data/move.ts index 12b83eafd6e..2ac4d74b712 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -10,7 +10,7 @@ import * as Utils from "../utils"; 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, TurnHeldItemTransferModifier } from "../modifier/modifier"; +import { AttackTypeBoosterModifier, BerryModifier, PokemonHeldItemModifier, PokemonMoveAccuracyBoosterModifier, PokemonMultiHitModifier, PreserveBerryModifier } from "../modifier/modifier"; import { BattlerIndex, BattleType } from "../battle"; import { TerrainType } from "./terrain"; import { ModifierPoolType } from "#app/modifier/modifier-type"; @@ -2371,7 +2371,7 @@ export class StealHeldItemChanceAttr extends MoveEffectAttr { if (heldItems.length) { const poolType = target.isPlayer() ? ModifierPoolType.PLAYER : target.hasTrainer() ? ModifierPoolType.TRAINER : ModifierPoolType.WILD; const highestItemTier = heldItems.map(m => m.type.getOrInferTier(poolType)).reduce((highestTier, tier) => Math.max(tier!, highestTier), 0); // TODO: is the bang after tier correct? - const tierHeldItems = heldItems.filter(m => m.type.getOrInferTier(poolType) === highestItemTier && !(m instanceof TurnHeldItemTransferModifier)); + const tierHeldItems = heldItems.filter(m => m.type.getOrInferTier(poolType) === highestItemTier); const stolenItem = tierHeldItems[user.randSeedInt(tierHeldItems.length)]; user.scene.tryTransferHeldItemModifier(stolenItem, user, false).then(success => { if (success) { diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index f08b56233f2..ac8dc556b98 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -3181,7 +3181,7 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier { const transferredModifierTypes: ModifierType[] = []; const itemModifiers = pokemon.scene.findModifiers(m => m instanceof PokemonHeldItemModifier - && m.pokemonId === targetPokemon.id && m.isTransferable && !(m instanceof TurnHeldItemTransferModifier), targetPokemon.isPlayer()) as PokemonHeldItemModifier[]; + && m.pokemonId === targetPokemon.id && m.isTransferable, targetPokemon.isPlayer()) as PokemonHeldItemModifier[]; let highestItemTier = itemModifiers.map(m => m.type.getOrInferTier(poolType)).reduce((highestTier, tier) => Math.max(tier!, highestTier), 0); // TODO: is this bang correct? let tierItemModifiers = itemModifiers.filter(m => m.type.getOrInferTier(poolType) === highestItemTier); From aef73dca6786d0dcb4f5c20c4ba1410cb941dbc0 Mon Sep 17 00:00:00 2001 From: frutescens Date: Fri, 15 Nov 2024 11:07:38 -0800 Subject: [PATCH 12/12] Added check for Classic Final Boss. --- src/phases/encounter-phase.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/phases/encounter-phase.ts b/src/phases/encounter-phase.ts index 6de0a3863f3..2cb60d7b18f 100644 --- a/src/phases/encounter-phase.ts +++ b/src/phases/encounter-phase.ts @@ -439,7 +439,7 @@ export class EncounterPhase extends BattlePhase { 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.isEndlessMajorBoss(this.scene.currentBattle.waveIndex)) { + 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);