Refactor platform UI and data flow across core pages
All checks were successful
Build Org Website / build (push) Successful in 50s
All checks were successful
Build Org Website / build (push) Successful in 50s
This commit is contained in:
86
assets/scripts/pages/princess-lima-game.js
Normal file → Executable file
86
assets/scripts/pages/princess-lima-game.js
Normal file → Executable file
@@ -7,6 +7,7 @@
|
||||
const Scenes = window.PrincessLimaScenes;
|
||||
const UI = window.PrincessLimaUI;
|
||||
const Audio = window.PrincessLimaAudio;
|
||||
const Intro = window.PrincessLimaIntro;
|
||||
|
||||
const controller = {
|
||||
root: null,
|
||||
@@ -14,15 +15,16 @@
|
||||
scene: null,
|
||||
state: null,
|
||||
audio: null,
|
||||
intro: null,
|
||||
ui: null,
|
||||
locked: true,
|
||||
transitioning: false,
|
||||
move: { up: false, down: false, left: false, right: false },
|
||||
lastSaveAt: 0,
|
||||
systemReducedMotion: window.matchMedia("(prefers-reduced-motion: reduce)").matches,
|
||||
getState: () => controller.state,
|
||||
reducedMotion: () => controller.state && controller.state.settings.reducedMotion !== null
|
||||
? controller.state.settings.reducedMotion : controller.systemReducedMotion,
|
||||
debugCollision: false,
|
||||
devWarn: (message) => {
|
||||
if (["localhost", "127.0.0.1"].includes(window.location.hostname)) console.warn(`[Princess Lima RPG] ${message}`);
|
||||
}
|
||||
@@ -32,19 +34,37 @@
|
||||
|
||||
function init() {
|
||||
const root = document.querySelector("[data-princess-lima-rpg]");
|
||||
if (!root || !Data || !State || !Systems || !Scenes || !UI || !Audio || !window.Phaser) return gracefulFailure();
|
||||
if (!root || !Data || !State || !Systems || !Scenes || !UI || !Audio || !Intro || !window.PrincessLimaMaps || !window.Phaser) return gracefulFailure();
|
||||
controller.root = root;
|
||||
controller.state = loadState();
|
||||
controller.audio = Audio.create(() => controller.state);
|
||||
controller.debugCollision = localDebug();
|
||||
controller.ui = UI.create(root, {
|
||||
getState: () => controller.state,
|
||||
onLock: (value) => { controller.locked = value; },
|
||||
onUseTonic: useTonic,
|
||||
onSetting: updateSetting,
|
||||
onFullscreen: toggleFullscreen,
|
||||
onReplayIntro: () => {
|
||||
controller.ui.close();
|
||||
startIntro(true);
|
||||
},
|
||||
onReset: resetSave,
|
||||
onRespawn: respawn
|
||||
});
|
||||
controller.intro = Intro.create(root, {
|
||||
onLock: (value) => { controller.locked = value; },
|
||||
onAudioUnlock: () => controller.audio.unlock(),
|
||||
onComplete: completeIntro,
|
||||
playVoice: (key) => controller.audio.playVoice(key),
|
||||
stopVoice: () => controller.audio.stopVoice(),
|
||||
playEffect: (key, volume) => controller.audio.play(key, volume),
|
||||
narrationEnabled: () => !controller.state || controller.state.settings.narrationEnabled,
|
||||
subtitlesEnabled: () => !controller.state || controller.state.settings.subtitles,
|
||||
soundEnabled: () => Boolean(controller.state && controller.state.settings.soundEnabled),
|
||||
toggleSound,
|
||||
status
|
||||
});
|
||||
bindInterface();
|
||||
startEngine();
|
||||
window.addEventListener("error", (event) => {
|
||||
@@ -85,14 +105,14 @@
|
||||
const classes = Scenes.createSceneClasses(controller);
|
||||
controller.game = new Phaser.Game({
|
||||
type: Phaser.AUTO,
|
||||
width: Data.WIDTH,
|
||||
width: 1000,
|
||||
height: Data.HEIGHT,
|
||||
parent: "princess-lima-game",
|
||||
pixelArt: true,
|
||||
roundPixels: true,
|
||||
backgroundColor: "#0a0b12",
|
||||
physics: { default: "arcade", arcade: { debug: localDebug(), gravity: { x: 0, y: 0 } } },
|
||||
scale: { mode: Phaser.Scale.FIT, autoCenter: Phaser.Scale.CENTER_BOTH, width: Data.WIDTH, height: Data.HEIGHT },
|
||||
scale: { mode: Phaser.Scale.FIT, autoCenter: Phaser.Scale.CENTER_BOTH, width: 1000, height: Data.HEIGHT },
|
||||
scene: classes,
|
||||
render: { antialias: false, pixelArt: true }
|
||||
});
|
||||
@@ -116,7 +136,16 @@
|
||||
const root = controller.root;
|
||||
root.querySelector("[data-lima-new]").addEventListener("click", () => openSetup());
|
||||
root.querySelector("[data-lima-continue]").addEventListener("click", () => {
|
||||
if (controller.state) beginAdventure();
|
||||
if (controller.state) {
|
||||
controller.audio.unlock();
|
||||
if (controller.state.introSeen) beginAdventure();
|
||||
else startIntro(false);
|
||||
}
|
||||
});
|
||||
root.querySelector("[data-lima-replay-intro]").addEventListener("click", () => startIntro(true));
|
||||
root.querySelector("[data-lima-menu-settings]").addEventListener("click", () => {
|
||||
if (controller.state) openPanel("settings");
|
||||
else controller.ui.show("settings-help", "Settings", "<p>Create a traveller to save audio and accessibility preferences. The introduction always includes subtitles and can be muted or skipped.</p>");
|
||||
});
|
||||
root.querySelector("[data-lima-credits]").addEventListener("click", () => controller.ui.show(
|
||||
"credits", "Credits",
|
||||
@@ -124,18 +153,6 @@
|
||||
));
|
||||
root.querySelector("[data-lima-setup-form]").addEventListener("submit", submitSetup);
|
||||
root.querySelector("[data-lima-setup-cancel]").addEventListener("click", closeSetup);
|
||||
root.querySelectorAll("[data-lima-move]").forEach((button) => {
|
||||
const direction = button.dataset.limaMove;
|
||||
const on = (event) => { event.preventDefault(); controller.move[direction] = true; focusGame(); };
|
||||
const off = (event) => { event.preventDefault(); controller.move[direction] = false; };
|
||||
button.addEventListener("pointerdown", on);
|
||||
button.addEventListener("pointerup", off);
|
||||
button.addEventListener("pointercancel", off);
|
||||
button.addEventListener("pointerleave", off);
|
||||
});
|
||||
bindButton("[data-lima-attack]", () => controller.scene && controller.scene.attack(controller.scene.time.now));
|
||||
bindButton("[data-lima-interact]", () => controller.scene && controller.scene.interact());
|
||||
bindButton("[data-lima-item]", useTonic);
|
||||
bindButton("[data-lima-pause]", () => openPanel("pause"));
|
||||
bindButton("[data-lima-inventory]", () => openPanel("inventory"));
|
||||
bindButton("[data-lima-quests]", () => openPanel("quests"));
|
||||
@@ -172,20 +189,41 @@
|
||||
controller.state = State.fresh(name, appearance);
|
||||
save();
|
||||
closeSetup();
|
||||
beginAdventure();
|
||||
startIntro(false);
|
||||
}
|
||||
|
||||
function beginAdventure() {
|
||||
controller.audio.unlock();
|
||||
controller.root.querySelector("[data-lima-menu]").hidden = true;
|
||||
controller.root.querySelector("[data-lima-intro]").hidden = true;
|
||||
controller.root.querySelector("[data-lima-hud]").hidden = false;
|
||||
controller.root.querySelector("[data-lima-touch]").hidden = false;
|
||||
controller.root.querySelector("[data-lima-status-stack]").hidden = false;
|
||||
controller.locked = false;
|
||||
controller.game.scene.start("LimaWorld", { region: controller.state.region });
|
||||
focusGame();
|
||||
}
|
||||
|
||||
function startIntro(replay) {
|
||||
controller.audio.unlock();
|
||||
controller.root.querySelector("[data-lima-menu]").hidden = true;
|
||||
controller.root.querySelector("[data-lima-hud]").hidden = true;
|
||||
controller.root.querySelector("[data-lima-status-stack]").hidden = true;
|
||||
controller.intro.start({ replay });
|
||||
}
|
||||
|
||||
function completeIntro(result) {
|
||||
if (controller.state && !result.replay) {
|
||||
controller.state.introSeen = true;
|
||||
controller.state = State.normalize(controller.state);
|
||||
save();
|
||||
beginAdventure();
|
||||
return;
|
||||
}
|
||||
controller.locked = true;
|
||||
controller.root.querySelector("[data-lima-menu]").hidden = false;
|
||||
controller.root.querySelector("[data-lima-menu] button").focus();
|
||||
}
|
||||
|
||||
function travel(region, spawn) {
|
||||
if (controller.transitioning || !Data.MAPS[region]) return;
|
||||
controller.transitioning = true;
|
||||
@@ -311,12 +349,20 @@
|
||||
text("[data-lima-chapter]", `Chapter ${controller.state.chapter}`);
|
||||
text("[data-lima-objective]", Systems.currentObjective(controller.state));
|
||||
text("[data-lima-tonics]", `Tonic ×${Systems.quantity(controller.state, "healing_tonic")}`);
|
||||
text("[data-lima-weapon]", controller.state.equipment.weapon ? Data.ITEMS[controller.state.equipment.weapon].name : "Unarmed");
|
||||
text("[data-lima-armour]", controller.state.equipment.armour ? Data.ITEMS[controller.state.equipment.armour].name : "None");
|
||||
text("[data-lima-selected-item]", `Healing Tonic ×${Systems.quantity(controller.state, "healing_tonic")}`);
|
||||
text("[data-lima-currency]", String(Systems.quantity(controller.state, "moon_coin")));
|
||||
text("[data-lima-sound]", controller.state.settings.soundEnabled ? "Sound On" : "Sound Muted");
|
||||
const healthBar = controller.root.querySelector(".lima-hud__healthbar i");
|
||||
if (healthBar) healthBar.style.width = `${controller.state.health / controller.state.maxHealth * 100}%`;
|
||||
controller.root.classList.toggle("is-high-contrast", controller.state.settings.highContrast);
|
||||
}
|
||||
|
||||
function cycleItem() {
|
||||
status("Healing Tonic selected. Press Q to use it.");
|
||||
}
|
||||
|
||||
function prompt(message) {
|
||||
text("[data-lima-prompt]", message || "Explore the road ahead.");
|
||||
}
|
||||
@@ -358,6 +404,6 @@
|
||||
|
||||
Object.assign(controller, {
|
||||
ready, travel, reloadRegion, persistPosition, setState, updateHud, status, prompt, boss,
|
||||
openDialogue, openPanel, gameOver, openEnding, useTonic
|
||||
openDialogue, openPanel, gameOver, openEnding, useTonic, toggleFullscreen, toggleSound, cycleItem
|
||||
});
|
||||
}());
|
||||
|
||||
Reference in New Issue
Block a user