[Feature][UI] Save Preview (#4410)
* Making 3 Option UI real
* idk anymore
* Revert "Making 3 Option UI real"
This reverts commit beaad44c1e
.
* Let's see
* Current issues - scrolling upwards and correct cursor landing
* argh
* Fixed reactive scrolling
* Adding ME handling
* set up descriptions
* Cleaned up UI i think
* stupid alder
* Added double trainer handling + changed enum name
* Apply suggestions from code review
Thank you Moka!
Co-authored-by: MokaStitcher <54149968+MokaStitcher@users.noreply.github.com>
* Arrow Visibility now depends on Session Slot hasData
* documentation
* Simplified calls to revertSessionSlot + changed function name per feedback
* Fixed scrollCursor issue.
* added comment
* Update src/ui/save-slot-select-ui-handler.ts
Co-authored-by: MokaStitcher <54149968+MokaStitcher@users.noreply.github.com>
* Fixed sound played + added better conditional
* Balance Team....
* ME related changes
* Apply suggestions from code review
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
Co-authored-by: MokaStitcher <54149968+MokaStitcher@users.noreply.github.com>
* Update src/data/mystery-encounters/mystery-encounter.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update src/data/mystery-encounters/mystery-encounter.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Sending Doubles-fix
* eslint..
---------
Co-authored-by: frutescens <info@laptop>
Co-authored-by: MokaStitcher <54149968+MokaStitcher@users.noreply.github.com>
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
This commit is contained in:
parent
d2c579cf2a
commit
ffe941d235
|
@ -3161,13 +3161,17 @@ export default class BattleScene extends SceneBase {
|
|||
/**
|
||||
* Loads or generates a mystery encounter
|
||||
* @param encounterType used to load session encounter when restarting game, etc.
|
||||
* @param canBypass optional boolean to indicate that the request is coming from a function that needs to access a Mystery Encounter outside of gameplay requirements
|
||||
* @returns
|
||||
*/
|
||||
getMysteryEncounter(encounterType?: MysteryEncounterType): MysteryEncounter {
|
||||
getMysteryEncounter(encounterType?: MysteryEncounterType, canBypass?: boolean): MysteryEncounter {
|
||||
// Loading override or session encounter
|
||||
let encounter: MysteryEncounter | null;
|
||||
if (!isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_OVERRIDE) && allMysteryEncounters.hasOwnProperty(Overrides.MYSTERY_ENCOUNTER_OVERRIDE)) {
|
||||
encounter = allMysteryEncounters[Overrides.MYSTERY_ENCOUNTER_OVERRIDE];
|
||||
} else if (canBypass) {
|
||||
encounter = allMysteryEncounters[encounterType ?? -1];
|
||||
return encounter;
|
||||
} else {
|
||||
encounter = !isNullOrUndefined(encounterType) ? allMysteryEncounters[encounterType] : null;
|
||||
}
|
||||
|
|
|
@ -128,6 +128,7 @@ export const ATrainersTestEncounter: MysteryEncounter =
|
|||
|
||||
return true;
|
||||
})
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -166,6 +166,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
|||
text: `${namespace}:intro`,
|
||||
}
|
||||
])
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -64,6 +64,7 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter =
|
|||
speaker: `${namespace}:speaker`,
|
||||
},
|
||||
])
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -110,6 +110,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
|||
|
||||
return true;
|
||||
})
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -276,6 +276,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
|
|||
|
||||
return true;
|
||||
})
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -148,6 +148,7 @@ export const ClowningAroundEncounter: MysteryEncounter =
|
|||
|
||||
return true;
|
||||
})
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -102,6 +102,7 @@ export const DancingLessonsEncounter: MysteryEncounter =
|
|||
text: `${namespace}:intro`,
|
||||
}
|
||||
])
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -117,6 +117,7 @@ export const DarkDealEncounter: MysteryEncounter =
|
|||
.withSceneWaveRangeRequirement(30, CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES[1])
|
||||
.withScenePartySizeRequirement(2, 6, true) // Must have at least 2 pokemon in party
|
||||
.withCatchAllowed(true)
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -84,6 +84,7 @@ export const DelibirdyEncounter: MysteryEncounter =
|
|||
text: `${namespace}:intro`,
|
||||
}
|
||||
])
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -51,6 +51,7 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter =
|
|||
},
|
||||
])
|
||||
.withAutoHideIntroVisuals(false)
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -52,6 +52,7 @@ export const FieldTripEncounter: MysteryEncounter =
|
|||
},
|
||||
])
|
||||
.withAutoHideIntroVisuals(false)
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -122,6 +122,7 @@ export const FieryFalloutEncounter: MysteryEncounter =
|
|||
|
||||
return true;
|
||||
})
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -120,6 +120,7 @@ export const FightOrFlightEncounter: MysteryEncounter =
|
|||
|
||||
return true;
|
||||
})
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -76,6 +76,7 @@ export const FunAndGamesEncounter: MysteryEncounter =
|
|||
text: `${namespace}:intro_dialogue`,
|
||||
},
|
||||
])
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -96,6 +96,7 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
|
|||
text: `${namespace}:intro`,
|
||||
}
|
||||
])
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -50,6 +50,7 @@ export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.with
|
|||
|
||||
return true;
|
||||
})
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -125,6 +125,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
|
|||
|
||||
return true;
|
||||
})
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -61,6 +61,7 @@ export const MysteriousChestEncounter: MysteryEncounter =
|
|||
text: `${namespace}:intro`,
|
||||
}
|
||||
])
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -69,6 +69,7 @@ export const PartTimerEncounter: MysteryEncounter =
|
|||
|
||||
return true;
|
||||
})
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -54,6 +54,7 @@ export const SafariZoneEncounter: MysteryEncounter =
|
|||
text: `${namespace}:intro`,
|
||||
},
|
||||
])
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -62,6 +62,7 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter =
|
|||
speaker: `${namespace}:speaker`,
|
||||
},
|
||||
])
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -88,6 +88,7 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter =
|
|||
|
||||
return true;
|
||||
})
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -58,6 +58,7 @@ export const TeleportingHijinksEncounter: MysteryEncounter =
|
|||
text: `${namespace}:intro`,
|
||||
}
|
||||
])
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -196,6 +196,7 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter =
|
|||
|
||||
return true;
|
||||
})
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -53,6 +53,7 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter =
|
|||
speaker: `${namespace}:speaker`,
|
||||
},
|
||||
])
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -117,6 +117,7 @@ export const TheStrongStuffEncounter: MysteryEncounter =
|
|||
|
||||
return true;
|
||||
})
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -94,6 +94,7 @@ export const TheWinstrateChallengeEncounter: MysteryEncounter =
|
|||
|
||||
return true;
|
||||
})
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -52,6 +52,7 @@ export const TrainingSessionEncounter: MysteryEncounter =
|
|||
text: `${namespace}:intro`,
|
||||
}
|
||||
])
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -54,6 +54,7 @@ export const TrashToTreasureEncounter: MysteryEncounter =
|
|||
text: `${namespace}:intro`,
|
||||
},
|
||||
])
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -125,6 +125,7 @@ export const UncommonBreedEncounter: MysteryEncounter =
|
|||
scene.time.delayedCall(500, () => scene.playSound("battle_anims/PRSFX- Spotlight2"));
|
||||
return true;
|
||||
})
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -125,6 +125,7 @@ export const WeirdDreamEncounter: MysteryEncounter =
|
|||
text: `${namespace}:intro_dialogue`,
|
||||
},
|
||||
])
|
||||
.setLocalizationKey(`${namespace}`)
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
|
|
|
@ -190,7 +190,7 @@ export default class MysteryEncounter implements IMysteryEncounter {
|
|||
secondaryPokemon?: PlayerPokemon[];
|
||||
|
||||
// #region Post-construct / Auto-populated params
|
||||
|
||||
localizationKey: string;
|
||||
/**
|
||||
* Dialogue object containing all the dialogue, messages, tooltips, etc. for an encounter
|
||||
*/
|
||||
|
@ -264,6 +264,7 @@ export default class MysteryEncounter implements IMysteryEncounter {
|
|||
Object.assign(this, encounter);
|
||||
}
|
||||
this.encounterTier = this.encounterTier ?? MysteryEncounterTier.COMMON;
|
||||
this.localizationKey = this.localizationKey ?? "";
|
||||
this.dialogue = this.dialogue ?? {};
|
||||
this.spriteConfigs = this.spriteConfigs ? [ ...this.spriteConfigs ] : [];
|
||||
// Default max is 1 for ROGUE encounters, 2 for others
|
||||
|
@ -528,6 +529,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||
options: [MysteryEncounterOption, MysteryEncounterOption, ...MysteryEncounterOption[]];
|
||||
enemyPartyConfigs: EnemyPartyConfig[] = [];
|
||||
|
||||
localizationKey: string = "";
|
||||
dialogue: MysteryEncounterDialogue = {};
|
||||
requirements: EncounterSceneRequirement[] = [];
|
||||
primaryPokemonRequirements: EncounterPokemonRequirement[] = [];
|
||||
|
@ -632,6 +634,16 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||
return this.withIntroSpriteConfigs(spriteConfigs).withIntroDialogue(dialogue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the localization key used by the encounter
|
||||
* @param localizationKey the string used as the key
|
||||
* @returns `this`
|
||||
*/
|
||||
setLocalizationKey(localizationKey: string): this {
|
||||
this.localizationKey = localizationKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* OPTIONAL
|
||||
*/
|
||||
|
|
|
@ -12,6 +12,7 @@ import { BattleType } from "../battle";
|
|||
import { RunEntry } from "../system/game-data";
|
||||
import { PlayerGender } from "#enums/player-gender";
|
||||
import { TrainerVariant } from "../field/trainer";
|
||||
import { RunDisplayMode } from "#app/ui/run-info-ui-handler";
|
||||
|
||||
export type RunSelectCallback = (cursor: number) => void;
|
||||
|
||||
|
@ -104,7 +105,7 @@ export default class RunHistoryUiHandler extends MessageUiHandler {
|
|||
if (button === Button.ACTION) {
|
||||
const cursor = this.cursor + this.scrollCursor;
|
||||
if (this.runs[cursor]) {
|
||||
this.scene.ui.setOverlayMode(Mode.RUN_INFO, this.runs[cursor].entryData, true);
|
||||
this.scene.ui.setOverlayMode(Mode.RUN_INFO, this.runs[cursor].entryData, RunDisplayMode.RUN_HISTORY, true);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import { SessionSaveData } from "../system/game-data";
|
|||
import { TextStyle, addTextObject, addBBCodeTextObject, getTextColor } from "./text";
|
||||
import { Mode } from "./ui";
|
||||
import { addWindow } from "./ui-theme";
|
||||
import { getPokeballAtlasKey } from "#app/data/pokeball";
|
||||
import * as Utils from "../utils";
|
||||
import PokemonData from "../system/pokemon-data";
|
||||
import i18next from "i18next";
|
||||
|
@ -22,6 +23,8 @@ import * as Modifier from "../modifier/modifier";
|
|||
import { Species } from "#enums/species";
|
||||
import { PlayerGender } from "#enums/player-gender";
|
||||
import { SettingKeyboard } from "#app/system/settings/settings-keyboard";
|
||||
import { getBiomeName } from "#app/data/balance/biomes";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
|
||||
/**
|
||||
* RunInfoUiMode indicates possible overlays of RunInfoUiHandler.
|
||||
|
@ -34,6 +37,11 @@ enum RunInfoUiMode {
|
|||
ENDING_ART
|
||||
}
|
||||
|
||||
export enum RunDisplayMode {
|
||||
RUN_HISTORY,
|
||||
SESSION_PREVIEW
|
||||
}
|
||||
|
||||
/**
|
||||
* Some variables are protected because this UI class will most likely be extended in the future to display more information.
|
||||
* These variables will most likely be shared across 'classes' aka pages.
|
||||
|
@ -41,6 +49,7 @@ enum RunInfoUiMode {
|
|||
* For now, I leave as is.
|
||||
*/
|
||||
export default class RunInfoUiHandler extends UiHandler {
|
||||
protected runDisplayMode: RunDisplayMode;
|
||||
protected runInfo: SessionSaveData;
|
||||
protected isVictory: boolean;
|
||||
protected pageMode: RunInfoUiMode;
|
||||
|
@ -66,6 +75,7 @@ export default class RunInfoUiHandler extends UiHandler {
|
|||
// The import of the modifiersModule is loaded here to sidestep async/await issues.
|
||||
this.modifiersModule = Modifier;
|
||||
this.runContainer.setVisible(false);
|
||||
this.scene.loadImage("encounter_exclaim", "mystery-encounters");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -87,9 +97,15 @@ export default class RunInfoUiHandler extends UiHandler {
|
|||
this.runContainer.add(gameStatsBg);
|
||||
|
||||
const run = args[0];
|
||||
this.runDisplayMode = args[1];
|
||||
if (this.runDisplayMode === RunDisplayMode.RUN_HISTORY) {
|
||||
this.runInfo = this.scene.gameData.parseSessionData(JSON.stringify(run.entry));
|
||||
this.isVictory = run.isVictory ?? false;
|
||||
} else if (this.runDisplayMode === RunDisplayMode.SESSION_PREVIEW) {
|
||||
this.runInfo = args[0];
|
||||
}
|
||||
// Assigning information necessary for the UI's creation
|
||||
this.runInfo = this.scene.gameData.parseSessionData(JSON.stringify(run.entry));
|
||||
this.isVictory = run.isVictory;
|
||||
|
||||
this.pageMode = RunInfoUiMode.MAIN;
|
||||
|
||||
// Creates Header and adds to this.runContainer
|
||||
|
@ -102,7 +118,11 @@ export default class RunInfoUiHandler extends UiHandler {
|
|||
const runResultWindow = addWindow(this.scene, 0, 0, this.statsBgWidth - 11, 65);
|
||||
runResultWindow.setOrigin(0, 0);
|
||||
this.runResultContainer.add(runResultWindow);
|
||||
this.parseRunResult();
|
||||
if (this.runDisplayMode === RunDisplayMode.RUN_HISTORY) {
|
||||
this.parseRunResult();
|
||||
} else if (this.runDisplayMode === RunDisplayMode.SESSION_PREVIEW) {
|
||||
this.parseRunStatus();
|
||||
}
|
||||
|
||||
// Creates Run Info Container
|
||||
this.runInfoContainer = this.scene.add.container(0, 89);
|
||||
|
@ -226,6 +246,66 @@ export default class RunInfoUiHandler extends UiHandler {
|
|||
this.runContainer.add(this.runResultContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is used when the Run Info UI is used to preview a Session.
|
||||
* It edits {@linkcode runResultContainer}, but most importantly - does not display the negative results of a Mystery Encounter or any details of a trainer's party.
|
||||
* Trainer Parties are replaced with their sprites, names, and their party size.
|
||||
* Mystery Encounters contain sprites associated with MEs + the title of the specific ME.
|
||||
*/
|
||||
private parseRunStatus() {
|
||||
const runStatusText = addTextObject(this.scene, 6, 5, `${i18next.t("saveSlotSelectUiHandler:wave")} ${this.runInfo.waveIndex} - ${getBiomeName(this.runInfo.arena.biome)}`, TextStyle.WINDOW, { fontSize : "65px", lineSpacing: 0.1 });
|
||||
|
||||
const enemyContainer = this.scene.add.container(0, 0);
|
||||
this.runResultContainer.add(enemyContainer);
|
||||
if (this.runInfo.battleType === BattleType.WILD) {
|
||||
if (this.runInfo.enemyParty.length === 1) {
|
||||
this.parseWildSingleDefeat(enemyContainer);
|
||||
} else if (this.runInfo.enemyParty.length === 2) {
|
||||
this.parseWildDoubleDefeat(enemyContainer);
|
||||
}
|
||||
} else if (this.runInfo.battleType === BattleType.TRAINER) {
|
||||
this.showTrainerSprites(enemyContainer);
|
||||
const row_limit = 3;
|
||||
this.runInfo.enemyParty.forEach((p, i) => {
|
||||
const pokeball = this.scene.add.sprite(0, 0, "pb");
|
||||
pokeball.setFrame(getPokeballAtlasKey(p.pokeball));
|
||||
pokeball.setScale(0.5);
|
||||
pokeball.setPosition(52 + ((i % row_limit) * 8), (i <= 2) ? 18 : 25);
|
||||
enemyContainer.add(pokeball);
|
||||
});
|
||||
const trainerObj = this.runInfo.trainer.toTrainer(this.scene);
|
||||
const RIVAL_TRAINER_ID_THRESHOLD = 375;
|
||||
let trainerName = "";
|
||||
if (this.runInfo.trainer.trainerType >= RIVAL_TRAINER_ID_THRESHOLD) {
|
||||
trainerName = (trainerObj.variant === TrainerVariant.FEMALE) ? i18next.t("trainerNames:rival_female") : i18next.t("trainerNames:rival");
|
||||
} else {
|
||||
trainerName = trainerObj.getName(0, true);
|
||||
}
|
||||
const boxString = i18next.t(trainerObj.variant !== TrainerVariant.DOUBLE ? "battle:trainerAppeared" : "battle:trainerAppearedDouble", { trainerName: trainerName }).replace(/\n/g, " ");
|
||||
const descContainer = this.scene.add.container(0, 0);
|
||||
const textBox = addTextObject(this.scene, 0, 0, boxString, TextStyle.WINDOW, { fontSize : "35px", wordWrap: { width: 200 }});
|
||||
descContainer.add(textBox);
|
||||
descContainer.setPosition(52, 29);
|
||||
this.runResultContainer.add(descContainer);
|
||||
} else if (this.runInfo.battleType === BattleType.MYSTERY_ENCOUNTER) {
|
||||
const encounterExclaim = this.scene.add.sprite(0, 0, "encounter_exclaim");
|
||||
encounterExclaim.setPosition(34, 26);
|
||||
encounterExclaim.setScale(0.65);
|
||||
const subSprite = this.scene.add.sprite(56, -106, "pkmn__sub");
|
||||
subSprite.setScale(0.65);
|
||||
subSprite.setPosition(34, 46);
|
||||
const mysteryEncounterTitle = i18next.t(this.scene.getMysteryEncounter(this.runInfo.mysteryEncounterType as MysteryEncounterType, true).localizationKey + ":title");
|
||||
const descContainer = this.scene.add.container(0, 0);
|
||||
const textBox = addTextObject(this.scene, 0, 0, mysteryEncounterTitle, TextStyle.WINDOW, { fontSize : "45px", wordWrap: { width: 160 }});
|
||||
descContainer.add(textBox);
|
||||
descContainer.setPosition(47, 37);
|
||||
this.runResultContainer.add([ encounterExclaim, subSprite, descContainer ]);
|
||||
}
|
||||
|
||||
this.runResultContainer.add(runStatusText);
|
||||
this.runContainer.add(this.runResultContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called to edit an enemyContainer to represent a loss from a defeat by a wild single Pokemon battle.
|
||||
* @param enemyContainer - container holding enemy visual and level information
|
||||
|
@ -278,40 +358,58 @@ export default class RunInfoUiHandler extends UiHandler {
|
|||
}
|
||||
|
||||
/**
|
||||
* This edits a container to represent a loss from a defeat by a trainer battle.
|
||||
* @param enemyContainer - container holding enemy visuals and level information
|
||||
* The trainers are placed to the left of their party.
|
||||
* Depending on the trainer icon, there may be overlap between the edges of the box or their party. (Capes...)
|
||||
*
|
||||
* Party Pokemon have their icons, terastalization status, and level shown.
|
||||
* This loads the enemy sprites, positions, and scales them according to the current display mode of the RunInfo UI and then adds them to the container parameter.
|
||||
* Used by {@linkcode parseRunStatus} and {@linkcode parseTrainerDefeat}
|
||||
* @param enemyContainer a Phaser Container that should hold enemy sprites
|
||||
*/
|
||||
private parseTrainerDefeat(enemyContainer: Phaser.GameObjects.Container) {
|
||||
private showTrainerSprites(enemyContainer: Phaser.GameObjects.Container) {
|
||||
// Creating the trainer sprite and adding it to enemyContainer
|
||||
const tObj = this.runInfo.trainer.toTrainer(this.scene);
|
||||
|
||||
// Loads trainer assets on demand, as they are not loaded by default in the scene
|
||||
tObj.config.loadAssets(this.scene, this.runInfo.trainer.variant).then(() => {
|
||||
const tObjSpriteKey = tObj.config.getSpriteKey(this.runInfo.trainer.variant === TrainerVariant.FEMALE, false);
|
||||
const tObjSprite = this.scene.add.sprite(0, 5, tObjSpriteKey);
|
||||
if (this.runInfo.trainer.variant === TrainerVariant.DOUBLE) {
|
||||
if (this.runInfo.trainer.variant === TrainerVariant.DOUBLE && !tObj.config.doubleOnly) {
|
||||
const doubleContainer = this.scene.add.container(5, 8);
|
||||
tObjSprite.setPosition(-3, -3);
|
||||
const tObjPartnerSpriteKey = tObj.config.getSpriteKey(true, true);
|
||||
const tObjPartnerSprite = this.scene.add.sprite(5, -3, tObjPartnerSpriteKey);
|
||||
// Double Trainers have smaller sprites than Single Trainers
|
||||
tObjPartnerSprite.setScale(0.20);
|
||||
tObjSprite.setScale(0.20);
|
||||
doubleContainer.add(tObjSprite);
|
||||
doubleContainer.add(tObjPartnerSprite);
|
||||
doubleContainer.setPosition(12, 38);
|
||||
if (this.runDisplayMode === RunDisplayMode.RUN_HISTORY) {
|
||||
tObjPartnerSprite.setScale(0.20);
|
||||
tObjSprite.setScale(0.20);
|
||||
doubleContainer.add(tObjSprite);
|
||||
doubleContainer.add(tObjPartnerSprite);
|
||||
doubleContainer.setPosition(12, 38);
|
||||
} else {
|
||||
tObjSprite.setScale(0.55);
|
||||
tObjSprite.setPosition(-9, -3);
|
||||
tObjPartnerSprite.setScale(0.55);
|
||||
doubleContainer.add([ tObjSprite, tObjPartnerSprite ]);
|
||||
doubleContainer.setPosition(28, 40);
|
||||
}
|
||||
enemyContainer.add(doubleContainer);
|
||||
} else {
|
||||
tObjSprite.setScale(0.35, 0.35);
|
||||
tObjSprite.setPosition(12, 28);
|
||||
const scale = (this.runDisplayMode === RunDisplayMode.RUN_HISTORY) ? 0.35 : 0.65;
|
||||
const position = (this.runDisplayMode === RunDisplayMode.RUN_HISTORY) ? [ 12, 28 ] : [ 32, 36 ];
|
||||
tObjSprite.setScale(scale, scale);
|
||||
tObjSprite.setPosition(position[0], position[1]);
|
||||
enemyContainer.add(tObjSprite);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This edits a container to represent a loss from a defeat by a trainer battle.
|
||||
* The trainers are placed to the left of their party.
|
||||
* Depending on the trainer icon, there may be overlap between the edges of the box or their party. (Capes...)
|
||||
*
|
||||
* Party Pokemon have their icons, terastalization status, and level shown.
|
||||
* @param enemyContainer - container holding enemy visuals and level information
|
||||
*/
|
||||
private parseTrainerDefeat(enemyContainer: Phaser.GameObjects.Container) {
|
||||
// Loads and adds trainer sprites to the UI
|
||||
this.showTrainerSprites(enemyContainer);
|
||||
// Determining which Terastallize Modifier belongs to which Pokemon
|
||||
// Creates a dictionary {PokemonId: TeraShardType}
|
||||
const teraPokemon = {};
|
||||
|
|
|
@ -10,6 +10,7 @@ import MessageUiHandler from "./message-ui-handler";
|
|||
import { TextStyle, addTextObject } from "./text";
|
||||
import { Mode } from "./ui";
|
||||
import { addWindow } from "./ui-theme";
|
||||
import { RunDisplayMode } from "#app/ui/run-info-ui-handler";
|
||||
|
||||
const sessionSlotCount = 5;
|
||||
|
||||
|
@ -33,7 +34,7 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler {
|
|||
|
||||
private scrollCursor: integer = 0;
|
||||
|
||||
private cursorObj: Phaser.GameObjects.NineSlice | null;
|
||||
private cursorObj: Phaser.GameObjects.Container | null;
|
||||
|
||||
private sessionSlotsContainerInitialY: number;
|
||||
|
||||
|
@ -83,9 +84,11 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler {
|
|||
this.saveSlotSelectCallback = args[1] as SaveSlotSelectCallback;
|
||||
|
||||
this.saveSlotSelectContainer.setVisible(true);
|
||||
this.populateSessionSlots();
|
||||
this.setScrollCursor(0);
|
||||
this.setCursor(0);
|
||||
this.populateSessionSlots()
|
||||
.then(() => {
|
||||
this.setScrollCursor(0);
|
||||
this.setCursor(0);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -147,21 +150,28 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler {
|
|||
success = true;
|
||||
}
|
||||
} else {
|
||||
const cursorPosition = this.cursor + this.scrollCursor;
|
||||
switch (button) {
|
||||
case Button.UP:
|
||||
if (this.cursor) {
|
||||
success = this.setCursor(this.cursor - 1);
|
||||
// Check to prevent cursor from accessing a negative index
|
||||
success = (this.cursor === 0) ? this.setCursor(this.cursor) : this.setCursor(this.cursor - 1, cursorPosition);
|
||||
} else if (this.scrollCursor) {
|
||||
success = this.setScrollCursor(this.scrollCursor - 1);
|
||||
success = this.setScrollCursor(this.scrollCursor - 1, cursorPosition);
|
||||
}
|
||||
break;
|
||||
case Button.DOWN:
|
||||
if (this.cursor < 2) {
|
||||
success = this.setCursor(this.cursor + 1);
|
||||
success = this.setCursor(this.cursor + 1, this.cursor);
|
||||
} else if (this.scrollCursor < sessionSlotCount - 3) {
|
||||
success = this.setScrollCursor(this.scrollCursor + 1);
|
||||
success = this.setScrollCursor(this.scrollCursor + 1, cursorPosition);
|
||||
}
|
||||
break;
|
||||
case Button.RIGHT:
|
||||
if (this.sessionSlots[cursorPosition].hasData && this.sessionSlots[cursorPosition].saveData) {
|
||||
this.scene.ui.setOverlayMode(Mode.RUN_INFO, this.sessionSlots[cursorPosition].saveData, RunDisplayMode.SESSION_PREVIEW);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,10 +184,10 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler {
|
|||
return success || error;
|
||||
}
|
||||
|
||||
populateSessionSlots() {
|
||||
async populateSessionSlots() {
|
||||
for (let s = 0; s < sessionSlotCount; s++) {
|
||||
const sessionSlot = new SessionSlot(this.scene, s);
|
||||
sessionSlot.load();
|
||||
await sessionSlot.load();
|
||||
this.scene.add.existing(sessionSlot);
|
||||
this.sessionSlotsContainer.add(sessionSlot);
|
||||
this.sessionSlots.push(sessionSlot);
|
||||
|
@ -198,25 +208,74 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler {
|
|||
this.saveSlotSelectMessageBoxContainer.setVisible(!!text?.length);
|
||||
}
|
||||
|
||||
setCursor(cursor: integer): boolean {
|
||||
/**
|
||||
* setCursor takes user navigation as an input and positions the cursor accordingly
|
||||
* @param cursor the index provided to the cursor
|
||||
* @param prevCursor the previous index occupied by the cursor - optional
|
||||
* @returns `true` if the cursor position has changed | `false` if it has not
|
||||
*/
|
||||
override setCursor(cursor: integer, prevCursor?: integer): boolean {
|
||||
const changed = super.setCursor(cursor);
|
||||
|
||||
if (!this.cursorObj) {
|
||||
this.cursorObj = this.scene.add.nineslice(0, 0, "select_cursor_highlight_thick", undefined, 296, 44, 6, 6, 6, 6);
|
||||
this.cursorObj.setOrigin(0, 0);
|
||||
this.cursorObj = this.scene.add.container(0, 0);
|
||||
const cursorBox = this.scene.add.nineslice(0, 0, "select_cursor_highlight_thick", undefined, 296, 44, 6, 6, 6, 6);
|
||||
const rightArrow = this.scene.add.image(0, 0, "cursor");
|
||||
rightArrow.setPosition(160, 0);
|
||||
rightArrow.setName("rightArrow");
|
||||
this.cursorObj.add([ cursorBox, rightArrow ]);
|
||||
this.sessionSlotsContainer.add(this.cursorObj);
|
||||
}
|
||||
this.cursorObj.setPosition(4, 4 + (cursor + this.scrollCursor) * 56);
|
||||
const cursorPosition = cursor + this.scrollCursor;
|
||||
const cursorIncrement = cursorPosition * 56;
|
||||
if (this.sessionSlots[cursorPosition] && this.cursorObj) {
|
||||
const hasData = this.sessionSlots[cursorPosition].hasData;
|
||||
// If the session slot lacks session data, it does not move from its default, central position.
|
||||
// Only session slots with session data will move leftwards and have a visible arrow.
|
||||
if (!hasData) {
|
||||
this.cursorObj.setPosition(151, 26 + cursorIncrement);
|
||||
this.sessionSlots[cursorPosition].setPosition(0, cursorIncrement);
|
||||
} else {
|
||||
this.cursorObj.setPosition(145, 26 + cursorIncrement);
|
||||
this.sessionSlots[cursorPosition].setPosition(-6, cursorIncrement);
|
||||
}
|
||||
this.setArrowVisibility(hasData);
|
||||
}
|
||||
if (!Utils.isNullOrUndefined(prevCursor)) {
|
||||
this.revertSessionSlot(prevCursor);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
setScrollCursor(scrollCursor: integer): boolean {
|
||||
/**
|
||||
* Helper function that resets the session slot position to its default central position
|
||||
* @param prevCursor the previous location of the cursor
|
||||
*/
|
||||
revertSessionSlot(prevCursor: integer): void {
|
||||
const sessionSlot = this.sessionSlots[prevCursor];
|
||||
if (sessionSlot) {
|
||||
sessionSlot.setPosition(0, prevCursor * 56);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that checks if the session slot involved holds data or not
|
||||
* @param hasData `true` if session slot contains data | 'false' if not
|
||||
*/
|
||||
setArrowVisibility(hasData: boolean): void {
|
||||
if (this.cursorObj) {
|
||||
const rightArrow = this.cursorObj?.getByName("rightArrow") as Phaser.GameObjects.Image;
|
||||
rightArrow.setVisible(hasData);
|
||||
}
|
||||
}
|
||||
|
||||
setScrollCursor(scrollCursor: integer, priorCursor?: integer): boolean {
|
||||
const changed = scrollCursor !== this.scrollCursor;
|
||||
|
||||
if (changed) {
|
||||
this.scrollCursor = scrollCursor;
|
||||
this.setCursor(this.cursor);
|
||||
this.setCursor(this.cursor, priorCursor);
|
||||
this.scene.tweens.add({
|
||||
targets: this.sessionSlotsContainer,
|
||||
y: this.sessionSlotsContainerInitialY - 56 * scrollCursor,
|
||||
|
@ -254,6 +313,8 @@ class SessionSlot extends Phaser.GameObjects.Container {
|
|||
public hasData: boolean;
|
||||
private loadingLabel: Phaser.GameObjects.Text;
|
||||
|
||||
public saveData: SessionSaveData;
|
||||
|
||||
constructor(scene: BattleScene, slotId: integer) {
|
||||
super(scene, 0, slotId * 56);
|
||||
|
||||
|
@ -337,6 +398,7 @@ class SessionSlot extends Phaser.GameObjects.Container {
|
|||
return;
|
||||
}
|
||||
this.hasData = true;
|
||||
this.saveData = sessionData;
|
||||
await this.setupWithData(sessionData);
|
||||
resolve(true);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue