p_client.c 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742
  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. #include "g_local.h"
  16. #include "m_player.h"
  17. void SP_misc_teleporter_dest (edict_t *ent);
  18. //
  19. // Gross, ugly, disgustuing hack section
  20. //
  21. // this function is an ugly as hell hack to fix some map flaws
  22. //
  23. // the coop spawn spots on some maps are SNAFU. There are coop spots
  24. // with the wrong targetname as well as spots with no name at all
  25. //
  26. // we use carnal knowledge of the maps to fix the coop spot targetnames to match
  27. // that of the nearest named single player spot
  28. static void SP_FixCoopSpots (edict_t *self)
  29. {
  30. edict_t *spot;
  31. vec3_t d;
  32. spot = NULL;
  33. while(1)
  34. {
  35. spot = G_Find(spot, FOFS(classname), "info_player_start");
  36. if (!spot)
  37. return;
  38. if (!spot->targetname)
  39. continue;
  40. VectorSubtract(self->s.origin, spot->s.origin, d);
  41. if (VectorLength(d) < 384)
  42. {
  43. if ((!self->targetname) || stricmp(self->targetname, spot->targetname) != 0)
  44. {
  45. // gi.dprintf("FixCoopSpots changed %s at %s targetname from %s to %s\n", self->classname, vtos(self->s.origin), self->targetname, spot->targetname);
  46. self->targetname = spot->targetname;
  47. }
  48. return;
  49. }
  50. }
  51. }
  52. // now if that one wasn't ugly enough for you then try this one on for size
  53. // some maps don't have any coop spots at all, so we need to create them
  54. // where they should have been
  55. static void SP_CreateCoopSpots (edict_t *self)
  56. {
  57. edict_t *spot;
  58. if(stricmp(level.mapname, "security") == 0)
  59. {
  60. spot = G_Spawn();
  61. spot->classname = "info_player_coop";
  62. spot->s.origin[0] = 188 - 64;
  63. spot->s.origin[1] = -164;
  64. spot->s.origin[2] = 80;
  65. spot->targetname = "jail3";
  66. spot->s.angles[1] = 90;
  67. spot = G_Spawn();
  68. spot->classname = "info_player_coop";
  69. spot->s.origin[0] = 188 + 64;
  70. spot->s.origin[1] = -164;
  71. spot->s.origin[2] = 80;
  72. spot->targetname = "jail3";
  73. spot->s.angles[1] = 90;
  74. spot = G_Spawn();
  75. spot->classname = "info_player_coop";
  76. spot->s.origin[0] = 188 + 128;
  77. spot->s.origin[1] = -164;
  78. spot->s.origin[2] = 80;
  79. spot->targetname = "jail3";
  80. spot->s.angles[1] = 90;
  81. return;
  82. }
  83. }
  84. /*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 32)
  85. The normal starting point for a level.
  86. */
  87. void SP_info_player_start(edict_t *self)
  88. {
  89. if (!coop->value)
  90. return;
  91. if(stricmp(level.mapname, "security") == 0)
  92. {
  93. // invoke one of our gross, ugly, disgusting hacks
  94. self->think = SP_CreateCoopSpots;
  95. self->nextthink = level.time + FRAMETIME;
  96. }
  97. }
  98. /*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 32)
  99. potential spawning position for deathmatch games
  100. */
  101. void SP_info_player_deathmatch(edict_t *self)
  102. {
  103. if (!deathmatch->value)
  104. {
  105. G_FreeEdict (self);
  106. return;
  107. }
  108. SP_misc_teleporter_dest (self);
  109. }
  110. /*QUAKED info_player_coop (1 0 1) (-16 -16 -24) (16 16 32)
  111. potential spawning position for coop games
  112. */
  113. void SP_info_player_coop(edict_t *self)
  114. {
  115. if (!coop->value)
  116. {
  117. G_FreeEdict (self);
  118. return;
  119. }
  120. if((stricmp(level.mapname, "jail2") == 0) ||
  121. (stricmp(level.mapname, "jail4") == 0) ||
  122. (stricmp(level.mapname, "mine1") == 0) ||
  123. (stricmp(level.mapname, "mine2") == 0) ||
  124. (stricmp(level.mapname, "mine3") == 0) ||
  125. (stricmp(level.mapname, "mine4") == 0) ||
  126. (stricmp(level.mapname, "lab") == 0) ||
  127. (stricmp(level.mapname, "boss1") == 0) ||
  128. (stricmp(level.mapname, "fact3") == 0) ||
  129. (stricmp(level.mapname, "biggun") == 0) ||
  130. (stricmp(level.mapname, "space") == 0) ||
  131. (stricmp(level.mapname, "command") == 0) ||
  132. (stricmp(level.mapname, "power2") == 0) ||
  133. (stricmp(level.mapname, "strike") == 0))
  134. {
  135. // invoke one of our gross, ugly, disgusting hacks
  136. self->think = SP_FixCoopSpots;
  137. self->nextthink = level.time + FRAMETIME;
  138. }
  139. }
  140. /*QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32)
  141. The deathmatch intermission point will be at one of these
  142. Use 'angles' instead of 'angle', so you can set pitch or roll as well as yaw. 'pitch yaw roll'
  143. */
  144. void SP_info_player_intermission(void)
  145. {
  146. }
  147. //=======================================================================
  148. void player_pain (edict_t *self, edict_t *other, float kick, int damage)
  149. {
  150. // player pain is handled at the end of the frame in P_DamageFeedback
  151. }
  152. qboolean IsFemale (edict_t *ent)
  153. {
  154. char *info;
  155. if (!ent->client)
  156. return false;
  157. info = Info_ValueForKey (ent->client->pers.userinfo, "skin");
  158. if (info[0] == 'f' || info[0] == 'F')
  159. return true;
  160. return false;
  161. }
  162. void ClientObituary (edict_t *self, edict_t *inflictor, edict_t *attacker)
  163. {
  164. int mod;
  165. char *message;
  166. char *message2;
  167. qboolean ff;
  168. if (coop->value && attacker->client)
  169. meansOfDeath |= MOD_FRIENDLY_FIRE;
  170. if (deathmatch->value || coop->value)
  171. {
  172. ff = meansOfDeath & MOD_FRIENDLY_FIRE;
  173. mod = meansOfDeath & ~MOD_FRIENDLY_FIRE;
  174. message = NULL;
  175. message2 = "";
  176. switch (mod)
  177. {
  178. case MOD_SUICIDE:
  179. message = "suicides";
  180. break;
  181. case MOD_FALLING:
  182. message = "cratered";
  183. break;
  184. case MOD_CRUSH:
  185. message = "was squished";
  186. break;
  187. case MOD_WATER:
  188. message = "sank like a rock";
  189. break;
  190. case MOD_SLIME:
  191. message = "melted";
  192. break;
  193. case MOD_LAVA:
  194. message = "does a back flip into the lava";
  195. break;
  196. case MOD_EXPLOSIVE:
  197. case MOD_BARREL:
  198. message = "blew up";
  199. break;
  200. case MOD_EXIT:
  201. message = "found a way out";
  202. break;
  203. case MOD_TARGET_LASER:
  204. message = "saw the light";
  205. break;
  206. case MOD_TARGET_BLASTER:
  207. message = "got blasted";
  208. break;
  209. case MOD_BOMB:
  210. case MOD_SPLASH:
  211. case MOD_TRIGGER_HURT:
  212. message = "was in the wrong place";
  213. break;
  214. }
  215. if (attacker == self)
  216. {
  217. switch (mod)
  218. {
  219. case MOD_HELD_GRENADE:
  220. message = "tried to put the pin back in";
  221. break;
  222. case MOD_HG_SPLASH:
  223. case MOD_G_SPLASH:
  224. if (IsFemale(self))
  225. message = "tripped on her own grenade";
  226. else
  227. message = "tripped on his own grenade";
  228. break;
  229. case MOD_R_SPLASH:
  230. if (IsFemale(self))
  231. message = "blew herself up";
  232. else
  233. message = "blew himself up";
  234. break;
  235. case MOD_BFG_BLAST:
  236. message = "should have used a smaller gun";
  237. break;
  238. default:
  239. if (IsFemale(self))
  240. message = "killed herself";
  241. else
  242. message = "killed himself";
  243. break;
  244. }
  245. }
  246. if (message)
  247. {
  248. gi.bprintf (PRINT_MEDIUM, "%s %s.\n", self->client->pers.netname, message);
  249. if (deathmatch->value)
  250. self->client->resp.score--;
  251. self->enemy = NULL;
  252. return;
  253. }
  254. self->enemy = attacker;
  255. if (attacker && attacker->client)
  256. {
  257. switch (mod)
  258. {
  259. case MOD_BLASTER:
  260. message = "was blasted by";
  261. break;
  262. case MOD_SHOTGUN:
  263. message = "was gunned down by";
  264. break;
  265. case MOD_SSHOTGUN:
  266. message = "was blown away by";
  267. message2 = "'s super shotgun";
  268. break;
  269. case MOD_MACHINEGUN:
  270. message = "was machinegunned by";
  271. break;
  272. case MOD_CHAINGUN:
  273. message = "was cut in half by";
  274. message2 = "'s chaingun";
  275. break;
  276. case MOD_GRENADE:
  277. message = "was popped by";
  278. message2 = "'s grenade";
  279. break;
  280. case MOD_G_SPLASH:
  281. message = "was shredded by";
  282. message2 = "'s shrapnel";
  283. break;
  284. case MOD_ROCKET:
  285. message = "ate";
  286. message2 = "'s rocket";
  287. break;
  288. case MOD_R_SPLASH:
  289. message = "almost dodged";
  290. message2 = "'s rocket";
  291. break;
  292. case MOD_HYPERBLASTER:
  293. message = "was melted by";
  294. message2 = "'s hyperblaster";
  295. break;
  296. case MOD_RAILGUN:
  297. message = "was railed by";
  298. break;
  299. case MOD_BFG_LASER:
  300. message = "saw the pretty lights from";
  301. message2 = "'s BFG";
  302. break;
  303. case MOD_BFG_BLAST:
  304. message = "was disintegrated by";
  305. message2 = "'s BFG blast";
  306. break;
  307. case MOD_BFG_EFFECT:
  308. message = "couldn't hide from";
  309. message2 = "'s BFG";
  310. break;
  311. case MOD_HANDGRENADE:
  312. message = "caught";
  313. message2 = "'s handgrenade";
  314. break;
  315. case MOD_HG_SPLASH:
  316. message = "didn't see";
  317. message2 = "'s handgrenade";
  318. break;
  319. case MOD_HELD_GRENADE:
  320. message = "feels";
  321. message2 = "'s pain";
  322. break;
  323. case MOD_TELEFRAG:
  324. message = "tried to invade";
  325. message2 = "'s personal space";
  326. break;
  327. //ZOID
  328. case MOD_GRAPPLE:
  329. message = "was caught by";
  330. message2 = "'s grapple";
  331. break;
  332. //ZOID
  333. }
  334. if (message)
  335. {
  336. gi.bprintf (PRINT_MEDIUM,"%s %s %s%s\n", self->client->pers.netname, message, attacker->client->pers.netname, message2);
  337. if (deathmatch->value)
  338. {
  339. if (ff)
  340. attacker->client->resp.score--;
  341. else
  342. attacker->client->resp.score++;
  343. }
  344. return;
  345. }
  346. }
  347. }
  348. gi.bprintf (PRINT_MEDIUM,"%s died.\n", self->client->pers.netname);
  349. if (deathmatch->value)
  350. self->client->resp.score--;
  351. }
  352. void Touch_Item (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf);
  353. void TossClientWeapon (edict_t *self)
  354. {
  355. gitem_t *item;
  356. edict_t *drop;
  357. qboolean quad;
  358. float spread;
  359. if (!deathmatch->value)
  360. return;
  361. item = self->client->pers.weapon;
  362. if (! self->client->pers.inventory[self->client->ammo_index] )
  363. item = NULL;
  364. if (item && (strcmp (item->pickup_name, "Blaster") == 0))
  365. item = NULL;
  366. if (!((int)(dmflags->value) & DF_QUAD_DROP))
  367. quad = false;
  368. else
  369. quad = (self->client->quad_framenum > (level.framenum + 10));
  370. if (item && quad)
  371. spread = 22.5;
  372. else
  373. spread = 0.0;
  374. if (item)
  375. {
  376. self->client->v_angle[YAW] -= spread;
  377. drop = Drop_Item (self, item);
  378. self->client->v_angle[YAW] += spread;
  379. drop->spawnflags = DROPPED_PLAYER_ITEM;
  380. }
  381. if (quad)
  382. {
  383. self->client->v_angle[YAW] += spread;
  384. drop = Drop_Item (self, FindItemByClassname ("item_quad"));
  385. self->client->v_angle[YAW] -= spread;
  386. drop->spawnflags |= DROPPED_PLAYER_ITEM;
  387. drop->touch = Touch_Item;
  388. drop->nextthink = level.time + (self->client->quad_framenum - level.framenum) * FRAMETIME;
  389. drop->think = G_FreeEdict;
  390. }
  391. }
  392. /*
  393. ==================
  394. LookAtKiller
  395. ==================
  396. */
  397. void LookAtKiller (edict_t *self, edict_t *inflictor, edict_t *attacker)
  398. {
  399. vec3_t dir;
  400. if (attacker && attacker != world && attacker != self)
  401. {
  402. VectorSubtract (attacker->s.origin, self->s.origin, dir);
  403. }
  404. else if (inflictor && inflictor != world && inflictor != self)
  405. {
  406. VectorSubtract (inflictor->s.origin, self->s.origin, dir);
  407. }
  408. else
  409. {
  410. self->client->killer_yaw = self->s.angles[YAW];
  411. return;
  412. }
  413. if (dir[0])
  414. self->client->killer_yaw = 180/M_PI*atan2(dir[1], dir[0]);
  415. else {
  416. self->client->killer_yaw = 0;
  417. if (dir[1] > 0)
  418. self->client->killer_yaw = 90;
  419. else if (dir[1] < 0)
  420. self->client->killer_yaw = -90;
  421. }
  422. if (self->client->killer_yaw < 0)
  423. self->client->killer_yaw += 360;
  424. }
  425. /*
  426. ==================
  427. player_die
  428. ==================
  429. */
  430. void player_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  431. {
  432. int n;
  433. VectorClear (self->avelocity);
  434. self->takedamage = DAMAGE_YES;
  435. self->movetype = MOVETYPE_TOSS;
  436. self->s.modelindex2 = 0; // remove linked weapon model
  437. //ZOID
  438. self->s.modelindex3 = 0; // remove linked ctf flag
  439. //ZOID
  440. self->s.angles[0] = 0;
  441. self->s.angles[2] = 0;
  442. self->s.sound = 0;
  443. self->client->weapon_sound = 0;
  444. self->maxs[2] = -8;
  445. // self->solid = SOLID_NOT;
  446. self->svflags |= SVF_DEADMONSTER;
  447. if (!self->deadflag)
  448. {
  449. self->client->respawn_time = level.time + 1.0;
  450. LookAtKiller (self, inflictor, attacker);
  451. self->client->ps.pmove.pm_type = PM_DEAD;
  452. ClientObituary (self, inflictor, attacker);
  453. //ZOID
  454. // if at start and same team, clear
  455. if (ctf->value && meansOfDeath == MOD_TELEFRAG &&
  456. self->client->resp.ctf_state < 2 &&
  457. self->client->resp.ctf_team == attacker->client->resp.ctf_team) {
  458. attacker->client->resp.score--;
  459. self->client->resp.ctf_state = 0;
  460. }
  461. CTFFragBonuses(self, inflictor, attacker);
  462. //ZOID
  463. TossClientWeapon (self);
  464. //ZOID
  465. CTFPlayerResetGrapple(self);
  466. CTFDeadDropFlag(self);
  467. CTFDeadDropTech(self);
  468. //ZOID
  469. if (deathmatch->value && !self->client->showscores)
  470. Cmd_Help_f (self); // show scores
  471. }
  472. // remove powerups
  473. self->client->quad_framenum = 0;
  474. self->client->invincible_framenum = 0;
  475. self->client->breather_framenum = 0;
  476. self->client->enviro_framenum = 0;
  477. self->flags &= ~FL_POWER_ARMOR;
  478. // clear inventory
  479. memset(self->client->pers.inventory, 0, sizeof(self->client->pers.inventory));
  480. if (self->health < -40)
  481. { // gib
  482. gi.sound (self, CHAN_BODY, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
  483. for (n= 0; n < 4; n++)
  484. ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
  485. ThrowClientHead (self, damage);
  486. //ZOID
  487. self->client->anim_priority = ANIM_DEATH;
  488. self->client->anim_end = 0;
  489. //ZOID
  490. self->takedamage = DAMAGE_NO;
  491. }
  492. else
  493. { // normal death
  494. if (!self->deadflag)
  495. {
  496. static int i;
  497. i = (i+1)%3;
  498. // start a death animation
  499. self->client->anim_priority = ANIM_DEATH;
  500. if (self->client->ps.pmove.pm_flags & PMF_DUCKED)
  501. {
  502. self->s.frame = FRAME_crdeath1-1;
  503. self->client->anim_end = FRAME_crdeath5;
  504. }
  505. else switch (i)
  506. {
  507. case 0:
  508. self->s.frame = FRAME_death101-1;
  509. self->client->anim_end = FRAME_death106;
  510. break;
  511. case 1:
  512. self->s.frame = FRAME_death201-1;
  513. self->client->anim_end = FRAME_death206;
  514. break;
  515. case 2:
  516. self->s.frame = FRAME_death301-1;
  517. self->client->anim_end = FRAME_death308;
  518. break;
  519. }
  520. gi.sound (self, CHAN_VOICE, gi.soundindex(va("*death%i.wav", (rand()%4)+1)), 1, ATTN_NORM, 0);
  521. }
  522. }
  523. self->deadflag = DEAD_DEAD;
  524. gi.linkentity (self);
  525. }
  526. //=======================================================================
  527. /*
  528. ==============
  529. InitClientPersistant
  530. This is only called when the game first initializes in single player,
  531. but is called after each death and level change in deathmatch
  532. ==============
  533. */
  534. void InitClientPersistant (gclient_t *client)
  535. {
  536. gitem_t *item;
  537. memset (&client->pers, 0, sizeof(client->pers));
  538. item = FindItem("Blaster");
  539. client->pers.selected_item = ITEM_INDEX(item);
  540. client->pers.inventory[client->pers.selected_item] = 1;
  541. client->pers.weapon = item;
  542. //ZOID
  543. client->pers.lastweapon = item;
  544. //ZOID
  545. //ZOID
  546. item = FindItem("Grapple");
  547. client->pers.inventory[ITEM_INDEX(item)] = 1;
  548. //ZOID
  549. client->pers.health = 100;
  550. client->pers.max_health = 100;
  551. client->pers.max_bullets = 200;
  552. client->pers.max_shells = 100;
  553. client->pers.max_rockets = 50;
  554. client->pers.max_grenades = 50;
  555. client->pers.max_cells = 200;
  556. client->pers.max_slugs = 50;
  557. client->pers.connected = true;
  558. }
  559. void InitClientResp (gclient_t *client)
  560. {
  561. //ZOID
  562. int ctf_team = client->resp.ctf_team;
  563. qboolean id_state = client->resp.id_state;
  564. //ZOID
  565. memset (&client->resp, 0, sizeof(client->resp));
  566. //ZOID
  567. client->resp.ctf_team = ctf_team;
  568. client->resp.id_state = id_state;
  569. //ZOID
  570. client->resp.enterframe = level.framenum;
  571. client->resp.coop_respawn = client->pers;
  572. //ZOID
  573. if (ctf->value && client->resp.ctf_team < CTF_TEAM1)
  574. CTFAssignTeam(client);
  575. //ZOID
  576. }
  577. /*
  578. ==================
  579. SaveClientData
  580. Some information that should be persistant, like health,
  581. is still stored in the edict structure, so it needs to
  582. be mirrored out to the client structure before all the
  583. edicts are wiped.
  584. ==================
  585. */
  586. void SaveClientData (void)
  587. {
  588. int i;
  589. edict_t *ent;
  590. for (i=0 ; i<game.maxclients ; i++)
  591. {
  592. ent = &g_edicts[1+i];
  593. if (!ent->inuse)
  594. continue;
  595. game.clients[i].pers.health = ent->health;
  596. game.clients[i].pers.max_health = ent->max_health;
  597. game.clients[i].pers.savedFlags = (ent->flags & (FL_GODMODE|FL_NOTARGET|FL_POWER_ARMOR));
  598. if (coop->value)
  599. game.clients[i].pers.score = ent->client->resp.score;
  600. }
  601. }
  602. void FetchClientEntData (edict_t *ent)
  603. {
  604. ent->health = ent->client->pers.health;
  605. ent->max_health = ent->client->pers.max_health;
  606. ent->flags |= ent->client->pers.savedFlags;
  607. if (coop->value)
  608. ent->client->resp.score = ent->client->pers.score;
  609. }
  610. /*
  611. =======================================================================
  612. SelectSpawnPoint
  613. =======================================================================
  614. */
  615. /*
  616. ================
  617. PlayersRangeFromSpot
  618. Returns the distance to the nearest player from the given spot
  619. ================
  620. */
  621. float PlayersRangeFromSpot (edict_t *spot)
  622. {
  623. edict_t *player;
  624. float bestplayerdistance;
  625. vec3_t v;
  626. int n;
  627. float playerdistance;
  628. bestplayerdistance = 9999999;
  629. for (n = 1; n <= maxclients->value; n++)
  630. {
  631. player = &g_edicts[n];
  632. if (!player->inuse)
  633. continue;
  634. if (player->health <= 0)
  635. continue;
  636. VectorSubtract (spot->s.origin, player->s.origin, v);
  637. playerdistance = VectorLength (v);
  638. if (playerdistance < bestplayerdistance)
  639. bestplayerdistance = playerdistance;
  640. }
  641. return bestplayerdistance;
  642. }
  643. /*
  644. ================
  645. SelectRandomDeathmatchSpawnPoint
  646. go to a random point, but NOT the two points closest
  647. to other players
  648. ================
  649. */
  650. edict_t *SelectRandomDeathmatchSpawnPoint (void)
  651. {
  652. edict_t *spot, *spot1, *spot2;
  653. int count = 0;
  654. int selection;
  655. float range, range1, range2;
  656. spot = NULL;
  657. range1 = range2 = 99999;
  658. spot1 = spot2 = NULL;
  659. while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL)
  660. {
  661. count++;
  662. range = PlayersRangeFromSpot(spot);
  663. if (range < range1)
  664. {
  665. range1 = range;
  666. spot1 = spot;
  667. }
  668. else if (range < range2)
  669. {
  670. range2 = range;
  671. spot2 = spot;
  672. }
  673. }
  674. if (!count)
  675. return NULL;
  676. if (count <= 2)
  677. {
  678. spot1 = spot2 = NULL;
  679. }
  680. else
  681. count -= 2;
  682. selection = rand() % count;
  683. spot = NULL;
  684. do
  685. {
  686. spot = G_Find (spot, FOFS(classname), "info_player_deathmatch");
  687. if (spot == spot1 || spot == spot2)
  688. selection++;
  689. } while(selection--);
  690. return spot;
  691. }
  692. /*
  693. ================
  694. SelectFarthestDeathmatchSpawnPoint
  695. ================
  696. */
  697. edict_t *SelectFarthestDeathmatchSpawnPoint (void)
  698. {
  699. edict_t *bestspot;
  700. float bestdistance, bestplayerdistance;
  701. edict_t *spot;
  702. spot = NULL;
  703. bestspot = NULL;
  704. bestdistance = 0;
  705. while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL)
  706. {
  707. bestplayerdistance = PlayersRangeFromSpot (spot);
  708. if (bestplayerdistance > bestdistance)
  709. {
  710. bestspot = spot;
  711. bestdistance = bestplayerdistance;
  712. }
  713. }
  714. if (bestspot)
  715. {
  716. return bestspot;
  717. }
  718. // if there is a player just spawned on each and every start spot
  719. // we have no choice to turn one into a telefrag meltdown
  720. spot = G_Find (NULL, FOFS(classname), "info_player_deathmatch");
  721. return spot;
  722. }
  723. edict_t *SelectDeathmatchSpawnPoint (void)
  724. {
  725. if ( (int)(dmflags->value) & DF_SPAWN_FARTHEST)
  726. return SelectFarthestDeathmatchSpawnPoint ();
  727. else
  728. return SelectRandomDeathmatchSpawnPoint ();
  729. }
  730. edict_t *SelectCoopSpawnPoint (edict_t *ent)
  731. {
  732. int index;
  733. edict_t *spot = NULL;
  734. char *target;
  735. index = ent->client - game.clients;
  736. // player 0 starts in normal player spawn point
  737. if (!index)
  738. return NULL;
  739. spot = NULL;
  740. // assume there are four coop spots at each spawnpoint
  741. while (1)
  742. {
  743. spot = G_Find (spot, FOFS(classname), "info_player_coop");
  744. if (!spot)
  745. return NULL; // we didn't have enough...
  746. target = spot->targetname;
  747. if (!target)
  748. target = "";
  749. if ( Q_stricmp(game.spawnpoint, target) == 0 )
  750. { // this is a coop spawn point for one of the clients here
  751. index--;
  752. if (!index)
  753. return spot; // this is it
  754. }
  755. }
  756. return spot;
  757. }
  758. /*
  759. ===========
  760. SelectSpawnPoint
  761. Chooses a player start, deathmatch start, coop start, etc
  762. ============
  763. */
  764. void SelectSpawnPoint (edict_t *ent, vec3_t origin, vec3_t angles)
  765. {
  766. edict_t *spot = NULL;
  767. if (deathmatch->value)
  768. //ZOID
  769. if (ctf->value)
  770. spot = SelectCTFSpawnPoint(ent);
  771. else
  772. //ZOID
  773. spot = SelectDeathmatchSpawnPoint ();
  774. else if (coop->value)
  775. spot = SelectCoopSpawnPoint (ent);
  776. // find a single player start spot
  777. if (!spot)
  778. {
  779. while ((spot = G_Find (spot, FOFS(classname), "info_player_start")) != NULL)
  780. {
  781. if (!game.spawnpoint[0] && !spot->targetname)
  782. break;
  783. if (!game.spawnpoint[0] || !spot->targetname)
  784. continue;
  785. if (Q_stricmp(game.spawnpoint, spot->targetname) == 0)
  786. break;
  787. }
  788. if (!spot)
  789. {
  790. if (!game.spawnpoint[0])
  791. { // there wasn't a spawnpoint without a target, so use any
  792. spot = G_Find (spot, FOFS(classname), "info_player_start");
  793. }
  794. if (!spot)
  795. gi.error ("Couldn't find spawn point %s\n", game.spawnpoint);
  796. }
  797. }
  798. VectorCopy (spot->s.origin, origin);
  799. origin[2] += 9;
  800. VectorCopy (spot->s.angles, angles);
  801. }
  802. //======================================================================
  803. void InitBodyQue (void)
  804. {
  805. int i;
  806. edict_t *ent;
  807. level.body_que = 0;
  808. for (i=0; i<BODY_QUEUE_SIZE ; i++)
  809. {
  810. ent = G_Spawn();
  811. ent->classname = "bodyque";
  812. }
  813. }
  814. void body_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  815. {
  816. int n;
  817. if (self->health < -40)
  818. {
  819. gi.sound (self, CHAN_BODY, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
  820. for (n= 0; n < 4; n++)
  821. ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
  822. self->s.origin[2] -= 48;
  823. ThrowClientHead (self, damage);
  824. self->takedamage = DAMAGE_NO;
  825. }
  826. }
  827. void CopyToBodyQue (edict_t *ent)
  828. {
  829. edict_t *body;
  830. // grab a body que and cycle to the next one
  831. body = &g_edicts[(int)maxclients->value + level.body_que + 1];
  832. level.body_que = (level.body_que + 1) % BODY_QUEUE_SIZE;
  833. // FIXME: send an effect on the removed body
  834. gi.unlinkentity (ent);
  835. gi.unlinkentity (body);
  836. body->s = ent->s;
  837. body->s.number = body - g_edicts;
  838. body->svflags = ent->svflags;
  839. VectorCopy (ent->mins, body->mins);
  840. VectorCopy (ent->maxs, body->maxs);
  841. VectorCopy (ent->absmin, body->absmin);
  842. VectorCopy (ent->absmax, body->absmax);
  843. VectorCopy (ent->size, body->size);
  844. body->solid = ent->solid;
  845. body->clipmask = ent->clipmask;
  846. body->owner = ent->owner;
  847. body->movetype = ent->movetype;
  848. body->die = body_die;
  849. body->takedamage = DAMAGE_YES;
  850. gi.linkentity (body);
  851. }
  852. void respawn (edict_t *self)
  853. {
  854. if (deathmatch->value || coop->value)
  855. {
  856. if (self->movetype != MOVETYPE_NOCLIP)
  857. CopyToBodyQue (self);
  858. self->svflags &= ~SVF_NOCLIENT;
  859. PutClientInServer (self);
  860. // add a teleportation effect
  861. self->s.event = EV_PLAYER_TELEPORT;
  862. // hold in place briefly
  863. self->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
  864. self->client->ps.pmove.pm_time = 14;
  865. self->client->respawn_time = level.time;
  866. return;
  867. }
  868. // restart the entire server
  869. gi.AddCommandString ("menu_loadgame\n");
  870. }
  871. //==============================================================
  872. /*
  873. ===========
  874. PutClientInServer
  875. Called when a player connects to a server or respawns in
  876. a deathmatch.
  877. ============
  878. */
  879. void PutClientInServer (edict_t *ent)
  880. {
  881. vec3_t mins = {-16, -16, -24};
  882. vec3_t maxs = {16, 16, 32};
  883. int index;
  884. vec3_t spawn_origin, spawn_angles;
  885. gclient_t *client;
  886. int i;
  887. client_persistant_t saved;
  888. client_respawn_t resp;
  889. // find a spawn point
  890. // do it before setting health back up, so farthest
  891. // ranging doesn't count this client
  892. SelectSpawnPoint (ent, spawn_origin, spawn_angles);
  893. index = ent-g_edicts-1;
  894. client = ent->client;
  895. // deathmatch wipes most client data every spawn
  896. if (deathmatch->value)
  897. {
  898. char userinfo[MAX_INFO_STRING];
  899. resp = client->resp;
  900. memcpy (userinfo, client->pers.userinfo, sizeof(userinfo));
  901. InitClientPersistant (client);
  902. ClientUserinfoChanged (ent, userinfo);
  903. }
  904. else if (coop->value)
  905. {
  906. int n;
  907. char userinfo[MAX_INFO_STRING];
  908. resp = client->resp;
  909. memcpy (userinfo, client->pers.userinfo, sizeof(userinfo));
  910. // this is kind of ugly, but it's how we want to handle keys in coop
  911. for (n = 0; n < MAX_ITEMS; n++)
  912. {
  913. if (itemlist[n].flags & IT_KEY)
  914. resp.coop_respawn.inventory[n] = client->pers.inventory[n];
  915. }
  916. client->pers = resp.coop_respawn;
  917. ClientUserinfoChanged (ent, userinfo);
  918. if (resp.score > client->pers.score)
  919. client->pers.score = resp.score;
  920. }
  921. else
  922. {
  923. memset (&resp, 0, sizeof(resp));
  924. }
  925. // clear everything but the persistant data
  926. saved = client->pers;
  927. memset (client, 0, sizeof(*client));
  928. client->pers = saved;
  929. if (client->pers.health <= 0)
  930. InitClientPersistant(client);
  931. client->resp = resp;
  932. // copy some data from the client to the entity
  933. FetchClientEntData (ent);
  934. // clear entity values
  935. ent->groundentity = NULL;
  936. ent->client = &game.clients[index];
  937. ent->takedamage = DAMAGE_AIM;
  938. ent->movetype = MOVETYPE_WALK;
  939. ent->viewheight = 22;
  940. ent->inuse = true;
  941. ent->classname = "player";
  942. ent->mass = 200;
  943. ent->solid = SOLID_BBOX;
  944. ent->deadflag = DEAD_NO;
  945. ent->air_finished = level.time + 12;
  946. ent->clipmask = MASK_PLAYERSOLID;
  947. ent->model = "players/male/tris.md2";
  948. ent->pain = player_pain;
  949. ent->die = player_die;
  950. ent->waterlevel = 0;
  951. ent->watertype = 0;
  952. ent->flags &= ~FL_NO_KNOCKBACK;
  953. ent->svflags &= ~SVF_DEADMONSTER;
  954. VectorCopy (mins, ent->mins);
  955. VectorCopy (maxs, ent->maxs);
  956. VectorClear (ent->velocity);
  957. // clear playerstate values
  958. memset (&ent->client->ps, 0, sizeof(client->ps));
  959. client->ps.pmove.origin[0] = spawn_origin[0]*8;
  960. client->ps.pmove.origin[1] = spawn_origin[1]*8;
  961. client->ps.pmove.origin[2] = spawn_origin[2]*8;
  962. //ZOID
  963. client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
  964. //ZOID
  965. if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV))
  966. {
  967. client->ps.fov = 90;
  968. }
  969. else
  970. {
  971. client->ps.fov = atoi(Info_ValueForKey(client->pers.userinfo, "fov"));
  972. if (client->ps.fov < 1)
  973. client->ps.fov = 90;
  974. else if (client->ps.fov > 160)
  975. client->ps.fov = 160;
  976. }
  977. client->ps.gunindex = gi.modelindex(client->pers.weapon->view_model);
  978. // clear entity state values
  979. ent->s.effects = 0;
  980. ent->s.skinnum = ent - g_edicts - 1;
  981. ent->s.modelindex = 255; // will use the skin specified model
  982. ent->s.modelindex2 = 255; // custom gun model
  983. // sknum is player num and weapon number
  984. // weapon number will be added in changeweapon
  985. ent->s.skinnum = ent - g_edicts - 1;
  986. ent->s.frame = 0;
  987. VectorCopy (spawn_origin, ent->s.origin);
  988. ent->s.origin[2] += 1; // make sure off ground
  989. VectorCopy (ent->s.origin, ent->s.old_origin);
  990. // set the delta angle
  991. for (i=0 ; i<3 ; i++)
  992. client->ps.pmove.delta_angles[i] = ANGLE2SHORT(spawn_angles[i] - client->resp.cmd_angles[i]);
  993. ent->s.angles[PITCH] = 0;
  994. ent->s.angles[YAW] = spawn_angles[YAW];
  995. ent->s.angles[ROLL] = 0;
  996. VectorCopy (ent->s.angles, client->ps.viewangles);
  997. VectorCopy (ent->s.angles, client->v_angle);
  998. //ZOID
  999. if (CTFStartClient(ent))
  1000. return;
  1001. //ZOID
  1002. if (!KillBox (ent))
  1003. { // could't spawn in?
  1004. }
  1005. gi.linkentity (ent);
  1006. // force the current weapon up
  1007. client->newweapon = client->pers.weapon;
  1008. ChangeWeapon (ent);
  1009. }
  1010. /*
  1011. =====================
  1012. ClientBeginDeathmatch
  1013. A client has just connected to the server in
  1014. deathmatch mode, so clear everything out before starting them.
  1015. =====================
  1016. */
  1017. void ClientBeginDeathmatch (edict_t *ent)
  1018. {
  1019. G_InitEdict (ent);
  1020. InitClientResp (ent->client);
  1021. // locate ent at a spawn point
  1022. PutClientInServer (ent);
  1023. if (level.intermissiontime)
  1024. {
  1025. MoveClientToIntermission (ent);
  1026. }
  1027. else
  1028. {
  1029. // send effect
  1030. gi.WriteByte (svc_muzzleflash);
  1031. gi.WriteShort (ent-g_edicts);
  1032. gi.WriteByte (MZ_LOGIN);
  1033. gi.multicast (ent->s.origin, MULTICAST_PVS);
  1034. }
  1035. gi.bprintf (PRINT_HIGH, "%s entered the game\n", ent->client->pers.netname);
  1036. // make sure all view stuff is valid
  1037. ClientEndServerFrame (ent);
  1038. }
  1039. /*
  1040. ===========
  1041. ClientBegin
  1042. called when a client has finished connecting, and is ready
  1043. to be placed into the game. This will happen every level load.
  1044. ============
  1045. */
  1046. void ClientBegin (edict_t *ent)
  1047. {
  1048. int i;
  1049. ent->client = game.clients + (ent - g_edicts - 1);
  1050. if (deathmatch->value)
  1051. {
  1052. ClientBeginDeathmatch (ent);
  1053. return;
  1054. }
  1055. // if there is already a body waiting for us (a loadgame), just
  1056. // take it, otherwise spawn one from scratch
  1057. if (ent->inuse == true)
  1058. {
  1059. // the client has cleared the client side viewangles upon
  1060. // connecting to the server, which is different than the
  1061. // state when the game is saved, so we need to compensate
  1062. // with deltaangles
  1063. for (i=0 ; i<3 ; i++)
  1064. ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(ent->client->ps.viewangles[i]);
  1065. }
  1066. else
  1067. {
  1068. // a spawn point will completely reinitialize the entity
  1069. // except for the persistant data that was initialized at
  1070. // ClientConnect() time
  1071. G_InitEdict (ent);
  1072. ent->classname = "player";
  1073. InitClientResp (ent->client);
  1074. PutClientInServer (ent);
  1075. }
  1076. if (level.intermissiontime)
  1077. {
  1078. MoveClientToIntermission (ent);
  1079. }
  1080. else
  1081. {
  1082. // send effect if in a multiplayer game
  1083. if (game.maxclients > 1)
  1084. {
  1085. gi.WriteByte (svc_muzzleflash);
  1086. gi.WriteShort (ent-g_edicts);
  1087. gi.WriteByte (MZ_LOGIN);
  1088. gi.multicast (ent->s.origin, MULTICAST_PVS);
  1089. gi.bprintf (PRINT_HIGH, "%s entered the game\n", ent->client->pers.netname);
  1090. }
  1091. }
  1092. // make sure all view stuff is valid
  1093. ClientEndServerFrame (ent);
  1094. }
  1095. /*
  1096. ===========
  1097. ClientUserInfoChanged
  1098. called whenever the player updates a userinfo variable.
  1099. The game can override any of the settings in place
  1100. (forcing skins or names, etc) before copying it off.
  1101. ============
  1102. */
  1103. void ClientUserinfoChanged (edict_t *ent, char *userinfo)
  1104. {
  1105. char *s;
  1106. int playernum;
  1107. // check for malformed or illegal info strings
  1108. if (!Info_Validate(userinfo))
  1109. {
  1110. strcpy (userinfo, "\\name\\badinfo\\skin\\male/grunt");
  1111. }
  1112. // set name
  1113. s = Info_ValueForKey (userinfo, "name");
  1114. strncpy (ent->client->pers.netname, s, sizeof(ent->client->pers.netname)-1);
  1115. // set skin
  1116. s = Info_ValueForKey (userinfo, "skin");
  1117. playernum = ent-g_edicts-1;
  1118. // combine name and skin into a configstring
  1119. //ZOID
  1120. if (ctf->value)
  1121. CTFAssignSkin(ent, s);
  1122. else
  1123. //ZOID
  1124. gi.configstring (CS_PLAYERSKINS+playernum, va("%s\\%s", ent->client->pers.netname, s) );
  1125. //ZOID
  1126. // set player name field (used in id_state view)
  1127. gi.configstring (CS_GENERAL+playernum, ent->client->pers.netname);
  1128. //ZOID
  1129. // fov
  1130. if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV))
  1131. {
  1132. ent->client->ps.fov = 90;
  1133. }
  1134. else
  1135. {
  1136. ent->client->ps.fov = atoi(Info_ValueForKey(userinfo, "fov"));
  1137. if (ent->client->ps.fov < 1)
  1138. ent->client->ps.fov = 90;
  1139. else if (ent->client->ps.fov > 160)
  1140. ent->client->ps.fov = 160;
  1141. }
  1142. // handedness
  1143. s = Info_ValueForKey (userinfo, "hand");
  1144. if (strlen(s))
  1145. {
  1146. ent->client->pers.hand = atoi(s);
  1147. }
  1148. // save off the userinfo in case we want to check something later
  1149. strncpy (ent->client->pers.userinfo, userinfo, sizeof(ent->client->pers.userinfo)-1);
  1150. }
  1151. /*
  1152. ===========
  1153. ClientConnect
  1154. Called when a player begins connecting to the server.
  1155. The game can refuse entrance to a client by returning false.
  1156. If the client is allowed, the connection process will continue
  1157. and eventually get to ClientBegin()
  1158. Changing levels will NOT cause this to be called again, but
  1159. loadgames will.
  1160. ============
  1161. */
  1162. qboolean ClientConnect (edict_t *ent, char *userinfo)
  1163. {
  1164. char *value;
  1165. // check to see if they are on the banned IP list
  1166. value = Info_ValueForKey (userinfo, "ip");
  1167. if (SV_FilterPacket(value)) {
  1168. Info_SetValueForKey(userinfo, "rejmsg", "Banned.");
  1169. return false;
  1170. }
  1171. // check for a password
  1172. value = Info_ValueForKey (userinfo, "password");
  1173. if (*password->string && strcmp(password->string, "none") &&
  1174. strcmp(password->string, value)) {
  1175. Info_SetValueForKey(userinfo, "rejmsg", "Password required or incorrect.");
  1176. return false;
  1177. }
  1178. // they can connect
  1179. ent->client = game.clients + (ent - g_edicts - 1);
  1180. // if there is already a body waiting for us (a loadgame), just
  1181. // take it, otherwise spawn one from scratch
  1182. if (ent->inuse == false)
  1183. {
  1184. // clear the respawning variables
  1185. //ZOID -- force team join
  1186. ent->client->resp.ctf_team = -1;
  1187. ent->client->resp.id_state = true;
  1188. //ZOID
  1189. InitClientResp (ent->client);
  1190. if (!game.autosaved || !ent->client->pers.weapon)
  1191. InitClientPersistant (ent->client);
  1192. }
  1193. ClientUserinfoChanged (ent, userinfo);
  1194. if (game.maxclients > 1)
  1195. gi.dprintf ("%s connected\n", ent->client->pers.netname);
  1196. ent->client->pers.connected = true;
  1197. return true;
  1198. }
  1199. /*
  1200. ===========
  1201. ClientDisconnect
  1202. Called when a player drops from the server.
  1203. Will not be called between levels.
  1204. ============
  1205. */
  1206. void ClientDisconnect (edict_t *ent)
  1207. {
  1208. int playernum;
  1209. if (!ent->client)
  1210. return;
  1211. gi.bprintf (PRINT_HIGH, "%s disconnected\n", ent->client->pers.netname);
  1212. //ZOID
  1213. CTFDeadDropFlag(ent);
  1214. CTFDeadDropTech(ent);
  1215. //ZOID
  1216. // send effect
  1217. gi.WriteByte (svc_muzzleflash);
  1218. gi.WriteShort (ent-g_edicts);
  1219. gi.WriteByte (MZ_LOGOUT);
  1220. gi.multicast (ent->s.origin, MULTICAST_PVS);
  1221. gi.unlinkentity (ent);
  1222. ent->s.modelindex = 0;
  1223. ent->solid = SOLID_NOT;
  1224. ent->inuse = false;
  1225. ent->classname = "disconnected";
  1226. ent->client->pers.connected = false;
  1227. playernum = ent-g_edicts-1;
  1228. gi.configstring (CS_PLAYERSKINS+playernum, "");
  1229. }
  1230. //==============================================================
  1231. edict_t *pm_passent;
  1232. // pmove doesn't need to know about passent and contentmask
  1233. trace_t PM_trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
  1234. {
  1235. if (pm_passent->health > 0)
  1236. return gi.trace (start, mins, maxs, end, pm_passent, MASK_PLAYERSOLID);
  1237. else
  1238. return gi.trace (start, mins, maxs, end, pm_passent, MASK_DEADSOLID);
  1239. }
  1240. unsigned CheckBlock (void *b, int c)
  1241. {
  1242. int v,i;
  1243. v = 0;
  1244. for (i=0 ; i<c ; i++)
  1245. v+= ((byte *)b)[i];
  1246. return v;
  1247. }
  1248. void PrintPmove (pmove_t *pm)
  1249. {
  1250. unsigned c1, c2;
  1251. c1 = CheckBlock (&pm->s, sizeof(pm->s));
  1252. c2 = CheckBlock (&pm->cmd, sizeof(pm->cmd));
  1253. Com_Printf ("sv %3i:%i %i\n", pm->cmd.impulse, c1, c2);
  1254. }
  1255. /*
  1256. ==============
  1257. ClientThink
  1258. This will be called once for each client frame, which will
  1259. usually be a couple times for each server frame.
  1260. ==============
  1261. */
  1262. void ClientThink (edict_t *ent, usercmd_t *ucmd)
  1263. {
  1264. gclient_t *client;
  1265. edict_t *other;
  1266. int i, j;
  1267. pmove_t pm;
  1268. level.current_entity = ent;
  1269. client = ent->client;
  1270. if (level.intermissiontime)
  1271. {
  1272. client->ps.pmove.pm_type = PM_FREEZE;
  1273. // can exit intermission after five seconds
  1274. if (level.time > level.intermissiontime + 5.0
  1275. && (ucmd->buttons & BUTTON_ANY) )
  1276. level.exitintermission = true;
  1277. return;
  1278. }
  1279. pm_passent = ent;
  1280. //ZOID
  1281. if (ent->client->chase_target) {
  1282. client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]);
  1283. client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]);
  1284. client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]);
  1285. return;
  1286. }
  1287. //ZOID
  1288. // set up for pmove
  1289. memset (&pm, 0, sizeof(pm));
  1290. if (ent->movetype == MOVETYPE_NOCLIP)
  1291. client->ps.pmove.pm_type = PM_SPECTATOR;
  1292. else if (ent->s.modelindex != 255)
  1293. client->ps.pmove.pm_type = PM_GIB;
  1294. else if (ent->deadflag)
  1295. client->ps.pmove.pm_type = PM_DEAD;
  1296. else
  1297. client->ps.pmove.pm_type = PM_NORMAL;
  1298. client->ps.pmove.gravity = sv_gravity->value;
  1299. pm.s = client->ps.pmove;
  1300. for (i=0 ; i<3 ; i++)
  1301. {
  1302. pm.s.origin[i] = ent->s.origin[i]*8;
  1303. pm.s.velocity[i] = ent->velocity[i]*8;
  1304. }
  1305. if (memcmp(&client->old_pmove, &pm.s, sizeof(pm.s)))
  1306. {
  1307. pm.snapinitial = true;
  1308. // gi.dprintf ("pmove changed!\n");
  1309. }
  1310. pm.cmd = *ucmd;
  1311. pm.trace = PM_trace; // adds default parms
  1312. pm.pointcontents = gi.pointcontents;
  1313. // perform a pmove
  1314. gi.Pmove (&pm);
  1315. // save results of pmove
  1316. client->ps.pmove = pm.s;
  1317. client->old_pmove = pm.s;
  1318. for (i=0 ; i<3 ; i++)
  1319. {
  1320. ent->s.origin[i] = pm.s.origin[i]*0.125;
  1321. ent->velocity[i] = pm.s.velocity[i]*0.125;
  1322. }
  1323. VectorCopy (pm.mins, ent->mins);
  1324. VectorCopy (pm.maxs, ent->maxs);
  1325. client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]);
  1326. client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]);
  1327. client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]);
  1328. if (ent->groundentity && !pm.groundentity && (pm.cmd.upmove >= 10) && (pm.waterlevel == 0))
  1329. {
  1330. gi.sound(ent, CHAN_VOICE, gi.soundindex("*jump1.wav"), 1, ATTN_NORM, 0);
  1331. PlayerNoise(ent, ent->s.origin, PNOISE_SELF);
  1332. }
  1333. ent->viewheight = pm.viewheight;
  1334. ent->waterlevel = pm.waterlevel;
  1335. ent->watertype = pm.watertype;
  1336. ent->groundentity = pm.groundentity;
  1337. if (pm.groundentity)
  1338. ent->groundentity_linkcount = pm.groundentity->linkcount;
  1339. if (ent->deadflag)
  1340. {
  1341. client->ps.viewangles[ROLL] = 40;
  1342. client->ps.viewangles[PITCH] = -15;
  1343. client->ps.viewangles[YAW] = client->killer_yaw;
  1344. }
  1345. else
  1346. {
  1347. VectorCopy (pm.viewangles, client->v_angle);
  1348. VectorCopy (pm.viewangles, client->ps.viewangles);
  1349. }
  1350. //ZOID
  1351. if (client->ctf_grapple)
  1352. CTFGrapplePull(client->ctf_grapple);
  1353. //ZOID
  1354. gi.linkentity (ent);
  1355. if (ent->movetype != MOVETYPE_NOCLIP)
  1356. G_TouchTriggers (ent);
  1357. // touch other objects
  1358. for (i=0 ; i<pm.numtouch ; i++)
  1359. {
  1360. other = pm.touchents[i];
  1361. for (j=0 ; j<i ; j++)
  1362. if (pm.touchents[j] == other)
  1363. break;
  1364. if (j != i)
  1365. continue; // duplicated
  1366. if (!other->touch)
  1367. continue;
  1368. other->touch (other, ent, NULL, NULL);
  1369. }
  1370. client->oldbuttons = client->buttons;
  1371. client->buttons = ucmd->buttons;
  1372. client->latched_buttons |= client->buttons & ~client->oldbuttons;
  1373. // save light level the player is standing on for
  1374. // monster sighting AI
  1375. ent->light_level = ucmd->lightlevel;
  1376. // fire weapon from final position if needed
  1377. if (client->latched_buttons & BUTTON_ATTACK
  1378. //ZOID
  1379. && ent->movetype != MOVETYPE_NOCLIP
  1380. //ZOID
  1381. )
  1382. {
  1383. if (!client->weapon_thunk)
  1384. {
  1385. client->weapon_thunk = true;
  1386. Think_Weapon (ent);
  1387. }
  1388. }
  1389. //ZOID
  1390. //regen tech
  1391. CTFApplyRegeneration(ent);
  1392. //ZOID
  1393. //ZOID
  1394. for (i = 1; i <= maxclients->value; i++) {
  1395. other = g_edicts + i;
  1396. if (other->inuse && other->client->chase_target == ent)
  1397. UpdateChaseCam(other);
  1398. }
  1399. if (client->menudirty && client->menutime <= level.time) {
  1400. PMenu_Do_Update(ent);
  1401. gi.unicast (ent, true);
  1402. client->menutime = level.time;
  1403. client->menudirty = false;
  1404. }
  1405. //ZOID
  1406. }
  1407. /*
  1408. ==============
  1409. ClientBeginServerFrame
  1410. This will be called once for each server frame, before running
  1411. any other entities in the world.
  1412. ==============
  1413. */
  1414. void ClientBeginServerFrame (edict_t *ent)
  1415. {
  1416. gclient_t *client;
  1417. int buttonMask;
  1418. if (level.intermissiontime)
  1419. return;
  1420. client = ent->client;
  1421. // run weapon animations if it hasn't been done by a ucmd_t
  1422. if (!client->weapon_thunk
  1423. //ZOID
  1424. && ent->movetype != MOVETYPE_NOCLIP
  1425. //ZOID
  1426. )
  1427. Think_Weapon (ent);
  1428. else
  1429. client->weapon_thunk = false;
  1430. if (ent->deadflag)
  1431. {
  1432. // wait for any button just going down
  1433. if ( level.time > client->respawn_time)
  1434. {
  1435. // in deathmatch, only wait for attack button
  1436. if (deathmatch->value)
  1437. buttonMask = BUTTON_ATTACK;
  1438. else
  1439. buttonMask = -1;
  1440. if ( ( client->latched_buttons & buttonMask ) ||
  1441. (deathmatch->value && ((int)dmflags->value & DF_FORCE_RESPAWN) ) ||
  1442. CTFMatchOn())
  1443. {
  1444. respawn(ent);
  1445. client->latched_buttons = 0;
  1446. }
  1447. }
  1448. return;
  1449. }
  1450. // add player trail so monsters can follow
  1451. if (!deathmatch->value)
  1452. if (!visible (ent, PlayerTrail_LastSpot() ) )
  1453. PlayerTrail_Add (ent->s.old_origin);
  1454. client->latched_buttons = 0;
  1455. }