diff --git a/config/keymap.cfg b/config/keymap.cfg index 4fc9b8d8..10e636b3 100755 --- a/config/keymap.cfg +++ b/config/keymap.cfg @@ -70,7 +70,7 @@ keymap 114 R "recalc" keymap 115 S "say :)" keymap 116 T "saycommand" keymap 117 U "undo" -keymap 118 V "paste" +keymap 118 V "showmenu voicecom" keymap 119 W "" keymap 120 X "delent" keymap 121 Y "saycommand %" diff --git a/config/menus_multiplayer.cfg b/config/menus_multiplayer.cfg index ddfb93b2..e67ad1da 100644 --- a/config/menus_multiplayer.cfg +++ b/config/menus_multiplayer.cfg @@ -45,7 +45,7 @@ menuitem "Open" "mastermode 0" menuitem "Private" "mastermode 1" -newmenu voicecom +newmenu voicecom 1 menuitem "Team Commands" [showmenu "Team Commands"] menuitem "Team State" [showmenu "Team State"] @@ -55,11 +55,10 @@ menuitem "Public Talk" [showmenu "Public Talk"] alias genvcitem [ menuitem $arg1 (concat "voicecom" $arg2 (concatword "[" $arg1 "]")) - echo menuitem $arg1 (concat "voicecom" $arg2 (concatword "[" $arg1 "]")) ] -newmenu "Team Commands" +newmenu "Team Commands" 1 genvcitem "Come on, move!" comeonmove genvcitem "Cover me!" coverme @@ -70,7 +69,7 @@ genvcitem "Recover the flag!" recovertheflag genvcitem "Stay together!" staytogether -newmenu "Team State" +newmenu "Team State" 1 genvcitem "Enemy down" enemydown genvcitem "I got one" igotone @@ -80,7 +79,7 @@ genvcitem "I'm on defense" imondefense genvcitem "Coming in with the flag!" comminginwiththeflag -newmenu "Team Talk" +newmenu "Team Talk" 1 genvcitem Yes yes genvcitem Affirmative affirmative @@ -91,7 +90,7 @@ genvcitem "There's no way, Sir!" theresnowaysir genvcitem "Sorry" sorry -newmenu "Team Shouts" +newmenu "Team Shouts" 1 genvcitem "We did it!" wedidit genvcitem "Go get 'em boys!" gogetemboys @@ -99,6 +98,6 @@ genvcitem "Good job, team!" goodjobteam genvcitem "I'm on your team, man!" imonyourteamman -newmenu "Public Talk" +newmenu "Public Talk" 1 genvcitem "Nice shot" niceshot \ No newline at end of file diff --git a/config/sounds.cfg b/config/sounds.cfg index 059156a1..f1f7eae9 100755 --- a/config/sounds.cfg +++ b/config/sounds.cfg @@ -47,6 +47,32 @@ registersound "misc/vote/vote_fail" // S_VOTEFAIL registersound "player/footsteps" 100 1 // S_FOOTSTEPS registersound "player/crouch" 100 // S_FOOTSTEPSCROUCH +registersound "voicecom/affirmative" +registersound "voicecom/allrightsir" +registersound "voicecom/comeonmove" +registersound "voicecom/cominginwiththeflag" +registersound "voicecom/coverme" +registersound "voicecom/defendtheflag" +registersound "voicecom/enemydown" +registersound "voicecom/gogetemboys" +registersound "voicecom/goodjobteam" +registersound "voicecom/igotone" +registersound "voicecom/imadecontact" +registersound "voicecom/imattacking" +registersound "voicecom/imondefense" +registersound "voicecom/imonyourteamman" +registersound "voicecom/negative" +registersound "voicecom/nocando" +registersound "voicecom/recovertheflag" +registersound "voicecom/sorry" +registersound "voicecom/spreadout" +registersound "voicecom/stayhere" +registersound "voicecom/staytogether" +registersound "voicecom/theresnowaysir" +registersound "voicecom/wedidit" +registersound "voicecom/yes" +registersound "voicecom/niceshot" + alias fade [ // 0=in, 1=out alias stepsize 5 alias numsteps (div $maxmusicvol $stepsize) @@ -55,5 +81,5 @@ alias fade [ // 0=in, 1=out if (= $arg1 1) [ alias curvol (- $maxmusicvol $curvol) ] sleep (* $i 100) (concat musicvol $curvol) ] -] +] diff --git a/packages/textures/kurt/klite2.jpg b/packages/textures/kurt/klite2.jpg index ec51a3de..dffb7ec4 100755 Binary files a/packages/textures/kurt/klite2.jpg and b/packages/textures/kurt/klite2.jpg differ diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index 866670d1..660f5425 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -829,6 +829,7 @@ void refreshsopmenu(void *menu, bool init) void followplayer(int i) { + if(player1->state==CS_ALIVE) return; showscores(false); player1->spectating = SM_FOLLOWPLAYER; if(players.length()) @@ -845,6 +846,7 @@ void followplayer(int i) void spectate() { + if(player1->state==CS_ALIVE) return; showscores(false); player1->spectating = SM_FLY; } diff --git a/source/src/clients2c.cpp b/source/src/clients2c.cpp index d1fa88ba..d706d4f6 100644 --- a/source/src/clients2c.cpp +++ b/source/src/clients2c.cpp @@ -165,7 +165,20 @@ void parsemessages(int cn, playerent *d, ucharbuf &p) case SV_SOUND: playsound(getint(p), !d ? NULL : d); break; - + + case SV_VOICECOMTEAM: + { + playerent *d = getclient(getint(p)); + if(d) d->lastvoicecom = lastmillis; + playsound(getint(p)); + break; + } + case SV_VOICECOM: + { + playsound(getint(p)); + if(d) d->lastvoicecom = lastmillis; + break; + } case SV_TEAMTEXT: { diff --git a/source/src/entity.h b/source/src/entity.h index 6469f8f2..31d72d55 100644 --- a/source/src/entity.h +++ b/source/src/entity.h @@ -328,7 +328,7 @@ struct playerent : dynent, playerstate int lifesequence; // sequence id for each respawn, used in damage test int frags, flagscore; int deaths() { return lifesequence + (state==CS_DEAD ? 1 : 0); } - int lastaction, lastmove, lastpain; + int lastaction, lastmove, lastpain, lastvoicecom; int clientrole; bool attacking; string name, team; @@ -348,7 +348,7 @@ struct playerent : dynent, playerstate float deltayaw, deltapitch, newyaw, newpitch; int smoothmillis; - playerent() : clientnum(-1), plag(0), ping(0), lifesequence(0), frags(0), flagscore(0), lastpain(0), clientrole(CR_DEFAULT), + playerent() : clientnum(-1), plag(0), ping(0), lifesequence(0), frags(0), flagscore(0), lastpain(0), lastvoicecom(0), clientrole(CR_DEFAULT), skin(0), nextskin(0), spectating(SM_NONE), followplayercn(0), weaponsel(NULL), nextweaponsel(NULL), primweap(NULL), nextprimweap(NULL), lastattackweapon(NULL), smoothmillis(-1) diff --git a/source/src/menus.cpp b/source/src/menus.cpp index 3d1a24f5..42b2d522 100644 --- a/source/src/menus.cpp +++ b/source/src/menus.cpp @@ -419,7 +419,7 @@ struct mitemcheckbox : mitem // console iface -void *addmenu(const char *name, const char *title, bool allowinput, void (__cdecl *refreshfunc)(void *, bool)) +void *addmenu(const char *name, const char *title, bool allowinput, void (__cdecl *refreshfunc)(void *, bool), bool hotkeys) { name = newstring(name); gmenu &menu = menus[name]; @@ -430,15 +430,16 @@ void *addmenu(const char *name, const char *title, bool allowinput, void (__cdec menu.mdl = NULL; menu.allowinput = allowinput; menu.inited = false; + menu.hotkeys = hotkeys; menu.refreshfunc = refreshfunc; menu.dirlist = NULL; lastmenu = &menu; return &menu; } -void newmenu(char *name) +void newmenu(char *name, char *hotkeys) { - addmenu(name); + addmenu(name, NULL, true, NULL, atoi(hotkeys) > 0); } void menumanual(void *menu, int n, char *text, char *action, color *bgcolor) @@ -517,17 +518,19 @@ void chmenumdl(char *menu, char *mdl, char *anim, char *rotspeed, char *scale) m.rotspeed = max(0, min(atoi(rotspeed), 100)); m.scale = max(0, min(atoi(scale), 100)); } - + + +COMMAND(newmenu, ARG_2STR); +COMMAND(menumdl, ARG_5STR); +COMMAND(menudirlist, ARG_3STR); +COMMAND(chmenumdl, ARG_6STR); +COMMAND(showmenu, ARG_1STR); COMMAND(menuitem, ARG_3STR); COMMAND(menuitemtextinput, ARG_4STR); COMMAND(menuitemslider, ARG_7STR); COMMAND(menuitemkeyinput, ARG_4STR); COMMAND(menuitemcheckbox, ARG_3STR); -COMMAND(showmenu, ARG_1STR); -COMMAND(newmenu, ARG_1STR); -COMMAND(menumdl, ARG_5STR); -COMMAND(menudirlist, ARG_3STR); -COMMAND(chmenumdl, ARG_6STR); + bool menukey(int code, bool isdown, int unicode) { @@ -557,6 +560,22 @@ bool menukey(int code, bool isdown, int unicode) case -5: menusel++; break; + + case SDLK_1: + case SDLK_2: + case SDLK_3: + case SDLK_4: + case SDLK_5: + case SDLK_6: + case SDLK_7: + case SDLK_8: + case SDLK_9: + if(curmenu->allowinput && curmenu->hotkeys) + { + mitem &m = *curmenu->items[code-SDLK_1]; + m.select(); + return true; + } default: { if(!curmenu->allowinput || !curmenu->items.inrange(menusel)) return false; @@ -575,7 +594,6 @@ bool menukey(int code, bool isdown, int unicode) mitem &m = *curmenu->items[menusel]; if(code==SDLK_RETURN || code==SDLK_SPACE || code==-1 || code==-2) { - if(!curmenu->items.inrange(menusel)) { menuset(NULL); return true; } m.select(); return true; } diff --git a/source/src/physics.cpp b/source/src/physics.cpp index 677b8fbf..cefd3ec3 100644 --- a/source/src/physics.cpp +++ b/source/src/physics.cpp @@ -229,6 +229,7 @@ float floor(short x, short y) } VARP(maxroll, 0, 0, 20); +VAR(recoilbackfade, 0, 100, 1000); // main physics routine, moves a player/monster for a curtime step // moveres indicated the physics precision (which is lower for monsters and multiplayer prediction) @@ -437,7 +438,9 @@ void moveplayer(physent *pl, int moveres, bool local, int curtime) pl->pitch += pl->pitchvel*(curtime/1000.0f)*pl->maxspeed*(pl->crouching ? 0.75f : 1.0f); pl->pitchvel *= fric-3; pl->pitchvel /= fric; - if(pl->pitchvel < 0.05f && pl->pitchvel > 0.001f) pl->pitchvel -= ((playerent *)pl)->weaponsel->info.recoilbackfade/100.0f; // slide back + extern int recoiltest; + if(recoiltest) if(pl->pitchvel < 0.05f && pl->pitchvel > 0.001f) pl->pitchvel -= recoilbackfade/100.0f; // slide back + else if(pl->pitchvel < 0.05f && pl->pitchvel > 0.001f) pl->pitchvel -= ((playerent *)pl)->weaponsel->info.recoilbackfade/100.0f; // slide back if(pl->pitchvel) fixcamerarange(pl); // fix pitch if necessary } } diff --git a/source/src/protocol.cpp b/source/src/protocol.cpp index 49d31d58..61072a17 100644 --- a/source/src/protocol.cpp +++ b/source/src/protocol.cpp @@ -104,7 +104,7 @@ const char *modestr(int n) { return (n>=0 && (size_t)n < sizeof(modenames)/sizeo char msgsizesl[] = // size inclusive message token, 0 for variable or not-checked sizes { - SV_INITS2C, 5, SV_INITC2S, 0, SV_POS, 0, SV_TEXT, 0, SV_TEAMTEXT, 0, SV_SOUND, 2, SV_CDIS, 2, + SV_INITS2C, 5, SV_INITC2S, 0, SV_POS, 0, SV_TEXT, 0, SV_TEAMTEXT, 0, SV_SOUND, 2, SV_VOICECOM, 2, SV_VOICECOMTEAM, 2, SV_CDIS, 2, SV_SHOOT, 0, SV_EXPLODE, 0, SV_SUICIDE, 1, SV_AKIMBO, 2, SV_RELOAD, 3, SV_GIBDIED, 4, SV_DIED, 4, SV_GIBDAMAGE, 6, SV_DAMAGE, 6, SV_HITPUSH, 6, SV_SHOTFX, 9, SV_THROWNADE, 8, SV_TRYSPAWN, 1, SV_SPAWNSTATE, 20, SV_SPAWN, 3, SV_FORCEDEATH, 2, SV_RESUME, 0, diff --git a/source/src/protocol.h b/source/src/protocol.h index 7593253b..ed2fb6bd 100644 --- a/source/src/protocol.h +++ b/source/src/protocol.h @@ -11,7 +11,7 @@ // network messages codes, c2s, c2c, s2c enum { - SV_INITS2C = 0, SV_INITC2S, SV_POS, SV_TEXT, SV_TEAMTEXT, SV_SOUND, SV_CDIS, + SV_INITS2C = 0, SV_INITC2S, SV_POS, SV_TEXT, SV_TEAMTEXT, SV_SOUND, SV_VOICECOM, SV_VOICECOMTEAM, SV_CDIS, SV_SHOOT, SV_EXPLODE, SV_SUICIDE, SV_AKIMBO, SV_RELOAD, SV_GIBDIED, SV_DIED, SV_GIBDAMAGE, SV_DAMAGE, SV_HITPUSH, SV_SHOTFX, SV_THROWNADE, SV_TRYSPAWN, SV_SPAWNSTATE, SV_SPAWN, SV_FORCEDEATH, SV_RESUME, diff --git a/source/src/protos.h b/source/src/protos.h index 702b133b..26eefacd 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -73,7 +73,7 @@ extern bool menuvisible(); extern void menumanual(void *menu, int n, char *text, char *action = NULL, color *bgcolor = NULL); extern void menuheader(void *menu, char *header = NULL, char *footer = NULL); extern bool menukey(int code, bool isdown, int unicode); -extern void *addmenu(const char *name, const char *title = NULL, bool allowinput = true, void (__cdecl *refreshfunc)(void *, bool) = NULL); +extern void *addmenu(const char *name, const char *title = NULL, bool allowinput = true, void (__cdecl *refreshfunc)(void *, bool) = NULL, bool hotkeys = false); extern void rendermenumdl(); extern void menuset(void *m); extern void menuselect(void *menu, int sel); @@ -91,7 +91,7 @@ struct mitem virtual int width() = 0; virtual void select() {} virtual void focus(bool on) {} - virtual void key(int code, bool isdown, int unicode) {} + virtual void key(int code, bool isdown, int unicode) { } virtual void init() {} bool isselection(); void renderbg(int x, int y, int w, color *c); @@ -115,7 +115,7 @@ struct gmenu vector items; int mwidth; int menusel; - bool allowinput, inited; + bool allowinput, inited, hotkeys; void (__cdecl *refreshfunc)(void *, bool); const char *mdl; @@ -162,10 +162,13 @@ extern void dot(int x, int y, float z); extern void linestyle(float width, int r, int g, int b); extern void blendbox(int x1, int y1, int x2, int y2, bool border, int tex = -1, color *c = NULL); extern void quad(GLuint tex, float x, float y, float s, float tx, float ty, float tsx, float tsy = 0); +extern void quad(GLuint tex, vec &c1, vec &c2, float tx, float ty, float tsx, float tsy); extern void circle(GLuint tex, float x, float y, float r, float tx, float ty, float tr, int subdiv = 32); 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); + // texture struct Texture diff --git a/source/src/rendergl.cpp b/source/src/rendergl.cpp index 54496dd3..26f59033 100644 --- a/source/src/rendergl.cpp +++ b/source/src/rendergl.cpp @@ -135,6 +135,19 @@ void quad(GLuint tex, float x, float y, float s, float tx, float ty, float tsx, xtraverts += 4; } +void quad(GLuint tex, vec &c1, vec &c2, float tx, float ty, float tsx, float tsy) +{ + if(!tsy) tsy = tsx; + glBindTexture(GL_TEXTURE_2D, tex); + glBegin(GL_QUADS); + glTexCoord2f(tx, ty); glVertex3f(c1.x, c1.y, c1.z); + glTexCoord2f(tx+tsx, ty); glVertex3f(c2.x, c1.y, c1.z); + glTexCoord2f(tx+tsx, ty+tsy); glVertex3f(c2.x, c2.y, c2.z); + glTexCoord2f(tx, ty+tsy); glVertex3f(c1.x, c2.y, c2.z); + glEnd(); + xtraverts += 4; +} + void circle(GLuint tex, float x, float y, float r, float tx, float ty, float tr, int subdiv) { glBindTexture(GL_TEXTURE_2D, tex); @@ -251,6 +264,26 @@ void blendbox(int x1, int y1, int x2, int y2, bool border, int tex, color *c) glDepthMask(GL_TRUE); } +VARP(aboveheadiconsize, 0, 50, 1000); +VARP(aboveheadiconfadetime, 1, 1000, 10000); + +void renderaboveheadicon(playerent *p) +{ + int t = lastmillis-p->lastvoicecom; + if(!aboveheadiconsize || !p->lastvoicecom || t > aboveheadiconfadetime) return; + glPushMatrix(); + glDisable(GL_CULL_FACE); + glTranslatef(p->o.x, p->o.y, p->o.z+p->aboveeye); + glRotatef(camera1->yaw-180, 0, 0, 1); + glColor3f(1.0f, 1.0f, 1.0f); + static Texture *tex = NULL; + if(!tex) tex = textureload("packages/misc/com.png"); + float s = aboveheadiconsize/100.0f; + quad(tex->id, vec(s/2.0f, 0.0f, s), vec(s/-2.0f, 0.0f, 0.0f), 0.0f, 0.0f, 1.0f, 1.0f); + glEnable(GL_CULL_FACE); + glPopMatrix(); +} + void rendercursor(int x, int y, int w) { color c(1, 1, 1, (sinf(lastmillis/200.0f)+1.0f)/2.0f); diff --git a/source/src/rendermodel.cpp b/source/src/rendermodel.cpp index c5260cb2..ccbec63a 100644 --- a/source/src/rendermodel.cpp +++ b/source/src/rendermodel.cpp @@ -458,9 +458,10 @@ void renderclient(playerent *d, const char *mdlname, const char *vwepname, int t else { anim = (d->crouching ? ANIM_CROUCH_WALK : ANIM_RUN)|ANIM_LOOP; speed = 1860/d->maxspeed; } rendermodel(mdlname, anim, tex, 1.5f, o, d->yaw+90, d->pitch/4, speed, basetime, d, vwepname); + if(isteam(player1->team, d->team)) renderaboveheadicon(d); } -VAR(teamdisplaymode, 0, 1, 2); +VARP(teamdisplaymode, 0, 1, 2); void renderclient(playerent *d) { diff --git a/source/src/server.cpp b/source/src/server.cpp index 117b64d9..caa91d85 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -939,6 +939,19 @@ void sendteamtext(char *text, int sender) if(packet->referenceCount==0) enet_packet_destroy(packet); } +void sendvoicecomteam(int sound, int sender) +{ + if(!m_teammode || !clients[sender]->team[0]) return; + ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); + ucharbuf p(packet->data, packet->dataLength); + putint(p, SV_VOICECOMTEAM); + putint(p, sender); + putint(p, sound); + enet_packet_resize(packet, p.length()); + loopv(clients) if(i!=sender && !strcmp(clients[i]->team, clients[sender]->team)) sendpacket(i, 1, packet); + if(packet->referenceCount==0) enet_packet_destroy(packet); +} + const char *disc_reason(int reason) { static const char *disc_reasons[] = { "normal", "end of packet", "client num", "kicked by server operator", "banned by server operator", "tag type", "connection refused due to ban", "wrong password", "failed admin login", "server FULL - maxclients", "server mastermode is \"private\"", "auto kick - did your score drop below the threshold?" }; @@ -1720,6 +1733,15 @@ void process(ENetPacket *packet, int sender, int chan) // sender may be -1 QUEUE_STR(text); break; + case SV_VOICECOM: + getint(p); + QUEUE_MSG; + break; + + case SV_VOICECOMTEAM: + sendvoicecomteam(getint(p), sender); + break; + case SV_INITC2S: { QUEUE_MSG; diff --git a/source/src/sound.cpp b/source/src/sound.cpp index 0ec000d2..9537c437 100644 --- a/source/src/sound.cpp +++ b/source/src/sound.cpp @@ -488,3 +488,30 @@ void playsoundc(int n) addmsg(SV_SOUND, "i", n); playsound(n); } + +void voicecom(char *sound, char *text) +{ + if(!sound || !sound[0]) return; + static int last = 0; + if(!last || lastmillis-last > 2000) + { + s_sprintfd(soundpath)("voicecom/%s", sound); + int s = findsound(soundpath, 0, gamesounds); + if(s < 0 || s < S_AFFIRMATIVE || s > S_NICESHOT) return; + playsound(s); + if(s == S_NICESHOT) // public + { + addmsg(SV_VOICECOM, "ri", s); + toserver(text); + } + else // team + { + addmsg(SV_VOICECOMTEAM, "ri", s); + s_sprintfd(teamtext)("%c%s", '%', text); + toserver(teamtext); + } + last = lastmillis; + } +} + +COMMAND(voicecom, ARG_2STR); \ No newline at end of file diff --git a/source/src/sound.h b/source/src/sound.h index de04a92e..9494e3cb 100644 --- a/source/src/sound.h +++ b/source/src/sound.h @@ -22,6 +22,31 @@ enum S_RAKIMBO, S_GUNCHANGE, S_GIB, S_HEADSHOT, S_CALLVOTE, S_VOTEPASS, S_VOTEFAIL, S_FOOTSTEPS, S_FOOTSTEPSCROUCH, + S_AFFIRMATIVE, + S_ALLRIGHTSIR, + S_COMEONMOVE, + S_COMINGINWITHTHEFLAG, + S_COVERME, + S_DEFENDTHEFLAG, + S_ENEMYDOWN, + S_GOGETEMBOYS, + S_GOODJOBTEAM, + S_IGOTONE, + S_IMADECONTACT, + S_IMATTACKING, + S_IMONDEFENSE, + S_IMONYOURTEAMMAN, + S_NEGATIVE, + S_NOCANDO, + S_RECOVERTHEFLAG, + S_SORRY, + S_SPREADOUT, + S_STAYHERE, + S_STAYTOGETHER, + S_THERESNOWAYSIR, + S_WEDIDIT, + S_YES, + S_NICESHOT, S_NULL }; diff --git a/source/src/weapon.cpp b/source/src/weapon.cpp index 8e294116..cdbb5cf6 100644 --- a/source/src/weapon.cpp +++ b/source/src/weapon.cpp @@ -583,6 +583,11 @@ void weapon::renderstats() draw_text(gunstats, 690, 827); } +VAR(recoiltest, 0, 0, 1); +VAR(recoilincrease, 1, 2, 10); +VAR(recoilbase, 0, 40, 1000); +VAR(maxrecoil, 0, 1000, 1000); + void weapon::attackphysics(vec &from, vec &to) // physical fx to the owner { const guninfo &g = info; @@ -601,8 +606,16 @@ void weapon::attackphysics(vec &from, vec &to) // physical fx to the owner #undef RNDD } // kickback & recoil - owner->vel.add(vec(unitv).mul(recoil/dist).mul(owner->crouching ? 0.75 : 1.0f)); - owner->pitchvel = min(powf(shots/(float)(g.recoilincrease), 2.0f)+(float)(g.recoilbase)/10.0f, (float)(g.maxrecoil)/10.0f); + if(recoiltest) + { + owner->vel.add(vec(unitv).mul(recoil/dist).mul(owner->crouching ? 0.75 : 1.0f)); + owner->pitchvel = min(powf(shots/(float)(recoilincrease), 2.0f)+(float)(recoilbase)/10.0f, (float)(maxrecoil)/10.0f); + } + else + { + owner->vel.add(vec(unitv).mul(recoil/dist).mul(owner->crouching ? 0.75 : 1.0f)); + owner->pitchvel = min(powf(shots/(float)(g.recoilincrease), 2.0f)+(float)(g.recoilbase)/10.0f, (float)(g.maxrecoil)/10.0f); + } } void weapon::renderhudmodel(int lastaction, int index)