diff --git a/data/GameManager.js b/data/GameManager.js index 0bb7c54..7ddc3d1 100644 --- a/data/GameManager.js +++ b/data/GameManager.js @@ -1,5 +1,6 @@ class EJS_GameManager { - constructor(Module) { + constructor(Module, EJS) { + this.EJS = EJS; this.Module = Module; this.FS = this.Module.FS; this.functions = { @@ -110,6 +111,30 @@ class EJS_GameManager { })(); } simulateInput(player, index, value) { + if ([24, 25, 26].includes(index)) { + if (index === 24 && value === 1) { + const slot = this.EJS.settings['save-state-slot'] ? this.EJS.settings['save-state-slot'] : "1"; + this.quickSave(slot); + this.EJS.displayMessage(this.EJS.localization("SAVED STATE TO SLOT")+" "+slot); + } + if (index === 25 && value === 1) { + const slot = this.EJS.settings['save-state-slot'] ? this.EJS.settings['save-state-slot'] : "1"; + this.quickLoad(slot); + this.EJS.displayMessage(this.EJS.localization("LOADED STATE FROM SLOT")+" "+slot); + } + if (index === 26 && value === 1) { + let newSlot; + try { + newSlot = parseFloat(this.EJS.settings['save-state-slot'] ? this.EJS.settings['save-state-slot'] : "1") + 1; + } catch(e) { + newSlot = 1; + } + if (newSlot > 9) newSlot = 1; + this.EJS.displayMessage(this.EJS.localization("SET SAVE STATE SLOT TO")+" "+newSlot); + this.EJS.changeSettingOption('save-state-slot', newSlot.toString()); + } + return; + } this.functions.simulateInput(player, index, value); } toggleMainLoop(playing) { diff --git a/data/css/main.css b/data/css/main.css index 68b085b..53239cd 100644 --- a/data/css/main.css +++ b/data/css/main.css @@ -1083,3 +1083,15 @@ .ejs_volume_parent input[type='range']:active::-ms-thumb { box-shadow:0 1px 1px rgba(0,0,0,0.15),0 0 0 1px rgba(47,52,61,0.2),0 0 0 3px rgba(255,255,255,0.5) } + +.ejs_message { + float: none; + overflow: hidden; + position: absolute; + top: 0; + color: red; + font-size: 17px; + padding: 10px; + text-align: left; + text-shadow: rgb(0, 0, 0) 1px 1px 1px; +} diff --git a/data/emulator.js b/data/emulator.js index a9c3bf5..9562f03 100644 --- a/data/emulator.js +++ b/data/emulator.js @@ -521,6 +521,18 @@ class EmulatorJS { saveInBrowserSupported() { return !!window.indexedDB && (typeof this.config.gameName === "string" || !this.config.gameUrl.startsWith("blob:")); } + displayMessage(message) { + if (!this.msgElem) { + this.msgElem = this.createElement("div"); + this.msgElem.classList.add("ejs_message"); + this.elements.parent.appendChild(this.msgElem); + } + clearTimeout(this.msgTimeout); + this.msgTimeout = setTimeout(() => { + this.msgElem.innerText = ""; + }, 3000) + this.msgElem.innerText = message; + } downloadStartState() { if (typeof this.config.loadState !== "string") { this.startGame(); @@ -589,7 +601,7 @@ class EmulatorJS { }, null, true, {method: "HEAD"}) } downloadRom() { - this.gameManager = new window.EJS_GameManager(this.Module); + this.gameManager = new window.EJS_GameManager(this.Module, this); this.textElem.innerText = this.localization("Download Game Data"); const gotGameData = (data) => { @@ -804,11 +816,13 @@ class EmulatorJS { const qSave = addButton("Quick Save", false, () => { const slot = this.settings['save-state-slot'] ? this.settings['save-state-slot'] : "1"; this.gameManager.quickSave(slot); + this.displayMessage(this.localization("SAVED STATE TO SLOT")+" "+slot); hideMenu(); }); const qLoad = addButton("Quick Load", false, () => { const slot = this.settings['save-state-slot'] ? this.settings['save-state-slot'] : "1"; this.gameManager.quickLoad(slot); + this.displayMessage(this.localization("LOADED STATE FROM SLOT")+" "+slot); hideMenu(); }); addButton("EmulatorJS", false, () => { @@ -997,6 +1011,7 @@ class EmulatorJS { if (stateUrl) URL.revokeObjectURL(stateUrl); if (this.settings['save-state-location'] === "browser" && this.saveInBrowserSupported()) { this.storage.states.put(this.getBaseFileName()+".state", state); + this.displayMessage(this.localization("SAVED LOADED TO BROWSER")); } else { const blob = new Blob([state]); stateUrl = URL.createObjectURL(blob); @@ -1012,6 +1027,7 @@ class EmulatorJS { if (this.settings['save-state-location'] === "browser" && this.saveInBrowserSupported()) { this.storage.states.get(this.getBaseFileName()+".state").then(e => { this.gameManager.loadState(e); + this.displayMessage(this.localization("SAVED LOADED FROM BROWSER")); }) } else { const file = await this.selectFile(); @@ -1596,6 +1612,7 @@ class EmulatorJS { } controls; keyChange(e) { + if (e.repeat) return; if (!this.started) return; if (this.controlPopup.parentElement.getAttribute("hidden") === null) { const num = this.controlPopup.getAttribute("button-num"); @@ -1613,7 +1630,7 @@ class EmulatorJS { e.preventDefault(); const special = [16, 17, 18, 19, 20, 21, 22, 23]; for (let i=0; i<4; i++) { - for (let j=0; j<26; j++) { + for (let j=0; j<27; j++) { if (this.controls[i][j] && this.controls[i][j].value === e.key.toLowerCase()) { this.gameManager.simulateInput(i, j, (e.type === 'keyup' ? 0 : (special.includes(j) ? 0x7fff : 1))); } @@ -1645,7 +1662,7 @@ class EmulatorJS { if (this.settingsMenu.style.display !== "none" || this.isPopupOpen()) return; const special = [16, 17, 18, 19, 20, 21, 22, 23]; for (let i=0; i<4; i++) { - for (let j=0; j<26; j++) { + for (let j=0; j<27; j++) { if (['buttonup', 'buttondown'].includes(e.type) && (this.controls[i][j] && this.controls[i][j].value2 === e.index)) { this.gameManager.simulateInput(i, j, (e.type === 'buttondown' ? 0 : (special.includes(j) ? 0x7fff : 1))); } else if (e.type === "axischanged") {