diff --git a/src/data/pokemon-evolutions.ts b/src/data/pokemon-evolutions.ts index c02182b422a..c41e1334962 100644 --- a/src/data/pokemon-evolutions.ts +++ b/src/data/pokemon-evolutions.ts @@ -85,6 +85,16 @@ export class SpeciesEvolution extends SpeciesFormEvolution { } } +export class FusionSpeciesFormEvolution extends SpeciesFormEvolution { + public primarySpeciesId: Species; + + constructor(primarySpeciesId: Species, evolution: SpeciesFormEvolution) { + super(evolution.speciesId, evolution.preFormKey, evolution.evoFormKey, evolution.level, evolution.item, evolution.condition, evolution.wildDelay); + + this.primarySpeciesId = primarySpeciesId; + } +} + export class SpeciesEvolutionCondition { public predicate: EvolutionConditionPredicate; public enforceFunc: EvolutionConditionEnforceFunc; diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 8d9bec6d081..241f74addb3 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -13,7 +13,7 @@ import { PokeballType } from '../data/pokeball'; import { Gender } from '../data/gender'; import { initMoveAnim, loadMoveAnimAssets } from '../data/battle-anims'; import { Status, StatusEffect } from '../data/status-effect'; -import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEvolutionCondition } from '../data/pokemon-evolutions'; +import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEvolutionCondition, FusionSpeciesFormEvolution } from '../data/pokemon-evolutions'; import { reverseCompatibleTms, tmSpecies } from '../data/tms'; import { DamagePhase, FaintPhase, LearnMovePhase, ObtainStatusEffectPhase, StatChangePhase, SwitchSummonPhase } from '../phases'; import { BattleStat } from '../data/battle-stat'; @@ -620,6 +620,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return this.shiny || (this.fusionSpecies && this.fusionShiny); } + isFusion(): boolean { + return !!this.fusionSpecies; + } + abstract isBoss(): boolean; getMoveset(ignoreOverride?: boolean): PokemonMove[] { @@ -766,14 +770,23 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } getEvolution(): SpeciesFormEvolution { - if (!pokemonEvolutions.hasOwnProperty(this.species.speciesId)) - return null; + if (pokemonEvolutions.hasOwnProperty(this.species.speciesId)) { + const evolutions = pokemonEvolutions[this.species.speciesId]; + for (let e of evolutions) { + if (!e.item && this.level >= e.level && (!e.preFormKey || this.getFormKey() === e.preFormKey)) { + if (e.condition === null || (e.condition as SpeciesEvolutionCondition).predicate(this)) + return e; + } + } + } - const evolutions = pokemonEvolutions[this.species.speciesId]; - for (let e of evolutions) { - if (!e.item && this.level >= e.level && (!e.preFormKey || this.getFormKey() === e.preFormKey)) { - if (e.condition === null || (e.condition as SpeciesEvolutionCondition).predicate(this)) - return e; + if (this.isFusion() && pokemonEvolutions.hasOwnProperty(this.fusionSpecies.speciesId)) { + const fusionEvolutions = pokemonEvolutions[this.fusionSpecies.speciesId].map(e => new FusionSpeciesFormEvolution(this.species.speciesId, e)); + for (let fe of fusionEvolutions) { + if (!fe.item && this.level >= fe.level && (!fe.preFormKey || this.getFusionFormKey() === fe.preFormKey)) { + if (fe.condition === null || (fe.condition as SpeciesEvolutionCondition).predicate(this)) + return fe; + } } } @@ -2116,9 +2129,21 @@ export class PlayerPokemon extends Pokemon { getPossibleEvolution(evolution: SpeciesFormEvolution): Promise { return new Promise(resolve => { - const species = getPokemonSpecies(evolution.speciesId); - const formIndex = evolution.evoFormKey !== null ? Math.max(species.forms.findIndex(f => f.formKey === evolution.evoFormKey), 0) : this.formIndex; - const ret = this.scene.addPlayerPokemon(species, this.level, this.abilityIndex, formIndex, this.gender, this.shiny, this.ivs, this.nature, this); + const evolutionSpecies = getPokemonSpecies(evolution.speciesId); + const isFusion = evolution instanceof FusionSpeciesFormEvolution; + let ret: PlayerPokemon; + if (isFusion) { + const originalFusionSpecies = this.fusionSpecies; + const originalFusionFormIndex = this.fusionFormIndex; + this.fusionSpecies = evolutionSpecies; + this.fusionFormIndex = evolution.evoFormKey !== null ? Math.max(evolutionSpecies.forms.findIndex(f => f.formKey === evolution.evoFormKey), 0) : this.fusionFormIndex; + ret = this.scene.addPlayerPokemon(this.species, this.level, this.abilityIndex, this.formIndex, this.gender, this.shiny, this.ivs, this.nature, this); + this.fusionSpecies = originalFusionSpecies; + this.fusionFormIndex = originalFusionFormIndex; + } else { + const formIndex = evolution.evoFormKey !== null && !isFusion ? Math.max(evolutionSpecies.forms.findIndex(f => f.formKey === evolution.evoFormKey), 0) : this.formIndex; + ret = this.scene.addPlayerPokemon(!isFusion ? evolutionSpecies : this.species, this.level, this.abilityIndex, formIndex, this.gender, this.shiny, this.ivs, this.nature, this); + } ret.loadAssets().then(() => resolve(ret)); }); } @@ -2127,13 +2152,28 @@ export class PlayerPokemon extends Pokemon { return new Promise(resolve => { this.pauseEvolutions = false; this.handleSpecialEvolutions(evolution); - this.species = getPokemonSpecies(evolution.speciesId); - if (evolution.preFormKey !== null) - this.formIndex = Math.max(this.species.forms.findIndex(f => f.formKey === evolution.evoFormKey), 0); + const isFusion = evolution instanceof FusionSpeciesFormEvolution; + if (!isFusion) + this.species = getPokemonSpecies(evolution.speciesId); + else + this.fusionSpecies = getPokemonSpecies(evolution.speciesId); + if (evolution.preFormKey !== null) { + const formIndex = Math.max((!isFusion ? this.species : this.fusionSpecies).forms.findIndex(f => f.formKey === evolution.evoFormKey), 0); + if (!isFusion) + this.formIndex = formIndex; + else + this.fusionFormIndex = formIndex; + } this.generateName(); - const abilityCount = this.getSpeciesForm().getAbilityCount(); - if (this.abilityIndex >= abilityCount) // Shouldn't happen - this.abilityIndex = abilityCount - 1; + if (!isFusion) { + const abilityCount = this.getSpeciesForm().getAbilityCount(); + if (this.abilityIndex >= abilityCount) // Shouldn't happen + this.abilityIndex = abilityCount - 1; + } else { + const abilityCount = this.getFusionSpeciesForm().getAbilityCount(); + if (this.fusionAbilityIndex >= abilityCount) // Shouldn't happen + this.fusionAbilityIndex = abilityCount - 1; + } this.compatibleTms.splice(0, this.compatibleTms.length); this.generateCompatibleTms(); const updateAndResolve = () => { @@ -2152,11 +2192,17 @@ export class PlayerPokemon extends Pokemon { } private handleSpecialEvolutions(evolution: SpeciesFormEvolution) { - if (this.species.speciesId === Species.NINCADA && evolution.speciesId === Species.NINJASK) { + const isFusion = evolution instanceof FusionSpeciesFormEvolution; + if ((!isFusion ? this.species : this.fusionSpecies).speciesId === Species.NINCADA && evolution.speciesId === Species.NINJASK) { const newEvolution = pokemonEvolutions[this.species.speciesId][1]; if (newEvolution.condition.predicate(this)) { const newPokemon = this.scene.addPlayerPokemon(this.species, this.level, this.abilityIndex, this.formIndex, this.gender, this.shiny, this.ivs, this.nature); newPokemon.natureOverride = this.natureOverride; + newPokemon.fusionSpecies = this.fusionSpecies; + newPokemon.fusionFormIndex = this.fusionFormIndex; + newPokemon.fusionAbilityIndex = this.fusionAbilityIndex; + newPokemon.fusionShiny = this.fusionShiny; + newPokemon.fusionGender = this.fusionGender; this.scene.getParty().push(newPokemon); newPokemon.evolve(newEvolution); const modifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier @@ -2203,10 +2249,6 @@ export class PlayerPokemon extends Pokemon { }); } - isFusion(): boolean { - return !!this.fusionSpecies; - } - clearFusionSpecies(): void { super.clearFusionSpecies(); this.generateCompatibleTms(); diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 9ddc6de50ba..bd1bfda8068 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -513,6 +513,9 @@ export class EvolutionItemModifierType extends PokemonModifierType implements Ge if (pokemonEvolutions.hasOwnProperty(pokemon.species.speciesId) && pokemonEvolutions[pokemon.species.speciesId].filter(e => e.item === this.evolutionItem && (!e.condition || e.condition.predicate(pokemon))).length) return null; + else if (pokemon.isFusion() && pokemonEvolutions.hasOwnProperty(pokemon.fusionSpecies.speciesId) && pokemonEvolutions[pokemon.fusionSpecies.speciesId].filter(e => e.item === this.evolutionItem + && (!e.condition || e.condition.predicate(pokemon))).length) + return null; return PartyUiHandler.NoEffectMessage; }, EvolutionItem[evolutionItem].toLowerCase()); @@ -621,10 +624,16 @@ class EvolutionItemModifierTypeGenerator extends ModifierTypeGenerator { if (pregenArgs) return new EvolutionItemModifierType(pregenArgs[0] as EvolutionItem); - const evolutionItemPool = party.filter(p => pokemonEvolutions.hasOwnProperty(p.species.speciesId)).map(p => { - const evolutions = pokemonEvolutions[p.species.speciesId]; - return evolutions.filter(e => e.item !== EvolutionItem.NONE && (e.evoFormKey === null || (e.preFormKey || '') === p.getFormKey()) && (!e.condition || e.condition.predicate(p))); - }).flat().flatMap(e => e.item).filter(i => (i > 50) === rare); + const evolutionItemPool = [ + party.filter(p => pokemonEvolutions.hasOwnProperty(p.species.speciesId)).map(p => { + const evolutions = pokemonEvolutions[p.species.speciesId]; + return evolutions.filter(e => e.item !== EvolutionItem.NONE && (e.evoFormKey === null || (e.preFormKey || '') === p.getFormKey()) && (!e.condition || e.condition.predicate(p))); + }).flat(), + party.filter(p => p.isFusion() && pokemonEvolutions.hasOwnProperty(p.fusionSpecies.speciesId)).map(p => { + const evolutions = pokemonEvolutions[p.fusionSpecies.speciesId]; + return evolutions.filter(e => e.item !== EvolutionItem.NONE && (e.evoFormKey === null || (e.preFormKey || '') === p.getFusionFormKey()) && (!e.condition || e.condition.predicate(p))); + }).flat() + ].flat().flatMap(e => e.item).filter(i => (i > 50) === rare); if (!evolutionItemPool.length) return null; diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 1604f91b886..5a2474532f8 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -8,7 +8,7 @@ import { Stat } from "../data/pokemon-stat"; import { addTextObject, TextStyle } from "../ui/text"; import { Type } from '../data/type'; import { EvolutionPhase } from '../evolution-phase'; -import { pokemonEvolutions } from '../data/pokemon-evolutions'; +import { FusionSpeciesFormEvolution, pokemonEvolutions } from '../data/pokemon-evolutions'; import { getPokemonMessage } from '../messages'; import * as Utils from "../utils"; import { TempBattleStat } from '../data/temp-battle-stat'; @@ -1183,10 +1183,18 @@ export class EvolutionItemModifier extends ConsumablePokemonModifier { apply(args: any[]): boolean { const pokemon = args[0] as PlayerPokemon; - const matchingEvolution = pokemonEvolutions[pokemon.species.speciesId].find(e => e.item === (this.type as ModifierTypes.EvolutionItemModifierType).evolutionItem + let matchingEvolution = pokemonEvolutions[pokemon.species.speciesId].find(e => e.item === (this.type as ModifierTypes.EvolutionItemModifierType).evolutionItem && (e.evoFormKey === null || (e.preFormKey || '') === pokemon.getFormKey()) && (!e.condition || e.condition.predicate(pokemon))); + if (!matchingEvolution && pokemon.isFusion()) { + matchingEvolution = pokemonEvolutions[pokemon.fusionSpecies.speciesId].find(e => e.item === (this.type as ModifierTypes.EvolutionItemModifierType).evolutionItem + && (e.evoFormKey === null || (e.preFormKey || '') === pokemon.getFusionFormKey()) + && (!e.condition || e.condition.predicate(pokemon))); + if (matchingEvolution) + matchingEvolution = new FusionSpeciesFormEvolution(pokemon.species.speciesId, matchingEvolution); + } + if (matchingEvolution) { pokemon.scene.unshiftPhase(new EvolutionPhase(pokemon.scene, pokemon, matchingEvolution, pokemon.level - 1)); return true; diff --git a/src/phases.ts b/src/phases.ts index 2c738cc4122..9a100af2eff 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -3752,7 +3752,8 @@ export class AttemptCapturePhase extends PokemonPhase { this.scene.playSound('pb_rel'); pokemon.setY(this.originalY); - pokemon.cry(pokemon.getHpRatio() > 0.25 ? undefined : { rate: 0.85 }); + if (pokemon.status?.effect !== StatusEffect.SLEEP) + pokemon.cry(pokemon.getHpRatio() > 0.25 ? undefined : { rate: 0.85 }); pokemon.tint(getPokeballTintColor(this.pokeballType)); pokemon.setVisible(true); pokemon.untint(250, 'Sine.easeOut');