From 95680b699ca4e6cd71202a6cfe4e105915ef7ff2 Mon Sep 17 00:00:00 2001 From: ac-stef Date: Sat, 23 May 2015 16:11:33 +0200 Subject: [PATCH] add undelete for entities BACKSPACE in combination with editmeta (LCTRL) now undeletes the last deleted entity. BACKSPACE in combination with editmeta2 (LSHIFT) brings up the menu "deleted entities". The edit menu now has a submenu "deleted entities" which lists all deleted entities and undeletes the selected one. undelent [] If no index is specified, the last deleted entity is restored. If an index is given, the specified entity from the list of deleted entities is restored. getdeletedentities Returns a list of deleted entities. Each line contains the entity type, the position and all seven attributes. unlistdeletedentity [] If is a number, the specified entry from the list of deleted entities gets removed. If is "all", the whole list of deleted entities gets deleted. If is "last" the last deleted entity is removed from the list of deleted entities. Returns the number of entities on the list of deleted entities (even if the parameter was unknown or not specified). DOCREF undelent getdeletedentities unlistdeletedentity --- config/menus_edit.cfg | 29 ++++++++++++++ config/resetbinds.cfg | 2 +- source/src/audiomanager.cpp | 1 + source/src/clientgame.cpp | 1 + source/src/editing.cpp | 1 + source/src/protos.h | 5 ++- source/src/rendermodel.cpp | 1 + source/src/world.cpp | 77 +++++++++++++++++++++++++++++++------ 8 files changed, 103 insertions(+), 14 deletions(-) diff --git a/config/menus_edit.cfg b/config/menus_edit.cfg index 39b1bf21..a932e094 100644 --- a/config/menus_edit.cfg +++ b/config/menus_edit.cfg @@ -13,6 +13,8 @@ menuitem (_ [Map operations...]) [ showmenu [Map operations] ] menuitem [Map config operations...] [ showmenu [Map config operations] ] menuitem (_ [Bots...]) [ showmenu [Creating bot waypoints] ] menuitem (_ [Settings...]) [ showmenu [Editing settings] ] +menuitem [Deleted entities] [ showmenu "deleted entities" ] + menuitem (_ Help?) [ echo (yellow) (_ [Please read the AssaultCube README which has a detailed guide on mapediting...]) ] tempalias tmp_cradius 12 @@ -287,6 +289,33 @@ menuitemcheckbox (_ [Enable auto save map: ]) "$autosavemap" [ autosavemap = $ar menuitemslider (_ [Time between auto saves (in minutes): ]) 2 60 "(div $timeBetAutoSaves 60000)" 1 [] [ timeBetAutoSaves = (* $arg1 60000) ] menuitemtextinput (_ [Make a map backup (.BAK) every: ]) "$numAutoSaveBackups" [ numAutoSaveBackups = $arg1 ] [ if (! $showedBAKinfo) [ echo This setting effects the number of autosavemaps between making a map backup file. "(.BAK)"; showedBAKinfo = 1 ] ] 4 +// deleted entities +newmenu "deleted entities" +menuinit __rebuilddeletedentitymenu + +tempalias __rebuilddeletedentitymenu [ + delmenu "deleted entities" + newmenu "deleted entities" + if (unlistdeletedentity) [ + push i 0 + looplist (getdeletedentities) [type x y z a1 a2 a3 a4 a5 a6 a7] [ + push desc (concat $type (concatword "[" $x "|" $y "|" $z "]") (concatword "(" $a1 ", " $a2 ", " $a3 ", " $a4 ", " $a5 ", " $a6 ", " $a7 ")")) + if (strcmp $type mapmodel) [desc = (concat $desc (mapmodelslotname $a2))] + if (&& $editing (strcmp $type sound)) [desc = (concat $desc (at (editmapsoundslot $a1) 0))] + if $editing [ + menuitem (pop desc) (concat gotoposition $x $y $z $a1 0 ";" undelent $i) + ][ + menuitem (pop desc) -1 + ] + += i 1 + ] + pop i + menuitem "\f3clear this list" "unlistdeletedentity all" + ] [ + menuitem "no deleted entities" -1 + ] +] + //Mapmodels newmenu Mapmodels menuinit __rebuildmapmodelmenus diff --git a/config/resetbinds.cfg b/config/resetbinds.cfg index 61d3f4f0..342d72f3 100644 --- a/config/resetbinds.cfg +++ b/config/resetbinds.cfg @@ -30,7 +30,7 @@ bind MOUSE3 weapon bind MOUSE4 key_universaldelta_plus bind MOUSE5 key_universaldelta_minus bind BACKSPACE dropflag -editbind BACKSPACE delent +editbind BACKSPACE [if $editmeta2down [showmenu "deleted entities" ; menuselection "deleted entities" (- (unlistdeletedentity) 1)] [if $editmetakeydown undelent delent]] bind TAB key_showscores bind CLEAR [] bind RETURN [] diff --git a/source/src/audiomanager.cpp b/source/src/audiomanager.cpp index 8555b9f3..f4bbbd28 100644 --- a/source/src/audiomanager.cpp +++ b/source/src/audiomanager.cpp @@ -866,6 +866,7 @@ void deletemapsoundslot(int *n, char *opt) // delete mapsound slot - only if unu entity &e = ents[i]; if(e.attr1 == *n) { // delete entity + deleted_ents.add(e); deletesoundentity(e); memset(&e, 0, sizeof(persistent_entity)); e.type = NOTUSED; diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index 950cc1e1..4eb18e59 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -1084,6 +1084,7 @@ void resetmap(bool mrproper) cleardynlights(); pruneundos(); changedents.setsize(0); + deleted_ents.setsize(0); particlereset(); if(mrproper) { diff --git a/source/src/editing.cpp b/source/src/editing.cpp index 3a08f9db..2919229d 100644 --- a/source/src/editing.cpp +++ b/source/src/editing.cpp @@ -1045,6 +1045,7 @@ void transformclipentities() // transforms all clip entities to tag clips, if t } if(!nodelete) { + deleted_ents.add(e); e.type = NOTUSED; // only delete entity, if it is now fully covered in tag clips thisrun++; } diff --git a/source/src/protos.h b/source/src/protos.h index b224bca8..ab3885a5 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -486,11 +486,12 @@ extern void remip(const block &b, int level = 0); extern void remipmore(const block &b, int level = 0); extern int closestent(); extern void deletesoundentity(entity &e); -extern int findtype(char *what); +extern int findtype(const char *what); extern int findentity(int type, int index = 0); extern int findentity(int type, int index, uchar attr2); -extern void newentity(int index, int x, int y, int z, char *what, float v1, float v2, float v3, float v4); +extern void newentity(int index, int x, int y, int z, const char *what, float v1, float v2, float v3, float v4); extern void mapmrproper(bool manual); +extern vector deleted_ents; // worldlight extern int lastcalclight; diff --git a/source/src/rendermodel.cpp b/source/src/rendermodel.cpp index 0f6e35d4..2712e3c5 100644 --- a/source/src/rendermodel.cpp +++ b/source/src/rendermodel.cpp @@ -166,6 +166,7 @@ void deletemapmodelslot(int *n, char *opt) // delete mapmodel slot - only if unu entity &e = ents[i]; if(e.attr2 == *n) { // delete entity + deleted_ents.add(e); memset(&e, 0, sizeof(persistent_entity)); e.type = NOTUSED; deld++; diff --git a/source/src/world.cpp b/source/src/world.cpp index d4fd46f6..97af6e0c 100644 --- a/source/src/world.cpp +++ b/source/src/world.cpp @@ -249,21 +249,19 @@ void deletesoundentity(entity &e) if(loc) loc->drop(); } +vector deleted_ents; + void delent() { int n = closestent(); if(n<0) { conoutf("no more entities"); return; } syncentchanges(true); int t = ents[n].type; - conoutf("%s entity deleted", entnames[t]); + conoutf("%s entity deleted", entnames[t % MAXENTTYPES]); entity &e = ents[n]; - - if (t == SOUND) //stop playing sound - { - deletesoundentity(e); - } - + if(t == SOUND) deletesoundentity(e); //stop playing sound + deleted_ents.add(e); ents[n].type = NOTUSED; addmsg(SV_EDITENT, "ri9i3", n, NOTUSED, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); @@ -273,15 +271,66 @@ void delent() } unsavededits++; } +COMMAND(delent, ""); -int findtype(char *what) +void undelent(char *index) +{ + if(noteditmode("undelent")) return; + if(!deleted_ents.length()) { conoutf("no more entities to undelete"); return; } + int n = isdigit(*index) ? strtol(index, NULL, 0) : deleted_ents.length() - 1; + if(deleted_ents.inrange(n)) + { + persistent_entity e = deleted_ents.remove(n); + int t = e.type < MAXENTTYPES ? e.type : NOTUSED; + if(OUTBORD(e.x, e.y)) conoutf("failed to undelete %s entity (coordinates outside map borders)", entnames[t]); + else + { + newentity(-1, e.x, e.y, e.z, entnames[t], float(e.attr1) / entscale[t][0], float(e.attr2) / entscale[t][1], float(e.attr3) / entscale[t][2], float(e.attr4) / entscale[t][3]); + *((persistent_entity *) &ents.last()) = e; + conoutf("%s entity undeleted", entnames[t]); + } + } +} +COMMAND(undelent, "s"); + +void getdeletedentities() +{ + vector res; + loopv(deleted_ents) + { + persistent_entity &e = deleted_ents[i]; + int t = e.type < MAXENTTYPES ? e.type : NOTUSED; + #define AA(x) floatstr(float(e.attr##x) / entscale[t][x - 1], true) + cvecprintf(res,"%s %d %d %d %s %s %s %s %s %s %s\n", entnames[e.type], e.x, e.y, e.z, AA(1), AA(2), AA(3), AA(4), AA(5), AA(6), AA(7)); + #undef AA + } + if(res.length()) res.last() = '\0'; + else res.add('\0'); + result(res.getbuf()); +} +COMMAND(getdeletedentities, ""); + +void unlistdeletedentity(char *which) +{ + if(!strcasecmp(which, "all")) deleted_ents.setsize(0); + else if(!strcasecmp(which, "last")) deleted_ents.pop(); + else if(isdigit(*which)) + { + int n = strtol(which, NULL, 0); + if(deleted_ents.inrange(n)) deleted_ents.remove(n); + } + intret(deleted_ents.length()); +} +COMMAND(unlistdeletedentity, "s"); + +int findtype(const char *what) { int t = getlistindex(what, entnames, true, NOTUSED); if(t == NOTUSED) conoutf("unknown entity type \"%s\"", what); return t; } -void newentity(int index, int x, int y, int z, char *what, float v1f, float v2f, float v3f, float v4f) // add an entity or overwrite an existing one +void newentity(int index, int x, int y, int z, const char *what, float v1f, float v2f, float v3f, float v4f) // add an entity or overwrite an existing one { int type = findtype(what); if(type == NOTUSED) return; @@ -354,7 +403,13 @@ void clearents(char *name) loopv(ents) { entity &e = ents[i]; - if(e.type==type) { e.type = NOTUSED; found = true; } + if(e.type == type) + { + if(type == SOUND) deletesoundentity(e); + deleted_ents.add(e); + e.type = NOTUSED; + found = true; + } } switch(type) { @@ -375,6 +430,7 @@ void deleteentity(char *ns) int t = e.type; if(t == SOUND) deletesoundentity(e); conoutf("deleted entity #%d (%s)", n, entnames[e.type]); + deleted_ents.add(e); memset(&e, 0, sizeof(persistent_entity)); e.type = NOTUSED; if(t == LIGHT) calclight(); @@ -688,7 +744,6 @@ COMMAND(mapenlarge, ""); COMMAND(mapshrink, ""); COMMAND(newmap, "i"); COMMANDN(recalc, calclight, ""); -COMMAND(delent, ""); void countperfectmips(int mip, int xx, int yy, int bs, int *stats) {