Merge branch 'beta' into pr-illusion

This commit is contained in:
Lylian BALL 2024-10-11 20:00:11 +02:00 committed by GitHub
commit eba3d1d0b5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 1062 additions and 252 deletions

View File

@ -2676,7 +2676,7 @@ export default class BattleScene extends SceneBase {
}
/**
* Removes all modifiers from enemy of PersistentModifier type
* Removes all modifiers from enemy pokemon of {@linkcode PersistentModifier} type
*/
clearEnemyModifiers(): void {
const modifiersToRemove = this.enemyModifiers.filter(m => m instanceof PersistentModifier);
@ -2687,10 +2687,11 @@ export default class BattleScene extends SceneBase {
}
/**
* Removes all modifiers from enemy of PokemonHeldItemModifier type
* Removes all modifiers from enemy pokemon of {@linkcode PokemonHeldItemModifier} type
* @param pokemon - If specified, only removes held items from that {@linkcode Pokemon}
*/
clearEnemyHeldItemModifiers(): void {
const modifiersToRemove = this.enemyModifiers.filter(m => m instanceof PokemonHeldItemModifier);
clearEnemyHeldItemModifiers(pokemon?: Pokemon): void {
const modifiersToRemove = this.enemyModifiers.filter(m => m instanceof PokemonHeldItemModifier && (!pokemon || m.getPokemon(this) === pokemon));
for (const m of modifiersToRemove) {
this.enemyModifiers.splice(this.enemyModifiers.indexOf(m), 1);
}

View File

@ -28,20 +28,13 @@ export enum ArenaTagSide {
}
export abstract class ArenaTag {
public tagType: ArenaTagType;
public turnCount: integer;
public sourceMove?: Moves;
public sourceId?: integer;
public side: ArenaTagSide;
constructor(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves | undefined, sourceId?: integer, side: ArenaTagSide = ArenaTagSide.BOTH) {
this.tagType = tagType;
this.turnCount = turnCount;
this.sourceMove = sourceMove;
this.sourceId = sourceId;
this.side = side;
}
constructor(
public tagType: ArenaTagType,
public turnCount: number,
public sourceMove?: Moves,
public sourceId?: number,
public side: ArenaTagSide = ArenaTagSide.BOTH
) {}
apply(arena: Arena, args: any[]): boolean {
return true;
@ -66,6 +59,18 @@ export abstract class ArenaTag {
? allMoves[this.sourceMove].name
: null;
}
/**
* When given a arena tag or json representing one, load the data for it.
* This is meant to be inherited from by any arena tag with custom attributes
* @param {ArenaTag | any} source An arena tag
*/
loadTag(source : ArenaTag | any) : void {
this.turnCount = source.turnCount;
this.sourceMove = source.sourceMove;
this.sourceId = source.sourceId;
this.side = source.side;
}
}
/**
@ -73,7 +78,7 @@ export abstract class ArenaTag {
* Prevents Pokémon on the opposing side from lowering the stats of the Pokémon in the Mist.
*/
export class MistTag extends ArenaTag {
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
constructor(turnCount: number, sourceId: number, side: ArenaTagSide) {
super(ArenaTagType.MIST, turnCount, Moves.MIST, sourceId, side);
}
@ -117,7 +122,7 @@ export class WeakenMoveScreenTag extends ArenaTag {
* @param side - The side (player or enemy) the tag affects.
* @param weakenedCategories - The categories of moves that are weakened by this tag.
*/
constructor(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves, sourceId: integer, side: ArenaTagSide, weakenedCategories: MoveCategory[]) {
constructor(tagType: ArenaTagType, turnCount: number, sourceMove: Moves, sourceId: number, side: ArenaTagSide, weakenedCategories: MoveCategory[]) {
super(tagType, turnCount, sourceMove, sourceId, side);
this.weakenedCategories = weakenedCategories;
@ -148,7 +153,7 @@ export class WeakenMoveScreenTag extends ArenaTag {
* Used by {@linkcode Moves.REFLECT}
*/
class ReflectTag extends WeakenMoveScreenTag {
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
constructor(turnCount: number, sourceId: number, side: ArenaTagSide) {
super(ArenaTagType.REFLECT, turnCount, Moves.REFLECT, sourceId, side, [ MoveCategory.PHYSICAL ]);
}
@ -164,7 +169,7 @@ class ReflectTag extends WeakenMoveScreenTag {
* Used by {@linkcode Moves.LIGHT_SCREEN}
*/
class LightScreenTag extends WeakenMoveScreenTag {
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
constructor(turnCount: number, sourceId: number, side: ArenaTagSide) {
super(ArenaTagType.LIGHT_SCREEN, turnCount, Moves.LIGHT_SCREEN, sourceId, side, [ MoveCategory.SPECIAL ]);
}
@ -180,7 +185,7 @@ class LightScreenTag extends WeakenMoveScreenTag {
* Used by {@linkcode Moves.AURORA_VEIL}
*/
class AuroraVeilTag extends WeakenMoveScreenTag {
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
constructor(turnCount: number, sourceId: number, side: ArenaTagSide) {
super(ArenaTagType.AURORA_VEIL, turnCount, Moves.AURORA_VEIL, sourceId, side, [ MoveCategory.SPECIAL, MoveCategory.PHYSICAL ]);
}
@ -203,7 +208,7 @@ export class ConditionalProtectTag extends ArenaTag {
/** Does this apply to all moves, including those that ignore other forms of protection? */
protected ignoresBypass: boolean;
constructor(tagType: ArenaTagType, sourceMove: Moves, sourceId: integer, side: ArenaTagSide, condition: ProtectConditionFunc, ignoresBypass: boolean = false) {
constructor(tagType: ArenaTagType, sourceMove: Moves, sourceId: number, side: ArenaTagSide, condition: ProtectConditionFunc, ignoresBypass: boolean = false) {
super(tagType, 1, sourceMove, sourceId, side);
this.protectConditionFunc = condition;
@ -265,7 +270,7 @@ export class ConditionalProtectTag extends ArenaTag {
*/
const QuickGuardConditionFunc: ProtectConditionFunc = (arena, moveId) => {
const move = allMoves[moveId];
const priority = new Utils.IntegerHolder(move.priority);
const priority = new Utils.NumberHolder(move.priority);
const effectPhase = arena.scene.getCurrentPhase();
if (effectPhase instanceof MoveEffectPhase) {
@ -281,7 +286,7 @@ const QuickGuardConditionFunc: ProtectConditionFunc = (arena, moveId) => {
* Condition: The incoming move has increased priority.
*/
class QuickGuardTag extends ConditionalProtectTag {
constructor(sourceId: integer, side: ArenaTagSide) {
constructor(sourceId: number, side: ArenaTagSide) {
super(ArenaTagType.QUICK_GUARD, Moves.QUICK_GUARD, sourceId, side, QuickGuardConditionFunc);
}
}
@ -312,7 +317,7 @@ const WideGuardConditionFunc: ProtectConditionFunc = (arena, moveId) : boolean =
* can be an ally or enemy.
*/
class WideGuardTag extends ConditionalProtectTag {
constructor(sourceId: integer, side: ArenaTagSide) {
constructor(sourceId: number, side: ArenaTagSide) {
super(ArenaTagType.WIDE_GUARD, Moves.WIDE_GUARD, sourceId, side, WideGuardConditionFunc);
}
}
@ -334,7 +339,7 @@ const MatBlockConditionFunc: ProtectConditionFunc = (arena, moveId) : boolean =>
* Condition: The incoming move is a Physical or Special attack move.
*/
class MatBlockTag extends ConditionalProtectTag {
constructor(sourceId: integer, side: ArenaTagSide) {
constructor(sourceId: number, side: ArenaTagSide) {
super(ArenaTagType.MAT_BLOCK, Moves.MAT_BLOCK, sourceId, side, MatBlockConditionFunc);
}
@ -372,7 +377,7 @@ const CraftyShieldConditionFunc: ProtectConditionFunc = (arena, moveId) => {
* not target all Pokemon or sides of the field.
*/
class CraftyShieldTag extends ConditionalProtectTag {
constructor(sourceId: integer, side: ArenaTagSide) {
constructor(sourceId: number, side: ArenaTagSide) {
super(ArenaTagType.CRAFTY_SHIELD, Moves.CRAFTY_SHIELD, sourceId, side, CraftyShieldConditionFunc, true);
}
}
@ -384,12 +389,12 @@ class CraftyShieldTag extends ConditionalProtectTag {
export class NoCritTag extends ArenaTag {
/**
* Constructor method for the NoCritTag class
* @param turnCount `integer` the number of turns this effect lasts
* @param turnCount `number` the number of turns this effect lasts
* @param sourceMove {@linkcode Moves} the move that created this effect
* @param sourceId `integer` the ID of the {@linkcode Pokemon} that created this effect
* @param sourceId `number` the ID of the {@linkcode Pokemon} that created this effect
* @param side {@linkcode ArenaTagSide} the side to which this effect belongs
*/
constructor(turnCount: integer, sourceMove: Moves, sourceId: integer, side: ArenaTagSide) {
constructor(turnCount: number, sourceMove: Moves, sourceId: number, side: ArenaTagSide) {
super(ArenaTagType.NO_CRIT, turnCount, sourceMove, sourceId, side);
}
@ -419,7 +424,7 @@ class WishTag extends ArenaTag {
private triggerMessage: string;
private healHp: number;
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
constructor(turnCount: number, sourceId: number, side: ArenaTagSide) {
super(ArenaTagType.WISH, turnCount, Moves.WISH, sourceId, side);
}
@ -460,7 +465,7 @@ export class WeakenMoveTypeTag extends ArenaTag {
* @param sourceMove - The move that created the tag.
* @param sourceId - The ID of the source of the tag.
*/
constructor(tagType: ArenaTagType, turnCount: integer, type: Type, sourceMove: Moves, sourceId: integer) {
constructor(tagType: ArenaTagType, turnCount: number, type: Type, sourceMove: Moves, sourceId: number) {
super(tagType, turnCount, sourceMove, sourceId);
this.weakenedType = type;
@ -481,7 +486,7 @@ export class WeakenMoveTypeTag extends ArenaTag {
* Weakens Electric type moves for a set amount of turns, usually 5.
*/
class MudSportTag extends WeakenMoveTypeTag {
constructor(turnCount: integer, sourceId: integer) {
constructor(turnCount: number, sourceId: number) {
super(ArenaTagType.MUD_SPORT, turnCount, Type.ELECTRIC, Moves.MUD_SPORT, sourceId);
}
@ -499,7 +504,7 @@ class MudSportTag extends WeakenMoveTypeTag {
* Weakens Fire type moves for a set amount of turns, usually 5.
*/
class WaterSportTag extends WeakenMoveTypeTag {
constructor(turnCount: integer, sourceId: integer) {
constructor(turnCount: number, sourceId: number) {
super(ArenaTagType.WATER_SPORT, turnCount, Type.FIRE, Moves.WATER_SPORT, sourceId);
}
@ -550,8 +555,8 @@ export class IonDelugeTag extends ArenaTag {
* Abstract class to implement arena traps.
*/
export class ArenaTrapTag extends ArenaTag {
public layers: integer;
public maxLayers: integer;
public layers: number;
public maxLayers: number;
/**
* Creates a new instance of the ArenaTrapTag class.
@ -562,7 +567,7 @@ export class ArenaTrapTag extends ArenaTag {
* @param side - The side (player or enemy) the tag affects.
* @param maxLayers - The maximum amount of layers this tag can have.
*/
constructor(tagType: ArenaTagType, sourceMove: Moves, sourceId: integer, side: ArenaTagSide, maxLayers: integer) {
constructor(tagType: ArenaTagType, sourceMove: Moves, sourceId: number, side: ArenaTagSide, maxLayers: number) {
super(tagType, 0, sourceMove, sourceId, side);
this.layers = 1;
@ -593,6 +598,12 @@ export class ArenaTrapTag extends ArenaTag {
getMatchupScoreMultiplier(pokemon: Pokemon): number {
return pokemon.isGrounded() ? 1 : Phaser.Math.Linear(0, 1 / Math.pow(2, this.layers), Math.min(pokemon.getHpRatio(), 0.5) * 2);
}
loadTag(source: any): void {
super.loadTag(source);
this.layers = source.layers;
this.maxLayers = source.maxLayers;
}
}
/**
@ -601,7 +612,7 @@ export class ArenaTrapTag extends ArenaTag {
* in damage for 1, 2, or 3 layers of Spikes respectively if they are summoned into this trap.
*/
class SpikesTag extends ArenaTrapTag {
constructor(sourceId: integer, side: ArenaTagSide) {
constructor(sourceId: number, side: ArenaTagSide) {
super(ArenaTagType.SPIKES, Moves.SPIKES, sourceId, side, 3);
}
@ -645,7 +656,7 @@ class SpikesTag extends ArenaTrapTag {
class ToxicSpikesTag extends ArenaTrapTag {
private neutralized: boolean;
constructor(sourceId: integer, side: ArenaTagSide) {
constructor(sourceId: number, side: ArenaTagSide) {
super(ArenaTagType.TOXIC_SPIKES, Moves.TOXIC_SPIKES, sourceId, side, 2);
this.neutralized = false;
}
@ -703,7 +714,7 @@ class ToxicSpikesTag extends ArenaTrapTag {
class DelayedAttackTag extends ArenaTag {
public targetIndex: BattlerIndex;
constructor(tagType: ArenaTagType, sourceMove: Moves | undefined, sourceId: integer, targetIndex: BattlerIndex) {
constructor(tagType: ArenaTagType, sourceMove: Moves | undefined, sourceId: number, targetIndex: BattlerIndex) {
super(tagType, 3, sourceMove, sourceId);
this.targetIndex = targetIndex;
@ -728,7 +739,7 @@ class DelayedAttackTag extends ArenaTag {
* who is summoned into the trap, based on the Rock type's type effectiveness.
*/
class StealthRockTag extends ArenaTrapTag {
constructor(sourceId: integer, side: ArenaTagSide) {
constructor(sourceId: number, side: ArenaTagSide) {
super(ArenaTagType.STEALTH_ROCK, Moves.STEALTH_ROCK, sourceId, side, 1);
}
@ -804,7 +815,7 @@ class StealthRockTag extends ArenaTrapTag {
* to any Pokémon who is summoned into this trap.
*/
class StickyWebTag extends ArenaTrapTag {
constructor(sourceId: integer, side: ArenaTagSide) {
constructor(sourceId: number, side: ArenaTagSide) {
super(ArenaTagType.STICKY_WEB, Moves.STICKY_WEB, sourceId, side, 1);
}
@ -838,7 +849,7 @@ class StickyWebTag extends ArenaTrapTag {
* also reversing the turn order for all Pokémon on the field as well.
*/
export class TrickRoomTag extends ArenaTag {
constructor(turnCount: integer, sourceId: integer) {
constructor(turnCount: number, sourceId: number) {
super(ArenaTagType.TRICK_ROOM, turnCount, Moves.TRICK_ROOM, sourceId);
}
@ -866,7 +877,7 @@ export class TrickRoomTag extends ArenaTag {
* {@linkcode Abilities.LEVITATE} for the duration of the arena tag, usually 5 turns.
*/
export class GravityTag extends ArenaTag {
constructor(turnCount: integer) {
constructor(turnCount: number) {
super(ArenaTagType.GRAVITY, turnCount, Moves.GRAVITY);
}
@ -890,7 +901,7 @@ export class GravityTag extends ArenaTag {
* Applies this arena tag for 4 turns (including the turn the move was used).
*/
class TailwindTag extends ArenaTag {
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
constructor(turnCount: number, sourceId: number, side: ArenaTagSide) {
super(ArenaTagType.TAILWIND, turnCount, Moves.TAILWIND, sourceId, side);
}
@ -928,7 +939,7 @@ class TailwindTag extends ArenaTag {
* Doubles the prize money from trainers and money moves like {@linkcode Moves.PAY_DAY} and {@linkcode Moves.MAKE_IT_RAIN}.
*/
class HappyHourTag extends ArenaTag {
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
constructor(turnCount: number, sourceId: number, side: ArenaTagSide) {
super(ArenaTagType.HAPPY_HOUR, turnCount, Moves.HAPPY_HOUR, sourceId, side);
}
@ -942,7 +953,7 @@ class HappyHourTag extends ArenaTag {
}
class SafeguardTag extends ArenaTag {
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
constructor(turnCount: number, sourceId: number, side: ArenaTagSide) {
super(ArenaTagType.SAFEGUARD, turnCount, Moves.SAFEGUARD, sourceId, side);
}
@ -955,6 +966,11 @@ class SafeguardTag extends ArenaTag {
}
}
class NoneTag extends ArenaTag {
constructor() {
super(ArenaTagType.NONE, 0);
}
}
/**
* This arena tag facilitates the application of the move Imprison
* Imprison remains in effect as long as the source Pokemon is active and present on the field.
@ -1102,7 +1118,8 @@ class GrassWaterPledgeTag extends ArenaTag {
}
}
export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves | undefined, sourceId: integer, targetIndex?: BattlerIndex, side: ArenaTagSide = ArenaTagSide.BOTH): ArenaTag | null {
// TODO: swap `sourceMove` and `sourceId` and make `sourceMove` an optional parameter
export function getArenaTag(tagType: ArenaTagType, turnCount: number, sourceMove: Moves | undefined, sourceId: number, targetIndex?: BattlerIndex, side: ArenaTagSide = ArenaTagSide.BOTH): ArenaTag | null {
switch (tagType) {
case ArenaTagType.MIST:
return new MistTag(turnCount, sourceId, side);
@ -1163,3 +1180,16 @@ export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMov
return null;
}
}
/**
* When given a battler tag or json representing one, creates an actual ArenaTag object with the same data.
* @param {ArenaTag | any} source An arena tag
* @return {ArenaTag} The valid arena tag
*/
export function loadArenaTag(source: ArenaTag | any): ArenaTag {
const tag = getArenaTag(source.tagType, source.turnCount, source.sourceMove, source.sourceId, source.targetIndex, source.side)
?? new NoneTag();
tag.loadTag(source);
return tag;
}

View File

@ -0,0 +1,603 @@
import { Species } from "#enums/species";
import { EggTier } from "#enums/egg-type";
/**
* Map of all starters and their respective {@linkcode EggTier}, which determines the type of egg the starter hatches from.
*/
export const speciesEggTiers = {
[Species.BULBASAUR]: EggTier.COMMON,
[Species.CHARMANDER]: EggTier.COMMON,
[Species.SQUIRTLE]: EggTier.COMMON,
[Species.CATERPIE]: EggTier.COMMON,
[Species.WEEDLE]: EggTier.COMMON,
[Species.PIDGEY]: EggTier.COMMON,
[Species.RATTATA]: EggTier.COMMON,
[Species.SPEAROW]: EggTier.COMMON,
[Species.EKANS]: EggTier.COMMON,
[Species.PIKACHU]: EggTier.COMMON,
[Species.SANDSHREW]: EggTier.COMMON,
[Species.NIDORAN_F]: EggTier.COMMON,
[Species.NIDORAN_M]: EggTier.COMMON,
[Species.CLEFAIRY]: EggTier.COMMON,
[Species.VULPIX]: EggTier.COMMON,
[Species.JIGGLYPUFF]: EggTier.COMMON,
[Species.ZUBAT]: EggTier.COMMON,
[Species.ODDISH]: EggTier.COMMON,
[Species.PARAS]: EggTier.COMMON,
[Species.VENONAT]: EggTier.COMMON,
[Species.DIGLETT]: EggTier.COMMON,
[Species.MEOWTH]: EggTier.COMMON,
[Species.PSYDUCK]: EggTier.COMMON,
[Species.MANKEY]: EggTier.RARE,
[Species.GROWLITHE]: EggTier.RARE,
[Species.POLIWAG]: EggTier.COMMON,
[Species.ABRA]: EggTier.RARE,
[Species.MACHOP]: EggTier.COMMON,
[Species.BELLSPROUT]: EggTier.COMMON,
[Species.TENTACOOL]: EggTier.COMMON,
[Species.GEODUDE]: EggTier.COMMON,
[Species.PONYTA]: EggTier.COMMON,
[Species.SLOWPOKE]: EggTier.COMMON,
[Species.MAGNEMITE]: EggTier.RARE,
[Species.FARFETCHD]: EggTier.COMMON,
[Species.DODUO]: EggTier.COMMON,
[Species.SEEL]: EggTier.COMMON,
[Species.GRIMER]: EggTier.COMMON,
[Species.SHELLDER]: EggTier.RARE,
[Species.GASTLY]: EggTier.RARE,
[Species.ONIX]: EggTier.COMMON,
[Species.DROWZEE]: EggTier.COMMON,
[Species.KRABBY]: EggTier.COMMON,
[Species.VOLTORB]: EggTier.COMMON,
[Species.EXEGGCUTE]: EggTier.COMMON,
[Species.CUBONE]: EggTier.COMMON,
[Species.HITMONLEE]: EggTier.RARE,
[Species.HITMONCHAN]: EggTier.RARE,
[Species.LICKITUNG]: EggTier.COMMON,
[Species.KOFFING]: EggTier.COMMON,
[Species.RHYHORN]: EggTier.COMMON,
[Species.CHANSEY]: EggTier.COMMON,
[Species.TANGELA]: EggTier.COMMON,
[Species.KANGASKHAN]: EggTier.RARE,
[Species.HORSEA]: EggTier.COMMON,
[Species.GOLDEEN]: EggTier.COMMON,
[Species.STARYU]: EggTier.COMMON,
[Species.MR_MIME]: EggTier.COMMON,
[Species.SCYTHER]: EggTier.RARE,
[Species.JYNX]: EggTier.RARE,
[Species.ELECTABUZZ]: EggTier.RARE,
[Species.MAGMAR]: EggTier.RARE,
[Species.PINSIR]: EggTier.RARE,
[Species.TAUROS]: EggTier.RARE,
[Species.MAGIKARP]: EggTier.RARE,
[Species.LAPRAS]: EggTier.RARE,
[Species.DITTO]: EggTier.COMMON,
[Species.EEVEE]: EggTier.COMMON,
[Species.PORYGON]: EggTier.RARE,
[Species.OMANYTE]: EggTier.COMMON,
[Species.KABUTO]: EggTier.COMMON,
[Species.AERODACTYL]: EggTier.RARE,
[Species.SNORLAX]: EggTier.RARE,
[Species.ARTICUNO]: EggTier.EPIC,
[Species.ZAPDOS]: EggTier.EPIC,
[Species.MOLTRES]: EggTier.EPIC,
[Species.DRATINI]: EggTier.RARE,
[Species.MEWTWO]: EggTier.LEGENDARY,
[Species.MEW]: EggTier.EPIC,
[Species.CHIKORITA]: EggTier.COMMON,
[Species.CYNDAQUIL]: EggTier.COMMON,
[Species.TOTODILE]: EggTier.COMMON,
[Species.SENTRET]: EggTier.COMMON,
[Species.HOOTHOOT]: EggTier.COMMON,
[Species.LEDYBA]: EggTier.COMMON,
[Species.SPINARAK]: EggTier.COMMON,
[Species.CHINCHOU]: EggTier.COMMON,
[Species.PICHU]: EggTier.COMMON,
[Species.CLEFFA]: EggTier.COMMON,
[Species.IGGLYBUFF]: EggTier.COMMON,
[Species.TOGEPI]: EggTier.COMMON,
[Species.NATU]: EggTier.COMMON,
[Species.MAREEP]: EggTier.COMMON,
[Species.MARILL]: EggTier.RARE,
[Species.SUDOWOODO]: EggTier.COMMON,
[Species.HOPPIP]: EggTier.COMMON,
[Species.AIPOM]: EggTier.COMMON,
[Species.SUNKERN]: EggTier.COMMON,
[Species.YANMA]: EggTier.COMMON,
[Species.WOOPER]: EggTier.COMMON,
[Species.MURKROW]: EggTier.COMMON,
[Species.MISDREAVUS]: EggTier.COMMON,
[Species.UNOWN]: EggTier.COMMON,
[Species.WOBBUFFET]: EggTier.COMMON,
[Species.GIRAFARIG]: EggTier.COMMON,
[Species.PINECO]: EggTier.COMMON,
[Species.DUNSPARCE]: EggTier.COMMON,
[Species.GLIGAR]: EggTier.COMMON,
[Species.SNUBBULL]: EggTier.COMMON,
[Species.QWILFISH]: EggTier.COMMON,
[Species.SHUCKLE]: EggTier.COMMON,
[Species.HERACROSS]: EggTier.RARE,
[Species.SNEASEL]: EggTier.RARE,
[Species.TEDDIURSA]: EggTier.RARE,
[Species.SLUGMA]: EggTier.COMMON,
[Species.SWINUB]: EggTier.COMMON,
[Species.CORSOLA]: EggTier.COMMON,
[Species.REMORAID]: EggTier.COMMON,
[Species.DELIBIRD]: EggTier.COMMON,
[Species.MANTINE]: EggTier.COMMON,
[Species.SKARMORY]: EggTier.RARE,
[Species.HOUNDOUR]: EggTier.COMMON,
[Species.PHANPY]: EggTier.COMMON,
[Species.STANTLER]: EggTier.COMMON,
[Species.SMEARGLE]: EggTier.COMMON,
[Species.TYROGUE]: EggTier.COMMON,
[Species.SMOOCHUM]: EggTier.COMMON,
[Species.ELEKID]: EggTier.COMMON,
[Species.MAGBY]: EggTier.COMMON,
[Species.MILTANK]: EggTier.RARE,
[Species.RAIKOU]: EggTier.EPIC,
[Species.ENTEI]: EggTier.EPIC,
[Species.SUICUNE]: EggTier.EPIC,
[Species.LARVITAR]: EggTier.RARE,
[Species.LUGIA]: EggTier.LEGENDARY,
[Species.HO_OH]: EggTier.LEGENDARY,
[Species.CELEBI]: EggTier.EPIC,
[Species.TREECKO]: EggTier.COMMON,
[Species.TORCHIC]: EggTier.RARE,
[Species.MUDKIP]: EggTier.COMMON,
[Species.POOCHYENA]: EggTier.COMMON,
[Species.ZIGZAGOON]: EggTier.COMMON,
[Species.WURMPLE]: EggTier.COMMON,
[Species.LOTAD]: EggTier.COMMON,
[Species.SEEDOT]: EggTier.COMMON,
[Species.TAILLOW]: EggTier.COMMON,
[Species.WINGULL]: EggTier.COMMON,
[Species.RALTS]: EggTier.COMMON,
[Species.SURSKIT]: EggTier.COMMON,
[Species.SHROOMISH]: EggTier.COMMON,
[Species.SLAKOTH]: EggTier.RARE,
[Species.NINCADA]: EggTier.RARE,
[Species.WHISMUR]: EggTier.COMMON,
[Species.MAKUHITA]: EggTier.COMMON,
[Species.AZURILL]: EggTier.RARE,
[Species.NOSEPASS]: EggTier.COMMON,
[Species.SKITTY]: EggTier.COMMON,
[Species.SABLEYE]: EggTier.COMMON,
[Species.MAWILE]: EggTier.COMMON,
[Species.ARON]: EggTier.COMMON,
[Species.MEDITITE]: EggTier.COMMON,
[Species.ELECTRIKE]: EggTier.COMMON,
[Species.PLUSLE]: EggTier.COMMON,
[Species.MINUN]: EggTier.COMMON,
[Species.VOLBEAT]: EggTier.COMMON,
[Species.ILLUMISE]: EggTier.COMMON,
[Species.ROSELIA]: EggTier.COMMON,
[Species.GULPIN]: EggTier.COMMON,
[Species.CARVANHA]: EggTier.COMMON,
[Species.WAILMER]: EggTier.COMMON,
[Species.NUMEL]: EggTier.COMMON,
[Species.TORKOAL]: EggTier.COMMON,
[Species.SPOINK]: EggTier.COMMON,
[Species.SPINDA]: EggTier.COMMON,
[Species.TRAPINCH]: EggTier.COMMON,
[Species.CACNEA]: EggTier.COMMON,
[Species.SWABLU]: EggTier.COMMON,
[Species.ZANGOOSE]: EggTier.RARE,
[Species.SEVIPER]: EggTier.COMMON,
[Species.LUNATONE]: EggTier.COMMON,
[Species.SOLROCK]: EggTier.COMMON,
[Species.BARBOACH]: EggTier.COMMON,
[Species.CORPHISH]: EggTier.COMMON,
[Species.BALTOY]: EggTier.COMMON,
[Species.LILEEP]: EggTier.COMMON,
[Species.ANORITH]: EggTier.COMMON,
[Species.FEEBAS]: EggTier.RARE,
[Species.CASTFORM]: EggTier.COMMON,
[Species.KECLEON]: EggTier.COMMON,
[Species.SHUPPET]: EggTier.COMMON,
[Species.DUSKULL]: EggTier.COMMON,
[Species.TROPIUS]: EggTier.COMMON,
[Species.CHIMECHO]: EggTier.COMMON,
[Species.ABSOL]: EggTier.RARE,
[Species.WYNAUT]: EggTier.COMMON,
[Species.SNORUNT]: EggTier.COMMON,
[Species.SPHEAL]: EggTier.COMMON,
[Species.CLAMPERL]: EggTier.COMMON,
[Species.RELICANTH]: EggTier.COMMON,
[Species.LUVDISC]: EggTier.COMMON,
[Species.BAGON]: EggTier.RARE,
[Species.BELDUM]: EggTier.RARE,
[Species.REGIROCK]: EggTier.EPIC,
[Species.REGICE]: EggTier.EPIC,
[Species.REGISTEEL]: EggTier.EPIC,
[Species.LATIAS]: EggTier.EPIC,
[Species.LATIOS]: EggTier.EPIC,
[Species.KYOGRE]: EggTier.LEGENDARY,
[Species.GROUDON]: EggTier.LEGENDARY,
[Species.RAYQUAZA]: EggTier.LEGENDARY,
[Species.JIRACHI]: EggTier.EPIC,
[Species.DEOXYS]: EggTier.EPIC,
[Species.TURTWIG]: EggTier.COMMON,
[Species.CHIMCHAR]: EggTier.COMMON,
[Species.PIPLUP]: EggTier.COMMON,
[Species.STARLY]: EggTier.COMMON,
[Species.BIDOOF]: EggTier.COMMON,
[Species.KRICKETOT]: EggTier.COMMON,
[Species.SHINX]: EggTier.COMMON,
[Species.BUDEW]: EggTier.COMMON,
[Species.CRANIDOS]: EggTier.COMMON,
[Species.SHIELDON]: EggTier.COMMON,
[Species.BURMY]: EggTier.COMMON,
[Species.COMBEE]: EggTier.COMMON,
[Species.PACHIRISU]: EggTier.COMMON,
[Species.BUIZEL]: EggTier.COMMON,
[Species.CHERUBI]: EggTier.COMMON,
[Species.SHELLOS]: EggTier.COMMON,
[Species.DRIFLOON]: EggTier.COMMON,
[Species.BUNEARY]: EggTier.COMMON,
[Species.GLAMEOW]: EggTier.COMMON,
[Species.CHINGLING]: EggTier.COMMON,
[Species.STUNKY]: EggTier.COMMON,
[Species.BRONZOR]: EggTier.COMMON,
[Species.BONSLY]: EggTier.COMMON,
[Species.MIME_JR]: EggTier.COMMON,
[Species.HAPPINY]: EggTier.COMMON,
[Species.CHATOT]: EggTier.COMMON,
[Species.SPIRITOMB]: EggTier.RARE,
[Species.GIBLE]: EggTier.RARE,
[Species.MUNCHLAX]: EggTier.RARE,
[Species.RIOLU]: EggTier.COMMON,
[Species.HIPPOPOTAS]: EggTier.COMMON,
[Species.SKORUPI]: EggTier.COMMON,
[Species.CROAGUNK]: EggTier.COMMON,
[Species.CARNIVINE]: EggTier.COMMON,
[Species.FINNEON]: EggTier.COMMON,
[Species.MANTYKE]: EggTier.COMMON,
[Species.SNOVER]: EggTier.COMMON,
[Species.ROTOM]: EggTier.RARE,
[Species.UXIE]: EggTier.EPIC,
[Species.MESPRIT]: EggTier.EPIC,
[Species.AZELF]: EggTier.EPIC,
[Species.DIALGA]: EggTier.LEGENDARY,
[Species.PALKIA]: EggTier.LEGENDARY,
[Species.HEATRAN]: EggTier.EPIC,
[Species.REGIGIGAS]: EggTier.EPIC,
[Species.GIRATINA]: EggTier.LEGENDARY,
[Species.CRESSELIA]: EggTier.EPIC,
[Species.PHIONE]: EggTier.RARE,
[Species.MANAPHY]: EggTier.EPIC,
[Species.DARKRAI]: EggTier.EPIC,
[Species.SHAYMIN]: EggTier.EPIC,
[Species.ARCEUS]: EggTier.LEGENDARY,
[Species.VICTINI]: EggTier.EPIC,
[Species.SNIVY]: EggTier.COMMON,
[Species.TEPIG]: EggTier.COMMON,
[Species.OSHAWOTT]: EggTier.COMMON,
[Species.PATRAT]: EggTier.COMMON,
[Species.LILLIPUP]: EggTier.COMMON,
[Species.PURRLOIN]: EggTier.COMMON,
[Species.PANSAGE]: EggTier.COMMON,
[Species.PANSEAR]: EggTier.COMMON,
[Species.PANPOUR]: EggTier.COMMON,
[Species.MUNNA]: EggTier.COMMON,
[Species.PIDOVE]: EggTier.COMMON,
[Species.BLITZLE]: EggTier.COMMON,
[Species.ROGGENROLA]: EggTier.COMMON,
[Species.WOOBAT]: EggTier.COMMON,
[Species.DRILBUR]: EggTier.RARE,
[Species.AUDINO]: EggTier.COMMON,
[Species.TIMBURR]: EggTier.RARE,
[Species.TYMPOLE]: EggTier.COMMON,
[Species.THROH]: EggTier.RARE,
[Species.SAWK]: EggTier.RARE,
[Species.SEWADDLE]: EggTier.COMMON,
[Species.VENIPEDE]: EggTier.COMMON,
[Species.COTTONEE]: EggTier.COMMON,
[Species.PETILIL]: EggTier.COMMON,
[Species.BASCULIN]: EggTier.RARE,
[Species.SANDILE]: EggTier.RARE,
[Species.DARUMAKA]: EggTier.RARE,
[Species.MARACTUS]: EggTier.COMMON,
[Species.DWEBBLE]: EggTier.COMMON,
[Species.SCRAGGY]: EggTier.COMMON,
[Species.SIGILYPH]: EggTier.RARE,
[Species.YAMASK]: EggTier.COMMON,
[Species.TIRTOUGA]: EggTier.COMMON,
[Species.ARCHEN]: EggTier.COMMON,
[Species.TRUBBISH]: EggTier.COMMON,
[Species.ZORUA]: EggTier.COMMON,
[Species.MINCCINO]: EggTier.COMMON,
[Species.GOTHITA]: EggTier.COMMON,
[Species.SOLOSIS]: EggTier.COMMON,
[Species.DUCKLETT]: EggTier.COMMON,
[Species.VANILLITE]: EggTier.COMMON,
[Species.DEERLING]: EggTier.COMMON,
[Species.EMOLGA]: EggTier.COMMON,
[Species.KARRABLAST]: EggTier.COMMON,
[Species.FOONGUS]: EggTier.COMMON,
[Species.FRILLISH]: EggTier.COMMON,
[Species.ALOMOMOLA]: EggTier.RARE,
[Species.JOLTIK]: EggTier.COMMON,
[Species.FERROSEED]: EggTier.COMMON,
[Species.KLINK]: EggTier.COMMON,
[Species.TYNAMO]: EggTier.COMMON,
[Species.ELGYEM]: EggTier.COMMON,
[Species.LITWICK]: EggTier.COMMON,
[Species.AXEW]: EggTier.RARE,
[Species.CUBCHOO]: EggTier.COMMON,
[Species.CRYOGONAL]: EggTier.RARE,
[Species.SHELMET]: EggTier.COMMON,
[Species.STUNFISK]: EggTier.COMMON,
[Species.MIENFOO]: EggTier.COMMON,
[Species.DRUDDIGON]: EggTier.RARE,
[Species.GOLETT]: EggTier.COMMON,
[Species.PAWNIARD]: EggTier.RARE,
[Species.BOUFFALANT]: EggTier.RARE,
[Species.RUFFLET]: EggTier.COMMON,
[Species.VULLABY]: EggTier.COMMON,
[Species.HEATMOR]: EggTier.COMMON,
[Species.DURANT]: EggTier.RARE,
[Species.DEINO]: EggTier.RARE,
[Species.LARVESTA]: EggTier.RARE,
[Species.COBALION]: EggTier.EPIC,
[Species.TERRAKION]: EggTier.EPIC,
[Species.VIRIZION]: EggTier.EPIC,
[Species.TORNADUS]: EggTier.EPIC,
[Species.THUNDURUS]: EggTier.EPIC,
[Species.RESHIRAM]: EggTier.LEGENDARY,
[Species.ZEKROM]: EggTier.LEGENDARY,
[Species.LANDORUS]: EggTier.EPIC,
[Species.KYUREM]: EggTier.LEGENDARY,
[Species.KELDEO]: EggTier.EPIC,
[Species.MELOETTA]: EggTier.EPIC,
[Species.GENESECT]: EggTier.EPIC,
[Species.CHESPIN]: EggTier.COMMON,
[Species.FENNEKIN]: EggTier.COMMON,
[Species.FROAKIE]: EggTier.RARE,
[Species.BUNNELBY]: EggTier.COMMON,
[Species.FLETCHLING]: EggTier.COMMON,
[Species.SCATTERBUG]: EggTier.COMMON,
[Species.LITLEO]: EggTier.COMMON,
[Species.FLABEBE]: EggTier.COMMON,
[Species.SKIDDO]: EggTier.COMMON,
[Species.PANCHAM]: EggTier.COMMON,
[Species.FURFROU]: EggTier.COMMON,
[Species.ESPURR]: EggTier.COMMON,
[Species.HONEDGE]: EggTier.RARE,
[Species.SPRITZEE]: EggTier.COMMON,
[Species.SWIRLIX]: EggTier.COMMON,
[Species.INKAY]: EggTier.COMMON,
[Species.BINACLE]: EggTier.COMMON,
[Species.SKRELP]: EggTier.COMMON,
[Species.CLAUNCHER]: EggTier.COMMON,
[Species.HELIOPTILE]: EggTier.COMMON,
[Species.TYRUNT]: EggTier.COMMON,
[Species.AMAURA]: EggTier.COMMON,
[Species.HAWLUCHA]: EggTier.RARE,
[Species.DEDENNE]: EggTier.COMMON,
[Species.CARBINK]: EggTier.COMMON,
[Species.GOOMY]: EggTier.RARE,
[Species.KLEFKI]: EggTier.COMMON,
[Species.PHANTUMP]: EggTier.COMMON,
[Species.PUMPKABOO]: EggTier.COMMON,
[Species.BERGMITE]: EggTier.COMMON,
[Species.NOIBAT]: EggTier.COMMON,
[Species.XERNEAS]: EggTier.LEGENDARY,
[Species.YVELTAL]: EggTier.LEGENDARY,
[Species.ZYGARDE]: EggTier.LEGENDARY,
[Species.DIANCIE]: EggTier.EPIC,
[Species.HOOPA]: EggTier.EPIC,
[Species.VOLCANION]: EggTier.EPIC,
[Species.ETERNAL_FLOETTE]: EggTier.RARE,
[Species.ROWLET]: EggTier.COMMON,
[Species.LITTEN]: EggTier.COMMON,
[Species.POPPLIO]: EggTier.RARE,
[Species.PIKIPEK]: EggTier.COMMON,
[Species.YUNGOOS]: EggTier.COMMON,
[Species.GRUBBIN]: EggTier.COMMON,
[Species.CRABRAWLER]: EggTier.COMMON,
[Species.ORICORIO]: EggTier.COMMON,
[Species.CUTIEFLY]: EggTier.COMMON,
[Species.ROCKRUFF]: EggTier.COMMON,
[Species.WISHIWASHI]: EggTier.COMMON,
[Species.MAREANIE]: EggTier.COMMON,
[Species.MUDBRAY]: EggTier.COMMON,
[Species.DEWPIDER]: EggTier.COMMON,
[Species.FOMANTIS]: EggTier.COMMON,
[Species.MORELULL]: EggTier.COMMON,
[Species.SALANDIT]: EggTier.COMMON,
[Species.STUFFUL]: EggTier.COMMON,
[Species.BOUNSWEET]: EggTier.COMMON,
[Species.COMFEY]: EggTier.RARE,
[Species.ORANGURU]: EggTier.RARE,
[Species.PASSIMIAN]: EggTier.RARE,
[Species.WIMPOD]: EggTier.COMMON,
[Species.SANDYGAST]: EggTier.COMMON,
[Species.PYUKUMUKU]: EggTier.COMMON,
[Species.TYPE_NULL]: EggTier.RARE,
[Species.MINIOR]: EggTier.RARE,
[Species.KOMALA]: EggTier.COMMON,
[Species.TURTONATOR]: EggTier.RARE,
[Species.TOGEDEMARU]: EggTier.COMMON,
[Species.MIMIKYU]: EggTier.RARE,
[Species.BRUXISH]: EggTier.RARE,
[Species.DRAMPA]: EggTier.RARE,
[Species.DHELMISE]: EggTier.RARE,
[Species.JANGMO_O]: EggTier.RARE,
[Species.TAPU_KOKO]: EggTier.EPIC,
[Species.TAPU_LELE]: EggTier.EPIC,
[Species.TAPU_BULU]: EggTier.EPIC,
[Species.TAPU_FINI]: EggTier.EPIC,
[Species.COSMOG]: EggTier.EPIC,
[Species.NIHILEGO]: EggTier.EPIC,
[Species.BUZZWOLE]: EggTier.EPIC,
[Species.PHEROMOSA]: EggTier.EPIC,
[Species.XURKITREE]: EggTier.EPIC,
[Species.CELESTEELA]: EggTier.EPIC,
[Species.KARTANA]: EggTier.EPIC,
[Species.GUZZLORD]: EggTier.EPIC,
[Species.NECROZMA]: EggTier.LEGENDARY,
[Species.MAGEARNA]: EggTier.EPIC,
[Species.MARSHADOW]: EggTier.EPIC,
[Species.POIPOLE]: EggTier.EPIC,
[Species.STAKATAKA]: EggTier.EPIC,
[Species.BLACEPHALON]: EggTier.EPIC,
[Species.ZERAORA]: EggTier.EPIC,
[Species.MELTAN]: EggTier.EPIC,
[Species.ALOLA_RATTATA]: EggTier.COMMON,
[Species.ALOLA_SANDSHREW]: EggTier.COMMON,
[Species.ALOLA_VULPIX]: EggTier.COMMON,
[Species.ALOLA_DIGLETT]: EggTier.COMMON,
[Species.ALOLA_MEOWTH]: EggTier.COMMON,
[Species.ALOLA_GEODUDE]: EggTier.COMMON,
[Species.ALOLA_GRIMER]: EggTier.COMMON,
[Species.GROOKEY]: EggTier.COMMON,
[Species.SCORBUNNY]: EggTier.RARE,
[Species.SOBBLE]: EggTier.COMMON,
[Species.SKWOVET]: EggTier.COMMON,
[Species.ROOKIDEE]: EggTier.COMMON,
[Species.BLIPBUG]: EggTier.COMMON,
[Species.NICKIT]: EggTier.COMMON,
[Species.GOSSIFLEUR]: EggTier.COMMON,
[Species.WOOLOO]: EggTier.COMMON,
[Species.CHEWTLE]: EggTier.COMMON,
[Species.YAMPER]: EggTier.COMMON,
[Species.ROLYCOLY]: EggTier.COMMON,
[Species.APPLIN]: EggTier.COMMON,
[Species.SILICOBRA]: EggTier.COMMON,
[Species.CRAMORANT]: EggTier.COMMON,
[Species.ARROKUDA]: EggTier.COMMON,
[Species.TOXEL]: EggTier.COMMON,
[Species.SIZZLIPEDE]: EggTier.COMMON,
[Species.CLOBBOPUS]: EggTier.COMMON,
[Species.SINISTEA]: EggTier.COMMON,
[Species.HATENNA]: EggTier.COMMON,
[Species.IMPIDIMP]: EggTier.COMMON,
[Species.MILCERY]: EggTier.COMMON,
[Species.FALINKS]: EggTier.RARE,
[Species.PINCURCHIN]: EggTier.COMMON,
[Species.SNOM]: EggTier.COMMON,
[Species.STONJOURNER]: EggTier.COMMON,
[Species.EISCUE]: EggTier.COMMON,
[Species.INDEEDEE]: EggTier.RARE,
[Species.MORPEKO]: EggTier.COMMON,
[Species.CUFANT]: EggTier.COMMON,
[Species.DRACOZOLT]: EggTier.RARE,
[Species.ARCTOZOLT]: EggTier.RARE,
[Species.DRACOVISH]: EggTier.RARE,
[Species.ARCTOVISH]: EggTier.RARE,
[Species.DURALUDON]: EggTier.RARE,
[Species.DREEPY]: EggTier.RARE,
[Species.ZACIAN]: EggTier.LEGENDARY,
[Species.ZAMAZENTA]: EggTier.LEGENDARY,
[Species.ETERNATUS]: EggTier.COMMON,
[Species.KUBFU]: EggTier.EPIC,
[Species.ZARUDE]: EggTier.EPIC,
[Species.REGIELEKI]: EggTier.EPIC,
[Species.REGIDRAGO]: EggTier.EPIC,
[Species.GLASTRIER]: EggTier.EPIC,
[Species.SPECTRIER]: EggTier.EPIC,
[Species.CALYREX]: EggTier.LEGENDARY,
[Species.GALAR_MEOWTH]: EggTier.COMMON,
[Species.GALAR_PONYTA]: EggTier.COMMON,
[Species.GALAR_SLOWPOKE]: EggTier.COMMON,
[Species.GALAR_FARFETCHD]: EggTier.COMMON,
[Species.GALAR_CORSOLA]: EggTier.COMMON,
[Species.GALAR_ZIGZAGOON]: EggTier.COMMON,
[Species.GALAR_DARUMAKA]: EggTier.RARE,
[Species.GALAR_YAMASK]: EggTier.COMMON,
[Species.GALAR_STUNFISK]: EggTier.COMMON,
[Species.GALAR_MR_MIME]: EggTier.COMMON,
[Species.GALAR_ARTICUNO]: EggTier.EPIC,
[Species.GALAR_ZAPDOS]: EggTier.EPIC,
[Species.GALAR_MOLTRES]: EggTier.EPIC,
[Species.HISUI_GROWLITHE]: EggTier.RARE,
[Species.HISUI_VOLTORB]: EggTier.COMMON,
[Species.HISUI_QWILFISH]: EggTier.RARE,
[Species.HISUI_SNEASEL]: EggTier.RARE,
[Species.HISUI_ZORUA]: EggTier.COMMON,
[Species.ENAMORUS]: EggTier.EPIC,
[Species.SPRIGATITO]: EggTier.RARE,
[Species.FUECOCO]: EggTier.RARE,
[Species.QUAXLY]: EggTier.RARE,
[Species.LECHONK]: EggTier.COMMON,
[Species.TAROUNTULA]: EggTier.COMMON,
[Species.NYMBLE]: EggTier.COMMON,
[Species.PAWMI]: EggTier.COMMON,
[Species.TANDEMAUS]: EggTier.RARE,
[Species.FIDOUGH]: EggTier.COMMON,
[Species.SMOLIV]: EggTier.COMMON,
[Species.SQUAWKABILLY]: EggTier.COMMON,
[Species.NACLI]: EggTier.RARE,
[Species.CHARCADET]: EggTier.RARE,
[Species.TADBULB]: EggTier.COMMON,
[Species.WATTREL]: EggTier.COMMON,
[Species.MASCHIFF]: EggTier.COMMON,
[Species.SHROODLE]: EggTier.COMMON,
[Species.BRAMBLIN]: EggTier.COMMON,
[Species.TOEDSCOOL]: EggTier.COMMON,
[Species.KLAWF]: EggTier.COMMON,
[Species.CAPSAKID]: EggTier.COMMON,
[Species.RELLOR]: EggTier.COMMON,
[Species.FLITTLE]: EggTier.COMMON,
[Species.TINKATINK]: EggTier.RARE,
[Species.WIGLETT]: EggTier.COMMON,
[Species.BOMBIRDIER]: EggTier.COMMON,
[Species.FINIZEN]: EggTier.COMMON,
[Species.VAROOM]: EggTier.RARE,
[Species.CYCLIZAR]: EggTier.RARE,
[Species.ORTHWORM]: EggTier.RARE,
[Species.GLIMMET]: EggTier.RARE,
[Species.GREAVARD]: EggTier.COMMON,
[Species.FLAMIGO]: EggTier.RARE,
[Species.CETODDLE]: EggTier.COMMON,
[Species.VELUZA]: EggTier.RARE,
[Species.DONDOZO]: EggTier.RARE,
[Species.TATSUGIRI]: EggTier.RARE,
[Species.GREAT_TUSK]: EggTier.EPIC,
[Species.SCREAM_TAIL]: EggTier.EPIC,
[Species.BRUTE_BONNET]: EggTier.EPIC,
[Species.FLUTTER_MANE]: EggTier.EPIC,
[Species.SLITHER_WING]: EggTier.EPIC,
[Species.SANDY_SHOCKS]: EggTier.EPIC,
[Species.IRON_TREADS]: EggTier.EPIC,
[Species.IRON_BUNDLE]: EggTier.EPIC,
[Species.IRON_HANDS]: EggTier.EPIC,
[Species.IRON_JUGULIS]: EggTier.EPIC,
[Species.IRON_MOTH]: EggTier.EPIC,
[Species.IRON_THORNS]: EggTier.EPIC,
[Species.FRIGIBAX]: EggTier.RARE,
[Species.GIMMIGHOUL]: EggTier.RARE,
[Species.WO_CHIEN]: EggTier.EPIC,
[Species.CHIEN_PAO]: EggTier.EPIC,
[Species.TING_LU]: EggTier.EPIC,
[Species.CHI_YU]: EggTier.EPIC,
[Species.ROARING_MOON]: EggTier.EPIC,
[Species.IRON_VALIANT]: EggTier.EPIC,
[Species.KORAIDON]: EggTier.LEGENDARY,
[Species.MIRAIDON]: EggTier.LEGENDARY,
[Species.WALKING_WAKE]: EggTier.EPIC,
[Species.IRON_LEAVES]: EggTier.EPIC,
[Species.POLTCHAGEIST]: EggTier.RARE,
[Species.OKIDOGI]: EggTier.EPIC,
[Species.MUNKIDORI]: EggTier.EPIC,
[Species.FEZANDIPITI]: EggTier.EPIC,
[Species.OGERPON]: EggTier.EPIC,
[Species.GOUGING_FIRE]: EggTier.EPIC,
[Species.RAGING_BOLT]: EggTier.EPIC,
[Species.IRON_BOULDER]: EggTier.EPIC,
[Species.IRON_CROWN]: EggTier.EPIC,
[Species.TERAPAGOS]: EggTier.LEGENDARY,
[Species.PECHARUNT]: EggTier.EPIC,
[Species.PALDEA_TAUROS]: EggTier.RARE,
[Species.PALDEA_WOOPER]: EggTier.COMMON,
[Species.BLOODMOON_URSALUNA]: EggTier.EPIC,
};

View File

@ -2640,16 +2640,16 @@ export class ImprisonTag extends MoveRestrictionBattlerTag {
/**
* Battler Tag that applies the effects of Syrup Bomb to the target Pokemon.
* For three turns, starting from the turn of hit, at the end of each turn, the target Pokemon's speed will decrease by 1.
* The tag can also expire by taking the target Pokemon off the field.
* The tag can also expire by taking the target Pokemon off the field, or the Pokemon that originally used the move.
*/
export class SyrupBombTag extends BattlerTag {
constructor() {
super(BattlerTagType.SYRUP_BOMB, BattlerTagLapseType.TURN_END, 3, Moves.SYRUP_BOMB);
constructor(sourceId: number) {
super(BattlerTagType.SYRUP_BOMB, BattlerTagLapseType.TURN_END, 3, Moves.SYRUP_BOMB, sourceId);
}
/**
* Adds the Syrup Bomb battler tag to the target Pokemon.
* @param {Pokemon} pokemon the target Pokemon
* @param pokemon - The target {@linkcode Pokemon}
*/
override onAdd(pokemon: Pokemon) {
super.onAdd(pokemon);
@ -2658,15 +2658,16 @@ export class SyrupBombTag extends BattlerTag {
/**
* Applies the single-stage speed down to the target Pokemon and decrements the tag's turn count
* @param {Pokemon} pokemon the target Pokemon
* @param {BattlerTagLapseType} _lapseType
* @returns `true` if the turnCount is still greater than 0 | `false` if the turnCount is 0 or the target Pokemon has been removed from the field
* @param pokemon - The target {@linkcode Pokemon}
* @param _lapseType - N/A
* @returns `true` if the `turnCount` is still greater than `0`; `false` if the `turnCount` is `0` or the target or source Pokemon has been removed from the field
*/
override lapse(pokemon: Pokemon, _lapseType: BattlerTagLapseType): boolean {
if (!pokemon.isActive(true)) {
if (this.sourceId && !pokemon.scene.getPokemonById(this.sourceId)?.isActive(true)) {
return false;
}
pokemon.scene.queueMessage(i18next.t("battlerTags:syrupBombLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })); // Custom message in lieu of an animation in mainline
// Custom message in lieu of an animation in mainline
pokemon.scene.queueMessage(i18next.t("battlerTags:syrupBombLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
pokemon.scene.unshiftPhase(new StatStageChangePhase(
pokemon.scene, pokemon.getBattlerIndex(), true,
[ Stat.SPD ], -1, true, false, true
@ -2677,12 +2678,8 @@ export class SyrupBombTag extends BattlerTag {
/**
* Retrieves a {@linkcode BattlerTag} based on the provided tag type, turn count, source move, and source ID.
*
* @param {BattlerTagType} tagType the type of the {@linkcode BattlerTagType}.
* @param turnCount the turn count.
* @param {Moves} sourceMove the source {@linkcode Moves}.
* @param sourceId the source ID.
* @returns {BattlerTag} the corresponding {@linkcode BattlerTag} object.
* @param sourceId - The ID of the pokemon adding the tag
* @returns The corresponding {@linkcode BattlerTag} object.
*/
export function getBattlerTag(tagType: BattlerTagType, turnCount: number, sourceMove: Moves, sourceId: number): BattlerTag {
switch (tagType) {
@ -2851,7 +2848,7 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source
case BattlerTagType.IMPRISON:
return new ImprisonTag(sourceId);
case BattlerTagType.SYRUP_BOMB:
return new SyrupBombTag();
return new SyrupBombTag(sourceId);
case BattlerTagType.NONE:
default:
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);

View File

@ -11,6 +11,7 @@ import { EggTier } from "#enums/egg-type";
import { Species } from "#enums/species";
import { EggSourceType } from "#enums/egg-source-types";
import { MANAPHY_EGG_MANAPHY_RATE, SAME_SPECIES_EGG_HA_RATE, GACHA_EGG_HA_RATE, GACHA_DEFAULT_RARE_EGGMOVE_RATE, SAME_SPECIES_EGG_RARE_EGGMOVE_RATE, GACHA_MOVE_UP_RARE_EGGMOVE_RATE, GACHA_DEFAULT_SHINY_RATE, GACHA_SHINY_UP_SHINY_RATE, SAME_SPECIES_EGG_SHINY_RATE, EGG_PITY_LEGENDARY_THRESHOLD, EGG_PITY_EPIC_THRESHOLD, EGG_PITY_RARE_THRESHOLD, SHINY_VARIANT_CHANCE, SHINY_EPIC_CHANCE, GACHA_DEFAULT_COMMON_EGG_THRESHOLD, GACHA_DEFAULT_RARE_EGG_THRESHOLD, GACHA_DEFAULT_EPIC_EGG_THRESHOLD, GACHA_LEGENDARY_UP_THRESHOLD_OFFSET, HATCH_WAVES_MANAPHY_EGG, HATCH_WAVES_COMMON_EGG, HATCH_WAVES_RARE_EGG, HATCH_WAVES_EPIC_EGG, HATCH_WAVES_LEGENDARY_EGG } from "#app/data/balance/rates";
import { speciesEggTiers } from "#app/data/balance/species-egg-tiers";
export const EGG_SEED = 1073741824;
@ -160,7 +161,7 @@ export class Egg {
// Override egg tier and hatchwaves if species was given
if (eggOptions?.species) {
this._tier = this.getEggTierFromSpeciesStarterValue();
this._tier = this.getEggTier();
this._hatchWaves = eggOptions.hatchWaves ?? this.getEggTierDefaultHatchWaves();
}
// If species has no variant, set variantTier to common. This needs to
@ -261,11 +262,11 @@ export class Egg {
return "Manaphy";
}
switch (this.tier) {
case EggTier.GREAT:
case EggTier.RARE:
return i18next.t("egg:greatTier");
case EggTier.ULTRA:
case EggTier.EPIC:
return i18next.t("egg:ultraTier");
case EggTier.MASTER:
case EggTier.LEGENDARY:
return i18next.t("egg:masterTier");
default:
return i18next.t("egg:defaultTier");
@ -336,9 +337,9 @@ export class Egg {
switch (eggTier ?? this._tier) {
case EggTier.COMMON:
return HATCH_WAVES_COMMON_EGG;
case EggTier.GREAT:
case EggTier.RARE:
return HATCH_WAVES_RARE_EGG;
case EggTier.ULTRA:
case EggTier.EPIC:
return HATCH_WAVES_EPIC_EGG;
}
return HATCH_WAVES_LEGENDARY_EGG;
@ -347,7 +348,7 @@ export class Egg {
private rollEggTier(): EggTier {
const tierValueOffset = this._sourceType === EggSourceType.GACHA_LEGENDARY ? GACHA_LEGENDARY_UP_THRESHOLD_OFFSET : 0;
const tierValue = Utils.randInt(256);
return tierValue >= GACHA_DEFAULT_COMMON_EGG_THRESHOLD + tierValueOffset ? EggTier.COMMON : tierValue >= GACHA_DEFAULT_RARE_EGG_THRESHOLD + tierValueOffset ? EggTier.GREAT : tierValue >= GACHA_DEFAULT_EPIC_EGG_THRESHOLD + tierValueOffset ? EggTier.ULTRA : EggTier.MASTER;
return tierValue >= GACHA_DEFAULT_COMMON_EGG_THRESHOLD + tierValueOffset ? EggTier.COMMON : tierValue >= GACHA_DEFAULT_RARE_EGG_THRESHOLD + tierValueOffset ? EggTier.RARE : tierValue >= GACHA_DEFAULT_EPIC_EGG_THRESHOLD + tierValueOffset ? EggTier.EPIC : EggTier.LEGENDARY;
}
private rollSpecies(scene: BattleScene): Species | null {
@ -367,7 +368,7 @@ export class Egg {
*/
const rand = (Utils.randSeedInt(MANAPHY_EGG_MANAPHY_RATE) !== 1);
return rand ? Species.PHIONE : Species.MANAPHY;
} else if (this.tier === EggTier.MASTER
} else if (this.tier === EggTier.LEGENDARY
&& this._sourceType === EggSourceType.GACHA_LEGENDARY) {
if (!Utils.randSeedInt(2)) {
return getLegendaryGachaSpeciesForTimestamp(scene, this.timestamp);
@ -378,15 +379,15 @@ export class Egg {
let maxStarterValue: integer;
switch (this.tier) {
case EggTier.GREAT:
case EggTier.RARE:
minStarterValue = 4;
maxStarterValue = 5;
break;
case EggTier.ULTRA:
case EggTier.EPIC:
minStarterValue = 6;
maxStarterValue = 7;
break;
case EggTier.MASTER:
case EggTier.LEGENDARY:
minStarterValue = 8;
maxStarterValue = 9;
break;
@ -398,8 +399,8 @@ export class Egg {
const ignoredSpecies = [ Species.PHIONE, Species.MANAPHY, Species.ETERNATUS ];
let speciesPool = Object.keys(speciesStarterCosts)
.filter(s => speciesStarterCosts[s] >= minStarterValue && speciesStarterCosts[s] <= maxStarterValue)
let speciesPool = Object.keys(speciesEggTiers)
.filter(s => speciesEggTiers[s] === this.tier)
.map(s => parseInt(s) as Species)
.filter(s => !pokemonPrevolutions.hasOwnProperty(s) && getPokemonSpecies(s).isObtainable() && ignoredSpecies.indexOf(s) === -1);
@ -430,7 +431,9 @@ export class Egg {
let totalWeight = 0;
const speciesWeights : number[] = [];
for (const speciesId of speciesPool) {
let weight = Math.floor((((maxStarterValue - speciesStarterCosts[speciesId]) / ((maxStarterValue - minStarterValue) + 1)) * 1.5 + 1) * 100);
// Accounts for species that have starter costs outside of the normal range for their EggTier
const speciesCostClamped = Phaser.Math.Clamp(speciesStarterCosts[speciesId], minStarterValue, maxStarterValue);
let weight = Math.floor((((maxStarterValue - speciesCostClamped) / ((maxStarterValue - minStarterValue) + 1)) * 1.5 + 1) * 100);
const species = getPokemonSpecies(speciesId);
if (species.isRegional()) {
weight = Math.floor(weight / 2);
@ -498,16 +501,16 @@ export class Egg {
private checkForPityTierOverrides(scene: BattleScene): void {
const tierValueOffset = this._sourceType === EggSourceType.GACHA_LEGENDARY ? GACHA_LEGENDARY_UP_THRESHOLD_OFFSET : 0;
scene.gameData.eggPity[EggTier.GREAT] += 1;
scene.gameData.eggPity[EggTier.ULTRA] += 1;
scene.gameData.eggPity[EggTier.MASTER] += 1 + tierValueOffset;
scene.gameData.eggPity[EggTier.RARE] += 1;
scene.gameData.eggPity[EggTier.EPIC] += 1;
scene.gameData.eggPity[EggTier.LEGENDARY] += 1 + tierValueOffset;
// These numbers are roughly the 80% mark. That is, 80% of the time you'll get an egg before this gets triggered.
if (scene.gameData.eggPity[EggTier.MASTER] >= EGG_PITY_LEGENDARY_THRESHOLD && this._tier === EggTier.COMMON) {
this._tier = EggTier.MASTER;
} else if (scene.gameData.eggPity[EggTier.ULTRA] >= EGG_PITY_EPIC_THRESHOLD && this._tier === EggTier.COMMON) {
this._tier = EggTier.ULTRA;
} else if (scene.gameData.eggPity[EggTier.GREAT] >= EGG_PITY_RARE_THRESHOLD && this._tier === EggTier.COMMON) {
this._tier = EggTier.GREAT;
if (scene.gameData.eggPity[EggTier.LEGENDARY] >= EGG_PITY_LEGENDARY_THRESHOLD && this._tier === EggTier.COMMON) {
this._tier = EggTier.LEGENDARY;
} else if (scene.gameData.eggPity[EggTier.EPIC] >= EGG_PITY_EPIC_THRESHOLD && this._tier === EggTier.COMMON) {
this._tier = EggTier.EPIC;
} else if (scene.gameData.eggPity[EggTier.RARE] >= EGG_PITY_RARE_THRESHOLD && this._tier === EggTier.COMMON) {
this._tier = EggTier.RARE;
}
scene.gameData.eggPity[this._tier] = 0;
}
@ -516,38 +519,24 @@ export class Egg {
scene.gameData.gameStats.eggsPulled++;
if (this.isManaphyEgg()) {
scene.gameData.gameStats.manaphyEggsPulled++;
this._hatchWaves = this.getEggTierDefaultHatchWaves(EggTier.ULTRA);
this._hatchWaves = this.getEggTierDefaultHatchWaves(EggTier.EPIC);
return;
}
switch (this.tier) {
case EggTier.GREAT:
case EggTier.RARE:
scene.gameData.gameStats.rareEggsPulled++;
break;
case EggTier.ULTRA:
case EggTier.EPIC:
scene.gameData.gameStats.epicEggsPulled++;
break;
case EggTier.MASTER:
case EggTier.LEGENDARY:
scene.gameData.gameStats.legendaryEggsPulled++;
break;
}
}
private getEggTierFromSpeciesStarterValue(): EggTier {
const speciesStartValue = speciesStarterCosts[this.species];
if (speciesStartValue >= 1 && speciesStartValue <= 3) {
return EggTier.COMMON;
}
if (speciesStartValue >= 4 && speciesStartValue <= 5) {
return EggTier.GREAT;
}
if (speciesStartValue >= 6 && speciesStartValue <= 7) {
return EggTier.ULTRA;
}
if (speciesStartValue >= 8) {
return EggTier.MASTER;
}
return EggTier.COMMON;
private getEggTier(): EggTier {
return speciesEggTiers[this.species];
}
////
@ -556,8 +545,8 @@ export class Egg {
}
export function getLegendaryGachaSpeciesForTimestamp(scene: BattleScene, timestamp: number): Species {
const legendarySpecies = Object.entries(speciesStarterCosts)
.filter(s => s[1] >= 8 && s[1] <= 9)
const legendarySpecies = Object.entries(speciesEggTiers)
.filter(s => s[1] === EggTier.LEGENDARY)
.map(s => parseInt(s[0]))
.filter(s => getPokemonSpecies(s).isObtainable());
@ -579,17 +568,9 @@ export function getLegendaryGachaSpeciesForTimestamp(scene: BattleScene, timesta
/**
* Check for a given species EggTier Value
* @param species - Species for wich we will check the egg tier it belongs to
* @param pokemonSpecies - Species for wich we will check the egg tier it belongs to
* @returns The egg tier of a given pokemon species
*/
export function getEggTierForSpecies(pokemonSpecies :PokemonSpecies): EggTier {
const speciesBaseValue = speciesStarterCosts[pokemonSpecies.getRootSpeciesId()];
if (speciesBaseValue <= 3) {
return EggTier.COMMON;
} else if (speciesBaseValue <= 5) {
return EggTier.GREAT;
} else if (speciesBaseValue <= 7) {
return EggTier.ULTRA;
}
return EggTier.MASTER;
return speciesEggTiers[pokemonSpecies.getRootSpeciesId()];
}

View File

@ -150,7 +150,7 @@ export const ATrainersTestEncounter: MysteryEncounter =
pulled: false,
sourceType: EggSourceType.EVENT,
eggDescriptor: encounter.misc.trainerEggDescription,
tier: EggTier.ULTRA
tier: EggTier.EPIC
};
encounter.setDialogueToken("eggType", i18next.t(`${namespace}:eggTypes.epic`));
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.SACRED_ASH ], guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ULTRA ], fillRemaining: true }, [ eggOptions ]);
@ -172,7 +172,7 @@ export const ATrainersTestEncounter: MysteryEncounter =
pulled: false,
sourceType: EggSourceType.EVENT,
eggDescriptor: encounter.misc.trainerEggDescription,
tier: EggTier.GREAT
tier: EggTier.RARE
};
encounter.setDialogueToken("eggType", i18next.t(`${namespace}:eggTypes.rare`));
setEncounterRewards(scene, { fillRemaining: false, rerollMultiplier: -1 }, [ eggOptions ]);

View File

@ -494,7 +494,7 @@ function getEggOptions(scene: BattleScene, commonEggs: number, rareEggs: number)
pulled: false,
sourceType: EggSourceType.EVENT,
eggDescriptor: eggDescription,
tier: EggTier.GREAT
tier: EggTier.RARE
});
}
}

View File

@ -1,6 +1,6 @@
export enum EggTier {
COMMON,
GREAT,
ULTRA,
MASTER
RARE,
EPIC,
LEGENDARY
}

View File

@ -50,7 +50,7 @@ export function getStatStageChangeDescriptionKey(stages: number, isIncrease: boo
return isIncrease ? "battle:statRose" : "battle:statFell";
} else if (stages === 2) {
return isIncrease ? "battle:statSharplyRose" : "battle:statHarshlyFell";
} else if (stages <= 6) {
} else if (stages > 2 && stages <= 6) {
return isIncrease ? "battle:statRoseDrastically" : "battle:statSeverelyFell";
}
return isIncrease ? "battle:statWontGoAnyHigher" : "battle:statWontGoAnyLower";

View File

@ -1130,7 +1130,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.scene.applyModifier(PokemonIncrementingStatModifier, this.isPlayer(), this, s, statHolder);
}
statHolder.value = Utils.clampInt(statHolder.value, 1, Number.MAX_SAFE_INTEGER);
statHolder.value = Phaser.Math.Clamp(statHolder.value, 1, Number.MAX_SAFE_INTEGER);
this.setStat(s, statHolder.value);
}

View File

@ -3635,7 +3635,7 @@ export function overrideHeldItems(scene: BattleScene, pokemon: Pokemon, isPlayer
}
if (!isPlayer) {
scene.clearEnemyHeldItemModifiers();
scene.clearEnemyHeldItemModifiers(pokemon);
}
heldItemsOverride.forEach(item => {

View File

@ -0,0 +1,23 @@
import { PostTurnStatusEffectPhase } from "#app/phases/post-turn-status-effect-phase";
import { Phase } from "#app/phase";
import { BattlerIndex } from "#app/battle";
import BattleScene from "#app/battle-scene";
export class CheckStatusEffectPhase extends Phase {
private order : BattlerIndex[];
constructor(scene : BattleScene, order : BattlerIndex[]) {
super(scene);
this.scene = scene;
this.order = order;
}
start() {
const field = this.scene.getField();
for (const o of this.order) {
if (field[o].status && field[o].status.isPostTurn()) {
this.scene.unshiftPhase(new PostTurnStatusEffectPhase(this.scene, o));
}
}
this.end();
}
}

View File

@ -6,7 +6,6 @@ import { StatusEffect } from "#app/enums/status-effect";
import Pokemon from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages";
import { PokemonPhase } from "./pokemon-phase";
import { PostTurnStatusEffectPhase } from "./post-turn-status-effect-phase";
export class ObtainStatusEffectPhase extends PokemonPhase {
private statusEffect?: StatusEffect | undefined;
@ -33,9 +32,6 @@ export class ObtainStatusEffectPhase extends PokemonPhase {
pokemon.updateInfo(true);
new CommonBattleAnim(CommonAnim.POISON + (this.statusEffect! - 1), pokemon).play(this.scene, false, () => {
this.scene.queueMessage(getStatusEffectObtainText(this.statusEffect, getPokemonNameWithAffix(pokemon), this.sourceText ?? undefined));
if (pokemon.status?.isPostTurn()) {
this.scene.pushPhase(new PostTurnStatusEffectPhase(this.scene, this.battlerIndex));
}
this.end();
});
return;

View File

@ -13,10 +13,10 @@ import { BerryPhase } from "./berry-phase";
import { FieldPhase } from "./field-phase";
import { MoveHeaderPhase } from "./move-header-phase";
import { MovePhase } from "./move-phase";
import { PostTurnStatusEffectPhase } from "./post-turn-status-effect-phase";
import { SwitchSummonPhase } from "./switch-summon-phase";
import { TurnEndPhase } from "./turn-end-phase";
import { WeatherEffectPhase } from "./weather-effect-phase";
import { CheckStatusEffectPhase } from "#app/phases/check-status-effect-phase";
import { BattlerIndex } from "#app/battle";
import { TrickRoomTag } from "#app/data/arena-tag";
import { SwitchType } from "#enums/switch-type";
@ -206,11 +206,8 @@ export class TurnStartPhase extends FieldPhase {
this.scene.pushPhase(new WeatherEffectPhase(this.scene));
for (const o of moveOrder) {
if (field[o].status && field[o].status.isPostTurn()) {
this.scene.pushPhase(new PostTurnStatusEffectPhase(this.scene, o));
}
}
/** Add a new phase to check who should be taking status damage */
this.scene.pushPhase(new CheckStatusEffectPhase(this.scene, moveOrder));
this.scene.pushPhase(new BerryPhase(this.scene));
this.scene.pushPhase(new TurnEndPhase(this.scene));

View File

@ -1,5 +1,5 @@
import { Arena } from "../field/arena";
import { ArenaTag } from "../data/arena-tag";
import { ArenaTag, loadArenaTag } from "../data/arena-tag";
import { Biome } from "#enums/biome";
import { Weather } from "../data/weather";
import { Terrain } from "#app/data/terrain";
@ -15,6 +15,10 @@ export default class ArenaData {
this.biome = sourceArena ? sourceArena.biomeType : source.biome;
this.weather = sourceArena ? sourceArena.weather : source.weather ? new Weather(source.weather.weatherType, source.weather.turnsLeft) : null;
this.terrain = sourceArena ? sourceArena.terrain : source.terrain ? new Terrain(source.terrain.terrainType, source.terrain.turnsLeft) : null;
this.tags = sourceArena ? sourceArena.tags : [];
this.tags = [];
if (source.tags) {
this.tags = source.tags.map(t => loadArenaTag(t));
}
}
}

View File

@ -31,7 +31,7 @@ import { TrainerVariant } from "#app/field/trainer";
import { Variant } from "#app/data/variant";
import { setSettingGamepad, SettingGamepad, settingGamepadDefaults } from "#app/system/settings/settings-gamepad";
import { setSettingKeyboard, SettingKeyboard } from "#app/system/settings/settings-keyboard";
import { TerrainChangedEvent, WeatherChangedEvent } from "#app/events/arena";
import { TagAddedEvent, TerrainChangedEvent, WeatherChangedEvent } from "#app/events/arena";
import * as Modifier from "#app/modifier/modifier";
import { StatusEffect } from "#app/data/status-effect";
import ChallengeData from "#app/system/challenge-data";
@ -50,6 +50,7 @@ import { applySessionDataPatches, applySettingsDataPatches, applySystemDataPatch
import { MysteryEncounterSaveData } from "#app/data/mystery-encounters/mystery-encounter-save-data";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { PokerogueApiClearSessionData } from "#app/@types/pokerogue-api";
import { ArenaTrapTag } from "#app/data/arena-tag";
export const defaultStarterSpecies: Species[] = [
Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE,
@ -1085,8 +1086,18 @@ export class GameData {
scene.arena.terrain = sessionData.arena.terrain;
scene.arena.eventTarget.dispatchEvent(new TerrainChangedEvent(TerrainType.NONE, scene.arena.terrain?.terrainType!, scene.arena.terrain?.turnsLeft!)); // TODO: is this bang correct?
// TODO
//scene.arena.tags = sessionData.arena.tags;
scene.arena.tags = sessionData.arena.tags;
if (scene.arena.tags) {
for (const tag of scene.arena.tags) {
if (tag instanceof ArenaTrapTag) {
const { tagType, side, turnCount, layers, maxLayers } = tag as ArenaTrapTag;
scene.arena.eventTarget.dispatchEvent(new TagAddedEvent(tagType, side, turnCount, layers, maxLayers));
} else {
scene.arena.eventTarget.dispatchEvent(new TagAddedEvent(tag.tagType, tag.side, tag.turnCount));
}
}
}
for (const modifierData of sessionData.modifiers) {
const modifier = modifierData.toModifier(scene, Modifier[modifierData.className]);

View File

@ -55,7 +55,7 @@ describe("Egg Generation Tests", () => {
let gachaSpeciesCount = 0;
for (let i = 0; i < EGG_HATCH_COUNT; i++) {
const result = new Egg({ scene, timestamp, sourceType: EggSourceType.GACHA_LEGENDARY, tier: EggTier.MASTER }).generatePlayerPokemon(scene).species.speciesId;
const result = new Egg({ scene, timestamp, sourceType: EggSourceType.GACHA_LEGENDARY, tier: EggTier.LEGENDARY }).generatePlayerPokemon(scene).species.speciesId;
if (result === expectedSpecies) {
gachaSpeciesCount++;
}
@ -82,7 +82,7 @@ describe("Egg Generation Tests", () => {
});
it("should return an rare tier egg", () => {
const scene = game.scene;
const expectedTier = EggTier.GREAT;
const expectedTier = EggTier.RARE;
const result = new Egg({ scene, tier: expectedTier }).tier;
@ -90,7 +90,7 @@ describe("Egg Generation Tests", () => {
});
it("should return an epic tier egg", () => {
const scene = game.scene;
const expectedTier = EggTier.ULTRA;
const expectedTier = EggTier.EPIC;
const result = new Egg({ scene, tier: expectedTier }).tier;
@ -98,7 +98,7 @@ describe("Egg Generation Tests", () => {
});
it("should return an legendary tier egg", () => {
const scene = game.scene;
const expectedTier = EggTier.MASTER;
const expectedTier = EggTier.LEGENDARY;
const result = new Egg({ scene, tier: expectedTier }).tier;
@ -200,7 +200,7 @@ describe("Egg Generation Tests", () => {
const scene = game.scene;
const expectedEggTier = EggTier.COMMON;
const result = new Egg({ scene, tier: EggTier.MASTER, species: Species.BULBASAUR }).tier;
const result = new Egg({ scene, tier: EggTier.LEGENDARY, species: Species.BULBASAUR }).tier;
expect(result).toBe(expectedEggTier);
});
@ -208,7 +208,7 @@ describe("Egg Generation Tests", () => {
const scene = game.scene;
const expectedHatchWaves = 10;
const result = new Egg({ scene, tier: EggTier.MASTER, species: Species.BULBASAUR }).hatchWaves;
const result = new Egg({ scene, tier: EggTier.LEGENDARY, species: Species.BULBASAUR }).hatchWaves;
expect(result).toBe(expectedHatchWaves);
});
@ -229,7 +229,7 @@ describe("Egg Generation Tests", () => {
const result = new EggData(legacyEgg).toEgg();
expect(result.tier).toBe(EggTier.GREAT);
expect(result.tier).toBe(EggTier.RARE);
expect(result.id).toBe(legacyEgg.id);
expect(result.timestamp).toBe(legacyEgg.timestamp);
expect(result.hatchWaves).toBe(legacyEgg.hatchWaves);
@ -241,9 +241,9 @@ describe("Egg Generation Tests", () => {
new Egg({ scene, sourceType: EggSourceType.GACHA_MOVE, pulled: true, tier: EggTier.COMMON });
expect(scene.gameData.eggPity[EggTier.GREAT]).toBe(startPityValues[EggTier.GREAT] + 1);
expect(scene.gameData.eggPity[EggTier.ULTRA]).toBe(startPityValues[EggTier.ULTRA] + 1);
expect(scene.gameData.eggPity[EggTier.MASTER]).toBe(startPityValues[EggTier.MASTER] + 1);
expect(scene.gameData.eggPity[EggTier.RARE]).toBe(startPityValues[EggTier.RARE] + 1);
expect(scene.gameData.eggPity[EggTier.EPIC]).toBe(startPityValues[EggTier.EPIC] + 1);
expect(scene.gameData.eggPity[EggTier.LEGENDARY]).toBe(startPityValues[EggTier.LEGENDARY] + 1);
});
it("should increase legendary egg pity by two", () => {
const scene = game.scene;
@ -251,9 +251,9 @@ describe("Egg Generation Tests", () => {
new Egg({ scene, sourceType: EggSourceType.GACHA_LEGENDARY, pulled: true, tier: EggTier.COMMON });
expect(scene.gameData.eggPity[EggTier.GREAT]).toBe(startPityValues[EggTier.GREAT] + 1);
expect(scene.gameData.eggPity[EggTier.ULTRA]).toBe(startPityValues[EggTier.ULTRA] + 1);
expect(scene.gameData.eggPity[EggTier.MASTER]).toBe(startPityValues[EggTier.MASTER] + 2);
expect(scene.gameData.eggPity[EggTier.RARE]).toBe(startPityValues[EggTier.RARE] + 1);
expect(scene.gameData.eggPity[EggTier.EPIC]).toBe(startPityValues[EggTier.EPIC] + 1);
expect(scene.gameData.eggPity[EggTier.LEGENDARY]).toBe(startPityValues[EggTier.LEGENDARY] + 2);
});
it("should not increase manaphy egg count if bulbasaurs are pulled", () => {
const scene = game.scene;
@ -277,7 +277,7 @@ describe("Egg Generation Tests", () => {
const scene = game.scene;
const startingRareEggsPulled = scene.gameData.gameStats.rareEggsPulled;
new Egg({ scene, sourceType: EggSourceType.GACHA_MOVE, pulled: true, tier: EggTier.GREAT });
new Egg({ scene, sourceType: EggSourceType.GACHA_MOVE, pulled: true, tier: EggTier.RARE });
expect(scene.gameData.gameStats.rareEggsPulled).toBe(startingRareEggsPulled + 1);
});
@ -285,7 +285,7 @@ describe("Egg Generation Tests", () => {
const scene = game.scene;
const startingEpicEggsPulled = scene.gameData.gameStats.epicEggsPulled;
new Egg({ scene, sourceType: EggSourceType.GACHA_MOVE, pulled: true, tier: EggTier.ULTRA });
new Egg({ scene, sourceType: EggSourceType.GACHA_MOVE, pulled: true, tier: EggTier.EPIC });
expect(scene.gameData.gameStats.epicEggsPulled).toBe(startingEpicEggsPulled + 1);
});
@ -293,7 +293,7 @@ describe("Egg Generation Tests", () => {
const scene = game.scene;
const startingLegendaryEggsPulled = scene.gameData.gameStats.legendaryEggsPulled;
new Egg({ scene, sourceType: EggSourceType.GACHA_MOVE, pulled: true, tier: EggTier.MASTER });
new Egg({ scene, sourceType: EggSourceType.GACHA_MOVE, pulled: true, tier: EggTier.LEGENDARY });
expect(scene.gameData.gameStats.legendaryEggsPulled).toBe(startingLegendaryEggsPulled + 1);
});
@ -301,8 +301,8 @@ describe("Egg Generation Tests", () => {
vi.spyOn(Utils, "randInt").mockReturnValue(1);
const scene = game.scene;
const expectedTier1 = EggTier.MASTER;
const expectedTier2 = EggTier.ULTRA;
const expectedTier1 = EggTier.LEGENDARY;
const expectedTier2 = EggTier.EPIC;
const result1 = new Egg({ scene, sourceType: EggSourceType.GACHA_LEGENDARY, pulled: true }).tier;
const result2 = new Egg({ scene, sourceType: EggSourceType.GACHA_MOVE, pulled: true }).tier;

View File

@ -1,7 +1,4 @@
import { StatusEffect } from "#app/data/status-effect";
import { EnemyCommandPhase } from "#app/phases/enemy-command-phase";
import { MessagePhase } from "#app/phases/message-phase";
import { TurnEndPhase } from "#app/phases/turn-end-phase";
import i18next from "#app/plugins/i18n";
import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
@ -10,6 +7,7 @@ import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const TIMEOUT = 20 * 1000;
describe("Items - Toxic orb", () => {
let phaserGame: Phaser.Game;
@ -27,40 +25,36 @@ describe("Items - Toxic orb", () => {
beforeEach(() => {
game = new GameManager(phaserGame);
const moveToUse = Moves.GROWTH;
const oppMoveToUse = Moves.TACKLE;
game.override.battleType("single");
game.override.enemySpecies(Species.RATTATA);
game.override.ability(Abilities.INSOMNIA);
game.override.enemyAbility(Abilities.INSOMNIA);
game.override.startingLevel(2000);
game.override.moveset([ moveToUse ]);
game.override.enemyMoveset([ oppMoveToUse, oppMoveToUse, oppMoveToUse, oppMoveToUse ]);
game.override.startingHeldItems([{
name: "TOXIC_ORB",
}]);
game.override
.battleType("single")
.enemySpecies(Species.RATTATA)
.ability(Abilities.BALL_FETCH)
.enemyAbility(Abilities.BALL_FETCH)
.moveset([ Moves.SPLASH ])
.enemyMoveset(Moves.SPLASH)
.startingHeldItems([{
name: "TOXIC_ORB",
}]);
vi.spyOn(i18next, "t");
});
it("TOXIC ORB", async () => {
const moveToUse = Moves.GROWTH;
await game.startBattle([
Species.MIGHTYENA,
Species.MIGHTYENA,
]);
expect(game.scene.modifiers[0].type.id).toBe("TOXIC_ORB");
it("badly poisons the holder", async () => {
await game.classicMode.startBattle([ Species.MIGHTYENA ]);
game.move.select(moveToUse);
const player = game.scene.getPlayerField()[0];
// will run the 13 phase from enemyCommandPhase to TurnEndPhase
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(TurnEndPhase);
game.move.select(Moves.SPLASH);
await game.phaseInterceptor.to("TurnEndPhase");
// Toxic orb should trigger here
await game.phaseInterceptor.run(MessagePhase);
await game.phaseInterceptor.run("MessagePhase");
expect(i18next.t).toHaveBeenCalledWith("statusEffect:toxic.obtainSource", expect.anything());
await game.phaseInterceptor.run(MessagePhase);
expect(i18next.t).toHaveBeenCalledWith("statusEffect:toxic.activation", expect.anything());
expect(game.scene.getParty()[0].status!.effect).toBe(StatusEffect.TOXIC);
}, 20000);
await game.toNextTurn();
expect(player.status?.effect).toBe(StatusEffect.TOXIC);
// Damage should not have ticked yet.
expect(player.status?.turnCount).toBe(0);
}, TIMEOUT);
});

View File

@ -1,4 +1,3 @@
import { allMoves } from "#app/data/move";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import { Abilities } from "#enums/abilities";
@ -7,7 +6,7 @@ import { Stat } from "#enums/stat";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { BattlerIndex } from "#app/battle";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
describe("Moves - SYRUP BOMB", () => {
let phaserGame: Phaser.Game;
@ -26,20 +25,21 @@ describe("Moves - SYRUP BOMB", () => {
beforeEach(() => {
game = new GameManager(phaserGame);
game.override
.starterSpecies(Species.MAGIKARP)
.battleType("single")
.enemySpecies(Species.SNORLAX)
.enemyAbility(Abilities.BALL_FETCH)
.ability(Abilities.BALL_FETCH)
.startingLevel(30)
.enemyLevel(100)
.moveset([ Moves.SYRUP_BOMB, Moves.SPLASH ])
.enemyMoveset(Moves.SPLASH);
vi.spyOn(allMoves[Moves.SYRUP_BOMB], "accuracy", "get").mockReturnValue(100);
});
//Bulbapedia Reference: https://bulbapedia.bulbagarden.net/wiki/syrup_bomb_(move)
it("decreases the target Pokemon's speed stat once per turn for 3 turns",
async () => {
await game.startBattle([ Species.MAGIKARP ]);
await game.classicMode.startBattle([ Species.MAGIKARP ]);
const targetPokemon = game.scene.getEnemyPokemon()!;
expect(targetPokemon.getStatStage(Stat.SPD)).toBe(0);
@ -66,7 +66,7 @@ describe("Moves - SYRUP BOMB", () => {
it("does not affect Pokemon with the ability Bulletproof",
async () => {
game.override.enemyAbility(Abilities.BULLETPROOF);
await game.startBattle([ Species.MAGIKARP ]);
await game.classicMode.startBattle([ Species.MAGIKARP ]);
const targetPokemon = game.scene.getEnemyPokemon()!;
@ -79,4 +79,18 @@ describe("Moves - SYRUP BOMB", () => {
expect(targetPokemon.getStatStage(Stat.SPD)).toBe(0);
}
);
it("stops lowering the target's speed if the user leaves the field", async () => {
await game.classicMode.startBattle([ Species.FEEBAS, Species.MILOTIC ]);
game.move.select(Moves.SYRUP_BOMB);
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
await game.move.forceHit();
await game.toNextTurn();
game.doSwitchPokemon(1);
await game.toNextTurn();
expect(game.scene.getEnemyPokemon()!.getStatStage(Stat.SPD)).toBe(-1);
});
});

View File

@ -0,0 +1,136 @@
import { ArenaTagSide, ArenaTrapTag } from "#app/data/arena-tag";
import { StatusEffect } from "#app/data/status-effect";
import { decrypt, encrypt, GameData, SessionSaveData } from "#app/system/game-data";
import { Abilities } from "#enums/abilities";
import { ArenaTagType } from "#enums/arena-tag-type";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
const TIMEOUT = 20 * 1000;
describe("Moves - Toxic Spikes", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
});
beforeEach(() => {
game = new GameManager(phaserGame);
game.override
.battleType("single")
.startingWave(5)
.enemySpecies(Species.RATTATA)
.enemyAbility(Abilities.BALL_FETCH)
.ability(Abilities.BALL_FETCH)
.enemyMoveset(Moves.SPLASH)
.moveset([ Moves.TOXIC_SPIKES, Moves.SPLASH, Moves.ROAR ]);
});
it("should not affect the opponent if they do not switch", async() => {
await game.classicMode.runToSummon([ Species.MIGHTYENA, Species.POOCHYENA ]);
const enemy = game.scene.getEnemyField()[0];
game.move.select(Moves.TOXIC_SPIKES);
await game.phaseInterceptor.to("TurnEndPhase");
game.move.select(Moves.SPLASH);
await game.phaseInterceptor.to("TurnEndPhase");
game.doSwitchPokemon(1);
await game.phaseInterceptor.to("TurnEndPhase");
expect(enemy.hp).toBe(enemy.getMaxHp());
expect(enemy.status?.effect).toBeUndefined();
}, TIMEOUT);
it("should poison the opponent if they switch into 1 layer", async() => {
await game.classicMode.runToSummon([ Species.MIGHTYENA ]);
game.move.select(Moves.TOXIC_SPIKES);
await game.phaseInterceptor.to("TurnEndPhase");
game.move.select(Moves.ROAR);
await game.phaseInterceptor.to("TurnEndPhase");
const enemy = game.scene.getEnemyField()[0];
expect(enemy.hp).toBeLessThan(enemy.getMaxHp());
expect(enemy.status?.effect).toBe(StatusEffect.POISON);
}, TIMEOUT);
it("should badly poison the opponent if they switch into 2 layers", async() => {
await game.classicMode.runToSummon([ Species.MIGHTYENA ]);
game.move.select(Moves.TOXIC_SPIKES);
await game.phaseInterceptor.to("TurnEndPhase");
game.move.select(Moves.TOXIC_SPIKES);
await game.phaseInterceptor.to("TurnEndPhase");
game.move.select(Moves.ROAR);
await game.phaseInterceptor.to("TurnEndPhase");
const enemy = game.scene.getEnemyField()[0];
expect(enemy.hp).toBeLessThan(enemy.getMaxHp());
expect(enemy.status?.effect).toBe(StatusEffect.TOXIC);
}, TIMEOUT);
it("should be removed if a grounded poison pokemon switches in", async() => {
game.override.enemySpecies(Species.GRIMER);
await game.classicMode.runToSummon([ Species.MIGHTYENA ]);
game.move.select(Moves.TOXIC_SPIKES);
await game.phaseInterceptor.to("TurnEndPhase");
game.move.select(Moves.TOXIC_SPIKES);
await game.phaseInterceptor.to("TurnEndPhase");
game.move.select(Moves.ROAR);
await game.phaseInterceptor.to("TurnEndPhase");
const enemy = game.scene.getEnemyField()[0];
expect(enemy.hp).toBe(enemy.getMaxHp());
expect(enemy.status?.effect).toBeUndefined();
expect(game.scene.arena.tags.length).toBe(0);
}, TIMEOUT);
it("shouldn't create multiple layers per use in doubles", async() => {
await game.classicMode.runToSummon([ Species.MIGHTYENA, Species.POOCHYENA ]);
game.move.select(Moves.TOXIC_SPIKES);
await game.phaseInterceptor.to("TurnEndPhase");
const arenaTags = (game.scene.arena.getTagOnSide(ArenaTagType.TOXIC_SPIKES, ArenaTagSide.ENEMY) as ArenaTrapTag);
expect(arenaTags.tagType).toBe(ArenaTagType.TOXIC_SPIKES);
expect(arenaTags.layers).toBe(1);
}, TIMEOUT);
it("should persist through reload", async() => {
game.override.startingWave(1);
const scene = game.scene;
const gameData = new GameData(scene);
await game.classicMode.runToSummon([ Species.MIGHTYENA ]);
game.move.select(Moves.TOXIC_SPIKES);
await game.phaseInterceptor.to("TurnEndPhase");
game.move.select(Moves.SPLASH);
await game.doKillOpponents();
await game.phaseInterceptor.to("BattleEndPhase");
await game.toNextWave();
const sessionData : SessionSaveData = gameData["getSessionSaveData"](game.scene);
localStorage.setItem("sessionTestData", encrypt(JSON.stringify(sessionData), true));
const recoveredData : SessionSaveData = gameData.parseSessionData(decrypt(localStorage.getItem("sessionTestData")!, true));
gameData.loadSession(game.scene, 0, recoveredData);
expect(sessionData.arena.tags).toEqual(recoveredData.arena.tags);
localStorage.removeItem("sessionTestData");
}, TIMEOUT);
});

View File

@ -128,7 +128,7 @@ describe("A Trainer's Test - Mystery Encounter", () => {
expect(eggsAfter).toBeDefined();
expect(eggsBeforeLength + 1).toBe(eggsAfter.length);
const eggTier = eggsAfter[eggsAfter.length - 1].tier;
expect(eggTier === EggTier.ULTRA || eggTier === EggTier.MASTER).toBeTruthy();
expect(eggTier === EggTier.EPIC || eggTier === EggTier.LEGENDARY).toBeTruthy();
});
});
@ -176,7 +176,7 @@ describe("A Trainer's Test - Mystery Encounter", () => {
expect(eggsAfter).toBeDefined();
expect(eggsBeforeLength + 1).toBe(eggsAfter.length);
const eggTier = eggsAfter[eggsAfter.length - 1].tier;
expect(eggTier).toBe(EggTier.GREAT);
expect(eggTier).toBe(EggTier.RARE);
});
it("should leave encounter without battle", async () => {

View File

@ -155,7 +155,7 @@ describe("The Expert Pokémon Breeder - Mystery Encounter", () => {
expect(eggsAfter).toBeDefined();
expect(eggsBeforeLength + commonEggs + rareEggs).toBe(eggsAfter.length);
expect(eggsAfter.filter(egg => egg.tier === EggTier.COMMON).length).toBe(commonEggs);
expect(eggsAfter.filter(egg => egg.tier === EggTier.GREAT).length).toBe(rareEggs);
expect(eggsAfter.filter(egg => egg.tier === EggTier.RARE).length).toBe(rareEggs);
game.phaseInterceptor.superEndPhase();
await game.phaseInterceptor.to(PostMysteryEncounterPhase);
@ -213,7 +213,7 @@ describe("The Expert Pokémon Breeder - Mystery Encounter", () => {
expect(eggsAfter).toBeDefined();
expect(eggsBeforeLength + commonEggs + rareEggs).toBe(eggsAfter.length);
expect(eggsAfter.filter(egg => egg.tier === EggTier.COMMON).length).toBe(commonEggs);
expect(eggsAfter.filter(egg => egg.tier === EggTier.GREAT).length).toBe(rareEggs);
expect(eggsAfter.filter(egg => egg.tier === EggTier.RARE).length).toBe(rareEggs);
game.phaseInterceptor.superEndPhase();
await game.phaseInterceptor.to(PostMysteryEncounterPhase);
@ -271,7 +271,7 @@ describe("The Expert Pokémon Breeder - Mystery Encounter", () => {
expect(eggsAfter).toBeDefined();
expect(eggsBeforeLength + commonEggs + rareEggs).toBe(eggsAfter.length);
expect(eggsAfter.filter(egg => egg.tier === EggTier.COMMON).length).toBe(commonEggs);
expect(eggsAfter.filter(egg => egg.tier === EggTier.GREAT).length).toBe(rareEggs);
expect(eggsAfter.filter(egg => egg.tier === EggTier.RARE).length).toBe(rareEggs);
game.phaseInterceptor.superEndPhase();
await game.phaseInterceptor.to(PostMysteryEncounterPhase);

View File

@ -40,7 +40,9 @@ export default class AchvsUiHandler extends MessageUiHandler {
private iconsBg: Phaser.GameObjects.NineSlice;
private icons: Phaser.GameObjects.Sprite[];
private titleBg: Phaser.GameObjects.NineSlice;
private titleText: Phaser.GameObjects.Text;
private scoreContainer: Phaser.GameObjects.Container;
private scoreText: Phaser.GameObjects.Text;
private unlockText: Phaser.GameObjects.Text;
@ -114,29 +116,31 @@ export default class AchvsUiHandler extends MessageUiHandler {
const titleBg = addWindow(this.scene, 0, this.headerBg.height + this.iconsBg.height, 174, 24);
titleBg.setOrigin(0, 0);
this.titleBg = titleBg;
this.titleText = addTextObject(this.scene, 0, 0, "", TextStyle.WINDOW);
const textSize = languageSettings[i18next.language]?.TextSize ?? this.titleText.style.fontSize;
this.titleText.setFontSize(textSize);
this.titleText.setOrigin(0, 0);
const titleBgCenterX = titleBg.x + titleBg.width / 2;
const titleBgCenterY = titleBg.y + titleBg.height / 2;
this.titleText.setOrigin(0.5, 0.5);
this.titleText.setPosition(titleBgCenterX, titleBgCenterY);
const scoreBg = addWindow(this.scene, titleBg.x + titleBg.width, titleBg.y, 46, 24);
this.scoreContainer = this.scene.add.container(titleBg.x + titleBg.width, titleBg.y);
const scoreBg = addWindow(this.scene, 0, 0, 46, 24);
scoreBg.setOrigin(0, 0);
this.scoreContainer.add(scoreBg);
this.scoreText = addTextObject(this.scene, 0, 0, "", TextStyle.WINDOW);
this.scoreText.setOrigin(0, 0);
this.scoreText.setPositionRelative(scoreBg, 8, 4);
this.scoreText = addTextObject(this.scene, scoreBg.width / 2, scoreBg.height / 2, "", TextStyle.WINDOW);
this.scoreText.setOrigin(0.5, 0.5);
this.scoreContainer.add(this.scoreText);
const unlockBg = addWindow(this.scene, scoreBg.x + scoreBg.width, scoreBg.y, 98, 24);
const unlockBg = addWindow(this.scene, this.scoreContainer.x + scoreBg.width, titleBg.y, 98, 24);
unlockBg.setOrigin(0, 0);
this.unlockText = addTextObject(this.scene, 0, 0, "", TextStyle.WINDOW);
this.unlockText.setOrigin(0, 0);
this.unlockText.setPositionRelative(unlockBg, 8, 4);
this.unlockText.setOrigin(0.5, 0.5);
this.unlockText.setPositionRelative(unlockBg, unlockBg.width / 2, unlockBg.height / 2);
const descriptionBg = addWindow(this.scene, 0, titleBg.y + titleBg.height, (this.scene.game.canvas.width / 6) - 2, 42);
descriptionBg.setOrigin(0, 0);
@ -157,8 +161,7 @@ export default class AchvsUiHandler extends MessageUiHandler {
this.mainContainer.add(this.iconsContainer);
this.mainContainer.add(titleBg);
this.mainContainer.add(this.titleText);
this.mainContainer.add(scoreBg);
this.mainContainer.add(this.scoreText);
this.mainContainer.add(this.scoreContainer);
this.mainContainer.add(unlockBg);
this.mainContainer.add(this.unlockText);
this.mainContainer.add(descriptionBg);
@ -167,8 +170,6 @@ export default class AchvsUiHandler extends MessageUiHandler {
ui.add(this.mainContainer);
this.currentPage = Page.ACHIEVEMENTS;
this.setCursor(0);
this.setScrollCursor(0);
this.mainContainer.setVisible(false);
}
@ -316,9 +317,19 @@ export default class AchvsUiHandler extends MessageUiHandler {
if (update || pageChange) {
switch (this.currentPage) {
case Page.ACHIEVEMENTS:
if (pageChange) {
this.titleBg.width = 174;
this.titleText.x = this.titleBg.width / 2;
this.scoreContainer.setVisible(true);
}
this.showAchv(achvs[Object.keys(achvs)[cursor + this.scrollCursor * this.COLS]]);
break;
case Page.VOUCHERS:
if (pageChange) {
this.titleBg.width = 220;
this.titleText.x = this.titleBg.width / 2;
this.scoreContainer.setVisible(false);
}
this.showVoucher(vouchers[Object.keys(vouchers)[cursor + this.scrollCursor * this.COLS]]);
break;
}
@ -442,6 +453,7 @@ export default class AchvsUiHandler extends MessageUiHandler {
this.currentPage = Page.ACHIEVEMENTS;
this.mainContainer.setVisible(false);
this.setScrollCursor(0);
this.setCursor(0, true);
this.eraseCursor();
}

View File

@ -600,7 +600,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
};
const updatePokemonHp = () => {
let duration = !instant ? Utils.clampInt(Math.abs((this.lastHp) - pokemon.hp) * 5, 250, 5000) : 0;
let duration = !instant ? Phaser.Math.Clamp(Math.abs((this.lastHp) - pokemon.hp) * 5, 250, 5000) : 0;
const speed = (this.scene as BattleScene).hpBarSpeed;
if (speed) {
duration = speed >= 3 ? 0 : duration / Math.pow(2, speed);

View File

@ -471,9 +471,9 @@ export default class EggGachaUiHandler extends MessageUiHandler {
getGuaranteedEggTierFromPullCount(pullCount: number): EggTier {
switch (pullCount) {
case 10:
return EggTier.GREAT;
return EggTier.RARE;
case 25:
return EggTier.ULTRA;
return EggTier.EPIC;
default:
return EggTier.COMMON;
}
@ -516,7 +516,7 @@ export default class EggGachaUiHandler extends MessageUiHandler {
const eggText = addTextObject(this.scene, 0, 14, egg.getEggDescriptor(), TextStyle.PARTY, { align: "center" });
eggText.setOrigin(0.5, 0);
eggText.setTint(getEggTierTextTint(!egg.isManaphyEgg() ? egg.tier : EggTier.ULTRA));
eggText.setTint(getEggTierTextTint(!egg.isManaphyEgg() ? egg.tier : EggTier.EPIC));
ret.add(eggText);
this.eggGachaSummaryContainer.addAt(ret, 0);

View File

@ -12,7 +12,8 @@ import { Mode } from "./ui";
import { addWindow } from "./ui-theme";
import { RunDisplayMode } from "#app/ui/run-info-ui-handler";
const sessionSlotCount = 5;
const SESSION_SLOTS_COUNT = 5;
const SLOTS_ON_SCREEN = 3;
export enum SaveSlotUiMode {
LOAD,
@ -84,12 +85,10 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler {
this.saveSlotSelectCallback = args[1] as SaveSlotSelectCallback;
this.saveSlotSelectContainer.setVisible(true);
this.populateSessionSlots()
.then(() => {
this.setScrollCursor(0);
this.setCursor(0);
});
this.populateSessionSlots();
this.setScrollCursor(0);
this.setCursor(0);
return true;
}
@ -161,9 +160,9 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler {
}
break;
case Button.DOWN:
if (this.cursor < 2) {
success = this.setCursor(this.cursor + 1, this.cursor);
} else if (this.scrollCursor < sessionSlotCount - 3) {
if (this.cursor < (SLOTS_ON_SCREEN - 1)) {
success = this.setCursor(this.cursor + 1, cursorPosition);
} else if (this.scrollCursor < SESSION_SLOTS_COUNT - SLOTS_ON_SCREEN) {
success = this.setScrollCursor(this.scrollCursor + 1, cursorPosition);
}
break;
@ -184,13 +183,19 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler {
return success || error;
}
async populateSessionSlots() {
for (let s = 0; s < sessionSlotCount; s++) {
populateSessionSlots() {
for (let s = 0; s < SESSION_SLOTS_COUNT; s++) {
const sessionSlot = new SessionSlot(this.scene, s);
await sessionSlot.load();
this.scene.add.existing(sessionSlot);
this.sessionSlotsContainer.add(sessionSlot);
this.sessionSlots.push(sessionSlot);
sessionSlot.load().then((success) => {
// If the cursor was moved to this slot while the session was loading
// call setCursor again to shift the slot position and show the arrow for save preview
if (success && (this.cursor + this.scrollCursor) === s) {
this.setCursor(s);
}
});
}
}
@ -209,12 +214,12 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler {
}
/**
* setCursor takes user navigation as an input and positions the cursor accordingly
* @param cursor the index provided to the cursor
* @param prevCursor the previous index occupied by the cursor - optional
* Move the cursor to a new position and update the view accordingly
* @param cursor the new cursor position, between `0` and `SLOTS_ON_SCREEN - 1`
* @param prevSlotIndex index of the previous session occupied by the cursor, between `0` and `SESSION_SLOTS_COUNT - 1` - optional
* @returns `true` if the cursor position has changed | `false` if it has not
*/
override setCursor(cursor: integer, prevCursor?: integer): boolean {
override setCursor(cursor: integer, prevSlotIndex?: integer): boolean {
const changed = super.setCursor(cursor);
if (!this.cursorObj) {
@ -241,21 +246,20 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler {
}
this.setArrowVisibility(hasData);
}
if (!Utils.isNullOrUndefined(prevCursor)) {
this.revertSessionSlot(prevCursor);
if (!Utils.isNullOrUndefined(prevSlotIndex)) {
this.revertSessionSlot(prevSlotIndex);
}
return changed;
}
/**
* Helper function that resets the session slot position to its default central position
* @param prevCursor the previous location of the cursor
* Helper function that resets the given session slot to its default central position
*/
revertSessionSlot(prevCursor: integer): void {
const sessionSlot = this.sessionSlots[prevCursor];
revertSessionSlot(slotIndex: integer): void {
const sessionSlot = this.sessionSlots[slotIndex];
if (sessionSlot) {
sessionSlot.setPosition(0, prevCursor * 56);
sessionSlot.setPosition(0, slotIndex * 56);
}
}
@ -270,12 +274,18 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler {
}
}
setScrollCursor(scrollCursor: integer, priorCursor?: integer): boolean {
/**
* Move the scrolling cursor to a new position and update the view accordingly
* @param scrollCursor the new cursor position, between `0` and `SESSION_SLOTS_COUNT - SLOTS_ON_SCREEN`
* @param prevSlotIndex index of the previous slot occupied by the cursor, between `0` and `SESSION_SLOTS_COUNT-1` - optional
* @returns `true` if the cursor position has changed | `false` if it has not
*/
setScrollCursor(scrollCursor: integer, prevSlotIndex?: integer): boolean {
const changed = scrollCursor !== this.scrollCursor;
if (changed) {
this.scrollCursor = scrollCursor;
this.setCursor(this.cursor, priorCursor);
this.setCursor(this.cursor, prevSlotIndex);
this.scene.tweens.add({
targets: this.sessionSlotsContainer,
y: this.sessionSlotsContainerInitialY - 56 * scrollCursor,
@ -290,6 +300,7 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler {
clear() {
super.clear();
this.saveSlotSelectContainer.setVisible(false);
this.setScrollCursor(0);
this.eraseCursor();
this.saveSlotSelectCallback = null;
this.clearSessionSlots();
@ -391,6 +402,10 @@ class SessionSlot extends Phaser.GameObjects.Container {
load(): Promise<boolean> {
return new Promise<boolean>(resolve => {
this.scene.gameData.getSession(this.slotId).then(async sessionData => {
// Ignore the results if the view was exited
if (!this.active) {
return;
}
if (!sessionData) {
this.hasData = false;
this.loadingLabel.setText(i18next.t("saveSlotSelectUiHandler:empty"));

View File

@ -356,11 +356,11 @@ export function getEggTierTextTint(tier: EggTier): integer {
switch (tier) {
case EggTier.COMMON:
return getModifierTierTextTint(ModifierTier.COMMON);
case EggTier.GREAT:
case EggTier.RARE:
return getModifierTierTextTint(ModifierTier.GREAT);
case EggTier.ULTRA:
case EggTier.EPIC:
return getModifierTierTextTint(ModifierTier.ULTRA);
case EggTier.MASTER:
case EggTier.LEGENDARY:
return getModifierTierTextTint(ModifierTier.MASTER);
}
}

View File

@ -38,10 +38,6 @@ export function shiftCharCodes(str: string, shiftCount: integer) {
return newStr;
}
export function clampInt(value: integer, min: integer, max: integer): integer {
return Math.min(Math.max(value, min), max);
}
export function randGauss(stdev: number, mean: number = 0): number {
if (!stdev) {
return 0;