Advertisement
Guest User

server.h

a guest
Jul 21st, 2013
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 35.38 KB | None | 0 0
  1. // server.h
  2.  
  3. #define SERVER_BUILTIN_MOD 0
  4. // 1 = super knife (gib only)
  5. // 2 = moon jump (gib only)
  6. // 4 = moon jump always on (no effect unless 2 is set)
  7. // 8 = gungame
  8. //16 = explosive ammo
  9. //32 = moonjump with no damage (mario)
  10. // 64 = /suicide for nuke
  11. // 128 = no explosive zombies
  12.  
  13. #define gamemode smode // allows the gamemode macros to work with the server mode
  14. #define mutators smuts // and mutators too
  15.  
  16. #define valid_flag(f) (f >= 0 && f < 2)
  17.  
  18. enum { GE_NONE = 0, /* sequenced */ GE_SHOT, GE_PROJ, GE_AKIMBO, GE_RELOAD, /* immediate */ GE_SUICIDEBOMB, /* unsequenced */ GE_HEAL, GE_AIRSTRIKE };
  19. enum { ST_EMPTY, ST_LOCAL, ST_TCPIP, ST_AI };
  20.  
  21. #if (SERVER_BUILTIN_MOD & 8)
  22. const int gungame[] = {
  23. WEAP_ASSAULT2,
  24. WEAP_SNIPER,
  25. WEAP_SNIPER2,
  26. WEAP_ASSAULT,
  27. WEAP_SUBGUN,
  28. WEAP_BOLT,
  29. WEAP_SHOTGUN,
  30. WEAP_PISTOL,
  31. WEAP_RPG,
  32. WEAP_HEAL, // nuke after killing with this
  33. };
  34. const int GUNGAME_MAX = sizeof(gungame)/sizeof(*gungame);
  35. #endif
  36.  
  37. extern bool canreachauthserv;
  38.  
  39. static int interm = 0, minremain = 0, gamemillis = 0, gamelimit = 0, gamemusicseed = 0;
  40. static const int DEATHMILLIS = 300;
  41. int smode = G_DM, smuts = G_M_TEAM, mastermode = MM_OPEN, botbalance = -1;
  42. int progressiveround = 1, zombiebalance = 1, zombiesremain = 1;
  43.  
  44. struct client;
  45.  
  46. struct posinfo
  47. {
  48. int cn;
  49. vec o, head;
  50. };
  51.  
  52. struct timedevent
  53. {
  54. bool valid;
  55. int type, millis, id;
  56. timedevent(int type, int millis, int id) : valid(true), type(type), millis(millis), id(id) { }
  57. virtual ~timedevent() {}
  58. virtual bool flush(client *ci, int fmillis);
  59. virtual void process(client *ci) = 0;
  60. };
  61.  
  62. struct shotevent : timedevent
  63. {
  64. int weap;
  65. vec to;
  66. vector<posinfo> pos;
  67. shotevent(int millis, int id, int weap) : timedevent(GE_SHOT, millis, id), weap(weap) { to = vec(0, 0, 0); pos.setsize(0); }
  68. bool compact;
  69. void process(client *ci);
  70. };
  71.  
  72. struct destroyevent : timedevent
  73. {
  74. int weap, flags;
  75. vec o;
  76. destroyevent(int millis, int id, int weap, int flags, const vec &o) : timedevent(GE_PROJ, millis, id), weap(weap), flags(flags), o(o) {}
  77. void process(client *ci);
  78. };
  79.  
  80. // switchevent?
  81.  
  82. struct akimboevent : timedevent
  83. {
  84. akimboevent(int millis, int id) : timedevent(GE_AKIMBO, millis, id) {}
  85. void process(client *ci);
  86. };
  87.  
  88. struct reloadevent : timedevent
  89. {
  90. int weap;
  91. reloadevent(int millis, int id, int weap) : timedevent(GE_RELOAD, millis, id), weap(weap) {}
  92. void process(client *ci);
  93. };
  94.  
  95. // unordered
  96. /*
  97. struct bowevent : timedevent
  98. {
  99. vec o;
  100. void process(client *ci);
  101. };
  102. */
  103.  
  104. struct healevent : timedevent
  105. {
  106. int hp;
  107. healevent(int millis, int actor, int hp) : timedevent(GE_HEAL, millis, actor), hp(hp) {}
  108. void process(client *ci);
  109. };
  110.  
  111. struct suicidebomberevent : timedevent
  112. {
  113. suicidebomberevent(int actor) : timedevent(GE_SUICIDEBOMB, 0, actor) {}
  114. void process(client *ci);
  115. };
  116.  
  117. struct airstrikeevent : timedevent
  118. {
  119. vec o;
  120. airstrikeevent(int millis, const vec &o) : timedevent(GE_AIRSTRIKE, millis, 0), o(o) {}
  121. void process(client *ci);
  122. };
  123.  
  124. template <int N>
  125. struct projectilestate
  126. {
  127. int projs[N];
  128. int numprojs;
  129. int throwable;
  130.  
  131. projectilestate() : numprojs(0) {}
  132.  
  133. void reset() { numprojs = 0; }
  134.  
  135. void add(int val)
  136. {
  137. if(numprojs>=N) numprojs = 0;
  138. projs[numprojs++] = val;
  139. ++throwable;
  140. }
  141.  
  142. bool removeany()
  143. {
  144. if(!numprojs) return false;
  145. --numprojs;
  146. return true;
  147. }
  148.  
  149. bool remove(int val)
  150. {
  151. loopi(numprojs) if(projs[i]==val)
  152. {
  153. projs[i] = projs[--numprojs];
  154. return true;
  155. }
  156. return false;
  157. }
  158. };
  159.  
  160. struct wound
  161. {
  162. int inflictor;
  163. int lastdealt;
  164. vec offset;
  165. };
  166.  
  167. struct clientstate : playerstate
  168. {
  169. vec o, aim, vel, lasto, lastspeedo, sg[SGRAYS], flagpickupo;
  170. float pitchvel, aspeed;
  171. int state, omillis, lastomillis, lmillis, smillis, movemillis, ldt, spj, speedtime, speedallow;
  172. int lastdeath, lastpain, lastffkill, lastspawn, lifesequence, skin, streakused;
  173. int lastkill, combo;
  174. bool crouching, onfloor; float fallz;
  175. int crouchmillis, scopemillis;
  176. int drownmillis; char drownval;
  177. int streakondeath;
  178. int lastshot, lastregen;
  179. projectilestate<6> grenades; // 5000ms TLL / (we can throw one every 650ms+200ms) = 6 nades possible
  180. projectilestate<3> knives;
  181. int akimbomillis;
  182. int points, flagscore, frags, deaths, shotdamage, damage;
  183. ivector revengelog;
  184. vector<wound> wounds;
  185. bool valid;
  186. #if (SERVER_BUILTIN_MOD & 8)
  187. int gungame;
  188. #endif
  189.  
  190. clientstate() : state(CS_DEAD), valid(true), playerstate() {}
  191.  
  192. bool isalive(int gamemillis)
  193. {
  194. if(interm) return false;
  195. return state==CS_ALIVE || (state==CS_DEAD && gamemillis - lastdeath <= DEATHMILLIS);
  196. }
  197.  
  198. bool waitexpired(int gamemillis)
  199. {
  200. const int wait = gamemillis - lastshot;
  201. loopi(WEAP_MAX) if(wait < gunwait[i]) return false;
  202. return true;
  203. }
  204.  
  205. void updateshot(int gamemillis)
  206. {
  207. const int wait = gamemillis-lastshot;
  208. loopi(WEAP_MAX)
  209. if(gunwait[i])
  210. gunwait[i] = max(gunwait[i] - wait, 0);
  211. lastshot = gamemillis;
  212. }
  213.  
  214. void allowspeeding(int gamemillis, int allow){
  215. speedallow = max(speedallow, gamemillis + allow);
  216. }
  217.  
  218. clientstate &invalidate(){
  219. valid = false;
  220. return *this;
  221. }
  222.  
  223. void reset()
  224. {
  225. state = CS_DEAD;
  226. lifesequence = -1;
  227. skin = 0;
  228. grenades.reset();
  229. knives.reset();
  230. akimbomillis = 0;
  231. points = flagscore = frags = deaths = shotdamage = damage = lastffkill = 0;
  232. revengelog.setsize(0);
  233. pointstreak = deathstreak = streakused = 0;
  234. radarearned = airstrikes = nukemillis = 0;
  235. valid = true;
  236. #if (SERVER_BUILTIN_MOD & 8)
  237. gungame = 0;
  238. #endif
  239. respawn();
  240. }
  241.  
  242. void respawn()
  243. {
  244. playerstate::respawn(gamemode, mutators);
  245. o = lasto = lastspeedo = vec(-1e10f, -1e10f, -1e10f);
  246. aim = vel = vec(0, 0, 0);
  247. pitchvel = aspeed = speedtime = speedallow = 0;
  248. omillis = lastomillis = lmillis = smillis = movemillis = ldt = spj = 0;
  249. drownmillis = drownval = 0;
  250. lastspawn = -1;
  251. lastdeath = lastpain = lastshot = lastregen = 0;
  252. lastkill = combo = 0;
  253. akimbomillis = 0;
  254. damagelog.setsize(0);
  255. wounds.shrink(0); // no more wounds!
  256. crouching = false;
  257. crouchmillis = scopemillis = 0;
  258. onfloor = false;
  259. fallz = -1e10f;
  260. streakondeath = -1;
  261. }
  262.  
  263. void addwound(int owner, const vec &woundloc)
  264. {
  265. wound &w = wounds.length() >= 8 ? wounds[0] : wounds.add();
  266. w.inflictor = owner;
  267. w.lastdealt = gamemillis;
  268. w.offset = woundloc;
  269. w.offset.sub(o);
  270. }
  271. };
  272.  
  273. struct savedscore
  274. {
  275. string name;
  276. enet_uint32 ip;
  277. int points, frags, assists, flagscore, deaths, shotdamage, damage;
  278.  
  279. void save(clientstate &cs)
  280. {
  281. points = cs.points;
  282. frags = cs.frags;
  283. assists = cs.assists;
  284. flagscore = cs.flagscore;
  285. deaths = cs.deaths;
  286. shotdamage = cs.shotdamage;
  287. damage = cs.damage;
  288. }
  289.  
  290. void restore(clientstate &cs)
  291. {
  292. cs.points = points;
  293. cs.frags = frags;
  294. cs.assists = assists;
  295. cs.flagscore = flagscore;
  296. cs.deaths = deaths;
  297. cs.shotdamage = shotdamage;
  298. cs.damage = damage;
  299. }
  300. };
  301.  
  302. struct client // server side version of "dynent" type
  303. {
  304. int type;
  305. int clientnum;
  306. ENetPeer *peer;
  307. string hostname;
  308. string name;
  309. int ping, team, vote, priv;
  310. bool muted;
  311. int acversion, acbuildtype, acthirdperson;
  312. int connectmillis;
  313. bool connected, connectauth, wantsmap;
  314. int authtoken, authmillis, authpriv, masterverdict, guid; uint authreq;
  315. bool haswelcome;
  316. bool isonrightmap;
  317. bool timesync;
  318. int overflow;
  319. int gameoffset, lastevent, lastvotecall, lastkickcall, name_relay;
  320. char newname[MAXNAMELEN+1];
  321. int demoflags;
  322. clientstate state;
  323. vector<timedevent *> events, timers;
  324. vector<uchar> position, messages;
  325. string lastsaytext;
  326. int saychars, lastsay, spamcount;
  327. int at3_score, at3_lastforce, eff_score;
  328. bool at3_dontmove;
  329. int spawnindex;
  330. int salt;
  331. string pwd;
  332. int mapcollisions;
  333. enet_uint32 bottomRTT;
  334. #if (SERVER_BUILTIN_MOD & 64)
  335. bool nuked;
  336. #endif
  337.  
  338. void addevent(timedevent *e)
  339. {
  340. if(events.length()<256) events.add(e);
  341. else delete e;
  342. }
  343.  
  344. void addtimer(timedevent *e)
  345. {
  346. if(timers.length()<256) timers.add(e);
  347. else delete e;
  348. }
  349.  
  350. void invalidateheals()
  351. {
  352. loopv(timers) if(timers[i]->type == GE_HEAL) timers[i]->valid = false;
  353. }
  354.  
  355. int getmillis(int millis, int id)
  356. {
  357. if(!timesync || (!events.length() && state.waitexpired(millis)))
  358. {
  359. timesync = true;
  360. gameoffset = millis-id;
  361. return millis;
  362. }
  363. return gameoffset+id;
  364. }
  365.  
  366. void removeexplosives() {
  367. state.grenades.reset(); // remove active/flying nades
  368. state.knives.reset(); // remove active/flying knives (usually useless, since knives are fast)
  369. // remove all dealt wounds
  370. extern vector<client *> clients;
  371. loopv(clients){
  372. if(clients[i]->type == ST_EMPTY) continue;
  373. clientstate &cs = clients[i]->state;
  374. loopvj(cs.wounds)
  375. if(cs.wounds[j].inflictor == clientnum)
  376. //cs.wounds.remove(j--);
  377. cs.wounds[j].inflictor = -1;
  378. }
  379. }
  380.  
  381. void suicide(int weap, int flags = FRAG_NONE){
  382. extern void serverdied(client *target, client *actor, int damage, int gun, int style, const vec &source, float killdist = 0.f);
  383. if(state.state != CS_DEAD) serverdied(this, this, 0, weap, flags, state.o);
  384. }
  385.  
  386. void mapchange()
  387. {
  388. state.reset();
  389. events.deletecontents();
  390. timers.deletecontents();
  391. removeexplosives();
  392. overflow = 0;
  393. timesync = wantsmap = false;
  394. isonrightmap = m_edit(gamemode);
  395. lastevent = 0;
  396. at3_lastforce = 0;
  397. mapcollisions = 0;
  398. #if (SERVER_BUILTIN_MOD & 64)
  399. nuked = false;
  400. #endif
  401. }
  402.  
  403. void reset()
  404. {
  405. name[0] = demoflags = authmillis = 0;
  406. ping = bottomRTT = 9999;
  407. team = 0; // TEAM_RED
  408. position.setsize(0);
  409. messages.setsize(0);
  410. connected = connectauth = wantsmap = haswelcome = false;
  411. lastvotecall = lastkickcall = 0;
  412. vote = VOTE_NEUTRAL;
  413. lastsaytext[0] = '\0';
  414. newname[0] = '\0';
  415. name_relay = 0;
  416. saychars = authreq = 0;
  417. spawnindex = -1;
  418. mapchange();
  419. priv = PRIV_NONE;
  420. muted = false;
  421. authpriv = -1;
  422. acversion = acbuildtype = acthirdperson = guid = 0;
  423. masterverdict = DISC_NONE;
  424. }
  425.  
  426. void zap()
  427. {
  428. type = ST_EMPTY;
  429. priv = PRIV_NONE;
  430. muted = false;
  431. authpriv = -1;
  432. guid = 0;
  433. masterverdict = DISC_NONE;
  434. connected = connectauth = wantsmap = haswelcome = false;
  435. removeexplosives();
  436. }
  437. };
  438.  
  439. struct savedlimit
  440. {
  441. enet_uint32 ip;
  442. int lastvotecall, lastkickcall;
  443. int saychars, lastsay, spamcount;
  444. #if (SERVER_BUILTIN_MOD & 64)
  445. bool nuked;
  446. #endif
  447.  
  448. void save(client &cl)
  449. {
  450. ip = cl.peer->address.host;
  451. lastvotecall = cl.lastvotecall;
  452. lastkickcall = cl.lastkickcall;
  453. saychars = cl.saychars;
  454. lastsay = cl.lastsay;
  455. spamcount = cl.spamcount;
  456. #if (SERVER_BUILTIN_MOD & 64)
  457. nuked = cl.nuked;
  458. #endif
  459. }
  460.  
  461. void restore(client &cl)
  462. {
  463. // obviously don't set his IP
  464. cl.lastvotecall = lastvotecall;
  465. cl.lastkickcall = lastkickcall;
  466. cl.saychars = saychars;
  467. cl.lastsay = lastsay;
  468. cl.spamcount = spamcount;
  469. #if (SERVER_BUILTIN_MOD & 64)
  470. cl.nuked = nuked;
  471. #endif
  472. }
  473. };
  474.  
  475. struct ban
  476. {
  477. enet_uint32 host;
  478. int millis;
  479. };
  480.  
  481. struct sconfirm{
  482. int id, team, actor, target;
  483. int points, frag, death;
  484. vec o;
  485. };
  486.  
  487. struct sknife{
  488. int id, millis;
  489. vec o;
  490. };
  491.  
  492. struct demofile
  493. {
  494. string info;
  495. uchar *data;
  496. int len;
  497. };
  498.  
  499. char *loadcfgfile(char *cfg, const char *name, int *len){
  500. if(name && name[0])
  501. {
  502. copystring(cfg, name);
  503. path(cfg);
  504. }
  505. char *p, *buf = loadfile(cfg, len);
  506. if(!buf)
  507. {
  508. if(name) logline(ACLOG_INFO,"could not read config file '%s'", name);
  509. return NULL;
  510. }
  511. if('\r' != '\n') // this is not a joke!
  512. {
  513. char c = strchr(buf, '\n') ? ' ' : '\n'; // in files without /n substitute /r with /n, otherwise remove /r
  514. for(p = buf; (p = strchr(p, '\r')); p++) *p = c;
  515. }
  516. for(p = buf; (p = strstr(p, "//")); ) // remove comments
  517. {
  518. while(*p != '\n' && *p != '\0') p++[0] = ' ';
  519. }
  520. for(p = buf; (p = strchr(p, '\t')); p++) *p = ' ';
  521. for(p = buf; (p = strchr(p, '\n')); p++) *p = '\0'; // one string per line
  522. return buf;
  523. }
  524.  
  525. #define MAXNICKFRAGMENTS 5
  526. enum { NWL_UNLISTED = 0, NWL_PASS, NWL_PWDFAIL, NWL_IPFAIL };
  527.  
  528. struct nickblacklist {
  529. struct iprchain { struct iprange ipr; const char *pwd; int next; };
  530. struct blackline { int frag[MAXNICKFRAGMENTS]; bool ignorecase; int line; void clear() { loopi(MAXNICKFRAGMENTS) frag[i] = -1; } };
  531. hashtable<const char *, int> whitelist;
  532. vector<iprchain> whitelistranges;
  533. vector<blackline> blacklines;
  534. vector<const char *> blfraglist;
  535.  
  536. void destroylists()
  537. {
  538. whitelistranges.setsize(0);
  539. enumeratek(whitelist, const char *, key, delete key);
  540. whitelist.clear(false);
  541. blfraglist.deletecontents();
  542. blacklines.setsize(0);
  543. }
  544.  
  545. void readnickblacklist(const char *name)
  546. {
  547. static string nbfilename;
  548. static int nbfilesize;
  549. const char *sep = " ";
  550. int len, line = 1, errors = 0;
  551. iprchain iprc;
  552. blackline bl;
  553.  
  554. if(!name && getfilesize(nbfilename) == nbfilesize) return;
  555. destroylists();
  556. char *buf = loadcfgfile(nbfilename, name, &len);
  557. nbfilesize = len;
  558. if(!buf) return;
  559. char *l, *s, *r, *p = buf;
  560. logline(ACLOG_VERBOSE,"reading nickname blacklist '%s'", nbfilename);
  561. while(p < buf + len)
  562. {
  563. l = p; p += strlen(p) + 1;
  564. l = strtok(l, sep);
  565. if(l)
  566. {
  567. s = strtok(NULL, sep);
  568. int ic = 0;
  569. if(s && (!strcmp(l, "accept") || !strcmp(l, "a")))
  570. { // accept nickname IP-range
  571. int *i = whitelist.access(s);
  572. if(!i) i = &whitelist.access(newstring(s), -1);
  573. s += strlen(s) + 1;
  574. while(s < p)
  575. {
  576. r = (char *) atoipr(s, &iprc.ipr);
  577. s += strspn(s, sep);
  578. iprc.pwd = r && *s ? NULL : newstring(s, strcspn(s, sep));
  579. if(r || *s)
  580. {
  581. iprc.next = *i;
  582. *i = whitelistranges.length();
  583. whitelistranges.add(iprc);
  584. s = r ? r : s + strlen(iprc.pwd);
  585. }
  586. else break;
  587. }
  588. s = NULL;
  589. }
  590. else if(s && (!strcmp(l, "block") || !strcmp(l, "b") || ic++ || !strcmp(l, "blocki") || !strcmp(l, "bi")))
  591. { // block nickname fragments (ic == ignore case)
  592. bl.clear();
  593. loopi(MAXNICKFRAGMENTS)
  594. {
  595. if(ic) strtoupper(s);
  596. loopvj(blfraglist)
  597. {
  598. if(!strcmp(s, blfraglist[j])) { bl.frag[i] = j; break; }
  599. }
  600. if(bl.frag[i] < 0)
  601. {
  602. bl.frag[i] = blfraglist.length();
  603. blfraglist.add(newstring(s));
  604. }
  605. s = strtok(NULL, sep);
  606. if(!s) break;
  607. }
  608. bl.ignorecase = ic > 0;
  609. bl.line = line;
  610. blacklines.add(bl);
  611. }
  612. else { logline(ACLOG_INFO," error in line %d, file %s: unknown keyword '%s'", line, nbfilename, l); errors++; }
  613. if(s && s[strspn(s, " ")]) { logline(ACLOG_INFO," error in line %d, file %s: ignored '%s'", line, nbfilename, s); errors++; }
  614. }
  615. line++;
  616. }
  617. delete[] buf;
  618. logline(ACLOG_VERBOSE," nickname whitelist (%d entries):", whitelist.numelems);
  619. string text;
  620. enumeratekt(whitelist, const char *, key, int, idx,
  621. {
  622. text[0] = '\0';
  623. for(int i = idx; i >= 0; i = whitelistranges[i].next)
  624. {
  625. iprchain &ic = whitelistranges[i];
  626. if(ic.pwd) concatformatstring(text, " pwd:\"%s\"", hiddenpwd(ic.pwd));
  627. else concatformatstring(text, " %s", iprtoa(ic.ipr));
  628. }
  629. logline(ACLOG_VERBOSE, " accept %s%s", key, text);
  630. });
  631. logline(ACLOG_VERBOSE," nickname blacklist (%d entries):", blacklines.length());
  632. loopv(blacklines)
  633. {
  634. text[0] = '\0';
  635. loopj(MAXNICKFRAGMENTS)
  636. {
  637. int k = blacklines[i].frag[j];
  638. if(k >= 0) { concatstring(text, " "); concatstring(text, blfraglist[k]); }
  639. }
  640. logline(ACLOG_VERBOSE, " %2d block%s%s", blacklines[i].line, blacklines[i].ignorecase ? "i" : "", text);
  641. }
  642. logline(ACLOG_INFO,"read %d + %d entries from nickname blacklist file '%s', %d errors", whitelist.numelems, blacklines.length(), nbfilename, errors);
  643. }
  644.  
  645. int checknickwhitelist(const client &c)
  646. {
  647. if(c.type != ST_TCPIP) return NWL_PASS;
  648. iprange ipr;
  649. ipr.lr = ENET_NET_TO_HOST_32(c.peer->address.host); // blacklist uses host byte order
  650. int *idx = whitelist.access(c.name);
  651. if(!idx) return NWL_UNLISTED; // no matching entry
  652. int i = *idx;
  653. bool needipr = false, iprok = false, needpwd = false, pwdok = false;
  654. while(i >= 0)
  655. {
  656. iprchain &ic = whitelistranges[i];
  657. if(ic.pwd)
  658. { // check pwd
  659. needpwd = true;
  660. if(pwdok || !strcmp(genpwdhash(c.name, ic.pwd, c.salt), c.pwd)) pwdok = true;
  661. }
  662. else
  663. { // check IP
  664. needipr = true;
  665. if(!cmpipmatch(&ipr, &ic.ipr)) iprok = true; // range match found
  666. }
  667. i = whitelistranges[i].next;
  668. }
  669. if(needpwd && !pwdok) return NWL_PWDFAIL; // wrong PWD
  670. if(needipr && !iprok) return NWL_IPFAIL; // wrong IP
  671. return NWL_PASS;
  672. }
  673.  
  674. int checknickblacklist(const char *name)
  675. {
  676. if(blacklines.empty()) return -2; // no nickname blacklist loaded
  677. string nameuc;
  678. copystring(nameuc, name);
  679. strtoupper(nameuc);
  680. loopv(blacklines)
  681. {
  682. loopj(MAXNICKFRAGMENTS)
  683. {
  684. int k = blacklines[i].frag[j];
  685. if(k < 0) return blacklines[i].line; // no more fragments to check
  686. if(strstr(blacklines[i].ignorecase ? nameuc : name, blfraglist[k]))
  687. {
  688. if(j == MAXNICKFRAGMENTS - 1) return blacklines[i].line; // all fragments match
  689. }
  690. else break; // this line no match
  691. }
  692. }
  693. return -1; // no match
  694. }
  695. } nbl;
  696.  
  697. #define FORBIDDENSIZE 15
  698. struct serverforbiddenlist
  699. {
  700. int num;
  701. char entries[100][2][FORBIDDENSIZE+1]; // 100 entries and 2 words (15 chars) per entry is more than enough
  702.  
  703. void initlist()
  704. {
  705. num = 0;
  706. memset(entries,'\0',2*100*(FORBIDDENSIZE+1));
  707. }
  708.  
  709. void addentry(char *s)
  710. {
  711. int len = strlen(s);
  712. if ( len > 128 || len < 3 ) return;
  713. int n = 0;
  714. string s1, s2;
  715. char *c1 = s1, *c2 = s2;
  716. if (num < 100 && (n = sscanf(s,"%s %s",s1,s2)) > 0 ) // no warnings
  717. {
  718. strncpy(entries[num][0],c1,FORBIDDENSIZE);
  719. if ( n > 1 ) strncpy(entries[num][1],c2,FORBIDDENSIZE);
  720. else entries[num][1][0]='\0';
  721. num++;
  722. }
  723. }
  724.  
  725. void read(const char *name)
  726. {
  727. static string forbiddenfilename;
  728. static int forbiddenfilesize;
  729. if(!name && getfilesize(forbiddenfilename) == forbiddenfilesize) return;
  730. initlist();
  731. int len;
  732. char *buf = loadcfgfile(forbiddenfilename, name, &len);
  733. forbiddenfilesize = len;
  734. if(!buf) return;
  735.  
  736. char *l, *p = buf;
  737. logline(ACLOG_VERBOSE, "reading forbidden list '%s'", forbiddenfilename);
  738. while(p < buf + forbiddenfilesize)
  739. {
  740. l = p; p += strlen(p) + 1;
  741. addentry(l);
  742. }
  743. logline(ACLOG_INFO,"read %d forbidden entries from '%s'", num, forbiddenfilename);
  744. DELETEA(buf);
  745. }
  746.  
  747. const char *forbidden(const char *s)
  748. {
  749. loopi(num){
  750. bool found = true;
  751. loopj(2){
  752. if(*entries[i][j] == '\0' || !findpattern(s,entries[i][j])){
  753. found = false;
  754. break;
  755. }
  756. if(found) break;
  757. }
  758. if(found){
  759. static char match[2*(FORBIDDENSIZE+1)];
  760. copystring(match, entries[i][0]);
  761. for(int j = 1; j<2; ++j){
  762. if(!*entries[i][j]) break;
  763. concatformatstring(match, " %s", entries[i][j]);
  764. }
  765. return match;
  766. }
  767. }
  768. return NULL;
  769. }
  770. } forbiddens;
  771.  
  772. #define CONFIG_MAXPAR 7
  773.  
  774. struct configset
  775. {
  776. string mapname;
  777. union
  778. {
  779. struct { int mode, muts, time, vote, minplayer, maxplayer, skiplines; };
  780. int par[CONFIG_MAXPAR];
  781. };
  782. };
  783.  
  784. // managed character allocation...
  785. struct botname
  786. {
  787. char *storage;
  788.  
  789. botname(){
  790. storage = new char[MAXNAMELEN+1];
  791. }
  792.  
  793. void putname(char *target, int sk){
  794. char *name = storage;
  795. const char *rank = ""; // prepend rank (only if based on skill)
  796.  
  797. if(*name == '*') // rank based on skill
  798. {
  799. if(*++name == ' ') ++name; // skip space
  800. // skill is from 45 to 95
  801. if(sk >= 90) rank = "Lt. "; // 10%
  802. else if(sk >= 80) rank = "Sgt. "; // 20%
  803. else if(sk >= 65) rank = "Cpl. "; // 30%
  804. // 40% Private
  805. else if(sk >= 55) rank = "Pfc. "; // 20%
  806. else rank = "Pvt. "; // 20%
  807. }
  808.  
  809. defformatstring(fname)("%s%s", rank, name);
  810. filtername(target, fname);
  811. }
  812.  
  813. ~botname(){
  814. delete[] storage;
  815. }
  816. };
  817. vector<botname> botnames;
  818.  
  819. void mkbotname(client &c){
  820. int skip = 0;
  821. if(m_zombie(gamemode))
  822. {
  823. // First block of ranked names are not for zombies
  824. loopv(botnames)
  825. {
  826. if(botnames[i].storage[0] == '*') skip = i + 1;
  827. else break;
  828. }
  829. }
  830. if(skip >= botnames.length()) filtername(c.name, m_zombie(gamemode) ? "a zombie" : "a bot");
  831. else botnames[rnd(botnames.length() - skip) + skip].putname(c.name, c.state.level);
  832. }
  833.  
  834. void clearai(), checkai();
  835. //void startgame(const char *newname, int newmode, int newtime = -1, bool notify = true);
  836. void resetmap(const char *newname, int newmode, int newmuts, int newtime = -1, bool notify = true);
  837. void disconnect_client(int n, int reason = -1);
  838. int clienthasflag(int cn);
  839. bool updateclientteam(int client, int team, int ftr);
  840. void convertcheck(bool quick = false);
  841. void shuffleteams(int ftr = FTR_AUTOTEAM);
  842. bool refillteams(bool now = false, int ftr = FTR_AUTOTEAM, bool aionly = true);
  843. void setpriv(int client, int priv);
  844. int mapavailable(const char *mapname);
  845. void getservermap(void);
  846. // int findmappath(const char *mapname, char *filename = NULL);
  847. mapstats *getservermapstats(const char *mapname, bool getlayout = false, int *maploc = NULL);
  848. int findmappath(const char *mapname, char *filename = NULL);
  849. void sendf(int cn, int chan, const char *format, ...);
  850. void sendteamscore(int team, int reciever = -1);
  851.  
  852. int explosion(client &owner, const vec &o2, int weap, bool gib = true, client *cflag = NULL);
  853. /*
  854. int calcscores();
  855. void recordpacket(int chan, void *data, int len);
  856. void senddisconnectedscores(int cn);
  857. void process(ENetPacket *packet, int sender, int chan);
  858. void welcomepacket(packetbuf &p, int n);
  859. void sendwelcome(client *cl, int chan = 1);
  860. void sendpacket(int n, int chan, ENetPacket *packet, int exclude = -1);
  861. int numclients();
  862. void forcedeath(client *cl);
  863.  
  864. extern bool isdedicated;
  865. extern string smapname;
  866. extern mapstats smapstats;
  867. extern char *maplayout;
  868. */
  869. void sendheadshot(const vec &from, const vec &to, int damage);
  870.  
  871. enum { MAP_NOTFOUND = 0, MAP_TEMP, MAP_CUSTOM, MAP_LOCAL, MAP_OFFICIAL, MAP_MAX };
  872. const char *maplocstr[MAP_MAX] = { "not found", "incoming", "custom", "local", "official", };
  873. #define readonlymap(x) ((x) >= MAP_CUSTOM)
  874. #define distributablemap(x) ((x) == MAP_TEMP || (x) == MAP_CUSTOM)
  875.  
  876. #ifdef _DEBUG
  877. // converts message code to char
  878. const char *messagenames(int n){
  879. const char *msgnames[N_NUM] = {
  880. "N_SERVINFO", "N_WELCOME", // before connection
  881. "N_INITCLIENT", "N_INITAI", "N_SETTEAM", "N_RESUME", "N_MAPIDENT", "N_DISC", "N_DELAI", "N_REASSIGNAI", // sent after (dis)connection
  882. "N_CLIENT", "N_POS", "N_SOUND", "N_PINGPONG", "N_PINGTIME", // automatic from client
  883. "N_TEXT", "N_WHOIS", "N_WHOISINFO", "N_NEWNAME", "N_SKIN", "N_THIRDPERSON", "N_LEVEL", "N_SWITCHTEAM", // user-initiated
  884. "N_CALLVOTE", "N_CALLVOTEERR", "N_VOTE", "N_VOTEREMAIN", "N_VOTERESULT", // votes
  885. "N_LISTDEMOS", "N_DEMO", "N_DEMOPLAYBACK", // demos
  886. "N_AUTHREQ", "N_AUTHCHAL", // auth
  887. "N_CLAIMPRIV", "N_SETPRIV", // privileges
  888. "N_MAPC2S", "N_MAPS2C", "N_MAPDELETE", "N_MAPREQ", "N_MAPFAIL", // map transit
  889. // editmode ONLY
  890. "N_EDITMODE", "N_EDITH", "N_EDITT", "N_EDITS", "N_EDITD", "N_EDITE", "N_EDITW", "N_EDITENT", "N_NEWMAP",
  891. // game events
  892. "N_SHOOT", "N_SHOOTC", "N_PROJ", "N_AKIMBO", "N_RELOAD", // clients to server events
  893. "N_SG", "N_SUICIDE", "N_QUICKSWITCH", "N_SWITCHWEAP", "N_LOADOUT", "N_THROWNADE", "N_THROWKNIFE", // server directly handled
  894. "N_RICOCHET", "N_REGEN", "N_HEAL", "N_BLEED", "N_STREAKREADY", "N_STREAKUSE", "N_HEADSHOT", "N_MULTI", // server to client
  895. "N_KNIFEADD", "N_KNIFEREMOVE", // knives
  896. "N_CONFIRMADD", "N_CONFIRMREMOVE", // kill confirmed
  897. // gameplay
  898. "N_POINTS", "N_SCORE", "N_TEAMSCORE", "N_KILL", "N_DAMAGE", // scoring
  899. "N_TRYSPAWN", "N_SPAWNSTATE", "N_SPAWN", "N_FORCEDEATH", "N_FORCEGIB", // spawning
  900. "N_ITEMSPAWN", "N_ITEMACC", // items
  901. "N_DROPFLAG", "N_FLAGINFO", "N_FLAGMSG", "N_FLAGSECURE", // flags
  902. "N_MAPCHANGE", "N_NEXTMAP", // map changes
  903. "N_TIMEUP", "N_ACCURACY", "N_ARENAWIN", "N_ZOMBIESWIN", "N_CONVERTWIN" // round end/remaining
  904. // extensions
  905. "N_SERVMSG", "N_EXT",
  906. };
  907. if(n < 0 || n >= N_NUM) return "unknown";
  908. return msgnames[n];
  909. }
  910. #endif
  911.  
  912. const char *entnames[MAXENTTYPES + 1] =
  913. {
  914. "none?",
  915. "light", "playerstart", "pistol", "ammobox","grenades",
  916. "health", "helmet", "armor", "akimbo",
  917. "mapmodel", "trigger", "ladder", "ctf-flag", "sound", "clip", "plclip", "max",
  918. };
  919.  
  920. // pickup stats
  921.  
  922. const itemstat ammostats[WEAP_MAX] =
  923. {
  924. { 1, 1, 2, S_ITEMAMMO }, // knife dummy
  925. { 2, 5, 6, S_ITEMAMMO }, // pistol
  926. {21, 28, 42, S_ITEMAMMO }, // shotgun
  927. { 3, 4, 6, S_ITEMAMMO }, // subgun
  928. { 3, 4, 8, S_ITEMAMMO }, // sniper
  929. { 2, 3, 4, S_ITEMAMMO }, // bolt sniper
  930. { 3, 4, 6, S_ITEMAMMO }, // m16
  931. { 1, 1, 3, S_ITEMAMMO }, // grenade
  932. { 4, 0, 6, S_ITEMAKIMBO }, // akimbo
  933. { 4, 6, 8, S_ITEMAMMO }, // heal
  934. { 1, 1, 1, S_ITEMAMMO }, // sword dummy
  935. { 3, 3, 6, S_ITEMAMMO }, // RPG
  936. { 3, 4, 6, S_ITEMAMMO }, // ak47
  937. { 2, 3, 4, S_ITEMAMMO }, // sniper2
  938. };
  939.  
  940. const itemstat powerupstats[] =
  941. {
  942. {35 * HEALTHSCALE, STARTHEALTH, MAXHEALTH, S_ITEMHEALTH }, //health
  943. {15, STARTARMOR, MAXARMOR, S_ITEMARMOR }, // helmet
  944. {40, STARTARMOR, MAXARMOR, S_ITEMARMOR }, // armor
  945. };
  946.  
  947. // weaponry
  948. const mul muls[MUL_NUM] =
  949. {
  950. //{ head, torso, leg; }
  951. { 3.5f, 1.1f, 1 }, // normal
  952. { 5, 1.4f, 1 }, // snipers
  953. { 4, 1.2f, 1 } // shotgun
  954. };
  955.  
  956. const guninfo guns[WEAP_MAX] =
  957. {
  958. // { modelname; sound, reload, reloadtime, attackdelay, damage, range, endrange, rangeminus, projspeed, part, spread, spreadrem, kick, addsize, magsize, mdl_kick_rot, mdl_kick_back, recoil, maxrecoil, recoilangle, pushfactor; auto;}
  959. { "knife", S_KNIFE, S_ITEMAMMO, 0, 500, 80, 4, 5, 72, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 3, true },
  960. { "pistol", S_PISTOL, S_RPISTOL, 1400, 90, 36, 24, 90, 17, 0, 0, 90, 90, 9, 12, 13, 6, 2, 32, 48, 70, 1, false},
  961. { "shotgun", S_SHOTGUN, S_RSHOTGUN, 750, 200, 10, 6, 16, 7, 0, 0, 295, 5, 12, 1, 8, 9, 5, 60, 70, 5, 2, false},
  962. { "subgun", S_SUBGUN, S_RSUBGUN, 2400, 67, 36, 32, 80, 21, 0, 0, 70, 93, 4, 32, 33, 1, 3, 27, 45, 65, 1, true },
  963. { "sniper", S_SNIPER, S_RSNIPER, 2000, 73, 45, 70, 110, 10, 0, 0, 235, 96, 0, 60, 60, 4, 4, 0, 0, 75, 2, true },
  964. { "bolt", S_BOLT, S_RBOLT, 2000, 1500, 120, 80, 130, 50, 0, 0, 250, 97, 36, 8, 9, 4, 4, 86, 90, 80, 3, false},
  965. { "assault", S_ASSAULT, S_RASSAULT, 2100, 73, 32, 45, 92, 10, 0, 0, 65, 95, 3, 30, 31, 0, 3, 25, 42, 60, 1, true },
  966. { "grenade", S_NULL, S_NULL, 1000, 650, 230, 0, 60, 27, 20, 6, 1, 0, 1, 0, 1, 3, 1, 0, 0, 0, 3, false},
  967. { "pistol", S_PISTOL, S_RAKIMBO, 1400, 80, 36, 30, 90, 17, 0, 0, 60, 0, 8, 24, 26, 6, 2, 28, 49, 72, 2, true },
  968. { "heal", S_SUBGUN, S_NULL, 1200, 100, 20, 4, 8, 10, 0, 0, 50, 1, 1, 10, 11, 0, 0, 10, 20, 8, 4, true },
  969. { "sword", S_SWORD, S_NULL, 0, 480, 90, 7, 9, 81, 0, 0, 1, 0, 1, 0, 1, 0, 2, 0, 0, 0, 0, true },
  970. { "rpg", S_RPG, S_NULL, 2000, 73, 170, 80, 130, 18, 0, 0, 200, 50, 0, 60, 60, 3, 1, 0, 0, 0, 2, true },
  971. { "assault2", S_ASSAULT2, S_RASSAULT2, 2000, 100, 46, 48, 120, 16, 0, 0, 150, 94, 3, 30, 31, 0, 3, 30, 47, 62, 1, true },
  972. { "sniper2", S_SNIPER2, S_RSNIPER2, 2000, 73, 110, 75, 120, 45, 0, 0, 300, 98, 0, 60, 60, 4, 4, 0, 0, 85, 5, true },
  973. };
  974.  
  975. const int obit_suicide(int weap){
  976. if(melee_weap(weap)) return OBIT_FF;
  977. if(weap >= 0 && weap <= OBIT_START) return weap;
  978. switch(weap - OBIT_START){
  979. case 0: return OBIT_ASSIST;
  980. case 1: return OBIT_NUKE;
  981. case 2: return OBIT_FALL;
  982. case 3: return OBIT_FALL_WATER;
  983. case 10: return OBIT_DEATH;
  984. case 11: return OBIT_BOT;
  985. case 12: return OBIT_CHEAT;
  986. case 13: return OBIT_DROWN;
  987. case 14: return OBIT_SPAWN;
  988. case 21: return OBIT_TEAM;
  989. case 22: return OBIT_SPECT;
  990. }
  991. return OBIT_DEATH;
  992. }
  993.  
  994. const char *suicname(int obit){
  995. static string k;
  996. *k = 0;
  997. switch(obit){
  998. // ricochet from teamkill specific
  999. case WEAP_SHOTGUN:
  1000. concatstring(k, "suic_shotgun");
  1001. break;
  1002. case WEAP_SUBGUN:
  1003. case WEAP_ASSAULT:
  1004. case WEAP_ASSAULT2:
  1005. concatstring(k, "suic_rifle");
  1006. break;
  1007. case WEAP_SNIPER:
  1008. case WEAP_BOLT:
  1009. case WEAP_SNIPER2:
  1010. concatstring(k, "suic_snipe");
  1011. break;
  1012. case WEAP_PISTOL:
  1013. case WEAP_AKIMBO:
  1014. concatstring(k, "suic_pistol");
  1015. break;
  1016. // END of ricochet
  1017. // teams
  1018. case OBIT_SPECT:
  1019. concatstring(k, "suic_spect");
  1020. break;
  1021. case OBIT_TEAM:
  1022. concatstring(k, "suic_team");
  1023. break;
  1024. // weapons
  1025. case WEAP_GRENADE:
  1026. concatstring(k, "suic_nade");
  1027. break;
  1028. case WEAP_HEAL:
  1029. concatstring(k, "suic_heal");
  1030. break;
  1031. case WEAP_RPG:
  1032. concatstring(k, "suic_rpg");
  1033. break;
  1034. case OBIT_DEATH:
  1035. concatstring(k, "suic_death");
  1036. break;
  1037. case OBIT_AIRSTRIKE:
  1038. concatstring(k, "suic_airstrike");
  1039. break;
  1040. case OBIT_NUKE:
  1041. concatstring(k, "suic_nuke");
  1042. break;
  1043. case OBIT_FF:
  1044. concatstring(k, "suic_ff");
  1045. break;
  1046. case OBIT_BOT:
  1047. concatstring(k, "suic_bot");
  1048. break;
  1049. case OBIT_DROWN:
  1050. concatstring(k, "suic_drown");
  1051. break;
  1052. case OBIT_FALL:
  1053. concatstring(k, "suic_fall");
  1054. break;
  1055. case OBIT_FALL_WATER:
  1056. concatstring(k, "suic_fall_water");
  1057. break;
  1058. case OBIT_CHEAT:
  1059. concatstring(k, "suic_cheat");
  1060. break;
  1061. case OBIT_SPAWN:
  1062. concatstring(k, "suic_spawn");
  1063. break;
  1064. default:
  1065. concatstring(k, "suicide");
  1066. break;
  1067. }
  1068. return k;
  1069. }
  1070.  
  1071. const bool isheadshot(int weapon, int style){
  1072. if(!(style & FRAG_GIB)) return false; // only gibs headshot
  1073. switch(weapon){
  1074. case WEAP_KNIFE:
  1075. case WEAP_SWORD:
  1076. case WEAP_GRENADE:
  1077. case WEAP_RPG:
  1078. if(style & FRAG_FLAG) break; // these weapons headshot if FRAG_FLAG is set
  1079. case WEAP_MAX + 1:
  1080. case WEAP_MAX + 10:
  1081. return false; // these weapons cannot headshot
  1082. }
  1083. // headshot = gib if otherwise
  1084. return true;
  1085. }
  1086.  
  1087. const int toobit(int weap, int style){
  1088. const bool gib = (style & FRAG_GIB) > 0,
  1089. flag = (style & FRAG_FLAG) > 0;
  1090. switch(weap){
  1091. case WEAP_KNIFE: return gib ? WEAP_KNIFE : flag ? OBIT_KNIFE_IMPACT : OBIT_KNIFE_BLEED;
  1092. case WEAP_RPG: return gib ? OBIT_IMPACT : flag ? OBIT_RPG_STUCK : WEAP_RPG;
  1093. case WEAP_GRENADE: return gib ? WEAP_GRENADE : OBIT_AIRSTRIKE;
  1094. case WEAP_MAX + 0: return OBIT_ASSIST; // assisted suicide
  1095. case WEAP_MAX + 1: return OBIT_NUKE;
  1096. case WEAP_MAX + 2: return OBIT_FALL;
  1097. case WEAP_MAX + 3: return OBIT_FALL_WATER; // splash?
  1098. }
  1099. return weap < WEAP_MAX ? weap : OBIT_DEATH;
  1100. }
  1101.  
  1102. const char *killname(int obit, bool headshot){
  1103. static string k;
  1104. *k = 0;
  1105. switch(obit){
  1106. case WEAP_GRENADE:
  1107. concatstring(k, headshot ? "kill_nade_hs" : "kill_nade");
  1108. break;
  1109. case WEAP_KNIFE:
  1110. concatstring(k, headshot ? "kill_knife_hs" : "kill_knife");
  1111. break;
  1112. case WEAP_BOLT:
  1113. concatstring(k, headshot ? "kill_bolt_hs" : "kill_bolt");
  1114. break;
  1115. case WEAP_SNIPER:
  1116. concatstring(k, headshot ? "kill_sniper_hs" : "kill_sniper");
  1117. break;
  1118. case WEAP_SNIPER2:
  1119. concatstring(k, headshot ? "kill_sniper2_hs" : "kill_sniper2");
  1120. break;
  1121. case WEAP_SUBGUN:
  1122. concatstring(k, headshot ? "kill_smg_hs" : "kill_smg");
  1123. break;
  1124. case WEAP_SHOTGUN:
  1125. concatstring(k, headshot ? "kill_shotgun_hs" : "kill_shotgun");
  1126. break;
  1127. case WEAP_ASSAULT:
  1128. concatstring(k, headshot ? "kill_ar_hs" : "kill_ar");
  1129. break;
  1130. case WEAP_ASSAULT2:
  1131. concatstring(k, headshot ? "kill_ak_hs" : "kill_ak");
  1132. break;
  1133. case WEAP_PISTOL:
  1134. concatstring(k, headshot ? "kill_pistol_hs" : "kill_pistol");
  1135. break;
  1136. case WEAP_AKIMBO:
  1137. concatstring(k, headshot ? "kill_akimbo_hs" : "kill_akimbo");
  1138. break;
  1139. case WEAP_HEAL:
  1140. concatstring(k, headshot ? "kill_heal_hs" : "kill_heal");
  1141. break;
  1142. case WEAP_SWORD:
  1143. concatstring(k, headshot ? "kill_sword_hs" : "kill_sword");
  1144. break;
  1145. case WEAP_RPG:
  1146. concatstring(k, "kill_rpg");
  1147. break;
  1148. // special obits
  1149. case OBIT_IMPACT:
  1150. concatstring(k, headshot ? "kill_impact_hs" : "kill_impact");
  1151. break;
  1152. case OBIT_RPG_STUCK:
  1153. concatstring(k, "kill_rpg_stuck");
  1154. break;
  1155. case OBIT_KNIFE_BLEED:
  1156. concatstring(k, "kill_knife_bleed");
  1157. break;
  1158. case OBIT_KNIFE_IMPACT:
  1159. concatstring(k, "kill_knife_impact");
  1160. break;
  1161. case OBIT_AIRSTRIKE:
  1162. concatstring(k, "kill_airstrike");
  1163. break;
  1164. case OBIT_ASSIST:
  1165. concatstring(k, headshot ? "kill_assist_hs" : "kill_assist");
  1166. break;
  1167. case OBIT_FALL:
  1168. concatstring(k, "kill_fall");
  1169. break;
  1170. case OBIT_NUKE:
  1171. concatstring(k, "kill_nuke");
  1172. break;
  1173. default:
  1174. concatstring(k, headshot ? "kill_hs" : "kill");
  1175. break;
  1176. }
  1177. return k;
  1178. }
  1179.  
  1180. // perk-related
  1181. float gunspeed(int gun, int ads, bool lightweight){
  1182. float ret = lightweight ? 1.07f : 1;
  1183. if(ads) ret *= 1 - ads / (lightweight ? 3500 : 3000.f);
  1184. switch(gun){
  1185. case WEAP_KNIFE:
  1186. case WEAP_PISTOL:
  1187. case WEAP_GRENADE:
  1188. case WEAP_HEAL:
  1189. //ret *= 1;
  1190. break;
  1191. case WEAP_SWORD:
  1192. ret *= .98f;
  1193. break;
  1194. case WEAP_AKIMBO:
  1195. ret *= .96f;
  1196. break;
  1197. case WEAP_SNIPER:
  1198. case WEAP_BOLT:
  1199. case WEAP_SNIPER2:
  1200. ret *= .93f;
  1201. break;
  1202. case WEAP_SHOTGUN:
  1203. case WEAP_SUBGUN:
  1204. ret *= .93f;
  1205. break;
  1206. case WEAP_ASSAULT:
  1207. case WEAP_ASSAULT2:
  1208. case WEAP_RPG:
  1209. ret *= .92f;
  1210. break;
  1211. }
  1212. return ret;
  1213. }
  1214.  
  1215. // format names for the server
  1216. const char *formatname(client *c)
  1217. {
  1218. if(!c) return "unknown";
  1219. static string cname[3];
  1220. static int idx = 0;
  1221. if(idx >= 3) idx %= 3;
  1222. if(c->type == ST_AI) formatstring(cname[idx])("%s [%d-%d]", c->name, c->clientnum, c->state.ownernum);
  1223. else formatstring(cname[idx])("%s (%d)", c->name, c->clientnum);
  1224. return cname[idx++];
  1225. }
  1226.  
  1227. // overloading!
  1228. const char *formatname(client &c)
  1229. {
  1230. return formatname(&c);
  1231. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement