Add Schooling ability for Wishiwashi and fix Beast Boost

This commit is contained in:
Flashfyre 2024-03-30 00:53:35 -04:00
parent 0bd941d6a1
commit dbca257a76
4 changed files with 97 additions and 6 deletions

View File

@ -14,6 +14,7 @@ import { Stat } from "./pokemon-stat";
import { PokemonHeldItemModifier } from "../modifier/modifier"; import { PokemonHeldItemModifier } from "../modifier/modifier";
import { Moves } from "./enums/moves"; import { Moves } from "./enums/moves";
import { TerrainType } from "./terrain"; import { TerrainType } from "./terrain";
import { SpeciesFormChangeManualTrigger } from "./pokemon-forms";
export class Ability { export class Ability {
public id: Abilities; public id: Abilities;
@ -130,6 +131,30 @@ export class DoubleBattleChanceAbAttr extends AbAttr {
} }
} }
export class PostBattleInitAbAttr extends AbAttr {
applyPostBattleInit(pokemon: Pokemon, args: any[]): boolean | Promise<boolean> {
return false;
}
}
export class PostBattleInitFormChangeAbAttr extends PostBattleInitAbAttr {
private formFunc: (p: Pokemon) => integer;
constructor(formFunc: ((p: Pokemon) => integer)) {
super(true);
this.formFunc = formFunc;
}
applyPostBattleInit(pokemon: Pokemon, args: any[]): boolean {
const formIndex = this.formFunc(pokemon);
if (formIndex !== pokemon.formIndex)
return pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false);
return false;
}
}
type PreDefendAbAttrCondition = (pokemon: Pokemon, attacker: Pokemon, move: PokemonMove) => boolean; type PreDefendAbAttrCondition = (pokemon: Pokemon, attacker: Pokemon, move: PokemonMove) => boolean;
export class PreDefendAbAttr extends AbAttr { export class PreDefendAbAttr extends AbAttr {
@ -786,6 +811,24 @@ export class PostSummonTerrainChangeAbAttr extends PostSummonAbAttr {
} }
} }
export class PostSummonFormChangeAbAttr extends PostSummonAbAttr {
private formFunc: (p: Pokemon) => integer;
constructor(formFunc: ((p: Pokemon) => integer)) {
super(true);
this.formFunc = formFunc;
}
applyPostSummon(pokemon: Pokemon, args: any[]): boolean {
const formIndex = this.formFunc(pokemon);
if (formIndex !== pokemon.formIndex)
return pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false);
return false;
}
}
export class PostSummonTransformAbAttr extends PostSummonAbAttr { export class PostSummonTransformAbAttr extends PostSummonAbAttr {
constructor() { constructor() {
super(true); super(true);
@ -1174,6 +1217,26 @@ export class PostTurnHealAbAttr extends PostTurnAbAttr {
} }
} }
export class PostTurnFormChangeAbAttr extends PostTurnAbAttr {
private formFunc: (p: Pokemon) => integer;
constructor(formFunc: ((p: Pokemon) => integer)) {
super(true);
this.formFunc = formFunc;
}
applyPostTurn(pokemon: Pokemon, args: any[]): boolean {
const formIndex = this.formFunc(pokemon);
if (formIndex !== pokemon.formIndex) {
pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false);
return true;
}
return false;
}
}
export class StatChangeMultiplierAbAttr extends AbAttr { export class StatChangeMultiplierAbAttr extends AbAttr {
private multiplier: integer; private multiplier: integer;
@ -1481,6 +1544,11 @@ export function applyAbAttrs(attrType: { new(...args: any[]): AbAttr }, pokemon:
return applyAbAttrsInternal<AbAttr>(attrType, pokemon, attr => attr.apply(pokemon, cancelled, args)); return applyAbAttrsInternal<AbAttr>(attrType, pokemon, attr => attr.apply(pokemon, cancelled, args));
} }
export function applyPostBattleInitAbAttrs(attrType: { new(...args: any[]): PostBattleInitAbAttr },
pokemon: Pokemon, ...args: any[]): Promise<void> {
return applyAbAttrsInternal<PostBattleInitAbAttr>(attrType, pokemon, attr => attr.applyPostBattleInit(pokemon, args));
}
export function applyPreDefendAbAttrs(attrType: { new(...args: any[]): PreDefendAbAttr }, export function applyPreDefendAbAttrs(attrType: { new(...args: any[]): PreDefendAbAttr },
pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> { pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
const simulated = args.length > 1 && args[1]; const simulated = args.length > 1 && args[1];
@ -2337,7 +2405,10 @@ export function initAbilities() {
new Ability(Abilities.GALVANIZE, "Galvanize (N)", "Normal-type moves become Electric-type moves. The power of those moves is boosted a little.", 7), new Ability(Abilities.GALVANIZE, "Galvanize (N)", "Normal-type moves become Electric-type moves. The power of those moves is boosted a little.", 7),
new Ability(Abilities.SURGE_SURFER, "Surge Surfer", "Doubles the Pokémon's Speed stat on Electric Terrain.", 7) new Ability(Abilities.SURGE_SURFER, "Surge Surfer", "Doubles the Pokémon's Speed stat on Electric Terrain.", 7)
.conditionalAttr(getTerrainCondition(TerrainType.ELECTRIC), BattleStatMultiplierAbAttr, BattleStat.SPD, 2), .conditionalAttr(getTerrainCondition(TerrainType.ELECTRIC), BattleStatMultiplierAbAttr, BattleStat.SPD, 2),
new Ability(Abilities.SCHOOLING, "Schooling (N)", "When it has a lot of HP, the Pokémon forms a powerful school. It stops schooling when its HP is low.", 7) new Ability(Abilities.SCHOOLING, "Schooling", "When it has a lot of HP, the Pokémon forms a powerful school. It stops schooling when its HP is low.", 7)
.attr(PostBattleInitFormChangeAbAttr, p => p.getHpRatio() <= 0.25 ? 0 : 1)
.attr(PostSummonFormChangeAbAttr, p => p.getHpRatio() <= 0.25 ? 0 : 1)
.attr(PostTurnFormChangeAbAttr, p => p.getHpRatio() <= 0.25 ? 0 : 1)
.attr(ProtectAbilityAbAttr), .attr(ProtectAbilityAbAttr),
new Ability(Abilities.DISGUISE, "Disguise (N)", "Once per battle, the shroud that covers the Pokémon can protect it from an attack.", 7) new Ability(Abilities.DISGUISE, "Disguise (N)", "Once per battle, the shroud that covers the Pokémon can protect it from an attack.", 7)
.ignorable() .ignorable()
@ -2365,7 +2436,19 @@ export function initAbilities() {
new Ability(Abilities.RECEIVER, "Receiver (N)", "The Pokémon copies the Ability of a defeated ally.", 7), new Ability(Abilities.RECEIVER, "Receiver (N)", "The Pokémon copies the Ability of a defeated ally.", 7),
new Ability(Abilities.POWER_OF_ALCHEMY, "Power of Alchemy (N)", "The Pokémon copies the Ability of a defeated ally.", 7), new Ability(Abilities.POWER_OF_ALCHEMY, "Power of Alchemy (N)", "The Pokémon copies the Ability of a defeated ally.", 7),
new Ability(Abilities.BEAST_BOOST, "Beast Boost", "The Pokémon boosts its most proficient stat each time it knocks out a Pokémon.", 7) new Ability(Abilities.BEAST_BOOST, "Beast Boost", "The Pokémon boosts its most proficient stat each time it knocks out a Pokémon.", 7)
.attr(PostVictoryStatChangeAbAttr, p => Utils.getEnumValues(BattleStat).slice(1, -2).map(s => s as BattleStat).findIndex(bs => p.getStat((bs + 1) as Stat)), 1), .attr(PostVictoryStatChangeAbAttr, p => {
const battleStats = Utils.getEnumValues(BattleStat).slice(0, -3).map(s => s as BattleStat);
let highestBattleStat = 0;
let highestBattleStatIndex = 0;
battleStats.map((bs: BattleStat, i: integer) => {
const stat = p.getStat(bs + 1);
if (stat > highestBattleStat) {
highestBattleStatIndex = i;
highestBattleStat = stat;
}
});
return highestBattleStatIndex;
}, 1),
new Ability(Abilities.RKS_SYSTEM, "RKS System (N)", "Changes the Pokémon's type to match the memory disc it holds.", 7) new Ability(Abilities.RKS_SYSTEM, "RKS System (N)", "Changes the Pokémon's type to match the memory disc it holds.", 7)
.attr(ProtectAbilityAbAttr), .attr(ProtectAbilityAbAttr),
new Ability(Abilities.ELECTRIC_SURGE, "Electric Surge", "Turns the ground into Electric Terrain when the Pokémon enters a battle.", 7) new Ability(Abilities.ELECTRIC_SURGE, "Electric Surge", "Turns the ground into Electric Terrain when the Pokémon enters a battle.", 7)

View File

@ -518,6 +518,10 @@ export const pokemonFormChanges: PokemonFormChanges = {
[Species.HOOPA]: [ [Species.HOOPA]: [
new SpeciesFormChange(Species.HOOPA, '', 'unbound', new SpeciesFormChangeItemTrigger(FormChangeItem.PRISON_BOTTLE)) new SpeciesFormChange(Species.HOOPA, '', 'unbound', new SpeciesFormChangeItemTrigger(FormChangeItem.PRISON_BOTTLE))
], ],
[Species.WISHIWASHI]: [
new SpeciesFormChange(Species.WISHIWASHI, '', 'school', new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.WISHIWASHI, 'school', '', new SpeciesFormChangeManualTrigger(), true)
],
[Species.NECROZMA]: [ [Species.NECROZMA]: [
new SpeciesFormChange(Species.NECROZMA, '', 'dawn-wings', new SpeciesFormChangeItemTrigger(FormChangeItem.N_LUNARIZER)), new SpeciesFormChange(Species.NECROZMA, '', 'dawn-wings', new SpeciesFormChangeItemTrigger(FormChangeItem.N_LUNARIZER)),
new SpeciesFormChange(Species.NECROZMA, '', 'dusk-mane', new SpeciesFormChangeItemTrigger(FormChangeItem.N_SOLARIZER)) new SpeciesFormChange(Species.NECROZMA, '', 'dusk-mane', new SpeciesFormChangeItemTrigger(FormChangeItem.N_SOLARIZER))

View File

@ -2514,7 +2514,7 @@ export class EnemyPokemon extends Pokemon {
while (segmentIndex - 1 < this.bossSegmentIndex) { while (segmentIndex - 1 < this.bossSegmentIndex) {
let boostedStat = BattleStat.RAND; let boostedStat = BattleStat.RAND;
const battleStats = Utils.getEnumValues(BattleStat).slice(0, -2); const battleStats = Utils.getEnumValues(BattleStat).slice(0, -3);
const statWeights = new Array().fill(battleStats.length).filter((bs: BattleStat) => this.summonData.battleStats[bs] < 6).map((bs: BattleStat) => this.getStat(bs + 1)); const statWeights = new Array().fill(battleStats.length).filter((bs: BattleStat) => this.summonData.battleStats[bs] < 6).map((bs: BattleStat) => this.getStat(bs + 1));
const statThresholds: integer[] = []; const statThresholds: integer[] = [];
let totalWeight = 0; let totalWeight = 0;

View File

@ -30,7 +30,7 @@ import { Weather, WeatherType, getRandomWeatherType, getTerrainBlockMessage, get
import { TempBattleStat } from "./data/temp-battle-stat"; import { TempBattleStat } from "./data/temp-battle-stat";
import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag"; import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag";
import { ArenaTagType } from "./data/enums/arena-tag-type"; import { ArenaTagType } from "./data/enums/arena-tag-type";
import { Abilities, CheckTrappedAbAttr, MoveAbilityBypassAbAttr, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr } from "./data/ability"; import { Abilities, CheckTrappedAbAttr, MoveAbilityBypassAbAttr, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, applyPostBattleInitAbAttrs, PostBattleInitAbAttr } from "./data/ability";
import { Unlockables, getUnlockableName } from "./system/unlockables"; import { Unlockables, getUnlockableName } from "./system/unlockables";
import { getBiomeKey } from "./field/arena"; import { getBiomeKey } from "./field/arena";
import { BattleType, BattlerIndex, TurnCommand } from "./battle"; import { BattleType, BattlerIndex, TurnCommand } from "./battle";
@ -811,13 +811,17 @@ export class EncounterPhase extends BattlePhase {
if (!this.loaded) { if (!this.loaded) {
const availablePartyMembers = this.scene.getParty().filter(p => !p.isFainted()); const availablePartyMembers = this.scene.getParty().filter(p => !p.isFainted());
if (!availablePartyMembers[0].isOnField()) if (availablePartyMembers[0].isOnField())
applyPostBattleInitAbAttrs(PostBattleInitAbAttr, availablePartyMembers[0]);
else
this.scene.pushPhase(new SummonPhase(this.scene, 0)); this.scene.pushPhase(new SummonPhase(this.scene, 0));
if (this.scene.currentBattle.double) { if (this.scene.currentBattle.double) {
if (availablePartyMembers.length > 1) { if (availablePartyMembers.length > 1) {
this.scene.pushPhase(new ToggleDoublePositionPhase(this.scene, true)); this.scene.pushPhase(new ToggleDoublePositionPhase(this.scene, true));
if (!availablePartyMembers[1].isOnField()) if (availablePartyMembers[1].isOnField())
applyPostBattleInitAbAttrs(PostBattleInitAbAttr, availablePartyMembers[1]);
else
this.scene.pushPhase(new SummonPhase(this.scene, 1)); this.scene.pushPhase(new SummonPhase(this.scene, 1));
} }
} else { } else {