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)