diff --git a/source/src/bot/bot.cpp b/source/src/bot/bot.cpp index 0c7f7aa3..c4f732d1 100644 --- a/source/src/bot/bot.cpp +++ b/source/src/bot/bot.cpp @@ -100,7 +100,7 @@ void CBot::Think() if(lastmillis-m_pMyEnt->lastaction<1200) { m_pMyEnt->move = 0; - moveplayer(m_pMyEnt, 1, false); + moveplayer(m_pMyEnt, 1, true); } else if (!m_arena && lastmillis-m_pMyEnt->lastaction>5000) Spawn(); @@ -145,7 +145,7 @@ void CBot::Think() m_iStuckCheckDelay = max(m_iStuckCheckDelay, lastmillis+100.0f); // Move the bot - moveplayer(m_pMyEnt, 1, false); + moveplayer(m_pMyEnt, 1, true); // Update bot info on all clients SendBotInfo(); diff --git a/source/src/bot/botmanager.cpp b/source/src/bot/botmanager.cpp index b56082e8..bde8869b 100644 --- a/source/src/bot/botmanager.cpp +++ b/source/src/bot/botmanager.cpp @@ -817,6 +817,7 @@ void CBotManager::ViewBot() player1->pitch = m_pBotToView->pitch; player1->roll = m_pBotToView->roll; player1->radius = 0; // Don't collide + player1->resetinterp(); } void CBotManager::DisableBotView() @@ -1220,6 +1221,7 @@ void telebot(void) { if (!bots[i] || !bots[i]->pBot) continue; bots[i]->o = tr.end; + bots[i]->resetinterp(); break; } } diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index 9ccf5029..d25dc4aa 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -150,6 +150,7 @@ void deathstate(playerent *pl) setscope(false); if(editmode) toggleedit(); } + else pl->resetinterp(); } void spawnstate(playerent *d) // reset player state not persistent accross spawns @@ -260,7 +261,7 @@ void moveotherplayers() } else moveplayer(d, 1, false); } - else if(d->state==CS_DEAD && lastmillis-d->lastpain<2000) moveplayer(d, 1, false); + else if(d->state==CS_DEAD && lastmillis-d->lastpain<2000) moveplayer(d, 1, true); } } @@ -897,6 +898,7 @@ void spectate(int mode) // set new spect mode player1->o = f->o; player1->yaw = f->yaw; player1->pitch = 0.0f; + player1->resetinterp(); } else entinmap(player1); // or drop 'em at a random place } diff --git a/source/src/clients2c.cpp b/source/src/clients2c.cpp index d8e76fb9..a1e880b2 100644 --- a/source/src/clients2c.cpp +++ b/source/src/clients2c.cpp @@ -99,7 +99,12 @@ void parsepositions(ucharbuf &p) updatepos(d); updatelagtime(d); extern int smoothmove, smoothdist; - if(smoothmove && d->smoothmillis>=0 && oldpos.dist(d->o) < smoothdist) + if(d->state==CS_DEAD) + { + d->resetinterp(); + d->smoothmillis = 0; + } + else if(smoothmove && d->smoothmillis>=0 && oldpos.dist(d->o) < smoothdist) { d->newpos = d->o; d->newyaw = d->yaw; diff --git a/source/src/entity.h b/source/src/entity.h index 82a831c1..67fd1b3f 100644 --- a/source/src/entity.h +++ b/source/src/entity.h @@ -93,6 +93,7 @@ enum { SM_NONE = 0, SM_DEATHCAM, SM_FOLLOW1ST, SM_FOLLOW3RD, SM_FOLLOW3RD_TRANSP struct physent { vec o, vel; // origin, velocity + vec deltapos, newpos; // movement interpolation float yaw, pitch, roll; // used as vec in one place float pitchvel; float maxspeed; // cubes per second, 24 for player @@ -105,13 +106,19 @@ struct physent uchar state, type; static const int crouchtime; - physent() : o(0, 0, 0), yaw(270), pitch(0), roll(0), pitchvel(0), + physent() : o(0, 0, 0), deltapos(0, 0, 0), newpos(0, 0, 0), yaw(270), pitch(0), roll(0), pitchvel(0), crouching(false), trycrouch(false), cancollide(true), lastcrouch(0), state(CS_ALIVE) { reset(); } virtual ~physent() {} + void resetinterp() + { + newpos = o; + deltapos = vec(0, 0, 0); + } + void reset() { vel.x = vel.y = vel.z = 0; @@ -352,7 +359,6 @@ struct playerent : dynent, playerstate poshist history; // Previous stored locations of this player - vec deltapos, newpos; float deltayaw, deltapitch, newyaw, newpitch; int smoothmillis; diff --git a/source/src/physics.cpp b/source/src/physics.cpp index 26a25bec..dc56cfc7 100644 --- a/source/src/physics.cpp +++ b/source/src/physics.cpp @@ -248,8 +248,8 @@ VAR(recoilbackfade, 0, 100, 1000); void moveplayer(physent *pl, int moveres, bool local, int curtime) { bool water = false; - const bool editfly = (editmode && local) || pl->state==CS_EDITING; - const bool specfly = local && pl->type==ENT_PLAYER && ((playerent *)pl)->spectatemode==SM_FLY; + const bool editfly = pl->state==CS_EDITING; + const bool specfly = pl->type==ENT_PLAYER && ((playerent *)pl)->spectatemode==SM_FLY; vec d; // vector of direction we ideally want to move in @@ -354,8 +354,7 @@ void moveplayer(physent *pl, int moveres, bool local, int curtime) pl->jumpnext = false; pl->vel.z = 2.0f; //1.7f; // physics impulse upwards if(water) { pl->vel.x /= 8; pl->vel.y /= 8; } // dampen velocity change even harder, gives correct water feel - if(local && !water) playsoundc(S_JUMP); - else if(pl->type==ENT_BOT) playsound(S_JUMP, pl); // Added by Rick + else if(pl==player1 || pl->type!=ENT_PLAYER) playsoundc(S_JUMP, pl); } pl->timeinair = 0; } @@ -370,8 +369,7 @@ void moveplayer(physent *pl, int moveres, bool local, int curtime) int sound = timeinair > 800 ? S_HARDLAND : S_SOFTLAND; if(pl->state!=CS_DEAD) { - if(local) playsoundc(sound); - else playsound(sound, pl); + if(pl==player1 || pl->type!=ENT_PLAYER) playsoundc(sound, pl); } } @@ -490,24 +488,55 @@ void moveplayer(physent *pl, int moveres, bool local, int curtime) const int PHYSFPS = 200; const int PHYSFRAMETIME = 1000 / PHYSFPS; -int physicsfraction = 0, physicsrepeat = 0; +int physsteps = 0, physframetime = PHYSFRAMETIME, lastphysframe = 0; -// optimally schedule physics frames inside the graphics frames -void physicsframe() +void physicsframe() // optimally schedule physics frames inside the graphics frames { - int faketime = curtime+physicsfraction; - physicsrepeat = faketime/PHYSFRAMETIME; - physicsfraction = faketime%PHYSFRAMETIME; + int diff = lastmillis + curtime - lastphysframe; + if(diff <= 0) physsteps = 0; + else + { + extern int gamespeed; + physframetime = clamp((PHYSFRAMETIME*gamespeed)/100, 1, PHYSFRAMETIME); + physsteps = (diff + physframetime - 1)/physframetime; + lastphysframe += physsteps * physframetime; + } } -void moveplayer(physent *p, int moveres, bool local) +void interppos(physent *pl) { - loopi(physicsrepeat) moveplayer(p, moveres, local, PHYSFRAMETIME); + pl->o = pl->newpos; + + int diff = lastphysframe - (lastmillis + curtime); + if(diff <= 0) return; + + vec deltapos(pl->deltapos); + deltapos.mul(min(diff, physframetime)/float(physframetime)); + pl->o.sub(deltapos); +} + +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) + { + pl->newpos = pl->o; + pl->deltapos.sub(pl->newpos); + } } void movebounceent(bounceent *p, int moveres, bool local) { - loopi(physicsrepeat) moveplayer(p, moveres, local, PHYSFRAMETIME); + moveplayer(p, moveres, local); } // movement input code @@ -586,17 +615,22 @@ void mousemove(int dx, int dy) void entinmap(physent *d) // brute force but effective way to find a free spawn spot in the map { + vec orig(d->o); loopi(100) // try max 100 times { float dx = (rnd(21)-10)/10.0f*i; // increasing distance float dy = (rnd(21)-10)/10.0f*i; d->o.x += dx; d->o.y += dy; - if(collide(d, true, 0, 0)) return; - d->o.x -= dx; - d->o.y -= dy; + if(collide(d, true, 0, 0)) + { + d->resetinterp(); + return; + } + d->o = orig; } - conoutf("can't find entity spawn spot! (%d, %d)", d->o.x, d->o.y); // leave ent at original pos, possibly stuck + d->resetinterp(); + conoutf("can't find entity spawn spot! (%d, %d)", d->o.x, d->o.y); } diff --git a/source/src/protos.h b/source/src/protos.h index c5536e6b..1315932b 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -492,7 +492,7 @@ extern void playsound(int n, physent *p = NULL, entity *ent = NULL, const vec *v extern void playsound(int n, int priority); extern void playsound(int n, entity *e, int priority = SP_NORMAL); extern void playsound(int n, const vec *v, int priority = SP_NORMAL); -extern void playsoundc(int n); +extern void playsoundc(int n, physent *p = NULL); extern void initsound(); extern void soundcleanup(); extern void checkmapsounds(); diff --git a/source/src/sound.cpp b/source/src/sound.cpp index a953b22f..829e6a42 100644 --- a/source/src/sound.cpp +++ b/source/src/sound.cpp @@ -985,10 +985,14 @@ void detachsounds(playerent *owner) } } -void playsoundc(int n) +void playsoundc(int n, physent *p) { - addmsg(SV_SOUND, "i", n); - playsound(n); + if(p && p!=player1) playsound(n, p); + else + { + addmsg(SV_SOUND, "i", n); + playsound(n); + } } void voicecom(char *sound, char *text) diff --git a/source/src/tools.h b/source/src/tools.h index b9b545af..bb9453a4 100644 --- a/source/src/tools.h +++ b/source/src/tools.h @@ -26,7 +26,7 @@ typedef unsigned int uint; #undef swap #endif template -void swap(T &a, T &b) +static inline void swap(T &a, T &b) { T t = a; a = b; @@ -39,16 +39,17 @@ void swap(T &a, T &b) #undef min #endif template -T max(T a, T b) +static inline T max(T a, T b) { return a > b ? a : b; } template -T min(T a, T b) +static inline T min(T a, T b) { return a < b ? a : b; } +#define clamp(a,b,c) (max(b, min(a, c))) #define rnd(max) (rand()%(max)) #define rndreset() (srand(1)) #define rndtime() { loopi(lastmillis&0xF) rnd(i+1); } diff --git a/source/src/weapon.cpp b/source/src/weapon.cpp index e141ca17..ddd011bf 100644 --- a/source/src/weapon.cpp +++ b/source/src/weapon.cpp @@ -310,7 +310,7 @@ void addgib(playerent *d) loopi(gibnum) { - bounceent *p = bounceents.add(new bounceent()); + bounceent *p = bounceents.add(new bounceent); p->owner = d; p->millis = lastmillis; p->timetolive = gibttl+rnd(10)*100; @@ -333,6 +333,8 @@ void addgib(playerent *d) p->vel.y = cosf(RAD*angle)*rnd(1000)/1000.0f; p->vel.z = rnd(1000)/1000.0f; p->vel.mul(speed/100.0f); + + p->resetinterp(); } } @@ -607,8 +609,9 @@ void grenadeent::_throw(const vec &from, const vec &vel) nadestate = NS_THROWED; this->vel = vel; this->o = from; + this->resetinterp(); inwater = hdr.waterlevel>o.z; - + if(local) { addmsg(SV_THROWNADE, "ri7", int(o.x*DMF), int(o.y*DMF), int(o.z*DMF), int(vel.x*DMF), int(vel.y*DMF), int(vel.z*DMF), lastmillis-millis);