Index: Makefile =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/Makefile,v retrieving revision 1.20 diff -r1.20 Makefile 28d27 < savegamedemo.o \ Index: client.cpp =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/client.cpp,v retrieving revision 1.86 diff -r1.86 client.cpp 54a55 > clientpassword[0] = '\0'; 81a83 > clientpassword[0] = '\0'; 100c102,106 < else conoutf("\f3could not connect to server"); --- > else > { > conoutf("\f3could not connect to server"); > clientpassword[0] = '\0'; > } 137,141d142 < else if(demoplayback) < { < // todo: additional cleanups < cleanup = true; < } 145d145 < stop(); 202d201 < if(demoplayback) return; 214a214,222 > case 'v': > { > int n = va_arg(args, int); > int *v = va_arg(args, int *); > loopi(n) putint(p, v[i]); > numi += n; > break; > } > 226,227c234,235 < int num = nums?0:numi; < if(num!=msgsizelookup(type)) { s_sprintfd(s)("inconsistant msg size for %d (%d != %d)", type, num, msgsizelookup(type)); fatal(s); } --- > int num = nums?0:numi, msgsize = msgsizelookup(type); > if(msgsize && num!=msgsize) { s_sprintfd(s)("inconsistant msg size for %d (%d != %d)", type, num, msgsize); fatal(s); } 255c263 < bool hasmsg = gun_changed || senditemstoserver || !c2sinit || messages.length() || lastmillis-lastping>250; --- > bool hasmsg = senditemstoserver || !c2sinit || messages.length() || lastmillis-lastping>250; 269,276c277,284 < putuint(q, (int)(d->yaw*DAF)); < putint(q, (int)(d->pitch*DAF)); < putint(q, (int)(d->roll*DAF)); < putint(q, (int)(d->vel.x*DVF)); // quantize to 1/100, almost always 1 byte < putint(q, (int)(d->vel.y*DVF)); < putint(q, (int)(d->vel.z*DVF)); < // pack rest in 1 int: strafe:2, move:2, onfloor:1, state:3, onladder: 1 < putint(q, (d->strafe&3) | ((d->move&3)<<2) | (((int)d->onfloor)<<4) | ((editmode ? CS_EDITING : d->state)<<5) | (((int)d->onladder)<<8) ); --- > putuint(q, (int)d->yaw); > putint(q, (int)d->pitch); > putint(q, (int)d->roll); > putint(q, (int)(d->vel.x*DVELF)); > putint(q, (int)(d->vel.y*DVELF)); > putint(q, (int)(d->vel.z*DVELF)); > // pack rest in 1 int: strafe:2, move:2, onfloor:1, onladder: 1 > putint(q, (d->strafe&3) | ((d->move&3)<<2) | (((int)d->onfloor)<<4) | (((int)d->onladder)<<5) ); 279d286 < incomingdemodata(0, q.buf, q.length(), true); 282d288 < bool serveriteminitdone = false; 292,297d297 < if(clientpassword[0]) < { < putint(p, SV_PWD); < sendstring(clientpassword, p); < clientpassword[0] = 0; < } 302,309d301 < putint(p, player1->lifesequence); < } < if(gun_changed) < { < packet->flags = ENET_PACKET_FLAG_RELIABLE; < putint(p, SV_WEAPCHANGE); < putint(p, player1->gunselect); < gun_changed = false; 318d309 < serveriteminitdone = true; 340d330 < incomingdemodata(42, p.buf, p.length()); 346c336,347 < if(serveriteminitdone) loadgamerest(); // hack --- > } > > void sendintro() > { > ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, 0); > ucharbuf p(packet->data, packet->dataLength); > putint(p, SV_CONNECT); > sendstring(clientpassword, p); > clientpassword[0] = '\0'; > putint(p, player1->nextprimary); > enet_packet_resize(packet, p.length()); > sendpackettoserv(1, packet); 376a378 > sendintro(); Index: clientgame.cpp =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/clientgame.cpp,v retrieving revision 1.162 diff -r1.162 clientgame.cpp 87c87 < void changeteam(int team) // force team and respawn --- > void changeteam(int team, bool forced) // force team and respawn 92c92 < deathstate(player1); --- > if(!forced) deathstate(player1); 147c147 < { --- > { 149c149,151 < if(d==player1) --- > d->spawnstate(gamemode); > //d->lastaction = lastmillis; > if(d==player1) 151d152 < gun_changed = true; 155,156d155 < equip(d); < if(m_osok) d->health = 1; 194,195d192 < < 198,199c195,200 < spawnplayer(player1); < showscores(false); --- > if(m_mp(gamemode)) addmsg(SV_TRYSPAWN, "r"); > else > { > spawnplayer(player1); > showscores(false); > } 214,228d214 < void arenacount(playerent *d, int &alive, int &dead, char *&lastteam, char *&lastname, bool &oneteam) < { < if(d->state!=CS_DEAD) < { < alive++; < if(lastteam && strcmp(lastteam, d->team)) oneteam = false; < lastteam = d->team; < lastname = d->name; < } < else < { < dead++; < } < } < 242a229,230 > removebounceents(d); > removeprojectiles(d); 246,247d233 < extern int democlientnum; < 259c245 < if(!demoplayback || i!=democlientnum) moveplayer(players[i], 2, false); // use physics to extrapolate player position --- > moveplayer(players[i], 2, false); // use physics to extrapolate player position 292,297c278,279 < 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 < } --- > 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 300c282,288 < if(!demoplayback) --- > //monsterthink(); > > // Added by Rick: let bots think > if(m_botmode) BotManager.Think(); > > //put game mode extra call here > if(player1->state==CS_DEAD) 302,316c290 < //monsterthink(); < < // Added by Rick: let bots think < if(m_botmode) BotManager.Think(); < < //put game mode extra call here < if(player1->state==CS_DEAD) < { < if(lastmillis-player1->lastpain<2000) < { < player1->move = player1->strafe = 0; < moveplayer(player1, 10, false); < } < } < else if(!intermission) --- > if(lastmillis-player1->lastpain<2000) 318,319c292,293 < moveplayer(player1, 20, true); < checkitems(player1); --- > player1->move = player1->strafe = 0; > moveplayer(player1, 10, false); 321d294 < c2sinfo(player1); // do this last, to reduce the effective frame lag 322a296,301 > else if(!intermission) > { > moveplayer(player1, 20, true); > checkitems(player1); > } > c2sinfo(player1); // do this last, to reduce the effective frame lag 344c323 < int findplayerstart(playerent *d) --- > void findplayerstart(playerent *d) 347,349c326,332 < < if(m_teammode) loopi(r) spawncycle = findentity(PLAYERSTART, spawncycle+1, team_int(d->team)); < else if(m_arena) loopi(r) spawncycle = findentity(PLAYERSTART, spawncycle+1, 100); --- > entity *e = NULL; > if(m_teammode || m_arena) > { > int type = m_teammode ? team_int(d->team) : 100; > loopi(r) spawncycle = findentity(PLAYERSTART, spawncycle+1, type); > if(spawncycle >= 0) e = &ents[spawncycle]; > } 352d334 < int bestent = -1; 358c340 < if(spawncycle < 0 || spawncycle >= ents.length()) continue; --- > if(spawncycle < 0) continue; 360c342 < if(bestent < 0 || dist < 0 || (bestdist >= 0 && dist > bestdist)) { bestent = spawncycle; bestdist = dist; } --- > if(!e || dist < 0 || (bestdist >= 0 && dist > bestdist)) { e = &ents[spawncycle]; bestdist = dist; } 362,363d343 < < return bestent; 365,366d344 < return spawncycle; < } 368,371c346 < void spawnplayer(playerent *d) // place at random spawn < { < int e = findplayerstart(d); < if(e!=-1) --- > if(e) 373,376c348,351 < d->o.x = ents[e].x; < d->o.y = ents[e].y; < d->o.z = ents[e].z; < d->yaw = ents[e].attr1; --- > d->o.x = e->x; > d->o.y = e->y; > d->o.z = e->z; > d->yaw = e->attr1; 387,388c362,369 < spawnstate(d); < d->state = CS_ALIVE; --- > } > > void spawnplayer(playerent *d) > { > findplayerstart(d); > d->respawn(); > d->spawnstate(gamemode); > d->state = d==player1 && editmode ? CS_EDITING : CS_ALIVE; 395c376 < void dodamage(int damage, int actor, playerent *act, bool gib, playerent *pl) --- > void dodamage(int damage, playerent *pl, playerent *actor, bool gib, bool local) 397,398c378,383 < if(!act) return; < if(pl->state!=CS_ALIVE || editmode || intermission) return; --- > if(pl->state!=CS_ALIVE || intermission) return; > > pl->lastpain = lastmillis; > if(local) damage = pl->dodamage(damage); > else if(actor==player1) return; > 402c387 < demoblend(damage); --- > pl->damageroll(damage); 404,410c389,395 < pl->lastpain = lastmillis; < int ad = damage*30/100; // let armour absorb when possible < if(ad>pl->armour) ad = pl->armour; < pl->armour -= ad; < damage -= ad; < float droll = damage/0.5f; < pl->roll += pl->roll>0 ? droll : (pl->roll<0 ? -droll : (rnd(2) ? droll : -droll)); // give player a kick depending on amount of damage --- > else damageeffect(damage, pl); > > if(pl->health<=0) { if(local) dokill(pl, actor, gib); } > else if(pl==player1) playsound(S_PAIN6); > else playsound(S_PAIN1+rnd(5), &pl->o); > > #if 0 413c398 < s_sprintfd(death)("%s", gib ? "gibbed" : "fragged"); --- > s_sprintfd(death)("%s", gib ? "gibbed" : "fragged"); 425c410 < if(act==player1) showteamkill(); --- > if(act==player1) showteamkill(); 429,430c414,415 < act->frags += gib ? 2 : 1; < conoutf("\f2%s %s %s", act==player1 ? "you" : colorname(act, 0), death, colorname(pl, 1)); --- > act->frags += gib ? 2 : 1; > conoutf("\f2%s %s %s", act==player1 ? "you" : colorname(act, 0), death, colorname(pl, 1)); 447c432 < setscope(false); --- > setscope(false); 449c434 < if(m_ctf) tryflagdrop(act && isteam(act->team, player1->team)); --- > if(m_ctf) tryflagdrop(act && isteam(act->team, player1->team)); 451,456c436,441 < deathstate(pl); < pl->lifesequence++; < playsound(S_DIE1+rnd(2), pl!=player1 ? &pl->o : NULL); < if(act && act->gunselect == GUN_SNIPER && gib) playsound(S_HEADSHOT); < if(gib) addgib(pl); < if(pl!=player1 || act->type==ENT_BOT) act->frags += gib ? 2 : 1; --- > deathstate(pl); > pl->lifesequence++; > playsound(S_DIE1+rnd(2), pl!=player1 ? &pl->o : NULL); > if(act && act->gunselect == GUN_SNIPER && gib) playsound(S_HEADSHOT); > if(gib) addgib(pl); > if(pl!=player1 || act->type==ENT_BOT) act->frags += gib ? 2 : 1; 461a447,498 > #endif > } > > void dokill(playerent *pl, playerent *act, bool gib) > { > if(pl->state!=CS_ALIVE || intermission) return; > > string pname, aname, death; > s_strcpy(pname, pl==player1 ? "you" : colorname(pl)); > s_strcpy(aname, act==player1 ? "you" : colorname(act)); > s_strcpy(death, gib ? "gibbed" : "fragged"); > > if(pl==act) > conoutf("\f2%s suicided%s", pname, pl==player1 ? "!" : ""); > else if(isteam(pl->team, act->team)) > { > if(pl==player1) conoutf("\f2you got %s by a teammate (%s)", death, aname); > else conoutf("\f2%s %s %s teammate (%s)", aname, death, act==player1 ? "a" : "his", pname); > if(act==player1) showteamkill(); > } > else > { > if(pl==player1) conoutf("\f2you got %s by %s", death, aname); > else conoutf("\f2%s %s %s", aname, death, pname); > } > > pl->state = CS_DEAD; > pl->lastaction = lastmillis; > pl->pitch = 0; > pl->roll = 60; > pl->strafe = 0; > pl->attacking = false; > pl->lifesequence++; > playsound(S_DIE1+rnd(2), pl!=player1 ? &pl->o : NULL); > if(pl==player1) > { > showscores(true); > setscope(false); > dblend = 0; > if(pl->inhandnade) thrownade(pl, vec(0,0,0), pl->inhandnade); > if(m_ctf) tryflagdrop(pl!=act && isteam(act->team, pl->team)); > } > if(gib) > { > if(pl!=act && act->gunselect == GUN_SNIPER) playsound(S_HEADSHOT); > addgib(pl); > } > if(!m_mp(gamemode)) > { > if(pl==act || isteam(pl->team, act->team)) act->frags--; > else act->frags += gib ? 2 : 1; > } 540a578,579 > int suicided = -1; > 551a591 > clearbounceents(); 554a595 > suicided = -1; 556,557c597,599 < spawnplayer(player1); < player1->frags = player1->flagscore = player1->lifesequence = 0; --- > if(!m_mp(gamemode)) spawnplayer(player1); > else findplayerstart(player1); > player1->frags = player1->flagscore = 0; 568d609 < clearbounceents(); 575,577c616,622 < if(player1->state==CS_DEAD) return; < dodamage(1000, -1, player1); < demodamage(1000, player1->o); --- > if(player1->state!=CS_ALIVE) return; > if(!m_mp(gamemode)) dokill(player1, player1); > else if(suicided!=player1->lifesequence) > { > addmsg(SV_SUICIDE, "r"); > suicided = player1->lifesequence; > } 588,596c633,634 < bool own = flag == team_int(player1->team), firstperson = false; < const char *teamstr; < if(demoplayback && !localdemoplayer1st()) < teamstr = flag ? "the RVSF" : "the CLA"; < else < { < teamstr = flag == team_int(player1->team) ? "your" : "the enemy"; < firstperson = f.actor == player1; < } --- > bool own = flag == team_int(player1->team), firstperson = f.actor == player1; > const char *teamstr = flag == team_int(player1->team) ? "your" : "the enemy"; 629,630d666 < else if(demoplayback) < conoutf("\f2%s scored for team %s", colorname(f.actor), f.actor->team); Index: clients2c.cpp =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/clients2c.cpp,v retrieving revision 1.118 diff -r1.118 clients2c.cpp 6d5 < extern int democlientnum; 24c23,29 < addmsg(SV_MAPCHANGE, "rsi", name, nextmode); --- > ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); > ucharbuf p(packet->data, packet->dataLength); > putint(p, SV_MAPCHANGE); > sendstring(name, p); > putint(p, nextmode); > enet_packet_resize(packet, p.length()); > sendpackettoserv(1, packet); 71,76c76,81 < yaw = getuint(p)/DAF; < pitch = getint(p)/DAF; < roll = getint(p)/DAF; < vel.x = getint(p)/DVF; < vel.y = getint(p)/DVF; < vel.z = getint(p)/DVF; --- > yaw = (float)getuint(p); > pitch = (float)getint(p); > roll = (float)getint(p); > vel.x = getint(p)/DVELF; > vel.y = getint(p)/DVELF; > vel.z = getint(p)/DVELF; 91,94d95 < int oldstate = d->state, state = f&7; < if(state==CS_DEAD && oldstate!=CS_DEAD) d->lastpain = lastmillis; < d->state = state; < f >>= 3; 96,97c97,99 < if(!demoplayback) updatepos(d); < if(oldstate!=CS_DEAD && d->state!=CS_DEAD) updatelagtime(d); --- > updatepos(d); > updatelagtime(d); > if(d->state==CS_LAGGED) d->state = CS_ALIVE; 111c113 < bool mapchanged = false, c2si = false, gib = false; --- > bool mapchanged = false; 140c142 < playsound(getint(p), !d || (localdemoplayer1st() && cn==democlientnum) ? NULL : &d->o); --- > playsound(getint(p), !d ? NULL : &d->o); 214d215 < gun_changed = true; 220,221d220 < d->lifesequence = getint(p); < c2si = true; 240c239 < case SV_SHOT: --- > case SV_EDITMODE: 242,251c241,304 < if(!d) return; < int gun = getint(p); < vec s, e; < s.x = getint(p)/DMF; < s.y = getint(p)/DMF; < s.z = getint(p)/DMF; < e.x = getint(p)/DMF; < e.y = getint(p)/DMF; < e.z = getint(p)/DMF; < if(gun==GUN_SHOTGUN) createrays(s, e); --- > int val = getint(p); > if(!d) break; > if(val) d->state = CS_EDITING; > else d->state = CS_ALIVE; > break; > } > > case SV_SPAWN: > { > int ls = getint(p), gunselect = getint(p); > if(!d) break; > d->lifesequence = ls; > d->gunselect = gunselect; > d->state = CS_ALIVE; > break; > } > > case SV_SPAWNSTATE: > { > if(editmode) toggleedit(); > player1->respawn(); > player1->lifesequence = getint(p); > player1->health = getint(p); > player1->armour = getint(p); > player1->primary = getint(p); > player1->gunselect = getint(p); > loopi(NUMGUNS) player1->ammo[i] = getint(p); > loopi(NUMGUNS) player1->mag[i] = getint(p); > player1->state = CS_ALIVE; > findplayerstart(player1); > showscores(false); > setscope(false); > if(player1->skin!=player1->nextskin) setskin(player1, player1->nextskin); > if(m_arena) > { > conoutf("new round starting... fight!"); > if(m_botmode) BotManager.RespawnBots(); > } > addmsg(SV_SPAWN, "rii", player1->lifesequence, player1->gunselect); > break; > } > > case SV_SHOTFX: > { > int scn = getint(p), gun = getint(p); > vec from, to; > loopk(3) from[k] = getint(p)/DMF; > loopk(3) to[k] = getint(p)/DMF; > playerent *s = getclient(scn); > if(!s || gun==GUN_GRENADE) break; > if(gun==GUN_SHOTGUN) createrays(from, to); > s->lastaction = lastmillis; > s->lastattackgun = s->gunselect; > shootv(gun, from, to, s, false, 0); > break; > } > > case SV_THROWNADE: > { > vec from, to; > loopk(3) from[k] = getint(p)/DMF; > loopk(3) to[k] = getint(p)/DMF; > int nademillis = getint(p); > if(!d) break; 253,254c306,307 < d->lastattackgun = gun; < shootv(gun, s, e, d, false, getint(p)); --- > d->lastattackgun = GUN_GRENADE; > shootv(GUN_GRENADE, from, to, d, false, nademillis); 257,258c310,311 < case SV_GIBDAMAGE: < gib = true; --- > > case SV_GIBDAMAGE: 260,281c313,325 < { < if(!d) return; < int target = getint(p); < int damage = getint(p); < int ls = getint(p); < if(!demoplayback && target==getclientnum()) < { < if(ls==player1->lifesequence) < { < particle_splash(3, damage/10, 1000, player1->o); < dodamage(damage, cn, d, gib); < } < } < else < { < playerent *victim = getclient(target); < if(victim) < { < playsound(S_PAIN1+rnd(5), &victim->o); < particle_splash(3, damage/10, 1000, victim->o); < victim->lastpain = lastmillis; < } --- > { > int tcn = getint(p), > acn = getint(p), > damage = getint(p), > armour = getint(p), > health = getint(p); > playerent *target = tcn==getclientnum() ? player1 : getclient(tcn), > *actor = acn==getclientnum() ? player1 : getclient(acn); > if(!target || !actor) break; > if(target==player1) > { > target->armour = armour; > target->health = health; 283,289c327,331 < gib = false; < break; < } < < case SV_GIBDIED: < gib = true; < case SV_DIED: --- > dodamage(damage, target, actor, type==SV_GIBDAMAGE, false); > break; > } > > case SV_HITPUSH: 291,340c333,336 < if(!d) return; < int actor = getint(p); < playerent *act = NULL; < s_sprintfd(death)("%s", gib ? "gibbed" : "fragged"); < < if(actor==cn) < { < conoutf("\f2%s suicided", colorname(d)); < act = d; < } < else if(actor==getclientnum() && (!demoplayback || localdemoplayer1st())) < { < act = player1; < int frags; < if(isteam(player1->team, d->team)) < { < frags = -1; < conoutf("\f2you %s a teammate (%s)", death, colorname(d)); < extern void showteamkill(); < showteamkill(); < } < else < { < frags = gib ? 2 : 1; < conoutf("\f2you %s %s", death, colorname(d)); < } < addmsg(SV_FRAGS, "ri", player1->frags += frags); < if(gib) addgib(d); < } < else < { < playerent *a = getclient(actor); < if(a) < { < act = a; < if(isteam(a->team, d->team)) < { < conoutf("\f2%s %s his teammate (%s)", colorname(a, 0), death, colorname(d, 1)); < } < else < { < conoutf("\f2%s %s %s", colorname(a, 0), death, colorname(d, 1)); < } < if(gib) addgib(d); < } < } < playsound(S_DIE1+rnd(2), &d->o); < if(act && act->gunselect == GUN_SNIPER && gib) playsound(S_HEADSHOT); < if(!c2si) d->lifesequence++; < gib = false; --- > int gun = getint(p), damage = getint(p); > vec dir; > loopk(3) dir[k] = getint(p)/DNF; > player1->hitpush(damage, dir, NULL, gun); 343,346c339,349 < < case SV_FRAGS: < if(!d) return; < d->frags = getint(p); --- > > case SV_GIBDIED: > case SV_DIED: > { > int vcn = getint(p), acn = getint(p), frags = getint(p); > playerent *victim = vcn==getclientnum() ? player1 : getclient(vcn), > *actor = acn==getclientnum() ? player1 : getclient(acn); > if(!actor) break; > actor->frags = frags; > if(!victim) break; > dokill(victim, actor, type==SV_GIBDIED); 347a351 > } 351,353c355 < int cn = getint(p), frags = getint(p), flags = getint(p), lseq = getint(p); < playerent *d = cn==getclientnum() ? player1 : newclient(cn); < if(d) --- > for(;;) 354a357,365 > int cn = getint(p); > if(cn<0) break; > int state = getint(p), lifesequence = getint(p), gunselect = getint(p), flagscore = getint(p), frags = getint(p); > playerent *d = (cn == getclientnum() ? player1 : newclient(cn)); > if(!d) continue; > if(d!=player1) d->state = state; > d->lifesequence = lifesequence; > d->gunselect = gunselect; > d->flagscore = flagscore; 356,357d366 < d->flagscore = flags; < d->lifesequence = lseq; 362,366d370 < case SV_ITEMPICKUP: < setspawn(getint(p), false); < getint(p); < break; < 369c373 < uint i = getint(p); --- > int i = getint(p); 374,375c378,382 < case SV_ITEMACC: // server acknowledges that I picked up this item < realpickup(getint(p), player1); --- > case SV_ITEMACC: > { > int i = getint(p), cn = getint(p); > playerent *d = cn==getclientnum() ? player1 : getclient(cn); > pickupeffects(i, d); 376a384 > } 422c430 < if(!demoplayback) addmsg(SV_CLIENTPING, "i", player1->ping = (player1->ping*5+lastmillis-millis)/6); --- > addmsg(SV_CLIENTPING, "i", player1->ping = (player1->ping*5+lastmillis-millis)/6); 515,516c523,524 < int alive = getint(p); < getstring(text, p); --- > int acn = getint(p); > playerent *alive = acn<0 ? NULL : (acn==getclientnum() ? player1 : getclient(acn)); 518,521c526,530 < if(!alive) conoutf("everyone died!"); < else if(m_botmode && player1->state==CS_DEAD) conoutf("the bots have won the round!"); < else if(m_teammode) conoutf("team %s has won the round!", text); < else conoutf("%s is the survivor!", text); --- > if(m_botmode && acn==-2) conoutf("the bots have won the round!"); > else if(!alive) conoutf("everyone died!"); > else if(m_teammode) conoutf("team %s has won the round!", alive->team); > else if(alive==player1) conoutf("you are the survivor!"); > else conoutf("%s is the survivor!", colorname(alive)); 525,529c534,544 < case SV_ARENASPAWN: < conoutf("new round starting... fight!"); < respawnself(); < if(m_botmode) BotManager.RespawnBots(); < clearbounceents(); --- > case SV_FORCEDEATH: > { > int cn = getint(p); > playerent *d = cn==getclientnum() ? player1 : newclient(cn); > if(!d) break; > if(d==player1) > { > if(editmode) toggleedit(); > showscores(true); > } > d->state = CS_DEAD; 530a546 > } 594,595c610 < changeteam(getint(p)); < if(!m_arena || joining<=2) spawnplayer(player1); --- > changeteam(getint(p), true); 599,603d613 < /* demo recording compat */ < case SV_PING: < getint(p); < break; < 605,613d614 < if(demoplayback) // filter demo messages < { < int size = msgsizelookup(type); < if(size>0) < { < loopi(size-1) getint(p); < break; < } < } 621,622d621 < incomingdemodata(chan, buf, len); < 630,633d628 < case 42: // player1 demo data only < extern int democlientnum; < parsemessages(democlientnum, getclient(democlientnum), p); < break; Index: cube.h =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/cube.h,v retrieving revision 1.111 diff -r1.111 cube.h 58d57 < #include "entity.h" 59a59 > #include "entity.h" Index: editing.cpp =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/editing.cpp,v retrieving revision 1.17 diff -r1.17 editing.cpp 52c52,53 < editing = editmode; --- > editing = editmode ? 1 : 0; > addmsg(SV_EDITMODE, "ri", editing); Index: entities.cpp =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/entities.cpp,v retrieving revision 1.90 diff -r1.90 entities.cpp 67,80d66 < itemstat itemstats[] = < { < {1, 1, 1, S_ITEMAMMO}, //knife dummy < {16, 32, 72, S_ITEMAMMO}, //pistol < {14, 28, 21, S_ITEMAMMO}, //shotgun < {60, 90, 90, S_ITEMAMMO}, //subgun < {10, 20, 15, S_ITEMAMMO}, //sniper < {30, 60, 60, S_ITEMAMMO}, //assault < {2, 0, 2, S_ITEMAMMO}, //grenade < {33, 100, 100, S_ITEMHEALTH}, //health < {50, 100, 100, S_ITEMARMOUR}, //armour < {16, 0, 72, S_ITEMPUP}, //powerup < }; < 84,94c70 < void equipitem(playerent *d, int i, int &v, int t) < { < itemstat &is = itemstats[t]; < ents[i].spawned = false; < v += is.add; < if(v>is.max) v = is.max; < if(d==player1) playsoundc(is.sound); < else playsound(is.sound, &d->o); < } < < void realpickup(int n, playerent *d) --- > void pickupeffects(int n, playerent *d) 96c72,77 < switch(ents[n].type) --- > entity &e = ents[n]; > e.spawned = false; > if(d!=player1 && d->type!=ENT_BOT) return; > d->pickup(e.type); > itemstat &is = d->itemstats(e.type); > if(&is) 98,105c79,84 < case I_CLIPS: < equipitem(d, n, d->ammo[1], 1); < break; < case I_AMMO: < equipitem(d, n, d->ammo[d->primary], d->primary); < break; < case I_GRENADE: < equipitem(d, n, d->mag[6], 6); --- > if(d==player1) playsoundc(is.sound); > else playsound(is.sound, &d->o); > } > switch(e.type) > { > case I_GRENADE: 108,113c87 < case I_HEALTH: < equipitem(d, n, d->health, 7); < break; < case I_ARMOUR: < equipitem(d, n, d->armour, 8); < break; --- > 116,118c90,94 < d->mag[GUN_PISTOL] = 16; < equipitem(d, n, d->ammo[1], 9); < if(d==player1 && d->gunselect!=GUN_SNIPER && !d->inhandnade) weaponswitch(GUN_PISTOL); --- > if(d==player1) > { > if(d->gunselect!=GUN_SNIPER && !d->inhandnade) weaponswitch(GUN_PISTOL); > addmsg(SV_AKIMBO, "ri", lastmillis); > } 124a101,142 > // these functions are called when the client touches the item > > void trypickup(int n, playerent *d) > { > entity &e = ents[n]; > switch(e.type) > { > default: > if(d->canpickup(e.type)) > { > if(d->type==ENT_PLAYER) addmsg(SV_ITEMPICKUP, "ri", n); > else if(d->type==ENT_BOT && serverpickup(n, -1)) pickupeffects(n, d); > e.spawned = false; > } > break; > > case LADDER: > d->onladder = true; > break; > > case CTF_FLAG: > { > if(d==player1) > { > int flag = e.attr2; > flaginfo &f = flaginfos[flag]; > flaginfo &of = flaginfos[team_opposite(flag)]; > if(f.state == CTFF_STOLEN) break; > > if(flag == team_int(d->team)) // its the own flag > { > if(f.state == CTFF_DROPPED) flagreturn(); > else if(f.state == CTFF_INBASE && of.state == CTFF_STOLEN && of.actor == d && of.ack) flagscore(); > } > else flagpickup(); > } > break; > } > } > } > > #if 0 183a202 > #endif 199c218 < if(dist1<1.5f && dist2 if(dist1<1.5f && dist2o.dist(v)<2.5f) pickup(i, d); --- > if(d->o.dist(v)<2.5f) trypickup(i, d); 216a236 > putint(p, ents[i].type); 234,260d253 < void equip(playerent *d) < { < if(m_pistol) d->primary = GUN_PISTOL; < else if(m_osok) d->primary = GUN_SNIPER; < else if(m_lss) d->primary = GUN_KNIFE; < else d->primary = d->nextprimary; < < loopi(NUMGUNS) d->ammo[i] = d->mag[i] = 0; < < d->mag[GUN_KNIFE] = d->ammo[GUN_KNIFE] = 1; < d->mag[GUN_GRENADE] = d->ammo[GUN_GRENADE] = 0; < < if(!m_nopistol) < { < d->ammo[GUN_PISTOL] = itemstats[GUN_PISTOL].max-magsize(GUN_PISTOL); < d->mag[GUN_PISTOL] = magsize(GUN_PISTOL); < } < < if(!m_noprimary) < { < d->ammo[d->primary] = itemstats[d->primary].start-magsize(d->primary); < d->mag[d->primary] = magsize(d->primary); < } < < d->gunselect = d->primary; < } < Index: entity.h =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/entity.h,v retrieving revision 1.16 diff -r1.16 entity.h 29a30,48 > struct itemstat { int add, start, max, sound; }; > static itemstat ammostats[] = > { > {1, 1, 1, S_ITEMAMMO}, //knife dummy > {16, 32, 72, S_ITEMAMMO}, //pistol > {14, 28, 21, S_ITEMAMMO}, //shotgun > {60, 90, 90, S_ITEMAMMO}, //subgun > {10, 20, 15, S_ITEMAMMO}, //sniper > {30, 60, 60, S_ITEMAMMO}, //assault > {2, 0, 2, S_ITEMAMMO} //grenade > }; > > static itemstat powerupstats[] = > { > {33, 100, 100, S_ITEMHEALTH}, //health > {50, 100, 100, S_ITEMARMOUR}, //armour > {16, 0, 72, S_ITEMPUP} //powerup > }; > 32a52,73 > #define SGRAYS 21 > #define SGSPREAD 2 > #define EXPDAMRAD 10 > > struct guninfo { short sound, reload, reloadtime, attackdelay, damage, projspeed, part, spread, recoil, magsize, mdl_kick_rot, mdl_kick_back; bool isauto; }; > static guninfo guns[NUMGUNS] = > { > { S_KNIFE, S_NULL, 0, 500, 50, 0, 0, 1, 1, 1, 0, 0, false }, > { S_PISTOL, S_RPISTOL, 1400, 170, 19, 0, 0, 80, 10, 8, 6, 5, false }, // *SGRAYS > { S_SHOTGUN, S_RSHOTGUN, 2400, 1000, 5, 0, 0, 1, 35, 7, 9, 9, false }, //reload time is for 1 shell from 7 too powerful to 6 > { S_SUBGUN, S_RSUBGUN, 1650, 80, 16, 0, 0, 70, 15, 30, 1, 2, true }, > { S_SNIPER, S_RSNIPER, 1950, 1500, 85, 0, 0, 60, 50, 5, 4, 4, false }, > { S_ASSAULT, S_RASSAULT, 2000, 130, 24, 0, 0, 20, 40, 15, 0, 2, true }, //recoil was 44 > { S_NULL, S_NULL, 1000, 650, 150, 20, 6, 1, 1, 1, 3, 1, false }, > }; > > static inline int reloadtime(int gun) { return guns[gun].reloadtime; } > static inline int attackdelay(int gun) { return guns[gun].attackdelay; } > static inline int magsize(int gun) { return guns[gun].magsize; } > static inline int kick_rot(int gun) { return guns[gun].mdl_kick_rot; } > static inline int kick_back(int gun) { return guns[gun].mdl_kick_back; } > 42,44d82 < struct itemstat { int add, start, max, sound; }; < // End add < 156c194,304 < struct playerent : dynent --- > struct playerstate > { > int health, armour; > int primary, nextprimary; > int gunselect, gunwait; > int akimbo; > int ammo[NUMGUNS], mag[NUMGUNS]; > > playerstate() : primary(GUN_ASSAULT), nextprimary(GUN_ASSAULT) {} > > itemstat &itemstats(int type) > { > switch(type) > { > case I_CLIPS: return ammostats[GUN_PISTOL]; > case I_AMMO: return ammostats[primary]; > case I_GRENADE: return ammostats[GUN_GRENADE]; > case I_HEALTH: > case I_ARMOUR: > case I_AKIMBO: > return powerupstats[type-I_HEALTH]; > default: > return *(itemstat *)0; > } > } > > bool canpickup(int type) > { > switch(type) > { > case I_CLIPS: return ammo[GUN_PISTOL] case I_AMMO: return ammo[primary] case I_GRENADE: return mag[GUN_GRENADE] case I_HEALTH: return health case I_ARMOUR: return armour case I_AKIMBO: return !akimbo; > default: return false; > } > } > > void additem(itemstat &is, int &v) > { > v += is.add; > if(v > is.max) v = is.max; > } > > void pickup(int type) > { > switch(type) > { > case I_CLIPS: additem(ammostats[GUN_PISTOL], ammo[GUN_PISTOL]); break; > case I_AMMO: additem(ammostats[primary], ammo[primary]); break; > case I_GRENADE: additem(ammostats[GUN_GRENADE], mag[GUN_GRENADE]); break; > case I_HEALTH: additem(powerupstats[type-I_HEALTH], health); break; > case I_ARMOUR: additem(powerupstats[type-I_HEALTH], armour); break; > case I_AKIMBO: > akimbo = 1; > mag[GUN_PISTOL] = 2*magsize(GUN_PISTOL); > additem(powerupstats[type-I_HEALTH], ammo[GUN_PISTOL]); > break; > } > } > > void respawn() > { > health = 100; > armour = 0; > gunselect = GUN_PISTOL; > gunwait = 0; > akimbo = 0; > loopi(NUMGUNS) ammo[i] = mag[i] = 0; > ammo[GUN_KNIFE] = mag[GUN_KNIFE] = 1; > } > > void spawnstate(int gamemode) > { > if(m_pistol) primary = GUN_PISTOL; > else if(m_osok) primary = GUN_SNIPER; > else if(m_lss) primary = GUN_KNIFE; > else primary = nextprimary; > > if(!m_nopistol) > { > ammo[GUN_PISTOL] = ammostats[GUN_PISTOL].max-magsize(GUN_PISTOL); > mag[GUN_PISTOL] = magsize(GUN_PISTOL); > } > > if(!m_noprimary) > { > ammo[primary] = ammostats[primary].start-magsize(primary); > mag[primary] = magsize(primary); > } > > gunselect = primary; > > if(m_osok) health = 1; > } > > // just subtract damage here, can set death, etc. later in code calling this > int dodamage(int damage) > { > int ad = damage*30/100; // let armour absorb when possible > if(ad>armour) ad = armour; > armour -= ad; > damage -= ad; > health -= damage; > return damage; > } > }; > > struct playerent : dynent, playerstate 161,162d308 < int health, armour; < int gunselect, gunwait; 164c310 < int clientrole; --- > int clientrole; 166,167d311 < int ammo[NUMGUNS]; < int mag[NUMGUNS]; 172,173d315 < int primary; //primary gun < int nextprimary; // primary after respawning 178d319 < int akimbo; 180c321 < int akimbomillis; --- > int akimbomillis; 185c326 < shots(0), reloading(false), primary(GUN_ASSAULT), nextprimary(GUN_ASSAULT), --- > shots(0), reloading(false), 191a333,345 > void damageroll(float damage) > { > float damroll = 2.0f*damage; > roll += roll>0 ? damroll : (roll<0 ? -damroll : (rnd(2) ? damroll : -damroll)); // give player a kick > } > > void hitpush(int damage, const vec &dir, playerent *actor, int gun) > { > vec push(dir); > push.mul(damage/100.0f); > vel.add(push); > } > 194c348,349 < reset(); --- > dynent::reset(); > playerstate::respawn(); 196,197d350 < health = 100; < armour = 0; 200,201d352 < gunselect = GUN_PISTOL; < gunwait = 0; 204,205d354 < akimbo = 0; < loopi(NUMGUNS) ammo[i] = mag[i] = 0; 227,234d375 < // Moved from server.cpp by Rick < struct server_entity // server side version of "entity" type < { < bool spawned; < int spawnsecs; < }; < // End move < Index: geom.h =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/geom.h,v retrieving revision 1.5 diff -r1.5 geom.h 42a43,72 > struct ivec > { > union > { > struct { int x, y, z; }; > int v[3]; > }; > > ivec() {} > ivec(const vec &v) : x(int(v.x)), y(int(v.y)), z(int(v.z)) {} > ivec(int a, int b, int c) : x(a), y(b), z(c) {} > > vec tovec() const { return vec(x, y, z); } > > int &operator[](int i) { return v[i]; } > int operator[](int i) const { return v[i]; } > > bool operator==(const ivec &v) const { return x==v.x && y==v.y && z==v.z; } > bool operator!=(const ivec &v) const { return x!=v.x || y!=v.y || z!=v.z; } > ivec &mul(int n) { x *= n; y *= n; z *= n; return *this; } > ivec &div(int n) { x /= n; y /= n; z /= n; return *this; } > ivec &add(int n) { x += n; y += n; z += n; return *this; } > ivec &sub(int n) { x -= n; y -= n; z -= n; return *this; } > ivec &add(const ivec &v) { x += v.x; y += v.y; z += v.z; return *this; } > ivec &sub(const ivec &v) { x -= v.x; y -= v.y; z -= v.z; return *this; } > ivec &mask(int n) { x &= n; y &= n; z &= n; return *this; } > ivec &cross(const ivec &a, const ivec &b) { x = a.y*b.z-a.z*b.y; y = a.z*b.x-a.x*b.z; z = a.x*b.y-a.y*b.x; return *this; } > int dot(const ivec &o) const { return x*o.x + y*o.y + z*o.z; } > }; > Index: main.cpp =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/main.cpp,v retrieving revision 1.104 diff -r1.104 main.cpp 7d6 < stop(); 27,28d25 < extern void stopreset(); < if(demoplayback) stopreset(); else stop(); 416,421c413 < if(demoplayback && demopaused) < { < curtime = 0; < millis = lastmillis; < } < else if(lastmillis) updateworld(curtime, lastmillis); --- > if(lastmillis) updateworld(curtime, lastmillis); 426c418 < if(!demoplayback) serverslice((int)time(NULL), 0); --- > serverslice(0); Index: physics.cpp =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/physics.cpp,v retrieving revision 1.62 diff -r1.62 physics.cpp 457d456 < else if(demoplayback && on) shiftdemoplayer(1); 465d463 < if(demoplayback && on) demopaused = !demopaused; 500c498 < if(camera1!=player1 && player1->state!=CS_DEAD && !demoplayback) --- > if(camera1!=player1 && player1->state!=CS_DEAD) Index: protocol.cpp =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/protocol.cpp,v retrieving revision 1.7 diff -r1.7 protocol.cpp 77,96d76 < // machine independent float (single precision, 24 bit mantissa, 7 bit exponent, sign) < < void putfloat(ucharbuf &p, float n) < { < int e; < double d = frexp((double) n, &e); < e += 64; < if (e < 0 || e > 127) e &= 0x7f; // hack: this float is not properly initialized... < int m = ((int) (d * (1<<24))) & ((1<<24)-1); < p.put(m); p.put(m>>8); p.put(m>>16); p.put(e | (d<0?0x80:0)); < } < < float getfloat(ucharbuf &p) < { < int m = p.get(); m |= p.get()<<8; m |= p.get()<<16; < int e = p.get(); < m |= e & 0x80 ? (-1 ^ ((1<<24)-1)) : 0; < return (float) ldexp((double) m / (1<<24), (e & 0x7f) - 64); < } < 127c107,109 < SV_GIBDIED, 2, SV_DIED, 2, SV_GIBDAMAGE, 4, SV_DAMAGE, 4, SV_SHOT, 9, SV_FRAGS, 2, SV_RESUME, 4, --- > 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, 129c111 < SV_MAPCHANGE, 0, SV_ITEMSPAWN, 2, SV_ITEMPICKUP, 3, --- > SV_MAPCHANGE, 0, SV_ITEMSPAWN, 2, SV_ITEMPICKUP, 2, 135c117 < SV_ARENASPAWN, 0, SV_ARENAWIN, 0, --- > SV_ARENAWIN, 2, 138c120 < SV_PWD, 0, --- > SV_CONNECT, 0, Index: protocol.h =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/protocol.h,v retrieving revision 1.19 diff -r1.19 protocol.h 6,7c6 < #define PROTOCOL_VERSION 1125 // bump when protocol changes < #define SAVEGAMEVERSION 1009 // bump if dynent/netprotocol changes or any other savegame/demo data bumped from 5 --- > #define PROTOCOL_VERSION 1126 // bump when protocol changes 13c12,14 < SV_GIBDIED, SV_DIED, SV_GIBDAMAGE, SV_DAMAGE, SV_SHOT, SV_FRAGS, SV_RESUME, --- > 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, 17c18 < SV_EDITH, SV_EDITT, SV_EDITS, SV_EDITD, SV_EDITE, --- > SV_EDITMODE, SV_EDITH, SV_EDITT, SV_EDITS, SV_EDITD, SV_EDITE, 21c22 < SV_ARENASPAWN, SV_ARENAWIN, --- > SV_ARENAWIN, 24c25 < SV_PWD, --- > SV_CONNECT, 31,32c32,33 < #define DAF 1.0f < #define DVF 100.0f --- > #define DNF 100.0f > #define DVELF 4.0f Index: protos.h =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/protos.h,v retrieving revision 1.137 diff -r1.137 protos.h 115c115 < extern void sendpackettoserv(int chan, struct _ENetPacket *packet); --- > extern void sendpackettoserv(int chan, ENetPacket *packet); 122c122 < extern void changeteam(int team); --- > extern void changeteam(int team, bool forced = false); 125c125 < extern bool sendpwd; --- > extern void sendintro(); 136c136,137 < extern void dodamage(int damage, int actor, playerent *act, bool gib = false, playerent *pl = player1); --- > extern void dodamage(int damage, playerent *pl, playerent *actor, bool gib = false, bool local = true); > extern void dokill(playerent *pl, playerent *act, bool gib = false); 157a159 > extern void findplayerstart(playerent *d); 265,276d266 < extern void loadgamerest(); < extern void incomingdemodata(int chan, uchar *buf, int len, bool extras = false); < extern void demoplaybackstep(); < extern void stop(); < extern void stopifrecording(); < extern void demodamage(int damage, vec &o); < extern void demoblend(int damage); < extern bool demopaused; < extern playerent *demoplayer; < extern void shiftdemoplayer(int i); < extern bool localdemoplayer1st(); < extern int demomillis(); 323a314 > extern void removebounceents(playerent *owner); 328a320 > extern void removeprojectiles(playerent *d); 336d327 < extern bool gun_changed; 341,343c332,334 < // Added by Rick < extern bool intersect(dynent *d, vec &from, vec &to, vec *end = NULL); < // End add by Rick --- > extern bool intersect(dynent *d, const vec &from, const vec &to, vec *end = NULL); > extern bool intersect(entity *e, const vec &from, const vec &to, vec *end = NULL); > extern void damageeffect(int damage, playerent *d); 349c340 < extern void realpickup(int n, playerent *d); --- > extern void pickupeffects(int n, playerent *d); 354,355d344 < extern void equip(playerent *d); < extern bool intersect(entity *e, vec &from, vec &to, vec *end=NULL); 375,376c364,365 < extern void localclienttoserver(int chan, struct _ENetPacket *); < extern void serverslice(int seconds, unsigned int timeout); --- > extern void localclienttoserver(int chan, ENetPacket *); > extern void serverslice(uint timeout); 381,382d369 < extern void putfloat(ucharbuf &p, float n); < extern float getfloat(ucharbuf &p); 390c377 < extern void serverms(int mode, int numplayers, int minremain, char *smapname, int seconds); --- > extern void serverms(int mode, int numplayers, int minremain, char *smapname, int millis); 392c379 < extern bool serverpickup(uint i, int sec, int sender); --- > extern bool serverpickup(int i, int sender); Index: rendergl.cpp =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/rendergl.cpp,v retrieving revision 1.87 diff -r1.87 rendergl.cpp 241,270c241 < if(demoplayback && demoplayer) < { < static physent democam; < extern bool firstpersondemo; < < if(demoplayer == player1 && firstpersondemo) < { < democam = *(physent *)player1; < } < else < { < static playerent *lastplayer = NULL; < if(lastplayer != demoplayer) < { < lastplayer = demoplayer; < democam = *(physent *)demoplayer; < democam.type = ENT_CAMERA; < democam.reset(); < democam.roll = 0; < democam.move = -1; < camera1 = &democam; < } < democam.o = demoplayer->o; < democam.o.x -= (float)(cosf(RAD*(demoplayer->yaw-90)))*demoplayer->radius*1.5f; < democam.o.y -= (float)(sinf(RAD*(demoplayer->yaw-90)))*demoplayer->radius*1.5f; < democam.o.z += demoplayer->eyeheight/3.0f; < if(!demopaused) democam.yaw = demoplayer->yaw; < } < } < else if(editmode || player1->state!=CS_DEAD) --- > if(editmode || player1->state!=CS_DEAD) 546c517 < if(player1->state!=CS_DEAD && (!demoplayback || localdemoplayer1st())) renderhudgun(); --- > if(player1->state!=CS_DEAD) renderhudgun(); Index: renderhud.cpp =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/renderhud.cpp,v retrieving revision 1.21 diff -r1.21 renderhud.cpp 52d51 < VARP(hidedemohud, 0, 0, 1); 279d277 < bool demo3rd = demoplayback && !localdemoplayer1st(); 285c283 < if(!demo3rd) --- > if(player1->state==CS_ALIVE && !player1->reloading && !didteamkill && !menuvisible) 287,292c285,288 < if(player1->state==CS_ALIVE && !player1->reloading && !didteamkill && !menuvisible) < { < bool drawteamwarning = targetplayer ? (isteam(targetplayer->team, player1->team) && targetplayer->state!=CS_DEAD) : false; < if(player1->gunselect==GUN_SNIPER && scoped) drawscope(); < else if((player1->gunselect!=GUN_SNIPER || drawteamwarning)) drawcrosshair(drawteamwarning); < } --- > bool drawteamwarning = targetplayer ? (isteam(targetplayer->team, player1->team) && targetplayer->state!=CS_DEAD) : false; > if(player1->gunselect==GUN_SNIPER && scoped) drawscope(); > else if((player1->gunselect!=GUN_SNIPER || drawteamwarning)) drawcrosshair(drawteamwarning); > } 294c290 < drawequipicons(); --- > drawequipicons(); 296,305c292,300 < glMatrixMode(GL_MODELVIEW); < if(!menuvisible && !hideradar) drawradar(w, h); < else drawteamicons(w, h); < glMatrixMode(GL_PROJECTION); < < char *infostr = editinfo(); < if(command) rendercommand(20, 1570); < else if(infostr) draw_text(infostr, 20, 1570); < else if(targetplayer) draw_text(colorname(targetplayer), 20, 1570); < } --- > glMatrixMode(GL_MODELVIEW); > if(!menuvisible && !hideradar) drawradar(w, h); > else drawteamicons(w, h); > glMatrixMode(GL_PROJECTION); > > char *infostr = editinfo(); > if(command) rendercommand(20, 1570); > else if(infostr) draw_text(infostr, 20, 1570); > else if(targetplayer) draw_text(colorname(targetplayer), 20, 1570); 322,336c317 < if(!hidedemohud && demoplayback) < { < const int left = VIRTW*2/80, top = VIRTH*2*3/4; < int dmillis = demomillis(); < s_sprintfd(time)("%d:%02d", dmillis/1000/60, dmillis/1000%60); < s_sprintfd(following)("\f0Following %s", colorname(demoplayer)); < < draw_text(time, left, top-FONTH); < draw_text(following, left, top); < draw_text("jump to pause", left, top+2*FONTH); < draw_text("attack to change view", left, top+3*FONTH); < draw_text("reload for slow-motion", left, top+4*FONTH); < } < < if(player1->state==CS_ALIVE && !demo3rd) --- > if(player1->state==CS_ALIVE) Index: rendermodel.cpp =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/rendermodel.cpp,v retrieving revision 1.37 diff -r1.37 rendermodel.cpp 371,372d370 < extern int democlientnum; < 388,389c386,387 < loopv(players) if((d = players[i]) && (!demoplayback || i!=democlientnum)) renderclient(d); < if(player1->state==CS_DEAD || (reflecting && !refracting) || (demoplayback && !localdemoplayer1st())) renderclient(player1); --- > loopv(players) if((d = players[i])) renderclient(d); > if(player1->state==CS_DEAD || (reflecting && !refracting)) renderclient(player1); Index: renderparticles.cpp =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/renderparticles.cpp,v retrieving revision 1.39 diff -r1.39 renderparticles.cpp 267d266 < VAR(demotracking, 0, 0, 1); 275,280d273 < if(demoplayback && demotracking) < { < vec nom(0, 0, 0); < newparticle(player1->o, nom, 100000000, 4); < } < Index: scoreboard.cpp =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/scoreboard.cpp,v retrieving revision 1.12 diff -r1.12 scoreboard.cpp 80c80 < if(!demoplayback) scores.add(player1); --- > scores.add(player1); 112c112 < if(!demoplayback) addteamscore(player1); --- > addteamscore(player1); Index: server.cpp =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/server.cpp,v retrieving revision 1.109 diff -r1.109 server.cpp 8a9,11 > static const int DEATHMILLIS = 250; > > enum { GE_NONE = 0, GE_SHOT, GE_EXPLODE, GE_HIT, GE_AKIMBO, GE_RELOAD, GE_SUICIDE, GE_PICKUP }; 14c17,81 < struct clientscore --- > struct shotevent > { > int type; > int millis; > int gun; > float from[3], to[3]; > }; > > struct explodeevent > { > int type; > int millis; > int gun; > }; > > struct hitevent > { > int type; > int target; > int lifesequence; > union > { > int info; > float dist; > }; > float dir[3]; > }; > > struct suicideevent > { > int type; > }; > > struct pickupevent > { > int type; > int ent; > }; > > struct akimboevent > { > int type; > int millis; > }; > > struct reloadevent > { > int type; > int millis; > int gun; > }; > > union gameevent > { > int type; > shotevent shot; > explodeevent explode; > hitevent hit; > suicideevent suicide; > pickupevent pickup; > akimboevent akimbo; > reloadevent reload; > }; > > struct clientstate : playerstate 16c83,96 < int frags, flags, lifesequence; --- > vec o; > int state; > int lastdeath, lifesequence; > int lastshot; > int grenades; > int akimbos, akimbomillis; > int flagscore, frags; > > clientstate() : state(CS_DEAD) {} > > bool isalive(int gamemillis) > { > return state==CS_ALIVE || (state==CS_DEAD && gamemillis - lastdeath <= DEATHMILLIS); > } 20c100,116 < frags = flags = lifesequence = 0; --- > state = CS_DEAD; > lifesequence = 0; > grenades = akimbos = 0; > akimbomillis = 0; > flagscore = frags = 0; > > respawn(); > } > > void respawn() > { > playerstate::respawn(); > o = vec(-1e10f, -1e10f, -1e10f); > lastdeath = 0; > lastshot = 0; > akimbos = 0; > akimbomillis = 0; 24c120 < struct savedscore : clientscore --- > struct savedscore 27a124,138 > int frags, flagscore, lifesequence; > > void save(clientstate &cs) > { > frags = cs.frags; > flagscore = cs.flagscore; > lifesequence = cs.lifesequence; > } > > void restore(clientstate &cs) > { > cs.frags = frags; > cs.flagscore = flagscore; > cs.lifesequence = lifesequence; > } 41,43d151 < uint pos[3]; < clientscore score; < bool arenadeath; 45c153,156 < bool isauthed; // for passworded servers --- > bool isauthed; // for passworded servers > int gameoffset; > clientstate state; > vector events; 47a159,166 > void mapchange() > { > mapvote[0] = 0; > state.reset(); > events.setsizenodelete(0); > gameoffset = -1; > } > 51,52d169 < score.reset(); < arenadeath = true; 56a174 > mapchange(); 89c207 < void sendpacket(int n, int chan, ENetPacket *packet) --- > void sendpacket(int n, int chan, ENetPacket *packet, int exclude = -1) 93c211 < loopv(clients) sendpacket(i, chan, packet); --- > loopv(clients) if(i!=exclude) sendpacket(i, chan, packet); 195a314,320 > int numnonlocalclients() > { > int nonlocalclients = 0; > loopv(clients) if(clients[i]->type==ST_TCPIP) nonlocalclients++; > return nonlocalclients; > } > 212c337 < clientscore *findscore(client &c, bool insert) --- > savedscore *findscore(client &c, bool insert) 219c344,349 < if(o.clientnum!=c.clientnum && o.peer->address.host==c.peer->address.host && !strcmp(o.name, c.name)) return &o.score; --- > if(o.clientnum!=c.clientnum && o.peer->address.host==c.peer->address.host && !strcmp(o.name, c.name)) > { > static savedscore curscore; > curscore.save(o.state); > return &curscore; > } 228d357 < sc.reset(); 234c363 < void resetscores() --- > struct server_entity // server side version of "entity" type 236,241c365,368 < loopv(clients) if(clients[i]->type==ST_TCPIP) < { < clients[i]->score.reset(); < } < scores.setsize(0); < } --- > int type; > bool spawned; > int spawntime; > }; 256c383 < sents[i].spawnsecs = 0; --- > sents[i].spawntime = 0; 260,261c387,388 < int interm = 0, minremain = 0, mapend = 0; < bool mapreload = false, autoteam = true; --- > static int interm = 0, minremain = 0, gamemillis = 0, gamelimit = 0; > static bool mapreload = false, autoteam = true; 263c390 < string serverpassword = ""; --- > static string serverpassword = ""; 271a399 > int exclude = -1; 279a408,419 > case 'x': > exclude = va_arg(args, int); > break; > > case 'v': > { > int n = va_arg(args, int); > int *v = va_arg(args, int *); > loopi(n) putint(p, v[i]); > break; > } > 286a427,435 > case 'm': > { > int n = va_arg(args, int); > enet_packet_resize(packet, packet->dataLength+n); > p.buf = packet->data; > p.maxlen += n; > p.put(va_arg(args, uchar *), n); > break; > } 290c439 < sendpacket(cn, chan, packet); --- > sendpacket(cn, chan, packet, exclude); 298a448,464 > void spawnstate(client *c) > { > clientstate &gs = c->state; > gs.spawnstate(smode); > gs.lifesequence++; > } > > void sendspawn(client *c) > { > clientstate &gs = c->state; > spawnstate(c); > sendf(c->clientnum, 1, "ri6vv", SV_SPAWNSTATE, gs.lifesequence, > gs.health, gs.armour, > gs.primary, gs.gunselect, > NUMGUNS, gs.ammo, NUMGUNS, gs.mag); > } > 303c469 < int pos[3]; --- > float pos[3]; 317c483 < else if(f.state==CTFF_DROPPED) loopi(3) putint(p, f.pos[i]); --- > else if(f.state==CTFF_DROPPED) loopi(3) putint(p, int(f.pos[i]*DMF)); 341c507 < loopi(3) f.pos[i] = clients[sender]->pos[i]; --- > loopi(3) f.pos[i] = clients[sender]->state.o[i]; 366c532 < f.lastupdate = lastsec; --- > f.lastupdate = gamemillis; 380,382c546 < int arenaround = 0; < < void arenareset() --- > bool canspawn(client *c, bool connecting = false) 384,388c548,553 < if(!m_arena) return; < < arenaround = 0; < loopv(clients) clients[i]->arenadeath = false; < sendf(-1, 1, "ri", SV_ARENASPAWN); --- > if(m_arena) > { > if(connecting && numnonlocalclients()<=2) return true; > return false; > } > return true; 391c556,558 < void arenacheck(int secs) --- > int arenaround = 0; > > void arenacheck() 393c560 < if(!m_arena || interm || secs if(!m_arena || interm || gamemillis arenaround = 0; > loopv(clients) if(clients[i]->type!=ST_EMPTY) sendspawn(clients[i]); 410c578 < if((dead && !alive) || clients[0]->arenadeath) --- > if((dead && !alive) || player1->state==CS_DEAD) 412,413c580,581 < sendf(-1, 1, "riis", SV_ARENAWIN, alive || player1->state!=CS_DEAD ? 1 : 0, player1->state==CS_DEAD ? "" : player1->name); < arenaround = secs+5; --- > sendf(-1, 1, "ri2", SV_ARENAWIN, player1->state==CS_ALIVE ? getclientnum() : (alive ? -2 : -1)); > arenaround = gamemillis+5000; 424,426c592,597 < if(c.arenadeath) dead = true; < else if(!alive) alive = &c; < else if(!m_teammode || strcmp(alive->team, c.team)) return; --- > if(c.state.state==CS_DEAD) dead = true; > else if(c.state.state==CS_ALIVE) > { > if(!alive) alive = &c; > else if(!m_teammode || strcmp(alive->team, c.team)) return; > } 429,430c600,601 < sendf(-1, 1, "riis", SV_ARENAWIN, alive ? 1 : 0, !alive ? "" : (m_teammode ? alive->team : alive->name)); < arenaround = secs+5; --- > sendf(-1, 1, "ri2", SV_ARENAWIN, !alive ? -1 : alive->clientnum); > arenaround = gamemillis+5000; 457,458c628,629 < clientscore *sc = findscore(c, true); < if(sc) *sc = c.score; --- > savedscore *sc = findscore(c, true); > if(sc) sc->save(c.state); 469c640 < bool serverpickup(uint i, int sec, int sender) // server side item pickup, acknowledge first client that gets it --- > int spawntime(int type) 471,472c642,646 < if(i>=(uint)sents.length()) return false; < if(sents[i].spawned) --- > int np = 0; > loopv(clients) if(clients[i]) np++; > np = np<3 ? 4 : (np>4 ? 2 : 3); // spawn times are dependent on number of players > int sec = 0; > switch(type) 474,477c648,873 < sents[i].spawned = false; < sents[i].spawnsecs = sec; < if(sender>=0) sendf(sender, 1, "rii", SV_ITEMACC, i); < return true; --- > case I_CLIPS: > case I_AMMO: > case I_GRENADE: sec = np*2; break; > case I_HEALTH: sec = np*5; break; > case I_ARMOUR: sec = 20; break; > case I_AKIMBO: sec = 60; break; > } > return sec*1000; > } > > bool serverpickup(int i, int sender) // server side item pickup, acknowledge first client that gets it > { > if(!sents.inrange(i)) return false; > server_entity &e = sents[i]; > if(!e.spawned) return false; > if(sender>=0) > { > client *cl = clients[sender]; > if(cl->type==ST_TCPIP) > { > if(cl->state.state!=CS_ALIVE || !cl->state.canpickup(e.type)) return false; > } > sendf(-1, 1, "ri3", SV_ITEMACC, i, sender); > cl->state.pickup(sents[i].type); > } > e.spawned = false; > e.spawntime = spawntime(e.type); > return true; > } > > void checkitemspawns(int diff) > { > if(!diff) return; > loopv(sents) if(sents[i].spawntime) > { > sents[i].spawntime -= diff; > if(sents[i].spawntime<=0) > { > sents[i].spawntime = 0; > sents[i].spawned = true; > sendf(-1, 1, "ri2", SV_ITEMSPAWN, i); > } > } > } > > void serverdamage(client *target, client *actor, int damage, int gun, bool gib, const vec &hitpush = vec(0, 0, 0)) > { > clientstate &ts = target->state; > ts.dodamage(damage); > sendf(-1, 1, "ri6", gib ? SV_GIBDAMAGE : SV_DAMAGE, target->clientnum, actor->clientnum, damage, ts.armour, ts.health); > if(target!=actor && !hitpush.iszero()) > { > vec v(hitpush); > if(!v.iszero()) v.normalize(); > sendf(target->clientnum, 1, "ri6", SV_HITPUSH, gun, damage, > int(v.x*DNF), int(v.y*DNF), int(v.z*DNF)); > } > if(ts.health<=0) > { > if(target!=actor && !isteam(target->team, actor->team)) actor->state.frags += gib ? 2 : 1; > else actor->state.frags--; > sendf(-1, 1, "ri4", gib ? SV_GIBDIED : SV_DIED, target->clientnum, actor->clientnum, actor->state.frags); > ts.state = CS_DEAD; > ts.lastdeath = gamemillis; > // don't issue respawn yet until DEATHMILLIS has elapsed > // ts.respawn(); > > if(actor->state.frags < scorethreshold) disconnect_client(actor->clientnum, DISC_AUTOKICK); > } > } > > void processevent(client *c, explodeevent &e) > { > clientstate &gs = c->state; > switch(e.gun) > { > case GUN_GRENADE: > if(gs.grenades<1) return; > gs.grenades--; > break; > > default: > return; > } > for(int i = 1; ievents.length() && c->events[i].type==GE_HIT; i++) > { > hitevent &h = c->events[i].hit; > client *target = clients[h.target]; > if(target->type==ST_EMPTY) continue; > if(target->state.state!=CS_ALIVE || h.lifesequence!=target->state.lifesequence || h.dist<0 || h.dist>=EXPDAMRAD) continue; > > int j = 1; > for(j = 1; jevents[j].hit.target==h.target) break; > if(j > int damage = int(guns[e.gun].damage*(1-h.dist/EXPDAMRAD)); > serverdamage(target, c, damage, e.gun, true, h.dir); > } > } > > void processevent(client *c, shotevent &e) > { > clientstate &gs = c->state; > int wait = e.millis - gs.lastshot; > if(!gs.isalive(gamemillis) || > (gs.gunwait && wait e.gun=NUMGUNS || > gs.mag[e.gun]<=0) > return; > if(e.gun!=GUN_KNIFE) gs.mag[e.gun]--; > gs.lastshot = e.millis; > gs.gunwait = attackdelay(e.gun); > if(e.gun==GUN_PISTOL && gs.akimbomillis>gamemillis) gs.gunwait /= 2; > sendf(-1, 1, "ri9x", SV_SHOTFX, c->clientnum, e.gun, > int(e.from[0]*DMF), int(e.from[1]*DMF), int(e.from[2]*DMF), > int(e.to[0]*DMF), int(e.to[1]*DMF), int(e.to[2]*DMF), > c->clientnum); > switch(e.gun) > { > case GUN_GRENADE: gs.grenades = min(gs.grenades+1, 8); break; > default: > { > int totalrays = 0, maxrays = e.gun==GUN_SHOTGUN ? SGRAYS : 1; > for(int i = 1; ievents.length() && c->events[i].type==GE_HIT; i++) > { > hitevent &h = c->events[i].hit; > client *target = clients[h.target]; > if(target->type==ST_EMPTY) continue; > if(target->state.state!=CS_ALIVE || h.lifesequence!=target->state.lifesequence) continue; > > int rays = e.gun==GUN_SHOTGUN ? h.info : 1; > if(rays<1) continue; > totalrays += rays; > if(totalrays>maxrays) continue; > > bool gib = false; > if(e.gun==GUN_KNIFE) gib = true; > else if(e.gun==GUN_SNIPER) gib = h.info!=0; > int damage = rays*guns[e.gun].damage; > if(e.gun==GUN_SNIPER && gib) damage *= 3; > serverdamage(target, c, damage, e.gun, gib, h.dir); > } > break; > } > } > } > > void processevent(client *c, suicideevent &e) > { > clientstate &gs = c->state; > if(gs.state!=CS_ALIVE) return; > gs.frags--; > sendf(-1, 1, "ri4", SV_DIED, c->clientnum, c->clientnum, gs.frags); > gs.state = CS_DEAD; > gs.respawn(); > } > > void processevent(client *c, pickupevent &e) > { > clientstate &gs = c->state; > if(!gs.isalive(gamemillis)) return; > serverpickup(e.ent, c->clientnum); > } > > void processevent(client *c, reloadevent &e) > { > clientstate &gs = c->state; > if(!gs.isalive(gamemillis) || > e.gun=NUMGUNS || > !reloadable_gun(e.gun) || > gs.ammo[e.gun]<=0) > return; > > bool akimbo = e.gun==GUN_PISTOL && gs.akimbomillis>e.millis; > int mag = (akimbo ? 2 : 1) * magsize(e.gun), numbullets = min(gs.ammo[e.gun], mag - gs.mag[e.gun]); > if(numbullets<=0) return; > > gs.mag[e.gun] += numbullets; > gs.ammo[e.gun] -= numbullets; > > int wait = e.millis - gs.lastshot; > if(gs.gunwait && wait else > { > gs.gunwait = reloadtime(e.gun); > gs.lastshot = e.millis; > } > } > > void processevent(client *c, akimboevent &e) > { > clientstate &gs = c->state; > if(!gs.isalive(gamemillis) || gs.akimbos<=0) return; > gs.akimbos--; > gs.akimbomillis = e.millis+30000; > } > > void clearevent(client *c) > { > int n = 1; > while(nevents.length() && c->events[n].type==GE_HIT) n++; > c->events.remove(0, n); > } > > void processevents() > { > loopv(clients) > { > client *c = clients[i]; > if(c->type==ST_EMPTY) continue; > while(c->events.length()) > { > gameevent &e = c->events[0]; > if(e.typegamemillis) break; > switch(e.type) > { > case GE_SHOT: processevent(c, e.shot); break; > case GE_EXPLODE: processevent(c, e.explode); break; > case GE_AKIMBO: processevent(c, e.akimbo); break; > case GE_RELOAD: processevent(c, e.reload); break; > // untimed events > case GE_SUICIDE: processevent(c, e.suicide); break; > case GE_PICKUP: processevent(c, e.pickup); break; > } > clearevent(c); > } 479d874 < return false; 573d967 < minremain = newtime >= 0 ? newtime : (m_teammode ? 15 : 10); 576c970,973 < mapend = lastsec+minremain*60; --- > minremain = newtime >= 0 ? newtime : (m_teammode ? 15 : 10); > gamemillis = 0; > gamelimit = minremain*60000; > 582c979 < resetscores(); --- > scores.setsize(0); 584c981,985 < if(notify) sendf(-1, 1, "risi", SV_MAPCHANGE, smapname, smode); --- > if(notify) > { > sendf(-1, 1, "risi", SV_MAPCHANGE, smapname, smode); > if(smode>1 || (smode==0 && numnonlocalclients()>0)) sendf(-1, 1, "ri2", SV_TIMEUP, minremain); > } 586c987 < arenareset(); --- > if(m_arena) arenaround = 0; 739,745d1139 < int numnonlocalclients() < { < int nonlocalclients = 0; < loopv(clients) if(clients[i]->type==ST_TCPIP) nonlocalclients++; < return nonlocalclients; < } < 774a1169,1258 > void sendwelcome(int n) > { > ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); > ucharbuf p(packet->data, packet->dataLength); > putint(p, SV_INITS2C); > putint(p, n); > putint(p, PROTOCOL_VERSION); > if(!smapname[0] && configsets.length()) nextcfgset(false); > int numcl = numclients(); > putint(p, smapname[0] ? numcl : -1); > putint(p, serverpassword[0] ? 1 : 0); > if(smapname[0]) > { > putint(p, SV_MAPCHANGE); > sendstring(smapname, p); > putint(p, smode); > if(smode>1 || (smode==0 && numnonlocalclients()>0)) > { > putint(p, SV_TIMEUP); > putint(p, minremain); > } > if(!configsets.length() || numcl > 1) > { > putint(p, SV_ITEMLIST); > loopv(sents) if(sents[i].spawned) > { > putint(p, i); > putint(p, sents[i].type); > } > putint(p, -1); > } > } > client *c = clients[n]; > if(c->type == ST_TCPIP && serveroperator() != -1) sendserveropinfo(n); > if(autoteam && numcl>1) > { > putint(p, SV_FORCETEAM); > putint(p, freeteam()); > } > if(m_mp(smode)) > { > if(!canspawn(c, true)) > { > putint(p, SV_FORCEDEATH); > putint(p, n); > sendf(-1, 1, "ri2x", SV_FORCEDEATH, n, n); > } > else > { > clientstate &gs = c->state; > spawnstate(c); > putint(p, SV_SPAWNSTATE); > putint(p, gs.lifesequence); > putint(p, gs.health); > putint(p, gs.armour); > putint(p, gs.primary); > putint(p, gs.gunselect); > loopi(NUMGUNS) putint(p, gs.ammo[i]); > loopi(NUMGUNS) putint(p, gs.mag[i]); > } > } > if(clients.length()>1) > { > putint(p, SV_RESUME); > loopv(clients) > { > client &c = *clients[i]; > if(c.type!=ST_TCPIP || c.clientnum==n) continue; > putint(p, c.clientnum); > putint(p, c.state.state); > putint(p, c.state.lifesequence); > putint(p, c.state.gunselect); > putint(p, c.state.flagscore); > putint(p, c.state.frags); > } > putint(p, -1); > } > putint(p, SV_SERVOPCMD); > putint(p, SOPCMD_AUTOTEAM); > putint(p, autoteam); > if(motd) > { > putint(p, SV_TEXT); > sendstring(motd, p); > } > enet_packet_resize(packet, p.length()); > sendpacket(n, 1, packet); > if(smapname[0] && m_ctf) loopi(2) sendflaginfo(i, -1, n); > } > 782c1266 < static int servtypes[] = { SV_INITS2C, SV_MAPRELOAD, SV_SERVMSG, SV_ITEMACC, SV_ITEMSPAWN, SV_TIMEUP, SV_CDIS, SV_PONG, SV_RESUME, SV_FLAGINFO, SV_ARENASPAWN, SV_ARENAWIN, SV_CLIENT }; --- > static int servtypes[] = { SV_INITS2C, SV_MAPRELOAD, SV_SERVMSG, SV_GIBDAMAGE, SV_DAMAGE, SV_HITPUSH, SV_SHOTFX, SV_DIED, SV_SPAWNSTATE, SV_FORCEDEATH, SV_ITEMACC, SV_ITEMSPAWN, SV_TIMEUP, SV_CDIS, SV_PONG, SV_RESUME, SV_FLAGINFO, SV_ARENAWIN, SV_CLIENT }; 799,804c1283,1284 < int nonlocalclients = numnonlocalclients(); < int primaryreason = serverpassword[0] ? DISC_WRONGPW : (mastermode!=MM_OPEN ? DISC_MASTERMODE : (nonlocalclients>maxclients ? DISC_MAXCLIENTS : (isbanned(sender) ? DISC_MBAN : DISC_NONE))); < < if(primaryreason == DISC_NONE) cl->isauthed = true; < else if(chan==0) return; < else if(chan!=1 || getint(p)!=SV_PWD) disconnect_client(sender, primaryreason); --- > if(chan==0) return; > else if(chan!=1 || getint(p)!=SV_CONNECT) disconnect_client(sender, DISC_TAGT); 806a1287 > int nonlocalclients = numnonlocalclients(); 808c1289,1290 < if(adminpasswd[0] && !strcmp(text, adminpasswd)) // pass admins always through --- > cl->state.nextprimary = getint(p); > if(adminpasswd && adminpasswd[0] && !strcmp(text, adminpasswd)) // pass admins always through 813c1295 < if(nonlocalclients>maxclients) for(int i = 0; i < nonlocalclients; i++) if(i != sender && clients[i]->type==ST_TCPIP) --- > if(nonlocalclients>maxclients) loopi(nonlocalclients) if(i != sender && clients[i]->type==ST_TCPIP) 826c1308,1309 < else disconnect_client(sender, DISC_MBAN); --- > else if(isbanned(sender)) disconnect_client(sender, DISC_MBAN); > else cl->isauthed = true; 828a1312 > sendwelcome(sender); 840,843d1323 < case SV_PWD: < getstring(text, p); < break; < 869c1349 < clientscore *sc = findscore(*cl, false); --- > savedscore *sc = findscore(*cl, false); 872,873c1352,1353 < cl->score = *sc; < sendf(-1, 1, "ri5", SV_RESUME, sender, sc->frags, sc->flags, sc->lifesequence); --- > sc->restore(cl->state); > sendf(-1, 1, "ri8", SV_RESUME, sender, cl->state.state, cl->state.lifesequence, cl->state.gunselect, sc->flagscore, sc->frags, -1); 880d1359 < getint(p); 895c1374 < --- > 901c1380 < server_entity se = { false, 0 }; --- > server_entity se = { getint(p), false, 0 }; 913c1392,1405 < serverpickup(n, getint(p), sender); --- > if(cl->type==ST_LOCAL) serverpickup(n, sender); > else > { > gameevent &pickup = cl->events.add(); > pickup.type = GE_PICKUP; > pickup.pickup.ent = n; > } > break; > } > > case SV_WEAPCHANGE: > { > int gunselect = getint(p); > cl->state.gunselect = gunselect; 917c1409,1499 < --- > > case SV_TRYSPAWN: > if(cl->state.state!=CS_DEAD || !canspawn(cl)) break; > if(cl->state.lastdeath) cl->state.respawn(); > sendspawn(cl); > break; > > case SV_SPAWN: > { > int ls = getint(p), gunselect = getint(p); > if(cl->state.state!=CS_DEAD || ls!=cl->state.lifesequence || !canspawn(cl)) break; > if(cl->state.lastdeath) cl->state.respawn(); > cl->state.state = CS_ALIVE; > cl->state.gunselect = gunselect; > QUEUE_MSG; > break; > } > > case SV_SUICIDE: > { > gameevent &suicide = cl->events.add(); > suicide.type = GE_SUICIDE; > break; > } > > case SV_SHOOT: > { > gameevent &shot = cl->events.add(); > shot.type = GE_SHOT; > #define seteventmillis(event) \ > { \ > if(cl->gameoffset<0) \ > { \ > cl->gameoffset = gamemillis - getint(p); \ > event.millis = gamemillis; \ > } \ > else event.millis = cl->gameoffset + getint(p); \ > } > seteventmillis(shot.shot); > shot.shot.gun = getint(p); > loopk(3) shot.shot.from[k] = getint(p)/DMF; > loopk(3) shot.shot.to[k] = getint(p)/DMF; > int hits = getint(p); > loopk(hits) > { > gameevent &hit = cl->events.add(); > hit.type = GE_HIT; > hit.hit.target = getint(p); > hit.hit.lifesequence = getint(p); > hit.hit.info = getint(p); > loopk(3) hit.hit.dir[k] = getint(p)/DNF; > } > break; > } > > case SV_EXPLODE: > { > gameevent &exp = cl->events.add(); > exp.type = GE_EXPLODE; > seteventmillis(exp.explode); > exp.explode.gun = getint(p); > int hits = getint(p); > loopk(hits) > { > gameevent &hit = cl->events.add(); > hit.type = GE_HIT; > hit.hit.target = getint(p); > hit.hit.lifesequence = getint(p); > hit.hit.dist = getint(p)/DMF; > loopk(3) hit.hit.dir[k] = getint(p)/DNF; > } > break; > } > > case SV_AKIMBO: > { > gameevent &akimbo = cl->events.add(); > akimbo.type = GE_AKIMBO; > seteventmillis(akimbo.akimbo); > break; > } > > case SV_RELOAD: > { > gameevent &reload = cl->events.add(); > reload.type = GE_RELOAD; > seteventmillis(reload.reload); > reload.reload.gun = getint(p); > break; > } > 933c1515 < loopi(3) clients[cn]->pos[i] = getuint(p); --- > loopi(3) clients[cn]->state.o[i] = getuint(p)/DMF; 999,1004d1580 < case SV_FRAGS: < cl->score.frags = getint(p); < if(cl->score.frags < scorethreshold) disconnect_client(sender, DISC_AUTOKICK); < QUEUE_MSG; < break; < 1006c1582 < cl->score.flags = getint(p); --- > cl->state.flagscore = getint(p); 1010,1016d1585 < case SV_GIBDIED: < case SV_DIED: < getint(p); < if(m_arena) cl->arenadeath = true; < cl->score.lifesequence++; < QUEUE_MSG; < break; 1030,1083d1598 < void send_welcome(int n) < { < ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); < ucharbuf p(packet->data, packet->dataLength); < putint(p, SV_INITS2C); < putint(p, n); < putint(p, PROTOCOL_VERSION); < if(!smapname[0] && configsets.length()) nextcfgset(false); < int numcl = numclients(); < putint(p, smapname[0] ? numcl : -1); < putint(p, serverpassword[0] ? 1 : 0); < if(smapname[0]) < { < putint(p, SV_MAPCHANGE); < sendstring(smapname, p); < putint(p, smode); < if(!configsets.length() || numcl > 1) < { < putint(p, SV_ITEMLIST); < loopv(sents) if(sents[i].spawned) putint(p, i); < putint(p, -1); < } < } < if(clients[n]->type == ST_TCPIP && serveroperator() != -1) sendserveropinfo(n); < loopv(clients) < { < client &c = *clients[i]; < if(c.type!=ST_TCPIP || c.clientnum==n) continue; < if(!c.score.frags && !c.score.flags) continue; < putint(p, SV_RESUME); < putint(p, c.clientnum); < putint(p, c.score.frags); < putint(p, c.score.flags); < putint(p, c.score.lifesequence); < } < if(autoteam && numcl>1) < { < putint(p, SV_FORCETEAM); < putint(p, freeteam()); < } < putint(p, SV_SERVOPCMD); < putint(p, SOPCMD_AUTOTEAM); < putint(p, autoteam); < if(motd) < { < putint(p, SV_TEXT); < sendstring(motd, p); < } < enet_packet_resize(packet, p.length()); < sendpacket(n, 1, packet); < if(smapname[0] && m_ctf) loopi(2) sendflaginfo(i, -1, n); < if(m_arena && numcl<=2) clients[n]->arenadeath = false; < } < 1106c1621 < if(!minremain) --- > if(minremain>0) 1108,1109c1623,1624 < interm = lastsec+10; < mapend = lastsec+1000; --- > minremain = gamemillis>=gamelimit ? 0 : (gamelimit - gamemillis + 60000 - 1)/60000; > sendf(-1, 1, "ri2", SV_TIMEUP, minremain); 1111c1626 < sendf(-1, 1, "rii", SV_TIMEUP, minremain--); --- > if(!interm && minremain<=0) interm = gamemillis+10000; 1136c1651,1653 < void serverslice(int seconds, unsigned int timeout) // main server update, called from cube main loop in sp, or dedicated server loop --- > static int servmillis = 0; > > void serverslice(uint timeout) // main server update, called from cube main loop in sp, or dedicated server loop 1138c1655,1664 < loopv(sents) // spawn entities when timer reached --- > #ifdef STANDALONE > int nextmillis = (int)enet_time_get(); > #else > int nextmillis = isdedicated ? (int)enet_time_get() : lastmillis; > #endif > int diff = nextmillis - servmillis; > gamemillis += diff; > servmillis = nextmillis; > > if(minremain>0) 1140c1666,1668 < if(sents[i].spawnsecs && (sents[i].spawnsecs -= seconds-lastsec)<=0) --- > processevents(); > checkitemspawns(diff); > if(m_ctf) loopi(2) 1142,1144c1670,1671 < sents[i].spawnsecs = 0; < sents[i].spawned = true; < sendf(-1, 1, "rii", SV_ITEMSPAWN, i); --- > sflaginfo &f = sflaginfos[i]; > if(f.state==CTFF_DROPPED && gamemillis-f.lastupdate>30000) flagaction(i, SV_FLAGRESET, -1); 1145a1673 > if(m_arena) arenacheck(); 1147,1155d1674 < < if(m_ctf) loopi(2) < { < sflaginfo &f = sflaginfos[i]; < if(f.state==CTFF_DROPPED && seconds-f.lastupdate>30) flagaction(i, SV_FLAGRESET, -1); < } < if(m_arena) arenacheck(seconds); < < lastsec = seconds; 1159,1160c1678,1680 < if((smode>1 || (smode==0 && nonlocalclients)) && seconds>mapend-minremain*60) checkintermission(); < if(interm && seconds>interm) --- > if((smode>1 || (gamemode==0 && nonlocalclients)) && gamemillis-diff>0 && gamemillis/60000!=(gamemillis-diff)/60000) > checkintermission(); > if(interm && gamemillis>interm) 1177c1697 < serverms(smode, numclients(), minremain, smapname, seconds); --- > serverms(smode, numclients(), minremain, smapname, servmillis); 1179c1699 < if(seconds-laststatus>60) // display bandwidth stats, useful for server ops --- > if(servmillis-laststatus>60*1000) // display bandwidth stats, useful for server ops 1181c1701 < laststatus = seconds; --- > laststatus = servmillis; 1206d1725 < send_welcome(c.clientnum); 1238a1758 > #ifndef STANDALONE 1249c1769 < send_welcome(c.clientnum); --- > sendintro(); 1250a1771 > #endif 1282c1803 < for(;;) serverslice(/*enet_time_get_sec()*/time(NULL), 5); --- > for(;;) serverslice(5); Index: serverms.cpp =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/serverms.cpp,v retrieving revision 1.19 diff -r1.19 serverms.cpp 76c76 < int updmaster = 0; --- > int lastupdmaster = 0; 82c82 < void updatemasterserver(int seconds) --- > void updatemasterserver(int millis) 84c84 < if(seconds>updmaster) // send alive signal to masterserver every hour of uptime --- > if(millis/(60*60*1000)!=lastupdmaster) // send alive signal to masterserver every hour of uptime 92c92 < updmaster = seconds+60*60; --- > lastupdmaster = millis/(60*60*1000); 153c153 < void serverms(int mode, int numplayers, int minremain, char *smapname, int seconds) --- > void serverms(int mode, int numplayers, int minremain, char *smapname, int millis) 156c156 < updatemasterserver(seconds); --- > updatemasterserver(millis); Index: sound.cpp =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/sound.cpp,v retrieving revision 1.34 diff -r1.34 sound.cpp 210d209 < if(demoplayback) return; Index: tools.h =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/tools.h,v retrieving revision 1.26 diff -r1.26 tools.h 187,208d180 < < void forcelen(int nl) < { < len = nl < 0 ? 0 : (nl > maxlen ? maxlen : nl); < flags = 0; < } < < void forcemaxlen(int nl) < { < maxlen = nl < 0 ? 0 : nl; < flags = 0; < } < < int advance(int sz) < { < sz = min(sz, maxlen-len); < len += sz; < return sz; < } < < T* current() { return buf + len; } < Index: weapon.cpp =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/weapon.cpp,v retrieving revision 1.128 diff -r1.128 weapon.cpp 6,9d5 < struct guninfo { short sound, reload, reloadtime, attackdelay, damage, projspeed, part, spread, recoil, magsize, mdl_kick_rot, mdl_kick_back; bool isauto; }; < < const int SGRAYS = 21; //down from 21, must be 32 or less (default) < const float SGSPREAD = 2; 14,24d9 < guninfo guns[NUMGUNS] = < { < { S_KNIFE, S_NULL, 0, 500, 50, 0, 0, 1, 1, 1, 0, 0, false }, < { S_PISTOL, S_RPISTOL, 1400, 170, 19, 0, 0, 80, 10, 8, 6, 5, false }, // *SGRAYS < { S_SHOTGUN, S_RSHOTGUN, 2400, 1000, 5, 0, 0, 1, 35, 7, 9, 9, false }, //reload time is for 1 shell from 7 too powerful to 6 < { S_SUBGUN, S_RSUBGUN, 1650, 80, 16, 0, 0, 70, 15, 30, 1, 2, true }, < { S_SNIPER, S_RSNIPER, 1950, 1500, 85, 0, 0, 60, 50, 5, 4, 4, false }, < { S_ASSAULT, S_RASSAULT, 2000, 130, 24, 0, 0, 20, 40, 15, 0, 2, true }, //recoil was 44 < { S_NULL, S_NULL, 1000, 1200, 150, 20, 6, 1, 1, 1, 3, 1, false }, < }; < 26d10 < bool gun_changed = false; 34c18 < gun_changed = true; --- > addmsg(SV_WEAPCHANGE, "ri", player1->gunselect); 117d100 < if(demoplayback) { setvar("gamespeed", getvar("gamespeed") != 100 ? 100 : 35); return; } 130,132d112 < < if(has_akimbo(d)) numbullets = guns[d->gunselect].magsize * 2 - d->mag[d->gunselect]; < 139a120,121 > > if(d==player1) addmsg(SV_RELOAD, "ri2", lastmillis, d->gunselect); 145,150d126 < int reloadtime(int gun) { return guns[gun].reloadtime; } < int attackdelay(int gun) { return guns[gun].attackdelay; } < int magsize(int gun) { return guns[gun].magsize; } < int kick_rot(int gun) { return guns[gun].mdl_kick_rot; } < int kick_back(int gun) { return guns[gun].mdl_kick_back; } < 164c140 < bool intersect(dynent *d, vec &from, vec &to, vec *end) // if lineseg hits entity bounding box --- > static inline bool intersect(const vec &o, const vec &rad, const vec &from, const vec &to, vec *end) // if lineseg hits entity bounding box 166c142,143 < vec v = to, w = d->o, *p; --- > const vec *p; > vec v = to, w = o; 184,189c161,187 < return p->x <= d->o.x+d->radius < && p->x >= d->o.x-d->radius < && p->y <= d->o.y+d->radius < && p->y >= d->o.y-d->radius < && p->z <= d->o.z+d->aboveeye < && p->z >= d->o.z-d->eyeheight; --- > if(p->x <= o.x+rad.x > && p->x >= o.x-rad.x > && p->y <= o.y+rad.y > && p->y >= o.y-rad.y > && p->z <= o.z+rad.z > && p->z >= o.z-rad.z) > { > if(end) *end = *p; > return true; > } > return false; > } > > bool intersect(dynent *d, const vec &from, const vec &to, vec *end) > { > vec o(d->o); > o.z += (d->aboveeye - d->eyeheight)/2; > return intersect(o, vec(d->radius, d->radius, (d->aboveeye + d->eyeheight)/2), from, to, end); > } > > bool intersect(entity *e, const vec &from, const vec &to, vec *end) > { > mapmodelinfo &mmi = getmminfo(e->attr2); > if(!&mmi || !mmi.h) return false; > > float lo = float(S(e->x, e->y)->floor+mmi.zoff+e->attr3); > return intersect(vec(e->x, e->y, lo+mmi.h/2.0f), vec(mmi.rad, mmi.rad, mmi.h/2.0f), from, to, end); 192c190 < playerent *intersectclosest(vec &from, vec &to, int &n, playerent *at) --- > playerent *intersectclosest(vec &from, vec &to, playerent *at) 200d197 < n = getclientnum(); 212d208 < n = i; 220,222c216 < if(demoplayback) return NULL; < int n; < return intersectclosest(player1->o, worldpos, n, player1); --- > return intersectclosest(player1->o, worldpos, player1); 225,227c219,220 < const int MAXPROJ = 100; < struct projectile { vec o, to; float speed; playerent *owner; int gun; bool inuse, local; }; < projectile projs[MAXPROJ]; --- > struct projectile { vec o, to; float speed; playerent *owner; int gun; bool local; }; > vector projs; 229c222 < void projreset() { loopi(MAXPROJ) projs[i].inuse = false; } --- > void projreset() { projs.setsize(0); } 233,245c226,232 < loopi(MAXPROJ) < { < projectile *p = &projs[i]; < if(p->inuse) continue; < p->inuse = true; < p->o = from; < p->to = to; < p->speed = speed; < p->local = local; < p->owner = owner; < p->gun = gun; < return; < } --- > projectile &p = projs.add(); > p.o = from; > p.to = to; > p.speed = speed; > p.local = local; > p.owner = owner; > p.gun = gun; 248c235,240 < void hit(int target, int damage, playerent *d, playerent *at, bool gib=false) --- > void removeprojectiles(playerent *owner) > { > loopv(projs) if(projs[i].owner==owner) projs.remove(i--); > } > > void damageeffect(int damage, playerent *d) 250c242,256 < if(d==player1 || d->type==ENT_BOT) dodamage(damage, -1, at, gib, d); --- > particle_splash(3, damage/10, 1000, d->o); > } > > struct hitmsg > { > int target, lifesequence, info; > ivec dir; > }; > vector hits; > > void hit(int damage, playerent *d, playerent *at, const vec &vel, int gun, bool gib, int info) > { > if(d==player1 || d->type==ENT_BOT || !m_mp(gamemode)) d->hitpush(damage, vel, at, gun); > > if(!m_mp(gamemode)) dodamage(damage, d, at, gib); 253,254c259,275 < addmsg(gib ? SV_GIBDAMAGE : SV_DAMAGE, "ri3", target, damage, d->lifesequence); < playsound(S_PAIN1+rnd(5), &d->o); --- > hitmsg &h = hits.add(); > h.target = d->clientnum; > h.lifesequence = d->lifesequence; > h.info = info; > if(d==player1) > { > h.dir = ivec(0, 0, 0); > d->damageroll(damage); > damageblend(damage); > playsound(S_PAIN6); > } > else > { > h.dir = ivec(int(vel.x*DNF), int(vel.y*DNF), int(vel.z*DNF)); > damageeffect(damage, d); > playsound(S_PAIN1+rnd(5), &d->o); > } 256,257d276 < particle_splash(3, damage/10, 1000, d->o); < demodamage(damage, d->o); 260c279,285 < const float RL_DAMRAD = 10; --- > void hitpush(int damage, playerent *d, playerent *at, vec &from, vec &to, int gun, bool gib, int info) > { > vec v(to); > v.sub(from); > v.normalize(); > hit(damage, d, at, v, gun, gib, info); > } 262c287,297 < void radialeffect(playerent *o, vec &v, int cn, int qdam, playerent *at) --- > float expdist(playerent *o, vec &dir, const vec &v) > { > vec middle = o->o; > middle.z += (o->aboveeye-o->eyeheight)/2; > float dist = middle.dist(v, dir); > dir.div(dist); > if(dist<0) dist = 0; > return dist; > } > > void radialeffect(playerent *o, vec &v, int qdam, playerent *at, int gun) 265,268c300,302 < vec temp; < float dist = o->o.dist(v, temp); < dist -= 2; // account for eye distance imprecision < if(dist vec dir; > float dist = expdist(o, dir, v); > if(distvel.add(temp.mul((RL_DAMRAD-dist)*damage/800)); --- > int damage = (int)(qdam*(1-dist/EXPDAMRAD)); > hit(damage, o, at, dir, gun, true, int(dist*DMF)); 277c309 < void splash(projectile *p, vec &v, vec &vold, int notthisplayer, int qdam) --- > void splash(projectile &p, vec &v, vec &vold, playerent *notthis, int qdam) 280,281c312 < p->inuse = false; < if(p->gun!=GUN_GRENADE) --- > if(p.gun!=GUN_GRENADE) 291,293c322,324 < dodynlight(vold, v, 0, 0, p->owner); < if(!p->local) return; < radialeffect(player1, v, -1, qdam, p->owner); --- > dodynlight(vold, v, 0, 0, p.owner); > if(!p.local) return; > radialeffect(player1, v, qdam, p.owner, p.gun); 296d326 < if(i==notthisplayer) continue; 298,299c328,329 < if(!o) continue; < radialeffect(o, v, i, qdam, p->owner); --- > if(!o || o==notthis) continue; > radialeffect(o, v, qdam, p.owner, p.gun); 304c334 < inline void projdamage(playerent *o, projectile *p, vec &v, int i, int qdam) --- > bool projdamage(playerent *o, projectile &p, vec &v, int qdam) 306,311c336,341 < if(o->state!=CS_ALIVE) return; < if(intersect(o, p->o, v)) < { < splash(p, v, p->o, i, qdam); < hit(i, qdam, o, p->owner, true); //fixme < } --- > if(o->state!=CS_ALIVE || !intersect(o, p.o, v)) return false; > splash(p, v, p.o, o, qdam); > vec dir; > expdist(o, dir, v); > hit(qdam, o, p.owner, dir, p.gun, true, 0); > return true; 316c346 < loopi(MAXPROJ) --- > loopv(projs) 318,321c348,349 < projectile *p = &projs[i]; < if(!p->inuse) continue; < //int qdam = guns[p->gun].damage*(p->owner->quadmillis ? 4 : 1); < int qdam = guns[p->gun].damage; --- > projectile &p = projs[i]; > int qdam = guns[p.gun].damage; 323,324c351,352 < float dist = p->to.dist(p->o, v); < float dtime = dist*1000/p->speed; --- > float dist = p.to.dist(p.o, v); > float dtime = dist*1000/p.speed; 326,327c354,357 < v.mul(time/dtime).add(p->o); < if(p->local) --- > v.mul(time/dtime).add(p.o); > bool exploded = false; > hits.setsizenodelete(0); > if(p.local) 332,333c362,363 < if(!o) continue; < projdamage(o, p, v, j, qdam); --- > if(!o || p.owner==o || o->o.reject(v, 10.0f)) continue; > if(projdamage(o, p, v, qdam)) exploded = true; 335c365 < if(p->owner!=player1) projdamage(player1, p, v, -1, qdam); --- > if(p.owner!=player1 && projdamage(player1, p, v, qdam)) exploded = true; 337c367 < if(p->inuse) --- > if(!exploded) 339c369,373 < if(time==dtime) splash(p, v, p->o, -1, qdam); --- > if(time==dtime) > { > splash(p, v, p.o, NULL, qdam); > exploded = true; > } 342,343c376,377 < if(p->gun==GUN_GRENADE) { dodynlight(p->o, v, 0, 255, p->owner); particle_splash(5, 2, 200, v); } < else { particle_splash(1, 1, 200, v); particle_splash(guns[p->gun].part, 1, 1, v); } --- > if(p.gun==GUN_GRENADE) { dodynlight(p.o, v, 0, 255, p.owner); particle_splash(5, 2, 200, v); } > else { particle_splash(1, 1, 200, v); particle_splash(guns[p.gun].part, 1, 1, v); } 346,347c380,381 < TraceLine(p->o, v, p->owner, true, &tr); < if (tr.collided) splash(p, v, p->o, -1, qdam); --- > TraceLine(p.o, v, p.owner, true, &tr); > if(tr.collided) splash(p, v, p.o, NULL, qdam); 351c385,391 < p->o = v; --- > if(exploded) > { > addmsg(SV_EXPLODE, "ri2iv", lastmillis, p.gun, > hits.length(), hits.length()*sizeof(hitmsg)/sizeof(int), hits.getbuf()); > projs.remove(i--); > } > else p.o = v; 363a404,408 > void removebounceents(playerent *owner) > { > loopv(bounceents) if(bounceents[i]->owner==owner) { delete bounceents[i]; bounceents.remove(i--); } > } > 476c521 < addmsg(SV_SHOT, "ri8", d->gunselect, (int)(d->o.x*DMF), (int)(d->o.y*DMF), (int)(d->o.z*DMF), (int)(vel.x*DMF), (int)(vel.y*DMF), (int)(vel.z*DMF), lastmillis-p->millis); --- > addmsg(SV_THROWNADE, "ri7", int(d->o.x*DMF), int(d->o.y*DMF), int(d->o.z*DMF), int(vel.x*DMF), int(vel.y*DMF), int(vel.z*DMF), lastmillis-p->millis); 501c546 < if(d==player1 && !demoplayback) playsoundc(S_GRENADEPULL); --- > if(d==player1) playsoundc(S_GRENADEPULL); 545c589 < if(d!=player1 || demoplayback) --- > if(d!=player1) 564,572d607 < void hitpush(int target, int damage, playerent *d, playerent *at, vec &from, vec &to, bool gib = false) < { < hit(target, damage, d, at, gib); < vec v; < float dist = to.dist(from, v); < v.mul(damage/dist/50); < d->vel.add(v); < } < 583c618 < int i = -1, gdam = guns[d->gunselect].damage; --- > int gdam = guns[d->gunselect].damage; 589d623 < int n = -1; 593c627 < int damage = 0; --- > int hitrays = 0; 595c629 < loop(r, SGRAYS) if((done&(1< loop(r, SGRAYS) if((done&(1< hitrays++; 602d635 < i = n; 607c640 < if(damage) hitpush(i, damage, o, d, from, to); --- > if(hitrays) hitpush(hitrays*gdam, o, d, from, to, d->gunselect, false, hitrays); 611c644 < else if((o = intersectclosest(from, to, i, d))) --- > else if((o = intersectclosest(from, to, d))) 623c656 < hitpush(i, gdam, o, d, from, to, gib); --- > hitpush(gdam, o, d, from, to, d->gunselect, gib, gib ? 1 : 0); 631c664 < if (d->gunselect==GUN_KNIFE || d->gunselect==GUN_GRENADE) return; --- > if(d->gunselect==GUN_KNIFE || d->gunselect==GUN_GRENADE) return; 684d716 < const int grenadepulltime = 650; 715c747 < d->gunwait = grenadepulltime; --- > d->gunwait = attackdelay(d->gunselect); 717a750,754 > > addmsg(SV_SHOOT, "ri2i6i", lastmillis, d->gunselect, > (int)(from.x*DMF), (int)(from.y*DMF), (int)(from.z*DMF), > (int)(to.x*DMF), (int)(to.y*DMF), (int)(to.z*DMF), > 0); 719c756 < else if(!d->attacking && d->inhandnade && attacktime>grenadepulltime) thrownade(d, d->inhandnade); --- > else if(!d->attacking && d->inhandnade && attacktime>attackdelay(d->gunselect)) thrownade(d, d->inhandnade); 761a799,802 > > hits.setsizenodelete(0); > > if(!guns[d->gunselect].projspeed) raydamage(from, to, d); 763,764c804,805 < if(has_akimbo(d)) d->gunwait = guns[d->gunselect].attackdelay / 2; //make akimbo pistols shoot twice as fast as normal pistol < else d->gunwait = guns[d->gunselect].attackdelay; --- > d->gunwait = attackdelay(d->gunselect); > if(has_akimbo(d)) d->gunwait /= 2; // make akimbo pistols shoot twice as fast as normal pistol 767,771c808,814 < if(d->type==ENT_PLAYER) addmsg(SV_SHOT, "ri8", d->gunselect, (int)(from.x*DMF), (int)(from.y*DMF), (int)(from.z*DMF), (int)(to.x*DMF), (int)(to.y*DMF), (int)(to.z*DMF), 0); < < if(guns[d->gunselect].projspeed || d->gunselect==GUN_GRENADE) return; < < raydamage(from, to, d); --- > if(d==player1) > { > addmsg(SV_SHOOT, "ri2i6iv", lastmillis, d->gunselect, > (int)(from.x*DMF), (int)(from.y*DMF), (int)(from.z*DMF), > (int)(to.x*DMF), (int)(to.y*DMF), (int)(to.z*DMF), > hits.length(), hits.length()*sizeof(hitmsg)/sizeof(int), hits.getbuf()); > } 772a816 > Index: worldio.cpp =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/worldio.cpp,v retrieving revision 1.35 diff -r1.35 worldio.cpp 213d212 < stopifrecording(); Index: bot/ac_bot.cpp =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/bot/ac_bot.cpp,v retrieving revision 1.27 diff -r1.27 ac_bot.cpp 17d16 < extern vector sents; Index: bot/ac_bot_ai.cpp =================================================================== RCS file: /cvsroot/actiongame/ac/source/src/bot/ac_bot_ai.cpp,v retrieving revision 1.14 diff -r1.14 ac_bot_ai.cpp 134c134 < sMaxAmmo = itemstats[GUN_PISTOL].max; --- > sMaxAmmo = ammostats[GUN_PISTOL].max; 139c139 < sMaxAmmo = itemstats[m_pMyEnt->primary].max; --- > sMaxAmmo = ammostats[m_pMyEnt->primary].max; 144c144 < sMaxAmmo = itemstats[GUN_GRENADE].max; --- > sMaxAmmo = ammostats[GUN_GRENADE].max; 149c149 < sMaxAmmo = itemstats[7].max; //FIXME --- > sMaxAmmo = powerupstats[I_HEALTH-I_HEALTH].max; //FIXME 154c154 < sMaxAmmo = itemstats[8].max; // FIXME --- > sMaxAmmo = powerupstats[I_ARMOUR-I_HEALTH].max; // FIXME