This commit is contained in:
Ally 2024-02-02 17:47:47 -07:00 committed by GitHub
commit fd17c97414
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 349 additions and 23 deletions

View File

@ -412,6 +412,8 @@ void editorclass::reset(void)
state = EditorState_DRAW;
substate = EditorSubState_MAIN;
undo_buffer.clear();
}
void editorclass::show_note(const char* text)
@ -2241,11 +2243,30 @@ 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);
}
@ -2263,6 +2284,82 @@ 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++)
{
const int x = i % SCREEN_WIDTH_TILES;
const int y = i / SCREEN_WIDTH_TILES;
ed.old_tiles[y * SCREEN_WIDTH_TILES + x] = ed.get_tile(x, y);
}
}
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 set_tile_interpolated(const int x1, const int x2, const int y1, const int y2, const int tile)
{
extern editorclass ed;
@ -2427,11 +2524,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)
@ -2447,6 +2546,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;
@ -2455,27 +2555,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, loc::gettext("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, loc::gettext("Enter script name:"), &entity->scriptname);
text_entity = index;
break;
case 19:
// Script Boxes (and terminals)
commit_entity(index);
get_input_line(TEXT_SCRIPT, loc::gettext("Enter script name:"), &entity->scriptname);
text_entity = index;
break;
@ -2498,6 +2605,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;
@ -2615,17 +2728,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;
@ -2980,21 +3098,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;
@ -3002,6 +3124,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;
@ -3009,6 +3132,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);
@ -3038,11 +3162,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, loc::gettext("Enter new room name:"), const_cast<std::string*>(&(cl.getroomprop(ed.levx, ed.levy)->roomname)));
game.mapheld = true;
@ -3082,6 +3208,7 @@ static void handle_draw_input()
if (key.keymap[SDLK_COMMA])
{
commit_roomdata_change();
if (key.keymap[SDLK_LCTRL] || key.keymap[SDLK_RCTRL])
{
cl.roomproperties[room].platv = plat_speed - 1;
@ -3094,6 +3221,7 @@ static void handle_draw_input()
}
else if (key.keymap[SDLK_PERIOD])
{
commit_roomdata_change();
if (key.keymap[SDLK_LCTRL] || key.keymap[SDLK_RCTRL])
{
cl.roomproperties[room].platv = plat_speed + 1;
@ -3146,6 +3274,123 @@ void editorclass::get_input_line(const enum TextMode mode, const std::string& pr
old_entity_text = key.keybuffer;
}
void process_editor_buffer(const bool undo)
{
extern editorclass ed;
std::vector<EditorUndoInfo>* buffer = undo ? &ed.undo_buffer : &ed.redo_buffer;
if (buffer->size() == 0)
{
ed.show_note(loc::gettext(undo ? "ERROR: Nothing to undo" : "ERROR: Nothing to redo"));
return;
}
EditorUndoInfo info = buffer->back();
buffer->pop_back();
ed.levx = info.room_x;
ed.levy = info.room_y;
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));
graphics.foregrounddrawn = false;
break;
case EditorUndoType_ENTITY_ADDED:
// Remove the entity
if (!INBOUNDS_VEC(info.entity_id, customentities))
{
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;
@ -3155,6 +3400,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;
@ -3180,11 +3431,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"));
@ -3215,9 +3478,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)
{
@ -3226,6 +3486,16 @@ void editorinput(void)
switch (ed.substate)
{
case EditorSubState_MAIN:
if (undo_pressed)
{
process_editor_buffer(true);
}
if (redo_pressed)
{
process_editor_buffer(false);
}
if (escape_pressed)
{
// We're just in draw mode, so go to the settings menu
@ -3274,6 +3544,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++;
@ -3283,26 +3555,43 @@ 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.levx = POS_MOD(ed.levx, cl.mapwidth);
ed.levy = POS_MOD(ed.levy, cl.mapheight);
ed.updatetiles = true;
ed.changeroom = true;
graphics.backgrounddrawn = false;
graphics.foregrounddrawn = false;
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.levx = POS_MOD(ed.levx, cl.mapwidth);
ed.levy = POS_MOD(ed.levy, cl.mapheight);
ed.show_note(buffer);
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);
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
{
commit_tiles();
ed.placing_tiles = false;
ed.updatetiles = true;
ed.changeroom = true;
graphics.backgrounddrawn = false;
@ -3331,6 +3620,11 @@ void editorinput(void)
else if (!key.leftbutton)
{
ed.lclickdelay = 0;
if (ed.placing_tiles)
{
commit_tiles();
ed.placing_tiles = false;
}
}
if (key.rightbutton)

View File

@ -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<GhostInfo> ghosts;
int current_ghosts;
std::vector<EditorUndoInfo> undo_buffer;
std::vector<EditorUndoInfo> redo_buffer;
bool placing_tiles = false;
int old_tiles[SCREEN_WIDTH_TILES * SCREEN_HEIGHT_TILES];
};
void editorrender(void);