Add candy system for passives and value reductions

This commit is contained in:
Flashfyre 2024-04-13 18:59:58 -04:00
parent ccf956a63c
commit 824a73ef71
22 changed files with 2497 additions and 1848 deletions

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

File diff suppressed because one or more lines are too long

View File

@ -2,7 +2,7 @@ import Phaser, { Time } from 'phaser';
import UI, { Mode } from './ui/ui';
import { NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, TurnInitPhase, ReturnPhase, LevelCapPhase, ShowTrainerPhase, LoginPhase, MovePhase, TitlePhase, SwitchPhase } from './phases';
import Pokemon, { PlayerPokemon, EnemyPokemon } from './field/pokemon';
import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies, initSpecies } from './data/pokemon-species';
import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies, initSpecies, speciesStarters } from './data/pokemon-species';
import * as Utils from './utils';
import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonHpRestoreModifier, HealingBoosterModifier, PersistentModifier, PokemonHeldItemModifier, ModifierPredicate, DoubleBattleChanceBoosterModifier, FusePokemonModifier, PokemonFormChangeItemModifier, TerastallizeModifier } from './modifier/modifier';
import { PokeballType } from './data/pokeball';
@ -57,6 +57,7 @@ import { initTouchControls } from './touch-controls';
import { UiTheme } from './enums/ui-theme';
import CacheBustedLoaderPlugin from './plugins/cache-busted-loader-plugin';
import { SceneBase } from './scene-base';
import CandyBar from './ui/candy-bar';
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1";
@ -81,6 +82,11 @@ export const startingWave = STARTING_WAVE_OVERRIDE || 1;
const expSpriteKeys: string[] = [];
const repeatInputDelayMillis = 250;
export let starterColors: StarterColors;
interface StarterColors {
[key: string]: [string, string]
}
export enum Button {
UP,
DOWN,
@ -142,6 +148,7 @@ export default class BattleScene extends SceneBase {
public pbTrayEnemy: PokeballTray;
public abilityBar: AbilityBar;
public partyExpBar: PartyExpBar;
public candyBar: CandyBar;
public arenaBg: Phaser.GameObjects.Sprite;
public arenaBgTransition: Phaser.GameObjects.Sprite;
public arenaPlayer: ArenaBase;
@ -359,6 +366,10 @@ export default class BattleScene extends SceneBase {
this.partyExpBar.setup();
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.setOrigin(1, 0);
this.fieldUI.add(this.waveCountText);
@ -440,7 +451,8 @@ export default class BattleScene extends SceneBase {
Promise.all([
Promise.all(loadPokemonAssets),
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(() => {
this.pushPhase(new LoginPhase(this));
this.pushPhase(new TitlePhase(this));
@ -472,12 +484,53 @@ export default class BattleScene extends SceneBase {
this.updateScoreText();
}
initExpSprites(): void {
initExpSprites(): Promise<void> {
return new Promise(resolve => {
if (expSpriteKeys.length)
return;
fetch('./exp_sprites.json').then(res => res.json()).then(keys => {
return resolve();
fetch('./exp-sprites.json').then(res => res.json()).then(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 +1128,7 @@ export default class BattleScene extends SceneBase {
this.scoreText.setY(this.moneyText.y + 10);
const offsetY = (this.scoreText.visible ? this.scoreText : this.moneyText).y + 15;
this.partyExpBar.setY(offsetY);
this.candyBar.setY(offsetY + 15);
this.ui?.achvBar.setY(this.game.canvas.height / 6 + offsetY);
}

View File

@ -64,6 +64,8 @@ function getDailyRunStarter(scene: BattleScene, starterSpeciesForm: PokemonSpeci
const starter: Starter = {
species: starterSpecies,
dexAttr: pokemon.getDexAttr(),
passive: false,
variant: 0,
nature: pokemon.getNature(),
pokerus: pokemon.pokerus
};

View File

@ -11,6 +11,7 @@ import { StarterMoveset } from '../system/game-data';
import { speciesEggMoves } from './egg-moves';
import { PartyMemberStrength } from "./enums/party-member-strength";
import { GameMode } from '../game-mode';
import { QuantizerCelebi, argbFromRgba, rgbaFromArgb } from "@material/material-color-utilities";
export enum Region {
NORMAL,
@ -381,6 +382,55 @@ export abstract class PokemonSpeciesForm {
cry.stop();
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 {
@ -3058,8 +3108,8 @@ export const starterPassiveAbilities = {
[Species.CHARMANDER]: Abilities.INTIMIDATE,
[Species.SQUIRTLE]: Abilities.DAUNTLESS_SHIELD,
[Species.CATERPIE]: Abilities.MAGICIAN,
[Species.WEEDLE]: Abilities.POISON_TOUCH,
[Species.PIDGEY]: Abilities.TECHNICIAN,
[Species.WEEDLE]: Abilities.TECHNICIAN,
[Species.PIDGEY]: Abilities.GALE_WINGS,
[Species.RATTATA]: Abilities.STRONG_JAW,
[Species.SPEAROW]: Abilities.MOXIE,
[Species.EKANS]: Abilities.ROUGH_SKIN,
@ -3070,14 +3120,14 @@ export const starterPassiveAbilities = {
[Species.ZUBAT]: Abilities.WIND_RIDER,
[Species.ODDISH]: Abilities.LINGERING_AROMA,
[Species.PARAS]: Abilities.POISON_HEAL,
[Species.VENONAT]: Abilities.TECHNICIAN,
[Species.VENONAT]: Abilities.SWARM,
[Species.DIGLETT]: Abilities.STURDY,
[Species.MEOWTH]: Abilities.NORMALIZE,
[Species.PSYDUCK]: Abilities.SIMPLE,
[Species.MANKEY]: Abilities.STAMINA,
[Species.GROWLITHE]: Abilities.BALL_FETCH,
[Species.MANKEY]: Abilities.IRON_FIST,
[Species.GROWLITHE]: Abilities.SPEED_BOOST,
[Species.POLIWAG]: Abilities.WATER_BUBBLE,
[Species.ABRA]: Abilities.TECHNICIAN,
[Species.ABRA]: Abilities.OPPORTUNIST,
[Species.MACHOP]: Abilities.IRON_FIST,
[Species.BELLSPROUT]: Abilities.CORROSION,
[Species.TENTACOOL]: Abilities.INNARDS_OUT,
@ -3103,7 +3153,7 @@ export const starterPassiveAbilities = {
[Species.TANGELA]: Abilities.TANGLING_HAIR,
[Species.KANGASKHAN]: Abilities.IRON_FIST,
[Species.HORSEA]: Abilities.DRIZZLE,
[Species.GOLDEEN]: Abilities.VOLT_ABSORB,
[Species.GOLDEEN]: Abilities.MULTISCALE,
[Species.STARYU]: Abilities.REGENERATOR,
[Species.SCYTHER]: Abilities.SPEED_BOOST,
[Species.PINSIR]: Abilities.SAP_SIPPER,
@ -3139,7 +3189,7 @@ export const starterPassiveAbilities = {
[Species.HOPPIP]: Abilities.PRANKSTER,
[Species.AIPOM]: Abilities.SCRAPPY,
[Species.SUNKERN]: Abilities.DROUGHT,
[Species.YANMA]: Abilities.TECHNICIAN,
[Species.YANMA]: Abilities.INFILTRATOR,
[Species.WOOPER]: Abilities.SIMPLE,
[Species.MURKROW]: Abilities.DEFIANT,
[Species.MISDREAVUS]: Abilities.DAZZLING,
@ -3154,7 +3204,7 @@ export const starterPassiveAbilities = {
[Species.HERACROSS]: Abilities.QUICK_FEET,
[Species.SNEASEL]: Abilities.MOXIE,
[Species.TEDDIURSA]: Abilities.GLUTTONY,
[Species.SLUGMA]: Abilities.DESOLATE_LAND,
[Species.SLUGMA]: Abilities.DROUGHT,
[Species.SWINUB]: Abilities.SLUSH_RUSH,
[Species.CORSOLA]: Abilities.STORM_DRAIN,
[Species.REMORAID]: Abilities.SKILL_LINK,
@ -3166,7 +3216,7 @@ export const starterPassiveAbilities = {
[Species.SMEARGLE]: Abilities.TRACE,
[Species.TYROGUE]: Abilities.STAMINA,
[Species.SMOOCHUM]: Abilities.CUTE_CHARM,
[Species.ELEKID]: Abilities.ADAPTABILITY,
[Species.ELEKID]: Abilities.IRON_FIST,
[Species.MAGBY]: Abilities.CONTRARY,
[Species.MILTANK]: Abilities.GLUTTONY,
[Species.RAIKOU]: Abilities.FLARE_BOOST,
@ -3192,7 +3242,7 @@ export const starterPassiveAbilities = {
[Species.SLAKOTH]: Abilities.GUTS,
[Species.NINCADA]: Abilities.OVERCOAT,
[Species.WHISMUR]: Abilities.PUNK_ROCK,
[Species.MAKUHITA]: Abilities.CONTRARY,
[Species.MAKUHITA]: Abilities.STAMINA,
[Species.AZURILL]: Abilities.UNNERVE,
[Species.NOSEPASS]: Abilities.LEVITATE,
[Species.SKITTY]: Abilities.SCRAPPY,
@ -3217,10 +3267,10 @@ export const starterPassiveAbilities = {
[Species.SWABLU]: Abilities.WHITE_SMOKE,
[Species.ZANGOOSE]: Abilities.SUPER_LUCK,
[Species.SEVIPER]: Abilities.MOLD_BREAKER,
[Species.LUNATONE]: Abilities.SHADOW_SHIELD,
[Species.SOLROCK]: Abilities.FULL_METAL_BODY,
[Species.LUNATONE]: Abilities.FAIRY_AURA,
[Species.SOLROCK]: Abilities.DROUGHT,
[Species.BARBOACH]: Abilities.BALL_FETCH,
[Species.CORPHISH]: Abilities.WATER_BUBBLE,
[Species.CORPHISH]: Abilities.TOUGH_CLAWS,
[Species.BALTOY]: Abilities.OWN_TEMPO,
[Species.LILEEP]: Abilities.WATER_ABSORB,
[Species.ANORITH]: Abilities.WATER_ABSORB,
@ -3237,7 +3287,7 @@ export const starterPassiveAbilities = {
[Species.CLAMPERL]: Abilities.SIMPLE,
[Species.RELICANTH]: Abilities.SOLID_ROCK,
[Species.LUVDISC]: Abilities.PICKUP,
[Species.BAGON]: Abilities.GALE_WINGS,
[Species.BAGON]: Abilities.BERSERK,
[Species.BELDUM]: Abilities.IRON_FIST,
[Species.REGIROCK]: Abilities.REGENERATOR,
[Species.REGICE]: Abilities.ICE_SCALES,
@ -3251,7 +3301,7 @@ export const starterPassiveAbilities = {
[Species.DEOXYS]: Abilities.STICKY_HOLD,
[Species.TURTWIG]: Abilities.HARVEST,
[Species.CHIMCHAR]: Abilities.DEFIANT,
[Species.PIPLUP]: Abilities.BATTLE_ARMOR,
[Species.PIPLUP]: Abilities.SLUSH_RUSH,
[Species.STARLY]: Abilities.ROCK_HEAD,
[Species.BIDOOF]: Abilities.NEUROFORCE,
[Species.KRICKETOT]: Abilities.SOUNDPROOF,
@ -3304,7 +3354,7 @@ export const starterPassiveAbilities = {
[Species.VICTINI]: Abilities.SUPER_LUCK,
[Species.SNIVY]: Abilities.MULTISCALE,
[Species.TEPIG]: Abilities.SAND_RUSH,
[Species.OSHAWOTT]: Abilities.LIGHTNING_ROD,
[Species.OSHAWOTT]: Abilities.MOLD_BREAKER,
[Species.PATRAT]: Abilities.STAKEOUT,
[Species.LILLIPUP]: Abilities.BALL_FETCH,
[Species.PURRLOIN]: Abilities.DEFIANT,
@ -3325,8 +3375,8 @@ export const starterPassiveAbilities = {
[Species.SEWADDLE]: Abilities.SHARPNESS,
[Species.VENIPEDE]: Abilities.INTIMIDATE,
[Species.COTTONEE]: Abilities.MISTY_SURGE,
[Species.PETILIL]: Abilities.ORICHALCUM_PULSE,
[Species.BASCULIN]: Abilities.ROCK_HEAD,
[Species.PETILIL]: Abilities.DROUGHT,
[Species.BASCULIN]: Abilities.OPPORTUNIST,
[Species.SANDILE]: Abilities.STRONG_JAW,
[Species.DARUMAKA]: Abilities.IRON_FIST,
[Species.MARACTUS]: Abilities.IRON_BARBS,
@ -3346,14 +3396,14 @@ export const starterPassiveAbilities = {
[Species.DEERLING]: Abilities.JUSTIFIED,
[Species.EMOLGA]: Abilities.WIND_POWER,
[Species.KARRABLAST]: Abilities.NO_GUARD,
[Species.FOONGUS]: Abilities.ADAPTABILITY,
[Species.FOONGUS]: Abilities.MIMICRY,
[Species.FRILLISH]: Abilities.MUMMY,
[Species.ALOMOMOLA]: Abilities.MULTISCALE,
[Species.JOLTIK]: Abilities.VOLT_ABSORB,
[Species.FERROSEED]: Abilities.SKILL_LINK,
[Species.KLINK]: Abilities.STEELWORKER,
[Species.TYNAMO]: Abilities.SWIFT_SWIM,
[Species.ELGYEM]: Abilities.COMMANDER,
[Species.ELGYEM]: Abilities.SHADOW_TAG,
[Species.LITWICK]: Abilities.SOUL_HEART,
[Species.AXEW]: Abilities.SHEER_FORCE,
[Species.CUBCHOO]: Abilities.INTIMIDATE,
@ -3362,7 +3412,7 @@ export const starterPassiveAbilities = {
[Species.STUNFISK]: Abilities.STORM_DRAIN,
[Species.MIENFOO]: Abilities.NO_GUARD,
[Species.DRUDDIGON]: Abilities.INTIMIDATE,
[Species.GOLETT]: Abilities.JUSTIFIED,
[Species.GOLETT]: Abilities.SHADOW_SHIELD,
[Species.PAWNIARD]: Abilities.SHARPNESS,
[Species.BOUFFALANT]: Abilities.THICK_FAT,
[Species.RUFFLET]: Abilities.RECKLESS,
@ -3380,7 +3430,7 @@ export const starterPassiveAbilities = {
[Species.ZEKROM]: Abilities.HADRON_ENGINE,
[Species.LANDORUS]: Abilities.PRANKSTER,
[Species.KYUREM]: Abilities.SNOW_WARNING,
[Species.KELDEO]: Abilities.HUGE_POWER,
[Species.KELDEO]: Abilities.SHARPNESS,
[Species.MELOETTA]: Abilities.PUNK_ROCK,
[Species.GENESECT]: Abilities.MEGA_LAUNCHER,
[Species.CHESPIN]: Abilities.IRON_BARBS,
@ -3425,7 +3475,7 @@ export const starterPassiveAbilities = {
[Species.POPPLIO]: Abilities.PUNK_ROCK,
[Species.PIKIPEK]: Abilities.ANGER_POINT,
[Species.YUNGOOS]: Abilities.HUGE_POWER,
[Species.GRUBBIN]: Abilities.GALVANIZE,
[Species.GRUBBIN]: Abilities.SPEED_BOOST,
[Species.CRABRAWLER]: Abilities.REFRIGERATE,
[Species.ORICORIO]: Abilities.ADAPTABILITY,
[Species.CUTIEFLY]: Abilities.FRIEND_GUARD,
@ -3442,7 +3492,7 @@ export const starterPassiveAbilities = {
[Species.COMFEY]: Abilities.FRIEND_GUARD,
[Species.ORANGURU]: Abilities.HOSPITALITY,
[Species.PASSIMIAN]: Abilities.COSTAR,
[Species.WIMPOD]: Abilities.BATTLE_ARMOR,
[Species.WIMPOD]: Abilities.TINTED_LENS,
[Species.SANDYGAST]: Abilities.DAUNTLESS_SHIELD,
[Species.PYUKUMUKU]: Abilities.IRON_BARBS,
[Species.TYPE_NULL]: Abilities.ADAPTABILITY,
@ -3465,7 +3515,7 @@ export const starterPassiveAbilities = {
[Species.PHEROMOSA]: Abilities.MOXIE,
[Species.XURKITREE]: Abilities.LIGHTNING_ROD,
[Species.CELESTEELA]: Abilities.CHLOROPHYLL,
[Species.KARTANA]: Abilities.INTREPID_SWORD,
[Species.KARTANA]: Abilities.SHARPNESS,
[Species.GUZZLORD]: Abilities.GLUTTONY,
[Species.NECROZMA]: Abilities.BEAST_BOOST,
[Species.MAGEARNA]: Abilities.STEELY_SPIRIT,
@ -3479,7 +3529,7 @@ export const starterPassiveAbilities = {
[Species.SCORBUNNY]: Abilities.RECKLESS,
[Species.SOBBLE]: Abilities.MIMICRY,
[Species.SKWOVET]: Abilities.HONEY_GATHER,
[Species.ROOKIDEE]: Abilities.JUSTIFIED,
[Species.ROOKIDEE]: Abilities.IRON_BARBS,
[Species.BLIPBUG]: Abilities.TINTED_LENS,
[Species.NICKIT]: Abilities.INTIMIDATE,
[Species.GOSSIFLEUR]: Abilities.STORM_DRAIN,
@ -3512,7 +3562,7 @@ export const starterPassiveAbilities = {
[Species.ARCTOVISH]: Abilities.STRONG_JAW,
[Species.DURALUDON]: Abilities.MEGA_LAUNCHER,
[Species.DREEPY]: Abilities.PARENTAL_BOND,
[Species.ZACIAN]: Abilities.SHARPNESS,
[Species.ZACIAN]: Abilities.GUARD_DOG,
[Species.ZAMAZENTA]: Abilities.GUARD_DOG,
[Species.ETERNATUS]: Abilities.SUPREME_OVERLORD,
[Species.KUBFU]: Abilities.IRON_FIST,
@ -3535,7 +3585,7 @@ export const starterPassiveAbilities = {
[Species.SMOLIV]: Abilities.RIPEN,
[Species.SQUAWKABILLY]: Abilities.GALE_WINGS,
[Species.NACLI]: Abilities.EARTH_EATER,
[Species.CHARCADET]: Abilities.CONTRARY,
[Species.CHARCADET]: Abilities.MIRROR_ARMOR,
[Species.TADBULB]: Abilities.TRANSISTOR,
[Species.WATTREL]: Abilities.GALE_WINGS,
[Species.MASCHIFF]: Abilities.STRONG_JAW,
@ -3562,15 +3612,15 @@ export const starterPassiveAbilities = {
[Species.TATSUGIRI]: Abilities.WATER_BUBBLE,
[Species.GREAT_TUSK]: Abilities.INTIMIDATE,
[Species.SCREAM_TAIL]: Abilities.PIXILATE,
[Species.BRUTE_BONNET]: Abilities.ADAPTABILITY,
[Species.BRUTE_BONNET]: Abilities.BEAST_BOOST,
[Species.FLUTTER_MANE]: Abilities.DAZZLING,
[Species.SLITHER_WING]: Abilities.SCRAPPY,
[Species.SLITHER_WING]: Abilities.MOXIE,
[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_HANDS]: Abilities.IRON_FIST,
[Species.IRON_JUGULIS]: Abilities.NO_GUARD,
[Species.IRON_MOTH]: Abilities.TINTED_LENS,
[Species.IRON_MOTH]: Abilities.LEVITATE,
[Species.IRON_THORNS]: Abilities.SAND_STREAM,
[Species.FRIGIBAX]: Abilities.THICK_FAT,
[Species.GIMMIGHOUL]: Abilities.SUPER_LUCK,
@ -3585,7 +3635,7 @@ export const starterPassiveAbilities = {
[Species.WALKING_WAKE]: Abilities.BEAST_BOOST,
[Species.IRON_LEAVES]: Abilities.SHARPNESS,
[Species.POLTCHAGEIST]: Abilities.FLAME_BODY,
[Species.OKIDOGI]: Abilities.STICKY_HOLD,
[Species.OKIDOGI]: Abilities.INTIMIDATE,
[Species.MUNKIDORI]: Abilities.PRANKSTER,
[Species.FEZANDIPITI]: Abilities.DAZZLING,
[Species.OGERPON]: Abilities.DISGUISE,

View File

@ -2,7 +2,7 @@ export function getData() {
const dataStr = localStorage.getItem('data');
if (!dataStr)
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() {

View File

@ -55,7 +55,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
public species: PokemonSpecies;
public formIndex: integer;
public abilityIndex: integer;
public passive: boolean;
public shiny: boolean;
public variant: integer;
public pokeball: PokeballType;
protected battleInfo: BattleInfo;
public level: integer;
@ -127,6 +129,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.hp = dataSource.hp;
this.stats = dataSource.stats;
this.ivs = dataSource.ivs;
this.passive = !!dataSource.passive;
this.variant = dataSource.variant || 0;
this.nature = dataSource.nature || 0 as Nature;
this.natureOverride = dataSource.natureOverride !== undefined ? dataSource.natureOverride : -1;
this.moveset = dataSource.moveset;
@ -727,7 +731,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
canApplyPassive(): boolean {
return this.isBoss();
return this.passive || this.isBoss();
}
canApplyAbility(passive: boolean = false): boolean {
@ -1237,8 +1241,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (this.scene.arena.terrain?.terrainType === TerrainType.MISTY && this.isGrounded() && type === Type.DRAGON)
damage.value = Math.floor(damage.value / 2);
applyMoveAttrs(ModifiedDamageAttr, source, this, move, damage);
const fixedDamage = new Utils.IntegerHolder(0);
applyMoveAttrs(FixedDamageAttr, source, this, move, fixedDamage);
if (!isTypeImmune && fixedDamage.value) {
@ -1247,8 +1249,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
result = HitResult.EFFECTIVE;
}
console.log('damage', damage.value, move.name, power.value, sourceAtk, targetDef);
if (!result) {
if (!typeMultiplier.value)
result = HitResult.NO_EFFECT;
@ -1275,6 +1275,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
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 (this.getHpRatio() === 1)
applyPreDefendAbAttrs(PreDefendFullHpEndureAbAttr, this, source, battlerMove, cancelled, damage);
@ -2156,7 +2160,7 @@ export class PlayerPokemon extends Pokemon {
}
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;
this.moveset = moveset.map(m => new PokemonMove(m));

View File

@ -44,7 +44,7 @@ import { EggHatchPhase } from "./egg-hatch-phase";
import { Egg } from "./data/egg";
import { vouchers } from "./system/voucher";
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 { SpeciesFormChangeActiveTrigger, SpeciesFormChangeManualTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangePreMoveTrigger } from "./data/pokemon-forms";
import { battleSpecDialogue, getCharVariantFromDialogue } from "./data/dialogue";
@ -175,7 +175,10 @@ export class TitlePhase extends Phase {
if (loggedInUser.lastSessionSlot > -1) {
options.push({
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({
@ -188,20 +191,29 @@ export class TitlePhase extends Phase {
this.end();
};
if (this.scene.gameData.unlocks[Unlockables.ENDLESS_MODE]) {
const options = [
const options: OptionSelectItem[] = [
{
label: gameModes[GameModes.CLASSIC].getName(),
handler: () => setModeAndEnd(GameModes.CLASSIC)
handler: () => {
setModeAndEnd(GameModes.CLASSIC);
return true;
}
},
{
label: gameModes[GameModes.ENDLESS].getName(),
handler: () => setModeAndEnd(GameModes.ENDLESS)
handler: () => {
setModeAndEnd(GameModes.ENDLESS);
return true;
}
}
];
if (this.scene.gameData.unlocks[Unlockables.SPLICED_ENDLESS_MODE]) {
options.push({
label: gameModes[GameModes.SPLICED_ENDLESS].getName(),
handler: () => setModeAndEnd(GameModes.SPLICED_ENDLESS)
handler: () => {
setModeAndEnd(GameModes.SPLICED_ENDLESS);
return true;
}
});
}
options.push({
@ -210,6 +222,7 @@ export class TitlePhase extends Phase {
this.scene.clearPhaseQueue();
this.scene.pushPhase(new TitlePhase(this.scene));
super.end();
return true;
}
});
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.end();
}
return true;
}
},
{
label: i18next.t('menu:loadGame'),
handler: () => this.scene.ui.setOverlayMode(Mode.SAVE_SLOT, SaveSlotUiMode.LOAD,
handler: () => {
this.scene.ui.setOverlayMode(Mode.SAVE_SLOT, SaveSlotUiMode.LOAD,
(slotId: integer) => {
if (slotId === -1)
return this.showOptions();
this.loadSaveSlot(slotId);
});
return true;
}
)
},
{
label: i18next.t('menu:dailyRun'),
handler: () => this.initDailyRun(),
handler: () => {
this.initDailyRun();
return true;
},
keepOpen: true
});
const config: OptionSelectConfig = {
@ -377,6 +396,7 @@ export class SelectGenderPhase extends Phase {
this.scene.gameData.gender = PlayerGender.MALE;
this.scene.gameData.saveSetting(Setting.Player_Gender, 0);
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.saveSetting(Setting.Player_Gender, 1);
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 starterPokemon = this.scene.addPlayerPokemon(starter.species, this.scene.gameMode.getStartingLevel(), starterProps.abilityIndex, starterFormIndex, starterGender, starterProps.shiny, starterIvs, starter.nature);
starterPokemon.tryPopulateMoveset(starter.moveset);
if (starter.passive)
starterPokemon.passive = true;
if (starter.variant && starter.dexAttr & DexAttr.SHINY)
starterPokemon.variant = starter.variant;
if (starter.pokerus)
starterPokemon.pokerus = true;
if (this.scene.gameMode.isSplicedOnly)

View File

@ -43,6 +43,11 @@ export enum PlayerGender {
FEMALE
}
export enum Passive {
UNLOCKED = 1,
ENABLED = 2
}
export function getDataTypeKey(dataType: GameDataType, slotId: integer = 0): string {
switch (dataType) {
case GameDataType.SYSTEM:
@ -64,8 +69,7 @@ interface SystemSaveData {
secretId: integer;
gender: PlayerGender;
dexData: DexData;
starterMoveData: StarterMoveData;
starterEggMoveData: StarterEggMoveData;
starterData: StarterData;
gameStats: GameStats;
unlocks: Unlocks;
achvUnlocks: AchvUnlocks;
@ -145,16 +149,25 @@ export interface DexAttrProps {
export type StarterMoveset = [ Moves ] | [ Moves, Moves ] | [ Moves, Moves, Moves ] | [ Moves, Moves, Moves, Moves ];
export interface StarterMoveData {
[key: integer]: StarterMoveset | StarterFormMoveData
}
export interface StarterFormMoveData {
[key: integer]: StarterMoveset
}
export interface StarterEggMoveData {
[key: integer]: integer
export interface StarterMoveData {
[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 {
@ -167,7 +180,12 @@ const systemShortKeys = {
natureAttr: '$na',
seenCount: '$s' ,
caughtCount: '$c',
ivs: '$i'
ivs: '$i',
moveset: '$m',
eggMoves: '$em',
candyCount: '$cc',
passive: '$p',
valueReduction: '$vr'
};
export class GameData {
@ -181,9 +199,7 @@ export class GameData {
public dexData: DexData;
private defaultDexData: DexData;
public starterMoveData: StarterMoveData;
public starterEggMoveData: StarterEggMoveData;
public starterData: StarterData;
public gameStats: GameStats;
@ -200,8 +216,7 @@ export class GameData {
this.loadSettings();
this.trainerId = Utils.randSeedInt(65536);
this.secretId = Utils.randSeedInt(65536);
this.starterMoveData = {};
this.starterEggMoveData = {};
this.starterData = {};
this.gameStats = new GameStats();
this.unlocks = {
[Unlockables.ENDLESS_MODE]: false,
@ -218,7 +233,7 @@ export class GameData {
};
this.eggs = [];
this.initDexData();
this.initEggMoveData();
this.initStarterData();
}
public saveSystem(): Promise<boolean> {
@ -234,8 +249,7 @@ export class GameData {
secretId: this.secretId,
gender: this.gender,
dexData: this.dexData,
starterMoveData: this.starterMoveData,
starterEggMoveData: this.starterEggMoveData,
starterData: this.starterData,
gameStats: this.gameStats,
unlocks: this.unlocks,
achvUnlocks: this.achvUnlocks,
@ -297,17 +311,24 @@ export class GameData {
this.saveSetting(Setting.Player_Gender, systemData.gender === PlayerGender.FEMALE ? 1 : 0);
this.starterMoveData = systemData.starterMoveData || {};
const initStarterData = !systemData.starterData;
this.starterEggMoveData = {};
this.initEggMoveData();
if (initStarterData) {
this.initStarterData();
if (systemData.starterEggMoveData) {
for (let key of Object.keys(systemData.starterEggMoveData)) {
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)
this.gameStats = systemData.gameStats;
@ -348,6 +369,16 @@ export class GameData {
this.consolidateDexData(this.dexData);
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);
} catch (err) {
console.error(err);
@ -388,7 +419,7 @@ export class GameData {
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;
}
@ -906,15 +937,23 @@ export class GameData {
this.dexData = data;
}
private initEggMoveData(): void {
const data: StarterEggMoveData = {};
private initStarterData(): void {
const starterData: StarterData = {};
const starterSpeciesIds = Object.keys(speciesEggMoves).map(k => parseInt(k) as Species);
const starterSpeciesIds = Object.keys(speciesStarters).map(k => parseInt(k) as Species);
for (let speciesId of starterSpeciesIds)
data[speciesId] = 0;
for (let speciesId of starterSpeciesIds) {
starterData[speciesId] = {
moveset: null,
eggMoves: 0,
candyCount: 0,
passiveAttr: 0,
variantAttr: 0,
valueReduction: 0
};
}
this.starterEggMoveData = data;
this.starterData = starterData;
}
setPokemonSeen(pokemon: Pokemon, incrementCount: boolean = true): void {
@ -943,6 +982,10 @@ export class GameData {
pokemon.formIndex = formIndex;
dexEntry.caughtAttr |= dexAttr;
dexEntry.natureAttr |= Math.pow(2, pokemon.nature + 1);
const hasPrevolution = pokemonPrevolutions.hasOwnProperty(species.speciesId);
const newCatch = !caughtAttr;
if (incrementCount) {
if (!fromEgg) {
dexEntry.caughtCount++;
@ -963,10 +1006,10 @@ export class GameData {
if (pokemon.isShiny())
this.gameStats.shinyPokemonHatched++;
}
}
const hasPrevolution = pokemonPrevolutions.hasOwnProperty(species.speciesId);
const newCatch = !caughtAttr;
if (!hasPrevolution)
this.addStarterCandy(species, (1 * (pokemon.isShiny() ? 5 : 1)) * (fromEgg || pokemon.isBoss() ? 2 : 1));
}
const checkPrevolution = () => {
if (hasPrevolution) {
@ -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> {
return new Promise<boolean>(resolve => {
const speciesId = species.speciesId;
@ -992,17 +1040,17 @@ export class GameData {
return;
}
if (!this.starterEggMoveData.hasOwnProperty(speciesId))
this.starterEggMoveData[speciesId] = 0;
if (!this.starterData[speciesId].eggMoves)
this.starterData[speciesId].eggMoves = 0;
const value = Math.pow(2, eggMoveIndex);
if (this.starterEggMoveData[speciesId] & value) {
if (this.starterData[speciesId].eggMoves & value) {
resolve(false);
return;
}
this.starterEggMoveData[speciesId] |= value;
this.starterData[speciesId].eggMoves |= value;
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);
@ -1094,7 +1142,6 @@ export class GameData {
getSpeciesStarterValue(speciesId: Species): number {
const baseValue = speciesStarters[speciesId];
let value = baseValue;
const caughtHatchedCount = this.dexData[speciesId].caughtCount + this.dexData[speciesId].hatchedCount;
const decrementValue = (value: number) => {
if (value > 1)
@ -1104,44 +1151,8 @@ export class GameData {
return value;
}
let thresholdA: integer;
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) {
for (let v = 0; v < this.starterData[speciesId].valueReduction; v++)
value = decrementValue(value);
if (caughtHatchedCount >= thresholdB)
value = decrementValue(value);
}
return value;
}

View File

@ -17,7 +17,9 @@ export default class PokemonData {
public species: Species;
public formIndex: integer;
public abilityIndex: integer;
public passive: boolean;
public shiny: boolean;
public variant: integer;
public pokeball: PokeballType;
public level: integer;
public exp: integer;
@ -53,7 +55,9 @@ export default class PokemonData {
this.species = sourcePokemon ? sourcePokemon.species.speciesId : source.species;
this.formIndex = Math.max(Math.min(source.formIndex, getPokemonSpecies(this.species).forms.length - 1), 0);
this.abilityIndex = source.abilityIndex;
this.passive = source.passive;
this.shiny = source.shiny;
this.variant = source.variant;
this.pokeball = source.pokeball;
this.level = source.level;
this.exp = source.exp;

View File

@ -4,6 +4,7 @@ import { Mode } from "./ui";
import UiHandler from "./ui-handler";
import { addWindow } from "./ui-theme";
import * as Utils from "../utils";
import { argbFromRgba } from "@material/material-color-utilities";
export interface OptionSelectConfig {
xOffset?: number;
@ -16,9 +17,11 @@ export interface OptionSelectConfig {
export interface OptionSelectItem {
label: string;
handler: Function;
handler: () => boolean;
keepOpen?: boolean;
overrideSound?: boolean;
item?: string;
itemArgs?: any[]
}
const scrollUpLabel = '↑';
@ -28,6 +31,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
protected optionSelectContainer: Phaser.GameObjects.Container;
protected optionSelectBg: Phaser.GameObjects.NineSlice;
protected optionSelectText: Phaser.GameObjects.Text;
protected optionSelectIcons: Phaser.GameObjects.Sprite[];
protected config: OptionSelectConfig;
@ -58,6 +62,8 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
this.optionSelectBg.setOrigin(1, 1);
this.optionSelectContainer.add(this.optionSelectBg);
this.optionSelectIcons = [];
this.setCursor(0);
}
@ -66,8 +72,12 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
if (this.optionSelectText)
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.optionSelectContainer.add(this.optionSelectText);
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.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 {
@ -132,10 +167,12 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
return false;
}
const option = this.config.options[this.cursor + (this.scrollCursor - (this.scrollCursor ? 1 : 0))];
option.handler();
if (option.handler()) {
if (!option.keepOpen)
this.clear();
playSound = !option.overrideSound;
} else
ui.playError();
} else {
switch (button) {
case Button.UP:
@ -182,12 +219,12 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
if (optionStartIndex)
options.unshift({
label: scrollUpLabel,
handler: () => { }
handler: () => true
});
if (optionEndIndex < optionsScrollTotal)
options.push({
label: scrollDownLabel,
handler: () => { }
handler: () => true
});
}

123
src/ui/candy-bar.ts Normal file
View 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);
}
}

View File

@ -20,11 +20,17 @@ export default class ConfirmUiHandler extends AbstractOptionSelectUiHandler {
options: [
{
label: 'Yes',
handler: args[0]
handler: () => {
args[0]();
return true;
}
},
{
label: 'No',
handler: args[1]
handler: () => {
args[1]();
return true;
}
}
],
delay: args.length >= 6 && args[5] !== null ? args[5] as integer : 0

View File

@ -5,7 +5,7 @@ import * as Utils from "../utils";
import { addWindow } from "./ui-theme";
import MessageUiHandler from "./message-ui-handler";
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 { updateUserInfo } from "../account";
@ -99,6 +99,7 @@ export default class MenuUiHandler extends MessageUiHandler {
callback(i);
ui.revertMode();
ui.showText(null, 0);
return true;
}
};
}).concat([{
@ -106,6 +107,7 @@ export default class MenuUiHandler extends MessageUiHandler {
handler: () => {
ui.revertMode();
ui.showText(null, 0);
return true;
}
}]),
xOffset: 98
@ -117,7 +119,10 @@ export default class MenuUiHandler extends MessageUiHandler {
if (Utils.isLocal) {
manageDataOptions.push({
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
});
}
@ -137,25 +142,35 @@ export default class MenuUiHandler extends MessageUiHandler {
i => dataSlots.indexOf(i) > -1,
slotId => this.scene.gameData.tryExportData(GameDataType.SESSION, slotId));
});
return true;
},
keepOpen: true
});
if (Utils.isLocal) {
manageDataOptions.push({
label: 'Import Data',
handler: () => this.scene.gameData.importData(GameDataType.SYSTEM),
handler: () => {
this.scene.gameData.importData(GameDataType.SYSTEM);
return true;
},
keepOpen: true
});
}
manageDataOptions.push(
{
label: 'Export Data',
handler: () => this.scene.gameData.tryExportData(GameDataType.SYSTEM),
handler: () => {
this.scene.gameData.tryExportData(GameDataType.SYSTEM);
return true;
},
keepOpen: true
},
{
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
};
const communityOptions = [
const communityOptions: OptionSelectItem[] = [
{
label: 'Wiki',
handler: () => window.open(wikiUrl, '_blank').focus(),
handler: () => {
window.open(wikiUrl, '_blank').focus();
return true;
},
keepOpen: true
},
{
label: 'Discord',
handler: () => window.open(discordUrl, '_blank').focus(),
handler: () => {
window.open(discordUrl, '_blank').focus();
return true;
},
keepOpen: true
},
{
label: 'GitHub',
handler: () => window.open(githubUrl, '_blank').focus(),
handler: () => {
window.open(githubUrl, '_blank').focus();
return true;
},
keepOpen: true
},
{
label: 'Cancel',
handler: () => this.scene.ui.revertMode()
handler: () => {
this.scene.ui.revertMode();
return true;
}
}
];

View File

@ -1,15 +1,14 @@
import BattleScene, { Button } from "../battle-scene";
import PokemonSpecies, { allSpecies, getPokemonSpecies, getPokemonSpeciesForm, speciesStarters } from "../data/pokemon-species";
import BattleScene, { Button, starterColors } from "../battle-scene";
import PokemonSpecies, { allSpecies, getPokemonSpecies, getPokemonSpeciesForm, speciesStarters, starterPassiveAbilities } from "../data/pokemon-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 MessageUiHandler from "./message-ui-handler";
import { Gender, getGenderColor, getGenderSymbol } from "../data/gender";
import { allAbilities } from "../data/ability";
import { GameMode, GameModes, gameModes } from "../game-mode";
import { Unlockables } from "../system/unlockables";
import { GameModes, gameModes } from "../game-mode";
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 PokemonIconAnimHandler, { PokemonIconAnimMode } from "./pokemon-icon-anim-handler";
import { StatsContainer } from "./stats-container";
@ -24,17 +23,65 @@ import { Type } from "../data/type";
import { Moves } from "../data/enums/moves";
import { speciesEggMoves } from "../data/egg-moves";
import { TitlePhase } from "../phases";
import { argbFromRgba } from "@material/material-color-utilities";
import { OptionSelectItem } from "./abstact-option-select-ui-handler";
export type StarterSelectCallback = (starters: Starter[]) => void;
export interface Starter {
species: PokemonSpecies;
dexAttr: bigint;
passive: boolean;
variant: integer;
nature: Nature;
moveset?: StarterMoveset;
pokerus: boolean;
}
function getPassiveCandyCount(baseValue: integer): integer {
switch (baseValue) {
case 1:
return 100;
case 2:
return 75;
case 3:
return 50;
case 4:
return 40
case 5:
return 30;
case 6:
return 20;
case 7:
return 15;
default:
return 10;
}
}
function getValueReductionCandyCounts(baseValue: integer): [integer, integer] {
switch (baseValue) {
case 1:
return [ 50, 150 ];
case 2:
return [ 30, 100 ];
case 3:
return [ 25, 75 ];
case 4:
return [ 20, 60 ];
case 5:
return [ 15, 50 ];
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' ];
export default class StarterSelectUiHandler extends MessageUiHandler {
@ -52,10 +99,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
private pokemonUncaughtText: Phaser.GameObjects.Text;
private pokemonAbilityLabelText: Phaser.GameObjects.Text;
private pokemonAbilityText: Phaser.GameObjects.Text;
private pokemonPassiveLabelText: Phaser.GameObjects.Text;
private pokemonPassiveText: Phaser.GameObjects.Text;
private pokemonNatureLabelText: Phaser.GameObjects.Text;
private pokemonNatureText: BBCodeText;
private pokemonCaughtCountLabelText: Phaser.GameObjects.Text;
private pokemonCaughtCountText: Phaser.GameObjects.Text;
private pokemonMovesContainer: Phaser.GameObjects.Container;
private pokemonMoveContainers: Phaser.GameObjects.Container[];
private pokemonMoveBgs: Phaser.GameObjects.NineSlice[];
@ -65,6 +112,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
private pokemonEggMoveContainers: Phaser.GameObjects.Container[];
private pokemonEggMoveBgs: Phaser.GameObjects.NineSlice[];
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 instructionsText: Phaser.GameObjects.Text;
private starterSelectMessageBox: Phaser.GameObjects.NineSlice;
@ -179,41 +232,77 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
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.pokemonGenderText = addTextObject(this.scene, 96, 112, '', TextStyle.SUMMARY_ALT);
this.pokemonGenderText.setOrigin(0, 0);
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.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.setVisible(false);
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.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.setVisible(false);
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.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.pokemonMoveBgs = [];
this.pokemonMoveLabels = [];
@ -373,7 +462,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonEggMovesContainer = this.scene.add.container(102, 85);
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);
this.pokemonEggMovesContainer.add(eggMovesLabel);
@ -622,6 +711,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
ui.playSelect();
} else
ui.playError();
return true;
},
overrideSound: true
},
@ -630,6 +720,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
handler: () => {
this.toggleStatsMode();
ui.setMode(Mode.STARTER_SELECT);
return true;
}
}
];
@ -639,7 +730,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
ui.showText('Select a move to swap out.', null, () => {
ui.setModeWithoutClear(Mode.OPTION_SELECT, {
options: moveset.map((m: Moves, i: number) => {
return {
const option: OptionSelectItem = {
label: allMoves[m].name,
handler: () => {
ui.setMode(Mode.STARTER_SELECT).then(() => {
@ -647,29 +738,37 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
ui.setModeWithoutClear(Mode.OPTION_SELECT, {
options: this.speciesStarterMoves.filter((sm: Moves) => sm !== m).map(sm => {
// make an option for each available starter move
return {
const option = {
label: allMoves[sm].name,
handler: () => {
this.switchMoveHandler(i, sm, m)
showSwapOptions(this.starterMoveset);
return true;
}
};
return option;
}).concat({
label: 'Cancel',
handler: () => showSwapOptions(this.starterMoveset)
handler: () => {
showSwapOptions(this.starterMoveset);
return true;
}
}),
maxOptions: 8,
yOffset: 19
});
});
});
return true;
}
}
};
return option;
}).concat({
label: 'Cancel',
handler: () => {
this.clearText();
ui.setMode(Mode.STARTER_SELECT);
return true;
}
}),
maxOptions: 8,
@ -682,6 +781,103 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
label: 'Manage Moves',
handler: () => {
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
});
};
options.push({
label: 'Use Candies',
handler: () => {
ui.setMode(Mode.STARTER_SELECT).then(() => showUseCandies());
return true;
}
});
}
@ -689,6 +885,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
label: 'Cancel',
handler: () => {
ui.setMode(Mode.STARTER_SELECT);
return true;
}
});
ui.setModeWithoutClear(Mode.OPTION_SELECT, {
@ -809,22 +1006,22 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
// species has different forms
if (pokemonFormLevelMoves.hasOwnProperty(speciesId)) {
// 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]))
this.scene.gameData.starterMoveData[speciesId] = { [props.formIndex]: this.starterMoveset.slice(0) as StarterMoveset };
const starterMoveData = this.scene.gameData.starterMoveData[speciesId][props.formIndex];
if (!this.scene.gameData.starterData[speciesId].moveset || Array.isArray(this.scene.gameData.starterData[speciesId].moveset))
this.scene.gameData.starterData[speciesId].moveset = { [props.formIndex]: this.starterMoveset.slice(0) as StarterMoveset };
const starterMoveData = this.scene.gameData.starterData[speciesId].moveset[props.formIndex];
// starterMoveData doesn't have active form moves
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
if (starterMoveData.hasOwnProperty(props.formIndex)) {
// active form move hasn't been updated
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
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);
}
@ -902,29 +1099,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
for (let s = 0; s < 81; s++) {
const speciesId = s < genLimit ? this.genSpecies[genCursorWithScroll][s].speciesId : 0 as Species;
const slotVisible = !!speciesId;
if (slotVisible) {
const baseStarterValue = speciesStarters[speciesId];
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));
}
if (slotVisible)
this.updateStarterValueLabel(s);
this.starterValueLabels[s].setVisible(slotVisible);
this.shinyIcons[s].setVisible(slotVisible && !!this.scene.gameData.dexData[speciesId].caughtAttr && !!(this.scene.gameData.dexData[speciesId].caughtAttr & DexAttr.SHINY));
}
@ -1007,16 +1183,25 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonNameText.setText(species.name);
if (this.speciesStarterDexEntry?.caughtAttr) {
const colorScheme = starterColors[species.speciesId];
this.pokemonGrowthRateText.setText(Utils.toReadableString(GrowthRate[species.growthRate]));
this.pokemonGrowthRateText.setColor(getGrowthRateColor(species.growthRate));
this.pokemonGrowthRateText.setShadowColor(getGrowthRateColor(species.growthRate, true));
this.pokemonGrowthRateLabelText.setVisible(true);
this.pokemonUncaughtText.setVisible(false);
this.pokemonAbilityLabelText.setVisible(true);
this.pokemonPassiveLabelText.setVisible(true);
this.pokemonNatureLabelText.setVisible(true);
this.pokemonCaughtCountLabelText.setVisible(true);
this.pokemonCaughtCountText.setText(`${this.speciesStarterDexEntry.caughtCount}/${this.speciesStarterDexEntry.hatchedCount} (${this.speciesStarterDexEntry.caughtCount + this.speciesStarterDexEntry.hatchedCount})`);
this.pokemonCaughtCountText.setVisible(true);
this.pokemonCaughtCountText.setText(`${this.speciesStarterDexEntry.caughtCount}`);
this.pokemonHatchedCountText.setText(`${this.speciesStarterDexEntry.hatchedCount}`);
this.pokemonCaughtHatchedContainer.setVisible(true);
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);
let starterIndex = -1;
@ -1056,9 +1241,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.type2Icon.setVisible(false);
this.pokemonUncaughtText.setVisible(true);
this.pokemonAbilityLabelText.setVisible(false);
this.pokemonPassiveLabelText.setVisible(false);
this.pokemonNatureLabelText.setVisible(false);
this.pokemonCaughtCountLabelText.setVisible(false);
this.pokemonCaughtCountText.setVisible(false);
this.pokemonCaughtHatchedContainer.setVisible(false);
this.pokemonCandyIcon.setVisible(false);
this.pokemonCandyOverlayIcon.setVisible(false);
this.pokemonCandyCountText.setVisible(false);
const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species, true);
const defaultNature = this.scene.gameData.getSpeciesDefaultNature(species);
@ -1076,9 +1264,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.type2Icon.setVisible(false);
this.pokemonUncaughtText.setVisible(!!species);
this.pokemonAbilityLabelText.setVisible(false);
this.pokemonPassiveLabelText.setVisible(false);
this.pokemonNatureLabelText.setVisible(false);
this.pokemonCaughtCountLabelText.setVisible(false);
this.pokemonCaughtCountText.setVisible(false);
this.pokemonCaughtHatchedContainer.setVisible(false);
this.pokemonCandyIcon.setVisible(false);
this.pokemonCandyOverlayIcon.setVisible(false);
this.pokemonCandyCountText.setVisible(false);
this.setSpeciesDetails(species, false, 0, false, 0, 0);
this.pokemonSprite.clearTint();
@ -1185,6 +1376,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
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));
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));
let levelMoves: LevelMoves;
@ -1195,18 +1391,18 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.speciesStarterMoves.push(...levelMoves.filter(lm => lm[0] <= 5).map(lm => lm[1]));
if (speciesEggMoves.hasOwnProperty(species.speciesId)) {
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]);
}
}
const speciesMoveData = this.scene.gameData.starterMoveData[species.speciesId];
const speciesMoveData = this.scene.gameData.starterData[species.speciesId].moveset;
let moveData: StarterMoveset = speciesMoveData
? Array.isArray(speciesMoveData)
? speciesMoveData as StarterMoveset
: (speciesMoveData as StarterFormMoveData)[formIndex]
: 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;
// Consolidate move data if it contains an incompatible move
if (this.starterMoveset.length < 4 && this.starterMoveset.length < availableStarterMoves.length)
@ -1216,6 +1412,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.setTypeIcons(speciesForm.type1, speciesForm.type2);
} else {
this.pokemonAbilityText.setText('');
this.pokemonPassiveText.setText('');
this.pokemonNatureText.setText('');
this.setTypeIcons(null, null);
}
@ -1225,6 +1422,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonNumberText.setShadowColor(this.getTextColor(TextStyle.SUMMARY, true));
this.pokemonGenderText.setText('');
this.pokemonAbilityText.setText('');
this.pokemonPassiveText.setText('');
this.pokemonNatureText.setText('');
this.setTypeIcons(null, null);
}
@ -1243,7 +1441,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
for (let em = 0; em < 4; em++) {
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.pokemonEggMoveLabels[em].setText(eggMove && eggMoveUnlocked ? eggMove.name : '???');
}
@ -1281,6 +1479,31 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.tryUpdateValue();
}
updateStarterValueLabel(cursor: integer): void {
const speciesId = this.genSpecies[this.genCursor][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 {
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);
@ -1331,6 +1554,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
return {
species: starterSpecies,
dexAttr: thisObj.starterAttr[i],
passive: !(thisObj.scene.gameData.starterData[starterSpecies.speciesId].passiveAttr ^ (PassiveAttr.ENABLED | PassiveAttr.UNLOCKED)),
variant: 0,
nature: thisObj.starterNatures[i] as Nature,
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

View File

@ -18,6 +18,7 @@ export enum TextStyle {
SUMMARY_BLUE,
SUMMARY_PINK,
SUMMARY_GOLD,
SUMMARY_GRAY,
MONEY,
SETTINGS_LABEL,
SETTINGS_SELECTED,
@ -75,10 +76,14 @@ function getTextStyleOptions(style: TextStyle, uiTheme: UiTheme, extraStyleOptio
switch (style) {
case TextStyle.SUMMARY:
case TextStyle.SUMMARY_ALT:
case TextStyle.SUMMARY_BLUE:
case TextStyle.SUMMARY_RED:
case TextStyle.SUMMARY_PINK:
case TextStyle.SUMMARY_GOLD:
case TextStyle.SUMMARY_GRAY:
case TextStyle.WINDOW:
case TextStyle.WINDOW_ALT:
case TextStyle.MESSAGE:
case TextStyle.SETTINGS_LABEL:
case TextStyle.SETTINGS_SELECTED:
@ -152,7 +157,9 @@ export function getTextColor(textStyle: TextStyle, shadow?: boolean, uiTheme: Ui
return !shadow ? '#f89890' : '#984038';
case TextStyle.SUMMARY_GOLD:
case TextStyle.MONEY:
return !shadow ? '#e8e8a8' : '#a0a060'
return !shadow ? '#e8e8a8' : '#a0a060';
case TextStyle.SUMMARY_GRAY:
return !shadow ? '#a0a0a0' : '#636363';
case TextStyle.SETTINGS_LABEL:
return !shadow ? '#f8b050' : '#c07800';
case TextStyle.SETTINGS_SELECTED:

View File

@ -312,3 +312,13 @@ export function deltaRgb(rgb1: integer[], rgb2: integer[]): integer {
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
};
}