diff --git a/packages/misc/hole.png b/packages/misc/hole.png index 6f662dea..aaf8c820 100644 Binary files a/packages/misc/hole.png and b/packages/misc/hole.png differ diff --git a/source/src/geom.h b/source/src/geom.h index 665592a6..56cf99b0 100644 --- a/source/src/geom.h +++ b/source/src/geom.h @@ -13,6 +13,8 @@ struct vec float &operator[](int i) { return v[i]; } float operator[](int i) const { return v[i]; } + bool iszero() const { return x==0 && y==0 && z==0; } + bool operator==(const vec &o) const { return x == o.x && y == o.y && z == o.z; } bool operator!=(const vec &o) const { return x != o.x || y != o.y || z != o.z; } diff --git a/source/src/physics.cpp b/source/src/physics.cpp index 8cb96870..99638621 100644 --- a/source/src/physics.cpp +++ b/source/src/physics.cpp @@ -5,6 +5,59 @@ #include "cube.h" +float raycube(const vec &o, const vec &ray, vec &surface) +{ + surface = vec(0, 0, 0); + + if(ray.iszero()) return -1; + + vec v = o; + float dist = 0, dx = 0, dy = 0, dz = 0; + + for(;;) + { + int x = int(v.x), y = int(v.y); + if(x < 0 || y < 0 || x >= ssize || y >= ssize) return -1; + sqr *s = S(x, y); + float floor = s->floor, ceil = s->ceil; + if(s->type==FHF) floor -= s->vdelta/4.0f; + if(s->type==CHF) ceil += s->vdelta/4.0f; + if(SOLID(s) || v.z < floor || v.z > ceil) + { + if((!dx && !dy) || s->wtex==DEFAULT_SKY || (!SOLID(s) && v.z > ceil && s->ctex==DEFAULT_SKY)) return -1; + if(s->type!=CORNER)// && s->type!=FHF && s->type!=CHF) + { + if(dx0 ? -1 : 1; + else surface.y = ray.y>0 ? -1 : 1; + sqr *n = S(x+(int)surface.x, y+(int)surface.y); + if(SOLID(n) || (v.z < floor && v.z < n->floor) || (v.z > ceil && v.z > n->ceil)) + { + surface = dx0 ? -1 : 1, 0) : vec(ray.x>0 ? -1 : 1, 0, 0); + n = S(x+(int)surface.x, y+(int)surface.y); + if(SOLID(n) || (v.z < floor && v.z < n->floor) || (v.z > ceil && v.z > n->ceil)) + surface = vec(0, 0, ray.z>0 ? -1 : 1); + } + } + dist = max(dist-0.1f, 0); + break; + } + dx = ray.x ? (x + (ray.x > 0 ? 1 : 0) - v.x)/ray.x : 1e16f; + dy = ray.y ? (y + (ray.y > 0 ? 1 : 0) - v.y)/ray.y : 1e16f; + dz = ray.z ? ((ray.z > 0 ? ceil : floor) - v.z)/ray.z : 1e16f; + if(dz < dx && dz < dy) + { + if(ray.z>0 && s->ctex==DEFAULT_SKY) return -1; + if(s->type!=FHF && s->type!=CHF) surface.z = ray.z>0 ? -1 : 1; + dist += dz; + break; + } + float disttonext = 0.1f + min(dx, dy); + v.add(vec(ray).mul(disttonext)); + dist += disttonext; + } + return dist; +} + bool plcollide(physent *d, physent *o, float &headspace, float &hi, float &lo) // collide with player or monster { if(o->state!=CS_ALIVE) return true; diff --git a/source/src/protos.h b/source/src/protos.h index b293b261..1ba79c00 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -207,6 +207,7 @@ extern void particle_splash(int type, int num, int fade, vec &p); extern void particle_trail(int type, int fade, vec &from, vec &to); extern void particle_fireball(int type, vec &o); extern void addshotline(dynent *d, vec &from, vec &to); +extern bool addbullethole(vec &from, vec &to, float radius = 1); extern void render_particles(int time); // worldio @@ -223,6 +224,7 @@ extern void demodamage(int damage, vec &o); extern void demoblend(int damage); // physics +extern float raycube(const vec &o, const vec &ray, vec &surface); extern void moveplayer(physent *pl, int moveres, bool local); extern void moveplayer(physent *pl, int moveres, bool local, int curtime); extern bool collide(physent *d, bool spawn, float drop, float rise); diff --git a/source/src/rendergl.cpp b/source/src/rendergl.cpp index 9bce1a3e..3c85e1c8 100644 --- a/source/src/rendergl.cpp +++ b/source/src/rendergl.cpp @@ -331,8 +331,6 @@ void drawhudgun(int w, int h, float aspect, int farplane) { if(scoped && player1->gunselect==GUN_SNIPER) return; - glEnable(GL_CULL_FACE); - glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective((float)100.0f*h/w, aspect, 0.3f, farplane); // fov fixed at 100° @@ -345,8 +343,6 @@ void drawhudgun(int w, int h, float aspect, int farplane) glLoadIdentity(); gluPerspective((float)fov*h/w, aspect, 0.15f, farplane); glMatrixMode(GL_MODELVIEW); - - glDisable(GL_CULL_FACE); } bool outsidemap(physent *pl) @@ -368,8 +364,8 @@ void readmatrices() glGetIntegerv(GL_VIEWPORT, viewport); glGetDoublev(GL_MODELVIEW_MATRIX, mm); glGetDoublev(GL_PROJECTION_MATRIX, pm); - camright = vec(float(mm[0]), float(mm[4]), float(mm[8])); - camup = vec(float(mm[1]), float(mm[5]), float(mm[9])); + camright = vec(float(mm[0]), float(mm[8]), float(mm[4])); + camup = vec(float(mm[1]), float(mm[9]), float(mm[5])); } // stupid function to cater for stupid ATI linux drivers that return incorrect depth values diff --git a/source/src/renderparticles.cpp b/source/src/renderparticles.cpp index 19bdbe72..c4c1e44f 100644 --- a/source/src/renderparticles.cpp +++ b/source/src/renderparticles.cpp @@ -2,12 +2,12 @@ #include "cube.h" -#define MAXPARTYPES 7 +#define MAXPARTYPES 8 struct particle { vec o, d; int fade, type; int millis; particle *next; }; particle *parlist[MAXPARTYPES], *parempty = NULL; -static Texture *parttex[3]; +static Texture *parttex[4]; void particleinit() { @@ -16,7 +16,8 @@ void particleinit() parttex[0] = textureload("packages/misc/base.png"); parttex[1] = textureload("packages/misc/smoke.png"); parttex[2] = textureload("packages/misc/explosion.jpg"); - + parttex[3] = textureload("packages/misc/hole.png"); + GLUquadricObj *qsphere = gluNewQuadric(); if(!qsphere) fatal("glu sphere"); gluQuadricDrawStyle(qsphere, GLU_FILL); @@ -69,7 +70,8 @@ enum { PT_PART = 0, PT_FIREBALL, - PT_SHOTLINE + PT_SHOTLINE, + PT_DECAL }; static struct parttype { int type; float r, g, b; int gr, tex; float sz; } parttypes[] = @@ -80,7 +82,8 @@ static struct parttype { int type; float r, g, b; int gr, tex; float sz; } partt { 0, 1.0f, 0.1f, 0.1f, 1, 1, 0.06f }, // red: blood spats { 0, 1.0f, 0.1f, 0.1f, 0, 1, 0.2f }, // red: demotrack { PT_FIREBALL, 1.0f, 1.0f, 1.0f, 0, 2, 7.0f }, // explosion fireball - { PT_SHOTLINE, 1.0f, 1.0f, 0.7f, 0, -1, 0.0f } // yellow: shotline + { PT_SHOTLINE, 1.0f, 1.0f, 0.7f, 0, -1, 0.0f }, // yellow: shotline + { PT_DECAL, 1.0f, 1.0f, 1.0f, 0, 3, 0.07f }, // hole decal }; VAR(demotracking, 0, 0, 1); @@ -127,6 +130,11 @@ void render_particles(int time) glColor4f(pt.r, pt.g, pt.b, 0.5f); glBegin(GL_LINES); break; + + case PT_DECAL: + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBegin(GL_QUADS); + break; } for(particle *p, **pp = &parlist[i]; (p = *pp);) @@ -134,10 +142,10 @@ void render_particles(int time) switch(pt.type) { case PT_PART: - glTexCoord2i(0, 1); glVertex3f(p->o.x+(-camright.x+camup.x)*sz, p->o.z+(-camright.y+camup.y)*sz, p->o.y+(-camright.z+camup.z)*sz); - glTexCoord2i(1, 1); glVertex3f(p->o.x+( camright.x+camup.x)*sz, p->o.z+( camright.y+camup.y)*sz, p->o.y+( camright.z+camup.z)*sz); - glTexCoord2i(1, 0); glVertex3f(p->o.x+( camright.x-camup.x)*sz, p->o.z+( camright.y-camup.y)*sz, p->o.y+( camright.z-camup.z)*sz); - glTexCoord2i(0, 0); glVertex3f(p->o.x+(-camright.x-camup.x)*sz, p->o.z+(-camright.y-camup.y)*sz, p->o.y+(-camright.z-camup.z)*sz); + glTexCoord2i(0, 1); glVertex3f(p->o.x+(-camright.x+camup.x)*sz, p->o.z+(-camright.z+camup.z)*sz, p->o.y+(-camright.y+camup.y)*sz); + glTexCoord2i(1, 1); glVertex3f(p->o.x+( camright.x+camup.x)*sz, p->o.z+( camright.z+camup.z)*sz, p->o.y+( camright.y+camup.y)*sz); + glTexCoord2i(1, 0); glVertex3f(p->o.x+( camright.x-camup.x)*sz, p->o.z+( camright.z-camup.z)*sz, p->o.y+( camright.y-camup.y)*sz); + glTexCoord2i(0, 0); glVertex3f(p->o.x+(-camright.x-camup.x)*sz, p->o.z+(-camright.z-camup.z)*sz, p->o.y+(-camright.y-camup.y)*sz); xtraverts += 4; break; @@ -160,6 +168,20 @@ void render_particles(int time) glVertex3f(p->d.x, p->d.z, p->d.y); xtraverts += 2; break; + + case PT_DECAL: + { + sqr *s = S((int)p->o.x, (int)p->o.y); + glColor4f(s->r/127.5f, s->g/127.5f, s->b/127.5, max(0, min((p->millis+p->fade - lastmillis)/1000.0f, 0.7f))); + vec dx(0, 0, 0), dy(0, 0, 0); + loopk(3) if(p->d[k]) { dx[(k+1)%3] = -1; dy[(k+2)%3] = p->d[k]; break; } + glTexCoord2i(0, 1); glVertex3f(p->o.x+(-dx.x+dy.x)*pt.sz, p->o.z+(-dx.z+dy.z)*pt.sz, p->o.y+(-dx.y+dy.y)*pt.sz); + glTexCoord2i(1, 1); glVertex3f(p->o.x+( dx.x+dy.x)*pt.sz, p->o.z+( dx.z+dy.z)*pt.sz, p->o.y+( dx.y+dy.y)*pt.sz); + glTexCoord2i(1, 0); glVertex3f(p->o.x+( dx.x-dy.x)*pt.sz, p->o.z+( dx.z-dy.z)*pt.sz, p->o.y+( dx.y-dy.y)*pt.sz); + glTexCoord2i(0, 0); glVertex3f(p->o.x+(-dx.x-dy.x)*pt.sz, p->o.z+(-dx.z-dy.z)*pt.sz, p->o.y+(-dx.y-dy.y)*pt.sz); + xtraverts += 4; + break; + } } if(lastmillis-p->millis>p->fade) @@ -171,12 +193,12 @@ void render_particles(int time) else { if(pt.gr) p->o.z -= ((lastmillis-p->millis)/3.0f)*time/(pt.gr*10000); - if(pt.type!=PT_SHOTLINE) p->o.add(vec(p->d).mul(time/20000.0f)); + if(pt.type==PT_PART) p->o.add(vec(p->d).mul(time/20000.0f)); pp = &p->next; } } - if(pt.type==PT_PART || pt.type==PT_SHOTLINE) glEnd(); + if(pt.type==PT_PART || pt.type==PT_SHOTLINE || pt.type==PT_DECAL) glEnd(); if(pt.tex<0) glEnable(GL_TEXTURE_2D); } @@ -226,6 +248,23 @@ void particle_fireball(int type, vec &o) newparticle(o, vec(0, 0, 0), (int)((parttypes[type].sz-1.0f)*100.0f), type); } +VARP(holettl, 0, 10000, 30000); + +bool addbullethole(vec &from, vec &to, float radius) +{ + if(!holettl) return false; + vec surface, ray(to); + ray.sub(from); + ray.normalize(); + float dist = raycube(from, ray, surface), mag = to.dist(from); + if(surface.iszero() || (radius>0 && (dist < mag-radius || dist > mag+radius))) return false; + vec o(from); + o.add(ray.mul(dist)); + o.add(vec(surface).mul(0.005f)); + newparticle(o, surface, holettl, 7); + return true; +} + void addshotline(dynent *pl, vec &from, vec &to) { if(pl == player1) return; diff --git a/source/src/weapon.cpp b/source/src/weapon.cpp index c575921f..2bac5e76 100644 --- a/source/src/weapon.cpp +++ b/source/src/weapon.cpp @@ -522,6 +522,11 @@ void shootv(int gun, vec &from, vec &to, playerent *d, bool local, int nademilli case GUN_SHOTGUN: { loopi(SGRAYS) particle_splash(0, 5, 200, sg[i]); + if(addbullethole(from, to)) + { + int holes = 3+rnd(5); + loopi(holes) addbullethole(from, sg[i], 0); + } break; } @@ -529,6 +534,7 @@ void shootv(int gun, vec &from, vec &to, playerent *d, bool local, int nademilli case GUN_SUBGUN: case GUN_ASSAULT: { + addbullethole(from, to); addshotline(d, from, to); particle_splash(0, 5, 250, to); break; @@ -546,6 +552,7 @@ void shootv(int gun, vec &from, vec &to, playerent *d, bool local, int nademilli case GUN_SNIPER: { + addbullethole(from, to); addshotline(d, from, to); particle_splash(0, 50, 200, to); particle_trail(1, 500, from, to);