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:
@@ -203,8 +203,8 @@ Current directives: `TILESET`, `SIZE`, `SPAWN`, `GRAVITY`, `WIND`, `BG_COLOR`, `
|
|||||||
| Action | Key | Status |
|
| Action | Key | Status |
|
||||||
|-----------|--------------|---------------|
|
|-----------|--------------|---------------|
|
||||||
| Move | Arrow keys | Implemented |
|
| Move | Arrow keys | Implemented |
|
||||||
| Jump | Z | Implemented |
|
| Jump | Z / Space | Implemented |
|
||||||
| Shoot | X / Space | Implemented |
|
| Shoot | X | Implemented |
|
||||||
| Aim up | UP (+ shoot) | Implemented |
|
| Aim up | UP (+ shoot) | Implemented |
|
||||||
| Aim diag | UP+LEFT/RIGHT (+ shoot) | Implemented |
|
| Aim diag | UP+LEFT/RIGHT (+ shoot) | Implemented |
|
||||||
| Dash | C | Implemented |
|
| Dash | C | Implemented |
|
||||||
|
|||||||
8
Makefile
8
Makefile
@@ -80,7 +80,13 @@ OBJ_ALL := $(SRC_ALL:src/%.c=$(OBJ_DIR)/%.o)
|
|||||||
|
|
||||||
all: $(BIN)
|
all: $(BIN)
|
||||||
|
|
||||||
$(BIN): $(OBJ_ALL) | outdirs
|
# On WASM builds the shell template is baked into the output HTML,
|
||||||
|
# so re-link whenever it changes.
|
||||||
|
ifdef WASM
|
||||||
|
EXTRA_LINK_DEPS := web/shell.html
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(BIN): $(OBJ_ALL) $(EXTRA_LINK_DEPS) | outdirs
|
||||||
$(CC) $(OBJ_ALL) -o $@ $(LDFLAGS)
|
$(CC) $(OBJ_ALL) -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
outdirs:
|
outdirs:
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ static SDL_Scancode s_bindings[ACTION_COUNT] = {
|
|||||||
|
|
||||||
/* Alternate bindings (0 = no alternate) */
|
/* Alternate bindings (0 = no alternate) */
|
||||||
static SDL_Scancode s_alt_bindings[ACTION_COUNT] = {
|
static SDL_Scancode s_alt_bindings[ACTION_COUNT] = {
|
||||||
[ACTION_SHOOT] = SDL_SCANCODE_SPACE,
|
[ACTION_JUMP] = SDL_SCANCODE_SPACE,
|
||||||
};
|
};
|
||||||
|
|
||||||
void input_init(void) {
|
void input_init(void) {
|
||||||
|
|||||||
178
web/shell.html
178
web/shell.html
@@ -60,6 +60,17 @@
|
|||||||
max-width: 1300px;
|
max-width: 1300px;
|
||||||
}
|
}
|
||||||
#hint { color: #666; }
|
#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 {
|
.ctrl-btn {
|
||||||
color: #4ecdc4;
|
color: #4ecdc4;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@@ -100,7 +111,7 @@
|
|||||||
<canvas class="emscripten" id="canvas" tabindex="1"
|
<canvas class="emscripten" id="canvas" tabindex="1"
|
||||||
width="640" height="360"></canvas>
|
width="640" height="360"></canvas>
|
||||||
</div>
|
</div>
|
||||||
<div id="controls">
|
<div id="controls" class="hidden">
|
||||||
<a class="ctrl-btn" id="editor-link" href="?edit">Editor</a>
|
<a class="ctrl-btn" id="editor-link" href="?edit">Editor</a>
|
||||||
<span class="ctrl-sep">|</span>
|
<span class="ctrl-sep">|</span>
|
||||||
<button class="ctrl-btn" id="btn-save" title="Save level (download .lvl)">Save</button>
|
<button class="ctrl-btn" id="btn-save" title="Save level (download .lvl)">Save</button>
|
||||||
@@ -112,10 +123,33 @@
|
|||||||
<span class="ctrl-sep">|</span>
|
<span class="ctrl-sep">|</span>
|
||||||
<span id="hint">E=editor P=test play 1-6=tools</span>
|
<span id="hint">E=editor P=test play 1-6=tools</span>
|
||||||
</div>
|
</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="status">Loading...</div>
|
||||||
<div id="progress-bar"><div id="progress-bar-inner"></div></div>
|
<div id="progress-bar"><div id="progress-bar-inner"></div></div>
|
||||||
|
|
||||||
<script>
|
<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 statusEl = document.getElementById('status');
|
||||||
var progressEl = document.getElementById('progress-bar');
|
var progressEl = document.getElementById('progress-bar');
|
||||||
var progressIn = document.getElementById('progress-bar-inner');
|
var progressIn = document.getElementById('progress-bar-inner');
|
||||||
@@ -155,16 +189,22 @@
|
|||||||
Module.setStatus('Error - check the browser console');
|
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) {
|
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.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (typeof _editor_save_flag_ptr === 'function') {
|
if (typeof _editor_save_flag_ptr === 'function') {
|
||||||
HEAP32[_editor_save_flag_ptr() >> 2] = 1;
|
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.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (typeof _editor_load_flag_ptr === 'function') {
|
if (typeof _editor_load_flag_ptr === 'function') {
|
||||||
@@ -173,72 +213,74 @@
|
|||||||
}
|
}
|
||||||
}, true); /* useCapture=true to intercept before SDL */
|
}, true); /* useCapture=true to intercept before SDL */
|
||||||
|
|
||||||
/* ── Button handlers ────────────────────────────── */
|
/* ── Editor-only features (button handlers, level picker) ── */
|
||||||
document.getElementById('btn-save').addEventListener('click', function() {
|
if (editorEnabled) {
|
||||||
if (typeof _editor_save_flag_ptr === 'function') {
|
document.getElementById('btn-save').addEventListener('click', function() {
|
||||||
HEAP32[_editor_save_flag_ptr() >> 2] = 1;
|
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]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
levels.sort();
|
/* Return focus to canvas so keys keep working */
|
||||||
} catch(e) {
|
document.getElementById('canvas').focus();
|
||||||
console.error('Could not read levels dir:', e);
|
});
|
||||||
|
|
||||||
|
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>
|
||||||
{{{ SCRIPT }}}
|
{{{ SCRIPT }}}
|
||||||
|
|||||||
Reference in New Issue
Block a user