From 780cc3f4f1faf7f18856c34bb1215e40d3622721 Mon Sep 17 00:00:00 2001 From: driAn Date: Sat, 1 Dec 2007 15:35:56 +0000 Subject: [PATCH] spectator mode, new recoil git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@1448 e016b1c5-ed68-44aa-a2f7-31cac88cffde --- source/src/clientgame.cpp | 43 +++++++++++++++------------ source/src/editing.cpp | 4 --- source/src/entity.h | 38 +++++++++++++++--------- source/src/hudgun.cpp | 4 +-- source/src/physics.cpp | 42 ++++++++++++++++++-------- source/src/rendergl.cpp | 60 ++++++++++++++++++++++++++++---------- source/src/rendermodel.cpp | 2 +- source/src/weapon.cpp | 15 ++++------ 8 files changed, 131 insertions(+), 77 deletions(-) diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index a7fc8eeb..a78c983f 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -134,7 +134,7 @@ void deathstate(playerent *pl) pl->attacking = false; pl->state = CS_DEAD; pl->pitch = 0; - pl->roll = 60; + //pl->roll = 60; pl->strafe = 0; if(pl == player1) { @@ -233,7 +233,25 @@ void zapplayer(playerent *&d) DELETEP(d); } -void otherplayers() +void movelocalplayer() +{ + if(player1->state==CS_DEAD && !player1->allowmove()) + { + if(lastmillis-player1->lastpain<2000) + { + player1->move = player1->strafe = 0; + moveplayer(player1, 10, false); + } + } + else if(!intermission) + { + moveplayer(player1, 20, true); + checkitems(player1); + } +} + +// use physics to extrapolate player position +void moveotherplayers() { loopv(players) if(players[i] && players[i]->type==ENT_PLAYER) { @@ -243,7 +261,7 @@ void otherplayers() players[i]->state = CS_LAGGED; continue; } - if(lagtime && (players[i]->state==CS_ALIVE || (players[i]->state==CS_DEAD && lastmillis-players[i]->lastpain<2000)) && !intermission) moveplayer(players[i], 2, false); // use physics to extrapolate player position + if(lagtime && (players[i]->state==CS_ALIVE || (players[i]->state==CS_DEAD && lastmillis-players[i]->lastpain<2000)) && !intermission) moveplayer(players[i], 2, false); } } @@ -279,26 +297,13 @@ void updateworld(int curtime, int lastmillis) // main game update loop if(getclientnum()>=0) shoot(player1, worldpos); // only shoot when connected to server gets2c(); // do this first, so we have most accurate information when our player moves movebounceents(); - otherplayers(); + moveotherplayers(); //monsterthink(); // Added by Rick: let bots think if(m_botmode) BotManager.Think(); - //put game mode extra call here - if(player1->state==CS_DEAD) - { - if(lastmillis-player1->lastpain<2000) - { - player1->move = player1->strafe = 0; - moveplayer(player1, 10, false); - } - } - else if(!intermission) - { - moveplayer(player1, 20, true); - checkitems(player1); - } + movelocalplayer(); c2sinfo(player1); // do this last, to reduce the effective frame lag } @@ -421,7 +426,7 @@ void dokill(playerent *pl, playerent *act, bool gib) pl->state = CS_DEAD; pl->lastaction = lastmillis; pl->pitch = 0; - pl->roll = 60; + //pl->roll = 60; pl->move = pl->strafe = 0; pl->attacking = false; playsound(S_DIE1+rnd(2), NULL, NULL, pl == player1 ? NULL : &pl->o); diff --git a/source/src/editing.cpp b/source/src/editing.cpp index c609ee66..1afc87b7 100644 --- a/source/src/editing.cpp +++ b/source/src/editing.cpp @@ -54,10 +54,6 @@ void toggleedit() addmsg(SV_EDITMODE, "ri", editing); } -// fixme! -void spec() { player1->state = CS_SPECTATE; } -COMMAND(spec, ARG_NONE); - COMMANDN(edittoggle, toggleedit, ARG_NONE); char *editinfo() diff --git a/source/src/entity.h b/source/src/entity.h index 30c951d1..cf0496fc 100644 --- a/source/src/entity.h +++ b/source/src/entity.h @@ -55,16 +55,16 @@ enum { GUN_KNIFE = 0, GUN_PISTOL, GUN_SHOTGUN, GUN_SUBGUN, GUN_SNIPER, GUN_ASSAU #define SGSPREAD 2 #define EXPDAMRAD 10 -struct guninfo { short sound, reload, reloadtime, attackdelay, damage, projspeed, part, spread, recoil, magsize, mdl_kick_rot, mdl_kick_back; bool isauto; }; +struct guninfo { short sound, reload, reloadtime, attackdelay, damage, projspeed, part, spread, recoil, magsize, mdl_kick_rot, mdl_kick_back, recoilincrease, recoilbase, maxrecoil, recoilbackfade; bool isauto; }; static guninfo guns[NUMGUNS] = { - { S_KNIFE, S_NULL, 0, 500, 50, 0, 0, 1, 1, 1, 0, 0, false }, - { S_PISTOL, S_RPISTOL, 1400, 170, 19, 0, 0, 80, 10, 8, 6, 5, false }, // *SGRAYS - { S_SHOTGUN, S_RSHOTGUN, 2400, 1000, 5, 0, 0, 1, 35, 7, 9, 9, false }, //reload time is for 1 shell from 7 too powerful to 6 - { S_SUBGUN, S_RSUBGUN, 1650, 80, 16, 0, 0, 70, 15, 30, 1, 2, true }, - { S_SNIPER, S_RSNIPER, 1950, 1500, 85, 0, 0, 60, 50, 5, 4, 4, false }, - { S_ASSAULT, S_RASSAULT, 2000, 130, 24, 0, 0, 20, 40, 15, 0, 2, true }, //recoil was 44 - { S_NULL, S_NULL, 1000, 650, 150, 20, 6, 1, 1, 1, 3, 1, false }, + { S_KNIFE, S_NULL, 0, 500, 50, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, false }, + { S_PISTOL, S_RPISTOL, 1400, 170, 19, 0, 0, 80, 10, 8, 6, 5, 1, 40, 75, 150, false }, // *SGRAYS + { S_SHOTGUN, S_RSHOTGUN, 2400, 1000, 5, 0, 0, 1, 35, 7, 9, 9, 1, 130, 500, 150, false }, //reload time is for 1 shell from 7 too powerful to 6 + { S_SUBGUN, S_RSUBGUN, 1650, 80, 16, 0, 0, 70, 15, 30, 1, 2, 3, 20, 60, 200, true }, + { S_SNIPER, S_RSNIPER, 1950, 1500, 85, 0, 0, 60, 50, 5, 4, 4, 1, 100, 500, 100, false }, + { S_ASSAULT, S_RASSAULT, 2000, 130, 24, 0, 0, 20, 40, 15, 0, 2, 2, 25, 60, 150, true }, //recoil was 44 + { S_NULL, S_NULL, 1000, 650, 150, 20, 6, 1, 1, 1, 3, 1, 0, 0, 0, 0, false }, }; static inline int reloadtime(int gun) { return guns[gun].reloadtime; } @@ -84,7 +84,8 @@ static inline int kick_back(int gun) { return guns[gun].mdl_kick_back; } enum { ENT_PLAYER = 0, ENT_BOT, ENT_CAMERA, ENT_BOUNCE }; enum { CS_ALIVE = 0, CS_DEAD, CS_SPAWNING, CS_LAGGED, CS_EDITING, CS_SPECTATE }; -enum { CR_DEFAULT, CR_MASTER, CR_ADMIN }; +enum { CR_DEFAULT = 0, CR_MASTER, CR_ADMIN }; +enum { SM_NONE = 0, SM_FLY, SM_FOLLOWPLAYER, SM_NUM }; struct physent { @@ -94,15 +95,14 @@ struct physent float maxspeed; // cubes per second, 24 for player int timeinair; // used for fake gravity float radius, eyeheight, aboveeye; // bounding box size - float dyneyeheight() { return crouching ? eyeheight*3.0f/4.0f : eyeheight; } + virtual float dyneyeheight() { return crouching ? eyeheight*3.0f/4.0f : eyeheight; } bool inwater; bool onfloor, onladder, jumpnext, crouching; char move, strafe; uchar state, type; - physent() : o(0, 0, 0), yaw(270), pitch(0), roll(0), pitchvel(0), maxspeed(16), - radius(1.1f), eyeheight(4.5f), aboveeye(0.7f), - state(CS_ALIVE), type(ENT_PLAYER) + physent() : o(0, 0, 0), yaw(270), pitch(0), roll(0), pitchvel(0), + state(CS_ALIVE) { reset(); } @@ -320,6 +320,9 @@ struct playerent : dynent, playerstate int reloading, weaponchanging; int nextweapon; // weapon we switch to int skin, nextskin; // skin after respawning + int spectating, followplayercn; + virtual float dyneyeheight() { return state==CS_DEAD && spectating==SM_FLY ? 1.0f : physent::dyneyeheight(); } + bool allowmove() { return state!=CS_DEAD || spectating==SM_FLY; } int thrownademillis; struct bounceent *inhandnade; @@ -330,9 +333,14 @@ struct playerent : dynent, playerstate playerent() : clientnum(-1), plag(0), ping(0), lifesequence(0), frags(0), flagscore(0), lastpain(0), lastteamkill(0), clientrole(CR_DEFAULT), shots(0), reloading(0), - skin(0), nextskin(0), inhandnade(NULL) + skin(0), nextskin(0), spectating(SM_NONE), followplayercn(0), inhandnade(NULL) { + type = ENT_PLAYER; name[0] = team[0] = 0; + eyeheight = 4.5f; + aboveeye = 0.7f; + radius = 1.1f; + maxspeed = 16.0f; respawn(); } @@ -359,6 +367,8 @@ struct playerent : dynent, playerstate akimbomillis = 0; attacking = false; weaponchanging = 0; + spectating = SM_NONE; + followplayercn = 0; } }; diff --git a/source/src/hudgun.cpp b/source/src/hudgun.cpp index 8a631caf..699abebf 100644 --- a/source/src/hudgun.cpp +++ b/source/src/hudgun.cpp @@ -67,7 +67,7 @@ struct weaponmove if(progress > 100.0f || progress < 0) progress = 1.0f; // f(x) = -sin(x-1.5)^3 kick = -sinf(pow((1.5f*progress)-1.5f,3)); - if(player1->crouching) kick *= 0.35f; + if(player1->crouching) kick *= 0.5f; } if(player1->lastaction && player1->lastattackgun==player1->gunselect) @@ -104,7 +104,7 @@ struct weaponmove sway.y *= swayspeed; sway.z *= swayupspeed; - if(player1->crouching) sway.mul(0.35f); + if(player1->crouching) sway.mul(0.5f); } pos.x -= base.x*k_back+sway.x; diff --git a/source/src/physics.cpp b/source/src/physics.cpp index 0cbe813c..98a148ca 100644 --- a/source/src/physics.cpp +++ b/source/src/physics.cpp @@ -223,7 +223,6 @@ float floor(short x, short y) } VARP(maxroll, 0, 0, 20); -VAR(recoilbackfade, 0, 100, 1000); // FIXME!! // main physics routine, moves a player/monster for a curtime step // moveres indicated the physics precision (which is lower for monsters and multiplayer prediction) @@ -233,7 +232,7 @@ void moveplayer(physent *pl, int moveres, bool local, int curtime) { const bool water = hdr.waterlevel>pl->o.z-0.5f; const bool editfly = (editmode && local) || pl->state==CS_EDITING; - const bool specfly = local && pl->state == CS_SPECTATE; + const bool specfly = local && pl->type==ENT_PLAYER && (pl->state==CS_SPECTATE || ((playerent *)pl)->spectating==SM_FLY); const float speed = curtime/(water ? 2000.0f : 1000.0f)*pl->maxspeed*(pl->crouching ? 0.5f : 1.0f); const float friction = water ? 20.0f : (pl->onfloor || editfly || specfly ? 6.0f : (pl->onladder ? 1.5f : 30.0f)); @@ -295,13 +294,6 @@ void moveplayer(physent *pl, int moveres, bool local, int curtime) d = pl->vel; d.mul(speed); - // smooth pitch - pl->pitch += pl->pitchvel*(curtime/1000.0f)*pl->maxspeed*(pl->crouching ? 0.5f : 1.0f); - pl->pitchvel *= fpsfric-3; - pl->pitchvel /= fpsfric; - if(pl->pitchvel < 0.05f && pl->pitchvel > 0.001f) pl->pitchvel -= recoilbackfade/100.0f; // slide back - if(pl->pitchvel) fixcamerarange(pl); // fix pitch if necessary - if(editfly) // just apply velocity { pl->o.add(d); @@ -431,6 +423,16 @@ void moveplayer(physent *pl, int moveres, bool local, int curtime) if(pl->roll>maxroll) pl->roll = (float)maxroll; if(pl->roll<-maxroll) pl->roll = (float)-maxroll; } + + // smooth pitch + if(pl == player1) + { + pl->pitch += pl->pitchvel*(curtime/1000.0f)*pl->maxspeed*(pl->crouching ? 0.5f : 1.0f); + pl->pitchvel *= fpsfric-3; + pl->pitchvel /= fpsfric; + if(pl->pitchvel < 0.05f && pl->pitchvel > 0.001f) pl->pitchvel -= guns[((playerent *)pl)->gunselect].recoilbackfade/100.0f; // slide back + if(pl->pitchvel) fixcamerarange(pl); // fix pitch if necessary + } } // play sounds on water transitions @@ -485,9 +487,25 @@ void attack(bool on) void jumpn(bool on) { if(intermission) return; - else if(player1->state==CS_DEAD) + if(player1->state==CS_DEAD) { - if(on) respawn(); + if(on) + { + if(player1->spectating == SM_FOLLOWPLAYER) + { + if(players.inrange(player1->followplayercn+1) && players[player1->followplayercn+1]) + { + player1->followplayercn++; // switch players + return; + } + } + + player1->spectating = (player1->spectating+1) % SM_NUM; + switch(player1->spectating) + { + case SM_FOLLOWPLAYER: player1->followplayercn = 0; + } + } } else player1->jumpnext = on; } @@ -526,7 +544,7 @@ void mousemove(int dx, int dy) camera1->yaw += (dx/SENSF)*(sensitivity/(float)sensitivityscale); camera1->pitch -= (dy/SENSF)*(sensitivity/(float)sensitivityscale)*(invmouse ? -1 : 1); fixcamerarange(); - if(camera1!=player1 && player1->state!=CS_DEAD) + if(camera1!=player1 && player1->allowmove()) { player1->yaw = camera1->yaw; player1->pitch = camera1->pitch; diff --git a/source/src/rendergl.cpp b/source/src/rendergl.cpp index aa3f701b..1e648850 100644 --- a/source/src/rendergl.cpp +++ b/source/src/rendergl.cpp @@ -244,27 +244,57 @@ VAR(fogcolour, 0, 0x8099B3, 0xFFFFFF); physent *camera1 = NULL; -void trypitch(int i) { camera1->pitch = (float)i; } -COMMAND(trypitch, ARG_1INT); - void recomputecamera() { - if(editmode || player1->state!=CS_DEAD) + if(player1->state==CS_DEAD && !editmode) { - camera1 = player1; + switch(player1->spectating) + { + case SM_NONE: + { + static physent deathcam; + if(camera1==&deathcam) return; + deathcam = *(physent *)player1; + deathcam.reset(); + deathcam.type = ENT_CAMERA; + deathcam.roll = 0; + deathcam.move = -1; + camera1 = &deathcam; + loopi(10) moveplayer(camera1, 10, true, 50); + break; + } + case SM_FLY: + camera1 = player1; + break; + case SM_FOLLOWPLAYER: + playerent *p = players[player1->followplayercn]; + if(!p) + { + player1->followplayercn = 0; + return; + } + static physent followcam; + static playerent *lastplayer; + if(lastplayer != p) + { + followcam = *(playerent*)p; + followcam.type = ENT_CAMERA; + followcam.reset(); + followcam.roll = 0; + followcam.move = -1; + lastplayer = p; + camera1 = &followcam; + } + followcam.o = p->o; + followcam.o.x -= (float)(cosf(RAD*(p->yaw-90)))*p->radius*1.5f; + followcam.o.y -= (float)(sinf(RAD*(p->yaw-90)))*p->radius*1.5f; + followcam.o.z += p->eyeheight/3.0f; + break; + } } else { - static physent deathcam; - if(camera1==&deathcam) return; - deathcam = *(physent *)player1; - deathcam.reset(); - deathcam.type = ENT_CAMERA; - deathcam.roll = 0; - deathcam.move = -1; - camera1 = &deathcam; - - loopi(10) moveplayer(camera1, 10, true, 50); + camera1 = player1; } } diff --git a/source/src/rendermodel.cpp b/source/src/rendermodel.cpp index 4c2a0fe9..231a5e19 100644 --- a/source/src/rendermodel.cpp +++ b/source/src/rendermodel.cpp @@ -337,6 +337,7 @@ void renderclient(playerent *d, char *mdlname, char *vwepname, int tex) int basetime = -((int)(size_t)d&0xFFF); if(d->state==CS_DEAD) { + if(d==player1 && d->allowmove()) return; loopv(bounceents) if(bounceents[i]->bouncestate==GIB && bounceents[i]->owner==d) return; d->pitch = 0.1f; int r = 6; @@ -354,7 +355,6 @@ void renderclient(playerent *d, char *mdlname, char *vwepname, int tex) o.z -= t*t/10000000000.0f*t; } } - //if(o.z<-1000) return; } else if(d->state==CS_EDITING) { anim = ANIM_JUMP|ANIM_END; } else if(d->state==CS_LAGGED) { anim = ANIM_SALUTE|ANIM_LOOP; } diff --git a/source/src/weapon.cpp b/source/src/weapon.cpp index da95e705..74c275d0 100644 --- a/source/src/weapon.cpp +++ b/source/src/weapon.cpp @@ -673,25 +673,20 @@ void raydamage(vec &from, vec &to, playerent *d) } } -//FIXME!! -VAR(recoilincrease, 1, 2, 10); -VAR(recoilbase, 0, 40, 1000); -VAR(maxrecoil, 0, 1000, 1000); - void spreadandrecoil(vec &from, vec &to, playerent *d) { if(d->gunselect==GUN_KNIFE || d->gunselect==GUN_GRENADE) return; //nothing special for a knife + guninfo &g = guns[d->gunselect]; vec unitv; float dist = to.dist(from, unitv); float f = dist/1000; - int spd = guns[d->gunselect].spread; - float rcl = guns[d->gunselect].recoil*-0.01f; + int spd = g.spread; + float rcl = g.recoil*-0.01f; if(d->gunselect==GUN_ASSAULT) { - if(d->shots > 3) - spd = 70; + if(d->shots > 3) spd = 70; rcl += (rnd(8)*-0.01f); } @@ -712,7 +707,7 @@ void spreadandrecoil(vec &from, vec &to, playerent *d) // kickback d->vel.add(vec(unitv).mul(rcl/dist).mul(d->crouching ? 0.5 : 1.0f)); // recoil - d->pitchvel = min(pow(d->shots/(float)recoilincrease, 2.0f)+(float)recoilbase/10.0f, (float)maxrecoil/10.0f); + d->pitchvel = min(pow(d->shots/(float)(g.recoilincrease), 2.0f)+(float)(g.recoilbase)/10.0f, (float)(g.maxrecoil)/10.0f); //if(d->pitch < 80.0f) d->pitchvel += guns[d->gunselect].recoil*0.15f*(float)testrecoil/100.0f; //if(d->pitch<80.0f) d->pitch += guns[d->gunselect].recoil*0.05f;