From c8686f9d668f07322117866b8c151655cf6c086a Mon Sep 17 00:00:00 2001 From: "Eevee (Evelyn Woods)" Date: Fri, 1 Jan 2021 12:44:20 -0700 Subject: [PATCH] Copy a level's title to the right places in the editor so it shows in the level browser --- js/main-editor.js | 65 +++++++++++++++++++++++++++-------------------- js/main.js | 44 +++++++++++++++++++++++++++++--- js/tileset.js | 4 +++ 3 files changed, 81 insertions(+), 32 deletions(-) diff --git a/js/main-editor.js b/js/main-editor.js index 75997ad..350807d 100644 --- a/js/main-editor.js +++ b/js/main-editor.js @@ -162,6 +162,7 @@ class EditorLevelMetaOverlay extends DialogOverlay { let title = els.title.value; if (title !== stored_level.title) { stored_level.title = title; + this.conductor.stored_game.level_metadata[this.conductor.level_index].title = title; this.conductor.update_level_title(); } let author = els.author.value; @@ -2543,34 +2544,7 @@ export class Editor extends PrimaryView { new EditorLevelMetaOverlay(this.conductor, this.stored_level).open(); }); this.save_button = _make_button("Save", ev => { - // TODO need feedback. or maybe not bc this should be replaced with autosave later - // TODO also need to update the pack data's last modified time - let stored_game = this.conductor.stored_game; - if (! stored_game.editor_metadata) - return; - - // Update the pack index; we need to do this to update the last modified time anyway, so - // there's no point in checking whether anything actually changed - let pack_key = stored_game.editor_metadata.key; - this.stash.packs[pack_key].title = stored_game.title; - this.stash.packs[pack_key].last_modified = Date.now(); - - // Update the pack itself - // TODO maybe should keep this around, but there's a tricky order of operations thing - // with it - let pack_stash = load_json_from_storage(pack_key); - pack_stash.title = stored_game.title; - pack_stash.last_modified = Date.now(); - - // Serialize the level itself - let buf = c2g.synthesize_level(this.stored_level); - let stringy_buf = string_from_buffer_ascii(buf); - - // Save everything at once, level first, to minimize chances of an error getting things - // out of sync - window.localStorage.setItem(this.stored_level.editor_metadata.key, stringy_buf); - save_json_to_storage(pack_key, pack_stash); - save_json_to_storage("Lexy's Labyrinth editor", this.stash); + this.save_level(); }); if (this.stored_level) { this.save_button.disabled = ! this.conductor.stored_game.editor_metadata; @@ -2672,6 +2646,8 @@ export class Editor extends PrimaryView { this.renderer.draw(); } + // Level creation, management, and saving + _make_cell() { let cell = new format_base.StoredCell; cell.push({type: TILE_TYPES['floor']}); @@ -2820,6 +2796,39 @@ export class Editor extends PrimaryView { this.conductor.change_level(index); } + save_level() { + // TODO need feedback. or maybe not bc this should be replaced with autosave later + // TODO also need to update the pack data's last modified time + let stored_game = this.conductor.stored_game; + if (! stored_game.editor_metadata) + return; + + // Update the pack index; we need to do this to update the last modified time anyway, so + // there's no point in checking whether anything actually changed + let pack_key = stored_game.editor_metadata.key; + this.stash.packs[pack_key].title = stored_game.title; + this.stash.packs[pack_key].last_modified = Date.now(); + + // Update the pack itself + // TODO maybe should keep this around, but there's a tricky order of operations thing + // with it + let pack_stash = load_json_from_storage(pack_key); + pack_stash.title = stored_game.title; + pack_stash.last_modified = Date.now(); + pack_stash.levels[this.conductor.level_index].title = this.stored_level.title; + pack_stash.levels[this.conductor.level_index].last_modified = Date.now(); + + // Serialize the level itself + let buf = c2g.synthesize_level(this.stored_level); + let stringy_buf = string_from_buffer_ascii(buf); + + // Save everything at once, level first, to minimize chances of an error getting things + // out of sync + window.localStorage.setItem(this.stored_level.editor_metadata.key, stringy_buf); + save_json_to_storage(pack_key, pack_stash); + save_json_to_storage("Lexy's Labyrinth editor", this.stash); + } + load_game(stored_game) { } diff --git a/js/main.js b/js/main.js index 3c1ca9a..3c5119c 100644 --- a/js/main.js +++ b/js/main.js @@ -446,11 +446,37 @@ class Player extends PrimaryView { return; } + // Per-tic navigation; only useful if the game isn't running + // FIXME these are funky in turn-based mode still. don't update the debug panel timer, + // and don't show us at the end of the tic + if (ev.key === ',') { + if (this.state === 'stopped' || this.state === 'paused' || this.turn_mode > 0) { + this.undo(); + this._redraw(); + this.set_state('paused'); + } + return; + } + if (ev.key === '.') { + if (this.state === 'waiting' || this.state === 'paused' || this.turn_mode > 0) { + this.advance_by(1, true); + this._redraw(); + if (this.state === 'waiting' || this.turn_mode === 1) { + this.set_state('paused'); + } + } + return; + } + if (ev.key === ' ') { if (this.state === 'waiting') { // Start without moving this.set_state('playing'); } + else if (this.state === 'paused') { + // Turns out I do this an awful lot expecting it to work, so + this.set_state('playing'); + } else if (this.state === 'stopped') { if (this.level.state === 'success') { // Advance to the next level @@ -656,7 +682,7 @@ class Player extends PrimaryView { } this.set_state('paused'); - this.advance_by(dt); + this.advance_by(dt, true); } else if (dt < 0) { if (this.state === 'waiting') { @@ -1084,7 +1110,7 @@ class Player extends PrimaryView { return input; } - advance_by(tics) { + advance_by(tics, force = false) { for (let i = 0; i < tics; i++) { // FIXME turn-based mode should be disabled during a replay let input = this.get_input(); @@ -1107,7 +1133,7 @@ class Player extends PrimaryView { let has_input = wait || input; // Turn-based mode complicates this slightly; it aligns us to the middle of a tic if (this.turn_mode === 2) { - if (has_input) { + if (has_input || force) { // Finish the current tic, then continue as usual. This means the end of the // tic doesn't count against the number of tics to advance -- because it already // did, the first time we tried it @@ -1121,7 +1147,7 @@ class Player extends PrimaryView { // We should now be at the start of a tic this.level.begin_tic(input); - if (this.turn_mode > 0 && this.level.can_accept_input() && !input) { + if (this.turn_mode > 0 && this.level.can_accept_input() && ! has_input) { // If we're in turn-based mode and could provide input here, but don't have any, // then wait until we do this.turn_mode = 2; @@ -1207,6 +1233,10 @@ class Player extends PrimaryView { if (this.turn_mode === 2) { // We're dawdling between tics, so nothing is actually animating, but the clock hasn't // advanced yet; pretend whatever's currently animating has finished + // FIXME this creates bizarre side effects like actors making a huge first step when + // stepping forwards one tic at a time, but without it you get force floors animating + // and then abruptly reversing in turn-based mode (maybe we should just not interpolate + // at all in that case??) tic_offset = 0.999; } else if (this.use_interpolation) { @@ -1224,6 +1254,7 @@ class Player extends PrimaryView { // Check for a stopped game *after* drawing, so that if the game ends, we still draw its // final result before stopping the draw loop // TODO for bonus points, also finish the player animation (but don't advance the game any further) + // TODO stop redrawing when in turn-based mode 2? if (this.state === 'playing' || this.state === 'rewinding') { this._redraw_handle = requestAnimationFrame(this._redraw_bound); } @@ -1334,6 +1365,11 @@ class Player extends PrimaryView { } autopause() { + if (this.turn_mode > 0) { + // Turn-based mode doesn't need this + return; + } + this.set_state('paused'); } diff --git a/js/tileset.js b/js/tileset.js index 83d0634..9c2c22f 100644 --- a/js/tileset.js +++ b/js/tileset.js @@ -1306,6 +1306,10 @@ export class Tileset { } coords = coords[Math.floor(i * coords.length)]; } + else if (tile && tile.type.movement_speed) { + // This is an actor that's not moving, so use the first frame + coords = coords[0]; + } else { // This tile animates on a global timer, one cycle every quarter of a second coords = coords[Math.floor(tic / this.animation_slowdown % 5 / 5 * coords.length)];