diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index 6151cbc8..7cae56ac 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -1,566 +1,566 @@ -// 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); - -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 - -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->quadmillis = 0; - d->gunselect = GUN_PISTOL; - d->gunwait = 0; - d->attacking = false; - if(d->primary==GUN_SNIPER && d->altattack) - setvar("fov",getvar("fov")+55); - d->altattack = false; - d->lastaction = 0; - d->gunselect = d->primary; - - 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) - { - 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; - }; - */ -}; - -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 = 3.2f; - d->aboveeye = 0.7f; - d->frags = 0; - 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->altattack = false; - d->nextprimary = 1; - d->nextarmour = false; - spawnstate(d); - return d; -}; -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; - } - - if(player1->hasarmour) - player1->maxspeed = 14; - else player1->maxspeed = 16; - - - - //force to a team if team mode - if (m_teammode) - { - if (strcmp(player1->team,"T") && strcmp(player1->team,"CT")) - { - player1->state = CS_DEAD; - //conoutf("set team to T or CT to joing game"); - if (rnd(2)<1) strcpy_s(player1->team,"T"); - else strcpy_s(player1->team,"CT"); - } - - //add checks here to force-drop flag if switching team with flag - - //add checks for end conditions of ctf - }; - - - //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 - }; -}; - -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 - }; - 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 -}; - -int spawncycle = -1; -int fixspawn = 2; - -void spawnplayer(dynent *d) // place at random spawn. also used by monsters! -{ - int r = fixspawn-->0 ? 4 : rnd(10)+1; - loopi(r) spawncycle = findentity(PLAYERSTART, spawncycle+1); - 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*25/100; // let armour absorb when possible armour absorbs 25% - 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); - }; - }; - }; - showscores(true); - addmsg(1, 2, SV_DIED, actor); - player1->lifesequence++; - player1->attacking = false; - player1->state = CS_DEAD; - player1->pitch = 0; - player1->roll = 60; - if(actor==-1) //suicide - playsound(S_SUICIDE); - else - playsound(S_DIE1+rnd(2)); //add suicide sound - 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 initclient() -{ - clientmap[0] = 0; - initclientnet(); -}; - -void startmap(char *name) // called just after a map load -{ - //if(netmapstart()) { gamemode = 0;}; //needs fixed to switch modes? - sleepwait = 0; - //put call to clear/restart game mode extras here - projreset(); - spawncycle = -1; - spawnplayer(player1); - player1->frags = 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); +// 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); + +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 + +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->quadmillis = 0; + d->gunselect = GUN_PISTOL; + d->gunwait = 0; + d->attacking = false; + if(d->primary==GUN_SNIPER && d->altattack) + setvar("fov",getvar("fov")+55); + d->altattack = false; + d->lastaction = 0; + d->gunselect = d->primary; + + 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) + { + 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; + }; + */ +}; + +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 = 3.2f; + d->aboveeye = 0.7f; + d->frags = 0; + 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->altattack = false; + d->nextprimary = 1; + d->nextarmour = false; + spawnstate(d); + return d; +}; +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; + } + + if(player1->hasarmour) + player1->maxspeed = 14; + else player1->maxspeed = 16; + + + + //force to a team if team mode + if (m_teammode) + { + if (strcmp(player1->team,"T") && strcmp(player1->team,"CT")) + { + player1->state = CS_DEAD; + //conoutf("set team to T or CT to joing game"); + if (rnd(2)<1) strcpy_s(player1->team,"T"); + else strcpy_s(player1->team,"CT"); + } + + //add checks here to force-drop flag if switching team with flag + + //add checks for end conditions of ctf + }; + + + //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 + }; +}; + +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 + }; + 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 +}; + +int spawncycle = -1; +int fixspawn = 2; + +void spawnplayer(dynent *d) // place at random spawn. also used by monsters! +{ + int r = fixspawn-->0 ? 4 : rnd(10)+1; + loopi(r) spawncycle = findentity(PLAYERSTART, spawncycle+1); + 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*25/100; // let armour absorb when possible armour absorbs 25% + 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); + }; + }; + }; + showscores(true); + addmsg(1, 2, SV_DIED, actor); + player1->lifesequence++; + player1->attacking = false; + player1->state = CS_DEAD; + player1->pitch = 0; + player1->roll = 60; + if(actor==-1) //suicide + playsound(S_SUICIDE); + else + playsound(S_DIE1+rnd(2)); //add suicide sound + 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 initclient() +{ + clientmap[0] = 0; + initclientnet(); +}; + +void startmap(char *name) // called just after a map load +{ + //if(netmapstart()) { gamemode = 0;}; //needs fixed to switch modes? + sleepwait = 0; + //put call to clear/restart game mode extras here + projreset(); + spawncycle = -1; + spawnplayer(player1); + player1->frags = 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); diff --git a/source/src/editing.cpp b/source/src/editing.cpp index 4df636b7..2a1c4a5c 100644 --- a/source/src/editing.cpp +++ b/source/src/editing.cpp @@ -44,7 +44,7 @@ void toggleedit() else { resettagareas(); // clear trigger areas to allow them to be edited - player1->health = 100; + player1->health = 100; //put call to clear/restar gamemode projreset(); }; diff --git a/source/src/entities.cpp b/source/src/entities.cpp index 90cd32c4..60bbed1a 100644 --- a/source/src/entities.cpp +++ b/source/src/entities.cpp @@ -1,244 +1,247 @@ -// entities.cpp: map entity related functions (pickup etc.) - -#include "cube.h" - -vector ents; - -//fill in 2nd rrounds wth grenade, 3rd with plasma -char *entmdlnames[] = -{ - "shells", "bullets", "rockets", "rrounds", "rrounds", "rrounds", "health", "armour", "quad", -}; - -int triggertime = 0; - -void renderent(entity &e, char *mdlname, float z, float yaw, int frame = 0, int numf = 1, int basetime = 0, float speed = 10.0f) -{ - rendermodel(mdlname, frame, numf, 0, 1.1f, e.x, z+S(e.x, e.y)->floor, e.y, yaw, 0, false, 1.0f, speed, 0, basetime); -}; - -void renderentities() -{ - if(lastmillis>triggertime+1000) triggertime = 0; - loopv(ents) - { - entity &e = ents[i]; - if(e.type==MAPMODEL) - { - mapmodelinfo &mmi = getmminfo(e.attr2); - if(!&mmi) continue; - rendermodel(mmi.name, 0, 1, e.attr4, (float)mmi.rad, e.x, (float)S(e.x, e.y)->floor+mmi.zoff+e.attr3, e.y, (float)((e.attr1+7)-(e.attr1+7)%15), 0, false, 1.0f, 10.0f, mmi.snap); - } - else - { - if(OUTBORD(e.x, e.y)) continue; - if(e.type!=CARROT) - { - if(!e.spawned) continue; - if(e.typeI_QUAD) continue; - renderent(e, entmdlnames[e.type-I_AMMO], (float)(1+sin(lastmillis/100.0+e.x+e.y)/20), lastmillis/10.0f); - } - else switch(e.attr2) - { - case 1: - case 3: - continue; - - case 2: - case 0: - if(!e.spawned) continue; - renderent(e, "carrot", (float)(1+sin(lastmillis/100.0+e.x+e.y)/20), lastmillis/(e.attr2 ? 1.0f : 10.0f)); - break; - - case 4: renderent(e, "switch2", 3, (float)e.attr3*90, (!e.spawned && !triggertime) ? 1 : 0, (e.spawned || !triggertime) ? 1 : 2, triggertime, 1050.0f); break; - case 5: renderent(e, "switch1", -0.15f, (float)e.attr3*90, (!e.spawned && !triggertime) ? 30 : 0, (e.spawned || !triggertime) ? 1 : 30, triggertime, 35.0f); break; - }; - }; - }; -}; - -struct itemstat { int add, max, sound; } itemstats[] = -{ - 7, 14, S_ITEMAMMO, //shotgun - 30, 90, S_ITEMAMMO, //subgun - 5, 15, S_ITEMAMMO, //sniper - 20, 40, S_ITEMAMMO, //assult - 5, 10, S_ITEMAMMO, //pistol - 1, 2, S_ITEMAMMO, //grenade - 25, 100, S_ITEMHEALTH, //health - 100, 125, S_ITEMARMOUR, //armour - 20000, 30000, S_ITEMPUP, //powerup -}; - -void baseammo(int gun) { player1->ammo[gun] = itemstats[gun-1].add*2; }; - -// these two functions are called when the server acknowledges that you really -// picked up the item (in multiplayer someone may grab it before you). - -void radditem(int i, int &v) -{ - itemstat &is = itemstats[ents[i].type-I_AMMO]; - ents[i].spawned = false; - v += is.add; - if(v>is.max) v = is.max; - playsoundc(is.sound); -}; - -void realpickup(int n, dynent *d) -{ - switch(ents[n].type) - { -/* case I_PISTOL: radditem(n, d->ammo[1]); break; - - case I_AMMO: radditem(n, d->ammo[2]); break; - case I_SUBGUN: radditem(n, d->ammo[3]); break; - case I_SNIPER: radditem(n, d->ammo[4]); break; - case I_ASSAULT: radditem(n, d->ammo[5]); break; - case I_GRENADE: radditem(n, d->ammo[6]); break; -*/ - case I_HEALTH: radditem(n, d->health); break; - - case I_ARMOUR: - radditem(n, d->armour); - d->hasarmour = true; - break; - - case I_QUAD: - radditem(n, d->quadmillis); - conoutf("you got the quad!"); - break; - }; -}; - -// these functions are called when the client touches the item - -void additem(int i, int &v, int spawnsec) -{ - if(v4 ? 2 : 3); // spawn times are dependent on number of players - int ammo = np*2; - switch(ents[n].type) - { -/* - case I_PISTOL: additem(n, d->ammo[1], ammo); break; - - case I_AMMO: additem(n, d->ammo[2], ammo); break; - case I_SUBGUN: additem(n, d->ammo[3], ammo); break; - case I_SNIPER: additem(n, d->ammo[4], ammo); break; - case I_ASSAULT: additem(n, d->ammo[5], ammo); break; - case I_GRENADE: additem(n, d->ammo[6], ammo); break; -*/ - case I_HEALTH: additem(n, d->health, np*5); break; - - case I_ARMOUR: - additem(n, d->armour, 20); - break; - - case I_QUAD: - additem(n, d->quadmillis, 60); - break; - - case CARROT: - ents[n].spawned = false; - triggertime = lastmillis; - trigger(ents[n].attr1, ents[n].attr2, false); // needs to go over server for multiplayer - break; - - }; -}; - -void checkitems() -{ - if(editmode) return; - loopv(ents) - { - entity &e = ents[i]; - if(e.type==NOTUSED) continue; - if(!ents[i].spawned) continue; - if(OUTBORD(e.x, e.y)) continue; - vec v = { e.x, e.y, S(e.x, e.y)->floor+player1->eyeheight }; - vdist(dist, t, player1->o, v); - if(dist<2.5) pickup(i, player1); - }; -}; - -void putitems(uchar *&p) // puts items in network stream and also spawns them locally -{ - loopv(ents) if((ents[i].type>=I_AMMO && ents[i].type<=I_QUAD) || ents[i].type==CARROT) - { - putint(p, i); - ents[i].spawned = true; - }; -}; - -void resetspawns() { loopv(ents) ents[i].spawned = false; }; -void setspawn(int i, bool on) { if(inextprimary!=i) d->ammo[i] = 0; - d->mag[GUN_KNIFE] = 1; - - d->mag[GUN_PISTOL] = 8; - d->ammo[GUN_PISTOL] = 24; - - if(m_pistols) - { - d->primary=GUN_PISTOL; - d->ammo[GUN_PISTOL] = 48; //change? - return; - }; - - if (d->primary==GUN_PISTOL) // || pistol only mode! - { - d->ammo[d->primary] = 48; - } - else if (d->primary>GUN_PISTOL && d->primaryammo[d->primary] = itemstats[d->primary-2].max; - d->mag[d->primary] = itemstats[d->primary-2].add; - } - else if (d->primary==GUN_GRENADE) - { - conoutf("you don't have to worry about blowing your hand off just yet..."); - } - - /* - if (d->armour) - { - d->armour = 100; - } - */ - //if(m_noitems) { conoutf("i am (not) sorry, but an armour choice is only for ts and lms"); return; }; - - if(d->nextarmour==true) - { - if(!m_noitems) return;{ conoutf("armour is only for ts and lms modes, maybe you can hide"); return; }; - d->hasarmour = true; - d->armour=itemstats[7].add; - } - else - { - d->hasarmour = false; - }; -}; - -void add(int num) -{ - if (num>0 && num<6) player1->nextprimary = num; - if (num==7 && m_noitems) player1->nextarmour=!player1->nextarmour; - else conoutf("armour is only for ts and lms modes, maybe you can hide"); -}; - +// entities.cpp: map entity related functions (pickup etc.) + +#include "cube.h" + +vector ents; + +//fill in 2nd rrounds wth grenade, 3rd with plasma +char *entmdlnames[] = +{ + "shells", "bullets", "rockets", "rrounds", "rrounds", "rrounds", "health", "armour", "quad", +}; + +int triggertime = 0; + +void renderent(entity &e, char *mdlname, float z, float yaw, int frame = 0, int numf = 1, int basetime = 0, float speed = 10.0f) +{ + rendermodel(mdlname, frame, numf, 0, 1.1f, e.x, z+S(e.x, e.y)->floor, e.y, yaw, 0, false, 1.0f, speed, 0, basetime); +}; + +void renderentities() +{ + if(lastmillis>triggertime+1000) triggertime = 0; + loopv(ents) + { + entity &e = ents[i]; + if(e.type==MAPMODEL) + { + mapmodelinfo &mmi = getmminfo(e.attr2); + if(!&mmi) continue; + rendermodel(mmi.name, 0, 1, e.attr4, (float)mmi.rad, e.x, (float)S(e.x, e.y)->floor+mmi.zoff+e.attr3, e.y, (float)((e.attr1+7)-(e.attr1+7)%15), 0, false, 1.0f, 10.0f, mmi.snap); + } + else + { + if(OUTBORD(e.x, e.y)) continue; + if(e.type!=CARROT) + { + if(!e.spawned) continue; + if(e.typeI_QUAD) continue; + renderent(e, entmdlnames[e.type-I_AMMO], (float)(1+sin(lastmillis/100.0+e.x+e.y)/20), lastmillis/10.0f); + } + else switch(e.attr2) + { + case 1: + case 3: + continue; + + case 2: + case 0: + if(!e.spawned) continue; + renderent(e, "carrot", (float)(1+sin(lastmillis/100.0+e.x+e.y)/20), lastmillis/(e.attr2 ? 1.0f : 10.0f)); + break; + + case 4: renderent(e, "switch2", 3, (float)e.attr3*90, (!e.spawned && !triggertime) ? 1 : 0, (e.spawned || !triggertime) ? 1 : 2, triggertime, 1050.0f); break; + case 5: renderent(e, "switch1", -0.15f, (float)e.attr3*90, (!e.spawned && !triggertime) ? 30 : 0, (e.spawned || !triggertime) ? 1 : 30, triggertime, 35.0f); break; + }; + }; + }; +}; + +struct itemstat { int add, max, sound; } itemstats[] = +{ + 7, 14, S_ITEMAMMO, //shotgun + 30, 90, S_ITEMAMMO, //subgun + 5, 15, S_ITEMAMMO, //sniper + 20, 40, S_ITEMAMMO, //assult + 5, 10, S_ITEMAMMO, //pistol + 1, 2, S_ITEMAMMO, //grenade + 25, 100, S_ITEMHEALTH, //health + 100, 125, S_ITEMARMOUR, //armour + 20000, 30000, S_ITEMPUP, //powerup +}; + +void baseammo(int gun) { player1->ammo[gun] = itemstats[gun-1].add*2; }; + +// these two functions are called when the server acknowledges that you really +// picked up the item (in multiplayer someone may grab it before you). + +void radditem(int i, int &v) +{ + itemstat &is = itemstats[ents[i].type-I_AMMO]; + ents[i].spawned = false; + v += is.add; + if(v>is.max) v = is.max; + playsoundc(is.sound); +}; + +void realpickup(int n, dynent *d) +{ + switch(ents[n].type) + { +/* case I_PISTOL: radditem(n, d->ammo[1]); break; + + case I_AMMO: radditem(n, d->ammo[2]); break; + case I_SUBGUN: radditem(n, d->ammo[3]); break; + case I_SNIPER: radditem(n, d->ammo[4]); break; + case I_ASSAULT: radditem(n, d->ammo[5]); break; + case I_GRENADE: radditem(n, d->ammo[6]); break; +*/ + case I_HEALTH: radditem(n, d->health); break; + + case I_ARMOUR: + radditem(n, d->armour); + d->hasarmour = true; + break; + + case I_QUAD: + radditem(n, d->quadmillis); + conoutf("you got the quad!"); + break; + }; +}; + +// these functions are called when the client touches the item + +void additem(int i, int &v, int spawnsec) +{ + if(v4 ? 2 : 3); // spawn times are dependent on number of players + int ammo = np*2; + switch(ents[n].type) + { +/* + case I_PISTOL: additem(n, d->ammo[1], ammo); break; + + case I_AMMO: additem(n, d->ammo[2], ammo); break; + case I_SUBGUN: additem(n, d->ammo[3], ammo); break; + case I_SNIPER: additem(n, d->ammo[4], ammo); break; + case I_ASSAULT: additem(n, d->ammo[5], ammo); break; + case I_GRENADE: additem(n, d->ammo[6], ammo); break; +*/ + case I_HEALTH: additem(n, d->health, np*5); break; + + case I_ARMOUR: + additem(n, d->armour, 20); + break; + + case I_QUAD: + additem(n, d->quadmillis, 60); + break; + + case CARROT: + ents[n].spawned = false; + triggertime = lastmillis; + trigger(ents[n].attr1, ents[n].attr2, false); // needs to go over server for multiplayer + break; + + }; +}; + +void checkitems() +{ + if(editmode) return; + loopv(ents) + { + entity &e = ents[i]; + if(e.type==NOTUSED) continue; + if(!ents[i].spawned) continue; + if(OUTBORD(e.x, e.y)) continue; + vec v = { e.x, e.y, S(e.x, e.y)->floor+player1->eyeheight }; + vdist(dist, t, player1->o, v); + if(dist<2.5) pickup(i, player1); + }; +}; + +void putitems(uchar *&p) // puts items in network stream and also spawns them locally +{ + loopv(ents) if((ents[i].type>=I_AMMO && ents[i].type<=I_QUAD) || ents[i].type==CARROT) + { + putint(p, i); + ents[i].spawned = true; + }; +}; + +void resetspawns() { loopv(ents) ents[i].spawned = false; }; +void setspawn(int i, bool on) { if(inextprimary!=i) d->ammo[i] = 0; + d->mag[GUN_KNIFE] = 1; + + d->mag[GUN_PISTOL] = 8; + d->ammo[GUN_PISTOL] = 24; + + if(m_pistols) + { + d->primary=GUN_PISTOL; + d->ammo[GUN_PISTOL] = 48; //change? + return; + }; + + if (d->primary==GUN_PISTOL) // || pistol only mode! + { + d->ammo[d->primary] = 48; + } + else if (d->primary>GUN_PISTOL && d->primaryammo[d->primary] = itemstats[d->primary-2].max; + d->mag[d->primary] = itemstats[d->primary-2].add; + } + else if (d->primary==GUN_GRENADE) + { + conoutf("you don't have to worry about blowing your hand off just yet..."); + } + + /* + if (d->armour) + { + d->armour = 100; + } + */ + //if(m_noitems) { conoutf("i am (not) sorry, but an armour choice is only for ts and lms"); return; }; + + if(d->nextarmour==true) + { + if(!m_noitems) return;{ conoutf("armour is only for ts and lms modes, maybe you can hide"); return; }; + d->hasarmour = true; + d->armour=itemstats[7].add; + } + else + { + d->hasarmour = false; + }; +}; + +void add(int num) +{ + if (num>0 && num<6) player1->nextprimary = num; + else + { + if (num==7 && m_noitems) player1->nextarmour=!player1->nextarmour; + else conoutf("armour is only for ts and lms modes, maybe you can hide"); + }; +}; + COMMAND(add,ARG_1INT); \ No newline at end of file diff --git a/source/src/renderextras.cpp b/source/src/renderextras.cpp index 3b4eae02..996bd68b 100644 --- a/source/src/renderextras.cpp +++ b/source/src/renderextras.cpp @@ -357,7 +357,7 @@ void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwat if (!player1->reloading && player1->gunselect!=GUN_KNIFE) { //draw_textf("%d", 690, 827, 2, player1->mag[player1->gunselect]); - char * gunstats; + char gunstats[64]; sprintf(gunstats,"%i/%i",player1->mag[player1->gunselect],player1->ammo[player1->gunselect]); draw_text(gunstats, 690, 827, 2); //clean up pointer? diff --git a/source/src/savegamedemo.cpp b/source/src/savegamedemo.cpp index 73669ea8..0421a828 100644 --- a/source/src/savegamedemo.cpp +++ b/source/src/savegamedemo.cpp @@ -105,7 +105,7 @@ void loadgamerest() { if(demoplayback || !f) return; - if(gzgeti()!=ents.length()) return loadgameout(); + if(gzgeti()!=ents.length()) { loadgameout(); return; } loopv(ents) { ents[i].spawned = gzgetc(f)!=0; diff --git a/source/src/worldio.cpp b/source/src/worldio.cpp index fedd06b2..5a786d5b 100644 --- a/source/src/worldio.cpp +++ b/source/src/worldio.cpp @@ -292,7 +292,7 @@ void load_world(char *mname) // still supports all map formats that have free(world); setupworld(hdr.sfactor); char texuse[256]; - loopi(256) texuse[i] = 0; + loopj(256) texuse[j] = 0; sqr *t = NULL; loopk(cubicsize) { @@ -358,7 +358,7 @@ void load_world(char *mname) // still supports all map formats that have calclight(); settagareas(); int xs, ys; - loopi(256) if(texuse) lookuptexture(i, xs, ys); + loop(g, 256) if(texuse) lookuptexture(g, xs, ys); conoutf("read map %s (%d milliseconds)", (int)cgzname, SDL_GetTicks()-lastmillis); conoutf("%s", (int)hdr.maptitle); startmap(mname);