Add form change system

pull/14/head
Flashfyre 2024-01-09 23:34:43 -05:00
parent e0b3ca064d
commit 6084d3aaa6
26 changed files with 3252 additions and 2365 deletions

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 599 B

View File

@ -39,6 +39,8 @@ import { vouchers } from "./system/voucher";
import { loggedInUser, updateUserInfo } from "./account";
import { GameDataType } from "./system/game-data";
import { addPokeballCaptureStars, addPokeballOpenParticles } from "./anims";
import { getPokemonSpecies } from "./data/pokemon-species";
import { SpeciesFormChangeActiveTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangeMoveUsedTrigger } from "./data/pokemon-forms";
export class LoginPhase extends BattlePhase {
private showText: boolean;
@ -883,6 +885,8 @@ export class SummonPhase extends PartyMemberPokemonPhase {
pokemon.resetTurnData();
this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);
this.queuePostSummon();
}
@ -938,6 +942,7 @@ export class SwitchSummonPhase extends SummonPhase {
onComplete: () => {
pokemon.setVisible(false);
this.scene.field.remove(pokemon);
this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);
this.scene.time.delayedCall(750, () => this.switchAndSummon());
}
});
@ -974,6 +979,8 @@ export class SwitchSummonPhase extends SummonPhase {
pokemon.transferSummon(this.lastPokemon);
this.lastPokemon?.resetSummonData();
this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);
}
queuePostSummon(): void {
@ -997,6 +1004,8 @@ export class ReturnPhase extends SwitchSummonPhase {
pokemon.resetTurnData();
pokemon.resetSummonData();
this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger);
}
}
@ -1844,6 +1853,8 @@ export class MoveEffectPhase extends PokemonPhase {
const hitResult = !isProtected ? target.apply(user, this.move) : HitResult.NO_EFFECT;
this.scene.triggerPokemonFormChange(user, SpeciesFormChangeMoveUsedTrigger);
applyAttrs.push(new Promise(resolve => {
applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).trigger === MoveEffectTrigger.PRE_APPLY,
user, target, this.move.getMove()).then(() => {
@ -2806,7 +2817,7 @@ export class LevelUpPhase extends PlayerPartyMemberPokemonPhase {
if (!pokemon.pauseEvolutions) {
const evolution = pokemon.getEvolution();
if (evolution)
this.scene.unshiftPhase(new EvolutionPhase(this.scene, this.partyMemberIndex, evolution, this.lastLevel));
this.scene.unshiftPhase(new EvolutionPhase(this.scene, pokemon as PlayerPokemon, evolution, this.lastLevel));
}
}
}
@ -2846,7 +2857,10 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
.then(() => {
this.scene.ui.setMode(messageMode).then(() => {
this.scene.playSoundWithoutBgm('level_up_fanfare', 1500);
this.scene.ui.showText(`${pokemon.name} learned\n${move.name}!`, null, () => this.end(), messageMode === Mode.EVOLUTION_SCENE ? 1000 : null, true);
this.scene.ui.showText(`${pokemon.name} learned\n${move.name}!`, null, () => {
this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeMoveLearnedTrigger, true);
this.end();
}, messageMode === Mode.EVOLUTION_SCENE ? 1000 : null, true);
});
});
});

View File

@ -5,7 +5,7 @@ import { EncounterPhase, SummonPhase, NextEncounterPhase, NewBiomeEncounterPhase
import Pokemon, { PlayerPokemon, EnemyPokemon } from './pokemon';
import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies, initSpecies, speciesStarters } from './data/pokemon-species';
import * as Utils from './utils';
import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonHpRestoreModifier, HealingBoosterModifier, PersistentModifier, PokemonHeldItemModifier, ModifierPredicate, DoubleBattleChanceBoosterModifier, FusePokemonModifier } from './modifier/modifier';
import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonHpRestoreModifier, HealingBoosterModifier, PersistentModifier, PokemonHeldItemModifier, ModifierPredicate, DoubleBattleChanceBoosterModifier, FusePokemonModifier, PokemonFormChangeItemModifier } from './modifier/modifier';
import { PokeballType } from './data/pokeball';
import { initAutoPlay } from './system/auto-play';
import { initCommonAnims, initMoveAnim, loadCommonAnimAssets, loadMoveAnimAssets, populateAnims } from './data/battle-anims';
@ -43,6 +43,8 @@ import UIPlugin from 'phaser3-rex-plugins/templates/ui/ui-plugin';
import { WindowVariant, getWindowVariantSuffix } from './ui/window';
import PokemonData from './system/pokemon-data';
import { Nature } from './data/nature';
import { SpeciesFormChangeTimeOfDayTrigger, SpeciesFormChangeTrigger, getSpeciesFormChangeMessage, pokemonFormChanges } from './data/pokemon-forms';
import { FormChangePhase, QuietFormChangePhase } from './form-change-phase';
const enableAuto = true;
const quickStart = false;
@ -99,6 +101,7 @@ export default class BattleScene extends Phaser.Scene {
private phaseQueuePrepend: BattlePhase[];
private phaseQueuePrependSpliceIndex: integer;
private currentPhase: BattlePhase;
private standbyPhase: BattlePhase;
public field: Phaser.GameObjects.Container;
public fieldUI: Phaser.GameObjects.Container;
public pbTray: PokeballTray;
@ -381,6 +384,7 @@ export default class BattleScene extends Phaser.Scene {
this.loadBgm('level_up_fanfare', 'bw/level_up_fanfare.mp3');
this.loadBgm('item_fanfare', 'bw/item_fanfare.mp3');
this.loadBgm('minor_fanfare', 'bw/minor_fanfare.mp3');
this.loadBgm('heal', 'bw/heal.mp3');
this.loadBgm('victory_trainer', 'bw/victory_trainer.mp3');
this.loadBgm('victory_gym', 'bw/victory_gym.mp3');
@ -806,9 +810,12 @@ export default class BattleScene extends Phaser.Scene {
this.arena.removeAllTags();
playerField.forEach((_, p) => this.unshiftPhase(new ReturnPhase(this, p)));
this.unshiftPhase(new ShowTrainerPhase(this));
}
for (let pokemon of this.getParty()) {
if (pokemon)
if (pokemon) {
if (resetArenaState)
pokemon.resetBattleData();
this.triggerPokemonFormChange(pokemon, SpeciesFormChangeTimeOfDayTrigger);
}
}
if (this.gameMode === GameMode.CLASSIC && !isNewBiome)
@ -843,7 +850,7 @@ export default class BattleScene extends Phaser.Scene {
return this.arena;
}
getSpeciesFormIndex(species: PokemonSpecies, gender?: Gender, ignoreArena?: boolean): integer {
getSpeciesFormIndex(species: PokemonSpecies, gender?: Gender, nature?: Nature, ignoreArena?: boolean): integer {
if (!species.forms?.length)
return 0;
@ -856,6 +863,11 @@ export default class BattleScene extends Phaser.Scene {
case Species.MEOWSTIC:
case Species.INDEEDEE:
return gender === Gender.FEMALE ? 1 : 0;
case Species.TOXTRICITY:
const lowkeyNatures = [ Nature.LONELY, Nature.BOLD, Nature.RELAXED, Nature.TIMID, Nature.SERIOUS, Nature.MODEST, Nature.MILD, Nature.QUIET, Nature.BASHFUL, Nature.CALM, Nature.GENTLE, Nature.CAREFUL ];
if (nature !== undefined && lowkeyNatures.indexOf(nature) > -1)
return 1;
return 0;
}
if (ignoreArena) {
@ -1292,6 +1304,10 @@ export default class BattleScene extends Phaser.Scene {
return this.currentPhase;
}
getStandbyPhase(): BattlePhase {
return this.standbyPhase;
}
pushPhase(phase: BattlePhase): void {
this.phaseQueue.push(phase);
}
@ -1316,6 +1332,12 @@ export default class BattleScene extends Phaser.Scene {
}
shiftPhase(): void {
if (this.standbyPhase) {
this.currentPhase = this.standbyPhase;
this.standbyPhase = null;
return;
}
if (this.phaseQueuePrependSpliceIndex > -1)
this.clearPhaseQueueSplice();
if (this.phaseQueuePrepend.length) {
@ -1328,6 +1350,17 @@ export default class BattleScene extends Phaser.Scene {
this.currentPhase.start();
}
overridePhase(phase: BattlePhase): boolean {
if (this.standbyPhase)
return false;
this.standbyPhase = this.currentPhase;
this.currentPhase = phase;
phase.start();
return true;
}
queueMessage(message: string, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer, defer?: boolean) {
const phase = new MessagePhase(this, message, callbackDelay, prompt, promptDelay);
if (!defer)
@ -1346,6 +1379,8 @@ export default class BattleScene extends Phaser.Scene {
this.validateAchvs(ModifierAchv, modifier);
if (modifier instanceof PersistentModifier) {
if ((modifier as PersistentModifier).add(this.modifiers, !!virtual, this)) {
if (modifier instanceof PokemonFormChangeItemModifier)
modifier.apply([ this.getPokemonById(modifier.pokemonId) ]);
if (playSound && !this.sound.get(soundName))
this.playSound(soundName);
} else if (!virtual) {
@ -1587,6 +1622,28 @@ export default class BattleScene extends Phaser.Scene {
return null;
}
triggerPokemonFormChange(pokemon: Pokemon, formChangeTriggerType: { new(...args: any[]): SpeciesFormChangeTrigger }, delayed: boolean = false, modal: boolean = false): boolean {
if (pokemonFormChanges.hasOwnProperty(pokemon.species.speciesId)) {
const matchingFormChange = pokemonFormChanges[pokemon.species.speciesId].find(fc => fc.findTrigger(formChangeTriggerType) && fc.canChange(pokemon));
if (matchingFormChange) {
let phase: BattlePhase;
if (pokemon instanceof PlayerPokemon && !matchingFormChange.quiet)
phase = new FormChangePhase(this, pokemon, matchingFormChange, modal);
else
phase = new QuietFormChangePhase(this, pokemon, matchingFormChange);
if (!matchingFormChange.quiet && modal)
this.overridePhase(phase);
else if (delayed)
this.pushPhase(phase);
else
this.unshiftPhase(phase);
return true;
}
}
return false;
}
validateAchvs(achvType: { new(...args: any[]): Achv }, ...args: any[]): void {
const filteredAchvs = Object.values(achvs).filter(a => a instanceof achvType);
for (let achv of filteredAchvs)

View File

@ -12,14 +12,14 @@ import { SpeciesFormKey } from "./pokemon-species";
import { WeatherType } from "./weather";
import { Biome } from "./biome";
import { TimeOfDay } from "../arena";
import { Nature } from "./nature";
export enum SpeciesWildEvolutionDelay {
NONE,
SHORT,
MEDIUM,
LONG,
VERY_LONG,
MEGA
VERY_LONG
}
export enum EvolutionItem {
@ -34,56 +34,7 @@ export enum EvolutionItem {
ICE_STONE,
DUSK_STONE,
DAWN_STONE,
SHINY_STONE,
ABOMASITE = 100,
ABSOLITE,
AERODACTYLITE,
AGGRONITE,
ALAKAZITE,
ALTARIANITE,
AMPHAROSITE,
AUDINITE,
BANETTITE,
BEEDRILLITE,
BLASTOISINITE,
BLAZIKENITE,
CAMERUPTITE,
CHARIZARDITE_X,
CHARIZARDITE_Y,
DIANCITE,
GALLADITE,
GARCHOMPITE,
GARDEVOIRITE,
GENGARITE,
GLALITITE,
GYARADOSITE,
HERACRONITE,
HOUNDOOMINITE,
KANGASKHANITE,
LATIASITE,
LATIOSITE,
LOPUNNITE,
LUCARIONITE,
MANECTITE,
MAWILITE,
MEDICHAMITE,
METAGROSSITE,
MEWTWONITE_X,
MEWTWONITE_Y,
PIDGEOTITE,
PINSIRITE,
RAYQUAZITE,
SABLENITE,
SALAMENCITE,
SCEPTILITE,
SCIZORITE,
SHARPEDONITE,
SLOWBRONITE,
STEELIXITE,
SWAMPERTITE,
TYRANITARITE,
VENUSAURITE,
SHINY_STONE
}
export type EvolutionConditionPredicate = (p: Pokemon) => boolean;
@ -1068,7 +1019,9 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.BARRASKEWDA, 26, null, null)
],
[Species.TOXEL]: [
new SpeciesEvolution(Species.TOXTRICITY, 30, null, null)
new SpeciesFormEvolution(Species.TOXTRICITY, '', 'lowkey', 30, null,
new SpeciesEvolutionCondition(p => [ Nature.LONELY, Nature.BOLD, Nature.RELAXED, Nature.TIMID, Nature.SERIOUS, Nature.MODEST, Nature.MILD, Nature.QUIET, Nature.BASHFUL, Nature.CALM, Nature.GENTLE, Nature.CAREFUL ].indexOf(p.nature) > -1)),
new SpeciesFormEvolution(Species.TOXTRICITY, '', 'amped', 30, null, null)
],
[Species.SIZZLIPEDE]: [
new SpeciesEvolution(Species.CENTISKORCH, 28, null, null)
@ -1618,146 +1571,6 @@ export const pokemonEvolutions: PokemonEvolutions = {
],
[Species.GIMMIGHOUL]: [
new SpeciesEvolution(Species.GHOLDENGO, 1, null, new SpeciesFriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.VENUSAUR]: [
new SpeciesFormEvolution(Species.VENUSAUR, '', SpeciesFormKey.MEGA, 1, EvolutionItem.VENUSAURITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.BLASTOISE]: [
new SpeciesFormEvolution(Species.BLASTOISE, '', SpeciesFormKey.MEGA, 1, EvolutionItem.BLASTOISINITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.CHARIZARD]: [
new SpeciesFormEvolution(Species.CHARIZARD, '', SpeciesFormKey.MEGA_X, 1, EvolutionItem.CHARIZARDITE_X, null, SpeciesWildEvolutionDelay.MEGA),
new SpeciesFormEvolution(Species.CHARIZARD, '', SpeciesFormKey.MEGA_Y, 1, EvolutionItem.CHARIZARDITE_Y, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.BEEDRILL]: [
new SpeciesFormEvolution(Species.BEEDRILL, '', SpeciesFormKey.MEGA, 1, EvolutionItem.BEEDRILLITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.PIDGEOT]: [
new SpeciesFormEvolution(Species.PIDGEOT, '', SpeciesFormKey.MEGA, 1, EvolutionItem.PIDGEOTITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.ALAKAZAM]: [
new SpeciesFormEvolution(Species.ALAKAZAM, '', SpeciesFormKey.MEGA, 1, EvolutionItem.ALAKAZITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.SLOWBRO]: [
new SpeciesFormEvolution(Species.SLOWBRO, '', SpeciesFormKey.MEGA, 1, EvolutionItem.SLOWBRONITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.GENGAR]: [
new SpeciesFormEvolution(Species.GENGAR, '', SpeciesFormKey.MEGA, 1, EvolutionItem.GENGARITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.KANGASKHAN]: [
new SpeciesFormEvolution(Species.KANGASKHAN, '', SpeciesFormKey.MEGA, 1, EvolutionItem.KANGASKHANITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.PINSIR]: [
new SpeciesFormEvolution(Species.PINSIR, '', SpeciesFormKey.MEGA, 1, EvolutionItem.PINSIRITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.GYARADOS]: [
new SpeciesFormEvolution(Species.GYARADOS, '', SpeciesFormKey.MEGA, 1, EvolutionItem.GYARADOSITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.AERODACTYL]: [
new SpeciesFormEvolution(Species.AERODACTYL, '', SpeciesFormKey.MEGA, 1, EvolutionItem.AERODACTYLITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.MEWTWO]: [
new SpeciesFormEvolution(Species.MEWTWO, '', SpeciesFormKey.MEGA_X, 1, EvolutionItem.MEWTWONITE_X, null, SpeciesWildEvolutionDelay.MEGA),
new SpeciesFormEvolution(Species.MEWTWO, '', SpeciesFormKey.MEGA_Y, 1, EvolutionItem.MEWTWONITE_Y, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.AMPHAROS]: [
new SpeciesFormEvolution(Species.AMPHAROS, '', SpeciesFormKey.MEGA, 1, EvolutionItem.AMPHAROSITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.STEELIX]: [
new SpeciesFormEvolution(Species.STEELIX, '', SpeciesFormKey.MEGA, 1, EvolutionItem.STEELIXITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.SCIZOR]: [
new SpeciesFormEvolution(Species.SCIZOR, '', SpeciesFormKey.MEGA, 1, EvolutionItem.SCIZORITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.HERACROSS]: [
new SpeciesFormEvolution(Species.HERACROSS, '', SpeciesFormKey.MEGA, 1, EvolutionItem.HERACRONITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.HOUNDOOM]: [
new SpeciesFormEvolution(Species.HOUNDOOM, '', SpeciesFormKey.MEGA, 1, EvolutionItem.HOUNDOOMINITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.TYRANITAR]: [
new SpeciesFormEvolution(Species.TYRANITAR, '', SpeciesFormKey.MEGA, 1, EvolutionItem.TYRANITARITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.SCEPTILE]: [
new SpeciesFormEvolution(Species.SCEPTILE, '', SpeciesFormKey.MEGA, 1, EvolutionItem.SCEPTILITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.BLAZIKEN]: [
new SpeciesFormEvolution(Species.BLAZIKEN, '', SpeciesFormKey.MEGA, 1, EvolutionItem.BLAZIKENITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.SWAMPERT]: [
new SpeciesFormEvolution(Species.SWAMPERT, '', SpeciesFormKey.MEGA, 1, EvolutionItem.SWAMPERTITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.GARDEVOIR]: [
new SpeciesFormEvolution(Species.GARDEVOIR, '', SpeciesFormKey.MEGA, 1, EvolutionItem.GARDEVOIRITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.SABLEYE]: [
new SpeciesFormEvolution(Species.SABLEYE, '', SpeciesFormKey.MEGA, 1, EvolutionItem.SABLENITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.MAWILE]: [
new SpeciesFormEvolution(Species.MAWILE, '', SpeciesFormKey.MEGA, 1, EvolutionItem.MAWILITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.AGGRON]: [
new SpeciesFormEvolution(Species.AGGRON, '', SpeciesFormKey.MEGA, 1, EvolutionItem.AGGRONITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.MEDICHAM]: [
new SpeciesFormEvolution(Species.MEDICHAM, '', SpeciesFormKey.MEGA, 1, EvolutionItem.MEDICHAMITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.MANECTRIC]: [
new SpeciesFormEvolution(Species.MANECTRIC, '', SpeciesFormKey.MEGA, 1, EvolutionItem.MANECTITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.SHARPEDO]: [
new SpeciesFormEvolution(Species.SHARPEDO, '', SpeciesFormKey.MEGA, 1, EvolutionItem.SHARPEDONITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.CAMERUPT]: [
new SpeciesFormEvolution(Species.CAMERUPT, '', SpeciesFormKey.MEGA, 1, EvolutionItem.CAMERUPTITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.ALTARIA]: [
new SpeciesFormEvolution(Species.ALTARIA, '', SpeciesFormKey.MEGA, 1, EvolutionItem.ALTARIANITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.BANETTE]: [
new SpeciesFormEvolution(Species.BANETTE, '', SpeciesFormKey.MEGA, 1, EvolutionItem.BANETTITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.ABSOL]: [
new SpeciesFormEvolution(Species.ABSOL, '', SpeciesFormKey.MEGA, 1, EvolutionItem.ABSOLITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.GLALIE]: [
new SpeciesFormEvolution(Species.GLALIE, '', SpeciesFormKey.MEGA, 1, EvolutionItem.GLALITITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.SALAMENCE]: [
new SpeciesFormEvolution(Species.SALAMENCE, '', SpeciesFormKey.MEGA, 1, EvolutionItem.SALAMENCITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.METAGROSS]: [
new SpeciesFormEvolution(Species.METAGROSS, '', SpeciesFormKey.MEGA, 1, EvolutionItem.METAGROSSITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.LATIAS]: [
new SpeciesFormEvolution(Species.LATIAS, '', SpeciesFormKey.MEGA, 1, EvolutionItem.LATIASITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.LATIOS]: [
new SpeciesFormEvolution(Species.LATIOS, '', SpeciesFormKey.MEGA, 1, EvolutionItem.LATIOSITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.RAYQUAZA]: [
new SpeciesFormEvolution(Species.RAYQUAZA, '', SpeciesFormKey.MEGA, 1, EvolutionItem.RAYQUAZITE, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.DRAGON_ASCENT).length > 0), SpeciesWildEvolutionDelay.MEGA)
],
[Species.LOPUNNY]: [
new SpeciesFormEvolution(Species.LOPUNNY, '', SpeciesFormKey.MEGA, 1, EvolutionItem.LOPUNNITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.GARCHOMP]: [
new SpeciesFormEvolution(Species.GARCHOMP, '', SpeciesFormKey.MEGA, 1, EvolutionItem.GARCHOMPITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.LUCARIO]: [
new SpeciesFormEvolution(Species.LUCARIO, '', SpeciesFormKey.MEGA, 1, EvolutionItem.LUCARIONITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.ABOMASNOW]: [
new SpeciesFormEvolution(Species.ABOMASNOW, '', SpeciesFormKey.MEGA, 1, EvolutionItem.ABOMASITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.GALLADE]: [
new SpeciesFormEvolution(Species.GALLADE, '', SpeciesFormKey.MEGA, 1, EvolutionItem.GALLADITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.AUDINO]: [
new SpeciesFormEvolution(Species.AUDINO, '', SpeciesFormKey.MEGA, 1, EvolutionItem.AUDINITE, null, SpeciesWildEvolutionDelay.MEGA)
],
[Species.DIANCIE]: [
new SpeciesFormEvolution(Species.DIANCIE, '', SpeciesFormKey.MEGA, 1, EvolutionItem.DIANCITE, null, SpeciesWildEvolutionDelay.MEGA)
]
};

462
src/data/pokemon-forms.ts Normal file
View File

@ -0,0 +1,462 @@
import { TimeOfDay } from "../arena";
import { PokemonFormChangeItemModifier } from "../modifier/modifier";
import Pokemon from "../pokemon";
import { Moves } from "./move";
import { SpeciesFormKey } from "./pokemon-species";
import { Species } from "./species";
import { StatusEffect } from "./status-effect";
export enum FormChangeItem {
NONE,
ABOMASITE,
ABSOLITE,
AERODACTYLITE,
AGGRONITE,
ALAKAZITE,
ALTARIANITE,
AMPHAROSITE,
AUDINITE,
BANETTITE,
BEEDRILLITE,
BLASTOISINITE,
BLAZIKENITE,
CAMERUPTITE,
CHARIZARDITE_X,
CHARIZARDITE_Y,
DIANCITE,
GALLADITE,
GARCHOMPITE,
GARDEVOIRITE,
GENGARITE,
GLALITITE,
GYARADOSITE,
HERACRONITE,
HOUNDOOMINITE,
KANGASKHANITE,
LATIASITE,
LATIOSITE,
LOPUNNITE,
LUCARIONITE,
MANECTITE,
MAWILITE,
MEDICHAMITE,
METAGROSSITE,
MEWTWONITE_X,
MEWTWONITE_Y,
PIDGEOTITE,
PINSIRITE,
RAYQUAZITE,
SABLENITE,
SALAMENCITE,
SCEPTILITE,
SCIZORITE,
SHARPEDONITE,
SLOWBRONITE,
STEELIXITE,
SWAMPERTITE,
TYRANITARITE,
VENUSAURITE,
BLUE_ORB = 50,
RED_ORB,
ADAMANT_CRYSTAL,
LUSTROUS_ORB,
GRISEOUS_CORE,
REVEAL_GLASS,
GRACIDEA
}
export type SpeciesFormChangeConditionPredicate = (p: Pokemon) => boolean;
export type SpeciesFormChangeConditionEnforceFunc = (p: Pokemon) => void;
export class SpeciesFormChange {
public speciesId: Species;
public preFormKey: string;
public formKey: string;
public trigger: SpeciesFormChangeTrigger;
public quiet: boolean;
constructor(speciesId: Species, preFormKey: string, evoFormKey: string, trigger: SpeciesFormChangeTrigger, quiet: boolean = false) {
this.speciesId = speciesId;
this.preFormKey = preFormKey;
this.formKey = evoFormKey;
this.trigger = trigger;
this.quiet = quiet;
}
canChange(pokemon: Pokemon): boolean {
if (pokemon.species.speciesId !== this.speciesId)
return false;
if (!pokemon.species.forms.length)
return false;
const formKeys = pokemon.species.forms.map(f => f.formKey);
if (formKeys[pokemon.formIndex] !== this.preFormKey)
return false;
if (formKeys[pokemon.formIndex] === this.formKey)
return false;
if (!this.trigger.canChange(pokemon))
return false;
return true;
}
findTrigger(triggerType: { new(...args: any[]): SpeciesFormChangeTrigger }): SpeciesFormChangeTrigger {
if (!this.trigger.hasTriggerType(triggerType))
return null;
let trigger = this.trigger;
if (trigger instanceof SpeciesFormChangeCompoundTrigger)
return trigger.triggers.find(t => t.hasTriggerType(triggerType));
return trigger;
}
}
export class SpeciesFormChangeCondition {
public predicate: SpeciesFormChangeConditionPredicate;
public enforceFunc: SpeciesFormChangeConditionEnforceFunc;
constructor(predicate: SpeciesFormChangeConditionPredicate, enforceFunc?: SpeciesFormChangeConditionEnforceFunc) {
this.predicate = predicate;
this.enforceFunc = enforceFunc;
}
}
export abstract class SpeciesFormChangeTrigger {
canChange(pokemon: Pokemon): boolean {
return true;
}
hasTriggerType(triggerType: { new(...args: any[]): SpeciesFormChangeTrigger }): boolean {
return this instanceof triggerType;
}
}
export class SpeciesFormChangeCompoundTrigger {
public triggers: SpeciesFormChangeTrigger[];
constructor(...triggers: SpeciesFormChangeTrigger[]) {
this.triggers = triggers;
}
canChange(pokemon: Pokemon): boolean {
for (let trigger of this.triggers) {
if (!trigger.canChange(pokemon))
return false;
}
return true;
}
hasTriggerType(triggerType: { new(...args: any[]): SpeciesFormChangeTrigger }): boolean {
return !!this.triggers.find(t => t.hasTriggerType(triggerType));
}
}
export class SpeciesFormChangeItemTrigger extends SpeciesFormChangeTrigger {
public item: FormChangeItem;
public active: boolean;
constructor(item: FormChangeItem, active: boolean = true) {
super();
this.item = item;
this.active = active;
}
canChange(pokemon: Pokemon): boolean {
return !!pokemon.scene.findModifier(m => m instanceof PokemonFormChangeItemModifier && m.pokemonId === pokemon.id && m.formChangeItem === this.item && m.active === this.active && (!pokemon.formIndex === this.active));
}
}
export class SpeciesFormChangeTimeOfDayTrigger extends SpeciesFormChangeTrigger {
public timesOfDay: TimeOfDay[];
constructor(...timesOfDay: TimeOfDay[]) {
super();
this.timesOfDay = timesOfDay;
}
canChange(pokemon: Pokemon): boolean {
return this.timesOfDay.indexOf(pokemon.scene.arena.getTimeOfDay()) > -1;
}
}
export class SpeciesFormChangeActiveTrigger extends SpeciesFormChangeTrigger {
public active: boolean;
constructor(active: boolean = false) {
super();
this.active = active;
}
canChange(pokemon: Pokemon): boolean {
return pokemon.isActive(true) === this.active;
}
}
export class SpeciesFormChangeStatusEffectTrigger extends SpeciesFormChangeTrigger {
public statusEffects: StatusEffect[];
public invert: boolean;
constructor(statusEffects: StatusEffect | StatusEffect[], invert: boolean = false) {
super();
if (!Array.isArray(statusEffects))
statusEffects = [ statusEffects ];
this.statusEffects = statusEffects;
this.invert = invert;
}
canChange(pokemon: Pokemon): boolean {
return (this.statusEffects.indexOf(pokemon.status?.effect || StatusEffect.NONE) > -1) !== this.invert;
}
}
export class SpeciesFormChangeMoveLearnedTrigger extends SpeciesFormChangeTrigger {
public move: Moves;
public known: boolean;
constructor(move: Moves, known: boolean = true) {
super();
this.move = move;
this.known = known;
}
canChange(pokemon: Pokemon): boolean {
return (!!pokemon.moveset.filter(m => m.moveId === this.move).length) === this.known;
}
}
export class SpeciesFormChangeMoveUsedTrigger extends SpeciesFormChangeTrigger {
public move: Moves;
public used: boolean;
constructor(move: Moves, used: boolean = true) {
super();
this.move = move;
this.used = used;
}
canChange(pokemon: Pokemon): boolean {
return pokemon.summonData && !!pokemon.getLastXMoves(1).filter(m => m.move === this.move).length === this.used;
}
}
export function getSpeciesFormChangeMessage(pokemon: Pokemon, formChange: SpeciesFormChange, preName: string): string {
const isMega = formChange.formKey.indexOf(SpeciesFormKey.MEGA) > -1;
const isRevert = !isMega && formChange.formKey === pokemon.species.forms[0].formKey;
const prefix = !pokemon.isPlayer() ? pokemon.hasTrainer() ? 'Foe ' : 'Wild ' : 'Your ';
if (isMega)
return `${prefix}${preName} mega-evolved\ninto ${pokemon.name}!`;
if (isRevert)
return `${prefix}${pokemon.name} reverted\nto its original form!`;
return `${prefix}${preName} changed form!`;
}
interface PokemonFormChanges {
[key: string]: SpeciesFormChange[]
}
export const pokemonFormChanges: PokemonFormChanges = {
[Species.VENUSAUR]: [
new SpeciesFormChange(Species.VENUSAUR, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.VENUSAURITE))
],
[Species.BLASTOISE]: [
new SpeciesFormChange(Species.BLASTOISE, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.BLASTOISINITE))
],
[Species.CHARIZARD]: [
new SpeciesFormChange(Species.CHARIZARD, '', SpeciesFormKey.MEGA_X, new SpeciesFormChangeItemTrigger(FormChangeItem.CHARIZARDITE_X)),
new SpeciesFormChange(Species.CHARIZARD, '', SpeciesFormKey.MEGA_Y, new SpeciesFormChangeItemTrigger(FormChangeItem.CHARIZARDITE_Y))
],
[Species.BEEDRILL]: [
new SpeciesFormChange(Species.BEEDRILL, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.BEEDRILLITE))
],
[Species.PIDGEOT]: [
new SpeciesFormChange(Species.PIDGEOT, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.PIDGEOTITE))
],
[Species.ALAKAZAM]: [
new SpeciesFormChange(Species.ALAKAZAM, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.ALAKAZITE))
],
[Species.SLOWBRO]: [
new SpeciesFormChange(Species.SLOWBRO, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.SLOWBRONITE))
],
[Species.GENGAR]: [
new SpeciesFormChange(Species.GENGAR, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.GENGARITE))
],
[Species.KANGASKHAN]: [
new SpeciesFormChange(Species.KANGASKHAN, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.KANGASKHANITE))
],
[Species.PINSIR]: [
new SpeciesFormChange(Species.PINSIR, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.PINSIRITE))
],
[Species.GYARADOS]: [
new SpeciesFormChange(Species.GYARADOS, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.GYARADOSITE))
],
[Species.AERODACTYL]: [
new SpeciesFormChange(Species.AERODACTYL, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.AERODACTYLITE))
],
[Species.MEWTWO]: [
new SpeciesFormChange(Species.MEWTWO, '', SpeciesFormKey.MEGA_X, new SpeciesFormChangeItemTrigger(FormChangeItem.MEWTWONITE_X)),
new SpeciesFormChange(Species.MEWTWO, '', SpeciesFormKey.MEGA_Y, new SpeciesFormChangeItemTrigger(FormChangeItem.MEWTWONITE_Y))
],
[Species.AMPHAROS]: [
new SpeciesFormChange(Species.AMPHAROS, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.AMPHAROSITE))
],
[Species.STEELIX]: [
new SpeciesFormChange(Species.STEELIX, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.STEELIXITE))
],
[Species.SCIZOR]: [
new SpeciesFormChange(Species.SCIZOR, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.SCIZORITE))
],
[Species.HERACROSS]: [
new SpeciesFormChange(Species.HERACROSS, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.HERACRONITE))
],
[Species.HOUNDOOM]: [
new SpeciesFormChange(Species.HOUNDOOM, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.HOUNDOOMINITE))
],
[Species.TYRANITAR]: [
new SpeciesFormChange(Species.TYRANITAR, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.TYRANITARITE))
],
[Species.SCEPTILE]: [
new SpeciesFormChange(Species.SCEPTILE, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.SCEPTILITE))
],
[Species.BLAZIKEN]: [
new SpeciesFormChange(Species.BLAZIKEN, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.BLAZIKENITE))
],
[Species.SWAMPERT]: [
new SpeciesFormChange(Species.SWAMPERT, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.SWAMPERTITE))
],
[Species.GARDEVOIR]: [
new SpeciesFormChange(Species.GARDEVOIR, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.GARDEVOIRITE))
],
[Species.SABLEYE]: [
new SpeciesFormChange(Species.SABLEYE, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.SABLENITE))
],
[Species.MAWILE]: [
new SpeciesFormChange(Species.MAWILE, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.MAWILITE))
],
[Species.AGGRON]: [
new SpeciesFormChange(Species.AGGRON, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.AGGRONITE))
],
[Species.MEDICHAM]: [
new SpeciesFormChange(Species.MEDICHAM, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.MEDICHAMITE))
],
[Species.MANECTRIC]: [
new SpeciesFormChange(Species.MANECTRIC, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.MANECTITE))
],
[Species.SHARPEDO]: [
new SpeciesFormChange(Species.SHARPEDO, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.SHARPEDONITE))
],
[Species.CAMERUPT]: [
new SpeciesFormChange(Species.CAMERUPT, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.CAMERUPTITE))
],
[Species.ALTARIA]: [
new SpeciesFormChange(Species.ALTARIA, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.ALTARIANITE))
],
[Species.BANETTE]: [
new SpeciesFormChange(Species.BANETTE, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.BANETTITE))
],
[Species.ABSOL]: [
new SpeciesFormChange(Species.ABSOL, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.ABSOLITE))
],
[Species.GLALIE]: [
new SpeciesFormChange(Species.GLALIE, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.GLALITITE))
],
[Species.SALAMENCE]: [
new SpeciesFormChange(Species.SALAMENCE, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.SALAMENCITE))
],
[Species.METAGROSS]: [
new SpeciesFormChange(Species.METAGROSS, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.METAGROSSITE))
],
[Species.LATIAS]: [
new SpeciesFormChange(Species.LATIAS, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.LATIASITE))
],
[Species.LATIOS]: [
new SpeciesFormChange(Species.LATIOS, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.LATIOSITE))
],
[Species.KYOGRE]: [
new SpeciesFormChange(Species.KYOGRE, '', SpeciesFormKey.PRIMAL, new SpeciesFormChangeItemTrigger(FormChangeItem.BLUE_ORB))
],
[Species.GROUDON]: [
new SpeciesFormChange(Species.GROUDON, '', SpeciesFormKey.PRIMAL, new SpeciesFormChangeItemTrigger(FormChangeItem.RED_ORB))
],
[Species.RAYQUAZA]: [
new SpeciesFormChange(Species.RAYQUAZA, '', SpeciesFormKey.MEGA, new SpeciesFormChangeCompoundTrigger(new SpeciesFormChangeItemTrigger(FormChangeItem.RAYQUAZITE), new SpeciesFormChangeMoveLearnedTrigger(Moves.DRAGON_ASCENT)))
],
[Species.LOPUNNY]: [
new SpeciesFormChange(Species.LOPUNNY, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.LOPUNNITE))
],
[Species.GARCHOMP]: [
new SpeciesFormChange(Species.GARCHOMP, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.GARCHOMPITE))
],
[Species.LUCARIO]: [
new SpeciesFormChange(Species.LUCARIO, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.LUCARIONITE))
],
[Species.ABOMASNOW]: [
new SpeciesFormChange(Species.ABOMASNOW, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.ABOMASITE))
],
[Species.GALLADE]: [
new SpeciesFormChange(Species.GALLADE, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.GALLADITE))
],
[Species.AUDINO]: [
new SpeciesFormChange(Species.AUDINO, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.AUDINITE))
],
[Species.DIALGA]: [
new SpeciesFormChange(Species.DIALGA, '', SpeciesFormKey.ORIGIN, new SpeciesFormChangeItemTrigger(FormChangeItem.ADAMANT_CRYSTAL))
],
[Species.PALKIA]: [
new SpeciesFormChange(Species.PALKIA, '', SpeciesFormKey.ORIGIN, new SpeciesFormChangeItemTrigger(FormChangeItem.LUSTROUS_ORB))
],
[Species.GIRATINA]: [
new SpeciesFormChange(Species.GIRATINA, '', SpeciesFormKey.ORIGIN, new SpeciesFormChangeItemTrigger(FormChangeItem.GRISEOUS_CORE))
],
[Species.SHAYMIN]: [
new SpeciesFormChange(Species.SHAYMIN, 'land', 'sky', new SpeciesFormChangeCompoundTrigger(new SpeciesFormChangeTimeOfDayTrigger(TimeOfDay.DAY, TimeOfDay.DUSK),
new SpeciesFormChangeItemTrigger(FormChangeItem.GRACIDEA), new SpeciesFormChangeStatusEffectTrigger(StatusEffect.FREEZE, true))),
new SpeciesFormChange(Species.SHAYMIN, 'sky', 'land', new SpeciesFormChangeTimeOfDayTrigger(TimeOfDay.DAWN, TimeOfDay.NIGHT)),
new SpeciesFormChange(Species.SHAYMIN, 'sky', 'land', new SpeciesFormChangeStatusEffectTrigger(StatusEffect.FREEZE))
],
[Species.TORNADUS]: [
new SpeciesFormChange(Species.TORNADUS, SpeciesFormKey.INCARNATE, SpeciesFormKey.THERIAN, new SpeciesFormChangeItemTrigger(FormChangeItem.REVEAL_GLASS))
],
[Species.THUNDURUS]: [
new SpeciesFormChange(Species.THUNDURUS, SpeciesFormKey.INCARNATE, SpeciesFormKey.THERIAN, new SpeciesFormChangeItemTrigger(FormChangeItem.REVEAL_GLASS))
],
[Species.LANDORUS]: [
new SpeciesFormChange(Species.LANDORUS, SpeciesFormKey.INCARNATE, SpeciesFormKey.THERIAN, new SpeciesFormChangeItemTrigger(FormChangeItem.REVEAL_GLASS))
],
[Species.KELDEO]: [
new SpeciesFormChange(Species.KELDEO, 'ordinary', 'resolute', new SpeciesFormChangeMoveLearnedTrigger(Moves.SACRED_SWORD)),
new SpeciesFormChange(Species.KELDEO, 'resolute', 'ordinary', new SpeciesFormChangeMoveLearnedTrigger(Moves.SACRED_SWORD, false))
],
[Species.MELOETTA]: [
new SpeciesFormChange(Species.MELOETTA, 'aria', 'pirouette', new SpeciesFormChangeMoveUsedTrigger(Moves.RELIC_SONG), true),
new SpeciesFormChange(Species.MELOETTA, 'pirouette', 'aria', new SpeciesFormChangeMoveUsedTrigger(Moves.RELIC_SONG), true),
new SpeciesFormChange(Species.MELOETTA, 'pirouette', 'aria', new SpeciesFormChangeActiveTrigger(false), true)
],
[Species.DIANCIE]: [
new SpeciesFormChange(Species.DIANCIE, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.DIANCITE))
],
[Species.ENAMORUS]: [
new SpeciesFormChange(Species.ENAMORUS, SpeciesFormKey.INCARNATE, SpeciesFormKey.THERIAN, new SpeciesFormChangeItemTrigger(FormChangeItem.REVEAL_GLASS))
]
};
{
const formChangeKeys = Object.keys(pokemonFormChanges);
formChangeKeys.forEach(pk => {
const formChanges = pokemonFormChanges[pk];
let newFormChanges: SpeciesFormChange[] = [];
for (let fc of formChanges) {
const itemTrigger = fc.findTrigger(SpeciesFormChangeItemTrigger) as SpeciesFormChangeItemTrigger;
if (itemTrigger && !formChanges.find(c => fc.formKey === c.preFormKey && fc.preFormKey === c.formKey))
newFormChanges.push(new SpeciesFormChange(fc.speciesId, fc.formKey, fc.preFormKey, new SpeciesFormChangeItemTrigger(itemTrigger.item, false)));
}
formChanges.push(...newFormChanges);
});
}

View File

@ -510,7 +510,11 @@ export class PokemonForm extends PokemonSpeciesForm {
export enum SpeciesFormKey {
MEGA = "mega",
MEGA_X = "mega-x",
MEGA_Y = "mega-y"
MEGA_Y = "mega-y",
PRIMAL = "primal",
ORIGIN = "origin",
INCARNATE = "incarnate",
THERIAN = "therian"
}
export const allSpecies: PokemonSpecies[] = [];
@ -1711,7 +1715,7 @@ export function initSpecies() {
new PokemonSpecies(Species.SANDYGAST, "Sandygast", 7, false, false, false, "Sand Heap Pokémon", Type.GHOST, Type.GROUND, 0.5, 70, Abilities.WATER_COMPACTION, Abilities.NONE, Abilities.SAND_VEIL, 320, 55, 55, 80, 70, 45, 15, 140, 50, 64, GrowthRate.MEDIUM_FAST, 50, false),
new PokemonSpecies(Species.PALOSSAND, "Palossand", 7, false, false, false, "Sand Castle Pokémon", Type.GHOST, Type.GROUND, 1.3, 250, Abilities.WATER_COMPACTION, Abilities.NONE, Abilities.SAND_VEIL, 480, 85, 75, 110, 100, 75, 35, 60, 50, 168, GrowthRate.MEDIUM_FAST, 50, false),
new PokemonSpecies(Species.PYUKUMUKU, "Pyukumuku", 7, false, false, false, "Sea Cucumber Pokémon", Type.WATER, null, 0.3, 1.2, Abilities.INNARDS_OUT, Abilities.NONE, Abilities.UNAWARE, 410, 55, 60, 130, 30, 130, 5, 60, 50, 144, GrowthRate.FAST, 50, false),
new PokemonSpecies(Species.TYPE_NULL, "Type: Null", 7, false, false, false, "Synthetic Pokémon", Type.NORMAL, null, 1.9, 120.5, Abilities.BATTLE_ARMOR, Abilities.NONE, Abilities.NONE, 534, 95, 95, 95, 95, 95, 59, 3, 0, 107, GrowthRate.SLOW, null, false),
new PokemonSpecies(Species.TYPE_NULL, "Type: Null", 7, true, false, false, "Synthetic Pokémon", Type.NORMAL, null, 1.9, 120.5, Abilities.BATTLE_ARMOR, Abilities.NONE, Abilities.NONE, 534, 95, 95, 95, 95, 95, 59, 3, 0, 107, GrowthRate.SLOW, null, false),
new PokemonSpecies(Species.SILVALLY, "Silvally", 7, true, false, false, "Synthetic Pokémon", Type.NORMAL, null, 2.3, 100.5, Abilities.RKS_SYSTEM, Abilities.NONE, Abilities.NONE, 570, 95, 95, 95, 95, 95, 95, 3, 0, 285, GrowthRate.SLOW, null, false, false,
new PokemonForm("Type: Normal", "normal", Type.NORMAL, null, 2.3, 100.5, Abilities.RKS_SYSTEM, Abilities.NONE, Abilities.NONE, 570, 95, 95, 95, 95, 95, 95, 3, 0, 285, false, ""),
new PokemonForm("Type: Fighting", "fighting", Type.FIGHTING, null, 2.3, 100.5, Abilities.RKS_SYSTEM, Abilities.NONE, Abilities.NONE, 570, 95, 95, 95, 95, 95, 95, 3, 0, 285),

View File

@ -445,11 +445,3 @@ export class EggHatchPhase extends BattlePhase {
return ret;
}
}
export class EndEvolutionPhase extends BattlePhase {
start() {
super.start();
this.scene.ui.setModeForceTransition(Mode.MESSAGE).then(() => this.end());
}
}

View File

@ -6,39 +6,47 @@ import EvolutionSceneHandler from "./ui/evolution-scene-handler";
import * as Utils from "./utils";
import { Mode } from "./ui/ui";
import { LearnMovePhase } from "./battle-phases";
import { SpeciesFormKey } from "./data/pokemon-species";
import { achvs } from "./system/achv";
import { cos, sin } from "./anims";
import { PlayerPokemon } from "./pokemon";
export class EvolutionPhase extends BattlePhase {
private partyMemberIndex: integer;
protected pokemon: PlayerPokemon;
protected lastLevel: integer;
private evolution: SpeciesEvolution;
private lastLevel: integer;
private evolutionContainer: Phaser.GameObjects.Container;
private evolutionBaseBg: Phaser.GameObjects.Image;
private evolutionBg: Phaser.GameObjects.Video;
private evolutionBgOverlay: Phaser.GameObjects.Rectangle;
private evolutionOverlay: Phaser.GameObjects.Rectangle;
private pokemonSprite: Phaser.GameObjects.Sprite;
private pokemonTintSprite: Phaser.GameObjects.Sprite;
private pokemonEvoSprite: Phaser.GameObjects.Sprite;
private pokemonEvoTintSprite: Phaser.GameObjects.Sprite;
protected evolutionContainer: Phaser.GameObjects.Container;
protected evolutionBaseBg: Phaser.GameObjects.Image;
protected evolutionBg: Phaser.GameObjects.Video;
protected evolutionBgOverlay: Phaser.GameObjects.Rectangle;
protected evolutionOverlay: Phaser.GameObjects.Rectangle;
protected pokemonSprite: Phaser.GameObjects.Sprite;
protected pokemonTintSprite: Phaser.GameObjects.Sprite;
protected pokemonEvoSprite: Phaser.GameObjects.Sprite;
protected pokemonEvoTintSprite: Phaser.GameObjects.Sprite;
constructor(scene: BattleScene, partyMemberIndex: integer, evolution: SpeciesEvolution, lastLevel: integer) {
constructor(scene: BattleScene, pokemon: PlayerPokemon, evolution: SpeciesEvolution, lastLevel: integer) {
super(scene);
this.partyMemberIndex = partyMemberIndex;
this.pokemon = pokemon;
this.evolution = evolution;
this.lastLevel = lastLevel;
}
validate(): boolean {
return !!this.evolution;
}
setMode(): Promise<void> {
return this.scene.ui.setModeForceTransition(Mode.EVOLUTION_SCENE);
}
start() {
super.start();
this.scene.ui.setModeForceTransition(Mode.EVOLUTION_SCENE).then(() => {
this.setMode().then(() => {
if (!this.evolution)
if (!this.validate())
return this.end();
this.scene.fadeOutBgm(null, false);
@ -75,29 +83,34 @@ export class EvolutionPhase extends BattlePhase {
this.pokemonEvoTintSprite.setVisible(false);
this.pokemonEvoTintSprite.setTintFill(0xFFFFFF);
this.evolutionOverlay = this.scene.add.rectangle(0, -this.scene.game.canvas.height / 6, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6, 0xFFFFFF);
this.evolutionOverlay = this.scene.add.rectangle(0, -this.scene.game.canvas.height / 6, this.scene.game.canvas.width / 6, (this.scene.game.canvas.height / 6) - 48, 0xFFFFFF);
this.evolutionOverlay.setOrigin(0, 0);
this.evolutionOverlay.setAlpha(0);
this.scene.fieldUI.add(this.evolutionOverlay);
const pokemon = this.scene.getParty()[this.partyMemberIndex];
const preName = pokemon.name;
this.scene.ui.add(this.evolutionOverlay);
[ this.pokemonSprite, this.pokemonTintSprite, this.pokemonEvoSprite, this.pokemonEvoTintSprite ].map(sprite => {
sprite.play(pokemon.getSpriteKey(true));
sprite.play(this.pokemon.getSpriteKey(true));
sprite.setPipeline(this.scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false });
sprite.pipelineData['ignoreTimeTint'] = true;
[ 'spriteColors', 'fusionSpriteColors' ].map(k => {
if (pokemon.summonData?.speciesForm)
if (this.pokemon.summonData?.speciesForm)
k += 'Base';
sprite.pipelineData[k] = pokemon.getSprite().pipelineData[k];
sprite.pipelineData[k] = this.pokemon.getSprite().pipelineData[k];
});
});
this.doEvolution();
});
}
doEvolution(): void {
const evolutionHandler = this.scene.ui.getHandler() as EvolutionSceneHandler;
const preName = this.pokemon.name;
this.scene.ui.showText(`What?\n${preName} is evolving!`, null, () => {
pokemon.cry();
this.pokemon.cry();
pokemon.getPossibleEvolution(this.evolution).then(evolvedPokemon => {
this.pokemon.getPossibleEvolution(this.evolution).then(evolvedPokemon => {
[ this.pokemonEvoSprite, this.pokemonEvoTintSprite ].map(sprite => {
sprite.play(evolvedPokemon.getSpriteKey(true));
@ -173,7 +186,7 @@ export class EvolutionPhase extends BattlePhase {
};
this.scene.ui.setOverlayMode(Mode.CONFIRM, () => {
this.scene.ui.revertMode();
pokemon.pauseEvolutions = true;
this.pokemon.pauseEvolutions = true;
this.scene.ui.showText(`Evolutions have been paused for ${preName}.`, null, end, 3000);
}, () => {
this.scene.ui.revertMode();
@ -190,10 +203,10 @@ export class EvolutionPhase extends BattlePhase {
this.scene.time.delayedCall(900, () => {
evolutionHandler.canCancel = false;
pokemon.evolve(this.evolution).then(() => {
const levelMoves = pokemon.getLevelMoves(this.lastLevel + 1, true);
this.pokemon.evolve(this.evolution).then(() => {
const levelMoves = this.pokemon.getLevelMoves(this.lastLevel + 1, true);
for (let lm of levelMoves)
this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, lm));
this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.scene.getParty().indexOf(this.pokemon), lm));
this.scene.unshiftPhase(new EndEvolutionPhase(this.scene));
this.scene.playSound('shine');
@ -220,14 +233,12 @@ export class EvolutionPhase extends BattlePhase {
onComplete: () => {
SoundFade.fadeOut(this.scene, evolutionBgm, 100);
this.scene.time.delayedCall(250, () => {
pokemon.cry();
this.pokemon.cry();
this.scene.time.delayedCall(1250, () => {
this.scene.playSoundWithoutBgm('evolution_fanfare');
if (this.evolution.evoFormKey && this.evolution.evoFormKey.indexOf(SpeciesFormKey.MEGA) > -1)
this.scene.validateAchv(achvs.MEGA_EVOLVE);
evolvedPokemon.destroy();
this.scene.ui.showText(`Congratulations! Your ${preName}\nevolved into ${pokemon.name}!`, null, () => this.end(), null, true, 3000);
this.scene.ui.showText(`Congratulations! Your ${preName}\nevolved into ${this.pokemon.name}!`, null, () => this.end(), null, true, Utils.fixedInt(4000));
this.scene.time.delayedCall(Utils.fixedInt(4250), () => this.scene.playBgm());
});
});
@ -249,7 +260,6 @@ export class EvolutionPhase extends BattlePhase {
});
});
}, 1000);
});
}
doSpiralUpward() {
@ -288,10 +298,10 @@ export class EvolutionPhase extends BattlePhase {
});
}
doCycle(l: number): Promise<boolean> {
doCycle(l: number, lastCycle: integer = 15): Promise<boolean> {
return new Promise(resolve => {
const evolutionHandler = this.scene.ui.getHandler() as EvolutionSceneHandler;
const isLastCycle = l === 15;
const isLastCycle = l === lastCycle;
this.scene.tweens.add({
targets: this.pokemonTintSprite,
scale: 0.25,
@ -308,8 +318,8 @@ export class EvolutionPhase extends BattlePhase {
onComplete: () => {
if (evolutionHandler.cancelled)
return resolve(false);
if (l < 15)
this.doCycle(l + 0.5).then(success => resolve(success));
if (l < lastCycle)
this.doCycle(l + 0.5, lastCycle).then(success => resolve(success));
else {
this.pokemonTintSprite.setVisible(false);
resolve(true);

188
src/form-change-phase.ts Normal file
View File

@ -0,0 +1,188 @@
import BattleScene from "./battle-scene";
import * as Utils from "./utils";
import { SpeciesFormKey } from "./data/pokemon-species";
import { achvs } from "./system/achv";
import { SpeciesFormChange, getSpeciesFormChangeMessage } from "./data/pokemon-forms";
import { EndEvolutionPhase, EvolutionPhase } from "./evolution-phase";
import Pokemon, { PlayerPokemon } from "./pokemon";
import { Mode } from "./ui/ui";
import PartyUiHandler from "./ui/party-ui-handler";
import { BattlePhase } from "./battle-phase";
export class FormChangePhase extends EvolutionPhase {
private formChange: SpeciesFormChange;
private modal: boolean;
constructor(scene: BattleScene, pokemon: PlayerPokemon, formChange: SpeciesFormChange, modal: boolean) {
super(scene, pokemon, null, 0);
this.formChange = formChange;
this.modal = modal;
}
validate(): boolean {
return !!this.formChange;
}
setMode(): Promise<void> {
if (!this.modal)
return super.setMode();
return this.scene.ui.setOverlayMode(Mode.EVOLUTION_SCENE);
}
doEvolution(): void {
const preName = this.pokemon.name;
this.pokemon.getPossibleForm(this.formChange).then(transformedPokemon => {
[ this.pokemonEvoSprite, this.pokemonEvoTintSprite ].map(sprite => {
sprite.play(transformedPokemon.getSpriteKey(true));
sprite.pipelineData['ignoreTimeTint'] = true;
[ 'spriteColors', 'fusionSpriteColors' ].map(k => {
if (transformedPokemon.summonData?.speciesForm)
k += 'Base';
sprite.pipelineData[k] = transformedPokemon.getSprite().pipelineData[k];
});
});
this.scene.time.delayedCall(250, () => {
this.scene.tweens.add({
targets: this.evolutionBgOverlay,
alpha: 1,
delay: 500,
duration: 1500,
ease: 'Sine.easeOut',
onComplete: () => {
this.scene.time.delayedCall(1000, () => {
this.scene.tweens.add({
targets: this.evolutionBgOverlay,
alpha: 0,
duration: 250
});
this.evolutionBg.setVisible(true);
this.evolutionBg.play();
});
this.scene.playSound('charge');
this.doSpiralUpward();
this.scene.tweens.addCounter({
from: 0,
to: 1,
duration: 2000,
onUpdate: t => {
this.pokemonTintSprite.setAlpha(t.getValue());
},
onComplete: () => {
this.pokemonSprite.setVisible(false);
this.scene.time.delayedCall(1100, () => {
this.scene.playSound('beam');
this.doArcDownward();
this.scene.time.delayedCall(1000, () => {
this.pokemonEvoTintSprite.setScale(0.25);
this.pokemonEvoTintSprite.setVisible(true);
this.doCycle(1, 1).then(_success => {
this.scene.playSound('sparkle');
this.pokemonEvoSprite.setVisible(true);
this.doCircleInward();
this.scene.time.delayedCall(900, () => {
this.pokemon.changeForm(this.formChange).then(() => {
if (!this.modal)
this.scene.unshiftPhase(new EndEvolutionPhase(this.scene));
this.scene.playSound('shine');
this.doSpray();
this.scene.tweens.add({
targets: this.evolutionOverlay,
alpha: 1,
duration: 250,
easing: 'Sine.easeIn',
onComplete: () => {
this.evolutionBgOverlay.setAlpha(1);
this.evolutionBg.setVisible(false);
this.scene.tweens.add({
targets: [ this.evolutionOverlay, this.pokemonEvoTintSprite ],
alpha: 0,
duration: 2000,
delay: 150,
easing: 'Sine.easeIn',
onComplete: () => {
this.scene.tweens.add({
targets: this.evolutionBgOverlay,
alpha: 0,
duration: 250,
onComplete: () => {
this.scene.time.delayedCall(250, () => {
this.pokemon.cry();
this.scene.time.delayedCall(1250, () => {
const isMega = this.formChange.formKey.indexOf(SpeciesFormKey.MEGA) > -1;
const isRevert = !isMega && this.formChange.formKey === this.pokemon.species.forms[0].formKey;
let playEvolutionFanfare = false;
if (isMega) {
this.scene.validateAchv(achvs.MEGA_EVOLVE);
playEvolutionFanfare = true;
}
const delay = playEvolutionFanfare ? 4000 : 1750;
this.scene.playSoundWithoutBgm(playEvolutionFanfare ? 'evolution_fanfare' : 'minor_fanfare');
transformedPokemon.destroy();
this.scene.ui.showText(getSpeciesFormChangeMessage(this.pokemon, this.formChange, preName), null, () => this.end(), null, true, Utils.fixedInt(delay));
this.scene.time.delayedCall(Utils.fixedInt(delay + 250), () => this.scene.playBgm());
});
});
}
});
}
});
}
});
});
});
});
});
});
}
})
}
});
});
});
}
end(): void {
if (this.modal) {
this.scene.ui.revertMode().then(() => {
if (this.scene.ui.getMode() === Mode.PARTY) {
const partyUiHandler = this.scene.ui.getHandler() as PartyUiHandler;
partyUiHandler.clearPartySlots();
partyUiHandler.populatePartySlots();
}
super.end();
});
} else
super.end();
}
}
export class QuietFormChangePhase extends BattlePhase {
protected pokemon: Pokemon;
protected formChange: SpeciesFormChange;
constructor(scene: BattleScene, pokemon: Pokemon, formChange: SpeciesFormChange) {
super(scene);
this.pokemon = pokemon;
this.formChange = formChange;
}
start(): void {
super.start();
if (this.pokemon.formIndex === this.pokemon.species.forms.findIndex(f => f.formKey === this.formChange.formKey))
return this.end();
const preName = this.pokemon.name;
this.pokemon.changeForm(this.formChange).then(() => {
this.scene.ui.showText(getSpeciesFormChangeMessage(this.pokemon, this.formChange, preName), null, () => this.end(), Utils.fixedInt(1500));
});
}
}

View File

@ -16,6 +16,7 @@ import { StatusEffect, getStatusEffectDescriptor } from '../data/status-effect';
import { SpeciesFormKey } from '../data/pokemon-species';
import BattleScene from '../battle-scene';
import { VoucherType, getVoucherTypeIcon, getVoucherTypeName } from '../system/voucher';
import { FormChangeItem, SpeciesFormChangeItemTrigger, pokemonFormChanges } from '../data/pokemon-forms';
type Modifier = Modifiers.Modifier;
@ -446,6 +447,26 @@ export class EvolutionItemModifierType extends PokemonModifierType implements Ge
}
}
export class FormChangeItemModifierType extends PokemonModifierType implements GeneratedPersistentModifierType {
public formChangeItem: FormChangeItem;
constructor(formChangeItem: FormChangeItem) {
super(Utils.toReadableString(FormChangeItem[formChangeItem]), `Causes certain Pokémon to change form`, (_type, args) => new Modifiers.PokemonFormChangeItemModifier(this, (args[0] as PlayerPokemon).id, formChangeItem, true),
(pokemon: PlayerPokemon) => {
if (pokemonFormChanges.hasOwnProperty(pokemon.species.speciesId) && !!pokemonFormChanges[pokemon.species.speciesId].find(fc => fc.trigger.hasTriggerType(SpeciesFormChangeItemTrigger)))
return null;
return PartyUiHandler.NoEffectMessage;
}, FormChangeItem[formChangeItem].toLowerCase());
this.formChangeItem = formChangeItem;
}
getPregenArgs(): any[] {
return [ this.formChangeItem ];
}
}
export class FusePokemonModifierType extends PokemonModifierType {
constructor(name: string, iconImage?: string) {
super(name, 'Combines two Pokémon (transfers ability, splits base stats and types, shares move pool)', (_type, args) => new Modifiers.FusePokemonModifier(this, (args[0] as PlayerPokemon).id, (args[1] as PlayerPokemon).id),
@ -524,7 +545,7 @@ class TmModifierTypeGenerator extends ModifierTypeGenerator {
}
class EvolutionItemModifierTypeGenerator extends ModifierTypeGenerator {
constructor(mega: boolean) {
constructor() {
super((party: Pokemon[], pregenArgs?: any[]) => {
if (pregenArgs)
return new EvolutionItemModifierType(pregenArgs[0] as EvolutionItem);
@ -532,7 +553,7 @@ class EvolutionItemModifierTypeGenerator extends ModifierTypeGenerator {
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().filter(e => (e.item >= 100) === mega).flatMap(e => e.item);
}).flat().flatMap(e => e.item);
if (!evolutionItemPool.length)
return null;
@ -542,6 +563,26 @@ class EvolutionItemModifierTypeGenerator extends ModifierTypeGenerator {
}
}
class FormChangeItemModifierTypeGenerator extends ModifierTypeGenerator {
constructor() {
super((party: Pokemon[], pregenArgs?: any[]) => {
if (pregenArgs)
return new FormChangeItemModifierType(pregenArgs[0] as FormChangeItem);
const formChangeItemPool = party.filter(p => pokemonFormChanges.hasOwnProperty(p.species.speciesId)).map(p => {
const formChanges = pokemonFormChanges[p.species.speciesId];
return formChanges.filter(fc => fc.formKey.indexOf(SpeciesFormKey.MEGA) === -1 || party[0].scene.getModifiers(Modifiers.MegaEvolutionAccessModifier).length)
.map(fc => fc.findTrigger(SpeciesFormChangeItemTrigger) as SpeciesFormChangeItemTrigger).filter(t => t && t.active);
}).flat().flatMap(fc => fc.item);
if (!formChangeItemPool.length)
return null;
return new FormChangeItemModifierType(formChangeItemPool[Utils.randSeedInt(formChangeItemPool.length)]);
});
}
}
export class ContactHeldItemTransferChanceModifierType extends PokemonHeldItemModifierType {
constructor(name: string, chancePercent: integer, iconImage?: string, group?: string, soundName?: string) {
super(name, `Upon attacking, there is a ${chancePercent}% chance the foe's held item will be stolen`, (type, args) => new Modifiers.ContactHeldItemTransferChanceModifier(type, (args[0] as Pokemon).id, chancePercent), iconImage, group, soundName);
@ -593,8 +634,8 @@ export const modifierTypes = {
RARE_CANDY: () => new PokemonLevelIncrementModifierType('Rare Candy'),
RARER_CANDY: () => new AllPokemonLevelIncrementModifierType('Rarer Candy'),
EVOLUTION_ITEM: () => new EvolutionItemModifierTypeGenerator(false),
MEGA_EVOLUTION_ITEM: () => new EvolutionItemModifierTypeGenerator(true),
EVOLUTION_ITEM: () => new EvolutionItemModifierTypeGenerator(),
FORM_CHANGE_ITEM: () => new FormChangeItemModifierTypeGenerator(),
MEGA_BRACELET: () => new ModifierType('Mega Bracelet', 'Mega stones become available', (type, _args) => new Modifiers.MegaEvolutionAccessModifier(type)),
@ -838,7 +879,7 @@ const modifierPool = {
new WeightedModifierType(modifierTypes.ABILITY_CHARM, 2),
new WeightedModifierType(modifierTypes.IV_SCANNER, 2),
new WeightedModifierType(modifierTypes.EXP_BALANCE, 1),
new WeightedModifierType(modifierTypes.MEGA_EVOLUTION_ITEM, (party: Pokemon[]) => party[0].scene.getModifiers(Modifiers.MegaEvolutionAccessModifier).length && !party.filter(p => p.getFormKey().indexOf(SpeciesFormKey.MEGA) > -1).length ? 1 : 0),
new WeightedModifierType(modifierTypes.FORM_CHANGE_ITEM, 1),
new WeightedModifierType(modifierTypes.REVERSE_DNA_SPLICERS, (party: Pokemon[]) => party[0].scene.gameMode !== GameMode.SPLICED_ENDLESS && party.filter(p => p.fusionSpecies).length ? 3 : 0),
].map(m => { m.setTier(ModifierTier.ULTRA); return m; }),
[ModifierTier.MASTER]: [

View File

@ -17,6 +17,7 @@ import { StatusEffect, getStatusEffectDescriptor } from '../data/status-effect';
import { MoneyAchv } from '../system/achv';
import { VoucherType } from '../system/voucher';
import { PreventBerryUseAbAttr, applyAbAttrs } from '../data/ability';
import { FormChangeItem, SpeciesFormChangeItemTrigger } from '../data/pokemon-forms';
type ModifierType = ModifierTypes.ModifierType;
export type ModifierPredicate = (modifier: Modifier) => boolean;
@ -990,7 +991,7 @@ export class EvolutionItemModifier extends ConsumablePokemonModifier {
&& (!e.condition || e.condition.predicate(pokemon)));
if (matchingEvolution) {
pokemon.scene.unshiftPhase(new EvolutionPhase(pokemon.scene, pokemon.scene.getParty().indexOf(pokemon), matchingEvolution, pokemon.level - 1));
pokemon.scene.unshiftPhase(new EvolutionPhase(pokemon.scene, pokemon, matchingEvolution, pokemon.level - 1));
return true;
}
@ -1260,6 +1261,39 @@ export class PokemonNatureWeightModifier extends PokemonHeldItemModifier {
}
}
export class PokemonFormChangeItemModifier extends PokemonHeldItemModifier {
public formChangeItem: FormChangeItem;
public active: boolean;
constructor(type: ModifierTypes.FormChangeItemModifierType, pokemonId: integer, formChangeItem: FormChangeItem, active: boolean, stackCount?: integer) {
super(type, pokemonId, stackCount);
this.formChangeItem = formChangeItem;
this.active = active;
}
matchType(modifier: Modifier): boolean {
return modifier instanceof PokemonFormChangeItemModifier && modifier.formChangeItem === this.formChangeItem;
}
clone(): PersistentModifier {
return new PokemonFormChangeItemModifier(this.type as ModifierTypes.FormChangeItemModifierType, this.pokemonId, this.formChangeItem, this.active, this.stackCount);
}
getArgs(): any[] {
return super.getArgs().concat(this.formChangeItem, this.active);
}
apply(args: any[]): boolean {
const pokemon = args[0] as Pokemon;
return pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeItemTrigger);
}
getMaxHeldItemCount(pokemon: Pokemon): integer {
return 1;
}
}
export class MoneyMultiplierModifier extends PersistentModifier {
constructor(type: ModifierType, stackCount?: integer) {
super(type, stackCount);

View File

@ -34,6 +34,7 @@ import { DamageAchv, achvs } from './system/achv';
import { DexAttr } from './system/game-data';
import { QuantizerCelebi, argbFromRgba, rgbaFromArgb } from '@material/material-color-utilities';
import { Nature, getNatureStatMultiplier } from './data/nature';
import { SpeciesFormChange, SpeciesFormChangeMoveUsedTrigger, SpeciesFormChangeStatusEffectTrigger } from './data/pokemon-forms';
export enum FieldPosition {
CENTER,
@ -146,10 +147,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
Utils.binToDec(Utils.decToBin(this.id).substring(25, 30))
];
this.nature = nature !== undefined
? nature
: Utils.randSeedInt(25) as Nature;
if (this.gender === undefined) {
if (this.species.malePercent === null)
this.gender = Gender.GENDERLESS;
@ -163,11 +160,16 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
if (this.formIndex === undefined)
this.formIndex = this.scene.getSpeciesFormIndex(species, this.gender, this.isPlayer());
this.formIndex = this.scene.getSpeciesFormIndex(species, this.gender, this.nature, this.isPlayer());
if (this.shiny === undefined)
this.trySetShiny();
if (nature !== undefined)
this.setNature(nature);
else
this.generateNature();
this.friendship = species.baseFriendship;
this.metLevel = level;
this.metBiome = scene.currentBattle ? scene.arena.biomeType : -1;
@ -544,6 +546,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.calculateStats();
}
generateNature(naturePool?: Nature[]): void {
if (naturePool === undefined)
naturePool = Utils.getEnumValues(Nature);
const nature = naturePool[Utils.randSeedInt(naturePool.length)];
this.setNature(nature);
}
getMaxHp(): integer {
return this.getStat(Stat.HP);
}
@ -796,7 +805,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.fusionGender = Gender.FEMALE;
}
this.fusionFormIndex = this.scene.getSpeciesFormIndex(this.fusionSpecies, this.fusionGender, true);
this.fusionFormIndex = this.scene.getSpeciesFormIndex(this.fusionSpecies, this.fusionGender, this.nature, true);
this.generateName();
}
@ -1227,6 +1236,22 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return this.summonData.moveQueue;
}
changeForm(formChange: SpeciesFormChange): Promise<void> {
return new Promise(resolve => {
this.formIndex = Math.max(this.species.forms.findIndex(f => f.formKey === formChange.formKey), 0);
this.generateName();
const abilityCount = this.getSpeciesForm().getAbilityCount();
if (this.abilityIndex >= abilityCount) // Shouldn't happen
this.abilityIndex = abilityCount - 1;
this.scene.gameData.setPokemonSeen(this, true);
this.loadAssets().then(() => {
this.calculateStats();
this.scene.updateModifiers(this.isPlayer(), true);
this.updateInfo().then(() => resolve());
});
});
}
cry(soundConfig?: Phaser.Types.Sound.SoundConfig): AnySound {
const cry = this.getSpeciesForm().cry(this.scene, soundConfig);
let duration = cry.totalDuration * 1000;
@ -1430,6 +1455,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
this.status = new Status(effect, 0, cureTurn);
if (effect !== StatusEffect.FAINT)
this.scene.triggerPokemonFormChange(this, SpeciesFormChangeStatusEffectTrigger, true);
return true;
}
@ -1462,6 +1491,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.battleSummonData = new PokemonBattleSummonData();
if (this.getTag(BattlerTagType.SEEDED))
this.lapseTag(BattlerTagType.SEEDED);
this.scene.triggerPokemonFormChange(this, SpeciesFormChangeMoveUsedTrigger, true);
}
resetTurnData(): void {
@ -1876,6 +1906,33 @@ export class PlayerPokemon extends Pokemon {
}
}
getPossibleForm(formChange: SpeciesFormChange): Promise<Pokemon> {
return new Promise(resolve => {
const formIndex = Math.max(this.species.forms.findIndex(f => f.formKey === formChange.formKey), 0);
const ret = this.scene.addPlayerPokemon(this.species, this.level, this.abilityIndex, formIndex, this.gender, this.shiny, this.ivs, this.nature, this);
ret.loadAssets().then(() => resolve(ret));
});
}
changeForm(formChange: SpeciesFormChange): Promise<void> {
return new Promise(resolve => {
this.formIndex = Math.max(this.species.forms.findIndex(f => f.formKey === formChange.formKey), 0);
this.generateName();
const abilityCount = this.getSpeciesForm().getAbilityCount();
if (this.abilityIndex >= abilityCount) // Shouldn't happen
this.abilityIndex = abilityCount - 1;
this.compatibleTms.splice(0, this.compatibleTms.length);
this.generateCompatibleTms();
this.scene.gameData.setPokemonSeen(this, false);
this.scene.gameData.setPokemonCaught(this, false);
this.loadAssets().then(() => {
this.calculateStats();
this.scene.updateModifiers(true, true);
this.updateInfo().then(() => resolve());
});
});
}
isFusion(): boolean {
return !!(this.fusionSpecies || (this.species.speciesId === Species.KYUREM && this.formIndex));
}
@ -2160,8 +2217,6 @@ export class EnemyPokemon extends Pokemon {
if (this.isFainted())
return 0;
let clearedSegment = false;
if (!ignoreSegments && this.isBoss()) {
const segmentSize = this.getMaxHp() / this.bossSegments;
for (let s = this.bossSegments - 1; s > 0; s--) {
@ -2169,7 +2224,6 @@ export class EnemyPokemon extends Pokemon {
if (this.hp > hpThreshold) {
if (this.hp - damage < hpThreshold) {
damage = this.hp - hpThreshold;
clearedSegment = true;
this.handleBossSegmentCleared(s);
}
break;

View File

@ -1,6 +1,6 @@
import BattleScene, { Button } from "../battle-scene";
import { addTextObject, TextStyle } from "./text";
import UI, { Mode } from "./ui";
import { Mode } from "./ui";
import * as Utils from "../utils";
import MessageUiHandler from "./message-ui-handler";
import { getStatName, Stat } from "../data/pokemon-stat";

View File

@ -44,11 +44,18 @@ export default class CommandUiHandler extends UiHandler {
this.commandsContainer.setVisible(true);
let commandPhase: CommandPhase;
let currentPhase = this.scene.getCurrentPhase();
if (currentPhase instanceof CommandPhase)
commandPhase = currentPhase;
else
commandPhase = this.scene.getStandbyPhase() as CommandPhase;
const messageHandler = this.getUi().getMessageHandler();
messageHandler.commandWindow.setVisible(true);
messageHandler.movesWindowContainer.setVisible(false);
messageHandler.message.setWordWrapWidth(1110);
messageHandler.showText(`What will\n${(this.scene.getCurrentPhase() as CommandPhase).getPokemon().name} do?`, 0);
messageHandler.showText(`What will\n${commandPhase.getPokemon().name} do?`, 0);
this.setCursor(this.getCursor());
return true;
@ -118,8 +125,6 @@ export default class CommandUiHandler extends UiHandler {
}
setCursor(cursor: integer): boolean {
const ui = this.getUi();
const changed = this.getCursor() !== cursor;
if (changed) {
if (!this.fieldIndex)
@ -140,6 +145,7 @@ export default class CommandUiHandler extends UiHandler {
clear(): void {
super.clear();
this.getUi().getMessageHandler().commandWindow.setVisible(false);
this.commandsContainer.setVisible(false);
this.getUi().getMessageHandler().clearText();
this.eraseCursor();

View File

@ -1,9 +1,12 @@
import BattleScene, { Button } from "../battle-scene";
import MessageUiHandler from "./message-ui-handler";
import { TextStyle, addTextObject } from "./text";
import { Mode } from "./ui";
import UiHandler from "./ui-handler";
export default class EvolutionSceneHandler extends UiHandler {
export default class EvolutionSceneHandler extends MessageUiHandler {
public evolutionContainer: Phaser.GameObjects.Container;
public messageBg: Phaser.GameObjects.Image;
public messageContainer: Phaser.GameObjects.Container;
public canCancel: boolean;
public cancelled: boolean;
@ -15,14 +18,48 @@ export default class EvolutionSceneHandler extends UiHandler {
this.canCancel = false;
this.cancelled = false;
const ui = this.getUi();
this.evolutionContainer = this.scene.add.container(0, -this.scene.game.canvas.height / 6);
this.scene.fieldUI.add(this.evolutionContainer);
ui.add(this.evolutionContainer);
const messageBg = this.scene.add.image(0, 0, 'bg');
messageBg.setOrigin(0, 1);
messageBg.setVisible(false);
ui.add(messageBg);
this.messageBg = messageBg;
this.messageContainer = this.scene.add.container(12, -39);
this.messageContainer.setVisible(false);
ui.add(this.messageContainer);
const message = addTextObject(this.scene, 0, 0, '', TextStyle.MESSAGE, {
maxLines: 2,
wordWrap: {
width: 1780
}
});
this.messageContainer.add(message);
this.message = message;
const prompt = this.scene.add.sprite(0, 0, 'prompt');
prompt.setVisible(false);
prompt.setOrigin(0, 0);
this.messageContainer.add(prompt);
this.prompt = prompt;
}
show(_args: any[]): boolean {
super.show(_args);
this.scene.fieldUI.bringToTop(this.evolutionContainer);
this.scene.ui.bringToTop(this.evolutionContainer);
this.scene.ui.bringToTop(this.messageBg);
this.scene.ui.bringToTop(this.messageContainer);
this.messageBg.setVisible(true);
this.messageContainer.setVisible(true);
return true;
}
@ -33,7 +70,18 @@ export default class EvolutionSceneHandler extends UiHandler {
return true;
}
return this.scene.ui.getMessageHandler().processInput(button);
const ui = this.getUi();
if (this.awaitingActionInput) {
if (button === Button.CANCEL || button === Button.ACTION) {
if (this.onActionInput) {
ui.playSelect();
const originalOnActionInput = this.onActionInput;
this.onActionInput = null;
originalOnActionInput();
return true;
}
}
}
}
setCursor(_cursor: integer): boolean {
@ -41,8 +89,11 @@ export default class EvolutionSceneHandler extends UiHandler {
}
clear() {
this.clearText();
this.canCancel = false;
this.cancelled = false;
this.evolutionContainer.removeAll(true);
this.messageContainer.setVisible(false);
this.messageBg.setVisible(false);
}
}

View File

@ -6,13 +6,14 @@ import { Command } from "./command-ui-handler";
import MessageUiHandler from "./message-ui-handler";
import { Mode } from "./ui";
import * as Utils from "../utils";
import { PokemonHeldItemModifier, SwitchEffectTransferModifier } from "../modifier/modifier";
import { PokemonFormChangeItemModifier, PokemonHeldItemModifier, SwitchEffectTransferModifier } from "../modifier/modifier";
import { Moves, allMoves } from "../data/move";
import { getGenderColor, getGenderSymbol } from "../data/gender";
import { StatusEffect } from "../data/status-effect";
import PokemonIconAnimHandler, { PokemonIconAnimMode } from "./pokemon-icon-anim-handler";
import { pokemonEvolutions } from "../data/pokemon-evolutions";
import { addWindow } from "./window";
import { SpeciesFormChangeItemTrigger } from "../data/pokemon-forms";
const defaultMessage = 'Choose a Pokémon.';
@ -38,11 +39,12 @@ export enum PartyOption {
TRANSFER,
SPLICE,
SUMMARY,
UNPAUSE_EVO,
UNPAUSE_EVOLUTION,
RELEASE,
SCROLL_UP = 1000,
SCROLL_DOWN = 1001,
MOVE_1 = 2000,
FORM_CHANGE_ITEM = 2000,
MOVE_1 = 3000,
MOVE_2,
MOVE_3,
MOVE_4
@ -72,6 +74,7 @@ export default class PartyUiHandler extends MessageUiHandler {
private optionsScrollCursor: integer = 0;
private optionsScrollTotal: integer = 0;
private optionsContainer: Phaser.GameObjects.Container;
private optionsBg: Phaser.GameObjects.NineSlice;
private optionsCursorObj: Phaser.GameObjects.Image;
private options: integer[];
@ -228,7 +231,7 @@ export default class PartyUiHandler extends MessageUiHandler {
}
ui.playSelect();
return true;
} else if ((option !== PartyOption.SUMMARY && option !== PartyOption.UNPAUSE_EVO && option !== PartyOption.RELEASE && option !== PartyOption.CANCEL)
} else if ((option !== PartyOption.SUMMARY && option !== PartyOption.UNPAUSE_EVOLUTION && option !== PartyOption.RELEASE && option !== PartyOption.CANCEL)
|| (option === PartyOption.RELEASE && this.partyUiMode === PartyUiMode.RELEASE)) {
let filterResult: string;
if (option !== PartyOption.TRANSFER && option !== PartyOption.SPLICE) {
@ -262,8 +265,23 @@ export default class PartyUiHandler extends MessageUiHandler {
this.selectCallback = null;
selectCallback(this.cursor, option);
}
} else {
if (option >= PartyOption.FORM_CHANGE_ITEM && this.scene.getCurrentPhase() instanceof CommandPhase) {
switch (this.partyUiMode) {
case PartyUiMode.SWITCH:
case PartyUiMode.FAINT_SWITCH:
case PartyUiMode.POST_BATTLE_SWITCH:
let formChangeItemModifiers = this.scene.findModifiers(m => m instanceof PokemonFormChangeItemModifier && m.pokemonId === pokemon.id) as PokemonFormChangeItemModifier[];
if (formChangeItemModifiers.find(m => m.active))
formChangeItemModifiers = formChangeItemModifiers.filter(m => m.active);
const modifier = formChangeItemModifiers[option - PartyOption.FORM_CHANGE_ITEM];
modifier.active = !modifier.active;
this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeItemTrigger, false, true);
break;
}
} else if (this.cursor)
(this.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.POKEMON, this.cursor, option === PartyOption.PASS_BATON);
}
if (this.partyUiMode !== PartyUiMode.MODIFIER && this.partyUiMode !== PartyUiMode.TM_MODIFIER && this.partyUiMode !== PartyUiMode.MOVE_MODIFIER)
ui.playSelect();
return true;
@ -275,7 +293,7 @@ export default class PartyUiHandler extends MessageUiHandler {
ui.playSelect();
ui.setModeWithoutClear(Mode.SUMMARY, pokemon).then(() => this.clearOptions());
return true;
} else if (option === PartyOption.UNPAUSE_EVO) {
} else if (option === PartyOption.UNPAUSE_EVOLUTION) {
this.clearOptions();
ui.playSelect();
pokemon.pauseEvolutions = false;
@ -356,7 +374,7 @@ export default class PartyUiHandler extends MessageUiHandler {
break;
case Button.RIGHT:
const battlerCount = this.scene.currentBattle.getBattlerCount();
if (slotCount && this.cursor < battlerCount)
if (slotCount > battlerCount && this.cursor < battlerCount)
success = this.setCursor(this.lastCursor < 6 ? this.lastCursor || battlerCount : battlerCount);
break;
}
@ -423,8 +441,7 @@ export default class PartyUiHandler extends MessageUiHandler {
this.optionsCursorObj.setOrigin(0, 0);
this.optionsContainer.add(this.optionsCursorObj);
}
const wideOptions = this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER;
this.optionsCursorObj.setPosition(-86 - (wideOptions ? 50 : 0), -19 - (16 * ((this.options.length - 1) - this.optionsCursor)));
this.optionsCursorObj.setPosition(8 - this.optionsBg.displayWidth, -19 - (16 * ((this.options.length - 1) - this.optionsCursor)));
} else {
changed = this.cursor !== cursor;
if (changed) {
@ -485,9 +502,7 @@ export default class PartyUiHandler extends MessageUiHandler {
this.updateOptions();
const wideOptions = this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER;
this.partyMessageBox.setSize(262 - (wideOptions ? 88 : 38), 30);
this.partyMessageBox.setSize(262 - Math.max(this.optionsBg.displayWidth - 56, 0), 30);
this.setCursor(0);
}
@ -512,6 +527,8 @@ export default class PartyUiHandler extends MessageUiHandler {
this.eraseOptionsCursor();
}
let formChangeItemModifiers: PokemonFormChangeItemModifier[];
if (this.partyUiMode !== PartyUiMode.MOVE_MODIFIER && this.partyUiMode !== PartyUiMode.REMEMBER_MOVE_MODIFIER && (this.transferMode || this.partyUiMode !== PartyUiMode.MODIFIER_TRANSFER)) {
switch (this.partyUiMode) {
case PartyUiMode.SWITCH:
@ -524,6 +541,13 @@ export default class PartyUiHandler extends MessageUiHandler {
&& (m as SwitchEffectTransferModifier).pokemonId === this.scene.getPlayerField()[this.fieldIndex].id))
this.options.push(PartyOption.PASS_BATON);
}
if (this.scene.getCurrentPhase() instanceof CommandPhase) {
formChangeItemModifiers = this.scene.findModifiers(m => m instanceof PokemonFormChangeItemModifier && m.pokemonId === pokemon.id) as PokemonFormChangeItemModifier[];
if (formChangeItemModifiers.find(m => m.active))
formChangeItemModifiers = formChangeItemModifiers.filter(m => m.active);
for (let i = 0; i < formChangeItemModifiers.length; i++)
this.options.push(PartyOption.FORM_CHANGE_ITEM + i);
}
break;
case PartyUiMode.MODIFIER:
this.options.push(PartyOption.APPLY);
@ -549,7 +573,7 @@ export default class PartyUiHandler extends MessageUiHandler {
this.options.push(PartyOption.SUMMARY);
if (pokemon.pauseEvolutions && pokemonEvolutions.hasOwnProperty(pokemon.species.speciesId))
this.options.push(PartyOption.UNPAUSE_EVO);
this.options.push(PartyOption.UNPAUSE_EVOLUTION);
if (this.partyUiMode === PartyUiMode.SWITCH)
this.options.push(PartyOption.RELEASE);
@ -582,14 +606,17 @@ export default class PartyUiHandler extends MessageUiHandler {
this.options.push(PartyOption.CANCEL);
const optionBg = addWindow(this.scene, 0, 0, wideOptions ? 144 : 94, 16 * this.options.length + 13);
optionBg.setOrigin(1, 1);
this.optionsBg = addWindow(this.scene, 0, 0, 0, 16 * this.options.length + 13);
this.optionsBg.setOrigin(1, 1);
this.optionsContainer.add(optionBg);
this.optionsContainer.add(this.optionsBg);
optionStartIndex = 0;
optionEndIndex = this.options.length;
let widestOptionWidth = 0;
let optionTexts: Phaser.GameObjects.Text[] = [];
for (let o = optionStartIndex; o < optionEndIndex; o++) {
const option = this.options[this.options.length - (o + 1)];
let altText = false;
@ -602,10 +629,11 @@ export default class PartyUiHandler extends MessageUiHandler {
case PartyOption.MOVE_4:
optionName = pokemon.moveset[option - PartyOption.MOVE_1].getName();
break;
case PartyOption.UNPAUSE_EVO:
optionName = 'Unpause Evo.';
break;
default:
if (formChangeItemModifiers && option >= PartyOption.FORM_CHANGE_ITEM) {
const modifier = formChangeItemModifiers[option - PartyOption.FORM_CHANGE_ITEM];
optionName = `${modifier.active ? 'Deactivate' : 'Activate'} ${modifier.type.name}`;
} else
optionName = Utils.toReadableString(PartyOption[option]);
break;
}
@ -625,15 +653,23 @@ export default class PartyUiHandler extends MessageUiHandler {
}
const yCoord = -6 - 16 * o;
const optionText = addTextObject(this.scene, -79 - (wideOptions ? 50 : 0), yCoord - 16, optionName, TextStyle.WINDOW);
const optionText = addTextObject(this.scene, 0, yCoord - 16, optionName, TextStyle.WINDOW);
if (altText) {
optionText.setColor('#40c8f8');
optionText.setShadowColor('#006090')
}
optionText.setOrigin(0, 0);
optionTexts.push(optionText);
widestOptionWidth = Math.max(optionText.displayWidth, widestOptionWidth);
this.optionsContainer.add(optionText);
}
this.optionsBg.width = Math.max(widestOptionWidth + 24, 94);
for (let optionText of optionTexts)
optionText.x = 15 - this.optionsBg.width;
}
startTransfer(): void {

View File

@ -345,6 +345,7 @@ export default class UI extends Phaser.GameObjects.Container {
const touchControls = document.getElementById('touchControls');
if (touchControls)
touchControls.dataset.uiMode = Mode[this.mode];
resolve(true);
};
if (noTransitionModes.indexOf(lastMode) === -1) {
@ -356,8 +357,6 @@ export default class UI extends Phaser.GameObjects.Container {
});
} else
doRevertMode();
resolve(true);
});
}