Indicator when a candy upgrade is available (#1083)

* initial implementation

* updated logic

* reverse retTint

* added candy overlays and colors

* added settings and minor fixes

* german changes

* logic fix

* german changes pt2

* german changes pt3

* setting name changed

* Update battle-scene.ts

* initial animation implementation

* minor fixes

* main compatibility

* minor fix

* logic for animations

* eslint fixes

* final generation logic

* Pause Animation when Selected or Purchased

* Disable Indicator if not Root Species

* Add to Reload and Add Anchor

* Fix Animation on Change

* Fix Icon on Change

* Code Cleanup

* fix

---------

Co-authored-by: Benjamin Odom <bennybroseph@gmail.com>
This commit is contained in:
José Ricardo Fleury Oliveira 2024-05-28 14:49:15 -03:00 committed by GitHub
parent 9893c21a7e
commit 7e003d68a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 342 additions and 32 deletions

2
package-lock.json generated
View File

@ -38,7 +38,7 @@
"vitest-canvas-mock": "^0.3.3"
},
"engines": {
"node": ">=18.0.0"
"node": ">=20.0.0"
}
},
"node_modules/@ampproject/remapping": {

View File

@ -2,6 +2,12 @@ import Move from "./data/move";
/** Alias for all {@linkcode BattleScene} events */
export enum BattleSceneEventType {
/**
* Triggers when the corresponding setting is changed
* @see {@linkcode CandyUpgradeNotificationChangedEvent}
*/
CANDY_UPGRADE_NOTIFICATION_CHANGED = "onCandyUpgradeDisplayChanged",
/**
* Triggers when a move is successfully used
* @see {@linkcode MoveUsedEvent}
@ -24,6 +30,20 @@ export enum BattleSceneEventType {
NEW_ARENA = "onNewArena",
}
/**
* Container class for {@linkcode BattleSceneEventType.CANDY_UPGRADE_NOTIFICATION_CHANGED} events
* @extends Event
*/
export class CandyUpgradeNotificationChangedEvent extends Event {
/** The new value the setting was changed to */
public newValue: number;
constructor(newValue: number) {
super(BattleSceneEventType.CANDY_UPGRADE_NOTIFICATION_CHANGED);
this.newValue = newValue;
}
}
/**
* Container class for {@linkcode BattleSceneEventType.MOVE_USED} events
* @extends Event

View File

@ -93,6 +93,19 @@ export default class BattleScene extends SceneBase {
public showLevelUpStats: boolean = true;
public enableTutorials: boolean = import.meta.env.VITE_BYPASS_TUTORIAL === "1";
public enableRetries: boolean = false;
/**
* Determines the condition for a notification should be shown for Candy Upgrades
* - 0 = 'Off'
* - 1 = 'Passives Only'
* - 2 = 'On'
*/
public candyUpgradeNotification: integer = 0;
/**
* Determines what type of notification is used for Candy Upgrades
* - 0 = 'Icon'
* - 1 = 'Animation'
*/
public candyUpgradeDisplay: integer = 0;
public moneyFormat: MoneyFormat = MoneyFormat.NORMAL;
public uiTheme: UiTheme = UiTheme.DEFAULT;
public windowType: integer = 0;

View File

@ -5,6 +5,7 @@ import BattleScene from "../battle-scene";
import { hasTouchscreen } from "../touch-controls";
import { updateWindowType } from "../ui/ui-theme";
import { PlayerGender } from "./game-data";
import { CandyUpgradeNotificationChangedEvent } from "#app/battle-scene-events.js";
import { MoneyFormat } from "../enums/money-format";
export enum Setting {
@ -18,6 +19,8 @@ export enum Setting {
Window_Type = "WINDOW_TYPE",
Tutorials = "TUTORIALS",
Enable_Retries = "ENABLE_RETRIES",
Candy_Upgrade_Notification = "CANDY_UPGRADE_NOTIFICATION",
Candy_Upgrade_Display = "CANDY_UPGRADE_DISPLAY",
Money_Format = "MONEY_FORMAT",
Sprite_Set = "SPRITE_SET",
Move_Animations = "MOVE_ANIMATIONS",
@ -52,6 +55,8 @@ export const settingOptions: SettingOptions = {
[Setting.Window_Type]: new Array(5).fill(null).map((_, i) => (i + 1).toString()),
[Setting.Tutorials]: ["Off", "On"],
[Setting.Enable_Retries]: ["Off", "On"],
[Setting.Candy_Upgrade_Notification]: ["Off", "Passives Only", "On"],
[Setting.Candy_Upgrade_Display]: ["Icon", "Animation"],
[Setting.Money_Format]: ["Normal", "Abbreviated"],
[Setting.Sprite_Set]: ["Consistent", "Mixed Animated"],
[Setting.Move_Animations]: ["Off", "On"],
@ -78,6 +83,8 @@ export const settingDefaults: SettingDefaults = {
[Setting.Window_Type]: 0,
[Setting.Tutorials]: 1,
[Setting.Enable_Retries]: 0,
[Setting.Candy_Upgrade_Notification]: 0,
[Setting.Candy_Upgrade_Display]: 0,
[Setting.Money_Format]: 0,
[Setting.Sprite_Set]: 0,
[Setting.Move_Animations]: 1,
@ -93,7 +100,7 @@ export const settingDefaults: SettingDefaults = {
[Setting.Vibration]: 0
};
export const reloadSettings: Setting[] = [Setting.UI_Theme, Setting.Language, Setting.Sprite_Set];
export const reloadSettings: Setting[] = [Setting.UI_Theme, Setting.Language, Setting.Sprite_Set, Setting.Candy_Upgrade_Display];
export function setSetting(scene: BattleScene, setting: Setting, value: integer): boolean {
switch (setting) {
@ -127,6 +134,16 @@ export function setSetting(scene: BattleScene, setting: Setting, value: integer)
case Setting.Enable_Retries:
scene.enableRetries = settingOptions[setting][value] === "On";
break;
case Setting.Candy_Upgrade_Notification:
if (scene.candyUpgradeNotification === value) {
break;
}
scene.candyUpgradeNotification = value;
scene.eventTarget.dispatchEvent(new CandyUpgradeNotificationChangedEvent(value));
break;
case Setting.Candy_Upgrade_Display:
scene.candyUpgradeDisplay = value;
case Setting.Money_Format:
switch (settingOptions[setting][value]) {
case "Normal":

View File

@ -1,3 +1,4 @@
import { BattleSceneEventType, CandyUpgradeNotificationChangedEvent } from "#app/battle-scene-events.js";
import { pokemonPrevolutions } from "#app/data/pokemon-evolutions";
import { Variant, getVariantTint } from "#app/data/variant";
import { argbFromRgba } from "@material/material-color-utilities";
@ -103,6 +104,29 @@ function getValueReductionCandyCounts(baseValue: integer): [integer, integer] {
return starterCandyCosts[baseValue - 1].costReduction;
}
/**
* Calculates the icon position for a Pokemon of a given UI index
* @param index UI index to calculate the icon position of
* @returns An interface with an x and y property
*/
function calcIconPosition(index: number): {x: number, y: number} {
const x = (index % 9) * 18;
const y = Math.floor(index / 9) * 18;
return {x: x, y: y};
}
/**
* Calculates the {@linkcode Phaser.GameObjects.Sprite} position for a Pokemon of a given UI index
* @param index UI index to calculate the icon position of
* @returns An interface with an x and y property
*/
function calcSpritePosition(index: number): {x: number, y: number} {
const position = calcIconPosition(index);
return {x: position.x - 2, y: position.y + 2};
}
const gens = [
i18next.t("starterSelectUiHandler:gen1"),
i18next.t("starterSelectUiHandler:gen2"),
@ -202,6 +226,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
private shinyIcons: Phaser.GameObjects.Image[][];
private hiddenAbilityIcons: Phaser.GameObjects.Image[];
private classicWinIcons: Phaser.GameObjects.Image[];
private candyUpgradeIcon: Phaser.GameObjects.Image[];
private candyUpgradeOverlayIcon: Phaser.GameObjects.Image[];
private iconAnimHandler: PokemonIconAnimHandler;
@ -392,9 +418,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.genSpecies[g].push(species);
const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species, false, true);
const defaultProps = this.scene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr);
const x = (s % 9) * 18;
const y = Math.floor(s / 9) * 18;
const icon = this.scene.add.sprite(x - 2, y + 2, species.getIconAtlasKey(defaultProps.formIndex, defaultProps.shiny, defaultProps.variant));
const position = calcIconPosition(s);
const icon = this.scene.add.sprite(position.x - 2, position.y + 2, species.getIconAtlasKey(defaultProps.formIndex, defaultProps.shiny, defaultProps.variant));
icon.setScale(0.5);
icon.setOrigin(0, 0);
icon.setFrame(species.getIconId(defaultProps.female, defaultProps.formIndex, defaultProps.shiny, defaultProps.variant));
@ -417,9 +442,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
});
this.starterValueLabels = new Array(81).fill(null).map((_, i) => {
const x = (i % 9) * 18;
const y = Math.floor(i / 9) * 18;
const ret = addTextObject(this.scene, x + 152, y + 11, "0", TextStyle.WINDOW, { fontSize: "32px" });
const position = calcIconPosition(i);
const ret = addTextObject(this.scene, position.x + 152, position.y + 11, "0", TextStyle.WINDOW, { fontSize: "32px" });
ret.setShadowOffset(2, 2);
ret.setOrigin(0, 0);
ret.setVisible(false);
@ -428,9 +452,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
});
const getShinyStar = (i: integer, v: integer): Phaser.GameObjects.Image => {
const x = (i % 9) * 18 - v * 3;
const y = Math.floor(i / 9) * 18;
const ret = this.scene.add.image(x + 163, y + 11, "shiny_star_small");
const position = calcIconPosition(i);
const ret = this.scene.add.image(position.x + 163, position.y + 11, "shiny_star_small");
ret.setOrigin(0, 0);
ret.setScale(0.5);
ret.setVisible(false);
@ -443,9 +466,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
});
this.hiddenAbilityIcons = new Array(81).fill(null).map((_, i) => {
const x = (i % 9) * 18;
const y = Math.floor(i / 9) * 18;
const ret = this.scene.add.image(x + 163, y + 16, "ha_capsule");
const position = calcIconPosition(i);
const ret = this.scene.add.image(position.x + 163, position.y + 16, "ha_capsule");
ret.setOrigin(0, 0);
ret.setScale(0.5);
ret.setVisible(false);
@ -454,9 +476,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
});
this.classicWinIcons = new Array(81).fill(null).map((_, i) => {
const x = (i % 9) * 18;
const y = Math.floor(i / 9) * 18;
const ret = this.scene.add.image(x + 153, y + 21, "champion_ribbon");
const position = calcIconPosition(i);
const ret = this.scene.add.image(position.x + 153, position.y + 21, "champion_ribbon");
ret.setOrigin(0, 0);
ret.setScale(0.5);
ret.setVisible(false);
@ -464,6 +485,26 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
return ret;
});
this.candyUpgradeIcon = new Array(81).fill(null).map((_, i) => {
const position = calcIconPosition(i);
const ret = this.scene.add.image(position.x + 163, position.y + 21, "candy");
ret.setOrigin(0, 0);
ret.setScale(0.25);
ret.setVisible(false);
this.starterSelectContainer.add(ret);
return ret;
});
this.candyUpgradeOverlayIcon = new Array(81).fill(null).map((_, i) => {
const position = calcIconPosition(i);
const ret = this.scene.add.image(position.x + 163, position.y + 21, "candy_overlay");
ret.setOrigin(0, 0);
ret.setScale(0.25);
ret.setVisible(false);
this.starterSelectContainer.add(ret);
return ret;
});
this.pokemonSprite = this.scene.add.sprite(53, 63, "pkmn__sub");
this.pokemonSprite.setPipeline(this.scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], ignoreTimeTint: true });
this.starterSelectContainer.add(this.pokemonSprite);
@ -653,6 +694,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.starterSelectContainer.add(this.statsContainer);
this.scene.eventTarget.addEventListener(BattleSceneEventType.CANDY_UPGRADE_NOTIFICATION_CHANGED, (e) => this.onCandyUpgradeDisplayChanged(e));
this.updateInstructions();
}
@ -660,20 +703,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
if (args.length >= 2 && args[0] instanceof Function && typeof args[1] === "number") {
super.show(args);
for (let g = 0; g < this.genSpecies.length; g++) {
this.genSpecies[g].forEach((species, s) => {
const dexEntry = this.scene.gameData.dexData[species.speciesId];
const icon = this.starterSelectGenIconContainers[g].getAt(s) as Phaser.GameObjects.Sprite;
if (dexEntry.caughtAttr) {
icon.clearTint();
} else if (dexEntry.seenAttr) {
icon.setTint(0x808080);
}
});
}
this.starterSelectCallback = args[0] as StarterSelectCallback;
this.starterSelectContainer.setVisible(true);
this.gameMode = args[1];
@ -684,6 +713,21 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.setCursor(0);
this.tryUpdateValue(0);
for (let g = 0; g < this.genSpecies.length; g++) {
this.genSpecies[g].forEach((species, s) => {
const icon = this.starterSelectGenIconContainers[g].getAt(s) as Phaser.GameObjects.Sprite;
const dexEntry = this.scene.gameData.dexData[species.speciesId];
if (dexEntry.caughtAttr) {
icon.clearTint();
} else if (dexEntry.seenAttr) {
icon.setTint(0x808080);
}
this.setUpgradeAnimation(icon, species);
});
}
handleTutorial(this.scene, Tutorial.Starter_Select);
return true;
@ -706,6 +750,161 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.starterSelectMessageBoxContainer.setVisible(!!text?.length);
}
/**
* Determines if 'Icon' based upgrade notifications should be shown
* @returns true if upgrade notifications are enabled and set to display an 'Icon'
*/
isUpgradeIconEnabled(): boolean {
return this.scene.candyUpgradeNotification !== 0 && this.scene.candyUpgradeDisplay === 0;
}
/**
* Determines if 'Animation' based upgrade notifications should be shown
* @returns true if upgrade notifications are enabled and set to display an 'Animation'
*/
isUpgradeAnimationEnabled(): boolean {
return this.scene.candyUpgradeNotification !== 0 && this.scene.candyUpgradeDisplay === 1;
}
/**
* Determines if a passive upgrade is available for the given species ID
* @param speciesId The ID of the species to check the passive of
* @returns true if the user has enough candies and a passive has not been unlocked already
*/
isPassiveAvailable(speciesId: number): boolean {
// Get this species ID's starter data
const starterData = this.scene.gameData.starterData[speciesId];
return starterData.candyCount >= getPassiveCandyCount(speciesStarters[speciesId])
&& !(starterData.passiveAttr & PassiveAttr.UNLOCKED);
}
/**
* Determines if a value reduction upgrade is available for the given species ID
* @param speciesId The ID of the species to check the value reduction of
* @returns true if the user has enough candies and all value reductions have not been unlocked already
*/
isValueReductionAvailable(speciesId: number): boolean {
// Get this species ID's starter data
const starterData = this.scene.gameData.starterData[speciesId];
return starterData.candyCount >= getValueReductionCandyCounts(speciesStarters[speciesId])[starterData.valueReduction]
&& starterData.valueReduction < 2;
}
/**
* Sets a bounce animation if enabled and the Pokemon has an upgrade
* @param icon {@linkcode Phaser.GameObjects.GameObject} to animate
* @param species {@linkcode PokemonSpecies} of the icon used to check for upgrades
* @param startPaused Should this animation be paused after it is added?
*/
setUpgradeAnimation(icon: Phaser.GameObjects.Sprite, species: PokemonSpecies, startPaused: boolean = false): void {
this.scene.tweens.killTweensOf(icon);
// Skip animations if they are disabled
if (this.scene.candyUpgradeDisplay === 0 || species.speciesId !== species.getRootSpeciesId(false)) {
return;
}
const position = calcSpritePosition(this.genSpecies[species.generation - 1].indexOf(species));
icon.y = position.y;
const tweenChain: Phaser.Types.Tweens.TweenChainBuilderConfig = {
targets: icon,
loop: -1,
// Make the initial bounce a little randomly delayed
delay: Utils.randIntRange(0, 50) * 5,
loopDelay: 1000,
tweens: [
{
targets: icon,
y: position.y - 5,
duration: Utils.fixedInt(125),
ease: "Cubic.easeOut",
yoyo: true
},
{
targets: icon,
y: position.y - 3,
duration: Utils.fixedInt(150),
ease: "Cubic.easeOut",
yoyo: true
}
],};
const passiveAvailable = this.isPassiveAvailable(species.speciesId);
// 'Only Passives' mode
if (this.scene.candyUpgradeNotification === 1) {
if (passiveAvailable) {
this.scene.tweens.chain(tweenChain).paused = startPaused;
}
// 'On' mode
} else if (this.scene.candyUpgradeNotification === 2) {
if (passiveAvailable || this.isValueReductionAvailable(species.speciesId)) {
this.scene.tweens.chain(tweenChain).paused = startPaused;
}
}
}
/**
* Sets the visibility of a Candy Upgrade Icon given an index
* @param index The UI index of the icon within this generation container
*/
setUpgradeIcon(index: number): void {
const species = this.genSpecies[this.getGenCursorWithScroll()][index];
const slotVisible = !!species?.speciesId;
if (!species // No Pokemon exists at that UI index
|| this.scene.candyUpgradeNotification === 0 // Notification setting is 'Off'
|| species?.getRootSpeciesId(false) !== species?.speciesId) { // Pokemon is not the base evolution and can't use candy
// Set all icons as hidden and exit early
this.candyUpgradeIcon[index].setVisible(false);
this.candyUpgradeOverlayIcon[index].setVisible(false);
return;
}
const passiveAvailable = this.isPassiveAvailable(species.speciesId);
// 'Only Passive Unlocks' mode
if (this.scene.candyUpgradeNotification === 1) {
this.candyUpgradeIcon[index].setVisible(slotVisible && passiveAvailable);
this.candyUpgradeOverlayIcon[index].setVisible(slotVisible && this.candyUpgradeIcon[index].visible);
// 'On' mode
} else if (this.scene.candyUpgradeNotification === 2) {
this.candyUpgradeIcon[index].setVisible(
slotVisible && ( passiveAvailable || this.isValueReductionAvailable(species.speciesId)));
this.candyUpgradeOverlayIcon[index].setVisible(slotVisible && this.candyUpgradeIcon[index].visible);
}
}
/**
* Processes an {@linkcode CandyUpgradeNotificationChangedEvent} sent when the corresponding setting changes
* @param event {@linkcode Event} sent by the callback
*/
onCandyUpgradeDisplayChanged(event: Event): void {
const candyUpgradeDisplayEvent = event as CandyUpgradeNotificationChangedEvent;
if (!candyUpgradeDisplayEvent) {
return;
}
// Loop through all visible candy icons when set to 'Icon' mode
if (this.scene.candyUpgradeDisplay === 0) {
this.genSpecies[this.getGenCursorWithScroll()].forEach((_species, s) => {
this.setUpgradeIcon(s);
});
return;
}
// Loop through all animations when set to 'Animation' mode
for (let g = 0; g < this.genSpecies.length; g++) {
this.genSpecies[g].forEach((species, s) => {
const icon = this.starterSelectGenIconContainers[g].getAt(s) as Phaser.GameObjects.Sprite;
this.setUpgradeAnimation(icon, species);
});
}
}
processInput(button: Button): boolean {
if (this.blockInput) {
return false;
@ -948,6 +1147,16 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
});
ui.setMode(Mode.STARTER_SELECT);
this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, undefined, undefined, undefined);
// Update the candy upgrade display
if (this.isUpgradeIconEnabled() ) {
this.setUpgradeIcon(this.cursor);
}
if (this.isUpgradeAnimationEnabled()) {
const genSpecies = this.genSpecies[this.lastSpecies.generation - 1];
this.setUpgradeAnimation(this.starterSelectGenIconContainers[this.lastSpecies.generation - 1].getAt(genSpecies.indexOf(this.lastSpecies)), this.lastSpecies, true);
}
return true;
}
return false;
@ -975,6 +1184,18 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.tryUpdateValue(0);
ui.setMode(Mode.STARTER_SELECT);
this.scene.playSound("buy");
// If the notification setting is set to 'On', update the candy upgrade display
if (this.scene.candyUpgradeNotification === 2) {
if (this.isUpgradeIconEnabled() ) {
this.setUpgradeIcon(this.cursor);
}
if (this.isUpgradeAnimationEnabled()) {
const genSpecies = this.genSpecies[this.lastSpecies.generation - 1];
this.setUpgradeAnimation(this.starterSelectGenIconContainers[this.lastSpecies.generation - 1].getAt(genSpecies.indexOf(this.lastSpecies)), this.lastSpecies, true);
}
}
return true;
}
return false;
@ -1293,6 +1514,25 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}
this.hiddenAbilityIcons[s].setVisible(slotVisible && !!this.scene.gameData.dexData[speciesId].caughtAttr && !!(this.scene.gameData.starterData[speciesId].abilityAttr & 4));
this.classicWinIcons[s].setVisible(slotVisible && this.scene.gameData.starterData[speciesId].classicWinCount > 0);
const species = this.genSpecies[genCursorWithScroll][s];
// 'Candy Icon' mode
if (this.scene.candyUpgradeDisplay === 0 && species?.getRootSpeciesId(false) === species?.speciesId) {
if (!starterColors[speciesId]) {
// Default to white if no colors are found
starterColors[speciesId] = [ "ffffff", "ffffff" ];
}
// Set the candy colors
this.candyUpgradeIcon[s].setTint(argbFromRgba(Utils.rgbHexToRgba(starterColors[speciesId][0])));
this.candyUpgradeOverlayIcon[s].setTint(argbFromRgba(Utils.rgbHexToRgba(starterColors[speciesId][1])));
this.setUpgradeIcon(s);
} else if (this.scene.candyUpgradeDisplay === 1) {
this.candyUpgradeIcon[s].setVisible(false);
this.candyUpgradeOverlayIcon[s].setVisible(false);
}
}
} else {
changed = super.setCursor(cursor);
@ -1370,6 +1610,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
lastSpeciesIcon.setTexture(this.lastSpecies.getIconAtlasKey(props.formIndex, props.shiny, props.variant), this.lastSpecies.getIconId(props.female, props.formIndex, props.shiny, props.variant));
this.checkIconId(lastSpeciesIcon, this.lastSpecies, props.female, props.formIndex, props.shiny, props.variant);
this.iconAnimHandler.addOrUpdate(lastSpeciesIcon, PokemonIconAnimMode.NONE);
// Resume the animation for the previously selected species
const speciesIndex = this.genSpecies[this.lastSpecies.generation - 1].indexOf(this.lastSpecies);
const icon = this.starterSelectGenIconContainers[this.lastSpecies.generation - 1].getAt(speciesIndex) as Phaser.GameObjects.Sprite;
this.scene.tweens.getTweensOf(icon).forEach(tween => tween.resume());
}
this.lastSpecies = species;
@ -1434,7 +1679,22 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonCandyDarknessOverlay.setCrop(0,0,16, candyCropY);
}
this.iconAnimHandler.addOrUpdate(this.starterSelectGenIconContainers[species.generation - 1].getAt(this.genSpecies[species.generation - 1].indexOf(species)) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.PASSIVE);
// Pause the animation when the species is selected
const speciesIndex = this.genSpecies[species.generation - 1].indexOf(species);
const icon = this.starterSelectGenIconContainers[species.generation - 1].getAt(speciesIndex) as Phaser.GameObjects.Sprite;
if (this.isUpgradeAnimationEnabled()) {
this.scene.tweens.getTweensOf(icon).forEach(tween => tween.pause());
// Reset the position of the icon
const position = calcSpritePosition(speciesIndex);
icon.x = position.x;
icon.y = position.y;
}
// Initiates the small up and down idle animation
this.iconAnimHandler.addOrUpdate(icon, PokemonIconAnimMode.PASSIVE);
let starterIndex = -1;