diff --git a/desktop_version/lang/ar/strings.xml b/desktop_version/lang/ar/strings.xml index e2dd70db..8fe6db86 100644 --- a/desktop_version/lang/ar/strings.xml +++ b/desktop_version/lang/ar/strings.xml @@ -646,6 +646,8 @@ + + diff --git a/desktop_version/lang/ca/strings.xml b/desktop_version/lang/ca/strings.xml index 29d89131..a0790dd8 100644 --- a/desktop_version/lang/ca/strings.xml +++ b/desktop_version/lang/ca/strings.xml @@ -638,6 +638,8 @@ + + diff --git a/desktop_version/lang/cy/strings.xml b/desktop_version/lang/cy/strings.xml index d9aa1816..9358b24f 100644 --- a/desktop_version/lang/cy/strings.xml +++ b/desktop_version/lang/cy/strings.xml @@ -638,6 +638,8 @@ + + diff --git a/desktop_version/lang/de/strings.xml b/desktop_version/lang/de/strings.xml index 979aaad6..c7551a80 100644 --- a/desktop_version/lang/de/strings.xml +++ b/desktop_version/lang/de/strings.xml @@ -638,6 +638,8 @@ + + diff --git a/desktop_version/lang/en/strings.xml b/desktop_version/lang/en/strings.xml index 45154fc9..dfe9ec99 100644 --- a/desktop_version/lang/en/strings.xml +++ b/desktop_version/lang/en/strings.xml @@ -638,6 +638,8 @@ + + diff --git a/desktop_version/lang/eo/strings.xml b/desktop_version/lang/eo/strings.xml index 735fe1e7..243bcf41 100644 --- a/desktop_version/lang/eo/strings.xml +++ b/desktop_version/lang/eo/strings.xml @@ -638,6 +638,8 @@ + + diff --git a/desktop_version/lang/es/strings.xml b/desktop_version/lang/es/strings.xml index 4ad7b06c..236aa161 100644 --- a/desktop_version/lang/es/strings.xml +++ b/desktop_version/lang/es/strings.xml @@ -638,6 +638,8 @@ + + diff --git a/desktop_version/lang/es_419/strings.xml b/desktop_version/lang/es_419/strings.xml index 5c316b44..cf7adbf1 100644 --- a/desktop_version/lang/es_419/strings.xml +++ b/desktop_version/lang/es_419/strings.xml @@ -638,6 +638,8 @@ + + diff --git a/desktop_version/lang/es_AR/strings.xml b/desktop_version/lang/es_AR/strings.xml index 66d225b2..17ba4288 100644 --- a/desktop_version/lang/es_AR/strings.xml +++ b/desktop_version/lang/es_AR/strings.xml @@ -638,6 +638,8 @@ + + diff --git a/desktop_version/lang/fa/strings.xml b/desktop_version/lang/fa/strings.xml index d81835a8..774c8c4a 100644 --- a/desktop_version/lang/fa/strings.xml +++ b/desktop_version/lang/fa/strings.xml @@ -638,6 +638,8 @@ + + diff --git a/desktop_version/lang/fr/strings.xml b/desktop_version/lang/fr/strings.xml index 8cfd849f..08c95560 100644 --- a/desktop_version/lang/fr/strings.xml +++ b/desktop_version/lang/fr/strings.xml @@ -638,6 +638,8 @@ + + diff --git a/desktop_version/lang/ga/strings.xml b/desktop_version/lang/ga/strings.xml index 625d9d6e..03111d7c 100644 --- a/desktop_version/lang/ga/strings.xml +++ b/desktop_version/lang/ga/strings.xml @@ -640,6 +640,8 @@ Déan cóip chúltaca, ar eagla na heagla." explanation="translation maintenance + + diff --git a/desktop_version/lang/it/strings.xml b/desktop_version/lang/it/strings.xml index 5075f520..c419afc9 100644 --- a/desktop_version/lang/it/strings.xml +++ b/desktop_version/lang/it/strings.xml @@ -638,6 +638,8 @@ + + diff --git a/desktop_version/lang/ja/strings.xml b/desktop_version/lang/ja/strings.xml index 166d1b58..1d1b5619 100644 --- a/desktop_version/lang/ja/strings.xml +++ b/desktop_version/lang/ja/strings.xml @@ -674,6 +674,8 @@ Steam Deckには対応していません。" explanation="" max="38*5" max_local + + diff --git a/desktop_version/lang/ko/strings.xml b/desktop_version/lang/ko/strings.xml index 9d47d4ec..ba273561 100755 --- a/desktop_version/lang/ko/strings.xml +++ b/desktop_version/lang/ko/strings.xml @@ -638,6 +638,8 @@ + + diff --git a/desktop_version/lang/nl/strings.xml b/desktop_version/lang/nl/strings.xml index 4dd6a972..abe333d4 100644 --- a/desktop_version/lang/nl/strings.xml +++ b/desktop_version/lang/nl/strings.xml @@ -638,6 +638,8 @@ + + diff --git a/desktop_version/lang/pl/strings.xml b/desktop_version/lang/pl/strings.xml index c0c44798..cebd78cd 100644 --- a/desktop_version/lang/pl/strings.xml +++ b/desktop_version/lang/pl/strings.xml @@ -638,6 +638,8 @@ + + diff --git a/desktop_version/lang/pt_BR/strings.xml b/desktop_version/lang/pt_BR/strings.xml index 1a01283f..82d2c96d 100644 --- a/desktop_version/lang/pt_BR/strings.xml +++ b/desktop_version/lang/pt_BR/strings.xml @@ -638,6 +638,8 @@ + + diff --git a/desktop_version/lang/pt_PT/strings.xml b/desktop_version/lang/pt_PT/strings.xml index 3d009543..c5ac85bb 100644 --- a/desktop_version/lang/pt_PT/strings.xml +++ b/desktop_version/lang/pt_PT/strings.xml @@ -638,6 +638,8 @@ + + diff --git a/desktop_version/lang/ru/strings.xml b/desktop_version/lang/ru/strings.xml index d412935e..da8b121c 100644 --- a/desktop_version/lang/ru/strings.xml +++ b/desktop_version/lang/ru/strings.xml @@ -663,6 +663,8 @@ + + diff --git a/desktop_version/lang/szl/strings.xml b/desktop_version/lang/szl/strings.xml index df9585b3..c67da027 100644 --- a/desktop_version/lang/szl/strings.xml +++ b/desktop_version/lang/szl/strings.xml @@ -638,6 +638,8 @@ + + diff --git a/desktop_version/lang/tr/strings.xml b/desktop_version/lang/tr/strings.xml index 5a8817f5..8a7e5142 100644 --- a/desktop_version/lang/tr/strings.xml +++ b/desktop_version/lang/tr/strings.xml @@ -638,6 +638,8 @@ + + diff --git a/desktop_version/lang/uk/strings.xml b/desktop_version/lang/uk/strings.xml index 75ec7058..046d4e8e 100644 --- a/desktop_version/lang/uk/strings.xml +++ b/desktop_version/lang/uk/strings.xml @@ -638,6 +638,8 @@ + + diff --git a/desktop_version/lang/zh/strings.xml b/desktop_version/lang/zh/strings.xml index 1487c97c..1ebf7b84 100644 --- a/desktop_version/lang/zh/strings.xml +++ b/desktop_version/lang/zh/strings.xml @@ -648,6 +648,8 @@ + + diff --git a/desktop_version/lang/zh_TW/strings.xml b/desktop_version/lang/zh_TW/strings.xml index cb176772..68a79880 100644 --- a/desktop_version/lang/zh_TW/strings.xml +++ b/desktop_version/lang/zh_TW/strings.xml @@ -648,6 +648,8 @@ + + diff --git a/desktop_version/src/Editor.cpp b/desktop_version/src/Editor.cpp index 4ee808f6..1115a71e 100644 --- a/desktop_version/src/Editor.cpp +++ b/desktop_version/src/Editor.cpp @@ -412,6 +412,11 @@ void editorclass::reset(void) state = EditorState_DRAW; substate = EditorSubState_MAIN; + + undo_buffer.clear(); + redo_buffer.clear(); + + placing_tiles = false; } void editorclass::show_note(const char* text) @@ -2262,11 +2267,29 @@ void editorclass::add_entity(int rx, int ry, int xp, int yp, int tp, int p1, int entity.p6 = p6; entity.scriptname = ""; + EditorUndoInfo info; + info.room_x = rx; + info.room_y = ry; + info.type = EditorUndoType_ENTITY_ADDED; + info.entity = entity; + info.entity_id = customentities.size(); + undo_buffer.push_back(info); + redo_buffer.clear(); + customentities.push_back(entity); } void editorclass::remove_entity(int t) { + EditorUndoInfo info; + info.room_x = levx; + info.room_y = levy; + info.type = EditorUndoType_ENTITY_REMOVED; + info.entity_id = t; + info.entity = customentities[t]; + undo_buffer.push_back(info); + redo_buffer.clear(); + customentities.erase(customentities.begin() + t); } @@ -2284,6 +2307,86 @@ int editorclass::get_entity_at(int rx, int ry, int xp, int yp) return -1; } +static void update_old_tiles() +{ + extern editorclass ed; + for (int i = 0; i < SCREEN_WIDTH_TILES * SCREEN_HEIGHT_TILES; i++) + { + ed.old_tiles[i] = ed.get_tile(i % SCREEN_WIDTH_TILES, i / SCREEN_WIDTH_TILES); + } +} + +static void commit_entity(int id) +{ + // We're gonna modify an entity, so save the old version + extern editorclass ed; + + EditorUndoInfo info; + + info.room_x = ed.levx; + info.room_y = ed.levy; + info.type = EditorUndoType_ENTITY_MODIFIED; + info.entity_id = id; + info.entity = customentities[id]; + ed.undo_buffer.push_back(info); + ed.redo_buffer.clear(); +} + +static void commit_tiles() +{ + // We either let go of the mouse button, or we switched rooms, so we need to commit the tiles to the undo buffer + extern editorclass ed; + + EditorUndoInfo info; + + info.room_x = ed.levx; + info.room_y = ed.levy; + info.type = EditorUndoType_TILES; + SDL_memcpy(info.tiles, ed.old_tiles, sizeof(ed.old_tiles)); + + ed.undo_buffer.push_back(info); + ed.redo_buffer.clear(); +} + +static void commit_roomdata_change() +{ + extern editorclass ed; + + EditorUndoInfo info; + + info.room_x = ed.levx; + info.room_y = ed.levy; + info.type = EditorUndoType_ROOMDATA; + info.room_data = *cl.getroomprop(ed.levx, ed.levy); + + ed.undo_buffer.push_back(info); + ed.redo_buffer.clear(); +} + +static void commit_roomdata_tiles_change() +{ + extern editorclass ed; + + EditorUndoInfo info; + + info.room_x = ed.levx; + info.room_y = ed.levy; + info.type = EditorUndoType_ROOMDATA_TILES; + update_old_tiles(); + SDL_memcpy(info.tiles, ed.old_tiles, sizeof(ed.old_tiles)); + info.room_data = *cl.getroomprop(ed.levx, ed.levy); + + ed.undo_buffer.push_back(info); + ed.redo_buffer.clear(); +} + +static void uncommit() +{ + extern editorclass ed; + + ed.undo_buffer.pop_back(); +} + static void set_tile_interpolated(const int x1, const int x2, const int y1, const int y2, const int tile) { extern editorclass ed; @@ -2418,9 +2521,19 @@ void editorclass::tool_remove() { case EditorTool_WALLS: case EditorTool_BACKING: + if (!placing_tiles) + { + placing_tiles = true; + update_old_tiles(); + } handle_tile_placement(0); break; case EditorTool_SPIKES: + if (!placing_tiles) + { + placing_tiles = true; + update_old_tiles(); + } set_tile_interpolated(old_tilex, tilex, old_tiley, tiley, 0); break; default: @@ -2448,11 +2561,13 @@ void editorclass::entity_clicked(const int index) { case 1: // Enemies + commit_entity(index); entity->p1 = (entity->p1 + 1) % 4; break; case 2: { // Moving Platforms and Conveyors + commit_entity(index); const bool conveyor = entity->p1 >= 5; entity->p1++; if (conveyor) @@ -2468,6 +2583,7 @@ void editorclass::entity_clicked(const int index) case 10: // Checkpoints // If it's not textured as a checkpoint, then just leave it be + commit_entity(index); if (entity->p1 == 0 || entity->p1 == 1) { entity->p1 = (entity->p1 + 1) % 2; @@ -2476,27 +2592,34 @@ void editorclass::entity_clicked(const int index) case 11: case 16: // Gravity Lines, Start Point + commit_entity(index); entity->p1 = (entity->p1 + 1) % 2; break; case 15: // Crewmates + commit_entity(index); entity->p1 = (entity->p1 + 1) % 6; break; case 17: // Roomtext + commit_entity(index); get_input_line(TEXT_ROOMTEXT, "Enter roomtext:", &entity->scriptname); text_entity = index; break; case 18: // Terminals + commit_entity(index); if (entity->p1 == 0 || entity->p1 == 1) { // Flip the terminal, but if it's not textured as a terminal leave it alone entity->p1 = (entity->p1 + 1) % 2; } - SDL_FALLTHROUGH; + get_input_line(TEXT_SCRIPT, "Enter script name:", &entity->scriptname); + text_entity = index; + break; case 19: // Script Boxes (and terminals) + commit_entity(index); get_input_line(TEXT_SCRIPT, "Enter script name:", &entity->scriptname); text_entity = index; break; @@ -2519,6 +2642,12 @@ void editorclass::tool_place() { int tile = 0; + if (!placing_tiles) + { + placing_tiles = true; + update_old_tiles(); + } + if (cl.getroomprop(levx, levy)->directmode >= 1) { tile = direct_mode_tile; @@ -2536,6 +2665,12 @@ void editorclass::tool_place() break; } case EditorTool_SPIKES: + if (!placing_tiles) + { + placing_tiles = true; + update_old_tiles(); + } + set_tile_interpolated(old_tilex, tilex, old_tiley, tiley, 8); break; case EditorTool_TRINKETS: @@ -2636,17 +2771,22 @@ void editorclass::tool_place() } break; case EditorTool_START_POINT: - //If there is another start point, destroy it + lclickdelay = 1; + //If there is another start point, move it instead for (size_t i = 0; i < customentities.size(); i++) { if (customentities[i].t == 16) { - remove_entity(i); - i--; + commit_entity(i); + customentities[i].rx = levx; + customentities[i].ry = levy; + customentities[i].x = tilex; + customentities[i].y = tiley; + customentities[i].p1 = 0; + return; } } add_entity(levx, levy, tilex, tiley, 16, 0); - lclickdelay = 1; break; default: break; @@ -2999,21 +3139,25 @@ static void handle_draw_input() { if (key.keymap[SDLK_F1]) { + commit_roomdata_tiles_change(); ed.switch_tileset(shift_down); ed.keydelay = 6; } if (key.keymap[SDLK_F2]) { + commit_roomdata_tiles_change(); ed.switch_tilecol(shift_down); ed.keydelay = 6; } if (key.keymap[SDLK_F3]) { + commit_roomdata_change(); ed.switch_enemy(shift_down); ed.keydelay = 6; } if (key.keymap[SDLK_F4]) { + commit_roomdata_change(); ed.keydelay = 6; ed.substate = EditorSubState_DRAW_BOX; ed.box_corner = BoxCorner_FIRST; @@ -3021,6 +3165,7 @@ static void handle_draw_input() } if (key.keymap[SDLK_F5]) { + commit_roomdata_change(); ed.keydelay = 6; ed.substate = EditorSubState_DRAW_BOX; ed.box_corner = BoxCorner_FIRST; @@ -3028,6 +3173,7 @@ static void handle_draw_input() } if (key.keymap[SDLK_F10]) { + commit_roomdata_tiles_change(); if (cl.getroomprop(ed.levx, ed.levy)->directmode == 1) { cl.setroomdirectmode(ed.levx, ed.levy, 0); @@ -3057,11 +3203,13 @@ static void handle_draw_input() if (key.keymap[SDLK_w]) { + commit_roomdata_change(); ed.switch_warpdir(shift_down); ed.keydelay = 6; } if (key.keymap[SDLK_e]) { + commit_roomdata_change(); ed.keydelay = 6; ed.get_input_line(TEXT_ROOMNAME, "Enter new room name:", const_cast(&(cl.getroomprop(ed.levx, ed.levy)->roomname))); game.mapheld = true; @@ -3104,6 +3252,7 @@ static void handle_draw_input() const bool shift = key.keymap[SDLK_LSHIFT] || key.keymap[SDLK_RSHIFT]; if (key.keymap[SDLK_COMMA]) { + commit_roomdata_change(); if (ctrl) { if (shift) @@ -3123,6 +3272,7 @@ static void handle_draw_input() } else if (key.keymap[SDLK_PERIOD]) { + commit_roomdata_change(); if (ctrl) { if (shift) @@ -3194,6 +3344,127 @@ void editorclass::get_input_line(const enum TextMode mode, const std::string& pr old_entity_text = key.keybuffer; } +static void handle_undo(const bool undo) +{ + extern editorclass ed; + + std::vector* buffer = undo ? &ed.undo_buffer : &ed.redo_buffer; + + if (buffer->size() == 0) + { + ed.show_note(undo ? loc::gettext("ERROR: Nothing to undo") : loc::gettext("ERROR: Nothing to redo")); + return; + } + + EditorUndoInfo info = buffer->back(); + buffer->pop_back(); + + ed.levx = info.room_x; + ed.levy = info.room_y; + + ed.updatetiles = true; + ed.changeroom = true; + graphics.backgrounddrawn = false; + graphics.foregrounddrawn = false; + + EditorUndoInfo new_info; + + new_info.room_x = info.room_x; + new_info.room_y = info.room_y; + new_info.type = info.type; + + switch (info.type) + { + case EditorUndoType_TILES: + for (size_t i = 0; i < SCREEN_WIDTH_TILES * SCREEN_HEIGHT_TILES; i++) + { + const int x = i % SCREEN_WIDTH_TILES; + const int y = i / SCREEN_WIDTH_TILES; + ed.old_tiles[i] = ed.get_tile(x, y); + cl.settile(ed.levx, ed.levy, x, y, info.tiles[i]); + } + + SDL_memcpy(new_info.tiles, ed.old_tiles, sizeof(ed.old_tiles)); + break; + case EditorUndoType_ENTITY_ADDED: + // Remove the entity + + if (!INBOUNDS_VEC(info.entity_id, customentities)) + { + // Not sure how this would happen, but we should just consume it... + return; + } + + new_info.type = EditorUndoType_ENTITY_REMOVED; + new_info.entity = customentities[info.entity_id]; + new_info.entity_id = info.entity_id; + customentities.erase(customentities.begin() + info.entity_id); + break; + case EditorUndoType_ENTITY_REMOVED: + // Add the entity back + + customentities.insert(customentities.begin() + info.entity_id, info.entity); + new_info.type = EditorUndoType_ENTITY_ADDED; + new_info.entity_id = info.entity_id; + new_info.entity = info.entity; + break; + case EditorUndoType_ENTITY_MODIFIED: + // Restore the entity + + if (!INBOUNDS_VEC(info.entity_id, customentities)) + { + return; + } + + new_info.entity = customentities[info.entity_id]; + new_info.entity_id = info.entity_id; + customentities[info.entity_id] = info.entity; + break; + case EditorUndoType_ROOMDATA: + new_info.room_data = cl.roomproperties[info.room_x + info.room_y * cl.maxwidth]; + cl.roomproperties[info.room_x + info.room_y * cl.maxwidth] = info.room_data; + graphics.backgrounddrawn = false; + break; + case EditorUndoType_ROOMDATA_TILES: + // Restore the room data + + for (size_t i = 0; i < SCREEN_WIDTH_TILES * SCREEN_HEIGHT_TILES; i++) + { + const int x = i % SCREEN_WIDTH_TILES; + const int y = i / SCREEN_WIDTH_TILES; + ed.old_tiles[i] = ed.get_tile(x, y); + cl.settile(ed.levx, ed.levy, x, y, info.tiles[i]); + } + + SDL_memcpy(new_info.tiles, ed.old_tiles, sizeof(ed.old_tiles)); + + new_info.room_data = cl.roomproperties[info.room_x + info.room_y * cl.maxwidth]; + + cl.roomproperties[info.room_x + info.room_y * cl.maxwidth] = info.room_data; + graphics.backgrounddrawn = false; + graphics.foregrounddrawn = false; + ed.updatetiles = true; + break; + case EditorUndoType_LEVEL_SIZE: + // Restore the level size + new_info.level_width = cl.mapwidth; + new_info.level_height = cl.mapheight; + + cl.mapwidth = info.level_width; + cl.mapheight = info.level_height; + break; + } + + if (undo) + { + ed.redo_buffer.push_back(new_info); + } + else + { + ed.undo_buffer.push_back(new_info); + } +} + void editorinput(void) { extern editorclass ed; @@ -3203,6 +3474,12 @@ void editorinput(void) return; } + bool undo_pressed = false; + bool redo_pressed = false; + + bool shift_down = key.keymap[SDLK_LSHIFT] || key.keymap[SDLK_RSHIFT]; + bool ctrl_down = key.keymap[SDLK_LCTRL] || key.keymap[SDLK_RCTRL]; + ed.old_tilex = ed.tilex; ed.old_tiley = ed.tiley; @@ -3228,11 +3505,23 @@ void editorinput(void) { game.press_right = true; } - if (key.isDown(KEYBOARD_z) || key.isDown(KEYBOARD_SPACE) || key.isDown(KEYBOARD_v) || key.isDown(game.controllerButton_flip)) + if ((key.isDown(KEYBOARD_z) && !ctrl_down) || key.isDown(KEYBOARD_SPACE) || key.isDown(KEYBOARD_v) || key.isDown(game.controllerButton_flip)) { game.press_action = true; }; + if (key.isDown(KEYBOARD_z) && ctrl_down && (ed.keydelay == 0)) + { + ed.keydelay = 6; + undo_pressed = true; + } + + if (key.isDown(SDLK_y) && ctrl_down && (ed.keydelay == 0)) + { + ed.keydelay = 6; + redo_pressed = true; + } + if (key.keymap[SDLK_F9] && (ed.keydelay == 0)) { ed.keydelay = 30; ed.show_note(loc::gettext("Reloaded resources")); @@ -3263,9 +3552,6 @@ void editorinput(void) game.mapheld = false; } - bool shift_down = key.keymap[SDLK_LSHIFT] || key.keymap[SDLK_RSHIFT]; - bool ctrl_down = key.keymap[SDLK_LCTRL] || key.keymap[SDLK_RCTRL]; - // Do different things depending on the current state (and substate) switch (ed.state) { @@ -3274,6 +3560,16 @@ void editorinput(void) switch (ed.substate) { case EditorSubState_MAIN: + + if (undo_pressed) + { + handle_undo(true); + } + if (redo_pressed) + { + handle_undo(false); + } + if (escape_pressed) { // We're just in draw mode, so go to the settings menu @@ -3322,6 +3618,8 @@ void editorinput(void) } else if (shift_down) { + int old_width = cl.mapwidth; + int old_height = cl.mapheight; if (up_pressed) cl.mapheight--; if (down_pressed) cl.mapheight++; @@ -3331,26 +3629,48 @@ void editorinput(void) cl.mapwidth = SDL_clamp(cl.mapwidth, 1, cl.maxwidth); cl.mapheight = SDL_clamp(cl.mapheight, 1, cl.maxheight); - ed.updatetiles = true; - ed.changeroom = true; - graphics.backgrounddrawn = false; - graphics.foregrounddrawn = false; + if (old_width != cl.mapwidth || old_height != cl.mapheight) + { + ed.updatetiles = true; + ed.changeroom = true; + graphics.backgrounddrawn = false; + graphics.foregrounddrawn = false; - ed.levx = POS_MOD(ed.levx, cl.mapwidth); - ed.levy = POS_MOD(ed.levy, cl.mapheight); + ed.levx = POS_MOD(ed.levx, cl.mapwidth); + ed.levy = POS_MOD(ed.levy, cl.mapheight); - char buffer[3 * SCREEN_WIDTH_CHARS + 1]; - vformat_buf( - buffer, sizeof(buffer), - loc::gettext("Mapsize is now [{width},{height}]"), - "width:int, height:int", - cl.mapwidth, cl.mapheight - ); + char buffer[3 * SCREEN_WIDTH_CHARS + 1]; + vformat_buf( + buffer, sizeof(buffer), + loc::gettext("Mapsize is now [{width},{height}]"), + "width:int, height:int", + cl.mapwidth, cl.mapheight + ); + + ed.show_note(buffer); - ed.show_note(buffer); + EditorUndoInfo info; + info.type = EditorUndoType_LEVEL_SIZE; + info.level_width = old_width; + info.level_height = old_height; + info.room_x = ed.levx; + info.room_y = ed.levy; + + ed.undo_buffer.push_back(info); + ed.redo_buffer.clear(); + } } else { + if (ed.placing_tiles) + { + // We were in the middle of placing tiles. Commit it, since we're done with the previous room. + commit_tiles(); + + // Must be done after every tile commit, as it's responsible for the "old tiles" cache + ed.placing_tiles = false; + } + ed.updatetiles = true; ed.changeroom = true; graphics.backgrounddrawn = false; @@ -3372,19 +3692,26 @@ void editorinput(void) } // Mouse input - if (key.leftbutton && ed.lclickdelay == 0) - { - ed.tool_place(); - } - else if (!key.leftbutton) - { - ed.lclickdelay = 0; - } - if (key.rightbutton) { ed.tool_remove(); } + else + { + if (key.leftbutton && ed.lclickdelay == 0) + { + ed.tool_place(); + } + else if (!key.leftbutton) + { + ed.lclickdelay = 0; + if (ed.placing_tiles) + { + commit_tiles(); + ed.placing_tiles = false; + } + } + } if (key.middlebutton) { @@ -3536,14 +3863,24 @@ void editorinput(void) if (escape_pressed) { - // Cancel it, and remove the enemy it's tied to if necessary + // Escape was pressed, cancel text entry key.disabletextentry(); + if (ed.current_text_mode >= FIRST_ENTTEXT && ed.current_text_mode <= LAST_ENTTEXT) { *ed.current_text_ptr = ed.old_entity_text; + + // Looks like we're giving an entity text for the first time, so cancelling should remove the entity if (ed.old_entity_text == "") { + // Remove it. ed.remove_entity(ed.text_entity); + + // We have to uncommit twice here; once to prevent saving the "remove entity" action... + uncommit(); + + // ...and once more to undo the "add entity" action we're cancelling + uncommit(); } } diff --git a/desktop_version/src/Editor.h b/desktop_version/src/Editor.h index f9fff570..770ead39 100644 --- a/desktop_version/src/Editor.h +++ b/desktop_version/src/Editor.h @@ -133,6 +133,33 @@ struct GhostInfo int frame; // .drawframe }; + +enum EditorUndoTypes +{ + EditorUndoType_TILES, // Tiles modified + EditorUndoType_ROOMDATA, // Room data modified + EditorUndoType_ROOMDATA_TILES, // Room data modified (and stores tiles) + EditorUndoType_ENTITY_ADDED, // Entity added + EditorUndoType_ENTITY_REMOVED, // Entity removed + EditorUndoType_ENTITY_MODIFIED, // Entity properties modified + EditorUndoType_LEVEL_SIZE // Level size modified +}; + +struct EditorUndoInfo +{ + EditorUndoTypes type; + int tiles[SCREEN_WIDTH_TILES * SCREEN_HEIGHT_TILES]; + int room_x; + int room_y; + EditorTilesets tileset; + int tilecol; + int entity_id; + CustomEntity entity; + RoomProperty room_data; + int level_width; + int level_height; +}; + class editorclass { public: @@ -282,6 +309,11 @@ public: std::vector ghosts; int current_ghosts; + + std::vector undo_buffer; + std::vector redo_buffer; + bool placing_tiles; + int old_tiles[SCREEN_WIDTH_TILES * SCREEN_HEIGHT_TILES]; }; void editorrender(void);