p_client.c 42 KB

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