diff --git a/src/battle-phases.ts b/src/battle-phases.ts index e4f2213da..89ff1fa90 100644 --- a/src/battle-phases.ts +++ b/src/battle-phases.ts @@ -25,7 +25,7 @@ import { Gender } from "./data/gender"; import { Weather, WeatherType, getRandomWeatherType, getWeatherDamageMessage, getWeatherLapseMessage } from "./data/weather"; import { TempBattleStat } from "./data/temp-battle-stat"; import { ArenaTagType, ArenaTrapTag, TrickRoomTag } from "./data/arena-tag"; -import { Abilities, CheckTrappedAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, SuppressWeatherEffectAbAttr, applyCheckTrappedAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreWeatherEffectAbAttrs } from "./data/ability"; +import { Abilities, CheckTrappedAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreWeatherEffectAbAttrs } from "./data/ability"; import { Unlockables, getUnlockableName } from "./system/unlockables"; import { getBiomeKey } from "./arena"; import { BattleType, BattlerIndex, TurnCommand } from "./battle"; @@ -1759,16 +1759,19 @@ export class StatChangePhase extends PokemonPhase { return !cancelled.value; }); + const levels = new Utils.IntegerHolder(this.levels); + applyAbAttrs(StatChangeMultiplierAbAttr, pokemon, null, levels); + const battleStats = this.getPokemon().summonData.battleStats; - const relLevels = filteredStats.map(stat => (this.levels >= 1 ? Math.min(battleStats[stat] + this.levels, 6) : Math.max(battleStats[stat] + this.levels, -6)) - battleStats[stat]); + const relLevels = filteredStats.map(stat => (levels.value >= 1 ? Math.min(battleStats[stat] + levels.value, 6) : Math.max(battleStats[stat] + levels.value, -6)) - battleStats[stat]); const end = () => { - const messages = this.getStatChangeMessages(filteredStats, relLevels); + const messages = this.getStatChangeMessages(filteredStats, levels.value, relLevels); for (let message of messages) this.scene.queueMessage(message); for (let stat of filteredStats) - pokemon.summonData.battleStats[stat] = Math.max(Math.min(pokemon.summonData.battleStats[stat] + this.levels, 6), -6); + pokemon.summonData.battleStats[stat] = Math.max(Math.min(pokemon.summonData.battleStats[stat] + levels.value, 6), -6); this.end(); }; @@ -1777,12 +1780,12 @@ export class StatChangePhase extends PokemonPhase { pokemon.enableMask(); const pokemonMaskSprite = pokemon.maskSprite; - const statSprite = this.scene.add.tileSprite((this.player ? 106 : 236) * 6, ((this.player ? 148 : 84) + (this.levels >= 1 ? 160 : 0)) * 6, 156, 316, 'battle_stats', filteredStats.length > 1 ? 'mix' : BattleStat[filteredStats[0]].toLowerCase()); + const statSprite = this.scene.add.tileSprite((this.player ? 106 : 236) * 6, ((this.player ? 148 : 84) + (levels.value >= 1 ? 160 : 0)) * 6, 156, 316, 'battle_stats', filteredStats.length > 1 ? 'mix' : BattleStat[filteredStats[0]].toLowerCase()); statSprite.setAlpha(0); statSprite.setScale(6); statSprite.setOrigin(0.5, 1); - this.scene.playSound(`stat_${this.levels >= 1 ? 'up' : 'down'}`); + this.scene.playSound(`stat_${levels.value >= 1 ? 'up' : 'down'}`); statSprite.setMask(new Phaser.Display.Masks.BitmapMask(this.scene, pokemonMaskSprite)); @@ -1803,7 +1806,7 @@ export class StatChangePhase extends PokemonPhase { this.scene.tweens.add({ targets: statSprite, duration: 1500, - y: `${this.levels >= 1 ? '-' : '+'}=${160 * 6}` + y: `${levels.value >= 1 ? '-' : '+'}=${160 * 6}` }); this.scene.time.delayedCall(1750, () => { @@ -1814,11 +1817,11 @@ export class StatChangePhase extends PokemonPhase { end(); } - getStatChangeMessages(stats: BattleStat[], relLevels: integer[]): string[] { + getStatChangeMessages(stats: BattleStat[], levels: integer, relLevels: integer[]): string[] { const messages: string[] = []; for (let s = 0; s < stats.length; s++) - messages.push(getPokemonMessage(this.getPokemon(), `'s ${getBattleStatName(stats[s])} ${getBattleStatLevelChangeDescription(Math.abs(relLevels[s]), this.levels >= 1)}!`)); + messages.push(getPokemonMessage(this.getPokemon(), `'s ${getBattleStatName(stats[s])} ${getBattleStatLevelChangeDescription(Math.abs(relLevels[s]), levels >= 1)}!`)); return messages; } } diff --git a/src/data/ability.ts b/src/data/ability.ts index 751a2ba2b..1d8d64fcc 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -762,6 +762,22 @@ export class PostWeatherLapseDamageAbAttr extends PostWeatherLapseAbAttr { } } +export class StatChangeMultiplierAbAttr extends AbAttr { + private multiplier: integer; + + constructor(multiplier: integer) { + super(true); + + this.multiplier = multiplier; + } + + apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + (args[0] as Utils.IntegerHolder).value *= this.multiplier; + + return true; + } +} + export class CheckTrappedAbAttr extends AbAttr { applyCheckTrapped(pokemon: Pokemon, trapped: Utils.BooleanHolder, args: any[]): boolean { return false; @@ -1450,7 +1466,8 @@ export function initAbilities() { .attr(RecoilMovePowerBoostAbAttr), new Ability(Abilities.RIVALRY, "Rivalry (N)", "Deals more damage to a Pokémon of same gender.", 4), new Ability(Abilities.SCRAPPY, "Scrappy (N)", "Enables moves to hit Ghost-type Pokémon.", 4), - new Ability(Abilities.SIMPLE, "Simple (N)", "Doubles all stat changes.", 4), + new Ability(Abilities.SIMPLE, "Simple", "Doubles all stat changes.", 4) + .attr(StatChangeMultiplierAbAttr, 2), new Ability(Abilities.SKILL_LINK, "Skill Link (N)", "Increases the frequency of multi-strike moves.", 4), new Ability(Abilities.SLOW_START, "Slow Start (N)", "Temporarily halves Attack and Speed.", 4), new Ability(Abilities.SNIPER, "Sniper (N)", "Powers up moves if they become critical hits.", 4), @@ -1474,7 +1491,8 @@ export function initAbilities() { new Ability(Abilities.ANALYTIC, "Analytic (N)", "Boosts move power when the Pokémon moves last.", 5), new Ability(Abilities.BIG_PECKS, "Big Pecks", "Protects the Pokémon from Defense-lowering attacks.", 5) .attr(ProtectStatAbAttr, BattleStat.DEF), - new Ability(Abilities.CONTRARY, "Contrary (N)", "Makes stat changes have an opposite effect.", 5), + new Ability(Abilities.CONTRARY, "Contrary", "Makes stat changes have an opposite effect.", 5) + .attr(StatChangeMultiplierAbAttr, -1), new Ability(Abilities.CURSED_BODY, "Cursed Body (N)", "May disable a move used on the Pokémon.", 5), new Ability(Abilities.DEFEATIST, "Defeatist (N)", "Lowers stats when HP drops below half.", 5), new Ability(Abilities.DEFIANT, "Defiant (N)", "Sharply raises Attack when the Pokémon's stats are lowered.", 5),