Added random starters option incl abilities, natures, and movesets
Added option for random starter teams incl natures, abilities and movesetspull/833/head
parent
7e5c7fb4f7
commit
fcbacb6281
|
@ -30,5 +30,7 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
|
||||||
"enablePassive": "Enable Passive",
|
"enablePassive": "Enable Passive",
|
||||||
"disablePassive": "Disable Passive",
|
"disablePassive": "Disable Passive",
|
||||||
"locked": "Locked",
|
"locked": "Locked",
|
||||||
"disabled": "Disabled"
|
"disabled": "Disabled",
|
||||||
|
"random": "Random",
|
||||||
|
"confirmRandomize":"Begin with a random team?"
|
||||||
}
|
}
|
|
@ -22,7 +22,7 @@ import { allMoves } from "../data/move";
|
||||||
import { Type } from "../data/type";
|
import { Type } from "../data/type";
|
||||||
import { Moves } from "../data/enums/moves";
|
import { Moves } from "../data/enums/moves";
|
||||||
import { speciesEggMoves } from "../data/egg-moves";
|
import { speciesEggMoves } from "../data/egg-moves";
|
||||||
import { TitlePhase } from "../phases";
|
import { EggLapsePhase, TitlePhase } from "../phases";
|
||||||
import { argbFromRgba } from "@material/material-color-utilities";
|
import { argbFromRgba } from "@material/material-color-utilities";
|
||||||
import { OptionSelectItem } from "./abstact-option-select-ui-handler";
|
import { OptionSelectItem } from "./abstact-option-select-ui-handler";
|
||||||
import { pokemonPrevolutions } from "#app/data/pokemon-evolutions";
|
import { pokemonPrevolutions } from "#app/data/pokemon-evolutions";
|
||||||
|
@ -131,6 +131,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||||
private starterSelectMessageBoxContainer: Phaser.GameObjects.Container;
|
private starterSelectMessageBoxContainer: Phaser.GameObjects.Container;
|
||||||
private statsContainer: StatsContainer;
|
private statsContainer: StatsContainer;
|
||||||
private pokemonFormText: Phaser.GameObjects.Text;
|
private pokemonFormText: Phaser.GameObjects.Text;
|
||||||
|
private startLabel: Phaser.GameObjects.Text;
|
||||||
|
|
||||||
private genMode: boolean;
|
private genMode: boolean;
|
||||||
private statsMode: boolean;
|
private statsMode: boolean;
|
||||||
|
@ -328,9 +329,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||||
this.valueLimitLabel.setOrigin(0.5, 0);
|
this.valueLimitLabel.setOrigin(0.5, 0);
|
||||||
this.starterSelectContainer.add(this.valueLimitLabel);
|
this.starterSelectContainer.add(this.valueLimitLabel);
|
||||||
|
|
||||||
const startLabel = addTextObject(this.scene, 124, 162, i18next.t("starterSelectUiHandler:start"), TextStyle.TOOLTIP_CONTENT);
|
const labelText = this.starterCursors.length > 0 ? i18next.t("starterSelectUiHandler:start") : i18next.t("starterSelectUiHandler:random");
|
||||||
startLabel.setOrigin(0.5, 0);
|
this.startLabel = addTextObject(this.scene, 124, 162, labelText, TextStyle.TOOLTIP_CONTENT);
|
||||||
this.starterSelectContainer.add(startLabel);
|
this.startLabel.setOrigin(0.5, 0);
|
||||||
|
this.starterSelectContainer.add(this.startLabel);
|
||||||
|
|
||||||
|
|
||||||
this.startCursorObj = this.scene.add.nineslice(111, 160, 'select_cursor', null, 26, 15, 6, 6, 6, 6);
|
this.startCursorObj = this.scene.add.nineslice(111, 160, 'select_cursor', null, 26, 15, 6, 6, 6, 6);
|
||||||
this.startCursorObj.setVisible(false);
|
this.startCursorObj.setVisible(false);
|
||||||
|
@ -640,6 +643,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||||
this.starterSelectContainer.add(this.statsContainer);
|
this.starterSelectContainer.add(this.statsContainer);
|
||||||
|
|
||||||
this.updateInstructions();
|
this.updateInstructions();
|
||||||
|
|
||||||
|
this.updateStartLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
show(args: any[]): boolean {
|
show(args: any[]): boolean {
|
||||||
|
@ -713,6 +718,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||||
this.popStarter();
|
this.popStarter();
|
||||||
success = true;
|
success = true;
|
||||||
this.updateInstructions();
|
this.updateInstructions();
|
||||||
|
this.updateStartLabel();
|
||||||
} else {
|
} else {
|
||||||
this.blockInput = true;
|
this.blockInput = true;
|
||||||
this.scene.clearPhaseQueue();
|
this.scene.clearPhaseQueue();
|
||||||
|
@ -805,10 +811,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||||
if (this.starterCursors.length === 6 || this.value === this.getValueLimit())
|
if (this.starterCursors.length === 6 || this.value === this.getValueLimit())
|
||||||
this.tryStart();
|
this.tryStart();
|
||||||
this.updateInstructions();
|
this.updateInstructions();
|
||||||
|
this.updateStartLabel();
|
||||||
ui.playSelect();
|
ui.playSelect();
|
||||||
} else
|
} else
|
||||||
ui.playError();
|
ui.playError();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
},
|
},
|
||||||
overrideSound: true
|
overrideSound: true
|
||||||
},
|
},
|
||||||
|
@ -1034,6 +1042,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||||
let newAbilityIndex = this.abilityCursor;
|
let newAbilityIndex = this.abilityCursor;
|
||||||
do {
|
do {
|
||||||
newAbilityIndex = (newAbilityIndex + 1) % abilityCount;
|
newAbilityIndex = (newAbilityIndex + 1) % abilityCount;
|
||||||
|
console.debug("Ability Index changed to " + newAbilityIndex);
|
||||||
if (!newAbilityIndex) {
|
if (!newAbilityIndex) {
|
||||||
if (abilityAttr & AbilityAttr.ABILITY_1)
|
if (abilityAttr & AbilityAttr.ABILITY_1)
|
||||||
break;
|
break;
|
||||||
|
@ -1246,6 +1255,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||||
this.setSpecies(this.genSpecies[this.getGenCursorWithScroll()][cursor]);
|
this.setSpecies(this.genSpecies[this.getGenCursorWithScroll()][cursor]);
|
||||||
|
|
||||||
this.updateInstructions();
|
this.updateInstructions();
|
||||||
|
this.updateStartLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
|
@ -1666,6 +1676,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||||
this.pokemonAdditionalMoveCountLabel.setVisible(this.speciesStarterMoves.length > 4);
|
this.pokemonAdditionalMoveCountLabel.setVisible(this.speciesStarterMoves.length > 4);
|
||||||
|
|
||||||
this.updateInstructions();
|
this.updateInstructions();
|
||||||
|
this.updateStartLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
setTypeIcons(type1: Type, type2: Type): void {
|
setTypeIcons(type1: Type, type2: Type): void {
|
||||||
|
@ -1743,10 +1754,47 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
tryStart(manualTrigger: boolean = false): boolean {
|
tryStart(manualTrigger: boolean = false): boolean {
|
||||||
if (!this.starterGens.length)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const ui = this.getUi();
|
const ui = this.getUi();
|
||||||
|
if (!this.starterGens.length){
|
||||||
|
const cancel = () => {
|
||||||
|
ui.setMode(Mode.STARTER_SELECT);
|
||||||
|
while(this.starterGens.length > 0){
|
||||||
|
this.popStarter();
|
||||||
|
}
|
||||||
|
this.updateStartLabel();
|
||||||
|
this.clearText();
|
||||||
|
};
|
||||||
|
ui.showText(i18next.t("starterSelectUiHandler:confirmRandomize"), null, () => {
|
||||||
|
this.randomizeStarters();
|
||||||
|
ui.setModeWithoutClear(Mode.CONFIRM, () => {
|
||||||
|
const startRun = (gameMode: GameModes) => {
|
||||||
|
this.scene.gameMode = gameModes[gameMode];
|
||||||
|
this.scene.money = this.scene.gameMode.getStartingMoney();
|
||||||
|
ui.setMode(Mode.STARTER_SELECT);
|
||||||
|
const thisObj = this;
|
||||||
|
const originalStarterSelectCallback = this.starterSelectCallback;
|
||||||
|
this.starterSelectCallback = null;
|
||||||
|
originalStarterSelectCallback(new Array(this.starterGens.length).fill(0).map(function (_, i) {
|
||||||
|
const starterSpecies = thisObj.genSpecies[thisObj.starterGens[i]][thisObj.starterCursors[i]];
|
||||||
|
return {
|
||||||
|
species: starterSpecies,
|
||||||
|
dexAttr: thisObj.starterAttr[i],
|
||||||
|
abilityIndex: thisObj.starterAbilityIndexes[i],
|
||||||
|
passive: !(thisObj.scene.gameData.starterData[starterSpecies.speciesId].passiveAttr ^ (PassiveAttr.ENABLED | PassiveAttr.UNLOCKED)),
|
||||||
|
nature: thisObj.starterNatures[i] as Nature,
|
||||||
|
moveset: thisObj.starterMovesets[i],
|
||||||
|
pokerus: !![ 0, 1, 2 ].filter(n => thisObj.pokerusGens[n] === starterSpecies.generation - 1 && thisObj.pokerusCursors[n] === thisObj.genSpecies[starterSpecies.generation - 1].indexOf(starterSpecies)).length
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
startRun(this.gameMode);
|
||||||
|
}, cancel, null, null, 19);
|
||||||
|
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
ui.setMode(Mode.STARTER_SELECT);
|
ui.setMode(Mode.STARTER_SELECT);
|
||||||
|
@ -1782,8 +1830,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}}
|
||||||
|
|
||||||
toggleStatsMode(on?: boolean): void {
|
toggleStatsMode(on?: boolean): void {
|
||||||
if (on === undefined)
|
if (on === undefined)
|
||||||
on = !this.statsMode;
|
on = !this.statsMode;
|
||||||
|
@ -1826,6 +1873,109 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||||
this.toggleStatsMode(false);
|
this.toggleStatsMode(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
randomizeStarters(): void {
|
||||||
|
let selectedSpeciesIds = new Set<number>(); //Set to track dupes
|
||||||
|
|
||||||
|
do{
|
||||||
|
//Calculate remaining value limit to ensure there are Starters available to select
|
||||||
|
let remainingValue = this.getValueLimit() - this.value;
|
||||||
|
// Prepare a list of all viable (i.e. based on remaning cost value) species options from all generations.
|
||||||
|
let viableOptions = [];
|
||||||
|
this.genSpecies.forEach((gen, genIndex) => {
|
||||||
|
gen.forEach(species => {
|
||||||
|
let speciesDexAttr = this.scene.gameData.dexData[species.speciesId].caughtAttr;
|
||||||
|
if (speciesDexAttr && // Ensure starter is "caught"
|
||||||
|
this.scene.gameData.getSpeciesStarterValue(species.speciesId) <= remainingValue &&
|
||||||
|
!selectedSpeciesIds.has(species.speciesId)) {
|
||||||
|
viableOptions.push({ species, genIndex });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (viableOptions.length === 0) break;
|
||||||
|
let selectedOption = viableOptions[Math.floor(Math.random() * viableOptions.length)]; //Select a random speccies
|
||||||
|
let selectedSpecies = selectedOption.species;
|
||||||
|
let selectedGenIndex = selectedOption.genIndex;
|
||||||
|
let speciesDexAttr = this.scene.gameData.dexData[selectedSpecies.speciesId].caughtAttr; //Retrieve the caught bit mask for this species from dexData
|
||||||
|
//Init variables we will need for randomization of natures, abilities, and moves
|
||||||
|
let randAbilityIndex = -1;
|
||||||
|
let randNatureIndex = -1;
|
||||||
|
let randomMoveset: integer[] = [];
|
||||||
|
//Update the team value by starter cost and start prepping to add starter to team
|
||||||
|
if (this.tryUpdateValue(this.scene.gameData.getSpeciesStarterValue(selectedSpecies.speciesId))) {
|
||||||
|
selectedSpeciesIds.add(selectedSpecies.speciesId);
|
||||||
|
const props = this.scene.gameData.getSpeciesDexAttrProps(selectedSpecies, speciesDexAttr);
|
||||||
|
this.starterIcons[this.starterCursors.length].setTexture(selectedSpecies.getIconAtlasKey(props.formIndex, props.shiny, props.variant));
|
||||||
|
this.starterIcons[this.starterCursors.length].setFrame(selectedSpecies.getIconId(props.female, props.formIndex, props.shiny, props.variant));
|
||||||
|
this.starterGens.push(selectedGenIndex);
|
||||||
|
this.starterCursors.push(this.genSpecies[selectedGenIndex].indexOf(selectedSpecies));
|
||||||
|
this.starterAttr.push(speciesDexAttr);
|
||||||
|
//Handle random abilities
|
||||||
|
let availableAbilities: integer[] = [];
|
||||||
|
if (this.scene.gameData.starterData[selectedSpecies.speciesId].abilityAttr & AbilityAttr.ABILITY_1) {
|
||||||
|
availableAbilities.push(0); }
|
||||||
|
if (this.scene.gameData.starterData[selectedSpecies.speciesId].abilityAttr & AbilityAttr.ABILITY_2) {
|
||||||
|
availableAbilities.push(1);
|
||||||
|
}
|
||||||
|
if (this.scene.gameData.starterData[selectedSpecies.speciesId].abilityAttr & AbilityAttr.ABILITY_HIDDEN) {
|
||||||
|
availableAbilities.push(2);
|
||||||
|
}
|
||||||
|
if (availableAbilities.length) {
|
||||||
|
randAbilityIndex = Math.floor(Math.random() * availableAbilities.length);
|
||||||
|
} else {
|
||||||
|
randAbilityIndex = this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(selectedSpecies)
|
||||||
|
}
|
||||||
|
this.starterAbilityIndexes.push(randAbilityIndex);
|
||||||
|
//Handle random natures
|
||||||
|
let natures = this.scene.gameData.getNaturesForAttr(this.scene.gameData.dexData[selectedSpecies.speciesId].natureAttr);
|
||||||
|
if (natures && natures.length > 0) {
|
||||||
|
randNatureIndex = Math.floor(Math.random() * natures.length);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
randNatureIndex = this.scene.gameData.getSpeciesDefaultNature(selectedSpecies);
|
||||||
|
}
|
||||||
|
this.starterNatures.push(randNatureIndex as unknown as Nature);
|
||||||
|
//Get random moves
|
||||||
|
let levelMoves: LevelMoves;
|
||||||
|
let availableStarterMoves: integer[] = [];
|
||||||
|
if (pokemonFormLevelMoves.hasOwnProperty(selectedSpecies.speciesId) && pokemonFormLevelMoves[selectedSpecies.speciesId].hasOwnProperty(props.formIndex))
|
||||||
|
levelMoves = pokemonFormLevelMoves[selectedSpecies.speciesId][props.formIndex];
|
||||||
|
else
|
||||||
|
levelMoves = pokemonSpeciesLevelMoves[selectedSpecies.speciesId];
|
||||||
|
availableStarterMoves.push(...levelMoves.filter(lm => lm[0] <= 5).map(lm => lm[1]));
|
||||||
|
if (speciesEggMoves.hasOwnProperty(selectedSpecies.speciesId)) {
|
||||||
|
for (let em = 0; em < 4; em++) {
|
||||||
|
if (this.scene.gameData.starterData[selectedSpecies.speciesId].eggMoves & Math.pow(2, em))
|
||||||
|
availableStarterMoves.push(speciesEggMoves[selectedSpecies.speciesId][em]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Determine the number of moves to select
|
||||||
|
let numMovesToSelect = Math.min(4, availableStarterMoves.length);
|
||||||
|
|
||||||
|
// Shuffle the availableStarterMoves array and pick the first numMovesToSelect moves
|
||||||
|
for (let i = availableStarterMoves.length - 1; i > 0; i--) {
|
||||||
|
let j = Math.floor(Math.random() * (i + 1));
|
||||||
|
[availableStarterMoves[i], availableStarterMoves[j]] = [availableStarterMoves[j], availableStarterMoves[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slice the first numMovesToSelect moves from the shuffled array
|
||||||
|
randomMoveset = availableStarterMoves.slice(0, numMovesToSelect);
|
||||||
|
this.starterMovesets.push(randomMoveset.slice(0) as StarterMoveset);
|
||||||
|
}
|
||||||
|
if (this.starterCursors.length === 6) break;
|
||||||
|
}
|
||||||
|
while (this.value < this.getValueLimit())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStartLabel(): void {
|
||||||
|
if(this.starterCursors.length > 0){
|
||||||
|
this.startLabel.setText(i18next.t("starterSelectUiHandler:start"));
|
||||||
|
}
|
||||||
|
else if(this.starterCursors.length === 0){
|
||||||
|
this.startLabel.setText(i18next.t("starterSelectUiHandler:random"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
checkIconId(icon: Phaser.GameObjects.Sprite, species: PokemonSpecies, female, formIndex, shiny, variant) {
|
checkIconId(icon: Phaser.GameObjects.Sprite, species: PokemonSpecies, female, formIndex, shiny, variant) {
|
||||||
if (icon.frame.name != species.getIconId(female, formIndex, shiny, variant)) {
|
if (icon.frame.name != species.getIconId(female, formIndex, shiny, variant)) {
|
||||||
console.log(`${species.name}'s variant icon does not exist. Replacing with default.`);
|
console.log(`${species.name}'s variant icon does not exist. Replacing with default.`);
|
||||||
|
|
Loading…
Reference in New Issue