Add egg gacha system and various minor changes
Add egg gacha system; remove certain mythical Pokemon from the wild pool as egg exclusive; add egg vouchers with UI; rework Shiny Charm odds; fix trainer Pokemon shiny odds not properly ignoring Shiny Charm modifier
This commit is contained in:
1 parent
50d4858caa
commit
aa94e044ab
71 files changed
+4303
-2241
No files matched your search
+8
-5
@@ -1,5 +1,6 @@
|
||||
import BattleScene from "../battle-scene";
|
||||
import { Achv } from "../system/achv";
|
||||
import { Voucher } from "../system/voucher";
|
||||
import { TextStyle, addTextObject } from "./text";
|
||||
|
||||
export default class AchvBar extends Phaser.GameObjects.Container {
|
||||
@@ -9,7 +10,7 @@ export default class AchvBar extends Phaser.GameObjects.Container {
|
||||
private scoreText: Phaser.GameObjects.Text;
|
||||
private descriptionText: Phaser.GameObjects.Text;
|
||||
|
||||
private queue: Achv[] = [];
|
||||
private queue: (Achv | Voucher)[] = [];
|
||||
|
||||
public shown: boolean;
|
||||
|
||||
@@ -47,7 +48,7 @@ export default class AchvBar extends Phaser.GameObjects.Container {
|
||||
this.shown = false;
|
||||
}
|
||||
|
||||
showAchv(achv: Achv): void {
|
||||
showAchv(achv: Achv | Voucher): void {
|
||||
if (this.shown) {
|
||||
this.queue.push(achv);
|
||||
return;
|
||||
@@ -56,10 +57,12 @@ export default class AchvBar extends Phaser.GameObjects.Container {
|
||||
const tier = achv.getTier();
|
||||
|
||||
this.bg.setTexture(`achv_bar${tier ? `_${tier + 1}` : ''}`);
|
||||
this.icon.setFrame(achv.iconImage);
|
||||
this.titleText.setText(achv.name);
|
||||
this.icon.setFrame(achv.getIconImage());
|
||||
this.titleText.setText(achv.getName());
|
||||
this.descriptionText.setText(achv.description);
|
||||
this.scoreText.setText(`+${achv.score}pt`);
|
||||
|
||||
if (achv instanceof Achv)
|
||||
this.scoreText.setText(`+${(achv as Achv).score}pt`);
|
||||
|
||||
(this.scene as BattleScene).playSound('achv');
|
||||
|
||||
|
||||
@@ -127,10 +127,10 @@ export default class CommandUiHandler extends UiHandler {
|
||||
|
||||
if (!this.cursorObj) {
|
||||
this.cursorObj = this.scene.add.image(0, 0, 'cursor');
|
||||
ui.add(this.cursorObj);
|
||||
this.commandsContainer.add(this.cursorObj);
|
||||
}
|
||||
|
||||
this.cursorObj.setPosition(211 + (cursor % 2 === 1 ? 56 : 0), -31 + (cursor >= 2 ? 16 : 0));
|
||||
this.cursorObj.setPosition(-5 + (cursor % 2 === 1 ? 56 : 0), 8 + (cursor >= 2 ? 16 : 0));
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,600 @@
|
||||
import BattleScene, { Button } from "../battle-scene";
|
||||
import { Mode } from "./ui";
|
||||
import { TextStyle, addTextObject, getModifierTierTextTint } from "./text";
|
||||
import MessageUiHandler from "./message-ui-handler";
|
||||
import * as Utils from "../utils";
|
||||
import { ModifierTier } from "../modifier/modifier-type";
|
||||
import { EGG_SEED, Egg, GachaType, getEggTierDefaultHatchWaves, getEggDescriptor, getLegendaryGachaSpeciesForTimestamp, getTypeGachaTypeForTimestamp } from "../data/egg";
|
||||
import { VoucherType, getVoucherTypeIcon } from "../system/voucher";
|
||||
import { getPokemonSpecies } from "../data/pokemon-species";
|
||||
import { Type } from "../data/type";
|
||||
|
||||
const defaultText = 'Select a machine.';
|
||||
|
||||
export default class EggGachaUiHandler extends MessageUiHandler {
|
||||
private eggGachaContainer: Phaser.GameObjects.Container;
|
||||
private eggGachaMessageBox: Phaser.GameObjects.NineSlice;
|
||||
private eggGachaOptionsContainer: Phaser.GameObjects.Container;
|
||||
private eggGachaOptionSelectBg: Phaser.GameObjects.NineSlice;
|
||||
|
||||
private gachaContainers: Phaser.GameObjects.Container[];
|
||||
private gachaKnobs: Phaser.GameObjects.Sprite[];
|
||||
private gachaHatches: Phaser.GameObjects.Sprite[];
|
||||
private gachaInfoContainers: Phaser.GameObjects.Container[];
|
||||
private eggGachaOverlay: Phaser.GameObjects.Rectangle;
|
||||
private eggGachaSummaryContainer: Phaser.GameObjects.Container;
|
||||
|
||||
private voucherCountLabels: Phaser.GameObjects.Text[];
|
||||
|
||||
private gachaCursor: integer;
|
||||
|
||||
private cursorObj: Phaser.GameObjects.Image;
|
||||
private transitioning: boolean;
|
||||
private transitionCancelled: boolean;
|
||||
|
||||
constructor(scene: BattleScene) {
|
||||
super(scene, Mode.EGG_GACHA);
|
||||
|
||||
this.gachaContainers = [];
|
||||
this.gachaKnobs = [];
|
||||
this.gachaHatches = [];
|
||||
this.gachaInfoContainers = [];
|
||||
|
||||
this.voucherCountLabels = [];
|
||||
}
|
||||
|
||||
setup() {
|
||||
this.gachaCursor = 0;
|
||||
|
||||
const ui = this.getUi();
|
||||
|
||||
this.eggGachaContainer = this.scene.add.container(0, -this.scene.game.canvas.height / 6);
|
||||
this.eggGachaContainer.setVisible(false);
|
||||
ui.add(this.eggGachaContainer);
|
||||
|
||||
const bg = this.scene.add.nineslice(0, 0, 'default_bg', null, 320, 180, 0, 0, 16, 0);
|
||||
bg.setOrigin(0, 0);
|
||||
|
||||
this.eggGachaContainer.add(bg);
|
||||
|
||||
const hatchFrameNames = this.scene.anims.generateFrameNames('gacha_hatch', { suffix: ".png", start: 1, end: 4 });
|
||||
this.scene.anims.create({
|
||||
key: 'open',
|
||||
frames: hatchFrameNames,
|
||||
frameRate: 12
|
||||
});
|
||||
this.scene.anims.create({
|
||||
key: 'close',
|
||||
frames: hatchFrameNames.reverse(),
|
||||
frameRate: 12
|
||||
});
|
||||
|
||||
Utils.getEnumValues(GachaType).forEach((gachaType, g) => {
|
||||
const gachaTypeKey = GachaType[gachaType].toString().toLowerCase();
|
||||
const gachaContainer = this.scene.add.container(180 * g, 18);
|
||||
|
||||
const gacha = this.scene.add.sprite(0, 0, `gacha_${gachaTypeKey}`);
|
||||
gacha.setOrigin(0, 0);
|
||||
|
||||
const gachaUnderlay = this.scene.add.sprite(115, 80, `gacha_underlay_${gachaTypeKey}`);
|
||||
gachaUnderlay.setOrigin(0, 0);
|
||||
|
||||
const gachaGlass = this.scene.add.sprite(0, 0, 'gacha_glass');
|
||||
gachaGlass.setOrigin(0, 0);
|
||||
|
||||
const gachaInfoContainer = this.scene.add.container(160, 46);
|
||||
|
||||
const gachaUpLabel = addTextObject(this.scene, 4, 0, 'UP!', TextStyle.WINDOW);
|
||||
gachaUpLabel.setOrigin(0, 0);
|
||||
gachaInfoContainer.add(gachaUpLabel);
|
||||
|
||||
switch (gachaType as GachaType) {
|
||||
case GachaType.LEGENDARY:
|
||||
const pokemonIcon = this.scene.add.sprite(-20, 6, 'pokemon_icons_0');
|
||||
pokemonIcon.setScale(0.5);
|
||||
pokemonIcon.setOrigin(0, 0.5);
|
||||
|
||||
gachaInfoContainer.add(pokemonIcon);
|
||||
break;
|
||||
case GachaType.TYPE:
|
||||
const typeIcon = this.scene.add.sprite(-22, 7, 'types', 'unknown');
|
||||
typeIcon.setScale(0.75);
|
||||
typeIcon.setOrigin(0, 0.5);
|
||||
|
||||
gachaUpLabel.x += 4;
|
||||
|
||||
gachaInfoContainer.add(typeIcon);
|
||||
break;
|
||||
case GachaType.SHINY:
|
||||
gachaUpLabel.setText('Shiny UP!');
|
||||
gachaUpLabel.setX(0);
|
||||
gachaUpLabel.setOrigin(0.5, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
const gachaKnob = this.scene.add.sprite(191, 89, 'gacha_knob');
|
||||
|
||||
const gachaHatch = this.scene.add.sprite(115, 73, 'gacha_hatch');
|
||||
gachaHatch.setOrigin(0, 0);
|
||||
|
||||
gachaContainer.add(gachaUnderlay);
|
||||
gachaContainer.add(gacha);
|
||||
gachaContainer.add(gachaGlass);
|
||||
gachaContainer.add(gachaKnob);
|
||||
gachaContainer.add(gachaHatch);
|
||||
gachaContainer.add(gachaInfoContainer);
|
||||
|
||||
gachaGlass.setAlpha(0.5);
|
||||
gachaHatch.setAlpha(0.9);
|
||||
|
||||
gachaHatch.on('animationupdate', (_anim, frame) => gachaUnderlay.setFrame(frame.textureFrame === '4.png' ? 'open_hatch' : 'default'));
|
||||
|
||||
this.gachaContainers.push(gachaContainer);
|
||||
this.gachaKnobs.push(gachaKnob);
|
||||
this.gachaHatches.push(gachaHatch);
|
||||
this.gachaInfoContainers.push(gachaInfoContainer);
|
||||
|
||||
this.eggGachaContainer.add(gachaContainer);
|
||||
|
||||
this.updateGachaInfo(g);
|
||||
});
|
||||
|
||||
this.eggGachaOptionsContainer = this.scene.add.container()
|
||||
|
||||
this.eggGachaOptionsContainer = this.scene.add.container((this.scene.game.canvas.width / 6), 148);
|
||||
this.eggGachaContainer.add(this.eggGachaOptionsContainer);
|
||||
|
||||
this.eggGachaOptionSelectBg = this.scene.add.nineslice(0, 0, 'window', null, 96, 96, 6, 6, 6, 6);
|
||||
this.eggGachaOptionSelectBg.setOrigin(1, 1);
|
||||
this.eggGachaOptionsContainer.add(this.eggGachaOptionSelectBg);
|
||||
|
||||
const optionText = addTextObject(this.scene, 0, 0, ' x1 1 Pull\n x10 10 Pulls\n x1 5 Pulls\n x1 10 Pulls\nCancel', TextStyle.WINDOW, { maxLines: 5 });
|
||||
optionText.setLineSpacing(12);
|
||||
this.eggGachaOptionsContainer.add(optionText);
|
||||
|
||||
optionText.setPositionRelative(this.eggGachaOptionSelectBg, 16, 9);
|
||||
|
||||
new Array(4).fill(null).map((_, i) => {
|
||||
const voucherType = i < 2 ? VoucherType.REGULAR : i === 2 ? VoucherType.PLUS : VoucherType.PREMIUM;
|
||||
const icon = this.scene.add.sprite(0, 0, 'items', getVoucherTypeIcon(voucherType));
|
||||
icon.setScale(0.5);
|
||||
icon.setPositionRelative(this.eggGachaOptionSelectBg, 20, 17 + i * 16);
|
||||
this.eggGachaOptionsContainer.add(icon);
|
||||
});
|
||||
|
||||
this.eggGachaContainer.add(this.eggGachaOptionsContainer);
|
||||
|
||||
new Array(Utils.getEnumKeys(VoucherType).length).fill(null).map((_, i) => {
|
||||
const container = this.scene.add.container((this.scene.game.canvas.width / 6) - 56 * i, 0);
|
||||
|
||||
const bg = this.scene.add.nineslice(0, 0, 'window', null, 56, 22, 6, 6, 6, 6);
|
||||
bg.setOrigin(1, 0);
|
||||
container.add(bg);
|
||||
|
||||
const countLabel = addTextObject(this.scene, -48, 3, '0', TextStyle.WINDOW);
|
||||
countLabel.setOrigin(0, 0);
|
||||
container.add(countLabel);
|
||||
|
||||
this.voucherCountLabels.push(countLabel);
|
||||
|
||||
const iconImage = getVoucherTypeIcon(i as VoucherType);
|
||||
|
||||
const icon = this.scene.add.sprite(-19, 2, 'items', iconImage);
|
||||
icon.setOrigin(0, 0);
|
||||
icon.setScale(0.5);
|
||||
container.add(icon);
|
||||
|
||||
this.eggGachaContainer.add(container);
|
||||
});
|
||||
|
||||
this.eggGachaOverlay = this.scene.add.rectangle(0, 0, bg.displayWidth, bg.displayHeight, 0x000000);
|
||||
this.eggGachaOverlay.setOrigin(0, 0);
|
||||
this.eggGachaOverlay.setAlpha(0);
|
||||
|
||||
this.eggGachaContainer.add(this.eggGachaOverlay);
|
||||
|
||||
this.eggGachaSummaryContainer = this.scene.add.container(0, 0);
|
||||
this.eggGachaSummaryContainer.setVisible(false);
|
||||
this.eggGachaContainer.add(this.eggGachaSummaryContainer);
|
||||
|
||||
const gachaMessageBoxContainer = this.scene.add.container(0, 148);
|
||||
this.eggGachaContainer.add(gachaMessageBoxContainer);
|
||||
|
||||
const gachaMessageBox = this.scene.add.nineslice(0, 0, 'window', null, 320, 32, 6, 6, 6, 6);
|
||||
gachaMessageBox.setOrigin(0, 0);
|
||||
gachaMessageBoxContainer.add(gachaMessageBox);
|
||||
|
||||
this.eggGachaMessageBox = gachaMessageBox;
|
||||
|
||||
const gachaMessageText = addTextObject(this.scene, 8, 8, '', TextStyle.WINDOW, { maxLines: 2 });
|
||||
gachaMessageText.setOrigin(0, 0);
|
||||
gachaMessageBoxContainer.add(gachaMessageText);
|
||||
|
||||
this.message = gachaMessageText;
|
||||
|
||||
this.eggGachaContainer.add(gachaMessageBoxContainer);
|
||||
|
||||
this.setCursor(0);
|
||||
}
|
||||
|
||||
show(args: any[]): void {
|
||||
super.show(args);
|
||||
|
||||
this.getUi().showText(defaultText, 0);
|
||||
|
||||
this.setGachaCursor(1);
|
||||
|
||||
for (let g = 0; g < this.gachaContainers.length; g++)
|
||||
this.updateGachaInfo(g);
|
||||
|
||||
this.updateVoucherCounts();
|
||||
|
||||
this.eggGachaContainer.setVisible(true);
|
||||
}
|
||||
|
||||
getDelayValue(delay: integer) {
|
||||
if (this.transitioning && this.transitionCancelled)
|
||||
delay = Math.ceil(delay / 5);
|
||||
return Utils.fixedInt(delay);
|
||||
}
|
||||
|
||||
pull(pullCount?: integer, count?: integer, eggs?: Egg[]) {
|
||||
this.eggGachaOptionsContainer.setVisible(false);
|
||||
this.setTransitioning(true);
|
||||
|
||||
if (!pullCount)
|
||||
pullCount = 1;
|
||||
if (!count)
|
||||
count = 0;
|
||||
if (!eggs) {
|
||||
eggs = [];
|
||||
|
||||
const tiers = new Array(pullCount).fill(null).map(() => {
|
||||
const tierValue = Utils.randInt(256);
|
||||
return tierValue >= 52 ? ModifierTier.COMMON : tierValue >= 8 ? ModifierTier.GREAT : tierValue >= 1 ? ModifierTier.ULTRA : ModifierTier.MASTER;
|
||||
});
|
||||
/*if (pullCount >= 100 && !tiers.filter(t => t >= ModifierTier.ULTRA).length)
|
||||
tiers[Utils.randInt(tiers.length)] = ModifierTier.ULTRA;*/
|
||||
if (pullCount >= 10 && !tiers.filter(t => t >= ModifierTier.GREAT).length)
|
||||
tiers[Utils.randInt(tiers.length)] = ModifierTier.GREAT;
|
||||
|
||||
const timestamp = new Date().getTime();
|
||||
|
||||
for (let tier of tiers) {
|
||||
const egg = new Egg(Utils.randInt(EGG_SEED, EGG_SEED * tier), this.gachaCursor, getEggTierDefaultHatchWaves(tier), timestamp);
|
||||
if (egg.isManaphyEgg())
|
||||
egg.hatchWaves = getEggTierDefaultHatchWaves(ModifierTier.ULTRA);
|
||||
eggs.push(egg);
|
||||
this.scene.gameData.eggs.push(egg);
|
||||
}
|
||||
|
||||
this.scene.gameData.saveSystem();
|
||||
}
|
||||
|
||||
if (this.transitionCancelled) {
|
||||
return this.showSummary(eggs);
|
||||
}
|
||||
|
||||
const egg = this.scene.add.sprite(127, 75, 'egg', `egg_${eggs[count].getKey()}`);
|
||||
egg.setScale(0.5);
|
||||
|
||||
this.gachaContainers[this.gachaCursor].add(egg);
|
||||
this.gachaContainers[this.gachaCursor].moveTo(egg, 1);
|
||||
|
||||
const doPullAnim = () => {
|
||||
this.scene.playSound('gacha_running', { loop: true });
|
||||
this.scene.time.delayedCall(this.getDelayValue(count ? 500 : 1250), () => {
|
||||
this.scene.playSound('gacha_dispense');
|
||||
this.scene.time.delayedCall(this.getDelayValue(750), () => {
|
||||
this.scene.sound.stopByKey('gacha_running');
|
||||
this.scene.tweens.add({
|
||||
targets: egg,
|
||||
duration: this.getDelayValue(350),
|
||||
y: 95,
|
||||
ease: 'Bounce.easeOut',
|
||||
onComplete: () => {
|
||||
this.scene.time.delayedCall(this.getDelayValue(125), () => {
|
||||
this.scene.playSound('pb_catch');
|
||||
this.gachaHatches[this.gachaCursor].play('open');
|
||||
this.scene.tweens.add({
|
||||
targets: egg,
|
||||
duration: this.getDelayValue(350),
|
||||
scale: 0.75,
|
||||
ease: 'Sine.easeIn'
|
||||
});
|
||||
this.scene.tweens.add({
|
||||
targets: egg,
|
||||
y: 110,
|
||||
duration: this.getDelayValue(350),
|
||||
ease: 'Back.easeOut',
|
||||
onComplete: () => {
|
||||
this.gachaHatches[this.gachaCursor].play('close');
|
||||
this.scene.tweens.add({
|
||||
targets: egg,
|
||||
y: 200,
|
||||
duration: this.getDelayValue(350),
|
||||
ease: 'Cubic.easeIn',
|
||||
onComplete: () => {
|
||||
if (++count < pullCount)
|
||||
this.pull(pullCount, count, eggs);
|
||||
else
|
||||
this.showSummary(eggs);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
if (!count) {
|
||||
this.scene.playSound('gacha_dial');
|
||||
this.scene.tweens.add({
|
||||
targets: this.gachaKnobs[this.gachaCursor],
|
||||
duration: this.getDelayValue(350),
|
||||
angle: 90,
|
||||
ease: 'Cubic.easeInOut',
|
||||
onComplete: () => {
|
||||
this.scene.tweens.add({
|
||||
targets: this.gachaKnobs[this.gachaCursor],
|
||||
duration: this.getDelayValue(350),
|
||||
angle: 0,
|
||||
ease: 'Sine.easeInOut'
|
||||
});
|
||||
this.scene.time.delayedCall(this.getDelayValue(350), doPullAnim);
|
||||
}
|
||||
});
|
||||
} else
|
||||
doPullAnim();
|
||||
}
|
||||
|
||||
showSummary(eggs: Egg[]): void {
|
||||
this.transitioning = false;
|
||||
this.eggGachaSummaryContainer.setVisible(true);
|
||||
|
||||
this.scene.tweens.add({
|
||||
targets: this.eggGachaOverlay,
|
||||
alpha: 0.5,
|
||||
ease: 'Sine.easeOut',
|
||||
duration: 750,
|
||||
onComplete: () => {
|
||||
const rows = Math.ceil(eggs.length / 5);
|
||||
const cols = Math.min(eggs.length, 5);
|
||||
const height = this.eggGachaOverlay.displayHeight - this.eggGachaMessageBox.displayHeight;
|
||||
const eggContainers = eggs.map((egg, t) => {
|
||||
const col = t % 5;
|
||||
const row = Math.floor(t / 5);
|
||||
const sliceWidth = this.eggGachaOverlay.displayWidth / (cols + 2);
|
||||
const sliceHeight = height / (rows + 2);
|
||||
const yOffset = (sliceHeight / 2 * (row / Math.max(rows - 1, 1))) + sliceHeight / 4;
|
||||
const ret = this.scene.add.container(sliceWidth * (col + 1) + (sliceWidth * 0.5), sliceHeight * (row + 1) + yOffset);
|
||||
ret.setScale(0.0001);
|
||||
|
||||
const eggSprite = this.scene.add.sprite(0, 0, 'egg', `egg_${egg.getKey()}`);
|
||||
ret.add(eggSprite);
|
||||
|
||||
const eggText = addTextObject(this.scene, 0, 14, getEggDescriptor(egg), TextStyle.PARTY, { align: 'center' });
|
||||
eggText.setOrigin(0.5, 0);
|
||||
eggText.setTint(getModifierTierTextTint(!egg.isManaphyEgg() ? egg.tier : ModifierTier.ULTRA));
|
||||
ret.add(eggText);
|
||||
|
||||
this.eggGachaSummaryContainer.add(ret);
|
||||
return ret;
|
||||
});
|
||||
|
||||
eggContainers.forEach((eggContainer, e) => {
|
||||
this.scene.tweens.add({
|
||||
targets: eggContainer,
|
||||
delay: this.getDelayValue(e * 100),
|
||||
duration: this.getDelayValue(350),
|
||||
scale: 1,
|
||||
ease: 'Sine.easeOut'
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
hideSummary() {
|
||||
this.setTransitioning(true);
|
||||
this.scene.tweens.add({
|
||||
targets: [ this.eggGachaOverlay, this.eggGachaSummaryContainer ],
|
||||
alpha: 0,
|
||||
duration: this.getDelayValue(250),
|
||||
ease: 'Cubic.easeIn',
|
||||
onComplete: () => {
|
||||
this.eggGachaSummaryContainer.setVisible(false);
|
||||
this.eggGachaSummaryContainer.setAlpha(1);
|
||||
this.eggGachaSummaryContainer.removeAll(true);
|
||||
this.setTransitioning(false);
|
||||
this.eggGachaOptionsContainer.setVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateGachaInfo(gachaType: GachaType): void {
|
||||
const infoContainer = this.gachaInfoContainers[gachaType];
|
||||
switch (gachaType as GachaType) {
|
||||
case GachaType.LEGENDARY:
|
||||
const species = getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(this.scene, new Date().getTime()));
|
||||
const pokemonIcon = infoContainer.getAt(1) as Phaser.GameObjects.Sprite;
|
||||
pokemonIcon.setTexture(species.getIconAtlasKey(), species.getIconId(false));
|
||||
break;
|
||||
case GachaType.TYPE:
|
||||
const typeIcon = infoContainer.getAt(1) as Phaser.GameObjects.Sprite;
|
||||
typeIcon.setFrame(Type[getTypeGachaTypeForTimestamp(this.scene, new Date().getTime())].toLowerCase());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
consumeVouchers(voucherType: VoucherType, count: integer): void {
|
||||
this.scene.gameData.voucherCounts[voucherType] = Math.max(this.scene.gameData.voucherCounts[voucherType] - count, 0);
|
||||
this.updateVoucherCounts();
|
||||
}
|
||||
|
||||
updateVoucherCounts(): void {
|
||||
this.voucherCountLabels.forEach((label, type) => {
|
||||
label.setText(this.scene.gameData.voucherCounts[type].toString());
|
||||
});
|
||||
}
|
||||
|
||||
showError(text: string): void {
|
||||
this.showText(text, null, () => this.showText(defaultText), Utils.fixedInt(1500));
|
||||
}
|
||||
|
||||
setTransitioning(transitioning: boolean): void {
|
||||
if (this.transitioning === transitioning)
|
||||
return;
|
||||
this.transitioning = transitioning;
|
||||
this.transitionCancelled = false;
|
||||
}
|
||||
|
||||
processInput(button: Button): boolean {
|
||||
const ui = this.getUi();
|
||||
|
||||
let success = false;
|
||||
let error = false;
|
||||
|
||||
if (this.transitioning) {
|
||||
if (!this.transitionCancelled && (button === Button.ACTION || button === Button.CANCEL)) {
|
||||
this.transitionCancelled = true;
|
||||
success = true;
|
||||
} else
|
||||
return false;
|
||||
} else {
|
||||
|
||||
if (this.eggGachaSummaryContainer.visible) {
|
||||
if (button === Button.ACTION || button === Button.CANCEL) {
|
||||
this.hideSummary();
|
||||
success = true;
|
||||
}
|
||||
} else {
|
||||
switch (button) {
|
||||
case Button.ACTION:
|
||||
switch (this.cursor) {
|
||||
case 0:
|
||||
if (!this.scene.gameData.voucherCounts[VoucherType.REGULAR]) {
|
||||
error = true;
|
||||
this.showError('You don\'t have enough vouchers!');
|
||||
} else if (this.scene.gameData.eggs.length < 99) {
|
||||
this.consumeVouchers(VoucherType.REGULAR, 1);
|
||||
this.pull();
|
||||
success = true;
|
||||
} else {
|
||||
error = true;
|
||||
this.showError('You have too many eggs!');
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (!this.scene.gameData.voucherCounts[VoucherType.PLUS]) {
|
||||
error = true;
|
||||
this.showError('You don\'t have enough vouchers!');
|
||||
} else if (this.scene.gameData.eggs.length < 95) {
|
||||
this.consumeVouchers(VoucherType.PLUS, 1);
|
||||
this.pull(5);
|
||||
success = true;
|
||||
} else {
|
||||
error = true;
|
||||
this.showError('You have too many eggs!');
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
case 3:
|
||||
if ((this.cursor === 1 && this.scene.gameData.voucherCounts[VoucherType.REGULAR] < 10)
|
||||
|| (this.cursor === 3 && !this.scene.gameData.voucherCounts[VoucherType.PREMIUM])) {
|
||||
error = true;
|
||||
this.showError('You don\'t have enough vouchers!');
|
||||
} else if (this.scene.gameData.eggs.length < 90) {
|
||||
if (this.cursor === 3)
|
||||
this.consumeVouchers(VoucherType.PREMIUM, 1);
|
||||
else
|
||||
this.consumeVouchers(VoucherType.REGULAR, 10);
|
||||
this.pull(10);
|
||||
success = true;
|
||||
} else {
|
||||
error = true;
|
||||
this.showError('You have too many eggs!');
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
ui.revertMode();
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Button.CANCEL:
|
||||
this.getUi().revertMode();
|
||||
success = true;
|
||||
break;
|
||||
case Button.UP:
|
||||
if (this.cursor)
|
||||
success = this.setCursor(this.cursor - 1);
|
||||
break;
|
||||
case Button.DOWN:
|
||||
if (this.cursor < 4)
|
||||
success = this.setCursor(this.cursor + 1);
|
||||
break;
|
||||
case Button.LEFT:
|
||||
if (this.gachaCursor)
|
||||
success = this.setGachaCursor(this.gachaCursor - 1);
|
||||
break;
|
||||
case Button.RIGHT:
|
||||
if (this.gachaCursor < Utils.getEnumKeys(GachaType).length - 1)
|
||||
success = this.setGachaCursor(this.gachaCursor + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (success)
|
||||
ui.playSelect();
|
||||
else if (error)
|
||||
ui.playError();
|
||||
|
||||
return success || error;
|
||||
}
|
||||
|
||||
setCursor(cursor: integer): boolean {
|
||||
const ret = super.setCursor(cursor);
|
||||
|
||||
if (!this.cursorObj) {
|
||||
this.cursorObj = this.scene.add.image(0, 0, 'cursor');
|
||||
this.eggGachaOptionsContainer.add(this.cursorObj);
|
||||
}
|
||||
|
||||
this.cursorObj.setPositionRelative(this.eggGachaOptionSelectBg, 10, 17 + this.cursor * 16);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
setGachaCursor(cursor: integer): boolean {
|
||||
let oldCursor = this.gachaCursor;
|
||||
|
||||
let changed = oldCursor !== cursor;
|
||||
|
||||
if (changed) {
|
||||
this.gachaCursor = cursor;
|
||||
|
||||
this.setTransitioning(true);
|
||||
|
||||
this.scene.tweens.add({
|
||||
targets: this.gachaContainers,
|
||||
duration: this.eggGachaContainer.visible ? 500 : 0,
|
||||
x: (_target, _key, _value, index) => 180 * (index - cursor),
|
||||
ease: 'Cubic.easeInOut',
|
||||
onComplete: () => this.setTransitioning(false)
|
||||
});
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
super.clear();
|
||||
this.setGachaCursor(-1);
|
||||
this.eggGachaContainer.setVisible(false);
|
||||
}
|
||||
}
|
||||
@@ -3,39 +3,40 @@ import { Mode } from "./ui";
|
||||
import UiHandler from "./uiHandler";
|
||||
|
||||
export default class EggHatchSceneHandler extends UiHandler {
|
||||
public eggHatchContainer: Phaser.GameObjects.Container;
|
||||
public eggHatchContainer: Phaser.GameObjects.Container;
|
||||
|
||||
constructor(scene: BattleScene) {
|
||||
super(scene, Mode.EGG_HATCH_SCENE);
|
||||
}
|
||||
|
||||
setup() {
|
||||
this.eggHatchContainer = this.scene.add.container(0, -this.scene.game.canvas.height / 6);
|
||||
this.scene.fieldUI.add(this.eggHatchContainer);
|
||||
constructor(scene: BattleScene) {
|
||||
super(scene, Mode.EGG_HATCH_SCENE);
|
||||
}
|
||||
|
||||
const eggLightraysAnimFrames = this.scene.anims.generateFrameNames('egg_lightrays', { start: 0, end: 3 });
|
||||
this.scene.anims.create({
|
||||
key: 'egg_lightrays',
|
||||
frames: eggLightraysAnimFrames,
|
||||
frameRate: 32
|
||||
});
|
||||
}
|
||||
setup() {
|
||||
this.eggHatchContainer = this.scene.add.container(0, -this.scene.game.canvas.height / 6);
|
||||
this.scene.fieldUI.add(this.eggHatchContainer);
|
||||
|
||||
show(_args: any[]): void {
|
||||
super.show(_args);
|
||||
|
||||
this.scene.fieldUI.bringToTop(this.eggHatchContainer);
|
||||
}
|
||||
|
||||
processInput(button: Button): boolean {
|
||||
return this.scene.ui.getMessageHandler().processInput(button);
|
||||
}
|
||||
|
||||
setCursor(_cursor: integer): boolean {
|
||||
return false;
|
||||
}
|
||||
const eggLightraysAnimFrames = this.scene.anims.generateFrameNames('egg_lightrays', { start: 0, end: 3 });
|
||||
this.scene.anims.create({
|
||||
key: 'egg_lightrays',
|
||||
frames: eggLightraysAnimFrames,
|
||||
frameRate: 32
|
||||
});
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.eggHatchContainer.removeAll(true);
|
||||
}
|
||||
}
|
||||
show(_args: any[]): void {
|
||||
super.show(_args);
|
||||
|
||||
this.getUi().showText(null, 0);
|
||||
}
|
||||
|
||||
processInput(button: Button): boolean {
|
||||
return this.scene.ui.getMessageHandler().processInput(button);
|
||||
}
|
||||
|
||||
setCursor(_cursor: integer): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
clear() {
|
||||
super.clear();
|
||||
this.eggHatchContainer.removeAll(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
import BattleScene, { Button } from "../battle-scene";
|
||||
import { Mode } from "./ui";
|
||||
import PokemonIconAnimHandler, { PokemonIconAnimMode } from "./pokemon-icon-anim-handler";
|
||||
import { TextStyle, addTextObject } from "./text";
|
||||
import MessageUiHandler from "./message-ui-handler";
|
||||
import { EGG_SEED, Egg, GachaType, getEggGachaTypeDescriptor, getEggHatchWavesMessage, getEggDescriptor } from "../data/egg";
|
||||
import * as Utils from "../utils";
|
||||
|
||||
export default class EggListUiHandler extends MessageUiHandler {
|
||||
private eggListContainer: Phaser.GameObjects.Container;
|
||||
private eggListIconContainer: Phaser.GameObjects.Container;
|
||||
private eggSprite: Phaser.GameObjects.Sprite;
|
||||
private eggNameText: Phaser.GameObjects.Text;
|
||||
private eggDateText: Phaser.GameObjects.Text;
|
||||
private eggHatchWavesText: Phaser.GameObjects.Text;
|
||||
private eggGachaInfoText: Phaser.GameObjects.Text;
|
||||
private eggListMessageBoxContainer: Phaser.GameObjects.Container;
|
||||
|
||||
private cursorObj: Phaser.GameObjects.Image;
|
||||
|
||||
private iconAnimHandler: PokemonIconAnimHandler;
|
||||
|
||||
constructor(scene: BattleScene) {
|
||||
super(scene, Mode.EGG_LIST);
|
||||
}
|
||||
|
||||
setup() {
|
||||
const ui = this.getUi();
|
||||
|
||||
this.eggListContainer = this.scene.add.container(0, -this.scene.game.canvas.height / 6);
|
||||
this.eggListContainer.setVisible(false);
|
||||
ui.add(this.eggListContainer);
|
||||
|
||||
const bgColor = this.scene.add.rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6, 0x006860);
|
||||
bgColor.setOrigin(0, 0);
|
||||
this.eggListContainer.add(bgColor);
|
||||
|
||||
const starterSelectBg = this.scene.add.image(1, 1, 'egg_list_bg');
|
||||
starterSelectBg.setOrigin(0, 0);
|
||||
this.eggListContainer.add(starterSelectBg);
|
||||
|
||||
this.iconAnimHandler = new PokemonIconAnimHandler();
|
||||
this.iconAnimHandler.setup(this.scene);
|
||||
|
||||
this.eggNameText = addTextObject(this.scene, 6, 66, '', TextStyle.SUMMARY);
|
||||
this.eggNameText.setOrigin(0, 0);
|
||||
this.eggListContainer.add(this.eggNameText);
|
||||
|
||||
this.eggDateText = addTextObject(this.scene, 8, 91, '', TextStyle.TOOLTIP_CONTENT);
|
||||
this.eggListContainer.add(this.eggDateText);
|
||||
|
||||
this.eggHatchWavesText = addTextObject(this.scene, 8, 108, '', TextStyle.TOOLTIP_CONTENT);
|
||||
this.eggHatchWavesText.setWordWrapWidth(540);
|
||||
this.eggListContainer.add(this.eggHatchWavesText);
|
||||
|
||||
this.eggGachaInfoText = addTextObject(this.scene, 8, 152, '', TextStyle.TOOLTIP_CONTENT);
|
||||
this.eggGachaInfoText.setWordWrapWidth(540);
|
||||
this.eggListContainer.add(this.eggGachaInfoText);
|
||||
|
||||
this.eggListIconContainer = this.scene.add.container(115, 9);
|
||||
this.eggListContainer.add(this.eggListIconContainer);
|
||||
|
||||
this.cursorObj = this.scene.add.image(0, 0, 'starter_select_cursor');
|
||||
this.cursorObj.setOrigin(0, 0);
|
||||
this.eggListContainer.add(this.cursorObj);
|
||||
|
||||
this.eggSprite = this.scene.add.sprite(54, 37, `egg`);
|
||||
this.eggListContainer.add(this.eggSprite);
|
||||
|
||||
this.eggListMessageBoxContainer = this.scene.add.container(0, this.scene.game.canvas.height / 6);
|
||||
this.eggListMessageBoxContainer.setVisible(false);
|
||||
this.eggListContainer.add(this.eggListMessageBoxContainer);
|
||||
|
||||
const starterSelectMessageBox = this.scene.add.image(0, 0, 'starter_select_message');
|
||||
starterSelectMessageBox.setOrigin(0, 1);
|
||||
this.eggListMessageBoxContainer.add(starterSelectMessageBox);
|
||||
|
||||
this.message = addTextObject(this.scene, 8, -8, '', TextStyle.WINDOW, { maxLines: 1 });
|
||||
this.message.setOrigin(0, 1);
|
||||
this.eggListMessageBoxContainer.add(this.message);
|
||||
|
||||
this.cursor = -1;
|
||||
}
|
||||
|
||||
show(args: any[]): void {
|
||||
super.show(args);
|
||||
|
||||
this.eggListContainer.setVisible(true);
|
||||
|
||||
let e = 0;
|
||||
|
||||
/*this.scene.gameData.eggs = [
|
||||
new Egg(1, 1, 5, new Date().getTime()),
|
||||
new Egg(1 + EGG_SEED, 1, 15, new Date().getTime()),
|
||||
new Egg(1 + EGG_SEED * 2, 1, 50, new Date().getTime()),
|
||||
new Egg(1 + EGG_SEED * 3, GachaType.LEGENDARY, 100, new Date().getTime())
|
||||
];*/
|
||||
|
||||
for (let egg of this.scene.gameData.eggs) {
|
||||
const x = (e % 11) * 18;
|
||||
const y = Math.floor(e / 11) * 18;
|
||||
const icon = this.scene.add.sprite(x - 2, y + 2, 'egg_icons');
|
||||
icon.setScale(0.5);
|
||||
icon.setOrigin(0, 0);
|
||||
icon.setFrame(egg.getKey());
|
||||
this.eggListIconContainer.add(icon);
|
||||
this.iconAnimHandler.addOrUpdate(icon, PokemonIconAnimMode.NONE);
|
||||
e++;
|
||||
}
|
||||
|
||||
this.setCursor(0);
|
||||
}
|
||||
|
||||
showText(text: string, delay?: integer, callback?: Function, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer) {
|
||||
super.showText(text, delay, callback, callbackDelay, prompt, promptDelay);
|
||||
}
|
||||
|
||||
processInput(button: Button): boolean {
|
||||
const ui = this.getUi();
|
||||
|
||||
let success = false;
|
||||
let error = false;
|
||||
|
||||
if (button === Button.CANCEL) {
|
||||
ui.revertMode();
|
||||
success = true;
|
||||
} else {
|
||||
const eggCount = this.eggListIconContainer.getAll().length;
|
||||
const rows = Math.ceil(eggCount / 11);
|
||||
const row = Math.floor(this.cursor / 11);
|
||||
switch (button) {
|
||||
case Button.UP:
|
||||
if (row)
|
||||
success = this.setCursor(this.cursor - 11);
|
||||
break;
|
||||
case Button.DOWN:
|
||||
if (row < rows - 2 || (row < rows - 1 && this.cursor % 11 <= (eggCount - 1) % 11))
|
||||
success = this.setCursor(this.cursor + 11);
|
||||
break;
|
||||
case Button.LEFT:
|
||||
if (this.cursor % 11)
|
||||
success = this.setCursor(this.cursor - 1);
|
||||
break;
|
||||
case Button.RIGHT:
|
||||
if (this.cursor % 11 < (row < rows - 1 ? 10 : (eggCount - 1) % 11))
|
||||
success = this.setCursor(this.cursor + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (success)
|
||||
ui.playSelect();
|
||||
else if (error)
|
||||
ui.playError();
|
||||
|
||||
return success || error;
|
||||
}
|
||||
|
||||
setEggDetails(egg: Egg): void {
|
||||
this.eggSprite.setFrame(`egg_${egg.getKey()}`);
|
||||
this.eggNameText.setText(`Egg (${getEggDescriptor(egg)})`);
|
||||
this.eggDateText.setText(
|
||||
new Date(egg.timestamp).toLocaleString(undefined, {
|
||||
weekday: 'short',
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: 'numeric'
|
||||
})
|
||||
);
|
||||
this.eggHatchWavesText.setText(getEggHatchWavesMessage(egg.hatchWaves));
|
||||
this.eggGachaInfoText.setText(getEggGachaTypeDescriptor(this.scene, egg));
|
||||
}
|
||||
|
||||
setCursor(cursor: integer): boolean {
|
||||
let changed = false;
|
||||
|
||||
let lastCursor = this.cursor;
|
||||
|
||||
changed = super.setCursor(cursor);
|
||||
|
||||
if (changed) {
|
||||
this.cursorObj.setPosition(114 + 18 * (cursor % 11), 10 + 18 * Math.floor(cursor / 11));
|
||||
|
||||
if (lastCursor > -1)
|
||||
this.iconAnimHandler.addOrUpdate(this.eggListIconContainer.getAt(lastCursor) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.NONE);
|
||||
this.iconAnimHandler.addOrUpdate(this.eggListIconContainer.getAt(cursor) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.ACTIVE);
|
||||
|
||||
this.setEggDetails(this.scene.gameData.eggs[cursor]);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
super.clear();
|
||||
this.cursor = -1;
|
||||
this.eggListContainer.setVisible(false);
|
||||
this.iconAnimHandler.removeAll();
|
||||
this.eggListIconContainer.removeAll(true);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,10 @@ import * as Utils from "../utils";
|
||||
|
||||
export enum MenuOptions {
|
||||
SETTINGS,
|
||||
ACHIEVEMENTS
|
||||
ACHIEVEMENTS,
|
||||
VOUCHERS,
|
||||
EGG_LIST,
|
||||
EGG_GACHA
|
||||
}
|
||||
|
||||
export default class MenuUiHandler extends UiHandler {
|
||||
@@ -62,6 +65,7 @@ export default class MenuUiHandler extends UiHandler {
|
||||
const ui = this.getUi();
|
||||
|
||||
let success = false;
|
||||
let error = false;
|
||||
|
||||
if (button === Button.ACTION) {
|
||||
switch (this.cursor as MenuOptions) {
|
||||
@@ -73,6 +77,24 @@ export default class MenuUiHandler extends UiHandler {
|
||||
this.scene.ui.setOverlayMode(Mode.ACHIEVEMENTS);
|
||||
success = true;
|
||||
break;
|
||||
case MenuOptions.VOUCHERS:
|
||||
this.scene.ui.setOverlayMode(Mode.VOUCHERS);
|
||||
success = true;
|
||||
break;
|
||||
case MenuOptions.EGG_LIST:
|
||||
if (this.scene.gameData.eggs.length) {
|
||||
this.scene.ui.revertMode();
|
||||
this.scene.ui.setOverlayMode(Mode.EGG_LIST);
|
||||
success = true;
|
||||
} else
|
||||
error = true;
|
||||
break;
|
||||
case MenuOptions.EGG_GACHA:
|
||||
this.scene.ui.revertMode();
|
||||
this.scene.ui.setOverlayMode(Mode.EGG_GACHA);
|
||||
success = true;
|
||||
break;
|
||||
|
||||
}
|
||||
} else if (button === Button.CANCEL) {
|
||||
success = true;
|
||||
@@ -93,6 +115,8 @@ export default class MenuUiHandler extends UiHandler {
|
||||
|
||||
if (success)
|
||||
ui.playSelect();
|
||||
else if (error)
|
||||
ui.playError();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ export enum PokemonIconAnimMode {
|
||||
}
|
||||
|
||||
export default class PokemonIconAnimHandler {
|
||||
private counter: Phaser.Tweens.Tween;
|
||||
private icons: Map<Phaser.GameObjects.Sprite, PokemonIconAnimMode>;
|
||||
private toggled: boolean;
|
||||
|
||||
@@ -22,7 +21,7 @@ export default class PokemonIconAnimHandler {
|
||||
for (let i of this.icons.keys())
|
||||
i.y += this.getModeYDelta(this.icons.get(i)) * (this.toggled ? 1 : -1);
|
||||
};
|
||||
this.counter = scene.tweens.addCounter({
|
||||
scene.tweens.addCounter({
|
||||
duration: Utils.fixedInt(200),
|
||||
from: 0,
|
||||
to: 1,
|
||||
@@ -70,4 +69,12 @@ export default class PokemonIconAnimHandler {
|
||||
this.icons.delete(i);
|
||||
}
|
||||
}
|
||||
|
||||
removeAll(): void {
|
||||
for (let i of this.icons.keys()) {
|
||||
if (this.toggled)
|
||||
i.y -= this.getModeYDelta(this.icons.get(i));
|
||||
this.icons.delete(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
+748
-748
File diff suppressed because it is too large.
Load diff
@@ -1,19 +1,24 @@
|
||||
import BBCodeText from "phaser3-rex-plugins/plugins/gameobjects/tagtext/bbcodetext/BBCodeText";
|
||||
import BattleScene from "../battle-scene";
|
||||
import { Stat, getStatName } from "../data/pokemon-stat";
|
||||
import { TextStyle, addTextObject } from "./text";
|
||||
import { TextStyle, addBBCodeTextObject, addTextObject, getTextColor } from "./text";
|
||||
import { Gender, getGenderColor } from "../data/gender";
|
||||
|
||||
const ivChartSize = 24;
|
||||
const ivChartStatCoordMultipliers = [ [ 0, 1 ], [ 0.825, 0.5 ], [ 0.825, -0.5 ], [ 0, -1 ], [ -0.825, -0.5 ], [ -0.825, 0.5 ] ];
|
||||
const defaultIvChartData = new Array(12).fill(null).map(() => 0);
|
||||
|
||||
export class StatsContainer extends Phaser.GameObjects.Container {
|
||||
private showDiff: boolean;
|
||||
private statsIvsCache: integer[];
|
||||
private ivChart: Phaser.GameObjects.Polygon;
|
||||
private ivStatValueTexts: Phaser.GameObjects.Text[];
|
||||
private ivStatValueTexts: BBCodeText[];
|
||||
|
||||
constructor(scene: BattleScene, x: number, y: number) {
|
||||
constructor(scene: BattleScene, x: number, y: number, showDiff?: boolean) {
|
||||
super(scene, x, y);
|
||||
|
||||
this.showDiff = !!showDiff;
|
||||
|
||||
this.setup();
|
||||
}
|
||||
|
||||
@@ -48,7 +53,7 @@ export class StatsContainer extends Phaser.GameObjects.Container {
|
||||
const statLabel = addTextObject(this.scene, ivChartBg.x + (ivChartSize) * ivChartStatCoordMultipliers[i][0] * 1.325, ivChartBg.y + (ivChartSize) * ivChartStatCoordMultipliers[i][1] * 1.325 - 4, getStatName(i as Stat), TextStyle.TOOLTIP_CONTENT);
|
||||
statLabel.setOrigin(0.5);
|
||||
|
||||
this.ivStatValueTexts[i] = addTextObject(this.scene, statLabel.x, statLabel.y + 8, '0', TextStyle.TOOLTIP_CONTENT);
|
||||
this.ivStatValueTexts[i] = addBBCodeTextObject(this.scene, statLabel.x, statLabel.y + 8, '0', TextStyle.TOOLTIP_CONTENT);
|
||||
this.ivStatValueTexts[i].setOrigin(0.5)
|
||||
|
||||
this.add(statLabel);
|
||||
@@ -56,13 +61,22 @@ export class StatsContainer extends Phaser.GameObjects.Container {
|
||||
});
|
||||
}
|
||||
|
||||
updateIvs(ivs: integer[]): void {
|
||||
updateIvs(ivs: integer[], originalIvs?: integer[]): void {
|
||||
if (ivs) {
|
||||
const ivChartData = new Array(6).fill(null).map((_, i) => [ (ivs[i] / 31) * ivChartSize * ivChartStatCoordMultipliers[i][0], (ivs[i] / 31) * ivChartSize * ivChartStatCoordMultipliers[i][1] ] ).flat();
|
||||
const lastIvChartData = this.statsIvsCache || defaultIvChartData;
|
||||
this.statsIvsCache = ivChartData.slice(0);
|
||||
|
||||
this.ivStatValueTexts.map((t: Phaser.GameObjects.Text, i: integer) => t.setText(ivs[i].toString()));
|
||||
this.ivStatValueTexts.map((t: BBCodeText, i: integer) => {
|
||||
let label = ivs[i].toString();
|
||||
if (this.showDiff && originalIvs) {
|
||||
if (originalIvs[i] < ivs[i])
|
||||
label += ` ([color=${getGenderColor(Gender.MALE)}]+${ivs[i] - originalIvs[i]}[/color])`;
|
||||
else
|
||||
label += ' (-)';
|
||||
}
|
||||
t.setText(`[shadow]${label}[/shadow]`);
|
||||
});
|
||||
|
||||
this.scene.tweens.addCounter({
|
||||
from: 0,
|
||||
|
||||
+30
-9
@@ -1,3 +1,5 @@
|
||||
import BBCodeText from "phaser3-rex-plugins/plugins/gameobjects/tagtext/bbcodetext/BBCodeText";
|
||||
|
||||
export enum TextStyle {
|
||||
MESSAGE,
|
||||
WINDOW,
|
||||
@@ -14,7 +16,32 @@ export enum TextStyle {
|
||||
TOOLTIP_CONTENT
|
||||
};
|
||||
|
||||
export function addTextObject(scene: Phaser.Scene, x: number, y: number, content: string, style: TextStyle, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle) {
|
||||
export function addTextObject(scene: Phaser.Scene, x: number, y: number, content: string, style: TextStyle, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle): Phaser.GameObjects.Text {
|
||||
const [ styleOptions, shadowColor, shadowSize ] = getTextStyleOptions(style, extraStyleOptions);
|
||||
|
||||
const ret = scene.add.text(x, y, content, styleOptions);
|
||||
ret.setScale(0.1666666667);
|
||||
ret.setShadow(shadowSize, shadowSize, shadowColor);
|
||||
if (!styleOptions.lineSpacing)
|
||||
ret.setLineSpacing(5);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
export function addBBCodeTextObject(scene: Phaser.Scene, x: number, y: number, content: string, style: TextStyle, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle): BBCodeText {
|
||||
const [ styleOptions, shadowColor, shadowSize ] = getTextStyleOptions(style, extraStyleOptions);
|
||||
|
||||
const ret = new BBCodeText(scene, x, y, content, styleOptions as BBCodeText.TextStyle);
|
||||
scene.add.existing(ret);
|
||||
ret.setScale(0.1666666667);
|
||||
ret.setShadow(shadowSize, shadowSize, shadowColor);
|
||||
if (!styleOptions.lineSpacing)
|
||||
ret.setLineSpacing(5);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
function getTextStyleOptions(style: TextStyle, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle): [ Phaser.Types.GameObjects.Text.TextStyle, string, integer ] {
|
||||
let shadowColor: string;
|
||||
let shadowSize = 6;
|
||||
|
||||
@@ -64,16 +91,10 @@ export function addTextObject(scene: Phaser.Scene, x: number, y: number, content
|
||||
styleOptions = Object.assign(styleOptions, extraStyleOptions);
|
||||
}
|
||||
|
||||
const ret = scene.add.text(x, y, content, styleOptions);
|
||||
ret.setScale(0.1666666667);
|
||||
ret.setShadow(shadowSize, shadowSize, shadowColor);
|
||||
if (!styleOptions.lineSpacing)
|
||||
ret.setLineSpacing(5);
|
||||
|
||||
return ret;
|
||||
return [ styleOptions, shadowColor, shadowSize ];
|
||||
}
|
||||
|
||||
export function getTextColor(textStyle: TextStyle, shadow?: boolean) {
|
||||
export function getTextColor(textStyle: TextStyle, shadow?: boolean): string {
|
||||
switch (textStyle) {
|
||||
case TextStyle.MESSAGE:
|
||||
return !shadow ? '#f8f8f8' : '#6b5a73';
|
||||
|
||||
+48
-14
@@ -21,6 +21,10 @@ import MenuUiHandler from './menu-ui-handler';
|
||||
import AchvsUiHandler from './achvs-ui-handler';
|
||||
import OptionSelectUiHandler from './option-select-ui-handler';
|
||||
import EggHatchSceneHandler from './egg-hatch-scene-handler';
|
||||
import EggListUiHandler from './egg-list-ui-handler';
|
||||
import EggGachaUiHandler from './egg-gacha-ui-handler';
|
||||
import VouchersUiHandler from './vouchers-ui-handler';
|
||||
import VoucherBar from './voucher-bar';
|
||||
|
||||
export enum Mode {
|
||||
MESSAGE,
|
||||
@@ -40,7 +44,10 @@ export enum Mode {
|
||||
GAME_MODE_SELECT,
|
||||
MENU,
|
||||
SETTINGS,
|
||||
ACHIEVEMENTS
|
||||
ACHIEVEMENTS,
|
||||
VOUCHERS,
|
||||
EGG_LIST,
|
||||
EGG_GACHA
|
||||
};
|
||||
|
||||
const transitionModes = [
|
||||
@@ -48,7 +55,9 @@ const transitionModes = [
|
||||
Mode.SUMMARY,
|
||||
Mode.STARTER_SELECT,
|
||||
Mode.EVOLUTION_SCENE,
|
||||
Mode.EGG_HATCH_SCENE
|
||||
Mode.EGG_HATCH_SCENE,
|
||||
Mode.EGG_LIST,
|
||||
Mode.EGG_GACHA
|
||||
];
|
||||
|
||||
const noTransitionModes = [
|
||||
@@ -56,7 +65,9 @@ const noTransitionModes = [
|
||||
Mode.OPTION_SELECT,
|
||||
Mode.GAME_MODE_SELECT,
|
||||
Mode.MENU,
|
||||
Mode.SETTINGS
|
||||
Mode.SETTINGS,
|
||||
Mode.ACHIEVEMENTS,
|
||||
Mode.VOUCHERS
|
||||
];
|
||||
|
||||
export default class UI extends Phaser.GameObjects.Container {
|
||||
@@ -65,6 +76,7 @@ export default class UI extends Phaser.GameObjects.Container {
|
||||
private handlers: UiHandler[];
|
||||
private overlay: Phaser.GameObjects.Rectangle;
|
||||
public achvBar: AchvBar;
|
||||
public voucherBar: VoucherBar;
|
||||
|
||||
private tooltipContainer: Phaser.GameObjects.Container;
|
||||
private tooltipBg: Phaser.GameObjects.NineSlice;
|
||||
@@ -96,7 +108,10 @@ export default class UI extends Phaser.GameObjects.Container {
|
||||
new GameModeSelectUiHandler(scene),
|
||||
new MenuUiHandler(scene),
|
||||
new SettingsUiHandler(scene),
|
||||
new AchvsUiHandler(scene)
|
||||
new AchvsUiHandler(scene),
|
||||
new VouchersUiHandler(scene),
|
||||
new EggListUiHandler(scene),
|
||||
new EggGachaUiHandler(scene)
|
||||
];
|
||||
}
|
||||
|
||||
@@ -110,7 +125,8 @@ export default class UI extends Phaser.GameObjects.Container {
|
||||
this.setupTooltip();
|
||||
|
||||
this.achvBar = new AchvBar(this.scene as BattleScene);
|
||||
this.achvBar.setup();
|
||||
this.achvBar.setup();
|
||||
|
||||
(this.scene as BattleScene).uiContainer.add(this.achvBar);
|
||||
}
|
||||
|
||||
@@ -267,8 +283,9 @@ export default class UI extends Phaser.GameObjects.Container {
|
||||
}
|
||||
resolve();
|
||||
};
|
||||
if ((transitionModes.indexOf(this.mode) > -1 || transitionModes.indexOf(mode) > -1)
|
||||
&& (noTransitionModes.indexOf(this.mode) === -1 && noTransitionModes.indexOf(mode) === -1) && !(this.scene as BattleScene).auto) {
|
||||
if (((!chainMode && ((transitionModes.indexOf(this.mode) > -1 || transitionModes.indexOf(mode) > -1)
|
||||
&& (noTransitionModes.indexOf(this.mode) === -1 && noTransitionModes.indexOf(mode) === -1)))
|
||||
|| (chainMode && noTransitionModes.indexOf(mode) === -1)) && !(this.scene as BattleScene).auto) {
|
||||
this.fadeOut(250).then(() => {
|
||||
this.scene.time.delayedCall(100, () => {
|
||||
doSetMode();
|
||||
@@ -300,12 +317,29 @@ export default class UI extends Phaser.GameObjects.Container {
|
||||
return this.setModeInternal(mode, false, false, true, args);
|
||||
}
|
||||
|
||||
revertMode(): boolean {
|
||||
if (!this.modeChain.length)
|
||||
return false;
|
||||
|
||||
this.getHandler().clear();
|
||||
this.mode = this.modeChain.pop();
|
||||
return true;
|
||||
revertMode(): Promise<boolean> {
|
||||
return new Promise<boolean>(resolve => {
|
||||
if (!this.modeChain.length)
|
||||
return resolve(false);
|
||||
|
||||
const lastMode = this.mode;
|
||||
|
||||
const doRevertMode = () => {
|
||||
this.getHandler().clear();
|
||||
this.mode = this.modeChain.pop();
|
||||
};
|
||||
|
||||
if (noTransitionModes.indexOf(lastMode) === -1) {
|
||||
this.fadeOut(250).then(() => {
|
||||
this.scene.time.delayedCall(100, () => {
|
||||
doRevertMode();
|
||||
this.fadeIn(250);
|
||||
});
|
||||
});
|
||||
} else
|
||||
doRevertMode();
|
||||
|
||||
resolve(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
import BattleScene, { Button } from "../battle-scene";
|
||||
import { Voucher, getVoucherTypeIcon, getVoucherTypeName, vouchers } from "../system/voucher";
|
||||
import MessageUiHandler from "./message-ui-handler";
|
||||
import { TextStyle, addTextObject } from "./text";
|
||||
import { Mode } from "./ui";
|
||||
|
||||
export default class VouchersUiHandler extends MessageUiHandler {
|
||||
private vouchersContainer: Phaser.GameObjects.Container;
|
||||
private voucherIconsContainer: Phaser.GameObjects.Container;
|
||||
|
||||
private voucherIconsBg: Phaser.GameObjects.NineSlice;
|
||||
private voucherIcons: Phaser.GameObjects.Sprite[];
|
||||
private titleText: 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.vouchersContainer = this.scene.add.container(1, -(this.scene.game.canvas.height / 6) + 1);
|
||||
|
||||
this.vouchersContainer.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, 'Vouchers', TextStyle.SETTINGS_LABEL);
|
||||
headerText.setOrigin(0, 0);
|
||||
headerText.setPositionRelative(headerBg, 8, 4);
|
||||
|
||||
this.voucherIconsBg = 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.voucherIconsBg.setOrigin(0, 0);
|
||||
|
||||
this.voucherIconsContainer = this.scene.add.container(6, headerBg.height + 6);
|
||||
|
||||
this.voucherIcons = [];
|
||||
|
||||
for (let a = 0; a < Object.keys(vouchers).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.voucherIcons.push(icon);
|
||||
this.voucherIconsContainer.add(icon);
|
||||
}
|
||||
|
||||
const titleBg = this.scene.add.nineslice(0, headerBg.height + this.voucherIconsBg.height, 'window', null, 220, 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 unlockBg = this.scene.add.nineslice(titleBg.x + titleBg.width, titleBg.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.vouchersContainer.add(headerBg);
|
||||
this.vouchersContainer.add(headerText);
|
||||
this.vouchersContainer.add(this.voucherIconsBg);
|
||||
this.vouchersContainer.add(this.voucherIconsContainer);
|
||||
this.vouchersContainer.add(titleBg);
|
||||
this.vouchersContainer.add(this.titleText);
|
||||
this.vouchersContainer.add(unlockBg);
|
||||
this.vouchersContainer.add(this.unlockText);
|
||||
this.vouchersContainer.add(descriptionBg);
|
||||
this.vouchersContainer.add(descriptionText);
|
||||
|
||||
ui.add(this.vouchersContainer);
|
||||
|
||||
this.setCursor(0);
|
||||
|
||||
this.vouchersContainer.setVisible(false);
|
||||
}
|
||||
|
||||
show(args: any[]) {
|
||||
super.show(args);
|
||||
|
||||
const voucherUnlocks = this.scene.gameData.voucherUnlocks;
|
||||
|
||||
Object.values(vouchers).forEach((voucher: Voucher, i: integer) => {
|
||||
const icon = this.voucherIcons[i];
|
||||
const unlocked = voucherUnlocks.hasOwnProperty(voucher.id);
|
||||
|
||||
icon.setFrame(getVoucherTypeIcon(voucher.voucherType));
|
||||
if (!unlocked)
|
||||
icon.setTintFill(0);
|
||||
else
|
||||
icon.clearTint();
|
||||
});
|
||||
|
||||
this.vouchersContainer.setVisible(true);
|
||||
this.setCursor(0);
|
||||
|
||||
this.getUi().moveTo(this.vouchersContainer, this.getUi().length - 1);
|
||||
|
||||
this.getUi().hideTooltip();
|
||||
}
|
||||
|
||||
protected showVoucher(voucher: Voucher) {
|
||||
const voucherUnlocks = this.scene.gameData.voucherUnlocks;
|
||||
const unlocked = voucherUnlocks.hasOwnProperty(voucher.id);
|
||||
|
||||
this.titleText.setText(getVoucherTypeName(voucher.voucherType));
|
||||
this.showText(voucher.description);
|
||||
this.unlockText.setText(unlocked ? new Date(voucherUnlocks[voucher.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(vouchers).length)
|
||||
success = this.setCursor(this.cursor + 17);
|
||||
break;
|
||||
case Button.LEFT:
|
||||
if (this.cursor)
|
||||
success = this.setCursor(this.cursor - 1);
|
||||
break;
|
||||
case Button.RIGHT:
|
||||
if (this.cursor < Object.keys(vouchers).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 updateVoucher = 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.voucherIconsContainer.add(this.cursorObj);
|
||||
updateVoucher = true;
|
||||
}
|
||||
|
||||
this.cursorObj.setPositionRelative(this.voucherIcons[this.cursor], 0, 0);
|
||||
|
||||
if (updateVoucher)
|
||||
this.showVoucher(vouchers[Object.keys(vouchers)[cursor]]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
clear() {
|
||||
super.clear();
|
||||
this.vouchersContainer.setVisible(false);
|
||||
this.eraseCursor();
|
||||
}
|
||||
|
||||
eraseCursor() {
|
||||
if (this.cursorObj)
|
||||
this.cursorObj.destroy();
|
||||
this.cursorObj = null;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user