diff --git a/src/GameManager.js b/src/GameManager.js
index bf66107..dee742a 100644
--- a/src/GameManager.js
+++ b/src/GameManager.js
@@ -11,7 +11,9 @@ class EJS_GameManager {
simulateInput: this.Module.cwrap('simulate_input', 'null', ['number', 'number', 'number']),
toggleMainLoop: this.Module.cwrap('toggleMainLoop', 'null', ['number']),
getCoreOptions: this.Module.cwrap('get_core_options', 'string', []),
- setVariable: this.Module.cwrap('set_variable', 'null', ['string', 'string'])
+ setVariable: this.Module.cwrap('set_variable', 'null', ['string', 'string']),
+ setCheat: this.Module.cwrap('set_cheat', 'null', ['number', 'number', 'string']),
+ resetCheat: this.Module.cwrap('reset_cheat', 'null', [])
}
this.mkdir("/home");
this.mkdir("/home/web_user");
@@ -101,7 +103,12 @@ class EJS_GameManager {
setVariable(option, value) {
this.functions.setVariable(option, value);
}
-
+ setCheat(index, enabled, code) {
+ this.functions.setCheat(index, enabled, code);
+ }
+ resetCheat() {
+ this.functions.resetCheat();
+ }
}
window.EJS_GameManager = EJS_GameManager;
diff --git a/src/css/main.css b/src/css/main.css
index 4cf6bc4..e95bc5e 100644
--- a/src/css/main.css
+++ b/src/css/main.css
@@ -247,6 +247,11 @@
.ejs_popup_container *, .ejs_popup_container *::after, .ejs_popup_container *::before {
box-sizing: border-box;
+
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
}
.ejs_popup_container h4 {
@@ -694,3 +699,189 @@
background: rgba(var(--ejs-primary-color),1);
color: #fff;
}
+
+.ejs_cheat_heading {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+ font-weight: 600 !important;
+ font-size: 1.25rem;
+ line-height: 1.25 !important;
+ color: rgba(var(--ejs-primary-color),1) !important;
+}
+.ejs_cheat_close {
+ font: inherit;
+ line-height: inherit;
+ width: auto;
+ background: transparent;
+ border: 0;
+ color: #bcbcbc !important;
+ cursor: pointer;
+}
+.ejs_cheat_close::before {
+ content: "\2715";
+ color: #bcbcbc !important;
+ font: inherit;
+ line-height: inherit;
+ width: auto;
+}
+.ejs_cheat_header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+.ejs_cheat_main {
+ margin-top: 2rem;
+ margin-bottom: 2rem;
+ line-height: 1.5;
+ color: rgba(0,0,0,0.8);
+ text-align: left;
+ color: #bcbcbc !important;
+ border: unset;
+}
+.ejs_cheat_code {
+ color: #000 !important;
+ font-size: 1rem;
+ padding: .4rem;
+ max-width: 100%;
+}
+@keyframes ejs_cheat_animation{
+ from{
+ transform:translateY(15%)
+ }
+ to{
+ transform:translateY(0)
+ }
+}
+.ejs_cheat_parent {
+ background-color: rgba(0,0,0,0.8);
+ border: 1px solid rgba(238,238,238,0.2);
+ padding: 30px;
+ min-width: 200px;
+ max-width: 500px;
+ max-height: 100vh;
+ border-radius: 4px;
+ overflow-y: auto;
+ box-sizing: border-box;
+ will-change: transform;
+ animation: ejs_cheat_animation .3s cubic-bezier(0,0,0.2,1);
+ font-size: 14px;
+}
+.ejs_popup_container_box {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0,0,0,0.6);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+.ejs_popup_submit {
+ touch-action: manipulation;
+ font: inherit;
+ line-height: inherit;
+ width: auto;
+}
+.ejs_button_button {
+ color: #fff !important;
+ padding-left: 1rem;
+ padding-right: 1rem;
+ padding-top: .5rem;
+ padding-bottom: .5rem;
+ background-color: #929292;
+ border-radius: .25rem;
+ border-style: none;
+ border-width: 0;
+ cursor: pointer;
+ -webkit-appearance: button;
+ text-transform: none;
+ overflow: visible;
+ margin: 0;
+ will-change: transform;
+ transition: transform .25s ease-out,-webkit-transform .25s ease-out;
+}
+.ejs_button_button:hover {
+ transform: scale(1.05);
+}
+.ejs_cheat_rows {
+ max-width: 320px;
+ margin: 0 auto;
+ text-align: left;
+ width: 100%;
+ float: none;
+ user-select: text !important;
+}
+.ejs_cheat_row {
+ padding-left: 2.25rem;
+ position: relative;
+ padding: .2em 0;
+ clear: both;
+}
+.ejs_cheat_row:hover {
+ background-color: rgba(0,0,0,0.8);
+}
+.ejs_cheat_row input[type=checkbox] {
+ position: absolute;
+ z-index: -1;
+ opacity: 0;
+ box-sizing: border-box;
+ width: auto;
+}
+.ejs_cheat_row label {
+ position: relative;
+ margin-bottom: 0;
+ vertical-align: top;
+ word-break: break-word;
+}
+
+.ejs_cheat_row label::before {
+ position: absolute;
+ top: .325rem;
+ display: block;
+ height: 1rem;
+ content: "";
+ background-color: #fff;
+ border: #adb5bd solid 1px;
+ left: -2.25rem;
+ width: 1.75rem;
+ pointer-events: all;
+ border-radius: .5rem;
+}
+
+.ejs_cheat_row input:checked+label::before {
+ color: #fff;
+ border-color: rgba(var(--ejs-primary-color),1);
+ background-color: rgba(var(--ejs-primary-color),1);
+}
+
+.ejs_cheat_row label::after {
+ position: absolute;
+ display: block;
+ content: "";
+ background-repeat: no-repeat;
+ background-position: center center;
+ top: calc(.325rem + 2px);
+ left: calc(-2.25rem + 2px);
+ width: calc(1rem - 4px);
+ height: calc(1rem - 4px);
+ background-color: #adb5bd;
+ border-radius: .5rem;
+ transition: transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out;
+}
+.ejs_cheat_row input:checked+label::after {
+ background-color: #fff;
+ -webkit-transform: translateX(0.75rem);
+ transform: translateX(0.75rem);
+}
+
+.ejs_cheat_row_button {
+ position: absolute;
+ padding: .1rem .5rem;
+ background-color: rgba(var(--ejs-primary-color),1);
+ color: #fff !important;
+ border-radius: .25rem;
+ cursor: pointer;
+ right: .025rem;
+ border: 0;
+}
diff --git a/src/emulator.js b/src/emulator.js
index c0de791..0d9935f 100644
--- a/src/emulator.js
+++ b/src/emulator.js
@@ -80,6 +80,7 @@ class EmulatorJS {
window.EJS_TESTING = this;
this.touch = false;
this.debug = (window.EJS_DEBUG_XX === true);
+ this.cheats = [];
this.setElements(element);
this.started = false;
this.paused = true;
@@ -448,6 +449,7 @@ class EmulatorJS {
startGame() {
this.textElem.remove();
this.textElem = null;
+
this.game.classList.remove("ejs_game");
this.game.appendChild(this.canvas);
const args = [];
@@ -464,11 +466,13 @@ class EmulatorJS {
this.setupSettingsMenu();
this.handleResize();
+ this.updateCheatUI();
}
bindListeners() {
this.createContextMenu();
this.createBottomMenuBar();
this.createControlSettingMenu();
+ this.createCheatsMenu()
this.setVirtualGamepad();
this.addEventListener(document, "keydown keyup", this.keyChange.bind(this));
this.addEventListener(window, "resize", this.handleResize.bind(this));
@@ -701,6 +705,9 @@ class EmulatorJS {
addButton("Control Settings", '', () => {
this.controlMenu.style.display = "";
});
+ addButton("Cheats", '', () => {
+ this.cheatMenu.style.display = "";
+ });
const spacer = this.createElement("span");
spacer.style = "flex:1;";
@@ -957,7 +964,7 @@ class EmulatorJS {
popup.classList.add("ejs_popup_container");
const popupMsg = this.createElement("div");
popupMsg.classList.add("ejs_popup_box");
- popupMsg.innerText = "yes";
+ popupMsg.innerText = "";
popup.setAttribute("hidden", "");
this.controlPopup = popupMsg;
popup.appendChild(popupMsg);
@@ -1037,6 +1044,7 @@ class EmulatorJS {
controls;
keyChange(e) {
if (!this.started) return;
+ if (this.cheatMenu.style.display !== "none" || this.settingsMenu.style.display !== "none") return;
e.preventDefault();
if (this.controlPopup.parentElement.getAttribute("hidden") === null) {
const num = this.controlPopup.getAttribute("button-num");
@@ -1594,15 +1602,149 @@ class EmulatorJS {
this.settingsMenu.appendChild(nested);
-
this.settingParent.appendChild(this.settingsMenu);
this.settingParent.style.position = "relative";
-
const homeSize = this.getElementSize(home);
nested.style.width = homeSize.width + "px";
nested.style.height = homeSize.height + "px";
this.settingsMenu.style.display = "none";
}
+ createSubPopup(hidden) {
+ const popup = this.createElement('div');
+ popup.classList.add("ejs_popup_container");
+ popup.classList.add("ejs_popup_container_box");
+ const popupMsg = this.createElement("div");
+ popupMsg.innerText = "";
+ if (hidden) popup.setAttribute("hidden", "");
+ popup.appendChild(popupMsg);
+ return [popup, popupMsg];
+ }
+ createCheatsMenu() {
+ const body = this.createPopup("Cheats", {
+ "Add Cheat": () => {
+ const popups = this.createSubPopup();
+ this.cheatMenu.appendChild(popups[0]);
+ popups[1].classList.add("ejs_cheat_parent");
+ popups[1].style.width = "100%";
+ const popup = popups[1];
+ const header = this.createElement("div");
+ header.classList.add("ejs_cheat_header");
+ const title = this.createElement("h2");
+ title.innerText = "Add Cheat Code";
+ title.classList.add("ejs_cheat_heading");
+ const close = this.createElement("button");
+ close.classList.add("ejs_cheat_close");
+ header.appendChild(title);
+ header.appendChild(close);
+ popup.appendChild(header);
+ this.addEventListener(close, "click", (e) => {
+ popups[0].remove();
+ })
+
+ const main = this.createElement("div");
+ main.classList.add("ejs_cheat_main");
+ const header3 = this.createElement("strong");
+ header3.innerText = "Code";
+ main.appendChild(header3);
+ main.appendChild(this.createElement("br"));
+ const mainText = this.createElement("textarea");
+ mainText.classList.add("ejs_cheat_code");
+ mainText.style.width = "100%";
+ mainText.style.height = "80px";
+ main.appendChild(mainText);
+ main.appendChild(this.createElement("br"));
+ const header2 = this.createElement("strong");
+ header2.innerText = "Description";
+ main.appendChild(header2);
+ main.appendChild(this.createElement("br"));
+ const mainText2 = this.createElement("input");
+ mainText2.type = "text";
+ mainText2.classList.add("ejs_cheat_code");
+ main.appendChild(mainText2);
+ main.appendChild(this.createElement("br"));
+ popup.appendChild(main);
+
+ const footer = this.createElement("footer");
+ const submit = this.createElement("button");
+ const closeButton = this.createElement("button");
+ submit.innerText = "Submit";
+ closeButton.innerText = "Close";
+ submit.classList.add("ejs_button_button");
+ closeButton.classList.add("ejs_button_button");
+ submit.classList.add("ejs_popup_submit");
+ closeButton.classList.add("ejs_popup_submit");
+ submit.style["background-color"] = "rgba(var(--ejs-primary-color),1)";
+ footer.appendChild(submit);
+ const span = this.createElement("span");
+ span.innerText = " ";
+ footer.appendChild(span);
+ footer.appendChild(closeButton);
+ popup.appendChild(footer);
+
+ this.addEventListener(submit, "click", (e) => {
+ if (!mainText.value.trim() || !mainText2.value.trim()) return;
+ popups[0].remove();
+ this.cheats.push({
+ code: mainText.value,
+ desc: mainText2.value,
+ checked: false
+ });
+ this.updateCheatUI();
+ })
+ this.addEventListener(closeButton, "click", (e) => {
+ popups[0].remove();
+ })
+
+ },
+ "Close": () => {
+ this.cheatMenu.style.display = "none";
+ }
+ }, true);
+ this.cheatMenu = body.parentElement;
+ const rows = this.createElement("div");
+ body.appendChild(rows);
+ rows.classList.add("ejs_cheat_rows");
+ this.elements.cheatRows = rows;
+ }
+ updateCheatUI() {
+ if (!this.cheats) this.cheats = [];
+ this.elements.cheatRows.innerHTML = "";
+
+ const addToMenu = (desc, checked, code, i) => {
+ const row = this.createElement("div");
+ row.classList.add("ejs_cheat_row");
+ const input = this.createElement("input");
+ input.type = "checkbox";
+ input.checked = checked;
+ input.value = i;
+ input.id = "ejs_cheat_switch_"+i;
+ row.appendChild(input);
+ const label = this.createElement("label");
+ label.for = "ejs_cheat_switch_"+i;
+ label.innerText = desc;
+ row.appendChild(label);
+ label.addEventListener("click", (e) => {
+ input.checked = !input.checked;
+ this.cheats[i].checked = input.checked;
+ this.cheatChanged(input.checked, code, i);
+ })
+ const close = this.createElement("a");
+ close.classList.add("ejs_cheat_row_button");
+ close.innerText = "×";
+ row.appendChild(close);
+
+ this.elements.cheatRows.appendChild(row);
+ this.cheatChanged(checked, code, i);
+
+ }
+ this.gameManager.resetCheat();
+ for (let i=0; i