Rebind Space to jump, gate editor behind localStorage flag
Space is now the alternate jump key (was shoot). Web shell shows game controls by default and hides editor UI unless localStorage.show_editor is set to 'true'. The E key and ?edit URL are blocked when the editor is not enabled. Also fix Makefile to track web/shell.html as a WASM link dependency so shell changes trigger a rebuild.
This commit is contained in:
178
web/shell.html
178
web/shell.html
@@ -60,6 +60,17 @@
|
||||
max-width: 1300px;
|
||||
}
|
||||
#hint { color: #666; }
|
||||
#game-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-top: 8px;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
max-width: 1300px;
|
||||
}
|
||||
.ctrl-btn {
|
||||
color: #4ecdc4;
|
||||
background: transparent;
|
||||
@@ -100,7 +111,7 @@
|
||||
<canvas class="emscripten" id="canvas" tabindex="1"
|
||||
width="640" height="360"></canvas>
|
||||
</div>
|
||||
<div id="controls">
|
||||
<div id="controls" class="hidden">
|
||||
<a class="ctrl-btn" id="editor-link" href="?edit">Editor</a>
|
||||
<span class="ctrl-sep">|</span>
|
||||
<button class="ctrl-btn" id="btn-save" title="Save level (download .lvl)">Save</button>
|
||||
@@ -112,10 +123,33 @@
|
||||
<span class="ctrl-sep">|</span>
|
||||
<span id="hint">E=editor P=test play 1-6=tools</span>
|
||||
</div>
|
||||
<div id="game-controls">
|
||||
<span>Arrows=move</span>
|
||||
<span class="ctrl-sep">|</span>
|
||||
<span>Z/Space=jump</span>
|
||||
<span class="ctrl-sep">|</span>
|
||||
<span>X=shoot</span>
|
||||
<span class="ctrl-sep">|</span>
|
||||
<span>C=dash</span>
|
||||
<span class="ctrl-sep">|</span>
|
||||
<span>Up=aim up</span>
|
||||
</div>
|
||||
<div id="status">Loading...</div>
|
||||
<div id="progress-bar"><div id="progress-bar-inner"></div></div>
|
||||
|
||||
<script>
|
||||
/* ── Editor gate: only enable when localStorage show_editor=true ── */
|
||||
var editorEnabled = false;
|
||||
try { editorEnabled = (localStorage.getItem('show_editor') === 'true'); } catch(e) {}
|
||||
if (editorEnabled) {
|
||||
document.getElementById('controls').classList.remove('hidden');
|
||||
document.getElementById('game-controls').classList.add('hidden');
|
||||
}
|
||||
/* Strip ?edit from URL when editor is not enabled */
|
||||
if (!editorEnabled && window.location.search.indexOf('edit') !== -1) {
|
||||
window.history.replaceState({}, '', window.location.pathname);
|
||||
}
|
||||
|
||||
var statusEl = document.getElementById('status');
|
||||
var progressEl = document.getElementById('progress-bar');
|
||||
var progressIn = document.getElementById('progress-bar-inner');
|
||||
@@ -155,16 +189,22 @@
|
||||
Module.setStatus('Error - check the browser console');
|
||||
};
|
||||
|
||||
/* ── Keyboard shortcuts: Ctrl+S / Ctrl+O ────────── */
|
||||
/* ── Keyboard shortcuts: Ctrl+S / Ctrl+O / E-key ── */
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 's') {
|
||||
/* Block E-key editor entry when editor is not enabled */
|
||||
if (!editorEnabled && e.key === 'e' && !e.ctrlKey && !e.metaKey) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return;
|
||||
}
|
||||
if (editorEnabled && (e.ctrlKey || e.metaKey) && e.key === 's') {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (typeof _editor_save_flag_ptr === 'function') {
|
||||
HEAP32[_editor_save_flag_ptr() >> 2] = 1;
|
||||
}
|
||||
}
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 'o') {
|
||||
if (editorEnabled && (e.ctrlKey || e.metaKey) && e.key === 'o') {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (typeof _editor_load_flag_ptr === 'function') {
|
||||
@@ -173,72 +213,74 @@
|
||||
}
|
||||
}, true); /* useCapture=true to intercept before SDL */
|
||||
|
||||
/* ── Button handlers ────────────────────────────── */
|
||||
document.getElementById('btn-save').addEventListener('click', function() {
|
||||
if (typeof _editor_save_flag_ptr === 'function') {
|
||||
HEAP32[_editor_save_flag_ptr() >> 2] = 1;
|
||||
}
|
||||
/* Return focus to canvas so keys keep working */
|
||||
document.getElementById('canvas').focus();
|
||||
});
|
||||
|
||||
document.getElementById('btn-load').addEventListener('click', function() {
|
||||
if (typeof _editor_load_flag_ptr === 'function') {
|
||||
HEAP32[_editor_load_flag_ptr() >> 2] = 1;
|
||||
}
|
||||
document.getElementById('canvas').focus();
|
||||
});
|
||||
|
||||
/* ── Level picker dropdown ──────────────────────── */
|
||||
var levelSelect = document.getElementById('level-select');
|
||||
|
||||
/* Populate the dropdown after the module is ready (FS available) */
|
||||
Module.postRun = Module.postRun || [];
|
||||
Module.postRun.push(function() {
|
||||
/* Scan for .lvl files in the virtual FS */
|
||||
var levels = [];
|
||||
try {
|
||||
var entries = FS.readdir('assets/levels');
|
||||
for (var i = 0; i < entries.length; i++) {
|
||||
if (entries[i].endsWith('.lvl') && entries[i][0] !== '_') {
|
||||
levels.push('assets/levels/' + entries[i]);
|
||||
}
|
||||
/* ── Editor-only features (button handlers, level picker) ── */
|
||||
if (editorEnabled) {
|
||||
document.getElementById('btn-save').addEventListener('click', function() {
|
||||
if (typeof _editor_save_flag_ptr === 'function') {
|
||||
HEAP32[_editor_save_flag_ptr() >> 2] = 1;
|
||||
}
|
||||
levels.sort();
|
||||
} catch(e) {
|
||||
console.error('Could not read levels dir:', e);
|
||||
/* Return focus to canvas so keys keep working */
|
||||
document.getElementById('canvas').focus();
|
||||
});
|
||||
|
||||
document.getElementById('btn-load').addEventListener('click', function() {
|
||||
if (typeof _editor_load_flag_ptr === 'function') {
|
||||
HEAP32[_editor_load_flag_ptr() >> 2] = 1;
|
||||
}
|
||||
document.getElementById('canvas').focus();
|
||||
});
|
||||
|
||||
/* ── Level picker dropdown ──────────────────────── */
|
||||
var levelSelect = document.getElementById('level-select');
|
||||
|
||||
/* Populate the dropdown after the module is ready (FS available) */
|
||||
Module.postRun = Module.postRun || [];
|
||||
Module.postRun.push(function() {
|
||||
/* Scan for .lvl files in the virtual FS */
|
||||
var levels = [];
|
||||
try {
|
||||
var entries = FS.readdir('assets/levels');
|
||||
for (var i = 0; i < entries.length; i++) {
|
||||
if (entries[i].endsWith('.lvl') && entries[i][0] !== '_') {
|
||||
levels.push('assets/levels/' + entries[i]);
|
||||
}
|
||||
}
|
||||
levels.sort();
|
||||
} catch(e) {
|
||||
console.error('Could not read levels dir:', e);
|
||||
}
|
||||
|
||||
for (var j = 0; j < levels.length; j++) {
|
||||
var opt = document.createElement('option');
|
||||
opt.value = levels[j];
|
||||
/* Show just the filename without path */
|
||||
opt.textContent = levels[j].replace('assets/levels/', '');
|
||||
levelSelect.appendChild(opt);
|
||||
}
|
||||
});
|
||||
|
||||
levelSelect.addEventListener('change', function() {
|
||||
var path = this.value;
|
||||
if (!path) return;
|
||||
|
||||
if (typeof _editor_load_vfs_file === 'function') {
|
||||
/* Pass the path string to C */
|
||||
var len = lengthBytesUTF8(path) + 1;
|
||||
var buf = _malloc(len);
|
||||
stringToUTF8(path, buf, len);
|
||||
_editor_load_vfs_file(buf);
|
||||
_free(buf);
|
||||
}
|
||||
|
||||
/* Reset dropdown to placeholder */
|
||||
this.selectedIndex = 0;
|
||||
document.getElementById('canvas').focus();
|
||||
});
|
||||
|
||||
/* Update title if in editor mode */
|
||||
if (window.location.search.indexOf('edit') !== -1) {
|
||||
document.title = 'Jump \'n Run - Level Editor';
|
||||
}
|
||||
|
||||
for (var j = 0; j < levels.length; j++) {
|
||||
var opt = document.createElement('option');
|
||||
opt.value = levels[j];
|
||||
/* Show just the filename without path */
|
||||
opt.textContent = levels[j].replace('assets/levels/', '');
|
||||
levelSelect.appendChild(opt);
|
||||
}
|
||||
});
|
||||
|
||||
levelSelect.addEventListener('change', function() {
|
||||
var path = this.value;
|
||||
if (!path) return;
|
||||
|
||||
if (typeof _editor_load_vfs_file === 'function') {
|
||||
/* Pass the path string to C */
|
||||
var len = lengthBytesUTF8(path) + 1;
|
||||
var buf = _malloc(len);
|
||||
stringToUTF8(path, buf, len);
|
||||
_editor_load_vfs_file(buf);
|
||||
_free(buf);
|
||||
}
|
||||
|
||||
/* Reset dropdown to placeholder */
|
||||
this.selectedIndex = 0;
|
||||
document.getElementById('canvas').focus();
|
||||
});
|
||||
|
||||
/* Update title if in editor mode */
|
||||
if (window.location.search.indexOf('edit') !== -1) {
|
||||
document.title = 'Jump \'n Run - Level Editor';
|
||||
}
|
||||
</script>
|
||||
{{{ SCRIPT }}}
|
||||
|
||||
Reference in New Issue
Block a user