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)) {