From 22add553a107827e64af13a3d426723a71c4fe8f Mon Sep 17 00:00:00 2001 From: Gwen Valentine Date: Tue, 23 Apr 2024 01:29:24 -0400 Subject: [PATCH] Castform and Cherrim Abilities Add support for Castform and Cherrim's form changes. Add a Weather form ability check. Current Implementation is identical to their gen 4 implementation. Cherrim changes forms regardless of whether their ability is suppressed Castform changes forms only if their ability is not suppressed Nuetralizing Gas be the death of us all. --- src/data/ability.ts | 5 ++- src/data/pokemon-forms.ts | 65 +++++++++++++++++++++++++++++++++++++++ src/field/arena.ts | 11 ++++++- src/phases.ts | 7 ++--- 4 files changed, 82 insertions(+), 6 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index bfc608dc7e0..30eda2685a2 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -2544,7 +2544,8 @@ export function initAbilities() { .attr(PostDefendContactApplyTagChanceAbAttr, 30, BattlerTagType.INFATUATED), new Ability(Abilities.PLUS, "Plus (N)", "Boosts the Sp. Atk stat of the Pokémon if an ally with the Plus or Minus Ability is also in battle.", 3), new Ability(Abilities.MINUS, "Minus (N)", "Boosts the Sp. Atk stat of the Pokémon if an ally with the Plus or Minus Ability is also in battle.", 3), - new Ability(Abilities.FORECAST, "Forecast (N)", "The Pokémon transforms with the weather to change its type to Water, Fire, or Ice.", 3) + new Ability(Abilities.FORECAST, "Forecast (P)", "The Pokémon transforms with the weather to change its type to Water, Fire, or Ice.", 3) + .attr(PostWeatherChangeAbAttr) .attr(UncopiableAbilityAbAttr) .attr(NoFusionAbilityAbAttr), new Ability(Abilities.STICKY_HOLD, "Sticky Hold", "Items held by the Pokémon are stuck fast and cannot be removed by other Pokémon.", 3) @@ -2706,6 +2707,7 @@ export function initAbilities() { new Ability(Abilities.FLOWER_GIFT, "Flower Gift (P)", "Boosts the Attack and Sp. Def stats of itself and allies in harsh sunlight.", 4) .conditionalAttr(getWeatherCondition(WeatherType.SUNNY || WeatherType.HARSH_SUN), BattleStatMultiplierAbAttr, BattleStat.ATK, 1.5) .conditionalAttr(getWeatherCondition(WeatherType.SUNNY || WeatherType.HARSH_SUN), BattleStatMultiplierAbAttr, BattleStat.SPDEF, 1.5) + .attr(PostWeatherChangeAbAttr) .attr(UncopiableAbilityAbAttr) .attr(NoFusionAbilityAbAttr) .ignorable(), @@ -3137,6 +3139,7 @@ export function initAbilities() { new Ability(Abilities.PROTOSYNTHESIS, "Protosynthesis", "Boosts the Pokémon's most proficient stat in harsh sunlight or if the Pokémon is holding Booster Energy.", 9) .conditionalAttr(getWeatherCondition(WeatherType.SUNNY, WeatherType.HARSH_SUN), PostSummonAddBattlerTagAbAttr, BattlerTagType.PROTOSYNTHESIS, 0, true) .attr(PostWeatherChangeAddBattlerTagAttr, BattlerTagType.PROTOSYNTHESIS, 0, WeatherType.SUNNY, WeatherType.HARSH_SUN) + .attr(UnsuppressableAbilityAbAttr) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) .attr(NoTransformAbilityAbAttr), diff --git a/src/data/pokemon-forms.ts b/src/data/pokemon-forms.ts index 4bf7b7ac875..ca5a86d2838 100644 --- a/src/data/pokemon-forms.ts +++ b/src/data/pokemon-forms.ts @@ -7,6 +7,9 @@ import { Species } from "./enums/species"; import { StatusEffect } from "./status-effect"; import { MoveCategory, allMoves } from "./move"; import { Abilities } from "./enums/abilities"; +import { WeatherType } from "./weather"; +import { UnsuppressableAbilityAbAttr } from "./ability"; +import { Ability } from "pokenode-ts"; export enum FormChangeItem { NONE, @@ -228,6 +231,43 @@ export class SpeciesFormChangeActiveTrigger extends SpeciesFormChangeTrigger { } } +//checks the current weather in battle to determine form +export class SpeciesFormChangeWeatherTrigger extends SpeciesFormChangeTrigger { + public weatherType: WeatherType[]; + public invert: boolean; + + constructor(weatherType: WeatherType | WeatherType[], invert:boolean = false){ + super(); + if(!Array.isArray(weatherType)) + weatherType = [weatherType]; + + this.weatherType = weatherType; + this.invert = invert; + } + + canChange(pokemon: Pokemon): boolean { + if(!pokemon.scene.arena.weather){ + return this.weatherType.indexOf(WeatherType.NONE) > -1 !== this.invert; + } + return this.weatherType.indexOf(pokemon.scene.arena.weather.weatherType) > -1 !== this.invert; + } +} + +export class SpeciesFormChangeAbilitySuppressionTrigger extends SpeciesFormChangeTrigger { + public ability : Abilities + public invert: boolean; + + constructor(ability : Abilities, invert:boolean = false){ + super(); + this.ability = ability + this.invert = invert; + } + + canChange(pokemon: Pokemon): boolean { + return pokemon.hasAbility(this.ability) !== this.invert; + } +} + export class SpeciesFormChangeStatusEffectTrigger extends SpeciesFormChangeTrigger { public statusEffects: StatusEffect[]; public invert: boolean; @@ -284,6 +324,7 @@ export class SpeciesFormChangePostMoveTrigger extends SpeciesFormChangeMoveTrigg } } +//Trigger for subforms having their own species form change that aren't interchangable, string check for the forms to match export class SpeciesDefaultFormMatchTrigger extends SpeciesFormChangeTrigger { private formKey: string; @@ -297,6 +338,7 @@ export class SpeciesDefaultFormMatchTrigger extends SpeciesFormChangeTrigger { } } + export function getSpeciesFormChangeMessage(pokemon: Pokemon, formChange: SpeciesFormChange, preName: string): string { const isMega = formChange.formKey.indexOf(SpeciesFormKey.MEGA) > -1; const isGmax = formChange.formKey.indexOf(SpeciesFormKey.GIGANTAMAX) > -1; @@ -674,6 +716,29 @@ export const pokemonFormChanges: PokemonFormChanges = { [Species.GALAR_DARMANITAN]: [ new SpeciesFormChange(Species.GALAR_DARMANITAN, '', 'zen', new SpeciesFormChangeManualTrigger(), true), new SpeciesFormChange(Species.GALAR_DARMANITAN, 'zen', '', new SpeciesFormChangeManualTrigger(), true) + ], + [Species.CASTFORM]: [ + //change to fire + new SpeciesFormChange(Species.CASTFORM, '', 'sunny', new SpeciesFormChangeWeatherTrigger([WeatherType.HARSH_SUN, WeatherType.SUNNY]), true, new SpeciesFormChangeCondition(p => p.hasAbility(Abilities.FORECAST))), + new SpeciesFormChange(Species.CASTFORM, 'rainy', 'sunny', new SpeciesFormChangeWeatherTrigger([WeatherType.HARSH_SUN, WeatherType.SUNNY]), true, new SpeciesFormChangeCondition(p => p.hasAbility(Abilities.FORECAST))), + new SpeciesFormChange(Species.CASTFORM, 'snowy', 'sunny', new SpeciesFormChangeWeatherTrigger([WeatherType.HARSH_SUN, WeatherType.SUNNY]), true, new SpeciesFormChangeCondition(p => p.hasAbility(Abilities.FORECAST))), + //change to water + new SpeciesFormChange(Species.CASTFORM, '', 'rainy', new SpeciesFormChangeWeatherTrigger([WeatherType.HEAVY_RAIN, WeatherType.RAIN]), true, new SpeciesFormChangeCondition(p => p.hasAbility(Abilities.FORECAST))), + new SpeciesFormChange(Species.CASTFORM, 'sunny', 'rainy', new SpeciesFormChangeWeatherTrigger([WeatherType.HEAVY_RAIN, WeatherType.RAIN]), true, new SpeciesFormChangeCondition(p => p.hasAbility(Abilities.FORECAST))), + new SpeciesFormChange(Species.CASTFORM, 'snowy', 'rainy', new SpeciesFormChangeWeatherTrigger([WeatherType.HEAVY_RAIN, WeatherType.RAIN]), true, new SpeciesFormChangeCondition(p => p.hasAbility(Abilities.FORECAST))),//loving in the moonlight + //change to ice + new SpeciesFormChange(Species.CASTFORM, '', 'snowy', new SpeciesFormChangeWeatherTrigger([WeatherType.SNOW, WeatherType.HAIL]), true, new SpeciesFormChangeCondition(p => p.hasAbility(Abilities.FORECAST))), + new SpeciesFormChange(Species.CASTFORM, 'sunny', 'snowy', new SpeciesFormChangeWeatherTrigger([WeatherType.SNOW, WeatherType.HAIL]), true, new SpeciesFormChangeCondition(p => p.hasAbility(Abilities.FORECAST))), + new SpeciesFormChange(Species.CASTFORM, 'rainy', 'snowy', new SpeciesFormChangeWeatherTrigger([WeatherType.SNOW, WeatherType.HAIL]), true, new SpeciesFormChangeCondition(p => p.hasAbility(Abilities.FORECAST))),//having a wonderful time + //change to normal + new SpeciesFormChange(Species.CASTFORM, 'sunny', '', new SpeciesFormChangeWeatherTrigger([WeatherType.FOG, WeatherType.NONE, WeatherType.SANDSTORM, WeatherType.STRONG_WINDS]), true, new SpeciesFormChangeCondition(p => p.hasAbility(Abilities.FORECAST))), + new SpeciesFormChange(Species.CASTFORM, 'rainy', '', new SpeciesFormChangeWeatherTrigger([WeatherType.FOG, WeatherType.NONE, WeatherType.SANDSTORM, WeatherType.STRONG_WINDS]), true, new SpeciesFormChangeCondition(p => p.hasAbility(Abilities.FORECAST))), + new SpeciesFormChange(Species.CASTFORM, 'snowy', '', new SpeciesFormChangeWeatherTrigger([WeatherType.FOG, WeatherType.NONE, WeatherType.SANDSTORM, WeatherType.STRONG_WINDS]), true, new SpeciesFormChangeCondition(p => p.hasAbility(Abilities.FORECAST))) + ], + [Species.CHERRIM]:[ + //the seasonal depression pokemon + new SpeciesFormChange(Species.CHERRIM, 'overcast', 'sunshine', new SpeciesFormChangeWeatherTrigger([WeatherType.HARSH_SUN, WeatherType.SUNNY]), true), + new SpeciesFormChange(Species.CHERRIM, 'sunshine', 'overcast', new SpeciesFormChangeWeatherTrigger([WeatherType.HARSH_SUN, WeatherType.SUNNY], true), true) ] }; diff --git a/src/field/arena.ts b/src/field/arena.ts index 910d998d68e..fd7973eea80 100644 --- a/src/field/arena.ts +++ b/src/field/arena.ts @@ -14,6 +14,7 @@ import { ArenaTagType } from "../data/enums/arena-tag-type"; import { TrainerType } from "../data/enums/trainer-type"; import { BattlerIndex } from "../battle"; import { Moves } from "../data/enums/moves"; +import { SpeciesFormChangeWeatherTrigger } from "../data/pokemon-forms"; import { TimeOfDay } from "../data/enums/time-of-day"; import { Terrain, TerrainType } from "../data/terrain"; import { PostTerrainChangeAbAttr, PostWeatherChangeAbAttr, applyPostTerrainChangeAbAttrs, applyPostWeatherChangeAbAttrs } from "../data/ability"; @@ -303,8 +304,16 @@ export class Arena { } this.scene.getField(true).filter(p => p.isOnField()).map(pokemon => { - pokemon.findAndRemoveTags(t => 'weatherTypes' in t && !(t.weatherTypes as WeatherType[]).find(t => t === weather)); + pokemon.findAndRemoveTags(t => 'weatherTypes' in t && !(t.weatherTypes as WeatherType[]).find(t => t === weather)); applyPostWeatherChangeAbAttrs(PostWeatherChangeAbAttr, pokemon, weather); + + if(this.weather){ + this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeWeatherTrigger, false ); + } + else{ + this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeWeatherTrigger, true ); + } + // }); return true; diff --git a/src/phases.ts b/src/phases.ts index 038907d9400..b3723df538e 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -45,7 +45,7 @@ import { vouchers } from "./system/voucher"; import { loggedInUser, updateUserInfo } from "./account"; import { PlayerGender, SessionSaveData } from "./system/game-data"; import { addPokeballCaptureStars, addPokeballOpenParticles } from "./field/anims"; -import { SpeciesFormChangeActiveTrigger, SpeciesFormChangeManualTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangePreMoveTrigger } from "./data/pokemon-forms"; +import { SpeciesFormChangeActiveTrigger, SpeciesFormChangeManualTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangePreMoveTrigger, SpeciesFormChangeWeatherTrigger} from "./data/pokemon-forms"; import { battleSpecDialogue, getCharVariantFromDialogue } from "./data/dialogue"; import ModifierSelectUiHandler, { SHOP_OPTIONS_ROW_LIMIT } from "./ui/modifier-select-ui-handler"; import { Setting } from "./system/settings"; @@ -1292,7 +1292,7 @@ export class SummonPhase extends PartyMemberPokemonPhase { if (!this.loaded || this.scene.currentBattle.battleType === BattleType.TRAINER || (this.scene.currentBattle.waveIndex % 10) === 1) { this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true); - + this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeWeatherTrigger, false); this.queuePostSummon(); } } @@ -2796,8 +2796,7 @@ export class WeatherEffectPhase extends CommonAnimPhase { } this.scene.ui.showText(getWeatherLapseMessage(this.weather.weatherType), null, () => { - this.executeForAll((pokemon: Pokemon) => applyPostWeatherLapseAbAttrs(PostWeatherLapseAbAttr, pokemon, this.weather)); - + this.executeForAll((pokemon: Pokemon) => applyPostWeatherLapseAbAttrs(PostWeatherLapseAbAttr, pokemon, this.weather)); super.start(); }); }