diff --git a/config/sounds.cfg b/config/sounds.cfg index c6ac92a6..94c080f9 100755 --- a/config/sounds.cfg +++ b/config/sounds.cfg @@ -31,7 +31,7 @@ registersound "free/tick12" //S_SUICIDE registersound "free/tick13" //S_FALL1 registersound "free/tick14" //S_FALL2 registersound "free/tick15" //S_FLAUNCH -registersound "free/tick16" //S_FEXPLODE +registersound "weapon/grenade_exp" //S_FEXPLODE registersound "player/splash1" //S_SPLASH1 registersound "player/splash2" //S_SPLASH2 registersound "ppm/deathr" //S_GRUNT1 16 @@ -43,3 +43,4 @@ registersound "ctf/flagreturn" //S_FLAGRETURN registersound "ctf/flagscore" //S_FLAGSCORE registersound "weapon/grenade_pull" // S_GRENADEPULL registersound "weapon/grenade_throw" // S_GRENADETHROW +registersound "weapon/pistol_reload" // S_RAKIMBO diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index f257636f..4ae78d63 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -1,1422 +1,624 @@ // clientgame.cpp: core game related stuff - - #include "cube.h" - #define sleep my_sleep - int nextmode = 0; // nextmode becomes gamemode after next map load - VAR(gamemode, 1, 0, 0); - - flaginfo flaginfos[2]; - - void mode(int n) { addmsg(1, 2, SV_GAMEMODE, nextmode = n); }; - COMMAND(mode, ARG_1INT); - - bool intermission = false; - - dynent *player1 = newdynent(); // our client - dvector players; // other clients - - vector physents; - - VAR(sensitivity, 0, 10, 1000); - VAR(sensitivityscale, 1, 1, 100); - VAR(invmouse, 0, 0, 1); - - int lastmillis = 0; - int curtime; - string clientmap; - - extern int framesinmap; - - char *getclientmap() { return clientmap; }; - - void resetmovement(dynent *d) - { - d->k_left = false; - d->k_right = false; - d->k_up = false; - d->k_down = false; - d->jumpnext = false; - d->strafe = 0; - d->move = 0; - }; - - void spawnstate(dynent *d) // reset player state not persistent accross spawns - { - resetmovement(d); - d->vel.x = d->vel.y = d->vel.z = 0; - d->onfloor = false; - d->timeinair = 0; - d->health = 100; - d->armour = 0; - //d->hasarmour = false; - //d->armourtype = A_BLUE; - //d->quadmillis = 0; - d->gunselect = GUN_PISTOL; - d->mag[6]=10; - d->gunwait = 0; - d->attacking = false; - d->lastaction = 0; - - - - - - radd(d); - - - - - - //loopi(NUMGUNS) if(d->nextprimary!=i) d->ammo[i] = 0; - - //d->mag[GUN_KNIFE] = 1; - - //equp with default pistol - - - - //d->mag[GUN_PISTOL] = 8; - - //if(d->nextprimary!=GUN_PISTOL) - - // d->ammo[GUN_PISTOL] = 16; - - //else - - // d->ammo[GUN_PISTOL] = 32; - - //temp for testing guns - - //d->ammo[GUN_SHOTGUN] = 100; - - //d->ammo[GUN_SUBGUN] = 400; - - //d->ammo[GUN_SNIPER] = 100; - - //d->ammo[GUN_ASSULT] = 400; - - - - //end tmp - - - - /* - - if(m_noitems) - + if(d==player1) { - - d->gunselect = GUN_RIFLE; - - d->armour = 0; - - if(m_noitemsrail) - - { - - d->health = 1; - - d->ammo[GUN_RIFLE] = 100; - - } - - else - - { - - if(gamemode==12) { d->gunselect = GUN_FIST; return; }; // eihruls secret "instafist" mode - - d->health = 256; - - if(m_tarena) - - { - - int gun1 = rnd(4)+1; - - baseammo(d->gunselect = gun1); - - for(;;) - - { - - int gun2 = rnd(4)+1; - - if(gun1!=gun2) { baseammo(gun2); break; }; - - }; - - } - - else if(m_arena) // insta arena - - { - - d->ammo[GUN_RIFLE] = 100; - - } - - else // efficiency - - { - - loopi(4) baseammo(i+1); - - d->gunselect = GUN_CG; - - }; - - d->ammo[GUN_CG] /= 2; - - }; - - } - - else - - { - - d->ammo[GUN_SG] = 5; - + gun_changed = true; + player1->primary = player1->nextprimary; + scoped = false; }; - - */ - - + radd(d); + d->akimbo = false; - }; - - dynent *newdynent() // create a new blank player or monster - { - dynent *d = (dynent *)gp()->alloc(sizeof(dynent)); - d->o.x = 0; - d->o.y = 0; - d->o.z = 0; - d->yaw = 270; - d->pitch = 0; - d->roll = 0; - d->maxspeed = 16; //16 max speed, 14 max with armour - d->outsidemap = false; - d->inwater = false; - d->radius = 1.1f; - d->eyeheight = 4.25f; - d->aboveeye = 0.7f; - d->frags = 0; - d->flagscore = 0; // EDIT: AH - d->plag = 0; - d->ping = 0; - d->lastupdate = lastmillis; - d->enemy = NULL; - d->monsterstate = 0; - d->name[0] = d->team[0] = 0; - d->blocked = false; - d->lifesequence = 0; - d->state = CS_ALIVE; - d->shots = 0; - d->reloading = false; - - d->nextprimary = 1; - + d->primary = d->nextprimary = GUN_ASSULT; d->hasarmour = false; - d->gunselect = GUN_PISTOL; - d->onladder = false; - d->isphysent = false; - spawnstate(d); - return d; - }; - - void ctf_death() // EDIT: AH - { - int flag = rb_opposite(rb_team_int(player1->team)); - flaginfo &f = flaginfos[flag]; - if(f.state==CTFF_STOLEN && f.thief==player1) - { - addmsg(1, 2, SV_FLAGDROP, flag); - f.flag->spawned = false; - f.state = CTFF_DROPPED; - }; - }; - - void respawnself() - { - spawnplayer(player1); - showscores(false); - }; - - void respawn() - { - if(player1->state==CS_DEAD) - { - player1->attacking = false; - if(m_arena) { conoutf("waiting for new round to start..."); return; }; - respawnself(); - }; - }; - - void arenacount(dynent *d, int &alive, int &dead, char *&lastteam, char *&lastname, bool &oneteam) - //void arenacount(dynent *d, int &alive, int &dead, char *&lastteam, bool &oneteam) - { - if(d->state!=CS_DEAD) - { - alive++; - if(lastteam && strcmp(lastteam, d->team)) oneteam = false; - lastteam = d->team; - lastname = d->name; - } - else - { - dead++; - }; - }; - - int arenarespawnwait = 0; - int arenadetectwait = 0; - - void arenarespawn() - { - if (!m_arena) return; - - if(arenarespawnwait) - { - if(arenarespawnwait0 && (alive<=1 || (m_teammode && oneteam))) - { - conoutf("arena round is over! next round in 5 seconds..."); - if(alive) - { - if(m_teammode) - conoutf("team %s has won the round", (int)lastteam); - else - conoutf("%s is the survior!", (int)lastname); - } - else conoutf("everyone died!"); - arenarespawnwait = lastmillis+5000; - arenadetectwait = lastmillis+10000; - player1->roll = 0; - }; - }; - }; - - - void checkquad(int time) - { - /* if(player1->quadmillis && (player1->quadmillis -= time)<0) - { - player1->quadmillis = 0; - playsoundc(S_PUPOUT); - conoutf("quad damage is over"); - }; - */ - }; - - -//generic function to check all kinds of crazy gamemode specific things - -void checkgame(int time) - -{ - - - - //allow faster movements when editing - -/* if (editmode) - - { - - player1->maxspeed=22; - - return; - - } - - else //otherwise max speed is 16 and 14 with armour - - { - - if(player1->armour>50) - - player1->maxspeed = 14; - - if(player1->armour>0) - - player1->maxspeed = 15; - - player1->maxspeed = 16; - - }; - -*/ - - - - //reset zoom if dead - - - - //etc - - //checkquad(time); - - - - if (player1->state==CS_DEAD) - - { - - player1->primary = player1->nextprimary; - - } - -}; - - - void zapdynent(dynent *&d) - { - if(d) gp()->dealloc(d, sizeof(dynent)); - d = NULL; - }; - - extern int democlientnum; - - void otherplayers() - { - loopv(players) if(players[i]) - { - const int lagtime = lastmillis-players[i]->lastupdate; - if(lagtime>1000 && players[i]->state==CS_ALIVE) - { - players[i]->state = CS_LAGGED; - continue; - }; - if(lagtime && players[i]->state != CS_DEAD && (!demoplayback || i!=democlientnum)) moveplayer(players[i], 2, false); // use physics to extrapolate player position - }; - }; - - extern void explode_nade(physent *i); - - void mphysents() - { - loopv(physents) if(physents[i]) - { - physent *p = physents[i]; - if(p->state == NADE_THROWED) moveplayer(p, 2, false); - // printf("physent %i: %i %i %i\n", i, lastmillis, p->millis, p->timetolife); - - if(lastmillis - p->millis >= p->timetolife) - { - if(p->state==NADE_ACTIVATED || p->state==NADE_THROWED) explode_nade(physents[i]); - physents.remove(i); - i--; - }; - }; - }; - - int sleepwait = 0; - string sleepcmd; - void sleep(char *msec, char *cmd) { sleepwait = atoi(msec)+lastmillis; strcpy_s(sleepcmd, cmd); }; - COMMAND(sleep, ARG_2STR); - - void updateworld(int millis) // main game update loop - { - if(lastmillis) - { - curtime = millis - lastmillis; - if(sleepwait && lastmillis>sleepwait) { execute(sleepcmd); sleepwait = 0; }; - physicsframe(); - - checkgame(curtime); - //if(m_arena) arenarespawn(); - arenarespawn(); - moveprojectiles((float)curtime); - demoplaybackstep(); - if(!demoplayback) - { - 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 - }; - mphysents(); - otherplayers(); - if(!demoplayback) - { - //put game mode extra call here - if(player1->state==CS_DEAD) - { - if(lastmillis-player1->lastaction<2000) - { - player1->move = player1->strafe = 0; - moveplayer(player1, 10, false); - }; - } - else if(!intermission) - { - moveplayer(player1, 20, true); - checkitems(); - }; - c2sinfo(player1); // do this last, to reduce the effective frame lag - }; - }; - lastmillis = millis; - }; - - void entinmap(dynent *d) // brute force but effective way to find a free spawn spot in the map - { - 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; - }; - conoutf("can't find entity spawn spot! (%d, %d)", (int)d->o.x, (int)d->o.y); - // leave ent at original pos, possibly stuck - }; - - // EDIT: AH - int securespawndist = 15; - - // Returns -1 for a free place, if not it returns the vdist to the nearest enemy - int nearestenemy(vec *v, string team) - { - float nearestPlayerDistSquared = -1; - loopv(players) - { - dynent *other = players[i]; - if(!other) continue; - if(isteam(team,other->team))continue; // its a teammate - vec place = {v->x, v->y, v->z}; - vdistsquared(distsquared, t, place, other->o); - if(nearestPlayerDistSquared == -1) nearestPlayerDistSquared = distsquared; // first run - else if(distsquared < nearestPlayerDistSquared) nearestPlayerDistSquared = distsquared; // if a player is closer - }; - if(nearestPlayerDistSquared >= securespawndist * securespawndist || nearestPlayerDistSquared == -1) return -1; // a distance more than securespawndist means the place is free - else return sqrt(nearestPlayerDistSquared); - }; - - int spawncycle = -1; - int fixspawn = 2; - - -void spawnplayer(dynent *d, bool secure) // place at random spawn. also used by monsters! - +void spawnplayer(dynent *d, bool secure) // place at random spawn { - loopj(10) // EDIT: AH - { - int r = fixspawn-->0 ? 4 : rnd(10)+1; - loopi(r) spawncycle = m_ctf ? findteamplayerstart(rb_team_int(d->team), spawncycle+1) : findentity(PLAYERSTART, spawncycle+1); - if(spawncycle!=-1 && secure) - { - entity &e = ents[spawncycle]; - vec pos = { e.x, e.y, e.z }; - if(nearestenemy(&pos, d->team) == -1) break; - } else break; - }; - if(spawncycle!=-1) - { - d->o.x = ents[spawncycle].x; - d->o.y = ents[spawncycle].y; - d->o.z = ents[spawncycle].z; - d->yaw = ents[spawncycle].attr1; - d->pitch = 0; - d->roll = 0; - } - else - { - d->o.x = d->o.y = (float)ssize/2; - d->o.z = 4; - }; - entinmap(d); - spawnstate(d); - d->state = CS_ALIVE; - }; - - // movement input code - - #define dir(name,v,d,s,os) void name(bool isdown) { player1->s = isdown; player1->v = isdown ? d : (player1->os ? -(d) : 0); player1->lastmove = lastmillis; }; - - dir(backward, move, -1, k_down, k_up); - dir(forward, move, 1, k_up, k_down); - dir(left, strafe, 1, k_left, k_right); - dir(right, strafe, -1, k_right, k_left); - - void attack(bool on) - { - if(intermission) return; - if(editmode) editdrag(on); - else if(player1->attacking = on) respawn(); - }; - - void jumpn(bool on) { if(!intermission && (player1->jumpnext = on) ) respawn(); }; - - COMMAND(backward, ARG_DOWN); - COMMAND(forward, ARG_DOWN); - COMMAND(left, ARG_DOWN); - COMMAND(right, ARG_DOWN); - COMMANDN(jump, jumpn, ARG_DOWN); - COMMAND(attack, ARG_DOWN); - COMMAND(showscores, ARG_DOWN); - - void fixplayer1range() - { - const float MAXPITCH = 90.0f; - if(player1->pitch>MAXPITCH) player1->pitch = MAXPITCH; - if(player1->pitch<-MAXPITCH) player1->pitch = -MAXPITCH; - while(player1->yaw<0.0f) player1->yaw += 360.0f; - while(player1->yaw>=360.0f) player1->yaw -= 360.0f; - }; - - void mousemove(int dx, int dy) - { - if(player1->state==CS_DEAD || intermission) return; - const float SENSF = 33.0f; // try match quake sens - player1->yaw += (dx/SENSF)*(sensitivity/(float)sensitivityscale); - player1->pitch -= (dy/SENSF)*(sensitivity/(float)sensitivityscale)*(invmouse ? -1 : 1); - fixplayer1range(); - }; - - // damage arriving from the network, monsters, yourself, all ends up here. - - void selfdamage(int damage, int actor, dynent *act) - { - if(player1->state!=CS_ALIVE || editmode || intermission) return; - damageblend(damage); - demoblend(damage); - int ad = damage*30/100;//int ad = damage*(player1->armourtype+1)*20/100; // let armour absorb when possible - if(ad>player1->armour) ad = player1->armour; - player1->armour -= ad; - damage -= ad; - float droll = damage/0.5f; - player1->roll += player1->roll>0 ? droll : (player1->roll<0 ? -droll : (rnd(2) ? droll : -droll)); // give player a kick depending on amount of damage - if((player1->health -= damage)<=0) - { - if(actor==-2) - { - conoutf("you got killed by %s!", (int)&act->name); - } - else if(actor==-1) - { - actor = getclientnum(); - conoutf("you suicided!"); - addmsg(1, 2, SV_FRAGS, --player1->frags); - } - else - { - dynent *a = getclient(actor); - if(a) - { - if(isteam(a->team, player1->team)) - { - conoutf("you got fragged by a teammate (%s)", (int)a->name); - } - else - { - conoutf("you got fragged by %s", (int)a->name); - }; - }; - }; - // EDIT: AH - if(m_ctf) ctf_death(); - - showscores(true); - + showscores(true); addmsg(1, 2, SV_DIED, actor); - player1->lifesequence++; - player1->attacking = false; - player1->state = CS_DEAD; - player1->oldpitch = player1->pitch; - player1->pitch = 0; - player1->roll = 60; - playsound(S_DIE1+rnd(2)); - spawnstate(player1); - player1->lastaction = lastmillis; - } - else - { - playsound(S_PAIN6); - }; - }; - - void timeupdate(int timeremain) - { - if(!timeremain) - { - intermission = true; - player1->attacking = false; - conoutf("intermission:"); - conoutf("game has ended!"); - showscores(true); - } - else - { - conoutf("time remaining: %d minutes", timeremain); - }; - }; - - dynent *getclient(int cn) // ensure valid entity - { - if(cn<0 || cn>=MAXCLIENTS) - { - neterr("clientnum"); - return NULL; - }; - while(cn>=players.length()) players.add(NULL); - return players[cn] ? players[cn] : (players[cn] = newdynent()); - }; - - void addc() { strcpy(getclient(1)->team, "CT"); getclient(1)->o = player1->o; strcpy(getclient(1)->name, "sucker"); } COMMAND(addc, ARG_NONE); // FIXME - - void initclient() - { - clientmap[0] = 0; - initclientnet(); - }; - - void preparectf() - { - loopi(2) flaginfos[i].flag = NULL; - loopv(ents) - { - entity &e = ents[i]; - if(e.type==CTF_FLAG) - { - e.spawned = true; - if(e.attr2<0||e.attr2>2) { conoutf("invalid ctf-flag entity (%i)", i); e.attr2 = 0; }; - flaginfo &f = flaginfos[e.attr2]; - f.flag = &e; - f.state = CTFF_INBASE; - f.originalpos.x = (float) e.x; - f.originalpos.y = (float) e.y; - f.originalpos.z = (float) e.z; - }; - }; - loopi(2) // ignore missing flags - { - flaginfo &f = flaginfos[i]; - if(f.flag == NULL) f.flag = new entity(); - } - ctf_team(player1->team); // ensure valid team - }; - - void startmap(char *name) // called just after a map load - { - //if(netmapstart()) { gamemode = 0;}; //needs fixed to switch modes? - netmapstart(); //should work - sleepwait = 0; - //put call to clear/restart game mode extras here - projreset(); - if(m_ctf) preparectf(); - shotlinereset(); - spawncycle = -1; - spawnplayer(player1, true); - player1->frags = 0; - player1->flagscore = 0; - loopv(players) if(players[i]) players[i]->frags = 0; - resetspawns(); - strcpy_s(clientmap, name); - if(editmode) toggleedit(); - setvar("gamespeed", 100); - setvar("fog", 180); - setvar("fogcolour", 0x8099B3); - showscores(false); - intermission = false; - framesinmap = 0; - conoutf("game mode is %s", (int)modestr(gamemode)); - }; - - COMMANDN(map, changemap, ARG_1STR); - - void suicide() - { - if (multiplayer()) conoutf("there are others willing to kill you..."); - else conoutf("this is not the answer"); - selfdamage(1000, -1, player1); - //if(d==player1) selfdamage(dm, -1, d); - //else { addmsg(1, 4, SV_DAMAGE, d, dm, d->lifesequence); playsound(S_FALL1+rnd(5), &d->o); }; - //particle_splash(3, 1000, 1000, player1->o); //edit out? - demodamage(1000, player1->o); - playsound(S_SUICIDE, &player1->o); - - }; - - COMMAND(suicide, ARG_NONE); - - void killdummies() - { - loopv(players) if(strcmp(players[i]->name, "dummy") == 0) { players[i]->lastaction = lastmillis; players[i]->health=1; }; - }; COMMAND(killdummies, ARG_NONE); - - // EDIT: AH - void flagaction(int flag, int action) - { - flaginfo &f = flaginfos[flag]; - if(!f.thief) return; - bool ownflag = flag == rb_team_int(player1->team); - switch(action) - { - case SV_FLAGPICKUP: - { - playsound(S_FLAGPICKUP); - if(f.thief==player1) - { - conoutf("you got the enemy flag"); - f.pick_ack = true; - } - - else conoutf("%s got %s flag", (int) f.thief->name, (int) (ownflag ? "your": "the enemy")); - + else conoutf("%s got %s flag", f.thief->name, ownflag ? "your": "the enemy"); break; - }; - case SV_FLAGDROP: - { - playsound(S_FLAGDROP); - if(f.thief==player1) conoutf("you lost the flag"); - - else conoutf("%s lost %s flag", (int) f.thief->name, (int) (ownflag ? "your" : "the enemy")); - + else conoutf("%s lost %s flag", f.thief->name, ownflag ? "your" : "the enemy"); break; - }; - case SV_FLAGRETURN: - { - playsound(S_FLAGRETURN); - if(f.thief==player1) conoutf("you returned your flag"); - - else conoutf("%s returned %s flag", (int) f.thief->name, (int) (ownflag ? "your" : "the enemy")); - + else conoutf("%s returned %s flag", f.thief->name, ownflag ? "your" : "the enemy"); break; - }; - case SV_FLAGSCORE: - { - playsound(S_FLAGSCORE); - if(f.thief==player1) - { - conoutf("you scored"); - addmsg(1, 2, SV_FLAGS, ++player1->flagscore); - } - - else conoutf("%s scored for %s team", (int) f.thief->name, (int) (ownflag ? "the enemy" : "your")); - + else conoutf("%s scored for %s team", f.thief->name, ownflag ? "the enemy" : "your"); break; - }; - default: break; - }; - }; - diff --git a/source/src/cube.h b/source/src/cube.h index c25c45ed..ed033001 100644 --- a/source/src/cube.h +++ b/source/src/cube.h @@ -243,9 +243,11 @@ enum S_DIE1, S_DIE2, S_SUICIDE, S_FALL1, S_FALL2, //31 S_FLAUNCH, S_FEXPLODE, //33 - S_FLAGDROP, S_FLAGPICKUP, S_FLAGRETURN, S_FLAGSCORE, S_SPLASH1, S_SPLASH2, - S_GRUNT1, S_GRUNT2, S_RUMBLE, //38 + S_GRUNT1, S_GRUNT2, S_RUMBLE, + S_FLAGDROP, S_FLAGPICKUP, S_FLAGRETURN, S_FLAGSCORE, + S_GRENADEPULL, S_GRENADETHROW, + S_RAKIMBO, S_NULL }; diff --git a/source/src/entities.cpp b/source/src/entities.cpp index 862e01c1..15443f1d 100644 --- a/source/src/entities.cpp +++ b/source/src/entities.cpp @@ -55,7 +55,7 @@ void renderentities() { if(!e.spawned) continue; if(e.typeI_AKIMBO) continue; - renderent(e, entmdlnames[e.type-I_CLIPS], (float)(1+sin(lastmillis/100.0+e.x+e.y)/20), lastmillis/10.0f); + renderent(e, entmdlnames[e.type-I_CLIPS], (float)(1+sin(lastmillis/100.0+e.x+e.y)/20), lastmillis/10.0f); } else switch(e.attr2) { @@ -113,6 +113,8 @@ void radditem(int i, int &v, int t) if(v>is.max) v = is.max; playsoundc(is.sound); }; + +extern void secondary(); void realpickup(int n, dynent *d) { @@ -141,8 +143,9 @@ void realpickup(int n, dynent *d) case I_AKIMBO: d->akimbo = true; - d->mag[GUN_PISTOL] = 16; - radditem(n, d->ammo[1], 9); + d->mag[GUN_PISTOL] = 16; + radditem(n, d->ammo[1], 9); + secondary(); conoutf("a lesser man would use a single pistol"); break; }; @@ -319,7 +322,6 @@ void item(int num) //if (num==6) conoutf("sorry, no nades yet"); if (num==7) { player1->hasarmour=!player1->hasarmour; /*toggle armour*/ }; - }; void weapon(int num) @@ -333,13 +335,14 @@ void weapon(int num) radd(player1); } gun_changed = true; -} +}; -COMMAND(weapon, ARG_1INT); COMMAND(item,ARG_1INT); -void akimbo(void) +void akimbo() { conoutf("akimbo=%d",player1->akimbo); -}; -COMMAND(akimbo, ARG_NONE); +}; + +COMMAND(akimbo, ARG_NONE); +COMMAND(weapon, ARG_1INT); diff --git a/source/src/menus.cpp b/source/src/menus.cpp index ba95bfd9..1b651be0 100644 --- a/source/src/menus.cpp +++ b/source/src/menus.cpp @@ -91,7 +91,7 @@ bool rendermenu() void rendermenumdl() { - if(vmenu<0) { menustack.setsize(0); return false; }; + if(vmenu<0) { menustack.setsize(0); return; }; if(vmenu==1) refreshservers(); gmenu &m = menus[vmenu]; if(!m.mdl) return; diff --git a/source/src/physics.cpp b/source/src/physics.cpp index f0f79471..0e4f9e62 100644 --- a/source/src/physics.cpp +++ b/source/src/physics.cpp @@ -228,11 +228,10 @@ void moveplayer(dynent *pl, int moveres, bool local, int curtime) if(pl->isphysent) { - pl->pitch += speed*5.0f; + pl->pitch += ((float) sqrt(dotprod(pl->vel, pl->vel)))*speed*5.0f; if(pl->pitch>360.0f) pl->pitch = 0.0f; - pl->yaw += speed*5.0f; + pl->yaw += ((float) sqrt(dotprod(pl->vel, pl->vel)))*speed*5.0f; if(pl->yaw>360.0f) pl->yaw = 0.0f; - } pl->blocked = false; @@ -375,109 +374,4 @@ void moveplayer(dynent *pl, int moveres, bool local, int curtime) void moveplayer(dynent *pl, int moveres, bool local) { loopi(physicsrepeat) moveplayer(pl, moveres, local, i ? curtime/physicsrepeat : curtime-curtime/physicsrepeat*(physicsrepeat-1)); -}; - -void movephysent(physent *pl) -{ - int moveres = 2; - bool local=true; - loopj(physicsrepeat) - { - const bool water = hdr.waterlevel>pl->o.z-0.5f; - const bool floating = (editmode && local); - - vec d; // vector of direction we ideally want to move in - - d = pl->vel; - - - const float speed = curtime/(water ? 2000.0f : 1000.0f)*pl->maxspeed; - const float friction = water ? 20.0f : (pl->onfloor || floating ? 6.0f : 30.0f); - - const float fpsfric = friction/curtime*20.0f; - - vmul(pl->vel, fpsfric-1); // slowly apply friction and direction to velocity, gives a smooth movement - vadd(pl->vel, d); - vdiv(pl->vel, fpsfric); - d = pl->vel; - vmul(d, speed); // d is now frametime based velocity vector - - pl->pitch = (pl->pitch+(speed)); - if(pl->pitch>360.0f) pl->pitch = 0.0f; - - printf("pitch %f\n", pl->pitch); - - if(pl->onfloor) - { - pl->timeinair = 0; - vmul(pl->vel, 0.8f); - } - else - { - pl->timeinair += curtime; - pl->pitch = (lastmillis-pl->millis) % 360; - pl->yaw = pl->pitch; - }; - - - //const float speed = curtime/(water ? 2000.0f : 1000.0f)*pl->maxspeed; - - const float gravity = 20; - const float f = 1.0f/moveres; - float dropf = pl->timeinair/15.0f; // incorrect, but works fine - if(water) { dropf = 5; pl->timeinair = 0; }; // float slowly down in water - const float drop = dropf*curtime/gravity/100/moveres; // at high fps, gravity kicks in too fast - const float rise = speed/moveres/1.2f; // extra smoothness when lifting up stairs -// if(pl->mtype = M_NADE)printf("%i\n", pl->onfloor); -/* d.x -= d.x/50.0f*curtime; - d.y -= d.y/50.0f*curtime;*/ - - - loopi(moveres) // discrete steps collision detection & sliding - { - // try move forward - pl->o.x += f*d.x; - pl->o.y += f*d.y; - pl->o.z += f*d.z; - if(collide(pl, false, drop, rise)) continue; - // player stuck, try slide along y axis - pl->blocked = true; - pl->o.x -= f*d.x; - if(collide(pl, false, drop, rise)) { pl->vel.x = -d.x; vmul(pl->vel, 0.8f); d.x = 0; continue; }; - pl->o.x += f*d.x; - // still stuck, try x axis - pl->o.y -= f*d.y; - if(collide(pl, false, drop, rise)) { pl->vel.y = -d.y; vmul(pl->vel, 0.8f); d.y = 0; continue; }; - pl->o.y += f*d.y; - // try just dropping down - pl->moving = false; - pl->o.x -= f*d.x; - pl->o.y -= f*d.y; - if(collide(pl, false, drop, rise)) { d.y = d.x = 0; vmul(pl->vel, 0.8f); continue; }; - pl->o.z -= f*d.z; - break; - }; - - // detect wether player is outside map, used for skipping zbuffer clear mostly - - - - if(pl->o.x < 0 || pl->o.x >= ssize || pl->o.y <0 || pl->o.y > ssize) - { - pl->outsidemap = true; - } - else - { - sqr *s = S((int)pl->o.x, (int)pl->o.y); - pl->outsidemap = SOLID(s) - || pl->o.z < s->floor - (s->type==FHF ? s->vdelta/4 : 0) - || pl->o.z > s->ceil + (s->type==CHF ? s->vdelta/4 : 0); - }; - - // play sounds on water transitions - - if(!pl->inwater && water) { playsound(S_SPLASH2, &pl->o); pl->vel.z = 0; } - else if(pl->inwater && !water) playsound(S_SPLASH1, &pl->o); - pl->inwater = water; - }; -}; +}; diff --git a/source/src/protos.h b/source/src/protos.h index 86671f3c..9edaf52f 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -97,7 +97,6 @@ extern void ctf_death(); //game mode extras extern void arenarespawn(); extern void respawn(); -extern void checkgame(int time); // clientextras extern void renderclients(); @@ -170,7 +169,8 @@ extern void damageblend(int n); extern void addshotline(dynent *d, vec &from, vec &to); extern void rendershotlines(); extern void shotlinereset(); -extern void renderphysents(); +extern void renderphysents(); +extern int scoped; // renderparticles extern void setorient(vec &r, vec &u); @@ -245,7 +245,9 @@ extern int attackdelay(int gun); extern int magsize(int gun); extern int kick_rot(int gun); extern int kick_back(int gun); -extern bool gun_changed; +extern bool gun_changed; +extern bool akimboside; +extern int akimbolastaction[2]; // entities extern void renderents(); diff --git a/source/src/rendergl.cpp b/source/src/rendergl.cpp index 0718607a..5b158eaa 100644 --- a/source/src/rendergl.cpp +++ b/source/src/rendergl.cpp @@ -277,17 +277,18 @@ VAR(fogcolour, 0, 0x8099B3, 0xFFFFFF); VAR(hudgun,0,1,1); -char *hudgunnames[] = { "knife", "pistol", "shotgun", "subgun", "sniper", "assault", "grenade" }; +char *hudgunnames[] = { "knife", "pistol", "shotgun", "subgun", "sniper", "assault", "grenade", "pistol/akimbo"}; void drawhudmodel(int start, int end, float speed, int base) { sprintf_sd(mdl)("hudguns/%s", hudgunnames[player1->gunselect]); rendermodel(mdl, start, end, 0, 1.0f, player1->o.x, player1->o.z, player1->o.y, player1->yaw+90, player1->pitch, false, 1.0f, speed, 0, base); -}; +}; + void drawhudgun(int w, int h, float aspect, int farplane) { - if(!hudgun || player1->state==CS_DEAD) return; + if(!hudgun || (scoped && player1->gunselect==GUN_SNIPER) || player1->state==CS_DEAD) return; glEnable(GL_CULL_FACE); diff --git a/source/src/rendermd3.cpp b/source/src/rendermd3.cpp index 02d517d2..86091300 100644 --- a/source/src/rendermd3.cpp +++ b/source/src/rendermd3.cpp @@ -80,7 +80,8 @@ struct md3model int numframes, numtags; bool loaded; vec scale; - void setanim(int anim); + void setanim(int anim); + void setanimstate(md3state &as); bool link(md3model *link, char *tag); bool load(char *path); void render(); @@ -93,7 +94,9 @@ md3model::md3model() { loaded = false; scale.x = scale.y = scale.z = MD3_DEFAULT_SCALE; - animstate = NULL; +// animstate = NULL; + animstate = new md3state(); + animstate->lastTime = lastmillis; }; md3model::~md3model() @@ -106,6 +109,13 @@ md3model::~md3model() if(links) free(links); if(tags) delete [] tags; }; + +void md3model::setanimstate(md3state &as) +{ + animstate->anim = as.anim; + animstate->frm = as.frm; + animstate->lastTime = as.lastTime; +}; void md3model::setanim(int anim) { @@ -375,9 +385,9 @@ void md3animation(char *first, char *nums, char *loopings, char *fps) /* configu COMMAND(md3animation, ARG_5STR); void loadweapons() -{ +{ firstweapon = models.length(); - loopi(NUMGUNS) + loopi(NUMGUNS+1) { sprintf(basedir, "packages/models/weapons/%s", hudgunnames[i]); md3model *mdl = new md3model(); @@ -393,21 +403,6 @@ void loadweapons() } }; -void rotatevec(vec &point, vec &rot) -{ - point.x=point.z*sin(rot.x)+point.x*cos(rot.x); - point.y=point.y; - point.z=point.z*cos(rot.x)-point.x*sin(rot.x); - - point.x=point.x; - point.y=point.y*cos(rot.y)-point.z*sin(rot.y); - point.z=point.y*sin(rot.y)+point.z*cos(rot.y); - - point.x=point.y*sin(rot.z)+point.x*cos(rot.z); - point.y=point.y*cos(rot.z)-point.x*sin(rot.z); - point.z=point.z; -}; - VAR(swayspeeddiv, 1, 125, 1000); VAR(swaymovediv, 1, 200, 1000); @@ -416,7 +411,83 @@ VAR(swayupmovediv, 1, 200, 1000); VAR(x, 0, 0, 1000); VAR(y, 0, 0, 1000); -VAR(z, 0, 0, 1000); +VAR(z, 0, 0, 1000); + +struct weaponmove +{ + float k_rot, kick; + vec pos; + int anim; + + weaponmove(vec base, int basetime) + { + bool akimbo = player1->akimbo && player1->gunselect==GUN_PISTOL; + bool throwingnade = player1->gunselect==GUN_GRENADE && player1->thrownademillis; + int timediff = throwingnade ? (lastmillis-player1->thrownademillis) : lastmillis-basetime; + kick = k_rot = 0.0f; + pos = player1->o; + anim = MDL_GUN_IDLE; + + if(akimbo && basetime>lastmillis) // akimbo gun queued for reloading + { + + } + else if(player1->reloading) + { + anim = MDL_GUN_RELOAD; + int rtime = reloadtime(player1->gunselect) / (akimbo ? 2 : 1); + float percent_done = (float)(timediff)*100.0f/rtime; + if(percent_done >= 100) percent_done = 100; + k_rot = -(sin((float)(percent_done*2/100.0f*90.0f)*PI/180.0f)*90); + } + else + { + vec sway = base; + + if(player1->gunselect==player1->lastattackgun) + { + int percent_done = timediff*100/attackdelay(player1->gunselect); + if(percent_done > 100) percent_done = 100.0; + // f(x) = -sin(x-1.5)^3A + kick = -sin(pow((1.5f/100*percent_done)-1.5f,3)); + }; + + if(kick>0.01f) + { + if(throwingnade) { anim = MDL_GUN_ATTACK2; return; } + else anim = MDL_GUN_ATTACK; + }; + + k_rot = kick_rot(player1->gunselect)*kick; + float k_back = kick_back(player1->gunselect)*kick/10; + + int swayt = (lastmillis+1)/10 % 100; + float swayspeed = (float) (sin((float)lastmillis/swayspeeddiv))/(swaymovediv/10.0f); + float swayupspeed = (float) (sin((float)lastmillis/swayupspeeddiv-90))/(swayupmovediv/10.0f); + + #define g0(x) ((x) < 0.0f ? -(x) : (x)) + float plspeed = min(1.0f, sqrt(g0(player1->vel.x*player1->vel.x) + g0(player1->vel.y*player1->vel.y))); + + swayspeed *= plspeed/2; + swayupspeed *= plspeed/2; + + float tmp = sway.x; + sway.x = sway.y; + sway.y = -tmp; + + if(swayupspeed<0.0f)swayupspeed = -swayupspeed; // sway a semicirle only + sway.z = 1.0f; + + sway.x *= swayspeed; + sway.y *= swayspeed; + sway.z *= swayupspeed; + + pos.x = player1->o.x-base.x*k_back+sway.x; + pos.y = player1->o.y-base.y*k_back+sway.y; + pos.z = player1->o.z-base.z*k_back+sway.z; + }; + }; +}; void rendermd3gun() { @@ -435,75 +506,28 @@ void rendermd3gun() light.y = s->g/ll+of; light.z = s->b/ll+of; }; - - md3model *weapon = models[firstweapon + player1->gunselect]; - if(!weapon->animstate) - { - weapon->animstate = new md3state(); - weapon->animstate->lastTime = lastmillis; - }; - - int rtime = reloadtime(player1->gunselect); - - if(player1->reloading) - { - weapon->setanim(MDL_GUN_RELOAD); - float percent_done = (float)(lastmillis-player1->lastaction)*100.0f/reloadtime(player1->gunselect); - if(percent_done >= 100) percent_done = 100; - weapon->draw(player1->o.x, player1->o.z, player1->o.y, player1->yaw + 90, player1->pitch-(sin((float)(percent_done*2/100.0f*90.0f)*PI/180.0f)*90), 1.0f, light); - } - else - { - float kick = 0.0f; - bool throwingnade = player1->gunselect==GUN_GRENADE && player1->thrownademillis; - - if(player1->gunselect==player1->lastattackgun) - { - int timedifference = throwingnade ? (lastmillis-player1->thrownademillis) : (lastmillis-player1->lastaction); - int percent_done = timedifference*100/attackdelay(player1->gunselect); - if(percent_done > 100) percent_done = 100.0; - // f(x) = -sin(x-1.5)^3 - kick = -sin(pow((1.5f/100*percent_done)-1.5f,3)); - }; - - if(kick > 0.01f) throwingnade ? weapon->setanim(MDL_GUN_ATTACK2) : weapon->setanim(MDL_GUN_ATTACK); - else weapon->setanim(MDL_GUN_IDLE); - - vdist(dist, unitv, player1->o, worldpos); - vdiv(unitv, dist); - float k_rot = kick_rot(player1->gunselect)*kick; - float k_back = kick_back(player1->gunselect)*kick/10; - - vec sway(unitv); - - int swayt = (lastmillis+1)/10 % 100; - float swayspeed = (float) (sin((float)lastmillis/swayspeeddiv))/(swaymovediv/10.0f); - float swayupspeed = (float) (sin((float)lastmillis/swayupspeeddiv-90))/(swayupmovediv/10.0f); - - - #define g0(x) ((x) < 0.0f ? -(x) : (x)) - float plspeed = min(1.0f, sqrt(g0(player1->vel.x*player1->vel.x) + g0(player1->vel.y*player1->vel.y))); - - swayspeed *= plspeed/2; - swayupspeed *= plspeed/2; - - // rotate 90° around z axis - float tmp = sway.x; - sway.x = sway.y; - sway.y = -tmp; - - if(swayupspeed<0.0f)swayupspeed = -swayupspeed; // sway a semicirle only - sway.z = 1.0f; - - sway.x *= swayspeed; - sway.y *= swayspeed; - sway.z *= swayupspeed; - - weapon->draw( player1->o.x-unitv.x*k_back+sway.x, - player1->o.z-unitv.z*k_back+sway.z, - player1->o.y-unitv.y*k_back+sway.y, - player1->yaw + 90, player1->pitch+k_rot, 1.0f, light); - }; + + vdist(dist, unitv, player1->o, worldpos); + vdiv(unitv, dist); + + md3model *weapon = models[firstweapon + player1->gunselect]; + md3model *akimbo = player1->akimbo && player1->gunselect==GUN_PISTOL ? models[firstweapon+NUMGUNS] : NULL; + + weaponmove *w1, *w2; + + if(akimbo) + { + w1 = new weaponmove(unitv, akimbolastaction[0]); + w2 = new weaponmove(unitv, akimbolastaction[1]); + akimbo->setanim(w2->anim); + } + else w1 = new weaponmove(unitv, player1->lastaction); + + if(!w1) return; + weapon->setanim(w1->anim); + weapon->draw( w1->pos.x, w1->pos.z, w1->pos.y, player1->yaw + 90, player1->pitch+w1->k_rot, 1.0f, light); + + if(akimbo && w2) akimbo->draw( w2->pos.x, w2->pos.z, w2->pos.y, player1->yaw + 90, player1->pitch+w2->k_rot, 1.0f, light); }; }; diff --git a/source/src/sound.cpp b/source/src/sound.cpp index f3a82ca0..a054aace 100644 --- a/source/src/sound.cpp +++ b/source/src/sound.cpp @@ -1,454 +1,227 @@ // sound.cpp: uses fmod on windows and sdl_mixer on unix (both had problems on the other platform) - - #include "cube.h" - - //#ifndef WIN32 // NOTE: fmod not being supported for the moment as it does not allow stereo pan/vol updating during playback - #define USE_MIXER - //#endif - - VARP(soundvol, 0, 255, 255); - VARP(musicvol, 0, 128, 255); - bool nosound = false; - - #define MAXCHAN 32 - #define SOUNDFREQ 22050 - - struct soundloc { vec loc; bool inuse; } soundlocs[MAXCHAN]; - - #ifdef USE_MIXER - #include "SDL_mixer.h" - #define MAXVOL MIX_MAX_VOLUME - Mix_Music *mod = NULL; - void *stream = NULL; - #else - #include "fmod.h" - #define MAXVOL 255 - FMUSIC_MODULE *mod = NULL; - FSOUND_STREAM *stream = NULL; - #endif - - void stopsound() - { - if(nosound) return; - if(mod) - { - #ifdef USE_MIXER - Mix_HaltMusic(); - Mix_FreeMusic(mod); - #else - FMUSIC_FreeSong(mod); - #endif - mod = NULL; - }; - if(stream) - { - #ifndef USE_MIXER - FSOUND_Stream_Close(stream); - #endif - stream = NULL; - }; - }; - - VAR(soundbufferlen, 128, 1024, 4096); - - void initsound() - { - memset(soundlocs, 0, sizeof(soundloc)*MAXCHAN); - #ifdef USE_MIXER - if(Mix_OpenAudio(SOUNDFREQ, MIX_DEFAULT_FORMAT, 2, soundbufferlen)<0) - { - conoutf("sound init failed (SDL_mixer): %s", (size_t)Mix_GetError()); - nosound = true; - }; - Mix_AllocateChannels(MAXCHAN); - #else - if(FSOUND_GetVersion()=0) { FSOUND_SetVolume(chan, (musicvol*MAXVOL)/255); FSOUND_SetPaused(chan, false); }; - } - else - { - conoutf("could not play music: %s", sn); - }; - #endif - }; - }; - - COMMAND(music, ARG_1STR); - - #ifdef USE_MIXER - vector samples; - #else - vector samples; - #endif - - cvector snames; - - int registersound(char *name) - { - loopv(snames) if(strcmp(snames[i], name)==0) return i; - snames.add(newstring(name)); - samples.add(NULL); - return samples.length()-1; - }; - - COMMAND(registersound, ARG_1EST); - - void cleansound() - { - if(nosound) return; - stopsound(); - #ifdef USE_MIXER - Mix_CloseAudio(); - #else - FSOUND_Close(); - #endif - }; - - VAR(stereo, 0, 1, 1); - - void updatechanvol(int chan, vec *loc) - { - int vol = soundvol, pan = 255/2; - if(loc) - { - vdist(dist, v, *loc, player1->o); - vol -= (int)(dist*3*soundvol/255); // simple mono distance attenuation - if(vol<0) vol = 0; - if(stereo && (v.x != 0 || v.y != 0)) - { - float yaw = -atan2(v.x, v.y) - player1->yaw*(PI / 180.0f); // relative angle of sound along X-Y axis - pan = int(255.9f*(0.5*sin(yaw)+0.5f)); // range is from 0 (left) to 255 (right) - }; - }; - vol = (vol*MAXVOL)/255; - #ifdef USE_MIXER - Mix_Volume(chan, vol); - Mix_SetPanning(chan, 255-pan, pan); - #else - FSOUND_SetVolume(chan, vol); - FSOUND_SetPan(chan, pan); - #endif - }; - - void newsoundloc(int chan, vec *loc) - { - assert(chan>=0 && chan5) return; // avoid bursts of sounds with heavy packetloss and in sp - if(n<0 || n>=samples.length()) { conoutf("unregistered sound: %d", n); return; }; - - if(!samples[n]) - { - sprintf_sd(buf)("packages/audio/sounds/%s.wav", snames[n]); - - #ifdef USE_MIXER - samples[n] = Mix_LoadWAV(path(buf)); - #else - samples[n] = FSOUND_Sample_Load(n, path(buf), FSOUND_LOOP_OFF, 0, 0); - #endif - - - if(!samples[n]) { conoutf("failed to load sample: %s", (int) buf); return; }; - + if(!samples[n]) { conoutf("failed to load sample: %s", buf); return; }; }; - - #ifdef USE_MIXER - int chan = Mix_PlayChannel(-1, samples[n], 0); - #else - int chan = FSOUND_PlaySoundEx(FSOUND_FREE, samples[n], NULL, true); - #endif - if(chan<0) return; - if(loc) newsoundloc(chan, loc); - updatechanvol(chan, loc); - #ifndef USE_MIXER - FSOUND_SetPaused(chan, false); - #endif - }; - - void sound(int n) { playsound(n, NULL); }; - COMMAND(sound, ARG_1INT); - diff --git a/source/src/weapon.cpp b/source/src/weapon.cpp index a16d336e..dcc7879b 100644 --- a/source/src/weapon.cpp +++ b/source/src/weapon.cpp @@ -4,7 +4,7 @@ struct guninfo { short sound, reload, reloadtime, attackdelay, damage, projspeed, part, spread, recoil, magsize, mdl_kick_rot, mdl_kick_back; char *name; }; -const int SGRAYS = 20; //down from 20 (defualt) +const int SGRAYS = 20; //down from 20 (default) const float SGSPREAD = 2; vec sg[SGRAYS]; @@ -12,52 +12,17 @@ vec sg[SGRAYS]; guninfo guns[NUMGUNS] = { { S_KNIFE, S_NULL, 0, 500, 50, 0, 0, 1, 1, 1, 0, 0, "knife" }, - { S_PISTOL, S_RPISTOL, 1400, 170, 20, 0, 0, 80, 10, 8, 6, 5, "pistol" }, // *SGRAYS - { S_SHOTGUN, S_RSHOTGUN, 2400, 1000, 6, 0, 0, 1, 35, 7, 9, 9, "shotgun" }, //reload time is for 1 shell from 7 too powerful to 6 - { S_SUBGUN, S_RSUBGUN, 1650, 80, 17, 0, 0, 70, 15, 30, 1, 2, "subgun" }, - { S_SNIPER, S_RSNIPER, 1950, 1500, 72, 0, 0, 60, 50, 5, 4, 4, "sniper" }, - { S_ASSULT, S_RASSULT, 2000, 130, 20, 0, 0, 20, 40, 20, 0, 2, "assult" }, //recoil was 44 - { S_GRENADE, S_NULL, 1000, 2000, 150, 20, 6, 1, 1, 1, 3, 1, "grenade" }, }; bool gun_changed = false; -//weapon selection -void wup() -{ - if(player1->gunselect==GUN_KNIFE) - player1->gunselect = GUN_PISTOL; - else if(player1->gunselect==GUN_PISTOL && player1->primary!=GUN_PISTOL) - player1->gunselect = player1->primary; - else if(player1->gunselect==player1->primary) - player1->gunselect=GUN_KNIFE; - - conoutf("%s selected", (int)guns[player1->gunselect].name); - - gun_changed = true; -}; - -void wdw() -{ - if(player1->gunselect==GUN_KNIFE) - player1->gunselect = player1->primary; - else if(player1->gunselect==player1->primary && player1->primary!=GUN_PISTOL) - player1->gunselect = GUN_PISTOL; - else if(player1->gunselect==GUN_PISTOL) - player1->gunselect=GUN_KNIFE; - - conoutf("%s selected", (int)guns[player1->gunselect].name); - - gun_changed = true; -}; - void primary() { player1->gunselect=player1->primary; @@ -77,23 +42,28 @@ void melee() }; COMMAND(primary,ARG_NONE); - COMMAND(secondary,ARG_NONE); +COMMAND(melee,ARG_NONE); -COMMAND(melee,ARG_NONE); -COMMAND(wup,ARG_NONE); -COMMAND(wdw,ARG_NONE); void reload() -{ +{ + bool akimbo = player1->gunselect==GUN_PISTOL && player1->akimbo!=0; + if(player1->gunselect==GUN_KNIFE || player1->gunselect==GUN_GRENADE) return; - if(player1->gunselect==GUN_PISTOL && player1->akimbo!=0 && player1->mag[player1->gunselect]>=(guns[player1->gunselect].magsize * 2)) return; + if(akimbo && player1->mag[player1->gunselect]>=(guns[player1->gunselect].magsize * 2)) return; else if(player1->mag[player1->gunselect]>=guns[player1->gunselect].magsize && player1->akimbo==0) return; if(player1->ammo[player1->gunselect]<=0) return; if(player1->reloading) return; player1->reloading = true; - player1->lastaction = lastmillis; + player1->lastaction = lastmillis; + + if(akimbo) + { + akimbolastaction[akimboside?1:0] = lastmillis; + akimbolastaction[akimboside?0:1] = lastmillis + (reloadtime(GUN_PISTOL)/2); + }; player1->gunwait = guns[player1->gunselect].reloadtime; @@ -114,7 +84,8 @@ void reload() player1->ammo[player1->gunselect] -= a; } - playsoundc(guns[player1->gunselect].reload); + if(akimbo) playsoundc(S_RAKIMBO); + else playsoundc(guns[player1->gunselect].reload); }; COMMAND(reload,ARG_NONE); @@ -309,6 +280,7 @@ void throw_nade(dynent *d, vec &to, physent *p) { if(!p || !d) return; printf("thrownade\n"); + playsound(S_GRENADETHROW, &d->o); p->isphysent = true; p->gravity = 20; @@ -399,7 +371,8 @@ physent *new_nade(dynent *d, int millis = 0) { curnade = p; d->thrownademillis = 0; - }; + }; + playsound(S_GRENADEPULL, &d->o); return p; }; @@ -414,7 +387,8 @@ void explode_nade(physent *i) vec dist = { 0.1f, 0.1f, 0.1f }; vadd(o, dist); throw_nade(i->owner, o, i); - }; + }; + playsound(S_FEXPLODE, &i->o); newprojectile(i->o, i->o, 1, true, i->owner, GUN_GRENADE); }; @@ -481,7 +455,10 @@ void raydamage(dynent *o, vec &from, vec &to, dynent *d, int i) if(damage) hitpush(i, damage, o, d, from, to); } else if(intersect(o, from, to)) hitpush(i, qdam, o, d, from, to); -}; +}; + +extern int scoped; + void spreadandrecoil(vec & from, vec & to, dynent * d) { //nothing special for a knife @@ -495,20 +472,20 @@ void spreadandrecoil(vec & from, vec & to, dynent * d) //recoil int rcl = guns[d->gunselect].recoil*-0.01f; - if (d->gunselect==GUN_ASSULT) + if(d->gunselect==GUN_ASSULT) { if(d->shots > 3) spd = 70; rcl += (rnd(8)*-0.01f); }; - if ((d->gunselect==GUN_SNIPER) && (d->vel.x<.25f && d->vel.y<.25f)) + if((d->gunselect==GUN_SNIPER) && (d->vel.x<.25f && d->vel.y<.25f) && scoped) { spd = 1; rcl = rcl / 3; }; - if (d->gunselect!=GUN_SHOTGUN) //no spread on shotgun + if(d->gunselect!=GUN_SHOTGUN) //no spread on shotgun { #define RNDD (rnd(spd)-spd/2)*f vec r = { RNDD, RNDD, RNDD }; @@ -523,6 +500,12 @@ void spreadandrecoil(vec & from, vec & to, dynent * d) if(d->pitch<80.0f) d->pitch += guns[d->gunselect].recoil*0.05f; }; + +VAR(grenadepulltime, 0, 100, 10000); + +bool akimboside = false; +int akimbolastaction[2] = {0,0}; + void shoot(dynent *d, vec &targ) { @@ -530,7 +513,7 @@ void shoot(dynent *d, vec &targ) if(!d->attacking && d->gunselect==GUN_GRENADE && curnade) // throw { - throw_nade(d, targ, curnade); + if(attacktime>grenadepulltime) throw_nade(d, targ, curnade); return; } @@ -547,9 +530,14 @@ void shoot(dynent *d, vec &targ) if(d->gunselect!=GUN_SUBGUN && d->gunselect!=GUN_ASSULT && d->gunselect!=GUN_GRENADE) d->attacking = false; //makes sub/assult autos else d->shots++; - if (d->gunselect==GUN_PISTOL && d->akimbo!=0) d->attacking = true; //make akimbo auto + if(d->gunselect==GUN_PISTOL && d->akimbo!=0) + { + d->attacking = true; //make akimbo auto + akimbolastaction[akimboside?1:0] = lastmillis; + akimboside = !akimboside; + } + d->lastaction = lastmillis; - d->lastaction = lastmillis; d->lastattackgun = d->gunselect; if(!d->mag[d->gunselect]) { playsoundc(S_NOAMMO); d->gunwait = 250; d->lastattackgun = -1; return; };