Removed unnecessary null checks for turnData and co.

I explicitly made them initialized by default for this very reason
This commit is contained in:
Bertie690 2025-04-29 14:06:12 -04:00
parent f82d3529ad
commit c34fd10ccb
12 changed files with 63 additions and 96 deletions

@ -1 +1 @@
Subproject commit 18c1963ef309612a5a7fef76f9879709a7202189 Subproject commit e98f0eb9c2022bc78b53f0444424c636498e725a

View File

@ -3631,14 +3631,10 @@ export class SuppressWeatherEffectAbAttr extends PreWeatherEffectAbAttr {
* Condition function to applied to abilities related to Sheer Force. * Condition function to applied to abilities related to Sheer Force.
* Checks if last move used against target was affected by a Sheer Force user and: * Checks if last move used against target was affected by a Sheer Force user and:
* Disables: Color Change, Pickpocket, Berserk, Anger Shell * Disables: Color Change, Pickpocket, Berserk, Anger Shell
* @returns {AbAttrCondition} If false disables the ability which the condition is applied to. * @returns An {@linkcode AbAttrCondition} to disable the ability under the proper conditions.
*/ */
function getSheerForceHitDisableAbCondition(): AbAttrCondition { function getSheerForceHitDisableAbCondition(): AbAttrCondition {
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
if (!pokemon.turnData) {
return true;
}
const lastReceivedAttack = pokemon.turnData.attacksReceived[0]; const lastReceivedAttack = pokemon.turnData.attacksReceived[0];
if (!lastReceivedAttack) { if (!lastReceivedAttack) {
return true; return true;
@ -3649,7 +3645,7 @@ function getSheerForceHitDisableAbCondition(): AbAttrCondition {
return true; return true;
} }
/**if the last move chance is greater than or equal to cero, and the last attacker's ability is sheer force*/ /** `true` if the last move's chance is above 0 and the last attacker's ability is sheer force */
const SheerForceAffected = allMoves[lastReceivedAttack.move].chance >= 0 && lastAttacker.hasAbility(Abilities.SHEER_FORCE); const SheerForceAffected = allMoves[lastReceivedAttack.move].chance >= 0 && lastAttacker.hasAbility(Abilities.SHEER_FORCE);
return !SheerForceAffected; return !SheerForceAffected;
@ -5695,6 +5691,7 @@ export class PostDamageForceSwitchAbAttr extends PostDamageAbAttr {
this.hpRatio = hpRatio; this.hpRatio = hpRatio;
} }
// TODO: Refactor to use more early returns
public override canApplyPostDamage( public override canApplyPostDamage(
pokemon: Pokemon, pokemon: Pokemon,
damage: number, damage: number,
@ -5722,6 +5719,7 @@ export class PostDamageForceSwitchAbAttr extends PostDamageAbAttr {
if (fordbiddenDefendingMoves.includes(enemyLastMoveUsed.move) || enemyLastMoveUsed.move === Moves.SKY_DROP && enemyLastMoveUsed.result === MoveResult.OTHER) { if (fordbiddenDefendingMoves.includes(enemyLastMoveUsed.move) || enemyLastMoveUsed.move === Moves.SKY_DROP && enemyLastMoveUsed.result === MoveResult.OTHER) {
return false; return false;
// Will not activate if the Pokémon's HP falls below half by a move affected by Sheer Force. // Will not activate if the Pokémon's HP falls below half by a move affected by Sheer Force.
// TODO: Make this use the sheer force disable condition
} else if (allMoves[enemyLastMoveUsed.move].chance >= 0 && source.hasAbility(Abilities.SHEER_FORCE)) { } else if (allMoves[enemyLastMoveUsed.move].chance >= 0 && source.hasAbility(Abilities.SHEER_FORCE)) {
return false; return false;
// Activate only after the last hit of multistrike moves // Activate only after the last hit of multistrike moves

View File

@ -768,32 +768,27 @@ class SpikesTag extends ArenaTrapTag {
} }
override activateTrap(pokemon: Pokemon, simulated: boolean): boolean { override activateTrap(pokemon: Pokemon, simulated: boolean): boolean {
if (pokemon.isGrounded()) { if (!pokemon.isGrounded()) {
const cancelled = new BooleanHolder(false); return false;
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
if (simulated) {
return !cancelled.value;
}
if (!cancelled.value) {
const damageHpRatio = 1 / (10 - 2 * this.layers);
const damage = toDmgValue(pokemon.getMaxHp() * damageHpRatio);
globalScene.queueMessage(
i18next.t("arenaTag:spikesActivateTrap", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
);
pokemon.damageAndUpdate(damage, { result: HitResult.INDIRECT });
if (pokemon.turnData) {
pokemon.turnData.damageTaken += damage;
}
return true;
}
} }
return false; const cancelled = new BooleanHolder(false);
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
if (simulated || cancelled.value) {
return !cancelled.value;
}
const damageHpRatio = 1 / (10 - 2 * this.layers);
const damage = toDmgValue(pokemon.getMaxHp() * damageHpRatio);
globalScene.queueMessage(
i18next.t("arenaTag:spikesActivateTrap", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
);
pokemon.damageAndUpdate(damage, { result: HitResult.INDIRECT });
pokemon.turnData.damageTaken += damage;
return true;
} }
} }
@ -962,31 +957,28 @@ class StealthRockTag extends ArenaTrapTag {
override activateTrap(pokemon: Pokemon, simulated: boolean): boolean { override activateTrap(pokemon: Pokemon, simulated: boolean): boolean {
const cancelled = new BooleanHolder(false); const cancelled = new BooleanHolder(false);
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
if (cancelled.value) { if (cancelled.value) {
return false; return false;
} }
const damageHpRatio = this.getDamageHpRatio(pokemon); const damageHpRatio = this.getDamageHpRatio(pokemon);
if (!damageHpRatio) {
return false;
}
if (damageHpRatio) { if (simulated) {
if (simulated) {
return true;
}
const damage = toDmgValue(pokemon.getMaxHp() * damageHpRatio);
globalScene.queueMessage(
i18next.t("arenaTag:stealthRockActivateTrap", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
);
pokemon.damageAndUpdate(damage, { result: HitResult.INDIRECT });
if (pokemon.turnData) {
pokemon.turnData.damageTaken += damage;
}
return true; return true;
} }
return false; const damage = toDmgValue(pokemon.getMaxHp() * damageHpRatio);
globalScene.queueMessage(
i18next.t("arenaTag:stealthRockActivateTrap", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
);
pokemon.damageAndUpdate(damage, { result: HitResult.INDIRECT });
pokemon.turnData.damageTaken += damage;
return true;
} }
getMatchupScoreMultiplier(pokemon: Pokemon): number { getMatchupScoreMultiplier(pokemon: Pokemon): number {

View File

@ -4388,10 +4388,10 @@ export class LastMoveDoublePowerAttr extends VariablePowerAttr {
const userAlly = user.getAlly(); const userAlly = user.getAlly();
const enemyAlly = enemy?.getAlly(); const enemyAlly = enemy?.getAlly();
if (!isNullOrUndefined(userAlly) && userAlly.turnData.acted) { if (userAlly?.turnData.acted) {
pokemonActed.push(userAlly); pokemonActed.push(userAlly);
} }
if (!isNullOrUndefined(enemyAlly) && enemyAlly.turnData.acted) { if (enemyAlly?.turnData.acted) {
pokemonActed.push(enemyAlly); pokemonActed.push(enemyAlly);
} }
} }
@ -4459,13 +4459,10 @@ export class CombinedPledgeStabBoostAttr extends MoveAttr {
* @extends VariablePowerAttr * @extends VariablePowerAttr
*/ */
export class RoundPowerAttr extends VariablePowerAttr { export class RoundPowerAttr extends VariablePowerAttr {
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { override apply(user: Pokemon, target: Pokemon, move: Move, args: [NumberHolder]): boolean {
const power = args[0]; const power = args[0];
if (!(power instanceof NumberHolder)) {
return false;
}
if (user.turnData?.joinedRound) { if (user.turnData.joinedRound) {
power.value *= 2; power.value *= 2;
return true; return true;
} }

View File

@ -397,9 +397,6 @@ export const ClowningAroundEncounter: MysteryEncounter = MysteryEncounterBuilder
newTypes.push(secondType); newTypes.push(secondType);
// Apply the type changes (to both base and fusion, if pokemon is fused) // Apply the type changes (to both base and fusion, if pokemon is fused)
if (!pokemon.customPokemonData) {
pokemon.customPokemonData = new CustomPokemonData();
}
pokemon.customPokemonData.types = newTypes; pokemon.customPokemonData.types = newTypes;
if (pokemon.isFusion()) { if (pokemon.isFusion()) {
if (!pokemon.fusionCustomPokemonData) { if (!pokemon.fusionCustomPokemonData) {

View File

@ -23,7 +23,6 @@ import { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species";
import type { PokemonHeldItemModifier } from "#app/modifier/modifier"; import type { PokemonHeldItemModifier } from "#app/modifier/modifier";
import { HiddenAbilityRateBoosterModifier, PokemonFormChangeItemModifier } from "#app/modifier/modifier"; import { HiddenAbilityRateBoosterModifier, PokemonFormChangeItemModifier } from "#app/modifier/modifier";
import { achvs } from "#app/system/achv"; import { achvs } from "#app/system/achv";
import { CustomPokemonData } from "#app/data/custom-pokemon-data";
import { showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import type { PokemonHeldItemModifierType } from "#app/modifier/modifier-type"; import type { PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type";
@ -601,9 +600,6 @@ async function postProcessTransformedPokemon(
newType = randSeedInt(18) as PokemonType; newType = randSeedInt(18) as PokemonType;
} }
newTypes.push(newType); newTypes.push(newType);
if (!newPokemon.customPokemonData) {
newPokemon.customPokemonData = new CustomPokemonData();
}
newPokemon.customPokemonData.types = newTypes; newPokemon.customPokemonData.types = newTypes;
// Enable passive if previous had it // Enable passive if previous had it

View File

@ -1031,9 +1031,6 @@ export function applyAbilityOverrideToPokemon(pokemon: Pokemon, ability: Abiliti
} }
pokemon.fusionCustomPokemonData.ability = ability; pokemon.fusionCustomPokemonData.ability = ability;
} else { } else {
if (!pokemon.customPokemonData) {
pokemon.customPokemonData = new CustomPokemonData();
}
pokemon.customPokemonData.ability = ability; pokemon.customPokemonData.ability = ability;
} }
} }

View File

@ -1412,9 +1412,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
/** /**
* Retrieves the entire set of stats of the {@linkcode Pokemon}. * Retrieves the entire set of stats of this {@linkcode Pokemon}.
* @param bypassSummonData prefer actual stats (`true` by default) or in-battle overriden stats (`false`) * @param bypassSummonData - whether to use actual stats or in-battle overriden stats from Transform; default `true`
* @returns the numeric values of the {@linkcode Pokemon}'s stats * @returns the numeric values of this {@linkcode Pokemon}'s stats
*/ */
getStats(bypassSummonData = true): number[] { getStats(bypassSummonData = true): number[] {
if (!bypassSummonData && this.summonData.stats) { if (!bypassSummonData && this.summonData.stats) {
@ -4973,13 +4973,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
transferTagsBySourceId(sourceId: number, newSourceId: number): void { transferTagsBySourceId(sourceId: number, newSourceId: number): void {
if (!this.summonData) { this.summonData.tags
return; .filter(t => t.sourceId === sourceId)
} .forEach(t => (t.sourceId = newSourceId));
const tags = this.summonData.tags;
tags
.filter(t => t.sourceId === sourceId)
.forEach(t => (t.sourceId = newSourceId));
} }
/** /**
@ -5664,6 +5660,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
this.summonData = new PokemonSummonData(); this.summonData = new PokemonSummonData();
this.setSwitchOutStatus(false); this.setSwitchOutStatus(false);
// TODO: Why do we remove leech seed on resetting summon data? That should be a BattlerTag thing...
if (this.getTag(BattlerTagType.SEEDED)) { if (this.getTag(BattlerTagType.SEEDED)) {
this.lapseTag(BattlerTagType.SEEDED); this.lapseTag(BattlerTagType.SEEDED);
} }
@ -7749,15 +7746,16 @@ export class PokemonSummonData {
public moveQueue: TurnMove[] = []; public moveQueue: TurnMove[] = [];
public tags: BattlerTag[] = []; public tags: BattlerTag[] = [];
public abilitySuppressed = false; public abilitySuppressed = false;
// Overrides for transform
public speciesForm: PokemonSpeciesForm | null = null; public speciesForm: PokemonSpeciesForm | null = null;
public fusionSpeciesForm: PokemonSpeciesForm | null = null; public fusionSpeciesForm: PokemonSpeciesForm | null = null;
public ability: Abilities = Abilities.NONE; public ability: Abilities | undefined;
public passiveAbility: Abilities = Abilities.NONE; public passiveAbility: Abilities | undefined;
public gender: Gender; public gender: Gender | undefined;
public fusionGender: Gender; public fusionGender: Gender | undefined;
public stats: number[] = [0, 0, 0, 0, 0, 0]; public stats: number[] = [0, 0, 0, 0, 0, 0];
public moveset: PokemonMove[] | null; public moveset: PokemonMove[] | null;
public illusionBroken: boolean = false;
// If not initialized this value will not be populated from save data. // If not initialized this value will not be populated from save data.
public types: PokemonType[] = []; public types: PokemonType[] = [];
@ -7765,6 +7763,7 @@ export class PokemonSummonData {
/** Data pertaining to this pokemon's illusion. */ /** Data pertaining to this pokemon's illusion. */
public illusion: IllusionData | null = null; public illusion: IllusionData | null = null;
public illusionBroken: boolean = false;
/** Array containing all berries eaten in the last turn; used by {@linkcode Abilities.CUD_CHEW} */ /** Array containing all berries eaten in the last turn; used by {@linkcode Abilities.CUD_CHEW} */
public berriesEatenLast: BerryType[] = []; public berriesEatenLast: BerryType[] = [];

View File

@ -1649,13 +1649,14 @@ export class FlinchChanceModifier extends PokemonHeldItemModifier {
} }
/** /**
* Applies {@linkcode FlinchChanceModifier} * Applies {@linkcode FlinchChanceModifier} to randomly flinch targets hit.
* @param pokemon the {@linkcode Pokemon} that holds the item * @param pokemon - The {@linkcode Pokemon} that holds the item
* @param flinched {@linkcode BooleanHolder} that is `true` if the pokemon flinched * @param flinched - A {@linkcode BooleanHolder} holding whether the pokemon has flinched
* @returns `true` if {@linkcode FlinchChanceModifier} has been applied * @returns `true` if {@linkcode FlinchChanceModifier} was applied successfully
*/ */
override apply(pokemon: Pokemon, flinched: BooleanHolder): boolean { override apply(pokemon: Pokemon, flinched: BooleanHolder): boolean {
// The check for pokemon.summonData is to ensure that a crash doesn't occur when a Pokemon with King's Rock procs a flinch // The check for pokemon.summonData is to ensure that a crash doesn't occur when a Pokemon with King's Rock procs a flinch
// TODO: Since summonData is always defined now, we can probably remove this
if (pokemon.summonData && !flinched.value && pokemon.randSeedInt(100) < this.getStackCount() * this.chance) { if (pokemon.summonData && !flinched.value && pokemon.randSeedInt(100) < this.getStackCount() * this.chance) {
flinched.value = true; flinched.value = true;
return true; return true;
@ -1782,6 +1783,7 @@ export class HitHealModifier extends PokemonHeldItemModifier {
*/ */
override apply(pokemon: Pokemon): boolean { override apply(pokemon: Pokemon): boolean {
if (pokemon.turnData.totalDamageDealt && !pokemon.isFullHp()) { if (pokemon.turnData.totalDamageDealt && !pokemon.isFullHp()) {
// TODO: this shouldn't be undefined AFAIK
globalScene.unshiftPhase( globalScene.unshiftPhase(
new PokemonHealPhase( new PokemonHealPhase(
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),

View File

@ -118,7 +118,7 @@ export class FaintPhase extends PokemonPhase {
pokemon.resetTera(); pokemon.resetTera();
if (pokemon.turnData?.attacksReceived?.length) { if (pokemon.turnData.attacksReceived?.length) {
const lastAttack = pokemon.turnData.attacksReceived[0]; const lastAttack = pokemon.turnData.attacksReceived[0];
applyPostFaintAbAttrs( applyPostFaintAbAttrs(
PostFaintAbAttr, PostFaintAbAttr,
@ -136,7 +136,7 @@ export class FaintPhase extends PokemonPhase {
for (const p of alivePlayField) { for (const p of alivePlayField) {
applyPostKnockOutAbAttrs(PostKnockOutAbAttr, p, pokemon); applyPostKnockOutAbAttrs(PostKnockOutAbAttr, p, pokemon);
} }
if (pokemon.turnData?.attacksReceived?.length) { if (pokemon.turnData.attacksReceived?.length) {
const defeatSource = this.source; const defeatSource = this.source;
if (defeatSource?.isOnField()) { if (defeatSource?.isOnField()) {

View File

@ -277,9 +277,6 @@ export class MoveEffectPhase extends PokemonPhase {
super.end(); super.end();
return; return;
} }
if (isNullOrUndefined(user.turnData)) {
user.resetTurnData();
}
} }
/** /**

View File

@ -217,16 +217,8 @@ export class StatStageChangePhase extends PokemonPhase {
for (const s of filteredStats) { for (const s of filteredStats) {
if (stages.value > 0 && pokemon.getStatStage(s) < 6) { if (stages.value > 0 && pokemon.getStatStage(s) < 6) {
if (!pokemon.turnData) {
// Temporary fix for missing turn data struct on turn 1
pokemon.resetTurnData();
}
pokemon.turnData.statStagesIncreased = true; pokemon.turnData.statStagesIncreased = true;
} else if (stages.value < 0 && pokemon.getStatStage(s) > -6) { } else if (stages.value < 0 && pokemon.getStatStage(s) > -6) {
if (!pokemon.turnData) {
// Temporary fix for missing turn data struct on turn 1
pokemon.resetTurnData();
}
pokemon.turnData.statStagesDecreased = true; pokemon.turnData.statStagesDecreased = true;
} }