Advertisement
Guest User

Untitled

a guest
Jul 11th, 2010
253
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 33.25 KB | None | 0 0
  1. // clientgame.cpp: core game related stuff
  2.  
  3. #include "pch.h"
  4. #include "cube.h"
  5. #include "bot/bot.h"
  6.  
  7. int nextmode = 0; // nextmode becomes gamemode after next map load
  8. VAR(gamemode, 1, 0, 0);
  9. VARP(modeacronyms, 0, 0, 1);
  10.  
  11. flaginfo flaginfos[2];
  12.  
  13. void mode(int n)
  14. {
  15. nextmode = n;
  16. if(m_mp(n) || !multiplayer()) addmsg(SV_GAMEMODE, "ri", n);
  17. }
  18. COMMAND(mode, ARG_1INT);
  19.  
  20. bool intermission = false;
  21. bool autoteambalance = false;
  22. int arenaintermission = 0;
  23.  
  24. playerent *player1 = newplayerent(); // our client
  25. vector<playerent *> players; // other clients
  26.  
  27. int lastmillis = 0, totalmillis = 0;
  28. int curtime = 0;
  29. string clientmap;
  30.  
  31. extern int framesinmap;
  32.  
  33. char *getclientmap() { return clientmap; }
  34.  
  35. extern bool c2sinit, senditemstoserver;
  36.  
  37. void setskin(playerent *pl, uint skin)
  38. {
  39. if(!pl) return;
  40. if(pl == player1) c2sinit=false;
  41. const int maxskin[2] = { 3, 5 };
  42. pl->skin = skin % (maxskin[team_int(pl->team)]+1);
  43. }
  44.  
  45. bool duplicatename(playerent *d, char *name = NULL)
  46. {
  47. if(!name) name = d->name;
  48. if(d!=player1 && !strcmp(name, player1->name)) return true;
  49. if(!strcmp(name, "you")) return true;
  50. loopv(players) if(players[i] && d!=players[i] && !strcmp(name, players[i]->name)) return true;
  51. return false;
  52. }
  53.  
  54. char *colorname(playerent *d, char *name, const char *prefix)
  55. {
  56. if(!name) name = d->name;
  57. if(name[0] && !duplicatename(d, name)) return name;
  58. static string cname[4];
  59. static int num = 0;
  60. num = (num + 1) % 4;
  61. s_sprintf(cname[num])("%s%s \fs\f6(%d)\fr", prefix, name, d->clientnum);
  62. return cname[num];
  63. }
  64.  
  65. char *colorping(int ping)
  66. {
  67. static string cping;
  68. if(multiplayer(false)) s_sprintf(cping)("\fs\f%d%d\fr", ping <= 500 ? 0 : ping <= 1000 ? 2 : 3, ping);
  69. else s_sprintf(cping)("%d", ping);
  70. return cping;
  71. }
  72.  
  73. char *colorpj(int pj)
  74. {
  75. static string cpj;
  76. if(multiplayer(false)) s_sprintf(cpj)("\fs\f%d%d\fr", pj <= 90 ? 0 : pj <= 170 ? 2 : 3, pj);
  77. else s_sprintf(cpj)("%d", pj);
  78. return cpj;
  79. }
  80.  
  81. void newname(const char *name)
  82. {
  83. if(name[0])
  84. {
  85. c2sinit = false;
  86. filtertext(player1->name, name, 0, MAXNAMELEN);
  87. if(!player1->name[0]) s_strcpy(player1->name, "unarmed");
  88. updateclientname(player1);
  89. }
  90. else conoutf("your name is: %s", player1->name);
  91. alias("curname", player1->name);
  92. }
  93.  
  94. int smallerteam()
  95. {
  96. int teamsize[2] = {0, 0};
  97. loopv(players) if(players[i]) teamsize[team_int(players[i]->team)]++;
  98. teamsize[team_int(player1->team)]++;
  99. if(teamsize[0] == teamsize[1]) return -1;
  100. return teamsize[0] < teamsize[1] ? 0 : 1;
  101. }
  102.  
  103. void changeteam(int team, bool respawn) // force team and respawn
  104. {
  105. c2sinit = false;
  106. if(m_flags) tryflagdrop(false);
  107. filtertext(player1->team, team_string(team), 0, MAXTEAMLEN);
  108. if(respawn) addmsg(SV_CHANGETEAM, "r");
  109. }
  110.  
  111. void newteam(char *name)
  112. {
  113. if(name[0])
  114. {
  115. if(m_teammode)
  116. {
  117. if(!strcmp(name, player1->team)) return; // same team
  118. if(player1->isspectating() && !(player1->state==CS_DEAD && player1->spectatemode == SM_DEATHCAM)) { conoutf("\f3you can not switch teams when spectating"); return; }
  119. if(!team_valid(name)) { conoutf("\f3\"%s\" is not a valid team name (try CLA or RVSF)", name); return; }
  120.  
  121. bool checkteamsize = autoteambalance && players.length() >= 1 && !m_botmode;
  122. int freeteam = smallerteam();
  123.  
  124. if(team_valid(name))
  125. {
  126. int team = team_int(name);
  127. if(checkteamsize && team != freeteam)
  128. {
  129. conoutf("\f3the %s team is already full", name);
  130. return;
  131. }
  132. changeteam(team);
  133. }
  134. else changeteam(checkteamsize ? (uint)freeteam : rnd(2)); // random assignement
  135. }
  136. }
  137. else conoutf("your team is: %s", player1->team);
  138. }
  139.  
  140. VARNP(skin, nextskin, 0, 0, 1000);
  141.  
  142. int curteam() { return team_int(player1->team); }
  143. int currole() { return player1->clientrole; }
  144. int curmode() { return gamemode; }
  145. void curmap(int cleaned) { result(cleaned ? behindpath(getclientmap()) : getclientmap()); }
  146. COMMANDN(team, newteam, ARG_1STR);
  147. COMMANDN(name, newname, ARG_1STR);
  148. COMMAND(curteam, ARG_IVAL);
  149. COMMAND(currole, ARG_IVAL);
  150. COMMAND(curmode, ARG_IVAL);
  151. COMMAND(curmap, ARG_1INT);
  152. VARP(showscoresondeath, 0, 1, 1);
  153.  
  154. void deathstate(playerent *pl)
  155. {
  156. pl->state = CS_DEAD;
  157. pl->spectatemode = SM_DEATHCAM;
  158. pl->respawnoffset = pl->lastpain = lastmillis;
  159. pl->move = pl->strafe = 0;
  160. pl->pitch = pl->roll = 0;
  161. pl->attacking = false;
  162. pl->weaponsel->onownerdies();
  163.  
  164. if(pl==player1)
  165. {
  166. if(showscoresondeath) showscores(true);
  167. setscope(false);
  168. if(editmode) toggleedit(true);
  169. damageblend(-1);
  170. }
  171. else pl->resetinterp();
  172. }
  173.  
  174. void spawnstate(playerent *d) // reset player state not persistent accross spawns
  175. {
  176. d->respawn();
  177. d->spawnstate(gamemode);
  178. if(d==player1)
  179. {
  180. if(player1->skin!=nextskin) setskin(player1, nextskin);
  181. setscope(false);
  182. }
  183. }
  184.  
  185. playerent *newplayerent() // create a new blank player
  186. {
  187. playerent *d = new playerent;
  188. d->lastupdate = totalmillis;
  189. setskin(d, rnd(6));
  190. weapon::equipplayer(d); // flowtron : avoid overwriting d->spawnstate(gamemode) stuff from the following line (this used to be called afterwards)
  191. spawnstate(d);
  192. return d;
  193. }
  194.  
  195. botent *newbotent() // create a new blank player
  196. {
  197. botent *d = new botent;
  198. d->lastupdate = totalmillis;
  199. setskin(d, rnd(6));
  200. spawnstate(d);
  201. weapon::equipplayer(d);
  202. loopv(players) if(i!=getclientnum() && !players[i])
  203. {
  204. players[i] = d;
  205. d->clientnum = i;
  206. return d;
  207. }
  208. if(players.length()==getclientnum()) players.add(NULL);
  209. d->clientnum = players.length();
  210. players.add(d);
  211. return d;
  212. }
  213.  
  214. void freebotent(botent *d)
  215. {
  216. loopv(players) if(players[i]==d)
  217. {
  218. DELETEP(players[i]);
  219. players.remove(i);
  220. }
  221. }
  222.  
  223. void zapplayer(playerent *&d)
  224. {
  225. DELETEP(d);
  226. }
  227.  
  228. void movelocalplayer()
  229. {
  230. if(player1->state==CS_DEAD && !player1->allowmove())
  231. {
  232. if(lastmillis-player1->lastpain<2000)
  233. {
  234. player1->move = player1->strafe = 0;
  235. moveplayer(player1, 10, false);
  236. }
  237. }
  238. else if(!intermission)
  239. {
  240. moveplayer(player1, 10, true);
  241. checkitems(player1);
  242. }
  243. }
  244.  
  245. // use physics to extrapolate player position
  246. VARP(smoothmove, 0, 75, 100);
  247. VARP(smoothdist, 0, 8, 16);
  248.  
  249. void predictplayer(playerent *d, bool move)
  250. {
  251. d->o = d->newpos;
  252. d->o.z += d->eyeheight;
  253. d->yaw = d->newyaw;
  254. d->pitch = d->newpitch;
  255. if(move)
  256. {
  257. moveplayer(d, 1, false);
  258. d->newpos = d->o;
  259. d->newpos.z -= d->eyeheight;
  260. }
  261. float k = 1.0f - float(lastmillis - d->smoothmillis)/smoothmove;
  262. if(k>0)
  263. {
  264. d->o.add(vec(d->deltapos).mul(k));
  265. d->yaw += d->deltayaw*k;
  266. if(d->yaw<0) d->yaw += 360;
  267. else if(d->yaw>=360) d->yaw -= 360;
  268. d->pitch += d->deltapitch*k;
  269. }
  270. }
  271.  
  272. void moveotherplayers()
  273. {
  274. loopv(players) if(players[i] && players[i]->type==ENT_PLAYER)
  275. {
  276. playerent *d = players[i];
  277. const int lagtime = totalmillis-d->lastupdate;
  278. if(!lagtime || intermission) continue;
  279. else if(lagtime>1000 && d->state==CS_ALIVE)
  280. {
  281. d->state = CS_LAGGED;
  282. continue;
  283. }
  284. if(d->state==CS_ALIVE || d->state==CS_EDITING)
  285. {
  286. if(smoothmove && d->smoothmillis>0) predictplayer(d, true);
  287. else moveplayer(d, 1, false);
  288. }
  289. else if(d->state==CS_DEAD && lastmillis-d->lastpain<2000) moveplayer(d, 1, true);
  290. }
  291. }
  292.  
  293.  
  294. bool showhudtimer(int maxsecs, int startmillis, const char *msg, bool flash)
  295. {
  296. static string str = "";
  297. static int tickstart = 0, curticks = -1, maxticks = -1;
  298. int nextticks = (lastmillis - startmillis) / 200;
  299. if(tickstart!=startmillis || maxticks != 5*maxsecs)
  300. {
  301. tickstart = startmillis;
  302. maxticks = 5*maxsecs;
  303. curticks = -1;
  304. s_strcpy(str, "\f3");
  305. }
  306. if(curticks >= maxticks) return false;
  307. nextticks = min(nextticks, maxticks);
  308. while(curticks < nextticks)
  309. {
  310. if(++curticks%5) s_strcat(str, ".");
  311. else
  312. {
  313. s_sprintfd(sec)("%d", maxsecs - (curticks/5));
  314. s_strcat(str, sec);
  315. }
  316. }
  317. if(nextticks < maxticks) hudeditf(HUDMSG_TIMER|HUDMSG_OVERWRITE, flash ? str : str+2);
  318. else hudeditf(HUDMSG_TIMER, msg);
  319. return true;
  320. }
  321.  
  322. int lastspawnattempt = 0;
  323.  
  324. void showrespawntimer()
  325. {
  326. if(intermission) return;
  327. if(m_arena)
  328. {
  329. if(!arenaintermission) return;
  330. showhudtimer(5, arenaintermission, "FIGHT!", lastspawnattempt >= arenaintermission && lastmillis < lastspawnattempt+100);
  331. }
  332. else if(player1->state==CS_DEAD && m_flags && (!player1->isspectating() || player1->spectatemode==SM_DEATHCAM))
  333. {
  334. int secs = 5;
  335. showhudtimer(secs, player1->respawnoffset, "READY!", lastspawnattempt >= arenaintermission && lastmillis < lastspawnattempt+100);
  336. }
  337. }
  338.  
  339. struct scriptsleep { int wait; char *cmd; };
  340. vector<scriptsleep> sleeps;
  341.  
  342. void addsleep(int msec, const char *cmd)
  343. {
  344. scriptsleep &s = sleeps.add();
  345. s.wait = msec+lastmillis;
  346. s.cmd = newstring(cmd);
  347. }
  348.  
  349. void addsleep_(char *msec, char *cmd)
  350. {
  351. addsleep(atoi(msec), cmd);
  352. }
  353.  
  354. void resetsleep()
  355. {
  356. loopv(sleeps) DELETEA(sleeps[i].cmd);
  357. sleeps.setsize(0);
  358. }
  359.  
  360. COMMANDN(sleep, addsleep_, ARG_2STR);
  361.  
  362. void updateworld(int curtime, int lastmillis) // main game update loop
  363. {
  364. // process command sleeps
  365. loopv(sleeps)
  366. {
  367. if(sleeps[i].wait && lastmillis > sleeps[i].wait)
  368. {
  369. char *cmd = sleeps[i].cmd;
  370. sleeps[i].cmd = NULL;
  371. execute(cmd);
  372. delete[] cmd;
  373. if(sleeps[i].cmd || !sleeps.inrange(i)) break;
  374. sleeps.remove(i--);
  375. }
  376. }
  377.  
  378. physicsframe();
  379. checkweaponswitch();
  380. checkakimbo();
  381. if(getclientnum()>=0) shoot(player1, worldpos); // only shoot when connected to server
  382. movebounceents();
  383. moveotherplayers();
  384. gets2c();
  385. showrespawntimer();
  386.  
  387. // Added by Rick: let bots think
  388. if(m_botmode) BotManager.Think();
  389.  
  390. movelocalplayer();
  391. c2sinfo(player1); // do this last, to reduce the effective frame lag
  392. }
  393.  
  394. #define SECURESPAWNDIST 15
  395. int spawncycle = -1;
  396. int fixspawn = 2;
  397.  
  398. // returns -1 for a free place, else dist to the nearest enemy
  399. float nearestenemy(vec place, char *team)
  400. {
  401. float nearestenemydist = -1;
  402. loopv(players)
  403. {
  404. playerent *other = players[i];
  405. if(!other || isteam(team, other->team)) continue;
  406. float dist = place.dist(other->o);
  407. if(dist < nearestenemydist || nearestenemydist == -1) nearestenemydist = dist;
  408. }
  409. if(nearestenemydist >= SECURESPAWNDIST || nearestenemydist < 0) return -1;
  410. else return nearestenemydist;
  411. }
  412.  
  413. void findplayerstart(playerent *d, bool mapcenter, int arenaspawn)
  414. {
  415. int r = fixspawn-->0 ? 4 : rnd(10)+1;
  416. entity *e = NULL;
  417. if(!mapcenter)
  418. {
  419. int type = m_teammode ? team_int(d->team) : 100;
  420. if(m_arena && arenaspawn >= 0)
  421. {
  422. int x = -1;
  423. loopi(arenaspawn + 1) x = findentity(PLAYERSTART, x+1, type);
  424. if(x >= 0) e = &ents[x];
  425. }
  426. else if((m_teammode || m_arena) && !m_ktf) // ktf uses ffa spawns
  427. {
  428. loopi(r) spawncycle = findentity(PLAYERSTART, spawncycle+1, type);
  429. if(spawncycle >= 0) e = &ents[spawncycle];
  430. }
  431. else
  432. {
  433. float bestdist = -1;
  434.  
  435. loopi(r)
  436. {
  437. spawncycle = m_ktf && numspawn[2] > 5 ? findentity(PLAYERSTART, spawncycle+1, 100) : findentity(PLAYERSTART, spawncycle+1);
  438. if(spawncycle < 0) continue;
  439. float dist = nearestenemy(vec(ents[spawncycle].x, ents[spawncycle].y, ents[spawncycle].z), d->team);
  440. if(!e || dist < 0 || (bestdist >= 0 && dist > bestdist)) { e = &ents[spawncycle]; bestdist = dist; }
  441. }
  442. }
  443. }
  444.  
  445. if(e)
  446. {
  447. d->o.x = e->x;
  448. d->o.y = e->y;
  449. d->o.z = e->z;
  450. d->yaw = e->attr1;
  451. d->pitch = 0;
  452. d->roll = 0;
  453. }
  454. else
  455. {
  456. d->o.x = d->o.y = (float)ssize/2;
  457. d->o.z = 4;
  458. }
  459.  
  460. entinmap(d);
  461. }
  462.  
  463. void spawnplayer(playerent *d)
  464. {
  465. d->respawn();
  466. d->spawnstate(gamemode);
  467. d->state = d==player1 && editmode ? CS_EDITING : CS_ALIVE;
  468. findplayerstart(d);
  469. }
  470.  
  471. void respawnself()
  472. {
  473. if(m_mp(gamemode)) addmsg(SV_TRYSPAWN, "r");
  474. else
  475. {
  476. showscores(false);
  477. setscope(false);
  478. spawnplayer(player1);
  479. player1->lifesequence++;
  480. player1->weaponswitch(player1->primweap);
  481. player1->weaponchanging -= weapon::weaponchangetime/2;
  482. }
  483. }
  484.  
  485. bool tryrespawn()
  486. {
  487. if(player1->state==CS_DEAD)
  488. {
  489. int respawnmillis = player1->respawnoffset+(m_arena ? 0 : (m_flags ? 5000 : 2000));
  490. if(lastmillis>respawnmillis)
  491. {
  492. player1->attacking = false;
  493. if(m_arena)
  494. {
  495. if(!arenaintermission) hudeditf(HUDMSG_TIMER, "waiting for new round to start...");
  496. else lastspawnattempt = lastmillis;
  497. return false;
  498. }
  499. respawnself();
  500. return true;
  501. }
  502. else lastspawnattempt = lastmillis;
  503. }
  504. return false;
  505. }
  506.  
  507. // damage arriving from the network, monsters, yourself, all ends up here.
  508.  
  509. void dodamage(int damage, playerent *pl, playerent *actor, bool gib, bool local)
  510. {
  511. if(pl->state != CS_ALIVE || intermission) return;
  512.  
  513. pl->respawnoffset = pl->lastpain = lastmillis;
  514. if(local) damage = pl->dodamage(damage);
  515. else if(actor==player1) return;
  516.  
  517. if(pl==player1)
  518. {
  519. updatedmgindicator(actor->o);
  520. damageblend(damage);
  521. pl->damageroll(damage);
  522. }
  523. damageeffect(damage, pl);
  524.  
  525. if(pl->health<=0) { if(local) dokill(pl, actor, gib); }
  526. else if(pl==player1) playsound(S_PAIN6, SP_HIGH);
  527. else playsound(S_PAIN1+rnd(5), pl);
  528. }
  529.  
  530. void dokill(playerent *pl, playerent *act, bool gib)
  531. {
  532. if(pl->state!=CS_ALIVE || intermission) return;
  533.  
  534. string pname, aname, death;
  535. s_strcpy(pname, pl==player1 ? "you" : colorname(pl));
  536. s_strcpy(aname, act==player1 ? "you" : colorname(act));
  537. s_strcpy(death, gib ? "gibbed" : "fragged");
  538. void (*outf)(const char *s, ...) = (pl == player1 || act == player1) ? hudoutf : conoutf;
  539.  
  540. if(pl==act)
  541. outf("\f2%s suicided%s", pname, pl==player1 ? "!" : "");
  542. else if(isteam(pl->team, act->team))
  543. {
  544. if(pl==player1) outf("\f2you got %s by teammate %s", death, aname);
  545. else outf("%s%s %s teammate %s", act==player1 ? "\f3" : "\f2", aname, death, pname);
  546. }
  547. else
  548. {
  549. if(pl==player1) outf("\f2you got %s by %s", death, aname);
  550. else outf("\f2%s %s %s", aname, death, pname);
  551. }
  552.  
  553. if(gib)
  554. {
  555. if(pl!=act && act->weaponsel->type == GUN_SNIPER) playsound(S_HEADSHOT, SP_LOW);
  556. addgib(pl);
  557. }
  558.  
  559. if(!m_mp(gamemode))
  560. {
  561. if(pl==act || isteam(pl->team, act->team)) act->frags--;
  562. else act->frags += gib ? 2 : 1;
  563. }
  564.  
  565. deathstate(pl);
  566. pl->deaths++;
  567. playsound(S_DIE1+rnd(2), pl);
  568. }
  569.  
  570. VAR(minutesremaining, 1, 0, 0);
  571.  
  572. void timeupdate(int timeremain)
  573. {
  574. minutesremaining = timeremain;
  575. if(!timeremain)
  576. {
  577. intermission = true;
  578. player1->attacking = false;
  579. conoutf("intermission:");
  580. conoutf("game has ended!");
  581. consolescores();
  582. showscores(true);
  583. if(identexists("start_intermission")) execute("start_intermission");
  584. }
  585. else
  586. {
  587. conoutf("time remaining: %d minutes", timeremain);
  588. if(timeremain==1)
  589. {
  590. musicsuggest(M_LASTMINUTE1 + rnd(2), 70*1000, true);
  591. hudoutf("1 minute left!");
  592. }
  593. }
  594. }
  595.  
  596. playerent *newclient(int cn) // ensure valid entity
  597. {
  598. if(cn<0 || cn>=MAXCLIENTS)
  599. {
  600. neterr("clientnum");
  601. return NULL;
  602. }
  603. while(cn>=players.length()) players.add(NULL);
  604. playerent *d = players[cn];
  605. if(d) return d;
  606. d = newplayerent();
  607. players[cn] = d;
  608. d->clientnum = cn;
  609. return d;
  610. }
  611.  
  612. playerent *getclient(int cn) // ensure valid entity
  613. {
  614. return players.inrange(cn) ? players[cn] : NULL;
  615. }
  616.  
  617. void initclient()
  618. {
  619. clientmap[0] = 0;
  620. newname("unarmed");
  621. changeteam(rnd(2), false);
  622. }
  623.  
  624. entity flagdummies[2] = // in case the map does not provide flags
  625. {
  626. entity(-1, -1, -1, CTF_FLAG, 0, 0, 0, 0),
  627. entity(-1, -1, -1, CTF_FLAG, 0, 1, 0, 0)
  628. };
  629.  
  630. void initflag(int i)
  631. {
  632. flaginfo &f = flaginfos[i];
  633. f.flagent = &flagdummies[i];
  634. f.pos = vec(f.flagent->x, f.flagent->y, f.flagent->z);
  635. f.ack = true;
  636. f.actor = NULL;
  637. f.actor_cn = -1;
  638. f.team = i;
  639. f.state = m_ktf ? CTFF_IDLE : CTFF_INBASE;
  640. }
  641.  
  642. void zapplayerflags(playerent *p)
  643. {
  644. loopi(2) if(flaginfos[i].state==CTFF_STOLEN && flaginfos[i].actor==p) initflag(i);
  645. }
  646.  
  647. void preparectf(bool cleanonly=false)
  648. {
  649. loopi(2) initflag(i);
  650. if(!cleanonly)
  651. {
  652. loopv(ents)
  653. {
  654. entity &e = ents[i];
  655. if(e.type==CTF_FLAG)
  656. {
  657. e.spawned = true;
  658. if(e.attr2>=2) { conoutf("\f3invalid ctf-flag entity (%i)", i); e.attr2 = 0; }
  659. flaginfo &f = flaginfos[e.attr2];
  660. f.flagent = &e;
  661. f.pos.x = (float) e.x;
  662. f.pos.y = (float) e.y;
  663. f.pos.z = (float) e.z;
  664. }
  665. }
  666. }
  667. }
  668.  
  669. struct gmdesc { int mode; char *desc; };
  670. vector<gmdesc> gmdescs;
  671.  
  672. void gamemodedesc(char *modenr, char *desc)
  673. {
  674. if(!modenr || !desc) return;
  675. struct gmdesc &gd = gmdescs.add();
  676. gd.mode = atoi(modenr);
  677. gd.desc = newstring(desc);
  678. }
  679.  
  680. COMMAND(gamemodedesc, ARG_2STR);
  681.  
  682. void resetmap()
  683. {
  684. resetsleep();
  685. clearminimap();
  686. cleardynlights();
  687. pruneundos();
  688. clearworldsounds();
  689. particlereset();
  690. setvar("gamespeed", 100);
  691. setvar("paused", 0);
  692. setvar("fog", 180);
  693. setvar("fogcolour", 0x8099B3);
  694. setvar("shadowyaw", 45);
  695. }
  696.  
  697. int suicided = -1;
  698.  
  699. void startmap(const char *name, bool reset) // called just after a map load
  700. {
  701. s_strcpy(clientmap, name);
  702. senditemstoserver = true;
  703. // Added by Rick
  704. if(m_botmode) BotManager.BeginMap(name);
  705. else kickallbots();
  706. // End add by Rick
  707. clearbounceents();
  708. resetspawns();
  709. preparectf(!m_flags);
  710. suicided = -1;
  711. spawncycle = -1;
  712. if(m_valid(gamemode) && !m_mp(gamemode)) respawnself();
  713. else findplayerstart(player1);
  714.  
  715. if(!reset) return;
  716.  
  717. player1->frags = player1->flagscore = player1->deaths = player1->lifesequence = 0;
  718. loopv(players) if(players[i]) players[i]->frags = players[i]->flagscore = players[i]->deaths = players[i]->lifesequence = 0;
  719. if(editmode) toggleedit(true);
  720. intermission = false;
  721. showscores(false);
  722. minutesremaining = -1;
  723. arenaintermission = 0;
  724. bool noflags = (m_ctf || m_ktf) && (!numflagspawn[0] || !numflagspawn[1]);
  725. if(*clientmap) conoutf("game mode is \"%s\"%s", modestr(gamemode, modeacronyms > 0), noflags ? " - \f2but there are no flag bases on this map" : "");
  726. if(multiplayer(false) || m_botmode)
  727. {
  728. loopv(gmdescs) if(gmdescs[i].mode == gamemode)
  729. {
  730. conoutf("\f1%s", gmdescs[i].desc);
  731. }
  732. }
  733.  
  734. // run once
  735. if(firstrun)
  736. {
  737. persistidents = false;
  738. execfile("config/firstrun.cfg");
  739. persistidents = true;
  740. firstrun = false;
  741. }
  742. // execute mapstart event
  743. const char *mapstartonce = getalias("mapstartonce");
  744. if(mapstartonce && mapstartonce[0])
  745. {
  746. addsleep(0, mapstartonce); // do this as a sleep to make sure map changes don't recurse inside a welcome packet
  747. alias("mapstartonce", "");
  748. }
  749. }
  750.  
  751. void suicide()
  752. {
  753. if(player1->state == CS_ALIVE && suicided!=player1->lifesequence)
  754. {
  755. addmsg(SV_SUICIDE, "r");
  756. suicided = player1->lifesequence;
  757. }
  758. }
  759.  
  760. COMMAND(suicide, ARG_NONE);
  761.  
  762. // console and audio feedback
  763.  
  764. void flagmsg(int flag, int message, int actor, int flagtime)
  765. {
  766. static int musicplaying = -1;
  767. playerent *act = getclient(actor);
  768. if(actor != getclientnum() && !act && message != FM_RESET) return;
  769. bool own = flag == team_int(player1->team);
  770. bool firstperson = actor == getclientnum();
  771. bool teammate = !act ? true : isteam(player1->team, act->team);
  772. bool firstpersondrop = false;
  773. const char *teamstr = m_ktf ? "the" : own ? "your" : "the enemy";
  774. const char *flagteam = m_ktf ? (teammate ? "your teammate " : "your enemy ") : "";
  775.  
  776. switch(message)
  777. {
  778. case FM_PICKUP:
  779. playsound(S_FLAGPICKUP, SP_HIGHEST);
  780. if(firstperson)
  781. {
  782. hudoutf("\f2you got the %sflag", m_ctf ? "enemy " : "");
  783. musicsuggest(M_FLAGGRAB, m_ctf ? 90*1000 : 900*1000, true);
  784. musicplaying = flag;
  785. }
  786. else hudoutf("\f2%s%s got %s flag", flagteam, colorname(act), teamstr);
  787. break;
  788. case FM_LOST:
  789. case FM_DROP:
  790. {
  791. const char *droplost = message == FM_LOST ? "lost" : "dropped";
  792. playsound(S_FLAGDROP, SP_HIGHEST);
  793. if(firstperson)
  794. {
  795. hudoutf("\f2you %s the flag", droplost);
  796. firstpersondrop = true;
  797. }
  798. else hudoutf("\f2%s %s %s flag", colorname(act), droplost, teamstr);
  799. break;
  800. }
  801. case FM_RETURN:
  802. playsound(S_FLAGRETURN, SP_HIGHEST);
  803. if(firstperson) hudoutf("\f2you returned your flag");
  804. else hudoutf("\f2%s returned %s flag", colorname(act), teamstr);
  805. break;
  806. case FM_SCORE:
  807. playsound(S_FLAGSCORE, SP_HIGHEST);
  808. if(firstperson)
  809. {
  810. hudoutf("\f2you scored");
  811. if(m_ctf) firstpersondrop = true;
  812. }
  813. else hudoutf("\f2%s scored for %s team", colorname(act), teammate ? "your" : "the enemy");
  814. break;
  815. case FM_KTFSCORE:
  816. {
  817. playsound(S_VOTEPASS, SP_HIGHEST); // need better ktf sound here
  818. const char *ta = firstperson ? "you have" : colorname(act);
  819. const char *tb = firstperson ? "" : " has";
  820. const char *tc = firstperson ? "" : flagteam;
  821. int m = flagtime / 60;
  822. if(m)
  823. hudoutf("\f2%s%s%s kept the flag for %d minute%s %d seconds now", tc, ta, tb, m, m == 1 ? "" : "s", flagtime % 60);
  824. else
  825. hudoutf("\f2%s%s%s kept the flag for %d seconds now", tc, ta, tb, flagtime);
  826. break;
  827. }
  828. case FM_SCOREFAIL: // sound?
  829. hudoutf("\f2%s failed to score (own team flag not taken)", firstperson ? "you" : colorname(act));
  830. break;
  831. case FM_RESET:
  832. playsound(S_FLAGRETURN, SP_HIGHEST);
  833. hudoutf("the server reset the flag");
  834. firstpersondrop = true;
  835. break;
  836. }
  837. if(firstpersondrop && flag == musicplaying)
  838. {
  839. musicfadeout(M_FLAGGRAB);
  840. musicplaying = -1;
  841. }
  842. }
  843.  
  844. void dropflag() { tryflagdrop(true); }
  845. COMMAND(dropflag, ARG_NONE);
  846.  
  847. char *votestring(int type, char *arg1, char *arg2)
  848. {
  849. const char *msgs[] = { "kick player %s", "ban player %s", "remove all bans", "set mastermode to %s", "%s autoteam", "force player %s to the enemy team", "give admin to player %s", "load map %s in mode %s", "%s demo recording for the next match", "stop demo recording", "clear all demos", "set server description to '%s'", "shuffle teams"};
  850. const char *msg = msgs[type];
  851. char *out = newstring(_MAXDEFSTR);
  852. out[_MAXDEFSTR] = '\0';
  853. switch(type)
  854. {
  855. case SA_KICK:
  856. case SA_BAN:
  857. case SA_FORCETEAM:
  858. case SA_GIVEADMIN:
  859. {
  860. int cn = atoi(arg1);
  861. playerent *p = (cn == getclientnum() ? player1 : getclient(cn));
  862. if(!p) break;
  863. s_sprintf(out)(msg, colorname(p));
  864. break;
  865. }
  866. case SA_MASTERMODE:
  867. s_sprintf(out)(msg, mmfullname(atoi(arg1)));
  868. break;
  869. case SA_AUTOTEAM:
  870. case SA_RECORDDEMO:
  871. s_sprintf(out)(msg, atoi(arg1) == 0 ? "disable" : "enable");
  872. break;
  873. case SA_MAP:
  874. s_sprintf(out)(msg, arg1, modestr(atoi(arg2), modeacronyms > 0));
  875. break;
  876. case SA_SERVERDESC:
  877. s_sprintf(out)(msg, arg1);
  878. break;
  879. default:
  880. s_sprintf(out)(msg, arg1, arg2);
  881. break;
  882. }
  883. return out;
  884. }
  885.  
  886. votedisplayinfo *newvotedisplayinfo(playerent *owner, int type, char *arg1, char *arg2)
  887. {
  888. if(type < 0 || type >= SA_NUM) return NULL;
  889. votedisplayinfo *v = new votedisplayinfo();
  890. v->owner = owner;
  891. v->type = type;
  892. v->millis = totalmillis + (30+10)*1000;
  893. char *votedesc = votestring(type, arg1, arg2);
  894. s_strcpy(v->desc, votedesc);
  895. DELETEA(votedesc);
  896. return v;
  897. }
  898.  
  899. votedisplayinfo *curvote = NULL, *calledvote = NULL;
  900.  
  901. void callvote(int type, char *arg1, char *arg2)
  902. {
  903. if(calledvote) return;
  904. votedisplayinfo *v = newvotedisplayinfo(player1, type, arg1, arg2);
  905. if(v)
  906. {
  907. calledvote = v;
  908. ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE);
  909. ucharbuf p(packet->data, packet->dataLength);
  910. putint(p, SV_CALLVOTE);
  911. putint(p, v->type);
  912. switch(v->type)
  913. {
  914. case SA_MAP:
  915. sendstring(arg1, p);
  916. putint(p, nextmode);
  917. break;
  918. case SA_SERVERDESC:
  919. sendstring(arg1, p);
  920. break;
  921. case SA_STOPDEMO:
  922. case SA_REMBANS:
  923. case SA_SHUFFLETEAMS:
  924. break;
  925. default:
  926. putint(p, atoi(arg1));
  927. break;
  928. }
  929. enet_packet_resize(packet, p.length());
  930. sendpackettoserv(1, packet);
  931. }
  932. else conoutf("\f3invalid vote");
  933. }
  934.  
  935. void scallvote(char *type, char *arg1, char *arg2)
  936. {
  937. if(type && inmainloop)
  938. {
  939. int t = atoi(type);
  940. if(t==SA_MAP) // FIXME
  941. {
  942. string n;
  943. itoa(n, nextmode);
  944. callvote(t, arg1, n);
  945. }
  946. else callvote(t, arg1, arg2);
  947. }
  948. }
  949.  
  950. int vote(int v)
  951. {
  952. if(!curvote || v < 0 || v >= VOTE_NUM) return 0;
  953. if(curvote->localplayervoted) { conoutf("\f3you voted already"); return 0; }
  954. ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE);
  955. ucharbuf p(packet->data, packet->dataLength);
  956. putint(p, SV_VOTE);
  957. putint(p, v);
  958. enet_packet_resize(packet, p.length());
  959. sendpackettoserv(1, packet);
  960. // flowtron : 2008 11 06 : I don't think the following comments are still current
  961. if(!curvote) { /*printf(":: curvote vanished!\n");*/ return 0; } // flowtron - happens when I call "/stopdemo"! .. seems the map-load happens in-between
  962. curvote->stats[v]++;
  963. curvote->localplayervoted = true;
  964. return 1;
  965. }
  966.  
  967. void displayvote(votedisplayinfo *v)
  968. {
  969. if(!v) return;
  970. DELETEP(curvote);
  971. curvote = v;
  972. conoutf("%s called a vote: %s", v->owner ? colorname(v->owner) : "", curvote->desc);
  973. playsound(S_CALLVOTE, SP_HIGHEST);
  974. curvote->localplayervoted = false;
  975. }
  976.  
  977. void callvotesuc()
  978. {
  979. if(!calledvote) return;
  980. displayvote(calledvote);
  981. calledvote = NULL;
  982. vote(VOTE_YES); // not automatically done by callvote to keep a clear sequence
  983. }
  984.  
  985. void callvoteerr(int e)
  986. {
  987. if(e < 0 || e >= VOTEE_NUM) return;
  988. conoutf("\f3could not vote: %s", voteerrorstr(e));
  989. DELETEP(calledvote);
  990. }
  991.  
  992. void votecount(int v) { if(curvote && v >= 0 && v < VOTE_NUM) curvote->stats[v]++; }
  993. void voteresult(int v)
  994. {
  995. if(curvote && v >= 0 && v < VOTE_NUM)
  996. {
  997. curvote->result = v;
  998. curvote->millis = totalmillis + 5000;
  999. conoutf("vote %s", v == VOTE_YES ? "passed" : "failed");
  1000. if(multiplayer(false)) playsound(v == VOTE_YES ? S_VOTEPASS : S_VOTEFAIL, SP_HIGH);
  1001. }
  1002. }
  1003.  
  1004. void clearvote() { DELETEP(curvote); DELETEP(calledvote); }
  1005.  
  1006. COMMANDN(callvote, scallvote, ARG_3STR); //fixme,ah
  1007. COMMAND(vote, ARG_1EXP);
  1008.  
  1009. void cleanplayervotes(playerent *p)
  1010. {
  1011. if(calledvote && calledvote->owner==p) calledvote->owner = NULL;
  1012. if(curvote && curvote->owner==p) curvote->owner = NULL;
  1013. }
  1014.  
  1015. void whois(int cn)
  1016. {
  1017. addmsg(SV_WHOIS, "ri", cn);
  1018. }
  1019.  
  1020. COMMAND(whois, ARG_1INT);
  1021.  
  1022. int sessionid = 0;
  1023.  
  1024. void setadmin(char *claim, char *password)
  1025. {
  1026. if(!claim || !password) return;
  1027. else addmsg(SV_SETADMIN, "ris", atoi(claim), genpwdhash(player1->name, password, sessionid));
  1028. }
  1029.  
  1030. COMMAND(setadmin, ARG_2STR);
  1031.  
  1032. void changemap(const char *name) // silently request map change, server may ignore
  1033. {
  1034. ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE);
  1035. ucharbuf p(packet->data, packet->dataLength);
  1036. putint(p, SV_NEXTMAP);
  1037. sendstring(name, p);
  1038. putint(p, nextmode);
  1039. enet_packet_resize(packet, p.length());
  1040. sendpackettoserv(1, packet);
  1041. }
  1042.  
  1043. struct mline { string name, cmd; };
  1044. static vector<mline> mlines;
  1045.  
  1046. void *kickmenu = NULL, *banmenu = NULL, *forceteammenu = NULL, *giveadminmenu = NULL;
  1047.  
  1048. void refreshsopmenu(void *menu, bool init)
  1049. {
  1050. menureset(menu);
  1051. mlines.setsize(0);
  1052. loopv(players) if(players[i])
  1053. {
  1054. mline &m = mlines.add();
  1055. s_strcpy(m.name, colorname(players[i]));
  1056. s_sprintf(m.cmd)("%s %d", menu==kickmenu ? "kick" : (menu==banmenu ? "ban" : (menu==forceteammenu ? "forceteam" : "giveadmin")), i);
  1057. menumanual(menu, m.name, m.cmd);
  1058. }
  1059. }
  1060.  
  1061. extern bool watchingdemo;
  1062.  
  1063. // rotate through all spec-able players
  1064. playerent *updatefollowplayer(int shiftdirection)
  1065. {
  1066. if(!shiftdirection)
  1067. {
  1068. playerent *f = players.inrange(player1->followplayercn) ? players[player1->followplayercn] : NULL;
  1069. if(f && (watchingdemo || !f->isspectating())) return f;
  1070. }
  1071.  
  1072. // collect spec-able players
  1073. vector<playerent *> available;
  1074. loopv(players) if(players[i])
  1075. {
  1076. if(m_teammode && !watchingdemo && !isteam(players[i]->team, player1->team)) continue;
  1077. if(players[i]->state==CS_DEAD || players[i]->isspectating()) continue;
  1078. available.add(players[i]);
  1079. }
  1080. if(!available.length()) return NULL;
  1081.  
  1082. // rotate
  1083. int oldidx = -1;
  1084. if(players.inrange(player1->followplayercn)) oldidx = available.find(players[player1->followplayercn]);
  1085. if(oldidx<0) oldidx = 0;
  1086. int idx = (oldidx+shiftdirection) % available.length();
  1087. if(idx<0) idx += available.length();
  1088.  
  1089. player1->followplayercn = available[idx]->clientnum;
  1090. return players[player1->followplayercn];
  1091. }
  1092.  
  1093. // set new spect mode
  1094. void spectate(int mode)
  1095. {
  1096. if(!player1->isspectating()) return;
  1097. if(mode == player1->spectatemode) return;
  1098. showscores(false);
  1099. switch(mode)
  1100. {
  1101. case SM_FOLLOW1ST:
  1102. case SM_FOLLOW3RD:
  1103. case SM_FOLLOW3RD_TRANSPARENT:
  1104. {
  1105. if(players.length() && updatefollowplayer()) break;
  1106. else mode = SM_FLY;
  1107. }
  1108. case SM_FLY:
  1109. {
  1110. if(player1->spectatemode != SM_FLY)
  1111. {
  1112. // set spectator location to last followed player
  1113. playerent *f = updatefollowplayer();
  1114. if(f)
  1115. {
  1116. player1->o = f->o;
  1117. player1->yaw = f->yaw;
  1118. player1->pitch = 0.0f;
  1119. player1->resetinterp();
  1120. }
  1121. else entinmap(player1); // or drop 'em at a random place
  1122. }
  1123. break;
  1124. }
  1125. default: break;
  1126. }
  1127. player1->spectatemode = mode;
  1128. }
  1129.  
  1130.  
  1131. void togglespect() // cycle through all spectating modes
  1132. {
  1133. if(m_botmode) spectate(SM_FLY);
  1134. else
  1135. {
  1136. int mode;
  1137. if(player1->spectatemode==SM_NONE) mode = SM_FOLLOW1ST; // start with 1st person spect
  1138. else mode = SM_FOLLOW1ST + ((player1->spectatemode - SM_FOLLOW1ST + 1) % (SM_NUM-SM_FOLLOW1ST));
  1139. spectate(mode);
  1140. }
  1141. }
  1142.  
  1143. void changefollowplayer(int shift)
  1144. {
  1145. updatefollowplayer(shift);
  1146. }
  1147.  
  1148. COMMAND(spectate, ARG_1INT);
  1149. COMMAND(togglespect, ARG_NONE);
  1150. COMMAND(changefollowplayer, ARG_1INT);
  1151.  
  1152. int isalive() { return player1->state==CS_ALIVE ? 1 : 0; }
  1153. COMMANDN(alive, isalive, ARG_IVAL);
  1154.  
  1155. void serverextension(char *ext, char *args)
  1156. {
  1157. if(!ext || !ext[0]) return;
  1158. size_t n = args ? strlen(args)+1 : 0;
  1159. if(n>0) addmsg(SV_EXTENSION, "rsis", ext, n, args);
  1160. else addmsg(SV_EXTENSION, "rsi", ext, n);
  1161. }
  1162.  
  1163. COMMAND(serverextension, ARG_2STR);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement