mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-04 15:32:18 +02:00
Compare commits
No commits in common. "f159b2e84d70dddb1df27b24e2252d8b6d94b303" and "1e97d1bbd34938186b512ba1eac773f00b161318" have entirely different histories.
f159b2e84d
...
1e97d1bbd3
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
Binary file not shown.
Before Width: | Height: | Size: 413 B |
Binary file not shown.
Before Width: | Height: | Size: 888 B After Width: | Height: | Size: 1.5 KiB |
@ -35,36 +35,36 @@ interface BiomeDepths {
|
|||||||
export const biomeLinks: BiomeLinks = {
|
export const biomeLinks: BiomeLinks = {
|
||||||
[Biome.TOWN]: Biome.PLAINS,
|
[Biome.TOWN]: Biome.PLAINS,
|
||||||
[Biome.PLAINS]: [ Biome.GRASS, Biome.METROPOLIS, Biome.LAKE ],
|
[Biome.PLAINS]: [ Biome.GRASS, Biome.METROPOLIS, Biome.LAKE ],
|
||||||
[Biome.GRASS]: [ Biome.TALL_GRASS, [ Biome.CONSTRUCTION_SITE, 2 ] ],
|
[Biome.GRASS]: Biome.TALL_GRASS,
|
||||||
[Biome.TALL_GRASS]: [ Biome.FOREST, Biome.CAVE ],
|
[Biome.TALL_GRASS]: [ Biome.FOREST, Biome.CAVE ],
|
||||||
[Biome.SLUM]: Biome.CONSTRUCTION_SITE,
|
[Biome.SLUM]: Biome.CONSTRUCTION_SITE,
|
||||||
[Biome.FOREST]: [ Biome.JUNGLE, Biome.MEADOW ],
|
[Biome.FOREST]: [ Biome.JUNGLE, Biome.MEADOW ],
|
||||||
[Biome.SEA]: [ Biome.SEABED, Biome.ICE_CAVE ],
|
[Biome.SEA]: [ Biome.SEABED, Biome.ICE_CAVE ],
|
||||||
[Biome.SWAMP]: [ Biome.GRAVEYARD, Biome.TALL_GRASS ],
|
[Biome.SWAMP]: [ Biome.GRAVEYARD, Biome.TALL_GRASS ],
|
||||||
[Biome.BEACH]: [ Biome.SEA, [ Biome.ISLAND, 3 ] ],
|
[Biome.BEACH]: [ Biome.SEA, [ Biome.ISLAND, 4 ] ],
|
||||||
[Biome.LAKE]: [ Biome.BEACH, Biome.SWAMP, Biome.CONSTRUCTION_SITE ],
|
[Biome.LAKE]: [ Biome.BEACH, Biome.SWAMP, Biome.CONSTRUCTION_SITE ],
|
||||||
[Biome.SEABED]: [ Biome.CAVE, [ Biome.VOLCANO, 3 ] ],
|
[Biome.SEABED]: [ Biome.CAVE, [ Biome.VOLCANO, 4 ] ],
|
||||||
[Biome.MOUNTAIN]: [ Biome.VOLCANO, [ Biome.DOJO, 2] [ Biome.WASTELAND, 2 ] ],
|
[Biome.MOUNTAIN]: [ Biome.VOLCANO, [ Biome.WASTELAND, 3 ] ],
|
||||||
[Biome.BADLANDS]: [ Biome.DESERT, Biome.MOUNTAIN ],
|
[Biome.BADLANDS]: [ Biome.DESERT, Biome.MOUNTAIN ],
|
||||||
[Biome.CAVE]: [ Biome.BADLANDS, Biome.LAKE ],
|
[Biome.CAVE]: [ Biome.BADLANDS, Biome.LAKE ],
|
||||||
[Biome.DESERT]: [ Biome.RUINS, [ Biome.CONSTRUCTION_SITE, 2 ] ],
|
[Biome.DESERT]: Biome.RUINS,
|
||||||
[Biome.ICE_CAVE]: Biome.SNOWY_FOREST,
|
[Biome.ICE_CAVE]: Biome.SNOWY_FOREST,
|
||||||
[Biome.MEADOW]: [ Biome.PLAINS, Biome.FAIRY_CAVE ],
|
[Biome.MEADOW]: [ Biome.PLAINS, [ Biome.FAIRY_CAVE, 2 ] ],
|
||||||
[Biome.POWER_PLANT]: Biome.FACTORY,
|
[Biome.POWER_PLANT]: Biome.FACTORY,
|
||||||
[Biome.VOLCANO]: [ Biome.BEACH, [ Biome.ICE_CAVE, 3 ] ],
|
[Biome.VOLCANO]: [ Biome.BEACH, [ Biome.ICE_CAVE, 4 ] ],
|
||||||
[Biome.GRAVEYARD]: Biome.ABYSS,
|
[Biome.GRAVEYARD]: Biome.ABYSS,
|
||||||
[Biome.DOJO]: [ Biome.PLAINS, [ Biome.JUNGLE, 2], [ Biome.TEMPLE, 2 ] ],
|
[Biome.DOJO]: [ Biome.PLAINS, [ Biome.TEMPLE, 3 ] ],
|
||||||
[Biome.FACTORY]: [ Biome.TALL_GRASS, [ Biome.LABORATORY, 3 ] ],
|
[Biome.FACTORY]: [ Biome.PLAINS, [ Biome.LABORATORY, 4 ] ],
|
||||||
[Biome.RUINS]: [ Biome.FOREST ],
|
[Biome.RUINS]: [ Biome.FOREST ],
|
||||||
[Biome.WASTELAND]: Biome.BADLANDS,
|
[Biome.WASTELAND]: Biome.BADLANDS,
|
||||||
[Biome.ABYSS]: [ Biome.CAVE, [ Biome.SPACE, 3 ], [ Biome.WASTELAND, 3 ] ],
|
[Biome.ABYSS]: [ Biome.CAVE, [ Biome.SPACE, 3 ], [ Biome.WASTELAND, 3 ] ],
|
||||||
[Biome.SPACE]: Biome.RUINS,
|
[Biome.SPACE]: Biome.RUINS,
|
||||||
[Biome.CONSTRUCTION_SITE]: [ Biome.POWER_PLANT, [ Biome.DOJO, 2 ] ],
|
[Biome.CONSTRUCTION_SITE]: [ Biome.DOJO, Biome.POWER_PLANT ],
|
||||||
[Biome.JUNGLE]: [ Biome.TEMPLE ],
|
[Biome.JUNGLE]: [ Biome.TEMPLE ],
|
||||||
[Biome.FAIRY_CAVE]: [ Biome.ICE_CAVE, [ Biome.SPACE, 2 ] ],
|
[Biome.FAIRY_CAVE]: [ Biome.ICE_CAVE, [ Biome.SPACE, 3 ] ],
|
||||||
[Biome.TEMPLE]: [ Biome.DESERT, [ Biome.SWAMP, 2 ], [ Biome.RUINS, 2 ] ],
|
[Biome.TEMPLE]: [ Biome.SWAMP, [ Biome.RUINS, 3 ] ],
|
||||||
[Biome.METROPOLIS]: Biome.SLUM,
|
[Biome.METROPOLIS]: Biome.SLUM,
|
||||||
[Biome.SNOWY_FOREST]: [ Biome.FOREST, Biome.MOUNTAIN, [ Biome.LAKE, 2 ] ],
|
[Biome.SNOWY_FOREST]: [ Biome.FOREST, Biome.LAKE, Biome.MOUNTAIN ],
|
||||||
[Biome.ISLAND]: Biome.SEA,
|
[Biome.ISLAND]: Biome.SEA,
|
||||||
[Biome.LABORATORY]: Biome.CONSTRUCTION_SITE
|
[Biome.LABORATORY]: Biome.CONSTRUCTION_SITE
|
||||||
};
|
};
|
||||||
@ -7663,12 +7663,6 @@ export function initBiomes() {
|
|||||||
biomeDepths[Biome.TOWN] = [ 0, 1 ];
|
biomeDepths[Biome.TOWN] = [ 0, 1 ];
|
||||||
|
|
||||||
const traverseBiome = (biome: Biome, depth: integer) => {
|
const traverseBiome = (biome: Biome, depth: integer) => {
|
||||||
if (biome === Biome.END) {
|
|
||||||
const biomeList = Object.keys(Biome).filter(key => !isNaN(Number(key)));
|
|
||||||
biomeList.pop(); // Removes Biome.END from the list
|
|
||||||
const randIndex = Utils.randInt(biomeList.length, 2); // Will never be Biome.TOWN or Biome.PLAINS
|
|
||||||
biome = Biome[biomeList[randIndex]];
|
|
||||||
}
|
|
||||||
const linkedBiomes: (Biome | [ Biome, integer ])[] = Array.isArray(biomeLinks[biome])
|
const linkedBiomes: (Biome | [ Biome, integer ])[] = Array.isArray(biomeLinks[biome])
|
||||||
? biomeLinks[biome] as (Biome | [ Biome, integer ])[]
|
? biomeLinks[biome] as (Biome | [ Biome, integer ])[]
|
||||||
: [ biomeLinks[biome] as Biome ];
|
: [ biomeLinks[biome] as Biome ];
|
||||||
|
@ -55,11 +55,6 @@ export enum ChallengeType {
|
|||||||
* @see {@link Challenge.applyFixedBattle}
|
* @see {@link Challenge.applyFixedBattle}
|
||||||
*/
|
*/
|
||||||
FIXED_BATTLES,
|
FIXED_BATTLES,
|
||||||
/**
|
|
||||||
* Modifies the effectiveness of Type matchups in battle
|
|
||||||
* @see {@linkcode Challenge.applyTypeEffectiveness}
|
|
||||||
*/
|
|
||||||
TYPE_EFFECTIVENESS,
|
|
||||||
/**
|
/**
|
||||||
* Modifies what level the AI pokemon are. UNIMPLEMENTED.
|
* Modifies what level the AI pokemon are. UNIMPLEMENTED.
|
||||||
*/
|
*/
|
||||||
@ -332,15 +327,6 @@ export abstract class Challenge {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* An apply function for TYPE_EFFECTIVENESS challenges. Derived classes should alter this.
|
|
||||||
* @param effectiveness {@linkcode Utils.NumberHolder} The current effectiveness of the move.
|
|
||||||
* @returns Whether this function did anything.
|
|
||||||
*/
|
|
||||||
applyTypeEffectiveness(effectiveness: Utils.NumberHolder): boolean {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An apply function for AI_LEVEL challenges. Derived classes should alter this.
|
* An apply function for AI_LEVEL challenges. Derived classes should alter this.
|
||||||
* @param level {@link Utils.IntegerHolder} The generated level.
|
* @param level {@link Utils.IntegerHolder} The generated level.
|
||||||
@ -665,7 +651,10 @@ export class FreshStartChallenge extends Challenge {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
override getDifficulty(): number {
|
/**
|
||||||
|
* @overrides
|
||||||
|
*/
|
||||||
|
getDifficulty(): number {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -677,38 +666,6 @@ export class FreshStartChallenge extends Challenge {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements an inverse battle challenge.
|
|
||||||
*/
|
|
||||||
export class InverseBattleChallenge extends Challenge {
|
|
||||||
constructor() {
|
|
||||||
super(Challenges.INVERSE_BATTLE, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static loadChallenge(source: InverseBattleChallenge | any): InverseBattleChallenge {
|
|
||||||
const newChallenge = new InverseBattleChallenge();
|
|
||||||
newChallenge.value = source.value;
|
|
||||||
newChallenge.severity = source.severity;
|
|
||||||
return newChallenge;
|
|
||||||
}
|
|
||||||
|
|
||||||
override getDifficulty(): number {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
applyTypeEffectiveness(effectiveness: Utils.NumberHolder): boolean {
|
|
||||||
if (effectiveness.value < 1) {
|
|
||||||
effectiveness.value = 2;
|
|
||||||
return true;
|
|
||||||
} else if (effectiveness.value > 1) {
|
|
||||||
effectiveness.value = 0.5;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lowers the amount of starter points available.
|
* Lowers the amount of starter points available.
|
||||||
*/
|
*/
|
||||||
@ -828,14 +785,6 @@ export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType
|
|||||||
* @returns True if any challenge was successfully applied.
|
* @returns True if any challenge was successfully applied.
|
||||||
*/
|
*/
|
||||||
export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType.FIXED_BATTLES, waveIndex: Number, battleConfig: FixedBattleConfig): boolean;
|
export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType.FIXED_BATTLES, waveIndex: Number, battleConfig: FixedBattleConfig): boolean;
|
||||||
/**
|
|
||||||
* Apply all challenges that modify type effectiveness.
|
|
||||||
* @param gameMode {@linkcode GameMode} The current gameMode
|
|
||||||
* @param challengeType {@linkcode ChallengeType} ChallengeType.TYPE_EFFECTIVENESS
|
|
||||||
* @param effectiveness {@linkcode Utils.NumberHolder} The current effectiveness of the move.
|
|
||||||
* @returns True if any challenge was successfully applied.
|
|
||||||
*/
|
|
||||||
export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType.TYPE_EFFECTIVENESS, effectiveness: Utils.NumberHolder): boolean;
|
|
||||||
/**
|
/**
|
||||||
* Apply all challenges that modify what level AI are.
|
* Apply all challenges that modify what level AI are.
|
||||||
* @param gameMode {@link GameMode} The current gameMode
|
* @param gameMode {@link GameMode} The current gameMode
|
||||||
@ -917,9 +866,6 @@ export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType
|
|||||||
case ChallengeType.FIXED_BATTLES:
|
case ChallengeType.FIXED_BATTLES:
|
||||||
ret ||= c.applyFixedBattle(args[0], args[1]);
|
ret ||= c.applyFixedBattle(args[0], args[1]);
|
||||||
break;
|
break;
|
||||||
case ChallengeType.TYPE_EFFECTIVENESS:
|
|
||||||
ret ||= c.applyTypeEffectiveness(args[0]);
|
|
||||||
break;
|
|
||||||
case ChallengeType.AI_LEVEL:
|
case ChallengeType.AI_LEVEL:
|
||||||
ret ||= c.applyLevelChange(args[0], args[1], args[2], args[3]);
|
ret ||= c.applyLevelChange(args[0], args[1], args[2], args[3]);
|
||||||
break;
|
break;
|
||||||
@ -961,8 +907,6 @@ export function copyChallenge(source: Challenge | any): Challenge {
|
|||||||
return LowerStarterPointsChallenge.loadChallenge(source);
|
return LowerStarterPointsChallenge.loadChallenge(source);
|
||||||
case Challenges.FRESH_START:
|
case Challenges.FRESH_START:
|
||||||
return FreshStartChallenge.loadChallenge(source);
|
return FreshStartChallenge.loadChallenge(source);
|
||||||
case Challenges.INVERSE_BATTLE:
|
|
||||||
return InverseBattleChallenge.loadChallenge(source);
|
|
||||||
}
|
}
|
||||||
throw new Error("Unknown challenge copied");
|
throw new Error("Unknown challenge copied");
|
||||||
}
|
}
|
||||||
@ -974,6 +918,5 @@ export function initChallenges() {
|
|||||||
new SingleGenerationChallenge(),
|
new SingleGenerationChallenge(),
|
||||||
new SingleTypeChallenge(),
|
new SingleTypeChallenge(),
|
||||||
new FreshStartChallenge(),
|
new FreshStartChallenge(),
|
||||||
new InverseBattleChallenge(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ export const speciesEggMoves = {
|
|||||||
[Species.SHELLDER]: [ Moves.ROCK_BLAST, Moves.WATER_SHURIKEN, Moves.BANEFUL_BUNKER, Moves.BONE_RUSH ],
|
[Species.SHELLDER]: [ Moves.ROCK_BLAST, Moves.WATER_SHURIKEN, Moves.BANEFUL_BUNKER, Moves.BONE_RUSH ],
|
||||||
[Species.GASTLY]: [ Moves.SLUDGE_BOMB, Moves.AURA_SPHERE, Moves.NASTY_PLOT, Moves.ASTRAL_BARRAGE ],
|
[Species.GASTLY]: [ Moves.SLUDGE_BOMB, Moves.AURA_SPHERE, Moves.NASTY_PLOT, Moves.ASTRAL_BARRAGE ],
|
||||||
[Species.ONIX]: [ Moves.SHORE_UP, Moves.BODY_PRESS, Moves.HEAVY_SLAM, Moves.DIAMOND_STORM ],
|
[Species.ONIX]: [ Moves.SHORE_UP, Moves.BODY_PRESS, Moves.HEAVY_SLAM, Moves.DIAMOND_STORM ],
|
||||||
[Species.DROWZEE]: [ Moves.BADDY_BAD, Moves.STRENGTH_SAP, Moves.LUMINA_CRASH, Moves.DARK_VOID ],
|
[Species.DROWZEE]: [ Moves.BADDY_BAD, Moves.STRENGTH_SAP, Moves.LUMINA_CRASH, Moves.SPORE ],
|
||||||
[Species.KRABBY]: [ Moves.FIRE_LASH, Moves.PLAY_ROUGH, Moves.IVY_CUDGEL, Moves.SHELL_SMASH ],
|
[Species.KRABBY]: [ Moves.FIRE_LASH, Moves.PLAY_ROUGH, Moves.IVY_CUDGEL, Moves.SHELL_SMASH ],
|
||||||
[Species.VOLTORB]: [ Moves.NASTY_PLOT, Moves.OVERHEAT, Moves.FROST_BREATH, Moves.ELECTRO_DRIFT ],
|
[Species.VOLTORB]: [ Moves.NASTY_PLOT, Moves.OVERHEAT, Moves.FROST_BREATH, Moves.ELECTRO_DRIFT ],
|
||||||
[Species.EXEGGCUTE]: [ Moves.FICKLE_BEAM, Moves.APPLE_ACID, Moves.TRICK_ROOM, Moves.LUMINA_CRASH ],
|
[Species.EXEGGCUTE]: [ Moves.FICKLE_BEAM, Moves.APPLE_ACID, Moves.TRICK_ROOM, Moves.LUMINA_CRASH ],
|
||||||
@ -125,7 +125,7 @@ export const speciesEggMoves = {
|
|||||||
[Species.SUICUNE]: [ Moves.RECOVER, Moves.NASTY_PLOT, Moves.FREEZE_DRY, Moves.STEAM_ERUPTION ],
|
[Species.SUICUNE]: [ Moves.RECOVER, Moves.NASTY_PLOT, Moves.FREEZE_DRY, Moves.STEAM_ERUPTION ],
|
||||||
[Species.LARVITAR]: [ Moves.DRAGON_DANCE, Moves.MOUNTAIN_GALE, Moves.SHORE_UP, Moves.DIAMOND_STORM ],
|
[Species.LARVITAR]: [ Moves.DRAGON_DANCE, Moves.MOUNTAIN_GALE, Moves.SHORE_UP, Moves.DIAMOND_STORM ],
|
||||||
[Species.LUGIA]: [ Moves.NASTY_PLOT, Moves.LUMINA_CRASH, Moves.AURA_SPHERE, Moves.OBLIVION_WING ],
|
[Species.LUGIA]: [ Moves.NASTY_PLOT, Moves.LUMINA_CRASH, Moves.AURA_SPHERE, Moves.OBLIVION_WING ],
|
||||||
[Species.HO_OH]: [ Moves.FLOATY_FALL, Moves.PRECIPICE_BLADES, Moves.REVIVAL_BLESSING, Moves.BOLT_BEAK ],
|
[Species.HO_OH]: [ Moves.FLOATY_FALL, Moves.SOLAR_BLADE, Moves.REVIVAL_BLESSING, Moves.BOLT_BEAK ],
|
||||||
[Species.CELEBI]: [ Moves.PHOTON_GEYSER, Moves.MATCHA_GOTCHA, Moves.REVIVAL_BLESSING, Moves.QUIVER_DANCE ],
|
[Species.CELEBI]: [ Moves.PHOTON_GEYSER, Moves.MATCHA_GOTCHA, Moves.REVIVAL_BLESSING, Moves.QUIVER_DANCE ],
|
||||||
[Species.TREECKO]: [ Moves.NASTY_PLOT, Moves.APPLE_ACID, Moves.SECRET_SWORD, Moves.DRAGON_ENERGY ],
|
[Species.TREECKO]: [ Moves.NASTY_PLOT, Moves.APPLE_ACID, Moves.SECRET_SWORD, Moves.DRAGON_ENERGY ],
|
||||||
[Species.TORCHIC]: [ Moves.HIGH_JUMP_KICK, Moves.SUPERCELL_SLAM, Moves.KNOCK_OFF, Moves.V_CREATE ],
|
[Species.TORCHIC]: [ Moves.HIGH_JUMP_KICK, Moves.SUPERCELL_SLAM, Moves.KNOCK_OFF, Moves.V_CREATE ],
|
||||||
@ -249,7 +249,7 @@ export const speciesEggMoves = {
|
|||||||
[Species.CRESSELIA]: [ Moves.COSMIC_POWER, Moves.SECRET_SWORD, Moves.SIZZLY_SLIDE, Moves.LUMINA_CRASH ],
|
[Species.CRESSELIA]: [ Moves.COSMIC_POWER, Moves.SECRET_SWORD, Moves.SIZZLY_SLIDE, Moves.LUMINA_CRASH ],
|
||||||
[Species.PHIONE]: [ Moves.BOUNCY_BUBBLE, Moves.FREEZE_DRY, Moves.SPLISHY_SPLASH, Moves.QUIVER_DANCE ],
|
[Species.PHIONE]: [ Moves.BOUNCY_BUBBLE, Moves.FREEZE_DRY, Moves.SPLISHY_SPLASH, Moves.QUIVER_DANCE ],
|
||||||
[Species.MANAPHY]: [ Moves.BOUNCY_BUBBLE, Moves.FREEZE_DRY, Moves.SPLISHY_SPLASH, Moves.QUIVER_DANCE ],
|
[Species.MANAPHY]: [ Moves.BOUNCY_BUBBLE, Moves.FREEZE_DRY, Moves.SPLISHY_SPLASH, Moves.QUIVER_DANCE ],
|
||||||
[Species.DARKRAI]: [ Moves.FIERY_WRATH, Moves.MOONBLAST, Moves.FIERY_DANCE, Moves.MAKE_IT_RAIN ],
|
[Species.DARKRAI]: [ Moves.FIERY_WRATH, Moves.MOONBLAST, Moves.SEARING_SHOT, Moves.SPORE ],
|
||||||
[Species.SHAYMIN]: [ Moves.MATCHA_GOTCHA, Moves.FIERY_DANCE, Moves.AEROBLAST, Moves.QUIVER_DANCE ],
|
[Species.SHAYMIN]: [ Moves.MATCHA_GOTCHA, Moves.FIERY_DANCE, Moves.AEROBLAST, Moves.QUIVER_DANCE ],
|
||||||
[Species.ARCEUS]: [ Moves.NO_RETREAT, Moves.COLLISION_COURSE, Moves.ASTRAL_BARRAGE, Moves.MULTI_ATTACK ],
|
[Species.ARCEUS]: [ Moves.NO_RETREAT, Moves.COLLISION_COURSE, Moves.ASTRAL_BARRAGE, Moves.MULTI_ATTACK ],
|
||||||
[Species.VICTINI]: [ Moves.BLUE_FLARE, Moves.BOLT_STRIKE, Moves.LUSTER_PURGE, Moves.VICTORY_DANCE ],
|
[Species.VICTINI]: [ Moves.BLUE_FLARE, Moves.BOLT_STRIKE, Moves.LUSTER_PURGE, Moves.VICTORY_DANCE ],
|
||||||
|
@ -4,7 +4,7 @@ import { EncoreTag, GulpMissileTag, HelpingHandTag, SemiInvulnerableTag, ShellTr
|
|||||||
import { getPokemonNameWithAffix } from "../messages";
|
import { getPokemonNameWithAffix } from "../messages";
|
||||||
import Pokemon, { AttackMoveResult, EnemyPokemon, HitResult, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "../field/pokemon";
|
import Pokemon, { AttackMoveResult, EnemyPokemon, HitResult, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "../field/pokemon";
|
||||||
import { StatusEffect, getStatusEffectHealText, isNonVolatileStatusEffect, getNonVolatileStatusEffects } from "./status-effect";
|
import { StatusEffect, getStatusEffectHealText, isNonVolatileStatusEffect, getNonVolatileStatusEffects } from "./status-effect";
|
||||||
import { getTypeDamageMultiplier, Type } from "./type";
|
import { getTypeResistances, Type } from "./type";
|
||||||
import { Constructor } from "#app/utils";
|
import { Constructor } from "#app/utils";
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import { WeatherType } from "./weather";
|
import { WeatherType } from "./weather";
|
||||||
@ -35,11 +35,8 @@ import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
|
|||||||
import { StatChangePhase } from "#app/phases/stat-change-phase";
|
import { StatChangePhase } from "#app/phases/stat-change-phase";
|
||||||
import { SwitchPhase } from "#app/phases/switch-phase";
|
import { SwitchPhase } from "#app/phases/switch-phase";
|
||||||
import { SwitchSummonPhase } from "#app/phases/switch-summon-phase";
|
import { SwitchSummonPhase } from "#app/phases/switch-summon-phase";
|
||||||
import { ShowAbilityPhase } from "#app/phases/show-ability-phase";
|
|
||||||
import { SpeciesFormChangeRevertWeatherFormTrigger } from "./pokemon-forms";
|
import { SpeciesFormChangeRevertWeatherFormTrigger } from "./pokemon-forms";
|
||||||
import { NumberHolder } from "#app/utils";
|
import { ShowAbilityPhase } from "#app/phases/show-ability-phase.js";
|
||||||
import { GameMode } from "#app/game-mode";
|
|
||||||
import { applyChallenges, ChallengeType } from "./challenge";
|
|
||||||
|
|
||||||
export enum MoveCategory {
|
export enum MoveCategory {
|
||||||
PHYSICAL,
|
PHYSICAL,
|
||||||
@ -4197,13 +4194,9 @@ export class WaterSuperEffectTypeMultiplierAttr extends VariableMoveTypeMultipli
|
|||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
const multiplier = args[0] as Utils.NumberHolder;
|
const multiplier = args[0] as Utils.NumberHolder;
|
||||||
if (target.isOfType(Type.WATER)) {
|
if (target.isOfType(Type.WATER)) {
|
||||||
const effectivenessAgainstWater = new Utils.NumberHolder(getTypeDamageMultiplier(move.type, Type.WATER));
|
multiplier.value *= 4; // Increased twice because initial reduction against water
|
||||||
applyChallenges(user.scene.gameMode, ChallengeType.TYPE_EFFECTIVENESS, effectivenessAgainstWater);
|
|
||||||
if (effectivenessAgainstWater.value !== 0) {
|
|
||||||
multiplier.value *= 2 / effectivenessAgainstWater.value;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -6224,7 +6217,7 @@ export class ResistLastMoveTypeAttr extends MoveEffectAttr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const userTypes = user.getTypes();
|
const userTypes = user.getTypes();
|
||||||
const validTypes = this.getTypeResistances(user.scene.gameMode, moveData.type).filter(t => !userTypes.includes(t)); // valid types are ones that are not already the user's types
|
const validTypes = getTypeResistances(moveData.type).filter(t => !userTypes.includes(t)); // valid types are ones that are not already the user's types
|
||||||
if (!validTypes.length) {
|
if (!validTypes.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -6236,25 +6229,6 @@ export class ResistLastMoveTypeAttr extends MoveEffectAttr {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the types resisting a given type. Used by Conversion 2
|
|
||||||
* @returns An array populated with Types, or an empty array if no resistances exist (Unknown or Stellar type)
|
|
||||||
*/
|
|
||||||
getTypeResistances(gameMode: GameMode, type: number): Type[] {
|
|
||||||
const typeResistances: Type[] = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < Object.keys(Type).length; i++) {
|
|
||||||
const multiplier = new NumberHolder(1);
|
|
||||||
multiplier.value = getTypeDamageMultiplier(type, i);
|
|
||||||
applyChallenges(gameMode, ChallengeType.TYPE_EFFECTIVENESS, multiplier);
|
|
||||||
if (multiplier.value < 1) {
|
|
||||||
typeResistances.push(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return typeResistances;
|
|
||||||
}
|
|
||||||
|
|
||||||
getCondition(): MoveConditionFunc {
|
getCondition(): MoveConditionFunc {
|
||||||
return (user, target, move) => {
|
return (user, target, move) => {
|
||||||
const moveHistory = target.getLastXMoves();
|
const moveHistory = target.getLastXMoves();
|
||||||
@ -7980,8 +7954,7 @@ export function initMoves() {
|
|||||||
.target(MoveTarget.ALL_NEAR_OTHERS),
|
.target(MoveTarget.ALL_NEAR_OTHERS),
|
||||||
new AttackMove(Moves.FREEZE_DRY, Type.ICE, MoveCategory.SPECIAL, 70, 100, 20, 10, 0, 6)
|
new AttackMove(Moves.FREEZE_DRY, Type.ICE, MoveCategory.SPECIAL, 70, 100, 20, 10, 0, 6)
|
||||||
.attr(StatusEffectAttr, StatusEffect.FREEZE)
|
.attr(StatusEffectAttr, StatusEffect.FREEZE)
|
||||||
.attr(WaterSuperEffectTypeMultiplierAttr)
|
.attr(WaterSuperEffectTypeMultiplierAttr),
|
||||||
.partial(), // This currently just multiplies the move's power instead of changing its effectiveness. It also doesn't account for abilities that modify type effectiveness such as tera shell.
|
|
||||||
new AttackMove(Moves.DISARMING_VOICE, Type.FAIRY, MoveCategory.SPECIAL, 40, -1, 15, -1, 0, 6)
|
new AttackMove(Moves.DISARMING_VOICE, Type.FAIRY, MoveCategory.SPECIAL, 40, -1, 15, -1, 0, 6)
|
||||||
.soundBased()
|
.soundBased()
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
|
@ -1132,7 +1132,7 @@ export function initSpecies() {
|
|||||||
),
|
),
|
||||||
new PokemonSpecies(Species.SNORLAX, 1, false, false, false, "Sleeping Pokémon", Type.NORMAL, null, 2.1, 460, Abilities.IMMUNITY, Abilities.THICK_FAT, Abilities.GLUTTONY, 540, 160, 110, 65, 65, 110, 30, 25, 50, 189, GrowthRate.SLOW, 87.5, false, true,
|
new PokemonSpecies(Species.SNORLAX, 1, false, false, false, "Sleeping Pokémon", Type.NORMAL, null, 2.1, 460, Abilities.IMMUNITY, Abilities.THICK_FAT, Abilities.GLUTTONY, 540, 160, 110, 65, 65, 110, 30, 25, 50, 189, GrowthRate.SLOW, 87.5, false, true,
|
||||||
new PokemonForm("Normal", "", Type.NORMAL, null, 2.1, 460, Abilities.IMMUNITY, Abilities.THICK_FAT, Abilities.GLUTTONY, 540, 160, 110, 65, 65, 110, 30, 25, 50, 189, false, null, true),
|
new PokemonForm("Normal", "", Type.NORMAL, null, 2.1, 460, Abilities.IMMUNITY, Abilities.THICK_FAT, Abilities.GLUTTONY, 540, 160, 110, 65, 65, 110, 30, 25, 50, 189, false, null, true),
|
||||||
new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.NORMAL, null, 35, 460, Abilities.THICK_FAT, Abilities.THICK_FAT, Abilities.THICK_FAT, 640, 200, 135, 85, 80, 125, 15, 25, 50, 189),
|
new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.NORMAL, Type.GRASS, 35, 460, Abilities.THICK_FAT, Abilities.THICK_FAT, Abilities.THICK_FAT, 640, 200, 135, 85, 80, 125, 15, 25, 50, 189),
|
||||||
),
|
),
|
||||||
new PokemonSpecies(Species.ARTICUNO, 1, true, false, false, "Freeze Pokémon", Type.ICE, Type.FLYING, 1.7, 55.4, Abilities.PRESSURE, Abilities.NONE, Abilities.SNOW_CLOAK, 580, 90, 85, 100, 95, 125, 85, 3, 35, 290, GrowthRate.SLOW, null, false),
|
new PokemonSpecies(Species.ARTICUNO, 1, true, false, false, "Freeze Pokémon", Type.ICE, Type.FLYING, 1.7, 55.4, Abilities.PRESSURE, Abilities.NONE, Abilities.SNOW_CLOAK, 580, 90, 85, 100, 95, 125, 85, 3, 35, 290, GrowthRate.SLOW, null, false),
|
||||||
new PokemonSpecies(Species.ZAPDOS, 1, true, false, false, "Electric Pokémon", Type.ELECTRIC, Type.FLYING, 1.6, 52.6, Abilities.PRESSURE, Abilities.NONE, Abilities.STATIC, 580, 90, 90, 85, 125, 90, 100, 3, 35, 290, GrowthRate.SLOW, null, false),
|
new PokemonSpecies(Species.ZAPDOS, 1, true, false, false, "Electric Pokémon", Type.ELECTRIC, Type.FLYING, 1.6, 52.6, Abilities.PRESSURE, Abilities.NONE, Abilities.STATIC, 580, 90, 90, 85, 125, 90, 100, 3, 35, 290, GrowthRate.SLOW, null, false),
|
||||||
@ -2252,19 +2252,19 @@ export function initSpecies() {
|
|||||||
new PokemonSpecies(Species.THWACKEY, 8, false, false, false, "Beat Pokémon", Type.GRASS, null, 0.7, 14, Abilities.OVERGROW, Abilities.NONE, Abilities.GRASSY_SURGE, 420, 70, 85, 70, 55, 60, 80, 45, 50, 147, GrowthRate.MEDIUM_SLOW, 87.5, false),
|
new PokemonSpecies(Species.THWACKEY, 8, false, false, false, "Beat Pokémon", Type.GRASS, null, 0.7, 14, Abilities.OVERGROW, Abilities.NONE, Abilities.GRASSY_SURGE, 420, 70, 85, 70, 55, 60, 80, 45, 50, 147, GrowthRate.MEDIUM_SLOW, 87.5, false),
|
||||||
new PokemonSpecies(Species.RILLABOOM, 8, false, false, false, "Drummer Pokémon", Type.GRASS, null, 2.1, 90, Abilities.OVERGROW, Abilities.NONE, Abilities.GRASSY_SURGE, 530, 100, 125, 90, 60, 70, 85, 45, 50, 265, GrowthRate.MEDIUM_SLOW, 87.5, false, true,
|
new PokemonSpecies(Species.RILLABOOM, 8, false, false, false, "Drummer Pokémon", Type.GRASS, null, 2.1, 90, Abilities.OVERGROW, Abilities.NONE, Abilities.GRASSY_SURGE, 530, 100, 125, 90, 60, 70, 85, 45, 50, 265, GrowthRate.MEDIUM_SLOW, 87.5, false, true,
|
||||||
new PokemonForm("Normal", "", Type.GRASS, null, 2.1, 90, Abilities.OVERGROW, Abilities.NONE, Abilities.GRASSY_SURGE, 530, 100, 125, 90, 60, 70, 85, 45, 50, 265, false, null, true),
|
new PokemonForm("Normal", "", Type.GRASS, null, 2.1, 90, Abilities.OVERGROW, Abilities.NONE, Abilities.GRASSY_SURGE, 530, 100, 125, 90, 60, 70, 85, 45, 50, 265, false, null, true),
|
||||||
new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.GRASS, null, 28, 90, Abilities.GRASSY_SURGE, Abilities.GRASSY_SURGE, Abilities.GRASSY_SURGE, 630, 125, 150, 105, 85, 85, 80, 45, 50, 265),
|
new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.GRASS, null, 28, 90, Abilities.GRASSY_SURGE, Abilities.GRASSY_SURGE, Abilities.GRASSY_SURGE, 630, 125, 150, 115, 65, 95, 80, 45, 50, 265),
|
||||||
),
|
),
|
||||||
new PokemonSpecies(Species.SCORBUNNY, 8, false, false, false, "Rabbit Pokémon", Type.FIRE, null, 0.3, 4.5, Abilities.BLAZE, Abilities.NONE, Abilities.LIBERO, 310, 50, 71, 40, 40, 40, 69, 45, 50, 62, GrowthRate.MEDIUM_SLOW, 87.5, false),
|
new PokemonSpecies(Species.SCORBUNNY, 8, false, false, false, "Rabbit Pokémon", Type.FIRE, null, 0.3, 4.5, Abilities.BLAZE, Abilities.NONE, Abilities.LIBERO, 310, 50, 71, 40, 40, 40, 69, 45, 50, 62, GrowthRate.MEDIUM_SLOW, 87.5, false),
|
||||||
new PokemonSpecies(Species.RABOOT, 8, false, false, false, "Rabbit Pokémon", Type.FIRE, null, 0.6, 9, Abilities.BLAZE, Abilities.NONE, Abilities.LIBERO, 420, 65, 86, 60, 55, 60, 94, 45, 50, 147, GrowthRate.MEDIUM_SLOW, 87.5, false),
|
new PokemonSpecies(Species.RABOOT, 8, false, false, false, "Rabbit Pokémon", Type.FIRE, null, 0.6, 9, Abilities.BLAZE, Abilities.NONE, Abilities.LIBERO, 420, 65, 86, 60, 55, 60, 94, 45, 50, 147, GrowthRate.MEDIUM_SLOW, 87.5, false),
|
||||||
new PokemonSpecies(Species.CINDERACE, 8, false, false, false, "Striker Pokémon", Type.FIRE, null, 1.4, 33, Abilities.BLAZE, Abilities.NONE, Abilities.LIBERO, 530, 80, 116, 75, 65, 75, 119, 45, 50, 265, GrowthRate.MEDIUM_SLOW, 87.5, false, true,
|
new PokemonSpecies(Species.CINDERACE, 8, false, false, false, "Striker Pokémon", Type.FIRE, null, 1.4, 33, Abilities.BLAZE, Abilities.NONE, Abilities.LIBERO, 530, 80, 116, 75, 65, 75, 119, 45, 50, 265, GrowthRate.MEDIUM_SLOW, 87.5, false, true,
|
||||||
new PokemonForm("Normal", "", Type.FIRE, null, 1.4, 33, Abilities.BLAZE, Abilities.NONE, Abilities.LIBERO, 530, 80, 116, 75, 65, 75, 119, 45, 50, 265, false, null, true),
|
new PokemonForm("Normal", "", Type.FIRE, null, 1.4, 33, Abilities.BLAZE, Abilities.NONE, Abilities.LIBERO, 530, 80, 116, 75, 65, 75, 119, 45, 50, 265, false, null, true),
|
||||||
new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.FIRE, null, 27, 33, Abilities.LIBERO, Abilities.LIBERO, Abilities.LIBERO, 630, 100, 146, 80, 90, 80, 134, 45, 50, 265),
|
new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.FIRE, null, 27, 33, Abilities.LIBERO, Abilities.LIBERO, Abilities.LIBERO, 630, 90, 151, 85, 85, 85, 134, 45, 50, 265),
|
||||||
),
|
),
|
||||||
new PokemonSpecies(Species.SOBBLE, 8, false, false, false, "Water Lizard Pokémon", Type.WATER, null, 0.3, 4, Abilities.TORRENT, Abilities.NONE, Abilities.SNIPER, 310, 50, 40, 40, 70, 40, 70, 45, 50, 62, GrowthRate.MEDIUM_SLOW, 87.5, false),
|
new PokemonSpecies(Species.SOBBLE, 8, false, false, false, "Water Lizard Pokémon", Type.WATER, null, 0.3, 4, Abilities.TORRENT, Abilities.NONE, Abilities.SNIPER, 310, 50, 40, 40, 70, 40, 70, 45, 50, 62, GrowthRate.MEDIUM_SLOW, 87.5, false),
|
||||||
new PokemonSpecies(Species.DRIZZILE, 8, false, false, false, "Water Lizard Pokémon", Type.WATER, null, 0.7, 11.5, Abilities.TORRENT, Abilities.NONE, Abilities.SNIPER, 420, 65, 60, 55, 95, 55, 90, 45, 50, 147, GrowthRate.MEDIUM_SLOW, 87.5, false),
|
new PokemonSpecies(Species.DRIZZILE, 8, false, false, false, "Water Lizard Pokémon", Type.WATER, null, 0.7, 11.5, Abilities.TORRENT, Abilities.NONE, Abilities.SNIPER, 420, 65, 60, 55, 95, 55, 90, 45, 50, 147, GrowthRate.MEDIUM_SLOW, 87.5, false),
|
||||||
new PokemonSpecies(Species.INTELEON, 8, false, false, false, "Secret Agent Pokémon", Type.WATER, null, 1.9, 45.2, Abilities.TORRENT, Abilities.NONE, Abilities.SNIPER, 530, 70, 85, 65, 125, 65, 120, 45, 50, 265, GrowthRate.MEDIUM_SLOW, 87.5, false, true,
|
new PokemonSpecies(Species.INTELEON, 8, false, false, false, "Secret Agent Pokémon", Type.WATER, null, 1.9, 45.2, Abilities.TORRENT, Abilities.NONE, Abilities.SNIPER, 530, 70, 85, 65, 125, 65, 120, 45, 50, 265, GrowthRate.MEDIUM_SLOW, 87.5, false, true,
|
||||||
new PokemonForm("Normal", "", Type.WATER, null, 1.9, 45.2, Abilities.TORRENT, Abilities.NONE, Abilities.SNIPER, 530, 70, 85, 65, 125, 65, 120, 45, 50, 265, false, null, true),
|
new PokemonForm("Normal", "", Type.WATER, null, 1.9, 45.2, Abilities.TORRENT, Abilities.NONE, Abilities.SNIPER, 530, 70, 85, 65, 125, 65, 120, 45, 50, 265, false, null, true),
|
||||||
new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.WATER, null, 40, 45.2, Abilities.SNIPER, Abilities.SNIPER, Abilities.SNIPER, 630, 95, 97, 77, 147, 77, 137, 45, 50, 265),
|
new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.WATER, null, 40, 45.2, Abilities.SNIPER, Abilities.SNIPER, Abilities.SNIPER, 630, 90, 90, 85, 150, 85, 130, 45, 50, 265),
|
||||||
),
|
),
|
||||||
new PokemonSpecies(Species.SKWOVET, 8, false, false, false, "Cheeky Pokémon", Type.NORMAL, null, 0.3, 2.5, Abilities.CHEEK_POUCH, Abilities.NONE, Abilities.GLUTTONY, 275, 70, 55, 55, 35, 35, 25, 255, 50, 55, GrowthRate.MEDIUM_FAST, 50, false),
|
new PokemonSpecies(Species.SKWOVET, 8, false, false, false, "Cheeky Pokémon", Type.NORMAL, null, 0.3, 2.5, Abilities.CHEEK_POUCH, Abilities.NONE, Abilities.GLUTTONY, 275, 70, 55, 55, 35, 35, 25, 255, 50, 55, GrowthRate.MEDIUM_FAST, 50, false),
|
||||||
new PokemonSpecies(Species.GREEDENT, 8, false, false, false, "Greedy Pokémon", Type.NORMAL, null, 0.6, 6, Abilities.CHEEK_POUCH, Abilities.NONE, Abilities.GLUTTONY, 460, 120, 95, 95, 55, 75, 20, 90, 50, 161, GrowthRate.MEDIUM_FAST, 50, false),
|
new PokemonSpecies(Species.GREEDENT, 8, false, false, false, "Greedy Pokémon", Type.NORMAL, null, 0.6, 6, Abilities.CHEEK_POUCH, Abilities.NONE, Abilities.GLUTTONY, 460, 120, 95, 95, 55, 75, 20, 90, 50, 161, GrowthRate.MEDIUM_FAST, 50, false),
|
||||||
@ -3470,7 +3470,7 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.SUICUNE]: Abilities.UNAWARE,
|
[Species.SUICUNE]: Abilities.UNAWARE,
|
||||||
[Species.LARVITAR]: Abilities.SAND_RUSH,
|
[Species.LARVITAR]: Abilities.SAND_RUSH,
|
||||||
[Species.LUGIA]: Abilities.DELTA_STREAM,
|
[Species.LUGIA]: Abilities.DELTA_STREAM,
|
||||||
[Species.HO_OH]: Abilities.MAGIC_GUARD,
|
[Species.HO_OH]: Abilities.DROUGHT,
|
||||||
[Species.CELEBI]: Abilities.GRASSY_SURGE,
|
[Species.CELEBI]: Abilities.GRASSY_SURGE,
|
||||||
[Species.TREECKO]: Abilities.TINTED_LENS,
|
[Species.TREECKO]: Abilities.TINTED_LENS,
|
||||||
[Species.TORCHIC]: Abilities.RECKLESS,
|
[Species.TORCHIC]: Abilities.RECKLESS,
|
||||||
@ -3591,7 +3591,7 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.HEATRAN]: Abilities.EARTH_EATER,
|
[Species.HEATRAN]: Abilities.EARTH_EATER,
|
||||||
[Species.REGIGIGAS]: Abilities.MINDS_EYE,
|
[Species.REGIGIGAS]: Abilities.MINDS_EYE,
|
||||||
[Species.GIRATINA]: Abilities.SHADOW_SHIELD,
|
[Species.GIRATINA]: Abilities.SHADOW_SHIELD,
|
||||||
[Species.CRESSELIA]: Abilities.SHADOW_SHIELD,
|
[Species.CRESSELIA]: Abilities.UNAWARE,
|
||||||
[Species.PHIONE]: Abilities.SIMPLE,
|
[Species.PHIONE]: Abilities.SIMPLE,
|
||||||
[Species.MANAPHY]: Abilities.PRIMORDIAL_SEA,
|
[Species.MANAPHY]: Abilities.PRIMORDIAL_SEA,
|
||||||
[Species.DARKRAI]: Abilities.UNNERVE,
|
[Species.DARKRAI]: Abilities.UNNERVE,
|
||||||
|
320
src/data/type.ts
320
src/data/type.ts
@ -23,7 +23,7 @@ export enum Type {
|
|||||||
|
|
||||||
export type TypeDamageMultiplier = 0 | 0.125 | 0.25 | 0.5 | 1 | 2 | 4 | 8;
|
export type TypeDamageMultiplier = 0 | 0.125 | 0.25 | 0.5 | 1 | 2 | 4 | 8;
|
||||||
|
|
||||||
export function getTypeDamageMultiplier(attackType: Type, defType: Type): TypeDamageMultiplier {
|
export function getTypeDamageMultiplier(attackType: integer, defType: integer): TypeDamageMultiplier {
|
||||||
if (attackType === Type.UNKNOWN || defType === Type.UNKNOWN) {
|
if (attackType === Type.UNKNOWN || defType === Type.UNKNOWN) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -33,10 +33,26 @@ export function getTypeDamageMultiplier(attackType: Type, defType: Type): TypeDa
|
|||||||
switch (attackType) {
|
switch (attackType) {
|
||||||
case Type.FIGHTING:
|
case Type.FIGHTING:
|
||||||
return 2;
|
return 2;
|
||||||
case Type.GHOST:
|
case Type.NORMAL:
|
||||||
return 0;
|
case Type.FLYING:
|
||||||
default:
|
case Type.POISON:
|
||||||
|
case Type.GROUND:
|
||||||
|
case Type.ROCK:
|
||||||
|
case Type.BUG:
|
||||||
|
case Type.STEEL:
|
||||||
|
case Type.FIRE:
|
||||||
|
case Type.WATER:
|
||||||
|
case Type.GRASS:
|
||||||
|
case Type.ELECTRIC:
|
||||||
|
case Type.PSYCHIC:
|
||||||
|
case Type.ICE:
|
||||||
|
case Type.DRAGON:
|
||||||
|
case Type.DARK:
|
||||||
|
case Type.FAIRY:
|
||||||
return 1;
|
return 1;
|
||||||
|
case Type.GHOST:
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
case Type.FIGHTING:
|
case Type.FIGHTING:
|
||||||
switch (attackType) {
|
switch (attackType) {
|
||||||
@ -44,12 +60,25 @@ export function getTypeDamageMultiplier(attackType: Type, defType: Type): TypeDa
|
|||||||
case Type.PSYCHIC:
|
case Type.PSYCHIC:
|
||||||
case Type.FAIRY:
|
case Type.FAIRY:
|
||||||
return 2;
|
return 2;
|
||||||
|
case Type.NORMAL:
|
||||||
|
case Type.FIGHTING:
|
||||||
|
case Type.POISON:
|
||||||
|
case Type.GROUND:
|
||||||
|
case Type.GHOST:
|
||||||
|
case Type.STEEL:
|
||||||
|
case Type.FIRE:
|
||||||
|
case Type.WATER:
|
||||||
|
case Type.GRASS:
|
||||||
|
case Type.ELECTRIC:
|
||||||
|
case Type.ICE:
|
||||||
|
case Type.DRAGON:
|
||||||
|
return 1;
|
||||||
case Type.ROCK:
|
case Type.ROCK:
|
||||||
case Type.BUG:
|
case Type.BUG:
|
||||||
case Type.DARK:
|
case Type.DARK:
|
||||||
return 0.5;
|
return 0.5;
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
case Type.FLYING:
|
case Type.FLYING:
|
||||||
switch (attackType) {
|
switch (attackType) {
|
||||||
@ -57,20 +86,43 @@ export function getTypeDamageMultiplier(attackType: Type, defType: Type): TypeDa
|
|||||||
case Type.ELECTRIC:
|
case Type.ELECTRIC:
|
||||||
case Type.ICE:
|
case Type.ICE:
|
||||||
return 2;
|
return 2;
|
||||||
|
case Type.NORMAL:
|
||||||
|
case Type.FLYING:
|
||||||
|
case Type.POISON:
|
||||||
|
case Type.GHOST:
|
||||||
|
case Type.STEEL:
|
||||||
|
case Type.FIRE:
|
||||||
|
case Type.WATER:
|
||||||
|
case Type.PSYCHIC:
|
||||||
|
case Type.DRAGON:
|
||||||
|
case Type.DARK:
|
||||||
|
case Type.FAIRY:
|
||||||
|
return 1;
|
||||||
case Type.FIGHTING:
|
case Type.FIGHTING:
|
||||||
case Type.BUG:
|
case Type.BUG:
|
||||||
case Type.GRASS:
|
case Type.GRASS:
|
||||||
return 0.5;
|
return 0.5;
|
||||||
case Type.GROUND:
|
case Type.GROUND:
|
||||||
return 0;
|
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
case Type.POISON:
|
case Type.POISON:
|
||||||
switch (attackType) {
|
switch (attackType) {
|
||||||
case Type.GROUND:
|
case Type.GROUND:
|
||||||
case Type.PSYCHIC:
|
case Type.PSYCHIC:
|
||||||
return 2;
|
return 2;
|
||||||
|
case Type.NORMAL:
|
||||||
|
case Type.FLYING:
|
||||||
|
case Type.ROCK:
|
||||||
|
case Type.GHOST:
|
||||||
|
case Type.STEEL:
|
||||||
|
case Type.FIRE:
|
||||||
|
case Type.WATER:
|
||||||
|
case Type.ELECTRIC:
|
||||||
|
case Type.ICE:
|
||||||
|
case Type.DRAGON:
|
||||||
|
case Type.DARK:
|
||||||
|
return 1;
|
||||||
case Type.FIGHTING:
|
case Type.FIGHTING:
|
||||||
case Type.POISON:
|
case Type.POISON:
|
||||||
case Type.BUG:
|
case Type.BUG:
|
||||||
@ -78,7 +130,7 @@ export function getTypeDamageMultiplier(attackType: Type, defType: Type): TypeDa
|
|||||||
case Type.FAIRY:
|
case Type.FAIRY:
|
||||||
return 0.5;
|
return 0.5;
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
case Type.GROUND:
|
case Type.GROUND:
|
||||||
switch (attackType) {
|
switch (attackType) {
|
||||||
@ -86,13 +138,25 @@ export function getTypeDamageMultiplier(attackType: Type, defType: Type): TypeDa
|
|||||||
case Type.GRASS:
|
case Type.GRASS:
|
||||||
case Type.ICE:
|
case Type.ICE:
|
||||||
return 2;
|
return 2;
|
||||||
|
case Type.NORMAL:
|
||||||
|
case Type.FIGHTING:
|
||||||
|
case Type.FLYING:
|
||||||
|
case Type.GROUND:
|
||||||
|
case Type.BUG:
|
||||||
|
case Type.GHOST:
|
||||||
|
case Type.STEEL:
|
||||||
|
case Type.FIRE:
|
||||||
|
case Type.PSYCHIC:
|
||||||
|
case Type.DRAGON:
|
||||||
|
case Type.DARK:
|
||||||
|
case Type.FAIRY:
|
||||||
|
return 1;
|
||||||
case Type.POISON:
|
case Type.POISON:
|
||||||
case Type.ROCK:
|
case Type.ROCK:
|
||||||
return 0.5;
|
return 0.5;
|
||||||
case Type.ELECTRIC:
|
case Type.ELECTRIC:
|
||||||
return 0;
|
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
case Type.ROCK:
|
case Type.ROCK:
|
||||||
switch (attackType) {
|
switch (attackType) {
|
||||||
@ -102,13 +166,23 @@ export function getTypeDamageMultiplier(attackType: Type, defType: Type): TypeDa
|
|||||||
case Type.WATER:
|
case Type.WATER:
|
||||||
case Type.GRASS:
|
case Type.GRASS:
|
||||||
return 2;
|
return 2;
|
||||||
|
case Type.ROCK:
|
||||||
|
case Type.BUG:
|
||||||
|
case Type.GHOST:
|
||||||
|
case Type.ELECTRIC:
|
||||||
|
case Type.PSYCHIC:
|
||||||
|
case Type.ICE:
|
||||||
|
case Type.DRAGON:
|
||||||
|
case Type.DARK:
|
||||||
|
case Type.FAIRY:
|
||||||
|
return 1;
|
||||||
case Type.NORMAL:
|
case Type.NORMAL:
|
||||||
case Type.FLYING:
|
case Type.FLYING:
|
||||||
case Type.POISON:
|
case Type.POISON:
|
||||||
case Type.FIRE:
|
case Type.FIRE:
|
||||||
return 0.5;
|
return 0.5;
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
case Type.BUG:
|
case Type.BUG:
|
||||||
switch (attackType) {
|
switch (attackType) {
|
||||||
@ -116,26 +190,51 @@ export function getTypeDamageMultiplier(attackType: Type, defType: Type): TypeDa
|
|||||||
case Type.ROCK:
|
case Type.ROCK:
|
||||||
case Type.FIRE:
|
case Type.FIRE:
|
||||||
return 2;
|
return 2;
|
||||||
|
case Type.NORMAL:
|
||||||
|
case Type.POISON:
|
||||||
|
case Type.BUG:
|
||||||
|
case Type.GHOST:
|
||||||
|
case Type.STEEL:
|
||||||
|
case Type.WATER:
|
||||||
|
case Type.ELECTRIC:
|
||||||
|
case Type.PSYCHIC:
|
||||||
|
case Type.ICE:
|
||||||
|
case Type.DRAGON:
|
||||||
|
case Type.DARK:
|
||||||
|
case Type.FAIRY:
|
||||||
|
return 1;
|
||||||
case Type.FIGHTING:
|
case Type.FIGHTING:
|
||||||
case Type.GROUND:
|
case Type.GROUND:
|
||||||
case Type.GRASS:
|
case Type.GRASS:
|
||||||
return 0.5;
|
return 0.5;
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
case Type.GHOST:
|
case Type.GHOST:
|
||||||
switch (attackType) {
|
switch (attackType) {
|
||||||
case Type.GHOST:
|
case Type.GHOST:
|
||||||
case Type.DARK:
|
case Type.DARK:
|
||||||
return 2;
|
return 2;
|
||||||
|
case Type.FLYING:
|
||||||
|
case Type.GROUND:
|
||||||
|
case Type.ROCK:
|
||||||
|
case Type.STEEL:
|
||||||
|
case Type.FIRE:
|
||||||
|
case Type.WATER:
|
||||||
|
case Type.GRASS:
|
||||||
|
case Type.ELECTRIC:
|
||||||
|
case Type.PSYCHIC:
|
||||||
|
case Type.ICE:
|
||||||
|
case Type.DRAGON:
|
||||||
|
case Type.FAIRY:
|
||||||
|
return 1;
|
||||||
case Type.POISON:
|
case Type.POISON:
|
||||||
case Type.BUG:
|
case Type.BUG:
|
||||||
return 0.5;
|
return 0.5;
|
||||||
case Type.NORMAL:
|
case Type.NORMAL:
|
||||||
case Type.FIGHTING:
|
case Type.FIGHTING:
|
||||||
return 0;
|
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
case Type.STEEL:
|
case Type.STEEL:
|
||||||
switch (attackType) {
|
switch (attackType) {
|
||||||
@ -143,6 +242,11 @@ export function getTypeDamageMultiplier(attackType: Type, defType: Type): TypeDa
|
|||||||
case Type.GROUND:
|
case Type.GROUND:
|
||||||
case Type.FIRE:
|
case Type.FIRE:
|
||||||
return 2;
|
return 2;
|
||||||
|
case Type.GHOST:
|
||||||
|
case Type.WATER:
|
||||||
|
case Type.ELECTRIC:
|
||||||
|
case Type.DARK:
|
||||||
|
return 1;
|
||||||
case Type.NORMAL:
|
case Type.NORMAL:
|
||||||
case Type.FLYING:
|
case Type.FLYING:
|
||||||
case Type.ROCK:
|
case Type.ROCK:
|
||||||
@ -155,9 +259,8 @@ export function getTypeDamageMultiplier(attackType: Type, defType: Type): TypeDa
|
|||||||
case Type.FAIRY:
|
case Type.FAIRY:
|
||||||
return 0.5;
|
return 0.5;
|
||||||
case Type.POISON:
|
case Type.POISON:
|
||||||
return 0;
|
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
case Type.FIRE:
|
case Type.FIRE:
|
||||||
switch (attackType) {
|
switch (attackType) {
|
||||||
@ -165,6 +268,16 @@ export function getTypeDamageMultiplier(attackType: Type, defType: Type): TypeDa
|
|||||||
case Type.ROCK:
|
case Type.ROCK:
|
||||||
case Type.WATER:
|
case Type.WATER:
|
||||||
return 2;
|
return 2;
|
||||||
|
case Type.NORMAL:
|
||||||
|
case Type.FIGHTING:
|
||||||
|
case Type.FLYING:
|
||||||
|
case Type.POISON:
|
||||||
|
case Type.GHOST:
|
||||||
|
case Type.ELECTRIC:
|
||||||
|
case Type.PSYCHIC:
|
||||||
|
case Type.DRAGON:
|
||||||
|
case Type.DARK:
|
||||||
|
return 1;
|
||||||
case Type.BUG:
|
case Type.BUG:
|
||||||
case Type.STEEL:
|
case Type.STEEL:
|
||||||
case Type.FIRE:
|
case Type.FIRE:
|
||||||
@ -173,20 +286,33 @@ export function getTypeDamageMultiplier(attackType: Type, defType: Type): TypeDa
|
|||||||
case Type.FAIRY:
|
case Type.FAIRY:
|
||||||
return 0.5;
|
return 0.5;
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
case Type.WATER:
|
case Type.WATER:
|
||||||
switch (attackType) {
|
switch (attackType) {
|
||||||
case Type.GRASS:
|
case Type.GRASS:
|
||||||
case Type.ELECTRIC:
|
case Type.ELECTRIC:
|
||||||
return 2;
|
return 2;
|
||||||
|
case Type.NORMAL:
|
||||||
|
case Type.FIGHTING:
|
||||||
|
case Type.FLYING:
|
||||||
|
case Type.POISON:
|
||||||
|
case Type.GROUND:
|
||||||
|
case Type.ROCK:
|
||||||
|
case Type.BUG:
|
||||||
|
case Type.GHOST:
|
||||||
|
case Type.PSYCHIC:
|
||||||
|
case Type.DRAGON:
|
||||||
|
case Type.DARK:
|
||||||
|
case Type.FAIRY:
|
||||||
|
return 1;
|
||||||
case Type.STEEL:
|
case Type.STEEL:
|
||||||
case Type.FIRE:
|
case Type.FIRE:
|
||||||
case Type.WATER:
|
case Type.WATER:
|
||||||
case Type.ICE:
|
case Type.ICE:
|
||||||
return 0.5;
|
return 0.5;
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
case Type.GRASS:
|
case Type.GRASS:
|
||||||
switch (attackType) {
|
switch (attackType) {
|
||||||
@ -196,24 +322,49 @@ export function getTypeDamageMultiplier(attackType: Type, defType: Type): TypeDa
|
|||||||
case Type.FIRE:
|
case Type.FIRE:
|
||||||
case Type.ICE:
|
case Type.ICE:
|
||||||
return 2;
|
return 2;
|
||||||
|
case Type.NORMAL:
|
||||||
|
case Type.FIGHTING:
|
||||||
|
case Type.ROCK:
|
||||||
|
case Type.GHOST:
|
||||||
|
case Type.STEEL:
|
||||||
|
case Type.PSYCHIC:
|
||||||
|
case Type.DRAGON:
|
||||||
|
case Type.DARK:
|
||||||
|
case Type.FAIRY:
|
||||||
|
return 1;
|
||||||
case Type.GROUND:
|
case Type.GROUND:
|
||||||
case Type.WATER:
|
case Type.WATER:
|
||||||
case Type.GRASS:
|
case Type.GRASS:
|
||||||
case Type.ELECTRIC:
|
case Type.ELECTRIC:
|
||||||
return 0.5;
|
return 0.5;
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
case Type.ELECTRIC:
|
case Type.ELECTRIC:
|
||||||
switch (attackType) {
|
switch (attackType) {
|
||||||
case Type.GROUND:
|
case Type.GROUND:
|
||||||
return 2;
|
return 2;
|
||||||
|
case Type.NORMAL:
|
||||||
|
case Type.FIGHTING:
|
||||||
|
case Type.POISON:
|
||||||
|
case Type.ROCK:
|
||||||
|
case Type.BUG:
|
||||||
|
case Type.GHOST:
|
||||||
|
case Type.FIRE:
|
||||||
|
case Type.WATER:
|
||||||
|
case Type.GRASS:
|
||||||
|
case Type.PSYCHIC:
|
||||||
|
case Type.ICE:
|
||||||
|
case Type.DRAGON:
|
||||||
|
case Type.DARK:
|
||||||
|
case Type.FAIRY:
|
||||||
|
return 1;
|
||||||
case Type.FLYING:
|
case Type.FLYING:
|
||||||
case Type.STEEL:
|
case Type.STEEL:
|
||||||
case Type.ELECTRIC:
|
case Type.ELECTRIC:
|
||||||
return 0.5;
|
return 0.5;
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
case Type.PSYCHIC:
|
case Type.PSYCHIC:
|
||||||
switch (attackType) {
|
switch (attackType) {
|
||||||
@ -221,11 +372,25 @@ export function getTypeDamageMultiplier(attackType: Type, defType: Type): TypeDa
|
|||||||
case Type.GHOST:
|
case Type.GHOST:
|
||||||
case Type.DARK:
|
case Type.DARK:
|
||||||
return 2;
|
return 2;
|
||||||
|
case Type.NORMAL:
|
||||||
|
case Type.FLYING:
|
||||||
|
case Type.POISON:
|
||||||
|
case Type.GROUND:
|
||||||
|
case Type.ROCK:
|
||||||
|
case Type.STEEL:
|
||||||
|
case Type.FIRE:
|
||||||
|
case Type.WATER:
|
||||||
|
case Type.GRASS:
|
||||||
|
case Type.ELECTRIC:
|
||||||
|
case Type.ICE:
|
||||||
|
case Type.DRAGON:
|
||||||
|
case Type.FAIRY:
|
||||||
|
return 1;
|
||||||
case Type.FIGHTING:
|
case Type.FIGHTING:
|
||||||
case Type.PSYCHIC:
|
case Type.PSYCHIC:
|
||||||
return 0.5;
|
return 0.5;
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
case Type.ICE:
|
case Type.ICE:
|
||||||
switch (attackType) {
|
switch (attackType) {
|
||||||
@ -234,10 +399,24 @@ export function getTypeDamageMultiplier(attackType: Type, defType: Type): TypeDa
|
|||||||
case Type.STEEL:
|
case Type.STEEL:
|
||||||
case Type.FIRE:
|
case Type.FIRE:
|
||||||
return 2;
|
return 2;
|
||||||
|
case Type.NORMAL:
|
||||||
|
case Type.FLYING:
|
||||||
|
case Type.POISON:
|
||||||
|
case Type.GROUND:
|
||||||
|
case Type.BUG:
|
||||||
|
case Type.GHOST:
|
||||||
|
case Type.WATER:
|
||||||
|
case Type.GRASS:
|
||||||
|
case Type.ELECTRIC:
|
||||||
|
case Type.PSYCHIC:
|
||||||
|
case Type.DRAGON:
|
||||||
|
case Type.DARK:
|
||||||
|
case Type.FAIRY:
|
||||||
|
return 1;
|
||||||
case Type.ICE:
|
case Type.ICE:
|
||||||
return 0.5;
|
return 0.5;
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
case Type.DRAGON:
|
case Type.DRAGON:
|
||||||
switch (attackType) {
|
switch (attackType) {
|
||||||
@ -245,13 +424,25 @@ export function getTypeDamageMultiplier(attackType: Type, defType: Type): TypeDa
|
|||||||
case Type.DRAGON:
|
case Type.DRAGON:
|
||||||
case Type.FAIRY:
|
case Type.FAIRY:
|
||||||
return 2;
|
return 2;
|
||||||
|
case Type.NORMAL:
|
||||||
|
case Type.FIGHTING:
|
||||||
|
case Type.FLYING:
|
||||||
|
case Type.POISON:
|
||||||
|
case Type.GROUND:
|
||||||
|
case Type.ROCK:
|
||||||
|
case Type.BUG:
|
||||||
|
case Type.GHOST:
|
||||||
|
case Type.STEEL:
|
||||||
|
case Type.PSYCHIC:
|
||||||
|
case Type.DARK:
|
||||||
|
return 1;
|
||||||
case Type.FIRE:
|
case Type.FIRE:
|
||||||
case Type.WATER:
|
case Type.WATER:
|
||||||
case Type.GRASS:
|
case Type.GRASS:
|
||||||
case Type.ELECTRIC:
|
case Type.ELECTRIC:
|
||||||
return 0.5;
|
return 0.5;
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
case Type.DARK:
|
case Type.DARK:
|
||||||
switch (attackType) {
|
switch (attackType) {
|
||||||
@ -259,33 +450,106 @@ export function getTypeDamageMultiplier(attackType: Type, defType: Type): TypeDa
|
|||||||
case Type.BUG:
|
case Type.BUG:
|
||||||
case Type.FAIRY:
|
case Type.FAIRY:
|
||||||
return 2;
|
return 2;
|
||||||
|
case Type.NORMAL:
|
||||||
|
case Type.FLYING:
|
||||||
|
case Type.POISON:
|
||||||
|
case Type.GROUND:
|
||||||
|
case Type.ROCK:
|
||||||
|
case Type.STEEL:
|
||||||
|
case Type.FIRE:
|
||||||
|
case Type.WATER:
|
||||||
|
case Type.GRASS:
|
||||||
|
case Type.ELECTRIC:
|
||||||
|
case Type.ICE:
|
||||||
|
case Type.DRAGON:
|
||||||
|
return 1;
|
||||||
case Type.GHOST:
|
case Type.GHOST:
|
||||||
case Type.DARK:
|
case Type.DARK:
|
||||||
return 0.5;
|
return 0.5;
|
||||||
case Type.PSYCHIC:
|
case Type.PSYCHIC:
|
||||||
return 0;
|
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
case Type.FAIRY:
|
case Type.FAIRY:
|
||||||
switch (attackType) {
|
switch (attackType) {
|
||||||
case Type.POISON:
|
case Type.POISON:
|
||||||
case Type.STEEL:
|
case Type.STEEL:
|
||||||
return 2;
|
return 2;
|
||||||
|
case Type.NORMAL:
|
||||||
|
case Type.FLYING:
|
||||||
|
case Type.GROUND:
|
||||||
|
case Type.ROCK:
|
||||||
|
case Type.GHOST:
|
||||||
|
case Type.FIRE:
|
||||||
|
case Type.WATER:
|
||||||
|
case Type.GRASS:
|
||||||
|
case Type.ELECTRIC:
|
||||||
|
case Type.PSYCHIC:
|
||||||
|
case Type.ICE:
|
||||||
|
case Type.FAIRY:
|
||||||
|
return 1;
|
||||||
case Type.FIGHTING:
|
case Type.FIGHTING:
|
||||||
case Type.BUG:
|
case Type.BUG:
|
||||||
case Type.DARK:
|
case Type.DARK:
|
||||||
return 0.5;
|
return 0.5;
|
||||||
case Type.DRAGON:
|
case Type.DRAGON:
|
||||||
return 0;
|
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
case Type.STELLAR:
|
case Type.STELLAR:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the types resisting a given type
|
||||||
|
* @returns An array populated with Types, or an empty array if no resistances exist (Unknown or Stellar type)
|
||||||
|
*/
|
||||||
|
export function getTypeResistances(type: number): Type[] {
|
||||||
|
switch (type) {
|
||||||
|
case Type.NORMAL:
|
||||||
|
return [Type.ROCK, Type.STEEL, Type.GHOST];
|
||||||
|
case Type.FIGHTING:
|
||||||
|
return [Type.FLYING, Type.POISON, Type.BUG, Type.PSYCHIC, Type.FAIRY, Type.GHOST];
|
||||||
|
case Type.FLYING:
|
||||||
|
return [Type.ROCK, Type.ELECTRIC, Type.STEEL];
|
||||||
|
case Type.POISON:
|
||||||
|
return [Type.POISON, Type.GROUND, Type.ROCK, Type.GHOST, Type.STEEL];
|
||||||
|
case Type.GROUND:
|
||||||
|
return [Type.BUG, Type.GRASS, Type.FLYING];
|
||||||
|
case Type.ROCK:
|
||||||
|
return [Type.FIGHTING, Type.GROUND, Type.STEEL];
|
||||||
|
case Type.BUG:
|
||||||
|
return [Type.FIGHTING, Type.FLYING, Type.POISON, Type.GHOST, Type.STEEL, Type.FIRE, Type.FAIRY];
|
||||||
|
case Type.GHOST:
|
||||||
|
return [Type.DARK, Type.NORMAL];
|
||||||
|
case Type.STEEL:
|
||||||
|
return [Type.STEEL, Type.FIRE, Type.WATER, Type.ELECTRIC];
|
||||||
|
case Type.FIRE:
|
||||||
|
return [Type.ROCK, Type.FIRE, Type.WATER, Type.DRAGON];
|
||||||
|
case Type.WATER:
|
||||||
|
return [Type.WATER, Type.GRASS, Type.DRAGON];
|
||||||
|
case Type.GRASS:
|
||||||
|
return [Type.FLYING, Type.POISON, Type.BUG, Type.STEEL, Type.FIRE, Type.GRASS, Type.DRAGON];
|
||||||
|
case Type.ELECTRIC:
|
||||||
|
return [Type.GRASS, Type.ELECTRIC, Type.DRAGON, Type.GROUND];
|
||||||
|
case Type.PSYCHIC:
|
||||||
|
return [Type.STEEL, Type.PSYCHIC];
|
||||||
|
case Type.ICE:
|
||||||
|
return [Type.STEEL, Type.FIRE, Type.WATER, Type.ICE];
|
||||||
|
case Type.DRAGON:
|
||||||
|
return [Type.STEEL, Type.FAIRY];
|
||||||
|
case Type.DARK:
|
||||||
|
return [Type.FIGHTING, Type.DARK, Type.FAIRY];
|
||||||
|
case Type.FAIRY:
|
||||||
|
return [Type.POISON, Type.STEEL, Type.FIRE];
|
||||||
|
case Type.UNKNOWN:
|
||||||
|
case Type.STELLAR:
|
||||||
|
default:
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,6 +3,5 @@ export enum Challenges {
|
|||||||
SINGLE_TYPE,
|
SINGLE_TYPE,
|
||||||
LOWER_MAX_STARTER_COST,
|
LOWER_MAX_STARTER_COST,
|
||||||
LOWER_STARTER_POINTS,
|
LOWER_STARTER_POINTS,
|
||||||
FRESH_START,
|
FRESH_START
|
||||||
INVERSE_BATTLE,
|
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,6 @@ import { BerryType } from "#enums/berry-type";
|
|||||||
import { Biome } from "#enums/biome";
|
import { Biome } from "#enums/biome";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import { Challenges } from "#enums/challenges";
|
|
||||||
import { getPokemonNameWithAffix } from "#app/messages.js";
|
import { getPokemonNameWithAffix } from "#app/messages.js";
|
||||||
import { DamagePhase } from "#app/phases/damage-phase.js";
|
import { DamagePhase } from "#app/phases/damage-phase.js";
|
||||||
import { FaintPhase } from "#app/phases/faint-phase.js";
|
import { FaintPhase } from "#app/phases/faint-phase.js";
|
||||||
@ -1316,15 +1315,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const multiplier = new Utils.NumberHolder(getTypeDamageMultiplier(moveType, defType));
|
|
||||||
applyChallenges(this.scene.gameMode, ChallengeType.TYPE_EFFECTIVENESS, multiplier);
|
return getTypeDamageMultiplier(moveType, defType);
|
||||||
return multiplier.value;
|
|
||||||
}).reduce((acc, cur) => acc * cur, 1) as TypeDamageMultiplier;
|
}).reduce((acc, cur) => acc * cur, 1) as TypeDamageMultiplier;
|
||||||
|
|
||||||
const typeMultiplierAgainstFlying = new Utils.NumberHolder(getTypeDamageMultiplier(moveType, Type.FLYING));
|
|
||||||
applyChallenges(this.scene.gameMode, ChallengeType.TYPE_EFFECTIVENESS, typeMultiplierAgainstFlying);
|
|
||||||
// Handle strong winds lowering effectiveness of types super effective against pure flying
|
// Handle strong winds lowering effectiveness of types super effective against pure flying
|
||||||
if (!ignoreStrongWinds && arena.weather?.weatherType === WeatherType.STRONG_WINDS && !arena.weather.isEffectSuppressed(this.scene) && this.isOfType(Type.FLYING) && typeMultiplierAgainstFlying.value === 2) {
|
if (!ignoreStrongWinds && arena.weather?.weatherType === WeatherType.STRONG_WINDS && !arena.weather.isEffectSuppressed(this.scene) && this.isOfType(Type.FLYING) && getTypeDamageMultiplier(moveType, Type.FLYING) === 2) {
|
||||||
multiplier /= 2;
|
multiplier /= 2;
|
||||||
if (!simulated) {
|
if (!simulated) {
|
||||||
this.scene.queueMessage(i18next.t("weather:strongWindsEffectMessage"));
|
this.scene.queueMessage(i18next.t("weather:strongWindsEffectMessage"));
|
||||||
@ -3846,7 +3842,7 @@ export class EnemyPokemon extends Pokemon {
|
|||||||
this.moveset = (formIndex !== undefined ? formIndex : this.formIndex)
|
this.moveset = (formIndex !== undefined ? formIndex : this.formIndex)
|
||||||
? [
|
? [
|
||||||
new PokemonMove(Moves.DYNAMAX_CANNON),
|
new PokemonMove(Moves.DYNAMAX_CANNON),
|
||||||
new PokemonMove(Moves.CROSS_POISON),
|
new PokemonMove(Moves.SLUDGE_BOMB),
|
||||||
new PokemonMove(Moves.FLAMETHROWER),
|
new PokemonMove(Moves.FLAMETHROWER),
|
||||||
new PokemonMove(Moves.RECOVER, 0, -4)
|
new PokemonMove(Moves.RECOVER, 0, -4)
|
||||||
]
|
]
|
||||||
@ -3856,9 +3852,6 @@ export class EnemyPokemon extends Pokemon {
|
|||||||
new PokemonMove(Moves.FLAMETHROWER),
|
new PokemonMove(Moves.FLAMETHROWER),
|
||||||
new PokemonMove(Moves.COSMIC_POWER)
|
new PokemonMove(Moves.COSMIC_POWER)
|
||||||
];
|
];
|
||||||
if (this.scene.gameMode.hasChallenge(Challenges.INVERSE_BATTLE)) {
|
|
||||||
this.moveset[2] = new PokemonMove(Moves.THUNDERBOLT);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
super.generateAndPopulateMoveset();
|
super.generateAndPopulateMoveset();
|
||||||
|
@ -269,9 +269,5 @@
|
|||||||
"FRESH_START": {
|
"FRESH_START": {
|
||||||
"name": "Hussa, noch einmal von vorn!",
|
"name": "Hussa, noch einmal von vorn!",
|
||||||
"description": "Schließe die 'Neuanfang' Herausforderung ab"
|
"description": "Schließe die 'Neuanfang' Herausforderung ab"
|
||||||
},
|
|
||||||
"INVERSE_BATTLE": {
|
|
||||||
"name": "Spieglein, Spieglein an der Wand",
|
|
||||||
"description": "Schließe die 'Umkehrkampf' Herausforderung ab"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -25,12 +25,5 @@
|
|||||||
"desc": "Du kannst nur die ursprünglichen Starter verwenden, genau so, als hättest du gerade erst mit Pokérogue begonnen.",
|
"desc": "Du kannst nur die ursprünglichen Starter verwenden, genau so, als hättest du gerade erst mit Pokérogue begonnen.",
|
||||||
"value.0": "Aus",
|
"value.0": "Aus",
|
||||||
"value.1": "An"
|
"value.1": "An"
|
||||||
},
|
|
||||||
"inverseBattle": {
|
|
||||||
"name": "Umkehrkampf",
|
|
||||||
"shortName": "Umkehrkampf",
|
|
||||||
"desc": "Die Typen-Effektivität wird umgekehrt, und kein Typ ist gegen einen anderen Typ immun.\nDeaktiviert die Erfolge anderer Herausforderungen.",
|
|
||||||
"value.0": "Aus",
|
|
||||||
"value.1": "An"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -260,9 +260,5 @@
|
|||||||
"FRESH_START": {
|
"FRESH_START": {
|
||||||
"name": "First Try!",
|
"name": "First Try!",
|
||||||
"description": "Complete the Fresh Start challenge."
|
"description": "Complete the Fresh Start challenge."
|
||||||
},
|
|
||||||
"INVERSE_BATTLE": {
|
|
||||||
"name": "Mirror rorriM",
|
|
||||||
"description": "Complete the Inverse Battle challenge.\n.egnellahc elttaB esrevnI eht etelpmoC"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -279,9 +279,5 @@
|
|||||||
"FRESH_START": {
|
"FRESH_START": {
|
||||||
"name": "First Try!",
|
"name": "First Try!",
|
||||||
"description": "Complete the Fresh Start challenge."
|
"description": "Complete the Fresh Start challenge."
|
||||||
},
|
|
||||||
"INVERSE_BATTLE": {
|
|
||||||
"name": "Mirror rorriM",
|
|
||||||
"description": "Complete the Inverse Battle challenge.\n.egnellahc elttaB esrevnI eht etelpmoC"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -25,12 +25,5 @@
|
|||||||
"desc": "You can only use the original starters, and only as if you had just started PokéRogue.",
|
"desc": "You can only use the original starters, and only as if you had just started PokéRogue.",
|
||||||
"value.0": "Off",
|
"value.0": "Off",
|
||||||
"value.1": "On"
|
"value.1": "On"
|
||||||
},
|
|
||||||
"inverseBattle": {
|
|
||||||
"name": "Inverse Battle",
|
|
||||||
"shortName": "Inverse",
|
|
||||||
"desc": "Type matchups are reversed and no type is immune to any other type.\nDisables other challenges' achievements.",
|
|
||||||
"value.0": "Off",
|
|
||||||
"value.1": "On"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,9 +2,5 @@
|
|||||||
"encounter": "It appears the time has finally come once again.\nYou know why you have come here, do you not?\n$You were drawn here, because you have been here before.\nCountless times.\n$Though, perhaps it can be counted.\nTo be precise, this is in fact your {{cycleCount}} cycle.\n$Each cycle your mind reverts to its former state.\nEven so, somehow, remnants of your former selves remain.\n$Until now you have yet to succeed, but I sense a different presence in you this time.\n\n$You are the only one here, though it is as if there is… another.\n$Will you finally prove a formidable challenge to me?\nThe challenge I have longed after for millennia?\n$We begin.",
|
"encounter": "It appears the time has finally come once again.\nYou know why you have come here, do you not?\n$You were drawn here, because you have been here before.\nCountless times.\n$Though, perhaps it can be counted.\nTo be precise, this is in fact your {{cycleCount}} cycle.\n$Each cycle your mind reverts to its former state.\nEven so, somehow, remnants of your former selves remain.\n$Until now you have yet to succeed, but I sense a different presence in you this time.\n\n$You are the only one here, though it is as if there is… another.\n$Will you finally prove a formidable challenge to me?\nThe challenge I have longed after for millennia?\n$We begin.",
|
||||||
"encounter_female": null,
|
"encounter_female": null,
|
||||||
"firstStageWin": "I see. The presence I felt was indeed real.\nIt appears I no longer need to hold back.\n$Do not disappoint me.",
|
"firstStageWin": "I see. The presence I felt was indeed real.\nIt appears I no longer need to hold back.\n$Do not disappoint me.",
|
||||||
"secondStageWin": "…Magnificent.",
|
"secondStageWin": "…Magnificent."
|
||||||
"key_ordinal_one": "st",
|
|
||||||
"key_ordinal_two": "nd",
|
|
||||||
"key_ordinal_few": "rd",
|
|
||||||
"key_ordinal_other": "th"
|
|
||||||
}
|
}
|
@ -14,8 +14,8 @@
|
|||||||
"importSlotSelect": "Select a slot to import to.",
|
"importSlotSelect": "Select a slot to import to.",
|
||||||
"exportSession": "Export Session",
|
"exportSession": "Export Session",
|
||||||
"exportSlotSelect": "Select a slot to export from.",
|
"exportSlotSelect": "Select a slot to export from.",
|
||||||
"importRunHistory": "Import Run History",
|
"importRunHistory":"Import Run History",
|
||||||
"exportRunHistory": "Export Run History",
|
"exportRunHistory":"Export Run History",
|
||||||
"importData": "Import Data",
|
"importData": "Import Data",
|
||||||
"exportData": "Export Data",
|
"exportData": "Export Data",
|
||||||
"consentPreferences": "Consent Preferences",
|
"consentPreferences": "Consent Preferences",
|
||||||
|
@ -170,9 +170,5 @@
|
|||||||
"CLASSIC_VICTORY": {
|
"CLASSIC_VICTORY": {
|
||||||
"name": "Imbatible",
|
"name": "Imbatible",
|
||||||
"description": "Completa el juego en modo clásico."
|
"description": "Completa el juego en modo clásico."
|
||||||
},
|
|
||||||
"INVERSE_BATTLE": {
|
|
||||||
"name": "Espejo ojepsE",
|
|
||||||
"description": "Completa el reto de Combate Inverso.\n.osrevnI etabmoC ed oter le atelpmoC"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -18,12 +18,5 @@
|
|||||||
"name": "Monotipo",
|
"name": "Monotipo",
|
||||||
"desc": "Solo puedes usar Pokémon with the {{type}} type.",
|
"desc": "Solo puedes usar Pokémon with the {{type}} type.",
|
||||||
"desc_default": "Solo puedes usar Pokémon del tipo elegido."
|
"desc_default": "Solo puedes usar Pokémon del tipo elegido."
|
||||||
},
|
|
||||||
"inverseBattle": {
|
|
||||||
"name": "Combate Inverso",
|
|
||||||
"shortName": "Inverso",
|
|
||||||
"desc": "La efectividad de los tipos es invertida. No hay inmunidades entre tipos.\nEste reto deshabilita logros de otros retos.",
|
|
||||||
"value.0": "Desactivado",
|
|
||||||
"value.1": "Activado"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -274,9 +274,5 @@
|
|||||||
"FRESH_START": {
|
"FRESH_START": {
|
||||||
"name": "Du premier coup !",
|
"name": "Du premier coup !",
|
||||||
"description": "Terminer un challenge « Nouveau départ »."
|
"description": "Terminer un challenge « Nouveau départ »."
|
||||||
},
|
|
||||||
"INVERSE_BATTLE": {
|
|
||||||
"name": "La teuté à verlan",
|
|
||||||
"description": "Terminer un challenge en Combat Inversé.\nMineter un lenjcha en Ba-con Versin."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,12 +25,5 @@
|
|||||||
"desc": "Vous ne pouvez choisir que les starters de base du jeu, comme si vous le recommenciez.",
|
"desc": "Vous ne pouvez choisir que les starters de base du jeu, comme si vous le recommenciez.",
|
||||||
"value.0": "Non",
|
"value.0": "Non",
|
||||||
"value.1": "Oui"
|
"value.1": "Oui"
|
||||||
},
|
|
||||||
"inverseBattle": {
|
|
||||||
"name": "Combat Inversé",
|
|
||||||
"shortName": "Inversé",
|
|
||||||
"desc": "Les affinités de la table des types sont inversées et plus aucun type n’a d’immunité.\nDésactive les succès des autres challenges.",
|
|
||||||
"value.0": "Non",
|
|
||||||
"value.1": "Oui"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -22,7 +22,6 @@
|
|||||||
},
|
},
|
||||||
"freshStart": {
|
"freshStart": {
|
||||||
"name": "出直し",
|
"name": "出直し",
|
||||||
"shortName": "出直し",
|
|
||||||
"desc": "ポケローグを 始めた ばかりの ような ままで ゲーム開始の 最初のパートナーしか 使えません",
|
"desc": "ポケローグを 始めた ばかりの ような ままで ゲーム開始の 最初のパートナーしか 使えません",
|
||||||
"value.0": "オフ",
|
"value.0": "オフ",
|
||||||
"value.1": "オン"
|
"value.1": "オン"
|
||||||
|
@ -260,9 +260,5 @@
|
|||||||
"FRESH_START": {
|
"FRESH_START": {
|
||||||
"name": "첫트!",
|
"name": "첫트!",
|
||||||
"description": "새 출발 챌린지 모드 클리어."
|
"description": "새 출발 챌린지 모드 클리어."
|
||||||
},
|
|
||||||
"INVERSE_BATTLE": {
|
|
||||||
"name": "상성 전문가(였던 것)",
|
|
||||||
"description": "거꾸로 배틀 챌린지 모드 클리어."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -25,12 +25,5 @@
|
|||||||
"desc": "포켓로그를 처음 시작했던 때처럼 강화가 전혀 되지 않은 오리지널 스타팅 포켓몬만 고를 수 있습니다.",
|
"desc": "포켓로그를 처음 시작했던 때처럼 강화가 전혀 되지 않은 오리지널 스타팅 포켓몬만 고를 수 있습니다.",
|
||||||
"value.0": "해제",
|
"value.0": "해제",
|
||||||
"value.1": "설정"
|
"value.1": "설정"
|
||||||
},
|
|
||||||
"inverseBattle": {
|
|
||||||
"name": "거꾸로 배틀",
|
|
||||||
"shortName": "거꾸로",
|
|
||||||
"desc": "타입 상성이 반대로 바뀌고 면역 타입은 약점 타입이 됩니다.\n설정 시 다른 챌린지 업적은 달성할 수 없습니다.",
|
|
||||||
"value.0": "해제",
|
|
||||||
"value.1": "설정"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -264,9 +264,5 @@
|
|||||||
"FRESH_START": {
|
"FRESH_START": {
|
||||||
"name": "De Primeira!",
|
"name": "De Primeira!",
|
||||||
"description": "Complete o desafio de novo começo."
|
"description": "Complete o desafio de novo começo."
|
||||||
},
|
|
||||||
"INVERSE_BATTLE": {
|
|
||||||
"name": "A torre da derrotA",
|
|
||||||
"description": "Complete o desafio da Batalha Inversa.\n.asrevnI ahlataB ad oifased o etelpmoC"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -25,12 +25,5 @@
|
|||||||
"desc": "Você só pode usar os iniciais originais, como se tivesse acabado de começar o PokéRogue.",
|
"desc": "Você só pode usar os iniciais originais, como se tivesse acabado de começar o PokéRogue.",
|
||||||
"value.0": "Desligado",
|
"value.0": "Desligado",
|
||||||
"value.1": "Ligado"
|
"value.1": "Ligado"
|
||||||
},
|
|
||||||
"inverseBattle": {
|
|
||||||
"name": "Batalha Inversa",
|
|
||||||
"shortName": "Inversa",
|
|
||||||
"desc": "Fraquezas e resistências de tipos são invertidas e nenhum tipo é imune a outro tipo.\nDesativa as conquistas de outros desafios.",
|
|
||||||
"value.0": "Desligado",
|
|
||||||
"value.1": "Ligado"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -268,9 +268,5 @@
|
|||||||
"FRESH_START": {
|
"FRESH_START": {
|
||||||
"name": "初次尝试!",
|
"name": "初次尝试!",
|
||||||
"description": "完成初次尝试挑战"
|
"description": "完成初次尝试挑战"
|
||||||
},
|
|
||||||
"INVERSE_BATTLE": {
|
|
||||||
"name": "镜子子镜",
|
|
||||||
"description": "完成逆转之战挑战\n战挑战之转逆成完"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,12 +25,5 @@
|
|||||||
"desc": "你只能使用御三家,就像是你第一次玩宝可梦肉鸽一样。",
|
"desc": "你只能使用御三家,就像是你第一次玩宝可梦肉鸽一样。",
|
||||||
"value.0": "关闭",
|
"value.0": "关闭",
|
||||||
"value.1": "开启"
|
"value.1": "开启"
|
||||||
},
|
|
||||||
"inverseBattle": {
|
|
||||||
"name": "逆转之战",
|
|
||||||
"shortName": "逆转之战",
|
|
||||||
"desc": "属性相克关系被反转,且没有任何属性对其他属性免疫。\n禁用其他挑战的成就。",
|
|
||||||
"value.0": "关闭",
|
|
||||||
"value.1": "开启"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -252,9 +252,5 @@
|
|||||||
},
|
},
|
||||||
"MONO_FAIRY": {
|
"MONO_FAIRY": {
|
||||||
"name": "林克,醒醒!"
|
"name": "林克,醒醒!"
|
||||||
},
|
|
||||||
"INVERSE_BATTLE": {
|
|
||||||
"name": "鏡子子鏡",
|
|
||||||
"description": "完成逆轉之戰挑戰\n戰挑戰之轉逆成完"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,12 +19,5 @@
|
|||||||
"name": "單屬性",
|
"name": "單屬性",
|
||||||
"desc": "你只能使用{{type}}\n屬性的寶可夢",
|
"desc": "你只能使用{{type}}\n屬性的寶可夢",
|
||||||
"desc_default": "你只能使用所選\n屬性的寶可夢"
|
"desc_default": "你只能使用所選\n屬性的寶可夢"
|
||||||
},
|
|
||||||
"inverseBattle": {
|
|
||||||
"name": "逆轉之戰",
|
|
||||||
"shortName": "逆轉之戰",
|
|
||||||
"desc": "屬性相克關系被反轉,且沒有任何屬性對其他屬性免疫。\n禁用其他挑戰的成就。",
|
|
||||||
"value.0": "關閉",
|
|
||||||
"value.1": "開啓"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -791,10 +791,10 @@ export class EvolutionItemModifierType extends PokemonModifierType implements Ge
|
|||||||
super("", EvolutionItem[evolutionItem].toLowerCase(), (_type, args) => new Modifiers.EvolutionItemModifier(this, (args[0] as PlayerPokemon).id),
|
super("", EvolutionItem[evolutionItem].toLowerCase(), (_type, args) => new Modifiers.EvolutionItemModifier(this, (args[0] as PlayerPokemon).id),
|
||||||
(pokemon: PlayerPokemon) => {
|
(pokemon: PlayerPokemon) => {
|
||||||
if (pokemonEvolutions.hasOwnProperty(pokemon.species.speciesId) && pokemonEvolutions[pokemon.species.speciesId].filter(e => e.item === this.evolutionItem
|
if (pokemonEvolutions.hasOwnProperty(pokemon.species.speciesId) && pokemonEvolutions[pokemon.species.speciesId].filter(e => e.item === this.evolutionItem
|
||||||
&& (!e.condition || e.condition.predicate(pokemon)) && (e.preFormKey === null || e.preFormKey === pokemon.getFormKey())).length && (pokemon.getFormKey() !== SpeciesFormKey.GIGANTAMAX)) {
|
&& (!e.condition || e.condition.predicate(pokemon)) && (e.preFormKey === pokemon.getFormKey())).length && (pokemon.getFormKey() !== SpeciesFormKey.GIGANTAMAX)) {
|
||||||
return null;
|
return null;
|
||||||
} else if (pokemon.isFusion() && pokemon.fusionSpecies && pokemonEvolutions.hasOwnProperty(pokemon.fusionSpecies.speciesId) && pokemonEvolutions[pokemon.fusionSpecies.speciesId].filter(e => e.item === this.evolutionItem
|
} else if (pokemon.isFusion() && pokemon.fusionSpecies && pokemonEvolutions.hasOwnProperty(pokemon.fusionSpecies.speciesId) && pokemonEvolutions[pokemon.fusionSpecies.speciesId].filter(e => e.item === this.evolutionItem
|
||||||
&& (!e.condition || e.condition.predicate(pokemon)) && (e.preFormKey === null || e.preFormKey === pokemon.getFusionFormKey())).length && (pokemon.getFusionFormKey() !== SpeciesFormKey.GIGANTAMAX)) {
|
&& (!e.condition || e.condition.predicate(pokemon)) && (e.preFormKey === pokemon.getFusionFormKey())).length && (pokemon.getFusionFormKey() !== SpeciesFormKey.GIGANTAMAX)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
import BattleScene from "#app/battle-scene";
|
import BattleScene from "#app/battle-scene.js";
|
||||||
import { BattleType, BattlerIndex } from "#app/battle";
|
import { BattleType, BattlerIndex } from "#app/battle.js";
|
||||||
import { applyAbAttrs, SyncEncounterNatureAbAttr } from "#app/data/ability";
|
import { applyAbAttrs, SyncEncounterNatureAbAttr } from "#app/data/ability.js";
|
||||||
import { getCharVariantFromDialogue } from "#app/data/dialogue";
|
import { getCharVariantFromDialogue } from "#app/data/dialogue.js";
|
||||||
import { TrainerSlot } from "#app/data/trainer-config";
|
import { TrainerSlot } from "#app/data/trainer-config.js";
|
||||||
import { getRandomWeatherType } from "#app/data/weather";
|
import { getRandomWeatherType } from "#app/data/weather.js";
|
||||||
import { BattleSpec } from "#app/enums/battle-spec";
|
import { BattleSpec } from "#app/enums/battle-spec.js";
|
||||||
import { PlayerGender } from "#app/enums/player-gender";
|
import { PlayerGender } from "#app/enums/player-gender.js";
|
||||||
import { Species } from "#app/enums/species";
|
import { Species } from "#app/enums/species.js";
|
||||||
import { EncounterPhaseEvent } from "#app/events/battle-scene";
|
import { EncounterPhaseEvent } from "#app/events/battle-scene.js";
|
||||||
import Pokemon, { FieldPosition } from "#app/field/pokemon";
|
import Pokemon, { FieldPosition } from "#app/field/pokemon.js";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages.js";
|
||||||
import { regenerateModifierPoolThresholds, ModifierPoolType } from "#app/modifier/modifier-type";
|
import { regenerateModifierPoolThresholds, ModifierPoolType } from "#app/modifier/modifier-type.js";
|
||||||
import { IvScannerModifier, TurnHeldItemTransferModifier } from "#app/modifier/modifier";
|
import { IvScannerModifier, TurnHeldItemTransferModifier } from "#app/modifier/modifier.js";
|
||||||
import { achvs } from "#app/system/achv";
|
import { achvs } from "#app/system/achv.js";
|
||||||
import { handleTutorial, Tutorial } from "#app/tutorial";
|
import { handleTutorial, Tutorial } from "#app/tutorial.js";
|
||||||
import { Mode } from "#app/ui/ui";
|
import { Mode } from "#app/ui/ui.js";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { BattlePhase } from "./battle-phase";
|
import { BattlePhase } from "./battle-phase";
|
||||||
import * as Utils from "#app/utils";
|
import * as Utils from "#app/utils.js";
|
||||||
import { CheckSwitchPhase } from "./check-switch-phase";
|
import { CheckSwitchPhase } from "./check-switch-phase";
|
||||||
import { GameOverPhase } from "./game-over-phase";
|
import { GameOverPhase } from "./game-over-phase";
|
||||||
import { PostSummonPhase } from "./post-summon-phase";
|
import { PostSummonPhase } from "./post-summon-phase";
|
||||||
@ -358,29 +358,24 @@ export class EncounterPhase extends BattlePhase {
|
|||||||
case BattleSpec.FINAL_BOSS:
|
case BattleSpec.FINAL_BOSS:
|
||||||
const enemy = this.scene.getEnemyPokemon();
|
const enemy = this.scene.getEnemyPokemon();
|
||||||
this.scene.ui.showText(this.getEncounterMessage(), null, () => {
|
this.scene.ui.showText(this.getEncounterMessage(), null, () => {
|
||||||
const localizationKey = "battleSpecDialogue:encounter";
|
|
||||||
if (this.scene.ui.shouldSkipDialogue(localizationKey)) {
|
|
||||||
// Logging mirrors logging found in dialogue-ui-handler
|
|
||||||
console.log(`Dialogue ${localizationKey} skipped`);
|
|
||||||
this.doEncounterCommon(false);
|
|
||||||
} else {
|
|
||||||
const count = 5643853 + this.scene.gameData.gameStats.classicSessionsPlayed;
|
const count = 5643853 + this.scene.gameData.gameStats.classicSessionsPlayed;
|
||||||
// The line below checks if an English ordinal is necessary or not based on whether an entry for encounterLocalizationKey exists in the language or not.
|
//The two lines below check if English ordinals (1st, 2nd, 3rd, Xth) are used and determine which one to use.
|
||||||
const ordinalUsed = !i18next.exists(localizationKey, {fallbackLng: []}) || i18next.resolvedLanguage === "en" ? i18next.t("battleSpecDialogue:key", { count: count, ordinal: true }) : "";
|
//Otherwise, it defaults to an empty string.
|
||||||
const cycleCount = count.toLocaleString() + ordinalUsed;
|
//As of 08-07-24: Spanish and Italian default to the English translations
|
||||||
|
const ordinalUse = ["en", "es", "it"];
|
||||||
|
const currentLanguage = i18next.resolvedLanguage ?? "en";
|
||||||
|
const ordinalIndex = (ordinalUse.includes(currentLanguage)) ? ["st", "nd", "rd"][((count + 90) % 100 - 10) % 10 - 1] ?? "th" : "";
|
||||||
|
const cycleCount = count.toLocaleString() + ordinalIndex;
|
||||||
const genderIndex = this.scene.gameData.gender ?? PlayerGender.UNSET;
|
const genderIndex = this.scene.gameData.gender ?? PlayerGender.UNSET;
|
||||||
const genderStr = PlayerGender[genderIndex].toLowerCase();
|
const genderStr = PlayerGender[genderIndex].toLowerCase();
|
||||||
const encounterDialogue = i18next.t(localizationKey, { context: genderStr, cycleCount: cycleCount });
|
const encounterDialogue = i18next.t("battleSpecDialogue:encounter", { context: genderStr, cycleCount: cycleCount });
|
||||||
if (!this.scene.gameData.getSeenDialogues()[localizationKey]) {
|
|
||||||
this.scene.gameData.saveSeenDialogue(localizationKey);
|
|
||||||
}
|
|
||||||
this.scene.ui.showDialogue(encounterDialogue, enemy?.species.name, null, () => {
|
this.scene.ui.showDialogue(encounterDialogue, enemy?.species.name, null, () => {
|
||||||
this.doEncounterCommon(false);
|
this.doEncounterCommon(false);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}, 1500, true);
|
}, 1500, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,8 @@ import { pokemonEvolutions } from "#app/data/pokemon-evolutions";
|
|||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import { PlayerGender } from "#enums/player-gender";
|
import { PlayerGender } from "#enums/player-gender";
|
||||||
import { Challenge, FreshStartChallenge, InverseBattleChallenge, SingleGenerationChallenge, SingleTypeChallenge } from "#app/data/challenge";
|
import { Challenge, FreshStartChallenge, SingleGenerationChallenge, SingleTypeChallenge } from "#app/data/challenge.js";
|
||||||
import { Challenges } from "#app/enums/challenges";
|
import { ConditionFn } from "#app/@types/common.js";
|
||||||
import { ConditionFn } from "#app/@types/common";
|
|
||||||
|
|
||||||
export enum AchvTier {
|
export enum AchvTier {
|
||||||
COMMON,
|
COMMON,
|
||||||
@ -138,8 +137,8 @@ export class ModifierAchv extends Achv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ChallengeAchv extends Achv {
|
export class ChallengeAchv extends Achv {
|
||||||
constructor(localizationKey: string, name: string, description: string, iconImage: string, score: integer, challengeFunc: (challenge: Challenge, scene: BattleScene) => boolean) {
|
constructor(localizationKey: string, name: string, description: string, iconImage: string, score: integer, challengeFunc: (challenge: Challenge) => boolean) {
|
||||||
super(localizationKey, name, description, iconImage, score, (_scene: BattleScene, args: any[]) => challengeFunc(args[0] as Challenge, _scene));
|
super(localizationKey, name, description, iconImage, score, (_scene: BattleScene, args: any[]) => challengeFunc((args[0] as Challenge)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,8 +275,6 @@ export function getAchievementDescription(localizationKey: string): string {
|
|||||||
return i18next.t("achv:MonoType.description", { context: genderStr, "type": i18next.t(`pokemonInfo:Type.${localizationKey.slice(5)}`) });
|
return i18next.t("achv:MonoType.description", { context: genderStr, "type": i18next.t(`pokemonInfo:Type.${localizationKey.slice(5)}`) });
|
||||||
case "FRESH_START":
|
case "FRESH_START":
|
||||||
return i18next.t("achv:FRESH_START.description", { context: genderStr });
|
return i18next.t("achv:FRESH_START.description", { context: genderStr });
|
||||||
case "INVERSE_BATTLE":
|
|
||||||
return i18next.t("achv:INVERSE_BATTLE.description", { context: genderStr });
|
|
||||||
default:
|
default:
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -326,35 +323,34 @@ export const achvs = {
|
|||||||
PERFECT_IVS: new Achv("PERFECT_IVS", "", "PERFECT_IVS.description", "blunder_policy", 100),
|
PERFECT_IVS: new Achv("PERFECT_IVS", "", "PERFECT_IVS.description", "blunder_policy", 100),
|
||||||
CLASSIC_VICTORY: new Achv("CLASSIC_VICTORY", "", "CLASSIC_VICTORY.description", "relic_crown", 150),
|
CLASSIC_VICTORY: new Achv("CLASSIC_VICTORY", "", "CLASSIC_VICTORY.description", "relic_crown", 150),
|
||||||
UNEVOLVED_CLASSIC_VICTORY: new Achv("UNEVOLVED_CLASSIC_VICTORY", "", "UNEVOLVED_CLASSIC_VICTORY.description", "eviolite", 175, c => c.getParty().some(p => p.getSpeciesForm(true).speciesId in pokemonEvolutions)),
|
UNEVOLVED_CLASSIC_VICTORY: new Achv("UNEVOLVED_CLASSIC_VICTORY", "", "UNEVOLVED_CLASSIC_VICTORY.description", "eviolite", 175, c => c.getParty().some(p => p.getSpeciesForm(true).speciesId in pokemonEvolutions)),
|
||||||
MONO_GEN_ONE_VICTORY: new ChallengeAchv("MONO_GEN_ONE", "", "MONO_GEN_ONE.description", "ribbon_gen1", 100, (c, scene) => c instanceof SingleGenerationChallenge && c.value === 1 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_GEN_ONE_VICTORY: new ChallengeAchv("MONO_GEN_ONE", "", "MONO_GEN_ONE.description", "ribbon_gen1", 100, c => c instanceof SingleGenerationChallenge && c.value === 1),
|
||||||
MONO_GEN_TWO_VICTORY: new ChallengeAchv("MONO_GEN_TWO", "", "MONO_GEN_TWO.description", "ribbon_gen2", 100, (c, scene) => c instanceof SingleGenerationChallenge && c.value === 2 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_GEN_TWO_VICTORY: new ChallengeAchv("MONO_GEN_TWO", "", "MONO_GEN_TWO.description", "ribbon_gen2", 100, c => c instanceof SingleGenerationChallenge && c.value === 2),
|
||||||
MONO_GEN_THREE_VICTORY: new ChallengeAchv("MONO_GEN_THREE", "", "MONO_GEN_THREE.description", "ribbon_gen3", 100, (c, scene) => c instanceof SingleGenerationChallenge && c.value === 3 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_GEN_THREE_VICTORY: new ChallengeAchv("MONO_GEN_THREE", "", "MONO_GEN_THREE.description", "ribbon_gen3", 100, c => c instanceof SingleGenerationChallenge && c.value === 3),
|
||||||
MONO_GEN_FOUR_VICTORY: new ChallengeAchv("MONO_GEN_FOUR", "", "MONO_GEN_FOUR.description", "ribbon_gen4", 100, (c, scene) => c instanceof SingleGenerationChallenge && c.value === 4 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_GEN_FOUR_VICTORY: new ChallengeAchv("MONO_GEN_FOUR", "", "MONO_GEN_FOUR.description", "ribbon_gen4", 100, c => c instanceof SingleGenerationChallenge && c.value === 4),
|
||||||
MONO_GEN_FIVE_VICTORY: new ChallengeAchv("MONO_GEN_FIVE", "", "MONO_GEN_FIVE.description", "ribbon_gen5", 100, (c, scene) => c instanceof SingleGenerationChallenge && c.value === 5 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_GEN_FIVE_VICTORY: new ChallengeAchv("MONO_GEN_FIVE", "", "MONO_GEN_FIVE.description", "ribbon_gen5", 100, c => c instanceof SingleGenerationChallenge && c.value === 5),
|
||||||
MONO_GEN_SIX_VICTORY: new ChallengeAchv("MONO_GEN_SIX", "", "MONO_GEN_SIX.description", "ribbon_gen6", 100, (c, scene) => c instanceof SingleGenerationChallenge && c.value === 6 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_GEN_SIX_VICTORY: new ChallengeAchv("MONO_GEN_SIX", "", "MONO_GEN_SIX.description", "ribbon_gen6", 100, c => c instanceof SingleGenerationChallenge && c.value === 6),
|
||||||
MONO_GEN_SEVEN_VICTORY: new ChallengeAchv("MONO_GEN_SEVEN", "", "MONO_GEN_SEVEN.description", "ribbon_gen7", 100, (c, scene) => c instanceof SingleGenerationChallenge && c.value === 7 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_GEN_SEVEN_VICTORY: new ChallengeAchv("MONO_GEN_SEVEN", "", "MONO_GEN_SEVEN.description", "ribbon_gen7", 100, c => c instanceof SingleGenerationChallenge && c.value === 7),
|
||||||
MONO_GEN_EIGHT_VICTORY: new ChallengeAchv("MONO_GEN_EIGHT", "", "MONO_GEN_EIGHT.description", "ribbon_gen8", 100, (c, scene) => c instanceof SingleGenerationChallenge && c.value === 8 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_GEN_EIGHT_VICTORY: new ChallengeAchv("MONO_GEN_EIGHT", "", "MONO_GEN_EIGHT.description", "ribbon_gen8", 100, c => c instanceof SingleGenerationChallenge && c.value === 8),
|
||||||
MONO_GEN_NINE_VICTORY: new ChallengeAchv("MONO_GEN_NINE", "", "MONO_GEN_NINE.description", "ribbon_gen9", 100, (c, scene) => c instanceof SingleGenerationChallenge && c.value === 9 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_GEN_NINE_VICTORY: new ChallengeAchv("MONO_GEN_NINE", "", "MONO_GEN_NINE.description", "ribbon_gen9", 100, c => c instanceof SingleGenerationChallenge && c.value === 9),
|
||||||
MONO_NORMAL: new ChallengeAchv("MONO_NORMAL", "", "MONO_NORMAL.description", "silk_scarf", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 1 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_NORMAL: new ChallengeAchv("MONO_NORMAL", "", "MONO_NORMAL.description", "silk_scarf", 100, c => c instanceof SingleTypeChallenge && c.value === 1),
|
||||||
MONO_FIGHTING: new ChallengeAchv("MONO_FIGHTING", "", "MONO_FIGHTING.description", "black_belt", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 2 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_FIGHTING: new ChallengeAchv("MONO_FIGHTING", "", "MONO_FIGHTING.description", "black_belt", 100, c => c instanceof SingleTypeChallenge && c.value === 2),
|
||||||
MONO_FLYING: new ChallengeAchv("MONO_FLYING", "", "MONO_FLYING.description", "sharp_beak", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 3 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_FLYING: new ChallengeAchv("MONO_FLYING", "", "MONO_FLYING.description", "sharp_beak", 100, c => c instanceof SingleTypeChallenge && c.value === 3),
|
||||||
MONO_POISON: new ChallengeAchv("MONO_POISON", "", "MONO_POISON.description", "poison_barb", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 4 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_POISON: new ChallengeAchv("MONO_POISON", "", "MONO_POISON.description", "poison_barb", 100, c => c instanceof SingleTypeChallenge && c.value === 4),
|
||||||
MONO_GROUND: new ChallengeAchv("MONO_GROUND", "", "MONO_GROUND.description", "soft_sand", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 5 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_GROUND: new ChallengeAchv("MONO_GROUND", "", "MONO_GROUND.description", "soft_sand", 100, c => c instanceof SingleTypeChallenge && c.value === 5),
|
||||||
MONO_ROCK: new ChallengeAchv("MONO_ROCK", "", "MONO_ROCK.description", "hard_stone", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 6 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_ROCK: new ChallengeAchv("MONO_ROCK", "", "MONO_ROCK.description", "hard_stone", 100, c => c instanceof SingleTypeChallenge && c.value === 6),
|
||||||
MONO_BUG: new ChallengeAchv("MONO_BUG", "", "MONO_BUG.description", "silver_powder", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 7 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_BUG: new ChallengeAchv("MONO_BUG", "", "MONO_BUG.description", "silver_powder", 100, c => c instanceof SingleTypeChallenge && c.value === 7),
|
||||||
MONO_GHOST: new ChallengeAchv("MONO_GHOST", "", "MONO_GHOST.description", "spell_tag", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 8 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_GHOST: new ChallengeAchv("MONO_GHOST", "", "MONO_GHOST.description", "spell_tag", 100, c => c instanceof SingleTypeChallenge && c.value === 8),
|
||||||
MONO_STEEL: new ChallengeAchv("MONO_STEEL", "", "MONO_STEEL.description", "metal_coat", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 9 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_STEEL: new ChallengeAchv("MONO_STEEL", "", "MONO_STEEL.description", "metal_coat", 100, c => c instanceof SingleTypeChallenge && c.value === 9),
|
||||||
MONO_FIRE: new ChallengeAchv("MONO_FIRE", "", "MONO_FIRE.description", "charcoal", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 10 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_FIRE: new ChallengeAchv("MONO_FIRE", "", "MONO_FIRE.description", "charcoal", 100, c => c instanceof SingleTypeChallenge && c.value === 10),
|
||||||
MONO_WATER: new ChallengeAchv("MONO_WATER", "", "MONO_WATER.description", "mystic_water", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 11 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_WATER: new ChallengeAchv("MONO_WATER", "", "MONO_WATER.description", "mystic_water", 100, c => c instanceof SingleTypeChallenge && c.value === 11),
|
||||||
MONO_GRASS: new ChallengeAchv("MONO_GRASS", "", "MONO_GRASS.description", "miracle_seed", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 12 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_GRASS: new ChallengeAchv("MONO_GRASS", "", "MONO_GRASS.description", "miracle_seed", 100, c => c instanceof SingleTypeChallenge && c.value === 12),
|
||||||
MONO_ELECTRIC: new ChallengeAchv("MONO_ELECTRIC", "", "MONO_ELECTRIC.description", "magnet", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 13 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_ELECTRIC: new ChallengeAchv("MONO_ELECTRIC", "", "MONO_ELECTRIC.description", "magnet", 100, c => c instanceof SingleTypeChallenge && c.value === 13),
|
||||||
MONO_PSYCHIC: new ChallengeAchv("MONO_PSYCHIC", "", "MONO_PSYCHIC.description", "twisted_spoon", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 14 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_PSYCHIC: new ChallengeAchv("MONO_PSYCHIC", "", "MONO_PSYCHIC.description", "twisted_spoon", 100, c => c instanceof SingleTypeChallenge && c.value === 14),
|
||||||
MONO_ICE: new ChallengeAchv("MONO_ICE", "", "MONO_ICE.description", "never_melt_ice", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 15 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_ICE: new ChallengeAchv("MONO_ICE", "", "MONO_ICE.description", "never_melt_ice", 100, c => c instanceof SingleTypeChallenge && c.value === 15),
|
||||||
MONO_DRAGON: new ChallengeAchv("MONO_DRAGON", "", "MONO_DRAGON.description", "dragon_fang", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 16 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_DRAGON: new ChallengeAchv("MONO_DRAGON", "", "MONO_DRAGON.description", "dragon_fang", 100, c => c instanceof SingleTypeChallenge && c.value === 16),
|
||||||
MONO_DARK: new ChallengeAchv("MONO_DARK", "", "MONO_DARK.description", "black_glasses", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 17 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_DARK: new ChallengeAchv("MONO_DARK", "", "MONO_DARK.description", "black_glasses", 100, c => c instanceof SingleTypeChallenge && c.value === 17),
|
||||||
MONO_FAIRY: new ChallengeAchv("MONO_FAIRY", "", "MONO_FAIRY.description", "fairy_feather", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 18 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
MONO_FAIRY: new ChallengeAchv("MONO_FAIRY", "", "MONO_FAIRY.description", "fairy_feather", 100, c => c instanceof SingleTypeChallenge && c.value === 18),
|
||||||
FRESH_START: new ChallengeAchv("FRESH_START", "", "FRESH_START.description", "reviver_seed", 100, (c, scene) => c instanceof FreshStartChallenge && c.value > 0 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)),
|
FRESH_START: new ChallengeAchv("FRESH_START", "", "FRESH_START.description", "reviver_seed", 100, c => c instanceof FreshStartChallenge && c.value === 1),
|
||||||
INVERSE_BATTLE: new ChallengeAchv("INVERSE_BATTLE", "", "INVERSE_BATTLE.description", "inverse", 100, c => c instanceof InverseBattleChallenge && c.value > 0),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function initAchievements() {
|
export function initAchievements() {
|
||||||
|
@ -243,8 +243,6 @@ export class StarterPrefs {
|
|||||||
if (pStr !== StarterPrefers_private_latest) {
|
if (pStr !== StarterPrefers_private_latest) {
|
||||||
// something changed, store the update
|
// something changed, store the update
|
||||||
localStorage.setItem(`starterPrefs_${loggedInUser?.username}`, pStr);
|
localStorage.setItem(`starterPrefs_${loggedInUser?.username}`, pStr);
|
||||||
// update the latest prefs
|
|
||||||
StarterPrefers_private_latest = pStr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,203 +0,0 @@
|
|||||||
import { BattlerIndex } from "#app/battle";
|
|
||||||
import { allMoves } from "#app/data/move";
|
|
||||||
import { Type } from "#app/data/type";
|
|
||||||
import { MoveEndPhase } from "#app/phases/move-end-phase";
|
|
||||||
import { TurnEndPhase } from "#app/phases/turn-end-phase";
|
|
||||||
import { Abilities } from "#enums/abilities";
|
|
||||||
import { ArenaTagType } from "#enums/arena-tag-type";
|
|
||||||
import { Challenges } from "#enums/challenges";
|
|
||||||
import { Moves } from "#enums/moves";
|
|
||||||
import { Species } from "#enums/species";
|
|
||||||
import { StatusEffect } from "#enums/status-effect";
|
|
||||||
import GameManager from "#test/utils/gameManager";
|
|
||||||
import Phaser from "phaser";
|
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
|
||||||
|
|
||||||
const TIMEOUT = 20 * 1000;
|
|
||||||
|
|
||||||
describe("Inverse Battle", () => {
|
|
||||||
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.challengeMode.addChallenge(Challenges.INVERSE_BATTLE, 1, 1);
|
|
||||||
|
|
||||||
game.override
|
|
||||||
.battleType("single")
|
|
||||||
.starterSpecies(Species.FEEBAS)
|
|
||||||
.ability(Abilities.BALL_FETCH)
|
|
||||||
.enemySpecies(Species.MAGIKARP)
|
|
||||||
.enemyAbility(Abilities.BALL_FETCH);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("1. immune types are 2x effective - Thunderbolt against Ground Type", async () => {
|
|
||||||
game.override.enemySpecies(Species.SANDSHREW);
|
|
||||||
|
|
||||||
await game.challengeMode.startBattle();
|
|
||||||
|
|
||||||
const player = game.scene.getPlayerPokemon()!;
|
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
|
||||||
|
|
||||||
expect(enemy.getMoveEffectiveness(player, allMoves[Moves.THUNDERBOLT])).toBe(2);
|
|
||||||
}, TIMEOUT);
|
|
||||||
|
|
||||||
it("2. 2x effective types are 0.5x effective - Thunderbolt against Flying Type", async () => {
|
|
||||||
game.override.enemySpecies(Species.PIDGEY);
|
|
||||||
|
|
||||||
await game.challengeMode.startBattle();
|
|
||||||
|
|
||||||
const player = game.scene.getPlayerPokemon()!;
|
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
|
||||||
|
|
||||||
expect(enemy.getMoveEffectiveness(player, allMoves[Moves.THUNDERBOLT])).toBe(0.5);
|
|
||||||
}, TIMEOUT);
|
|
||||||
|
|
||||||
it("3. 0.5x effective types are 2x effective - Thunderbolt against Electric Type", async () => {
|
|
||||||
game.override.enemySpecies(Species.CHIKORITA);
|
|
||||||
|
|
||||||
await game.challengeMode.startBattle();
|
|
||||||
|
|
||||||
const player = game.scene.getPlayerPokemon()!;
|
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
|
||||||
|
|
||||||
expect(enemy.getMoveEffectiveness(player, allMoves[Moves.THUNDERBOLT])).toBe(2);
|
|
||||||
}, TIMEOUT);
|
|
||||||
|
|
||||||
it("4. Stealth Rock follows the inverse matchups - Stealth Rock against Charizard deals 1/32 of max HP", async () => {
|
|
||||||
game.scene.arena.addTag(ArenaTagType.STEALTH_ROCK, 1, Moves.STEALTH_ROCK, 0);
|
|
||||||
game.override
|
|
||||||
.enemySpecies(Species.CHARIZARD)
|
|
||||||
.enemyLevel(100);
|
|
||||||
|
|
||||||
await game.challengeMode.startBattle();
|
|
||||||
|
|
||||||
const charizard = game.scene.getEnemyPokemon()!;
|
|
||||||
|
|
||||||
const maxHp = charizard.getMaxHp();
|
|
||||||
const damage_prediction = Math.max(Math.round(charizard.getMaxHp() / 32), 1);
|
|
||||||
console.log("Damage calcuation before round: " + charizard.getMaxHp() / 32);
|
|
||||||
const currentHp = charizard.hp;
|
|
||||||
const expectedHP = maxHp - damage_prediction;
|
|
||||||
|
|
||||||
console.log("Charizard's max HP: " + maxHp, "Damage: " + damage_prediction, "Current HP: " + currentHp, "Expected HP: " + expectedHP);
|
|
||||||
expect(currentHp).toBeGreaterThan(maxHp * 31 / 32 - 1);
|
|
||||||
}, TIMEOUT);
|
|
||||||
|
|
||||||
it("5. Freeze Dry is 2x effective against Water Type like other Ice type Move - Freeze Dry against Squirtle", async () => {
|
|
||||||
game.override.enemySpecies(Species.SQUIRTLE);
|
|
||||||
|
|
||||||
await game.challengeMode.startBattle();
|
|
||||||
|
|
||||||
const player = game.scene.getPlayerPokemon()!;
|
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
|
||||||
|
|
||||||
expect(enemy.getMoveEffectiveness(player, allMoves[Moves.FREEZE_DRY])).toBe(2);
|
|
||||||
}, TIMEOUT);
|
|
||||||
|
|
||||||
it("6. Water Absorb should heal against water moves - Water Absorb against Water gun", async () => {
|
|
||||||
game.override
|
|
||||||
.moveset([Moves.WATER_GUN])
|
|
||||||
.enemyAbility(Abilities.WATER_ABSORB);
|
|
||||||
|
|
||||||
await game.challengeMode.startBattle();
|
|
||||||
|
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
|
||||||
enemy.hp = enemy.getMaxHp() - 1;
|
|
||||||
game.move.select(Moves.WATER_GUN);
|
|
||||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
|
||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEndPhase);
|
|
||||||
|
|
||||||
expect(enemy.hp).toBe(enemy.getMaxHp());
|
|
||||||
}, TIMEOUT);
|
|
||||||
|
|
||||||
it("7. Fire type does not get burned - Will-O-Wisp against Charmander", async () => {
|
|
||||||
game.override
|
|
||||||
.moveset([Moves.WILL_O_WISP])
|
|
||||||
.enemySpecies(Species.CHARMANDER);
|
|
||||||
|
|
||||||
await game.challengeMode.startBattle();
|
|
||||||
|
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
|
||||||
|
|
||||||
game.move.select(Moves.WILL_O_WISP);
|
|
||||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
|
||||||
await game.move.forceHit();
|
|
||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEndPhase);
|
|
||||||
|
|
||||||
expect(enemy.status?.effect).not.toBe(StatusEffect.BURN);
|
|
||||||
}, TIMEOUT);
|
|
||||||
|
|
||||||
it("8. Electric type does not get paralyzed - Nuzzle against Pikachu", async () => {
|
|
||||||
game.override
|
|
||||||
.moveset([Moves.NUZZLE])
|
|
||||||
.enemySpecies(Species.PIKACHU)
|
|
||||||
.enemyLevel(50);
|
|
||||||
|
|
||||||
await game.challengeMode.startBattle();
|
|
||||||
|
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
|
||||||
|
|
||||||
game.move.select(Moves.NUZZLE);
|
|
||||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
|
||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEndPhase);
|
|
||||||
|
|
||||||
expect(enemy.status?.effect).not.toBe(StatusEffect.PARALYSIS);
|
|
||||||
}, TIMEOUT);
|
|
||||||
|
|
||||||
|
|
||||||
it("10. Anticipation should trigger on 2x effective moves - Anticipation against Thunderbolt", async () => {
|
|
||||||
game.override
|
|
||||||
.moveset([Moves.THUNDERBOLT])
|
|
||||||
.enemySpecies(Species.SANDSHREW)
|
|
||||||
.enemyAbility(Abilities.ANTICIPATION);
|
|
||||||
|
|
||||||
await game.challengeMode.startBattle();
|
|
||||||
|
|
||||||
expect(game.scene.getEnemyPokemon()?.summonData.abilitiesApplied[0]).toBe(Abilities.ANTICIPATION);
|
|
||||||
}, TIMEOUT);
|
|
||||||
|
|
||||||
it("11. Conversion 2 should change the type to the resistive type - Conversion 2 against Dragonite", async () => {
|
|
||||||
game.override
|
|
||||||
.moveset([Moves.CONVERSION_2])
|
|
||||||
.enemyMoveset([Moves.DRAGON_CLAW, Moves.DRAGON_CLAW, Moves.DRAGON_CLAW, Moves.DRAGON_CLAW]);
|
|
||||||
|
|
||||||
await game.challengeMode.startBattle();
|
|
||||||
|
|
||||||
const player = game.scene.getPlayerPokemon()!;
|
|
||||||
|
|
||||||
game.move.select(Moves.CONVERSION_2);
|
|
||||||
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
|
|
||||||
|
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
|
||||||
|
|
||||||
expect(player.getTypes()[0]).toBe(Type.DRAGON);
|
|
||||||
}, TIMEOUT);
|
|
||||||
|
|
||||||
it("12. Flying Press should be 0.25x effective against Grass + Dark Type - Flying Press against Meowscarada", async () => {
|
|
||||||
game.override
|
|
||||||
.moveset([Moves.FLYING_PRESS])
|
|
||||||
.enemySpecies(Species.MEOWSCARADA);
|
|
||||||
|
|
||||||
await game.challengeMode.startBattle();
|
|
||||||
|
|
||||||
const player = game.scene.getPlayerPokemon()!;
|
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
|
||||||
|
|
||||||
expect(enemy.getMoveEffectiveness(player, allMoves[Moves.FLYING_PRESS])).toBe(0.25);
|
|
||||||
}, TIMEOUT);
|
|
||||||
});
|
|
@ -1,87 +0,0 @@
|
|||||||
import { allMoves } from "#app/data/move.js";
|
|
||||||
import { StatusEffect } from "#app/enums/status-effect.js";
|
|
||||||
import { CommandPhase } from "#app/phases/command-phase.js";
|
|
||||||
import { Abilities } from "#enums/abilities";
|
|
||||||
import { Moves } from "#enums/moves";
|
|
||||||
import { Species } from "#enums/species";
|
|
||||||
import GameManager from "#test/utils/gameManager";
|
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
|
||||||
|
|
||||||
describe("Moves - Sparkly Swirl", () => {
|
|
||||||
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
|
|
||||||
.enemySpecies(Species.SHUCKLE)
|
|
||||||
.enemyLevel(100)
|
|
||||||
.enemyMoveset(SPLASH_ONLY)
|
|
||||||
.enemyAbility(Abilities.BALL_FETCH)
|
|
||||||
.moveset([Moves.SPARKLY_SWIRL, Moves.SPLASH])
|
|
||||||
.ability(Abilities.BALL_FETCH);
|
|
||||||
|
|
||||||
vi.spyOn(allMoves[Moves.SPARKLY_SWIRL], "accuracy", "get").mockReturnValue(100);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should cure status effect of the user, its ally, and all party pokemon", async () => {
|
|
||||||
game.override
|
|
||||||
.battleType("double")
|
|
||||||
.statusEffect(StatusEffect.BURN);
|
|
||||||
await game.classicMode.startBattle([Species.RATTATA, Species.RATTATA, Species.RATTATA]);
|
|
||||||
const [leftPlayer, rightPlayer, partyPokemon] = game.scene.getParty();
|
|
||||||
const leftOpp = game.scene.getEnemyPokemon()!;
|
|
||||||
|
|
||||||
vi.spyOn(leftPlayer, "resetStatus");
|
|
||||||
vi.spyOn(rightPlayer, "resetStatus");
|
|
||||||
vi.spyOn(partyPokemon, "resetStatus");
|
|
||||||
|
|
||||||
game.move.select(Moves.SPARKLY_SWIRL, 0, leftOpp.getBattlerIndex());
|
|
||||||
await game.phaseInterceptor.to(CommandPhase);
|
|
||||||
game.move.select(Moves.SPLASH, 1);
|
|
||||||
await game.toNextTurn();
|
|
||||||
|
|
||||||
expect(leftPlayer.resetStatus).toHaveBeenCalledOnce();
|
|
||||||
expect(rightPlayer.resetStatus).toHaveBeenCalledOnce();
|
|
||||||
expect(partyPokemon.resetStatus).toHaveBeenCalledOnce();
|
|
||||||
|
|
||||||
expect(leftPlayer.status?.effect).toBeUndefined();
|
|
||||||
expect(rightPlayer.status?.effect).toBeUndefined();
|
|
||||||
expect(partyPokemon.status?.effect).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not cure status effect of the target/target's allies", async () => {
|
|
||||||
game.override
|
|
||||||
.battleType("double")
|
|
||||||
.enemyStatusEffect(StatusEffect.BURN);
|
|
||||||
await game.classicMode.startBattle([Species.RATTATA, Species.RATTATA]);
|
|
||||||
const [leftOpp, rightOpp] = game.scene.getEnemyField();
|
|
||||||
|
|
||||||
vi.spyOn(leftOpp, "resetStatus");
|
|
||||||
vi.spyOn(rightOpp, "resetStatus");
|
|
||||||
|
|
||||||
game.move.select(Moves.SPARKLY_SWIRL, 0, leftOpp.getBattlerIndex());
|
|
||||||
await game.phaseInterceptor.to(CommandPhase);
|
|
||||||
game.move.select(Moves.SPLASH, 1);
|
|
||||||
await game.toNextTurn();
|
|
||||||
|
|
||||||
expect(leftOpp.resetStatus).toHaveBeenCalledTimes(0);
|
|
||||||
expect(rightOpp.resetStatus).toHaveBeenCalledTimes(0);
|
|
||||||
|
|
||||||
expect(leftOpp.status?.effect).toBeTruthy();
|
|
||||||
expect(rightOpp.status?.effect).toBeTruthy();
|
|
||||||
|
|
||||||
expect(leftOpp.status?.effect).toBe(StatusEffect.BURN);
|
|
||||||
expect(rightOpp.status?.effect).toBe(StatusEffect.BURN);
|
|
||||||
});
|
|
||||||
});
|
|
@ -40,7 +40,6 @@ import fs from "fs";
|
|||||||
import { vi } from "vitest";
|
import { vi } from "vitest";
|
||||||
import { ClassicModeHelper } from "./helpers/classicModeHelper";
|
import { ClassicModeHelper } from "./helpers/classicModeHelper";
|
||||||
import { DailyModeHelper } from "./helpers/dailyModeHelper";
|
import { DailyModeHelper } from "./helpers/dailyModeHelper";
|
||||||
import { ChallengeModeHelper } from "./helpers/challengeModeHelper";
|
|
||||||
import { MoveHelper } from "./helpers/moveHelper";
|
import { MoveHelper } from "./helpers/moveHelper";
|
||||||
import { OverridesHelper } from "./helpers/overridesHelper";
|
import { OverridesHelper } from "./helpers/overridesHelper";
|
||||||
import { SettingsHelper } from "./helpers/settingsHelper";
|
import { SettingsHelper } from "./helpers/settingsHelper";
|
||||||
@ -58,7 +57,6 @@ export default class GameManager {
|
|||||||
public readonly move: MoveHelper;
|
public readonly move: MoveHelper;
|
||||||
public readonly classicMode: ClassicModeHelper;
|
public readonly classicMode: ClassicModeHelper;
|
||||||
public readonly dailyMode: DailyModeHelper;
|
public readonly dailyMode: DailyModeHelper;
|
||||||
public readonly challengeMode: ChallengeModeHelper;
|
|
||||||
public readonly settings: SettingsHelper;
|
public readonly settings: SettingsHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -79,7 +77,6 @@ export default class GameManager {
|
|||||||
this.move = new MoveHelper(this);
|
this.move = new MoveHelper(this);
|
||||||
this.classicMode = new ClassicModeHelper(this);
|
this.classicMode = new ClassicModeHelper(this);
|
||||||
this.dailyMode = new DailyModeHelper(this);
|
this.dailyMode = new DailyModeHelper(this);
|
||||||
this.challengeMode = new ChallengeModeHelper(this);
|
|
||||||
this.settings = new SettingsHelper(this);
|
this.settings = new SettingsHelper(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
import { BattleStyle } from "#app/enums/battle-style";
|
|
||||||
import { Species } from "#app/enums/species";
|
|
||||||
import overrides from "#app/overrides";
|
|
||||||
import { EncounterPhase } from "#app/phases/encounter-phase";
|
|
||||||
import { SelectStarterPhase } from "#app/phases/select-starter-phase";
|
|
||||||
import { Mode } from "#app/ui/ui";
|
|
||||||
import { generateStarter } from "../gameManagerUtils";
|
|
||||||
import { GameManagerHelper } from "./gameManagerHelper";
|
|
||||||
import { Challenge } from "#app/data/challenge";
|
|
||||||
import { CommandPhase } from "#app/phases/command-phase";
|
|
||||||
import { TurnInitPhase } from "#app/phases/turn-init-phase";
|
|
||||||
import { Challenges } from "#enums/challenges";
|
|
||||||
import { copyChallenge } from "data/challenge";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper to handle Challenge mode specifics
|
|
||||||
*/
|
|
||||||
export class ChallengeModeHelper extends GameManagerHelper {
|
|
||||||
|
|
||||||
challenges: Challenge[] = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a challenge to the challenge mode helper.
|
|
||||||
* @param id - The challenge id.
|
|
||||||
* @param value - The challenge value.
|
|
||||||
* @param severity - The challenge severity.
|
|
||||||
*/
|
|
||||||
addChallenge(id: Challenges, value: number, severity: number) {
|
|
||||||
const challenge = copyChallenge({ id, value, severity });
|
|
||||||
this.challenges.push(challenge);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs the Challenge game to the summon phase.
|
|
||||||
* @param gameMode - Optional game mode to set.
|
|
||||||
* @returns A promise that resolves when the summon phase is reached.
|
|
||||||
*/
|
|
||||||
async runToSummon(species?: Species[]) {
|
|
||||||
await this.game.runToTitle();
|
|
||||||
|
|
||||||
this.game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
|
|
||||||
this.game.scene.gameMode.challenges = this.challenges;
|
|
||||||
const starters = generateStarter(this.game.scene, species);
|
|
||||||
const selectStarterPhase = new SelectStarterPhase(this.game.scene);
|
|
||||||
this.game.scene.pushPhase(new EncounterPhase(this.game.scene, false));
|
|
||||||
selectStarterPhase.initBattle(starters);
|
|
||||||
});
|
|
||||||
|
|
||||||
await this.game.phaseInterceptor.run(EncounterPhase);
|
|
||||||
if (overrides.OPP_HELD_ITEMS_OVERRIDE.length === 0) {
|
|
||||||
this.game.removeEnemyHeldItems();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transitions to the start of a battle.
|
|
||||||
* @param species - Optional array of species to start the battle with.
|
|
||||||
* @returns A promise that resolves when the battle is started.
|
|
||||||
*/
|
|
||||||
async startBattle(species?: Species[]) {
|
|
||||||
await this.runToSummon(species);
|
|
||||||
|
|
||||||
if (this.game.scene.battleStyle === BattleStyle.SWITCH) {
|
|
||||||
this.game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => {
|
|
||||||
this.game.setMode(Mode.MESSAGE);
|
|
||||||
this.game.endPhase();
|
|
||||||
}, () => this.game.isCurrentPhase(CommandPhase) || this.game.isCurrentPhase(TurnInitPhase));
|
|
||||||
|
|
||||||
this.game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => {
|
|
||||||
this.game.setMode(Mode.MESSAGE);
|
|
||||||
this.game.endPhase();
|
|
||||||
}, () => this.game.isCurrentPhase(CommandPhase) || this.game.isCurrentPhase(TurnInitPhase));
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.game.phaseInterceptor.to(CommandPhase);
|
|
||||||
console.log("==================[New Turn]==================");
|
|
||||||
}
|
|
||||||
}
|
|
@ -77,21 +77,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected setupOptions() {
|
protected setupOptions() {
|
||||||
const configOptions = this.config?.options ?? [];
|
const options = this.config?.options || [];
|
||||||
|
|
||||||
let options: OptionSelectItem[];
|
|
||||||
|
|
||||||
// for performance reasons, this limits how many options we can see at once. Without this, it would try to make text options for every single options
|
|
||||||
// which makes the performance take a hit. If there's not enough options to do this (set to 10 at the moment) and the ui mode !== Mode.AUTO_COMPLETE,
|
|
||||||
// this is ignored and the original code is untouched, with the options array being all the options from the config
|
|
||||||
if (configOptions.length >= 10 && this.scene.ui.getMode() === Mode.AUTO_COMPLETE) {
|
|
||||||
const optionsScrollTotal = configOptions.length;
|
|
||||||
const optionStartIndex = this.scrollCursor;
|
|
||||||
const optionEndIndex = Math.min(optionsScrollTotal, optionStartIndex + (!optionStartIndex || this.scrollCursor + (this.config?.maxOptions! - 1) >= optionsScrollTotal ? this.config?.maxOptions! - 1 : this.config?.maxOptions! - 2));
|
|
||||||
options = configOptions.slice(optionStartIndex, optionEndIndex + 2);
|
|
||||||
} else {
|
|
||||||
options = configOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.optionSelectText) {
|
if (this.optionSelectText) {
|
||||||
this.optionSelectText.destroy();
|
this.optionSelectText.destroy();
|
||||||
@ -206,19 +192,6 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
|
|||||||
} else {
|
} else {
|
||||||
ui.playError();
|
ui.playError();
|
||||||
}
|
}
|
||||||
} else if (button === Button.SUBMIT && ui.getMode() === Mode.AUTO_COMPLETE) {
|
|
||||||
// this is here to differentiate between a Button.SUBMIT vs Button.ACTION within the autocomplete handler
|
|
||||||
// this is here because Button.ACTION is picked up as z on the keyboard, meaning if you're typing and hit z, it'll select the option you've chosen
|
|
||||||
success = true;
|
|
||||||
const option = this.config?.options[this.cursor + (this.scrollCursor - (this.scrollCursor ? 1 : 0))];
|
|
||||||
if (option?.handler()) {
|
|
||||||
if (!option.keepOpen) {
|
|
||||||
this.clear();
|
|
||||||
}
|
|
||||||
playSound = !option.overrideSound;
|
|
||||||
} else {
|
|
||||||
ui.playError();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
switch (button) {
|
switch (button) {
|
||||||
case Button.UP:
|
case Button.UP:
|
||||||
|
@ -64,15 +64,12 @@ export default class AdminUiHandler extends FormModalUiHandler {
|
|||||||
Utils.apiPost("admin/account/discord-link", `username=${encodeURIComponent(this.inputs[0].text)}&discordId=${encodeURIComponent(this.inputs[1].text)}`, "application/x-www-form-urlencoded", true)
|
Utils.apiPost("admin/account/discord-link", `username=${encodeURIComponent(this.inputs[0].text)}&discordId=${encodeURIComponent(this.inputs[1].text)}`, "application/x-www-form-urlencoded", true)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
console.error(response);
|
return response.text();
|
||||||
}
|
}
|
||||||
this.inputs[0].setText("");
|
return response.json();
|
||||||
this.inputs[1].setText("");
|
|
||||||
this.scene.ui.revertMode();
|
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.then(response => {
|
||||||
console.error(err);
|
this.scene.ui.setMode(Mode.ADMIN, config);
|
||||||
this.scene.ui.revertMode();
|
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
import { Button } from "#enums/buttons";
|
|
||||||
import BattleScene from "../battle-scene";
|
|
||||||
import AbstractOptionSelectUiHandler from "./abstact-option-select-ui-handler";
|
|
||||||
import { Mode } from "./ui";
|
|
||||||
|
|
||||||
export default class AutoCompleteUiHandler extends AbstractOptionSelectUiHandler {
|
|
||||||
modalContainer: Phaser.GameObjects.Container;
|
|
||||||
constructor(scene: BattleScene, mode: Mode = Mode.OPTION_SELECT) {
|
|
||||||
super(scene, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
getWindowWidth(): integer {
|
|
||||||
return 64;
|
|
||||||
}
|
|
||||||
|
|
||||||
show(args: any[]): boolean {
|
|
||||||
if (args[0].modalContainer) {
|
|
||||||
const { modalContainer } = args[0];
|
|
||||||
const show = super.show(args);
|
|
||||||
this.modalContainer = modalContainer;
|
|
||||||
this.setupOptions();
|
|
||||||
|
|
||||||
return show;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected setupOptions() {
|
|
||||||
super.setupOptions();
|
|
||||||
if (this.modalContainer) {
|
|
||||||
this.optionSelectContainer.setSize(this.optionSelectContainer.height, Math.max(this.optionSelectText.displayWidth + 24, this.getWindowWidth()));
|
|
||||||
this.optionSelectContainer.setPositionRelative(this.modalContainer, this.optionSelectBg.width, this.optionSelectBg.height + 50);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
processInput(button: Button): boolean {
|
|
||||||
// the cancel and action button are here because if you're typing, x and z are used for cancel/action. This means you could be typing something and accidentally cancel/select when you don't mean to
|
|
||||||
// the submit button is therefore used to select a choice (the enter button), though this does not work on my local dev testing for phones, as for my phone/keyboard combo, the enter and z key are both
|
|
||||||
// bound to Button.ACTION, which makes this not work on mobile
|
|
||||||
if (button !== Button.CANCEL && button !== Button.ACTION) {
|
|
||||||
return super.processInput(button);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -21,8 +21,6 @@ export default class BattleMessageUiHandler extends MessageUiHandler {
|
|||||||
public movesWindowContainer: Phaser.GameObjects.Container;
|
public movesWindowContainer: Phaser.GameObjects.Container;
|
||||||
public nameBoxContainer: Phaser.GameObjects.Container;
|
public nameBoxContainer: Phaser.GameObjects.Container;
|
||||||
|
|
||||||
public readonly wordWrapWidth: number = 1780;
|
|
||||||
|
|
||||||
constructor(scene: BattleScene) {
|
constructor(scene: BattleScene) {
|
||||||
super(scene, Mode.MESSAGE);
|
super(scene, Mode.MESSAGE);
|
||||||
}
|
}
|
||||||
@ -65,7 +63,7 @@ export default class BattleMessageUiHandler extends MessageUiHandler {
|
|||||||
const message = addTextObject(this.scene, 0, 0, "", TextStyle.MESSAGE, {
|
const message = addTextObject(this.scene, 0, 0, "", TextStyle.MESSAGE, {
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
wordWrap: {
|
wordWrap: {
|
||||||
width: this.wordWrapWidth
|
width: 1780
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
messageContainer.add(message);
|
messageContainer.add(message);
|
||||||
@ -131,7 +129,7 @@ export default class BattleMessageUiHandler extends MessageUiHandler {
|
|||||||
|
|
||||||
this.commandWindow.setVisible(false);
|
this.commandWindow.setVisible(false);
|
||||||
this.movesWindowContainer.setVisible(false);
|
this.movesWindowContainer.setVisible(false);
|
||||||
this.message.setWordWrapWidth(this.wordWrapWidth);
|
this.message.setWordWrapWidth(1780);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -163,9 +161,7 @@ export default class BattleMessageUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showDialogue(text: string, name?: string, delay?: integer | null, callback?: Function, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer) {
|
showDialogue(text: string, name?: string, delay?: integer | null, callback?: Function, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer) {
|
||||||
if (name) {
|
name && this.showNameText(name);
|
||||||
this.showNameText(name);
|
|
||||||
}
|
|
||||||
super.showDialogue(text, name, delay, callback, callbackDelay, prompt, promptDelay);
|
super.showDialogue(text, name, delay, callback, callbackDelay, prompt, promptDelay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import BattleScene, { bypassLogin } from "../battle-scene";
|
|||||||
import { TextStyle, addTextObject, getTextStyleOptions } from "./text";
|
import { TextStyle, addTextObject, getTextStyleOptions } from "./text";
|
||||||
import { Mode } from "./ui";
|
import { Mode } from "./ui";
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import { addWindow, WindowVariant } from "./ui-theme";
|
import { addWindow } from "./ui-theme";
|
||||||
import MessageUiHandler from "./message-ui-handler";
|
import MessageUiHandler from "./message-ui-handler";
|
||||||
import { OptionSelectConfig, OptionSelectItem } from "./abstact-option-select-ui-handler";
|
import { OptionSelectConfig, OptionSelectItem } from "./abstact-option-select-ui-handler";
|
||||||
import { Tutorial, handleTutorial } from "../tutorial";
|
import { Tutorial, handleTutorial } from "../tutorial";
|
||||||
@ -11,7 +11,6 @@ import i18next from "i18next";
|
|||||||
import { Button } from "#enums/buttons";
|
import { Button } from "#enums/buttons";
|
||||||
import { GameDataType } from "#enums/game-data-type";
|
import { GameDataType } from "#enums/game-data-type";
|
||||||
import BgmBar from "#app/ui/bgm-bar";
|
import BgmBar from "#app/ui/bgm-bar";
|
||||||
import AwaitableUiHandler from "./awaitable-ui-handler";
|
|
||||||
|
|
||||||
enum MenuOptions {
|
enum MenuOptions {
|
||||||
GAME_SETTINGS,
|
GAME_SETTINGS,
|
||||||
@ -32,10 +31,6 @@ const githubUrl = "https://github.com/pagefaultgames/pokerogue";
|
|||||||
const redditUrl = "https://www.reddit.com/r/pokerogue";
|
const redditUrl = "https://www.reddit.com/r/pokerogue";
|
||||||
|
|
||||||
export default class MenuUiHandler extends MessageUiHandler {
|
export default class MenuUiHandler extends MessageUiHandler {
|
||||||
private readonly textPadding = 8;
|
|
||||||
private readonly defaultMessageBoxWidth = 220;
|
|
||||||
private readonly defaultWordWrapWidth = 1224;
|
|
||||||
|
|
||||||
private menuContainer: Phaser.GameObjects.Container;
|
private menuContainer: Phaser.GameObjects.Container;
|
||||||
private menuMessageBoxContainer: Phaser.GameObjects.Container;
|
private menuMessageBoxContainer: Phaser.GameObjects.Container;
|
||||||
private menuOverlay: Phaser.GameObjects.Rectangle;
|
private menuOverlay: Phaser.GameObjects.Rectangle;
|
||||||
@ -51,20 +46,17 @@ export default class MenuUiHandler extends MessageUiHandler {
|
|||||||
protected manageDataConfig: OptionSelectConfig;
|
protected manageDataConfig: OptionSelectConfig;
|
||||||
protected communityConfig: OptionSelectConfig;
|
protected communityConfig: OptionSelectConfig;
|
||||||
|
|
||||||
// Windows for the default message box and the message box for testing dialogue
|
|
||||||
private menuMessageBox: Phaser.GameObjects.NineSlice;
|
|
||||||
private dialogueMessageBox: Phaser.GameObjects.NineSlice;
|
|
||||||
|
|
||||||
protected scale: number = 0.1666666667;
|
protected scale: number = 0.1666666667;
|
||||||
|
|
||||||
public bgmBar: BgmBar;
|
public bgmBar: BgmBar;
|
||||||
|
|
||||||
|
|
||||||
constructor(scene: BattleScene, mode: Mode | null = null) {
|
constructor(scene: BattleScene, mode: Mode | null = null) {
|
||||||
super(scene, mode);
|
super(scene, mode);
|
||||||
|
|
||||||
this.excludedMenus = () => [
|
this.excludedMenus = () => [
|
||||||
{ condition: [Mode.COMMAND, Mode.TITLE].includes(mode ?? Mode.TITLE), options: [MenuOptions.EGG_GACHA, MenuOptions.EGG_LIST] },
|
{ condition: [Mode.COMMAND, Mode.TITLE].includes(mode ?? Mode.TITLE), options: [ MenuOptions.EGG_GACHA, MenuOptions.EGG_LIST] },
|
||||||
{ condition: bypassLogin, options: [MenuOptions.LOG_OUT] }
|
{ condition: bypassLogin, options: [ MenuOptions.LOG_OUT ] }
|
||||||
];
|
];
|
||||||
|
|
||||||
this.menuOptions = Utils.getEnumKeys(MenuOptions)
|
this.menuOptions = Utils.getEnumKeys(MenuOptions)
|
||||||
@ -106,8 +98,8 @@ export default class MenuUiHandler extends MessageUiHandler {
|
|||||||
render() {
|
render() {
|
||||||
const ui = this.getUi();
|
const ui = this.getUi();
|
||||||
this.excludedMenus = () => [
|
this.excludedMenus = () => [
|
||||||
{ condition: ![Mode.COMMAND, Mode.TITLE].includes(ui.getModeChain()[0]), options: [MenuOptions.EGG_GACHA, MenuOptions.EGG_LIST] },
|
{ condition: ![Mode.COMMAND, Mode.TITLE].includes(ui.getModeChain()[0]), options: [ MenuOptions.EGG_GACHA, MenuOptions.EGG_LIST] },
|
||||||
{ condition: bypassLogin, options: [MenuOptions.LOG_OUT] }
|
{ condition: bypassLogin, options: [ MenuOptions.LOG_OUT ] }
|
||||||
];
|
];
|
||||||
|
|
||||||
this.menuOptions = Utils.getEnumKeys(MenuOptions)
|
this.menuOptions = Utils.getEnumKeys(MenuOptions)
|
||||||
@ -123,12 +115,12 @@ export default class MenuUiHandler extends MessageUiHandler {
|
|||||||
this.menuBg = addWindow(this.scene,
|
this.menuBg = addWindow(this.scene,
|
||||||
(this.scene.game.canvas.width / 6) - (this.optionSelectText.displayWidth + 25),
|
(this.scene.game.canvas.width / 6) - (this.optionSelectText.displayWidth + 25),
|
||||||
0,
|
0,
|
||||||
this.optionSelectText.displayWidth + 19 + 24 * this.scale,
|
this.optionSelectText.displayWidth + 19+24*this.scale,
|
||||||
(this.scene.game.canvas.height / 6) - 2
|
(this.scene.game.canvas.height / 6) - 2
|
||||||
);
|
);
|
||||||
this.menuBg.setOrigin(0, 0);
|
this.menuBg.setOrigin(0, 0);
|
||||||
|
|
||||||
this.optionSelectText.setPositionRelative(this.menuBg, 10 + 24 * this.scale, 6);
|
this.optionSelectText.setPositionRelative(this.menuBg, 10+24*this.scale, 6);
|
||||||
|
|
||||||
this.menuContainer.add(this.menuBg);
|
this.menuContainer.add(this.menuBg);
|
||||||
|
|
||||||
@ -139,27 +131,20 @@ export default class MenuUiHandler extends MessageUiHandler {
|
|||||||
this.menuMessageBoxContainer = this.scene.add.container(0, 130);
|
this.menuMessageBoxContainer = this.scene.add.container(0, 130);
|
||||||
this.menuMessageBoxContainer.setName("menu-message-box");
|
this.menuMessageBoxContainer.setName("menu-message-box");
|
||||||
this.menuMessageBoxContainer.setVisible(false);
|
this.menuMessageBoxContainer.setVisible(false);
|
||||||
|
this.menuContainer.add(this.menuMessageBoxContainer);
|
||||||
|
|
||||||
// Window for general messages
|
const menuMessageBox = addWindow(this.scene, 0, -0, 220, 48);
|
||||||
this.menuMessageBox = addWindow(this.scene, 0, 0, this.defaultMessageBoxWidth, 48);
|
menuMessageBox.setOrigin(0, 0);
|
||||||
this.menuMessageBox.setOrigin(0, 0);
|
this.menuMessageBoxContainer.add(menuMessageBox);
|
||||||
this.menuMessageBoxContainer.add(this.menuMessageBox);
|
|
||||||
|
|
||||||
// Full-width window used for testing dialog messages in debug mode
|
const menuMessageText = addTextObject(this.scene, 8, 8, "", TextStyle.WINDOW, { maxLines: 2 });
|
||||||
this.dialogueMessageBox = addWindow(this.scene, -this.textPadding, 0, this.scene.game.canvas.width / 6 + this.textPadding * 2, 49, false, false, 0, 0, WindowVariant.THIN);
|
|
||||||
this.dialogueMessageBox.setOrigin(0, 0);
|
|
||||||
this.menuMessageBoxContainer.add(this.dialogueMessageBox);
|
|
||||||
|
|
||||||
const menuMessageText = addTextObject(this.scene, this.textPadding, this.textPadding, "", TextStyle.WINDOW, { maxLines: 2 });
|
|
||||||
menuMessageText.setName("menu-message");
|
menuMessageText.setName("menu-message");
|
||||||
|
menuMessageText.setWordWrapWidth(1224);
|
||||||
menuMessageText.setOrigin(0, 0);
|
menuMessageText.setOrigin(0, 0);
|
||||||
this.menuMessageBoxContainer.add(menuMessageText);
|
this.menuMessageBoxContainer.add(menuMessageText);
|
||||||
|
|
||||||
this.message = menuMessageText;
|
this.message = menuMessageText;
|
||||||
|
|
||||||
// By default we use the general purpose message window
|
|
||||||
this.setDialogTestMode(false);
|
|
||||||
|
|
||||||
this.menuContainer.add(this.menuMessageBoxContainer);
|
this.menuContainer.add(this.menuMessageBoxContainer);
|
||||||
|
|
||||||
const manageDataOptions: any[] = []; // TODO: proper type
|
const manageDataOptions: any[] = []; // TODO: proper type
|
||||||
@ -170,7 +155,7 @@ export default class MenuUiHandler extends MessageUiHandler {
|
|||||||
const config: OptionSelectConfig = {
|
const config: OptionSelectConfig = {
|
||||||
options: new Array(5).fill(null).map((_, i) => i).filter(slotFilter).map(i => {
|
options: new Array(5).fill(null).map((_, i) => i).filter(slotFilter).map(i => {
|
||||||
return {
|
return {
|
||||||
label: i18next.t("menuUiHandler:slot", { slotNumber: i + 1 }),
|
label: i18next.t("menuUiHandler:slot", {slotNumber: i+1}),
|
||||||
handler: () => {
|
handler: () => {
|
||||||
callback(i);
|
callback(i);
|
||||||
ui.revertMode();
|
ui.revertMode();
|
||||||
@ -272,55 +257,8 @@ export default class MenuUiHandler extends MessageUiHandler {
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
keepOpen: true
|
keepOpen: true
|
||||||
});
|
|
||||||
if (Utils.isLocal || Utils.isBeta) { // this should make sure we don't have this option in live
|
|
||||||
manageDataOptions.push({
|
|
||||||
label: "Test Dialogue",
|
|
||||||
handler: () => {
|
|
||||||
ui.playSelect();
|
|
||||||
const prefilledText = "";
|
|
||||||
const buttonAction: any = {};
|
|
||||||
buttonAction["buttonActions"] = [
|
|
||||||
(sanitizedName: string) => {
|
|
||||||
ui.revertMode();
|
|
||||||
ui.playSelect();
|
|
||||||
const dialogueTestName = sanitizedName;
|
|
||||||
const dialogueName = decodeURIComponent(escape(atob(dialogueTestName)));
|
|
||||||
const handler = ui.getHandler() as AwaitableUiHandler;
|
|
||||||
handler.tutorialActive = true;
|
|
||||||
const interpolatorOptions: any = {};
|
|
||||||
const splitArr = dialogueName.split(" "); // this splits our inputted text into words to cycle through later
|
|
||||||
const translatedString = splitArr[0]; // this is our outputted i18 string
|
|
||||||
const regex = RegExp("\\{\\{(\\w*)\\}\\}", "g"); // this is a regex expression to find all the text between {{ }} in the i18 output
|
|
||||||
const matches = i18next.t(translatedString).match(regex) ?? [];
|
|
||||||
if (matches.length > 0) {
|
|
||||||
for (let match = 0; match < matches.length; match++) {
|
|
||||||
// we add 1 here because splitArr[0] is our first value for the translatedString, and after that is where the variables are
|
|
||||||
// the regex here in the replace (/\W/g) is to remove the {{ and }} and just give us all alphanumeric characters
|
|
||||||
if (typeof splitArr[match + 1] !== "undefined") {
|
|
||||||
interpolatorOptions[matches[match].replace(/\W/g, "")] = i18next.t(splitArr[match + 1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Switch to the dialog test window
|
|
||||||
this.setDialogTestMode(true);
|
|
||||||
ui.showText(String(i18next.t(translatedString, interpolatorOptions)), null, () => this.scene.ui.showText("", 0, () => {
|
|
||||||
handler.tutorialActive = false;
|
|
||||||
// Go back to the default message window
|
|
||||||
this.setDialogTestMode(false);
|
|
||||||
}), null, true);
|
|
||||||
},
|
},
|
||||||
() => {
|
{
|
||||||
ui.revertMode();
|
|
||||||
}
|
|
||||||
];
|
|
||||||
ui.setMode(Mode.TEST_DIALOGUE, buttonAction, prefilledText);
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
keepOpen: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
manageDataOptions.push({
|
|
||||||
label: i18next.t("menuUiHandler:cancel"),
|
label: i18next.t("menuUiHandler:cancel"),
|
||||||
handler: () => {
|
handler: () => {
|
||||||
this.scene.ui.revertMode();
|
this.scene.ui.revertMode();
|
||||||
@ -483,7 +421,7 @@ export default class MenuUiHandler extends MessageUiHandler {
|
|||||||
break;
|
break;
|
||||||
case MenuOptions.MANAGE_DATA:
|
case MenuOptions.MANAGE_DATA:
|
||||||
if (!bypassLogin && !this.manageDataConfig.options.some(o => o.label === i18next.t("menuUiHandler:linkDiscord") || o.label === i18next.t("menuUiHandler:unlinkDiscord"))) {
|
if (!bypassLogin && !this.manageDataConfig.options.some(o => o.label === i18next.t("menuUiHandler:linkDiscord") || o.label === i18next.t("menuUiHandler:unlinkDiscord"))) {
|
||||||
this.manageDataConfig.options.splice(this.manageDataConfig.options.length - 1, 0,
|
this.manageDataConfig.options.splice(this.manageDataConfig.options.length-1, 0,
|
||||||
{
|
{
|
||||||
label: loggedInUser?.discordId === "" ? i18next.t("menuUiHandler:linkDiscord") : i18next.t("menuUiHandler:unlinkDiscord"),
|
label: loggedInUser?.discordId === "" ? i18next.t("menuUiHandler:linkDiscord") : i18next.t("menuUiHandler:unlinkDiscord"),
|
||||||
handler: () => {
|
handler: () => {
|
||||||
@ -609,21 +547,6 @@ export default class MenuUiHandler extends MessageUiHandler {
|
|||||||
return success || error;
|
return success || error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Switch the message window style and size when we are replaying dialog for debug purposes
|
|
||||||
* In "dialog test mode", the window takes the whole width of the screen and the text
|
|
||||||
* is set up to wrap around the same way as the dialogue during the game
|
|
||||||
* @param isDialogMode whether to use the dialog test
|
|
||||||
*/
|
|
||||||
setDialogTestMode(isDialogMode: boolean) {
|
|
||||||
this.menuMessageBox.setVisible(!isDialogMode);
|
|
||||||
this.dialogueMessageBox.setVisible(isDialogMode);
|
|
||||||
// If we're testing dialog, we use the same word wrapping as the battle message handler
|
|
||||||
this.message.setWordWrapWidth(isDialogMode ? this.scene.ui.getMessageHandler().wordWrapWidth : this.defaultWordWrapWidth);
|
|
||||||
this.message.setX(isDialogMode ? this.textPadding + 1 : this.textPadding);
|
|
||||||
this.message.setY(isDialogMode ? this.textPadding + 0.4 : this.textPadding);
|
|
||||||
}
|
|
||||||
|
|
||||||
showText(text: string, delay?: number, callback?: Function, callbackDelay?: number, prompt?: boolean, promptDelay?: number): void {
|
showText(text: string, delay?: number, callback?: Function, callbackDelay?: number, prompt?: boolean, promptDelay?: number): void {
|
||||||
this.menuMessageBoxContainer.setVisible(!!text);
|
this.menuMessageBoxContainer.setVisible(!!text);
|
||||||
|
|
||||||
|
@ -374,14 +374,23 @@ export default class RunInfoUiHandler extends UiHandler {
|
|||||||
case GameModes.CHALLENGE:
|
case GameModes.CHALLENGE:
|
||||||
modeText.appendText(`${i18next.t("gameMode:challenge")}`, false);
|
modeText.appendText(`${i18next.t("gameMode:challenge")}`, false);
|
||||||
modeText.appendText(`\t\t${i18next.t("runHistory:challengeRules")}: `);
|
modeText.appendText(`\t\t${i18next.t("runHistory:challengeRules")}: `);
|
||||||
const rules: string[] = this.challengeParser();
|
const runChallenges = this.runInfo.challenges;
|
||||||
|
const rules: string[] = [];
|
||||||
|
for (let i = 0; i < runChallenges.length; i++) {
|
||||||
|
if (runChallenges[i].id === Challenges.SINGLE_GENERATION && runChallenges[i].value !== 0) {
|
||||||
|
rules.push(i18next.t(`runHistory:challengeMonoGen${runChallenges[i].value}`));
|
||||||
|
} else if (runChallenges[i].id === Challenges.SINGLE_TYPE && runChallenges[i].value !== 0) {
|
||||||
|
rules.push(i18next.t(`pokemonInfo:Type.${Type[runChallenges[i].value-1]}` as const));
|
||||||
|
} else if (runChallenges[i].id === Challenges.FRESH_START && runChallenges[i].value !== 0) {
|
||||||
|
rules.push(i18next.t("challenges:freshStart.name"));
|
||||||
|
}
|
||||||
|
}
|
||||||
if (rules) {
|
if (rules) {
|
||||||
for (let i = 0; i < rules.length; i++) {
|
for (let i = 0; i < rules.length; i++) {
|
||||||
const newline = i > 0 && i%2 === 0;
|
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
modeText.appendText(" + ", newline);
|
modeText.appendText(" + ", false);
|
||||||
}
|
}
|
||||||
modeText.appendText(rules[i], newline);
|
modeText.appendText(rules[i], false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -457,34 +466,6 @@ export default class RunInfoUiHandler extends UiHandler {
|
|||||||
this.runContainer.add(this.runInfoContainer);
|
this.runContainer.add(this.runInfoContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This function parses the Challenges section of the Run Entry and returns a list of active challenge.
|
|
||||||
* @return string[] of active challenge names
|
|
||||||
*/
|
|
||||||
private challengeParser(): string[] {
|
|
||||||
const rules: string[] = [];
|
|
||||||
for (let i = 0; i < this.runInfo.challenges.length; i++) {
|
|
||||||
if (this.runInfo.challenges[i].value !== 0) {
|
|
||||||
switch (this.runInfo.challenges[i].id) {
|
|
||||||
case Challenges.SINGLE_GENERATION:
|
|
||||||
rules.push(i18next.t(`runHistory:challengeMonoGen${this.runInfo.challenges[i].value}`));
|
|
||||||
break;
|
|
||||||
case Challenges.SINGLE_TYPE:
|
|
||||||
rules.push(i18next.t(`pokemonInfo:Type.${Type[this.runInfo.challenges[i].value-1]}` as const));
|
|
||||||
break;
|
|
||||||
case Challenges.FRESH_START:
|
|
||||||
rules.push(i18next.t("challenges:freshStart.name"));
|
|
||||||
break;
|
|
||||||
case Challenges.INVERSE_BATTLE:
|
|
||||||
//
|
|
||||||
rules.push(i18next.t("challenges:inverseBattle.shortName").split("").reverse().join(""));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rules;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses and displays the run's player party.
|
* Parses and displays the run's player party.
|
||||||
* Default Information: Icon, Level, Nature, Ability, Passive, Shiny Status, Fusion Status, Stats, and Moves.
|
* Default Information: Icon, Level, Nature, Ability, Passive, Shiny Status, Fusion Status, Stats, and Moves.
|
||||||
|
@ -915,9 +915,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.allSpecies.forEach((species, s) => {
|
this.allSpecies.forEach((species, s) => {
|
||||||
const icon = this.starterContainers[s].icon;
|
const icon = this.starterContainers[s].icon;
|
||||||
const dexEntry = this.scene.gameData.dexData[species.speciesId];
|
const dexEntry = this.scene.gameData.dexData[species.speciesId];
|
||||||
|
this.starterPreferences[species.speciesId] = this.starterPreferences[species.speciesId] ?? {};
|
||||||
// Initialize the StarterAttributes for this species
|
|
||||||
this.starterPreferences[species.speciesId] = this.initStarterPrefs(species);
|
|
||||||
|
|
||||||
if (dexEntry.caughtAttr) {
|
if (dexEntry.caughtAttr) {
|
||||||
icon.clearTint();
|
icon.clearTint();
|
||||||
@ -944,93 +942,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the starter attributes for the given PokemonSpecies, after sanitizing them.
|
|
||||||
* If somehow a preference is set for a form, variant, gender, ability or nature
|
|
||||||
* that wasn't actually unlocked or is invalid it will be cleared here
|
|
||||||
*
|
|
||||||
* @param species The species to get Starter Preferences for
|
|
||||||
* @returns StarterAttributes for the species
|
|
||||||
*/
|
|
||||||
initStarterPrefs(species: PokemonSpecies): StarterAttributes {
|
|
||||||
const starterAttributes = this.starterPreferences[species.speciesId];
|
|
||||||
const dexEntry = this.scene.gameData.dexData[species.speciesId];
|
|
||||||
const starterData = this.scene.gameData.starterData[species.speciesId];
|
|
||||||
|
|
||||||
// no preferences or Pokemon wasn't caught, return empty attribute
|
|
||||||
if (!starterAttributes || !dexEntry.caughtAttr) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const caughtAttr = dexEntry.caughtAttr;
|
|
||||||
|
|
||||||
const hasShiny = caughtAttr & DexAttr.SHINY;
|
|
||||||
const hasNonShiny = caughtAttr & DexAttr.NON_SHINY;
|
|
||||||
if (starterAttributes.shiny && !hasShiny) {
|
|
||||||
// shiny form wasn't unlocked, purging shiny and variant setting
|
|
||||||
delete starterAttributes.shiny;
|
|
||||||
delete starterAttributes.variant;
|
|
||||||
} else if (starterAttributes.shiny === false && !hasNonShiny) {
|
|
||||||
// non shiny form wasn't unlocked, purging shiny setting
|
|
||||||
delete starterAttributes.shiny;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (starterAttributes.variant !== undefined && !isNaN(starterAttributes.variant)) {
|
|
||||||
const unlockedVariants = [
|
|
||||||
hasNonShiny,
|
|
||||||
hasShiny && caughtAttr & DexAttr.DEFAULT_VARIANT,
|
|
||||||
hasShiny && caughtAttr & DexAttr.VARIANT_2,
|
|
||||||
hasShiny && caughtAttr & DexAttr.VARIANT_3
|
|
||||||
];
|
|
||||||
if (!unlockedVariants[starterAttributes.variant + 1]) { // add 1 as -1 = non-shiny
|
|
||||||
// requested variant wasn't unlocked, purging setting
|
|
||||||
delete starterAttributes.variant;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (starterAttributes.female !== undefined) {
|
|
||||||
if (!(starterAttributes.female ? caughtAttr & DexAttr.FEMALE : caughtAttr & DexAttr.MALE)) {
|
|
||||||
// requested gender wasn't unlocked, purging setting
|
|
||||||
delete starterAttributes.female;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (starterAttributes.ability !== undefined) {
|
|
||||||
const speciesHasSingleAbility = species.ability2 === species.ability1;
|
|
||||||
const abilityAttr = starterData.abilityAttr;
|
|
||||||
const hasAbility1 = abilityAttr & AbilityAttr.ABILITY_1;
|
|
||||||
const hasAbility2 = abilityAttr & AbilityAttr.ABILITY_2;
|
|
||||||
const hasHiddenAbility = abilityAttr & AbilityAttr.ABILITY_HIDDEN;
|
|
||||||
// Due to a past bug it is possible that some Pokemon with a single ability have the ability2 flag
|
|
||||||
// In this case, we only count ability2 as valid if ability1 was not unlocked, otherwise we ignore it
|
|
||||||
const unlockedAbilities = [
|
|
||||||
hasAbility1,
|
|
||||||
speciesHasSingleAbility ? hasAbility2 && !hasAbility1 : hasAbility2,
|
|
||||||
hasHiddenAbility
|
|
||||||
];
|
|
||||||
if (!unlockedAbilities[starterAttributes.ability]) {
|
|
||||||
// requested ability wasn't unlocked, purging setting
|
|
||||||
delete starterAttributes.ability;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedForm = starterAttributes.form;
|
|
||||||
if (selectedForm !== undefined && (!species.forms[selectedForm]?.isStarterSelectable || !(caughtAttr & this.scene.gameData.getFormAttr(selectedForm)))) {
|
|
||||||
// requested form wasn't unlocked/isn't a starter form, purging setting
|
|
||||||
delete starterAttributes.form;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (starterAttributes.nature !== undefined) {
|
|
||||||
const unlockedNatures = this.scene.gameData.getNaturesForAttr(dexEntry.natureAttr);
|
|
||||||
if (unlockedNatures.indexOf(starterAttributes.nature as unknown as Nature) < 0) {
|
|
||||||
// requested nature wasn't unlocked, purging setting
|
|
||||||
delete starterAttributes.nature;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return starterAttributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the selections for all filters to their default starting value
|
* Set the selections for all filters to their default starting value
|
||||||
*/
|
*/
|
||||||
@ -1838,9 +1749,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
switch (button) {
|
switch (button) {
|
||||||
case Button.CYCLE_SHINY:
|
case Button.CYCLE_SHINY:
|
||||||
if (this.canCycleShiny) {
|
if (this.canCycleShiny) {
|
||||||
const newVariant = starterAttributes.variant ? starterAttributes.variant as Variant : props.variant;
|
const newVariant = props.variant;
|
||||||
starterAttributes.shiny = starterAttributes.shiny ? !starterAttributes.shiny : true;
|
starterAttributes.shiny = starterAttributes.shiny ? !starterAttributes.shiny : true;
|
||||||
this.setSpeciesDetails(this.lastSpecies, !props.shiny, undefined, undefined, props.shiny ? 0 : newVariant, undefined, undefined);
|
this.setSpeciesDetails(this.lastSpecies, !props.shiny, undefined, undefined, props.shiny ? 0 : undefined, undefined, undefined);
|
||||||
if (starterAttributes.shiny) {
|
if (starterAttributes.shiny) {
|
||||||
this.scene.playSound("se/sparkle");
|
this.scene.playSound("se/sparkle");
|
||||||
// Set the variant label to the shiny tint
|
// Set the variant label to the shiny tint
|
||||||
@ -1849,6 +1760,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonShinyIcon.setTint(tint);
|
this.pokemonShinyIcon.setTint(tint);
|
||||||
this.pokemonShinyIcon.setVisible(true);
|
this.pokemonShinyIcon.setVisible(true);
|
||||||
} else {
|
} else {
|
||||||
|
// starterAttributes.variant = 0;
|
||||||
|
if (starterAttributes?.variant) {
|
||||||
|
delete starterAttributes.variant;
|
||||||
|
}
|
||||||
this.pokemonShinyIcon.setVisible(false);
|
this.pokemonShinyIcon.setVisible(false);
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
@ -2361,39 +2276,43 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
container.cost = this.scene.gameData.getSpeciesStarterValue(container.species.speciesId);
|
container.cost = this.scene.gameData.getSpeciesStarterValue(container.species.speciesId);
|
||||||
|
|
||||||
// First, ensure you have the caught attributes for the species else default to bigint 0
|
// First, ensure you have the caught attributes for the species else default to bigint 0
|
||||||
const caughtAttr = this.scene.gameData.dexData[container.species.speciesId]?.caughtAttr || BigInt(0);
|
const isCaught = this.scene.gameData.dexData[container.species.speciesId]?.caughtAttr || BigInt(0);
|
||||||
const starterData = this.scene.gameData.starterData[container.species.speciesId];
|
|
||||||
|
// Define the variables based on whether their respective variants have been caught
|
||||||
|
const isVariant3Caught = !!(isCaught & DexAttr.VARIANT_3);
|
||||||
|
const isVariant2Caught = !!(isCaught & DexAttr.VARIANT_2);
|
||||||
|
const isVariantCaught = !!(isCaught & DexAttr.SHINY);
|
||||||
|
const isUncaught = !isCaught && !isVariantCaught && !isVariant2Caught && !isVariant3Caught;
|
||||||
|
const isPassiveUnlocked = this.scene.gameData.starterData[container.species.speciesId].passiveAttr > 0;
|
||||||
|
const isPassiveUnlockable = this.isPassiveAvailable(container.species.speciesId) && !isPassiveUnlocked;
|
||||||
|
const isCostReduced = this.scene.gameData.starterData[container.species.speciesId].valueReduction > 0;
|
||||||
|
const isCostReductionUnlockable = this.isValueReductionAvailable(container.species.speciesId);
|
||||||
|
const isFavorite = this.starterPreferences[container.species.speciesId]?.favorite ?? false;
|
||||||
|
|
||||||
|
const isWin = this.scene.gameData.starterData[container.species.speciesId].classicWinCount > 0;
|
||||||
|
const isNotWin = this.scene.gameData.starterData[container.species.speciesId].classicWinCount === 0;
|
||||||
|
const isUndefined = this.scene.gameData.starterData[container.species.speciesId].classicWinCount === undefined;
|
||||||
|
const isHA = this.scene.gameData.starterData[container.species.speciesId].abilityAttr & AbilityAttr.ABILITY_HIDDEN;
|
||||||
|
const isEggPurchasable = this.isSameSpeciesEggAvailable(container.species.speciesId);
|
||||||
|
|
||||||
// Gen filter
|
|
||||||
const fitsGen = this.filterBar.getVals(DropDownColumn.GEN).includes(container.species.generation);
|
const fitsGen = this.filterBar.getVals(DropDownColumn.GEN).includes(container.species.generation);
|
||||||
|
|
||||||
// Type filter
|
|
||||||
const fitsType = this.filterBar.getVals(DropDownColumn.TYPES).some(type => container.species.isOfType((type as number) - 1));
|
const fitsType = this.filterBar.getVals(DropDownColumn.TYPES).some(type => container.species.isOfType((type as number) - 1));
|
||||||
|
|
||||||
// Caught / Shiny filter
|
|
||||||
const isNonShinyCaught = !!(caughtAttr & DexAttr.NON_SHINY);
|
|
||||||
const isShinyCaught = !!(caughtAttr & DexAttr.SHINY);
|
|
||||||
const isVariant1Caught = isShinyCaught && !!(caughtAttr & DexAttr.DEFAULT_VARIANT);
|
|
||||||
const isVariant2Caught = isShinyCaught && !!(caughtAttr & DexAttr.VARIANT_2);
|
|
||||||
const isVariant3Caught = isShinyCaught && !!(caughtAttr & DexAttr.VARIANT_3);
|
|
||||||
const isUncaught = !isNonShinyCaught && !isVariant1Caught && !isVariant2Caught && !isVariant3Caught;
|
|
||||||
const fitsCaught = this.filterBar.getVals(DropDownColumn.CAUGHT).some(caught => {
|
const fitsCaught = this.filterBar.getVals(DropDownColumn.CAUGHT).some(caught => {
|
||||||
if (caught === "SHINY3") {
|
if (caught === "SHINY3") {
|
||||||
return isVariant3Caught;
|
return isVariant3Caught;
|
||||||
} else if (caught === "SHINY2") {
|
} else if (caught === "SHINY2") {
|
||||||
return isVariant2Caught && !isVariant3Caught;
|
return isVariant2Caught && !isVariant3Caught;
|
||||||
} else if (caught === "SHINY") {
|
} else if (caught === "SHINY") {
|
||||||
return isVariant1Caught && !isVariant2Caught && !isVariant3Caught;
|
return isVariantCaught && !isVariant2Caught && !isVariant3Caught;
|
||||||
} else if (caught === "NORMAL") {
|
} else if (caught === "NORMAL") {
|
||||||
return isNonShinyCaught && !isVariant1Caught && !isVariant2Caught && !isVariant3Caught;
|
return isCaught && !isVariantCaught && !isVariant2Caught && !isVariant3Caught;
|
||||||
} else if (caught === "UNCAUGHT") {
|
} else if (caught === "UNCAUGHT") {
|
||||||
return isUncaught;
|
return isUncaught;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Passive Filter
|
|
||||||
const isPassiveUnlocked = starterData.passiveAttr > 0;
|
|
||||||
const isPassiveUnlockable = this.isPassiveAvailable(container.species.speciesId) && !isPassiveUnlocked;
|
|
||||||
const fitsPassive = this.filterBar.getVals(DropDownColumn.UNLOCKS).some(unlocks => {
|
const fitsPassive = this.filterBar.getVals(DropDownColumn.UNLOCKS).some(unlocks => {
|
||||||
if (unlocks.val === "PASSIVE" && unlocks.state === DropDownState.ON) {
|
if (unlocks.val === "PASSIVE" && unlocks.state === DropDownState.ON) {
|
||||||
return isPassiveUnlocked;
|
return isPassiveUnlocked;
|
||||||
@ -2406,9 +2325,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Cost Reduction Filter
|
|
||||||
const isCostReduced = starterData.valueReduction > 0;
|
|
||||||
const isCostReductionUnlockable = this.isValueReductionAvailable(container.species.speciesId);
|
|
||||||
const fitsCostReduction = this.filterBar.getVals(DropDownColumn.UNLOCKS).some(unlocks => {
|
const fitsCostReduction = this.filterBar.getVals(DropDownColumn.UNLOCKS).some(unlocks => {
|
||||||
if (unlocks.val === "COST_REDUCTION" && unlocks.state === DropDownState.ON) {
|
if (unlocks.val === "COST_REDUCTION" && unlocks.state === DropDownState.ON) {
|
||||||
return isCostReduced;
|
return isCostReduced;
|
||||||
@ -2421,8 +2337,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Favorite Filter
|
|
||||||
const isFavorite = this.starterPreferences[container.species.speciesId]?.favorite ?? false;
|
|
||||||
const fitsFavorite = this.filterBar.getVals(DropDownColumn.MISC).some(misc => {
|
const fitsFavorite = this.filterBar.getVals(DropDownColumn.MISC).some(misc => {
|
||||||
if (misc.val === "FAVORITE" && misc.state === DropDownState.ON) {
|
if (misc.val === "FAVORITE" && misc.state === DropDownState.ON) {
|
||||||
return isFavorite;
|
return isFavorite;
|
||||||
@ -2435,34 +2349,28 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Ribbon / Classic Win Filter
|
|
||||||
const hasWon = starterData.classicWinCount > 0;
|
|
||||||
const hasNotWon = starterData.classicWinCount === 0;
|
|
||||||
const isUndefined = starterData.classicWinCount === undefined;
|
|
||||||
const fitsWin = this.filterBar.getVals(DropDownColumn.MISC).some(misc => {
|
const fitsWin = this.filterBar.getVals(DropDownColumn.MISC).some(misc => {
|
||||||
|
if (container.species.speciesId < 10) {
|
||||||
|
}
|
||||||
if (misc.val === "WIN" && misc.state === DropDownState.ON) {
|
if (misc.val === "WIN" && misc.state === DropDownState.ON) {
|
||||||
return hasWon;
|
return isWin;
|
||||||
} else if (misc.val === "WIN" && misc.state === DropDownState.EXCLUDE) {
|
} else if (misc.val === "WIN" && misc.state === DropDownState.EXCLUDE) {
|
||||||
return hasNotWon || isUndefined;
|
return isNotWin || isUndefined;
|
||||||
} else if (misc.val === "WIN" && misc.state === DropDownState.OFF) {
|
} else if (misc.val === "WIN" && misc.state === DropDownState.OFF) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// HA Filter
|
|
||||||
const hasHA = starterData.abilityAttr & AbilityAttr.ABILITY_HIDDEN;
|
|
||||||
const fitsHA = this.filterBar.getVals(DropDownColumn.MISC).some(misc => {
|
const fitsHA = this.filterBar.getVals(DropDownColumn.MISC).some(misc => {
|
||||||
if (misc.val === "HIDDEN_ABILITY" && misc.state === DropDownState.ON) {
|
if (misc.val === "HIDDEN_ABILITY" && misc.state === DropDownState.ON) {
|
||||||
return hasHA;
|
return isHA;
|
||||||
} else if (misc.val === "HIDDEN_ABILITY" && misc.state === DropDownState.EXCLUDE) {
|
} else if (misc.val === "HIDDEN_ABILITY" && misc.state === DropDownState.EXCLUDE) {
|
||||||
return !hasHA;
|
return !isHA;
|
||||||
} else if (misc.val === "HIDDEN_ABILITY" && misc.state === DropDownState.OFF) {
|
} else if (misc.val === "HIDDEN_ABILITY" && misc.state === DropDownState.OFF) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Egg Purchasable Filter
|
|
||||||
const isEggPurchasable = this.isSameSpeciesEggAvailable(container.species.speciesId);
|
|
||||||
const fitsEgg = this.filterBar.getVals(DropDownColumn.MISC).some(misc => {
|
const fitsEgg = this.filterBar.getVals(DropDownColumn.MISC).some(misc => {
|
||||||
if (misc.val === "EGG" && misc.state === DropDownState.ON) {
|
if (misc.val === "EGG" && misc.state === DropDownState.ON) {
|
||||||
return isEggPurchasable;
|
return isEggPurchasable;
|
||||||
@ -2473,7 +2381,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Pokerus Filter
|
|
||||||
const fitsPokerus = this.filterBar.getVals(DropDownColumn.MISC).some(misc => {
|
const fitsPokerus = this.filterBar.getVals(DropDownColumn.MISC).some(misc => {
|
||||||
if (misc.val === "POKERUS" && misc.state === DropDownState.ON) {
|
if (misc.val === "POKERUS" && misc.state === DropDownState.ON) {
|
||||||
return this.pokerusSpecies.includes(container.species);
|
return this.pokerusSpecies.includes(container.species);
|
||||||
@ -2672,13 +2579,56 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.natureCursor = species ? this.scene.gameData.getSpeciesDefaultNature(species) : 0;
|
this.natureCursor = species ? this.scene.gameData.getSpeciesDefaultNature(species) : 0;
|
||||||
|
|
||||||
const starterAttributes : StarterAttributes | null = species ? {...this.starterPreferences[species.speciesId]} : null;
|
const starterAttributes : StarterAttributes | null = species ? {...this.starterPreferences[species.speciesId]} : null;
|
||||||
|
// validate starterAttributes
|
||||||
|
if (starterAttributes) {
|
||||||
|
// this may cause changes so we created a copy of the attributes before
|
||||||
|
if (starterAttributes.variant && !isNaN(starterAttributes.variant)) {
|
||||||
|
if (![
|
||||||
|
this.speciesStarterDexEntry!.caughtAttr & DexAttr.NON_SHINY, // TODO: is that bang correct?
|
||||||
|
this.speciesStarterDexEntry!.caughtAttr & DexAttr.DEFAULT_VARIANT, // TODO: is that bang correct?
|
||||||
|
this.speciesStarterDexEntry!.caughtAttr & DexAttr.VARIANT_2, // TODO: is that bang correct?
|
||||||
|
this.speciesStarterDexEntry!.caughtAttr & DexAttr.VARIANT_3 // TODO: is that bang correct?
|
||||||
|
][starterAttributes.variant+1]) { // add 1 as -1 = non-shiny
|
||||||
|
// requested variant wasn't unlocked, purging setting
|
||||||
|
delete starterAttributes.variant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof starterAttributes.female !== "boolean" || !(starterAttributes.female ?
|
||||||
|
this.speciesStarterDexEntry!.caughtAttr & DexAttr.FEMALE : // TODO: is this bang correct?
|
||||||
|
this.speciesStarterDexEntry!.caughtAttr & DexAttr.MALE // TODO: is this bang correct?
|
||||||
|
)) {
|
||||||
|
// requested gender wasn't unlocked, purging setting
|
||||||
|
delete starterAttributes.female;
|
||||||
|
}
|
||||||
|
|
||||||
|
const abilityAttr = this.scene.gameData.starterData[species!.speciesId].abilityAttr; // TODO: is this bang correct?
|
||||||
|
if (![
|
||||||
|
abilityAttr & AbilityAttr.ABILITY_1,
|
||||||
|
species!.ability2 ? (abilityAttr & AbilityAttr.ABILITY_2) : abilityAttr & AbilityAttr.ABILITY_HIDDEN, // TODO: is this bang correct?
|
||||||
|
species!.ability2 && abilityAttr & AbilityAttr.ABILITY_HIDDEN // TODO: is this bang correct?
|
||||||
|
][starterAttributes.ability!]) { // TODO: is this bang correct?
|
||||||
|
// requested ability wasn't unlocked, purging setting
|
||||||
|
delete starterAttributes.ability;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(species?.forms[starterAttributes.form!]?.isStarterSelectable && this.speciesStarterDexEntry!.caughtAttr & this.scene.gameData.getFormAttr(starterAttributes.form!))) { // TODO: are those bangs correct?
|
||||||
|
// requested form wasn't unlocked/isn't a starter form, purging setting
|
||||||
|
delete starterAttributes.form;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.scene.gameData.getNaturesForAttr(this.speciesStarterDexEntry?.natureAttr).indexOf(starterAttributes.nature as unknown as Nature) < 0) {
|
||||||
|
// requested nature wasn't unlocked, purging setting
|
||||||
|
delete starterAttributes.nature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (starterAttributes?.nature) {
|
if (starterAttributes?.nature) {
|
||||||
// load default nature from stater save data, if set
|
// load default nature from stater save data, if set
|
||||||
this.natureCursor = starterAttributes.nature;
|
this.natureCursor = starterAttributes.nature;
|
||||||
}
|
}
|
||||||
if (starterAttributes?.ability && !isNaN(starterAttributes.ability)) {
|
if (starterAttributes?.ability && !isNaN(starterAttributes.ability)) {
|
||||||
// load default ability from stater save data, if set
|
// load default nature from stater save data, if set
|
||||||
this.abilityCursor = starterAttributes.ability;
|
this.abilityCursor = starterAttributes.ability;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2725,6 +2675,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonLuckText.setText(luck.toString());
|
this.pokemonLuckText.setText(luck.toString());
|
||||||
this.pokemonLuckText.setTint(getVariantTint(Math.min(luck - 1, 2) as Variant));
|
this.pokemonLuckText.setTint(getVariantTint(Math.min(luck - 1, 2) as Variant));
|
||||||
this.pokemonLuckLabelText.setVisible(this.pokemonLuckText.visible);
|
this.pokemonLuckLabelText.setVisible(this.pokemonLuckText.visible);
|
||||||
|
this.pokemonShinyIcon.setVisible(this.starterPreferences[species.speciesId]?.shiny ?? false);
|
||||||
|
|
||||||
//Growth translate
|
//Growth translate
|
||||||
let growthReadable = Utils.toReadableString(GrowthRate[species.growthRate]);
|
let growthReadable = Utils.toReadableString(GrowthRate[species.growthRate]);
|
||||||
@ -2748,14 +2699,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonHatchedIcon.setFrame(getEggTierForSpecies(species));
|
this.pokemonHatchedIcon.setFrame(getEggTierForSpecies(species));
|
||||||
}
|
}
|
||||||
this.pokemonHatchedCountText.setText(`${this.speciesStarterDexEntry.hatchedCount}`);
|
this.pokemonHatchedCountText.setText(`${this.speciesStarterDexEntry.hatchedCount}`);
|
||||||
|
|
||||||
const defaultDexAttr = this.getCurrentDexProps(species.speciesId);
|
const defaultDexAttr = this.getCurrentDexProps(species.speciesId);
|
||||||
const defaultProps = this.scene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr);
|
const defaultProps = this.scene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr);
|
||||||
const variant = defaultProps.variant;
|
const variant = defaultProps.variant;
|
||||||
const tint = getVariantTint(variant);
|
const tint = getVariantTint(variant);
|
||||||
this.pokemonShinyIcon.setFrame(getVariantIcon(variant));
|
this.pokemonShinyIcon.setFrame(getVariantIcon(variant));
|
||||||
this.pokemonShinyIcon.setTint(tint);
|
this.pokemonShinyIcon.setTint(tint);
|
||||||
this.pokemonShinyIcon.setVisible(defaultProps.shiny);
|
|
||||||
this.pokemonCaughtHatchedContainer.setVisible(true);
|
this.pokemonCaughtHatchedContainer.setVisible(true);
|
||||||
if (pokemonPrevolutions.hasOwnProperty(species.speciesId)) {
|
if (pokemonPrevolutions.hasOwnProperty(species.speciesId)) {
|
||||||
this.pokemonCaughtHatchedContainer.setY(16);
|
this.pokemonCaughtHatchedContainer.setY(16);
|
||||||
@ -2945,13 +2894,21 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
const dexEntry = this.scene.gameData.dexData[species.speciesId];
|
const dexEntry = this.scene.gameData.dexData[species.speciesId];
|
||||||
const abilityAttr = this.scene.gameData.starterData[species.speciesId].abilityAttr;
|
const abilityAttr = this.scene.gameData.starterData[species.speciesId].abilityAttr;
|
||||||
|
|
||||||
const caughtAttr = this.scene.gameData.dexData[species.speciesId]?.caughtAttr || BigInt(0);
|
const isCaught = this.scene.gameData.dexData[species.speciesId]?.caughtAttr || BigInt(0);
|
||||||
|
const isVariant3Caught = !!(isCaught & DexAttr.VARIANT_3);
|
||||||
|
const isVariant2Caught = !!(isCaught & DexAttr.VARIANT_2);
|
||||||
|
const isDefaultVariantCaught = !!(isCaught & DexAttr.DEFAULT_VARIANT);
|
||||||
|
const isVariantCaught = !!(isCaught & DexAttr.SHINY);
|
||||||
|
const isMaleCaught = !!(isCaught & DexAttr.MALE);
|
||||||
|
const isFemaleCaught = !!(isCaught & DexAttr.FEMALE);
|
||||||
|
|
||||||
|
const starterAttributes = this.starterPreferences[species.speciesId];
|
||||||
|
|
||||||
if (!dexEntry.caughtAttr) {
|
|
||||||
const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId));
|
const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId));
|
||||||
const defaultAbilityIndex = this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species);
|
const defaultAbilityIndex = this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species);
|
||||||
const defaultNature = this.scene.gameData.getSpeciesDefaultNature(species);
|
const defaultNature = this.scene.gameData.getSpeciesDefaultNature(species);
|
||||||
|
|
||||||
|
if (!dexEntry.caughtAttr) {
|
||||||
if (shiny === undefined || shiny !== props.shiny) {
|
if (shiny === undefined || shiny !== props.shiny) {
|
||||||
shiny = props.shiny;
|
shiny = props.shiny;
|
||||||
}
|
}
|
||||||
@ -2970,6 +2927,83 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
if (natureIndex === undefined || natureIndex !== defaultNature) {
|
if (natureIndex === undefined || natureIndex !== defaultNature) {
|
||||||
natureIndex = defaultNature;
|
natureIndex = defaultNature;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// compare current shiny, formIndex, female, variant, abilityIndex, natureIndex with the caught ones
|
||||||
|
// if the current ones are not caught, we need to find the next caught ones
|
||||||
|
if (shiny) {
|
||||||
|
if (!(isVariantCaught || isVariant2Caught || isVariant3Caught)) {
|
||||||
|
shiny = false;
|
||||||
|
starterAttributes.shiny = false;
|
||||||
|
variant = 0;
|
||||||
|
starterAttributes.variant = 0;
|
||||||
|
} else {
|
||||||
|
shiny = true;
|
||||||
|
starterAttributes.shiny = true;
|
||||||
|
if (variant === 0 && !isDefaultVariantCaught) {
|
||||||
|
if (isVariant2Caught) {
|
||||||
|
variant = 1;
|
||||||
|
starterAttributes.variant = 1;
|
||||||
|
} else if (isVariant3Caught) {
|
||||||
|
variant = 2;
|
||||||
|
starterAttributes.variant = 2;
|
||||||
|
} else {
|
||||||
|
variant = 0;
|
||||||
|
starterAttributes.variant = 0;
|
||||||
|
}
|
||||||
|
} else if (variant === 1 && !isVariant2Caught) {
|
||||||
|
if (isVariantCaught) {
|
||||||
|
variant = 0;
|
||||||
|
starterAttributes.variant = 0;
|
||||||
|
} else if (isVariant3Caught) {
|
||||||
|
variant = 2;
|
||||||
|
starterAttributes.variant = 2;
|
||||||
|
} else {
|
||||||
|
variant = 0;
|
||||||
|
starterAttributes.variant = 0;
|
||||||
|
}
|
||||||
|
} else if (variant === 2 && !isVariant3Caught) {
|
||||||
|
if (isVariantCaught) {
|
||||||
|
variant = 0;
|
||||||
|
starterAttributes.variant = 0;
|
||||||
|
} else if (isVariant2Caught) {
|
||||||
|
variant = 1;
|
||||||
|
starterAttributes.variant = 1;
|
||||||
|
} else {
|
||||||
|
variant = 0;
|
||||||
|
starterAttributes.variant = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (female) {
|
||||||
|
if (!isFemaleCaught) {
|
||||||
|
female = false;
|
||||||
|
starterAttributes.female = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!isMaleCaught) {
|
||||||
|
female = true;
|
||||||
|
starterAttributes.female = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (species.forms) {
|
||||||
|
const formCount = species.forms.length;
|
||||||
|
let newFormIndex = formIndex??0;
|
||||||
|
if (species.forms[newFormIndex]) {
|
||||||
|
const isValidForm = species.forms[newFormIndex].isStarterSelectable && dexEntry.caughtAttr & this.scene.gameData.getFormAttr(newFormIndex);
|
||||||
|
if (!isValidForm) {
|
||||||
|
do {
|
||||||
|
newFormIndex = (newFormIndex + 1) % formCount;
|
||||||
|
if (species.forms[newFormIndex].isStarterSelectable && dexEntry.caughtAttr & this.scene.gameData.getFormAttr(newFormIndex)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (newFormIndex !== props.formIndex);
|
||||||
|
formIndex = newFormIndex;
|
||||||
|
starterAttributes.form = formIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.shinyOverlay.setVisible(shiny ?? false); // TODO: is false the correct default?
|
this.shinyOverlay.setVisible(shiny ?? false); // TODO: is false the correct default?
|
||||||
@ -3011,19 +3045,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
currentFilteredContainer.checkIconId(female, formIndex, shiny, variant);
|
currentFilteredContainer.checkIconId(female, formIndex, shiny, variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
const isNonShinyCaught = !!(caughtAttr & DexAttr.NON_SHINY);
|
this.canCycleShiny = isVariantCaught || isVariant2Caught || isVariant3Caught;
|
||||||
const isShinyCaught = !!(caughtAttr & DexAttr.SHINY);
|
|
||||||
const isVariant1Caught = isShinyCaught && !!(caughtAttr & DexAttr.DEFAULT_VARIANT);
|
|
||||||
const isVariant2Caught = isShinyCaught && !!(caughtAttr & DexAttr.VARIANT_2);
|
|
||||||
const isVariant3Caught = isShinyCaught && !!(caughtAttr & DexAttr.VARIANT_3);
|
|
||||||
|
|
||||||
this.canCycleShiny = isNonShinyCaught && isShinyCaught;
|
|
||||||
this.canCycleVariant = !!shiny && [ isVariant1Caught, isVariant2Caught, isVariant3Caught].filter(v => v).length > 1;
|
|
||||||
|
|
||||||
const isMaleCaught = !!(caughtAttr & DexAttr.MALE);
|
|
||||||
const isFemaleCaught = !!(caughtAttr & DexAttr.FEMALE);
|
|
||||||
this.canCycleGender = isMaleCaught && isFemaleCaught;
|
this.canCycleGender = isMaleCaught && isFemaleCaught;
|
||||||
|
|
||||||
const hasAbility1 = abilityAttr & AbilityAttr.ABILITY_1;
|
const hasAbility1 = abilityAttr & AbilityAttr.ABILITY_1;
|
||||||
let hasAbility2 = abilityAttr & AbilityAttr.ABILITY_2;
|
let hasAbility2 = abilityAttr & AbilityAttr.ABILITY_2;
|
||||||
const hasHiddenAbility = abilityAttr & AbilityAttr.ABILITY_HIDDEN;
|
const hasHiddenAbility = abilityAttr & AbilityAttr.ABILITY_HIDDEN;
|
||||||
@ -3038,11 +3061,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.canCycleAbility = [ hasAbility1, hasAbility2, hasHiddenAbility ].filter(a => a).length > 1;
|
this.canCycleAbility = [ hasAbility1, hasAbility2, hasHiddenAbility ].filter(a => a).length > 1;
|
||||||
|
|
||||||
this.canCycleForm = species.forms.filter(f => f.isStarterSelectable || !pokemonFormChanges[species.speciesId]?.find(fc => fc.formKey))
|
this.canCycleForm = species.forms.filter(f => f.isStarterSelectable || !pokemonFormChanges[species.speciesId]?.find(fc => fc.formKey))
|
||||||
.map((_, f) => dexEntry.caughtAttr & this.scene.gameData.getFormAttr(f)).filter(f => f).length > 1;
|
.map((_, f) => dexEntry.caughtAttr & this.scene.gameData.getFormAttr(f)).filter(f => f).length > 1;
|
||||||
this.canCycleNature = this.scene.gameData.getNaturesForAttr(dexEntry.natureAttr).length > 1;
|
this.canCycleNature = this.scene.gameData.getNaturesForAttr(dexEntry.natureAttr).length > 1;
|
||||||
|
this.canCycleVariant = !!shiny && [ dexEntry.caughtAttr & DexAttr.DEFAULT_VARIANT, dexEntry.caughtAttr & DexAttr.VARIANT_2, dexEntry.caughtAttr & DexAttr.VARIANT_3].filter(v => v).length > 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dexEntry.caughtAttr && species.malePercent !== null) {
|
if (dexEntry.caughtAttr && species.malePercent !== null) {
|
||||||
@ -3420,55 +3442,39 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
return canStart;
|
return canStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* this creates a temporary dex attr props that we use to check whether a pokemon is valid for a challenge.
|
||||||
* Creates a temporary dex attr props that will be used to check whether a pokemon is valid for a challenge
|
* when checking for certain challenges (i.e. mono type), we need to check for form changes AND evolutions
|
||||||
* and to display the correct shiny, variant, and form based on the StarterPreferences
|
* However, since some pokemon can evolve based on their intial gender/form, we need a way to look for that
|
||||||
*
|
* This temporary dex attr will therefore ONLY look at gender and form, since there's no cases of shinies/variants
|
||||||
* @param speciesId the id of the species to get props for
|
* having different evolutions to their non shiny/variant part, and so those can be ignored
|
||||||
* @returns the dex props
|
* Since the current form and gender is stored in the starter preferences, this is where we get the values from
|
||||||
*/
|
*/
|
||||||
getCurrentDexProps(speciesId: number): bigint {
|
getCurrentDexProps(speciesId: number): bigint {
|
||||||
let props = 0n;
|
let props = 0n;
|
||||||
const caughtAttr = this.scene.gameData.dexData[speciesId].caughtAttr;
|
|
||||||
|
|
||||||
/* this checks the gender of the pokemon; this works by checking a) that the starter preferences for the species exist, and if so, is it female. If so, it'll add DexAttr.FEMALE to our temp props
|
if (this.starterPreferences[speciesId]?.female) { // this checks the gender of the pokemon
|
||||||
* It then checks b) if the caughtAttr for the pokemon is female and NOT male - this means that the ONLY gender we've gotten is female, and we need to add DexAttr.FEMALE to our temp props
|
|
||||||
* If neither of these pass, we add DexAttr.MALE to our temp props
|
|
||||||
*/
|
|
||||||
if (this.starterPreferences[speciesId]?.female || ((caughtAttr & DexAttr.FEMALE) > 0n && (caughtAttr & DexAttr.MALE) === 0n)) {
|
|
||||||
props += DexAttr.FEMALE;
|
props += DexAttr.FEMALE;
|
||||||
} else {
|
} else {
|
||||||
props += DexAttr.MALE;
|
props += DexAttr.MALE;
|
||||||
}
|
}
|
||||||
/* This part is very similar to above, but instead of for gender, it checks for shiny within starter preferences.
|
if (this.starterPreferences[speciesId]?.shiny) {
|
||||||
* If they're not there, it checks the caughtAttr for shiny only (i.e. SHINY === true && NON_SHINY === false)
|
|
||||||
*/
|
|
||||||
if (this.starterPreferences[speciesId]?.shiny || ((caughtAttr & DexAttr.SHINY) > 0n && (caughtAttr & DexAttr.NON_SHINY) === 0n)) {
|
|
||||||
props += DexAttr.SHINY;
|
props += DexAttr.SHINY;
|
||||||
if (this.starterPreferences[speciesId]?.variant) {
|
if (this.starterPreferences[speciesId]?.variant) {
|
||||||
props += BigInt(Math.pow(2, this.starterPreferences[speciesId]?.variant)) * DexAttr.DEFAULT_VARIANT;
|
props += BigInt(Math.pow(2, this.starterPreferences[speciesId]?.variant)) * DexAttr.DEFAULT_VARIANT;
|
||||||
} else {
|
} else {
|
||||||
/* This calculates the correct variant if there's no starter preferences for it.
|
|
||||||
* This gets the lowest tier variant that you've caught (in line with other mechanics) and adds it to the temp props
|
|
||||||
*/
|
|
||||||
if ((caughtAttr & DexAttr.DEFAULT_VARIANT) > 0) {
|
|
||||||
props += DexAttr.DEFAULT_VARIANT;
|
props += DexAttr.DEFAULT_VARIANT;
|
||||||
}
|
}
|
||||||
if ((caughtAttr & DexAttr.VARIANT_2) > 0) {
|
|
||||||
props += DexAttr.VARIANT_2;
|
|
||||||
} else if ((caughtAttr & DexAttr.VARIANT_3) > 0) {
|
|
||||||
props += DexAttr.VARIANT_3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
props += DexAttr.NON_SHINY;
|
props += DexAttr.NON_SHINY;
|
||||||
|
if (this.starterPreferences[speciesId]?.variant) {
|
||||||
|
delete this.starterPreferences[speciesId].variant;
|
||||||
|
}
|
||||||
props += DexAttr.DEFAULT_VARIANT; // we add the default variant here because non shiny versions are listed as default variant
|
props += DexAttr.DEFAULT_VARIANT; // we add the default variant here because non shiny versions are listed as default variant
|
||||||
}
|
}
|
||||||
if (this.starterPreferences[speciesId]?.form) { // this checks for the form of the pokemon
|
if (this.starterPreferences[speciesId]?.form) { // this checks for the form of the pokemon
|
||||||
props += BigInt(Math.pow(2, this.starterPreferences[speciesId]?.form)) * DexAttr.DEFAULT_FORM;
|
props += BigInt(Math.pow(2, this.starterPreferences[speciesId]?.form)) * DexAttr.DEFAULT_FORM;
|
||||||
} else {
|
} else {
|
||||||
// Get the first unlocked form
|
props += DexAttr.DEFAULT_FORM;
|
||||||
props += this.scene.gameData.getFormAttr(this.scene.gameData.getFormIndex(caughtAttr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return props;
|
return props;
|
||||||
|
@ -1,147 +0,0 @@
|
|||||||
import { FormModalUiHandler } from "./form-modal-ui-handler";
|
|
||||||
import { ModalConfig } from "./modal-ui-handler";
|
|
||||||
import i18next from "i18next";
|
|
||||||
import { PlayerPokemon } from "#app/field/pokemon";
|
|
||||||
import { OptionSelectItem } from "./abstact-option-select-ui-handler";
|
|
||||||
import { isNullOrUndefined } from "#app/utils";
|
|
||||||
import { Mode } from "./ui";
|
|
||||||
|
|
||||||
export default class TestDialogueUiHandler extends FormModalUiHandler {
|
|
||||||
|
|
||||||
keys: string[];
|
|
||||||
|
|
||||||
constructor(scene, mode) {
|
|
||||||
super(scene, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
super.setup();
|
|
||||||
|
|
||||||
const flattenKeys = (object, topKey?: string, midleKey?: string[]): Array<any> => {
|
|
||||||
return Object.keys(object).map((t, i) => {
|
|
||||||
const value = Object.values(object)[i];
|
|
||||||
|
|
||||||
if (typeof value === "object" && !isNullOrUndefined(value)) { // we check for not null or undefined here because if the language json file has a null key, the typeof will still be an object, but that object will be null, causing issues
|
|
||||||
// If the value is an object, execute the same process
|
|
||||||
// si el valor es un objeto ejecuta el mismo proceso
|
|
||||||
|
|
||||||
return flattenKeys(value, topKey ?? t, topKey ? midleKey ? [...midleKey, t] : [t] : undefined).filter((t) => t.length > 0);
|
|
||||||
} else if (typeof value === "string" || isNullOrUndefined(value)) { // we check for null or undefined here as per above - the typeof is still an object but the value is null so we need to exit out of this and pass the null key
|
|
||||||
|
|
||||||
// Return in the format expected by i18next
|
|
||||||
return midleKey ? `${topKey}:${midleKey.map((m) => m).join(".")}.${t}` : `${topKey}:${t}`;
|
|
||||||
}
|
|
||||||
}).filter((t) => t);
|
|
||||||
};
|
|
||||||
|
|
||||||
const keysInArrays = flattenKeys(i18next.getDataByLanguage(String(i18next.resolvedLanguage))).filter((t) => t.length > 0); // Array of arrays
|
|
||||||
const keys = keysInArrays.flat(Infinity).map(String); // One array of string
|
|
||||||
this.keys = keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
getModalTitle(config?: ModalConfig): string {
|
|
||||||
return "Test Dialogue";
|
|
||||||
}
|
|
||||||
|
|
||||||
getFields(config?: ModalConfig): string[] {
|
|
||||||
return [ "Dialogue" ];
|
|
||||||
}
|
|
||||||
|
|
||||||
getWidth(config?: ModalConfig): number {
|
|
||||||
return 300;
|
|
||||||
}
|
|
||||||
|
|
||||||
getMargin(config?: ModalConfig): [number, number, number, number] {
|
|
||||||
return [ 0, 0, 48, 0 ];
|
|
||||||
}
|
|
||||||
|
|
||||||
getButtonLabels(config?: ModalConfig): string[] {
|
|
||||||
return [ "Check", "Cancel" ];
|
|
||||||
}
|
|
||||||
|
|
||||||
getReadableErrorMessage(error: string): string {
|
|
||||||
const colonIndex = error?.indexOf(":");
|
|
||||||
if (colonIndex > 0) {
|
|
||||||
error = error.slice(0, colonIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.getReadableErrorMessage(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
show(args: any[]): boolean {
|
|
||||||
const ui = this.getUi();
|
|
||||||
const input = this.inputs[0];
|
|
||||||
input.setMaxLength(255);
|
|
||||||
|
|
||||||
input.on("keydown", (inputObject, evt: KeyboardEvent) => {
|
|
||||||
if (["escape", "space"].some((v) => v === evt.key.toLowerCase() || v === evt.code.toLowerCase()) && ui.getMode() === Mode.AUTO_COMPLETE) {
|
|
||||||
// Delete autocomplete list and recovery focus.
|
|
||||||
inputObject.on("blur", () => inputObject.node.focus(), { once: true });
|
|
||||||
ui.revertMode();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
input.on("textchange", (inputObject, evt: InputEvent) => {
|
|
||||||
// Delete autocomplete.
|
|
||||||
if (ui.getMode() === Mode.AUTO_COMPLETE) {
|
|
||||||
ui.revertMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
let options: OptionSelectItem[] = [];
|
|
||||||
const splitArr = inputObject.text.split(" ");
|
|
||||||
const filteredKeys = this.keys.filter((command) => command.toLowerCase().includes(splitArr[splitArr.length - 1].toLowerCase()));
|
|
||||||
if (inputObject.text !== "" && filteredKeys.length > 0) {
|
|
||||||
// if performance is required, you could reduce the number of total results by changing the slice below to not have all ~8000 inputs going
|
|
||||||
options = filteredKeys.slice(0).map((value) => {
|
|
||||||
return {
|
|
||||||
label: value,
|
|
||||||
handler: () => {
|
|
||||||
// this is here to make sure that if you try to backspace then enter, the last known evt.data (backspace) is picked up
|
|
||||||
// this is because evt.data is null for backspace, so without this, the autocomplete windows just closes
|
|
||||||
if (!isNullOrUndefined(evt.data) || evt.inputType?.toLowerCase() === "deletecontentbackward") {
|
|
||||||
const separatedArray = inputObject.text.split(" ");
|
|
||||||
separatedArray[separatedArray.length - 1] = value;
|
|
||||||
inputObject.setText(separatedArray.join(" "));
|
|
||||||
}
|
|
||||||
ui.revertMode();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.length > 0) {
|
|
||||||
const modalOpts = {
|
|
||||||
options: options,
|
|
||||||
maxOptions: 5,
|
|
||||||
modalContainer: this.modalContainer
|
|
||||||
};
|
|
||||||
ui.setOverlayMode(Mode.AUTO_COMPLETE, modalOpts);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
if (super.show(args)) {
|
|
||||||
const config = args[0] as ModalConfig;
|
|
||||||
this.inputs[0].resize(1150, 116);
|
|
||||||
this.inputContainers[0].list[0].width = 200;
|
|
||||||
if (args[1] && typeof (args[1] as PlayerPokemon).getNameToRender === "function") {
|
|
||||||
this.inputs[0].text = (args[1] as PlayerPokemon).getNameToRender();
|
|
||||||
} else {
|
|
||||||
this.inputs[0].text = args[1];
|
|
||||||
}
|
|
||||||
this.submitAction = (_) => {
|
|
||||||
if (ui.getMode() === Mode.TEST_DIALOGUE) {
|
|
||||||
this.sanitizeInputs();
|
|
||||||
const sanitizedName = btoa(unescape(encodeURIComponent(this.inputs[0].text)));
|
|
||||||
config.buttonActions[0](sanitizedName);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -49,8 +49,6 @@ import RenameFormUiHandler from "./rename-form-ui-handler";
|
|||||||
import AdminUiHandler from "./admin-ui-handler";
|
import AdminUiHandler from "./admin-ui-handler";
|
||||||
import RunHistoryUiHandler from "./run-history-ui-handler";
|
import RunHistoryUiHandler from "./run-history-ui-handler";
|
||||||
import RunInfoUiHandler from "./run-info-ui-handler";
|
import RunInfoUiHandler from "./run-info-ui-handler";
|
||||||
import TestDialogueUiHandler from "#app/ui/test-dialogue-ui-handler";
|
|
||||||
import AutoCompleteUiHandler from "./autocomplete-ui-handler";
|
|
||||||
|
|
||||||
export enum Mode {
|
export enum Mode {
|
||||||
MESSAGE,
|
MESSAGE,
|
||||||
@ -91,8 +89,6 @@ export enum Mode {
|
|||||||
RENAME_POKEMON,
|
RENAME_POKEMON,
|
||||||
RUN_HISTORY,
|
RUN_HISTORY,
|
||||||
RUN_INFO,
|
RUN_INFO,
|
||||||
TEST_DIALOGUE,
|
|
||||||
AUTO_COMPLETE,
|
|
||||||
ADMIN,
|
ADMIN,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,8 +127,6 @@ const noTransitionModes = [
|
|||||||
Mode.UNAVAILABLE,
|
Mode.UNAVAILABLE,
|
||||||
Mode.OUTDATED,
|
Mode.OUTDATED,
|
||||||
Mode.RENAME_POKEMON,
|
Mode.RENAME_POKEMON,
|
||||||
Mode.TEST_DIALOGUE,
|
|
||||||
Mode.AUTO_COMPLETE,
|
|
||||||
Mode.ADMIN,
|
Mode.ADMIN,
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -197,8 +191,6 @@ export default class UI extends Phaser.GameObjects.Container {
|
|||||||
new RenameFormUiHandler(scene),
|
new RenameFormUiHandler(scene),
|
||||||
new RunHistoryUiHandler(scene),
|
new RunHistoryUiHandler(scene),
|
||||||
new RunInfoUiHandler(scene),
|
new RunInfoUiHandler(scene),
|
||||||
new TestDialogueUiHandler(scene, Mode.TEST_DIALOGUE),
|
|
||||||
new AutoCompleteUiHandler(scene),
|
|
||||||
new AdminUiHandler(scene),
|
new AdminUiHandler(scene),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user