From 81d2cc3ac6e106ed12554ac77ab0c943c7bdd41a Mon Sep 17 00:00:00 2001 From: driAn Date: Wed, 16 Apr 2008 19:36:20 +0000 Subject: [PATCH] spectfov, weap code restructured git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@1799 e016b1c5-ed68-44aa-a2f7-31cac88cffde --- source/src/clientgame.cpp | 4 +- source/src/pch.h | 7 +- source/src/protos.h | 4 +- source/src/rendergl.cpp | 20 +- source/src/renderhud.cpp | 3 +- source/src/sound.cpp | 14 +- source/src/weapon.cpp | 838 +++++++++++++++++++------------------- source/src/weapon.h | 119 ++++++ 8 files changed, 559 insertions(+), 450 deletions(-) diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index dc2eaf92..11b1978f 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -375,8 +375,8 @@ void spawnplayer(playerent *d) void respawnself() { - if(player1->isspectating()) findplayerstart(player1, true); - else if(m_mp(gamemode)) addmsg(SV_TRYSPAWN, "r"); + /*if(player1->isspectating()) findplayerstart(player1, true); + else*/ if(m_mp(gamemode)) addmsg(SV_TRYSPAWN, "r"); else { showscores(false); diff --git a/source/src/pch.h b/source/src/pch.h index d4178514..5f924215 100644 --- a/source/src/pch.h +++ b/source/src/pch.h @@ -46,9 +46,4 @@ #endif #include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alut.h" -#include "vorbis/vorbisfile.h" +#include \ No newline at end of file diff --git a/source/src/protos.h b/source/src/protos.h index 238dda01..890b848a 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -180,6 +180,9 @@ extern void gl_drawframe(int w, int h, float changelod, float curfps); extern void clearminimap(); extern void rendercursor(int x, int y, int w); extern void renderaboveheadicon(playerent *p); +extern void drawcrosshair(bool showteamwarning); +extern void drawscope(); +extern float dynfov(); // texture @@ -454,7 +457,6 @@ extern void renderclient(playerent *d); extern void renderclient(playerent *d, const char *mdlname, const char *vwepname, int tex = 0); // weapon -extern bool scoped; extern void shoot(playerent *d, vec &to); extern void createrays(vec &from, vec &to); extern void moveprojectiles(float time); diff --git a/source/src/rendergl.cpp b/source/src/rendergl.cpp index ddd08bae..8e24fb32 100644 --- a/source/src/rendergl.cpp +++ b/source/src/rendergl.cpp @@ -288,6 +288,16 @@ void rendercursor(int x, int y, int w) } VARP(fov, 90, 100, 120); +VARP(scopefov, 5, 50, 50); +VARP(spectfov, 5, 50, 120); + +float dynfov() +{ + if(player1->weaponsel->type == GUN_SNIPER && ((sniperrifle *)player1->weaponsel)->scoped) return (float)scopefov; + else if(player1->state == CS_SPECTATE) return (float)spectfov; + else return (float)fov; +} + VAR(fog, 64, 180, 1024); VAR(fogcolour, 0, 0x8099B3, 0xFFFFFF); float fovy, aspect; @@ -423,7 +433,7 @@ void drawreflection(float hf, int w, int h, float changelod, bool refract) resetcubes(); render_world(camera1->o.x, camera1->o.y, refract ? camera1->o.z : hf, changelod, - (int)camera1->yaw, (refract ? 1 : -1)*(int)camera1->pitch, (float)fov, size, size); + (int)camera1->yaw, (refract ? 1 : -1)*(int)camera1->pitch, dynfov(), size, size); setupstrips(); @@ -620,14 +630,12 @@ void sethudgunperspective(bool on) glScalef(1, 1, 0.5f); // fix hudugns colliding with map geometry gluPerspective((float)100.0f*screen->h/screen->w, aspect, 0.3f, farplane); // fov fixed at 100° } - else gluPerspective((float)fov*screen->h/screen->w, aspect, 0.15f, farplane); + else gluPerspective((float)dynfov()*screen->h/screen->w, aspect, 0.15f, farplane); glMatrixMode(GL_MODELVIEW); } void drawhudgun(int w, int h, float aspect, int farplane) { - if(scoped && player1->weaponsel->type==GUN_SNIPER) return; - sethudgunperspective(true); if(hudgun && player1->state==CS_ALIVE) player1->weaponsel->renderhudmodel(); @@ -703,7 +711,7 @@ void gl_drawframe(int w, int h, float changelod, float curfps) recomputecamera(); float hf = hdr.waterlevel-0.3f; - fovy = (float)fov*h/w; + fovy = (float)dynfov()*h/w; aspect = w/(float)h; bool underwater = camera1->o.zo.x, camera1->o.y, camera1->o.z, changelod, - (int)camera1->yaw, (int)camera1->pitch, (float)fov, w, h); + (int)camera1->yaw, (int)camera1->pitch, dynfov(), w, h); setupstrips(); diff --git a/source/src/renderhud.cpp b/source/src/renderhud.cpp index 23873894..8e90df79 100644 --- a/source/src/renderhud.cpp +++ b/source/src/renderhud.cpp @@ -378,8 +378,7 @@ void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwat if(player1->state==CS_ALIVE && !player1->weaponsel->reloading && !menu) { bool drawteamwarning = targetplayer ? (isteam(targetplayer->team, player1->team) && targetplayer->state!=CS_DEAD) : false; - if(player1->weaponsel->type==GUN_SNIPER && scoped) drawscope(); - else if((player1->weaponsel->type!=GUN_SNIPER || drawteamwarning)) drawcrosshair(drawteamwarning); + player1->weaponsel->renderaimhelp(drawteamwarning); } drawdmgindicator(); diff --git a/source/src/sound.cpp b/source/src/sound.cpp index ac7bf877..f87e3406 100644 --- a/source/src/sound.cpp +++ b/source/src/sound.cpp @@ -3,6 +3,11 @@ #include "pch.h" #include "cube.h" +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alut.h" +#include "vorbis/vorbisfile.h" + bool nosound = true; bool alerr() @@ -83,7 +88,7 @@ struct oggstream alGetError(); alSourceQueueBuffers(sourceid, 2, bufferids); alSourcePlay(sourceid); - extern int musicvol; gain(musicvol/255.0f); + extern void setmusicvol(); setmusicvol(); ASSERT(!alGetError()); return true; } @@ -413,7 +418,6 @@ struct location { if(p) // players { - //if(p == camera1) gain(s->vol/1000.0f*0.1f); if(p != camera1) { //gain(s->vol/1000.0f); @@ -449,10 +453,8 @@ VARFP(soundvol, 0, 128, 255, alListenerf(AL_GAIN, soundvol/255.0f*10.0f); }); -VARFP(musicvol, 0, 128, 255, -{ - if(gamemusic.playing()) gamemusic.gain(musicvol/255.0f); -}); +void setmusicvol() { extern int musicvol; if(gamemusic.playing()) gamemusic.gain(musicvol/255.0f); } +VARFP(musicvol, 0, 128, 255, setmusicvol()); char *musicdonecmd = NULL; diff --git a/source/src/weapon.cpp b/source/src/weapon.cpp index a4fab47a..12fdd72d 100644 --- a/source/src/weapon.cpp +++ b/source/src/weapon.cpp @@ -73,28 +73,6 @@ COMMAND(curweapon, ARG_1EXP); COMMAND(magcontent, ARG_1EXP); COMMAND(magreserve, ARG_1EXP); -VAR(scopefov, 5, 50, 50); -bool scoped = false; -int oldfov = 100; - -void setscope(bool activate) -{ - if(player1->weaponsel->type != GUN_SNIPER || player1->state == CS_DEAD || player1->weaponsel->reloading) return; - if(activate == scoped) return; - if(activate) - { - oldfov = getvar("fov"); - setvar("fov", scopefov); - } - else - { - setvar("fov", oldfov); - } - scoped = activate; -} - -COMMAND(setscope, ARG_1INT); - void tryreload(playerent *p) { if(!p || p->state!=CS_ALIVE || p->weaponsel->reloading || p->weaponchanging) return; @@ -530,6 +508,8 @@ void raydamage(vec &from, vec &to, playerent *d) } } +// weapon + weapon::weapon(struct playerent *owner, int type) : type(type), owner(owner), info(guns[type]), ammo(owner->ammo[type]), mag(owner->mag[type]), gunwait(owner->gunwait[type]), reloading(0) { @@ -652,416 +632,12 @@ void weapon::onselecting() } void weapon::renderhudmodel() { renderhudmodel(owner->lastaction); } +void weapon::renderaimhelp(bool teamwarning) { drawcrosshair(teamwarning); } int weapon::dynspread() { return info.spread; } float weapon::dynrecoil() { return info.recoil; } bool weapon::selectable() { return this != owner->weaponsel && owner->state == CS_ALIVE && !owner->weaponchanging; } bool weapon::deselectable() { return !reloading; } - -struct grenadeent : bounceent -{ - grenadeent (playerent *owner, int millis = 0) - { - ASSERT(owner); - bounceent::owner = owner; - bounceent::millis = lastmillis; - timetolife = 2000-millis; - bouncestate = NADE_ACTIVATED; - maxspeed = 27.0f; - rotspeed = 6.0f; - } - - void explode() - { - static vec n(0,0,0); - if(bouncestate != NADE_THROWED) owner->weapons[GUN_GRENADE]->attack(n); - playsound(S_FEXPLODE, &o); - newprojectile(o, o, 1, owner==player1, owner, GUN_GRENADE, millis); - } - - virtual void destroy() - { - if(bouncestate==NADE_ACTIVATED || bouncestate==NADE_THROWED) explode(); - } -}; - -struct grenades : weapon -{ - grenadeent *inhandnade; - const int throwwait; - int throwmillis; - - grenades(playerent *owner) : weapon(owner, GUN_GRENADE), inhandnade(NULL), throwwait((13*1000)/40), throwmillis(0) {} - - bool attack(vec &targ) - { - int attackmillis = lastmillis-owner->lastaction; - vec &from = owner->o; - vec &to = targ; - - if(throwmillis && attackmillis >= throwwait) - { - throwmillis = 0; - if(!mag) - { - owner->weaponchanging = lastmillis-1-(weaponchangetime/2); - owner->nextweaponsel = owner->weaponsel = owner->primweap; - } - return false; - } - - if(attackmillisattacking && !inhandnade) // activate - { - if(!mag) return false; - throwmillis = 0; - inhandnade = new grenadeent(owner); - bounceents.add(inhandnade); - updatelastaction(owner); - mag--; - gunwait = info.attackdelay; - owner->lastattackweapon = this; - addmsg(SV_SHOOT, "ri2i6i", lastmillis, owner->weaponsel->type, - (int)(from.x*DMF), (int)(from.y*DMF), (int)(from.z*DMF), - (int)(to.x*DMF), (int)(to.y*DMF), (int)(to.z*DMF), - 0); - playsound(S_GRENADEPULL, SP_HIGH); - } - else if(inhandnade && attackmillis>info.attackdelay) - { - if(!owner->attacking) thrownade(); // throw - else if(!inhandnade->isalive(lastmillis)) // drop & have fun - { - vec n(0,0,0); - thrownade(owner->o, n, inhandnade); - } - } - return true; - } - - void attackfx(vec &from, vec &to, int millis) // other player's grenades - { - throwmillis = lastmillis-millis; - if(millis == 0) playsound(S_GRENADEPULL, owner); // activate - else if(millis > 0) // throw - { - inhandnade = new grenadeent(owner, millis); - bounceents.add(inhandnade); - thrownade(from, to, inhandnade); - } - } - - int modelanim() - { - if(throwing()) return ANIM_GUN_THROW; - else - { - int animtime = min(gunwait, (int)info.attackdelay); - if(inhand() || lastmillis - owner->lastaction < animtime) return ANIM_GUN_SHOOT; - } - return ANIM_GUN_IDLE; - } - - bool throwing() { return throwmillis && !inhandnade; } - bool inhand() { return throwmillis <= 0 && inhandnade; } - - void thrownade() - { - const float speed = cosf(RAD*owner->pitch); - vec vel(sinf(RAD*owner->yaw)*speed, -cosf(RAD*owner->yaw)*speed, sinf(RAD*owner->pitch)); - vel.mul(1.5f); - - vec from(vel); - from.normalize(); - from.mul(owner->radius+inhandnade->radius); - from.mul(1.8f); - from.add(owner->o); - - thrownade(from, vel, inhandnade); - owner->attacking = false; - } - - void thrownade(const vec &from, const vec &vel, bounceent *p) - { - if(!p) return; - p->vel = vel; - p->o = from; - p->bouncestate = NADE_THROWED; - loopi(10) moveplayer(p, 10, true, 10); - - p->bouncestate = NADE_THROWED; - inhandnade = NULL; - - if(owner==player1) - { - throwmillis = lastmillis; - playsound(S_GRENADETHROW, SP_HIGH); - updatelastaction(player1); - addmsg(SV_THROWNADE, "ri7", int(p->o.x*DMF), int(p->o.y*DMF), int(p->o.z*DMF), int(p->vel.x*DMF), int(p->vel.y*DMF), int(p->vel.z*DMF), lastmillis-p->millis); - } - else playsound(S_GRENADETHROW, owner); - } - - void renderstats() - { - char gunstats[64]; - sprintf(gunstats, "%i", mag); - draw_text(gunstats, 690, 827); - } - - bool selectable() { return weapon::selectable() && !inhand() && mag; } - void reset() { throwmillis = 0; } - - void onselecting() { reset(); playsound(S_GUNCHANGE); } - //void onammopicked() { reset(); } - void onownerdies() - { - reset(); - if(owner==player1 && inhandnade) inhandnade->explode(); - } -}; - -struct gun : weapon -{ - gun(playerent *owner, int type) : weapon(owner, type) {} - - virtual bool attack(vec &targ) - { - int attackmillis = lastmillis-owner->lastaction; - if(attackmillisattacking) - { - shots = 0; - checkautoreload(); - return false; - } - - updatelastaction(owner); - if(!mag) - { - playsoundc(S_NOAMMO); - gunwait += 250; - owner->lastattackweapon = NULL; - shots = 0; - checkautoreload(); - return false; - } - - owner->lastattackweapon = this; - shots++; - - if(!info.isauto) owner->attacking = false; - - vec from = owner->o; - vec to = targ; - from.z -= weaponbeloweye; - - attackphysics(from, to); - - hits.setsizenodelete(0); - raydamage(from, to, owner); - attackfx(from, to, 0); - - gunwait = info.attackdelay; - mag--; - - sendshoot(from, to); - return true; - } - - virtual void attackfx(vec &from, vec &to, int millis) - { - addbullethole(from, to); - addshotline(owner, from, to); - particle_splash(0, 5, 250, to); - attacksound(); - } - - int modelanim() { return modelattacking() ? ANIM_GUN_SHOOT|ANIM_LOOP : ANIM_GUN_IDLE; }; - - void checkautoreload() { if(autoreload && owner==player1 && !mag) reload(); } -}; - -struct shotgun : gun -{ - shotgun(playerent *owner) : gun(owner, GUN_SHOTGUN) {} - - bool attack(vec &targ) - { - vec from = owner->o; - from.z -= weaponbeloweye; - createrays(from, targ); - return gun::attack(targ); - } - - void attackfx(vec &from, vec &to, int millis) - { - 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, false); - } - attacksound(); - } - - bool selectable() { return weapon::selectable() && !m_noprimary && this == owner->primweap; } -}; - -struct subgun : gun -{ - subgun(playerent *owner) : gun(owner, GUN_SUBGUN) {} - bool selectable() { return weapon::selectable() && !m_noprimary && this == owner->primweap; } -}; - -struct sniperrifle : gun -{ - sniperrifle(playerent *owner) : gun(owner, GUN_SNIPER) {} - - void attackfx(vec &from, vec &to, int millis) - { - addbullethole(from, to); - addshotline(owner, from, to); - particle_splash(0, 50, 200, to); - particle_trail(1, 500, from, to); - attacksound(); - } - - bool reload() - { - bool r = weapon::reload(); - if(owner==player1 && r) setscope(false); - return r; - } - - int dynspread() { return scoped ? 1 : info.spread; } - float dynrecoil() { return scoped ? info.recoil / 3 : info.recoil; } - bool selectable() { return weapon::selectable() && !m_noprimary && this == owner->primweap; } - void onselecting() { weapon::onselecting(); setscope(false); } - void ondeselecting() { setscope(false); } -}; - -struct assaultrifle : gun -{ - assaultrifle(playerent *owner) : gun(owner, GUN_ASSAULT) {} - - int dynspread() { return shots > 3 ? 70 : info.spread; } - float dynrecoil() { return info.recoil + (rnd(8)*-0.01f); } - bool selectable() { return weapon::selectable() && !m_noprimary && this == owner->primweap; } -}; - -struct pistol : gun -{ - pistol(playerent *owner) : gun(owner, GUN_PISTOL) {} - bool selectable() { return weapon::selectable() && !m_nopistol; } -}; - -struct akimbo : gun -{ - akimbo(playerent *owner) : gun(owner, GUN_AKIMBO), akimbomillis(0) - { - akimbolastaction[0] = akimbolastaction[1] = 0; - } - - bool akimboside; - int akimbomillis; - int akimbolastaction[2]; - - bool attack(vec &targ) - { - if(gun::attack(targ)) - { - akimbolastaction[akimboside?1:0] = lastmillis; - akimboside = !akimboside; - return true; - } - return false; - } - - void onammopicked() - { - akimbomillis = lastmillis + 30000; - if(owner==player1) - { - if(owner->weaponsel->type!=GUN_SNIPER && owner->weaponsel->type!=GUN_GRENADE) weaponswitch(this); - addmsg(SV_AKIMBO, "ri", lastmillis); - } - } - - void onselecting() - { - gun::onselecting(); - akimbolastaction[0] = akimbolastaction[1] = lastmillis; - } - - bool selectable() { return weapon::selectable() && !m_nopistol && owner->akimbo; } - void updatetimers() { weapon::updatetimers(); /*loopi(2) akimbolastaction[i] = lastmillis;*/ } - void reset() { akimbolastaction[0] = akimbolastaction[1] = akimbomillis = 0; akimboside = false; } - - void renderhudmodel() - { - weapon::renderhudmodel(akimbolastaction[0], 0); - weapon::renderhudmodel(akimbolastaction[1], 1); - } - - bool timerout() { return akimbomillis && akimbomillis <= lastmillis; } -}; - -struct knife : weapon -{ - knife(playerent *owner) : weapon(owner, GUN_KNIFE) {} - - bool attack(vec &targ) - { - int attackmillis = lastmillis-owner->lastaction; - if(attackmillisattacking) return false; - updatelastaction(owner); - - owner->lastattackweapon = this; - owner->attacking = false; - - vec from = owner->o; - vec to = targ; - from.z -= weaponbeloweye; - - vec unitv; - float dist = to.dist(from, unitv); - unitv.div(dist); - unitv.mul(3); // punch range - to = from; - to.add(unitv); - - hits.setsizenodelete(0); - raydamage(from, to, owner); - attackfx(from, to, 0); - sendshoot(from, to); - gunwait = info.attackdelay; - return true; - }; - - int modelanim() { return modelattacking() ? ANIM_GUN_SHOOT : ANIM_GUN_IDLE; }; - - void drawstats() {} - void attackfx(vec &from, vec &to, int millis) { attacksound(); } - void renderstats() { }; -}; - - -void shoot(playerent *p, vec &targ) -{ - if(p->state==CS_DEAD || p->weaponchanging) return; - weapon *weap = p->weaponsel; - if(weap) weap->attack(targ); -} - void weapon::equipplayer(playerent *pl) { if(!pl) return; @@ -1078,6 +654,414 @@ void weapon::equipplayer(playerent *pl) pl->setnextprimary(GUN_ASSAULT); } + +// grenadeent + +grenadeent::grenadeent (playerent *owner, int millis) +{ + ASSERT(owner); + bounceent::owner = owner; + bounceent::millis = lastmillis; + timetolife = 2000-millis; + bouncestate = NADE_ACTIVATED; + maxspeed = 27.0f; + rotspeed = 6.0f; +} + +void grenadeent::explode() +{ + static vec n(0,0,0); + if(bouncestate != NADE_THROWED) owner->weapons[GUN_GRENADE]->attack(n); + playsound(S_FEXPLODE, &o); + newprojectile(o, o, 1, owner==player1, owner, GUN_GRENADE, millis); +} + +void grenadeent::destroy() +{ + if(bouncestate==NADE_ACTIVATED || bouncestate==NADE_THROWED) explode(); +} + + +// grenades + +grenades::grenades(playerent *owner) : weapon(owner, GUN_GRENADE), inhandnade(NULL), throwwait((13*1000)/40), throwmillis(0) {} + +bool grenades::attack(vec &targ) +{ + int attackmillis = lastmillis-owner->lastaction; + vec &from = owner->o; + vec &to = targ; + + if(throwmillis && attackmillis >= throwwait) + { + throwmillis = 0; + if(!mag) + { + owner->weaponchanging = lastmillis-1-(weaponchangetime/2); + owner->nextweaponsel = owner->weaponsel = owner->primweap; + } + return false; + } + + if(attackmillisattacking && !inhandnade) // activate + { + if(!mag) return false; + throwmillis = 0; + inhandnade = new grenadeent(owner); + bounceents.add(inhandnade); + updatelastaction(owner); + mag--; + gunwait = info.attackdelay; + owner->lastattackweapon = this; + addmsg(SV_SHOOT, "ri2i6i", lastmillis, owner->weaponsel->type, + (int)(from.x*DMF), (int)(from.y*DMF), (int)(from.z*DMF), + (int)(to.x*DMF), (int)(to.y*DMF), (int)(to.z*DMF), + 0); + playsound(S_GRENADEPULL, SP_HIGH); + } + else if(inhandnade && attackmillis>info.attackdelay) + { + if(!owner->attacking) thrownade(); // throw + else if(!inhandnade->isalive(lastmillis)) // drop & have fun + { + vec n(0,0,0); + thrownade(owner->o, n, inhandnade); + } + } + return true; +} + +void grenades::attackfx(vec &from, vec &to, int millis) // other player's grenades +{ + throwmillis = lastmillis-millis; + if(millis == 0) playsound(S_GRENADEPULL, owner); // activate + else if(millis > 0) // throw + { + inhandnade = new grenadeent(owner, millis); + bounceents.add(inhandnade); + thrownade(from, to, inhandnade); + } +} + +int grenades::modelanim() +{ + if(throwing()) return ANIM_GUN_THROW; + else + { + int animtime = min(gunwait, (int)info.attackdelay); + if(inhand() || lastmillis - owner->lastaction < animtime) return ANIM_GUN_SHOOT; + } + return ANIM_GUN_IDLE; +} + +bool grenades::throwing() { return throwmillis && !inhandnade; } +bool grenades::inhand() { return throwmillis <= 0 && inhandnade; } + +void grenades::thrownade() +{ + const float speed = cosf(RAD*owner->pitch); + vec vel(sinf(RAD*owner->yaw)*speed, -cosf(RAD*owner->yaw)*speed, sinf(RAD*owner->pitch)); + vel.mul(1.5f); + + vec from(vel); + from.normalize(); + from.mul(owner->radius+inhandnade->radius); + from.mul(1.8f); + from.add(owner->o); + + thrownade(from, vel, inhandnade); + owner->attacking = false; +} + +void grenades::thrownade(const vec &from, const vec &vel, bounceent *p) +{ + if(!p) return; + p->vel = vel; + p->o = from; + p->bouncestate = NADE_THROWED; + loopi(10) moveplayer(p, 10, true, 10); + + p->bouncestate = NADE_THROWED; + inhandnade = NULL; + + if(owner==player1) + { + throwmillis = lastmillis; + playsound(S_GRENADETHROW, SP_HIGH); + updatelastaction(player1); + addmsg(SV_THROWNADE, "ri7", int(p->o.x*DMF), int(p->o.y*DMF), int(p->o.z*DMF), int(p->vel.x*DMF), int(p->vel.y*DMF), int(p->vel.z*DMF), lastmillis-p->millis); + } + else playsound(S_GRENADETHROW, owner); +} + +void grenades::renderstats() +{ + char gunstats[64]; + sprintf(gunstats, "%i", mag); + draw_text(gunstats, 690, 827); +} + +bool grenades::selectable() { return weapon::selectable() && !inhand() && mag; } +void grenades::reset() { throwmillis = 0; } + +void grenades::onselecting() { reset(); playsound(S_GUNCHANGE); } +void grenades::onownerdies() +{ + reset(); + if(owner==player1 && inhandnade) inhandnade->explode(); +} + + +// gun base class + +gun::gun(playerent *owner, int type) : weapon(owner, type) {}; + +bool gun::attack(vec &targ) +{ + int attackmillis = lastmillis-owner->lastaction; + if(attackmillisattacking) + { + shots = 0; + checkautoreload(); + return false; + } + + updatelastaction(owner); + if(!mag) + { + playsoundc(S_NOAMMO); + gunwait += 250; + owner->lastattackweapon = NULL; + shots = 0; + checkautoreload(); + return false; + } + + owner->lastattackweapon = this; + shots++; + + if(!info.isauto) owner->attacking = false; + + vec from = owner->o; + vec to = targ; + from.z -= weaponbeloweye; + + attackphysics(from, to); + + hits.setsizenodelete(0); + raydamage(from, to, owner); + attackfx(from, to, 0); + + gunwait = info.attackdelay; + mag--; + + sendshoot(from, to); + return true; +} + +void gun::attackfx(vec &from, vec &to, int millis) +{ + addbullethole(from, to); + addshotline(owner, from, to); + particle_splash(0, 5, 250, to); + attacksound(); +} + +int gun::modelanim() { return modelattacking() ? ANIM_GUN_SHOOT|ANIM_LOOP : ANIM_GUN_IDLE; }; +void gun::checkautoreload() { if(autoreload && owner==player1 && !mag) reload(); } + + +// shotgun + +shotgun::shotgun(playerent *owner) : gun(owner, GUN_SHOTGUN) {} + +bool shotgun::attack(vec &targ) +{ + vec from = owner->o; + from.z -= weaponbeloweye; + createrays(from, targ); + return gun::attack(targ); +} + +void shotgun::attackfx(vec &from, vec &to, int millis) +{ + 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, false); + } + attacksound(); +} + +bool shotgun::selectable() { return weapon::selectable() && !m_noprimary && this == owner->primweap; } + + +// subgun + +subgun::subgun(playerent *owner) : gun(owner, GUN_SUBGUN) {} +bool subgun::selectable() { return weapon::selectable() && !m_noprimary && this == owner->primweap; } + + +// sniperrifle + +sniperrifle::sniperrifle(playerent *owner) : scoped(false), gun(owner, GUN_SNIPER) {} + +void sniperrifle::attackfx(vec &from, vec &to, int millis) +{ + addbullethole(from, to); + addshotline(owner, from, to); + particle_splash(0, 50, 200, to); + particle_trail(1, 500, from, to); + attacksound(); +} + +bool sniperrifle::reload() +{ + bool r = weapon::reload(); + if(owner==player1 && r) setscope(false); + return r; +} + +int sniperrifle::dynspread() { return scoped ? 1 : info.spread; } +float sniperrifle::dynrecoil() { return scoped ? info.recoil / 3 : info.recoil; } +bool sniperrifle::selectable() { return weapon::selectable() && !m_noprimary && this == owner->primweap; } +void sniperrifle::onselecting() { weapon::onselecting(); scoped = false; } +void sniperrifle::ondeselecting() { scoped = false; } +void sniperrifle::renderhudmodel() { if(!scoped) weapon::renderhudmodel(); } +void sniperrifle::renderaimhelp(bool teamwarning) { if(scoped) drawscope(); if(teamwarning) drawcrosshair(teamwarning); } + +void sniperrifle::setscope(bool enable) { if(this == owner->weaponsel && !reloading && owner->state == CS_ALIVE) scoped = enable; } + + +// assaultrifle + +assaultrifle::assaultrifle(playerent *owner) : gun(owner, GUN_ASSAULT) {} + +int assaultrifle::dynspread() { return shots > 3 ? 70 : info.spread; } +float assaultrifle::dynrecoil() { return info.recoil + (rnd(8)*-0.01f); } +bool assaultrifle::selectable() { return weapon::selectable() && !m_noprimary && this == owner->primweap; } + + +// pistol + +pistol::pistol(playerent *owner) : gun(owner, GUN_PISTOL) {} +bool pistol::selectable() { return weapon::selectable() && !m_nopistol; } + + +// akimbo + +akimbo::akimbo(playerent *owner) : gun(owner, GUN_AKIMBO), akimbomillis(0) +{ + akimbolastaction[0] = akimbolastaction[1] = 0; +} + +bool akimbo::attack(vec &targ) +{ + if(gun::attack(targ)) + { + akimbolastaction[akimboside?1:0] = lastmillis; + akimboside = !akimboside; + return true; + } + return false; +} + +void akimbo::onammopicked() +{ + akimbomillis = lastmillis + 30000; + if(owner==player1) + { + if(owner->weaponsel->type!=GUN_SNIPER && owner->weaponsel->type!=GUN_GRENADE) weaponswitch(this); + addmsg(SV_AKIMBO, "ri", lastmillis); + } +} + +void akimbo::onselecting() +{ + gun::onselecting(); + akimbolastaction[0] = akimbolastaction[1] = lastmillis; +} + +bool akimbo::selectable() { return weapon::selectable() && !m_nopistol && owner->akimbo; } +void akimbo::updatetimers() { weapon::updatetimers(); /*loopi(2) akimbolastaction[i] = lastmillis;*/ } +void akimbo::reset() { akimbolastaction[0] = akimbolastaction[1] = akimbomillis = 0; akimboside = false; } + +void akimbo::renderhudmodel() +{ + weapon::renderhudmodel(akimbolastaction[0], 0); + weapon::renderhudmodel(akimbolastaction[1], 1); +} + +bool akimbo::timerout() { return akimbomillis && akimbomillis <= lastmillis; } + + +// knife + +knife::knife(playerent *owner) : weapon(owner, GUN_KNIFE) {} + +bool knife::attack(vec &targ) +{ + int attackmillis = lastmillis-owner->lastaction; + if(attackmillisattacking) return false; + updatelastaction(owner); + + owner->lastattackweapon = this; + owner->attacking = false; + + vec from = owner->o; + vec to = targ; + from.z -= weaponbeloweye; + + vec unitv; + float dist = to.dist(from, unitv); + unitv.div(dist); + unitv.mul(3); // punch range + to = from; + to.add(unitv); + + hits.setsizenodelete(0); + raydamage(from, to, owner); + attackfx(from, to, 0); + sendshoot(from, to); + gunwait = info.attackdelay; + return true; +}; + +int knife::modelanim() { return modelattacking() ? ANIM_GUN_SHOOT : ANIM_GUN_IDLE; }; + +void knife::drawstats() {} +void knife::attackfx(vec &from, vec &to, int millis) { attacksound(); } +void knife::renderstats() { }; + + +void setscope(bool enable) +{ + if(player1->weaponsel->type != GUN_SNIPER) return; + sniperrifle *sr = (sniperrifle *)player1->weaponsel; + sr->setscope(enable); +} + +COMMAND(setscope, ARG_1INT); + + +void shoot(playerent *p, vec &targ) +{ + if(p->state==CS_DEAD || p->weaponchanging) return; + weapon *weap = p->weaponsel; + if(weap) weap->attack(targ); +} + void checkakimbo() { if(player1->akimbo) diff --git a/source/src/weapon.h b/source/src/weapon.h index ff986619..401c8521 100644 --- a/source/src/weapon.h +++ b/source/src/weapon.h @@ -1,3 +1,4 @@ + struct playerent; struct weapon @@ -30,6 +31,7 @@ struct weapon virtual bool deselectable(); virtual void renderstats(); virtual void renderhudmodel(); + virtual void renderaimhelp(bool teamwarning); virtual void onselecting(); virtual void ondeselecting() {} @@ -41,3 +43,120 @@ struct weapon void renderhudmodel(int lastaction, int index = 0); }; +struct grenadeent; +struct bounceent; + +struct grenades : weapon +{ + grenadeent *inhandnade; + const int throwwait; + int throwmillis; + + grenades(playerent *owner); + bool attack(vec &targ); + void attackfx(vec &from, vec &to, int millis); + int modelanim(); + bool throwing(); + bool inhand(); + void thrownade(); + void thrownade(const vec &from, const vec &vel, bounceent *p); + void renderstats(); + bool selectable(); + void reset(); + void onselecting(); + void onownerdies(); +}; + + +struct gun : weapon +{ + gun::gun(playerent *owner, int type); + virtual bool attack(vec &targ); + virtual void attackfx(vec &from, vec &to, int millis); + int modelanim(); + void checkautoreload(); +}; + + +struct subgun : gun +{ + subgun(playerent *owner); + bool selectable(); +}; + + +struct sniperrifle : gun +{ + bool scoped; + + sniperrifle(playerent *owner); + void attackfx(vec &from, vec &to, int millis); + bool reload(); + + int dynspread(); + float dynrecoil(); + bool selectable(); + void onselecting(); + void ondeselecting(); + void renderhudmodel(); + void renderaimhelp(bool teamwarning); + + void setscope(bool enable); +}; + + +struct shotgun : gun +{ + shotgun(playerent *owner); + bool attack(vec &targ); + void attackfx(vec &from, vec &to, int millis); + bool selectable(); +}; + + +struct assaultrifle : gun +{ + assaultrifle(playerent *owner); + int dynspread(); + float dynrecoil(); + bool selectable(); +}; + + +struct pistol : gun +{ + pistol(playerent *owner); + bool selectable(); +}; + + +struct akimbo : gun +{ + akimbo(playerent *owner); + + bool akimboside; + int akimbomillis; + int akimbolastaction[2]; + + bool attack(vec &targ); + void onammopicked(); + void onselecting(); + bool selectable(); + void updatetimers(); + void reset(); + void renderhudmodel(); + bool timerout(); +}; + + +struct knife : weapon +{ + knife(playerent *owner); + + bool attack(vec &targ); + int modelanim(); + + void drawstats(); + void attackfx(vec &from, vec &to, int millis); + void renderstats(); +}; \ No newline at end of file