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
BIN
public/audio/se/gacha_dial.wav
Normal file
BIN
public/audio/se/gacha_dispense.wav
Normal file
BIN
public/audio/se/gacha_running.wav
Normal file
@ -1,6 +1,6 @@
|
||||
{
|
||||
"id": 383,
|
||||
"graphic": "'!",
|
||||
"graphic": "!",
|
||||
"frames": [
|
||||
[
|
||||
{
|
||||
|
Before Width: | Height: | Size: 951 B |
BIN
public/images/egg/default.png
Normal file
After Width: | Height: | Size: 337 B |
@ -4,7 +4,7 @@
|
||||
"image": "egg.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {
|
||||
"w": 112,
|
||||
"w": 138,
|
||||
"h": 30
|
||||
},
|
||||
"scale": 1,
|
||||
@ -12,14 +12,14 @@
|
||||
{
|
||||
"filename": "egg_0",
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"trimmed": false,
|
||||
"sourceSize": {
|
||||
"w": 32,
|
||||
"h": 32
|
||||
"w": 28,
|
||||
"h": 30
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 2,
|
||||
"y": 1,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 28,
|
||||
"h": 30
|
||||
},
|
||||
@ -33,14 +33,14 @@
|
||||
{
|
||||
"filename": "egg_1",
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"trimmed": false,
|
||||
"sourceSize": {
|
||||
"w": 32,
|
||||
"h": 32
|
||||
"w": 28,
|
||||
"h": 30
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 2,
|
||||
"y": 1,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 28,
|
||||
"h": 30
|
||||
},
|
||||
@ -54,14 +54,14 @@
|
||||
{
|
||||
"filename": "egg_2",
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"trimmed": false,
|
||||
"sourceSize": {
|
||||
"w": 32,
|
||||
"h": 32
|
||||
"w": 28,
|
||||
"h": 30
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 2,
|
||||
"y": 1,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 28,
|
||||
"h": 30
|
||||
},
|
||||
@ -75,14 +75,14 @@
|
||||
{
|
||||
"filename": "egg_3",
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"trimmed": false,
|
||||
"sourceSize": {
|
||||
"w": 32,
|
||||
"h": 32
|
||||
"w": 28,
|
||||
"h": 30
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 2,
|
||||
"y": 1,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 28,
|
||||
"h": 30
|
||||
},
|
||||
@ -92,6 +92,27 @@
|
||||
"w": 28,
|
||||
"h": 30
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "egg_manaphy",
|
||||
"rotated": false,
|
||||
"trimmed": false,
|
||||
"sourceSize": {
|
||||
"w": 26,
|
||||
"h": 30
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 26,
|
||||
"h": 30
|
||||
},
|
||||
"frame": {
|
||||
"x": 112,
|
||||
"y": 0,
|
||||
"w": 26,
|
||||
"h": 30
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -99,6 +120,6 @@
|
||||
"meta": {
|
||||
"app": "https://www.codeandweb.com/texturepacker",
|
||||
"version": "3.0",
|
||||
"smartupdate": "$TexturePacker:SmartUpdate:a2a114a3e275355f11c124f7ddc3a158:87e6ddecd2221fa223d5a07b1b3bb040:f2ac48b1c7b5b0a41ac50c4888a029cf$"
|
||||
"smartupdate": "$TexturePacker:SmartUpdate:ba653f2a1c1d028d27d209346c8f5cda:d1a96146bbb57b7f2dbd12209e9e846d:f2ac48b1c7b5b0a41ac50c4888a029cf$"
|
||||
}
|
||||
}
|
BIN
public/images/egg/egg.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 304 B After Width: | Height: | Size: 304 B |
125
public/images/egg/egg_icons.json
Normal file
@ -0,0 +1,125 @@
|
||||
{
|
||||
"textures": [
|
||||
{
|
||||
"image": "egg_icons.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {
|
||||
"w": 64,
|
||||
"h": 15
|
||||
},
|
||||
"scale": 1,
|
||||
"frames": [
|
||||
{
|
||||
"filename": "0",
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"sourceSize": {
|
||||
"w": 40,
|
||||
"h": 30
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 14,
|
||||
"y": 14,
|
||||
"w": 13,
|
||||
"h": 14
|
||||
},
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 13,
|
||||
"h": 14
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "1",
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"sourceSize": {
|
||||
"w": 40,
|
||||
"h": 30
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 14,
|
||||
"y": 14,
|
||||
"w": 13,
|
||||
"h": 14
|
||||
},
|
||||
"frame": {
|
||||
"x": 13,
|
||||
"y": 0,
|
||||
"w": 13,
|
||||
"h": 14
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "2",
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"sourceSize": {
|
||||
"w": 40,
|
||||
"h": 30
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 14,
|
||||
"y": 14,
|
||||
"w": 13,
|
||||
"h": 14
|
||||
},
|
||||
"frame": {
|
||||
"x": 26,
|
||||
"y": 0,
|
||||
"w": 13,
|
||||
"h": 14
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "3",
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"sourceSize": {
|
||||
"w": 40,
|
||||
"h": 30
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 14,
|
||||
"y": 14,
|
||||
"w": 13,
|
||||
"h": 14
|
||||
},
|
||||
"frame": {
|
||||
"x": 39,
|
||||
"y": 0,
|
||||
"w": 13,
|
||||
"h": 14
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "manaphy",
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"sourceSize": {
|
||||
"w": 40,
|
||||
"h": 30
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 14,
|
||||
"y": 13,
|
||||
"w": 12,
|
||||
"h": 15
|
||||
},
|
||||
"frame": {
|
||||
"x": 52,
|
||||
"y": 0,
|
||||
"w": 12,
|
||||
"h": 15
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"app": "https://www.codeandweb.com/texturepacker",
|
||||
"version": "3.0",
|
||||
"smartupdate": "$TexturePacker:SmartUpdate:5bdeccfea3b20316b6f997ded4917832:9d7fd6a01652d18587263aea89256028:9ca79c86befa783c0f0fdd62dae4f950$"
|
||||
}
|
||||
}
|
BIN
public/images/egg/egg_icons.png
Normal file
After Width: | Height: | Size: 559 B |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 402 B After Width: | Height: | Size: 402 B |
BIN
public/images/egg/gacha_glass.png
Normal file
After Width: | Height: | Size: 562 B |
104
public/images/egg/gacha_hatch.json
Normal file
@ -0,0 +1,104 @@
|
||||
{
|
||||
"textures": [
|
||||
{
|
||||
"image": "gacha_hatch.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {
|
||||
"w": 53,
|
||||
"h": 53
|
||||
},
|
||||
"scale": 1,
|
||||
"frames": [
|
||||
{
|
||||
"filename": "1.png",
|
||||
"rotated": false,
|
||||
"trimmed": false,
|
||||
"sourceSize": {
|
||||
"w": 25,
|
||||
"h": 32
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 25,
|
||||
"h": 32
|
||||
},
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 25,
|
||||
"h": 32
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "2.png",
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"sourceSize": {
|
||||
"w": 25,
|
||||
"h": 32
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 25,
|
||||
"h": 31
|
||||
},
|
||||
"frame": {
|
||||
"x": 25,
|
||||
"y": 0,
|
||||
"w": 25,
|
||||
"h": 31
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "3.png",
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"sourceSize": {
|
||||
"w": 25,
|
||||
"h": 32
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 25,
|
||||
"h": 22
|
||||
},
|
||||
"frame": {
|
||||
"x": 25,
|
||||
"y": 31,
|
||||
"w": 25,
|
||||
"h": 22
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "4.png",
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"sourceSize": {
|
||||
"w": 25,
|
||||
"h": 32
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 25,
|
||||
"h": 12
|
||||
},
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 32,
|
||||
"w": 25,
|
||||
"h": 12
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"app": "https://www.codeandweb.com/texturepacker",
|
||||
"version": "3.0",
|
||||
"smartupdate": "$TexturePacker:SmartUpdate:dba061ae0c944cad946da89a3db61ef3:6bcb3cebd91542179a70caca502090cd:03d3c0cdbe3979a45ab948bf5fc6c5fe$"
|
||||
}
|
||||
}
|
BIN
public/images/egg/gacha_hatch.png
Normal file
After Width: | Height: | Size: 433 B |
BIN
public/images/egg/gacha_knob.png
Normal file
After Width: | Height: | Size: 279 B |
BIN
public/images/egg/gacha_legendary.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
public/images/egg/gacha_shiny.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
public/images/egg/gacha_type.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
62
public/images/egg/gacha_underlay_legendary.json
Normal file
@ -0,0 +1,62 @@
|
||||
{
|
||||
"textures": [
|
||||
{
|
||||
"image": "gacha_underlay_legendary.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {
|
||||
"w": 25,
|
||||
"h": 104
|
||||
},
|
||||
"scale": 1,
|
||||
"frames": [
|
||||
{
|
||||
"filename": "default",
|
||||
"rotated": false,
|
||||
"trimmed": false,
|
||||
"sourceSize": {
|
||||
"w": 25,
|
||||
"h": 52
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 25,
|
||||
"h": 52
|
||||
},
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 25,
|
||||
"h": 52
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "open_hatch",
|
||||
"rotated": false,
|
||||
"trimmed": false,
|
||||
"sourceSize": {
|
||||
"w": 25,
|
||||
"h": 52
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 25,
|
||||
"h": 52
|
||||
},
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 52,
|
||||
"w": 25,
|
||||
"h": 52
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"app": "https://www.codeandweb.com/texturepacker",
|
||||
"version": "3.0",
|
||||
"smartupdate": "$TexturePacker:SmartUpdate:2714c584c99d3f151df83633a3e573e2:9a5a390cb558062cd2b0d8b9e577816a:dc9ad86988e4cd7eb47a54564121d8fa$"
|
||||
}
|
||||
}
|
BIN
public/images/egg/gacha_underlay_legendary.png
Normal file
After Width: | Height: | Size: 272 B |
62
public/images/egg/gacha_underlay_shiny.json
Normal file
@ -0,0 +1,62 @@
|
||||
{
|
||||
"textures": [
|
||||
{
|
||||
"image": "gacha_underlay_shiny.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {
|
||||
"w": 25,
|
||||
"h": 104
|
||||
},
|
||||
"scale": 1,
|
||||
"frames": [
|
||||
{
|
||||
"filename": "default",
|
||||
"rotated": false,
|
||||
"trimmed": false,
|
||||
"sourceSize": {
|
||||
"w": 25,
|
||||
"h": 52
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 25,
|
||||
"h": 52
|
||||
},
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 25,
|
||||
"h": 52
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "open_hatch",
|
||||
"rotated": false,
|
||||
"trimmed": false,
|
||||
"sourceSize": {
|
||||
"w": 25,
|
||||
"h": 52
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 25,
|
||||
"h": 52
|
||||
},
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 52,
|
||||
"w": 25,
|
||||
"h": 52
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"app": "https://www.codeandweb.com/texturepacker",
|
||||
"version": "3.0",
|
||||
"smartupdate": "$TexturePacker:SmartUpdate:2714c584c99d3f151df83633a3e573e2:9a5a390cb558062cd2b0d8b9e577816a:dc9ad86988e4cd7eb47a54564121d8fa$"
|
||||
}
|
||||
}
|
BIN
public/images/egg/gacha_underlay_shiny.png
Normal file
After Width: | Height: | Size: 420 B |
62
public/images/egg/gacha_underlay_type.json
Normal file
@ -0,0 +1,62 @@
|
||||
{
|
||||
"textures": [
|
||||
{
|
||||
"image": "gacha_underlay_type.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {
|
||||
"w": 25,
|
||||
"h": 104
|
||||
},
|
||||
"scale": 1,
|
||||
"frames": [
|
||||
{
|
||||
"filename": "default",
|
||||
"rotated": false,
|
||||
"trimmed": false,
|
||||
"sourceSize": {
|
||||
"w": 25,
|
||||
"h": 52
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 25,
|
||||
"h": 52
|
||||
},
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 25,
|
||||
"h": 52
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "open_hatch",
|
||||
"rotated": false,
|
||||
"trimmed": false,
|
||||
"sourceSize": {
|
||||
"w": 25,
|
||||
"h": 52
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 25,
|
||||
"h": 52
|
||||
},
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 52,
|
||||
"w": 25,
|
||||
"h": 52
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"app": "https://www.codeandweb.com/texturepacker",
|
||||
"version": "3.0",
|
||||
"smartupdate": "$TexturePacker:SmartUpdate:2714c584c99d3f151df83633a3e573e2:9a5a390cb558062cd2b0d8b9e577816a:dc9ad86988e4cd7eb47a54564121d8fa$"
|
||||
}
|
||||
}
|
BIN
public/images/egg/gacha_underlay_type.png
Normal file
After Width: | Height: | Size: 421 B |
BIN
public/images/egg/open_hatch.png
Normal file
After Width: | Height: | Size: 314 B |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 31 KiB |
BIN
public/images/items/coupon.png
Normal file
After Width: | Height: | Size: 253 B |
BIN
public/images/items/golden_mystic_ticket.png
Normal file
After Width: | Height: | Size: 338 B |
BIN
public/images/items/mystic_ticket.png
Normal file
After Width: | Height: | Size: 261 B |
BIN
public/images/items/pair_of_tickets.png
Normal file
After Width: | Height: | Size: 255 B |
BIN
public/images/pokemon/icons/egg/0.png
Normal file
After Width: | Height: | Size: 333 B |
BIN
public/images/pokemon/icons/egg/1.png
Normal file
After Width: | Height: | Size: 338 B |
BIN
public/images/pokemon/icons/egg/2.png
Normal file
After Width: | Height: | Size: 325 B |
BIN
public/images/pokemon/icons/egg/3.png
Normal file
After Width: | Height: | Size: 333 B |
BIN
public/images/pokemon/icons/egg/manaphy.png
Normal file
After Width: | Height: | Size: 358 B |
BIN
public/images/ui/egg_list_bg.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
@ -34,7 +34,10 @@ import { Species } from "./data/species";
|
||||
import { HealAchv, LevelAchv, MoneyAchv, achvs } from "./system/achv";
|
||||
import { DexEntry } from "./system/game-data";
|
||||
import { pokemonPrevolutions } from "./data/pokemon-evolutions";
|
||||
import { trainerConfigs } from "./data/trainer-type";
|
||||
import { TrainerType, trainerConfigs } from "./data/trainer-type";
|
||||
import { EggHatchPhase } from "./egg-hatch-phase";
|
||||
import { Egg } from "./data/egg";
|
||||
import { vouchers } from "./system/voucher";
|
||||
|
||||
export class CheckLoadPhase extends BattlePhase {
|
||||
private loaded: boolean;
|
||||
@ -92,6 +95,11 @@ export class CheckLoadPhase extends BattlePhase {
|
||||
}
|
||||
}
|
||||
|
||||
for (let achv of Object.keys(this.scene.gameData.achvUnlocks)) {
|
||||
if (vouchers.hasOwnProperty(achv))
|
||||
this.scene.validateVoucher(vouchers[achv]);
|
||||
}
|
||||
|
||||
super.end();
|
||||
}
|
||||
}
|
||||
@ -2338,6 +2346,7 @@ export class VictoryPhase extends PokemonPhase {
|
||||
this.scene.pushPhase(new BattleEndPhase(this.scene));
|
||||
if (this.scene.currentBattle.battleType === BattleType.TRAINER)
|
||||
this.scene.pushPhase(new TrainerVictoryPhase(this.scene));
|
||||
this.scene.pushPhase(new EggLapsePhase(this.scene));
|
||||
if (this.scene.gameMode !== GameMode.CLASSIC || this.scene.currentBattle.waveIndex < this.scene.finalWave) {
|
||||
if (this.scene.currentBattle.waveIndex % 10)
|
||||
this.scene.pushPhase(new SelectModifierPhase(this.scene));
|
||||
@ -2347,9 +2356,11 @@ export class VictoryPhase extends PokemonPhase {
|
||||
if (this.scene.currentBattle.waveIndex <= 150 && !(this.scene.currentBattle.waveIndex % 50))
|
||||
this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.GOLDEN_POKEBALL));
|
||||
}
|
||||
if (this.scene.gameMode !== GameMode.CLASSIC && !(this.scene.currentBattle.waveIndex % 50))
|
||||
if (this.scene.gameMode !== GameMode.CLASSIC && !(this.scene.currentBattle.waveIndex % 50)) {
|
||||
this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.VOUCHER));
|
||||
this.scene.pushPhase(new AddEnemyBuffModifierPhase(this.scene));
|
||||
}
|
||||
}
|
||||
this.scene.pushPhase(new NewBattlePhase(this.scene));
|
||||
} else
|
||||
this.scene.pushPhase(new GameOverPhase(this.scene, true));
|
||||
@ -2367,6 +2378,10 @@ export class TrainerVictoryPhase extends BattlePhase {
|
||||
start() {
|
||||
this.scene.playBgm(this.scene.currentBattle.trainer.config.victoryBgm);
|
||||
|
||||
const trainerType = this.scene.currentBattle.trainer.config.trainerType;
|
||||
if (vouchers.hasOwnProperty(TrainerType[trainerType]))
|
||||
this.scene.validateVoucher(vouchers[TrainerType[trainerType]]);
|
||||
|
||||
this.scene.unshiftPhase(new MoneyRewardPhase(this.scene, this.scene.currentBattle.trainer.config.moneyMultiplier));
|
||||
|
||||
const modifierRewardFuncs = this.scene.currentBattle.trainer.config.modifierRewardFuncs;
|
||||
@ -2964,18 +2979,7 @@ export class AttemptCapturePhase extends PokemonPhase {
|
||||
if (pokemon.species.mythical)
|
||||
this.scene.validateAchv(achvs.CATCH_MYTHICAL);
|
||||
|
||||
let dexEntry: DexEntry;
|
||||
let speciesId = pokemon.species.speciesId;
|
||||
do {
|
||||
dexEntry = this.scene.gameData.dexData[speciesId];
|
||||
const dexIvs = dexEntry.ivs;
|
||||
for (let i = 0; i < dexIvs.length; i++) {
|
||||
if (dexIvs[i] < pokemon.ivs[i])
|
||||
dexIvs[i] = pokemon.ivs[i];
|
||||
}
|
||||
if (dexIvs.filter(iv => iv === 31).length === 6)
|
||||
this.scene.validateAchv(achvs.PERFECT_IVS);
|
||||
} while (pokemonPrevolutions.hasOwnProperty(speciesId) && (speciesId = pokemonPrevolutions[speciesId]));
|
||||
this.scene.gameData.updateSpeciesDexIvs(pokemon.species.speciesId, pokemon.ivs);
|
||||
|
||||
this.scene.ui.showText(`${pokemon.name} was caught!`, null, () => {
|
||||
const end = () => {
|
||||
@ -3229,6 +3233,31 @@ export class SelectModifierPhase extends BattlePhase {
|
||||
}
|
||||
}
|
||||
|
||||
export class EggLapsePhase extends BattlePhase {
|
||||
constructor(scene: BattleScene) {
|
||||
super(scene);
|
||||
}
|
||||
|
||||
start() {
|
||||
super.start();
|
||||
|
||||
const eggsToHatch: Egg[] = [];
|
||||
|
||||
for (let egg of this.scene.gameData.eggs) {
|
||||
if (--egg.hatchWaves < 1)
|
||||
eggsToHatch.push(egg);
|
||||
}
|
||||
|
||||
if (eggsToHatch.length)
|
||||
this.scene.queueMessage('Oh?');
|
||||
|
||||
for (let egg of eggsToHatch)
|
||||
this.scene.unshiftPhase(new EggHatchPhase(this.scene, egg));
|
||||
|
||||
this.end();
|
||||
}
|
||||
}
|
||||
|
||||
export class AddEnemyBuffModifierPhase extends BattlePhase {
|
||||
constructor(scene: BattleScene) {
|
||||
super(scene);
|
||||
|
@ -35,6 +35,8 @@ import MessageUiHandler from './ui/message-ui-handler';
|
||||
import { Species } from './data/species';
|
||||
import InvertPostFX from './pipelines/invert';
|
||||
import { Achv, ModifierAchv, achvs } from './system/achv';
|
||||
import { GachaType } from './data/egg';
|
||||
import { Voucher, vouchers } from './system/voucher';
|
||||
|
||||
const enableAuto = true;
|
||||
const quickStart = false;
|
||||
@ -301,10 +303,22 @@ export default class BattleScene extends Phaser.Scene {
|
||||
this.loadAtlas('types', '');
|
||||
this.loadAtlas('statuses', '');
|
||||
this.loadAtlas('categories', '');
|
||||
this.loadAtlas('egg', '');
|
||||
this.loadAtlas('egg_crack', '');
|
||||
this.loadAtlas('egg_shard', '');
|
||||
this.loadAtlas('egg_lightrays', '');
|
||||
|
||||
this.loadAtlas('egg', 'egg');
|
||||
this.loadAtlas('egg_crack', 'egg');
|
||||
this.loadAtlas('egg_icons', 'egg');
|
||||
this.loadAtlas('egg_shard', 'egg');
|
||||
this.loadAtlas('egg_lightrays', 'egg');
|
||||
Utils.getEnumKeys(GachaType).forEach(gt => {
|
||||
const key = gt.toLowerCase();
|
||||
this.loadImage(`gacha_${key}`, 'egg');
|
||||
this.loadAtlas(`gacha_underlay_${key}`, 'egg');
|
||||
});
|
||||
this.loadImage('gacha_glass', 'egg');
|
||||
this.loadAtlas('gacha_hatch', 'egg');
|
||||
this.loadImage('gacha_knob', 'egg');
|
||||
|
||||
this.loadImage('egg_list_bg', 'ui');
|
||||
|
||||
for (let i = 0; i < 10; i++)
|
||||
this.loadAtlas(`pokemon_icons_${i}`, 'ui');
|
||||
@ -345,6 +359,9 @@ export default class BattleScene extends Phaser.Scene {
|
||||
|
||||
this.loadSe('egg_crack');
|
||||
this.loadSe('egg_hatch');
|
||||
this.loadSe('gacha_dial');
|
||||
this.loadSe('gacha_running');
|
||||
this.loadSe('gacha_dispense');
|
||||
|
||||
this.loadSe('PRSFX- Transform', 'battle_anims');
|
||||
|
||||
@ -714,9 +731,6 @@ export default class BattleScene extends Phaser.Scene {
|
||||
|
||||
//this.pushPhase(new TrainerMessageTestPhase(this));
|
||||
|
||||
//for (let t = 0; t < 4; t++)
|
||||
//this.pushPhase(new EggHatchPhase(this, new Egg(2423432 + EGG_SEED * t, GachaType.LEGENDARY, new Date().getTime())));
|
||||
|
||||
if (!waveIndex) {
|
||||
const isNewBiome = !lastBattle || !(lastBattle.waveIndex % 10);
|
||||
const resetArenaState = isNewBiome || this.currentBattle.battleType === BattleType.TRAINER;
|
||||
@ -1447,7 +1461,6 @@ export default class BattleScene extends Phaser.Scene {
|
||||
|
||||
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)
|
||||
this.validateAchv(achv, args);
|
||||
}
|
||||
@ -1456,6 +1469,19 @@ export default class BattleScene extends Phaser.Scene {
|
||||
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 (vouchers.hasOwnProperty(achv.id))
|
||||
this.validateVoucher(vouchers[achv.id]);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
validateVoucher(voucher: Voucher, args?: any[]): boolean {
|
||||
if (!this.gameData.voucherUnlocks.hasOwnProperty(voucher.id) && voucher.validate(this, args)) {
|
||||
this.gameData.voucherUnlocks[voucher.id] = new Date().getTime();
|
||||
this.ui.achvBar.showAchv(voucher);
|
||||
this.gameData.voucherCounts[voucher.voucherType]++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -181,24 +181,20 @@ export const biomePokemonPools: BiomePokemonPools = {
|
||||
Species.VENONAT,
|
||||
Species.MEOWTH,
|
||||
Species.BELLSPROUT,
|
||||
Species.PICHU,
|
||||
Species.IGGLYBUFF,
|
||||
Species.LOTAD,
|
||||
Species.SEEDOT,
|
||||
Species.SHROOMISH,
|
||||
Species.NINCADA,
|
||||
Species.WHISMUR,
|
||||
Species.AZURILL,
|
||||
Species.SKITTY,
|
||||
Species.KRICKETOT,
|
||||
Species.BUDEW,
|
||||
Species.COMBEE,
|
||||
Species.CHERUBI,
|
||||
Species.VENIPEDE,
|
||||
Species.MINCCINO
|
||||
],
|
||||
[BiomePoolTier.RARE]: [ Species.ABRA, Species.CLEFFA, Species.SURSKIT ],
|
||||
[BiomePoolTier.SUPER_RARE]: [ Species.EEVEE, Species.TOGEPI, Species.TYROGUE, Species.SMOOCHUM, Species.ELEKID, Species.MAGBY, Species.RALTS, Species.WYNAUT, Species.BONSLY, Species.MIME_JR, Species.HAPPINY, Species.MUNCHLAX, Species.RIOLU ],
|
||||
[BiomePoolTier.RARE]: [ Species.ABRA, Species.SURSKIT ],
|
||||
[BiomePoolTier.SUPER_RARE]: [ Species.EEVEE, Species.RALTS ],
|
||||
[BiomePoolTier.ULTRA_RARE]: [ Species.DITTO ],
|
||||
[BiomePoolTier.BOSS]: [],
|
||||
[BiomePoolTier.BOSS_RARE]: [],
|
||||
@ -250,7 +246,7 @@ export const biomePokemonPools: BiomePokemonPools = {
|
||||
[BiomePoolTier.BOSS]: [ Species.JUMPLUFF, Species.SUNFLORA, Species.WHIMSICOTT ],
|
||||
[BiomePoolTier.BOSS_RARE]: [ Species.VENUSAUR, Species.SUDOWOODO, Species.TORTERRA ],
|
||||
[BiomePoolTier.BOSS_SUPER_RARE]: [],
|
||||
[BiomePoolTier.BOSS_ULTRA_RARE]: [ Species.SHAYMIN ]
|
||||
[BiomePoolTier.BOSS_ULTRA_RARE]: []
|
||||
},
|
||||
[Biome.TALL_GRASS]: {
|
||||
[BiomePoolTier.COMMON]: [
|
||||
@ -329,7 +325,7 @@ export const biomePokemonPools: BiomePokemonPools = {
|
||||
{ 1: [ Species.ROWLET ], 17: [ Species.DARTRIX ], 36: [ Species.DECIDUEYE ] }
|
||||
],
|
||||
[BiomePoolTier.SUPER_RARE]: [ Species.DURANT ],
|
||||
[BiomePoolTier.ULTRA_RARE]: [ Species.CELEBI, Species.KARTANA ],
|
||||
[BiomePoolTier.ULTRA_RARE]: [ Species.KARTANA ],
|
||||
[BiomePoolTier.BOSS]: [
|
||||
Species.VENOMOTH,
|
||||
Species.VICTREEBEL,
|
||||
@ -351,7 +347,7 @@ export const biomePokemonPools: BiomePokemonPools = {
|
||||
],
|
||||
[BiomePoolTier.BOSS_RARE]: [ Species.HERACROSS, Species.STANTLER, Species.SCEPTILE, Species.ESCAVALIER, Species.ACCELGOR, Species.DURANT, Species.CHESNAUGHT, Species.DECIDUEYE, Species.LYCANROC ],
|
||||
[BiomePoolTier.BOSS_SUPER_RARE]: [ Species.KARTANA ],
|
||||
[BiomePoolTier.BOSS_ULTRA_RARE]: [ Species.CELEBI, Species.CALYREX ]
|
||||
[BiomePoolTier.BOSS_ULTRA_RARE]: [ Species.CALYREX ]
|
||||
},
|
||||
[Biome.SEA]: {
|
||||
[BiomePoolTier.COMMON]: [
|
||||
@ -474,7 +470,7 @@ export const biomePokemonPools: BiomePokemonPools = {
|
||||
{ 1: [ Species.SKRELP ], 48: [ Species.DRAGALGE ] },
|
||||
Species.PINCURCHIN
|
||||
],
|
||||
[BiomePoolTier.RARE]: [ Species.QWILFISH, Species.CORSOLA, Species.OCTILLERY, { 1: [ Species.MANTYKE ], 20: [ Species.MANTINE ] }, Species.PHIONE, Species.ALOMOMOLA, { 1: [ Species.TYNAMO ], 39: [ Species.EELEKTRIK ] }, Species.DHELMISE ],
|
||||
[BiomePoolTier.RARE]: [ Species.QWILFISH, Species.CORSOLA, Species.OCTILLERY, { 1: [ Species.MANTYKE ], 20: [ Species.MANTINE ] }, Species.ALOMOMOLA, { 1: [ Species.TYNAMO ], 39: [ Species.EELEKTRIK ] }, Species.DHELMISE ],
|
||||
[BiomePoolTier.SUPER_RARE]: [
|
||||
{ 1: [ Species.OMANYTE ], 40: [ Species.OMASTAR ] },
|
||||
{ 1: [ Species.KABUTO ], 40: [ Species.KABUTOPS ] },
|
||||
@ -484,10 +480,10 @@ export const biomePokemonPools: BiomePokemonPools = {
|
||||
Species.ARCTOVISH,
|
||||
Species.HISUI_QWILFISH
|
||||
],
|
||||
[BiomePoolTier.ULTRA_RARE]: [ Species.FEEBAS, Species.MANAPHY, Species.NIHILEGO ],
|
||||
[BiomePoolTier.ULTRA_RARE]: [ Species.FEEBAS, Species.NIHILEGO ],
|
||||
[BiomePoolTier.BOSS]: [ Species.LANTURN, Species.QWILFISH, Species.CORSOLA, Species.OCTILLERY, Species.MANTINE, Species.WAILORD, Species.HUNTAIL, Species.GOREBYSS, Species.LUVDISC, Species.JELLICENT, Species.ALOMOMOLA, Species.DRAGALGE, Species.BARRASKEWDA ],
|
||||
[BiomePoolTier.BOSS_RARE]: [ Species.OMASTAR, Species.KABUTOPS, Species.RELICANTH, Species.PHIONE, Species.EELEKTROSS, Species.PYUKUMUKU, Species.DHELMISE, Species.ARCTOVISH, Species.BASCULEGION ],
|
||||
[BiomePoolTier.BOSS_SUPER_RARE]: [ Species.MILOTIC, Species.MANAPHY, Species.NIHILEGO, Species.CURSOLA, Species.OVERQWIL ],
|
||||
[BiomePoolTier.BOSS_RARE]: [ Species.OMASTAR, Species.KABUTOPS, Species.RELICANTH, Species.EELEKTROSS, Species.PYUKUMUKU, Species.DHELMISE, Species.ARCTOVISH, Species.BASCULEGION ],
|
||||
[BiomePoolTier.BOSS_SUPER_RARE]: [ Species.MILOTIC, Species.NIHILEGO, Species.CURSOLA, Species.OVERQWIL ],
|
||||
[BiomePoolTier.BOSS_ULTRA_RARE]: [ Species.KYOGRE ]
|
||||
},
|
||||
[Biome.MOUNTAIN]: {
|
||||
@ -573,10 +569,10 @@ export const biomePokemonPools: BiomePokemonPools = {
|
||||
],
|
||||
[BiomePoolTier.RARE]: [ Species.ONIX, { 1: [ Species.FERROSEED ], 40: [ Species.FERROTHORN ] }, Species.CARBINK ],
|
||||
[BiomePoolTier.SUPER_RARE]: [ Species.SHUCKLE ],
|
||||
[BiomePoolTier.ULTRA_RARE]: [ Species.REGISTEEL, Species.UXIE ],
|
||||
[BiomePoolTier.ULTRA_RARE]: [ Species.UXIE ],
|
||||
[BiomePoolTier.BOSS]: [ Species.PARASECT, Species.ONIX, Species.CROBAT, Species.URSARING, Species.EXPLOUD, Species.PROBOPASS, Species.GIGALITH, Species.SWOOBAT, Species.DIGGERSBY, Species.NOIVERN, Species.GOLISOPOD ],
|
||||
[BiomePoolTier.BOSS_RARE]: [ Species.SHUCKLE, Species.FERROTHORN, Species.LYCANROC ],
|
||||
[BiomePoolTier.BOSS_SUPER_RARE]: [ Species.REGISTEEL, Species.UXIE ],
|
||||
[BiomePoolTier.BOSS_SUPER_RARE]: [ Species.UXIE ],
|
||||
[BiomePoolTier.BOSS_ULTRA_RARE]: []
|
||||
},
|
||||
[Biome.DESERT]: {
|
||||
@ -726,7 +722,7 @@ export const biomePokemonPools: BiomePokemonPools = {
|
||||
{ 1: [ Species.CLOBBOPUS ], 20: [ Species.GRAPPLOCT ] }
|
||||
],
|
||||
[BiomePoolTier.UNCOMMON]: [ { 1: [ Species.CROAGUNK ], 37: [ Species.TOXICROAK ] }, { 1: [ Species.SCRAGGY ], 39: [ Species.SCRAFTY ] }, { 1: [ Species.MIENFOO ], 50: [ Species.MIENSHAO ] } ],
|
||||
[BiomePoolTier.RARE]: [ { 1: [ Species.TYROGUE ], 20: [ Species.HITMONLEE ] }, Species.HITMONCHAN, Species.LUCARIO, Species.THROH, Species.SAWK ],
|
||||
[BiomePoolTier.RARE]: [ Species.HITMONLEE, Species.HITMONCHAN, Species.LUCARIO, Species.THROH, Species.SAWK ],
|
||||
[BiomePoolTier.SUPER_RARE]: [ Species.HITMONTOP, Species.GALLADE, Species.GALAR_FARFETCHD ],
|
||||
[BiomePoolTier.ULTRA_RARE]: [ Species.TERRAKION, Species.KUBFU, Species.GALAR_ZAPDOS ],
|
||||
[BiomePoolTier.BOSS]: [ Species.PRIMEAPE, Species.HITMONLEE, Species.HITMONCHAN, Species.HARIYAMA, Species.MEDICHAM, Species.LUCARIO, Species.TOXICROAK, Species.THROH, Species.SAWK, Species.SCRAFTY, Species.MIENSHAO, Species.BEWEAR, Species.GRAPPLOCT ],
|
||||
@ -745,11 +741,11 @@ export const biomePokemonPools: BiomePokemonPools = {
|
||||
[BiomePoolTier.UNCOMMON]: [ { 1: [ Species.BRONZOR ], 33: [ Species.BRONZONG ] }, Species.KLEFKI ],
|
||||
[BiomePoolTier.RARE]: [],
|
||||
[BiomePoolTier.SUPER_RARE]: [ { 1: [ Species.PORYGON ], 20: [ Species.PORYGON2 ] }, { 1: [ Species.BELDUM ], 20: [ Species.METANG ], 45: [ Species.METAGROSS ] } ],
|
||||
[BiomePoolTier.ULTRA_RARE]: [ Species.GENESECT, Species.MAGEARNA, Species.MELTAN ],
|
||||
[BiomePoolTier.ULTRA_RARE]: [ Species.GENESECT, Species.MAGEARNA ],
|
||||
[BiomePoolTier.BOSS]: [ Species.KLINKLANG, Species.KLEFKI ],
|
||||
[BiomePoolTier.BOSS_RARE]: [],
|
||||
[BiomePoolTier.BOSS_SUPER_RARE]: [ Species.GENESECT, Species.MAGEARNA ],
|
||||
[BiomePoolTier.BOSS_ULTRA_RARE]: [ Species.MELMETAL ]
|
||||
[BiomePoolTier.BOSS_ULTRA_RARE]: []
|
||||
},
|
||||
[Biome.RUINS]: {
|
||||
[BiomePoolTier.COMMON]: [
|
||||
@ -763,11 +759,11 @@ export const biomePokemonPools: BiomePokemonPools = {
|
||||
[BiomePoolTier.UNCOMMON]: [ { 1: [ Species.ABRA ], 16: [ Species.KADABRA ] }, Species.SIGILYPH ],
|
||||
[BiomePoolTier.RARE]: [ Species.MR_MIME, Species.WOBBUFFET, { 1: [ Species.GOTHITA ], 32: [ Species.GOTHORITA ], 41: [ Species.GOTHITELLE ] }, Species.STONJOURNER ],
|
||||
[BiomePoolTier.SUPER_RARE]: [ Species.ESPEON, { 1: [ Species.ARCHEN ], 37: [ Species.ARCHEOPS ] }, { 1: [ Species.GALAR_YAMASK ], 34: [ Species.RUNERIGUS ] } ],
|
||||
[BiomePoolTier.ULTRA_RARE]: [ Species.MEW, Species.VICTINI ],
|
||||
[BiomePoolTier.ULTRA_RARE]: [ Species.REGISTEEL ],
|
||||
[BiomePoolTier.BOSS]: [ Species.ALAKAZAM, Species.HYPNO, Species.XATU, Species.GRUMPIG, Species.CLAYDOL, Species.SIGILYPH, Species.GOTHITELLE, Species.BEHEEYEM ],
|
||||
[BiomePoolTier.BOSS_RARE]: [ Species.MR_MIME, Species.ESPEON, Species.WOBBUFFET, Species.ARCHEOPS ],
|
||||
[BiomePoolTier.BOSS_SUPER_RARE]: [ Species.VICTINI, Species.RUNERIGUS ],
|
||||
[BiomePoolTier.BOSS_ULTRA_RARE]: [ Species.MEW ]
|
||||
[BiomePoolTier.BOSS_SUPER_RARE]: [ Species.REGISTEEL, Species.RUNERIGUS ],
|
||||
[BiomePoolTier.BOSS_ULTRA_RARE]: []
|
||||
},
|
||||
[Biome.WASTELAND]: {
|
||||
[BiomePoolTier.COMMON]: [
|
||||
@ -812,11 +808,11 @@ export const biomePokemonPools: BiomePokemonPools = {
|
||||
[BiomePoolTier.UNCOMMON]: [ { 1: [ Species.BALTOY ], 36: [ Species.CLAYDOL ] }, { 1: [ Species.ELGYEM ], 42: [ Species.BEHEEYEM ] } ],
|
||||
[BiomePoolTier.RARE]: [ { 1: [ Species.BELDUM ], 20: [ Species.METANG ], 45: [ Species.METAGROSS ] }, Species.SIGILYPH, { 1: [ Species.SOLOSIS ], 32: [ Species.DUOSION ], 41: [ Species.REUNICLUS ] } ],
|
||||
[BiomePoolTier.SUPER_RARE]: [ { 1: [ Species.PORYGON ], 20: [ Species.PORYGON2 ] } ],
|
||||
[BiomePoolTier.ULTRA_RARE]: [ Species.JIRACHI, Species.DEOXYS, Species.CRESSELIA, { 1: [ Species.COSMOG ], 43: [ Species.COSMOEM ] }, Species.CELESTEELA ],
|
||||
[BiomePoolTier.ULTRA_RARE]: [ Species.DEOXYS, Species.CRESSELIA, { 1: [ Species.COSMOG ], 43: [ Species.COSMOEM ] }, Species.CELESTEELA ],
|
||||
[BiomePoolTier.BOSS]: [ Species.CLEFABLE, Species.LUNATONE, Species.SOLROCK, Species.BRONZONG, Species.MUSHARNA, Species.REUNICLUS, Species.MINIOR ],
|
||||
[BiomePoolTier.BOSS_RARE]: [ Species.METAGROSS, Species.PORYGON_Z ],
|
||||
[BiomePoolTier.BOSS_SUPER_RARE]: [ Species.JIRACHI, Species.DEOXYS, Species.CRESSELIA, Species.CELESTEELA ],
|
||||
[BiomePoolTier.BOSS_ULTRA_RARE]: [ Species.RAYQUAZA, Species.ARCEUS, Species.SOLGALEO, Species.LUNALA, Species.NECROZMA ]
|
||||
[BiomePoolTier.BOSS_SUPER_RARE]: [ Species.DEOXYS, Species.CRESSELIA, Species.CELESTEELA ],
|
||||
[BiomePoolTier.BOSS_ULTRA_RARE]: [ Species.RAYQUAZA, Species.SOLGALEO, Species.LUNALA, Species.NECROZMA ]
|
||||
},
|
||||
[Biome.CONSTRUCTION_SITE]: {
|
||||
[BiomePoolTier.COMMON]: [
|
||||
@ -831,7 +827,7 @@ export const biomePokemonPools: BiomePokemonPools = {
|
||||
{ 1: [ Species.RHYHORN ], 42: [ Species.RHYDON ] },
|
||||
{ 1: [ Species.SCRAGGY ], 39: [ Species.SCRAFTY ] }
|
||||
],
|
||||
[BiomePoolTier.RARE]: [ Species.ONIX, { 1: [ Species.TYROGUE ], 20: [ Species.HITMONLEE ] }, Species.HITMONCHAN, Species.DURALUDON ],
|
||||
[BiomePoolTier.RARE]: [ Species.ONIX, Species.HITMONLEE, Species.HITMONCHAN, Species.DURALUDON ],
|
||||
[BiomePoolTier.SUPER_RARE]: [ Species.DITTO, Species.HITMONTOP, { 1: [ Species.GALAR_MEOWTH ], 28: [ Species.PERRSERKER ] } ],
|
||||
[BiomePoolTier.ULTRA_RARE]: [ Species.COBALION ],
|
||||
[BiomePoolTier.BOSS]: [ Species.MACHAMP, Species.CONKELDURR ],
|
||||
@ -1075,7 +1071,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
||||
[BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ],
|
||||
[BiomePoolTier.SUPER_RARE]: [],
|
||||
[BiomePoolTier.ULTRA_RARE]: [],
|
||||
[BiomePoolTier.BOSS]: [ TrainerType.NORMAN, TrainerType.CHEREN, TrainerType.LENORA ],
|
||||
[BiomePoolTier.BOSS]: [ TrainerType.CILAN, TrainerType.CHILI, TrainerType.CRESS, TrainerType.CHEREN, TrainerType.LENORA ],
|
||||
[BiomePoolTier.BOSS_RARE]: [],
|
||||
[BiomePoolTier.BOSS_SUPER_RARE]: [],
|
||||
[BiomePoolTier.BOSS_ULTRA_RARE]: []
|
||||
@ -1108,7 +1104,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
||||
[BiomePoolTier.RARE]: [ TrainerType.ARTIST ],
|
||||
[BiomePoolTier.SUPER_RARE]: [],
|
||||
[BiomePoolTier.ULTRA_RARE]: [],
|
||||
[BiomePoolTier.BOSS]: [ TrainerType.CHEREN ],
|
||||
[BiomePoolTier.BOSS]: [ TrainerType.NORMAN, TrainerType.CHEREN ],
|
||||
[BiomePoolTier.BOSS_RARE]: [],
|
||||
[BiomePoolTier.BOSS_SUPER_RARE]: [],
|
||||
[BiomePoolTier.BOSS_ULTRA_RARE]: []
|
||||
@ -2206,10 +2202,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
||||
[ Biome.END, BiomePoolTier.ULTRA_RARE ]
|
||||
]
|
||||
],
|
||||
[ Species.MEW, Type.PSYCHIC, -1, [
|
||||
[ Biome.RUINS, BiomePoolTier.ULTRA_RARE ],
|
||||
[ Biome.RUINS, BiomePoolTier.BOSS_ULTRA_RARE ]
|
||||
]
|
||||
[ Species.MEW, Type.PSYCHIC, -1, [ ]
|
||||
],
|
||||
[ Species.CHIKORITA, Type.GRASS, -1, [
|
||||
[ Biome.TALL_GRASS, BiomePoolTier.RARE ]
|
||||
@ -2306,21 +2299,13 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
||||
[ Biome.SEABED, BiomePoolTier.BOSS ]
|
||||
]
|
||||
],
|
||||
[ Species.PICHU, Type.ELECTRIC, -1, [
|
||||
[ Biome.TOWN, BiomePoolTier.UNCOMMON ]
|
||||
]
|
||||
[ Species.PICHU, Type.ELECTRIC, -1, [ ]
|
||||
],
|
||||
[ Species.CLEFFA, Type.FAIRY, -1, [
|
||||
[ Biome.TOWN, BiomePoolTier.RARE ]
|
||||
]
|
||||
[ Species.CLEFFA, Type.FAIRY, -1, [ ]
|
||||
],
|
||||
[ Species.IGGLYBUFF, Type.NORMAL, Type.FAIRY, [
|
||||
[ Biome.TOWN, BiomePoolTier.UNCOMMON ]
|
||||
]
|
||||
[ Species.IGGLYBUFF, Type.NORMAL, Type.FAIRY, [ ]
|
||||
],
|
||||
[ Species.TOGEPI, Type.FAIRY, -1, [
|
||||
[ Biome.TOWN, BiomePoolTier.SUPER_RARE ]
|
||||
]
|
||||
[ Species.TOGEPI, Type.FAIRY, -1, [ ]
|
||||
],
|
||||
[ Species.TOGETIC, Type.FAIRY, Type.FLYING, [
|
||||
[ Biome.FAIRY_CAVE, BiomePoolTier.UNCOMMON ]
|
||||
@ -2615,11 +2600,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
||||
[ Biome.METROPOLIS, BiomePoolTier.SUPER_RARE ]
|
||||
]
|
||||
],
|
||||
[ Species.TYROGUE, Type.FIGHTING, -1, [
|
||||
[ Biome.TOWN, BiomePoolTier.SUPER_RARE ],
|
||||
[ Biome.DOJO, BiomePoolTier.RARE ],
|
||||
[ Biome.CONSTRUCTION_SITE, BiomePoolTier.RARE ]
|
||||
]
|
||||
[ Species.TYROGUE, Type.FIGHTING, -1, [ ]
|
||||
],
|
||||
[ Species.HITMONTOP, Type.FIGHTING, -1, [
|
||||
[ Biome.DOJO, BiomePoolTier.SUPER_RARE ],
|
||||
@ -2627,17 +2608,11 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
||||
[ Biome.CONSTRUCTION_SITE, BiomePoolTier.SUPER_RARE ]
|
||||
]
|
||||
],
|
||||
[ Species.SMOOCHUM, Type.ICE, Type.PSYCHIC, [
|
||||
[ Biome.TOWN, BiomePoolTier.SUPER_RARE ]
|
||||
]
|
||||
[ Species.SMOOCHUM, Type.ICE, Type.PSYCHIC, [ ]
|
||||
],
|
||||
[ Species.ELEKID, Type.ELECTRIC, -1, [
|
||||
[ Biome.TOWN, BiomePoolTier.SUPER_RARE ]
|
||||
]
|
||||
[ Species.ELEKID, Type.ELECTRIC, -1, [ ]
|
||||
],
|
||||
[ Species.MAGBY, Type.FIRE, -1, [
|
||||
[ Biome.TOWN, BiomePoolTier.SUPER_RARE ]
|
||||
]
|
||||
[ Species.MAGBY, Type.FIRE, -1, [ ]
|
||||
],
|
||||
[ Species.MILTANK, Type.NORMAL, -1, [
|
||||
[ Biome.MEADOW, BiomePoolTier.RARE ],
|
||||
@ -2688,10 +2663,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
||||
[ Biome.MOUNTAIN, BiomePoolTier.BOSS_ULTRA_RARE ]
|
||||
]
|
||||
],
|
||||
[ Species.CELEBI, Type.PSYCHIC, Type.GRASS, [
|
||||
[ Biome.FOREST, BiomePoolTier.ULTRA_RARE ],
|
||||
[ Biome.FOREST, BiomePoolTier.BOSS_ULTRA_RARE ]
|
||||
]
|
||||
[ Species.CELEBI, Type.PSYCHIC, Type.GRASS, [ ]
|
||||
],
|
||||
[ Species.TREECKO, Type.GRASS, -1, [
|
||||
[ Biome.FOREST, BiomePoolTier.RARE ]
|
||||
@ -2918,9 +2890,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
||||
[ Biome.DOJO, BiomePoolTier.BOSS ]
|
||||
]
|
||||
],
|
||||
[ Species.AZURILL, Type.NORMAL, Type.FAIRY, [
|
||||
[ Biome.TOWN, BiomePoolTier.UNCOMMON ]
|
||||
]
|
||||
[ Species.AZURILL, Type.NORMAL, Type.FAIRY, [ ]
|
||||
],
|
||||
[ Species.NOSEPASS, Type.ROCK, -1, [
|
||||
[ Biome.CAVE, BiomePoolTier.UNCOMMON ]
|
||||
@ -3216,9 +3186,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
||||
[ Biome.ABYSS, BiomePoolTier.BOSS ]
|
||||
]
|
||||
],
|
||||
[ Species.WYNAUT, Type.PSYCHIC, -1, [
|
||||
[ Biome.TOWN, BiomePoolTier.SUPER_RARE ]
|
||||
]
|
||||
[ Species.WYNAUT, Type.PSYCHIC, -1, [ ]
|
||||
],
|
||||
[ Species.SNORUNT, Type.ICE, -1, [
|
||||
[ Biome.ICE_CAVE, BiomePoolTier.UNCOMMON ]
|
||||
@ -3306,8 +3274,8 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
||||
]
|
||||
],
|
||||
[ Species.REGISTEEL, Type.STEEL, -1, [
|
||||
[ Biome.CAVE, BiomePoolTier.ULTRA_RARE ],
|
||||
[ Biome.CAVE, BiomePoolTier.BOSS_SUPER_RARE ]
|
||||
[ Biome.RUINS, BiomePoolTier.ULTRA_RARE ],
|
||||
[ Biome.RUINS, BiomePoolTier.BOSS_SUPER_RARE ]
|
||||
]
|
||||
],
|
||||
[ Species.LATIAS, Type.DRAGON, Type.PSYCHIC, [
|
||||
@ -3333,10 +3301,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
||||
[ Biome.END, BiomePoolTier.ULTRA_RARE ]
|
||||
]
|
||||
],
|
||||
[ Species.JIRACHI, Type.STEEL, Type.PSYCHIC, [
|
||||
[ Biome.SPACE, BiomePoolTier.ULTRA_RARE ],
|
||||
[ Biome.SPACE, BiomePoolTier.BOSS_SUPER_RARE ]
|
||||
]
|
||||
[ Species.JIRACHI, Type.STEEL, Type.PSYCHIC, [ ]
|
||||
],
|
||||
[ Species.DEOXYS, Type.PSYCHIC, -1, [
|
||||
[ Biome.SPACE, BiomePoolTier.ULTRA_RARE ],
|
||||
@ -3435,9 +3400,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
||||
[ Biome.POWER_PLANT, BiomePoolTier.BOSS ]
|
||||
]
|
||||
],
|
||||
[ Species.BUDEW, Type.GRASS, Type.POISON, [
|
||||
[ Biome.TOWN, BiomePoolTier.UNCOMMON ]
|
||||
]
|
||||
[ Species.BUDEW, Type.GRASS, Type.POISON, [ ]
|
||||
],
|
||||
[ Species.ROSERADE, Type.GRASS, Type.POISON, [
|
||||
[ Biome.MEADOW, BiomePoolTier.BOSS ]
|
||||
@ -3599,17 +3562,11 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
||||
[ Biome.LABORATORY, BiomePoolTier.BOSS ]
|
||||
]
|
||||
],
|
||||
[ Species.BONSLY, Type.ROCK, -1, [
|
||||
[ Biome.TOWN, BiomePoolTier.SUPER_RARE ]
|
||||
]
|
||||
[ Species.BONSLY, Type.ROCK, -1, [ ]
|
||||
],
|
||||
[ Species.MIME_JR, Type.PSYCHIC, Type.FAIRY, [
|
||||
[ Biome.TOWN, BiomePoolTier.SUPER_RARE ]
|
||||
]
|
||||
[ Species.MIME_JR, Type.PSYCHIC, Type.FAIRY, [ ]
|
||||
],
|
||||
[ Species.HAPPINY, Type.NORMAL, -1, [
|
||||
[ Biome.TOWN, BiomePoolTier.SUPER_RARE ]
|
||||
]
|
||||
[ Species.HAPPINY, Type.NORMAL, -1, []
|
||||
],
|
||||
[ Species.CHATOT, Type.NORMAL, Type.FLYING, [
|
||||
[ Biome.JUNGLE, BiomePoolTier.SUPER_RARE ]
|
||||
@ -3638,13 +3595,9 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
||||
[ Biome.END, BiomePoolTier.COMMON ]
|
||||
]
|
||||
],
|
||||
[ Species.MUNCHLAX, Type.NORMAL, -1, [
|
||||
[ Biome.TOWN, BiomePoolTier.SUPER_RARE ]
|
||||
]
|
||||
[ Species.MUNCHLAX, Type.NORMAL, -1, [ ]
|
||||
],
|
||||
[ Species.RIOLU, Type.FIGHTING, -1, [
|
||||
[ Biome.TOWN, BiomePoolTier.SUPER_RARE ]
|
||||
]
|
||||
[ Species.RIOLU, Type.FIGHTING, -1, [ ]
|
||||
],
|
||||
[ Species.LUCARIO, Type.FIGHTING, Type.STEEL, [
|
||||
[ Biome.DOJO, BiomePoolTier.RARE ],
|
||||
@ -3844,34 +3797,22 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
||||
[ Biome.SPACE, BiomePoolTier.BOSS_SUPER_RARE ]
|
||||
]
|
||||
],
|
||||
[ Species.PHIONE, Type.WATER, -1, [
|
||||
[ Biome.SEABED, BiomePoolTier.RARE ],
|
||||
[ Biome.SEABED, BiomePoolTier.BOSS_RARE ]
|
||||
]
|
||||
[ Species.PHIONE, Type.WATER, -1, [ ]
|
||||
],
|
||||
[ Species.MANAPHY, Type.WATER, -1, [
|
||||
[ Biome.SEABED, BiomePoolTier.ULTRA_RARE ],
|
||||
[ Biome.SEABED, BiomePoolTier.BOSS_SUPER_RARE ]
|
||||
]
|
||||
[ Species.MANAPHY, Type.WATER, -1, [ ]
|
||||
],
|
||||
[ Species.DARKRAI, Type.DARK, -1, [
|
||||
[ Biome.ABYSS, BiomePoolTier.ULTRA_RARE ],
|
||||
[ Biome.ABYSS, BiomePoolTier.BOSS_SUPER_RARE ]
|
||||
]
|
||||
],
|
||||
[ Species.SHAYMIN, Type.GRASS, -1, [
|
||||
[ Biome.GRASS, BiomePoolTier.BOSS_ULTRA_RARE ]
|
||||
]
|
||||
[ Species.SHAYMIN, Type.GRASS, -1, [ ]
|
||||
],
|
||||
[ Species.ARCEUS, Type.NORMAL, -1, [
|
||||
[ Biome.SPACE, BiomePoolTier.BOSS_ULTRA_RARE ],
|
||||
[ Biome.END, BiomePoolTier.ULTRA_RARE ]
|
||||
]
|
||||
],
|
||||
[ Species.VICTINI, Type.PSYCHIC, Type.FIRE, [
|
||||
[ Biome.RUINS, BiomePoolTier.ULTRA_RARE ],
|
||||
[ Biome.RUINS, BiomePoolTier.BOSS_SUPER_RARE ]
|
||||
]
|
||||
[ Species.VICTINI, Type.PSYCHIC, Type.FIRE, [ ]
|
||||
],
|
||||
[ Species.SNIVY, Type.GRASS, -1, [
|
||||
[ Biome.JUNGLE, BiomePoolTier.RARE ]
|
||||
@ -5345,13 +5286,9 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
||||
[ Biome.POWER_PLANT, BiomePoolTier.BOSS_SUPER_RARE ]
|
||||
]
|
||||
],
|
||||
[ Species.MELTAN, Type.STEEL, -1, [
|
||||
[ Biome.FACTORY, BiomePoolTier.ULTRA_RARE ]
|
||||
]
|
||||
[ Species.MELTAN, Type.STEEL, -1, [ ]
|
||||
],
|
||||
[ Species.MELMETAL, Type.STEEL, -1, [
|
||||
[ Biome.FACTORY, BiomePoolTier.BOSS_ULTRA_RARE ]
|
||||
]
|
||||
[ Species.MELMETAL, Type.STEEL, -1, [ ]
|
||||
],
|
||||
[ Species.GROOKEY, Type.GRASS, -1, [
|
||||
[ Biome.JUNGLE, BiomePoolTier.RARE ]
|
||||
@ -6619,7 +6556,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
||||
]
|
||||
],
|
||||
[ TrainerType.NORMAN, [
|
||||
[ Biome.PLAINS, BiomePoolTier.BOSS ]
|
||||
[ Biome.METROPOLIS, BiomePoolTier.BOSS ]
|
||||
]
|
||||
],
|
||||
[ TrainerType.WINONA, [
|
||||
@ -6673,9 +6610,15 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
||||
[ Biome.POWER_PLANT, BiomePoolTier.BOSS ]
|
||||
]
|
||||
],
|
||||
[ TrainerType.CILAN, [] ],
|
||||
[ TrainerType.CHILI, [] ],
|
||||
[ TrainerType.CRESS, [] ],
|
||||
[ TrainerType.CILAN, [
|
||||
[ Biome.PLAINS, BiomePoolTier.BOSS ]
|
||||
] ],
|
||||
[ TrainerType.CHILI, [
|
||||
[ Biome.PLAINS, BiomePoolTier.BOSS ]
|
||||
] ],
|
||||
[ TrainerType.CRESS, [
|
||||
[ Biome.PLAINS, BiomePoolTier.BOSS ]
|
||||
] ],
|
||||
[ TrainerType.CHEREN, [
|
||||
[ Biome.PLAINS, BiomePoolTier.BOSS ],
|
||||
[ Biome.METROPOLIS, BiomePoolTier.BOSS ]
|
||||
|
@ -1,4 +1,9 @@
|
||||
import { ModifierTier } from "../modifier/modifier-type";
|
||||
import { Type } from "./type";
|
||||
import * as Utils from "../utils";
|
||||
import BattleScene from "../battle-scene";
|
||||
import { Species } from "./species";
|
||||
import { getPokemonSpecies, speciesStarters } from "./pokemon-species";
|
||||
|
||||
export const EGG_SEED = 1073741824;
|
||||
|
||||
@ -12,12 +17,99 @@ export class Egg {
|
||||
public id: integer;
|
||||
public tier: ModifierTier;
|
||||
public gachaType: GachaType;
|
||||
public hatchWaves: integer;
|
||||
public timestamp: integer;
|
||||
|
||||
constructor(id: integer, gachaType: GachaType, timestamp: integer) {
|
||||
constructor(id: integer, gachaType: GachaType, hatchWaves: integer, timestamp: integer) {
|
||||
this.id = id;
|
||||
this.tier = Math.floor(id / EGG_SEED);
|
||||
this.gachaType = gachaType;
|
||||
this.hatchWaves = hatchWaves;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
isManaphyEgg(): boolean {
|
||||
return this.tier === ModifierTier.COMMON && !(this.id % 255);
|
||||
}
|
||||
|
||||
getKey(): string {
|
||||
if (this.isManaphyEgg())
|
||||
return 'manaphy';
|
||||
return this.tier.toString();
|
||||
}
|
||||
}
|
||||
|
||||
export function getEggTierDefaultHatchWaves(tier: ModifierTier): integer {
|
||||
switch (tier) {
|
||||
case ModifierTier.COMMON:
|
||||
return 10;
|
||||
case ModifierTier.GREAT:
|
||||
return 25;
|
||||
case ModifierTier.ULTRA:
|
||||
return 50;
|
||||
}
|
||||
return 100;
|
||||
}
|
||||
|
||||
export function getEggDescriptor(egg: Egg): string {
|
||||
if (egg.isManaphyEgg())
|
||||
return 'Manaphy';
|
||||
switch (egg.tier) {
|
||||
case ModifierTier.GREAT:
|
||||
return 'Rare';
|
||||
case ModifierTier.ULTRA:
|
||||
return 'Epic';
|
||||
case ModifierTier.MASTER:
|
||||
return 'Legendary';
|
||||
default:
|
||||
return 'Common';
|
||||
}
|
||||
}
|
||||
|
||||
export function getEggHatchWavesMessage(hatchWaves: integer): string {
|
||||
if (hatchWaves <= 5)
|
||||
return 'Sounds can be heard coming from inside! It will hatch soon!';
|
||||
if (hatchWaves <= 15)
|
||||
return 'It appears to move occasionally. It may be close to hatching.';
|
||||
if (hatchWaves <= 50)
|
||||
return 'What will hatch from this? It doesn\'t seem close to hatching.';
|
||||
return 'It looks like this Egg will take a long time to hatch.';
|
||||
}
|
||||
|
||||
export function getEggGachaTypeDescriptor(scene: BattleScene, egg: Egg): string {
|
||||
if (egg.isManaphyEgg())
|
||||
return '';
|
||||
switch (egg.gachaType) {
|
||||
case GachaType.LEGENDARY:
|
||||
return `Legendary Rate Up (${getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(scene, egg.timestamp)).getName()})`;
|
||||
case GachaType.TYPE:
|
||||
return `Type Rate Up (${Utils.toReadableString(Type[getTypeGachaTypeForTimestamp(scene, egg.timestamp)])})`;
|
||||
case GachaType.SHINY:
|
||||
return 'Shiny Rate Up';
|
||||
}
|
||||
}
|
||||
|
||||
export function getLegendaryGachaSpeciesForTimestamp(scene: BattleScene, timestamp: integer): Species {
|
||||
const legendarySpecies = Object.entries(speciesStarters)
|
||||
.filter(s => s[1] >= 8 && s[1] <= 9)
|
||||
.map(s => parseInt(s[0]));
|
||||
|
||||
let ret: Species;
|
||||
|
||||
scene.executeWithSeedOffset(() => {
|
||||
ret = Phaser.Math.RND.pick(legendarySpecies);
|
||||
}, Utils.getSunday(new Date(timestamp)).getTime(), EGG_SEED.toString());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
export function getTypeGachaTypeForTimestamp(scene: BattleScene, timestamp: integer): Type {
|
||||
const types = Utils.getEnumValues(Type);
|
||||
let ret: Type;
|
||||
|
||||
scene.executeWithSeedOffset(() => {
|
||||
ret = Phaser.Math.RND.pick(types);
|
||||
}, Utils.getSunday(new Date(timestamp)).getTime(), EGG_SEED.toString());
|
||||
|
||||
return ret;
|
||||
}
|
@ -230,7 +230,7 @@ export abstract class PokemonSpeciesForm {
|
||||
const originalWarn = console.warn;
|
||||
// Ignore warnings for missing frames, because there will be a lot
|
||||
console.warn = () => {};
|
||||
const frameNames = scene.anims.generateFrameNames(this.getSpriteKey(female, formIndex, shiny), { zeroPad: 4, suffix: ".png", start: 1, end: 256 });
|
||||
const frameNames = scene.anims.generateFrameNames(this.getSpriteKey(female, formIndex, shiny), { zeroPad: 4, suffix: ".png", start: 1, end: 400 });
|
||||
console.warn = originalWarn;
|
||||
scene.anims.create({
|
||||
key: this.getSpriteKey(female, formIndex, shiny),
|
||||
|
@ -3,12 +3,16 @@ import { BattlePhase } from "./battle-phase";
|
||||
import BattleScene, { AnySound } from "./battle-scene";
|
||||
import * as Utils from "./utils";
|
||||
import { Mode } from "./ui/ui";
|
||||
import { Egg } from "./data/egg";
|
||||
import { EGG_SEED, Egg, GachaType, getLegendaryGachaSpeciesForTimestamp, getTypeGachaTypeForTimestamp } from "./data/egg";
|
||||
import EggHatchSceneHandler from "./ui/egg-hatch-scene-handler";
|
||||
import { ModifierTier } from "./modifier/modifier-type";
|
||||
import { Species } from "./data/species";
|
||||
import Pokemon, { PlayerPokemon } from "./pokemon";
|
||||
import { getPokemonSpecies, speciesStarters } from "./data/pokemon-species";
|
||||
import { StatsContainer } from "./ui/stats-container";
|
||||
import { TextStyle, addTextObject } from "./ui/text";
|
||||
import { Gender, getGenderColor, getGenderSymbol } from "./data/gender";
|
||||
import { achvs } from "./system/achv";
|
||||
|
||||
export class EggHatchPhase extends BattlePhase {
|
||||
private egg: Egg;
|
||||
@ -22,6 +26,9 @@ export class EggHatchPhase extends BattlePhase {
|
||||
private eggLightraysOverlay: Phaser.GameObjects.Sprite;
|
||||
private pokemonSprite: Phaser.GameObjects.Sprite;
|
||||
|
||||
private infoContainer: Phaser.GameObjects.Container;
|
||||
private statsContainer: StatsContainer;
|
||||
|
||||
constructor(scene: BattleScene, egg: Egg) {
|
||||
super(scene);
|
||||
|
||||
@ -36,6 +43,13 @@ export class EggHatchPhase extends BattlePhase {
|
||||
if (!this.egg)
|
||||
return this.end();
|
||||
|
||||
const eggIndex = this.scene.gameData.eggs.findIndex(e => e.id === this.egg.id);
|
||||
|
||||
if (eggIndex === -1)
|
||||
return this.end();
|
||||
|
||||
this.scene.gameData.eggs.splice(eggIndex, 1);
|
||||
|
||||
this.scene.fadeOutBgm(null, false);
|
||||
|
||||
const eggHatchHandler = this.scene.ui.getHandler() as EggHatchSceneHandler;
|
||||
@ -48,7 +62,7 @@ export class EggHatchPhase extends BattlePhase {
|
||||
|
||||
this.eggContainer = this.scene.add.container(this.eggHatchBg.displayWidth / 2, this.eggHatchBg.displayHeight / 2);
|
||||
|
||||
this.eggSprite = this.scene.add.sprite(0, 0, 'egg', `egg_${this.egg.tier}`);
|
||||
this.eggSprite = this.scene.add.sprite(0, 0, 'egg', `egg_${this.egg.getKey()}`);
|
||||
this.eggCrackSprite = this.scene.add.sprite(0, 0, 'egg_crack', '0');
|
||||
this.eggCrackSprite.setVisible(false);
|
||||
|
||||
@ -70,9 +84,58 @@ export class EggHatchPhase extends BattlePhase {
|
||||
this.eggHatchOverlay.setAlpha(0);
|
||||
this.scene.fieldUI.add(this.eggHatchOverlay);
|
||||
|
||||
const infoBg = this.scene.add.nineslice(0, 0, 'window', null, 96, 116, 6, 6, 6, 6);
|
||||
|
||||
this.infoContainer = this.scene.add.container(this.eggHatchBg.displayWidth + infoBg.width / 2, this.eggHatchBg.displayHeight / 2);
|
||||
|
||||
this.statsContainer = new StatsContainer(this.scene, -48, -54, true);
|
||||
|
||||
this.infoContainer.add(infoBg);
|
||||
this.infoContainer.add(this.statsContainer);
|
||||
|
||||
const pokemonGenderLabelText = addTextObject(this.scene, -16, 32, 'Gender:', TextStyle.WINDOW, { fontSize: '64px' });
|
||||
pokemonGenderLabelText.setOrigin(1, 0);
|
||||
pokemonGenderLabelText.setVisible(false);
|
||||
this.infoContainer.add(pokemonGenderLabelText);
|
||||
|
||||
const pokemonGenderText = addTextObject(this.scene, -12, 32, '', TextStyle.WINDOW, { fontSize: '64px' });
|
||||
pokemonGenderText.setOrigin(0, 0);
|
||||
pokemonGenderText.setVisible(false);
|
||||
this.infoContainer.add(pokemonGenderText);
|
||||
|
||||
const pokemonAbilityLabelText = addTextObject(this.scene, -16, 32, 'Ability:', TextStyle.WINDOW, { fontSize: '64px' });
|
||||
pokemonAbilityLabelText.setOrigin(1, 0);
|
||||
this.infoContainer.add(pokemonAbilityLabelText);
|
||||
|
||||
const pokemonAbilityText = addTextObject(this.scene, -12, 32, '', TextStyle.WINDOW, { fontSize: '64px' });
|
||||
pokemonAbilityText.setOrigin(0, 0);
|
||||
this.infoContainer.add(pokemonAbilityText);
|
||||
|
||||
this.eggHatchContainer.add(this.infoContainer);
|
||||
|
||||
const pokemon = this.generatePokemon();
|
||||
|
||||
console.log(pokemon.name, pokemon);
|
||||
let abilityYOffset = 5;
|
||||
|
||||
if (pokemon.gender > Gender.GENDERLESS) {
|
||||
pokemonGenderText.setText(getGenderSymbol(pokemon.gender));
|
||||
pokemonGenderText.setColor(getGenderColor(pokemon.gender));
|
||||
pokemonGenderText.setShadowColor(getGenderColor(pokemon.gender, true));
|
||||
pokemonGenderLabelText.setVisible(true);
|
||||
pokemonGenderText.setVisible(true);
|
||||
|
||||
abilityYOffset = 10;
|
||||
}
|
||||
|
||||
[ pokemonAbilityLabelText, pokemonAbilityText ].map(t => t.y += abilityYOffset);
|
||||
|
||||
pokemonAbilityText.setText(pokemon.getAbility().name);
|
||||
|
||||
const originalIvs: integer[] = this.scene.gameData.dexData[pokemon.species.speciesId].caughtAttr
|
||||
? this.scene.gameData.dexData[pokemon.species.speciesId].ivs
|
||||
: null;
|
||||
|
||||
this.statsContainer.updateIvs(pokemon.ivs, originalIvs);
|
||||
|
||||
this.pokemonSprite.setVisible(false);
|
||||
|
||||
@ -108,19 +171,35 @@ export class EggHatchPhase extends BattlePhase {
|
||||
ease: 'Cubic.easeIn'
|
||||
});
|
||||
this.scene.time.delayedCall(Utils.fixedInt(1500), () => {
|
||||
if (pokemon.species.mythical)
|
||||
this.scene.validateAchv(achvs.HATCH_MYTHICAL);
|
||||
if (pokemon.species.legendary)
|
||||
this.scene.validateAchv(achvs.HATCH_LEGENDARY);
|
||||
if (pokemon.isShiny())
|
||||
this.scene.validateAchv(achvs.HATCH_SHINY);
|
||||
this.eggContainer.setVisible(false);
|
||||
this.pokemonSprite.play(pokemon.getSpriteKey(true));
|
||||
this.pokemonSprite.setVisible(true);
|
||||
this.scene.time.delayedCall(Utils.fixedInt(1000), () => {
|
||||
pokemon.cry();
|
||||
this.scene.time.delayedCall(Utils.fixedInt(1250), () => {
|
||||
this.scene.tweens.add({
|
||||
targets: this.infoContainer,
|
||||
duration: Utils.fixedInt(750),
|
||||
ease: 'Cubic.easeInOut',
|
||||
x: this.eggHatchBg.displayWidth - 48
|
||||
});
|
||||
|
||||
this.scene.playSoundWithoutBgm('evolution_fanfare');
|
||||
|
||||
this.scene.ui.showText(`${pokemon.name} hatched from the egg!`, null, () => {
|
||||
this.scene.gameData.updateSpeciesDexIvs(pokemon.species.speciesId, pokemon.ivs);
|
||||
this.scene.gameData.setPokemonCaught(pokemon).then(() => {
|
||||
this.scene.ui.showText(null, 0);
|
||||
this.end();
|
||||
});
|
||||
}, null, true, 3000);
|
||||
this.scene.time.delayedCall(Utils.fixedInt(4250), () => this.scene.playBgm());
|
||||
//this.scene.time.delayedCall(Utils.fixedInt(4250), () => this.scene.playBgm());
|
||||
});
|
||||
});
|
||||
this.scene.tweens.add({
|
||||
@ -193,7 +272,8 @@ export class EggHatchPhase extends BattlePhase {
|
||||
doSprayParticle(trigIndex: integer, offsetY: number) {
|
||||
const initialX = this.eggHatchBg.displayWidth / 2;
|
||||
const initialY = this.eggHatchBg.displayHeight / 2 + offsetY;
|
||||
const particle = this.scene.add.image(initialX, initialY, 'egg_shard', `${this.egg.tier}_${Math.floor(trigIndex / 2)}`);
|
||||
const shardKey = !this.egg.isManaphyEgg() ? this.egg.tier.toString() : '1';
|
||||
const particle = this.scene.add.image(initialX, initialY, 'egg_shard', `${shardKey}_${Math.floor(trigIndex / 2)}`);
|
||||
this.eggHatchContainer.add(particle);
|
||||
|
||||
let f = 0;
|
||||
@ -228,12 +308,34 @@ export class EggHatchPhase extends BattlePhase {
|
||||
}
|
||||
|
||||
generatePokemon(): Pokemon {
|
||||
let ret: Pokemon;
|
||||
let speciesOverride: Species;
|
||||
|
||||
if (this.egg.isManaphyEgg()) {
|
||||
this.scene.executeWithSeedOffset(() => {
|
||||
const rand = Utils.randSeedInt(8);
|
||||
|
||||
speciesOverride = rand ? Species.PHIONE : Species.MANAPHY;
|
||||
}, this.egg.id, EGG_SEED.toString());
|
||||
} else if (this.egg.tier === ModifierTier.MASTER
|
||||
&& this.egg.gachaType === GachaType.LEGENDARY) {
|
||||
this.scene.executeWithSeedOffset(() => {
|
||||
if (!Utils.randSeedInt(2))
|
||||
speciesOverride = getLegendaryGachaSpeciesForTimestamp(this.scene, this.egg.timestamp);
|
||||
}, this.egg.id, EGG_SEED.toString());
|
||||
}
|
||||
|
||||
if (speciesOverride) {
|
||||
this.scene.executeWithSeedOffset(() => {
|
||||
ret = new PlayerPokemon(this.scene, getPokemonSpecies(speciesOverride), 5, null, null, undefined, false);
|
||||
}, this.egg.id, EGG_SEED.toString());
|
||||
} else {
|
||||
let minStarterValue: integer;
|
||||
let maxStarterValue: integer;
|
||||
|
||||
switch (this.egg.tier) {
|
||||
case ModifierTier.GREAT:
|
||||
minStarterValue = 3;
|
||||
minStarterValue = 4;
|
||||
maxStarterValue = 5;
|
||||
break;
|
||||
case ModifierTier.ULTRA:
|
||||
@ -246,14 +348,32 @@ export class EggHatchPhase extends BattlePhase {
|
||||
break;
|
||||
default:
|
||||
minStarterValue = 1;
|
||||
maxStarterValue = 2;
|
||||
maxStarterValue = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
const speciesPool = Object.keys(speciesStarters)
|
||||
const ignoredSpecies = [ Species.PHIONE, Species.MANAPHY, Species.ETERNATUS ];
|
||||
|
||||
let speciesPool = Object.keys(speciesStarters)
|
||||
.filter(s => speciesStarters[s] >= minStarterValue && speciesStarters[s] <= maxStarterValue)
|
||||
.map(s => parseInt(s) as Species)
|
||||
.filter(s => getPokemonSpecies(s).isObtainable());
|
||||
.filter(s => getPokemonSpecies(s).isObtainable() && ignoredSpecies.indexOf(s) === -1);
|
||||
|
||||
if (this.egg.gachaType === GachaType.TYPE) {
|
||||
let tryOverrideType: boolean;
|
||||
|
||||
this.scene.executeWithSeedOffset(() => {
|
||||
tryOverrideType = !Utils.randSeedInt(2);
|
||||
}, this.egg.id, EGG_SEED.toString());
|
||||
|
||||
if (tryOverrideType) {
|
||||
const type = getTypeGachaTypeForTimestamp(this.scene, this.egg.timestamp);
|
||||
const typeFilteredSpeciesPool = speciesPool
|
||||
.filter(s => getPokemonSpecies(s).isOfType(type));
|
||||
if (typeFilteredSpeciesPool.length)
|
||||
speciesPool = typeFilteredSpeciesPool;
|
||||
}
|
||||
}
|
||||
|
||||
let totalWeight = 0;
|
||||
const speciesWeights = [];
|
||||
@ -273,13 +393,14 @@ export class EggHatchPhase extends BattlePhase {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, this.egg.id);
|
||||
|
||||
console.log(species, totalWeight);
|
||||
ret = new PlayerPokemon(this.scene, getPokemonSpecies(species), 5, null, null, undefined, false);
|
||||
}, this.egg.id, EGG_SEED.toString());
|
||||
}
|
||||
|
||||
const pokemon = new PlayerPokemon(this.scene, getPokemonSpecies(species), 5, null, null);
|
||||
ret.trySetShiny(this.egg.gachaType === GachaType.SHINY ? 1024 : 512);
|
||||
|
||||
return pokemon;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ import Phaser from 'phaser';
|
||||
import BattleScene from './battle-scene';
|
||||
import InvertPostFX from './pipelines/invert';
|
||||
import { version } from '../package.json';
|
||||
import BBCodeTextPlugin from 'phaser3-rex-plugins/plugins/bbcodetext-plugin';
|
||||
|
||||
const config: Phaser.Types.Core.GameConfig = {
|
||||
type: Phaser.WEBGL,
|
||||
@ -11,6 +12,13 @@ const config: Phaser.Types.Core.GameConfig = {
|
||||
height: 1080,
|
||||
mode: Phaser.Scale.FIT
|
||||
},
|
||||
plugins: {
|
||||
global: [{
|
||||
key: 'rexBBCodeTextPlugin',
|
||||
plugin: BBCodeTextPlugin,
|
||||
start: true
|
||||
}]
|
||||
},
|
||||
pixelArt: true,
|
||||
pipeline: [ InvertPostFX ] as unknown as Phaser.Types.Core.PipelineConfig,
|
||||
scene: [ BattleScene ],
|
||||
|
@ -15,6 +15,7 @@ import { GameMode } from '../game-mode';
|
||||
import { StatusEffect, getStatusEffectDescriptor } from '../data/status-effect';
|
||||
import { SpeciesFormKey } from '../data/pokemon-species';
|
||||
import BattleScene from '../battle-scene';
|
||||
import { VoucherType, getVoucherTypeIcon, getVoucherTypeName } from '../system/voucher';
|
||||
|
||||
type Modifier = Modifiers.Modifier;
|
||||
|
||||
@ -96,6 +97,13 @@ class AddPokeballModifierType extends ModifierType {
|
||||
}
|
||||
}
|
||||
|
||||
class AddVoucherModifierType extends ModifierType {
|
||||
constructor(voucherType: VoucherType, count: integer) {
|
||||
super(`${count}x ${getVoucherTypeName(voucherType)}`, `Receive ${getVoucherTypeName(voucherType)} x${count}`,
|
||||
(_type, _args) => new Modifiers.AddVoucherModifier(this, voucherType, count), getVoucherTypeIcon(voucherType), 'voucher');
|
||||
}
|
||||
}
|
||||
|
||||
export class PokemonModifierType extends ModifierType {
|
||||
public selectFilter: PokemonSelectFilter;
|
||||
|
||||
@ -702,6 +710,10 @@ export const modifierTypes = {
|
||||
|
||||
MINI_BLACK_HOLE: () => new TurnHeldItemTransferModifierType('Mini Black Hole'),
|
||||
|
||||
VOUCHER: () => new AddVoucherModifierType(VoucherType.REGULAR, 1),
|
||||
VOUCHER_PLUS: () => new AddVoucherModifierType(VoucherType.PLUS, 1),
|
||||
VOUCHER_PREMIUM: () => new AddVoucherModifierType(VoucherType.PREMIUM, 1),
|
||||
|
||||
GOLDEN_POKEBALL: () => new ModifierType(`Golden ${getPokeballName(PokeballType.POKEBALL)}`, 'Adds 1 extra item option at the end of every battle',
|
||||
(type, _args) => new Modifiers.ExtraModifierModifier(type), 'pb_gold', null, 'pb_bounce_1'),
|
||||
|
||||
@ -811,16 +823,17 @@ const modifierPool = {
|
||||
new WeightedModifierType(modifierTypes.ABILITY_CHARM, 2),
|
||||
new WeightedModifierType(modifierTypes.IV_SCANNER, 2),
|
||||
new WeightedModifierType(modifierTypes.EXP_BALANCE, 1),
|
||||
new WeightedModifierType(modifierTypes.COIN_CASE, 1),
|
||||
new WeightedModifierType(modifierTypes.MEGA_EVOLUTION_ITEM, (party: Pokemon[]) => party[0].scene.getModifiers(Modifiers.MegaEvolutionAccessModifier).length && !party.filter(p => p.getFormKey().indexOf(SpeciesFormKey.MEGA) > -1).length ? 1 : 0),
|
||||
new WeightedModifierType(modifierTypes.REVERSE_DNA_SPLICERS, (party: Pokemon[]) => party[0].scene.gameMode !== GameMode.SPLICED_ENDLESS && party.filter(p => p.fusionSpecies).length ? 3 : 0),
|
||||
].map(m => { m.setTier(ModifierTier.ULTRA); return m; }),
|
||||
[ModifierTier.MASTER]: [
|
||||
new WeightedModifierType(modifierTypes.MASTER_BALL, 3),
|
||||
new WeightedModifierType(modifierTypes.SHINY_CHARM, 2),
|
||||
new WeightedModifierType(modifierTypes.MEGA_BRACELET, 1),
|
||||
new WeightedModifierType(modifierTypes.DNA_SPLICERS, (party: Pokemon[]) => party[0].scene.gameMode !== GameMode.SPLICED_ENDLESS && party.filter(p => !p.fusionSpecies).length > 1 ? 1 : 0),
|
||||
new WeightedModifierType(modifierTypes.MINI_BLACK_HOLE, (party: Pokemon[]) => party[0].scene.gameData.unlocks[Unlockables.MINI_BLACK_HOLE] ? 1 : 0),
|
||||
new WeightedModifierType(modifierTypes.MASTER_BALL, 32),
|
||||
new WeightedModifierType(modifierTypes.SHINY_CHARM, 18),
|
||||
new WeightedModifierType(modifierTypes.MEGA_BRACELET, 12),
|
||||
new WeightedModifierType(modifierTypes.VOUCHER, 6),
|
||||
new WeightedModifierType(modifierTypes.VOUCHER_PLUS, 1),
|
||||
new WeightedModifierType(modifierTypes.DNA_SPLICERS, (party: Pokemon[]) => party[0].scene.gameMode !== GameMode.SPLICED_ENDLESS && party.filter(p => !p.fusionSpecies).length > 1 ? 12 : 0),
|
||||
new WeightedModifierType(modifierTypes.MINI_BLACK_HOLE, (party: Pokemon[]) => party[0].scene.gameData.unlocks[Unlockables.MINI_BLACK_HOLE] ? 2 : 0),
|
||||
].map(m => { m.setTier(ModifierTier.MASTER); return m; }),
|
||||
[ModifierTier.LUXURY]: [
|
||||
new WeightedModifierType(modifierTypes.GOLDEN_EXP_CHARM, 1),
|
||||
|
@ -15,6 +15,7 @@ import { TempBattleStat } from '../data/temp-battle-stat';
|
||||
import { BerryType, getBerryEffectFunc, getBerryPredicate } from '../data/berry';
|
||||
import { StatusEffect, getStatusEffectDescriptor } from '../data/status-effect';
|
||||
import { MoneyAchv } from '../system/achv';
|
||||
import { VoucherType } from '../system/voucher';
|
||||
|
||||
type ModifierType = ModifierTypes.ModifierType;
|
||||
export type ModifierPredicate = (modifier: Modifier) => boolean;
|
||||
@ -234,6 +235,25 @@ export class AddPokeballModifier extends ConsumableModifier {
|
||||
}
|
||||
}
|
||||
|
||||
export class AddVoucherModifier extends ConsumableModifier {
|
||||
private voucherType: VoucherType;
|
||||
private count: integer;
|
||||
|
||||
constructor(type: ModifierType, voucherType: VoucherType, count: integer) {
|
||||
super(type);
|
||||
|
||||
this.voucherType = voucherType;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
apply(args: any[]): boolean {
|
||||
const voucherCounts = (args[0] as BattleScene).gameData.voucherCounts;
|
||||
voucherCounts[this.voucherType] += this.count;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class LapsingPersistentModifier extends PersistentModifier {
|
||||
protected battlesLeft: integer;
|
||||
|
||||
@ -1299,7 +1319,7 @@ export class ShinyRateBoosterModifier extends PersistentModifier {
|
||||
}
|
||||
|
||||
apply(args: any[]): boolean {
|
||||
(args[0] as Utils.IntegerHolder).value /= Math.pow(2, -3 - this.getStackCount());
|
||||
(args[0] as Utils.IntegerHolder).value *= Math.pow(2, 2 + this.getStackCount());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -271,7 +271,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
const originalWarn = console.warn;
|
||||
// Ignore warnings for missing frames, because there will be a lot
|
||||
console.warn = () => {};
|
||||
const battleFrameNames = this.scene.anims.generateFrameNames(this.getBattleSpriteKey(), { zeroPad: 4, suffix: ".png", start: 1, end: 256 });
|
||||
const battleFrameNames = this.scene.anims.generateFrameNames(this.getBattleSpriteKey(), { zeroPad: 4, suffix: ".png", start: 1, end: 400 });
|
||||
console.warn = originalWarn;
|
||||
this.scene.anims.create({
|
||||
key: this.getBattleSpriteKey(),
|
||||
@ -686,7 +686,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
this.summonData.moveset[moveIndex] = move;
|
||||
}
|
||||
|
||||
trySetShiny(): boolean {
|
||||
trySetShiny(thresholdOverride?: integer): boolean {
|
||||
const rand1 = Utils.binToDec(Utils.decToBin(this.id).substring(0, 16));
|
||||
const rand2 = Utils.binToDec(Utils.decToBin(this.id).substring(16, 32));
|
||||
|
||||
@ -694,10 +694,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
const F = rand1 ^ rand2;
|
||||
|
||||
let shinyThreshold = new Utils.IntegerHolder(32);
|
||||
if (thresholdOverride === undefined) {
|
||||
if (!this.hasTrainer()) {
|
||||
this.scene.applyModifiers(ShinyRateBoosterModifier, true, shinyThreshold);
|
||||
console.log(shinyThreshold.value);
|
||||
console.log(shinyThreshold.value, 'SHINY THRESHOLD');
|
||||
}
|
||||
} else
|
||||
shinyThreshold.value = thresholdOverride;
|
||||
|
||||
this.shiny = (E ^ F) < shinyThreshold.value;
|
||||
if ((E ^ F) < 32)
|
||||
@ -1836,11 +1839,13 @@ export class EnemyPokemon extends Pokemon {
|
||||
|
||||
constructor(scene: BattleScene, species: PokemonSpecies, level: integer, trainer: boolean, dataSource?: PokemonData) {
|
||||
super(scene, 236, 84, species, level, dataSource?.abilityIndex, dataSource ? dataSource.formIndex : scene.getSpeciesFormIndex(species),
|
||||
dataSource?.gender, dataSource?.shiny, null, dataSource);
|
||||
dataSource?.gender, dataSource ? dataSource.shiny : false, null, dataSource);
|
||||
|
||||
this.trainer = trainer;
|
||||
|
||||
if (!dataSource) {
|
||||
this.trySetShiny();
|
||||
|
||||
let prevolution: Species;
|
||||
let speciesId = species.speciesId;
|
||||
while ((prevolution = pokemonPrevolutions[speciesId])) {
|
||||
|
@ -31,6 +31,14 @@ export class Achv {
|
||||
this.conditionFunc = conditionFunc;
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
getIconImage(): string {
|
||||
return this.iconImage;
|
||||
}
|
||||
|
||||
setSecret(hasParent?: boolean): this {
|
||||
this.secret = true;
|
||||
this.hasParent = !!hasParent;
|
||||
@ -118,10 +126,13 @@ export const achvs = {
|
||||
MEGA_EVOLVE: new Achv('Megamorph', 'Mega evolve a Pokémon', 'mega_bracelet', 50),
|
||||
SPLICE: new Achv('Infinite Fusion', 'Splice two Pokémon together with DNA Splicers', 'dna_splicers', 10),
|
||||
MINI_BLACK_HOLE: new ModifierAchv('A Hole Lot of Items', 'Acquire a Mini Black Hole', 'mini_black_hole', 25, modifier => modifier instanceof TurnHeldItemTransferModifier).setSecret(),
|
||||
CATCH_LEGENDARY: new Achv('Legendary', 'Catch a legendary Pokémon', 'mb', 50).setSecret(),
|
||||
CATCH_MYTHICAL: new Achv('Mythical', 'Catch a mythical Pokémon', 'strange_ball', 50).setSecret(),
|
||||
CATCH_LEGENDARY: new Achv('Legendary', 'Catch a legendary Pokémon', 'mb', 75).setSecret(),
|
||||
SEE_SHINY: new Achv('Shiny', 'Find a shiny Pokémon in the wild', 'pb_gold', 75),
|
||||
SHINY_PARTY: new Achv('That\'s Dedication', 'Have a full party of shiny Pokémon', 'shiny_charm', 100).setSecret(true),
|
||||
HATCH_MYTHICAL: new Achv('Mythical Egg', 'Hatch a mythical Pokémon from an egg', 'pair_of_tickets', 75).setSecret(),
|
||||
HATCH_LEGENDARY: new Achv('Legendary Egg', 'Hatch a legendary Pokémon from an egg', 'mystic_ticket', 100).setSecret(),
|
||||
HATCH_SHINY: new Achv('Shiny Egg', 'Hatch a shiny Pokémon from an egg', 'golden_mystic_ticket', 100).setSecret(),
|
||||
HIDDEN_ABILITY: new Achv('Hidden Potential', 'Catch a Pokémon with a hidden ability', 'ability_charm', 75),
|
||||
PERFECT_IVS: new Achv('Certificate of Authenticity', 'Get perfect IVs on a Pokémon', 'blunder_policy', 100),
|
||||
CLASSIC_VICTORY: new Achv('Undefeated', 'Beat the game in classic mode', 'relic_crown', 150)
|
||||
|
@ -3,16 +3,18 @@ import { Egg, GachaType } from "../data/egg";
|
||||
export default class EggData {
|
||||
public id: integer;
|
||||
public gachaType: GachaType;
|
||||
public hatchWaves: integer;
|
||||
public timestamp: integer;
|
||||
|
||||
constructor(source: Egg | any) {
|
||||
const sourceEgg = source instanceof Egg ? source as Egg : null;
|
||||
this.id = sourceEgg ? sourceEgg.id : source.id;
|
||||
this.gachaType = sourceEgg ? sourceEgg.gachaType : source.gachaType;
|
||||
this.hatchWaves = sourceEgg ? sourceEgg.hatchWaves : source.hatchWaves;
|
||||
this.timestamp = sourceEgg ? sourceEgg.timestamp : source.timestamp;
|
||||
}
|
||||
|
||||
toEgg(): Egg {
|
||||
return new Egg(this.id, this.gachaType, this.timestamp);
|
||||
return new Egg(this.id, this.gachaType, this.hatchWaves, this.timestamp);
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ import { Setting, setSetting, settingDefaults } from "./settings";
|
||||
import { achvs } from "./achv";
|
||||
import EggData from "./egg-data";
|
||||
import { Egg } from "../data/egg";
|
||||
import { VoucherType, vouchers } from "./voucher";
|
||||
|
||||
interface SystemSaveData {
|
||||
trainerId: integer;
|
||||
@ -23,6 +24,8 @@ interface SystemSaveData {
|
||||
dexData: DexData;
|
||||
unlocks: Unlocks;
|
||||
achvUnlocks: AchvUnlocks;
|
||||
voucherUnlocks: VoucherUnlocks;
|
||||
voucherCounts: VoucherCounts;
|
||||
eggs: EggData[];
|
||||
gameVersion: string;
|
||||
timestamp: integer;
|
||||
@ -54,6 +57,14 @@ interface AchvUnlocks {
|
||||
[key: string]: integer
|
||||
}
|
||||
|
||||
interface VoucherUnlocks {
|
||||
[key: string]: integer
|
||||
}
|
||||
|
||||
export interface VoucherCounts {
|
||||
[type: string]: integer;
|
||||
}
|
||||
|
||||
export interface DexData {
|
||||
[key: integer]: DexEntry
|
||||
}
|
||||
@ -96,6 +107,8 @@ export class GameData {
|
||||
|
||||
public achvUnlocks: AchvUnlocks;
|
||||
|
||||
public voucherUnlocks: VoucherUnlocks;
|
||||
public voucherCounts: VoucherCounts;
|
||||
public eggs: Egg[];
|
||||
|
||||
constructor(scene: BattleScene) {
|
||||
@ -109,6 +122,12 @@ export class GameData {
|
||||
[Unlockables.SPLICED_ENDLESS_MODE]: false
|
||||
};
|
||||
this.achvUnlocks = {};
|
||||
this.voucherUnlocks = {};
|
||||
this.voucherCounts = {
|
||||
[VoucherType.REGULAR]: 0,
|
||||
[VoucherType.PLUS]: 0,
|
||||
[VoucherType.PREMIUM]: 0
|
||||
};
|
||||
this.eggs = [];
|
||||
this.initDexData();
|
||||
this.loadSystem();
|
||||
@ -124,6 +143,8 @@ export class GameData {
|
||||
dexData: this.dexData,
|
||||
unlocks: this.unlocks,
|
||||
achvUnlocks: this.achvUnlocks,
|
||||
voucherUnlocks: this.voucherUnlocks,
|
||||
voucherCounts: this.voucherCounts,
|
||||
eggs: this.eggs.map(e => new EggData(e)),
|
||||
gameVersion: this.scene.game.config.gameVersion,
|
||||
timestamp: new Date().getTime()
|
||||
@ -141,7 +162,16 @@ export class GameData {
|
||||
if (!localStorage.hasOwnProperty('data'))
|
||||
return false;
|
||||
|
||||
const data = JSON.parse(atob(localStorage.getItem('data')), (k: string, v: any) => k.endsWith('Attr') ? BigInt(v) : v) as SystemSaveData;
|
||||
const data = JSON.parse(atob(localStorage.getItem('data')), (k: string, v: any) => {
|
||||
if (k === 'eggs') {
|
||||
const ret: EggData[] = [];
|
||||
for (let e of v)
|
||||
ret.push(new EggData(e));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return k.endsWith('Attr') ? BigInt(v) : v;
|
||||
}) as SystemSaveData;
|
||||
|
||||
console.debug(data);
|
||||
|
||||
@ -168,6 +198,20 @@ export class GameData {
|
||||
}
|
||||
}
|
||||
|
||||
if (data.voucherUnlocks) {
|
||||
for (let v of Object.keys(data.voucherUnlocks)) {
|
||||
if (vouchers.hasOwnProperty(v))
|
||||
this.voucherUnlocks[v] = data.voucherUnlocks[v];
|
||||
}
|
||||
}
|
||||
|
||||
if (data.voucherCounts) {
|
||||
Utils.getEnumKeys(VoucherType).forEach(key => {
|
||||
const index = VoucherType[key];
|
||||
this.voucherCounts[index] = data.voucherCounts[index] || 0;
|
||||
});
|
||||
}
|
||||
|
||||
this.eggs = data.eggs
|
||||
? data.eggs.map(e => e.toEgg())
|
||||
: [];
|
||||
@ -423,6 +467,20 @@ export class GameData {
|
||||
});
|
||||
}
|
||||
|
||||
updateSpeciesDexIvs(speciesId: Species, ivs: integer[]): void {
|
||||
let dexEntry: DexEntry;
|
||||
do {
|
||||
dexEntry = this.scene.gameData.dexData[speciesId];
|
||||
const dexIvs = dexEntry.ivs;
|
||||
for (let i = 0; i < dexIvs.length; i++) {
|
||||
if (dexIvs[i] < ivs[i])
|
||||
dexIvs[i] = ivs[i];
|
||||
}
|
||||
if (dexIvs.filter(iv => iv === 31).length === 6)
|
||||
this.scene.validateAchv(achvs.PERFECT_IVS);
|
||||
} while (pokemonPrevolutions.hasOwnProperty(speciesId) && (speciesId = pokemonPrevolutions[speciesId]));
|
||||
}
|
||||
|
||||
getSpeciesDefaultDexAttr(species: PokemonSpecies): bigint {
|
||||
let ret = 0n;
|
||||
const dexEntry = this.dexData[species.speciesId];
|
||||
|
106
src/system/voucher.ts
Normal file
@ -0,0 +1,106 @@
|
||||
import BattleScene from "../battle-scene";
|
||||
import { TrainerType, trainerConfigs } from "../data/trainer-type";
|
||||
import { ModifierTier } from "../modifier/modifier-type";
|
||||
import { Achv, achvs } from "./achv";
|
||||
|
||||
export enum VoucherType {
|
||||
REGULAR,
|
||||
PLUS,
|
||||
PREMIUM
|
||||
}
|
||||
|
||||
export class Voucher {
|
||||
public id: string;
|
||||
public voucherType: VoucherType;
|
||||
public description: string;
|
||||
|
||||
private conditionFunc: (scene: BattleScene, args: any[]) => boolean;
|
||||
|
||||
constructor(voucherType: VoucherType, description: string, conditionFunc?: (scene: BattleScene, args: any[]) => boolean) {
|
||||
this.description = description;
|
||||
this.voucherType = voucherType;
|
||||
this.conditionFunc = conditionFunc;
|
||||
}
|
||||
|
||||
validate(scene: BattleScene, args: any[]): boolean {
|
||||
return !this.conditionFunc || this.conditionFunc(scene, args);
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return getVoucherTypeName(this.voucherType);
|
||||
}
|
||||
|
||||
getIconImage(): string {
|
||||
return getVoucherTypeIcon(this.voucherType);
|
||||
}
|
||||
|
||||
getTier(): ModifierTier {
|
||||
switch (this.voucherType) {
|
||||
case VoucherType.REGULAR:
|
||||
return ModifierTier.GREAT;
|
||||
case VoucherType.PLUS:
|
||||
return ModifierTier.ULTRA;
|
||||
case VoucherType.PREMIUM:
|
||||
return ModifierTier.MASTER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getVoucherTypeName(voucherType: VoucherType): string {
|
||||
switch (voucherType) {
|
||||
case VoucherType.REGULAR:
|
||||
return 'Egg Voucher';
|
||||
case VoucherType.PLUS:
|
||||
return 'Egg Voucher Plus';
|
||||
case VoucherType.PREMIUM:
|
||||
return 'Egg Voucher Premium';
|
||||
}
|
||||
}
|
||||
|
||||
export function getVoucherTypeIcon(voucherType: VoucherType): string {
|
||||
switch (voucherType) {
|
||||
case VoucherType.REGULAR:
|
||||
return 'coupon';
|
||||
case VoucherType.PLUS:
|
||||
return 'pair_of_tickets';
|
||||
case VoucherType.PREMIUM:
|
||||
return 'mystic_ticket';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export interface Vouchers {
|
||||
[key: string]: Voucher
|
||||
}
|
||||
|
||||
export const vouchers: Vouchers = {};
|
||||
|
||||
const voucherAchvs: Achv[] = [ achvs.CLASSIC_VICTORY ];
|
||||
|
||||
{
|
||||
(function() {
|
||||
const bossTrainerTypes = Object.keys(trainerConfigs)
|
||||
.filter(tt => trainerConfigs[tt].isBoss && trainerConfigs[tt].getDerivedType() !== TrainerType.RIVAL);
|
||||
|
||||
for (let trainerType of bossTrainerTypes) {
|
||||
const voucherType = trainerConfigs[trainerType].moneyMultiplier < 10
|
||||
? VoucherType.REGULAR
|
||||
: VoucherType.PLUS;
|
||||
const key = TrainerType[trainerType];
|
||||
vouchers[key] = new Voucher(voucherType, `Defeat ${trainerConfigs[trainerType].name}`);
|
||||
}
|
||||
|
||||
for (let achv of voucherAchvs) {
|
||||
const voucherType = achv.score >= 150
|
||||
? VoucherType.PREMIUM
|
||||
: achv.score >= 100
|
||||
? VoucherType.PLUS
|
||||
: VoucherType.REGULAR;
|
||||
vouchers[achv.id] = new Voucher(voucherType, achv.description);
|
||||
}
|
||||
|
||||
const voucherKeys = Object.keys(vouchers);
|
||||
for (let k of voucherKeys)
|
||||
vouchers[k].id = k;
|
||||
})();
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
600
src/ui/egg-gacha-ui-handler.ts
Normal file
@ -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);
|
||||
}
|
||||
}
|
@ -24,7 +24,7 @@ export default class EggHatchSceneHandler extends UiHandler {
|
||||
show(_args: any[]): void {
|
||||
super.show(_args);
|
||||
|
||||
this.scene.fieldUI.bringToTop(this.eggHatchContainer);
|
||||
this.getUi().showText(null, 0);
|
||||
}
|
||||
|
||||
processInput(button: Button): boolean {
|
||||
@ -36,6 +36,7 @@ export default class EggHatchSceneHandler extends UiHandler {
|
||||
}
|
||||
|
||||
clear() {
|
||||
super.clear();
|
||||
this.eggHatchContainer.removeAll(true);
|
||||
}
|
||||
}
|
201
src/ui/egg-list-ui-handler.ts
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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,
|
||||
|
@ -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';
|
||||
|
52
src/ui/ui.ts
@ -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)
|
||||
];
|
||||
}
|
||||
|
||||
@ -111,6 +126,7 @@ export default class UI extends Phaser.GameObjects.Container {
|
||||
|
||||
this.achvBar = new AchvBar(this.scene as BattleScene);
|
||||
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 {
|
||||
revertMode(): Promise<boolean> {
|
||||
return new Promise<boolean>(resolve => {
|
||||
if (!this.modeChain.length)
|
||||
return false;
|
||||
return resolve(false);
|
||||
|
||||
const lastMode = this.mode;
|
||||
|
||||
const doRevertMode = () => {
|
||||
this.getHandler().clear();
|
||||
this.mode = this.modeChain.pop();
|
||||
return true;
|
||||
};
|
||||
|
||||
if (noTransitionModes.indexOf(lastMode) === -1) {
|
||||
this.fadeOut(250).then(() => {
|
||||
this.scene.time.delayedCall(100, () => {
|
||||
doRevertMode();
|
||||
this.fadeIn(250);
|
||||
});
|
||||
});
|
||||
} else
|
||||
doRevertMode();
|
||||
|
||||
resolve(true);
|
||||
});
|
||||
}
|
||||
}
|
196
src/ui/vouchers-ui-handler.ts
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -76,6 +76,13 @@ export function randIntRange(min: integer, max: integer): integer {
|
||||
return randInt(max - min, min);
|
||||
}
|
||||
|
||||
export function getSunday(date: Date): Date {
|
||||
const day = date.getDay(),
|
||||
diff = date.getDate() - day;
|
||||
const newDate = new Date(date.setDate(diff));
|
||||
return new Date(newDate.getFullYear(), newDate.getMonth(), newDate.getDate());
|
||||
}
|
||||
|
||||
export function getFrameMs(frameCount: integer): integer {
|
||||
return Math.floor((1 / 60) * 1000 * frameCount);
|
||||
}
|
||||
|