From c9ef46062f2d0649fb1bd3ee17ee6d176a53b3c1 Mon Sep 17 00:00:00 2001 From: ac-stef Date: Wed, 20 May 2015 14:37:50 +0200 Subject: [PATCH] finish attr5..7 and highres entity attributes * some cleanups in editing.cpp (putting COMMAND to the function, removing unnecessary COMMANDF) * upgrade transformclipentities for floating point clip entities * changed some entity commands to float attributes entproperty [] index and increment work like before, but increment is now a float for some attributes. If unscaled is "1", increment is applied as unscaled integer, which means, it will change float attributes at their highest resolution. getentattr [] Works like before, but returns float values for some attributes. If unscaled is "1", raw integer values (representing the highest resolution) are returned. entset Works like before, but some attributes may be specified as floats. editentity <...> Now uses float values for some attributes. Return values also may be float. DOCREF newent entproperty getentattr entset editentity --- source/src/editing.cpp | 140 ++++++++++++++++++++++------------------- source/src/protos.h | 2 +- source/src/world.cpp | 107 +++++++++++++++++-------------- source/src/worldio.cpp | 2 +- 4 files changed, 136 insertions(+), 115 deletions(-) diff --git a/source/src/editing.cpp b/source/src/editing.cpp index 31b8532e..3a08f9db 100644 --- a/source/src/editing.cpp +++ b/source/src/editing.cpp @@ -107,7 +107,7 @@ char *editinfo() entity &c = ents[e]; int t = c.type < MAXENTTYPES ? c.type : 0; #define AA(x) floatstr(float(c.attr##x) / entscale[t][x - 1], true) - formatstring(info)("closest entity = %s (%s, %s, %s, %s, %s, %s, %s)", entnames[t], AA(1), AA(2), AA(3), AA(4), AA(5), AA(6), AA(7)); + formatstring(info)("closest entity: %s (%s, %s, %s, %s, %s, %s, %s)", entnames[t], AA(1), AA(2), AA(3), AA(4), AA(5), AA(6), AA(7)); #undef AA const char *slotinfo = "unassigned slot"; if(t == MAPMODEL) @@ -154,6 +154,10 @@ void resetselections() sels.shrink(0); } +COMMANDF(select, "iiii", (int *x, int *y, int *xs, int *ys) { resetselections(); addselection(*x, *y, *xs, *ys, 0); }); +COMMANDF(addselection, "iiii", (int *x, int *y, int *xs, int *ys) { addselection(*x, *y, *xs, *ys, 0); }); +COMMAND(resetselections, ""); + // reset all invalid selections void checkselections() { @@ -429,6 +433,7 @@ void editundo() freeblock(p); unsavededits++; } +COMMANDN(undo, editundo, ""); void editredo() { @@ -441,6 +446,7 @@ void editredo() freeblock(p); unsavededits++; } +COMMANDN(redo, editredo, ""); extern int worldiodebug; @@ -545,6 +551,7 @@ void copy() } } +COMMAND(copy, ""); void paste() { @@ -572,6 +579,7 @@ void paste() } } } +COMMAND(paste, ""); // Count the walls of type "type" contained in the current selection void countwalls(int *type) @@ -586,6 +594,7 @@ void countwalls(int *type) loopselsxy(if(s->type==*type) counter++) intret(counter); } +COMMAND(countwalls, "i"); void tofronttex() // maintain most recently used of the texture lists when applying texture { @@ -671,47 +680,49 @@ void edittexxy(int type, int t, block &sel) }); } -void edittex(int type, int dir) +void edittex(int *type, int *dir) { EDITSEL; - if(type<0 || type>3) return; - if(type!=lasttype) { tofronttex(); lasttype = type; } - int atype = type==3 ? 1 : type; + if(*type < 0 || *type > 3) return; + if(*type != lasttype) { tofronttex(); lasttype = *type; } + int atype = *type == 3 ? 1 : *type; int i = curedittex[atype]; - i = i<0 ? 0 : i+dir; + i = i < 0 ? 0 : i + *dir; curedittex[atype] = i = min(max(i, 0), 255); int t = lasttex = hdr.texlists[atype][i]; loopv(sels) { - edittexxy(type, t, sels[i]); - addmsg(SV_EDITT, "ri6", sels[i].x, sels[i].y, sels[i].xs, sels[i].ys, type, t); + edittexxy(*type, t, sels[i]); + addmsg(SV_EDITT, "ri6", sels[i].x, sels[i].y, sels[i].xs, sels[i].ys, *type, t); } unsavededits++; } +COMMAND(edittex, "ii"); -void settex(int texture, int type) +void settex(int *texture, int *type) { EDITSEL; - if(type<0 || type>3) return; - int atype = type==3 ? 1 : type; + if(*type < 0 || *type > 3) return; + int atype = *type == 3 ? 1 : *type; int t = -1; - loopi(256) if(texture == (int)hdr.texlists[atype][i]) + loopi(256) if(*texture == (int)hdr.texlists[atype][i]) { t = (int)hdr.texlists[atype][i]; break; } - if(t<0) + if(t < 0) { conoutf("invalid/unavaible texture"); return; } loopv(sels) { - edittexxy(type, t, sels[i]); - addmsg(SV_EDITT, "ri6", sels[i].x, sels[i].y, sels[i].xs, sels[i].ys, type, t); + edittexxy(*type, t, sels[i]); + addmsg(SV_EDITT, "ri6", sels[i].x, sels[i].y, sels[i].xs, sels[i].ys, *type, t); } unsavededits++; } +COMMAND(settex, "ii"); void replace() { @@ -731,6 +742,7 @@ void replace() remip(b); unsavededits++; } +COMMAND(replace, ""); void edittypexy(int type, block &sel) { @@ -787,7 +799,6 @@ void equalize(int *flr) addmsg(SV_EDITE, "ri5", sel.x, sel.y, sel.xs, sel.ys, isfloor); } } - COMMAND(equalize, "i"); void setvdeltaxy(int delta, block &sel) @@ -796,15 +807,16 @@ void setvdeltaxy(int delta, block &sel) remipmore(sel); } -void setvdelta(int delta) +void setvdelta(int *delta) { EDITSEL; loopv(sels) { - setvdeltaxy(delta, sels[i]); - addmsg(SV_EDITD, "ri5", sels[i].x, sels[i].y, sels[i].xs, sels[i].ys, delta); + setvdeltaxy(*delta, sels[i]); + addmsg(SV_EDITD, "ri5", sels[i].x, sels[i].y, sels[i].xs, sels[i].ys, *delta); } } +COMMANDN(vdelta, setvdelta, "i"); const int MAXARCHVERT = 50; int archverts[MAXARCHVERT][MAXARCHVERT]; @@ -820,6 +832,7 @@ void archvertex(int *span, int *vert, int *delta) if(*span>=MAXARCHVERT || *vert>=MAXARCHVERT || *span<0 || *vert<0) return; archverts[*span][*vert] = *delta; } +COMMAND(archvertex, "iii"); void arch(int *sidedelta) { @@ -838,24 +851,26 @@ void arch(int *sidedelta) remipmore(sel); } } +COMMAND(arch, "i"); -void slope(int xd, int yd) +void slope(int *xd, int *yd) { EDITSELMP; loopv(sels) { block &sel = sels[i]; int off = 0; - if(xd<0) off -= xd*sel.xs; - if(yd<0) off -= yd*sel.ys; + if(*xd < 0) off -= *xd * sel.xs; + if(*yd < 0) off -= *yd * sel.ys; sel.xs++; sel.ys++; - loopselxy(sel, s->vdelta = xd*x+yd*y+off); + loopselxy(sel, s->vdelta = *xd * x + *yd * y + off); remipmore(sel); } } +COMMAND(slope, "ii"); -void perlin(int scale, int seed, int psize) +void perlin(int *scale, int *seed, int *psize) { EDITSELMP; loopv(sels) @@ -866,12 +881,13 @@ void perlin(int scale, int seed, int psize) makeundo(sel); sel.xs--; sel.ys--; - perlinarea(sel, scale, seed, psize); + perlinarea(sel, *scale, *seed, *psize); sel.xs++; sel.ys++; remipmore(sel); } } +COMMAND(perlin, "iii"); VARF(fullbright, 0, 0, 1, if(fullbright) @@ -887,16 +903,19 @@ void edittag(int *tag) EDITSELMP; loopselsxy(s->tag = *tag); } +COMMAND(edittag, "i"); -void newent(char *what, int *a1, int *a2, int *a3, int *a4) +void newent(char *what, float *a1, float *a2, float *a3, float *a4) { EDITSEL; loopv(sels) newentity(-1, sels[i].x, sels[i].y, (int)camera1->o.z, what, *a1, *a2, *a3, *a4); } +COMMAND(newent, "sffff"); -void movemap(int xo, int yo, int zo) // move whole map +void movemap(int *xop, int *yop, int *zop) // move whole map { EDITMP; + int xo = *xop, yo = *yop, zo = *zop; if(!worldbordercheck(MINBORD + max(-xo, 0), MINBORD + max(xo, 0), MINBORD + max(-yo, 0), MINBORD + max(yo, 0), max(zo, 0), max(-zo, 0))) { conoutf("not enough space to move the map"); @@ -933,6 +952,7 @@ void movemap(int xo, int yo, int zo) // move whole map resetmap(false); unsavededits++; } +COMMAND(movemap, "iii"); void selfliprotate(block &sel, int dir) { @@ -962,17 +982,18 @@ void selfliprotate(block &sel, int dir) freeblock(org); } -void selectionrotate(int dir) +void selectionrotate(int *dir) { EDITSELMP; - dir &= 3; - if(!dir) return; + *dir &= 3; + if(!*dir) return; loopv(sels) { block &sel = sels[i]; - if(sel.xs == sel.ys || dir == 2) selfliprotate(sel, dir); + if(sel.xs == sel.ys || *dir == 2) selfliprotate(sel, *dir); } } +COMMAND(selectionrotate, "i"); void selectionflip(char *axis) { @@ -981,74 +1002,61 @@ void selectionflip(char *axis) if(c != 'X' && c != 'Y') return; loopv(sels) selfliprotate(sels[i], c == 'X' ? 11 : 12); } - -COMMANDF(select, "iiii", (int *x, int *y, int *xs, int *ys) { resetselections(); addselection(*x, *y, *xs, *ys, 0); }); -COMMANDF(addselection, "iiii", (int *x, int *y, int *xs, int *ys) { addselection(*x, *y, *xs, *ys, 0); }); -COMMAND(resetselections, ""); -COMMAND(edittag, "i"); -COMMAND(replace, ""); -COMMAND(archvertex, "iii"); -COMMAND(arch, "i"); -COMMANDF(slope, "ii", (int *xd, int *yd) { slope(*xd, *yd); }); -COMMANDF(vdelta, "i", (int *d) { setvdelta(*d); }); -COMMANDN(undo, editundo, ""); -COMMANDN(redo, editredo, ""); -COMMAND(copy, ""); -COMMAND(paste, ""); -COMMANDF(edittex, "ii", (int *type, int *dir) { edittex(*type, *dir); }); -COMMAND(newent, "siiii"); -COMMANDF(perlin, "iii", (int *sc, int *se, int *ps) { perlin(*sc, *se, *ps); }); -COMMANDF(movemap, "iii", (int *x, int *y, int *z) { movemap(*x, *y, *z); }); -COMMANDF(selectionrotate, "i", (int *d) { selectionrotate(*d); }); COMMAND(selectionflip, "s"); -COMMAND(countwalls, "i"); -COMMANDF(settex, "ii", (int *texture, int *type) { settex(*texture, *type); }); -#if 0 // fix clip scaling + void transformclipentities() // transforms all clip entities to tag clips, if they are big enough (so, that no player could be above or below them) -{ +{ // (hardcoded factor ENTSCALE10 for attr1 and ENTSCALE5 for attr2-4) EDITMP; - int total = 0, thisrun; + int total = 0, thisrun, bonus = 5; do { thisrun = 0; loopv(ents) { entity &e = ents[i]; - if((e.type == CLIP || e.type == PLCLIP) && e.attr2 && e.attr3 && e.attr4) + if((e.type == CLIP || e.type == PLCLIP) && e.attr2 / ENTSCALE5 && e.attr3 / ENTSCALE5 && e.attr4 / ENTSCALE5) { int allowedspace = e.type == CLIP ? 1 : 4; int clipmask = e.type == CLIP ? TAGCLIP : TAGPLCLIP; - int x1 = e.x - e.attr2, x2 = e.x + e.attr2 - 1, y1 = e.y - e.attr3, y2 = e.y + e.attr3 - 1; - int z1 = S(e.x, e.y)->floor + e.attr1, z2 = z1 + e.attr4; - bool bigenough = true; - for(int xx = x1; xx <= x2; xx++) for(int yy = y1; yy <= y2; yy++) + int i2 = e.attr2 / ENTSCALE5, i3 = e.attr3 / ENTSCALE5; // floor values + int r2 = (e.attr2 % ENTSCALE5) > 0, r3 = (e.attr3 % ENTSCALE5) > 0; // fractions + int x1i = e.x - i2, x2i = e.x + i2 - 1, y1i = e.y - i3, y2i = e.y + i3 - 1; // inner rectangle (fully covered cubes) + int x1o = x1i - r2, x2o = x2i + r2, y1o = y1i - r3, y2o = y2i + r3; // outer rectangle (partially covered cubes) + float z1 = S(e.x, e.y)->floor + float(e.attr1) / ENTSCALE10, z2 = z1 + float(e.attr4) / ENTSCALE5; + bool bigenough = true, nodelete = false; + for(int xx = x1o; xx <= x2o; xx++) for(int yy = y1o; yy <= y2o; yy++) // loop over outer rectangle to check, if a clip has the required height { if(OUTBORD(xx,yy) || SOLID(S(xx,yy))) continue; + bool inner = xx >= x1i && xx <= x2i && yy >= y1i && yy <= y2i; // flag: xx|yy is inner rectangle sqr *s[4] = { S(xx, yy), S(xx + 1, yy), S(xx, yy + 1), S(xx + 1, yy + 1) }; int vdeltamax = 0; loopj(4) if(s[j]->vdelta > vdeltamax) vdeltamax = s[j]->vdelta; int floor = s[0]->floor - (s[0]->type == FHF ? (vdeltamax + 3) / 4 : 0), ceil = s[0]->ceil - (s[0]->type == CHF ? (vdeltamax + 3) / 4 : 0); - if((z1 - floor > allowedspace || ceil - z2 > allowedspace) && !(s[0]->tag & (TAGCLIP | clipmask))) bigenough = false; + bool alreadytagged = (s[0]->tag & (TAGCLIP | clipmask)) != 0; + if((z1 - floor > allowedspace || ceil - z2 > allowedspace) && !alreadytagged) bigenough = false; + if(!inner && !alreadytagged) nodelete = true; // fractional part of the clip would not be covered: entity can not be deleted } if(bigenough) { - for(int xx = x1; xx <= x2; xx++) for(int yy = y1; yy <= y2; yy++) + for(int xx = x1i; xx <= x2i; xx++) for(int yy = y1i; yy <= y2i; yy++) // only convert inner rectangle to tag clips { if(!OUTBORD(xx,yy) && !SOLID(S(xx,yy))) S(xx, yy)->tag |= clipmask; } - e.type = NOTUSED; - thisrun++; + if(!nodelete) + { + e.type = NOTUSED; // only delete entity, if it is now fully covered in tag clips + thisrun++; + } } } } total += thisrun; } - while(thisrun); + while(thisrun || bonus-- > 0); loopi(ssize) loopj(ssize) { sqr *s = S(i,j); if(s->tag & TAGCLIP) s->tag &= ~TAGPLCLIP; } conoutf("changed %d clip entities to tagged clip areas", total); if(total) unsavededits++; } COMMAND(transformclipentities, ""); -#endif diff --git a/source/src/protos.h b/source/src/protos.h index 0121450b..b224bca8 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -489,7 +489,7 @@ extern void deletesoundentity(entity &e); extern int findtype(char *what); extern int findentity(int type, int index = 0); extern int findentity(int type, int index, uchar attr2); -extern entity *newentity(int index, int x, int y, int z, char *what, int v1, int v2, int v3, int v4); +extern void newentity(int index, int x, int y, int z, char *what, float v1, float v2, float v3, float v4); extern void mapmrproper(bool manual); // worldlight diff --git a/source/src/world.cpp b/source/src/world.cpp index 6bc09a8b..d4fd46f6 100644 --- a/source/src/world.cpp +++ b/source/src/world.cpp @@ -166,13 +166,16 @@ int closestent() // used for delent and edit mode ent display return best; } -void entproperty(int prop, int amount) +void entproperty(int *prop, float *famount, int *unscaled) { int n = closestent(); - if(n<0) return; + if(n < 0) return; entity &e = ents[n]; int old_a1 = e.attr1; - switch(prop) + int t = e.type < MAXENTTYPES ? e.type : 0; + int amount = int(*famount * (*prop >= 0 && *prop < 7 && !*unscaled ? entscale[t][*prop] : 1)); + + switch(*prop) { case 0: e.attr1 += amount; break; case 1: e.attr2 += amount; break; @@ -199,6 +202,7 @@ void entproperty(int prop, int amount) if(changedents.find(n) == -1) changedents.add(n); // apply ent changes later (reduces network traffic) unsavededits++; } +COMMAND(entproperty, "ifi"); hashtable mapinfo, &resdata = mapinfo; @@ -210,22 +214,33 @@ void getenttype() if(type < 0 || type >= MAXENTTYPES) return; result(entnames[type]); } - -void getentattr(int *attr) -{ - int e = closestent(); - if(e>=0) switch(*attr) - { - case 0: intret(ents[e].attr1); return; - case 1: intret(ents[e].attr2); return; - case 2: intret(ents[e].attr3); return; - case 3: intret(ents[e].attr4); return; - } - intret(0); -} - COMMAND(getenttype, ""); -COMMAND(getentattr, "i"); + +void getentattr(int *attr, int *unscaled) +{ + int n = closestent(); + const char *res = "0"; + if(n >= 0) + { + entity &e = ents[n]; + int t = e.type < MAXENTTYPES ? e.type : 0; + int scale = *attr >= 0 && *attr < 7 && !*unscaled ? entscale[t][*attr] : 1; + switch(*attr) + { + #define CHKATTR(x) case x - 1: res = floatstr(float(e.attr##x) / scale, true); break + CHKATTR(1); + CHKATTR(2); + CHKATTR(3); + CHKATTR(4); + CHKATTR(5); + CHKATTR(6); + CHKATTR(7); + #undef CHKATTR + } + } + result(res); +} +COMMAND(getentattr, "ii"); void deletesoundentity(entity &e) { @@ -266,41 +281,35 @@ int findtype(char *what) return t; } -entity *newentity(int index, int x, int y, int z, char *what, int v1, int v2, int v3, int v4) +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 { int type = findtype(what); - if(type==NOTUSED) return NULL; - - if (type == SOUND && index >= 0) - { - entity &o = ents[index]; - - entityreference entref(&o); - location *loc = audiomgr.locations.find(o.attr1, &entref, mapsounds); - - if(loc) - loc->drop(); + if(type == NOTUSED) return; + if (index >= 0 && ents[index].type == SOUND) deletesoundentity(ents[index]); // overwriting sound entity + switch(type) + { // MAPMODEL, PLAYERSTART and CTF-FLAG use the current camera direction as value for attr1, so attr234 need to be moved + case MAPMODEL: + v4f = v3f; + v3f = v2f; + case PLAYERSTART: + case CTF_FLAG: + v2f = v1f; + int y = camera1->yaw; + if(type != PLAYERSTART) y = y + 7 - (y + 7) % 15; + v1f = y; + break; } + int v1 = v1f * entscale[type][0], v2 = v2f * entscale[type][1], v3 = v3f * entscale[type][2], v4 = v4f * entscale[type][3]; entity e(x, y, z, type, v1, v2, v3, v4); switch(type) { case LIGHT: - if(v1>64) e.attr1 = 64; + if(v1 > 64) e.attr1 = 64; if(!v1) e.attr1 = 16; if(!v2 && !v3 && !v4) e.attr2 = 255; break; - - case MAPMODEL: - e.attr4 = e.attr3; - e.attr3 = e.attr2; - case PLAYERSTART: - case CTF_FLAG: - e.attr2 = v1; - e.attr1 = int(camera1->yaw * ENTSCALE10); - if(type != PLAYERSTART) e.attr1 = e.attr1 + 70 - (e.attr1 + 70) % 150; - break; } clampentityattributes(e); syncentchanges(true); @@ -323,10 +332,9 @@ entity *newentity(int index, int x, int y, int z, char *what, int v1, int v2, in case SOUND: audiomgr.preloadmapsound(e); break; } unsavededits++; - return index<0 ? &ents.last() : &ents[index]; } -void entset(char *what, int *a1, int *a2, int *a3, int *a4) +void entset(char *what, float *a1, float *a2, float *a3, float *a4) { int n = closestent(); if(n>=0) @@ -336,7 +344,7 @@ void entset(char *what, int *a1, int *a2, int *a3, int *a4) } } -COMMAND(entset, "siiii"); +COMMAND(entset, "sffff"); void clearents(char *name) { @@ -384,6 +392,7 @@ void editentity(char **args, int numargs) // index x y z a1 a2 a3 a4 ... entity &e = ents[n]; bool edit = false; for(int i = 1; i < numargs; i++) if(*args[i]) edit = true; // only arguments other than empty strings can edit anything - otherwise we're just browsing + int t = e.type < MAXENTTYPES ? e.type : NOTUSED; if(edit) { if(e.type == SOUND) @@ -394,7 +403,7 @@ void editentity(char **args, int numargs) // index x y z a1 a2 a3 a4 ... } for(int i = 1; i < numargs; i++) if(*args[i]) { - int v = ATOI(args[i]); + int v = atof(args[i]) * (i < 4 || i > 10 ? 1 : entscale[t][i - 4]); switch(i) { case 1: e.x = v; break; @@ -404,6 +413,9 @@ void editentity(char **args, int numargs) // index x y z a1 a2 a3 a4 ... case 5: e.attr2 = v; break; case 6: e.attr3 = v; break; case 7: e.attr4 = v; break; + case 8: e.attr5 = v; break; + case 9: e.attr6 = v; break; + case 10: e.attr7 = v; break; } } clampentityattributes(e); @@ -415,7 +427,9 @@ void editentity(char **args, int numargs) // index x y z a1 a2 a3 a4 ... unsavededits++; } // give back unchanged or new entity properties - formatstring(res)("%s %d %d %d %d %d %d %d", entnames[e.type], e.x, e.y, e.z, e.attr1, e.attr2, e.attr3, e.attr4); + #define AA(x) floatstr(float(e.attr##x) / entscale[t][x - 1], true) + formatstring(res)("%s %d %d %d %s %s %s %s %s %s %s", 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 } result(res); } @@ -675,7 +689,6 @@ COMMAND(mapshrink, ""); COMMAND(newmap, "i"); COMMANDN(recalc, calclight, ""); COMMAND(delent, ""); -COMMANDF(entproperty, "ii", (int *p, int *a) { entproperty(*p, *a); }); void countperfectmips(int mip, int xx, int yy, int bs, int *stats) { diff --git a/source/src/worldio.cpp b/source/src/worldio.cpp index 775c9d96..84daa889 100644 --- a/source/src/worldio.cpp +++ b/source/src/worldio.cpp @@ -708,7 +708,7 @@ bool load_world(char *mname) // still supports all map formats that have if(e.type == LIGHT && e.attr1 >= 0) { if(!e.attr2) e.attr2 = 255; // needed for MAPVERSION<=2 - if(e.attr1>32) e.attr1 = 32; // 12_03 and below + if(e.attr1 > 32) e.attr1 = 32; // 12_03 and below (but applied to _all_ files!) } transformoldentitytypes(hdr.version, e.type); if(oldentityformat && e.type < MAXENTTYPES)