Remember last opened level in editor; prevent deleting the current level

This commit is contained in:
Eevee (Evelyn Woods) 2021-01-16 02:50:52 -07:00
parent ac9b702eaa
commit b9037c1ce1
3 changed files with 51 additions and 37 deletions

View File

@ -183,22 +183,31 @@ export class DialogOverlay extends Overlay {
} }
} }
// Informational popup dialog
export class AlertOverlay extends DialogOverlay {
constructor(conductor, message, title = "heads up") {
super(conductor);
this.set_title(title);
this.main.append(mk('p', {}, message));
this.add_button("a'ight", ev => {
this.close();
});
}
}
// Yes/no popup dialog // Yes/no popup dialog
export class ConfirmOverlay extends DialogOverlay { export class ConfirmOverlay extends DialogOverlay {
constructor(conductor, message, what) { constructor(conductor, message, what) {
super(conductor); super(conductor);
this.set_title("just checking"); this.set_title("just checking");
this.main.append(mk('p', {}, message)); this.main.append(mk('p', {}, message));
let yes = mk('button', {type: 'button'}, "yep"); this.add_button("yep", ev => {
let no = mk('button', {type: 'button'}, "nope");
yes.addEventListener('click', ev => {
this.close(); this.close();
what(); what();
}); });
no.addEventListener('click', ev => { this.add_button("nope", ev => {
this.close(); this.close();
}); });
this.footer.append(yes, no);
} }
} }

View File

@ -4,7 +4,7 @@ import { DIRECTIONS, LAYERS, TICS_PER_SECOND } from './defs.js';
import { TILES_WITH_PROPS } from './editor-tile-overlays.js'; import { TILES_WITH_PROPS } from './editor-tile-overlays.js';
import * as format_base from './format-base.js'; import * as format_base from './format-base.js';
import * as c2g from './format-c2g.js'; import * as c2g from './format-c2g.js';
import { PrimaryView, TransientOverlay, DialogOverlay, flash_button, load_json_from_storage, save_json_to_storage } from './main-base.js'; import { PrimaryView, TransientOverlay, DialogOverlay, AlertOverlay, flash_button, load_json_from_storage, save_json_to_storage } from './main-base.js';
import CanvasRenderer from './renderer-canvas.js'; import CanvasRenderer from './renderer-canvas.js';
import TILE_TYPES from './tiletypes.js'; import TILE_TYPES from './tiletypes.js';
import { SVG_NS, mk, mk_button, mk_svg, string_from_buffer_ascii, bytestring_to_buffer, walk_grid } from './util.js'; import { SVG_NS, mk, mk_button, mk_svg, string_from_buffer_ascii, bytestring_to_buffer, walk_grid } from './util.js';
@ -285,7 +285,7 @@ class EditorLevelBrowserOverlay extends DialogOverlay {
this.add_button("create", ev => { this.add_button("create", ev => {
let index = this.selection + 1; let index = this.selection + 1;
let stored_level = this.conductor.editor._make_empty_level(index + 1, 32, 32); let stored_level = this.conductor.editor._make_empty_level(index + 1, 32, 32);
this.conductor.editor.insert_level(stored_level, index); this.conductor.editor.move_level(stored_level, index);
this._after_insert_level(stored_level, index); this._after_insert_level(stored_level, index);
this.undo_stack.push(() => { this.undo_stack.push(() => {
@ -303,10 +303,10 @@ class EditorLevelBrowserOverlay extends DialogOverlay {
}); });
this.undo_button.disabled = false; this.undo_button.disabled = false;
}); });
this.add_button("delete", ev => { this.delete_button = this.add_button("delete", ev => {
let index = this.selection; let index = this.selection;
if (index === this.conductor.level_index) { if (index === this.conductor.level_index) {
// FIXME complain, or disable button new AlertOverlay(this.conductor, "You can't delete the level you have open.").open();
return; return;
} }
@ -320,7 +320,7 @@ class EditorLevelBrowserOverlay extends DialogOverlay {
this.undo_stack.push(() => { this.undo_stack.push(() => {
let stored_level = meta.stored_level ?? c2g.parse_level( let stored_level = meta.stored_level ?? c2g.parse_level(
bytestring_to_buffer(serialized_level), index + 1); bytestring_to_buffer(serialized_level), index + 1);
this.conductor.editor.insert_level(stored_level, index); this.conductor.editor.move_level(stored_level, index);
if (this.selection >= index) { if (this.selection >= index) {
this.selection += 1; this.selection += 1;
} }
@ -328,6 +328,7 @@ class EditorLevelBrowserOverlay extends DialogOverlay {
}); });
this.undo_button.disabled = false; this.undo_button.disabled = false;
}); });
this._update_delete_button();
// Right buttons // Right buttons
this.add_button_gap(); this.add_button_gap();
@ -381,6 +382,11 @@ class EditorLevelBrowserOverlay extends DialogOverlay {
this.list.childNodes[this.selection].classList.remove('--selected'); this.list.childNodes[this.selection].classList.remove('--selected');
this.selection = index; this.selection = index;
this.list.childNodes[this.selection].classList.add('--selected'); this.list.childNodes[this.selection].classList.add('--selected');
this._update_delete_button();
}
_update_delete_button() {
this.delete_button.disabled = !! (this.selection === this.conductor.level_index);
} }
schedule_level_render() { schedule_level_render() {
@ -421,7 +427,7 @@ class EditorLevelBrowserOverlay extends DialogOverlay {
_delete_level(index) { _delete_level(index) {
let num_levels = this.conductor.stored_game.level_metadata.length; let num_levels = this.conductor.stored_game.level_metadata.length;
let stored_level = this.conductor.editor.delete_level(index); let stored_level = this.conductor.editor.move_level(index, null);
this.list.childNodes[this.selection].classList.remove('--selected'); this.list.childNodes[this.selection].classList.remove('--selected');
this.list.childNodes[index].remove(); this.list.childNodes[index].remove();
@ -457,6 +463,7 @@ class EditorLevelBrowserOverlay extends DialogOverlay {
else { else {
this.selection = selection; this.selection = selection;
} }
this._update_delete_button();
} }
} }
@ -2983,7 +2990,7 @@ export class Editor extends PrimaryView {
return stored_level; return stored_level;
} }
_save_pack_to_stash(stored_pack, current_level) { _save_pack_to_stash(stored_pack) {
if (! stored_pack.editor_metadata) { if (! stored_pack.editor_metadata) {
console.error("Asked to save a stored pack that's not part of the editor", stored_pack); console.error("Asked to save a stored pack that's not part of the editor", stored_pack);
return; return;
@ -2997,9 +3004,7 @@ export class Editor extends PrimaryView {
this.stash.packs[pack_key] = { this.stash.packs[pack_key] = {
title: stored_pack.title, title: stored_pack.title,
level_count: stored_pack.level_metadata.length, level_count: stored_pack.level_metadata.length,
// FIXME i want to update current_level on browse but don't want to affect last_modified
last_modified: Date.now(), last_modified: Date.now(),
current_level: current_level,
}; };
save_json_to_storage("Lexy's Labyrinth editor", this.stash); save_json_to_storage("Lexy's Labyrinth editor", this.stash);
} }
@ -3052,7 +3057,7 @@ export class Editor extends PrimaryView {
}); });
this.conductor.load_game(stored_pack); this.conductor.load_game(stored_pack);
this._save_pack_to_stash(stored_pack, 0); this._save_pack_to_stash(stored_pack);
save_json_to_storage(pack_key, { save_json_to_storage(pack_key, {
levels: [{ levels: [{
@ -3060,6 +3065,7 @@ export class Editor extends PrimaryView {
title: stored_level.title, title: stored_level.title,
last_modified: Date.now(), last_modified: Date.now(),
}], }],
current_level_index: 0,
}); });
this._save_level_to_storage(stored_level); this._save_level_to_storage(stored_level);
@ -3092,7 +3098,7 @@ export class Editor extends PrimaryView {
number: i + 1, number: i + 1,
}); });
} }
this.conductor.load_game(stored_pack); this.conductor.load_game(stored_pack, null, pack_stash.current_level_index);
this.conductor.switch_to_editor(); this.conductor.switch_to_editor();
} }
@ -3101,7 +3107,7 @@ export class Editor extends PrimaryView {
// source is a number, it's an index; otherwise, it's a level, assumed to be newly-created, and // source is a number, it's an index; otherwise, it's a level, assumed to be newly-created, and
// will be given a new key and saved to localStorage. (Passing null and a level will, // will be given a new key and saved to localStorage. (Passing null and a level will,
// of course, do nothing. Passing an out of bounds source index will also do nothing.) // of course, do nothing. Passing an out of bounds source index will also do nothing.)
_move_level(source, dest_index) { move_level(source, dest_index) {
let stored_pack = this.conductor.stored_game; let stored_pack = this.conductor.stored_game;
if (! stored_pack.editor_metadata) { if (! stored_pack.editor_metadata) {
return; return;
@ -3171,8 +3177,6 @@ export class Editor extends PrimaryView {
stored_pack.level_metadata.splice(dest_index, 0, level_metadata); stored_pack.level_metadata.splice(dest_index, 0, level_metadata);
pack_stash.levels.splice(dest_index, 0, pack_stash_entry); pack_stash.levels.splice(dest_index, 0, pack_stash_entry);
} }
// This is done with now; the pack stash has no numbering
save_json_to_storage(stored_pack.editor_metadata.key, pack_stash);
// Renumber levels as necessary // Renumber levels as necessary
let delta, start_index, end_index; let delta, start_index, end_index;
@ -3216,7 +3220,10 @@ export class Editor extends PrimaryView {
// FIXME refuse to delete the current level // FIXME refuse to delete the current level
this.conductor.level_index = dest_index; this.conductor.level_index = dest_index;
} }
else if (start_index <= this.conductor.level_index && this.conductor.level_index <= end_index) { else if (
this.conductor.level_index === dest_index ||
(start_index <= this.conductor.level_index && this.conductor.level_index <= end_index))
{
this.conductor.level_index += delta; this.conductor.level_index += delta;
// Update the current level if it's not stored in the metadata yet // Update the current level if it's not stored in the metadata yet
if (! stored_level) { if (! stored_level) {
@ -3229,20 +3236,14 @@ export class Editor extends PrimaryView {
this.conductor.update_level_title(); this.conductor.update_level_title();
this.conductor.update_nav_buttons(); this.conductor.update_nav_buttons();
// Save the pack to the editor stash, and we should be done! // Save the pack stash and editor stash, and we should be done!
this._save_pack_to_stash(stored_pack, this.conductor.level_index); pack_stash.current_level_index = this.conductor.level_index;
save_json_to_storage(stored_pack.editor_metadata.key, pack_stash);
this._save_pack_to_stash(stored_pack);
return stored_level; return stored_level;
} }
insert_level(stored_level, index) {
return this._move_level(stored_level, index);
}
move_level(from_index, to_index) {
return this._move_level(from_index, to_index);
}
duplicate_level(index) { duplicate_level(index) {
// The most reliable way to clone a level is to reserialize its current state // The most reliable way to clone a level is to reserialize its current state
// TODO with autosave this shouldn't be necessary, just copy the existing serialization // TODO with autosave this shouldn't be necessary, just copy the existing serialization
@ -3250,10 +3251,6 @@ export class Editor extends PrimaryView {
return this._move_level(stored_level, index + 1); return this._move_level(stored_level, index + 1);
} }
delete_level(index) {
return this._move_level(index, null);
}
save_level() { save_level() {
// TODO need feedback. or maybe not bc this should be replaced with autosave later // 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 // TODO also need to update the pack data's last modified time
@ -3275,7 +3272,7 @@ export class Editor extends PrimaryView {
// out of sync // out of sync
this._save_level_to_storage(this.stored_level); this._save_level_to_storage(this.stored_level);
save_json_to_storage(pack_key, pack_stash); save_json_to_storage(pack_key, pack_stash);
this._save_pack_to_stash(stored_pack, this.conductor.level_index); this._save_pack_to_stash(stored_pack);
} }
// Level loading // Level loading
@ -3289,6 +3286,14 @@ export class Editor extends PrimaryView {
this.update_viewport_size(); this.update_viewport_size();
this.update_cell_coordinates(); this.update_cell_coordinates();
// Remember current level for an editor level
if (this.conductor.stored_game.editor_metadata) {
let pack_key = this.conductor.stored_game.editor_metadata.key;
let pack_stash = load_json_from_storage(pack_key);
pack_stash.current_level_index = this.conductor.level_index;
save_json_to_storage(pack_key, pack_stash);
}
// Load connections // Load connections
this.connections_g.textContent = ''; this.connections_g.textContent = '';
for (let [src, dest] of Object.entries(this.stored_level.custom_trap_wiring)) { for (let [src, dest] of Object.entries(this.stored_level.custom_trap_wiring)) {

View File

@ -3668,7 +3668,7 @@ class Conductor {
return this.tilesets['ll']; return this.tilesets['ll'];
} }
load_game(stored_game, identifier = null) { load_game(stored_game, identifier = null, level_index = null) {
this.stored_game = stored_game; this.stored_game = stored_game;
this._pack_test_dialog = null; this._pack_test_dialog = null;
@ -3742,7 +3742,7 @@ class Conductor {
this.player.load_game(stored_game); this.player.load_game(stored_game);
this.editor.load_game(stored_game); this.editor.load_game(stored_game);
return this.change_level((this.current_pack_savefile.current_level ?? 1) - 1); return this.change_level(level_index ?? (this.current_pack_savefile.current_level ?? 1) - 1);
} }
change_level(level_index) { change_level(level_index) {