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);