From 0a1172b75f571685c264a8b9d8ee224bbf11381f Mon Sep 17 00:00:00 2001 From: xolatile Date: Wed, 6 Aug 2025 22:54:55 +0200 Subject: Please do not hate me, it makes sense... --- src/engine/physics.cpp | 773 ++++++++++++++++--------------------------------- 1 file changed, 245 insertions(+), 528 deletions(-) (limited to 'src/engine/physics.cpp') diff --git a/src/engine/physics.cpp b/src/engine/physics.cpp index b1b800a..a43e8b4 100644 --- a/src/engine/physics.cpp +++ b/src/engine/physics.cpp @@ -10,11 +10,9 @@ const int MAXCLIPPLANES = 1024; static clipplanes clipcache[MAXCLIPPLANES]; static int clipcacheversion = -2; -static inline clipplanes &getclipplanes(const cube &c, const ivec &o, int size, bool collide = true, int offset = 0) -{ +static inline clipplanes &getclipplanes(const cube &c, const ivec &o, int size, bool collide = true, int offset = 0) { clipplanes &p = clipcache[int(&c - worldroot)&(MAXCLIPPLANES-1)]; - if(p.owner != &c || p.version != clipcacheversion+offset) - { + if(p.owner != &c || p.version != clipcacheversion+offset) { p.owner = &c; p.version = clipcacheversion+offset; genclipplanes(c, o, size, p, collide); @@ -22,11 +20,9 @@ static inline clipplanes &getclipplanes(const cube &c, const ivec &o, int size, return p; } -void resetclipplanes() -{ +void resetclipplanes() { clipcacheversion += 2; - if(!clipcacheversion) - { + if(!clipcacheversion) { memclear(clipcache); clipcacheversion = 2; } @@ -36,24 +32,24 @@ void resetclipplanes() #define INTERSECTPLANES(setentry, exit) \ float enterdist = -1e16f, exitdist = 1e16f; \ - loopi(p.size) \ - { \ + loopi(p.size) { \ + \ float pdist = p.p[i].dist(v), facing = ray.dot(p.p[i]); \ - if(facing < 0) \ - { \ + if(facing < 0) { \ + \ pdist /= -facing; \ - if(pdist > enterdist) \ - { \ + if(pdist > enterdist) { \ + \ if(pdist > exitdist) exit; \ enterdist = pdist; \ setentry; \ } \ } \ - else if(facing > 0) \ - { \ + else if(facing > 0) { \ + \ pdist /= -facing; \ - if(pdist < exitdist) \ - { \ + if(pdist < exitdist) { \ + \ if(pdist < enterdist) exit; \ exitdist = pdist; \ } \ @@ -62,19 +58,19 @@ void resetclipplanes() } #define INTERSECTBOX(setentry, exit) \ - loop(i, 3) \ - { \ - if(ray[i]) \ - { \ + loop(i, 3) { \ + \ + if(ray[i]) { \ + \ float prad = fabs(p.r[i] * invray[i]), pdist = (p.o[i] - v[i]) * invray[i], pmin = pdist - prad, pmax = pdist + prad; \ - if(pmin > enterdist) \ - { \ + if(pmin > enterdist) { \ + \ if(pmin > exitdist) exit; \ enterdist = pmin; \ setentry; \ } \ - if(pmax < exitdist) \ - { \ + if(pmax < exitdist) { \ + \ if(pmax < enterdist) exit; \ exitdist = pmax; \ } \ @@ -84,8 +80,7 @@ void resetclipplanes() vec hitsurface; -static inline bool raycubeintersect(const clipplanes &p, const cube &c, const vec &v, const vec &ray, const vec &invray, float &dist) -{ +static inline bool raycubeintersect(const clipplanes &p, const cube &c, const vec &v, const vec &ray, const vec &invray, float &dist) { int entry = -1, bbentry = -1; INTERSECTPLANES(entry = i, return false); INTERSECTBOX(bbentry = i, return false); @@ -100,59 +95,50 @@ extern void entselectionbox(const entity &e, vec &eo, vec &es); float hitentdist; int hitent, hitorient; -static float disttoent(octaentities *oc, const vec &o, const vec &ray, float radius, int mode, extentity *t) -{ +static float disttoent(octaentities *oc, const vec &o, const vec &ray, float radius, int mode, extentity *t) { vec eo, es; int orient = -1; float dist = radius, f = 0.0f; const vector &ents = entities::getents(); - #define entintersect(mask, type, func) {\ - if((mode&(mask))==(mask)) loopv(oc->type) \ - { \ + if((mode&(mask))==(mask)) loopv(oc->type) { \ + \ extentity &e = *ents[oc->type[i]]; \ if(!(e.flags&EF_OCTA) || &e==t) continue; \ func; \ - if(f0 && vec(ray).mul(f).add(o).insidebb(oc->o, oc->size)) \ - { \ + if(f0 && vec(ray).mul(f).add(o).insidebb(oc->o, oc->size)) { \ + \ hitentdist = dist = f; \ hitent = oc->type[i]; \ hitorient = orient; \ } \ } \ } - entintersect(RAY_POLY, mapmodels, if(!mmintersect(e, o, ray, radius, mode, f)) continue; ); - entintersect(RAY_ENTS, other, entselectionbox(e, eo, es); if(!rayboxintersect(eo, es, o, ray, f, orient)) continue; ); - entintersect(RAY_ENTS, mapmodels, entselectionbox(e, eo, es); if(!rayboxintersect(eo, es, o, ray, f, orient)) continue; ); - return dist; } -static float disttooutsideent(const vec &o, const vec &ray, float radius, int mode, extentity *t) -{ +static float disttooutsideent(const vec &o, const vec &ray, float radius, int mode, extentity *t) { vec eo, es; int orient; float dist = radius, f = 0.0f; const vector &ents = entities::getents(); - loopv(outsideents) - { + loopv(outsideents) { extentity &e = *ents[outsideents[i]]; if(!(e.flags&EF_OCTA) || &e==t) continue; entselectionbox(e, eo, es); if(!rayboxintersect(eo, es, o, ray, f, orient)) continue; - if(f0) - { + if(f0) { hitentdist = dist = f; hitent = outsideents[i]; hitorient = orient; @@ -162,12 +148,10 @@ static float disttooutsideent(const vec &o, const vec &ray, float radius, int mo } // optimized shadow version -static float shadowent(octaentities *oc, const vec &o, const vec &ray, float radius, int mode, extentity *t) -{ +static float shadowent(octaentities *oc, const vec &o, const vec &ray, float radius, int mode, extentity *t) { float dist = radius, f = 0.0f; const vector &ents = entities::getents(); - loopv(oc->mapmodels) - { + loopv(oc->mapmodels) { extentity &e = *ents[oc->mapmodels[i]]; if(!(e.flags&EF_OCTA) || &e==t) continue; if(!mmintersect(e, o, ray, radius, mode, f)) continue; @@ -185,14 +169,14 @@ static float shadowent(octaentities *oc, const vec &o, const vec &ray, float rad ivec lsizemask(invray.x>0 ? 1 : 0, invray.y>0 ? 1 : 0, invray.z>0 ? 1 : 0); \ #define CHECKINSIDEWORLD \ - if(!insideworld(o)) \ - { \ + if(!insideworld(o)) { \ + \ float disttoworld = 0, exitworld = 1e16f; \ - loopi(3) \ - { \ + loopi(3) { \ + \ float c = v[i]; \ - if(c<0 || c>=worldsize) \ - { \ + if(c<0 || c>=worldsize) { \ + \ float d = ((invray[i]>0?0:worldsize)-c)*invray[i]; \ if(d<0) return (radius>0?radius:-1); \ disttoworld = max(disttoworld, 0.1f + d); \ @@ -207,15 +191,15 @@ static float shadowent(octaentities *oc, const vec &o, const vec &ray, float rad #define DOWNOCTREE(disttoent, earlyexit) \ cube *lc = levels[lshift]; \ - for(;;) \ - { \ + for(;;) { \ + \ lshift--; \ lc += octastep(x, y, z, lshift); \ - if(lc->ext && lc->ext->ents && lshift < elvl) \ - { \ + if(lc->ext && lc->ext->ents && lshift < elvl) { \ + \ float edist = disttoent(lc->ext->ents, o, ray, dent, mode, t); \ - if(edist < dent) \ - { \ + if(edist < dent) { \ + \ earlyexit return min(edist, dist); \ elvl = lshift; \ dent = min(dent, edist); \ @@ -246,103 +230,76 @@ static float shadowent(octaentities *oc, const vec &o, const vec &ray, float rad if(diff >= uint(worldsize)) exitworld; \ diff >>= lshift; \ if(!diff) exitworld; \ - do \ - { \ + do { \ + \ lshift++; \ diff >>= 1; \ } while(diff); -float raycube(const vec &o, const vec &ray, float radius, int mode, int size, extentity *t) -{ +float raycube(const vec &o, const vec &ray, float radius, int mode, int size, extentity *t) { if(ray.iszero()) return 0; - INITRAYCUBE; CHECKINSIDEWORLD; - int closest = -1, x = int(v.x), y = int(v.y), z = int(v.z); - for(;;) - { + for(;;) { DOWNOCTREE(disttoent, if(mode&RAY_SHADOW)); - int lsize = 1<0 || !(mode&RAY_SKIPFIRST)) && (((mode&RAY_EDITMAT) && c.material != MAT_AIR) || (!(mode&RAY_PASS) && lsize==size && !isempty(c)) || isentirelysolid(c) || - dent < dist)) - { + dent < dist)) { if(closest >= 0) { hitsurface = vec(0, 0, 0); hitsurface[closest] = ray[closest]>0 ? -1 : 1; } return min(dent, dist); } - ivec lo(x&(~0U<0 || !(mode&RAY_SKIPFIRST))) return min(dent, dist+f); } - FINDCLOSEST(closest = 0, closest = 1, closest = 2); - if(radius>0 && dist>=radius) return min(dent, dist); - UPOCTREE(return min(dent, radius>0 ? radius : dist)); } } // optimized version for lightmap shadowing... every cycle here counts!!! -float shadowray(const vec &o, const vec &ray, float radius, int mode, extentity *t) -{ +float shadowray(const vec &o, const vec &ray, float radius, int mode, extentity *t) { INITRAYCUBE; CHECKINSIDEWORLD; - - int side = O_BOTTOM, x = int(v.x), y = int(v.y), z = int(v.z); - for(;;) - { + int side = O_BOTTOM, x = int(v.x), y = int(v.y), z = int(v.z); (void) side; + for(;;) { DOWNOCTREE(shadowent, ); - cube &c = *lc; ivec lo(x&(~0U<= 0) - { + if(exitdist >= 0) { return dist+max(enterdist+0.1f, 0.0f); } } } - nextcube: FINDCLOSEST(side = O_RIGHT - lsizemask.x, side = O_FRONT - lsizemask.y, side = O_TOP - lsizemask.z); - if(dist>=radius) return dist; - UPOCTREE(return radius); } } // thread safe version -struct ShadowRayCache -{ +struct ShadowRayCache { clipplanes clipcache[MAXCLIPPLANES]; int version; - ShadowRayCache() : version(-1) {} }; @@ -350,65 +307,49 @@ ShadowRayCache *newshadowraycache() { return new ShadowRayCache; } void freeshadowraycache(ShadowRayCache *&cache) { delete cache; cache = NULL; } -void resetshadowraycache(ShadowRayCache *cache) -{ +void resetshadowraycache(ShadowRayCache *cache) { cache->version++; - if(!cache->version) - { + if(!cache->version) { memclear(cache->clipcache); cache->version = 1; } } -float shadowray(ShadowRayCache *cache, const vec &o, const vec &ray, float radius, int mode, extentity *t) -{ +float shadowray(ShadowRayCache *cache, const vec &o, const vec &ray, float radius, int mode, extentity *t) { INITRAYCUBE; CHECKINSIDEWORLD; - - int side = O_BOTTOM, x = int(v.x), y = int(v.y), z = int(v.z); - for(;;) - { + int side = O_BOTTOM, x = int(v.x), y = int(v.y), z = int(v.z); (void) side; + for(;;) { DOWNOCTREE(shadowent, ); - cube &c = *lc; ivec lo(x&(~0U<clipcache[int(&c - worldroot)&(MAXCLIPPLANES-1)]; if(p.owner != &c || p.version != cache->version) { p.owner = &c; p.version = cache->version; genclipplanes(c, lo, 1<= 0) - { + if(exitdist >= 0) { return dist+max(enterdist+0.1f, 0.0f); } } } - nextcube: FINDCLOSEST(side = O_RIGHT - lsizemask.x, side = O_FRONT - lsizemask.y, side = O_TOP - lsizemask.z); - if(dist>=radius) return dist; - UPOCTREE(return radius); } } -float rayent(const vec &o, const vec &ray, float radius, int mode, int size, int &orient, int &ent) -{ +float rayent(const vec &o, const vec &ray, float radius, int mode, int size, int &orient, int &ent) { hitent = -1; hitentdist = radius; hitorient = -1; float dist = raycube(o, ray, radius, mode, size); - if((mode&RAY_ENTS) == RAY_ENTS) - { + if((mode&RAY_ENTS) == RAY_ENTS) { float dent = disttooutsideent(o, ray, dist < 0 ? 1e16f : dist, mode, NULL); if(dent < 1e15f && (dist < 0 || dent < dist)) dist = dent; } @@ -417,8 +358,7 @@ float rayent(const vec &o, const vec &ray, float radius, int mode, int size, int return dist; } -float raycubepos(const vec &o, const vec &ray, vec &hitpos, float radius, int mode, int size) -{ +float raycubepos(const vec &o, const vec &ray, vec &hitpos, float radius, int mode, int size) { hitpos = ray; float dist = raycube(o, ray, radius, mode, size); if(radius>0 && dist>=radius) dist = radius; @@ -426,8 +366,7 @@ float raycubepos(const vec &o, const vec &ray, vec &hitpos, float radius, int mo return dist; } -bool raycubelos(const vec &o, const vec &dest, vec &hitpos) -{ +bool raycubelos(const vec &o, const vec &dest, vec &hitpos) { vec ray(dest); ray.sub(o); float mag = ray.magnitude(); @@ -436,8 +375,7 @@ bool raycubelos(const vec &o, const vec &dest, vec &hitpos) return distance >= mag; } -float rayfloor(const vec &o, vec &floor, int mode, float radius) -{ +float rayfloor(const vec &o, vec &floor, int mode, float radius) { if(o.z<=0) return -1; hitsurface = vec(0, 0, 1); float dist = raycube(o, vec(0, 0, -1), radius, mode); @@ -460,53 +398,42 @@ const float WALLZ = 0.2f; extern const float JUMPVEL = 125.0f; extern const float GRAVITY = 200.0f; -bool ellipseboxcollide(physent *d, const vec &dir, const vec &o, const vec ¢er, float yaw, float xr, float yr, float hi, float lo) -{ +bool ellipseboxcollide(physent *d, const vec &dir, const vec &o, const vec ¢er, float yaw, float xr, float yr, float hi, float lo) { float below = (o.z+center.z-lo) - (d->o.z+d->aboveeye), above = (d->o.z-d->eyeheight) - (o.z+center.z+hi); if(below>=0 || above>=0) return false; - vec yo(d->o); yo.sub(o); yo.rotate_around_z(-yaw*RAD); yo.sub(center); - float dx = clamp(yo.x, -xr, xr) - yo.x, dy = clamp(yo.y, -yr, yr) - yo.y, dist = sqrtf(dx*dx + dy*dy) - d->radius; - if(dist < 0) - { + if(dist < 0) { int sx = yo.x <= -xr ? -1 : (yo.x >= xr ? 1 : 0), sy = yo.y <= -yr ? -1 : (yo.y >= yr ? 1 : 0); - if(dist > (yo.z < 0 ? below : above) && (sx || sy)) - { + if(dist > (yo.z < 0 ? below : above) && (sx || sy)) { vec ydir(dir); ydir.rotate_around_z(-yaw*RAD); - if(sx*yo.x - xr > sy*yo.y - yr) - { - if(dir.iszero() || sx*ydir.x < -1e-6f) - { + if(sx*yo.x - xr > sy*yo.y - yr) { + if(dir.iszero() || sx*ydir.x < -1e-6f) { collidewall = vec(sx, 0, 0); collidewall.rotate_around_z(yaw*RAD); return true; } } - else if(dir.iszero() || sy*ydir.y < -1e-6f) - { + else if(dir.iszero() || sy*ydir.y < -1e-6f) { collidewall = vec(0, sy, 0); collidewall.rotate_around_z(yaw*RAD); return true; } } - if(yo.z < 0) - { - if(dir.iszero() || (dir.z > 0 && (d->type>=ENT_INANIMATE || below >= d->zmargin-(d->eyeheight+d->aboveeye)/4.0f))) - { + if(yo.z < 0) { + if(dir.iszero() || (dir.z > 0 && (d->type>=ENT_INANIMATE || below >= d->zmargin-(d->eyeheight+d->aboveeye)/4.0f))) { collidewall = vec(0, 0, -1); return true; } } - else if(dir.iszero() || (dir.z < 0 && (d->type>=ENT_INANIMATE || above >= d->zmargin-(d->eyeheight+d->aboveeye)/3.0f))) - { + else if(dir.iszero() || (dir.z < 0 && (d->type>=ENT_INANIMATE || above >= d->zmargin-(d->eyeheight+d->aboveeye)/3.0f))) { collidewall = vec(0, 0, 1); return true; } @@ -515,8 +442,7 @@ bool ellipseboxcollide(physent *d, const vec &dir, const vec &o, const vec ¢ return false; } -bool ellipsecollide(physent *d, const vec &dir, const vec &o, const vec ¢er, float yaw, float xr, float yr, float hi, float lo) -{ +bool ellipsecollide(physent *d, const vec &dir, const vec &o, const vec ¢er, float yaw, float xr, float yr, float hi, float lo) { float below = (o.z+center.z-lo) - (d->o.z+d->aboveeye), above = (d->o.z-d->eyeheight) - (o.z+center.z+hi); if(below>=0 || above>=0) return false; @@ -528,24 +454,19 @@ bool ellipsecollide(physent *d, const vec &dir, const vec &o, const vec ¢er, float dx = d->xradius*cosf(dangle), dy = d->yradius*sinf(dangle); float ex = xr*cosf(eangle), ey = yr*sinf(eangle); float dist = sqrtf(x*x + y*y) - sqrtf(dx*dx + dy*dy) - sqrtf(ex*ex + ey*ey); - if(dist < 0) - { - if(dist > (d->o.z < yo.z ? below : above) && (dir.iszero() || x*dir.x + y*dir.y > 0)) - { + if(dist < 0) { + if(dist > (d->o.z < yo.z ? below : above) && (dir.iszero() || x*dir.x + y*dir.y > 0)) { collidewall = vec(-x, -y, 0); if(!collidewall.iszero()) collidewall.normalize(); return true; } - if(d->o.z < yo.z) - { - if(dir.iszero() || (dir.z > 0 && (d->type>=ENT_INANIMATE || below >= d->zmargin-(d->eyeheight+d->aboveeye)/4.0f))) - { + if(d->o.z < yo.z) { + if(dir.iszero() || (dir.z > 0 && (d->type>=ENT_INANIMATE || below >= d->zmargin-(d->eyeheight+d->aboveeye)/4.0f))) { collidewall = vec(0, 0, -1); return true; } } - else if(dir.iszero() || (dir.z < 0 && (d->type>=ENT_INANIMATE || above >= d->zmargin-(d->eyeheight+d->aboveeye)/3.0f))) - { + else if(dir.iszero() || (dir.z < 0 && (d->type>=ENT_INANIMATE || above >= d->zmargin-(d->eyeheight+d->aboveeye)/3.0f))) { collidewall = vec(0, 0, 1); return true; } @@ -558,15 +479,13 @@ bool ellipsecollide(physent *d, const vec &dir, const vec &o, const vec ¢er, static uint dynentframe = 0; -static struct dynentcacheentry -{ +static struct dynentcacheentry { int x, y; uint frame; vector dynents; } dynentcache[DYNENTCACHESIZE]; -void cleardynentcache() -{ +void cleardynentcache() { dynentframe++; if(!dynentframe || dynentframe == 1) loopi(DYNENTCACHESIZE) dynentcache[i].frame = 0; if(!dynentframe) dynentframe = 1; @@ -576,8 +495,7 @@ VARF(dynentsize, 4, 7, 12, cleardynentcache()); #define DYNENTHASH(x, y) (((((x)^(y))<<5) + (((x)^(y))>>5)) & (DYNENTCACHESIZE - 1)) -const vector &checkdynentcache(int x, int y) -{ +const vector &checkdynentcache(int x, int y) { dynentcacheentry &dec = dynentcache[DYNENTHASH(x, y)]; if(dec.x == x && dec.y == y && dec.frame == dynentframe) return dec.dynents; dec.x = x; @@ -585,8 +503,7 @@ const vector &checkdynentcache(int x, int y) dec.frame = dynentframe; dec.dynents.shrink(0); int numdyns = game::numdynents(), dsize = 1<state != CS_ALIVE || d->o.x+d->radius <= dx || d->o.x-d->radius >= dx+dsize || @@ -601,23 +518,18 @@ const vector &checkdynentcache(int x, int y) for(int curx = max(int(o.x-radius), 0)>>dynentsize, endx = min(int(o.x+radius), worldsize-1)>>dynentsize; curx <= endx; curx++) \ for(int cury = max(int(o.y-radius), 0)>>dynentsize, endy = min(int(o.y+radius), worldsize-1)>>dynentsize; cury <= endy; cury++) -void updatedynentcache(physent *d) -{ - loopdynentcache(x, y, d->o, d->radius) - { +void updatedynentcache(physent *d) { + loopdynentcache(x, y, d->o, d->radius) { dynentcacheentry &dec = dynentcache[DYNENTHASH(x, y)]; if(dec.x != x || dec.y != y || dec.frame != dynentframe || dec.dynents.find(d) >= 0) continue; dec.dynents.add(d); } } -bool overlapsdynent(const vec &o, float radius) -{ - loopdynentcache(x, y, o, radius) - { +bool overlapsdynent(const vec &o, float radius) { + loopdynentcache(x, y, o, radius) { const vector &dynents = checkdynentcache(x, y); - loopv(dynents) - { + loopv(dynents) { physent *d = dynents[i]; if(o.dist(d->o)-d->radius < radius) return true; } @@ -626,13 +538,11 @@ bool overlapsdynent(const vec &o, float radius) } template -static inline bool plcollide(physent *d, const vec &dir, physent *o) -{ +static inline bool plcollide(physent *d, const vec &dir, physent *o) { E entvol(d); O obvol(o); vec cp; - if(mpr::collide(entvol, obvol, NULL, NULL, &cp)) - { + if(mpr::collide(entvol, obvol, NULL, NULL, &cp)) { vec wn = vec(cp).sub(obvol.center()); collidewall = obvol.contactface(wn, dir.iszero() ? vec(wn).neg() : dir); if(!collidewall.iszero()) return true; @@ -641,10 +551,8 @@ static inline bool plcollide(physent *d, const vec &dir, physent *o) return false; } -static inline bool plcollide(physent *d, const vec &dir, physent *o) -{ - switch(d->collidetype) - { +static inline bool plcollide(physent *d, const vec &dir, physent *o) { + switch(d->collidetype) { case COLLIDE_ELLIPSE: case COLLIDE_ELLIPSE_PRECISE: if(o->collidetype == COLLIDE_OBB) return ellipseboxcollide(d, dir, o->o, vec(0, 0, 0), o->yaw, o->xradius, o->yradius, o->aboveeye, o->eyeheight); @@ -656,33 +564,27 @@ static inline bool plcollide(physent *d, const vec &dir, physent *o) } } -bool plcollide(physent *d, const vec &dir, bool insideplayercol) // collide with player or monster -{ +bool plcollide(physent *d, const vec &dir, bool insideplayercol) { // collide with player or monster { if(d->type==ENT_CAMERA || d->state!=CS_ALIVE) return false; int lastinside = collideinside; physent *insideplayer = NULL; - loopdynentcache(x, y, d->o, d->radius) - { + loopdynentcache(x, y, d->o, d->radius) { const vector &dynents = checkdynentcache(x, y); - loopv(dynents) - { + loopv(dynents) { physent *o = dynents[i]; if(o==d || d->o.reject(o->o, d->radius+o->radius)) continue; - if(plcollide(d, dir, o)) - { + if(plcollide(d, dir, o)) { collideplayer = o; game::dynentcollide(d, o, collidewall); return true; } - if(collideinside > lastinside) - { + if(collideinside > lastinside) { lastinside = collideinside; insideplayer = o; } } } - if(insideplayer && insideplayercol) - { + if(insideplayer && insideplayercol) { collideplayer = insideplayer; game::dynentcollide(d, insideplayer, vec(0, 0, 0)); return true; @@ -690,8 +592,7 @@ bool plcollide(physent *d, const vec &dir, bool insideplayercol) // collide with return false; } -void rotatebb(vec ¢er, vec &radius, int yaw) -{ +void rotatebb(vec ¢er, vec &radius, int yaw) { if(yaw < 0) yaw = 360 + yaw%360; else if(yaw >= 360) yaw %= 360; const vec2 &rot = sincos360[yaw]; @@ -703,13 +604,11 @@ void rotatebb(vec ¢er, vec &radius, int yaw) } template -static inline bool mmcollide(physent *d, const vec &dir, const extentity &e, const vec ¢er, const vec &radius, float yaw) -{ +static inline bool mmcollide(physent *d, const vec &dir, const extentity &e, const vec ¢er, const vec &radius, float yaw) { E entvol(d); M mdlvol(e.o, center, radius, yaw); vec cp; - if(mpr::collide(entvol, mdlvol, NULL, NULL, &cp)) - { + if(mpr::collide(entvol, mdlvol, NULL, NULL, &cp)) { vec wn = vec(cp).sub(mdlvol.center()); collidewall = mdlvol.contactface(wn, dir.iszero() ? vec(wn).neg() : dir); if(!collidewall.iszero()) return true; @@ -718,34 +617,27 @@ static inline bool mmcollide(physent *d, const vec &dir, const extentity &e, con return false; } -bool mmcollide(physent *d, const vec &dir, octaentities &oc) // collide with a mapmodel -{ +bool mmcollide(physent *d, const vec &dir, octaentities &oc) { // collide with a mapmodel { const vector &ents = entities::getents(); - loopv(oc.mapmodels) - { + loopv(oc.mapmodels) { extentity &e = *ents[oc.mapmodels[i]]; if(e.flags&EF_NOCOLLIDE) continue; model *m = loadmapmodel(e.attr2); if(!m || !m->collide) continue; - vec center, radius; float rejectradius = m->collisionbox(center, radius); if(d->o.reject(e.o, d->radius + rejectradius)) continue; - float yaw = e.attr1; - switch(d->collidetype) - { + switch(d->collidetype) { case COLLIDE_ELLIPSE: case COLLIDE_ELLIPSE_PRECISE: - if(m->ellipsecollide) - { + if(m->ellipsecollide) { if(ellipsecollide(d, dir, e.o, center, yaw, radius.x, radius.y, radius.z, radius.z)) return true; } else if(ellipseboxcollide(d, dir, e.o, center, yaw, radius.x, radius.y, radius.z, radius.z)) return true; break; case COLLIDE_OBB: - if(m->ellipsecollide) - { + if(m->ellipsecollide) { if(mmcollide(d, dir, e, center, radius, yaw)) return true; } else if(mmcollide(d, dir, e, center, radius, yaw)) return true; @@ -757,24 +649,22 @@ bool mmcollide(physent *d, const vec &dir, octaentities &oc) // collide wit } template -static bool fuzzycollidesolid(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size) // collide with solid cube geometry -{ +static bool fuzzycollidesolid(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size) { // collide with solid cube geometry { int crad = size/2; if(fabs(d->o.x - co.x - crad) > d->radius + crad || fabs(d->o.y - co.y - crad) > d->radius + crad || d->o.z + d->aboveeye < co.z || d->o.z - d->eyeheight > co.z + size) return false; - E entvol(d); collidewall = vec(0, 0, 0); float bestdist = -1e10f; int visible = isentirelysolid(c) ? c.visible : 0xFF; - #define CHECKSIDE(side, distval, dotval, margin, normal) if(visible&(1< 0) return false; \ if(dist <= bestdist) continue; \ - if(!dir.iszero()) \ - { \ + if(!dir.iszero()) { \ + \ if(dotval >= -cutoff*dir.magnitude()) continue; \ if(d->typeo.y - d->radius - (co.y + size), dir.y, -d->radius, vec(0, 1, 0)); CHECKSIDE(O_BOTTOM, co.z - (d->o.z + d->aboveeye), -dir.z, d->zmargin-(d->eyeheight+d->aboveeye)/4.0f, vec(0, 0, -1)); CHECKSIDE(O_TOP, d->o.z - d->eyeheight - (co.z + size), dir.z, d->zmargin-(d->eyeheight+d->aboveeye)/3.0f, vec(0, 0, 1)); - - if(collidewall.iszero()) - { + if(collidewall.iszero()) { collideinside++; return false; } @@ -797,24 +685,20 @@ static bool fuzzycollidesolid(physent *d, const vec &dir, float cutoff, const cu } template -static inline bool clampcollide(const clipplanes &p, const E &entvol, const plane &w, const vec &pw) -{ - if(w.x && (w.y || w.z) && fabs(pw.x - p.o.x) > p.r.x) - { +static inline bool clampcollide(const clipplanes &p, const E &entvol, const plane &w, const vec &pw) { + if(w.x && (w.y || w.z) && fabs(pw.x - p.o.x) > p.r.x) { vec c = entvol.center(); float fv = pw.x < p.o.x ? p.o.x-p.r.x : p.o.x+p.r.x, fdist = (w.x*fv + w.y*c.y + w.z*c.z + w.offset) / (w.y*w.y + w.z*w.z); vec fdir(fv - c.x, -w.y*fdist, -w.z*fdist); if((pw.y-c.y-fdir.y)*w.y + (pw.z-c.z-fdir.z)*w.z >= 0 && entvol.supportpoint(fdir).squaredist(c) < fdir.squaredlen()) return true; } - if(w.y && (w.x || w.z) && fabs(pw.y - p.o.y) > p.r.y) - { + if(w.y && (w.x || w.z) && fabs(pw.y - p.o.y) > p.r.y) { vec c = entvol.center(); float fv = pw.y < p.o.y ? p.o.y-p.r.y : p.o.y+p.r.y, fdist = (w.x*c.x + w.y*fv + w.z*c.z + w.offset) / (w.x*w.x + w.z*w.z); vec fdir(-w.x*fdist, fv - c.y, -w.z*fdist); if((pw.x-c.x-fdir.x)*w.x + (pw.z-c.z-fdir.z)*w.z >= 0 && entvol.supportpoint(fdir).squaredist(c) < fdir.squaredlen()) return true; } - if(w.z && (w.x || w.y) && fabs(pw.z - p.o.z) > p.r.z) - { + if(w.z && (w.x || w.y) && fabs(pw.z - p.o.z) > p.r.z) { vec c = entvol.center(); float fv = pw.z < p.o.z ? p.o.z-p.r.z : p.o.z+p.r.z, fdist = (w.x*c.x + w.y*c.y + w.z*fv + w.offset) / (w.x*w.x + w.y*w.y); vec fdir(-w.x*fdist, -w.y*fdist, fv - c.z); @@ -824,14 +708,11 @@ static inline bool clampcollide(const clipplanes &p, const E &entvol, const plan } template -static bool fuzzycollideplanes(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size) // collide with deformed cube geometry -{ +static bool fuzzycollideplanes(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size) { // collide with deformed cube geometry { const clipplanes &p = getclipplanes(c, co, size); - if(fabs(d->o.x - p.o.x) > p.r.x + d->radius || fabs(d->o.y - p.o.y) > p.r.y + d->radius || d->o.z + d->aboveeye < p.o.z - p.r.z || d->o.z - d->eyeheight > p.o.z + p.r.z) return false; - collidewall = vec(0, 0, 0); float bestdist = -1e10f; int visible = p.visible; @@ -841,11 +722,9 @@ static bool fuzzycollideplanes(physent *d, const vec &dir, float cutoff, const c CHECKSIDE(O_FRONT, d->o.y - d->radius - (p.o.y + p.r.y), dir.y, -d->radius, vec(0, 1, 0)); CHECKSIDE(O_BOTTOM, p.o.z - p.r.z - (d->o.z + d->aboveeye), -dir.z, d->zmargin-(d->eyeheight+d->aboveeye)/4.0f, vec(0, 0, -1)); CHECKSIDE(O_TOP, d->o.z - d->eyeheight - (p.o.z + p.r.z), dir.z, d->zmargin-(d->eyeheight+d->aboveeye)/3.0f, vec(0, 0, 1)); - E entvol(d); int bestplane = -1; - loopi(p.size) - { + loopi(p.size) { const plane &w = p.p[i]; vec pw = entvol.supportpoint(vec(w).neg()); float dist = w.dist(pw); @@ -853,8 +732,7 @@ static bool fuzzycollideplanes(physent *d, const vec &dir, float cutoff, const c if(dist <= bestdist) continue; bestplane = -1; bestdist = dist; - if(!dir.iszero()) - { + if(!dir.iszero()) { if(w.dot(dir) >= -cutoff*dir.magnitude()) continue; if(d->type= 0) collidewall = p.p[bestplane]; - else if(collidewall.iszero()) - { + else if(collidewall.iszero()) { collideinside++; return false; } @@ -875,17 +752,14 @@ static bool fuzzycollideplanes(physent *d, const vec &dir, float cutoff, const c } template -static bool cubecollidesolid(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size) // collide with solid cube geometry -{ +static bool cubecollidesolid(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size) { // collide with solid cube geometry { int crad = size/2; if(fabs(d->o.x - co.x - crad) > d->radius + crad || fabs(d->o.y - co.y - crad) > d->radius + crad || d->o.z + d->aboveeye < co.z || d->o.z - d->eyeheight > co.z + size) return false; - E entvol(d); bool collided = mpr::collide(mpr::SolidCube(co, size), entvol); if(!collided) return false; - collidewall = vec(0, 0, 0); float bestdist = -1e10f; int visible = isentirelysolid(c) ? c.visible : 0xFF; @@ -895,9 +769,7 @@ static bool cubecollidesolid(physent *d, const vec &dir, float cutoff, const cub CHECKSIDE(O_FRONT, entvol.back() - (co.y + size), dir.y, -d->radius, vec(0, 1, 0)); CHECKSIDE(O_BOTTOM, co.z - entvol.top(), -dir.z, d->zmargin-(d->eyeheight+d->aboveeye)/4.0f, vec(0, 0, -1)); CHECKSIDE(O_TOP, entvol.bottom() - (co.z + size), dir.z, d->zmargin-(d->eyeheight+d->aboveeye)/3.0f, vec(0, 0, 1)); - - if(collidewall.iszero()) - { + if(collidewall.iszero()) { collideinside++; return false; } @@ -905,18 +777,14 @@ static bool cubecollidesolid(physent *d, const vec &dir, float cutoff, const cub } template -static bool cubecollideplanes(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size) // collide with deformed cube geometry -{ +static bool cubecollideplanes(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size) { // collide with deformed cube geometry { const clipplanes &p = getclipplanes(c, co, size); - if(fabs(d->o.x - p.o.x) > p.r.x + d->radius || fabs(d->o.y - p.o.y) > p.r.y + d->radius || d->o.z + d->aboveeye < p.o.z - p.r.z || d->o.z - d->eyeheight > p.o.z + p.r.z) return false; - E entvol(d); bool collided = mpr::collide(mpr::CubePlanes(p), entvol); if(!collided) return false; - collidewall = vec(0, 0, 0); float bestdist = -1e10f; int visible = p.visible; @@ -926,18 +794,15 @@ static bool cubecollideplanes(physent *d, const vec &dir, float cutoff, const cu CHECKSIDE(O_FRONT, entvol.back() - (p.o.y + p.r.y), dir.y, -d->radius, vec(0, 1, 0)); CHECKSIDE(O_BOTTOM, p.o.z - p.r.z - entvol.top(), -dir.z, d->zmargin-(d->eyeheight+d->aboveeye)/4.0f, vec(0, 0, -1)); CHECKSIDE(O_TOP, entvol.bottom() - (p.o.z + p.r.z), dir.z, d->zmargin-(d->eyeheight+d->aboveeye)/3.0f, vec(0, 0, 1)); - int bestplane = -1; - loopi(p.size) - { + loopi(p.size) { const plane &w = p.p[i]; vec pw = entvol.supportpoint(vec(w).neg()); float dist = w.dist(pw); if(dist <= bestdist) continue; bestplane = -1; bestdist = dist; - if(!dir.iszero()) - { + if(!dir.iszero()) { if(w.dot(dir) >= -cutoff*dir.magnitude()) continue; if(d->type= 0) collidewall = p.p[bestplane]; - else if(collidewall.iszero()) - { + else if(collidewall.iszero()) { collideinside++; return false; } return true; } -static inline bool cubecollide(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size, bool solid) -{ - switch(d->collidetype) - { +static inline bool cubecollide(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size, bool solid) { + switch(d->collidetype) { case COLLIDE_OBB: if(isentirelysolid(c) || solid) return cubecollidesolid(d, dir, cutoff, c, co, size); else return cubecollideplanes(d, dir, cutoff, c, co, size); @@ -974,21 +836,16 @@ static inline bool cubecollide(physent *d, const vec &dir, float cutoff, const c } } -static inline bool octacollide(physent *d, const vec &dir, float cutoff, const ivec &bo, const ivec &bs, const cube *c, const ivec &cor, int size) // collide with octants -{ - loopoctabox(cor, size, bo, bs) - { +static inline bool octacollide(physent *d, const vec &dir, float cutoff, const ivec &bo, const ivec &bs, const cube *c, const ivec &cor, int size) { // collide with octants { + loopoctabox(cor, size, bo, bs) { if(c[i].ext && c[i].ext->ents) if(mmcollide(d, dir, *c[i].ext->ents)) return true; ivec o(i, cor, size); - if(c[i].children) - { + if(c[i].children) { if(octacollide(d, dir, cutoff, bo, bs, c[i].children, o, size>>1)) return true; } - else - { + else { bool solid = false; - switch(c[i].material&MATF_CLIP) - { + switch(c[i].material&MATF_CLIP) { case MAT_NOCLIP: continue; case MAT_GAMECLIP: if(d->type==ENT_AI) solid = true; break; case MAT_CLIP: if(d->type= uint(worldsize)) @@ -1009,16 +865,14 @@ static inline bool octacollide(physent *d, const vec &dir, float cutoff, const i const cube *c = &worldroot[octastep(bo.x, bo.y, bo.z, scale)]; if(c->ext && c->ext->ents && mmcollide(d, dir, *c->ext->ents)) return true; scale--; - while(c->children && !(diff&(1<children && !(diff&(1<children[octastep(bo.x, bo.y, bo.z, scale)]; if(c->ext && c->ext->ents && mmcollide(d, dir, *c->ext->ents)) return true; scale--; } if(c->children) return octacollide(d, dir, cutoff, bo, bs, c->children, ivec(bo).mask(~((2<material&MATF_CLIP) - { + switch(c->material&MATF_CLIP) { case MAT_NOCLIP: return false; case MAT_GAMECLIP: if(d->type==ENT_AI) solid = true; break; case MAT_CLIP: if(d->type 1e-6f) - { + if(speed > 1e-6f) { float step = dir.magnitude(); dir = d->vel; dir.add(d->falling); @@ -1052,11 +903,9 @@ void recalcdir(physent *d, const vec &oldvel, vec &dir) } } -void slideagainst(physent *d, vec &dir, const vec &obstacle, bool foundfloor, bool slidecollide) -{ +void slideagainst(physent *d, vec &dir, const vec &obstacle, bool foundfloor, bool slidecollide) { vec wall(obstacle); - if(foundfloor ? wall.z > 0 : slidecollide) - { + if(foundfloor ? wall.z > 0 : slidecollide) { wall.z = 0; if(!wall.iszero()) wall.normalize(); } @@ -1067,14 +916,11 @@ void slideagainst(physent *d, vec &dir, const vec &obstacle, bool foundfloor, bo recalcdir(d, oldvel, dir); } -void switchfloor(physent *d, vec &dir, const vec &floor) -{ +void switchfloor(physent *d, vec &dir, const vec &floor) { if(floor.z >= FLOORZ) d->falling = vec(0, 0, 0); - vec oldvel(d->vel); oldvel.add(d->falling); - if(dir.dot(floor) >= 0) - { + if(dir.dot(floor) >= 0) { if(d->physstate < PHYS_SLIDE || fabs(dir.dot(d->floor)) > 0.01f*dir.magnitude()) return; d->vel.projectxy(floor, 0.0f); } @@ -1083,57 +929,46 @@ void switchfloor(physent *d, vec &dir, const vec &floor) recalcdir(d, oldvel, dir); } -bool trystepup(physent *d, vec &dir, const vec &obstacle, float maxstep, const vec &floor) -{ +bool trystepup(physent *d, vec &dir, const vec &obstacle, float maxstep, const vec &floor) { vec old(d->o), stairdir = (obstacle.z >= 0 && obstacle.z < SLOPEZ ? vec(-obstacle.x, -obstacle.y, 0) : vec(dir.x, dir.y, 0)).rescale(1); bool cansmooth = true; /* check if there is space atop the stair to move to */ - if(d->physstate != PHYS_STEP_UP) - { + if(d->physstate != PHYS_STEP_UP) { vec checkdir = stairdir; checkdir.mul(0.1f); checkdir.z += maxstep + 0.1f; d->o.add(checkdir); - if(collide(d)) - { + if(collide(d)) { d->o = old; if(!collide(d, vec(0, 0, -1), SLOPEZ)) return false; cansmooth = false; } } - - if(cansmooth) - { + if(cansmooth) { vec checkdir = stairdir; checkdir.z += 1; checkdir.mul(maxstep); d->o = old; d->o.add(checkdir); int scale = 2; - if(collide(d, checkdir)) - { - if(!collide(d, vec(0, 0, -1), SLOPEZ)) - { + if(collide(d, checkdir)) { + if(!collide(d, vec(0, 0, -1), SLOPEZ)) { d->o = old; return false; } d->o.add(checkdir); if(collide(d, vec(0, 0, -1), SLOPEZ)) scale = 1; } - if(scale != 1) - { + if(scale != 1) { d->o = old; d->o.sub(checkdir.mul(vec(2, 2, 1))); if(!collide(d, vec(0, 0, -1), SLOPEZ)) scale = 1; } - d->o = old; vec smoothdir(dir.x, dir.y, 0); float magxy = smoothdir.magnitude(); - if(magxy > 1e-9f) - { - if(magxy > scale*dir.z) - { + if(magxy > 1e-9f) { + if(magxy > scale*dir.z) { smoothdir.mul(1/magxy); smoothdir.z = 1.0f/scale; smoothdir.mul(dir.magnitude()/smoothdir.magnitude()); @@ -1141,11 +976,9 @@ bool trystepup(physent *d, vec &dir, const vec &obstacle, float maxstep, const v else smoothdir.z = dir.z; d->o.add(smoothdir); d->o.z += maxstep + 0.1f; - if(!collide(d, smoothdir)) - { + if(!collide(d, smoothdir)) { d->o.z -= maxstep + 0.1f; - if(d->physstate == PHYS_FALL || d->floor != floor) - { + if(d->physstate == PHYS_FALL || d->floor != floor) { d->timeinair = 0; d->floor = floor; switchfloor(d, dir, d->floor); @@ -1155,14 +988,11 @@ bool trystepup(physent *d, vec &dir, const vec &obstacle, float maxstep, const v } } } - /* try stepping up */ d->o = old; d->o.z += dir.magnitude(); - if(!collide(d, vec(0, 0, 1))) - { - if(d->physstate == PHYS_FALL || d->floor != floor) - { + if(!collide(d, vec(0, 0, 1))) { + if(d->physstate == PHYS_FALL || d->floor != floor) { d->timeinair = 0; d->floor = floor; switchfloor(d, dir, d->floor); @@ -1174,34 +1004,28 @@ bool trystepup(physent *d, vec &dir, const vec &obstacle, float maxstep, const v return false; } -bool trystepdown(physent *d, vec &dir, float step, float xy, float z, bool init = false) -{ +bool trystepdown(physent *d, vec &dir, float step, float xy, float z, bool init = false) { vec stepdir(dir.x, dir.y, 0); stepdir.z = -stepdir.magnitude2()*z/xy; if(!stepdir.z) return false; stepdir.normalize(); - vec old(d->o); d->o.add(vec(stepdir).mul(STAIRHEIGHT/fabs(stepdir.z))).z -= STAIRHEIGHT; d->zmargin = -STAIRHEIGHT; - if(collide(d, vec(0, 0, -1), SLOPEZ)) - { + if(collide(d, vec(0, 0, -1), SLOPEZ)) { d->o = old; d->o.add(vec(stepdir).mul(step)); d->zmargin = 0; - if(!collide(d, vec(0, 0, -1))) - { + if(!collide(d, vec(0, 0, -1))) { vec stepfloor(stepdir); stepfloor.mul(-stepfloor.z).z += 1; stepfloor.normalize(); - if(d->physstate >= PHYS_SLOPE && d->floor != stepfloor) - { + if(d->physstate >= PHYS_SLOPE && d->floor != stepfloor) { // prevent alternating step-down/step-up states if player would keep bumping into the same floor vec stepped(d->o); d->o.z -= 0.5f; d->zmargin = -0.5f; - if(collide(d, stepdir) && collidewall == d->floor) - { + if(collide(d, stepdir) && collidewall == d->floor) { d->o = old; if(!init) { d->o.x += dir.x; d->o.y += dir.y; if(dir.z <= 0 || collide(d, dir)) d->o.z += dir.z; } d->zmargin = 0; @@ -1225,14 +1049,12 @@ bool trystepdown(physent *d, vec &dir, float step, float xy, float z, bool init return false; } -bool trystepdown(physent *d, vec &dir, bool init = false) -{ +bool trystepdown(physent *d, vec &dir, bool init = false) { if((!d->move && !d->strafe) || !game::allowmove(d)) return false; vec old(d->o); d->o.z -= STAIRHEIGHT; d->zmargin = -STAIRHEIGHT; - if(!collide(d, vec(0, 0, -1), SLOPEZ)) - { + if(!collide(d, vec(0, 0, -1), SLOPEZ)) { d->o = old; d->zmargin = 0; return false; @@ -1251,10 +1073,8 @@ bool trystepdown(physent *d, vec &dir, bool init = false) return false; } -void falling(physent *d, vec &dir, const vec &floor) -{ - if(floor.z > 0.0f && floor.z < SLOPEZ) - { +void falling(physent *d, vec &dir, const vec &floor) { + if(floor.z > 0.0f && floor.z < SLOPEZ) { if(floor.z >= WALLZ) switchfloor(d, dir, floor); d->timeinair = 0; d->physstate = PHYS_SLIDE; @@ -1264,11 +1084,9 @@ void falling(physent *d, vec &dir, const vec &floor) d->physstate = PHYS_FALL; } -void landing(physent *d, vec &dir, const vec &floor, bool collided) -{ +void landing(physent *d, vec &dir, const vec &floor, bool collided) { #if 0 - if(d->physstate == PHYS_FALL) - { + if(d->physstate == PHYS_FALL) { d->timeinair = 0; if(dir.z < 0.0f) dir.z = d->vel.z = 0.0f; } @@ -1280,40 +1098,32 @@ void landing(physent *d, vec &dir, const vec &floor, bool collided) d->floor = floor; } -bool findfloor(physent *d, bool collided, const vec &obstacle, bool &slide, vec &floor) -{ +bool findfloor(physent *d, bool collided, const vec &obstacle, bool &slide, vec &floor) { bool found = false; vec moved(d->o); d->o.z -= 0.1f; - if(collide(d, vec(0, 0, -1), d->physstate == PHYS_SLOPE || d->physstate == PHYS_STEP_DOWN ? SLOPEZ : FLOORZ)) - { + if(collide(d, vec(0, 0, -1), d->physstate == PHYS_SLOPE || d->physstate == PHYS_STEP_DOWN ? SLOPEZ : FLOORZ)) { floor = collidewall; found = true; } - else if(collided && obstacle.z >= SLOPEZ) - { + else if(collided && obstacle.z >= SLOPEZ) { floor = obstacle; found = true; slide = false; } - else if(d->physstate == PHYS_STEP_UP || d->physstate == PHYS_SLIDE) - { - if(collide(d, vec(0, 0, -1)) && collidewall.z > 0.0f) - { + else if(d->physstate == PHYS_STEP_UP || d->physstate == PHYS_SLIDE) { + if(collide(d, vec(0, 0, -1)) && collidewall.z > 0.0f) { floor = collidewall; if(floor.z >= SLOPEZ) found = true; } } - else if(d->physstate >= PHYS_SLOPE && d->floor.z < 1.0f) - { - if(collide(d, vec(d->floor).neg(), 0.95f) || collide(d, vec(0, 0, -1))) - { + else if(d->physstate >= PHYS_SLOPE && d->floor.z < 1.0f) { + if(collide(d, vec(d->floor).neg(), 0.95f) || collide(d, vec(0, 0, -1))) { floor = collidewall; if(floor.z >= SLOPEZ && floor.z < 1.0f) found = true; } } - if(collided && (!found || obstacle.z > floor.z)) - { + if(collided && (!found || obstacle.z > floor.z)) { floor = obstacle; slide = !found && (floor.z < WALLZ || floor.z >= SLOPEZ); } @@ -1321,49 +1131,41 @@ bool findfloor(physent *d, bool collided, const vec &obstacle, bool &slide, vec return found; } -bool move(physent *d, vec &dir) -{ +bool move(physent *d, vec &dir) { vec old(d->o); bool collided = false, slidecollide = false; vec obstacle = vec(0, 0, 0); d->o.add(dir); - if(collide(d, dir) || ((d->type==ENT_AI || d->type==ENT_INANIMATE) && collide(d, vec(0, 0, 0), 0, false))) - { + if(collide(d, dir) || ((d->type==ENT_AI || d->type==ENT_INANIMATE) && collide(d, vec(0, 0, 0), 0, false))) { obstacle = collidewall; /* check to see if there is an obstacle that would prevent this one from being used as a floor (or ceiling bump) */ - if(d->type==ENT_PLAYER && ((collidewall.z>=SLOPEZ && dir.z<0) || (collidewall.z<=-SLOPEZ && dir.z>0)) && (dir.x || dir.y) && collide(d, vec(dir.x, dir.y, 0))) - { + if(d->type==ENT_PLAYER && ((collidewall.z>=SLOPEZ && dir.z<0) || (collidewall.z<=-SLOPEZ && dir.z>0)) && (dir.x || dir.y) && collide(d, vec(dir.x, dir.y, 0))) { if(collidewall.dot(dir) >= 0) slidecollide = true; obstacle = collidewall; } d->o = old; d->o.z -= STAIRHEIGHT; d->zmargin = -STAIRHEIGHT; - if(d->physstate == PHYS_SLOPE || d->physstate == PHYS_FLOOR || (collide(d, vec(0, 0, -1), SLOPEZ) && (d->physstate==PHYS_STEP_UP || d->physstate==PHYS_STEP_DOWN || collidewall.z>=FLOORZ))) - { + if(d->physstate == PHYS_SLOPE || d->physstate == PHYS_FLOOR || (collide(d, vec(0, 0, -1), SLOPEZ) && (d->physstate==PHYS_STEP_UP || d->physstate==PHYS_STEP_DOWN || collidewall.z>=FLOORZ))) { d->o = old; d->zmargin = 0; if(trystepup(d, dir, obstacle, STAIRHEIGHT, d->physstate == PHYS_SLOPE || d->physstate == PHYS_FLOOR ? d->floor : vec(collidewall))) return true; } - else - { + else { d->o = old; d->zmargin = 0; } /* can't step over the obstacle, so just slide against it */ collided = true; } - else if(d->physstate == PHYS_STEP_UP) - { - if(collide(d, vec(0, 0, -1), SLOPEZ)) - { + else if(d->physstate == PHYS_STEP_UP) { + if(collide(d, vec(0, 0, -1), SLOPEZ)) { d->o = old; if(trystepup(d, dir, vec(0, 0, 1), STAIRHEIGHT, vec(collidewall))) return true; d->o.add(dir); } } - else if(d->physstate == PHYS_STEP_DOWN && dir.dot(d->floor) <= 1e-6f) - { + else if(d->physstate == PHYS_STEP_DOWN && dir.dot(d->floor) <= 1e-6f) { vec moved(d->o); d->o = old; if(trystepdown(d, dir)) return true; @@ -1372,8 +1174,7 @@ bool move(physent *d, vec &dir) vec floor(0, 0, 0); bool slide = collided, found = findfloor(d, collided, obstacle, slide, floor); - if(slide || (!collided && floor.z > 0 && floor.z < WALLZ)) - { + if(slide || (!collided && floor.z > 0 && floor.z < WALLZ)) { slideagainst(d, dir, slide ? obstacle : floor, found, slidecollide); //if(d->type == ENT_AI || d->type == ENT_INANIMATE) d->blocked = true; @@ -1383,21 +1184,17 @@ bool move(physent *d, vec &dir) return !collided; } -bool bounce(physent *d, float secs, float elasticity, float grav) -{ +bool bounce(physent *d, float secs, float elasticity, float grav) { // make sure bouncers don't start inside geometry if(d->physstate!=PHYS_BOUNCE && collide(d, vec(0, 0, 0), 0, false)) return true; d->vel.z -= grav*GRAVITY*secs; vec old(d->o); - loopi(2) - { + loopi(2) { vec dir(d->vel); dir.mul(secs); d->o.add(dir); - if(!collide(d, dir, 0, true, true)) - { - if(collideinside) - { + if(!collide(d, dir, 0, true, true)) { + if(collideinside) { d->o = old; d->vel.mul(-elasticity); } @@ -1411,8 +1208,7 @@ bool bounce(physent *d, float secs, float elasticity, float grav) d->vel.mul(k); d->vel.sub(vec(collidewall).mul(elasticity*2.0f*c)); } - if(d->physstate!=PHYS_BOUNCE) - { + if(d->physstate!=PHYS_BOUNCE) { // make sure bouncers don't start inside geometry if(d->o == old) return !collideplayer; d->physstate = PHYS_BOUNCE; @@ -1420,8 +1216,7 @@ bool bounce(physent *d, float secs, float elasticity, float grav) return collideplayer!=NULL; } -void avoidcollision(physent *d, const vec &dir, physent *obstacle, float space) -{ +void avoidcollision(physent *d, const vec &dir, physent *obstacle, float space) { float rad = obstacle->radius+d->radius; vec bbmin(obstacle->o); bbmin.x -= rad; @@ -1433,31 +1228,24 @@ void avoidcollision(physent *d, const vec &dir, physent *obstacle, float space) bbmax.y += rad; bbmax.z += obstacle->aboveeye+d->eyeheight; bbmax.add(space); - loopi(3) if(d->o[i] <= bbmin[i] || d->o[i] >= bbmax[i]) return; - float mindist = 1e16f; - loopi(3) if(dir[i] != 0) - { + loopi(3) if(dir[i] != 0) { float dist = ((dir[i] > 0 ? bbmax[i] : bbmin[i]) - d->o[i]) / dir[i]; mindist = min(mindist, dist); } if(mindist >= 0.0f && mindist < 1e15f) d->o.add(vec(dir).mul(mindist)); } -bool movecamera(physent *pl, const vec &dir, float dist, float stepdist) -{ +bool movecamera(physent *pl, const vec &dir, float dist, float stepdist) { int steps = (int)ceil(dist/stepdist); if(steps <= 0) return true; - vec d(dir); d.mul(dist/steps); - loopi(steps) - { + loopi(steps) { vec oldpos(pl->o); pl->o.add(d); - if(collide(pl, vec(0, 0, 0), 0, false)) - { + if(collide(pl, vec(0, 0, 0), 0, false)) { pl->o = oldpos; return false; } @@ -1465,22 +1253,18 @@ bool movecamera(physent *pl, const vec &dir, float dist, float stepdist) return true; } -void dropenttofloor(entity *e) -{ +void dropenttofloor(entity *e) { float radius = 1.0f; float height = 4.0f; vec o = e->o; - static struct dropent : physent - { - dropent() - { + static struct dropent : physent { + dropent() { type = ENT_BOUNCE; vel = vec(0, 0, -1); } } d; d.o = o; - if(!insideworld(d.o)) - { + if(!insideworld(d.o)) { if(d.o.z < worldsize) return; d.o.z = worldsize - 1e-3f; if(!insideworld(d.o)) return; @@ -1495,35 +1279,27 @@ void dropenttofloor(entity *e) o = d.o; } -void vecfromyawpitch(float yaw, float pitch, int move, int strafe, vec &m) -{ - if(move) - { +void vecfromyawpitch(float yaw, float pitch, int move, int strafe, vec &m) { + if(move) { m.x = move*-sinf(RAD*yaw); m.y = move*cosf(RAD*yaw); } else m.x = m.y = 0; - - if(pitch) - { + if(pitch) { m.x *= cosf(RAD*pitch); m.y *= cosf(RAD*pitch); m.z = move*sinf(RAD*pitch); } else m.z = 0; - - if(strafe) - { + if(strafe) { m.x += strafe*cosf(RAD*yaw); m.y += strafe*sinf(RAD*yaw); } } -void vectoyawpitch(const vec &v, float &yaw, float &pitch) -{ +void vectoyawpitch(const vec &v, float &yaw, float &pitch) { if(v.iszero()) yaw = pitch = 0; - else - { + else { yaw = -atan2(v.x, v.y)/RAD; pitch = asin(v.z/v.magnitude())/RAD; } @@ -1536,51 +1312,36 @@ FVAR(straferoll, 0, 0.033f, 90); FVAR(faderoll, 0, 0.95f, 1); VAR(floatspeed, 1, 100, 10000); -void modifyvelocity(physent *pl, bool local, bool floating, int curtime) -{ +void modifyvelocity(physent *pl, bool local, bool floating, int curtime) { bool allowmove = game::allowmove(pl); - if(floating) - { - if(pl->jumping && allowmove) - { + if(floating) { + if(pl->jumping && allowmove) { pl->jumping = false; pl->vel.z = max(pl->vel.z, JUMPVEL); } } - else if(pl->physstate >= PHYS_SLOPE) - { + else if(pl->physstate >= PHYS_SLOPE) { if(!pl->inwater) pl->vel.div(8); - if(pl->jumping && allowmove) - { + if(pl->jumping && allowmove) { pl->jumping = false; - pl->vel.z = max(pl->vel.z, JUMPVEL); // physics impulse upwards - game::physicstrigger(pl, local, 1); } } if(!floating && pl->physstate == PHYS_FALL) pl->timeinair = min(pl->timeinair + curtime, 1000); - vec m(0.0f, 0.0f, 0.0f); - if((pl->move || pl->strafe) && allowmove) - { + if((pl->move || pl->strafe) && allowmove) { vecfromyawpitch(pl->yaw, floating || pl->type==ENT_CAMERA ? pl->pitch : 0, pl->move, pl->strafe, m); - if(!floating && pl->physstate >= PHYS_SLOPE) m.z = -(m.x*pl->floor.x + m.y*pl->floor.y)/pl->floor.z; // move up or down slopes in air - m.normalize(); } - vec d(m); speedmodifier*=(pl->physstate!=PHYS_FLOOR)*(speedmodifier>0); speedmodifier=(speedmodifier>100.0f)?100.0f:speedmodifier; d.mul(pl->maxspeed + speedmodifier); - - if(pl->type==ENT_PLAYER) - { - if(floating) - { + if(pl->type==ENT_PLAYER) { + if(floating) { if(pl==player) d.mul(floatspeed/100.0f); } else if(allowmove) d.mul((pl->move && !pl->strafe ? 1.3f : 1.0f) * (pl->physstate < PHYS_SLOPE ? 1.3f : 1.0f)); @@ -1589,22 +1350,18 @@ void modifyvelocity(physent *pl, bool local, bool floating, int curtime) pl->vel.lerp(d, pl->vel, pow(1 - 1/fric, curtime/20.0f)); } -void modifygravity(physent *pl, int curtime) -{ +void modifygravity(physent *pl, int curtime) { float secs = curtime/1000.0f; vec g(0, 0, 0); if(pl->physstate == PHYS_FALL) g.z -= GRAVITY*secs; - else if(pl->floor.z > 0 && pl->floor.z < FLOORZ) - { + else if(pl->floor.z > 0 && pl->floor.z < FLOORZ) { g.z = -1; g.project(pl->floor); g.normalize(); g.mul(GRAVITY*secs); } if(!game::allowmove(pl) || (!pl->move && !pl->strafe)) pl->falling.add(g); - - if(pl->physstate >= PHYS_SLOPE) - { + if(pl->physstate >= PHYS_SLOPE) { float fric = 6.0f, c = clamp((pl->floor.z - SLOPEZ)/(FLOORZ-SLOPEZ), 0.0f, 1.0f); pl->falling.mul(pow(1 - c/fric, curtime/20.0f)); @@ -1615,71 +1372,53 @@ void modifygravity(physent *pl, int curtime) // moveres indicated the physics precision (which is lower for monsters and multiplayer prediction) // local is false for multiplayer prediction -bool moveplayer(physent *pl, int moveres, bool local, int curtime) -{ +bool moveplayer(physent *pl, int moveres, bool local, int curtime) { int material = lookupmaterial(vec(pl->o.x, pl->o.y, pl->o.z + (3*pl->aboveeye - pl->eyeheight)/4)); bool floating = pl->type==ENT_PLAYER && (pl->state==CS_EDITING || pl->state==CS_SPECTATOR); float secs = curtime/1000.f; - // apply gravity if(!floating) modifygravity(pl, curtime); // apply any player generated changes in velocity modifyvelocity(pl, local, floating, curtime); - vec d(pl->vel); if(!floating) d.mul(0.5f); d.add(pl->falling); d.mul(secs); - pl->blocked = false; - - if(floating) // just apply velocity - { - if(pl->physstate != PHYS_FLOAT) - { + if(floating) { // just apply velocity { + if(pl->physstate != PHYS_FLOAT) { pl->physstate = PHYS_FLOAT; pl->timeinair = 0; pl->falling = vec(0, 0, 0); } pl->o.add(d); } - else // apply velocity with collision - { + else { // apply velocity with collision { const float f = 1.0f/moveres; const int timeinair = pl->timeinair; int collisions = 0; - d.mul(f); loopi(moveres) if(!move(pl, d) && ++collisions<5) i--; // discrete steps collision detection & sliding - if(timeinair > 800 && !pl->timeinair) // if we land after long time must have been a high jump, make thud sound - { + if(timeinair > 800 && !pl->timeinair) { // if we land after long time must have been a high jump, make thud sound { game::physicstrigger(pl, local, -1); } } - if(pl->state==CS_ALIVE) updatedynentcache(pl); - // automatically apply smooth roll when strafing - if(pl->strafe && maxroll) pl->roll = clamp(pl->roll - pow(clamp(1.0f + pl->strafe*pl->roll/maxroll, 0.0f, 1.0f), 0.33f)*pl->strafe*curtime*straferoll, -maxroll, maxroll); else pl->roll *= curtime == PHYSFRAMETIME ? faderoll : pow(faderoll, curtime/float(PHYSFRAMETIME)); - if(pl->inwater) game::physicstrigger(pl, local, 0, pl->inwater); pl->inwater = MAT_AIR; - if(pl->state==CS_ALIVE && (pl->o.z < 0 || material&MAT_DEATH)) game::suicide(pl); - return true; } int physsteps = 0, physframetime = PHYSFRAMETIME, lastphysframe = 0; -void physicsframe() // optimally schedule physics frames inside the graphics frames -{ +void physicsframe() { // optimally schedule physics frames inside the graphics frames { int diff = lastmillis - lastphysframe; if(diff <= 0) physsteps = 0; - else - { + else { physframetime = clamp(game::scaletime(PHYSFRAMETIME)/100, 1, PHYSFRAMETIME); physsteps = (diff + physframetime - 1)/physframetime; lastphysframe += physsteps * physframetime; @@ -1689,50 +1428,39 @@ void physicsframe() // optimally schedule physics frames inside the graphics VAR(physinterp, 0, 1, 1); -void interppos(physent *pl) -{ +void interppos(physent *pl) { pl->o = pl->newpos; - int diff = lastphysframe - lastmillis; if(diff <= 0 || !physinterp) return; - vec deltapos(pl->deltapos); deltapos.mul(min(diff, physframetime)/float(physframetime)); pl->o.add(deltapos); } -void moveplayer(physent *pl, int moveres, bool local) -{ - if(physsteps <= 0) - { +void moveplayer(physent *pl, int moveres, bool local) { + if(physsteps <= 0) { if(local) interppos(pl); return; } - if(local) pl->o = pl->newpos; loopi(physsteps-1) moveplayer(pl, moveres, local, physframetime); if(local) pl->deltapos = pl->o; moveplayer(pl, moveres, local, physframetime); - if(local) - { + if(local) { pl->newpos = pl->o; pl->deltapos.sub(pl->newpos); interppos(pl); } } -bool bounce(physent *d, float elasticity, float grav) -{ - if(physsteps <= 0) - { +bool bounce(physent *d, float elasticity, float grav) { + if(physsteps <= 0) { interppos(d); return false; } - d->o = d->newpos; bool hitplayer = false; - loopi(physsteps-1) - { + loopi(physsteps-1) { if(bounce(d, physframetime/1000.0f, elasticity, grav)) hitplayer = true; } d->deltapos = d->o; @@ -1743,8 +1471,7 @@ bool bounce(physent *d, float elasticity, float grav) return hitplayer; } -void updatephysstate(physent *d) -{ +void updatephysstate(physent *d) { if(d->physstate == PHYS_FALL) return; d->timeinair = 0; vec old(d->o); @@ -1752,8 +1479,7 @@ void updatephysstate(physent *d) * May be inaccurate since movement collisions are not considered. * If good floor is not found, just keep the old floor and hope it's correct enough. */ - switch(d->physstate) - { + switch(d->physstate) { case PHYS_SLOPE: case PHYS_FLOOR: case PHYS_STEP_DOWN: @@ -1761,13 +1487,11 @@ void updatephysstate(physent *d) if(collide(d, vec(0, 0, -1), d->physstate == PHYS_SLOPE || d->physstate == PHYS_STEP_DOWN ? SLOPEZ : FLOORZ)) d->floor = collidewall; break; - case PHYS_STEP_UP: d->o.z -= STAIRHEIGHT+0.15f; if(collide(d, vec(0, 0, -1), SLOPEZ)) d->floor = collidewall; break; - case PHYS_SLIDE: d->o.z -= 0.15f; if(collide(d, vec(0, 0, -1)) && collidewall.z < SLOPEZ) @@ -1788,30 +1512,23 @@ dir(right, strafe, -1, k_right, k_left); ICOMMAND(jump, "D", (int *down), { if(!*down || game::canjump()) player->jumping = *down!=0; }); ICOMMAND(attack, "D", (int *down), { game::doattack(*down!=0); }); -bool entinmap(dynent *d, bool avoidplayers) // brute force but effective way to find a free spawn spot in the map -{ +bool entinmap(dynent *d, bool avoidplayers) { // brute force but effective way to find a free spawn spot in the map { d->o.z += d->eyeheight; // pos specified is at feet vec orig = d->o; - loopi(100) // try max 100 times - { - if(i) - { + loopi(100) { // try max 100 times { + if(i) { d->o = orig; d->o.x += (rnd(21)-10)*i/5; // increasing distance d->o.y += (rnd(21)-10)*i/5; d->o.z += (rnd(21)-10)*i/5; } - - if(!collide(d) && !collideinside) - { - if(collideplayer) - { + if(!collide(d) && !collideinside) { + if(collideplayer) { if(!avoidplayers) continue; d->o = orig; d->resetinterp(); return false; } - d->resetinterp(); return true; } -- cgit v1.2.3