From f774e4d841df041e19bc1ac680653b7c27b5ae16 Mon Sep 17 00:00:00 2001 From: ac-stef Date: Fri, 8 May 2015 16:32:16 +0200 Subject: [PATCH] higher resolution for entity attributes Interpret the values for entity yaw angles and clip entity sizes as fifths or tenths of cubes or degree. This makes some entity attributes appear as float values to the user. The map file still only keeps integer values - but now they are interpreted differently - for example, a health pack elevation value of 6 now means 0.6 cubes instead of 6. Note: the scaling factors are hardcoded - use ENTSCALE5 or ENTSCALE10 whereever possible. For generic entity editing, the scaling values are also stored in entscale[] - but that table can not be changed without breaking the map format! This scaling is similar to the treatment of the vdelta values of map cubes. --- source/src/clientgame.cpp | 2 +- source/src/clients2c.cpp | 3 ++- source/src/editing.cpp | 10 ++++++--- source/src/entities.cpp | 46 +++++++++++++++++++-------------------- source/src/entity.h | 5 +++++ source/src/physics.cpp | 6 ++--- source/src/server.h | 43 ++++++++++++++++++++++++++++++++++++ source/src/world.cpp | 4 ++-- source/src/worldio.cpp | 42 ++++++++++++++++++++++++----------- 9 files changed, 115 insertions(+), 46 deletions(-) diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index de92bd3a..950cc1e1 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -660,7 +660,7 @@ void gotoplayerstart(playerent *d, entity *e) d->o.x = e->x; d->o.y = e->y; d->o.z = e->z; - d->yaw = e->attr1; + d->yaw = float(e->attr1) / ENTSCALE10; d->pitch = 0; d->roll = 0; } diff --git a/source/src/clients2c.cpp b/source/src/clients2c.cpp index 515e1764..96de285b 100644 --- a/source/src/clients2c.cpp +++ b/source/src/clients2c.cpp @@ -276,8 +276,9 @@ bool good_map() // call this function only at startmap { entity &e2 = ents[j]; if (e2.type < I_CLIPS || e2.type > I_AKIMBO || i == j) continue; + // only I_CLIPS, I_AMMO, I_GRENADE, I_HEALTH, I_HELMET, I_ARMOUR, I_AKIMBO #define DIST(x) (e1.x - e2.x) -#define DIST_ATT ((e1.z + e1.attr1) - (e2.z + e2.attr1)) +#define DIST_ATT ((e1.z + float(e1.attr1) / entscale[e1.type][0]) - (e2.z + float(e2.attr1) / entscale[e2.type][0])) float r2 = DIST(x)*DIST(x) + DIST(y)*DIST(y) + DIST_ATT*DIST_ATT; #undef DIST_ATT #undef DIST diff --git a/source/src/editing.cpp b/source/src/editing.cpp index d22fea93..68a939b4 100644 --- a/source/src/editing.cpp +++ b/source/src/editing.cpp @@ -105,7 +105,10 @@ char *editinfo() if(e >= 0) { entity &c = ents[e]; - formatstring(info)("closest entity = %s (%d, %d, %d, %d, %d, %d, %d), ", entnames[c.type], c.attr1, c.attr2, c.attr3, c.attr4, c.attr5, c.attr6, c.attr7); + 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)); + #undef AA } if(selset()) concatformatstring(info, "selection = (%d, %d)", (sels.last()).xs, (sels.last()).ys); else concatformatstring(info, "no selection"); @@ -378,7 +381,7 @@ void gotoentity(int *n) player1->o.x = ents[*n].x; player1->o.y = ents[*n].y; player1->o.z = ents[*n].z; - player1->yaw = (ents[*n].attr1 % 360 + 360) % 360; // works for most ;) + player1->yaw = ((ents[*n].attr1 / ENTSCALE10) % 360 + 360) % 360; // works for most ;) player1->pitch = 0; player1->resetinterp(); } @@ -984,7 +987,7 @@ 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) { EDITMP; @@ -1032,3 +1035,4 @@ void transformclipentities() // transforms all clip entities to tag clips, if t } COMMAND(transformclipentities, ""); +#endif diff --git a/source/src/entities.cpp b/source/src/entities.cpp index efde1907..424c26fc 100644 --- a/source/src/entities.cpp +++ b/source/src/entities.cpp @@ -8,28 +8,28 @@ VAR(showmodelclipping, 0, 0, 1); vector ents; vector eh_ents; // edithide entities const char *entmdlnames[] = - { - "pistolclips", "ammobox", "nade", "health", "helmet", "kevlar", "akimbo", "nades", //FIXME - }; +{ + "pistolclips", "ammobox", "nade", "health", "helmet", "kevlar", "akimbo", "nades" //FIXME +}; - void renderent(entity &e) - { - /* FIXME: if the item list change, this hack will be messed */ +void renderent(entity &e) +{ + /* FIXME: if the item list change, this hack will be messed */ - defformatstring(widn)("modmdlpickup%d", e.type-3); - defformatstring(mdlname)("pickups/%s", identexists(widn)?getalias(widn): + defformatstring(widn)("modmdlpickup%d", e.type-3); + defformatstring(mdlname)("pickups/%s", identexists(widn)?getalias(widn): - entmdlnames[e.type-I_CLIPS+(m_lss && e.type==I_GRENADE ? 5:0)]); + entmdlnames[e.type-I_CLIPS+(m_lss && e.type==I_GRENADE ? 5:0)]); - float z = (float)(1+sinf(lastmillis/100.0f+e.x+e.y)/20), yaw = lastmillis/10.0f; - rendermodel(mdlname, ANIM_MAPMODEL|ANIM_LOOP|ANIM_DYNALLOC, 0, 0, vec(e.x, e.y, z+S(e.x, e.y)->floor+e.attr1), 0, yaw, 0); - } + float z = (float)(1+sinf(lastmillis/100.0f+e.x+e.y)/20), yaw = lastmillis/10.0f; + rendermodel(mdlname, ANIM_MAPMODEL|ANIM_LOOP|ANIM_DYNALLOC, 0, 0, vec(e.x, e.y, z+S(e.x, e.y)->floor + float(e.attr1) / ENTSCALE10), 0, yaw, 0); +} void renderclip(entity &e) { - float xradius = max(float(e.attr2), 0.1f), yradius = max(float(e.attr3), 0.1f); - vec bbmin(e.x - xradius, e.y - yradius, float(S(e.x, e.y)->floor+e.attr1)), - bbmax(e.x + xradius, e.y + yradius, bbmin.z + max(float(e.attr4), 0.1f)); + float xradius = max(float(e.attr2) / ENTSCALE5, 0.1f), yradius = max(float(e.attr3) / ENTSCALE5, 0.1f); + vec bbmin(e.x - xradius, e.y - yradius, float(S(e.x, e.y)->floor + float(e.attr1) / ENTSCALE10)), + bbmax(e.x + xradius, e.y + yradius, bbmin.z + max(float(e.attr4) / ENTSCALE5, 0.1f)); glDisable(GL_TEXTURE_2D); switch(e.type) @@ -67,7 +67,7 @@ void rendermapmodels() { mapmodelinfo &mmi = getmminfo(e.attr2); if(!&mmi) continue; - rendermodel(mmi.name, ANIM_MAPMODEL|ANIM_LOOP, e.attr4, 0, vec(e.x, e.y, (float)S(e.x, e.y)->floor+mmi.zoff+e.attr3), e.attr6, e.attr1 / 4.0f, e.attr5 / 4.0f, 10.0f); + rendermodel(mmi.name, ANIM_MAPMODEL|ANIM_LOOP, e.attr4, 0, vec(e.x, e.y, S(e.x, e.y)->floor + mmi.zoff + float(e.attr3) / ENTSCALE5), e.attr6, float(e.attr1) / ENTSCALE10, float(e.attr5) / ENTSCALE10, 10.0f); } } } @@ -218,7 +218,7 @@ void renderentities() if(e.type==CTF_FLAG) { defformatstring(path)("pickups/flags/%s", team_basestring(e.attr2)); - rendermodel(path, ANIM_FLAG|ANIM_LOOP, 0, 0, vec(e.x, e.y, (float)S(e.x, e.y)->floor), 0, e.attr1 / 4.0f, 0, 120.0f); + rendermodel(path, ANIM_FLAG|ANIM_LOOP, 0, 0, vec(e.x, e.y, (float)S(e.x, e.y)->floor), 0, float(e.attr1) / ENTSCALE10, 0, 120.0f); } else if((e.type == CLIP || e.type == PLCLIP) && showclips && !stenciling) renderclip(e); else if(e.type == MAPMODEL && showclips && showmodelclipping && !stenciling) @@ -228,9 +228,9 @@ void renderentities() { entity ce = e; ce.type = MAPMODEL; - ce.attr1 = mmi.zoff+e.attr3; - ce.attr2 = ce.attr3 = mmi.rad; - ce.attr4 = mmi.h; + ce.attr1 = (mmi.zoff + float(e.attr3) / ENTSCALE5) * ENTSCALE10; + ce.attr2 = ce.attr3 = mmi.rad * ENTSCALE5; + ce.attr4 = mmi.h * ENTSCALE5; renderclip(ce); } } @@ -243,7 +243,7 @@ void renderentities() { glColor3f(0, 1, 1); vec dir; - vecfromyawpitch(e.attr1, 0, -1, 0, dir); + vecfromyawpitch(float(e.attr1) / ENTSCALE10, 0, -1, 0, dir); renderentarrow(e, dir, 4); glColor3f(1, 1, 1); } @@ -271,7 +271,7 @@ void renderentities() if(OUTBORD(f.pos.x, f.pos.y)) break; entity &e = *f.flagent; defformatstring(path)("pickups/flags/%s%s", m_ktf ? "" : team_basestring(i), m_htf ? "_htf" : m_ktf ? "ktf" : ""); - if(f.flagent->spawned) rendermodel(path, ANIM_FLAG|ANIM_LOOP, 0, 0, vec(f.pos.x, f.pos.y, f.state==CTFF_INBASE ? (float)S(int(f.pos.x), int(f.pos.y))->floor : f.pos.z), 0, e.attr1 / 4.0f, 0, 120.0f); + if(f.flagent->spawned) rendermodel(path, ANIM_FLAG|ANIM_LOOP, 0, 0, vec(f.pos.x, f.pos.y, f.state==CTFF_INBASE ? (float)S(int(f.pos.x), int(f.pos.y))->floor : f.pos.z), 0, float(e.attr1) / ENTSCALE10, 0, 120.0f); break; } case CTFF_IDLE: @@ -426,7 +426,7 @@ void checkitems(playerent *d) if(e.type==CTF_FLAG) continue; // simple 2d collision vec v(e.x, e.y, S(e.x, e.y)->floor+eyeheight); - if(isitem(e.type)) v.z += e.attr1; + if(isitem(e.type)) v.z += float(e.attr1) / ENTSCALE10; if(d->o.dist(v)<2.5f) trypickup(i, d); } if(m_flags) loopi(2) diff --git a/source/src/entity.h b/source/src/entity.h index 190aca85..46a362c8 100644 --- a/source/src/entity.h +++ b/source/src/entity.h @@ -15,6 +15,11 @@ enum // static entity types MAXENTTYPES }; +extern short entwraparound[MAXENTTYPES][7]; +extern uchar entscale[MAXENTTYPES][7]; +#define ENTSCALE10 10 +#define ENTSCALE5 5 + enum {MAP_IS_BAD, MAP_IS_EDITABLE, MAP_IS_GOOD}; extern const char *entnames[]; diff --git a/source/src/physics.cpp b/source/src/physics.cpp index 87395c7e..1c3975ab 100644 --- a/source/src/physics.cpp +++ b/source/src/physics.cpp @@ -139,9 +139,9 @@ bool mmcollide(physent *d, float &hi, float &lo) // collide with a map // if(e.type==CLIP || (e.type == PLCLIP && d->type == ENT_PLAYER)) if (e.type==CLIP || (e.type == PLCLIP && (d->type == ENT_BOT || d->type == ENT_PLAYER || (d->type == ENT_BOUNCE && ((bounceent *)d)->plclipped)))) // don't allow bots to hack themselves into plclips - Bukz 2011/04/14 { - if(fabs(e.x-d->o.x) < e.attr2 + d->radius && fabs(e.y-d->o.y) < e.attr3 + d->radius) + if(fabs(e.x-d->o.x) < float(e.attr2) / ENTSCALE5 + d->radius && fabs(e.y-d->o.y) < float(e.attr3) / ENTSCALE5 + d->radius) { - const float cz = float(S(e.x, e.y)->floor+e.attr1), ch = float(e.attr4); + const float cz = float(S(e.x, e.y)->floor + float(e.attr1) / ENTSCALE10), ch = float(e.attr4) / ENTSCALE5; const float dz = d->o.z-d->eyeheight; if(dz < cz - 0.42) { if(czlo) lo = cz+ch; @@ -155,7 +155,7 @@ bool mmcollide(physent *d, float &hi, float &lo) // collide with a map const float r = mmi.rad+d->radius; if(fabs(e.x-d->o.x)o.y)floor+mmi.zoff+e.attr3); + const float mmz = float(S(e.x, e.y)->floor + mmi.zoff + float(e.attr3) / ENTSCALE5); const float dz = d->o.z-eyeheight; if(dz < mmz - 0.42) { if(mmz < hi) hi = mmz; } else if(mmz+mmi.h>lo) lo = mmz+mmi.h; diff --git a/source/src/server.h b/source/src/server.h index 8b4f126a..e2683466 100644 --- a/source/src/server.h +++ b/source/src/server.h @@ -451,6 +451,49 @@ const char *entnames[] = "mapmodel", "trigger", "ladder", "ctf-flag", "sound", "clip", "plclip", "" }; +// entity attribute scaling and wraparound definitions for mapformat 10 +short entwraparound[MAXENTTYPES][7] = +{ // limit angles to 0..359 degree and mapsound slot numbers to 0..255 + { 0, 0, 0, 0, 0, 0, 0 }, // deleted + { 0, 0, 0, 0, 0, 0, 0 }, // light + { 3600, 0, 0, 0, 0, 0, 0 }, // playerstart + { 0, 0, 0, 0, 0, 0, 0 }, // pistol + { 0, 0, 0, 0, 0, 0, 0 }, // ammobox + { 0, 0, 0, 0, 0, 0, 0 }, // grenades + { 0, 0, 0, 0, 0, 0, 0 }, // health + { 0, 0, 0, 0, 0, 0, 0 }, // helmet + { 0, 0, 0, 0, 0, 0, 0 }, // armour + { 0, 0, 0, 0, 0, 0, 0 }, // akimbo + { 3600, 0, 0, 0, 3600, 0, 0 }, // mapmodel + { 0, 0, 0, 0, 0, 0, 0 }, // trigger + { 0, 0, 0, 0, 0, 0, 0 }, // ladder + { 3600, 0, 0, 0, 0, 0, 0 }, // ctf-flag + { 256, 0, 0, 0, 0, 0, 0 }, // sound + { 0, 0, 0, 0, 0, 0, 0 }, // clip + { 0, 0, 0, 0, 0, 0, 0 } // plclip +}; + +uchar entscale[MAXENTTYPES][7] = +{ // (no zeros allowed here!) + { 1, 1, 1, 1, 1, 1, 1 }, // deleted + { 1, 1, 1, 1, 1, 1, 1 }, // light + { 10, 1, 1, 1, 1, 1, 1 }, // playerstart + { 10, 1, 1, 1, 1, 1, 1 }, // pistol + { 10, 1, 1, 1, 1, 1, 1 }, // ammobox + { 10, 1, 1, 1, 1, 1, 1 }, // grenades + { 10, 1, 1, 1, 1, 1, 1 }, // health + { 10, 1, 1, 1, 1, 1, 1 }, // helmet + { 10, 1, 1, 1, 1, 1, 1 }, // armour + { 10, 1, 1, 1, 1, 1, 1 }, // akimbo + { 10, 1, 5, 1, 10, 1, 1 }, // mapmodel + { 1, 1, 1, 1, 1, 1, 1 }, // trigger + { 1, 1, 1, 1, 1, 1, 1 }, // ladder + { 10, 1, 1, 1, 1, 1, 1 }, // ctf-flag + { 1, 1, 1, 1, 1, 1, 1 }, // sound + { 10, 5, 5, 5, 1, 1, 1 }, // clip + { 10, 5, 5, 5, 1, 1, 1 } // plclip +}; + // see entity.h:61: struct itemstat { int add, start, max, sound; }; // Please update ./ac_website/htdocs/docs/introduction.html if these figures change. itemstat ammostats[NUMGUNS] = diff --git a/source/src/world.cpp b/source/src/world.cpp index 86c8bc2a..3cd432b4 100644 --- a/source/src/world.cpp +++ b/source/src/world.cpp @@ -297,8 +297,8 @@ entity *newentity(int index, int x, int y, int z, char *what, int v1, int v2, in case PLAYERSTART: case CTF_FLAG: e.attr2 = v1; - e.attr1 = (int)camera1->yaw; - if(type != PLAYERSTART) e.attr1 = (e.attr1 + 7 - (e.attr1 + 7) % 15) * 4; + e.attr1 = int(camera1->yaw * ENTSCALE10); + if(type != PLAYERSTART) e.attr1 = e.attr1 + 70 - (e.attr1 + 70) % 150; break; } syncentchanges(true); diff --git a/source/src/worldio.cpp b/source/src/worldio.cpp index eb7fd83c..5eda2eef 100644 --- a/source/src/worldio.cpp +++ b/source/src/worldio.cpp @@ -551,7 +551,7 @@ void save_world(char *mname, bool skipoptimise, bool addcomfort) ucharbuf hx = packheaderextras(addcomfort ? 0 : (1 << HX_EDITUNDO)); // if addcomfort -> add undos/redos int writeextra = 0; if(hx.maxlen) tmp.headersize += writeextra = clamp(hx.maxlen, 0, MAXHEADEREXTRA); - if(writeextra || skipoptimise) tmp.version = 10; // 9 and 10 are the same, but in 10 the headersize is reliable - if we don't need it, stick to 9 + if(writeextra || skipoptimise || true) tmp.version = 10; // use format 10, if required bool oldentityformat = tmp.version < 10; tmp.maprevision += advancemaprevision; DEBUG("version " << tmp.version << " headersize " << tmp.headersize << " entities " << tmp.numents << " factor " << tmp.sfactor << " revision " << tmp.maprevision); @@ -568,7 +568,16 @@ void save_world(char *mname, bool skipoptimise, bool addcomfort) { if(!ne--) break; persistent_entity tmp = ents[i]; - if(oldentityformat && tmp.type == MAPMODEL) tmp.attr1 = tmp.attr1 / 4; + if(oldentityformat && tmp.type < MAXENTTYPES) + { + tmp.attr1 = tmp.attr1 / entscale[tmp.type][0]; + tmp.attr2 = tmp.attr2 / entscale[tmp.type][1]; + tmp.attr3 = tmp.attr3 / entscale[tmp.type][2]; + tmp.attr4 = tmp.attr4 / entscale[tmp.type][3]; + tmp.attr5 = tmp.attr5 / entscale[tmp.type][4]; + tmp.attr6 = tmp.attr6 / entscale[tmp.type][5]; + tmp.attr7 = tmp.attr7 / entscale[tmp.type][6]; + } lilswap((short *)&tmp, 4); lilswap(&tmp.attr5, 1); f->write(&tmp, oldentityformat ? 12 : sizeof(persistent_entity)); @@ -696,7 +705,7 @@ bool load_world(char *mname) // still supports all map formats that have ents.shrink(0); loopi(3) numspawn[i] = 0; loopi(2) numflagspawn[i] = 0; - bool oldentityformat = hdr.version < 10; + bool oldentityformat = hdr.version < 10; // version < 10 have only 4 attributes and no scaling loopi(hdr.numents) { entity &e = ents.add(); @@ -705,22 +714,29 @@ bool load_world(char *mname) // still supports all map formats that have if(oldentityformat) e.attr5 = e.attr6 = e.attr7 = 0; else lilswap(&e.attr5, 1); e.spawned = false; - if(e.type == LIGHT) + 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 } transformoldentitytypes(hdr.version, e.type); - if(oldentityformat) + if(oldentityformat && e.type < MAXENTTYPES) { - switch(e.type) - { - case CTF_FLAG: - case MAPMODEL: - e.attr1 = e.attr1 + 7 - (e.attr1 + 7) % 15; // round the angle to the nearest 15-degree-step - e.attr1 = (e.attr1 % 360) * 4; // cut down to less that one rotation and set resolution to 0.25 degree - break; - } + if(e.type == CTF_FLAG || e.type == MAPMODEL) e.attr1 = e.attr1 + 7 - (e.attr1 + 7) % 15; // round the angle to the nearest 15-degree-step, like old versions did during rendering + if(e.type == LIGHT && e.attr1 < 0) e.attr1 = 0; // negative lights had no meaning before version 10 + int ov, ss; + #define SCALEATTR(x) \ + if((ss = entwraparound[e.type][x - 1] / entscale[e.type][x - 1])) e.attr##x = (int(e.attr##x) % ss + ss) % ss; \ + e.attr##x = ov = e.attr##x * entscale[e.type][x - 1]; \ + if(ov != e.attr##x) conoutf("overflow during conversion of attr%d of entity #%d (%s) - pls check before saving the map", x, i, entnames[e.type]); + SCALEATTR(1); + SCALEATTR(2); + SCALEATTR(3); + SCALEATTR(4); + SCALEATTR(5); + SCALEATTR(6); + SCALEATTR(7); + #undef SCALEATTR } if(e.type == PLAYERSTART && (e.attr2 == 0 || e.attr2 == 1 || e.attr2 == 100)) {