Merge branch 'pagefaultgames:main' into main

This commit is contained in:
Stophles 2024-04-06 13:44:50 -05:00 committed by GitHub
commit 9b62d3ac60
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 7247 additions and 7097 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 505 B

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 72 KiB

View File

@ -1,6 +1,6 @@
import Phaser from 'phaser';
import UI, { Mode } from './ui/ui';
import { NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, TurnInitPhase, ReturnPhase, LevelCapPhase, ShowTrainerPhase, LoginPhase, MovePhase, TitlePhase } from './phases';
import { NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, TurnInitPhase, ReturnPhase, LevelCapPhase, ShowTrainerPhase, LoginPhase, MovePhase, TitlePhase, SwitchPhase } from './phases';
import Pokemon, { PlayerPokemon, EnemyPokemon } from './field/pokemon';
import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies, initSpecies } from './data/pokemon-species';
import * as Utils from './utils';
@ -710,6 +710,9 @@ export default class BattleScene extends SceneBase {
const lastBattle = this.currentBattle;
if (lastBattle?.double && !newDouble)
this.tryRemovePhase(p => p instanceof SwitchPhase);
const maxExpLevel = this.getMaxExpLevel();
this.lastEnemyTrainer = lastBattle?.trainer ?? null;

View File

@ -204,7 +204,7 @@ export class PreDefendFullHpEndureAbAttr extends PreDefendAbAttr {
if (pokemon.getHpRatio() < 1 || (args[0] as Utils.NumberHolder).value < pokemon.hp)
return false;
return pokemon.addTag(BattlerTagType.ENDURING, 1);
return pokemon.addTag(BattlerTagType.STURDY, 1);
}
}

View File

@ -721,6 +721,21 @@ export class EnduringTag extends BattlerTag {
}
}
export class SturdyTag extends BattlerTag {
constructor(sourceMove: Moves) {
super(BattlerTagType.STURDY, BattlerTagLapseType.TURN_END, 0, sourceMove);
}
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
if (lapseType === BattlerTagLapseType.CUSTOM) {
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ' endured\nthe hit!'));
return true;
}
return super.lapse(pokemon, lapseType);
}
}
export class PerishSongTag extends BattlerTag {
constructor(turnCount: integer) {
super(BattlerTagType.PERISH_SONG, BattlerTagLapseType.TURN_END, turnCount, Moves.PERISH_SONG);
@ -1013,6 +1028,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc
return new ContactBurnProtectedTag(sourceMove);
case BattlerTagType.ENDURING:
return new EnduringTag(sourceMove);
case BattlerTagType.STURDY:
return new SturdyTag(sourceMove);
case BattlerTagType.PERISH_SONG:
return new PerishSongTag(turnCount);
case BattlerTagType.TRUANT:

View File

@ -279,7 +279,7 @@ export const biomePokemonPools: BiomePokemonPools = {
[TimeOfDay.ALL]: [ Species.NINJASK, Species.ZANGOOSE, Species.KECLEON, Species.LURANTIS, Species.LOKIX ]
},
[BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [ Species.BELLOSSOM ], [TimeOfDay.DAY]: [ Species.BELLOSSOM ], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.PINSIR, Species.MEGANIUM, Species.FARIGIRAF ] },
[BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] },
[BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.ROTOM ] },
[BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] }
},
[Biome.METROPOLIS]: {
@ -436,7 +436,7 @@ export const biomePokemonPools: BiomePokemonPools = {
[TimeOfDay.ALL]: [ Species.TENTACRUEL, Species.FLOATZEL, Species.SIMIPOUR, Species.KILOWATTREL ]
},
[BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.KINGDRA, Species.EMPOLEON, Species.PRIMARINA ] },
[BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] },
[BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.ROTOM ] },
[BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.LUGIA ] }
},
[Biome.SWAMP]: {
@ -724,7 +724,7 @@ export const biomePokemonPools: BiomePokemonPools = {
[TimeOfDay.ALL]: [ Species.PIDGEOT, Species.FEAROW, Species.SKARMORY, Species.AGGRON, Species.GOGOAT, Species.GARGANACL ]
},
[BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [ Species.HISUI_BRAVIARY ], [TimeOfDay.DAY]: [ Species.HISUI_BRAVIARY ], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.BLAZIKEN, Species.RAMPARDOS, Species.BASTIODON, Species.HAWLUCHA ] },
[BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.TORNADUS, Species.TING_LU, Species.OGERPON ] },
[BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.ROTOM, Species.TORNADUS, Species.TING_LU, Species.OGERPON ] },
[BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.HO_OH ] }
},
[Biome.BADLANDS]: {
@ -893,7 +893,7 @@ export const biomePokemonPools: BiomePokemonPools = {
[TimeOfDay.ALL]: [ Species.DEWGONG, Species.GLALIE, Species.WALREIN, Species.WEAVILE, Species.MAMOSWINE, Species.FROSLASS, Species.VANILLUXE, Species.BEARTIC, Species.CRYOGONAL, Species.AVALUGG, Species.CRABOMINABLE, Species.CETITAN ]
},
[BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.JYNX, Species.LAPRAS, Species.GLACEON, Species.AURORUS ] },
[BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.ARTICUNO, Species.REGICE ] },
[BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.ARTICUNO, Species.REGICE, Species.ROTOM ] },
[BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.KYUREM ] }
},
[Biome.MEADOW]: {
@ -1037,7 +1037,7 @@ export const biomePokemonPools: BiomePokemonPools = {
[TimeOfDay.NIGHT]: [],
[TimeOfDay.ALL]: [ Species.CHARIZARD, Species.FLAREON, Species.TYPHLOSION, Species.INFERNAPE, Species.EMBOAR, Species.VOLCARONA, Species.DELPHOX, Species.INCINEROAR, Species.CINDERACE, Species.ARMAROUGE ]
},
[BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.MOLTRES, Species.ENTEI, Species.HEATRAN, Species.VOLCANION, Species.CHI_YU, Species.HISUI_ARCANINE ] },
[BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.MOLTRES, Species.ENTEI, Species.ROTOM, Species.HEATRAN, Species.VOLCANION, Species.CHI_YU, Species.HISUI_ARCANINE ] },
[BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.RESHIRAM ] }
},
[Biome.GRAVEYARD]: {
@ -1582,7 +1582,7 @@ export const biomePokemonPools: BiomePokemonPools = {
[BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.TYPE_NULL ] },
[BiomePoolTier.BOSS]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.MUK, Species.ELECTRODE, Species.BRONZONG, Species.MAGNEZONE, Species.PORYGON_Z, Species.REUNICLUS, Species.KLINKLANG ] },
[BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] },
[BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.ZYGARDE, Species.SILVALLY ] },
[BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.ROTOM, Species.ZYGARDE, Species.SILVALLY ] },
[BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.MEWTWO, Species.MIRAIDON ] }
},
[Biome.END]: {
@ -4321,11 +4321,17 @@ export const biomeTrainerPools: BiomeTrainerPools = {
],
[ Species.ROTOM, Type.ELECTRIC, Type.GHOST, [
[ Biome.LABORATORY, BiomePoolTier.SUPER_RARE ],
[ Biome.LABORATORY, BiomePoolTier.BOSS_SUPER_RARE ],
[ Biome.VOLCANO, BiomePoolTier.SUPER_RARE ],
[ Biome.VOLCANO, BiomePoolTier.BOSS_SUPER_RARE ],
[ Biome.SEA, BiomePoolTier.SUPER_RARE ],
[ Biome.SEA, BiomePoolTier.BOSS_SUPER_RARE ],
[ Biome.ICE_CAVE, BiomePoolTier.SUPER_RARE ],
[ Biome.ICE_CAVE, BiomePoolTier.BOSS_SUPER_RARE ],
[ Biome.MOUNTAIN, BiomePoolTier.SUPER_RARE ],
[ Biome.TALL_GRASS, BiomePoolTier.SUPER_RARE ]
[ Biome.MOUNTAIN, BiomePoolTier.BOSS_SUPER_RARE ],
[ Biome.TALL_GRASS, BiomePoolTier.SUPER_RARE ],
[ Biome.TALL_GRASS, BiomePoolTier.BOSS_SUPER_RARE ]
]
],
[ Species.UXIE, Type.PSYCHIC, -1, [

View File

@ -29,6 +29,7 @@ export enum BattlerTagType {
BANEFUL_BUNKER = "BANEFUL_BUNKER",
BURNING_BULWARK = "BURNING_BULWARK",
ENDURING = "ENDURING",
STURDY = "STURDY",
PERISH_SONG = "PERISH_SONG",
TRUANT = "TRUANT",
SLOW_START = "SLOW_START",

View File

@ -638,7 +638,7 @@ export class RecoilAttr extends MoveEffectAttr {
if (cancelled.value)
return false;
user.damageAndUpdate(recoilDamage, HitResult.OTHER, false, true);
user.damageAndUpdate(recoilDamage, HitResult.OTHER, false, true, true);
user.scene.queueMessage(getPokemonMessage(user, ' is hit\nwith recoil!'));
return true;
@ -2264,7 +2264,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
private batonPass: boolean;
constructor(user?: boolean, batonPass?: boolean) {
super(false, MoveEffectTrigger.HIT);
super(false, MoveEffectTrigger.HIT, true);
this.user = !!user;
this.batonPass = !!batonPass;

View File

@ -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;
@ -506,8 +516,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.DUSCLOPS, 37, null, null)
],
[Species.SNORUNT]: [
new SpeciesEvolution(Species.GLALIE, 42, null, null),
new SpeciesEvolution(Species.FROSLASS, 1, EvolutionItem.DAWN_STONE, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE), SpeciesWildEvolutionDelay.VERY_LONG)
new SpeciesEvolution(Species.GLALIE, 42, null, new SpeciesEvolutionCondition(p => p.gender === Gender.MALE, p => p.gender = Gender.MALE)),
new SpeciesEvolution(Species.FROSLASS, 42, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE))
],
[Species.SPHEAL]: [
new SpeciesEvolution(Species.SEALEO, 32, null, null)
@ -1354,8 +1364,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.LILLIGANT, 1, EvolutionItem.SUN_STONE, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY), SpeciesWildEvolutionDelay.LONG)
],
[Species.BASCULIN]: [
new SpeciesFormEvolution(Species.BASCULEGION, 'white-striped', 'male', 25, null, new SpeciesEvolutionCondition(p => p.gender === Gender.MALE, p => p.gender = Gender.MALE), SpeciesWildEvolutionDelay.VERY_LONG),
new SpeciesFormEvolution(Species.BASCULEGION, 'white-striped', 'female', 25, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE), SpeciesWildEvolutionDelay.VERY_LONG)
new SpeciesFormEvolution(Species.BASCULEGION, 'white-striped', 'male', 40, null, new SpeciesEvolutionCondition(p => p.gender === Gender.MALE, p => p.gender = Gender.MALE), SpeciesWildEvolutionDelay.VERY_LONG),
new SpeciesFormEvolution(Species.BASCULEGION, 'white-striped', 'female', 40, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE), SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.MINCCINO]: [
new SpeciesEvolution(Species.CINCCINO, 1, EvolutionItem.SHINY_STONE, null, SpeciesWildEvolutionDelay.LONG)

View File

@ -536,7 +536,8 @@ export const pokemonFormChanges: PokemonFormChanges = {
],
[Species.AEGISLASH]: [
new SpeciesFormChange(Species.AEGISLASH, 'blade', 'shield', new SpeciesFormChangePreMoveTrigger(Moves.KINGS_SHIELD), true, new SpeciesFormChangeCondition(p => p.getAbility().id === Abilities.STANCE_CHANGE)),
new SpeciesFormChange(Species.AEGISLASH, 'shield', 'blade', new SpeciesFormChangePreMoveTrigger(m => allMoves[m].category !== MoveCategory.STATUS), true, new SpeciesFormChangeCondition(p => p.getAbility().id === Abilities.STANCE_CHANGE))
new SpeciesFormChange(Species.AEGISLASH, 'shield', 'blade', new SpeciesFormChangePreMoveTrigger(m => allMoves[m].category !== MoveCategory.STATUS), true, new SpeciesFormChangeCondition(p => p.getAbility().id === Abilities.STANCE_CHANGE)),
new SpeciesFormChange(Species.AEGISLASH, 'blade', 'shield', new SpeciesFormChangeActiveTrigger(false), true)
],
[Species.DIANCIE]: [
new SpeciesFormChange(Species.DIANCIE, '', SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.DIANCITE))

View File

@ -3030,6 +3030,19 @@ export const speciesStarters = {
[Species.BLOODMOON_URSALUNA]: 7,
};
export const noStarterFormKeys: string[] = [
SpeciesFormKey.MEGA,
SpeciesFormKey.MEGA_X,
SpeciesFormKey.MEGA_Y,
SpeciesFormKey.PRIMAL,
SpeciesFormKey.ORIGIN,
SpeciesFormKey.THERIAN,
SpeciesFormKey.GIGANTAMAX,
SpeciesFormKey.GIGANTAMAX_RAPID,
SpeciesFormKey.GIGANTAMAX_SINGLE,
SpeciesFormKey.ETERNAMAX
].map(k => k.toString());
// TODO: Remove
{
//setTimeout(() => {

View File

@ -26,10 +26,12 @@ export class Weather {
constructor(weatherType: WeatherType, turnsLeft?: integer) {
this.weatherType = weatherType;
this.turnsLeft = turnsLeft || 0;
this.turnsLeft = !this.isImmutable() ? turnsLeft || 0 : 0;
}
lapse(): boolean {
if (this.isImmutable())
return true;
if (this.turnsLeft)
return !!--this.turnsLeft;

View File

@ -269,9 +269,8 @@ export class Arena {
trySetWeather(weather: WeatherType, hasPokemonSource: boolean): boolean {
// override hook for debugging
if (WEATHER_OVERRIDE) {
if (WEATHER_OVERRIDE)
return this.trySetWeatherOverride(WEATHER_OVERRIDE);
}
if (this.weather?.weatherType === (weather || undefined))
return false;

View File

@ -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;
}
}
}
@ -1271,11 +1284,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
damage(damage: integer, ignoreSegments: boolean = false, preventEndure: boolean = false): integer {
if (this.isFainted())
return 0;
const surviveDamage = new Utils.BooleanHolder(false);
if (this.hp >= 1 && this.hp - damage <= 0 && !preventEndure) {
const surviveDamage = new Utils.BooleanHolder(false);
if (this.lapseTag(BattlerTagType.ENDURING))
surviveDamage.value = true;
if (!preventEndure && this.hp - damage <= 0) {
if(this.hp >= 1 && this.getTag(BattlerTagType.ENDURING))
surviveDamage.value = this.lapseTag(BattlerTagType.ENDURING)
else if (this.hp > 1 && this.getTag(BattlerTagType.STURDY))
surviveDamage.value = this.lapseTag(BattlerTagType.STURDY)
if (!surviveDamage.value)
this.scene.applyModifiers(SurviveDamageModifier, this.isPlayer(), this, surviveDamage);
if (surviveDamage.value)
@ -2116,9 +2131,21 @@ export class PlayerPokemon extends Pokemon {
getPossibleEvolution(evolution: SpeciesFormEvolution): Promise<Pokemon> {
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 +2154,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 +2194,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 +2251,6 @@ export class PlayerPokemon extends Pokemon {
});
}
isFusion(): boolean {
return !!this.fusionSpecies;
}
clearFusionSpecies(): void {
super.clearFusionSpecies();
this.generateCompatibleTms();

View File

@ -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;
@ -886,7 +895,7 @@ export const modifierTypes = {
SHINY_CHARM: () => new ModifierType('Shiny Charm', 'Dramatically increases the chance of a wild Pokémon being shiny', (type, _args) => new Modifiers.ShinyRateBoosterModifier(type)),
ABILITY_CHARM: () => new ModifierType('Ability Charm', 'Dramatically increases the chance of a wild Pokémon having a hidden ability', (type, _args) => new Modifiers.HiddenAbilityRateBoosterModifier(type)),
IV_SCANNER: () => new ModifierType('IV Scanner', 'Allows scanning the IVs of wild Pokémon', (type, _args) => new Modifiers.IvScannerModifier(type), 'scanner'),
IV_SCANNER: () => new ModifierType('IV Scanner', 'Allows scanning the IVs of wild Pokémon. 2 IVs are revealed per stack. The best IVs are shown first.', (type, _args) => new Modifiers.IvScannerModifier(type), 'scanner'),
DNA_SPLICERS: () => new FusePokemonModifierType('DNA Splicers'),

View File

@ -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,9 +1183,19 @@ 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
&& (e.evoFormKey === null || (e.preFormKey || '') === pokemon.getFormKey())
&& (!e.condition || e.condition.predicate(pokemon)));
let matchingEvolution = pokemonEvolutions.hasOwnProperty(pokemon.species.speciesId)
? 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)))
: null;
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));
@ -1865,7 +1875,7 @@ export class IvScannerModifier extends PersistentModifier {
}
getMaxStackCount(scene: BattleScene): integer {
return 5;
return 3;
}
}

View File

@ -55,7 +55,7 @@ import { OptionSelectConfig, OptionSelectItem } from "./ui/abstact-option-select
import { SaveSlotUiMode } from "./ui/save-slot-select-ui-handler";
import { fetchDailyRunSeed, getDailyRunStarters } from "./data/daily-run";
import { GameModes, gameModes } from "./game-mode";
import { getPokemonSpecies } from "./data/pokemon-species";
import { getPokemonSpecies, speciesStarters } from "./data/pokemon-species";
export class LoginPhase extends Phase {
private showText: boolean;
@ -765,7 +765,7 @@ export class EncounterPhase extends BattlePhase {
enemyField.map(p => this.scene.pushPhase(new PostSummonPhase(this.scene, p.getBattlerIndex())));
const ivScannerModifier = this.scene.findModifier(m => m instanceof IvScannerModifier);
if (ivScannerModifier)
enemyField.map(p => this.scene.pushPhase(new ScanIvsPhase(this.scene, p.getBattlerIndex(), Math.min(ivScannerModifier.getStackCount(), 6))));
enemyField.map(p => this.scene.pushPhase(new ScanIvsPhase(this.scene, p.getBattlerIndex(), Math.min(ivScannerModifier.getStackCount() * 2, 6))));
}
if (!this.loaded) {
@ -1512,7 +1512,7 @@ export class CommandPhase extends FieldPhase {
}
break;
case Command.BALL:
if (this.scene.arena.biomeType === Biome.END) {
if (this.scene.arena.biomeType === Biome.END && (!this.scene.gameMode.isClassic || this.scene.gameData.getStarterCount(d => !!d.caughtAttr) < Object.keys(speciesStarters).length - 1)) {
this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex);
this.scene.ui.setMode(Mode.MESSAGE);
this.scene.ui.showText(`An unseen force\nprevents using Poké Balls.`, null, () => {
@ -2571,7 +2571,7 @@ export class WeatherEffectPhase extends CommonAnimPhase {
const damage = Math.ceil(pokemon.getMaxHp() / 16);
this.scene.queueMessage(getWeatherDamageMessage(this.weather.weatherType, pokemon));
pokemon.damageAndUpdate(damage);
pokemon.damageAndUpdate(damage, HitResult.OTHER, false, false, true);
};
this.executeForAll((pokemon: Pokemon) => {
@ -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');

View File

@ -1,7 +1,7 @@
import BattleScene, { PokeballCounts, bypassLogin } from "../battle-scene";
import Pokemon, { EnemyPokemon, PlayerPokemon } from "../field/pokemon";
import { pokemonPrevolutions } from "../data/pokemon-evolutions";
import PokemonSpecies, { allSpecies, getPokemonSpecies, speciesStarters } from "../data/pokemon-species";
import PokemonSpecies, { SpeciesFormKey, allSpecies, getPokemonSpecies, noStarterFormKeys, speciesStarters } from "../data/pokemon-species";
import { Species } from "../data/enums/species";
import * as Utils from "../utils";
import PokemonData from "./pokemon-data";
@ -936,7 +936,12 @@ export class GameData {
return new Promise<void>(resolve => {
const dexEntry = this.dexData[species.speciesId];
const caughtAttr = dexEntry.caughtAttr;
dexEntry.caughtAttr |= pokemon.getDexAttr();
const formIndex = pokemon.formIndex;
if (noStarterFormKeys.includes(pokemon.getFormKey()))
pokemon.formIndex = 0;
const dexAttr = pokemon.getDexAttr();
pokemon.formIndex = formIndex;
dexEntry.caughtAttr |= dexAttr;
dexEntry.natureAttr |= Math.pow(2, pokemon.nature + 1);
if (incrementCount) {
if (!fromEgg) {
@ -1018,6 +1023,27 @@ export class GameData {
} while (pokemonPrevolutions.hasOwnProperty(speciesId) && (speciesId = pokemonPrevolutions[speciesId]));
}
getSpeciesCount(dexEntryPredicate: (entry: DexEntry) => boolean): integer {
const dexKeys = Object.keys(this.dexData);
let speciesCount = 0;
for (let s of dexKeys) {
if (dexEntryPredicate(this.dexData[s]))
speciesCount++;
}
return speciesCount;
}
getStarterCount(dexEntryPredicate: (entry: DexEntry) => boolean): integer {
const starterKeys = Object.keys(speciesStarters);
let starterCount = 0;
for (let s of starterKeys) {
const starterDexEntry = this.dexData[s];
if (dexEntryPredicate(starterDexEntry))
starterCount++;
}
return starterCount;
}
getSpeciesDefaultDexAttr(species: PokemonSpecies, forSeen: boolean = false): bigint {
let ret = 0n;
const dexEntry = this.dexData[species.speciesId];

View File

@ -193,7 +193,14 @@ export default class BattleMessageUiHandler extends MessageUiHandler {
if (shownIvsCount < 6) {
let statsPool = stats.slice(0);
for (let i = 0; i < shownIvsCount; i++) {
const shownStat = Utils.randSeedItem(statsPool);
let shownStat: Stat;
let highestIv = -1;
statsPool.map(s => {
if (ivs[s] > highestIv) {
shownStat = s as Stat;
highestIv = ivs[s];
}
});
shownStats.push(shownStat);
statsPool.splice(statsPool.indexOf(shownStat), 1);
}

View File

@ -25,49 +25,29 @@ const displayStats: DisplayStats = {
startersUnlocked: {
label: 'Starters',
sourceFunc: gameData => {
const starterKeys = Object.keys(speciesStarters);
let starterCount = 0;
for (let s of starterKeys) {
if (gameData.dexData[s].caughtAttr)
starterCount++;
}
return `${starterCount} (${Math.floor((starterCount / starterKeys.length) * 1000) / 10}%)`;
const starterCount = gameData.getStarterCount(d => !!d.caughtAttr);
return `${starterCount} (${Math.floor((starterCount / Object.keys(speciesStarters).length) * 1000) / 10}%)`;
}
},
shinyStartersUnlocked: {
label: 'Shiny Starters',
sourceFunc: gameData => {
const starterKeys = Object.keys(speciesStarters);
let starterCount = 0;
for (let s of starterKeys) {
if (gameData.dexData[s].caughtAttr & DexAttr.SHINY)
starterCount++;
}
return `${starterCount} (${Math.floor((starterCount / starterKeys.length) * 1000) / 10}%)`;
const starterCount = gameData.getStarterCount(d => !!(d.caughtAttr & DexAttr.SHINY));
return `${starterCount} (${Math.floor((starterCount / Object.keys(speciesStarters).length) * 1000) / 10}%)`;
}
},
dexSeen: {
label: 'Species Seen',
sourceFunc: gameData => {
const dexKeys = Object.keys(gameData.dexData);
let seenCount = 0;
for (let s of dexKeys) {
if (gameData.dexData[s].seenAttr)
seenCount++;
}
return `${seenCount} (${Math.floor((seenCount / dexKeys.length) * 1000) / 10}%)`;
const seenCount = gameData.getSpeciesCount(d => !!d.seenAttr);
return `${seenCount} (${Math.floor((seenCount / Object.keys(gameData.dexData).length) * 1000) / 10}%)`;
}
},
dexCaught: {
label: 'Species Caught',
sourceFunc: gameData => {
const dexKeys = Object.keys(gameData.dexData);
let caughtCount = 0;
for (let s of dexKeys) {
if (gameData.dexData[s].caughtAttr)
caughtCount++;
}
return `${caughtCount} (${Math.floor((caughtCount / dexKeys.length) * 1000) / 10}%)`;
const caughtCount = gameData.getSpeciesCount(d => !!d.caughtAttr);
return `${caughtCount} (${Math.floor((caughtCount / Object.keys(gameData.dexData).length) * 1000) / 10}%)`;
}
},
classicSessionsPlayed: 'Classic Runs',