Add achievement system and UI
Add achievement system and UI; fix counting invalid inputs in UI handlers for input delay
This commit is contained in:
1 parent
ff93e6233f
commit
cbbb8e972b
49 files changed
+4920
-3764
No files matched your search
+22
-1
@@ -31,6 +31,7 @@ import { getBiomeKey } from "./arena";
|
||||
import { BattleType, BattlerIndex, TurnCommand } from "./battle";
|
||||
import { GameMode } from "./game-mode";
|
||||
import { Species } from "./data/species";
|
||||
import { HealAchv, LevelAchv, MoneyAchv, achvs } from "./system/achv";
|
||||
|
||||
export class CheckLoadPhase extends BattlePhase {
|
||||
private loaded: boolean;
|
||||
@@ -329,6 +330,8 @@ export class EncounterPhase extends BattlePhase {
|
||||
enemyPokemon.untint(100, 'Sine.easeOut');
|
||||
enemyPokemon.cry();
|
||||
enemyPokemon.showInfo();
|
||||
if (enemyPokemon.isShiny())
|
||||
this.scene.validateAchv(achvs.SEE_SHINY);
|
||||
});
|
||||
let text = enemyField.length === 1
|
||||
? `A wild ${enemyField[0].name} appeared!`
|
||||
@@ -2259,6 +2262,8 @@ export class MoneyRewardPhase extends BattlePhase {
|
||||
this.scene.money += moneyAmount.value;
|
||||
this.scene.updateMoneyText();
|
||||
|
||||
this.scene.validateAchvs(MoneyAchv);
|
||||
|
||||
this.scene.ui.showText(`You got ₽${moneyAmount.value.toLocaleString('en-US')}\nfor winning!`, null, () => this.end(), null, true);
|
||||
}
|
||||
}
|
||||
@@ -2299,6 +2304,8 @@ export class GameOverPhase extends BattlePhase {
|
||||
this.scene.gameData.clearSession();
|
||||
|
||||
this.scene.time.delayedCall(1000, () => {
|
||||
if (this.victory)
|
||||
this.scene.validateAchv(achvs.CLASSIC_VICTORY);
|
||||
const fadeDuration = this.victory ? 10000 : 5000;
|
||||
this.scene.fadeOutBgm(fadeDuration, true);
|
||||
this.scene.ui.fadeOut(fadeDuration).then(() => {
|
||||
@@ -2464,6 +2471,8 @@ export class LevelUpPhase extends PlayerPartyMemberPokemonPhase {
|
||||
start() {
|
||||
super.start();
|
||||
|
||||
this.scene.validateAchvs(LevelAchv, new Utils.IntegerHolder(this.level));
|
||||
|
||||
const pokemon = this.getPokemon();
|
||||
const prevStats = pokemon.stats.slice(0);
|
||||
pokemon.calculateStats();
|
||||
@@ -2633,7 +2642,9 @@ export class PokemonHealPhase extends CommonAnimPhase {
|
||||
const hpRestoreMultiplier = new Utils.IntegerHolder(1);
|
||||
if (!this.revive)
|
||||
this.scene.applyModifiers(HealingBoosterModifier, this.player, hpRestoreMultiplier);
|
||||
pokemon.heal(this.hpHealed * hpRestoreMultiplier.value);
|
||||
const healAmount = new Utils.NumberHolder(this.hpHealed * hpRestoreMultiplier.value);
|
||||
pokemon.heal(healAmount.value);
|
||||
this.scene.validateAchvs(HealAchv, healAmount)
|
||||
pokemon.updateInfo().then(() => super.end());
|
||||
} else if (this.showFullHpMessage)
|
||||
this.message = getPokemonMessage(pokemon, `'s\nHP is full!`);
|
||||
@@ -2783,6 +2794,16 @@ export class AttemptCapturePhase extends PokemonPhase {
|
||||
catch() {
|
||||
const pokemon = this.getPokemon() as EnemyPokemon;
|
||||
this.scene.unshiftPhase(new VictoryPhase(this.scene, this.battlerIndex));
|
||||
|
||||
if (pokemon.getAbility().id === (!pokemon.fusionSpecies ? pokemon.getSpeciesForm() : pokemon.getFusionSpeciesForm()).abilityHidden)
|
||||
this.scene.validateAchv(achvs.HIDDEN_ABILITY);
|
||||
|
||||
if (pokemon.species.pseudoLegendary || pokemon.species.legendary)
|
||||
this.scene.validateAchv(achvs.CATCH_LEGENDARY);
|
||||
|
||||
if (pokemon.species.mythical)
|
||||
this.scene.validateAchv(achvs.CATCH_MYTHICAL);
|
||||
|
||||
this.scene.ui.showText(`${pokemon.name} was caught!`, null, () => {
|
||||
const end = () => {
|
||||
this.removePb();
|
||||
|
||||
+45
-15
@@ -16,7 +16,7 @@ import { GameData } from './system/game-data';
|
||||
import StarterSelectUiHandler from './ui/starter-select-ui-handler';
|
||||
import { TextStyle, addTextObject } from './ui/text';
|
||||
import { Moves, initMoves } from './data/move';
|
||||
import { ModifierPoolType, getDefaultModifierTypeForTier, getEnemyModifierTypesForWave, getModifierType, modifierTypes } from './modifier/modifier-type';
|
||||
import { ModifierPoolType, getDefaultModifierTypeForTier, getEnemyModifierTypesForWave } from './modifier/modifier-type';
|
||||
import AbilityBar from './ui/ability-bar';
|
||||
import { BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, applyAbAttrs, initAbilities } from './data/ability';
|
||||
import Battle, { BattleType, FixedBattleConfig, fixedBattles } from './battle';
|
||||
@@ -34,6 +34,7 @@ import SettingsUiHandler from './ui/settings-ui-handler';
|
||||
import MessageUiHandler from './ui/message-ui-handler';
|
||||
import { Species } from './data/species';
|
||||
import InvertPostFX from './pipelines/invert';
|
||||
import { Achv, achvs } from './system/achv';
|
||||
|
||||
const enableAuto = true;
|
||||
const quickStart = false;
|
||||
@@ -199,6 +200,10 @@ export default class BattleScene extends Phaser.Scene {
|
||||
this.loadImage('icon_owned', 'ui');
|
||||
this.loadImage('ability_bar', 'ui');
|
||||
this.loadImage('party_exp_bar', 'ui');
|
||||
this.loadImage('achv_bar', 'ui');
|
||||
this.loadImage('achv_bar_2', 'ui');
|
||||
this.loadImage('achv_bar_3', 'ui');
|
||||
this.loadImage('achv_bar_4', 'ui');
|
||||
this.loadImage('shiny_star', 'ui', 'shiny.png');
|
||||
this.loadImage('icon_spliced', 'ui');
|
||||
|
||||
@@ -306,6 +311,7 @@ export default class BattleScene extends Phaser.Scene {
|
||||
this.loadSe('beam');
|
||||
this.loadSe('upgrade');
|
||||
this.loadSe('buy');
|
||||
this.loadSe('achv');
|
||||
this.loadSe('error');
|
||||
|
||||
this.loadSe('pb_rel');
|
||||
@@ -838,6 +844,7 @@ export default class BattleScene extends Phaser.Scene {
|
||||
this.waveCountText.setY(-(this.game.canvas.height / 6) + (this.enemyModifiers.filter(m => m.isIconVisible(this)).length ? 15 : 0));
|
||||
this.moneyText.setY(this.waveCountText.y + 10);
|
||||
this.partyExpBar.setY(this.moneyText.y + 15);
|
||||
this.ui?.achvBar.setY((this.game.canvas.height / 6 + this.moneyText.y + 15));
|
||||
}
|
||||
|
||||
getMaxExpLevel(ignoreLevelCap?: boolean): integer {
|
||||
@@ -867,18 +874,19 @@ export default class BattleScene extends Phaser.Scene {
|
||||
checkInput(): boolean {
|
||||
if (this.blockInput)
|
||||
return;
|
||||
let inputSuccess = false;
|
||||
if (this.isButtonPressed(Button.UP))
|
||||
this.ui.processInput(Button.UP);
|
||||
inputSuccess = this.ui.processInput(Button.UP);
|
||||
else if (this.isButtonPressed(Button.DOWN))
|
||||
this.ui.processInput(Button.DOWN);
|
||||
inputSuccess = this.ui.processInput(Button.DOWN);
|
||||
else if (this.isButtonPressed(Button.LEFT))
|
||||
this.ui.processInput(Button.LEFT);
|
||||
inputSuccess = this.ui.processInput(Button.LEFT);
|
||||
else if (this.isButtonPressed(Button.RIGHT))
|
||||
this.ui.processInput(Button.RIGHT);
|
||||
inputSuccess = this.ui.processInput(Button.RIGHT);
|
||||
else if (this.isButtonPressed(Button.ACTION))
|
||||
this.ui.processInput(Button.ACTION);
|
||||
inputSuccess = this.ui.processInput(Button.ACTION);
|
||||
else if (this.isButtonPressed(Button.CANCEL))
|
||||
this.ui.processInput(Button.CANCEL);
|
||||
inputSuccess = this.ui.processInput(Button.CANCEL);
|
||||
else if (this.isButtonPressed(Button.MENU)) {
|
||||
switch (this.ui.getMode()) {
|
||||
case Mode.MESSAGE:
|
||||
@@ -894,8 +902,7 @@ export default class BattleScene extends Phaser.Scene {
|
||||
case Mode.STARTER_SELECT:
|
||||
case Mode.CONFIRM:
|
||||
case Mode.GAME_MODE_SELECT:
|
||||
this.ui.setModeWithoutClear(Mode.SETTINGS);
|
||||
this.playSound('menu_open');
|
||||
this.ui.setOverlayMode(Mode.MENU);
|
||||
break;
|
||||
case Mode.SETTINGS:
|
||||
this.ui.revertMode();
|
||||
@@ -904,16 +911,15 @@ export default class BattleScene extends Phaser.Scene {
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (this.ui?.getHandler() instanceof StarterSelectUiHandler) {
|
||||
} else if (this.ui?.getHandler() instanceof StarterSelectUiHandler) {
|
||||
if (this.isButtonPressed(Button.CYCLE_SHINY))
|
||||
this.ui.processInput(Button.CYCLE_SHINY);
|
||||
inputSuccess = this.ui.processInput(Button.CYCLE_SHINY);
|
||||
else if (this.isButtonPressed(Button.CYCLE_FORM))
|
||||
this.ui.processInput(Button.CYCLE_FORM);
|
||||
inputSuccess = this.ui.processInput(Button.CYCLE_FORM);
|
||||
else if (this.isButtonPressed(Button.CYCLE_GENDER))
|
||||
this.ui.processInput(Button.CYCLE_GENDER);
|
||||
inputSuccess = this.ui.processInput(Button.CYCLE_GENDER);
|
||||
else if (this.isButtonPressed(Button.CYCLE_ABILITY))
|
||||
this.ui.processInput(Button.CYCLE_ABILITY);
|
||||
inputSuccess = this.ui.processInput(Button.CYCLE_ABILITY);
|
||||
else
|
||||
return;
|
||||
}
|
||||
@@ -1413,4 +1419,28 @@ export default class BattleScene extends Phaser.Scene {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
validateAchvs(achvType: { new(...args: any[]): Achv }, ...args: any[]): void {
|
||||
const filteredAchvs = Object.values(achvs).filter(a => a instanceof achvType);
|
||||
let newAchv = false;
|
||||
for (let achv of filteredAchvs) {
|
||||
if (this.validateAchv(achv, args, false))
|
||||
newAchv = true;
|
||||
}
|
||||
|
||||
if (newAchv)
|
||||
this.gameData.saveSystem();
|
||||
}
|
||||
|
||||
validateAchv(achv: Achv, args?: any[], save: boolean = true): boolean {
|
||||
if (!this.gameData.achvUnlocks.hasOwnProperty(achv.id) && achv.validate(this, args)) {
|
||||
this.gameData.achvUnlocks[achv.id] = new Date().getTime();
|
||||
this.ui.achvBar.showAchv(achv);
|
||||
if (save)
|
||||
this.gameData.saveSystem();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+10
-10
@@ -101,7 +101,7 @@ export default class Move {
|
||||
return this.attrs.filter(a => a instanceof attrType);
|
||||
}
|
||||
|
||||
attr<T extends new (...args: any[]) => MoveAttr>(AttrType: T, ...args: ConstructorParameters<T>): Move {
|
||||
attr<T extends new (...args: any[]) => MoveAttr>(AttrType: T, ...args: ConstructorParameters<T>): this {
|
||||
const attr = new AttrType(...args);
|
||||
this.attrs.push(attr);
|
||||
const attrCondition = attr.getCondition();
|
||||
@@ -111,7 +111,7 @@ export default class Move {
|
||||
return this;
|
||||
}
|
||||
|
||||
addAttr(attr: MoveAttr): Move {
|
||||
addAttr(attr: MoveAttr): this {
|
||||
this.attrs.push(attr);
|
||||
const attrCondition = attr.getCondition();
|
||||
if (attrCondition)
|
||||
@@ -120,7 +120,7 @@ export default class Move {
|
||||
return this;
|
||||
}
|
||||
|
||||
target(moveTarget: MoveTarget): Move {
|
||||
target(moveTarget: MoveTarget): this {
|
||||
this.moveTarget = moveTarget;
|
||||
return this;
|
||||
}
|
||||
@@ -129,7 +129,7 @@ export default class Move {
|
||||
return !!(this.flags & flag);
|
||||
}
|
||||
|
||||
condition(condition: MoveCondition): Move {
|
||||
condition(condition: MoveCondition): this {
|
||||
this.conditions.push(condition);
|
||||
|
||||
return this;
|
||||
@@ -142,32 +142,32 @@ export default class Move {
|
||||
this.flags ^= flag;
|
||||
}
|
||||
|
||||
makesContact(makesContact?: boolean): Move {
|
||||
makesContact(makesContact?: boolean): this {
|
||||
this.setFlag(MoveFlags.MAKES_CONTACT, makesContact);
|
||||
return this;
|
||||
}
|
||||
|
||||
ignoresProtect(ignoresProtect?: boolean): Move {
|
||||
ignoresProtect(ignoresProtect?: boolean): this {
|
||||
this.setFlag(MoveFlags.IGNORE_PROTECT, ignoresProtect);
|
||||
return this;
|
||||
}
|
||||
|
||||
ignoresVirtual(ignoresVirtual?: boolean): Move {
|
||||
ignoresVirtual(ignoresVirtual?: boolean): this {
|
||||
this.setFlag(MoveFlags.IGNORE_VIRTUAL, ignoresVirtual);
|
||||
return this;
|
||||
}
|
||||
|
||||
soundBased(soundBased?: boolean): Move {
|
||||
soundBased(soundBased?: boolean): this {
|
||||
this.setFlag(MoveFlags.SOUND_BASED, soundBased);
|
||||
return this;
|
||||
}
|
||||
|
||||
hidesUser(hidesUser?: boolean): Move {
|
||||
hidesUser(hidesUser?: boolean): this {
|
||||
this.setFlag(MoveFlags.HIDE_USER, hidesUser);
|
||||
return this;
|
||||
}
|
||||
|
||||
hidesTarget(hidesTarget?: boolean): Move {
|
||||
hidesTarget(hidesTarget?: boolean): this {
|
||||
this.setFlag(MoveFlags.HIDE_TARGET, hidesTarget);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
function getData() {
|
||||
const dataStr = localStorage.getItem('data');
|
||||
if (!dataStr)
|
||||
return null;
|
||||
return JSON.parse(atob(dataStr));
|
||||
}
|
||||
|
||||
function getSession() {
|
||||
const sessionStr = localStorage.getItem('sessionData');
|
||||
if (!sessionStr)
|
||||
|
||||
@@ -6,7 +6,7 @@ import { EvolutionItem, pokemonEvolutions } from '../data/pokemon-evolutions';
|
||||
import { Stat, getStatName } from '../data/pokemon-stat';
|
||||
import { tmPoolTiers, tmSpecies } from '../data/tms';
|
||||
import { Type } from '../data/type';
|
||||
import PartyUiHandler, { PokemonMoveSelectFilter, PokemonRememberMoveSelectFilter, PokemonSelectFilter } from '../ui/party-ui-handler';
|
||||
import PartyUiHandler, { PokemonMoveSelectFilter, PokemonSelectFilter } from '../ui/party-ui-handler';
|
||||
import * as Utils from '../utils';
|
||||
import { TempBattleStat, getTempBattleStatBoosterItemName, getTempBattleStatName } from '../data/temp-battle-stat';
|
||||
import { BerryType, getBerryEffectDescription, getBerryName } from '../data/berry';
|
||||
|
||||
@@ -15,6 +15,7 @@ import { TempBattleStat } from '../data/temp-battle-stat';
|
||||
import { BerryType, getBerryEffectFunc, getBerryPredicate } from '../data/berry';
|
||||
import { Species } from '../data/species';
|
||||
import { StatusEffect, getStatusEffectDescriptor } from '../data/status-effect';
|
||||
import { MoneyAchv } from '../system/achv';
|
||||
|
||||
type ModifierType = ModifierTypes.ModifierType;
|
||||
export type ModifierPredicate = (modifier: Modifier) => boolean;
|
||||
@@ -1171,6 +1172,7 @@ export class DamageMoneyRewardModifier extends PokemonHeldItemModifier {
|
||||
scene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount);
|
||||
scene.money += moneyAmount.value;
|
||||
scene.updateMoneyText();
|
||||
scene.validateAchvs(MoneyAchv);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1194,6 +1196,7 @@ export class MoneyInterestModifier extends PersistentModifier {
|
||||
const interestAmount = Math.floor(scene.money * 0.2 * this.getStackCount());
|
||||
scene.money += interestAmount;
|
||||
scene.updateMoneyText();
|
||||
scene.validateAchvs(MoneyAchv);
|
||||
|
||||
scene.queueMessage(`You received interest of ₽${interestAmount.toLocaleString('en-US')}\nfrom the ${this.type.name}!`, null, true);
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import PartyUiHandler, { PartyOption, PartyUiMode } from './ui/party-ui-handler'
|
||||
import SoundFade from 'phaser3-rex-plugins/plugins/soundfade';
|
||||
import { GameMode } from './game-mode';
|
||||
import { LevelMoves } from './data/pokemon-level-moves';
|
||||
import { DamageAchv, achvs } from './system/achv';
|
||||
|
||||
export enum FieldPosition {
|
||||
CENTER,
|
||||
@@ -867,6 +868,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
this.scene.setPhaseQueueSplice();
|
||||
damage.value = Math.min(damage.value, this.hp);
|
||||
this.damage(damage.value);
|
||||
if (source.isPlayer())
|
||||
this.scene.validateAchvs(DamageAchv, damage);
|
||||
source.turnData.damageDealt += damage.value;
|
||||
this.turnData.attacksReceived.unshift({ move: move.id, result: result as DamageResult, damage: damage.value, critical: isCritical, sourceId: source.id });
|
||||
if (source.isPlayer() && !this.isPlayer())
|
||||
@@ -1013,6 +1016,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
this.summonData.battleStats[stat] = source.summonData.battleStats[stat];
|
||||
for (let tag of source.summonData.tags)
|
||||
this.summonData.tags.push(tag);
|
||||
if (battleStats.filter(bs => bs === 6).length)
|
||||
this.scene.validateAchv(achvs.TRANSFER_MAX_BATTLE_STAT);
|
||||
}
|
||||
|
||||
getMoveHistory(): TurnMove[] {
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
import BattleScene from "../battle-scene";
|
||||
import * as Utils from "../utils";
|
||||
|
||||
export enum AchvTier {
|
||||
COMMON,
|
||||
GREAT,
|
||||
ULTRA,
|
||||
MASTER
|
||||
}
|
||||
|
||||
export class Achv {
|
||||
public id: string;
|
||||
public name: string;
|
||||
public description: string;
|
||||
public iconImage: string;
|
||||
public score: integer;
|
||||
|
||||
public secret: boolean;
|
||||
public hasParent: boolean;
|
||||
public parentId: string;
|
||||
|
||||
private conditionFunc: (scene: BattleScene, args: any[]) => boolean;
|
||||
|
||||
constructor(name: string, description: string, iconImage: string, score: integer, conditionFunc?: (scene: BattleScene, args: any[]) => boolean) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.iconImage = iconImage;
|
||||
this.score = score;
|
||||
this.conditionFunc = conditionFunc;
|
||||
}
|
||||
|
||||
setSecret(hasParent?: boolean): this {
|
||||
this.secret = true;
|
||||
this.hasParent = !!hasParent;
|
||||
return this;
|
||||
}
|
||||
|
||||
validate(scene: BattleScene, args: any[]): boolean {
|
||||
return !this.conditionFunc || this.conditionFunc(scene, args);
|
||||
}
|
||||
|
||||
getTier(): AchvTier {
|
||||
if (this.score >= 250)
|
||||
return AchvTier.MASTER;
|
||||
if (this.score >= 100)
|
||||
return AchvTier.ULTRA;
|
||||
if (this.score >= 25)
|
||||
return AchvTier.GREAT;
|
||||
return AchvTier.COMMON;
|
||||
}
|
||||
}
|
||||
|
||||
export class MoneyAchv extends Achv {
|
||||
private moneyAmount: integer;
|
||||
|
||||
constructor(name: string, moneyAmount: integer, iconImage: string, score: integer) {
|
||||
super(name, `Accumulate a total of ₽${moneyAmount.toLocaleString('en-US')}`, iconImage, score, (scene: BattleScene, _args: any[]) => scene.money >= this.moneyAmount);
|
||||
|
||||
this.moneyAmount = moneyAmount;
|
||||
}
|
||||
}
|
||||
|
||||
export class DamageAchv extends Achv {
|
||||
private damageAmount: integer;
|
||||
|
||||
constructor(name: string, damageAmount: integer, iconImage: string, score: integer) {
|
||||
super(name, `Inflict ${damageAmount.toLocaleString('en-US')} damage in one hit`, iconImage, score, (_scene: BattleScene, args: any[]) => (args[0] as Utils.NumberHolder).value >= this.damageAmount);
|
||||
|
||||
this.damageAmount = damageAmount;
|
||||
}
|
||||
}
|
||||
|
||||
export class HealAchv extends Achv {
|
||||
private healAmount: integer;
|
||||
|
||||
constructor(name: string, healAmount: integer, iconImage: string, score: integer) {
|
||||
super(name, `Heal ${healAmount.toLocaleString('en-US')} HP at once with a move, ability, or held item`, iconImage, score, (_scene: BattleScene, args: any[]) => (args[0] as Utils.NumberHolder).value >= this.healAmount);
|
||||
|
||||
this.healAmount = healAmount;
|
||||
}
|
||||
}
|
||||
|
||||
export class LevelAchv extends Achv {
|
||||
private level: integer;
|
||||
|
||||
constructor(name: string, level: integer, iconImage: string, score: integer) {
|
||||
super(name, `Level up a Pokémon to Lv${level}`, iconImage, score, (scene: BattleScene, args: any[]) => (args[0] as Utils.IntegerHolder).value >= this.level);
|
||||
|
||||
this.level = level;
|
||||
}
|
||||
}
|
||||
|
||||
export const achvs = {
|
||||
_10K_MONEY: new MoneyAchv('Money Haver', 10000, 'nugget', 10),
|
||||
_100K_MONEY: new MoneyAchv('Rich', 100000, 'big_nugget', 25).setSecret(true),
|
||||
_1M_MONEY: new MoneyAchv('Millionaire', 1000000, 'relic_gold', 100).setSecret(true),
|
||||
_10M_MONEY: new MoneyAchv('One Percenter', 10000000, 'coin_case', 250).setSecret(true),
|
||||
_250_DMG: new DamageAchv('Hard Hitter', 1000, 'lucky_punch', 10),
|
||||
_1000_DMG: new DamageAchv('Harder Hitter', 1000, 'lucky_punch_great', 25).setSecret(true),
|
||||
_2500_DMG: new DamageAchv('That\'s a Lotta Damage!', 2500, 'lucky_punch_ultra', 100).setSecret(true),
|
||||
_10000_DMG: new DamageAchv('One Punch Man', 10000, 'lucky_punch_master', 250).setSecret(true),
|
||||
_250_HEAL: new HealAchv('Novice Healer', 250, 'potion', 10),
|
||||
_1000_HEAL: new HealAchv('Big Healer', 1000, 'super_potion', 25).setSecret(true),
|
||||
_2500_HEAL: new HealAchv('Cleric', 2500, 'hyper_potion', 100).setSecret(true),
|
||||
_10000_HEAL: new HealAchv('Recovery Master', 10000, 'max_potion', 250).setSecret(true),
|
||||
LV_100: new LevelAchv('But Wait, There\'s More!', 50, 'rare_candy', 50).setSecret(),
|
||||
LV_250: new LevelAchv('Elite', 250, 'rarer_candy', 150).setSecret(true),
|
||||
LV_1000: new LevelAchv('To Go Even Further Beyond', 250, 'candy_jar', 400).setSecret(true),
|
||||
TRANSFER_MAX_BATTLE_STAT: new Achv('Teamwork', 'Baton pass to another party member with at least one stat maxed out', 'stick', 25),
|
||||
CATCH_LEGENDARY: new Achv('Legendary', 'Catch a legendary Pokémon', 'mb', 100).setSecret(),
|
||||
CATCH_MYTHICAL: new Achv('Mythical', 'Catch a mythical Pokémon', 'strange_ball', 100).setSecret(),
|
||||
SEE_SHINY: new Achv('Shiny', 'Find a shiny Pokémon in the wild', 'pb_gold', 150).setSecret(),
|
||||
HIDDEN_ABILITY: new Achv('Hidden Potential', 'Catch a Pokémon with a hidden ability', 'ability_charm', 150).setSecret(),
|
||||
CLASSIC_VICTORY: new Achv('Undefeated', 'Beat the game in classic mode', 'relic_crown', 250)
|
||||
};
|
||||
|
||||
{
|
||||
(function() {
|
||||
const achvKeys = Object.keys(achvs);
|
||||
achvKeys.forEach((a: string, i: integer) => {
|
||||
achvs[a].id = a;
|
||||
if (achvs[a].hasParent)
|
||||
achvs[a].parentId = achvKeys[i - 1];
|
||||
});
|
||||
})();
|
||||
}
|
||||
+19
-1
@@ -7,7 +7,6 @@ import { Species } from "../data/species";
|
||||
import * as Utils from "../utils";
|
||||
import PokemonData from "./pokemon-data";
|
||||
import PersistentModifierData from "./modifier-data";
|
||||
import { PokemonHeldItemModifier } from "../modifier/modifier";
|
||||
import ArenaData from "./arena-data";
|
||||
import { Unlockables } from "./unlockables";
|
||||
import { GameMode } from "../game-mode";
|
||||
@@ -15,12 +14,14 @@ import { BattleType } from "../battle";
|
||||
import TrainerData from "./trainer-data";
|
||||
import { trainerConfigs } from "../data/trainer-type";
|
||||
import { Setting, setSetting, settingDefaults } from "./settings";
|
||||
import { achvs } from "./achv";
|
||||
|
||||
interface SystemSaveData {
|
||||
trainerId: integer;
|
||||
secretId: integer;
|
||||
dexData: DexData;
|
||||
unlocks: Unlocks;
|
||||
achvUnlocks: AchvUnlocks;
|
||||
timestamp: integer;
|
||||
}
|
||||
|
||||
@@ -45,6 +46,10 @@ interface Unlocks {
|
||||
[key: integer]: boolean;
|
||||
}
|
||||
|
||||
interface AchvUnlocks {
|
||||
[key: string]: integer
|
||||
}
|
||||
|
||||
export interface DexData {
|
||||
[key: integer]: DexData | DexEntry
|
||||
}
|
||||
@@ -81,6 +86,8 @@ export class GameData {
|
||||
|
||||
public unlocks: Unlocks;
|
||||
|
||||
public achvUnlocks: AchvUnlocks;
|
||||
|
||||
constructor(scene: BattleScene) {
|
||||
this.scene = scene;
|
||||
this.loadSettings();
|
||||
@@ -91,6 +98,7 @@ export class GameData {
|
||||
[Unlockables.MINI_BLACK_HOLE]: false,
|
||||
[Unlockables.SPLICED_ENDLESS_MODE]: false
|
||||
};
|
||||
this.achvUnlocks = {};
|
||||
this.initDexData();
|
||||
this.loadSystem();
|
||||
}
|
||||
@@ -98,12 +106,15 @@ export class GameData {
|
||||
public saveSystem(): boolean {
|
||||
if (this.scene.quickStart)
|
||||
return false;
|
||||
|
||||
console.log(this.achvUnlocks, "wah")
|
||||
|
||||
const data: SystemSaveData = {
|
||||
trainerId: this.trainerId,
|
||||
secretId: this.secretId,
|
||||
dexData: this.dexData,
|
||||
unlocks: this.unlocks,
|
||||
achvUnlocks: this.achvUnlocks,
|
||||
timestamp: new Date().getTime()
|
||||
};
|
||||
|
||||
@@ -129,6 +140,13 @@ export class GameData {
|
||||
}
|
||||
}
|
||||
|
||||
if (data.achvUnlocks) {
|
||||
for (let a of Object.keys(data.achvUnlocks)) {
|
||||
if (achvs.hasOwnProperty(a))
|
||||
this.achvUnlocks[a] = data.achvUnlocks[a];
|
||||
}
|
||||
}
|
||||
|
||||
if (data.timestamp === undefined)
|
||||
this.convertDexData(data.dexData);
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
import BattleScene from "../battle-scene";
|
||||
import { Achv } from "../system/achv";
|
||||
import { TextStyle, addTextObject } from "./text";
|
||||
|
||||
export default class AchvBar extends Phaser.GameObjects.Container {
|
||||
private bg: Phaser.GameObjects.NineSlice;
|
||||
private icon: Phaser.GameObjects.Sprite;
|
||||
private titleText: Phaser.GameObjects.Text;
|
||||
private scoreText: Phaser.GameObjects.Text;
|
||||
private descriptionText: Phaser.GameObjects.Text;
|
||||
|
||||
private queue: Achv[] = [];
|
||||
|
||||
public shown: boolean;
|
||||
|
||||
constructor(scene: BattleScene) {
|
||||
super(scene, scene.game.canvas.width / 6, 0);
|
||||
}
|
||||
|
||||
setup(): void {
|
||||
this.bg = this.scene.add.nineslice(0, 0, 'achv_bar', null, 160, 40, 41, 6, 16, 4);
|
||||
this.bg.setOrigin(0, 0);
|
||||
|
||||
this.add(this.bg);
|
||||
|
||||
this.icon = this.scene.add.sprite(4, 4, 'items');
|
||||
this.icon.setOrigin(0, 0);
|
||||
this.add(this.icon);
|
||||
|
||||
this.titleText = addTextObject(this.scene, 40, 3, '', TextStyle.MESSAGE, { fontSize: '72px' });
|
||||
this.titleText.setOrigin(0, 0);
|
||||
this.add(this.titleText);
|
||||
|
||||
this.scoreText = addTextObject(this.scene, 150, 3, '', TextStyle.MESSAGE, { fontSize: '72px' });
|
||||
this.scoreText.setOrigin(1, 0);
|
||||
this.add(this.scoreText);
|
||||
|
||||
this.descriptionText = addTextObject(this.scene, 43, 16, '', TextStyle.WINDOW, { fontSize: '72px' });
|
||||
this.descriptionText.setOrigin(0, 0);
|
||||
this.add(this.descriptionText);
|
||||
|
||||
this.descriptionText.setWordWrapWidth(664);
|
||||
this.descriptionText.setLineSpacing(-5);
|
||||
|
||||
this.setScale(0.5);
|
||||
|
||||
this.shown = false;
|
||||
}
|
||||
|
||||
showAchv(achv: Achv): void {
|
||||
if (this.shown) {
|
||||
this.queue.push(achv);
|
||||
return;
|
||||
}
|
||||
|
||||
const tier = achv.getTier();
|
||||
|
||||
this.bg.setTexture(`achv_bar${tier ? `_${tier + 1}` : ''}`);
|
||||
this.icon.setFrame(achv.iconImage);
|
||||
this.titleText.setText(achv.name);
|
||||
this.descriptionText.setText(achv.description);
|
||||
this.scoreText.setText(`+${achv.score}pt`);
|
||||
|
||||
(this.scene as BattleScene).playSound('achv');
|
||||
|
||||
this.scene.tweens.add({
|
||||
targets: this,
|
||||
x: (this.scene.game.canvas.width / 6) - 76,
|
||||
duration: 500,
|
||||
ease: 'Sine.easeOut'
|
||||
});
|
||||
|
||||
this.scene.time.delayedCall(10000, () => this.hide());
|
||||
|
||||
this.setVisible(true);
|
||||
this.shown = true;
|
||||
}
|
||||
|
||||
protected hide(): void {
|
||||
if (!this.shown)
|
||||
return;
|
||||
|
||||
this.scene.tweens.add({
|
||||
targets: this,
|
||||
x: (this.scene.game.canvas.width / 6),
|
||||
duration: 500,
|
||||
ease: 'Sine.easeIn',
|
||||
onComplete: () => {
|
||||
this.shown = false;
|
||||
this.setVisible(false);
|
||||
if (this.queue.length)
|
||||
this.showAchv(this.queue.shift());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
import BattleScene, { Button } from "../battle-scene";
|
||||
import { Achv, achvs } from "../system/achv";
|
||||
import MessageUiHandler from "./message-ui-handler";
|
||||
import { TextStyle, addTextObject } from "./text";
|
||||
import { Mode } from "./ui";
|
||||
|
||||
export default class AchvsUiHandler extends MessageUiHandler {
|
||||
private achvsContainer: Phaser.GameObjects.Container;
|
||||
private achvIconsContainer: Phaser.GameObjects.Container;
|
||||
|
||||
private achvIconsBg: Phaser.GameObjects.NineSlice;
|
||||
private achvIcons: Phaser.GameObjects.Sprite[];
|
||||
private titleText: Phaser.GameObjects.Text;
|
||||
private scoreText: Phaser.GameObjects.Text;
|
||||
private unlockText: Phaser.GameObjects.Text;
|
||||
|
||||
private cursorObj: Phaser.GameObjects.NineSlice;
|
||||
|
||||
constructor(scene: BattleScene, mode?: Mode) {
|
||||
super(scene, mode);
|
||||
}
|
||||
|
||||
setup() {
|
||||
const ui = this.getUi();
|
||||
|
||||
this.achvsContainer = this.scene.add.container(1, -(this.scene.game.canvas.height / 6) + 1);
|
||||
|
||||
this.achvsContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6), Phaser.Geom.Rectangle.Contains);
|
||||
|
||||
const headerBg = this.scene.add.nineslice(0, 0, 'window', null, (this.scene.game.canvas.width / 6) - 2, 24, 6, 6, 6, 6);
|
||||
headerBg.setOrigin(0, 0);
|
||||
|
||||
const headerText = addTextObject(this.scene, 0, 0, 'Achievements', TextStyle.SETTINGS_LABEL);
|
||||
headerText.setOrigin(0, 0);
|
||||
headerText.setPositionRelative(headerBg, 8, 4);
|
||||
|
||||
this.achvIconsBg = this.scene.add.nineslice(0, headerBg.height, 'window', null, (this.scene.game.canvas.width / 6) - 2, (this.scene.game.canvas.height / 6) - headerBg.height - 68, 6, 6, 6, 6);
|
||||
this.achvIconsBg.setOrigin(0, 0);
|
||||
|
||||
this.achvIconsContainer = this.scene.add.container(6, headerBg.height + 6);
|
||||
|
||||
this.achvIcons = [];
|
||||
|
||||
for (let a = 0; a < Object.keys(achvs).length; a++) {
|
||||
const x = (a % 17) * 18;
|
||||
const y = Math.floor(a / 17) * 18;
|
||||
|
||||
const icon = this.scene.add.sprite(x, y, 'items', 'unknown');
|
||||
icon.setOrigin(0, 0);
|
||||
icon.setScale(0.5);
|
||||
|
||||
this.achvIcons.push(icon);
|
||||
this.achvIconsContainer.add(icon);
|
||||
}
|
||||
|
||||
const titleBg = this.scene.add.nineslice(0, headerBg.height + this.achvIconsBg.height, 'window', null, 174, 24, 6, 6, 6, 6);
|
||||
titleBg.setOrigin(0, 0);
|
||||
|
||||
this.titleText = addTextObject(this.scene, 0, 0, '', TextStyle.WINDOW);
|
||||
this.titleText.setOrigin(0, 0);
|
||||
this.titleText.setPositionRelative(titleBg, 8, 4);
|
||||
|
||||
const scoreBg = this.scene.add.nineslice(titleBg.x + titleBg.width, titleBg.y, 'window', null, 46, 24, 6, 6, 6, 6);
|
||||
scoreBg.setOrigin(0, 0);
|
||||
|
||||
this.scoreText = addTextObject(this.scene, 0, 0, '', TextStyle.WINDOW);
|
||||
this.scoreText.setOrigin(0, 0);
|
||||
this.scoreText.setPositionRelative(scoreBg, 8, 4);
|
||||
|
||||
const unlockBg = this.scene.add.nineslice(scoreBg.x + scoreBg.width, scoreBg.y, 'window', null, 98, 24, 6, 6, 6, 6);
|
||||
unlockBg.setOrigin(0, 0);
|
||||
|
||||
this.unlockText = addTextObject(this.scene, 0, 0, '', TextStyle.WINDOW);
|
||||
this.unlockText.setOrigin(0, 0);
|
||||
this.unlockText.setPositionRelative(unlockBg, 8, 4);
|
||||
|
||||
const descriptionBg = this.scene.add.nineslice(0, titleBg.y + titleBg.height, 'window', null, (this.scene.game.canvas.width / 6) - 2, 42, 6, 6, 6, 6);
|
||||
descriptionBg.setOrigin(0, 0);
|
||||
|
||||
const descriptionText = addTextObject(this.scene, 0, 0, '', TextStyle.WINDOW, { maxLines: 2 });
|
||||
descriptionText.setWordWrapWidth(1870);
|
||||
descriptionText.setOrigin(0, 0);
|
||||
descriptionText.setPositionRelative(descriptionBg, 8, 4);
|
||||
|
||||
this.message = descriptionText;
|
||||
|
||||
this.achvsContainer.add(headerBg);
|
||||
this.achvsContainer.add(headerText);
|
||||
this.achvsContainer.add(this.achvIconsBg);
|
||||
this.achvsContainer.add(this.achvIconsContainer);
|
||||
this.achvsContainer.add(titleBg);
|
||||
this.achvsContainer.add(this.titleText);
|
||||
this.achvsContainer.add(scoreBg);
|
||||
this.achvsContainer.add(this.scoreText);
|
||||
this.achvsContainer.add(unlockBg);
|
||||
this.achvsContainer.add(this.unlockText);
|
||||
this.achvsContainer.add(descriptionBg);
|
||||
this.achvsContainer.add(descriptionText);
|
||||
|
||||
ui.add(this.achvsContainer);
|
||||
|
||||
this.setCursor(0);
|
||||
|
||||
this.achvsContainer.setVisible(false);
|
||||
}
|
||||
|
||||
show(args: any[]) {
|
||||
super.show(args);
|
||||
|
||||
const achvUnlocks = this.scene.gameData.achvUnlocks;
|
||||
|
||||
Object.values(achvs).forEach((achv: Achv, i: integer) => {
|
||||
const icon = this.achvIcons[i];
|
||||
const unlocked = achvUnlocks.hasOwnProperty(achv.id);
|
||||
const hidden = achv.secret && (!achv.parentId || !achvUnlocks.hasOwnProperty(achv.parentId));
|
||||
const tinted = !hidden && !unlocked;
|
||||
|
||||
icon.setFrame(!hidden ? achv.iconImage : 'unknown');
|
||||
if (tinted)
|
||||
icon.setTintFill(0);
|
||||
else
|
||||
icon.clearTint();
|
||||
});
|
||||
|
||||
this.achvsContainer.setVisible(true);
|
||||
this.setCursor(0);
|
||||
|
||||
this.getUi().moveTo(this.achvsContainer, this.getUi().length - 1);
|
||||
|
||||
this.getUi().hideTooltip();
|
||||
}
|
||||
|
||||
protected showAchv(achv: Achv) {
|
||||
const achvUnlocks = this.scene.gameData.achvUnlocks;
|
||||
const unlocked = achvUnlocks.hasOwnProperty(achv.id);
|
||||
const hidden = achv.secret && (!achv.parentId || !achvUnlocks.hasOwnProperty(achv.parentId));
|
||||
|
||||
this.titleText.setText(unlocked ? achv.name : '???');
|
||||
this.showText(!hidden ? achv.description : '');
|
||||
this.scoreText.setText(`${achv.score}pt`);
|
||||
this.unlockText.setText(unlocked ? new Date(achvUnlocks[achv.id]).toLocaleDateString() : 'Locked');
|
||||
}
|
||||
|
||||
processInput(button: Button): boolean {
|
||||
const ui = this.getUi();
|
||||
|
||||
let success = false;
|
||||
|
||||
if (button === Button.CANCEL) {
|
||||
success = true;
|
||||
this.scene.ui.revertMode();
|
||||
} else {
|
||||
switch (button) {
|
||||
case Button.UP:
|
||||
if (this.cursor >= 17)
|
||||
success = this.setCursor(this.cursor - 17);
|
||||
break;
|
||||
case Button.DOWN:
|
||||
if (this.cursor + 17 < Object.keys(achvs).length)
|
||||
success = this.setCursor(this.cursor + 17);
|
||||
break;
|
||||
case Button.LEFT:
|
||||
if (this.cursor % 17)
|
||||
success = this.setCursor(this.cursor - 1);
|
||||
break;
|
||||
case Button.RIGHT:
|
||||
if (this.cursor % 17 < 16 && this.cursor < Object.keys(achvs).length - 1)
|
||||
success = this.setCursor(this.cursor + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (success)
|
||||
ui.playSelect();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
setCursor(cursor: integer): boolean {
|
||||
let ret = super.setCursor(cursor);
|
||||
|
||||
let updateAchv = ret;
|
||||
|
||||
if (!this.cursorObj) {
|
||||
this.cursorObj = this.scene.add.nineslice(0, 0, 'starter_select_cursor_highlight', null, 16, 16, 1, 1, 1, 1);
|
||||
this.cursorObj.setOrigin(0, 0);
|
||||
this.achvIconsContainer.add(this.cursorObj);
|
||||
updateAchv = true;
|
||||
}
|
||||
|
||||
this.cursorObj.setPositionRelative(this.achvIcons[this.cursor], 0, 0);
|
||||
|
||||
if (updateAchv)
|
||||
this.showAchv(achvs[Object.keys(achvs)[cursor]]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
clear() {
|
||||
super.clear();
|
||||
this.achvsContainer.setVisible(false);
|
||||
this.eraseCursor();
|
||||
}
|
||||
|
||||
eraseCursor() {
|
||||
if (this.cursorObj)
|
||||
this.cursorObj.destroy();
|
||||
this.cursorObj = null;
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,7 @@ export default class BallUiHandler extends UiHandler {
|
||||
this.setCursor(this.cursor);
|
||||
}
|
||||
|
||||
processInput(button: Button) {
|
||||
processInput(button: Button): boolean {
|
||||
const ui = this.getUi();
|
||||
|
||||
let success = false;
|
||||
@@ -91,6 +91,8 @@ export default class BallUiHandler extends UiHandler {
|
||||
|
||||
if (success)
|
||||
ui.playSelect();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
updateCounts() {
|
||||
|
||||
@@ -102,7 +102,7 @@ export default class BattleMessageUiHandler extends MessageUiHandler {
|
||||
this.message.setWordWrapWidth(1780);
|
||||
}
|
||||
|
||||
processInput(button: Button): void {
|
||||
processInput(button: Button): boolean {
|
||||
const ui = this.getUi();
|
||||
if (this.awaitingActionInput) {
|
||||
if (button === Button.CANCEL || button === Button.ACTION) {
|
||||
@@ -111,6 +111,7 @@ export default class BattleMessageUiHandler extends MessageUiHandler {
|
||||
const originalOnActionInput = this.onActionInput;
|
||||
this.onActionInput = null;
|
||||
originalOnActionInput();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ export default class BiomeSelectUiHandler extends UiHandler {
|
||||
}
|
||||
}
|
||||
|
||||
processInput(button: Button) {
|
||||
processInput(button: Button): boolean {
|
||||
const ui = this.getUi();
|
||||
|
||||
let success = false;
|
||||
@@ -78,6 +78,8 @@ export default class BiomeSelectUiHandler extends UiHandler {
|
||||
|
||||
if (success)
|
||||
ui.playSelect();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
setCursor(cursor: integer): boolean {
|
||||
|
||||
@@ -51,7 +51,7 @@ export default class CommandUiHandler extends UiHandler {
|
||||
this.setCursor(this.getCursor());
|
||||
}
|
||||
|
||||
processInput(button: Button) {
|
||||
processInput(button: Button): boolean {
|
||||
const ui = this.getUi();
|
||||
|
||||
let success = false;
|
||||
@@ -104,6 +104,8 @@ export default class CommandUiHandler extends UiHandler {
|
||||
|
||||
if (success)
|
||||
ui.playSelect();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
getCursor(): integer {
|
||||
|
||||
@@ -20,8 +20,8 @@ export default class EvolutionSceneHandler extends UiHandler {
|
||||
this.scene.fieldUI.bringToTop(this.evolutionContainer);
|
||||
}
|
||||
|
||||
processInput(button: Button) {
|
||||
this.scene.ui.getMessageHandler().processInput(button);
|
||||
processInput(button: Button): boolean {
|
||||
return this.scene.ui.getMessageHandler().processInput(button);
|
||||
}
|
||||
|
||||
setCursor(_cursor: integer): boolean {
|
||||
|
||||
@@ -47,7 +47,7 @@ export default class FightUiHandler extends UiHandler {
|
||||
this.displayMoves();
|
||||
}
|
||||
|
||||
processInput(button: Button) {
|
||||
processInput(button: Button): boolean {
|
||||
const ui = this.getUi();
|
||||
|
||||
let success = false;
|
||||
@@ -87,6 +87,8 @@ export default class FightUiHandler extends UiHandler {
|
||||
|
||||
if (success)
|
||||
ui.playSelect();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
getCursor(): integer {
|
||||
|
||||
@@ -42,7 +42,7 @@ export default class GameModeSelectUiHandler extends OptionSelectUiHandler {
|
||||
}
|
||||
}
|
||||
|
||||
processInput(button: Button) {
|
||||
processInput(button: Button): boolean {
|
||||
const ui = this.getUi();
|
||||
|
||||
const options = this.getOptions();
|
||||
@@ -59,5 +59,7 @@ export default class GameModeSelectUiHandler extends OptionSelectUiHandler {
|
||||
ui.playSelect();
|
||||
} else
|
||||
return super.processInput(button);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
import BattleScene, { Button } from "../battle-scene";
|
||||
import { TextStyle, addTextObject } from "./text";
|
||||
import { Mode } from "./ui";
|
||||
import UiHandler from "./uiHandler";
|
||||
import * as Utils from "../utils";
|
||||
|
||||
export enum MenuOptions {
|
||||
SETTINGS,
|
||||
ACHIEVEMENTS
|
||||
}
|
||||
|
||||
export default class MenuUiHandler extends UiHandler {
|
||||
private menuContainer: Phaser.GameObjects.Container;
|
||||
|
||||
private menuBg: Phaser.GameObjects.NineSlice;
|
||||
protected optionSelectText: Phaser.GameObjects.Text;
|
||||
|
||||
private cursorObj: Phaser.GameObjects.Image;
|
||||
|
||||
constructor(scene: BattleScene, mode?: Mode) {
|
||||
super(scene, mode);
|
||||
}
|
||||
|
||||
setup() {
|
||||
const ui = this.getUi();
|
||||
|
||||
this.menuContainer = this.scene.add.container(1, -(this.scene.game.canvas.height / 6) + 1);
|
||||
|
||||
this.menuContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6), Phaser.Geom.Rectangle.Contains);
|
||||
|
||||
this.menuBg = this.scene.add.nineslice((this.scene.game.canvas.width / 6) - 92, 0, 'window', null, 90, (this.scene.game.canvas.height / 6) - 2, 6, 6, 6, 6);
|
||||
this.menuBg.setOrigin(0, 0);
|
||||
|
||||
this.menuContainer.add(this.menuBg);
|
||||
|
||||
this.optionSelectText = addTextObject(this.scene, 0, 0, Utils.getEnumKeys(MenuOptions).map(o => Utils.toReadableString(o)).join('\n'), TextStyle.WINDOW, { maxLines: Utils.getEnumKeys(MenuOptions).length });
|
||||
this.optionSelectText.setPositionRelative(this.menuBg, 14, 6);
|
||||
this.optionSelectText.setLineSpacing(12);
|
||||
this.menuContainer.add(this.optionSelectText);
|
||||
|
||||
ui.add(this.menuContainer);
|
||||
|
||||
this.setCursor(0);
|
||||
|
||||
this.menuContainer.setVisible(false);
|
||||
}
|
||||
|
||||
show(args: any[]) {
|
||||
super.show(args);
|
||||
|
||||
this.menuContainer.setVisible(true);
|
||||
this.setCursor(0);
|
||||
|
||||
this.getUi().moveTo(this.menuContainer, this.getUi().length - 1);
|
||||
|
||||
this.getUi().hideTooltip();
|
||||
|
||||
this.scene.playSound('menu_open');
|
||||
}
|
||||
|
||||
processInput(button: Button): boolean {
|
||||
const ui = this.getUi();
|
||||
|
||||
let success = false;
|
||||
|
||||
if (button === Button.ACTION) {
|
||||
switch (this.cursor as MenuOptions) {
|
||||
case MenuOptions.SETTINGS:
|
||||
this.scene.ui.setOverlayMode(Mode.SETTINGS);
|
||||
success = true;
|
||||
break;
|
||||
case MenuOptions.ACHIEVEMENTS:
|
||||
this.scene.ui.setOverlayMode(Mode.ACHIEVEMENTS);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
} else if (button === Button.CANCEL) {
|
||||
success = true;
|
||||
this.scene.ui.revertMode();
|
||||
} else {
|
||||
switch (button) {
|
||||
case Button.UP:
|
||||
if (this.cursor)
|
||||
success = this.setCursor(this.cursor - 1);
|
||||
break;
|
||||
case Button.DOWN:
|
||||
if (this.cursor < Utils.getEnumKeys(MenuOptions).length)
|
||||
success = this.setCursor(this.cursor + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (success)
|
||||
ui.playSelect();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
setCursor(cursor: integer): boolean {
|
||||
const ret = super.setCursor(cursor);
|
||||
|
||||
if (!this.cursorObj) {
|
||||
this.cursorObj = this.scene.add.image(0, 0, 'cursor');
|
||||
this.cursorObj.setOrigin(0, 0);
|
||||
this.menuContainer.add(this.cursorObj);
|
||||
}
|
||||
|
||||
this.cursorObj.setPositionRelative(this.menuBg, 7, 9 + this.cursor * 16);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
clear() {
|
||||
super.clear();
|
||||
this.menuContainer.setVisible(false);
|
||||
this.eraseCursor();
|
||||
}
|
||||
|
||||
eraseCursor() {
|
||||
if (this.cursorObj)
|
||||
this.cursorObj.destroy();
|
||||
this.cursorObj = null;
|
||||
}
|
||||
}
|
||||
@@ -137,11 +137,11 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
|
||||
});
|
||||
}
|
||||
|
||||
processInput(button: Button) {
|
||||
processInput(button: Button): boolean {
|
||||
const ui = this.getUi();
|
||||
|
||||
if (!this.awaitingActionInput)
|
||||
return;
|
||||
return false;
|
||||
|
||||
let success = false;
|
||||
|
||||
@@ -193,6 +193,8 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
|
||||
|
||||
if (success)
|
||||
ui.playSelect();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
setCursor(cursor: integer): boolean {
|
||||
|
||||
@@ -65,7 +65,7 @@ export default abstract class OptionSelectUiHandler extends UiHandler {
|
||||
}
|
||||
}
|
||||
|
||||
processInput(button: Button) {
|
||||
processInput(button: Button): boolean {
|
||||
const ui = this.getUi();
|
||||
|
||||
let success = false;
|
||||
@@ -94,6 +94,8 @@ export default abstract class OptionSelectUiHandler extends UiHandler {
|
||||
|
||||
if (success)
|
||||
ui.playSelect();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
setCursor(cursor: integer): boolean {
|
||||
|
||||
+23
-16
@@ -177,23 +177,22 @@ export default class PartyUiHandler extends MessageUiHandler {
|
||||
this.setCursor(this.cursor < 6 ? this.cursor : 0);
|
||||
}
|
||||
|
||||
processInput(button: Button) {
|
||||
processInput(button: Button): boolean {
|
||||
const ui = this.getUi();
|
||||
|
||||
if (this.pendingPrompt)
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (this.awaitingActionInput) {
|
||||
if (button === Button.ACTION || button === Button.CANCEL) {
|
||||
if (this.onActionInput) {
|
||||
ui.playSelect();
|
||||
const originalOnActionInput = this.onActionInput;
|
||||
this.onActionInput = null;
|
||||
originalOnActionInput();
|
||||
this.awaitingActionInput = false;
|
||||
}
|
||||
if ((button === Button.ACTION || button === Button.CANCEL) && this.onActionInput) {
|
||||
ui.playSelect();
|
||||
const originalOnActionInput = this.onActionInput;
|
||||
this.onActionInput = null;
|
||||
originalOnActionInput();
|
||||
this.awaitingActionInput = false;
|
||||
return true;
|
||||
}
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
let success = false;
|
||||
@@ -206,6 +205,7 @@ export default class PartyUiHandler extends MessageUiHandler {
|
||||
this.startTransfer();
|
||||
this.clearOptions();
|
||||
ui.playSelect();
|
||||
return true;
|
||||
} else if (this.partyUiMode === PartyUiMode.REMEMBER_MOVE_MODIFIER && option !== PartyOption.CANCEL) {
|
||||
let filterResult = (this.selectFilter as PokemonSelectFilter)(pokemon);
|
||||
if (filterResult === null) {
|
||||
@@ -216,6 +216,7 @@ export default class PartyUiHandler extends MessageUiHandler {
|
||||
this.showText(filterResult as string, null, () => this.showText(null, 0), null, true);
|
||||
}
|
||||
ui.playSelect();
|
||||
return true;
|
||||
} else if ((option !== PartyOption.SUMMARY && option !== PartyOption.RELEASE && option !== PartyOption.CANCEL)
|
||||
|| (option === PartyOption.RELEASE && this.partyUiMode === PartyUiMode.RELEASE)) {
|
||||
let filterResult: string;
|
||||
@@ -254,7 +255,7 @@ export default class PartyUiHandler extends MessageUiHandler {
|
||||
(this.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.POKEMON, this.cursor, option === PartyOption.PASS_BATON);
|
||||
if (this.partyUiMode !== PartyUiMode.MODIFIER && this.partyUiMode !== PartyUiMode.TM_MODIFIER && this.partyUiMode !== PartyUiMode.MOVE_MODIFIER)
|
||||
ui.playSelect();
|
||||
return;
|
||||
return true;
|
||||
} else {
|
||||
this.clearOptions();
|
||||
this.showText(filterResult as string, null, () => this.showText(null, 0), null, true);
|
||||
@@ -262,6 +263,7 @@ export default class PartyUiHandler extends MessageUiHandler {
|
||||
} else if (option === PartyOption.SUMMARY) {
|
||||
ui.playSelect();
|
||||
ui.setModeWithoutClear(Mode.SUMMARY, pokemon).then(() => this.clearOptions());
|
||||
return true;
|
||||
} else if (option === PartyOption.RELEASE) {
|
||||
this.clearOptions();
|
||||
ui.playSelect();
|
||||
@@ -277,11 +279,13 @@ export default class PartyUiHandler extends MessageUiHandler {
|
||||
});
|
||||
} else
|
||||
this.showText('You can\'t release a Pokémon that\'s in battle!', null, () => this.showText(null, 0), null, true);
|
||||
return true;
|
||||
} else if (option === PartyOption.CANCEL)
|
||||
this.processInput(Button.CANCEL);
|
||||
return this.processInput(Button.CANCEL);
|
||||
} else if (button === Button.CANCEL) {
|
||||
this.clearOptions();
|
||||
ui.playSelect();
|
||||
return true;
|
||||
} else {
|
||||
switch (button) {
|
||||
case Button.UP:
|
||||
@@ -300,8 +304,8 @@ export default class PartyUiHandler extends MessageUiHandler {
|
||||
} else if (this.partyUiMode === PartyUiMode.FAINT_SWITCH)
|
||||
ui.playError();
|
||||
else
|
||||
this.processInput(Button.CANCEL);
|
||||
return;
|
||||
return this.processInput(Button.CANCEL);
|
||||
return true;
|
||||
} else if (button === Button.CANCEL) {
|
||||
if ((this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER || this.partyUiMode === PartyUiMode.SPLICE) && this.transferMode) {
|
||||
this.clearTransfer();
|
||||
@@ -317,7 +321,8 @@ export default class PartyUiHandler extends MessageUiHandler {
|
||||
ui.playSelect();
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const slotCount = this.partySlots.length;
|
||||
@@ -343,6 +348,8 @@ export default class PartyUiHandler extends MessageUiHandler {
|
||||
|
||||
if (success)
|
||||
ui.playSelect();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
populatePartySlots() {
|
||||
|
||||
@@ -91,9 +91,7 @@ export default class SettingsUiHandler extends UiHandler {
|
||||
|
||||
const settings: object = localStorage.hasOwnProperty('settings') ? JSON.parse(localStorage.getItem('settings')) : {};
|
||||
|
||||
Object.keys(settingDefaults).forEach((setting, s) => {
|
||||
this.setOptionCursor(s, settings.hasOwnProperty(setting) ? settings[setting] : settingDefaults[setting]);
|
||||
});
|
||||
Object.keys(settingDefaults).forEach((setting, s) => this.setOptionCursor(s, settings.hasOwnProperty(setting) ? settings[setting] : settingDefaults[setting]));
|
||||
|
||||
this.settingsContainer.setVisible(true);
|
||||
this.setCursor(0);
|
||||
@@ -103,7 +101,7 @@ export default class SettingsUiHandler extends UiHandler {
|
||||
this.getUi().hideTooltip();
|
||||
}
|
||||
|
||||
processInput(button: Button) {
|
||||
processInput(button: Button): boolean {
|
||||
const ui = this.getUi();
|
||||
|
||||
let success = false;
|
||||
@@ -134,6 +132,8 @@ export default class SettingsUiHandler extends UiHandler {
|
||||
|
||||
if (success)
|
||||
ui.playSelect();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
setCursor(cursor: integer): boolean {
|
||||
|
||||
@@ -301,10 +301,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
this.starterSelectMessageBoxContainer.setVisible(true);
|
||||
}
|
||||
|
||||
processInput(button: Button): void {
|
||||
processInput(button: Button): boolean {
|
||||
const ui = this.getUi();
|
||||
|
||||
let success = false;
|
||||
let error = false;
|
||||
|
||||
if (this.genMode) {
|
||||
switch (button) {
|
||||
@@ -323,7 +324,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
} else {
|
||||
if (button === Button.ACTION) {
|
||||
if (!this.speciesStarterDexEntry)
|
||||
ui.playError();
|
||||
error = true;
|
||||
else if (this.starterCursors.length < 3) {
|
||||
let isDupe = false;
|
||||
for (let s = 0; s < this.starterCursors.length; s++) {
|
||||
@@ -380,7 +381,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
success = true;
|
||||
this.updateInstructions();
|
||||
} else
|
||||
ui.playError();
|
||||
error = true;
|
||||
}
|
||||
} else if (button === Button.CANCEL) {
|
||||
if (this.starterCursors.length) {
|
||||
@@ -388,7 +389,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
success = true;
|
||||
this.updateInstructions();
|
||||
} else
|
||||
ui.playError();
|
||||
error = true;
|
||||
} else {
|
||||
const genStarters = this.starterSelectGenIconContainers[this.genCursor].getAll().length;
|
||||
const rows = Math.ceil(genStarters / 9);
|
||||
@@ -446,6 +447,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
|
||||
if (success)
|
||||
ui.playSelect();
|
||||
else if (error)
|
||||
ui.playError();
|
||||
|
||||
return success || error;
|
||||
}
|
||||
|
||||
updateInstructions(): void {
|
||||
|
||||
@@ -241,13 +241,14 @@ export default class SummaryUiHandler extends UiHandler {
|
||||
this.hideStatus(!fromSummary);
|
||||
}
|
||||
|
||||
processInput(button: Button) {
|
||||
processInput(button: Button): boolean {
|
||||
if (this.transitioning)
|
||||
return;
|
||||
return false;
|
||||
|
||||
const ui = this.getUi();
|
||||
|
||||
let success = false;
|
||||
let error = false;
|
||||
|
||||
if (this.moveSelect) {
|
||||
if (button === Button.ACTION) {
|
||||
@@ -283,9 +284,9 @@ export default class SummaryUiHandler extends UiHandler {
|
||||
}
|
||||
success = true;
|
||||
} else if (this.moveCursor === 4)
|
||||
this.processInput(Button.CANCEL);
|
||||
return this.processInput(Button.CANCEL);
|
||||
else
|
||||
ui.playError();
|
||||
error = true;
|
||||
} else if (button === Button.CANCEL) {
|
||||
this.hideMoveSelect();
|
||||
success = true;
|
||||
@@ -336,6 +337,10 @@ export default class SummaryUiHandler extends UiHandler {
|
||||
|
||||
if (success)
|
||||
ui.playSelect();
|
||||
else if (error)
|
||||
ui.playError();
|
||||
|
||||
return success || error;
|
||||
}
|
||||
|
||||
setCursor(cursor: integer): boolean {
|
||||
|
||||
@@ -41,7 +41,7 @@ export default class TargetSelectUiHandler extends UiHandler {
|
||||
this.setCursor(this.targets.indexOf(this.cursor) > -1 ? this.cursor : this.targets[0]);
|
||||
}
|
||||
|
||||
processInput(button: Button) {
|
||||
processInput(button: Button): boolean {
|
||||
const ui = this.getUi();
|
||||
|
||||
let success = false;
|
||||
@@ -72,6 +72,8 @@ export default class TargetSelectUiHandler extends UiHandler {
|
||||
|
||||
if (success)
|
||||
ui.playSelect();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
setCursor(cursor: integer): boolean {
|
||||
|
||||
+1
-1
@@ -107,7 +107,7 @@ export function getModifierTierTextTint(tier: integer): integer {
|
||||
case 1: // ModifierTier.GREAT:
|
||||
return 0x3890f8;
|
||||
case 2: // ModifierTier.ULTRA:
|
||||
return 0xf8d038
|
||||
return 0xf8d038;
|
||||
case 3: // ModifierTier.MASTER:
|
||||
return 0xe020c0;
|
||||
case 4: // ModifierTier.LUXURY:
|
||||
|
||||
+38
-16
@@ -15,8 +15,10 @@ import BiomeSelectUiHandler from './biome-select-ui-handler';
|
||||
import TargetSelectUiHandler from './target-select-ui-handler';
|
||||
import GameModeSelectUiHandler from './game-mode-select-ui-handler';
|
||||
import SettingsUiHandler from './settings-ui-handler';
|
||||
import { TextStyle, addTextObject, getTextColor } from './text';
|
||||
import { getPokeballTintColor } from '../data/pokeball';
|
||||
import { TextStyle, addTextObject } from './text';
|
||||
import AchvBar from './achv-bar';
|
||||
import MenuUiHandler from './menu-ui-handler';
|
||||
import AchvsUiHandler from './achvs-ui-handler';
|
||||
|
||||
export enum Mode {
|
||||
MESSAGE,
|
||||
@@ -32,7 +34,9 @@ export enum Mode {
|
||||
EVOLUTION_SCENE,
|
||||
CONFIRM,
|
||||
GAME_MODE_SELECT,
|
||||
SETTINGS
|
||||
MENU,
|
||||
SETTINGS,
|
||||
ACHIEVEMENTS
|
||||
};
|
||||
|
||||
const transitionModes = [
|
||||
@@ -45,14 +49,21 @@ const transitionModes = [
|
||||
const noTransitionModes = [
|
||||
Mode.CONFIRM,
|
||||
Mode.GAME_MODE_SELECT,
|
||||
Mode.MENU,
|
||||
Mode.SETTINGS
|
||||
];
|
||||
|
||||
const menuModes = [
|
||||
Mode.MENU,
|
||||
Mode.SETTINGS
|
||||
];
|
||||
|
||||
export default class UI extends Phaser.GameObjects.Container {
|
||||
private mode: Mode;
|
||||
private lastMode: Mode;
|
||||
private modeChain: Mode[];
|
||||
private handlers: UiHandler[];
|
||||
private overlay: Phaser.GameObjects.Rectangle;
|
||||
public achvBar: AchvBar;
|
||||
|
||||
private tooltipContainer: Phaser.GameObjects.Container;
|
||||
private tooltipBg: Phaser.GameObjects.NineSlice;
|
||||
@@ -65,6 +76,7 @@ export default class UI extends Phaser.GameObjects.Container {
|
||||
super(scene, 0, scene.game.canvas.height / 6);
|
||||
|
||||
this.mode = Mode.MESSAGE;
|
||||
this.modeChain = [];
|
||||
this.handlers = [
|
||||
new BattleMessageUiHandler(scene),
|
||||
new CommandUiHandler(scene),
|
||||
@@ -79,7 +91,9 @@ export default class UI extends Phaser.GameObjects.Container {
|
||||
new EvolutionSceneHandler(scene),
|
||||
new ConfirmUiHandler(scene),
|
||||
new GameModeSelectUiHandler(scene),
|
||||
new SettingsUiHandler(scene)
|
||||
new MenuUiHandler(scene),
|
||||
new SettingsUiHandler(scene),
|
||||
new AchvsUiHandler(scene)
|
||||
];
|
||||
}
|
||||
|
||||
@@ -91,6 +105,10 @@ export default class UI extends Phaser.GameObjects.Container {
|
||||
(this.scene as BattleScene).uiContainer.add(this.overlay);
|
||||
this.overlay.setVisible(false);
|
||||
this.setupTooltip();
|
||||
|
||||
this.achvBar = new AchvBar(this.scene as BattleScene);
|
||||
this.achvBar.setup();
|
||||
(this.scene as BattleScene).uiContainer.add(this.achvBar);
|
||||
}
|
||||
|
||||
private setupTooltip() {
|
||||
@@ -121,11 +139,11 @@ export default class UI extends Phaser.GameObjects.Container {
|
||||
return this.handlers[Mode.MESSAGE] as BattleMessageUiHandler;
|
||||
}
|
||||
|
||||
processInput(button: Button): void {
|
||||
processInput(button: Button): boolean {
|
||||
if (this.overlayActive)
|
||||
return;
|
||||
return false;
|
||||
|
||||
this.getHandler().processInput(button);
|
||||
return this.getHandler().processInput(button);
|
||||
}
|
||||
|
||||
showText(text: string, delay?: integer, callback?: Function, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer): void {
|
||||
@@ -229,7 +247,7 @@ export default class UI extends Phaser.GameObjects.Container {
|
||||
});
|
||||
}
|
||||
|
||||
private setModeInternal(mode: Mode, clear: boolean, forceTransition: boolean, args: any[]): Promise<void> {
|
||||
private setModeInternal(mode: Mode, clear: boolean, forceTransition: boolean, chainMode: boolean, args: any[]): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
if (this.mode === mode && !forceTransition) {
|
||||
resolve();
|
||||
@@ -239,7 +257,8 @@ export default class UI extends Phaser.GameObjects.Container {
|
||||
if (this.mode !== mode) {
|
||||
if (clear)
|
||||
this.getHandler().clear();
|
||||
this.lastMode = this.mode && !clear ? this.mode : undefined;
|
||||
if (chainMode && this.mode && !clear)
|
||||
this.modeChain.push(this.mode);
|
||||
this.mode = mode;
|
||||
this.getHandler().show(args);
|
||||
}
|
||||
@@ -263,23 +282,26 @@ export default class UI extends Phaser.GameObjects.Container {
|
||||
}
|
||||
|
||||
setMode(mode: Mode, ...args: any[]): Promise<void> {
|
||||
return this.setModeInternal(mode, true, false, args);
|
||||
return this.setModeInternal(mode, true, false, false, args);
|
||||
}
|
||||
|
||||
setModeForceTransition(mode: Mode, ...args: any[]): Promise<void> {
|
||||
return this.setModeInternal(mode, true, true, args);
|
||||
return this.setModeInternal(mode, true, true, false, args);
|
||||
}
|
||||
|
||||
setModeWithoutClear(mode: Mode, ...args: any[]): Promise<void> {
|
||||
return this.setModeInternal(mode, false, false, args);
|
||||
return this.setModeInternal(mode, false, false, false, args);
|
||||
}
|
||||
|
||||
setOverlayMode(mode: Mode, ...args: any[]): Promise<void> {
|
||||
return this.setModeInternal(mode, false, false, true, args);
|
||||
}
|
||||
|
||||
revertMode(): void {
|
||||
if (!this.lastMode)
|
||||
if (!this.modeChain.length)
|
||||
return;
|
||||
|
||||
this.getHandler().clear();
|
||||
this.mode = this.lastMode;
|
||||
this.lastMode = undefined;
|
||||
this.mode = this.modeChain.pop();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -18,7 +18,7 @@ export default abstract class UiHandler {
|
||||
this.active = true;
|
||||
}
|
||||
|
||||
abstract processInput(button: Button): void;
|
||||
abstract processInput(button: Button): boolean;
|
||||
|
||||
getUi() {
|
||||
return this.scene.ui;
|
||||
|
||||
+2
-4
@@ -134,11 +134,9 @@ export class NumberHolder {
|
||||
}
|
||||
}
|
||||
|
||||
export class IntegerHolder {
|
||||
public value: integer;
|
||||
|
||||
export class IntegerHolder extends NumberHolder {
|
||||
constructor(value: integer) {
|
||||
this.value = value;
|
||||
super(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user