Merge branch 'main' into main
@ -39,6 +39,11 @@
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.addEventListener('beforeinstallprompt', e => {
|
||||||
|
// Prevent invasive install prompt (users are still able to install as an app)
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
BIN
public/images/items/candy.png
Normal file
After Width: | Height: | Size: 402 B |
BIN
public/images/items/candy_overlay.png
Normal file
After Width: | Height: | Size: 263 B |
BIN
public/images/items/mystery_egg.png
Normal file
After Width: | Height: | Size: 252 B |
BIN
public/images/ui/ha_capsule.png
Normal file
After Width: | Height: | Size: 297 B |
BIN
public/images/ui/legacy/ha_capsule.png
Normal file
After Width: | Height: | Size: 297 B |
1
public/starter-colors.json
Normal file
@ -2,7 +2,7 @@ import Phaser, { Time } from 'phaser';
|
|||||||
import UI, { Mode } from './ui/ui';
|
import UI, { Mode } from './ui/ui';
|
||||||
import { NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, TurnInitPhase, ReturnPhase, LevelCapPhase, ShowTrainerPhase, LoginPhase, MovePhase, TitlePhase, SwitchPhase } from './phases';
|
import { NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, TurnInitPhase, ReturnPhase, LevelCapPhase, ShowTrainerPhase, LoginPhase, MovePhase, TitlePhase, SwitchPhase } from './phases';
|
||||||
import Pokemon, { PlayerPokemon, EnemyPokemon } from './field/pokemon';
|
import Pokemon, { PlayerPokemon, EnemyPokemon } from './field/pokemon';
|
||||||
import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies, initSpecies } from './data/pokemon-species';
|
import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies, initSpecies, speciesStarters } from './data/pokemon-species';
|
||||||
import * as Utils from './utils';
|
import * as Utils from './utils';
|
||||||
import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonHpRestoreModifier, HealingBoosterModifier, PersistentModifier, PokemonHeldItemModifier, ModifierPredicate, DoubleBattleChanceBoosterModifier, FusePokemonModifier, PokemonFormChangeItemModifier, TerastallizeModifier } from './modifier/modifier';
|
import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonHpRestoreModifier, HealingBoosterModifier, PersistentModifier, PokemonHeldItemModifier, ModifierPredicate, DoubleBattleChanceBoosterModifier, FusePokemonModifier, PokemonFormChangeItemModifier, TerastallizeModifier } from './modifier/modifier';
|
||||||
import { PokeballType } from './data/pokeball';
|
import { PokeballType } from './data/pokeball';
|
||||||
@ -55,8 +55,8 @@ import PokemonInfoContainer from './ui/pokemon-info-container';
|
|||||||
import { biomeDepths } from './data/biomes';
|
import { biomeDepths } from './data/biomes';
|
||||||
import { initTouchControls } from './touch-controls';
|
import { initTouchControls } from './touch-controls';
|
||||||
import { UiTheme } from './enums/ui-theme';
|
import { UiTheme } from './enums/ui-theme';
|
||||||
import CacheBustedLoaderPlugin from './plugins/cache-busted-loader-plugin';
|
|
||||||
import { SceneBase } from './scene-base';
|
import { SceneBase } from './scene-base';
|
||||||
|
import CandyBar from './ui/candy-bar';
|
||||||
|
|
||||||
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1";
|
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1";
|
||||||
|
|
||||||
@ -81,6 +81,11 @@ export const startingWave = STARTING_WAVE_OVERRIDE || 1;
|
|||||||
const expSpriteKeys: string[] = [];
|
const expSpriteKeys: string[] = [];
|
||||||
const repeatInputDelayMillis = 250;
|
const repeatInputDelayMillis = 250;
|
||||||
|
|
||||||
|
export let starterColors: StarterColors;
|
||||||
|
interface StarterColors {
|
||||||
|
[key: string]: [string, string]
|
||||||
|
}
|
||||||
|
|
||||||
export enum Button {
|
export enum Button {
|
||||||
UP,
|
UP,
|
||||||
DOWN,
|
DOWN,
|
||||||
@ -142,6 +147,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
public pbTrayEnemy: PokeballTray;
|
public pbTrayEnemy: PokeballTray;
|
||||||
public abilityBar: AbilityBar;
|
public abilityBar: AbilityBar;
|
||||||
public partyExpBar: PartyExpBar;
|
public partyExpBar: PartyExpBar;
|
||||||
|
public candyBar: CandyBar;
|
||||||
public arenaBg: Phaser.GameObjects.Sprite;
|
public arenaBg: Phaser.GameObjects.Sprite;
|
||||||
public arenaBgTransition: Phaser.GameObjects.Sprite;
|
public arenaBgTransition: Phaser.GameObjects.Sprite;
|
||||||
public arenaPlayer: ArenaBase;
|
public arenaPlayer: ArenaBase;
|
||||||
@ -207,8 +213,6 @@ export default class BattleScene extends SceneBase {
|
|||||||
this.phaseQueuePrepend = [];
|
this.phaseQueuePrepend = [];
|
||||||
this.phaseQueuePrependSpliceIndex = -1;
|
this.phaseQueuePrependSpliceIndex = -1;
|
||||||
this.nextCommandPhaseQueue = [];
|
this.nextCommandPhaseQueue = [];
|
||||||
|
|
||||||
Phaser.Plugins.PluginCache.register('Loader', CacheBustedLoaderPlugin, 'load');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadPokemonAtlas(key: string, atlasPath: string, experimental?: boolean) {
|
loadPokemonAtlas(key: string, atlasPath: string, experimental?: boolean) {
|
||||||
@ -359,6 +363,10 @@ export default class BattleScene extends SceneBase {
|
|||||||
this.partyExpBar.setup();
|
this.partyExpBar.setup();
|
||||||
this.fieldUI.add(this.partyExpBar);
|
this.fieldUI.add(this.partyExpBar);
|
||||||
|
|
||||||
|
this.candyBar = new CandyBar(this);
|
||||||
|
this.candyBar.setup();
|
||||||
|
this.fieldUI.add(this.candyBar);
|
||||||
|
|
||||||
this.waveCountText = addTextObject(this, (this.game.canvas.width / 6) - 2, 0, startingWave.toString(), TextStyle.BATTLE_INFO);
|
this.waveCountText = addTextObject(this, (this.game.canvas.width / 6) - 2, 0, startingWave.toString(), TextStyle.BATTLE_INFO);
|
||||||
this.waveCountText.setOrigin(1, 0);
|
this.waveCountText.setOrigin(1, 0);
|
||||||
this.fieldUI.add(this.waveCountText);
|
this.fieldUI.add(this.waveCountText);
|
||||||
@ -440,7 +448,8 @@ export default class BattleScene extends SceneBase {
|
|||||||
Promise.all([
|
Promise.all([
|
||||||
Promise.all(loadPokemonAssets),
|
Promise.all(loadPokemonAssets),
|
||||||
initCommonAnims().then(() => loadCommonAnimAssets(this, true)),
|
initCommonAnims().then(() => loadCommonAnimAssets(this, true)),
|
||||||
Promise.all([ Moves.TACKLE, Moves.TAIL_WHIP, Moves.FOCUS_ENERGY, Moves.STRUGGLE ].map(m => initMoveAnim(m))).then(() => loadMoveAnimAssets(this, defaultMoves, true))
|
Promise.all([ Moves.TACKLE, Moves.TAIL_WHIP, Moves.FOCUS_ENERGY, Moves.STRUGGLE ].map(m => initMoveAnim(m))).then(() => loadMoveAnimAssets(this, defaultMoves, true)),
|
||||||
|
this.initStarterColors()
|
||||||
]).then(() => {
|
]).then(() => {
|
||||||
this.pushPhase(new LoginPhase(this));
|
this.pushPhase(new LoginPhase(this));
|
||||||
this.pushPhase(new TitlePhase(this));
|
this.pushPhase(new TitlePhase(this));
|
||||||
@ -472,12 +481,53 @@ export default class BattleScene extends SceneBase {
|
|||||||
this.updateScoreText();
|
this.updateScoreText();
|
||||||
}
|
}
|
||||||
|
|
||||||
initExpSprites(): void {
|
initExpSprites(): Promise<void> {
|
||||||
if (expSpriteKeys.length)
|
return new Promise(resolve => {
|
||||||
return;
|
if (expSpriteKeys.length)
|
||||||
fetch('./exp_sprites.json').then(res => res.json()).then(keys => {
|
return resolve();
|
||||||
if (Array.isArray(keys))
|
fetch('./exp-sprites.json').then(res => res.json()).then(keys => {
|
||||||
expSpriteKeys.push(...keys);
|
if (Array.isArray(keys))
|
||||||
|
expSpriteKeys.push(...keys);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initStarterColors(): Promise<void> {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
if (starterColors)
|
||||||
|
return resolve();
|
||||||
|
|
||||||
|
fetch('./starter-colors.json').then(res => res.json()).then(sc => {
|
||||||
|
starterColors = {};
|
||||||
|
Object.keys(sc).forEach(key => {
|
||||||
|
starterColors[key] = sc[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
/*const loadPokemonAssets: Promise<void>[] = [];
|
||||||
|
|
||||||
|
for (let s of Object.keys(speciesStarters)) {
|
||||||
|
const species = getPokemonSpecies(parseInt(s));
|
||||||
|
loadPokemonAssets.push(species.loadAssets(this, false, 0, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
Promise.all(loadPokemonAssets).then(() => {
|
||||||
|
const starterCandyColors = {};
|
||||||
|
const rgbaToHexFunc = (r, g, b) => [r, g, b].map(x => x.toString(16).padStart(2, '0')).join('');
|
||||||
|
|
||||||
|
for (let s of Object.keys(speciesStarters)) {
|
||||||
|
const species = getPokemonSpecies(parseInt(s));
|
||||||
|
|
||||||
|
starterCandyColors[species.speciesId] = species.generateCandyColors(this).map(c => rgbaToHexFunc(c[0], c[1], c[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(JSON.stringify(starterCandyColors));
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
});*/
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1075,6 +1125,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
this.scoreText.setY(this.moneyText.y + 10);
|
this.scoreText.setY(this.moneyText.y + 10);
|
||||||
const offsetY = (this.scoreText.visible ? this.scoreText : this.moneyText).y + 15;
|
const offsetY = (this.scoreText.visible ? this.scoreText : this.moneyText).y + 15;
|
||||||
this.partyExpBar.setY(offsetY);
|
this.partyExpBar.setY(offsetY);
|
||||||
|
this.candyBar.setY(offsetY + 15);
|
||||||
this.ui?.achvBar.setY(this.game.canvas.height / 6 + offsetY);
|
this.ui?.achvBar.setY(this.game.canvas.height / 6 + offsetY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import { Weather, WeatherType } from "./weather";
|
|||||||
import { BattlerTag } from "./battler-tags";
|
import { BattlerTag } from "./battler-tags";
|
||||||
import { BattlerTagType } from "./enums/battler-tag-type";
|
import { BattlerTagType } from "./enums/battler-tag-type";
|
||||||
import { StatusEffect, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect";
|
import { StatusEffect, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect";
|
||||||
|
import { Gender } from "./gender";
|
||||||
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, RecoilAttr, StatusMoveTypeImmunityAttr, allMoves } from "./move";
|
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, RecoilAttr, StatusMoveTypeImmunityAttr, allMoves } from "./move";
|
||||||
import { ArenaTagType } from "./enums/arena-tag-type";
|
import { ArenaTagType } from "./enums/arena-tag-type";
|
||||||
import { Stat } from "./pokemon-stat";
|
import { Stat } from "./pokemon-stat";
|
||||||
@ -81,6 +82,7 @@ type AbAttrCondition = (pokemon: Pokemon) => boolean;
|
|||||||
|
|
||||||
type PokemonAttackCondition = (user: Pokemon, target: Pokemon, move: Move) => boolean;
|
type PokemonAttackCondition = (user: Pokemon, target: Pokemon, move: Move) => boolean;
|
||||||
type PokemonDefendCondition = (target: Pokemon, user: Pokemon, move: Move) => boolean;
|
type PokemonDefendCondition = (target: Pokemon, user: Pokemon, move: Move) => boolean;
|
||||||
|
type PokemonStatChangeCondition = (target: Pokemon, statsChanged: BattleStat[], levels: integer) => boolean;
|
||||||
|
|
||||||
export abstract class AbAttr {
|
export abstract class AbAttr {
|
||||||
public showAbility: boolean;
|
public showAbility: boolean;
|
||||||
@ -384,6 +386,12 @@ export class PostDefendAbAttr extends AbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class PostStatChangeAbAttr extends AbAttr {
|
||||||
|
applyPostStatChange(pokemon: Pokemon, statsChanged: BattleStat[], levelChanged: integer, selfTarget: boolean, args: any[]): boolean | Promise<boolean> {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class MoveImmunityAbAttr extends PreDefendAbAttr {
|
export class MoveImmunityAbAttr extends PreDefendAbAttr {
|
||||||
private immuneCondition: PreDefendAbAttrCondition;
|
private immuneCondition: PreDefendAbAttrCondition;
|
||||||
|
|
||||||
@ -572,6 +580,70 @@ export class PostDefendWeatherChangeAbAttr extends PostDefendAbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class PostDefendAbilitySwapAbAttr extends PostDefendAbAttr {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean {
|
||||||
|
if (move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && !attacker.getAbility().hasAttr(UnswappableAbilityAbAttr)) {
|
||||||
|
const tempAbilityId = attacker.getAbility().id;
|
||||||
|
attacker.summonData.ability = pokemon.getAbility().id;
|
||||||
|
pokemon.summonData.ability = tempAbilityId;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string {
|
||||||
|
return getPokemonMessage(pokemon, ` swapped\nabilities with its target!`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PostDefendAbilityGiveAbAttr extends PostDefendAbAttr {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean {
|
||||||
|
if (move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && !attacker.getAbility().hasAttr(UnsuppressableAbilityAbAttr) && !attacker.getAbility().hasAttr(PostDefendAbilityGiveAbAttr)) {
|
||||||
|
attacker.summonData.ability = pokemon.getAbility().id;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string {
|
||||||
|
return getPokemonMessage(pokemon, ` gave its target\n${abilityName}!`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PostStatChangeStatChangeAbAttr extends PostStatChangeAbAttr {
|
||||||
|
private condition: PokemonStatChangeCondition;
|
||||||
|
private statsToChange: BattleStat[];
|
||||||
|
private levels: integer;
|
||||||
|
|
||||||
|
constructor(condition: PokemonStatChangeCondition, statsToChange: BattleStat[], levels: integer) {
|
||||||
|
super(true);
|
||||||
|
|
||||||
|
this.condition = condition;
|
||||||
|
this.statsToChange = statsToChange;
|
||||||
|
this.levels = levels;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyPostStatChange(pokemon: Pokemon, statsChanged: BattleStat[], levelsChanged: integer, selfTarget: boolean, args: any[]): boolean {
|
||||||
|
if (this.condition(pokemon, statsChanged, levelsChanged) && !selfTarget) {
|
||||||
|
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, (pokemon).getBattlerIndex(), true, this.statsToChange, this.levels));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class PreAttackAbAttr extends AbAttr {
|
export class PreAttackAbAttr extends AbAttr {
|
||||||
applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: PokemonMove, args: any[]): boolean | Promise<boolean> {
|
applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: PokemonMove, args: any[]): boolean | Promise<boolean> {
|
||||||
return false;
|
return false;
|
||||||
@ -616,6 +688,30 @@ export class MoveTypeChangePowerMultiplierAbAttr extends VariableMoveTypeAbAttr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class MoveTypeChangeAttr extends PreAttackAbAttr {
|
||||||
|
private newType: Type;
|
||||||
|
private powerMultiplier: number;
|
||||||
|
private condition: PokemonAttackCondition;
|
||||||
|
|
||||||
|
constructor(newType: Type, powerMultiplier: number, condition: PokemonAttackCondition){
|
||||||
|
super(true);
|
||||||
|
this.newType = newType;
|
||||||
|
this.powerMultiplier = powerMultiplier;
|
||||||
|
this.condition = condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: PokemonMove, args: any[]): boolean {
|
||||||
|
if (this.condition(pokemon, defender, move.getMove())) {
|
||||||
|
const type = (args[0] as Utils.IntegerHolder);
|
||||||
|
type.value = this.newType;
|
||||||
|
(args[1] as Utils.NumberHolder).value *= this.powerMultiplier;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class MovePowerBoostAbAttr extends VariableMovePowerAbAttr {
|
export class MovePowerBoostAbAttr extends VariableMovePowerAbAttr {
|
||||||
private condition: PokemonAttackCondition;
|
private condition: PokemonAttackCondition;
|
||||||
private powerMultiplier: number;
|
private powerMultiplier: number;
|
||||||
@ -747,19 +843,21 @@ export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PostAttackContactApplyStatusEffectAbAttr extends PostAttackAbAttr {
|
export class PostAttackApplyStatusEffectAbAttr extends PostAttackAbAttr {
|
||||||
|
private contactRequired: boolean;
|
||||||
private chance: integer;
|
private chance: integer;
|
||||||
private effects: StatusEffect[];
|
private effects: StatusEffect[];
|
||||||
|
|
||||||
constructor(chance: integer, ...effects: StatusEffect[]) {
|
constructor(contactRequired: boolean, chance: integer, ...effects: StatusEffect[]) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
this.contactRequired = contactRequired;
|
||||||
this.chance = chance;
|
this.chance = chance;
|
||||||
this.effects = effects;
|
this.effects = effects;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPostAttack(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean {
|
applyPostAttack(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean {
|
||||||
if (move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && pokemon.randSeedInt(100) < this.chance && !pokemon.status) {
|
if (pokemon != attacker && (!this.contactRequired || move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) && pokemon.randSeedInt(100) < this.chance && !pokemon.status) {
|
||||||
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)];
|
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)];
|
||||||
return attacker.trySetStatus(effect, true);
|
return attacker.trySetStatus(effect, true);
|
||||||
}
|
}
|
||||||
@ -768,6 +866,12 @@ export class PostAttackContactApplyStatusEffectAbAttr extends PostAttackAbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class PostAttackContactApplyStatusEffectAbAttr extends PostAttackApplyStatusEffectAbAttr {
|
||||||
|
constructor(chance: integer, ...effects: StatusEffect[]) {
|
||||||
|
super(true, chance, ...effects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr {
|
export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr {
|
||||||
private condition: PokemonDefendCondition;
|
private condition: PokemonDefendCondition;
|
||||||
|
|
||||||
@ -829,7 +933,7 @@ class PostVictoryStatChangeAbAttr extends PostVictoryAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class PostKnockOutAbAttr extends AbAttr {
|
export class PostKnockOutAbAttr extends AbAttr {
|
||||||
applyPostKnockOut(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise<boolean> {
|
applyPostKnockOut(pokemon: Pokemon, passive: boolean, knockedOut: Pokemon, args: any[]): boolean | Promise<boolean> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -845,7 +949,7 @@ export class PostKnockOutStatChangeAbAttr extends PostKnockOutAbAttr {
|
|||||||
this.levels = levels;
|
this.levels = levels;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPostKnockOut(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise<boolean> {
|
applyPostKnockOut(pokemon: Pokemon, passive: boolean, knockedOut: Pokemon, args: any[]): boolean | Promise<boolean> {
|
||||||
const stat = typeof this.stat === 'function'
|
const stat = typeof this.stat === 'function'
|
||||||
? this.stat(pokemon)
|
? this.stat(pokemon)
|
||||||
: this.stat;
|
: this.stat;
|
||||||
@ -855,6 +959,22 @@ export class PostKnockOutStatChangeAbAttr extends PostKnockOutAbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class CopyFaintedAllyAbilityAbAttr extends PostKnockOutAbAttr {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
applyPostKnockOut(pokemon: Pokemon, passive: boolean, knockedOut: Pokemon, args: any[]): boolean | Promise<boolean> {
|
||||||
|
if (pokemon.isPlayer() === knockedOut.isPlayer() && !knockedOut.getAbility().hasAttr(UncopiableAbilityAbAttr)) {
|
||||||
|
pokemon.summonData.ability = knockedOut.getAbility().id;
|
||||||
|
pokemon.scene.queueMessage(getPokemonMessage(knockedOut, `'s ${allAbilities[knockedOut.getAbility().id].name} was taken over!`));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class IgnoreOpponentStatChangesAbAttr extends AbAttr {
|
export class IgnoreOpponentStatChangesAbAttr extends AbAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(false);
|
super(false);
|
||||||
@ -1018,6 +1138,27 @@ export class PostSummonFormChangeAbAttr extends PostSummonAbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class TraceAbAttr extends PostSummonAbAttr {
|
||||||
|
applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean {
|
||||||
|
const targets = pokemon.getOpponents();
|
||||||
|
let target: Pokemon;
|
||||||
|
if (targets.length > 1)
|
||||||
|
pokemon.scene.executeWithSeedOffset(() => target = Utils.randSeedItem(targets), pokemon.scene.currentBattle.waveIndex);
|
||||||
|
else
|
||||||
|
target = targets[0];
|
||||||
|
|
||||||
|
// Wonder Guard is normally uncopiable so has the attribute, but trace specifically can copy it
|
||||||
|
if (target.getAbility().hasAttr(UncopiableAbilityAbAttr) && target.getAbility().id !== Abilities.WONDER_GUARD)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
pokemon.summonData.ability = target.getAbility().id;
|
||||||
|
|
||||||
|
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` traced ${target.name}'s\n${allAbilities[target.getAbility().id].name}!`));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class PostSummonTransformAbAttr extends PostSummonAbAttr {
|
export class PostSummonTransformAbAttr extends PostSummonAbAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(true);
|
super(true);
|
||||||
@ -1033,6 +1174,7 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr {
|
|||||||
|
|
||||||
pokemon.summonData.speciesForm = target.getSpeciesForm();
|
pokemon.summonData.speciesForm = target.getSpeciesForm();
|
||||||
pokemon.summonData.fusionSpeciesForm = target.getFusionSpeciesForm();
|
pokemon.summonData.fusionSpeciesForm = target.getFusionSpeciesForm();
|
||||||
|
pokemon.summonData.ability = target.getAbility().id;
|
||||||
pokemon.summonData.gender = target.getGender();
|
pokemon.summonData.gender = target.getGender();
|
||||||
pokemon.summonData.fusionGender = target.getFusionGender();
|
pokemon.summonData.fusionGender = target.getFusionGender();
|
||||||
pokemon.summonData.stats = [ pokemon.stats[Stat.HP] ].concat(target.stats.slice(1));
|
pokemon.summonData.stats = [ pokemon.stats[Stat.HP] ].concat(target.stats.slice(1));
|
||||||
@ -1900,8 +2042,8 @@ export function applyPostAttackAbAttrs(attrType: { new(...args: any[]): PostAtta
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function applyPostKnockOutAbAttrs(attrType: { new(...args: any[]): PostKnockOutAbAttr },
|
export function applyPostKnockOutAbAttrs(attrType: { new(...args: any[]): PostKnockOutAbAttr },
|
||||||
pokemon: Pokemon, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, knockedOut: Pokemon, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PostKnockOutAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostKnockOut(pokemon, passive, args), args);
|
return applyAbAttrsInternal<PostKnockOutAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostKnockOut(pokemon, passive, knockedOut, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPostVictoryAbAttrs(attrType: { new(...args: any[]): PostVictoryAbAttr },
|
export function applyPostVictoryAbAttrs(attrType: { new(...args: any[]): PostVictoryAbAttr },
|
||||||
@ -1924,6 +2066,11 @@ export function applyPreStatChangeAbAttrs(attrType: { new(...args: any[]): PreSt
|
|||||||
return applyAbAttrsInternal<PreStatChangeAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreStatChange(pokemon, passive, stat, cancelled, args), args);
|
return applyAbAttrsInternal<PreStatChangeAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreStatChange(pokemon, passive, stat, cancelled, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function applyPostStatChangeAbAttrs(attrType: { new(...args: any[]): PostStatChangeAbAttr },
|
||||||
|
pokemon: Pokemon, stats: BattleStat[], levels: integer, selfTarget: boolean, ...args: any[]): Promise<void> {
|
||||||
|
return applyAbAttrsInternal<PostStatChangeAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostStatChange(pokemon, stats, levels, selfTarget, args), args);
|
||||||
|
}
|
||||||
|
|
||||||
export function applyPreSetStatusAbAttrs(attrType: { new(...args: any[]): PreSetStatusAbAttr },
|
export function applyPreSetStatusAbAttrs(attrType: { new(...args: any[]): PreSetStatusAbAttr },
|
||||||
pokemon: Pokemon, effect: StatusEffect, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, effect: StatusEffect, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
||||||
const simulated = args.length > 1 && args[1];
|
const simulated = args.length > 1 && args[1];
|
||||||
@ -2085,7 +2232,8 @@ export function initAbilities() {
|
|||||||
.attr(ProtectStatAbAttr, BattleStat.ACC)
|
.attr(ProtectStatAbAttr, BattleStat.ACC)
|
||||||
.attr(DoubleBattleChanceAbAttr)
|
.attr(DoubleBattleChanceAbAttr)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.TRACE, "Trace (N)", "When it enters a battle, the Pokémon copies an opposing Pokémon's Ability.", 3)
|
new Ability(Abilities.TRACE, "Trace", "When it enters a battle, the Pokémon copies an opposing Pokémon's Ability.", 3)
|
||||||
|
.attr(TraceAbAttr)
|
||||||
.attr(UncopiableAbilityAbAttr),
|
.attr(UncopiableAbilityAbAttr),
|
||||||
new Ability(Abilities.HUGE_POWER, "Huge Power", "Doubles the Pokémon's Attack stat.", 3)
|
new Ability(Abilities.HUGE_POWER, "Huge Power", "Doubles the Pokémon's Attack stat.", 3)
|
||||||
.attr(BattleStatMultiplierAbAttr, BattleStat.ATK, 2),
|
.attr(BattleStatMultiplierAbAttr, BattleStat.ATK, 2),
|
||||||
@ -2190,7 +2338,9 @@ export function initAbilities() {
|
|||||||
new Ability(Abilities.MOTOR_DRIVE, "Motor Drive", "Boosts its Speed stat if hit by an Electric-type move instead of taking damage.", 4)
|
new Ability(Abilities.MOTOR_DRIVE, "Motor Drive", "Boosts its Speed stat if hit by an Electric-type move instead of taking damage.", 4)
|
||||||
.attr(TypeImmunityStatChangeAbAttr, Type.ELECTRIC, BattleStat.SPD, 1)
|
.attr(TypeImmunityStatChangeAbAttr, Type.ELECTRIC, BattleStat.SPD, 1)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.RIVALRY, "Rivalry (N)", "Becomes competitive and deals more damage to Pokémon of the same gender, but deals less to Pokémon of the opposite gender.", 4),
|
new Ability(Abilities.RIVALRY, "Rivalry", "Becomes competitive and deals more damage to Pokémon of the same gender, but deals less to Pokémon of the opposite gender.", 4)
|
||||||
|
.attr(MovePowerBoostAbAttr, (user, target, move) => user.gender !== Gender.GENDERLESS && target.gender !== Gender.GENDERLESS && user.gender === target.gender, 1.25)
|
||||||
|
.attr(MovePowerBoostAbAttr, (user, target, move) => user.gender !== Gender.GENDERLESS && target.gender !== Gender.GENDERLESS && user.gender !== target.gender, 0.75),
|
||||||
new Ability(Abilities.STEADFAST, "Steadfast", "The Pokémon's determination boosts the Speed stat each time the Pokémon flinches.", 4)
|
new Ability(Abilities.STEADFAST, "Steadfast", "The Pokémon's determination boosts the Speed stat each time the Pokémon flinches.", 4)
|
||||||
.attr(FlinchStatChangeAbAttr, BattleStat.SPD, 1),
|
.attr(FlinchStatChangeAbAttr, BattleStat.SPD, 1),
|
||||||
new Ability(Abilities.SNOW_CLOAK, "Snow Cloak", "Boosts evasiveness in a hailstorm.", 4)
|
new Ability(Abilities.SNOW_CLOAK, "Snow Cloak", "Boosts evasiveness in a hailstorm.", 4)
|
||||||
@ -2231,8 +2381,12 @@ export function initAbilities() {
|
|||||||
.attr(PostWeatherLapseDamageAbAttr, 2, WeatherType.SUNNY, WeatherType.HARSH_SUN)
|
.attr(PostWeatherLapseDamageAbAttr, 2, WeatherType.SUNNY, WeatherType.HARSH_SUN)
|
||||||
.attr(BattleStatMultiplierAbAttr, BattleStat.SPATK, 1.5)
|
.attr(BattleStatMultiplierAbAttr, BattleStat.SPATK, 1.5)
|
||||||
.condition(getWeatherCondition(WeatherType.SUNNY, WeatherType.HARSH_SUN)),
|
.condition(getWeatherCondition(WeatherType.SUNNY, WeatherType.HARSH_SUN)),
|
||||||
new Ability(Abilities.QUICK_FEET, "Quick Feet (N)", "Boosts the Speed stat if the Pokémon has a status condition.", 4),
|
new Ability(Abilities.QUICK_FEET, "Quick Feet", "Boosts the Speed stat if the Pokémon has a status condition.", 4)
|
||||||
new Ability(Abilities.NORMALIZE, "Normalize (N)", "All the Pokémon's moves become Normal type. The power of those moves is boosted a little.", 4),
|
.conditionalAttr(pokemon => pokemon.status.effect === StatusEffect.PARALYSIS, BattleStatMultiplierAbAttr, BattleStat.SPD, 2)
|
||||||
|
.conditionalAttr(pokemon => !!pokemon.status, BattleStatMultiplierAbAttr, BattleStat.SPD, 1.5),
|
||||||
|
new Ability(Abilities.NORMALIZE, "Normalize", "All the Pokémon's moves become Normal type. The power of those moves is boosted a little.", 4)
|
||||||
|
.attr(MoveTypeChangeAttr, Type.NORMAL, 1.2, (user, target, move) => move.id !== Moves.HIDDEN_POWER && move.id !== Moves.WEATHER_BALL &&
|
||||||
|
move.id !== Moves.NATURAL_GIFT && move.id !== Moves.JUDGMENT && move.id !== Moves.TECHNO_BLAST),
|
||||||
new Ability(Abilities.SNIPER, "Sniper (N)", "Powers up moves if they become critical hits when attacking.", 4),
|
new Ability(Abilities.SNIPER, "Sniper (N)", "Powers up moves if they become critical hits when attacking.", 4),
|
||||||
new Ability(Abilities.MAGIC_GUARD, "Magic Guard", "The Pokémon only takes damage from attacks.", 4)
|
new Ability(Abilities.MAGIC_GUARD, "Magic Guard", "The Pokémon only takes damage from attacks.", 4)
|
||||||
.attr(BlockNonDirectDamageAbAttr),
|
.attr(BlockNonDirectDamageAbAttr),
|
||||||
@ -2300,7 +2454,8 @@ export function initAbilities() {
|
|||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.UNNERVE, "Unnerve", "Unnerves opposing Pokémon and makes them unable to eat Berries.", 5)
|
new Ability(Abilities.UNNERVE, "Unnerve", "Unnerves opposing Pokémon and makes them unable to eat Berries.", 5)
|
||||||
.attr(PreventBerryUseAbAttr),
|
.attr(PreventBerryUseAbAttr),
|
||||||
new Ability(Abilities.DEFIANT, "Defiant (N)", "Boosts the Pokémon's Attack stat sharply when its stats are lowered.", 5),
|
new Ability(Abilities.DEFIANT, "Defiant", "Boosts the Pokémon's Attack stat sharply when its stats are lowered.", 5)
|
||||||
|
.attr(PostStatChangeStatChangeAbAttr, (target, statsChanged, levels) => levels < 0, [BattleStat.ATK], 2),
|
||||||
new Ability(Abilities.DEFEATIST, "Defeatist", "Halves the Pokémon's Attack and Sp. Atk stats when its HP becomes half or less.", 5)
|
new Ability(Abilities.DEFEATIST, "Defeatist", "Halves the Pokémon's Attack and Sp. Atk stats when its HP becomes half or less.", 5)
|
||||||
.attr(BattleStatMultiplierAbAttr, BattleStat.ATK, 0.5)
|
.attr(BattleStatMultiplierAbAttr, BattleStat.ATK, 0.5)
|
||||||
.attr(BattleStatMultiplierAbAttr, BattleStat.SPATK, 0.5)
|
.attr(BattleStatMultiplierAbAttr, BattleStat.SPATK, 0.5)
|
||||||
@ -2356,7 +2511,9 @@ export function initAbilities() {
|
|||||||
.attr(PostSummonTransformAbAttr)
|
.attr(PostSummonTransformAbAttr)
|
||||||
.attr(UncopiableAbilityAbAttr),
|
.attr(UncopiableAbilityAbAttr),
|
||||||
new Ability(Abilities.INFILTRATOR, "Infiltrator (N)", "Passes through the opposing Pokémon's barrier, substitute, and the like and strikes.", 5),
|
new Ability(Abilities.INFILTRATOR, "Infiltrator (N)", "Passes through the opposing Pokémon's barrier, substitute, and the like and strikes.", 5),
|
||||||
new Ability(Abilities.MUMMY, "Mummy (N)", "Contact with the Pokémon changes the attacker's Ability to Mummy.", 5),
|
new Ability(Abilities.MUMMY, "Mummy", "Contact with the Pokémon changes the attacker's Ability to Mummy.", 5)
|
||||||
|
.attr(PostDefendAbilityGiveAbAttr)
|
||||||
|
.bypassFaint(),
|
||||||
new Ability(Abilities.MOXIE, "Moxie", "The Pokémon shows moxie, and that boosts the Attack stat after knocking out any Pokémon.", 5)
|
new Ability(Abilities.MOXIE, "Moxie", "The Pokémon shows moxie, and that boosts the Attack stat after knocking out any Pokémon.", 5)
|
||||||
.attr(PostVictoryStatChangeAbAttr, BattleStat.ATK, 1),
|
.attr(PostVictoryStatChangeAbAttr, BattleStat.ATK, 1),
|
||||||
new Ability(Abilities.JUSTIFIED, "Justified", "Being hit by a Dark-type move boosts the Attack stat of the Pokémon, for justice.", 5)
|
new Ability(Abilities.JUSTIFIED, "Justified", "Being hit by a Dark-type move boosts the Attack stat of the Pokémon, for justice.", 5)
|
||||||
@ -2406,7 +2563,8 @@ export function initAbilities() {
|
|||||||
new Ability(Abilities.BULLETPROOF, "Bulletproof", "Protects the Pokémon from some ball and bomb moves.", 6)
|
new Ability(Abilities.BULLETPROOF, "Bulletproof", "Protects the Pokémon from some ball and bomb moves.", 6)
|
||||||
.attr(MoveImmunityAbAttr, (pokemon, attacker, move) => pokemon !== attacker && move.getMove().hasFlag(MoveFlags.BALLBOMB_MOVE))
|
.attr(MoveImmunityAbAttr, (pokemon, attacker, move) => pokemon !== attacker && move.getMove().hasFlag(MoveFlags.BALLBOMB_MOVE))
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.COMPETITIVE, "Competitive (N)", "Boosts the Sp. Atk stat sharply when a stat is lowered.", 6),
|
new Ability(Abilities.COMPETITIVE, "Competitive", "Boosts the Sp. Atk stat sharply when a stat is lowered.", 6)
|
||||||
|
.attr(PostStatChangeStatChangeAbAttr, (target, statsChanged, levels) => levels < 0, [BattleStat.SPATK], 2),
|
||||||
new Ability(Abilities.STRONG_JAW, "Strong Jaw", "The Pokémon's strong jaw boosts the power of its biting moves.", 6)
|
new Ability(Abilities.STRONG_JAW, "Strong Jaw", "The Pokémon's strong jaw boosts the power of its biting moves.", 6)
|
||||||
.attr(MovePowerBoostAbAttr, (user, target, move) => move.hasFlag(MoveFlags.BITING_MOVE), 1.5),
|
.attr(MovePowerBoostAbAttr, (user, target, move) => move.hasFlag(MoveFlags.BITING_MOVE), 1.5),
|
||||||
new Ability(Abilities.REFRIGERATE, "Refrigerate", "Normal-type moves become Ice-type moves. The power of those moves is boosted a little.", 6)
|
new Ability(Abilities.REFRIGERATE, "Refrigerate", "Normal-type moves become Ice-type moves. The power of those moves is boosted a little.", 6)
|
||||||
@ -2476,7 +2634,8 @@ export function initAbilities() {
|
|||||||
.condition(getWeatherCondition(WeatherType.HAIL)),
|
.condition(getWeatherCondition(WeatherType.HAIL)),
|
||||||
new Ability(Abilities.LONG_REACH, "Long Reach", "The Pokémon uses its moves without making contact with the target.", 7)
|
new Ability(Abilities.LONG_REACH, "Long Reach", "The Pokémon uses its moves without making contact with the target.", 7)
|
||||||
.attr(IgnoreContactAbAttr),
|
.attr(IgnoreContactAbAttr),
|
||||||
new Ability(Abilities.LIQUID_VOICE, "Liquid Voice (N)", "All sound-based moves become Water-type moves.", 7),
|
new Ability(Abilities.LIQUID_VOICE, "Liquid Voice", "All sound-based moves become Water-type moves.", 7)
|
||||||
|
.attr(MoveTypeChangeAttr, Type.WATER, 1, (user, target, move) => move.hasFlag(MoveFlags.SOUND_BASED)),
|
||||||
new Ability(Abilities.TRIAGE, "Triage", "Gives priority to a healing move.", 7)
|
new Ability(Abilities.TRIAGE, "Triage", "Gives priority to a healing move.", 7)
|
||||||
.attr(IncrementMovePriorityAbAttr, (pokemon, move) => move.hasFlag(MoveFlags.TRIAGE_MOVE), 3),
|
.attr(IncrementMovePriorityAbAttr, (pokemon, move) => move.hasFlag(MoveFlags.TRIAGE_MOVE), 3),
|
||||||
new Ability(Abilities.GALVANIZE, "Galvanize", "Normal-type moves become Electric-type moves. The power of those moves is boosted a little.", 7)
|
new Ability(Abilities.GALVANIZE, "Galvanize", "Normal-type moves become Electric-type moves. The power of those moves is boosted a little.", 7)
|
||||||
@ -2524,9 +2683,11 @@ export function initAbilities() {
|
|||||||
.attr(PostKnockOutStatChangeAbAttr, BattleStat.SPATK, 1),
|
.attr(PostKnockOutStatChangeAbAttr, BattleStat.SPATK, 1),
|
||||||
new Ability(Abilities.TANGLING_HAIR, "Tangling Hair", "Contact with the Pokémon lowers the attacker's Speed stat.", 7)
|
new Ability(Abilities.TANGLING_HAIR, "Tangling Hair", "Contact with the Pokémon lowers the attacker's Speed stat.", 7)
|
||||||
.attr(PostDefendStatChangeAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT), BattleStat.SPD, -1, false),
|
.attr(PostDefendStatChangeAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT), BattleStat.SPD, -1, false),
|
||||||
new Ability(Abilities.RECEIVER, "Receiver (N)", "The Pokémon copies the Ability of a defeated ally.", 7)
|
new Ability(Abilities.RECEIVER, "Receiver", "The Pokémon copies the Ability of a defeated ally.", 7)
|
||||||
|
.attr(CopyFaintedAllyAbilityAbAttr)
|
||||||
.attr(UncopiableAbilityAbAttr),
|
.attr(UncopiableAbilityAbAttr),
|
||||||
new Ability(Abilities.POWER_OF_ALCHEMY, "Power of Alchemy (N)", "The Pokémon copies the Ability of a defeated ally.", 7)
|
new Ability(Abilities.POWER_OF_ALCHEMY, "Power of Alchemy", "The Pokémon copies the Ability of a defeated ally.", 7)
|
||||||
|
.attr(CopyFaintedAllyAbilityAbAttr)
|
||||||
.attr(UncopiableAbilityAbAttr),
|
.attr(UncopiableAbilityAbAttr),
|
||||||
new Ability(Abilities.BEAST_BOOST, "Beast Boost", "The Pokémon boosts its most proficient stat each time it knocks out a Pokémon.", 7)
|
new Ability(Abilities.BEAST_BOOST, "Beast Boost", "The Pokémon boosts its most proficient stat each time it knocks out a Pokémon.", 7)
|
||||||
.attr(PostVictoryStatChangeAbAttr, p => {
|
.attr(PostVictoryStatChangeAbAttr, p => {
|
||||||
@ -2604,7 +2765,9 @@ export function initAbilities() {
|
|||||||
new Ability(Abilities.SCREEN_CLEANER, "Screen Cleaner (N)", "When the Pokémon enters a battle, the effects of Light Screen, Reflect, and Aurora Veil are nullified for both opposing and ally Pokémon.", 8),
|
new Ability(Abilities.SCREEN_CLEANER, "Screen Cleaner (N)", "When the Pokémon enters a battle, the effects of Light Screen, Reflect, and Aurora Veil are nullified for both opposing and ally Pokémon.", 8),
|
||||||
new Ability(Abilities.STEELY_SPIRIT, "Steely Spirit (N)", "Powers up ally Pokémon's Steel-type moves.", 8),
|
new Ability(Abilities.STEELY_SPIRIT, "Steely Spirit (N)", "Powers up ally Pokémon's Steel-type moves.", 8),
|
||||||
new Ability(Abilities.PERISH_BODY, "Perish Body (N)", "When hit by a move that makes direct contact, the Pokémon and the attacker will faint after three turns unless they switch out of battle.", 8),
|
new Ability(Abilities.PERISH_BODY, "Perish Body (N)", "When hit by a move that makes direct contact, the Pokémon and the attacker will faint after three turns unless they switch out of battle.", 8),
|
||||||
new Ability(Abilities.WANDERING_SPIRIT, "Wandering Spirit (N)", "The Pokémon exchanges Abilities with a Pokémon that hits it with a move that makes direct contact.", 8),
|
new Ability(Abilities.WANDERING_SPIRIT, "Wandering Spirit (P)", "The Pokémon exchanges Abilities with a Pokémon that hits it with a move that makes direct contact.", 8)
|
||||||
|
.attr(PostDefendAbilitySwapAbAttr)
|
||||||
|
.bypassFaint(),
|
||||||
new Ability(Abilities.GORILLA_TACTICS, "Gorilla Tactics (N)", "Boosts the Pokémon's Attack stat but only allows the use of the first selected move.", 8),
|
new Ability(Abilities.GORILLA_TACTICS, "Gorilla Tactics (N)", "Boosts the Pokémon's Attack stat but only allows the use of the first selected move.", 8),
|
||||||
new Ability(Abilities.NEUTRALIZING_GAS, "Neutralizing Gas (N)", "If the Pokémon with Neutralizing Gas is in the battle, the effects of all Pokémon's Abilities will be nullified or will not be triggered.", 8)
|
new Ability(Abilities.NEUTRALIZING_GAS, "Neutralizing Gas (N)", "If the Pokémon with Neutralizing Gas is in the battle, the effects of all Pokémon's Abilities will be nullified or will not be triggered.", 8)
|
||||||
.attr(UncopiableAbilityAbAttr)
|
.attr(UncopiableAbilityAbAttr)
|
||||||
@ -2642,7 +2805,9 @@ export function initAbilities() {
|
|||||||
.attr(UncopiableAbilityAbAttr)
|
.attr(UncopiableAbilityAbAttr)
|
||||||
.attr(UnswappableAbilityAbAttr)
|
.attr(UnswappableAbilityAbAttr)
|
||||||
.attr(UnsuppressableAbilityAbAttr),
|
.attr(UnsuppressableAbilityAbAttr),
|
||||||
new Ability(Abilities.LINGERING_AROMA, "Lingering Aroma (N)", "Contact with the Pokémon changes the attacker's Ability to Lingering Aroma.", 9),
|
new Ability(Abilities.LINGERING_AROMA, "Lingering Aroma", "Contact with the Pokémon changes the attacker's Ability to Lingering Aroma.", 9)
|
||||||
|
.attr(PostDefendAbilityGiveAbAttr)
|
||||||
|
.bypassFaint(),
|
||||||
new Ability(Abilities.SEED_SOWER, "Seed Sower", "Turns the ground into Grassy Terrain when the Pokémon is hit by an attack.", 9)
|
new Ability(Abilities.SEED_SOWER, "Seed Sower", "Turns the ground into Grassy Terrain when the Pokémon is hit by an attack.", 9)
|
||||||
.attr(PostDefendTerrainChangeAbAttr, TerrainType.GRASSY),
|
.attr(PostDefendTerrainChangeAbAttr, TerrainType.GRASSY),
|
||||||
new Ability(Abilities.THERMAL_EXCHANGE, "Thermal Exchange (P)", "Boosts the Attack stat when the Pokémon is hit by a Fire-type move. The Pokémon also cannot be burned.", 9)
|
new Ability(Abilities.THERMAL_EXCHANGE, "Thermal Exchange (P)", "Boosts the Attack stat when the Pokémon is hit by a Fire-type move. The Pokémon also cannot be burned.", 9)
|
||||||
@ -2720,7 +2885,8 @@ export function initAbilities() {
|
|||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.SUPERSWEET_SYRUP, "Supersweet Syrup (N)", "A sickly sweet scent spreads across the field the first time the Pokémon enters a battle, lowering the evasiveness of opposing Pokémon.", 9),
|
new Ability(Abilities.SUPERSWEET_SYRUP, "Supersweet Syrup (N)", "A sickly sweet scent spreads across the field the first time the Pokémon enters a battle, lowering the evasiveness of opposing Pokémon.", 9),
|
||||||
new Ability(Abilities.HOSPITALITY, "Hospitality (N)", "When the Pokémon enters a battle, it showers its ally with hospitality, restoring a small amount of the ally's HP.", 9),
|
new Ability(Abilities.HOSPITALITY, "Hospitality (N)", "When the Pokémon enters a battle, it showers its ally with hospitality, restoring a small amount of the ally's HP.", 9),
|
||||||
new Ability(Abilities.TOXIC_CHAIN, "Toxic Chain (N)", "The power of the Pokémon's toxic chain may badly poison any target the Pokémon hits with a move.", 9),
|
new Ability(Abilities.TOXIC_CHAIN, "Toxic Chain", "The power of the Pokémon's toxic chain may badly poison any target the Pokémon hits with a move.", 9)
|
||||||
|
.attr(PostAttackApplyStatusEffectAbAttr, false, 30, StatusEffect.TOXIC),
|
||||||
new Ability(Abilities.EMBODY_ASPECT_TEAL, "Embody Aspect", "The Pokémon's heart fills with memories, causing the Teal Mask to shine and the Pokémon's Speed stat to be boosted.", 9)
|
new Ability(Abilities.EMBODY_ASPECT_TEAL, "Embody Aspect", "The Pokémon's heart fills with memories, causing the Teal Mask to shine and the Pokémon's Speed stat to be boosted.", 9)
|
||||||
.attr(PostBattleInitStatChangeAbAttr, BattleStat.SPD, 1, true)
|
.attr(PostBattleInitStatChangeAbAttr, BattleStat.SPD, 1, true)
|
||||||
.attr(UncopiableAbilityAbAttr)
|
.attr(UncopiableAbilityAbAttr)
|
||||||
|
@ -64,6 +64,8 @@ function getDailyRunStarter(scene: BattleScene, starterSpeciesForm: PokemonSpeci
|
|||||||
const starter: Starter = {
|
const starter: Starter = {
|
||||||
species: starterSpecies,
|
species: starterSpecies,
|
||||||
dexAttr: pokemon.getDexAttr(),
|
dexAttr: pokemon.getDexAttr(),
|
||||||
|
passive: false,
|
||||||
|
variant: 0,
|
||||||
nature: pokemon.getNature(),
|
nature: pokemon.getNature(),
|
||||||
pokerus: pokemon.pokerus
|
pokerus: pokemon.pokerus
|
||||||
};
|
};
|
||||||
|
151
src/data/move.ts
@ -12,8 +12,9 @@ import * as Utils from "../utils";
|
|||||||
import { WeatherType } from "./weather";
|
import { WeatherType } from "./weather";
|
||||||
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
|
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
|
||||||
import { ArenaTagType } from "./enums/arena-tag-type";
|
import { ArenaTagType } from "./enums/arena-tag-type";
|
||||||
import { UnswappableAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr } from "./ability";
|
import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, NoTransformAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr } from "./ability";
|
||||||
import { Abilities } from "./enums/abilities";
|
import { Abilities } from "./enums/abilities";
|
||||||
|
import { allAbilities } from './ability';
|
||||||
import { PokemonHeldItemModifier } from "../modifier/modifier";
|
import { PokemonHeldItemModifier } from "../modifier/modifier";
|
||||||
import { BattlerIndex } from "../battle";
|
import { BattlerIndex } from "../battle";
|
||||||
import { Stat } from "./pokemon-stat";
|
import { Stat } from "./pokemon-stat";
|
||||||
@ -21,6 +22,7 @@ import { TerrainType } from "./terrain";
|
|||||||
import { SpeciesFormChangeActiveTrigger } from "./pokemon-forms";
|
import { SpeciesFormChangeActiveTrigger } from "./pokemon-forms";
|
||||||
import { Species } from "./enums/species";
|
import { Species } from "./enums/species";
|
||||||
import { ModifierPoolType } from "#app/modifier/modifier-type";
|
import { ModifierPoolType } from "#app/modifier/modifier-type";
|
||||||
|
import { Command } from "../ui/command-ui-handler";
|
||||||
|
|
||||||
export enum MoveCategory {
|
export enum MoveCategory {
|
||||||
PHYSICAL,
|
PHYSICAL,
|
||||||
@ -2935,6 +2937,91 @@ export class SketchAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class AbilityChangeAttr extends MoveEffectAttr {
|
||||||
|
public ability: Abilities;
|
||||||
|
|
||||||
|
constructor(ability: Abilities, selfTarget?: boolean) {
|
||||||
|
super(selfTarget, MoveEffectTrigger.HIT);
|
||||||
|
|
||||||
|
this.ability = ability;
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
|
if (!super.apply(user, target, move, args))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
(this.selfTarget ? user : target).summonData.ability = this.ability;
|
||||||
|
|
||||||
|
user.scene.queueMessage('The ' + getPokemonMessage((this.selfTarget ? user : target), ` acquired\n${allAbilities[this.ability].name}!`));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCondition(): MoveConditionFunc {
|
||||||
|
return (user, target, move) => !(this.selfTarget ? user : target).getAbility().hasAttr(UnsuppressableAbilityAbAttr) && (this.selfTarget ? user : target).getAbility().id !== this.ability;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AbilityCopyAttr extends MoveEffectAttr {
|
||||||
|
public copyToPartner: boolean;
|
||||||
|
|
||||||
|
constructor(copyToPartner: boolean = false) {
|
||||||
|
super(false, MoveEffectTrigger.HIT);
|
||||||
|
|
||||||
|
this.copyToPartner = copyToPartner;
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
|
if (!super.apply(user, target, move, args))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
user.summonData.ability = target.getAbility().id;
|
||||||
|
|
||||||
|
user.scene.queueMessage(getPokemonMessage(user, ` copied the `) + getPokemonMessage(target, `'s\n${allAbilities[target.getAbility().id].name}!`));
|
||||||
|
|
||||||
|
if (this.copyToPartner && user.scene.currentBattle?.double && user.getAlly().hp) {
|
||||||
|
user.getAlly().summonData.ability = target.getAbility().id;
|
||||||
|
user.getAlly().scene.queueMessage(getPokemonMessage(user.getAlly(), ` copied the `) + getPokemonMessage(target, `'s\n${allAbilities[target.getAbility().id].name}!`));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCondition(): MoveConditionFunc {
|
||||||
|
return (user, target, move) => {
|
||||||
|
let ret = !target.getAbility().hasAttr(UncopiableAbilityAbAttr) && !user.getAbility().hasAttr(UnsuppressableAbilityAbAttr);
|
||||||
|
if (this.copyToPartner && user.scene.currentBattle?.double)
|
||||||
|
ret = ret && (!user.getAlly().hp || !user.getAlly().getAbility().hasAttr(UnsuppressableAbilityAbAttr));
|
||||||
|
else
|
||||||
|
ret = ret && user.getAbility().id !== target.getAbility().id;
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AbilityGiveAttr extends MoveEffectAttr {
|
||||||
|
public copyToPartner: boolean;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(false, MoveEffectTrigger.HIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
|
if (!super.apply(user, target, move, args))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
target.summonData.ability = user.getAbility().id;
|
||||||
|
|
||||||
|
user.scene.queueMessage('The' + getPokemonMessage(target, `\nacquired ${allAbilities[user.getAbility().id].name}!`));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCondition(): MoveConditionFunc {
|
||||||
|
return (user, target, move) => !user.getAbility().hasAttr(UncopiableAbilityAbAttr) && !target.getAbility().hasAttr(UnsuppressableAbilityAbAttr) && user.getAbility().id !== target.getAbility().id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class SwitchAbilitiesAttr extends MoveEffectAttr {
|
export class SwitchAbilitiesAttr extends MoveEffectAttr {
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
if (!super.apply(user, target, move, args))
|
if (!super.apply(user, target, move, args))
|
||||||
@ -2944,7 +3031,7 @@ export class SwitchAbilitiesAttr extends MoveEffectAttr {
|
|||||||
user.summonData.ability = target.getAbility().id;
|
user.summonData.ability = target.getAbility().id;
|
||||||
target.summonData.ability = tempAbilityId;
|
target.summonData.ability = tempAbilityId;
|
||||||
|
|
||||||
user.scene.queueMessage(getPokemonMessage(user, ` swapped\nAbilities with its target!`));
|
user.scene.queueMessage(getPokemonMessage(user, ` swapped\nabilities with its target!`));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2962,6 +3049,7 @@ export class TransformAttr extends MoveEffectAttr {
|
|||||||
|
|
||||||
user.summonData.speciesForm = target.getSpeciesForm();
|
user.summonData.speciesForm = target.getSpeciesForm();
|
||||||
user.summonData.fusionSpeciesForm = target.getFusionSpeciesForm();
|
user.summonData.fusionSpeciesForm = target.getFusionSpeciesForm();
|
||||||
|
user.summonData.ability = target.getAbility().id;
|
||||||
user.summonData.gender = target.getGender();
|
user.summonData.gender = target.getGender();
|
||||||
user.summonData.fusionGender = target.getFusionGender();
|
user.summonData.fusionGender = target.getFusionGender();
|
||||||
user.summonData.stats = [ user.stats[Stat.HP] ].concat(target.stats.slice(1));
|
user.summonData.stats = [ user.stats[Stat.HP] ].concat(target.stats.slice(1));
|
||||||
@ -3800,9 +3888,10 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.FACADE, "Facade", Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 20, "This attack move doubles its power if the user is poisoned, burned, or paralyzed.", -1, 0, 3)
|
new AttackMove(Moves.FACADE, "Facade", Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 20, "This attack move doubles its power if the user is poisoned, burned, or paralyzed.", -1, 0, 3)
|
||||||
.attr(MovePowerMultiplierAttr, (user, target, move) => user.status
|
.attr(MovePowerMultiplierAttr, (user, target, move) => user.status
|
||||||
&& (user.status.effect === StatusEffect.BURN || user.status.effect === StatusEffect.POISON || user.status.effect === StatusEffect.TOXIC || user.status.effect === StatusEffect.PARALYSIS) ? 2 : 1),
|
&& (user.status.effect === StatusEffect.BURN || user.status.effect === StatusEffect.POISON || user.status.effect === StatusEffect.TOXIC || user.status.effect === StatusEffect.PARALYSIS) ? 2 : 1),
|
||||||
new AttackMove(Moves.FOCUS_PUNCH, "Focus Punch (P)", Type.FIGHTING, MoveCategory.PHYSICAL, 150, 100, 20, "The user focuses its mind before launching a punch. This move fails if the user is hit before it is used.", -1, -3, 3)
|
new AttackMove(Moves.FOCUS_PUNCH, "Focus Punch", Type.FIGHTING, MoveCategory.PHYSICAL, 150, 100, 20, "The user focuses its mind before launching a punch. This move fails if the user is hit before it is used.", -1, -3, 3)
|
||||||
.punchingMove()
|
.punchingMove()
|
||||||
.ignoresVirtual(),
|
.ignoresVirtual()
|
||||||
|
.condition((user, target, move) => !user.turnData.attacksReceived.find(r => r.damage)),
|
||||||
new AttackMove(Moves.SMELLING_SALTS, "Smelling Salts", Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 10, "This attack's power is doubled when used on a target with paralysis. This also cures the target's paralysis, however.", -1, 0, 3)
|
new AttackMove(Moves.SMELLING_SALTS, "Smelling Salts", Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 10, "This attack's power is doubled when used on a target with paralysis. This also cures the target's paralysis, however.", -1, 0, 3)
|
||||||
.attr(MovePowerMultiplierAttr, (user, target, move) => target.status?.effect === StatusEffect.PARALYSIS ? 2 : 1)
|
.attr(MovePowerMultiplierAttr, (user, target, move) => target.status?.effect === StatusEffect.PARALYSIS ? 2 : 1)
|
||||||
.attr(HealStatusEffectAttr, true, StatusEffect.PARALYSIS),
|
.attr(HealStatusEffectAttr, true, StatusEffect.PARALYSIS),
|
||||||
@ -3815,7 +3904,8 @@ export function initMoves() {
|
|||||||
.attr(AddBattlerTagAttr, BattlerTagType.HELPING_HAND)
|
.attr(AddBattlerTagAttr, BattlerTagType.HELPING_HAND)
|
||||||
.target(MoveTarget.NEAR_ALLY),
|
.target(MoveTarget.NEAR_ALLY),
|
||||||
new StatusMove(Moves.TRICK, "Trick (N)", Type.PSYCHIC, 100, 10, "The user catches the target off guard and swaps its held item with its own.", -1, 0, 3),
|
new StatusMove(Moves.TRICK, "Trick (N)", Type.PSYCHIC, 100, 10, "The user catches the target off guard and swaps its held item with its own.", -1, 0, 3),
|
||||||
new StatusMove(Moves.ROLE_PLAY, "Role Play (N)", Type.PSYCHIC, -1, 10, "The user mimics the target completely, copying the target's Ability.", -1, 0, 3),
|
new StatusMove(Moves.ROLE_PLAY, "Role Play", Type.PSYCHIC, -1, 10, "The user mimics the target completely, copying the target's Ability.", -1, 0, 3)
|
||||||
|
.attr(AbilityCopyAttr),
|
||||||
new SelfStatusMove(Moves.WISH, "Wish (N)", Type.NORMAL, -1, 10, "One turn after this move is used, the user's or its replacement's HP is restored by half the user's max HP.", -1, 0, 3)
|
new SelfStatusMove(Moves.WISH, "Wish (N)", Type.NORMAL, -1, 10, "One turn after this move is used, the user's or its replacement's HP is restored by half the user's max HP.", -1, 0, 3)
|
||||||
.triageMove(),
|
.triageMove(),
|
||||||
new SelfStatusMove(Moves.ASSIST, "Assist", Type.NORMAL, -1, 20, "The user hurriedly and randomly uses a move among those known by ally Pokémon.", -1, 0, 3)
|
new SelfStatusMove(Moves.ASSIST, "Assist", Type.NORMAL, -1, 20, "The user hurriedly and randomly uses a move among those known by ally Pokémon.", -1, 0, 3)
|
||||||
@ -3827,7 +3917,8 @@ export function initMoves() {
|
|||||||
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], -1, true),
|
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], -1, true),
|
||||||
new SelfStatusMove(Moves.MAGIC_COAT, "Magic Coat (N)", Type.PSYCHIC, -1, 15, "Moves like Leech Seed and moves that inflict status conditions are blocked by a barrier and reflected back to the user of those moves.", -1, 4, 3),
|
new SelfStatusMove(Moves.MAGIC_COAT, "Magic Coat (N)", Type.PSYCHIC, -1, 15, "Moves like Leech Seed and moves that inflict status conditions are blocked by a barrier and reflected back to the user of those moves.", -1, 4, 3),
|
||||||
new SelfStatusMove(Moves.RECYCLE, "Recycle (N)", Type.NORMAL, -1, 10, "The user recycles a held item that has been used in battle so it can be used again.", -1, 0, 3),
|
new SelfStatusMove(Moves.RECYCLE, "Recycle (N)", Type.NORMAL, -1, 10, "The user recycles a held item that has been used in battle so it can be used again.", -1, 0, 3),
|
||||||
new AttackMove(Moves.REVENGE, "Revenge (P)", Type.FIGHTING, MoveCategory.PHYSICAL, 60, 100, 10, "This attack move's power is doubled if the user has been hurt by the opponent in the same turn.", -1, -4, 3),
|
new AttackMove(Moves.REVENGE, "Revenge", Type.FIGHTING, MoveCategory.PHYSICAL, 60, 100, 10, "This attack move's power is doubled if the user has been hurt by the opponent in the same turn.", -1, -4, 3)
|
||||||
|
.attr(TurnDamagedDoublePowerAttr),
|
||||||
new AttackMove(Moves.BRICK_BREAK, "Brick Break (P)", Type.FIGHTING, MoveCategory.PHYSICAL, 75, 100, 15, "The user attacks with a swift chop. It can also break barriers, such as Light Screen and Reflect.", -1, 0, 3)
|
new AttackMove(Moves.BRICK_BREAK, "Brick Break (P)", Type.FIGHTING, MoveCategory.PHYSICAL, 75, 100, 15, "The user attacks with a swift chop. It can also break barriers, such as Light Screen and Reflect.", -1, 0, 3)
|
||||||
.attr(RemoveScreensAttr),
|
.attr(RemoveScreensAttr),
|
||||||
new StatusMove(Moves.YAWN, "Yawn", Type.NORMAL, -1, 10, "The user lets loose a huge yawn that lulls the target into falling asleep on the next turn.", -1, 0, 3)
|
new StatusMove(Moves.YAWN, "Yawn", Type.NORMAL, -1, 10, "The user lets loose a huge yawn that lulls the target into falling asleep on the next turn.", -1, 0, 3)
|
||||||
@ -4098,8 +4189,10 @@ export function initMoves() {
|
|||||||
});
|
});
|
||||||
return uniqueUsedMoveIds.size >= movesetMoveIds.length - 1;
|
return uniqueUsedMoveIds.size >= movesetMoveIds.length - 1;
|
||||||
}),
|
}),
|
||||||
new StatusMove(Moves.WORRY_SEED, "Worry Seed (N)", Type.GRASS, 100, 10, "A seed that causes worry is planted on the target. It prevents sleep by making the target's Ability Insomnia.", -1, 0, 4),
|
new StatusMove(Moves.WORRY_SEED, "Worry Seed", Type.GRASS, 100, 10, "A seed that causes worry is planted on the target. It prevents sleep by making the target's Ability Insomnia.", -1, 0, 4)
|
||||||
new AttackMove(Moves.SUCKER_PUNCH, "Sucker Punch (P)", Type.DARK, MoveCategory.PHYSICAL, 70, 100, 5, "This move enables the user to attack first. This move fails if the target is not readying an attack.", -1, 1, 4),
|
.attr(AbilityChangeAttr, Abilities.INSOMNIA),
|
||||||
|
new AttackMove(Moves.SUCKER_PUNCH, "Sucker Punch", Type.DARK, MoveCategory.PHYSICAL, 70, 100, 5, "This move enables the user to attack first. This move fails if the target is not readying an attack.", -1, 1, 4)
|
||||||
|
.condition((user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.FIGHT && !target.turnData.acted && allMoves[user.scene.currentBattle.turnCommands[target.getBattlerIndex()].move.move].category !== MoveCategory.STATUS),
|
||||||
new StatusMove(Moves.TOXIC_SPIKES, "Toxic Spikes", Type.POISON, -1, 20, "The user lays a trap of poison spikes at the feet of the opposing team. The spikes will poison opposing Pokémon that switch into battle.", -1, 0, 4)
|
new StatusMove(Moves.TOXIC_SPIKES, "Toxic Spikes", Type.POISON, -1, 20, "The user lays a trap of poison spikes at the feet of the opposing team. The spikes will poison opposing Pokémon that switch into battle.", -1, 0, 4)
|
||||||
.attr(AddArenaTrapTagAttr, ArenaTagType.TOXIC_SPIKES)
|
.attr(AddArenaTrapTagAttr, ArenaTagType.TOXIC_SPIKES)
|
||||||
.target(MoveTarget.ENEMY_SIDE),
|
.target(MoveTarget.ENEMY_SIDE),
|
||||||
@ -4347,8 +4440,10 @@ export function initMoves() {
|
|||||||
.ballBombMove(),
|
.ballBombMove(),
|
||||||
new AttackMove(Moves.FOUL_PLAY, "Foul Play", Type.DARK, MoveCategory.PHYSICAL, 95, 100, 15, "The user turns the target's power against it. The higher the target's Attack stat, the greater the damage it deals.", -1, 0, 5)
|
new AttackMove(Moves.FOUL_PLAY, "Foul Play", Type.DARK, MoveCategory.PHYSICAL, 95, 100, 15, "The user turns the target's power against it. The higher the target's Attack stat, the greater the damage it deals.", -1, 0, 5)
|
||||||
.attr(TargetAtkUserAtkAttr),
|
.attr(TargetAtkUserAtkAttr),
|
||||||
new StatusMove(Moves.SIMPLE_BEAM, "Simple Beam (N)", Type.NORMAL, 100, 15, "The user's mysterious psychic wave changes the target's Ability to Simple.", -1, 0, 5),
|
new StatusMove(Moves.SIMPLE_BEAM, "Simple Beam", Type.NORMAL, 100, 15, "The user's mysterious psychic wave changes the target's Ability to Simple.", -1, 0, 5)
|
||||||
new StatusMove(Moves.ENTRAINMENT, "Entrainment (N)", Type.NORMAL, 100, 15, "The user dances with an odd rhythm that compels the target to mimic it, making the target's Ability the same as the user's.", -1, 0, 5),
|
.attr(AbilityChangeAttr, Abilities.SIMPLE),
|
||||||
|
new StatusMove(Moves.ENTRAINMENT, "Entrainment", Type.NORMAL, 100, 15, "The user dances with an odd rhythm that compels the target to mimic it, making the target's Ability the same as the user's.", -1, 0, 5)
|
||||||
|
.attr(AbilityGiveAttr),
|
||||||
new StatusMove(Moves.AFTER_YOU, "After You (N)", Type.NORMAL, -1, 15, "The user helps the target and makes it use its move right after the user.", -1, 0, 5)
|
new StatusMove(Moves.AFTER_YOU, "After You (N)", Type.NORMAL, -1, 15, "The user helps the target and makes it use its move right after the user.", -1, 0, 5)
|
||||||
.ignoresProtect(),
|
.ignoresProtect(),
|
||||||
new AttackMove(Moves.ROUND, "Round (P)", Type.NORMAL, MoveCategory.SPECIAL, 60, 100, 15, "The user attacks the target with a song. Others can join in the Round to increase the power of the attack.", -1, 0, 5)
|
new AttackMove(Moves.ROUND, "Round (P)", Type.NORMAL, MoveCategory.SPECIAL, 60, 100, 15, "The user attacks the target with a song. Others can join in the Round to increase the power of the attack.", -1, 0, 5)
|
||||||
@ -4792,7 +4887,8 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.PULVERIZING_PANCAKE, "Pulverizing Pancake (P)", Type.NORMAL, MoveCategory.PHYSICAL, 210, -1, 1, "Z-Power brings out the true capabilities of the user, Snorlax. The Pokémon moves its enormous body energetically and attacks the target with full force.", -1, 0, 7),
|
new AttackMove(Moves.PULVERIZING_PANCAKE, "Pulverizing Pancake (P)", Type.NORMAL, MoveCategory.PHYSICAL, 210, -1, 1, "Z-Power brings out the true capabilities of the user, Snorlax. The Pokémon moves its enormous body energetically and attacks the target with full force.", -1, 0, 7),
|
||||||
new SelfStatusMove(Moves.EXTREME_EVOBOOST, "Extreme Evoboost", Type.NORMAL, -1, 1, "After obtaining Z-Power, the user, Eevee, gets energy from its evolved friends and boosts its stats sharply.", 100, 0, 7)
|
new SelfStatusMove(Moves.EXTREME_EVOBOOST, "Extreme Evoboost", Type.NORMAL, -1, 1, "After obtaining Z-Power, the user, Eevee, gets energy from its evolved friends and boosts its stats sharply.", 100, 0, 7)
|
||||||
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 2, true),
|
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 2, true),
|
||||||
new AttackMove(Moves.GENESIS_SUPERNOVA, "Genesis Supernova (P)", Type.PSYCHIC, MoveCategory.SPECIAL, 185, -1, 1, "After obtaining Z-Power, the user, Mew, attacks the target with full force. The terrain will be charged with psychic energy.", -1, 0, 7),
|
new AttackMove(Moves.GENESIS_SUPERNOVA, "Genesis Supernova", Type.PSYCHIC, MoveCategory.SPECIAL, 185, -1, 1, "After obtaining Z-Power, the user, Mew, attacks the target with full force. The terrain will be charged with psychic energy.", -1, 0, 7)
|
||||||
|
.attr(TerrainChangeAttr, TerrainType.PSYCHIC),
|
||||||
/* End Unused */
|
/* End Unused */
|
||||||
new AttackMove(Moves.SHELL_TRAP, "Shell Trap (P)", Type.FIRE, MoveCategory.SPECIAL, 150, 100, 5, "The user sets a shell trap. If the user is hit by a physical move, the trap will explode and inflict damage on opposing Pokémon.", -1, -3, 7)
|
new AttackMove(Moves.SHELL_TRAP, "Shell Trap (P)", Type.FIRE, MoveCategory.SPECIAL, 150, 100, 5, "The user sets a shell trap. If the user is hit by a physical move, the trap will explode and inflict damage on opposing Pokémon.", -1, -3, 7)
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
@ -4841,6 +4937,7 @@ export function initMoves() {
|
|||||||
.attr(ClearTerrainAttr)
|
.attr(ClearTerrainAttr)
|
||||||
.makesContact(false),
|
.makesContact(false),
|
||||||
new AttackMove(Moves.CLANGOROUS_SOULBLAZE, "Clangorous Soulblaze (P)", Type.DRAGON, MoveCategory.SPECIAL, 185, -1, 1, "After obtaining Z-Power, the user, Kommo-o, attacks the opposing Pokémon with full force. This move boosts the user's stats.", 100, 0, 7)
|
new AttackMove(Moves.CLANGOROUS_SOULBLAZE, "Clangorous Soulblaze (P)", Type.DRAGON, MoveCategory.SPECIAL, 185, -1, 1, "After obtaining Z-Power, the user, Kommo-o, attacks the opposing Pokémon with full force. This move boosts the user's stats.", 100, 0, 7)
|
||||||
|
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 1, true)
|
||||||
.soundBased()
|
.soundBased()
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
/* End Unused */
|
/* End Unused */
|
||||||
@ -4981,8 +5078,9 @@ export function initMoves() {
|
|||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
new AttackMove(Moves.APPLE_ACID, "Apple Acid", Type.GRASS, MoveCategory.SPECIAL, 80, 100, 10, "The user attacks the target with an acidic liquid created from tart apples. This also lowers the target's Sp. Def stat.", 100, 0, 8)
|
new AttackMove(Moves.APPLE_ACID, "Apple Acid", Type.GRASS, MoveCategory.SPECIAL, 80, 100, 10, "The user attacks the target with an acidic liquid created from tart apples. This also lowers the target's Sp. Def stat.", 100, 0, 8)
|
||||||
.attr(StatChangeAttr, BattleStat.SPDEF, -1),
|
.attr(StatChangeAttr, BattleStat.SPDEF, -1),
|
||||||
new AttackMove(Moves.GRAV_APPLE, "Grav Apple (P)", Type.GRASS, MoveCategory.PHYSICAL, 80, 100, 10, "The user inflicts damage by dropping an apple from high above. This also lowers the target's Defense stat.", 100, 0, 8)
|
new AttackMove(Moves.GRAV_APPLE, "Grav Apple", Type.GRASS, MoveCategory.PHYSICAL, 80, 100, 10, "The user inflicts damage by dropping an apple from high above. This also lowers the target's Defense stat.", 100, 0, 8)
|
||||||
.attr(StatChangeAttr, BattleStat.DEF, -1)
|
.attr(StatChangeAttr, BattleStat.DEF, -1)
|
||||||
|
.attr(MovePowerMultiplierAttr, (user, target, move) => user.scene.arena.getTag(ArenaTagType.GRAVITY) ? 1.5 : 1)
|
||||||
.makesContact(false),
|
.makesContact(false),
|
||||||
new AttackMove(Moves.SPIRIT_BREAK, "Spirit Break", Type.FAIRY, MoveCategory.PHYSICAL, 75, 100, 15, "The user attacks the target with so much force that it could break the target's spirit. This also lowers the target's Sp. Atk stat.", 100, 0, 8)
|
new AttackMove(Moves.SPIRIT_BREAK, "Spirit Break", Type.FAIRY, MoveCategory.PHYSICAL, 75, 100, 15, "The user attacks the target with so much force that it could break the target's spirit. This also lowers the target's Sp. Atk stat.", 100, 0, 8)
|
||||||
.attr(StatChangeAttr, BattleStat.SPATK, -1),
|
.attr(StatChangeAttr, BattleStat.SPATK, -1),
|
||||||
@ -5050,7 +5148,7 @@ export function initMoves() {
|
|||||||
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE)
|
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE)
|
||||||
.attr(StatusEffectAttr, StatusEffect.BURN),
|
.attr(StatusEffectAttr, StatusEffect.BURN),
|
||||||
new StatusMove(Moves.JUNGLE_HEALING, "Jungle Healing (P)", Type.GRASS, -1, 10, "The user becomes one with the jungle, restoring HP and healing any status conditions of itself and its ally Pokémon in battle.", -1, 0, 8)
|
new StatusMove(Moves.JUNGLE_HEALING, "Jungle Healing (P)", Type.GRASS, -1, 10, "The user becomes one with the jungle, restoring HP and healing any status conditions of itself and its ally Pokémon in battle.", -1, 0, 8)
|
||||||
.attr(HealAttr, 0.25)
|
.attr(HealAttr, 0.25, true, false)
|
||||||
.target(MoveTarget.USER_AND_ALLIES),
|
.target(MoveTarget.USER_AND_ALLIES),
|
||||||
new AttackMove(Moves.WICKED_BLOW, "Wicked Blow", Type.DARK, MoveCategory.PHYSICAL, 75, 100, 5, "The user, having mastered the Dark style, strikes the target with a fierce blow. This attack always results in a critical hit.", -1, 0, 8)
|
new AttackMove(Moves.WICKED_BLOW, "Wicked Blow", Type.DARK, MoveCategory.PHYSICAL, 75, 100, 5, "The user, having mastered the Dark style, strikes the target with a fierce blow. This attack always results in a critical hit.", -1, 0, 8)
|
||||||
.attr(CritOnlyAttr)
|
.attr(CritOnlyAttr)
|
||||||
@ -5260,7 +5358,8 @@ export function initMoves() {
|
|||||||
.attr(LapseBattlerTagAttr, [ BattlerTagType.BIND, BattlerTagType.WRAP, BattlerTagType.FIRE_SPIN, BattlerTagType.WHIRLPOOL, BattlerTagType.CLAMP, BattlerTagType.SAND_TOMB, BattlerTagType.MAGMA_STORM, BattlerTagType.THUNDER_CAGE, BattlerTagType.SEEDED ], true)
|
.attr(LapseBattlerTagAttr, [ BattlerTagType.BIND, BattlerTagType.WRAP, BattlerTagType.FIRE_SPIN, BattlerTagType.WHIRLPOOL, BattlerTagType.CLAMP, BattlerTagType.SAND_TOMB, BattlerTagType.MAGMA_STORM, BattlerTagType.THUNDER_CAGE, BattlerTagType.SEEDED ], true)
|
||||||
.attr(StatusEffectAttr, StatusEffect.POISON)
|
.attr(StatusEffectAttr, StatusEffect.POISON)
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
new StatusMove(Moves.DOODLE, "Doodle (N)", Type.NORMAL, 100, 10, "The user captures the very essence of the target in a sketch. This changes the Abilities of the user and its ally Pokémon to that of the target.", -1, 0, 9),
|
new StatusMove(Moves.DOODLE, "Doodle", Type.NORMAL, 100, 10, "The user captures the very essence of the target in a sketch. This changes the Abilities of the user and its ally Pokémon to that of the target.", -1, 0, 9)
|
||||||
|
.attr(AbilityCopyAttr, true),
|
||||||
new SelfStatusMove(Moves.FILLET_AWAY, "Fillet Away", Type.NORMAL, -1, 10, "The user sharply boosts its Attack, Sp. Atk, and Speed stats by using its own HP.", -1, 0, 9)
|
new SelfStatusMove(Moves.FILLET_AWAY, "Fillet Away", Type.NORMAL, -1, 10, "The user sharply boosts its Attack, Sp. Atk, and Speed stats by using its own HP.", -1, 0, 9)
|
||||||
.attr(CutHpStatBoostAttr, [ BattleStat.ATK, BattleStat.SPATK, BattleStat.SPD ], 2, 2),
|
.attr(CutHpStatBoostAttr, [ BattleStat.ATK, BattleStat.SPATK, BattleStat.SPD ], 2, 2),
|
||||||
new AttackMove(Moves.KOWTOW_CLEAVE, "Kowtow Cleave", Type.DARK, MoveCategory.PHYSICAL, 85, -1, 10, "The user slashes at the target after kowtowing to make the target let down its guard. This attack never misses.", -1, 0, 9)
|
new AttackMove(Moves.KOWTOW_CLEAVE, "Kowtow Cleave", Type.DARK, MoveCategory.PHYSICAL, 85, -1, 10, "The user slashes at the target after kowtowing to make the target let down its guard. This attack never misses.", -1, 0, 9)
|
||||||
@ -5287,8 +5386,10 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.HYDRO_STEAM, "Hydro Steam (P)", Type.WATER, MoveCategory.SPECIAL, 80, 100, 15, "The user blasts the target with boiling-hot water. This move's power is not lowered in harsh sunlight but rather boosted by 50 percent.", -1, 0, 9),
|
new AttackMove(Moves.HYDRO_STEAM, "Hydro Steam (P)", Type.WATER, MoveCategory.SPECIAL, 80, 100, 15, "The user blasts the target with boiling-hot water. This move's power is not lowered in harsh sunlight but rather boosted by 50 percent.", -1, 0, 9),
|
||||||
new AttackMove(Moves.RUINATION, "Ruination", Type.DARK, MoveCategory.SPECIAL, 1, 90, 10, "The user summons a ruinous disaster. This cuts the target's HP in half.", -1, 0, 9)
|
new AttackMove(Moves.RUINATION, "Ruination", Type.DARK, MoveCategory.SPECIAL, 1, 90, 10, "The user summons a ruinous disaster. This cuts the target's HP in half.", -1, 0, 9)
|
||||||
.attr(TargetHalfHpDamageAttr),
|
.attr(TargetHalfHpDamageAttr),
|
||||||
new AttackMove(Moves.COLLISION_COURSE, "Collision Course (P)", Type.FIGHTING, MoveCategory.PHYSICAL, 100, 100, 5, "The user transforms and crashes to the ground, causing a massive prehistoric explosion. This move's power is boosted more than usual if it's a supereffective hit.", -1, 0, 9),
|
new AttackMove(Moves.COLLISION_COURSE, "Collision Course", Type.FIGHTING, MoveCategory.PHYSICAL, 100, 100, 5, "The user transforms and crashes to the ground, causing a massive prehistoric explosion. This move's power is boosted more than usual if it's a supereffective hit.", -1, 0, 9)
|
||||||
new AttackMove(Moves.ELECTRO_DRIFT, "Electro Drift (P)", Type.ELECTRIC, MoveCategory.SPECIAL, 100, 100, 5, "The user races forward at ultrafast speeds, piercing its target with futuristic electricity. This move's power is boosted more than usual if it's a supereffective hit.", -1, 0, 9)
|
.attr(MovePowerMultiplierAttr, (user, target, move) => target.getAttackTypeEffectiveness(move.type) >= 2 ? 5461/4096 : 1),
|
||||||
|
new AttackMove(Moves.ELECTRO_DRIFT, "Electro Drift", Type.ELECTRIC, MoveCategory.SPECIAL, 100, 100, 5, "The user races forward at ultrafast speeds, piercing its target with futuristic electricity. This move's power is boosted more than usual if it's a supereffective hit.", -1, 0, 9)
|
||||||
|
.attr(MovePowerMultiplierAttr, (user, target, move) => target.getAttackTypeEffectiveness(move.type) >= 2 ? 5461/4096 : 1)
|
||||||
.makesContact(),
|
.makesContact(),
|
||||||
new SelfStatusMove(Moves.SHED_TAIL, "Shed Tail (N)", Type.NORMAL, -1, 10, "The user creates a substitute for itself using its own HP before switching places with a party Pokémon in waiting.", -1, 0, 9),
|
new SelfStatusMove(Moves.SHED_TAIL, "Shed Tail (N)", Type.NORMAL, -1, 10, "The user creates a substitute for itself using its own HP before switching places with a party Pokémon in waiting.", -1, 0, 9),
|
||||||
new StatusMove(Moves.CHILLY_RECEPTION, "Chilly Reception", Type.ICE, -1, 10, "The user tells a chillingly bad joke before switching places with a party Pokémon in waiting. This summons a snowstorm lasting five turns.", -1, 0, 9)
|
new StatusMove(Moves.CHILLY_RECEPTION, "Chilly Reception", Type.ICE, -1, 10, "The user tells a chillingly bad joke before switching places with a party Pokémon in waiting. This summons a snowstorm lasting five turns.", -1, 0, 9)
|
||||||
@ -5321,7 +5422,11 @@ export function initMoves() {
|
|||||||
.triageMove(),
|
.triageMove(),
|
||||||
new AttackMove(Moves.DOUBLE_SHOCK, "Double Shock (P)", Type.ELECTRIC, MoveCategory.PHYSICAL, 120, 100, 5, "The user discharges all the electricity from its body to perform a high-damage attack. After using this move, the user will no longer be Electric type.", -1, 0, 9),
|
new AttackMove(Moves.DOUBLE_SHOCK, "Double Shock (P)", Type.ELECTRIC, MoveCategory.PHYSICAL, 120, 100, 5, "The user discharges all the electricity from its body to perform a high-damage attack. After using this move, the user will no longer be Electric type.", -1, 0, 9),
|
||||||
new AttackMove(Moves.GIGATON_HAMMER, "Gigaton Hammer (P)", Type.STEEL, MoveCategory.PHYSICAL, 160, 100, 5, "The user swings its whole body around to attack with its huge hammer. This move can't be used twice in a row.", -1, 0, 9)
|
new AttackMove(Moves.GIGATON_HAMMER, "Gigaton Hammer (P)", Type.STEEL, MoveCategory.PHYSICAL, 160, 100, 5, "The user swings its whole body around to attack with its huge hammer. This move can't be used twice in a row.", -1, 0, 9)
|
||||||
.makesContact(false),
|
.makesContact(false)
|
||||||
|
.condition((user, target, move) => {
|
||||||
|
const turnMove = user.getLastXMoves(1);
|
||||||
|
return !turnMove.length || turnMove[0].move !== move.id || turnMove[0].result !== MoveResult.SUCCESS;
|
||||||
|
}), // TODO Add Instruct/Encore interaction
|
||||||
new AttackMove(Moves.COMEUPPANCE, "Comeuppance", Type.DARK, MoveCategory.PHYSICAL, 1, 100, 10, "The user retaliates with much greater force against the opponent that last inflicted damage on it.", -1, 0, 9)
|
new AttackMove(Moves.COMEUPPANCE, "Comeuppance", Type.DARK, MoveCategory.PHYSICAL, 1, 100, 10, "The user retaliates with much greater force against the opponent that last inflicted damage on it.", -1, 0, 9)
|
||||||
.attr(CounterDamageAttr, (move: Move) => (move.category === MoveCategory.PHYSICAL || move.category === MoveCategory.SPECIAL), 1.5)
|
.attr(CounterDamageAttr, (move: Move) => (move.category === MoveCategory.PHYSICAL || move.category === MoveCategory.SPECIAL), 1.5)
|
||||||
.target(MoveTarget.ATTACKER),
|
.target(MoveTarget.ATTACKER),
|
||||||
@ -5344,7 +5449,11 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.MAGICAL_TORQUE, "Magical Torque", Type.FAIRY, MoveCategory.PHYSICAL, 100, 100, 10, "The user revs their fae-like engine into the target. This may also confuse the target.", 30, 0, 9)
|
new AttackMove(Moves.MAGICAL_TORQUE, "Magical Torque", Type.FAIRY, MoveCategory.PHYSICAL, 100, 100, 10, "The user revs their fae-like engine into the target. This may also confuse the target.", 30, 0, 9)
|
||||||
.attr(ConfuseAttr)
|
.attr(ConfuseAttr)
|
||||||
.makesContact(false),
|
.makesContact(false),
|
||||||
new AttackMove(Moves.BLOOD_MOON, "Blood Moon (P)", Type.NORMAL, MoveCategory.SPECIAL, 140, 100, 5, "The user unleashes the full brunt of its spirit from a full moon that shines as red as blood. This move can't be used twice in a row.", -1, 0, 9),
|
new AttackMove(Moves.BLOOD_MOON, "Blood Moon (P)", Type.NORMAL, MoveCategory.SPECIAL, 140, 100, 5, "The user unleashes the full brunt of its spirit from a full moon that shines as red as blood. This move can't be used twice in a row.", -1, 0, 9)
|
||||||
|
.condition((user, target, move) => {
|
||||||
|
const turnMove = user.getLastXMoves(1);
|
||||||
|
return !turnMove.length || turnMove[0].move !== move.id || turnMove[0].result !== MoveResult.SUCCESS;
|
||||||
|
}), // TODO Add Instruct/Encore interaction
|
||||||
new AttackMove(Moves.MATCHA_GOTCHA, "Matcha Gotcha", Type.GRASS, MoveCategory.SPECIAL, 80, 90, 15, "The user fires a blast of tea that it mixed. The user's HP is restored by up to half the damage taken by the target. This may also leave the target with a burn.", 20, 0, 9)
|
new AttackMove(Moves.MATCHA_GOTCHA, "Matcha Gotcha", Type.GRASS, MoveCategory.SPECIAL, 80, 90, 15, "The user fires a blast of tea that it mixed. The user's HP is restored by up to half the damage taken by the target. This may also leave the target with a burn.", 20, 0, 9)
|
||||||
.attr(HitHealAttr)
|
.attr(HitHealAttr)
|
||||||
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE)
|
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE)
|
||||||
@ -5368,11 +5477,13 @@ export function initMoves() {
|
|||||||
.attr(DoublePowerChanceAttr),
|
.attr(DoublePowerChanceAttr),
|
||||||
new StatusMove(Moves.BURNING_BULWARK, "Burning Bulwark", Type.FIRE, -1, 10, "The user's intensely hot fur protects it from attacks and also burns any attacker that makes direct contact with it.", 100, 4, 9)
|
new StatusMove(Moves.BURNING_BULWARK, "Burning Bulwark", Type.FIRE, -1, 10, "The user's intensely hot fur protects it from attacks and also burns any attacker that makes direct contact with it.", 100, 4, 9)
|
||||||
.attr(ProtectAttr, BattlerTagType.BURNING_BULWARK),
|
.attr(ProtectAttr, BattlerTagType.BURNING_BULWARK),
|
||||||
new AttackMove(Moves.THUNDERCLAP, "Thunderclap (P)", Type.ELECTRIC, MoveCategory.SPECIAL, 70, 100, 5, "This move enables the user to attack first with a jolt of electricity. This move fails if the target is not readying an attack.", -1, 1, 9),
|
new AttackMove(Moves.THUNDERCLAP, "Thunderclap", Type.ELECTRIC, MoveCategory.SPECIAL, 70, 100, 5, "This move enables the user to attack first with a jolt of electricity. This move fails if the target is not readying an attack.", -1, 1, 9)
|
||||||
|
.condition((user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.FIGHT && !target.turnData.acted && allMoves[user.scene.currentBattle.turnCommands[target.getBattlerIndex()].move.move].category !== MoveCategory.STATUS),
|
||||||
new AttackMove(Moves.MIGHTY_CLEAVE, "Mighty Cleave", Type.ROCK, MoveCategory.PHYSICAL, 95, 100, 5, "The user wields the light that has accumulated atop its head to cleave the target. This move hits even if the target protects itself.", -1, 0, 9)
|
new AttackMove(Moves.MIGHTY_CLEAVE, "Mighty Cleave", Type.ROCK, MoveCategory.PHYSICAL, 95, 100, 5, "The user wields the light that has accumulated atop its head to cleave the target. This move hits even if the target protects itself.", -1, 0, 9)
|
||||||
.ignoresProtect(),
|
.ignoresProtect(),
|
||||||
new AttackMove(Moves.TACHYON_CUTTER, "Tachyon Cutter", Type.STEEL, MoveCategory.SPECIAL, 50, -1, 10, "The user attacks by launching particle blades at the target twice in a row. This attack never misses.", -1, 0, 9)
|
new AttackMove(Moves.TACHYON_CUTTER, "Tachyon Cutter", Type.STEEL, MoveCategory.SPECIAL, 50, -1, 10, "The user attacks by launching particle blades at the target twice in a row. This attack never misses.", -1, 0, 9)
|
||||||
.attr(MultiHitAttr, MultiHitType._2),
|
.attr(MultiHitAttr, MultiHitType._2)
|
||||||
|
.slicingMove(),
|
||||||
new AttackMove(Moves.HARD_PRESS, "Hard Press", Type.STEEL, MoveCategory.PHYSICAL, 100, 100, 5, "The target is crushed with an arm, a claw, or the like to inflict damage. The more HP the target has left, the greater the move's power.", -1, 0, 9)
|
new AttackMove(Moves.HARD_PRESS, "Hard Press", Type.STEEL, MoveCategory.PHYSICAL, 100, 100, 5, "The target is crushed with an arm, a claw, or the like to inflict damage. The more HP the target has left, the greater the move's power.", -1, 0, 9)
|
||||||
.attr(OpponentHighHpPowerAttr),
|
.attr(OpponentHighHpPowerAttr),
|
||||||
new StatusMove(Moves.DRAGON_CHEER, "Dragon Cheer (P)", Type.DRAGON, -1, 15, "The user raises its allies' morale with a draconic cry so that their future attacks have a heightened chance of landing critical hits. This rouses Dragon types more.", 100, 0, 9)
|
new StatusMove(Moves.DRAGON_CHEER, "Dragon Cheer (P)", Type.DRAGON, -1, 15, "The user raises its allies' morale with a draconic cry so that their future attacks have a heightened chance of landing critical hits. This rouses Dragon types more.", 100, 0, 9)
|
||||||
|
@ -11,6 +11,7 @@ import { StarterMoveset } from '../system/game-data';
|
|||||||
import { speciesEggMoves } from './egg-moves';
|
import { speciesEggMoves } from './egg-moves';
|
||||||
import { PartyMemberStrength } from "./enums/party-member-strength";
|
import { PartyMemberStrength } from "./enums/party-member-strength";
|
||||||
import { GameMode } from '../game-mode';
|
import { GameMode } from '../game-mode';
|
||||||
|
import { QuantizerCelebi, argbFromRgba, rgbaFromArgb } from "@material/material-color-utilities";
|
||||||
|
|
||||||
export enum Region {
|
export enum Region {
|
||||||
NORMAL,
|
NORMAL,
|
||||||
@ -381,6 +382,55 @@ export abstract class PokemonSpeciesForm {
|
|||||||
cry.stop();
|
cry.stop();
|
||||||
return cry;
|
return cry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generateCandyColors(scene: BattleScene): integer[][] {
|
||||||
|
const sourceTexture = scene.textures.get(this.getSpriteKey(false));
|
||||||
|
|
||||||
|
const sourceFrame = sourceTexture.frames[sourceTexture.firstFrame];
|
||||||
|
const sourceImage = sourceTexture.getSourceImage() as HTMLImageElement;
|
||||||
|
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
|
||||||
|
const spriteColors: integer[][] = [];
|
||||||
|
|
||||||
|
const context = canvas.getContext('2d');
|
||||||
|
const frame = sourceFrame;
|
||||||
|
canvas.width = frame.width;
|
||||||
|
canvas.height = frame.height;
|
||||||
|
context.drawImage(sourceImage, frame.cutX, frame.cutY, frame.width, frame.height, 0, 0, frame.width, frame.height);
|
||||||
|
const imageData = context.getImageData(frame.cutX, frame.cutY, frame.width, frame.height);
|
||||||
|
const pixelData = imageData.data;
|
||||||
|
|
||||||
|
for (let i = 0; i < pixelData.length; i += 4) {
|
||||||
|
if (pixelData[i + 3]) {
|
||||||
|
const pixel = pixelData.slice(i, i + 4);
|
||||||
|
const [ r, g, b, a ] = pixel;
|
||||||
|
if (!spriteColors.find(c => c[0] === r && c[1] === g && c[2] === b))
|
||||||
|
spriteColors.push([ r, g, b, a ]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const pixelColors = [];
|
||||||
|
for (let i = 0; i < pixelData.length; i += 4) {
|
||||||
|
const total = pixelData.slice(i, i + 3).reduce((total: integer, value: integer) => total + value, 0);
|
||||||
|
if (!total)
|
||||||
|
continue;
|
||||||
|
pixelColors.push(argbFromRgba({ r: pixelData[i], g: pixelData[i + 1], b: pixelData[i + 2], a: pixelData[i + 3] }));
|
||||||
|
}
|
||||||
|
|
||||||
|
let paletteColors: Map<number, number>;
|
||||||
|
|
||||||
|
const originalRandom = Math.random;
|
||||||
|
Math.random = () => Phaser.Math.RND.realInRange(0, 1);
|
||||||
|
|
||||||
|
scene.executeWithSeedOffset(() => {
|
||||||
|
paletteColors = QuantizerCelebi.quantize(pixelColors, 2);
|
||||||
|
}, 0, 'This result should not vary');
|
||||||
|
|
||||||
|
Math.random = originalRandom;
|
||||||
|
|
||||||
|
return Array.from(paletteColors.keys()).map(c => Object.values(rgbaFromArgb(c)) as integer[]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class PokemonSpecies extends PokemonSpeciesForm {
|
export default class PokemonSpecies extends PokemonSpeciesForm {
|
||||||
@ -1567,7 +1617,7 @@ export function initSpecies() {
|
|||||||
new PokemonSpecies(Species.ALOMOMOLA, "Alomomola", 5, false, false, false, "Caring Pokémon", Type.WATER, null, 1.2, 31.6, Abilities.HEALER, Abilities.HYDRATION, Abilities.REGENERATOR, 470, 165, 75, 80, 40, 45, 65, 75, 70, 165, GrowthRate.FAST, 50, false),
|
new PokemonSpecies(Species.ALOMOMOLA, "Alomomola", 5, false, false, false, "Caring Pokémon", Type.WATER, null, 1.2, 31.6, Abilities.HEALER, Abilities.HYDRATION, Abilities.REGENERATOR, 470, 165, 75, 80, 40, 45, 65, 75, 70, 165, GrowthRate.FAST, 50, false),
|
||||||
new PokemonSpecies(Species.JOLTIK, "Joltik", 5, false, false, false, "Attaching Pokémon", Type.BUG, Type.ELECTRIC, 0.1, 0.6, Abilities.COMPOUND_EYES, Abilities.UNNERVE, Abilities.SWARM, 319, 50, 47, 50, 57, 50, 65, 190, 50, 64, GrowthRate.MEDIUM_FAST, 50, false),
|
new PokemonSpecies(Species.JOLTIK, "Joltik", 5, false, false, false, "Attaching Pokémon", Type.BUG, Type.ELECTRIC, 0.1, 0.6, Abilities.COMPOUND_EYES, Abilities.UNNERVE, Abilities.SWARM, 319, 50, 47, 50, 57, 50, 65, 190, 50, 64, GrowthRate.MEDIUM_FAST, 50, false),
|
||||||
new PokemonSpecies(Species.GALVANTULA, "Galvantula", 5, false, false, false, "EleSpider Pokémon", Type.BUG, Type.ELECTRIC, 0.8, 14.3, Abilities.COMPOUND_EYES, Abilities.UNNERVE, Abilities.SWARM, 472, 70, 77, 60, 97, 60, 108, 75, 50, 165, GrowthRate.MEDIUM_FAST, 50, false),
|
new PokemonSpecies(Species.GALVANTULA, "Galvantula", 5, false, false, false, "EleSpider Pokémon", Type.BUG, Type.ELECTRIC, 0.8, 14.3, Abilities.COMPOUND_EYES, Abilities.UNNERVE, Abilities.SWARM, 472, 70, 77, 60, 97, 60, 108, 75, 50, 165, GrowthRate.MEDIUM_FAST, 50, false),
|
||||||
new PokemonSpecies(Species.FERROSEED, "Ferroseed", 5, false, false, false, "Thorn Seed Pokémon", Type.GRASS, Type.STEEL, 0.6, 18.8, Abilities.IRON_BARBS, Abilities.NONE, Abilities.NONE, 305, 44, 50, 91, 24, 86, 10, 255, 50, 61, GrowthRate.MEDIUM_FAST, 50, false),
|
new PokemonSpecies(Species.FERROSEED, "Ferroseed", 5, false, false, false, "Thorn Seed Pokémon", Type.GRASS, Type.STEEL, 0.6, 18.8, Abilities.IRON_BARBS, Abilities.NONE, Abilities.IRON_BARBS, 305, 44, 50, 91, 24, 86, 10, 255, 50, 61, GrowthRate.MEDIUM_FAST, 50, false),
|
||||||
new PokemonSpecies(Species.FERROTHORN, "Ferrothorn", 5, false, false, false, "Thorn Pod Pokémon", Type.GRASS, Type.STEEL, 1, 110, Abilities.IRON_BARBS, Abilities.NONE, Abilities.ANTICIPATION, 489, 74, 94, 131, 54, 116, 20, 90, 50, 171, GrowthRate.MEDIUM_FAST, 50, false),
|
new PokemonSpecies(Species.FERROTHORN, "Ferrothorn", 5, false, false, false, "Thorn Pod Pokémon", Type.GRASS, Type.STEEL, 1, 110, Abilities.IRON_BARBS, Abilities.NONE, Abilities.ANTICIPATION, 489, 74, 94, 131, 54, 116, 20, 90, 50, 171, GrowthRate.MEDIUM_FAST, 50, false),
|
||||||
new PokemonSpecies(Species.KLINK, "Klink", 5, false, false, false, "Gear Pokémon", Type.STEEL, null, 0.3, 21, Abilities.PLUS, Abilities.MINUS, Abilities.CLEAR_BODY, 300, 40, 55, 70, 45, 60, 30, 130, 50, 60, GrowthRate.MEDIUM_SLOW, null, false),
|
new PokemonSpecies(Species.KLINK, "Klink", 5, false, false, false, "Gear Pokémon", Type.STEEL, null, 0.3, 21, Abilities.PLUS, Abilities.MINUS, Abilities.CLEAR_BODY, 300, 40, 55, 70, 45, 60, 30, 130, 50, 60, GrowthRate.MEDIUM_SLOW, null, false),
|
||||||
new PokemonSpecies(Species.KLANG, "Klang", 5, false, false, false, "Gear Pokémon", Type.STEEL, null, 0.6, 51, Abilities.PLUS, Abilities.MINUS, Abilities.CLEAR_BODY, 440, 60, 80, 95, 70, 85, 50, 60, 50, 154, GrowthRate.MEDIUM_SLOW, null, false),
|
new PokemonSpecies(Species.KLANG, "Klang", 5, false, false, false, "Gear Pokémon", Type.STEEL, null, 0.6, 51, Abilities.PLUS, Abilities.MINUS, Abilities.CLEAR_BODY, 440, 60, 80, 95, 70, 85, 50, 60, 50, 154, GrowthRate.MEDIUM_SLOW, null, false),
|
||||||
@ -3058,8 +3108,8 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.CHARMANDER]: Abilities.INTIMIDATE,
|
[Species.CHARMANDER]: Abilities.INTIMIDATE,
|
||||||
[Species.SQUIRTLE]: Abilities.DAUNTLESS_SHIELD,
|
[Species.SQUIRTLE]: Abilities.DAUNTLESS_SHIELD,
|
||||||
[Species.CATERPIE]: Abilities.MAGICIAN,
|
[Species.CATERPIE]: Abilities.MAGICIAN,
|
||||||
[Species.WEEDLE]: Abilities.POISON_TOUCH,
|
[Species.WEEDLE]: Abilities.TECHNICIAN,
|
||||||
[Species.PIDGEY]: Abilities.TECHNICIAN,
|
[Species.PIDGEY]: Abilities.GALE_WINGS,
|
||||||
[Species.RATTATA]: Abilities.STRONG_JAW,
|
[Species.RATTATA]: Abilities.STRONG_JAW,
|
||||||
[Species.SPEAROW]: Abilities.MOXIE,
|
[Species.SPEAROW]: Abilities.MOXIE,
|
||||||
[Species.EKANS]: Abilities.ROUGH_SKIN,
|
[Species.EKANS]: Abilities.ROUGH_SKIN,
|
||||||
@ -3070,14 +3120,14 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.ZUBAT]: Abilities.WIND_RIDER,
|
[Species.ZUBAT]: Abilities.WIND_RIDER,
|
||||||
[Species.ODDISH]: Abilities.LINGERING_AROMA,
|
[Species.ODDISH]: Abilities.LINGERING_AROMA,
|
||||||
[Species.PARAS]: Abilities.POISON_HEAL,
|
[Species.PARAS]: Abilities.POISON_HEAL,
|
||||||
[Species.VENONAT]: Abilities.TECHNICIAN,
|
[Species.VENONAT]: Abilities.SWARM,
|
||||||
[Species.DIGLETT]: Abilities.STURDY,
|
[Species.DIGLETT]: Abilities.STURDY,
|
||||||
[Species.MEOWTH]: Abilities.NORMALIZE,
|
[Species.MEOWTH]: Abilities.NORMALIZE,
|
||||||
[Species.PSYDUCK]: Abilities.SIMPLE,
|
[Species.PSYDUCK]: Abilities.SIMPLE,
|
||||||
[Species.MANKEY]: Abilities.STAMINA,
|
[Species.MANKEY]: Abilities.IRON_FIST,
|
||||||
[Species.GROWLITHE]: Abilities.BALL_FETCH,
|
[Species.GROWLITHE]: Abilities.SPEED_BOOST,
|
||||||
[Species.POLIWAG]: Abilities.WATER_BUBBLE,
|
[Species.POLIWAG]: Abilities.WATER_BUBBLE,
|
||||||
[Species.ABRA]: Abilities.TECHNICIAN,
|
[Species.ABRA]: Abilities.OPPORTUNIST,
|
||||||
[Species.MACHOP]: Abilities.IRON_FIST,
|
[Species.MACHOP]: Abilities.IRON_FIST,
|
||||||
[Species.BELLSPROUT]: Abilities.CORROSION,
|
[Species.BELLSPROUT]: Abilities.CORROSION,
|
||||||
[Species.TENTACOOL]: Abilities.INNARDS_OUT,
|
[Species.TENTACOOL]: Abilities.INNARDS_OUT,
|
||||||
@ -3103,7 +3153,7 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.TANGELA]: Abilities.TANGLING_HAIR,
|
[Species.TANGELA]: Abilities.TANGLING_HAIR,
|
||||||
[Species.KANGASKHAN]: Abilities.IRON_FIST,
|
[Species.KANGASKHAN]: Abilities.IRON_FIST,
|
||||||
[Species.HORSEA]: Abilities.DRIZZLE,
|
[Species.HORSEA]: Abilities.DRIZZLE,
|
||||||
[Species.GOLDEEN]: Abilities.VOLT_ABSORB,
|
[Species.GOLDEEN]: Abilities.MULTISCALE,
|
||||||
[Species.STARYU]: Abilities.REGENERATOR,
|
[Species.STARYU]: Abilities.REGENERATOR,
|
||||||
[Species.SCYTHER]: Abilities.SPEED_BOOST,
|
[Species.SCYTHER]: Abilities.SPEED_BOOST,
|
||||||
[Species.PINSIR]: Abilities.SAP_SIPPER,
|
[Species.PINSIR]: Abilities.SAP_SIPPER,
|
||||||
@ -3139,7 +3189,7 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.HOPPIP]: Abilities.PRANKSTER,
|
[Species.HOPPIP]: Abilities.PRANKSTER,
|
||||||
[Species.AIPOM]: Abilities.SCRAPPY,
|
[Species.AIPOM]: Abilities.SCRAPPY,
|
||||||
[Species.SUNKERN]: Abilities.DROUGHT,
|
[Species.SUNKERN]: Abilities.DROUGHT,
|
||||||
[Species.YANMA]: Abilities.TECHNICIAN,
|
[Species.YANMA]: Abilities.INFILTRATOR,
|
||||||
[Species.WOOPER]: Abilities.SIMPLE,
|
[Species.WOOPER]: Abilities.SIMPLE,
|
||||||
[Species.MURKROW]: Abilities.DEFIANT,
|
[Species.MURKROW]: Abilities.DEFIANT,
|
||||||
[Species.MISDREAVUS]: Abilities.DAZZLING,
|
[Species.MISDREAVUS]: Abilities.DAZZLING,
|
||||||
@ -3154,7 +3204,7 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.HERACROSS]: Abilities.QUICK_FEET,
|
[Species.HERACROSS]: Abilities.QUICK_FEET,
|
||||||
[Species.SNEASEL]: Abilities.MOXIE,
|
[Species.SNEASEL]: Abilities.MOXIE,
|
||||||
[Species.TEDDIURSA]: Abilities.GLUTTONY,
|
[Species.TEDDIURSA]: Abilities.GLUTTONY,
|
||||||
[Species.SLUGMA]: Abilities.DESOLATE_LAND,
|
[Species.SLUGMA]: Abilities.DROUGHT,
|
||||||
[Species.SWINUB]: Abilities.SLUSH_RUSH,
|
[Species.SWINUB]: Abilities.SLUSH_RUSH,
|
||||||
[Species.CORSOLA]: Abilities.STORM_DRAIN,
|
[Species.CORSOLA]: Abilities.STORM_DRAIN,
|
||||||
[Species.REMORAID]: Abilities.SKILL_LINK,
|
[Species.REMORAID]: Abilities.SKILL_LINK,
|
||||||
@ -3166,7 +3216,7 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.SMEARGLE]: Abilities.TRACE,
|
[Species.SMEARGLE]: Abilities.TRACE,
|
||||||
[Species.TYROGUE]: Abilities.STAMINA,
|
[Species.TYROGUE]: Abilities.STAMINA,
|
||||||
[Species.SMOOCHUM]: Abilities.CUTE_CHARM,
|
[Species.SMOOCHUM]: Abilities.CUTE_CHARM,
|
||||||
[Species.ELEKID]: Abilities.ADAPTABILITY,
|
[Species.ELEKID]: Abilities.IRON_FIST,
|
||||||
[Species.MAGBY]: Abilities.CONTRARY,
|
[Species.MAGBY]: Abilities.CONTRARY,
|
||||||
[Species.MILTANK]: Abilities.GLUTTONY,
|
[Species.MILTANK]: Abilities.GLUTTONY,
|
||||||
[Species.RAIKOU]: Abilities.FLARE_BOOST,
|
[Species.RAIKOU]: Abilities.FLARE_BOOST,
|
||||||
@ -3192,7 +3242,7 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.SLAKOTH]: Abilities.GUTS,
|
[Species.SLAKOTH]: Abilities.GUTS,
|
||||||
[Species.NINCADA]: Abilities.OVERCOAT,
|
[Species.NINCADA]: Abilities.OVERCOAT,
|
||||||
[Species.WHISMUR]: Abilities.PUNK_ROCK,
|
[Species.WHISMUR]: Abilities.PUNK_ROCK,
|
||||||
[Species.MAKUHITA]: Abilities.CONTRARY,
|
[Species.MAKUHITA]: Abilities.STAMINA,
|
||||||
[Species.AZURILL]: Abilities.UNNERVE,
|
[Species.AZURILL]: Abilities.UNNERVE,
|
||||||
[Species.NOSEPASS]: Abilities.LEVITATE,
|
[Species.NOSEPASS]: Abilities.LEVITATE,
|
||||||
[Species.SKITTY]: Abilities.SCRAPPY,
|
[Species.SKITTY]: Abilities.SCRAPPY,
|
||||||
@ -3217,10 +3267,10 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.SWABLU]: Abilities.WHITE_SMOKE,
|
[Species.SWABLU]: Abilities.WHITE_SMOKE,
|
||||||
[Species.ZANGOOSE]: Abilities.SUPER_LUCK,
|
[Species.ZANGOOSE]: Abilities.SUPER_LUCK,
|
||||||
[Species.SEVIPER]: Abilities.MOLD_BREAKER,
|
[Species.SEVIPER]: Abilities.MOLD_BREAKER,
|
||||||
[Species.LUNATONE]: Abilities.SHADOW_SHIELD,
|
[Species.LUNATONE]: Abilities.FAIRY_AURA,
|
||||||
[Species.SOLROCK]: Abilities.FULL_METAL_BODY,
|
[Species.SOLROCK]: Abilities.DROUGHT,
|
||||||
[Species.BARBOACH]: Abilities.BALL_FETCH,
|
[Species.BARBOACH]: Abilities.BALL_FETCH,
|
||||||
[Species.CORPHISH]: Abilities.WATER_BUBBLE,
|
[Species.CORPHISH]: Abilities.TOUGH_CLAWS,
|
||||||
[Species.BALTOY]: Abilities.OWN_TEMPO,
|
[Species.BALTOY]: Abilities.OWN_TEMPO,
|
||||||
[Species.LILEEP]: Abilities.WATER_ABSORB,
|
[Species.LILEEP]: Abilities.WATER_ABSORB,
|
||||||
[Species.ANORITH]: Abilities.WATER_ABSORB,
|
[Species.ANORITH]: Abilities.WATER_ABSORB,
|
||||||
@ -3237,7 +3287,7 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.CLAMPERL]: Abilities.SIMPLE,
|
[Species.CLAMPERL]: Abilities.SIMPLE,
|
||||||
[Species.RELICANTH]: Abilities.SOLID_ROCK,
|
[Species.RELICANTH]: Abilities.SOLID_ROCK,
|
||||||
[Species.LUVDISC]: Abilities.PICKUP,
|
[Species.LUVDISC]: Abilities.PICKUP,
|
||||||
[Species.BAGON]: Abilities.GALE_WINGS,
|
[Species.BAGON]: Abilities.BERSERK,
|
||||||
[Species.BELDUM]: Abilities.IRON_FIST,
|
[Species.BELDUM]: Abilities.IRON_FIST,
|
||||||
[Species.REGIROCK]: Abilities.REGENERATOR,
|
[Species.REGIROCK]: Abilities.REGENERATOR,
|
||||||
[Species.REGICE]: Abilities.ICE_SCALES,
|
[Species.REGICE]: Abilities.ICE_SCALES,
|
||||||
@ -3251,7 +3301,7 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.DEOXYS]: Abilities.STICKY_HOLD,
|
[Species.DEOXYS]: Abilities.STICKY_HOLD,
|
||||||
[Species.TURTWIG]: Abilities.HARVEST,
|
[Species.TURTWIG]: Abilities.HARVEST,
|
||||||
[Species.CHIMCHAR]: Abilities.DEFIANT,
|
[Species.CHIMCHAR]: Abilities.DEFIANT,
|
||||||
[Species.PIPLUP]: Abilities.BATTLE_ARMOR,
|
[Species.PIPLUP]: Abilities.SLUSH_RUSH,
|
||||||
[Species.STARLY]: Abilities.ROCK_HEAD,
|
[Species.STARLY]: Abilities.ROCK_HEAD,
|
||||||
[Species.BIDOOF]: Abilities.NEUROFORCE,
|
[Species.BIDOOF]: Abilities.NEUROFORCE,
|
||||||
[Species.KRICKETOT]: Abilities.SOUNDPROOF,
|
[Species.KRICKETOT]: Abilities.SOUNDPROOF,
|
||||||
@ -3286,7 +3336,7 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.FINNEON]: Abilities.DRIZZLE,
|
[Species.FINNEON]: Abilities.DRIZZLE,
|
||||||
[Species.MANTYKE]: Abilities.STORM_DRAIN,
|
[Species.MANTYKE]: Abilities.STORM_DRAIN,
|
||||||
[Species.SNOVER]: Abilities.SNOW_CLOAK,
|
[Species.SNOVER]: Abilities.SNOW_CLOAK,
|
||||||
[Species.ROTOM]: Abilities.ELECTRIC_SURGE,
|
[Species.ROTOM]: Abilities.MOTOR_DRIVE,
|
||||||
[Species.UXIE]: Abilities.ILLUSION,
|
[Species.UXIE]: Abilities.ILLUSION,
|
||||||
[Species.MESPRIT]: Abilities.MOODY,
|
[Species.MESPRIT]: Abilities.MOODY,
|
||||||
[Species.AZELF]: Abilities.NEUROFORCE,
|
[Species.AZELF]: Abilities.NEUROFORCE,
|
||||||
@ -3304,7 +3354,7 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.VICTINI]: Abilities.SUPER_LUCK,
|
[Species.VICTINI]: Abilities.SUPER_LUCK,
|
||||||
[Species.SNIVY]: Abilities.MULTISCALE,
|
[Species.SNIVY]: Abilities.MULTISCALE,
|
||||||
[Species.TEPIG]: Abilities.SAND_RUSH,
|
[Species.TEPIG]: Abilities.SAND_RUSH,
|
||||||
[Species.OSHAWOTT]: Abilities.LIGHTNING_ROD,
|
[Species.OSHAWOTT]: Abilities.MOLD_BREAKER,
|
||||||
[Species.PATRAT]: Abilities.STAKEOUT,
|
[Species.PATRAT]: Abilities.STAKEOUT,
|
||||||
[Species.LILLIPUP]: Abilities.BALL_FETCH,
|
[Species.LILLIPUP]: Abilities.BALL_FETCH,
|
||||||
[Species.PURRLOIN]: Abilities.DEFIANT,
|
[Species.PURRLOIN]: Abilities.DEFIANT,
|
||||||
@ -3325,8 +3375,8 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.SEWADDLE]: Abilities.SHARPNESS,
|
[Species.SEWADDLE]: Abilities.SHARPNESS,
|
||||||
[Species.VENIPEDE]: Abilities.INTIMIDATE,
|
[Species.VENIPEDE]: Abilities.INTIMIDATE,
|
||||||
[Species.COTTONEE]: Abilities.MISTY_SURGE,
|
[Species.COTTONEE]: Abilities.MISTY_SURGE,
|
||||||
[Species.PETILIL]: Abilities.ORICHALCUM_PULSE,
|
[Species.PETILIL]: Abilities.DROUGHT,
|
||||||
[Species.BASCULIN]: Abilities.ROCK_HEAD,
|
[Species.BASCULIN]: Abilities.OPPORTUNIST,
|
||||||
[Species.SANDILE]: Abilities.STRONG_JAW,
|
[Species.SANDILE]: Abilities.STRONG_JAW,
|
||||||
[Species.DARUMAKA]: Abilities.IRON_FIST,
|
[Species.DARUMAKA]: Abilities.IRON_FIST,
|
||||||
[Species.MARACTUS]: Abilities.IRON_BARBS,
|
[Species.MARACTUS]: Abilities.IRON_BARBS,
|
||||||
@ -3346,14 +3396,14 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.DEERLING]: Abilities.JUSTIFIED,
|
[Species.DEERLING]: Abilities.JUSTIFIED,
|
||||||
[Species.EMOLGA]: Abilities.WIND_POWER,
|
[Species.EMOLGA]: Abilities.WIND_POWER,
|
||||||
[Species.KARRABLAST]: Abilities.NO_GUARD,
|
[Species.KARRABLAST]: Abilities.NO_GUARD,
|
||||||
[Species.FOONGUS]: Abilities.ADAPTABILITY,
|
[Species.FOONGUS]: Abilities.MIMICRY,
|
||||||
[Species.FRILLISH]: Abilities.MUMMY,
|
[Species.FRILLISH]: Abilities.MUMMY,
|
||||||
[Species.ALOMOMOLA]: Abilities.MULTISCALE,
|
[Species.ALOMOMOLA]: Abilities.MULTISCALE,
|
||||||
[Species.JOLTIK]: Abilities.VOLT_ABSORB,
|
[Species.JOLTIK]: Abilities.VOLT_ABSORB,
|
||||||
[Species.FERROSEED]: Abilities.SKILL_LINK,
|
[Species.FERROSEED]: Abilities.SKILL_LINK,
|
||||||
[Species.KLINK]: Abilities.STEELWORKER,
|
[Species.KLINK]: Abilities.STEELWORKER,
|
||||||
[Species.TYNAMO]: Abilities.SWIFT_SWIM,
|
[Species.TYNAMO]: Abilities.SWIFT_SWIM,
|
||||||
[Species.ELGYEM]: Abilities.COMMANDER,
|
[Species.ELGYEM]: Abilities.SHADOW_TAG,
|
||||||
[Species.LITWICK]: Abilities.SOUL_HEART,
|
[Species.LITWICK]: Abilities.SOUL_HEART,
|
||||||
[Species.AXEW]: Abilities.SHEER_FORCE,
|
[Species.AXEW]: Abilities.SHEER_FORCE,
|
||||||
[Species.CUBCHOO]: Abilities.INTIMIDATE,
|
[Species.CUBCHOO]: Abilities.INTIMIDATE,
|
||||||
@ -3362,7 +3412,7 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.STUNFISK]: Abilities.STORM_DRAIN,
|
[Species.STUNFISK]: Abilities.STORM_DRAIN,
|
||||||
[Species.MIENFOO]: Abilities.NO_GUARD,
|
[Species.MIENFOO]: Abilities.NO_GUARD,
|
||||||
[Species.DRUDDIGON]: Abilities.INTIMIDATE,
|
[Species.DRUDDIGON]: Abilities.INTIMIDATE,
|
||||||
[Species.GOLETT]: Abilities.JUSTIFIED,
|
[Species.GOLETT]: Abilities.SHADOW_SHIELD,
|
||||||
[Species.PAWNIARD]: Abilities.SHARPNESS,
|
[Species.PAWNIARD]: Abilities.SHARPNESS,
|
||||||
[Species.BOUFFALANT]: Abilities.THICK_FAT,
|
[Species.BOUFFALANT]: Abilities.THICK_FAT,
|
||||||
[Species.RUFFLET]: Abilities.RECKLESS,
|
[Species.RUFFLET]: Abilities.RECKLESS,
|
||||||
@ -3380,7 +3430,7 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.ZEKROM]: Abilities.HADRON_ENGINE,
|
[Species.ZEKROM]: Abilities.HADRON_ENGINE,
|
||||||
[Species.LANDORUS]: Abilities.PRANKSTER,
|
[Species.LANDORUS]: Abilities.PRANKSTER,
|
||||||
[Species.KYUREM]: Abilities.SNOW_WARNING,
|
[Species.KYUREM]: Abilities.SNOW_WARNING,
|
||||||
[Species.KELDEO]: Abilities.HUGE_POWER,
|
[Species.KELDEO]: Abilities.SHARPNESS,
|
||||||
[Species.MELOETTA]: Abilities.PUNK_ROCK,
|
[Species.MELOETTA]: Abilities.PUNK_ROCK,
|
||||||
[Species.GENESECT]: Abilities.MEGA_LAUNCHER,
|
[Species.GENESECT]: Abilities.MEGA_LAUNCHER,
|
||||||
[Species.CHESPIN]: Abilities.IRON_BARBS,
|
[Species.CHESPIN]: Abilities.IRON_BARBS,
|
||||||
@ -3407,7 +3457,7 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.AMAURA]: Abilities.SERENE_GRACE,
|
[Species.AMAURA]: Abilities.SERENE_GRACE,
|
||||||
[Species.HAWLUCHA]: Abilities.RECKLESS,
|
[Species.HAWLUCHA]: Abilities.RECKLESS,
|
||||||
[Species.DEDENNE]: Abilities.SIMPLE,
|
[Species.DEDENNE]: Abilities.SIMPLE,
|
||||||
[Species.CARBINK]: Abilities.OBLIVIOUS,
|
[Species.CARBINK]: Abilities.SOLID_ROCK,
|
||||||
[Species.GOOMY]: Abilities.POISON_HEAL,
|
[Species.GOOMY]: Abilities.POISON_HEAL,
|
||||||
[Species.KLEFKI]: Abilities.TRIAGE,
|
[Species.KLEFKI]: Abilities.TRIAGE,
|
||||||
[Species.PHANTUMP]: Abilities.UNNERVE,
|
[Species.PHANTUMP]: Abilities.UNNERVE,
|
||||||
@ -3425,7 +3475,7 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.POPPLIO]: Abilities.PUNK_ROCK,
|
[Species.POPPLIO]: Abilities.PUNK_ROCK,
|
||||||
[Species.PIKIPEK]: Abilities.ANGER_POINT,
|
[Species.PIKIPEK]: Abilities.ANGER_POINT,
|
||||||
[Species.YUNGOOS]: Abilities.HUGE_POWER,
|
[Species.YUNGOOS]: Abilities.HUGE_POWER,
|
||||||
[Species.GRUBBIN]: Abilities.GALVANIZE,
|
[Species.GRUBBIN]: Abilities.SPEED_BOOST,
|
||||||
[Species.CRABRAWLER]: Abilities.REFRIGERATE,
|
[Species.CRABRAWLER]: Abilities.REFRIGERATE,
|
||||||
[Species.ORICORIO]: Abilities.ADAPTABILITY,
|
[Species.ORICORIO]: Abilities.ADAPTABILITY,
|
||||||
[Species.CUTIEFLY]: Abilities.FRIEND_GUARD,
|
[Species.CUTIEFLY]: Abilities.FRIEND_GUARD,
|
||||||
@ -3442,7 +3492,7 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.COMFEY]: Abilities.FRIEND_GUARD,
|
[Species.COMFEY]: Abilities.FRIEND_GUARD,
|
||||||
[Species.ORANGURU]: Abilities.HOSPITALITY,
|
[Species.ORANGURU]: Abilities.HOSPITALITY,
|
||||||
[Species.PASSIMIAN]: Abilities.COSTAR,
|
[Species.PASSIMIAN]: Abilities.COSTAR,
|
||||||
[Species.WIMPOD]: Abilities.BATTLE_ARMOR,
|
[Species.WIMPOD]: Abilities.TINTED_LENS,
|
||||||
[Species.SANDYGAST]: Abilities.DAUNTLESS_SHIELD,
|
[Species.SANDYGAST]: Abilities.DAUNTLESS_SHIELD,
|
||||||
[Species.PYUKUMUKU]: Abilities.IRON_BARBS,
|
[Species.PYUKUMUKU]: Abilities.IRON_BARBS,
|
||||||
[Species.TYPE_NULL]: Abilities.ADAPTABILITY,
|
[Species.TYPE_NULL]: Abilities.ADAPTABILITY,
|
||||||
@ -3465,7 +3515,7 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.PHEROMOSA]: Abilities.MOXIE,
|
[Species.PHEROMOSA]: Abilities.MOXIE,
|
||||||
[Species.XURKITREE]: Abilities.LIGHTNING_ROD,
|
[Species.XURKITREE]: Abilities.LIGHTNING_ROD,
|
||||||
[Species.CELESTEELA]: Abilities.CHLOROPHYLL,
|
[Species.CELESTEELA]: Abilities.CHLOROPHYLL,
|
||||||
[Species.KARTANA]: Abilities.INTREPID_SWORD,
|
[Species.KARTANA]: Abilities.SHARPNESS,
|
||||||
[Species.GUZZLORD]: Abilities.GLUTTONY,
|
[Species.GUZZLORD]: Abilities.GLUTTONY,
|
||||||
[Species.NECROZMA]: Abilities.BEAST_BOOST,
|
[Species.NECROZMA]: Abilities.BEAST_BOOST,
|
||||||
[Species.MAGEARNA]: Abilities.STEELY_SPIRIT,
|
[Species.MAGEARNA]: Abilities.STEELY_SPIRIT,
|
||||||
@ -3479,7 +3529,7 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.SCORBUNNY]: Abilities.RECKLESS,
|
[Species.SCORBUNNY]: Abilities.RECKLESS,
|
||||||
[Species.SOBBLE]: Abilities.MIMICRY,
|
[Species.SOBBLE]: Abilities.MIMICRY,
|
||||||
[Species.SKWOVET]: Abilities.HONEY_GATHER,
|
[Species.SKWOVET]: Abilities.HONEY_GATHER,
|
||||||
[Species.ROOKIDEE]: Abilities.JUSTIFIED,
|
[Species.ROOKIDEE]: Abilities.IRON_BARBS,
|
||||||
[Species.BLIPBUG]: Abilities.TINTED_LENS,
|
[Species.BLIPBUG]: Abilities.TINTED_LENS,
|
||||||
[Species.NICKIT]: Abilities.INTIMIDATE,
|
[Species.NICKIT]: Abilities.INTIMIDATE,
|
||||||
[Species.GOSSIFLEUR]: Abilities.STORM_DRAIN,
|
[Species.GOSSIFLEUR]: Abilities.STORM_DRAIN,
|
||||||
@ -3512,7 +3562,7 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.ARCTOVISH]: Abilities.STRONG_JAW,
|
[Species.ARCTOVISH]: Abilities.STRONG_JAW,
|
||||||
[Species.DURALUDON]: Abilities.MEGA_LAUNCHER,
|
[Species.DURALUDON]: Abilities.MEGA_LAUNCHER,
|
||||||
[Species.DREEPY]: Abilities.PARENTAL_BOND,
|
[Species.DREEPY]: Abilities.PARENTAL_BOND,
|
||||||
[Species.ZACIAN]: Abilities.SHARPNESS,
|
[Species.ZACIAN]: Abilities.GUARD_DOG,
|
||||||
[Species.ZAMAZENTA]: Abilities.GUARD_DOG,
|
[Species.ZAMAZENTA]: Abilities.GUARD_DOG,
|
||||||
[Species.ETERNATUS]: Abilities.SUPREME_OVERLORD,
|
[Species.ETERNATUS]: Abilities.SUPREME_OVERLORD,
|
||||||
[Species.KUBFU]: Abilities.IRON_FIST,
|
[Species.KUBFU]: Abilities.IRON_FIST,
|
||||||
@ -3535,7 +3585,7 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.SMOLIV]: Abilities.RIPEN,
|
[Species.SMOLIV]: Abilities.RIPEN,
|
||||||
[Species.SQUAWKABILLY]: Abilities.GALE_WINGS,
|
[Species.SQUAWKABILLY]: Abilities.GALE_WINGS,
|
||||||
[Species.NACLI]: Abilities.EARTH_EATER,
|
[Species.NACLI]: Abilities.EARTH_EATER,
|
||||||
[Species.CHARCADET]: Abilities.CONTRARY,
|
[Species.CHARCADET]: Abilities.MIRROR_ARMOR,
|
||||||
[Species.TADBULB]: Abilities.TRANSISTOR,
|
[Species.TADBULB]: Abilities.TRANSISTOR,
|
||||||
[Species.WATTREL]: Abilities.GALE_WINGS,
|
[Species.WATTREL]: Abilities.GALE_WINGS,
|
||||||
[Species.MASCHIFF]: Abilities.STRONG_JAW,
|
[Species.MASCHIFF]: Abilities.STRONG_JAW,
|
||||||
@ -3562,15 +3612,15 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.TATSUGIRI]: Abilities.WATER_BUBBLE,
|
[Species.TATSUGIRI]: Abilities.WATER_BUBBLE,
|
||||||
[Species.GREAT_TUSK]: Abilities.INTIMIDATE,
|
[Species.GREAT_TUSK]: Abilities.INTIMIDATE,
|
||||||
[Species.SCREAM_TAIL]: Abilities.PIXILATE,
|
[Species.SCREAM_TAIL]: Abilities.PIXILATE,
|
||||||
[Species.BRUTE_BONNET]: Abilities.ADAPTABILITY,
|
[Species.BRUTE_BONNET]: Abilities.BEAST_BOOST,
|
||||||
[Species.FLUTTER_MANE]: Abilities.DAZZLING,
|
[Species.FLUTTER_MANE]: Abilities.DAZZLING,
|
||||||
[Species.SLITHER_WING]: Abilities.SCRAPPY,
|
[Species.SLITHER_WING]: Abilities.MOXIE,
|
||||||
[Species.SANDY_SHOCKS]: Abilities.EARTH_EATER,
|
[Species.SANDY_SHOCKS]: Abilities.EARTH_EATER,
|
||||||
[Species.IRON_TREADS]: Abilities.STEAM_ENGINE,
|
[Species.IRON_TREADS]: Abilities.BULLETPROOF,
|
||||||
[Species.IRON_BUNDLE]: Abilities.SNOW_WARNING,
|
[Species.IRON_BUNDLE]: Abilities.SNOW_WARNING,
|
||||||
[Species.IRON_HANDS]: Abilities.IRON_FIST,
|
[Species.IRON_HANDS]: Abilities.IRON_FIST,
|
||||||
[Species.IRON_JUGULIS]: Abilities.NO_GUARD,
|
[Species.IRON_JUGULIS]: Abilities.NO_GUARD,
|
||||||
[Species.IRON_MOTH]: Abilities.TINTED_LENS,
|
[Species.IRON_MOTH]: Abilities.LEVITATE,
|
||||||
[Species.IRON_THORNS]: Abilities.SAND_STREAM,
|
[Species.IRON_THORNS]: Abilities.SAND_STREAM,
|
||||||
[Species.FRIGIBAX]: Abilities.THICK_FAT,
|
[Species.FRIGIBAX]: Abilities.THICK_FAT,
|
||||||
[Species.GIMMIGHOUL]: Abilities.SUPER_LUCK,
|
[Species.GIMMIGHOUL]: Abilities.SUPER_LUCK,
|
||||||
@ -3585,7 +3635,7 @@ export const starterPassiveAbilities = {
|
|||||||
[Species.WALKING_WAKE]: Abilities.BEAST_BOOST,
|
[Species.WALKING_WAKE]: Abilities.BEAST_BOOST,
|
||||||
[Species.IRON_LEAVES]: Abilities.SHARPNESS,
|
[Species.IRON_LEAVES]: Abilities.SHARPNESS,
|
||||||
[Species.POLTCHAGEIST]: Abilities.FLAME_BODY,
|
[Species.POLTCHAGEIST]: Abilities.FLAME_BODY,
|
||||||
[Species.OKIDOGI]: Abilities.STICKY_HOLD,
|
[Species.OKIDOGI]: Abilities.INTIMIDATE,
|
||||||
[Species.MUNKIDORI]: Abilities.PRANKSTER,
|
[Species.MUNKIDORI]: Abilities.PRANKSTER,
|
||||||
[Species.FEZANDIPITI]: Abilities.DAZZLING,
|
[Species.FEZANDIPITI]: Abilities.DAZZLING,
|
||||||
[Species.OGERPON]: Abilities.DISGUISE,
|
[Species.OGERPON]: Abilities.DISGUISE,
|
||||||
|
@ -2,7 +2,7 @@ export function getData() {
|
|||||||
const dataStr = localStorage.getItem('data');
|
const dataStr = localStorage.getItem('data');
|
||||||
if (!dataStr)
|
if (!dataStr)
|
||||||
return null;
|
return null;
|
||||||
return JSON.parse(atob(dataStr), (k, v) => k.endsWith('Attr') ? BigInt(v) : v);
|
return JSON.parse(atob(dataStr), (k, v) => k.endsWith('Attr') && ![ 'natureAttr', 'passiveAttr', 'variantAttr' ].includes(k) ? BigInt(v) : v);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getSession() {
|
export function getSession() {
|
||||||
|
@ -25,7 +25,7 @@ import { TempBattleStat } from '../data/temp-battle-stat';
|
|||||||
import { ArenaTagSide, WeakenMoveScreenTag, WeakenMoveTypeTag } from '../data/arena-tag';
|
import { ArenaTagSide, WeakenMoveScreenTag, WeakenMoveTypeTag } from '../data/arena-tag';
|
||||||
import { ArenaTagType } from "../data/enums/arena-tag-type";
|
import { ArenaTagType } from "../data/enums/arena-tag-type";
|
||||||
import { Biome } from "../data/enums/biome";
|
import { Biome } from "../data/enums/biome";
|
||||||
import { Ability, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs } from '../data/ability';
|
import { Ability, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs } from '../data/ability';
|
||||||
import { Abilities } from "#app/data/enums/abilities";
|
import { Abilities } from "#app/data/enums/abilities";
|
||||||
import PokemonData from '../system/pokemon-data';
|
import PokemonData from '../system/pokemon-data';
|
||||||
import { BattlerIndex } from '../battle';
|
import { BattlerIndex } from '../battle';
|
||||||
@ -55,7 +55,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
public species: PokemonSpecies;
|
public species: PokemonSpecies;
|
||||||
public formIndex: integer;
|
public formIndex: integer;
|
||||||
public abilityIndex: integer;
|
public abilityIndex: integer;
|
||||||
|
public passive: boolean;
|
||||||
public shiny: boolean;
|
public shiny: boolean;
|
||||||
|
public variant: integer;
|
||||||
public pokeball: PokeballType;
|
public pokeball: PokeballType;
|
||||||
protected battleInfo: BattleInfo;
|
protected battleInfo: BattleInfo;
|
||||||
public level: integer;
|
public level: integer;
|
||||||
@ -127,6 +129,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
this.hp = dataSource.hp;
|
this.hp = dataSource.hp;
|
||||||
this.stats = dataSource.stats;
|
this.stats = dataSource.stats;
|
||||||
this.ivs = dataSource.ivs;
|
this.ivs = dataSource.ivs;
|
||||||
|
this.passive = !!dataSource.passive;
|
||||||
|
this.variant = dataSource.variant || 0;
|
||||||
this.nature = dataSource.nature || 0 as Nature;
|
this.nature = dataSource.nature || 0 as Nature;
|
||||||
this.natureOverride = dataSource.natureOverride !== undefined ? dataSource.natureOverride : -1;
|
this.natureOverride = dataSource.natureOverride !== undefined ? dataSource.natureOverride : -1;
|
||||||
this.moveset = dataSource.moveset;
|
this.moveset = dataSource.moveset;
|
||||||
@ -712,8 +716,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
if (OPP_ABILITY_OVERRIDE && !this.isPlayer())
|
if (OPP_ABILITY_OVERRIDE && !this.isPlayer())
|
||||||
return allAbilities[OPP_ABILITY_OVERRIDE];
|
return allAbilities[OPP_ABILITY_OVERRIDE];
|
||||||
if (this.isFusion())
|
if (this.isFusion())
|
||||||
return allAbilities[this.getFusionSpeciesForm().getAbility(this.fusionAbilityIndex)];
|
return allAbilities[this.getFusionSpeciesForm(ignoreOverride).getAbility(this.fusionAbilityIndex)];
|
||||||
let abilityId = this.getSpeciesForm().getAbility(this.abilityIndex);
|
let abilityId = this.getSpeciesForm(ignoreOverride).getAbility(this.abilityIndex);
|
||||||
if (abilityId === Abilities.NONE)
|
if (abilityId === Abilities.NONE)
|
||||||
abilityId = this.species.ability1;
|
abilityId = this.species.ability1;
|
||||||
return allAbilities[abilityId];
|
return allAbilities[abilityId];
|
||||||
@ -727,7 +731,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
canApplyPassive(): boolean {
|
canApplyPassive(): boolean {
|
||||||
return this.isBoss();
|
return this.passive || this.isBoss();
|
||||||
}
|
}
|
||||||
|
|
||||||
canApplyAbility(passive: boolean = false): boolean {
|
canApplyAbility(passive: boolean = false): boolean {
|
||||||
@ -1120,6 +1124,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
applyMoveAttrs(VariableMoveTypeAttr, source, this, move, variableType);
|
applyMoveAttrs(VariableMoveTypeAttr, source, this, move, variableType);
|
||||||
// 2nd argument is for MoveTypeChangePowerMultiplierAbAttr
|
// 2nd argument is for MoveTypeChangePowerMultiplierAbAttr
|
||||||
applyAbAttrs(VariableMoveTypeAbAttr, source, null, variableType, typeChangeMovePowerMultiplier);
|
applyAbAttrs(VariableMoveTypeAbAttr, source, null, variableType, typeChangeMovePowerMultiplier);
|
||||||
|
applyPreAttackAbAttrs(MoveTypeChangeAttr, source, this, battlerMove, variableType, typeChangeMovePowerMultiplier);
|
||||||
const type = variableType.value as Type;
|
const type = variableType.value as Type;
|
||||||
const types = this.getTypes(true, true);
|
const types = this.getTypes(true, true);
|
||||||
|
|
||||||
@ -1237,8 +1242,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
if (this.scene.arena.terrain?.terrainType === TerrainType.MISTY && this.isGrounded() && type === Type.DRAGON)
|
if (this.scene.arena.terrain?.terrainType === TerrainType.MISTY && this.isGrounded() && type === Type.DRAGON)
|
||||||
damage.value = Math.floor(damage.value / 2);
|
damage.value = Math.floor(damage.value / 2);
|
||||||
|
|
||||||
applyMoveAttrs(ModifiedDamageAttr, source, this, move, damage);
|
|
||||||
|
|
||||||
const fixedDamage = new Utils.IntegerHolder(0);
|
const fixedDamage = new Utils.IntegerHolder(0);
|
||||||
applyMoveAttrs(FixedDamageAttr, source, this, move, fixedDamage);
|
applyMoveAttrs(FixedDamageAttr, source, this, move, fixedDamage);
|
||||||
if (!isTypeImmune && fixedDamage.value) {
|
if (!isTypeImmune && fixedDamage.value) {
|
||||||
@ -1246,8 +1249,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
isCritical = false;
|
isCritical = false;
|
||||||
result = HitResult.EFFECTIVE;
|
result = HitResult.EFFECTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('damage', damage.value, move.name, power.value, sourceAtk, targetDef);
|
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
if (!typeMultiplier.value)
|
if (!typeMultiplier.value)
|
||||||
@ -1275,6 +1276,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
this.scene.applyModifiers(EnemyDamageReducerModifier, false, damage);
|
this.scene.applyModifiers(EnemyDamageReducerModifier, false, damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applyMoveAttrs(ModifiedDamageAttr, source, this, move, damage);
|
||||||
|
|
||||||
|
console.log('damage', damage.value, move.name, power.value, sourceAtk, targetDef);
|
||||||
|
|
||||||
if (damage.value) {
|
if (damage.value) {
|
||||||
if (this.getHpRatio() === 1)
|
if (this.getHpRatio() === 1)
|
||||||
applyPreDefendAbAttrs(PreDefendFullHpEndureAbAttr, this, source, battlerMove, cancelled, damage);
|
applyPreDefendAbAttrs(PreDefendFullHpEndureAbAttr, this, source, battlerMove, cancelled, damage);
|
||||||
@ -2156,7 +2161,7 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tryPopulateMoveset(moveset: StarterMoveset): boolean {
|
tryPopulateMoveset(moveset: StarterMoveset): boolean {
|
||||||
if (!this.getSpeciesForm().validateStarterMoveset(moveset, this.scene.gameData.starterEggMoveData[this.species.getRootSpeciesId()]))
|
if (!this.getSpeciesForm().validateStarterMoveset(moveset, this.scene.gameData.starterData[this.species.getRootSpeciesId()].eggMoves))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
this.moveset = moveset.map(m => new PokemonMove(m));
|
this.moveset = moveset.map(m => new PokemonMove(m));
|
||||||
@ -2814,6 +2819,7 @@ export class PokemonBattleSummonData {
|
|||||||
|
|
||||||
export class PokemonTurnData {
|
export class PokemonTurnData {
|
||||||
public flinched: boolean;
|
public flinched: boolean;
|
||||||
|
public acted: boolean;
|
||||||
public hitCount: integer;
|
public hitCount: integer;
|
||||||
public hitsLeft: integer;
|
public hitsLeft: integer;
|
||||||
public damageDealt: integer = 0;
|
public damageDealt: integer = 0;
|
||||||
|
@ -3,6 +3,7 @@ import { Biome } from "./data/enums/biome";
|
|||||||
import { TrainerType } from "./data/enums/trainer-type";
|
import { TrainerType } from "./data/enums/trainer-type";
|
||||||
import { trainerConfigs } from "./data/trainer-config";
|
import { trainerConfigs } from "./data/trainer-config";
|
||||||
import { getBiomeHasProps } from "./field/arena";
|
import { getBiomeHasProps } from "./field/arena";
|
||||||
|
import CacheBustedLoaderPlugin from "./plugins/cache-busted-loader-plugin";
|
||||||
import { SceneBase } from "./scene-base";
|
import { SceneBase } from "./scene-base";
|
||||||
import { WindowVariant, getWindowVariantSuffix } from "./ui/ui-theme";
|
import { WindowVariant, getWindowVariantSuffix } from "./ui/ui-theme";
|
||||||
import * as Utils from "./utils";
|
import * as Utils from "./utils";
|
||||||
@ -10,6 +11,8 @@ import * as Utils from "./utils";
|
|||||||
export class LoadingScene extends SceneBase {
|
export class LoadingScene extends SceneBase {
|
||||||
constructor() {
|
constructor() {
|
||||||
super('loading');
|
super('loading');
|
||||||
|
|
||||||
|
Phaser.Plugins.PluginCache.register('Loader', CacheBustedLoaderPlugin, 'load');
|
||||||
}
|
}
|
||||||
|
|
||||||
preload() {
|
preload() {
|
||||||
@ -58,6 +61,7 @@ export class LoadingScene extends SceneBase {
|
|||||||
this.loadImage('achv_bar_3', 'ui');
|
this.loadImage('achv_bar_3', 'ui');
|
||||||
this.loadImage('achv_bar_4', 'ui');
|
this.loadImage('achv_bar_4', 'ui');
|
||||||
this.loadImage('shiny_star', 'ui', 'shiny.png');
|
this.loadImage('shiny_star', 'ui', 'shiny.png');
|
||||||
|
this.loadImage('ha_capsule', 'ui', 'ha_capsule.png');
|
||||||
this.loadImage('icon_spliced', 'ui');
|
this.loadImage('icon_spliced', 'ui');
|
||||||
this.loadImage('icon_tera', 'ui');
|
this.loadImage('icon_tera', 'ui');
|
||||||
this.loadImage('type_tera', 'ui');
|
this.loadImage('type_tera', 'ui');
|
||||||
|
@ -2,7 +2,7 @@ import BattleScene, { STARTER_FORM_OVERRIDE, STARTER_SPECIES_OVERRIDE, bypassLog
|
|||||||
import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove, MoveResult, DamageResult, FieldPosition, HitResult, TurnMove } from "./field/pokemon";
|
import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove, MoveResult, DamageResult, FieldPosition, HitResult, TurnMove } from "./field/pokemon";
|
||||||
import * as Utils from './utils';
|
import * as Utils from './utils';
|
||||||
import { Moves } from "./data/enums/moves";
|
import { Moves } from "./data/enums/moves";
|
||||||
import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveEffectAttr, MoveFlags, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr, MoveTarget, OneHitKOAttr, getMoveTargets, MoveTargetSet, MoveEffectTrigger, CopyMoveAttr, AttackMove, SelfStatusMove, DelayedAttackAttr, RechargeAttr, PreMoveMessageAttr, HealStatusEffectAttr, IgnoreOpponentStatChangesAttr, NoEffectAttr } from "./data/move";
|
import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveEffectAttr, MoveFlags, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr, MoveTarget, OneHitKOAttr, getMoveTargets, MoveTargetSet, MoveEffectTrigger, CopyMoveAttr, AttackMove, SelfStatusMove, DelayedAttackAttr, RechargeAttr, PreMoveMessageAttr, HealStatusEffectAttr, IgnoreOpponentStatChangesAttr, NoEffectAttr, FixedDamageAttr } from "./data/move";
|
||||||
import { Mode } from './ui/ui';
|
import { Mode } from './ui/ui';
|
||||||
import { Command } from "./ui/command-ui-handler";
|
import { Command } from "./ui/command-ui-handler";
|
||||||
import { Stat } from "./data/pokemon-stat";
|
import { Stat } from "./data/pokemon-stat";
|
||||||
@ -30,7 +30,7 @@ import { Weather, WeatherType, getRandomWeatherType, getTerrainBlockMessage, get
|
|||||||
import { TempBattleStat } from "./data/temp-battle-stat";
|
import { TempBattleStat } from "./data/temp-battle-stat";
|
||||||
import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag";
|
import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag";
|
||||||
import { ArenaTagType } from "./data/enums/arena-tag-type";
|
import { ArenaTagType } from "./data/enums/arena-tag-type";
|
||||||
import { CheckTrappedAbAttr, MoveAbilityBypassAbAttr, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, applyPostBattleInitAbAttrs, PostBattleInitAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr } from "./data/ability";
|
import { CheckTrappedAbAttr, MoveAbilityBypassAbAttr, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, applyPostBattleInitAbAttrs, PostBattleInitAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs } from "./data/ability";
|
||||||
import { Abilities } from "./data/enums/abilities";
|
import { Abilities } from "./data/enums/abilities";
|
||||||
import { Unlockables, getUnlockableName } from "./system/unlockables";
|
import { Unlockables, getUnlockableName } from "./system/unlockables";
|
||||||
import { getBiomeKey } from "./field/arena";
|
import { getBiomeKey } from "./field/arena";
|
||||||
@ -44,7 +44,7 @@ import { EggHatchPhase } from "./egg-hatch-phase";
|
|||||||
import { Egg } from "./data/egg";
|
import { Egg } from "./data/egg";
|
||||||
import { vouchers } from "./system/voucher";
|
import { vouchers } from "./system/voucher";
|
||||||
import { loggedInUser, updateUserInfo } from "./account";
|
import { loggedInUser, updateUserInfo } from "./account";
|
||||||
import { GameDataType, PlayerGender, SessionSaveData } from "./system/game-data";
|
import { DexAttr, GameDataType, PlayerGender, SessionSaveData } from "./system/game-data";
|
||||||
import { addPokeballCaptureStars, addPokeballOpenParticles } from "./field/anims";
|
import { addPokeballCaptureStars, addPokeballOpenParticles } from "./field/anims";
|
||||||
import { SpeciesFormChangeActiveTrigger, SpeciesFormChangeManualTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangePreMoveTrigger } from "./data/pokemon-forms";
|
import { SpeciesFormChangeActiveTrigger, SpeciesFormChangeManualTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangePreMoveTrigger } from "./data/pokemon-forms";
|
||||||
import { battleSpecDialogue, getCharVariantFromDialogue } from "./data/dialogue";
|
import { battleSpecDialogue, getCharVariantFromDialogue } from "./data/dialogue";
|
||||||
@ -175,7 +175,10 @@ export class TitlePhase extends Phase {
|
|||||||
if (loggedInUser.lastSessionSlot > -1) {
|
if (loggedInUser.lastSessionSlot > -1) {
|
||||||
options.push({
|
options.push({
|
||||||
label: i18next.t('menu:continue'),
|
label: i18next.t('menu:continue'),
|
||||||
handler: () => this.loadSaveSlot(this.lastSessionData ? -1 : loggedInUser.lastSessionSlot)
|
handler: () => {
|
||||||
|
this.loadSaveSlot(this.lastSessionData ? -1 : loggedInUser.lastSessionSlot);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
options.push({
|
options.push({
|
||||||
@ -188,20 +191,29 @@ export class TitlePhase extends Phase {
|
|||||||
this.end();
|
this.end();
|
||||||
};
|
};
|
||||||
if (this.scene.gameData.unlocks[Unlockables.ENDLESS_MODE]) {
|
if (this.scene.gameData.unlocks[Unlockables.ENDLESS_MODE]) {
|
||||||
const options = [
|
const options: OptionSelectItem[] = [
|
||||||
{
|
{
|
||||||
label: gameModes[GameModes.CLASSIC].getName(),
|
label: gameModes[GameModes.CLASSIC].getName(),
|
||||||
handler: () => setModeAndEnd(GameModes.CLASSIC)
|
handler: () => {
|
||||||
|
setModeAndEnd(GameModes.CLASSIC);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: gameModes[GameModes.ENDLESS].getName(),
|
label: gameModes[GameModes.ENDLESS].getName(),
|
||||||
handler: () => setModeAndEnd(GameModes.ENDLESS)
|
handler: () => {
|
||||||
|
setModeAndEnd(GameModes.ENDLESS);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
if (this.scene.gameData.unlocks[Unlockables.SPLICED_ENDLESS_MODE]) {
|
if (this.scene.gameData.unlocks[Unlockables.SPLICED_ENDLESS_MODE]) {
|
||||||
options.push({
|
options.push({
|
||||||
label: gameModes[GameModes.SPLICED_ENDLESS].getName(),
|
label: gameModes[GameModes.SPLICED_ENDLESS].getName(),
|
||||||
handler: () => setModeAndEnd(GameModes.SPLICED_ENDLESS)
|
handler: () => {
|
||||||
|
setModeAndEnd(GameModes.SPLICED_ENDLESS);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
options.push({
|
options.push({
|
||||||
@ -210,6 +222,7 @@ export class TitlePhase extends Phase {
|
|||||||
this.scene.clearPhaseQueue();
|
this.scene.clearPhaseQueue();
|
||||||
this.scene.pushPhase(new TitlePhase(this.scene));
|
this.scene.pushPhase(new TitlePhase(this.scene));
|
||||||
super.end();
|
super.end();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.scene.ui.showText(i18next.t("menu:selectGameMode"), null, () => this.scene.ui.setOverlayMode(Mode.OPTION_SELECT, { options: options }));
|
this.scene.ui.showText(i18next.t("menu:selectGameMode"), null, () => this.scene.ui.setOverlayMode(Mode.OPTION_SELECT, { options: options }));
|
||||||
@ -219,21 +232,27 @@ export class TitlePhase extends Phase {
|
|||||||
this.scene.ui.clearText();
|
this.scene.ui.clearText();
|
||||||
this.end();
|
this.end();
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: i18next.t('menu:loadGame'),
|
label: i18next.t('menu:loadGame'),
|
||||||
handler: () => this.scene.ui.setOverlayMode(Mode.SAVE_SLOT, SaveSlotUiMode.LOAD,
|
handler: () => {
|
||||||
(slotId: integer) => {
|
this.scene.ui.setOverlayMode(Mode.SAVE_SLOT, SaveSlotUiMode.LOAD,
|
||||||
if (slotId === -1)
|
(slotId: integer) => {
|
||||||
return this.showOptions();
|
if (slotId === -1)
|
||||||
this.loadSaveSlot(slotId);
|
return this.showOptions();
|
||||||
}
|
this.loadSaveSlot(slotId);
|
||||||
)
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: i18next.t('menu:dailyRun'),
|
label: i18next.t('menu:dailyRun'),
|
||||||
handler: () => this.initDailyRun(),
|
handler: () => {
|
||||||
|
this.initDailyRun();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
keepOpen: true
|
keepOpen: true
|
||||||
});
|
});
|
||||||
const config: OptionSelectConfig = {
|
const config: OptionSelectConfig = {
|
||||||
@ -377,6 +396,7 @@ export class SelectGenderPhase extends Phase {
|
|||||||
this.scene.gameData.gender = PlayerGender.MALE;
|
this.scene.gameData.gender = PlayerGender.MALE;
|
||||||
this.scene.gameData.saveSetting(Setting.Player_Gender, 0);
|
this.scene.gameData.saveSetting(Setting.Player_Gender, 0);
|
||||||
this.scene.gameData.saveSystem().then(() => this.end());
|
this.scene.gameData.saveSystem().then(() => this.end());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -385,6 +405,7 @@ export class SelectGenderPhase extends Phase {
|
|||||||
this.scene.gameData.gender = PlayerGender.FEMALE;
|
this.scene.gameData.gender = PlayerGender.FEMALE;
|
||||||
this.scene.gameData.saveSetting(Setting.Player_Gender, 1);
|
this.scene.gameData.saveSetting(Setting.Player_Gender, 1);
|
||||||
this.scene.gameData.saveSystem().then(() => this.end());
|
this.scene.gameData.saveSystem().then(() => this.end());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -437,6 +458,10 @@ export class SelectStarterPhase extends Phase {
|
|||||||
const starterIvs = this.scene.gameData.dexData[starter.species.speciesId].ivs.slice(0);
|
const starterIvs = this.scene.gameData.dexData[starter.species.speciesId].ivs.slice(0);
|
||||||
const starterPokemon = this.scene.addPlayerPokemon(starter.species, this.scene.gameMode.getStartingLevel(), starterProps.abilityIndex, starterFormIndex, starterGender, starterProps.shiny, starterIvs, starter.nature);
|
const starterPokemon = this.scene.addPlayerPokemon(starter.species, this.scene.gameMode.getStartingLevel(), starterProps.abilityIndex, starterFormIndex, starterGender, starterProps.shiny, starterIvs, starter.nature);
|
||||||
starterPokemon.tryPopulateMoveset(starter.moveset);
|
starterPokemon.tryPopulateMoveset(starter.moveset);
|
||||||
|
if (starter.passive)
|
||||||
|
starterPokemon.passive = true;
|
||||||
|
if (starter.variant && starter.dexAttr & DexAttr.SHINY)
|
||||||
|
starterPokemon.variant = starter.variant;
|
||||||
if (starter.pokerus)
|
if (starter.pokerus)
|
||||||
starterPokemon.pokerus = true;
|
starterPokemon.pokerus = true;
|
||||||
if (this.scene.gameMode.isSplicedOnly)
|
if (this.scene.gameMode.isSplicedOnly)
|
||||||
@ -2130,6 +2155,8 @@ export class MovePhase extends BattlePhase {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const doMove = () => {
|
const doMove = () => {
|
||||||
|
this.pokemon.turnData.acted = true; // Record that the move was attempted, even if it fails
|
||||||
|
|
||||||
this.pokemon.lapseTags(BattlerTagLapseType.PRE_MOVE);
|
this.pokemon.lapseTags(BattlerTagLapseType.PRE_MOVE);
|
||||||
|
|
||||||
if (!this.followUp && this.canMove() && !this.cancelled) {
|
if (!this.followUp && this.canMove() && !this.cancelled) {
|
||||||
@ -2294,7 +2321,7 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
const hitCount = new Utils.IntegerHolder(1);
|
const hitCount = new Utils.IntegerHolder(1);
|
||||||
// Assume single target for multi hit
|
// Assume single target for multi hit
|
||||||
applyMoveAttrs(MultiHitAttr, user, this.getTarget(), this.move.getMove(), hitCount);
|
applyMoveAttrs(MultiHitAttr, user, this.getTarget(), this.move.getMove(), hitCount);
|
||||||
if (this.move.getMove() instanceof AttackMove)
|
if (this.move.getMove() instanceof AttackMove && !this.move.getMove().getAttrs(FixedDamageAttr).length)
|
||||||
this.scene.applyModifiers(PokemonMultiHitModifier, user.isPlayer(), user, hitCount, new Utils.IntegerHolder(0));
|
this.scene.applyModifiers(PokemonMultiHitModifier, user.isPlayer(), user, hitCount, new Utils.IntegerHolder(0));
|
||||||
user.turnData.hitsLeft = user.turnData.hitCount = hitCount.value;
|
user.turnData.hitsLeft = user.turnData.hitCount = hitCount.value;
|
||||||
}
|
}
|
||||||
@ -2605,6 +2632,7 @@ export class StatChangePhase extends PokemonPhase {
|
|||||||
for (let stat of filteredStats)
|
for (let stat of filteredStats)
|
||||||
pokemon.summonData.battleStats[stat] = Math.max(Math.min(pokemon.summonData.battleStats[stat] + levels.value, 6), -6);
|
pokemon.summonData.battleStats[stat] = Math.max(Math.min(pokemon.summonData.battleStats[stat] + levels.value, 6), -6);
|
||||||
|
|
||||||
|
applyPostStatChangeAbAttrs(PostStatChangeAbAttr, pokemon, filteredStats, this.levels, this.selfTarget)
|
||||||
this.end();
|
this.end();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2950,7 +2978,7 @@ export class FaintPhase extends PokemonPhase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const alivePlayField = this.scene.getField(true);
|
const alivePlayField = this.scene.getField(true);
|
||||||
alivePlayField.forEach(p => applyPostKnockOutAbAttrs(PostKnockOutAbAttr, p));
|
alivePlayField.forEach(p => applyPostKnockOutAbAttrs(PostKnockOutAbAttr, p, pokemon));
|
||||||
if (pokemon.turnData?.attacksReceived?.length) {
|
if (pokemon.turnData?.attacksReceived?.length) {
|
||||||
const defeatSource = this.scene.getPokemonById(pokemon.turnData.attacksReceived[0].sourceId);
|
const defeatSource = this.scene.getPokemonById(pokemon.turnData.attacksReceived[0].sourceId);
|
||||||
if (defeatSource?.isOnField())
|
if (defeatSource?.isOnField())
|
||||||
|
@ -20,6 +20,9 @@ i18next.init({
|
|||||||
lng: DEFAULT_LANGUAGE_OVERRIDE ? DEFAULT_LANGUAGE_OVERRIDE : 'en',
|
lng: DEFAULT_LANGUAGE_OVERRIDE ? DEFAULT_LANGUAGE_OVERRIDE : 'en',
|
||||||
fallbackLng: 'en',
|
fallbackLng: 'en',
|
||||||
debug: true,
|
debug: true,
|
||||||
|
interpolation: {
|
||||||
|
escapeValue: false,
|
||||||
|
},
|
||||||
resources: {
|
resources: {
|
||||||
en: {
|
en: {
|
||||||
menu: enMenu,
|
menu: enMenu,
|
||||||
|
@ -43,6 +43,11 @@ export enum PlayerGender {
|
|||||||
FEMALE
|
FEMALE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum Passive {
|
||||||
|
UNLOCKED = 1,
|
||||||
|
ENABLED = 2
|
||||||
|
}
|
||||||
|
|
||||||
export function getDataTypeKey(dataType: GameDataType, slotId: integer = 0): string {
|
export function getDataTypeKey(dataType: GameDataType, slotId: integer = 0): string {
|
||||||
switch (dataType) {
|
switch (dataType) {
|
||||||
case GameDataType.SYSTEM:
|
case GameDataType.SYSTEM:
|
||||||
@ -64,8 +69,7 @@ interface SystemSaveData {
|
|||||||
secretId: integer;
|
secretId: integer;
|
||||||
gender: PlayerGender;
|
gender: PlayerGender;
|
||||||
dexData: DexData;
|
dexData: DexData;
|
||||||
starterMoveData: StarterMoveData;
|
starterData: StarterData;
|
||||||
starterEggMoveData: StarterEggMoveData;
|
|
||||||
gameStats: GameStats;
|
gameStats: GameStats;
|
||||||
unlocks: Unlocks;
|
unlocks: Unlocks;
|
||||||
achvUnlocks: AchvUnlocks;
|
achvUnlocks: AchvUnlocks;
|
||||||
@ -145,16 +149,25 @@ export interface DexAttrProps {
|
|||||||
|
|
||||||
export type StarterMoveset = [ Moves ] | [ Moves, Moves ] | [ Moves, Moves, Moves ] | [ Moves, Moves, Moves, Moves ];
|
export type StarterMoveset = [ Moves ] | [ Moves, Moves ] | [ Moves, Moves, Moves ] | [ Moves, Moves, Moves, Moves ];
|
||||||
|
|
||||||
export interface StarterMoveData {
|
|
||||||
[key: integer]: StarterMoveset | StarterFormMoveData
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface StarterFormMoveData {
|
export interface StarterFormMoveData {
|
||||||
[key: integer]: StarterMoveset
|
[key: integer]: StarterMoveset
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StarterEggMoveData {
|
export interface StarterMoveData {
|
||||||
[key: integer]: integer
|
[key: integer]: StarterMoveset | StarterFormMoveData
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StarterDataEntry {
|
||||||
|
moveset: StarterMoveset | StarterFormMoveData;
|
||||||
|
eggMoves: integer;
|
||||||
|
candyCount: integer;
|
||||||
|
passiveAttr: integer;
|
||||||
|
variantAttr: integer;
|
||||||
|
valueReduction: integer;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StarterData {
|
||||||
|
[key: integer]: StarterDataEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TutorialFlags {
|
export interface TutorialFlags {
|
||||||
@ -167,7 +180,12 @@ const systemShortKeys = {
|
|||||||
natureAttr: '$na',
|
natureAttr: '$na',
|
||||||
seenCount: '$s' ,
|
seenCount: '$s' ,
|
||||||
caughtCount: '$c',
|
caughtCount: '$c',
|
||||||
ivs: '$i'
|
ivs: '$i',
|
||||||
|
moveset: '$m',
|
||||||
|
eggMoves: '$em',
|
||||||
|
candyCount: '$cc',
|
||||||
|
passive: '$p',
|
||||||
|
valueReduction: '$vr'
|
||||||
};
|
};
|
||||||
|
|
||||||
export class GameData {
|
export class GameData {
|
||||||
@ -181,9 +199,7 @@ export class GameData {
|
|||||||
public dexData: DexData;
|
public dexData: DexData;
|
||||||
private defaultDexData: DexData;
|
private defaultDexData: DexData;
|
||||||
|
|
||||||
public starterMoveData: StarterMoveData;
|
public starterData: StarterData;
|
||||||
|
|
||||||
public starterEggMoveData: StarterEggMoveData;
|
|
||||||
|
|
||||||
public gameStats: GameStats;
|
public gameStats: GameStats;
|
||||||
|
|
||||||
@ -200,8 +216,7 @@ export class GameData {
|
|||||||
this.loadSettings();
|
this.loadSettings();
|
||||||
this.trainerId = Utils.randSeedInt(65536);
|
this.trainerId = Utils.randSeedInt(65536);
|
||||||
this.secretId = Utils.randSeedInt(65536);
|
this.secretId = Utils.randSeedInt(65536);
|
||||||
this.starterMoveData = {};
|
this.starterData = {};
|
||||||
this.starterEggMoveData = {};
|
|
||||||
this.gameStats = new GameStats();
|
this.gameStats = new GameStats();
|
||||||
this.unlocks = {
|
this.unlocks = {
|
||||||
[Unlockables.ENDLESS_MODE]: false,
|
[Unlockables.ENDLESS_MODE]: false,
|
||||||
@ -218,7 +233,7 @@ export class GameData {
|
|||||||
};
|
};
|
||||||
this.eggs = [];
|
this.eggs = [];
|
||||||
this.initDexData();
|
this.initDexData();
|
||||||
this.initEggMoveData();
|
this.initStarterData();
|
||||||
}
|
}
|
||||||
|
|
||||||
public saveSystem(): Promise<boolean> {
|
public saveSystem(): Promise<boolean> {
|
||||||
@ -234,8 +249,7 @@ export class GameData {
|
|||||||
secretId: this.secretId,
|
secretId: this.secretId,
|
||||||
gender: this.gender,
|
gender: this.gender,
|
||||||
dexData: this.dexData,
|
dexData: this.dexData,
|
||||||
starterMoveData: this.starterMoveData,
|
starterData: this.starterData,
|
||||||
starterEggMoveData: this.starterEggMoveData,
|
|
||||||
gameStats: this.gameStats,
|
gameStats: this.gameStats,
|
||||||
unlocks: this.unlocks,
|
unlocks: this.unlocks,
|
||||||
achvUnlocks: this.achvUnlocks,
|
achvUnlocks: this.achvUnlocks,
|
||||||
@ -297,17 +311,24 @@ export class GameData {
|
|||||||
|
|
||||||
this.saveSetting(Setting.Player_Gender, systemData.gender === PlayerGender.FEMALE ? 1 : 0);
|
this.saveSetting(Setting.Player_Gender, systemData.gender === PlayerGender.FEMALE ? 1 : 0);
|
||||||
|
|
||||||
this.starterMoveData = systemData.starterMoveData || {};
|
const initStarterData = !systemData.starterData;
|
||||||
|
|
||||||
this.starterEggMoveData = {};
|
|
||||||
this.initEggMoveData();
|
|
||||||
|
|
||||||
if (systemData.starterEggMoveData) {
|
if (initStarterData) {
|
||||||
for (let key of Object.keys(systemData.starterEggMoveData)) {
|
this.initStarterData();
|
||||||
if (this.starterEggMoveData.hasOwnProperty(key))
|
|
||||||
this.starterEggMoveData[key] = systemData.starterEggMoveData[key];
|
if (systemData['starterMoveData']) {
|
||||||
|
const starterMoveData = systemData['starterMoveData'];
|
||||||
|
for (let s of Object.keys(starterMoveData))
|
||||||
|
this.starterData[s].moveset = starterMoveData[s];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (systemData['starterEggMoveData']) {
|
||||||
|
const starterEggMoveData = systemData['starterEggMoveData'];
|
||||||
|
for (let s of Object.keys(starterEggMoveData))
|
||||||
|
this.starterData[s].eggMoves = starterEggMoveData[s];
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
this.starterData = systemData.starterData;
|
||||||
|
|
||||||
if (systemData.gameStats)
|
if (systemData.gameStats)
|
||||||
this.gameStats = systemData.gameStats;
|
this.gameStats = systemData.gameStats;
|
||||||
@ -348,6 +369,16 @@ export class GameData {
|
|||||||
this.consolidateDexData(this.dexData);
|
this.consolidateDexData(this.dexData);
|
||||||
this.defaultDexData = null;
|
this.defaultDexData = null;
|
||||||
|
|
||||||
|
if (initStarterData) {
|
||||||
|
const starterIds = Object.keys(this.starterData).map(s => parseInt(s) as Species);
|
||||||
|
for (let s of starterIds) {
|
||||||
|
this.starterData[s].candyCount += this.dexData[s].caughtCount;
|
||||||
|
this.starterData[s].candyCount += this.dexData[s].hatchedCount * 2;
|
||||||
|
if (this.dexData[s].caughtAttr & DexAttr.SHINY)
|
||||||
|
this.starterData[s].candyCount += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
resolve(true);
|
resolve(true);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
@ -388,7 +419,7 @@ export class GameData {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return k.endsWith('Attr') && k !== 'natureAttr' ? BigInt(v) : v;
|
return k.endsWith('Attr') && ![ 'natureAttr', 'passiveAttr', 'variantAttr' ].includes(k) ? BigInt(v) : v;
|
||||||
}) as SystemSaveData;
|
}) as SystemSaveData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -906,15 +937,23 @@ export class GameData {
|
|||||||
this.dexData = data;
|
this.dexData = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private initEggMoveData(): void {
|
private initStarterData(): void {
|
||||||
const data: StarterEggMoveData = {};
|
const starterData: StarterData = {};
|
||||||
|
|
||||||
const starterSpeciesIds = Object.keys(speciesEggMoves).map(k => parseInt(k) as Species);
|
|
||||||
|
|
||||||
for (let speciesId of starterSpeciesIds)
|
const starterSpeciesIds = Object.keys(speciesStarters).map(k => parseInt(k) as Species);
|
||||||
data[speciesId] = 0;
|
|
||||||
|
|
||||||
this.starterEggMoveData = data;
|
for (let speciesId of starterSpeciesIds) {
|
||||||
|
starterData[speciesId] = {
|
||||||
|
moveset: null,
|
||||||
|
eggMoves: 0,
|
||||||
|
candyCount: 0,
|
||||||
|
passiveAttr: 0,
|
||||||
|
variantAttr: 0,
|
||||||
|
valueReduction: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
this.starterData = starterData;
|
||||||
}
|
}
|
||||||
|
|
||||||
setPokemonSeen(pokemon: Pokemon, incrementCount: boolean = true): void {
|
setPokemonSeen(pokemon: Pokemon, incrementCount: boolean = true): void {
|
||||||
@ -943,6 +982,10 @@ export class GameData {
|
|||||||
pokemon.formIndex = formIndex;
|
pokemon.formIndex = formIndex;
|
||||||
dexEntry.caughtAttr |= dexAttr;
|
dexEntry.caughtAttr |= dexAttr;
|
||||||
dexEntry.natureAttr |= Math.pow(2, pokemon.nature + 1);
|
dexEntry.natureAttr |= Math.pow(2, pokemon.nature + 1);
|
||||||
|
|
||||||
|
const hasPrevolution = pokemonPrevolutions.hasOwnProperty(species.speciesId);
|
||||||
|
const newCatch = !caughtAttr;
|
||||||
|
|
||||||
if (incrementCount) {
|
if (incrementCount) {
|
||||||
if (!fromEgg) {
|
if (!fromEgg) {
|
||||||
dexEntry.caughtCount++;
|
dexEntry.caughtCount++;
|
||||||
@ -963,11 +1006,11 @@ export class GameData {
|
|||||||
if (pokemon.isShiny())
|
if (pokemon.isShiny())
|
||||||
this.gameStats.shinyPokemonHatched++;
|
this.gameStats.shinyPokemonHatched++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!hasPrevolution)
|
||||||
|
this.addStarterCandy(species, (1 * (pokemon.isShiny() ? 5 : 1)) * (fromEgg || pokemon.isBoss() ? 2 : 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasPrevolution = pokemonPrevolutions.hasOwnProperty(species.speciesId);
|
|
||||||
const newCatch = !caughtAttr;
|
|
||||||
|
|
||||||
const checkPrevolution = () => {
|
const checkPrevolution = () => {
|
||||||
if (hasPrevolution) {
|
if (hasPrevolution) {
|
||||||
const prevolutionSpecies = pokemonPrevolutions[species.speciesId];
|
const prevolutionSpecies = pokemonPrevolutions[species.speciesId];
|
||||||
@ -984,6 +1027,11 @@ export class GameData {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addStarterCandy(species: PokemonSpecies, count: integer): void {
|
||||||
|
this.scene.candyBar.showStarterSpeciesCandy(species.speciesId, count);
|
||||||
|
this.starterData[species.speciesId].candyCount += count;
|
||||||
|
}
|
||||||
|
|
||||||
setEggMoveUnlocked(species: PokemonSpecies, eggMoveIndex: integer): Promise<boolean> {
|
setEggMoveUnlocked(species: PokemonSpecies, eggMoveIndex: integer): Promise<boolean> {
|
||||||
return new Promise<boolean>(resolve => {
|
return new Promise<boolean>(resolve => {
|
||||||
const speciesId = species.speciesId;
|
const speciesId = species.speciesId;
|
||||||
@ -992,17 +1040,17 @@ export class GameData {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.starterEggMoveData.hasOwnProperty(speciesId))
|
if (!this.starterData[speciesId].eggMoves)
|
||||||
this.starterEggMoveData[speciesId] = 0;
|
this.starterData[speciesId].eggMoves = 0;
|
||||||
|
|
||||||
const value = Math.pow(2, eggMoveIndex);
|
const value = Math.pow(2, eggMoveIndex);
|
||||||
|
|
||||||
if (this.starterEggMoveData[speciesId] & value) {
|
if (this.starterData[speciesId].eggMoves & value) {
|
||||||
resolve(false);
|
resolve(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.starterEggMoveData[speciesId] |= value;
|
this.starterData[speciesId].eggMoves |= value;
|
||||||
|
|
||||||
this.scene.playSound('level_up_fanfare');
|
this.scene.playSound('level_up_fanfare');
|
||||||
this.scene.ui.showText(`${eggMoveIndex === 3 ? 'Rare ' : ''}Egg Move unlocked: ${allMoves[speciesEggMoves[speciesId][eggMoveIndex]].name}`, null, () => resolve(true), null, true);
|
this.scene.ui.showText(`${eggMoveIndex === 3 ? 'Rare ' : ''}Egg Move unlocked: ${allMoves[speciesEggMoves[speciesId][eggMoveIndex]].name}`, null, () => resolve(true), null, true);
|
||||||
@ -1094,7 +1142,6 @@ export class GameData {
|
|||||||
getSpeciesStarterValue(speciesId: Species): number {
|
getSpeciesStarterValue(speciesId: Species): number {
|
||||||
const baseValue = speciesStarters[speciesId];
|
const baseValue = speciesStarters[speciesId];
|
||||||
let value = baseValue;
|
let value = baseValue;
|
||||||
const caughtHatchedCount = this.dexData[speciesId].caughtCount + this.dexData[speciesId].hatchedCount;
|
|
||||||
|
|
||||||
const decrementValue = (value: number) => {
|
const decrementValue = (value: number) => {
|
||||||
if (value > 1)
|
if (value > 1)
|
||||||
@ -1104,44 +1151,8 @@ export class GameData {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
let thresholdA: integer;
|
for (let v = 0; v < this.starterData[speciesId].valueReduction; v++)
|
||||||
let thresholdB: integer;
|
|
||||||
|
|
||||||
switch (baseValue) {
|
|
||||||
case 1:
|
|
||||||
[ thresholdA, thresholdB ] = [ 25, 100 ];
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
[ thresholdA, thresholdB ] = [ 20, 70 ];
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
[ thresholdA, thresholdB ] = [ 15, 50 ];
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
[ thresholdA, thresholdB ] = [ 10, 30 ];
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
[ thresholdA, thresholdB ] = [ 8, 25 ];
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
[ thresholdA, thresholdB ] = [ 5, 15 ];
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
[ thresholdA, thresholdB ] = [ 4, 12 ];
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
[ thresholdA, thresholdB ] = [ 3, 10 ];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
[ thresholdA, thresholdB ] = [ 2, 5 ];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (caughtHatchedCount >= thresholdA) {
|
|
||||||
value = decrementValue(value);
|
value = decrementValue(value);
|
||||||
if (caughtHatchedCount >= thresholdB)
|
|
||||||
value = decrementValue(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,9 @@ export default class PokemonData {
|
|||||||
public species: Species;
|
public species: Species;
|
||||||
public formIndex: integer;
|
public formIndex: integer;
|
||||||
public abilityIndex: integer;
|
public abilityIndex: integer;
|
||||||
|
public passive: boolean;
|
||||||
public shiny: boolean;
|
public shiny: boolean;
|
||||||
|
public variant: integer;
|
||||||
public pokeball: PokeballType;
|
public pokeball: PokeballType;
|
||||||
public level: integer;
|
public level: integer;
|
||||||
public exp: integer;
|
public exp: integer;
|
||||||
@ -53,7 +55,9 @@ export default class PokemonData {
|
|||||||
this.species = sourcePokemon ? sourcePokemon.species.speciesId : source.species;
|
this.species = sourcePokemon ? sourcePokemon.species.speciesId : source.species;
|
||||||
this.formIndex = Math.max(Math.min(source.formIndex, getPokemonSpecies(this.species).forms.length - 1), 0);
|
this.formIndex = Math.max(Math.min(source.formIndex, getPokemonSpecies(this.species).forms.length - 1), 0);
|
||||||
this.abilityIndex = source.abilityIndex;
|
this.abilityIndex = source.abilityIndex;
|
||||||
|
this.passive = source.passive;
|
||||||
this.shiny = source.shiny;
|
this.shiny = source.shiny;
|
||||||
|
this.variant = source.variant;
|
||||||
this.pokeball = source.pokeball;
|
this.pokeball = source.pokeball;
|
||||||
this.level = source.level;
|
this.level = source.level;
|
||||||
this.exp = source.exp;
|
this.exp = source.exp;
|
||||||
|
@ -4,6 +4,7 @@ import { Mode } from "./ui";
|
|||||||
import UiHandler from "./ui-handler";
|
import UiHandler from "./ui-handler";
|
||||||
import { addWindow } from "./ui-theme";
|
import { addWindow } from "./ui-theme";
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
|
import { argbFromRgba } from "@material/material-color-utilities";
|
||||||
|
|
||||||
export interface OptionSelectConfig {
|
export interface OptionSelectConfig {
|
||||||
xOffset?: number;
|
xOffset?: number;
|
||||||
@ -16,9 +17,11 @@ export interface OptionSelectConfig {
|
|||||||
|
|
||||||
export interface OptionSelectItem {
|
export interface OptionSelectItem {
|
||||||
label: string;
|
label: string;
|
||||||
handler: Function;
|
handler: () => boolean;
|
||||||
keepOpen?: boolean;
|
keepOpen?: boolean;
|
||||||
overrideSound?: boolean;
|
overrideSound?: boolean;
|
||||||
|
item?: string;
|
||||||
|
itemArgs?: any[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const scrollUpLabel = '↑';
|
const scrollUpLabel = '↑';
|
||||||
@ -28,6 +31,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
|
|||||||
protected optionSelectContainer: Phaser.GameObjects.Container;
|
protected optionSelectContainer: Phaser.GameObjects.Container;
|
||||||
protected optionSelectBg: Phaser.GameObjects.NineSlice;
|
protected optionSelectBg: Phaser.GameObjects.NineSlice;
|
||||||
protected optionSelectText: Phaser.GameObjects.Text;
|
protected optionSelectText: Phaser.GameObjects.Text;
|
||||||
|
protected optionSelectIcons: Phaser.GameObjects.Sprite[];
|
||||||
|
|
||||||
protected config: OptionSelectConfig;
|
protected config: OptionSelectConfig;
|
||||||
|
|
||||||
@ -58,6 +62,8 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
|
|||||||
this.optionSelectBg.setOrigin(1, 1);
|
this.optionSelectBg.setOrigin(1, 1);
|
||||||
this.optionSelectContainer.add(this.optionSelectBg);
|
this.optionSelectContainer.add(this.optionSelectBg);
|
||||||
|
|
||||||
|
this.optionSelectIcons = [];
|
||||||
|
|
||||||
this.setCursor(0);
|
this.setCursor(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,8 +72,12 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
|
|||||||
|
|
||||||
if (this.optionSelectText)
|
if (this.optionSelectText)
|
||||||
this.optionSelectText.destroy();
|
this.optionSelectText.destroy();
|
||||||
|
if (this.optionSelectIcons?.length) {
|
||||||
|
this.optionSelectIcons.map(i => i.destroy());
|
||||||
|
this.optionSelectIcons.splice(0, this.optionSelectIcons.length);
|
||||||
|
}
|
||||||
|
|
||||||
this.optionSelectText = addTextObject(this.scene, 0, 0, options.map(o => o.label).join('\n'), TextStyle.WINDOW, { maxLines: options.length });
|
this.optionSelectText = addTextObject(this.scene, 0, 0, options.map(o => o.item ? ` ${o.label}` : o.label).join('\n'), TextStyle.WINDOW, { maxLines: options.length });
|
||||||
this.optionSelectText.setLineSpacing(12);
|
this.optionSelectText.setLineSpacing(12);
|
||||||
this.optionSelectContainer.add(this.optionSelectText);
|
this.optionSelectContainer.add(this.optionSelectText);
|
||||||
this.optionSelectContainer.setPosition((this.scene.game.canvas.width / 6) - 1 - (this.config?.xOffset || 0), -48 + (this.config?.yOffset || 0));
|
this.optionSelectContainer.setPosition((this.scene.game.canvas.width / 6) - 1 - (this.config?.xOffset || 0), -48 + (this.config?.yOffset || 0));
|
||||||
@ -80,6 +90,31 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
|
|||||||
this.optionSelectBg.height = this.getWindowHeight();
|
this.optionSelectBg.height = this.getWindowHeight();
|
||||||
|
|
||||||
this.optionSelectText.setPositionRelative(this.optionSelectBg, 16, 9);
|
this.optionSelectText.setPositionRelative(this.optionSelectBg, 16, 9);
|
||||||
|
|
||||||
|
options.forEach((option: OptionSelectItem, i: integer) => {
|
||||||
|
if (option.item) {
|
||||||
|
const itemIcon = this.scene.add.sprite(0, 0, 'items', option.item);
|
||||||
|
itemIcon.setScale(0.5);
|
||||||
|
this.optionSelectIcons.push(itemIcon);
|
||||||
|
|
||||||
|
this.optionSelectContainer.add(itemIcon);
|
||||||
|
|
||||||
|
itemIcon.setPositionRelative(this.optionSelectText, 6, 7 + 16 * i);
|
||||||
|
|
||||||
|
if (option.item === 'candy') {
|
||||||
|
const itemOverlayIcon = this.scene.add.sprite(0, 0, 'items', 'candy_overlay');
|
||||||
|
itemOverlayIcon.setScale(0.5);
|
||||||
|
this.optionSelectIcons.push(itemOverlayIcon);
|
||||||
|
|
||||||
|
this.optionSelectContainer.add(itemOverlayIcon);
|
||||||
|
|
||||||
|
itemOverlayIcon.setPositionRelative(this.optionSelectText, 6, 7 + 16 * i);
|
||||||
|
|
||||||
|
itemIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(option.itemArgs[0])));
|
||||||
|
itemOverlayIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(option.itemArgs[1])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
show(args: any[]): boolean {
|
show(args: any[]): boolean {
|
||||||
@ -132,10 +167,12 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const option = this.config.options[this.cursor + (this.scrollCursor - (this.scrollCursor ? 1 : 0))];
|
const option = this.config.options[this.cursor + (this.scrollCursor - (this.scrollCursor ? 1 : 0))];
|
||||||
option.handler();
|
if (option.handler()) {
|
||||||
if (!option.keepOpen)
|
if (!option.keepOpen)
|
||||||
this.clear();
|
this.clear();
|
||||||
playSound = !option.overrideSound;
|
playSound = !option.overrideSound;
|
||||||
|
} else
|
||||||
|
ui.playError();
|
||||||
} else {
|
} else {
|
||||||
switch (button) {
|
switch (button) {
|
||||||
case Button.UP:
|
case Button.UP:
|
||||||
@ -182,12 +219,12 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
|
|||||||
if (optionStartIndex)
|
if (optionStartIndex)
|
||||||
options.unshift({
|
options.unshift({
|
||||||
label: scrollUpLabel,
|
label: scrollUpLabel,
|
||||||
handler: () => { }
|
handler: () => true
|
||||||
});
|
});
|
||||||
if (optionEndIndex < optionsScrollTotal)
|
if (optionEndIndex < optionsScrollTotal)
|
||||||
options.push({
|
options.push({
|
||||||
label: scrollDownLabel,
|
label: scrollDownLabel,
|
||||||
handler: () => { }
|
handler: () => true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
123
src/ui/candy-bar.ts
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
import BattleScene, { starterColors } from "../battle-scene";
|
||||||
|
import { TextStyle, addTextObject } from "./text";
|
||||||
|
import { argbFromRgba } from "@material/material-color-utilities";
|
||||||
|
import * as Utils from "../utils";
|
||||||
|
import { Species } from "#app/data/enums/species";
|
||||||
|
|
||||||
|
export default class CandyBar extends Phaser.GameObjects.Container {
|
||||||
|
private bg: Phaser.GameObjects.NineSlice;
|
||||||
|
private candyIcon: Phaser.GameObjects.Sprite;
|
||||||
|
private candyOverlayIcon: Phaser.GameObjects.Sprite;
|
||||||
|
private countText: Phaser.GameObjects.Text;
|
||||||
|
private speciesId: Species;
|
||||||
|
|
||||||
|
private tween: Phaser.Tweens.Tween;
|
||||||
|
private autoHideTimer: number;
|
||||||
|
|
||||||
|
public shown: boolean;
|
||||||
|
|
||||||
|
constructor(scene: BattleScene) {
|
||||||
|
super(scene, (scene.game.canvas.width / 6), -((scene.game.canvas.height) / 6) + 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
setup(): void {
|
||||||
|
this.bg = this.scene.add.nineslice(0, 0, 'party_exp_bar', null, 8, 18, 21, 5, 6, 4);
|
||||||
|
this.bg.setOrigin(0, 0);
|
||||||
|
|
||||||
|
this.add(this.bg);
|
||||||
|
|
||||||
|
this.candyIcon = this.scene.add.sprite(14, 0, 'items', 'candy');
|
||||||
|
this.candyIcon.setOrigin(0.5, 0);
|
||||||
|
this.candyIcon.setScale(0.5);
|
||||||
|
|
||||||
|
this.add(this.candyIcon);
|
||||||
|
|
||||||
|
this.candyOverlayIcon = this.scene.add.sprite(14, 0, 'items', 'candy_overlay');
|
||||||
|
this.candyOverlayIcon.setOrigin(0.5, 0);
|
||||||
|
this.candyOverlayIcon.setScale(0.5);
|
||||||
|
|
||||||
|
this.add(this.candyOverlayIcon);
|
||||||
|
|
||||||
|
this.countText = addTextObject(this.scene, 22, 4, '', TextStyle.BATTLE_INFO);
|
||||||
|
this.countText.setOrigin(0, 0);
|
||||||
|
this.add(this.countText);
|
||||||
|
|
||||||
|
this.setVisible(false);
|
||||||
|
this.shown = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
showStarterSpeciesCandy(starterSpeciesId: Species, count: integer): Promise<void> {
|
||||||
|
return new Promise<void>(resolve => {
|
||||||
|
if (this.shown) {
|
||||||
|
if (this.speciesId === starterSpeciesId)
|
||||||
|
return resolve();
|
||||||
|
else
|
||||||
|
return this.hide().then(() => this.showStarterSpeciesCandy(starterSpeciesId, count)).then(() => resolve());
|
||||||
|
}
|
||||||
|
|
||||||
|
const colorScheme = starterColors[starterSpeciesId];
|
||||||
|
|
||||||
|
this.candyIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(colorScheme[0])));
|
||||||
|
this.candyOverlayIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(colorScheme[1])));
|
||||||
|
|
||||||
|
this.countText.setText(`${(this.scene as BattleScene).gameData.starterData[starterSpeciesId].candyCount + count} (+${count.toString()})`);
|
||||||
|
|
||||||
|
this.bg.width = this.countText.displayWidth + 28;
|
||||||
|
|
||||||
|
(this.scene as BattleScene).fieldUI.bringToTop(this);
|
||||||
|
|
||||||
|
if (this.tween)
|
||||||
|
this.tween.stop();
|
||||||
|
|
||||||
|
this.tween = this.scene.tweens.add({
|
||||||
|
targets: this,
|
||||||
|
x: (this.scene.game.canvas.width / 6) - (this.bg.width - 5),
|
||||||
|
duration: 500,
|
||||||
|
ease: 'Sine.easeOut',
|
||||||
|
onComplete: () => {
|
||||||
|
this.tween = null;
|
||||||
|
this.resetAutoHideTimer();
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setVisible(true);
|
||||||
|
this.shown = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
hide(): Promise<void> {
|
||||||
|
return new Promise<void>(resolve => {
|
||||||
|
if (!this.shown)
|
||||||
|
return resolve();
|
||||||
|
|
||||||
|
if (this.autoHideTimer)
|
||||||
|
clearInterval(this.autoHideTimer);
|
||||||
|
|
||||||
|
if (this.tween)
|
||||||
|
this.tween.stop();
|
||||||
|
|
||||||
|
this.tween = this.scene.tweens.add({
|
||||||
|
targets: this,
|
||||||
|
x: (this.scene.game.canvas.width / 6),
|
||||||
|
duration: 500,
|
||||||
|
ease: 'Sine.easeIn',
|
||||||
|
onComplete: () => {
|
||||||
|
this.tween = null;
|
||||||
|
this.shown = false;
|
||||||
|
this.setVisible(false);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
resetAutoHideTimer(): void {
|
||||||
|
if (this.autoHideTimer)
|
||||||
|
clearInterval(this.autoHideTimer);
|
||||||
|
this.autoHideTimer = setTimeout(() => {
|
||||||
|
this.hide();
|
||||||
|
this.autoHideTimer = null;
|
||||||
|
}, 2500);
|
||||||
|
}
|
||||||
|
}
|
@ -20,11 +20,17 @@ export default class ConfirmUiHandler extends AbstractOptionSelectUiHandler {
|
|||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
label: 'Yes',
|
label: 'Yes',
|
||||||
handler: args[0]
|
handler: () => {
|
||||||
|
args[0]();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'No',
|
label: 'No',
|
||||||
handler: args[1]
|
handler: () => {
|
||||||
|
args[1]();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
delay: args.length >= 6 && args[5] !== null ? args[5] as integer : 0
|
delay: args.length >= 6 && args[5] !== null ? args[5] as integer : 0
|
||||||
|
@ -339,7 +339,7 @@ export default class EggGachaUiHandler extends MessageUiHandler {
|
|||||||
const tierValueOffset = this.gachaCursor === GachaType.LEGENDARY ? 1 : 0;
|
const tierValueOffset = this.gachaCursor === GachaType.LEGENDARY ? 1 : 0;
|
||||||
const tiers = new Array(pullCount).fill(null).map(() => {
|
const tiers = new Array(pullCount).fill(null).map(() => {
|
||||||
const tierValue = Utils.randInt(256);
|
const tierValue = Utils.randInt(256);
|
||||||
return tierValue >= 52 + tierValueOffset ? EggTier.COMMON : tierValue + tierValueOffset >= 8 ? EggTier.GREAT : tierValue >= 1 + tierValueOffset ? EggTier.ULTRA : EggTier.MASTER;
|
return tierValue >= 52 + tierValueOffset ? EggTier.COMMON : tierValue >= 8 + tierValueOffset ? EggTier.GREAT : tierValue >= 1 + tierValueOffset ? EggTier.ULTRA : EggTier.MASTER;
|
||||||
});
|
});
|
||||||
if (pullCount >= 25 && !tiers.filter(t => t >= EggTier.ULTRA).length)
|
if (pullCount >= 25 && !tiers.filter(t => t >= EggTier.ULTRA).length)
|
||||||
tiers[Utils.randInt(tiers.length)] = EggTier.ULTRA;
|
tiers[Utils.randInt(tiers.length)] = EggTier.ULTRA;
|
||||||
|
@ -5,7 +5,7 @@ import * as Utils from "../utils";
|
|||||||
import { addWindow } from "./ui-theme";
|
import { addWindow } from "./ui-theme";
|
||||||
import MessageUiHandler from "./message-ui-handler";
|
import MessageUiHandler from "./message-ui-handler";
|
||||||
import { GameDataType } from "../system/game-data";
|
import { GameDataType } from "../system/game-data";
|
||||||
import { OptionSelectConfig } 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";
|
||||||
import { updateUserInfo } from "../account";
|
import { updateUserInfo } from "../account";
|
||||||
|
|
||||||
@ -99,6 +99,7 @@ export default class MenuUiHandler extends MessageUiHandler {
|
|||||||
callback(i);
|
callback(i);
|
||||||
ui.revertMode();
|
ui.revertMode();
|
||||||
ui.showText(null, 0);
|
ui.showText(null, 0);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}).concat([{
|
}).concat([{
|
||||||
@ -106,6 +107,7 @@ export default class MenuUiHandler extends MessageUiHandler {
|
|||||||
handler: () => {
|
handler: () => {
|
||||||
ui.revertMode();
|
ui.revertMode();
|
||||||
ui.showText(null, 0);
|
ui.showText(null, 0);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}]),
|
}]),
|
||||||
xOffset: 98
|
xOffset: 98
|
||||||
@ -117,7 +119,10 @@ export default class MenuUiHandler extends MessageUiHandler {
|
|||||||
if (Utils.isLocal) {
|
if (Utils.isLocal) {
|
||||||
manageDataOptions.push({
|
manageDataOptions.push({
|
||||||
label: 'Import Session',
|
label: 'Import Session',
|
||||||
handler: () => confirmSlot('Select a slot to import to.', () => true, slotId => this.scene.gameData.importData(GameDataType.SESSION, slotId)),
|
handler: () => {
|
||||||
|
confirmSlot('Select a slot to import to.', () => true, slotId => this.scene.gameData.importData(GameDataType.SESSION, slotId));
|
||||||
|
return true;
|
||||||
|
},
|
||||||
keepOpen: true
|
keepOpen: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -137,25 +142,35 @@ export default class MenuUiHandler extends MessageUiHandler {
|
|||||||
i => dataSlots.indexOf(i) > -1,
|
i => dataSlots.indexOf(i) > -1,
|
||||||
slotId => this.scene.gameData.tryExportData(GameDataType.SESSION, slotId));
|
slotId => this.scene.gameData.tryExportData(GameDataType.SESSION, slotId));
|
||||||
});
|
});
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
keepOpen: true
|
keepOpen: true
|
||||||
});
|
});
|
||||||
if (Utils.isLocal) {
|
if (Utils.isLocal) {
|
||||||
manageDataOptions.push({
|
manageDataOptions.push({
|
||||||
label: 'Import Data',
|
label: 'Import Data',
|
||||||
handler: () => this.scene.gameData.importData(GameDataType.SYSTEM),
|
handler: () => {
|
||||||
|
this.scene.gameData.importData(GameDataType.SYSTEM);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
keepOpen: true
|
keepOpen: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
manageDataOptions.push(
|
manageDataOptions.push(
|
||||||
{
|
{
|
||||||
label: 'Export Data',
|
label: 'Export Data',
|
||||||
handler: () => this.scene.gameData.tryExportData(GameDataType.SYSTEM),
|
handler: () => {
|
||||||
|
this.scene.gameData.tryExportData(GameDataType.SYSTEM);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
keepOpen: true
|
keepOpen: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Cancel',
|
label: 'Cancel',
|
||||||
handler: () => this.scene.ui.revertMode()
|
handler: () => {
|
||||||
|
this.scene.ui.revertMode();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -164,25 +179,37 @@ export default class MenuUiHandler extends MessageUiHandler {
|
|||||||
options: manageDataOptions
|
options: manageDataOptions
|
||||||
};
|
};
|
||||||
|
|
||||||
const communityOptions = [
|
const communityOptions: OptionSelectItem[] = [
|
||||||
{
|
{
|
||||||
label: 'Wiki',
|
label: 'Wiki',
|
||||||
handler: () => window.open(wikiUrl, '_blank').focus(),
|
handler: () => {
|
||||||
|
window.open(wikiUrl, '_blank').focus();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
keepOpen: true
|
keepOpen: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Discord',
|
label: 'Discord',
|
||||||
handler: () => window.open(discordUrl, '_blank').focus(),
|
handler: () => {
|
||||||
|
window.open(discordUrl, '_blank').focus();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
keepOpen: true
|
keepOpen: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'GitHub',
|
label: 'GitHub',
|
||||||
handler: () => window.open(githubUrl, '_blank').focus(),
|
handler: () => {
|
||||||
|
window.open(githubUrl, '_blank').focus();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
keepOpen: true
|
keepOpen: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Cancel',
|
label: 'Cancel',
|
||||||
handler: () => this.scene.ui.revertMode()
|
handler: () => {
|
||||||
|
this.scene.ui.revertMode();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
import BattleScene, { Button } from "../battle-scene";
|
import BattleScene, { Button, starterColors } from "../battle-scene";
|
||||||
import PokemonSpecies, { allSpecies, getPokemonSpecies, getPokemonSpeciesForm, speciesStarters } from "../data/pokemon-species";
|
import PokemonSpecies, { allSpecies, getPokemonSpecies, getPokemonSpeciesForm, speciesStarters, starterPassiveAbilities } from "../data/pokemon-species";
|
||||||
import { Species } from "../data/enums/species";
|
import { Species } from "../data/enums/species";
|
||||||
import { TextStyle, addBBCodeTextObject, addTextObject, getTextColor } from "./text";
|
import { TextStyle, addBBCodeTextObject, addTextObject } from "./text";
|
||||||
import { Mode } from "./ui";
|
import { Mode } from "./ui";
|
||||||
import MessageUiHandler from "./message-ui-handler";
|
import MessageUiHandler from "./message-ui-handler";
|
||||||
import { Gender, getGenderColor, getGenderSymbol } from "../data/gender";
|
import { Gender, getGenderColor, getGenderSymbol } from "../data/gender";
|
||||||
import { allAbilities } from "../data/ability";
|
import { allAbilities } from "../data/ability";
|
||||||
import { GameMode, GameModes, gameModes } from "../game-mode";
|
import { GameModes, gameModes } from "../game-mode";
|
||||||
import { Unlockables } from "../system/unlockables";
|
|
||||||
import { GrowthRate, getGrowthRateColor } from "../data/exp";
|
import { GrowthRate, getGrowthRateColor } from "../data/exp";
|
||||||
import { DexAttr, DexAttrProps, DexEntry, StarterFormMoveData, StarterMoveset } from "../system/game-data";
|
import { DexAttr, DexAttrProps, DexEntry, Passive as PassiveAttr, StarterFormMoveData, StarterMoveset } from "../system/game-data";
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import PokemonIconAnimHandler, { PokemonIconAnimMode } from "./pokemon-icon-anim-handler";
|
import PokemonIconAnimHandler, { PokemonIconAnimMode } from "./pokemon-icon-anim-handler";
|
||||||
import { StatsContainer } from "./stats-container";
|
import { StatsContainer } from "./stats-container";
|
||||||
@ -24,17 +23,66 @@ import { Type } from "../data/type";
|
|||||||
import { Moves } from "../data/enums/moves";
|
import { Moves } from "../data/enums/moves";
|
||||||
import { speciesEggMoves } from "../data/egg-moves";
|
import { speciesEggMoves } from "../data/egg-moves";
|
||||||
import { TitlePhase } from "../phases";
|
import { TitlePhase } from "../phases";
|
||||||
|
import { argbFromRgba } from "@material/material-color-utilities";
|
||||||
|
import { OptionSelectItem } from "./abstact-option-select-ui-handler";
|
||||||
|
import { pokemonPrevolutions } from "#app/data/pokemon-evolutions";
|
||||||
|
|
||||||
export type StarterSelectCallback = (starters: Starter[]) => void;
|
export type StarterSelectCallback = (starters: Starter[]) => void;
|
||||||
|
|
||||||
export interface Starter {
|
export interface Starter {
|
||||||
species: PokemonSpecies;
|
species: PokemonSpecies;
|
||||||
dexAttr: bigint;
|
dexAttr: bigint;
|
||||||
|
passive: boolean;
|
||||||
|
variant: integer;
|
||||||
nature: Nature;
|
nature: Nature;
|
||||||
moveset?: StarterMoveset;
|
moveset?: StarterMoveset;
|
||||||
pokerus: boolean;
|
pokerus: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPassiveCandyCount(baseValue: integer): integer {
|
||||||
|
switch (baseValue) {
|
||||||
|
case 1:
|
||||||
|
return 50;
|
||||||
|
case 2:
|
||||||
|
return 45;
|
||||||
|
case 3:
|
||||||
|
return 40;
|
||||||
|
case 4:
|
||||||
|
return 30;
|
||||||
|
case 5:
|
||||||
|
return 25;
|
||||||
|
case 6:
|
||||||
|
return 20;
|
||||||
|
case 7:
|
||||||
|
return 15;
|
||||||
|
default:
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getValueReductionCandyCounts(baseValue: integer): [integer, integer] {
|
||||||
|
switch (baseValue) {
|
||||||
|
case 1:
|
||||||
|
return [ 30, 75];
|
||||||
|
case 2:
|
||||||
|
return [ 25, 60 ];
|
||||||
|
case 3:
|
||||||
|
return [ 20, 50 ];
|
||||||
|
case 4:
|
||||||
|
return [ 15, 40 ];
|
||||||
|
case 5:
|
||||||
|
return [ 12, 35 ];
|
||||||
|
case 6:
|
||||||
|
return [ 10, 30 ];
|
||||||
|
case 7:
|
||||||
|
return [ 8, 20 ];
|
||||||
|
case 8:
|
||||||
|
return [ 5, 15 ];
|
||||||
|
default:
|
||||||
|
return [ 3, 10 ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const gens = [ 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX' ];
|
const gens = [ 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX' ];
|
||||||
|
|
||||||
export default class StarterSelectUiHandler extends MessageUiHandler {
|
export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||||
@ -52,10 +100,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
private pokemonUncaughtText: Phaser.GameObjects.Text;
|
private pokemonUncaughtText: Phaser.GameObjects.Text;
|
||||||
private pokemonAbilityLabelText: Phaser.GameObjects.Text;
|
private pokemonAbilityLabelText: Phaser.GameObjects.Text;
|
||||||
private pokemonAbilityText: Phaser.GameObjects.Text;
|
private pokemonAbilityText: Phaser.GameObjects.Text;
|
||||||
|
private pokemonPassiveLabelText: Phaser.GameObjects.Text;
|
||||||
|
private pokemonPassiveText: Phaser.GameObjects.Text;
|
||||||
private pokemonNatureLabelText: Phaser.GameObjects.Text;
|
private pokemonNatureLabelText: Phaser.GameObjects.Text;
|
||||||
private pokemonNatureText: BBCodeText;
|
private pokemonNatureText: BBCodeText;
|
||||||
private pokemonCaughtCountLabelText: Phaser.GameObjects.Text;
|
|
||||||
private pokemonCaughtCountText: Phaser.GameObjects.Text;
|
|
||||||
private pokemonMovesContainer: Phaser.GameObjects.Container;
|
private pokemonMovesContainer: Phaser.GameObjects.Container;
|
||||||
private pokemonMoveContainers: Phaser.GameObjects.Container[];
|
private pokemonMoveContainers: Phaser.GameObjects.Container[];
|
||||||
private pokemonMoveBgs: Phaser.GameObjects.NineSlice[];
|
private pokemonMoveBgs: Phaser.GameObjects.NineSlice[];
|
||||||
@ -65,6 +113,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
private pokemonEggMoveContainers: Phaser.GameObjects.Container[];
|
private pokemonEggMoveContainers: Phaser.GameObjects.Container[];
|
||||||
private pokemonEggMoveBgs: Phaser.GameObjects.NineSlice[];
|
private pokemonEggMoveBgs: Phaser.GameObjects.NineSlice[];
|
||||||
private pokemonEggMoveLabels: Phaser.GameObjects.Text[];
|
private pokemonEggMoveLabels: Phaser.GameObjects.Text[];
|
||||||
|
private pokemonCandyIcon: Phaser.GameObjects.Sprite;
|
||||||
|
private pokemonCandyOverlayIcon: Phaser.GameObjects.Sprite;
|
||||||
|
private pokemonCandyCountText: Phaser.GameObjects.Text;
|
||||||
|
private pokemonCaughtHatchedContainer: Phaser.GameObjects.Container;
|
||||||
|
private pokemonCaughtCountText: Phaser.GameObjects.Text;
|
||||||
|
private pokemonHatchedCountText: Phaser.GameObjects.Text;
|
||||||
private genOptionsText: Phaser.GameObjects.Text;
|
private genOptionsText: Phaser.GameObjects.Text;
|
||||||
private instructionsText: Phaser.GameObjects.Text;
|
private instructionsText: Phaser.GameObjects.Text;
|
||||||
private starterSelectMessageBox: Phaser.GameObjects.NineSlice;
|
private starterSelectMessageBox: Phaser.GameObjects.NineSlice;
|
||||||
@ -109,6 +163,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
private startCursorObj: Phaser.GameObjects.NineSlice;
|
private startCursorObj: Phaser.GameObjects.NineSlice;
|
||||||
private starterValueLabels: Phaser.GameObjects.Text[];
|
private starterValueLabels: Phaser.GameObjects.Text[];
|
||||||
private shinyIcons: Phaser.GameObjects.Image[];
|
private shinyIcons: Phaser.GameObjects.Image[];
|
||||||
|
private hiddenAbilityIcons: Phaser.GameObjects.Image[];
|
||||||
|
|
||||||
private iconAnimHandler: PokemonIconAnimHandler;
|
private iconAnimHandler: PokemonIconAnimHandler;
|
||||||
|
|
||||||
@ -169,51 +224,41 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonGrowthRateText.setOrigin(0, 0);
|
this.pokemonGrowthRateText.setOrigin(0, 0);
|
||||||
this.starterSelectContainer.add(this.pokemonGrowthRateText);
|
this.starterSelectContainer.add(this.pokemonGrowthRateText);
|
||||||
|
|
||||||
this.type1Icon = this.scene.add.sprite(8, 98, 'types');
|
|
||||||
this.type1Icon.setScale(0.5);
|
|
||||||
this.type1Icon.setOrigin(0, 0);
|
|
||||||
this.starterSelectContainer.add(this.type1Icon);
|
|
||||||
|
|
||||||
this.type2Icon = this.scene.add.sprite(26, 98, 'types');
|
|
||||||
this.type2Icon.setScale(0.5);
|
|
||||||
this.type2Icon.setOrigin(0, 0);
|
|
||||||
this.starterSelectContainer.add(this.type2Icon);
|
|
||||||
|
|
||||||
this.pokemonGenderText = addTextObject(this.scene, 96, 112, '', TextStyle.SUMMARY_ALT);
|
this.pokemonGenderText = addTextObject(this.scene, 96, 112, '', TextStyle.SUMMARY_ALT);
|
||||||
this.pokemonGenderText.setOrigin(0, 0);
|
this.pokemonGenderText.setOrigin(0, 0);
|
||||||
this.starterSelectContainer.add(this.pokemonGenderText);
|
this.starterSelectContainer.add(this.pokemonGenderText);
|
||||||
|
|
||||||
this.pokemonUncaughtText = addTextObject(this.scene, 6, 126, 'Uncaught', TextStyle.SUMMARY_ALT, { fontSize: '56px' });
|
this.pokemonUncaughtText = addTextObject(this.scene, 6, 127, 'Uncaught', TextStyle.SUMMARY_ALT, { fontSize: '56px' });
|
||||||
this.pokemonUncaughtText.setOrigin(0, 0);
|
this.pokemonUncaughtText.setOrigin(0, 0);
|
||||||
this.starterSelectContainer.add(this.pokemonUncaughtText);
|
this.starterSelectContainer.add(this.pokemonUncaughtText);
|
||||||
|
|
||||||
this.pokemonAbilityLabelText = addTextObject(this.scene, 6, 126, 'Ability:', TextStyle.SUMMARY_ALT, { fontSize: '56px' });
|
this.pokemonAbilityLabelText = addTextObject(this.scene, 6, 127, 'Ability:', TextStyle.SUMMARY_ALT, { fontSize: '56px' });
|
||||||
this.pokemonAbilityLabelText.setOrigin(0, 0);
|
this.pokemonAbilityLabelText.setOrigin(0, 0);
|
||||||
this.pokemonAbilityLabelText.setVisible(false);
|
this.pokemonAbilityLabelText.setVisible(false);
|
||||||
this.starterSelectContainer.add(this.pokemonAbilityLabelText);
|
this.starterSelectContainer.add(this.pokemonAbilityLabelText);
|
||||||
|
|
||||||
this.pokemonAbilityText = addTextObject(this.scene, 30, 126, '', TextStyle.SUMMARY_ALT, { fontSize: '56px' });
|
this.pokemonAbilityText = addTextObject(this.scene, 31, 127, '', TextStyle.SUMMARY_ALT, { fontSize: '56px' });
|
||||||
this.pokemonAbilityText.setOrigin(0, 0);
|
this.pokemonAbilityText.setOrigin(0, 0);
|
||||||
this.starterSelectContainer.add(this.pokemonAbilityText);
|
this.starterSelectContainer.add(this.pokemonAbilityText);
|
||||||
|
|
||||||
this.pokemonNatureLabelText = addTextObject(this.scene, 6, 135, 'Nature:', TextStyle.SUMMARY_ALT, { fontSize: '56px' });
|
this.pokemonPassiveLabelText = addTextObject(this.scene, 6, 136, 'Passive:', TextStyle.SUMMARY_ALT, { fontSize: '56px' });
|
||||||
|
this.pokemonPassiveLabelText.setOrigin(0, 0);
|
||||||
|
this.pokemonPassiveLabelText.setVisible(false);
|
||||||
|
this.starterSelectContainer.add(this.pokemonPassiveLabelText);
|
||||||
|
|
||||||
|
this.pokemonPassiveText = addTextObject(this.scene, 31, 136, '', TextStyle.SUMMARY_ALT, { fontSize: '56px' });
|
||||||
|
this.pokemonPassiveText.setOrigin(0, 0);
|
||||||
|
this.starterSelectContainer.add(this.pokemonPassiveText);
|
||||||
|
|
||||||
|
this.pokemonNatureLabelText = addTextObject(this.scene, 6, 145, 'Nature:', TextStyle.SUMMARY_ALT, { fontSize: '56px' });
|
||||||
this.pokemonNatureLabelText.setOrigin(0, 0);
|
this.pokemonNatureLabelText.setOrigin(0, 0);
|
||||||
this.pokemonNatureLabelText.setVisible(false);
|
this.pokemonNatureLabelText.setVisible(false);
|
||||||
this.starterSelectContainer.add(this.pokemonNatureLabelText);
|
this.starterSelectContainer.add(this.pokemonNatureLabelText);
|
||||||
|
|
||||||
this.pokemonNatureText = addBBCodeTextObject(this.scene, 30, 135, '', TextStyle.SUMMARY_ALT, { fontSize: '56px' });
|
this.pokemonNatureText = addBBCodeTextObject(this.scene, 31, 145, '', TextStyle.SUMMARY_ALT, { fontSize: '56px' });
|
||||||
this.pokemonNatureText.setOrigin(0, 0);
|
this.pokemonNatureText.setOrigin(0, 0);
|
||||||
this.starterSelectContainer.add(this.pokemonNatureText);
|
this.starterSelectContainer.add(this.pokemonNatureText);
|
||||||
|
|
||||||
this.pokemonCaughtCountLabelText = addTextObject(this.scene, 6, 144, 'Caught/Hatched:', TextStyle.SUMMARY_ALT, { fontSize: '56px' });
|
|
||||||
this.pokemonCaughtCountLabelText.setOrigin(0, 0);
|
|
||||||
this.pokemonCaughtCountLabelText.setVisible(false);
|
|
||||||
this.starterSelectContainer.add(this.pokemonCaughtCountLabelText);
|
|
||||||
|
|
||||||
this.pokemonCaughtCountText = addTextObject(this.scene, 58, 144, '0/0 (0)', TextStyle.SUMMARY_ALT, { fontSize: '56px' });
|
|
||||||
this.pokemonCaughtCountText.setOrigin(0, 0);
|
|
||||||
this.starterSelectContainer.add(this.pokemonCaughtCountText);
|
|
||||||
|
|
||||||
this.pokemonMoveContainers = [];
|
this.pokemonMoveContainers = [];
|
||||||
this.pokemonMoveBgs = [];
|
this.pokemonMoveBgs = [];
|
||||||
this.pokemonMoveLabels = [];
|
this.pokemonMoveLabels = [];
|
||||||
@ -338,9 +383,66 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.hiddenAbilityIcons = new Array(81).fill(null).map((_, i) => {
|
||||||
|
const x = (i % 9) * 18;
|
||||||
|
const y = Math.floor(i / 9) * 18;
|
||||||
|
const ret = this.scene.add.image(x + 163, y + 16, 'ha_capsule');
|
||||||
|
ret.setOrigin(0, 0);
|
||||||
|
ret.setScale(0.5);
|
||||||
|
ret.setVisible(false);
|
||||||
|
this.starterSelectContainer.add(ret);
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
|
||||||
this.pokemonSprite = this.scene.add.sprite(53, 63, `pkmn__sub`);
|
this.pokemonSprite = this.scene.add.sprite(53, 63, `pkmn__sub`);
|
||||||
this.starterSelectContainer.add(this.pokemonSprite);
|
this.starterSelectContainer.add(this.pokemonSprite);
|
||||||
|
|
||||||
|
this.type1Icon = this.scene.add.sprite(8, 98, 'types');
|
||||||
|
this.type1Icon.setScale(0.5);
|
||||||
|
this.type1Icon.setOrigin(0, 0);
|
||||||
|
this.starterSelectContainer.add(this.type1Icon);
|
||||||
|
|
||||||
|
this.type2Icon = this.scene.add.sprite(26, 98, 'types');
|
||||||
|
this.type2Icon.setScale(0.5);
|
||||||
|
this.type2Icon.setOrigin(0, 0);
|
||||||
|
this.starterSelectContainer.add(this.type2Icon);
|
||||||
|
|
||||||
|
this.pokemonCandyIcon = this.scene.add.sprite(1, 12, 'items', 'candy');
|
||||||
|
this.pokemonCandyIcon.setScale(0.5);
|
||||||
|
this.pokemonCandyIcon.setOrigin(0, 0);
|
||||||
|
this.starterSelectContainer.add(this.pokemonCandyIcon);
|
||||||
|
|
||||||
|
this.pokemonCandyOverlayIcon = this.scene.add.sprite(1, 12, 'items', 'candy_overlay');
|
||||||
|
this.pokemonCandyOverlayIcon.setScale(0.5);
|
||||||
|
this.pokemonCandyOverlayIcon.setOrigin(0, 0);
|
||||||
|
this.starterSelectContainer.add(this.pokemonCandyOverlayIcon);
|
||||||
|
|
||||||
|
this.pokemonCandyCountText = addTextObject(this.scene, 14, 18, 'x0', TextStyle.WINDOW_ALT, { fontSize: '56px' });
|
||||||
|
this.pokemonCandyCountText.setOrigin(0, 0);
|
||||||
|
this.starterSelectContainer.add(this.pokemonCandyCountText);
|
||||||
|
|
||||||
|
this.pokemonCaughtHatchedContainer = this.scene.add.container(2, 25);
|
||||||
|
this.pokemonCaughtHatchedContainer.setScale(0.5);
|
||||||
|
this.starterSelectContainer.add(this.pokemonCaughtHatchedContainer);
|
||||||
|
|
||||||
|
const pokemonCaughtIcon = this.scene.add.sprite(1, 0, 'items', 'pb');
|
||||||
|
pokemonCaughtIcon.setOrigin(0, 0);
|
||||||
|
pokemonCaughtIcon.setScale(0.75);
|
||||||
|
this.pokemonCaughtHatchedContainer.add(pokemonCaughtIcon);
|
||||||
|
|
||||||
|
this.pokemonCaughtCountText = addTextObject(this.scene, 24, 4, '0', TextStyle.SUMMARY_ALT);
|
||||||
|
this.pokemonCaughtCountText.setOrigin(0, 0);
|
||||||
|
this.pokemonCaughtHatchedContainer.add(this.pokemonCaughtCountText);
|
||||||
|
|
||||||
|
const pokemonHatchedIcon = this.scene.add.sprite(1, 14, 'items', 'mystery_egg');
|
||||||
|
pokemonHatchedIcon.setOrigin(0, 0);
|
||||||
|
pokemonHatchedIcon.setScale(0.75);
|
||||||
|
this.pokemonCaughtHatchedContainer.add(pokemonHatchedIcon);
|
||||||
|
|
||||||
|
this.pokemonHatchedCountText = addTextObject(this.scene, 24, 19, '0', TextStyle.SUMMARY_ALT);
|
||||||
|
this.pokemonHatchedCountText.setOrigin(0, 0);
|
||||||
|
this.pokemonCaughtHatchedContainer.add(this.pokemonHatchedCountText);
|
||||||
|
|
||||||
this.pokemonMovesContainer = this.scene.add.container(102, 16);
|
this.pokemonMovesContainer = this.scene.add.container(102, 16);
|
||||||
this.pokemonMovesContainer.setScale(0.5);
|
this.pokemonMovesContainer.setScale(0.5);
|
||||||
|
|
||||||
@ -373,7 +475,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonEggMovesContainer = this.scene.add.container(102, 85);
|
this.pokemonEggMovesContainer = this.scene.add.container(102, 85);
|
||||||
this.pokemonEggMovesContainer.setScale(0.375);
|
this.pokemonEggMovesContainer.setScale(0.375);
|
||||||
|
|
||||||
const eggMovesLabel = addTextObject(this.scene, -46, 0, 'Egg Moves', TextStyle.SUMMARY_ALT);
|
const eggMovesLabel = addTextObject(this.scene, -46, 0, 'Egg Moves', TextStyle.WINDOW_ALT);
|
||||||
eggMovesLabel.setOrigin(0.5, 0);
|
eggMovesLabel.setOrigin(0.5, 0);
|
||||||
|
|
||||||
this.pokemonEggMovesContainer.add(eggMovesLabel);
|
this.pokemonEggMovesContainer.add(eggMovesLabel);
|
||||||
@ -622,6 +724,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
ui.playSelect();
|
ui.playSelect();
|
||||||
} else
|
} else
|
||||||
ui.playError();
|
ui.playError();
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
overrideSound: true
|
overrideSound: true
|
||||||
},
|
},
|
||||||
@ -630,6 +733,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
handler: () => {
|
handler: () => {
|
||||||
this.toggleStatsMode();
|
this.toggleStatsMode();
|
||||||
ui.setMode(Mode.STARTER_SELECT);
|
ui.setMode(Mode.STARTER_SELECT);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@ -639,7 +743,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
ui.showText('Select a move to swap out.', null, () => {
|
ui.showText('Select a move to swap out.', null, () => {
|
||||||
ui.setModeWithoutClear(Mode.OPTION_SELECT, {
|
ui.setModeWithoutClear(Mode.OPTION_SELECT, {
|
||||||
options: moveset.map((m: Moves, i: number) => {
|
options: moveset.map((m: Moves, i: number) => {
|
||||||
return {
|
const option: OptionSelectItem = {
|
||||||
label: allMoves[m].name,
|
label: allMoves[m].name,
|
||||||
handler: () => {
|
handler: () => {
|
||||||
ui.setMode(Mode.STARTER_SELECT).then(() => {
|
ui.setMode(Mode.STARTER_SELECT).then(() => {
|
||||||
@ -647,29 +751,37 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
ui.setModeWithoutClear(Mode.OPTION_SELECT, {
|
ui.setModeWithoutClear(Mode.OPTION_SELECT, {
|
||||||
options: this.speciesStarterMoves.filter((sm: Moves) => sm !== m).map(sm => {
|
options: this.speciesStarterMoves.filter((sm: Moves) => sm !== m).map(sm => {
|
||||||
// make an option for each available starter move
|
// make an option for each available starter move
|
||||||
return {
|
const option = {
|
||||||
label: allMoves[sm].name,
|
label: allMoves[sm].name,
|
||||||
handler: () => {
|
handler: () => {
|
||||||
this.switchMoveHandler(i, sm, m)
|
this.switchMoveHandler(i, sm, m)
|
||||||
showSwapOptions(this.starterMoveset);
|
showSwapOptions(this.starterMoveset);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
return option;
|
||||||
}).concat({
|
}).concat({
|
||||||
label: 'Cancel',
|
label: 'Cancel',
|
||||||
handler: () => showSwapOptions(this.starterMoveset)
|
handler: () => {
|
||||||
|
showSwapOptions(this.starterMoveset);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
maxOptions: 8,
|
maxOptions: 8,
|
||||||
yOffset: 19
|
yOffset: 19
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
return option;
|
||||||
}).concat({
|
}).concat({
|
||||||
label: 'Cancel',
|
label: 'Cancel',
|
||||||
handler: () => {
|
handler: () => {
|
||||||
this.clearText();
|
this.clearText();
|
||||||
ui.setMode(Mode.STARTER_SELECT);
|
ui.setMode(Mode.STARTER_SELECT);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
maxOptions: 8,
|
maxOptions: 8,
|
||||||
@ -682,6 +794,105 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
label: 'Manage Moves',
|
label: 'Manage Moves',
|
||||||
handler: () => {
|
handler: () => {
|
||||||
showSwapOptions(this.starterMoveset);
|
showSwapOptions(this.starterMoveset);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const starterData = this.scene.gameData.starterData[this.lastSpecies.speciesId];
|
||||||
|
const candyCount = starterData.candyCount;
|
||||||
|
const passiveAttr = starterData.passiveAttr;
|
||||||
|
if (passiveAttr & PassiveAttr.UNLOCKED) {
|
||||||
|
if (!(passiveAttr & PassiveAttr.ENABLED)) {
|
||||||
|
options.push({
|
||||||
|
label: 'Enable Passive',
|
||||||
|
handler: () => {
|
||||||
|
starterData.passiveAttr |= PassiveAttr.ENABLED;
|
||||||
|
ui.setMode(Mode.STARTER_SELECT);
|
||||||
|
this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, undefined, undefined);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
options.push({
|
||||||
|
label: 'Disable Passive',
|
||||||
|
handler: () => {
|
||||||
|
starterData.passiveAttr ^= PassiveAttr.ENABLED;
|
||||||
|
ui.setMode(Mode.STARTER_SELECT);
|
||||||
|
this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, undefined, undefined);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const showUseCandies = () => {
|
||||||
|
const options = [];
|
||||||
|
if (!(passiveAttr & PassiveAttr.UNLOCKED)) {
|
||||||
|
const passiveCost = getPassiveCandyCount(speciesStarters[this.lastSpecies.speciesId]);
|
||||||
|
options.push({
|
||||||
|
label: `x${passiveCost} Unlock Passive (${allAbilities[starterPassiveAbilities[this.lastSpecies.speciesId]].name})`,
|
||||||
|
handler: () => {
|
||||||
|
if (candyCount >= passiveCost) {
|
||||||
|
starterData.passiveAttr |= PassiveAttr.UNLOCKED | PassiveAttr.ENABLED;
|
||||||
|
starterData.candyCount -= passiveCost;
|
||||||
|
this.pokemonCandyCountText.setText(`x${starterData.candyCount}`);
|
||||||
|
this.scene.gameData.saveSystem().then(success => {
|
||||||
|
if (!success)
|
||||||
|
return this.scene.reset(true);
|
||||||
|
});
|
||||||
|
ui.setMode(Mode.STARTER_SELECT);
|
||||||
|
this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, undefined, undefined);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
item: 'candy',
|
||||||
|
itemArgs: starterColors[this.lastSpecies.speciesId]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const valueReduction = starterData.valueReduction;
|
||||||
|
if (valueReduction < 2) {
|
||||||
|
const reductionCost = getValueReductionCandyCounts(speciesStarters[this.lastSpecies.speciesId])[valueReduction];
|
||||||
|
options.push({
|
||||||
|
label: `x${reductionCost} Reduce Cost`,
|
||||||
|
handler: () => {
|
||||||
|
if (candyCount >= reductionCost) {
|
||||||
|
starterData.valueReduction++;
|
||||||
|
starterData.candyCount -= reductionCost;
|
||||||
|
this.pokemonCandyCountText.setText(`x${starterData.candyCount}`);
|
||||||
|
this.scene.gameData.saveSystem().then(success => {
|
||||||
|
if (!success)
|
||||||
|
return this.scene.reset(true);
|
||||||
|
});
|
||||||
|
this.updateStarterValueLabel(this.cursor);
|
||||||
|
this.tryUpdateValue(0);
|
||||||
|
ui.setMode(Mode.STARTER_SELECT);
|
||||||
|
this.scene.playSound('buy');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
item: 'candy',
|
||||||
|
itemArgs: starterColors[this.lastSpecies.speciesId]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
options.push({
|
||||||
|
label: 'Cancel',
|
||||||
|
handler: () => {
|
||||||
|
ui.setMode(Mode.STARTER_SELECT);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ui.setModeWithoutClear(Mode.OPTION_SELECT, {
|
||||||
|
options: options,
|
||||||
|
yOffset: 47
|
||||||
|
});
|
||||||
|
};
|
||||||
|
if (!pokemonPrevolutions.hasOwnProperty(this.lastSpecies.speciesId)) {
|
||||||
|
options.push({
|
||||||
|
label: 'Use Candies',
|
||||||
|
handler: () => {
|
||||||
|
ui.setMode(Mode.STARTER_SELECT).then(() => showUseCandies());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -689,6 +900,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
label: 'Cancel',
|
label: 'Cancel',
|
||||||
handler: () => {
|
handler: () => {
|
||||||
ui.setMode(Mode.STARTER_SELECT);
|
ui.setMode(Mode.STARTER_SELECT);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ui.setModeWithoutClear(Mode.OPTION_SELECT, {
|
ui.setModeWithoutClear(Mode.OPTION_SELECT, {
|
||||||
@ -809,22 +1021,22 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
// species has different forms
|
// species has different forms
|
||||||
if (pokemonFormLevelMoves.hasOwnProperty(speciesId)) {
|
if (pokemonFormLevelMoves.hasOwnProperty(speciesId)) {
|
||||||
// starterMoveData doesn't have base form moves or is using the single form format
|
// starterMoveData doesn't have base form moves or is using the single form format
|
||||||
if (!this.scene.gameData.starterMoveData.hasOwnProperty(speciesId) || Array.isArray(this.scene.gameData.starterMoveData[speciesId]))
|
if (!this.scene.gameData.starterData[speciesId].moveset || Array.isArray(this.scene.gameData.starterData[speciesId].moveset))
|
||||||
this.scene.gameData.starterMoveData[speciesId] = { [props.formIndex]: this.starterMoveset.slice(0) as StarterMoveset };
|
this.scene.gameData.starterData[speciesId].moveset = { [props.formIndex]: this.starterMoveset.slice(0) as StarterMoveset };
|
||||||
const starterMoveData = this.scene.gameData.starterMoveData[speciesId][props.formIndex];
|
const starterMoveData = this.scene.gameData.starterData[speciesId].moveset[props.formIndex];
|
||||||
|
|
||||||
// starterMoveData doesn't have active form moves
|
// starterMoveData doesn't have active form moves
|
||||||
if (!starterMoveData.hasOwnProperty(props.formIndex))
|
if (!starterMoveData.hasOwnProperty(props.formIndex))
|
||||||
this.scene.gameData.starterMoveData[speciesId][props.formIndex] = this.starterMoveset.slice(0) as StarterMoveset;
|
this.scene.gameData.starterData[speciesId].moveset[props.formIndex] = this.starterMoveset.slice(0) as StarterMoveset;
|
||||||
|
|
||||||
// does the species' starter move data have its form's starter moves and has it been updated
|
// does the species' starter move data have its form's starter moves and has it been updated
|
||||||
if (starterMoveData.hasOwnProperty(props.formIndex)) {
|
if (starterMoveData.hasOwnProperty(props.formIndex)) {
|
||||||
// active form move hasn't been updated
|
// active form move hasn't been updated
|
||||||
if (starterMoveData[props.formIndex][existingMoveIndex] !== newMove)
|
if (starterMoveData[props.formIndex][existingMoveIndex] !== newMove)
|
||||||
this.scene.gameData.starterMoveData[speciesId][props.formIndex] = this.starterMoveset.slice(0) as StarterMoveset;
|
this.scene.gameData.starterData[speciesId].moveset[props.formIndex] = this.starterMoveset.slice(0) as StarterMoveset;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
this.scene.gameData.starterMoveData[speciesId] = this.starterMoveset.slice(0) as StarterMoveset;
|
this.scene.gameData.starterData[speciesId].moveset = this.starterMoveset.slice(0) as StarterMoveset;
|
||||||
this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, undefined, undefined, false);
|
this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, undefined, undefined, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -902,31 +1114,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
for (let s = 0; s < 81; s++) {
|
for (let s = 0; s < 81; s++) {
|
||||||
const speciesId = s < genLimit ? this.genSpecies[genCursorWithScroll][s].speciesId : 0 as Species;
|
const speciesId = s < genLimit ? this.genSpecies[genCursorWithScroll][s].speciesId : 0 as Species;
|
||||||
const slotVisible = !!speciesId;
|
const slotVisible = !!speciesId;
|
||||||
if (slotVisible) {
|
if (slotVisible)
|
||||||
const baseStarterValue = speciesStarters[speciesId];
|
this.updateStarterValueLabel(s);
|
||||||
const starterValue = slotVisible ? this.scene.gameData.getSpeciesStarterValue(speciesId) : 0;
|
|
||||||
let valueStr = starterValue.toString();
|
|
||||||
if (valueStr.startsWith('0.'))
|
|
||||||
valueStr = valueStr.slice(1);
|
|
||||||
this.starterValueLabels[s].setText(valueStr);
|
|
||||||
let textStyle: TextStyle;
|
|
||||||
switch (baseStarterValue - starterValue) {
|
|
||||||
case 0:
|
|
||||||
textStyle = TextStyle.WINDOW;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
case 0.5:
|
|
||||||
textStyle = TextStyle.SUMMARY_BLUE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
textStyle = TextStyle.SUMMARY_GOLD;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this.starterValueLabels[s].setColor(this.getTextColor(textStyle));
|
|
||||||
this.starterValueLabels[s].setShadowColor(this.getTextColor(textStyle, true));
|
|
||||||
}
|
|
||||||
this.starterValueLabels[s].setVisible(slotVisible);
|
this.starterValueLabels[s].setVisible(slotVisible);
|
||||||
this.shinyIcons[s].setVisible(slotVisible && !!this.scene.gameData.dexData[speciesId].caughtAttr && !!(this.scene.gameData.dexData[speciesId].caughtAttr & DexAttr.SHINY));
|
this.shinyIcons[s].setVisible(slotVisible && !!this.scene.gameData.dexData[speciesId].caughtAttr && !!(this.scene.gameData.dexData[speciesId].caughtAttr & DexAttr.SHINY));
|
||||||
|
this.hiddenAbilityIcons[s].setVisible(slotVisible && !!this.scene.gameData.dexData[speciesId].caughtAttr && !!(this.scene.gameData.dexData[speciesId].caughtAttr & DexAttr.ABILITY_HIDDEN));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
changed = super.setCursor(cursor);
|
changed = super.setCursor(cursor);
|
||||||
@ -1007,16 +1199,31 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonNameText.setText(species.name);
|
this.pokemonNameText.setText(species.name);
|
||||||
|
|
||||||
if (this.speciesStarterDexEntry?.caughtAttr) {
|
if (this.speciesStarterDexEntry?.caughtAttr) {
|
||||||
|
const colorScheme = starterColors[species.speciesId];
|
||||||
|
|
||||||
this.pokemonGrowthRateText.setText(Utils.toReadableString(GrowthRate[species.growthRate]));
|
this.pokemonGrowthRateText.setText(Utils.toReadableString(GrowthRate[species.growthRate]));
|
||||||
this.pokemonGrowthRateText.setColor(getGrowthRateColor(species.growthRate));
|
this.pokemonGrowthRateText.setColor(getGrowthRateColor(species.growthRate));
|
||||||
this.pokemonGrowthRateText.setShadowColor(getGrowthRateColor(species.growthRate, true));
|
this.pokemonGrowthRateText.setShadowColor(getGrowthRateColor(species.growthRate, true));
|
||||||
this.pokemonGrowthRateLabelText.setVisible(true);
|
this.pokemonGrowthRateLabelText.setVisible(true);
|
||||||
this.pokemonUncaughtText.setVisible(false);
|
this.pokemonUncaughtText.setVisible(false);
|
||||||
this.pokemonAbilityLabelText.setVisible(true);
|
this.pokemonAbilityLabelText.setVisible(true);
|
||||||
|
this.pokemonPassiveLabelText.setVisible(true);
|
||||||
this.pokemonNatureLabelText.setVisible(true);
|
this.pokemonNatureLabelText.setVisible(true);
|
||||||
this.pokemonCaughtCountLabelText.setVisible(true);
|
this.pokemonCaughtCountText.setText(`${this.speciesStarterDexEntry.caughtCount}`);
|
||||||
this.pokemonCaughtCountText.setText(`${this.speciesStarterDexEntry.caughtCount}/${this.speciesStarterDexEntry.hatchedCount} (${this.speciesStarterDexEntry.caughtCount + this.speciesStarterDexEntry.hatchedCount})`);
|
this.pokemonHatchedCountText.setText(`${this.speciesStarterDexEntry.hatchedCount}`);
|
||||||
this.pokemonCaughtCountText.setVisible(true);
|
this.pokemonCaughtHatchedContainer.setVisible(true);
|
||||||
|
if (pokemonPrevolutions.hasOwnProperty(species.speciesId)) {
|
||||||
|
this.pokemonCaughtHatchedContainer.setY(16);
|
||||||
|
[ this.pokemonCandyIcon, this.pokemonCandyOverlayIcon, this.pokemonCandyCountText ].map(c => c.setVisible(false));
|
||||||
|
} else {
|
||||||
|
this.pokemonCaughtHatchedContainer.setY(25);
|
||||||
|
this.pokemonCandyIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(colorScheme[0])));
|
||||||
|
this.pokemonCandyIcon.setVisible(true);
|
||||||
|
this.pokemonCandyOverlayIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(colorScheme[1])));
|
||||||
|
this.pokemonCandyOverlayIcon.setVisible(true);
|
||||||
|
this.pokemonCandyCountText.setText(`x${this.scene.gameData.starterData[species.speciesId].candyCount}`);
|
||||||
|
this.pokemonCandyCountText.setVisible(true);
|
||||||
|
}
|
||||||
this.iconAnimHandler.addOrUpdate(this.starterSelectGenIconContainers[species.generation - 1].getAt(this.genSpecies[species.generation - 1].indexOf(species)) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.PASSIVE);
|
this.iconAnimHandler.addOrUpdate(this.starterSelectGenIconContainers[species.generation - 1].getAt(this.genSpecies[species.generation - 1].indexOf(species)) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.PASSIVE);
|
||||||
|
|
||||||
let starterIndex = -1;
|
let starterIndex = -1;
|
||||||
@ -1056,9 +1263,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.type2Icon.setVisible(false);
|
this.type2Icon.setVisible(false);
|
||||||
this.pokemonUncaughtText.setVisible(true);
|
this.pokemonUncaughtText.setVisible(true);
|
||||||
this.pokemonAbilityLabelText.setVisible(false);
|
this.pokemonAbilityLabelText.setVisible(false);
|
||||||
|
this.pokemonPassiveLabelText.setVisible(false);
|
||||||
this.pokemonNatureLabelText.setVisible(false);
|
this.pokemonNatureLabelText.setVisible(false);
|
||||||
this.pokemonCaughtCountLabelText.setVisible(false);
|
this.pokemonCaughtHatchedContainer.setVisible(false);
|
||||||
this.pokemonCaughtCountText.setVisible(false);
|
this.pokemonCandyIcon.setVisible(false);
|
||||||
|
this.pokemonCandyOverlayIcon.setVisible(false);
|
||||||
|
this.pokemonCandyCountText.setVisible(false);
|
||||||
|
|
||||||
const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species, true);
|
const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species, true);
|
||||||
const defaultNature = this.scene.gameData.getSpeciesDefaultNature(species);
|
const defaultNature = this.scene.gameData.getSpeciesDefaultNature(species);
|
||||||
@ -1076,9 +1286,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.type2Icon.setVisible(false);
|
this.type2Icon.setVisible(false);
|
||||||
this.pokemonUncaughtText.setVisible(!!species);
|
this.pokemonUncaughtText.setVisible(!!species);
|
||||||
this.pokemonAbilityLabelText.setVisible(false);
|
this.pokemonAbilityLabelText.setVisible(false);
|
||||||
|
this.pokemonPassiveLabelText.setVisible(false);
|
||||||
this.pokemonNatureLabelText.setVisible(false);
|
this.pokemonNatureLabelText.setVisible(false);
|
||||||
this.pokemonCaughtCountLabelText.setVisible(false);
|
this.pokemonCaughtHatchedContainer.setVisible(false);
|
||||||
this.pokemonCaughtCountText.setVisible(false);
|
this.pokemonCandyIcon.setVisible(false);
|
||||||
|
this.pokemonCandyOverlayIcon.setVisible(false);
|
||||||
|
this.pokemonCandyCountText.setVisible(false);
|
||||||
|
|
||||||
this.setSpeciesDetails(species, false, 0, false, 0, 0);
|
this.setSpeciesDetails(species, false, 0, false, 0, 0);
|
||||||
this.pokemonSprite.clearTint();
|
this.pokemonSprite.clearTint();
|
||||||
@ -1185,6 +1398,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonAbilityText.setColor(this.getTextColor(!isHidden ? TextStyle.SUMMARY_ALT : TextStyle.SUMMARY_GOLD));
|
this.pokemonAbilityText.setColor(this.getTextColor(!isHidden ? TextStyle.SUMMARY_ALT : TextStyle.SUMMARY_GOLD));
|
||||||
this.pokemonAbilityText.setShadowColor(this.getTextColor(!isHidden ? TextStyle.SUMMARY_ALT : TextStyle.SUMMARY_GOLD, true));
|
this.pokemonAbilityText.setShadowColor(this.getTextColor(!isHidden ? TextStyle.SUMMARY_ALT : TextStyle.SUMMARY_GOLD, true));
|
||||||
|
|
||||||
|
const passiveAttr = this.scene.gameData.starterData[species.speciesId].passiveAttr;
|
||||||
|
this.pokemonPassiveText.setText(passiveAttr & PassiveAttr.UNLOCKED ? passiveAttr & PassiveAttr.ENABLED ? allAbilities[starterPassiveAbilities[this.lastSpecies.speciesId]].name : 'Disabled' : 'Locked');
|
||||||
|
this.pokemonPassiveText.setColor(this.getTextColor(passiveAttr === (PassiveAttr.UNLOCKED | PassiveAttr.ENABLED) ? TextStyle.SUMMARY_ALT : TextStyle.SUMMARY_GRAY));
|
||||||
|
this.pokemonPassiveText.setShadowColor(this.getTextColor(passiveAttr === (PassiveAttr.UNLOCKED | PassiveAttr.ENABLED) ? TextStyle.SUMMARY_ALT : TextStyle.SUMMARY_GRAY, true));
|
||||||
|
|
||||||
this.pokemonNatureText.setText(getNatureName(natureIndex as unknown as Nature, true, true, false, this.scene.uiTheme));
|
this.pokemonNatureText.setText(getNatureName(natureIndex as unknown as Nature, true, true, false, this.scene.uiTheme));
|
||||||
|
|
||||||
let levelMoves: LevelMoves;
|
let levelMoves: LevelMoves;
|
||||||
@ -1195,18 +1413,18 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.speciesStarterMoves.push(...levelMoves.filter(lm => lm[0] <= 5).map(lm => lm[1]));
|
this.speciesStarterMoves.push(...levelMoves.filter(lm => lm[0] <= 5).map(lm => lm[1]));
|
||||||
if (speciesEggMoves.hasOwnProperty(species.speciesId)) {
|
if (speciesEggMoves.hasOwnProperty(species.speciesId)) {
|
||||||
for (let em = 0; em < 4; em++) {
|
for (let em = 0; em < 4; em++) {
|
||||||
if (this.scene.gameData.starterEggMoveData[species.speciesId] & Math.pow(2, em))
|
if (this.scene.gameData.starterData[species.speciesId].eggMoves & Math.pow(2, em))
|
||||||
this.speciesStarterMoves.push(speciesEggMoves[species.speciesId][em]);
|
this.speciesStarterMoves.push(speciesEggMoves[species.speciesId][em]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const speciesMoveData = this.scene.gameData.starterMoveData[species.speciesId];
|
const speciesMoveData = this.scene.gameData.starterData[species.speciesId].moveset;
|
||||||
let moveData: StarterMoveset = speciesMoveData
|
let moveData: StarterMoveset = speciesMoveData
|
||||||
? Array.isArray(speciesMoveData)
|
? Array.isArray(speciesMoveData)
|
||||||
? speciesMoveData as StarterMoveset
|
? speciesMoveData as StarterMoveset
|
||||||
: (speciesMoveData as StarterFormMoveData)[formIndex]
|
: (speciesMoveData as StarterFormMoveData)[formIndex]
|
||||||
: null;
|
: null;
|
||||||
const availableStarterMoves = this.speciesStarterMoves.concat(speciesEggMoves.hasOwnProperty(species.speciesId) ? speciesEggMoves[species.speciesId].filter((_, em: integer) => this.scene.gameData.starterEggMoveData[species.speciesId] & Math.pow(2, em)) : []);
|
const availableStarterMoves = this.speciesStarterMoves.concat(speciesEggMoves.hasOwnProperty(species.speciesId) ? speciesEggMoves[species.speciesId].filter((_, em: integer) => this.scene.gameData.starterData[species.speciesId].eggMoves & Math.pow(2, em)) : []);
|
||||||
this.starterMoveset = (moveData || (this.speciesStarterMoves.slice(0, 4) as StarterMoveset)).filter(m => availableStarterMoves.find(sm => sm === m)) as StarterMoveset;
|
this.starterMoveset = (moveData || (this.speciesStarterMoves.slice(0, 4) as StarterMoveset)).filter(m => availableStarterMoves.find(sm => sm === m)) as StarterMoveset;
|
||||||
// Consolidate move data if it contains an incompatible move
|
// Consolidate move data if it contains an incompatible move
|
||||||
if (this.starterMoveset.length < 4 && this.starterMoveset.length < availableStarterMoves.length)
|
if (this.starterMoveset.length < 4 && this.starterMoveset.length < availableStarterMoves.length)
|
||||||
@ -1216,6 +1434,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.setTypeIcons(speciesForm.type1, speciesForm.type2);
|
this.setTypeIcons(speciesForm.type1, speciesForm.type2);
|
||||||
} else {
|
} else {
|
||||||
this.pokemonAbilityText.setText('');
|
this.pokemonAbilityText.setText('');
|
||||||
|
this.pokemonPassiveText.setText('');
|
||||||
this.pokemonNatureText.setText('');
|
this.pokemonNatureText.setText('');
|
||||||
this.setTypeIcons(null, null);
|
this.setTypeIcons(null, null);
|
||||||
}
|
}
|
||||||
@ -1225,6 +1444,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonNumberText.setShadowColor(this.getTextColor(TextStyle.SUMMARY, true));
|
this.pokemonNumberText.setShadowColor(this.getTextColor(TextStyle.SUMMARY, true));
|
||||||
this.pokemonGenderText.setText('');
|
this.pokemonGenderText.setText('');
|
||||||
this.pokemonAbilityText.setText('');
|
this.pokemonAbilityText.setText('');
|
||||||
|
this.pokemonPassiveText.setText('');
|
||||||
this.pokemonNatureText.setText('');
|
this.pokemonNatureText.setText('');
|
||||||
this.setTypeIcons(null, null);
|
this.setTypeIcons(null, null);
|
||||||
}
|
}
|
||||||
@ -1243,7 +1463,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
|
|
||||||
for (let em = 0; em < 4; em++) {
|
for (let em = 0; em < 4; em++) {
|
||||||
const eggMove = hasEggMoves ? allMoves[speciesEggMoves[species.speciesId][em]] : null;
|
const eggMove = hasEggMoves ? allMoves[speciesEggMoves[species.speciesId][em]] : null;
|
||||||
const eggMoveUnlocked = eggMove && this.scene.gameData.starterEggMoveData.hasOwnProperty(species.speciesId) && this.scene.gameData.starterEggMoveData[species.speciesId] & Math.pow(2, em);
|
const eggMoveUnlocked = eggMove && this.scene.gameData.starterData[species.speciesId].eggMoves & Math.pow(2, em);
|
||||||
this.pokemonEggMoveBgs[em].setFrame(Type[eggMove ? eggMove.type : Type.UNKNOWN].toString().toLowerCase());
|
this.pokemonEggMoveBgs[em].setFrame(Type[eggMove ? eggMove.type : Type.UNKNOWN].toString().toLowerCase());
|
||||||
this.pokemonEggMoveLabels[em].setText(eggMove && eggMoveUnlocked ? eggMove.name : '???');
|
this.pokemonEggMoveLabels[em].setText(eggMove && eggMoveUnlocked ? eggMove.name : '???');
|
||||||
}
|
}
|
||||||
@ -1281,6 +1501,31 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.tryUpdateValue();
|
this.tryUpdateValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateStarterValueLabel(cursor: integer): void {
|
||||||
|
const speciesId = this.genSpecies[this.getGenCursorWithScroll()][cursor].speciesId;
|
||||||
|
const baseStarterValue = speciesStarters[speciesId];
|
||||||
|
const starterValue = this.scene.gameData.getSpeciesStarterValue(speciesId);
|
||||||
|
let valueStr = starterValue.toString();
|
||||||
|
if (valueStr.startsWith('0.'))
|
||||||
|
valueStr = valueStr.slice(1);
|
||||||
|
this.starterValueLabels[cursor].setText(valueStr);
|
||||||
|
let textStyle: TextStyle;
|
||||||
|
switch (baseStarterValue - starterValue) {
|
||||||
|
case 0:
|
||||||
|
textStyle = TextStyle.WINDOW;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case 0.5:
|
||||||
|
textStyle = TextStyle.SUMMARY_BLUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
textStyle = TextStyle.SUMMARY_GOLD;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.starterValueLabels[cursor].setColor(this.getTextColor(textStyle));
|
||||||
|
this.starterValueLabels[cursor].setShadowColor(this.getTextColor(textStyle, true));
|
||||||
|
}
|
||||||
|
|
||||||
tryUpdateValue(add?: integer): boolean {
|
tryUpdateValue(add?: integer): boolean {
|
||||||
const value = this.starterGens.reduce((total: integer, gen: integer, i: integer) => total += this.scene.gameData.getSpeciesStarterValue(this.genSpecies[gen][this.starterCursors[i]].speciesId), 0);
|
const value = this.starterGens.reduce((total: integer, gen: integer, i: integer) => total += this.scene.gameData.getSpeciesStarterValue(this.genSpecies[gen][this.starterCursors[i]].speciesId), 0);
|
||||||
const newValue = value + (add || 0);
|
const newValue = value + (add || 0);
|
||||||
@ -1331,6 +1576,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
return {
|
return {
|
||||||
species: starterSpecies,
|
species: starterSpecies,
|
||||||
dexAttr: thisObj.starterAttr[i],
|
dexAttr: thisObj.starterAttr[i],
|
||||||
|
passive: !(thisObj.scene.gameData.starterData[starterSpecies.speciesId].passiveAttr ^ (PassiveAttr.ENABLED | PassiveAttr.UNLOCKED)),
|
||||||
|
variant: 0,
|
||||||
nature: thisObj.starterNatures[i] as Nature,
|
nature: thisObj.starterNatures[i] as Nature,
|
||||||
moveset: thisObj.starterMovesets[i],
|
moveset: thisObj.starterMovesets[i],
|
||||||
pokerus: !![ 0, 1, 2 ].filter(n => thisObj.pokerusGens[n] === starterSpecies.generation - 1 && thisObj.pokerusCursors[n] === thisObj.genSpecies[starterSpecies.generation - 1].indexOf(starterSpecies)).length
|
pokerus: !![ 0, 1, 2 ].filter(n => thisObj.pokerusGens[n] === starterSpecies.generation - 1 && thisObj.pokerusCursors[n] === thisObj.genSpecies[starterSpecies.generation - 1].indexOf(starterSpecies)).length
|
||||||
|
@ -18,6 +18,7 @@ export enum TextStyle {
|
|||||||
SUMMARY_BLUE,
|
SUMMARY_BLUE,
|
||||||
SUMMARY_PINK,
|
SUMMARY_PINK,
|
||||||
SUMMARY_GOLD,
|
SUMMARY_GOLD,
|
||||||
|
SUMMARY_GRAY,
|
||||||
MONEY,
|
MONEY,
|
||||||
SETTINGS_LABEL,
|
SETTINGS_LABEL,
|
||||||
SETTINGS_SELECTED,
|
SETTINGS_SELECTED,
|
||||||
@ -75,10 +76,14 @@ function getTextStyleOptions(style: TextStyle, uiTheme: UiTheme, extraStyleOptio
|
|||||||
|
|
||||||
switch (style) {
|
switch (style) {
|
||||||
case TextStyle.SUMMARY:
|
case TextStyle.SUMMARY:
|
||||||
|
case TextStyle.SUMMARY_ALT:
|
||||||
|
case TextStyle.SUMMARY_BLUE:
|
||||||
case TextStyle.SUMMARY_RED:
|
case TextStyle.SUMMARY_RED:
|
||||||
case TextStyle.SUMMARY_PINK:
|
case TextStyle.SUMMARY_PINK:
|
||||||
case TextStyle.SUMMARY_GOLD:
|
case TextStyle.SUMMARY_GOLD:
|
||||||
|
case TextStyle.SUMMARY_GRAY:
|
||||||
case TextStyle.WINDOW:
|
case TextStyle.WINDOW:
|
||||||
|
case TextStyle.WINDOW_ALT:
|
||||||
case TextStyle.MESSAGE:
|
case TextStyle.MESSAGE:
|
||||||
case TextStyle.SETTINGS_LABEL:
|
case TextStyle.SETTINGS_LABEL:
|
||||||
case TextStyle.SETTINGS_SELECTED:
|
case TextStyle.SETTINGS_SELECTED:
|
||||||
@ -152,7 +157,9 @@ export function getTextColor(textStyle: TextStyle, shadow?: boolean, uiTheme: Ui
|
|||||||
return !shadow ? '#f89890' : '#984038';
|
return !shadow ? '#f89890' : '#984038';
|
||||||
case TextStyle.SUMMARY_GOLD:
|
case TextStyle.SUMMARY_GOLD:
|
||||||
case TextStyle.MONEY:
|
case TextStyle.MONEY:
|
||||||
return !shadow ? '#e8e8a8' : '#a0a060'
|
return !shadow ? '#e8e8a8' : '#a0a060';
|
||||||
|
case TextStyle.SUMMARY_GRAY:
|
||||||
|
return !shadow ? '#a0a0a0' : '#636363';
|
||||||
case TextStyle.SETTINGS_LABEL:
|
case TextStyle.SETTINGS_LABEL:
|
||||||
return !shadow ? '#f8b050' : '#c07800';
|
return !shadow ? '#f8b050' : '#c07800';
|
||||||
case TextStyle.SETTINGS_SELECTED:
|
case TextStyle.SETTINGS_SELECTED:
|
||||||
|
10
src/utils.ts
@ -311,4 +311,14 @@ export function deltaRgb(rgb1: integer[], rgb2: integer[]): integer {
|
|||||||
const t = (r1 + r2) / 2;
|
const t = (r1 + r2) / 2;
|
||||||
|
|
||||||
return Math.ceil(Math.sqrt(2 * drp2 + 4 * dgp2 + 3 * dbp2 + t * (drp2 - dbp2) / 256));
|
return Math.ceil(Math.sqrt(2 * drp2 + 4 * dgp2 + 3 * dbp2 + t * (drp2 - dbp2) / 256));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function rgbHexToRgba(hex: string) {
|
||||||
|
const color = hex.match(/^([\da-f]{2})([\da-f]{2})([\da-f]{2})$/i);
|
||||||
|
return {
|
||||||
|
r: parseInt(color[1], 16),
|
||||||
|
g: parseInt(color[2], 16),
|
||||||
|
b: parseInt(color[3], 16),
|
||||||
|
a: 255
|
||||||
|
};
|
||||||
}
|
}
|