client.qc 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118
  1. /* Copyright (C) 1996-2022 id Software LLC
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation; either version 2 of the License, or
  5. (at your option) any later version.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program; if not, write to the Free Software
  12. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  13. See file, 'COPYING', for details.
  14. */
  15. // updated to quake v1.06 10/8/96
  16. // prototypes
  17. void () W_WeaponFrame;
  18. void() W_SetCurrentAmmo;
  19. void() player_pain;
  20. void() player_stand1;
  21. void (vector org) spawn_tfog;
  22. void (vector org, entity death_owner) spawn_tdeath;
  23. void(entity targ, entity attacker) dmatch_score;
  24. float modelindex_eyes, modelindex_player;
  25. /*
  26. =============================================================================
  27. LEVEL CHANGING / INTERMISSION
  28. =============================================================================
  29. */
  30. float intermission_running;
  31. float intermission_exittime;
  32. /*QUAKED info_intermission (1 0.5 0.5) (-16 -16 -16) (16 16 16)
  33. This is the camera point for the intermission.
  34. Use mangle instead of angle, so you can set pitch or roll as well as yaw. 'pitch roll yaw'
  35. */
  36. void() info_intermission =
  37. {
  38. };
  39. void() SetChangeParms =
  40. {
  41. if (self.health <= 0 || deathmatch)
  42. {
  43. SetNewParms ();
  44. parm14 = self.steam; // Save the current team of the player
  45. return;
  46. }
  47. // remove items
  48. self.items = self.items - (self.items & (IT_KEY1 | IT_KEY2 |
  49. IT_INVULNERABILITY | IT_SUIT |
  50. IT_QUAD | IT_INVISIBILITY) );
  51. self.items2 = self.items2 - (self.items2 &
  52. (IT2_ANTIGRAV | IT2_SHIELD | IT2_SUPERHEALTH));
  53. self.gravity = 1.0;
  54. // cap super health
  55. if (self.health > self.max_health)
  56. self.health = self.max_health;
  57. if (self.health < self.max_health / 2)
  58. self.health = self.max_health / 2;
  59. teamplay = cvar ( "teamplay" );
  60. if (teamplay >= TEAM_CTF) // don't carry items between levels in CTF
  61. SetNewParms();
  62. else
  63. {
  64. parm1 = self.items;
  65. parm2 = self.health;
  66. parm3 = self.armorvalue;
  67. if (self.ammo_shells1 < 25)
  68. parm4 = 25;
  69. else
  70. parm4 = self.ammo_shells1;
  71. parm5 = self.ammo_nails1;
  72. parm6 = self.ammo_rockets1;
  73. parm7 = self.ammo_cells1;
  74. parm8 = self.weapon;
  75. parm9 = self.armortype * 100;
  76. parm10 = self.items2;
  77. parm11 = self.ammo_lava_nails;
  78. parm12 = self.ammo_multi_rockets;
  79. parm13 = self.ammo_plasma;
  80. }
  81. parm14 = self.steam; // save team setting
  82. };
  83. void() SetNewParms =
  84. {
  85. //ZOID--
  86. if (deathmatch && teamplay >= TEAM_CTF) {
  87. parm1 = IT_SHOTGUN | IT_AXE | IT_GRAPPLE;
  88. parm10 = IT2_ARMOR1;
  89. parm3 = 50;
  90. parm9 = 30;
  91. } else {
  92. parm1 = IT_SHOTGUN | IT_AXE;
  93. parm3 = 0;
  94. parm9 = 0;
  95. parm10 = 0;
  96. }
  97. //--ZOID
  98. if (skill == 3 && !deathmatch)
  99. parm2 = 50;
  100. else
  101. parm2 = 100;
  102. parm4 = 25;
  103. parm5 = 0;
  104. parm6 = 0;
  105. parm7 = 0;
  106. parm8 = 1;
  107. parm11 = 0;
  108. parm12 = 0;
  109. parm13 = 0;
  110. //ZOID--
  111. parm14 = -1; // CTF: reset current team selection
  112. //--ZOID
  113. };
  114. void() DecodeLevelParms =
  115. {
  116. if (serverflags)
  117. {
  118. if (world.model == "maps/start.bsp")
  119. SetNewParms (); // take away all stuff on starting new episode
  120. }
  121. if (world.model == "maps/r2m1.bsp" && !deathmatch)
  122. SetNewParms ();
  123. // PGM - 01/29 change to have level 8 reset all your stuff.
  124. self.items = parm1;
  125. self.health = parm2;
  126. self.armorvalue = parm3;
  127. self.ammo_shells1 = parm4;
  128. self.ammo_nails1 = parm5;
  129. self.ammo_rockets1 = parm6;
  130. self.ammo_cells1 = parm7;
  131. // cute bug, if grapple was selected, it still will be on level change
  132. if (parm8 == IT_GRAPPLE && teamplay < TEAM_CTF)
  133. self.weapon = IT_AXE;
  134. else
  135. self.weapon = parm8;
  136. self.armortype = parm9 * 0.01;
  137. self.items2 = parm10;
  138. self.ammo_lava_nails = parm11;
  139. self.ammo_multi_rockets = parm12;
  140. self.ammo_plasma = parm13;
  141. //ZOID--
  142. if (TeamColorIsLegal(parm14)) {
  143. self.steam = parm14;
  144. TeamSetSkin();
  145. }
  146. //--ZOID
  147. };
  148. /*
  149. ============
  150. FindIntermission
  151. Returns the entity to view from
  152. ============
  153. */
  154. entity() FindIntermission =
  155. {
  156. local entity spot;
  157. local float cyc;
  158. // look for info_intermission first
  159. spot = find (world, classname, "info_intermission");
  160. if (spot)
  161. { // pick a random one
  162. cyc = random() * 4;
  163. while (cyc > 1)
  164. {
  165. spot = find (spot, classname, "info_intermission");
  166. if (!spot)
  167. spot = find (spot, classname, "info_intermission");
  168. cyc = cyc - 1;
  169. }
  170. return spot;
  171. }
  172. // then look for the start position
  173. spot = find (world, classname, "info_player_start");
  174. if (spot)
  175. return spot;
  176. // testinfo_player_start is only found in regioned levels
  177. spot = find (world, classname, "testplayerstart");
  178. if (spot)
  179. return spot;
  180. objerror ("FindIntermission: no spot");
  181. };
  182. string nextmap;
  183. void() GotoNextMap =
  184. {
  185. if (cvar("samelevel")) // if samelevel is set, stay on same level
  186. changelevel (mapname);
  187. else
  188. changelevel (nextmap);
  189. };
  190. void() ExitIntermission =
  191. {
  192. // skip any text in deathmatch
  193. if (deathmatch)
  194. {
  195. GotoNextMap ();
  196. return;
  197. }
  198. intermission_exittime = time + 1;
  199. intermission_running = intermission_running + 1;
  200. //
  201. // run some text if at the end of an episode
  202. //
  203. if (intermission_running == 2)
  204. {
  205. if (world.model == "maps/e1m7.bsp")
  206. {
  207. WriteByte (MSG_ALL, SVC_CDTRACK);
  208. WriteByte (MSG_ALL, 2);
  209. WriteByte (MSG_ALL, 3);
  210. if (!cvar("registered"))
  211. {
  212. WriteByte (MSG_ALL, SVC_FINALE);
  213. WriteString (MSG_ALL, "$qc_finale_e1_shareware");
  214. }
  215. else
  216. {
  217. WriteByte (MSG_ALL, SVC_FINALE);
  218. WriteString (MSG_ALL, "$qc_finale_e1");
  219. }
  220. return;
  221. }
  222. else if (world.model == "maps/e2m6.bsp")
  223. {
  224. WriteByte (MSG_ALL, SVC_CDTRACK);
  225. WriteByte (MSG_ALL, 2);
  226. WriteByte (MSG_ALL, 3);
  227. WriteByte (MSG_ALL, SVC_FINALE);
  228. WriteString (MSG_ALL, "$qc_finale_e2");
  229. return;
  230. }
  231. else if (world.model == "maps/e3m6.bsp")
  232. {
  233. WriteByte (MSG_ALL, SVC_CDTRACK);
  234. WriteByte (MSG_ALL, 2);
  235. WriteByte (MSG_ALL, 3);
  236. WriteByte (MSG_ALL, SVC_FINALE);
  237. WriteString (MSG_ALL, "$qc_finale_e3");
  238. return;
  239. }
  240. else if (world.model == "maps/e4m7.bsp")
  241. {
  242. WriteByte (MSG_ALL, SVC_CDTRACK);
  243. WriteByte (MSG_ALL, 2);
  244. WriteByte (MSG_ALL, 3);
  245. WriteByte (MSG_ALL, SVC_FINALE);
  246. WriteString (MSG_ALL, "$qc_finale_e4");
  247. return;
  248. }
  249. else if (world.model == "maps/r1m7.bsp")
  250. {
  251. WriteByte (MSG_ALL, SVC_FINALE);
  252. //------------------------------------- end here
  253. WriteString (MSG_ALL, "$qc_finale_r1");
  254. return;
  255. }
  256. if (coop && mapname == "r2m8" )
  257. {
  258. localcmd("menu_credits\n");
  259. localcmd("disconnect\n");
  260. return;
  261. }
  262. else
  263. {
  264. GotoNextMap();
  265. }
  266. }
  267. if (intermission_running == 3)
  268. {
  269. if (!cvar("registered"))
  270. { // shareware episode has been completed, go to sell screen
  271. WriteByte (MSG_ALL, SVC_SELLSCREEN);
  272. return;
  273. }
  274. if ( (serverflags&15) == 15)
  275. {
  276. WriteByte (MSG_ALL, SVC_FINALE);
  277. WriteString (MSG_ALL, "$qc_finale_all_runes");
  278. return;
  279. }
  280. }
  281. if (coop)
  282. {
  283. if ( mapname == "r2m8" )
  284. {
  285. localcmd("menu_credits\n");
  286. localcmd("disconnect\n");
  287. return;
  288. }
  289. }
  290. else
  291. {
  292. GotoNextMap();
  293. }
  294. };
  295. /*
  296. ============
  297. IntermissionThink
  298. When the player presses attack or jump, change to the next level
  299. ============
  300. */
  301. void() IntermissionThink =
  302. {
  303. if (time < intermission_exittime)
  304. return;
  305. if (!self.button0 && !self.button1 && !self.button2)
  306. return;
  307. ExitIntermission ();
  308. };
  309. void() execute_changelevel =
  310. {
  311. local entity pos;
  312. intermission_running = 1;
  313. // enforce a wait time before allowing changelevel
  314. if (deathmatch)
  315. intermission_exittime = time + 5;
  316. else
  317. intermission_exittime = time + 2;
  318. WriteByte (MSG_ALL, SVC_CDTRACK);
  319. WriteByte (MSG_ALL, 3);
  320. WriteByte (MSG_ALL, 3);
  321. pos = FindIntermission ();
  322. other = find (world, classname, "player");
  323. while (other != world)
  324. {
  325. other.view_ofs = '0 0 0';
  326. other.angles = other.v_angle = pos.mangle;
  327. other.fixangle = TRUE; // turn this way immediately
  328. other.nextthink = time + 0.5;
  329. other.takedamage = DAMAGE_NO;
  330. other.solid = SOLID_NOT;
  331. other.movetype = MOVETYPE_NONE;
  332. other.modelindex = 0;
  333. setorigin (other, pos.origin);
  334. other = find (other, classname, "player");
  335. }
  336. WriteByte (MSG_ALL, SVC_INTERMISSION);
  337. if (campaign && world.model == "maps/r1m7.bsp")
  338. {
  339. WriteByte (MSG_ALL, SVC_ACHIEVEMENT);
  340. WriteString(MSG_ALL, "ACH_COMPLETE_R1M7");
  341. }
  342. };
  343. void() changelevel_touch =
  344. {
  345. local entity pos;
  346. if (other.classname != "player")
  347. return;
  348. if ((cvar("noexit") == 1) || ((cvar("noexit") == 2) && (mapname != "start")))
  349. {
  350. T_Damage (other, self, self, 50000);
  351. return;
  352. }
  353. if (coop || deathmatch)
  354. {
  355. bprint("$qc_exited", other.netname);
  356. }
  357. nextmap = self.map;
  358. SUB_UseTargets ();
  359. if ( (self.spawnflags & 1) && (deathmatch == 0) )
  360. { // NO_INTERMISSION
  361. GotoNextMap();
  362. return;
  363. }
  364. self.touch = SUB_Null;
  365. // we can't move people right now, because touch functions are called
  366. // in the middle of C movement code, so set a think time to do it
  367. self.think = execute_changelevel;
  368. self.nextthink = time + 0.1;
  369. };
  370. /*QUAKED trigger_changelevel (0.5 0.5 0.5) ? NO_INTERMISSION
  371. When the player touches this, he gets sent to the map listed in the "map" variable. Unless the NO_INTERMISSION flag is set, the view will go to the info_intermission spot and display stats.
  372. */
  373. void() trigger_changelevel =
  374. {
  375. if (!self.map)
  376. objerror ("chagnelevel trigger doesn't have map");
  377. InitTrigger ();
  378. self.touch = changelevel_touch;
  379. };
  380. /*
  381. =============================================================================
  382. PLAYER GAME EDGE FUNCTIONS
  383. =============================================================================
  384. */
  385. void() set_suicide_frame;
  386. // called by ClientKill and DeadThink
  387. void() respawn =
  388. {
  389. if (coop)
  390. {
  391. // make a copy of the dead body for appearances sake
  392. CopyToBodyQue (self);
  393. // get the spawn parms as they were at level start
  394. setspawnparms (self);
  395. // respawn
  396. PutClientInServer ();
  397. }
  398. else if (deathmatch)
  399. {
  400. // make a copy of the dead body for appearances sake
  401. CopyToBodyQue (self);
  402. // set default spawn parms
  403. SetNewParms ();
  404. // respawn
  405. PutClientInServer ();
  406. // set the skin correctly.
  407. TeamSetSkin();
  408. }
  409. else
  410. { // restart the entire server
  411. cvar_set("campaign", ftos(campaign));
  412. localcmd ("restart\n");
  413. }
  414. };
  415. /*
  416. ============
  417. ClientKill
  418. Player entered the suicide command
  419. ============
  420. */
  421. void() ClientKill =
  422. {
  423. local entity vSphere;
  424. // ZOID--
  425. if (self.suicide_count > 3)
  426. {
  427. sprint(self, "$qc_suicided_too_much");
  428. return;
  429. }
  430. TeamDropFlagOfPlayer(self);
  431. self.suicide_count = self.suicide_count + 1;
  432. // --ZOID
  433. if ( tag_token_owner == self)
  434. {
  435. self.health = 0;
  436. self.solid = SOLID_NOT;
  437. tag_token_drop();
  438. }
  439. if ( self.items2 & IT2_V_SPHERE)
  440. {
  441. vSphere = find ( world, classname, "Vengeance");
  442. while (vSphere)
  443. {
  444. if ( vSphere.owner == self )
  445. {
  446. remove (vSphere);
  447. }
  448. vSphere = find(vSphere, classname, "Vengeance");
  449. }
  450. }
  451. bprint("$qc_suicides", self.netname);
  452. set_suicide_frame ();
  453. self.modelindex = modelindex_player;
  454. self.frags = self.frags - 2; // extra penalty
  455. respawn ();
  456. };
  457. /*
  458. ============
  459. PlayerVisibleToSpawnPoint
  460. Returns true if player can see this point
  461. ============
  462. */
  463. float PlayerVisibleToSpawnPoint( entity point ) {
  464. local vector spot1, spot2;
  465. local entity player = find( world, classname, "player" );
  466. while ( player ) {
  467. if ( player.health > 0 ) {
  468. spot1 = point.origin + player.view_ofs;
  469. spot2 = player.origin + player.view_ofs;
  470. traceline( spot1, spot2, TRUE, point );
  471. if ( trace_fraction >= 1.0f ) {
  472. return TRUE;
  473. }
  474. }
  475. player = find( player, classname, "player" );
  476. }
  477. return FALSE;
  478. }
  479. float IDEAL_DIST_FROM_DM_SPAWN_POINT = 384;
  480. float MIN_DIST_FROM_DM_SPAWN_POINT = 84;
  481. /*
  482. ============
  483. SelectSpawnPoint
  484. Returns the entity to spawn at
  485. ============
  486. */
  487. entity() SelectSpawnPointRogue =
  488. {
  489. local entity spot;
  490. local entity thing;
  491. local float pcount;
  492. //ZOID--
  493. local entity startspot;
  494. local float t;
  495. //--ZOID
  496. // testinfo_player_start is only found in regioned levels
  497. spot = find (world, classname, "testplayerstart");
  498. if (spot)
  499. return spot;
  500. // choose a info_player_deathmatch point
  501. if (coop)
  502. {
  503. lastspawn = find(lastspawn, classname, "info_player_coop");
  504. if (lastspawn == world)
  505. lastspawn = find (lastspawn, classname, "info_player_start");
  506. if (lastspawn != world)
  507. return lastspawn;
  508. }
  509. else if (deathmatch)
  510. {
  511. startspot = spot = lastspawn;
  512. t = 0;
  513. if (!self.ctf_killed && teamplay >= TEAM_CTF)
  514. {
  515. if (self.steam == TEAM1)
  516. {
  517. startspot = spot = team1_lastspawn;
  518. t = TEAM1;
  519. }
  520. else if (self.steam == TEAM2)
  521. {
  522. startspot = spot = team2_lastspawn;
  523. t = TEAM2;
  524. }
  525. }
  526. while (1)
  527. {
  528. if (t == TEAM1)
  529. spot = find(spot, classname, "info_player_team1");
  530. else if (t == TEAM2)
  531. spot = find(spot, classname, "info_player_team2");
  532. else
  533. spot = find(spot, classname, "info_player_deathmatch");
  534. if (spot != world)
  535. {
  536. if (spot == startspot)
  537. return startspot;
  538. pcount = 0;
  539. thing = findradius(spot.origin, 32);
  540. while(thing)
  541. {
  542. if (thing.classname == "player")
  543. pcount = pcount + 1;
  544. thing = thing.chain;
  545. }
  546. if (pcount == 0)
  547. {
  548. if (t == TEAM1)
  549. team1_lastspawn = spot;
  550. else if (t == TEAM2)
  551. team2_lastspawn = spot;
  552. else
  553. lastspawn = spot;
  554. return spot;
  555. }
  556. }
  557. else
  558. t = 0;
  559. // pgm fix for ctf in levels w/o ctf support
  560. }
  561. }
  562. if (serverflags)
  563. { // return with a rune to start
  564. spot = find (world, classname, "info_player_start2");
  565. if (spot)
  566. return spot;
  567. }
  568. spot = find (world, classname, "info_player_start");
  569. if (!spot)
  570. error ("PutClientInServer: no info_player_start on level");
  571. return spot;
  572. };
  573. entity SelectSpawnPointEX(float forceSpawn) {
  574. local entity spot, thing;
  575. local float numspots, totalspots;
  576. local float pcount;
  577. local entity spots;
  578. numspots = 0;
  579. totalspots = 0;
  580. // testinfo_player_start is only found in regioned levels
  581. spot = find( world, classname, "testplayerstart" );
  582. if ( spot )
  583. return spot;
  584. // choose a info_player_deathmatch point
  585. if ( coop ) {
  586. lastspawn = find( lastspawn, classname, "info_player_coop" );
  587. if ( lastspawn == world ) {
  588. lastspawn = find( lastspawn, classname, "info_player_start" );
  589. }
  590. if ( lastspawn != world ) {
  591. return lastspawn;
  592. }
  593. } else if ( deathmatch ) {
  594. // find all spots that don't have visible players nearby
  595. spots = world;
  596. spot = find( world, classname, "info_player_deathmatch" );
  597. while( spot ) {
  598. totalspots = totalspots + 1;
  599. thing = findradius( spot.origin, IDEAL_DIST_FROM_DM_SPAWN_POINT );
  600. pcount = 0;
  601. while( thing ) {
  602. if ( thing.classname == "player" && thing.health > 0 ) {
  603. pcount = pcount + 1;
  604. }
  605. thing = thing.chain;
  606. }
  607. if ( pcount == 0 ) {
  608. if ( PlayerVisibleToSpawnPoint( spot ) ) {
  609. pcount = pcount + 1;
  610. }
  611. }
  612. if ( pcount == 0 ) { // good spot!
  613. spot.goalentity = spots;
  614. spots = spot;
  615. numspots = numspots + 1;
  616. }
  617. // Get the next spot in the chain
  618. spot = find( spot, classname, "info_player_deathmatch" );
  619. }
  620. totalspots = totalspots - 1;
  621. // on small maps with few spawn points, our "ideal" spawn conditions may not be possible to meet
  622. // so fallback to just trying to pick a point without a player on top of it, so we don't start
  623. // a spawn frag loop
  624. if ( numspots == 0 ) {
  625. spot = find( world, classname, "info_player_deathmatch" );
  626. while( spot ) {
  627. thing = findradius( spot.origin, MIN_DIST_FROM_DM_SPAWN_POINT );
  628. pcount = 0;
  629. while( thing ) {
  630. if ( thing.classname == "player" && thing.health > 0 ) {
  631. pcount = pcount + 1;
  632. }
  633. thing = thing.chain;
  634. }
  635. if ( pcount == 0 ) { // good spot!
  636. spot.goalentity = spots;
  637. spots = spot;
  638. numspots = numspots + 1;
  639. }
  640. // Get the next spot in the chain
  641. spot = find( spot, classname, "info_player_deathmatch" );
  642. }
  643. }
  644. // uncomment to force a deferred spawn
  645. // if (forceSpawn == FALSE) return world;
  646. if ( !numspots ) {
  647. if (forceSpawn == FALSE) {
  648. return world;
  649. }
  650. // no spots available so just pick one at random
  651. totalspots = rint( ( random() * totalspots ) );
  652. spot = find( world, classname, "info_player_deathmatch" );
  653. while( totalspots > 0 ) {
  654. totalspots = totalspots - 1;
  655. spot = find( spot, classname, "info_player_deathmatch" );
  656. }
  657. return spot;
  658. }
  659. // Generate a random number between 1 and numspots
  660. numspots = numspots - 1;
  661. numspots = rint( ( random() * numspots ) );
  662. spot = spots;
  663. while( numspots > 0 ) {
  664. spot = spot.goalentity;
  665. numspots = numspots - 1;
  666. }
  667. return spot;
  668. }
  669. if ( serverflags ) { // return with a rune to start
  670. spot = find( world, classname, "info_player_start2" );
  671. if ( spot ) {
  672. return spot;
  673. }
  674. }
  675. spot = find( world, classname, "info_player_start" );
  676. if ( !spot ) {
  677. error( "PutClientInServer: no info_player_start on level" );
  678. }
  679. return spot;
  680. };
  681. entity SelectSpawnPoint(float forceSpawn) {
  682. // use the original rogue spawn logic in tctf
  683. if (teamplay >= TEAM_CTF) {
  684. return SelectSpawnPointRogue();
  685. } else {
  686. return SelectSpawnPointEX(forceSpawn);
  687. }
  688. }
  689. /*
  690. ===========
  691. PutClientInServer
  692. called each time a player is spawned
  693. ============
  694. */
  695. void() DecodeLevelParms;
  696. void() PlayerDie;
  697. void() player_touch;
  698. void() PutClientInServer =
  699. {
  700. local entity spot;
  701. self.classname = "player";
  702. if (skill == 3 && !deathmatch)
  703. self.health = 50;
  704. else
  705. self.health = 100;
  706. self.takedamage = DAMAGE_AIM;
  707. self.solid = SOLID_SLIDEBOX;
  708. self.movetype = MOVETYPE_WALK;
  709. self.show_hostile = 0;
  710. if (skill == 3 && !deathmatch)
  711. self.max_health = 50;
  712. else
  713. self.max_health = 100;
  714. self.flags = FL_CLIENT;
  715. self.air_finished = time + 12;
  716. self.dmg = 2; // initial water damage
  717. self.super_damage_finished = 0;
  718. self.radsuit_finished = 0;
  719. self.invisible_finished = 0;
  720. self.invincible_finished = 0;
  721. self.effects = 0;
  722. self.invincible_time = 0;
  723. self.shield_finished = 0;
  724. self.antigrav_finished = 0;
  725. //ZOID--
  726. self.ctf_lastreturnedflag = -10;
  727. self.ctf_lastfraggedcarrier = -10;
  728. self.ctf_flagsince = -10;
  729. self.ctf_lasthurtcarrier = -10;
  730. //--ZOID
  731. if ( coop ) {
  732. self.team = TEAM_HUMANS;
  733. }
  734. DecodeLevelParms ();
  735. // spawn selection must be after DecodeLevelParms because of team stuff
  736. spot = SelectSpawnPoint ();
  737. W_SetCurrentAmmo ();
  738. self.attack_finished = time;
  739. self.th_pain = player_pain;
  740. self.th_die = PlayerDie;
  741. self.deadflag = DEAD_NO;
  742. // paustime is set by teleporters to keep the player from moving a while
  743. self.pausetime = 0;
  744. // spot = SelectSpawnPoint ();
  745. self.origin = spot.origin + '0 0 1';
  746. self.angles = spot.angles;
  747. self.fixangle = TRUE; // turn this way immediately
  748. self.touch = player_touch;
  749. // oh, this is a hack!
  750. setmodel (self, "progs/eyes.mdl");
  751. modelindex_eyes = self.modelindex;
  752. setmodel (self, "progs/player.mdl");
  753. modelindex_player = self.modelindex;
  754. setsize (self, VEC_HULL_MIN, VEC_HULL_MAX);
  755. self.view_ofs = '0 0 22';
  756. player_stand1 ();
  757. if (deathmatch || coop)
  758. {
  759. makevectors(self.angles);
  760. spawn_tfog (self.origin + v_forward*20);
  761. }
  762. //Grapple stuff
  763. self.on_hook = FALSE;
  764. self.hook_out = FALSE;
  765. spawn_tdeath (self.origin, self);
  766. stuffcmd(self, "-attack\n"); // prevent shooting after respawning
  767. };
  768. /*
  769. =============================================================================
  770. QUAKED FUNCTIONS
  771. =============================================================================
  772. */
  773. /*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 24)
  774. The normal starting point for a level.
  775. */
  776. void() info_player_start =
  777. {
  778. };
  779. /*QUAKED info_player_start2 (1 0 0) (-16 -16 -24) (16 16 24)
  780. Only used on start map for the return point from an episode.
  781. */
  782. void() info_player_start2 =
  783. {
  784. };
  785. /*
  786. saved out by quaked in region mode
  787. */
  788. void() testplayerstart =
  789. {
  790. };
  791. /*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 24)
  792. potential spawning position for deathmatch games
  793. */
  794. void() info_player_deathmatch =
  795. {
  796. SpawnRunes();
  797. };
  798. /*QUAKED info_player_coop (1 0 1) (-16 -16 -24) (16 16 24)
  799. potential spawning position for coop games
  800. */
  801. void() info_player_coop =
  802. {
  803. };
  804. /*
  805. ===============================================================================
  806. RULES
  807. ===============================================================================
  808. */
  809. /*
  810. go to the next level for deathmatch
  811. */
  812. void() NextLevel =
  813. {
  814. local entity o;
  815. if (mapname == "start")
  816. {
  817. /*
  818. if (!cvar("registered"))
  819. {
  820. mapname = "e1m1";
  821. }
  822. else if (!(serverflags & 1))
  823. {
  824. mapname = "e1m1";
  825. serverflags = serverflags | 1;
  826. }
  827. else if (!(serverflags & 2))
  828. {
  829. mapname = "e2m1";
  830. serverflags = serverflags | 2;
  831. }
  832. else if (!(serverflags & 4))
  833. {
  834. mapname = "e3m1";
  835. serverflags = serverflags | 4;
  836. }
  837. else if (!(serverflags & 8))
  838. {
  839. mapname = "e4m1";
  840. serverflags = serverflags - 7;
  841. }
  842. */
  843. // PGM 03/02/97 - make it always go to rogue level1 when in our progs
  844. mapname = "r1m1";
  845. o = spawn();
  846. o.map = mapname;
  847. }
  848. else
  849. {
  850. // find a trigger changelevel
  851. o = find(world, classname, "trigger_changelevel");
  852. // go back to start if no trigger_changelevel
  853. if (!o)
  854. {
  855. mapname = "start";
  856. o = spawn();
  857. o.map = mapname;
  858. }
  859. }
  860. nextmap = o.map;
  861. gameover = TRUE;
  862. if (o.nextthink < time)
  863. {
  864. o.think = execute_changelevel;
  865. o.nextthink = time + 0.1;
  866. }
  867. };
  868. /*
  869. ============
  870. CheckRules
  871. Exit deathmatch games upon conditions
  872. ============
  873. */
  874. void() CheckRules =
  875. {
  876. local float timelimit;
  877. local float fraglimit;
  878. if (gameover) // someone else quit the game already
  879. return;
  880. timelimit = cvar("timelimit") * 60;
  881. fraglimit = cvar("fraglimit");
  882. if (timelimit && time >= timelimit)
  883. {
  884. NextLevel ();
  885. return;
  886. }
  887. if (fraglimit && self.frags >= fraglimit)
  888. {
  889. NextLevel ();
  890. return;
  891. }
  892. //ZOID--
  893. // update team scores?
  894. TeamCheckUpdate();
  895. //--ZOID
  896. };
  897. //============================================================================
  898. void() PlayerDeathThink =
  899. {
  900. local entity old_self;
  901. local float forward;
  902. if ((self.flags & FL_ONGROUND))
  903. {
  904. forward = vlen (self.velocity);
  905. forward = forward - 20;
  906. if (forward <= 0)
  907. self.velocity = '0 0 0';
  908. else
  909. self.velocity = forward * normalize(self.velocity);
  910. }
  911. if (self.spawn_deferred)
  912. {
  913. local entity spot;
  914. spot = SelectSpawnPoint(FALSE);
  915. //dprint("time {} >= self.spawn_deferred {}\n", ftos(time), ftos(self.spawn_deferred));
  916. if (spot != world || time >= self.spawn_deferred) {
  917. respawn();
  918. }
  919. return;
  920. }
  921. // wait for all buttons released
  922. if (self.deadflag == DEAD_DEAD)
  923. {
  924. if (self.button2 || self.button1 || self.button0)
  925. return;
  926. self.deadflag = DEAD_RESPAWNABLE;
  927. return;
  928. }
  929. // wait for any button down
  930. if (!self.button2 && !self.button1 && !self.button0)
  931. return;
  932. self.button0 = 0;
  933. self.button1 = 0;
  934. self.button2 = 0;
  935. respawn();
  936. };
  937. void() PlayerJump =
  938. {
  939. local vector start, end;
  940. if (self.flags & FL_WATERJUMP)
  941. return;
  942. if (self.waterlevel >= 2)
  943. {
  944. if (self.watertype == CONTENT_WATER)
  945. self.velocity_z = 100;
  946. else if (self.watertype == CONTENT_SLIME)
  947. self.velocity_z = 80;
  948. else
  949. self.velocity_z = 50;
  950. // play swiming sound
  951. if (self.swim_flag < time)
  952. {
  953. self.swim_flag = time + 1;
  954. if (random() < 0.5)
  955. sound (self, CHAN_BODY, "misc/water1.wav", 1, ATTN_NORM);
  956. else
  957. sound (self, CHAN_BODY, "misc/water2.wav", 1, ATTN_NORM);
  958. }
  959. return;
  960. }
  961. if (!(self.flags & FL_ONGROUND))
  962. return;
  963. if ( !(self.flags & FL_JUMPRELEASED) )
  964. return; // don't pogo stick
  965. self.flags = self.flags - (self.flags & FL_JUMPRELEASED);
  966. self.flags = self.flags - FL_ONGROUND; // don't stairwalk
  967. self.button2 = 0;
  968. // player jumping sound
  969. sound (self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM);
  970. self.velocity_z = self.velocity_z + 270;
  971. };
  972. /*
  973. ===========
  974. WaterMove
  975. ============
  976. */
  977. .float dmgtime;
  978. void() WaterMove =
  979. {
  980. //dprint (ftos(self.waterlevel));
  981. if (self.movetype == MOVETYPE_NOCLIP)
  982. return;
  983. if (self.health < 0)
  984. return;
  985. if (self.waterlevel != 3)
  986. {
  987. if (self.air_finished < time)
  988. sound (self, CHAN_VOICE, "player/gasp2.wav", 1, ATTN_NORM);
  989. else if (self.air_finished < time + 9)
  990. sound (self, CHAN_VOICE, "player/gasp1.wav", 1, ATTN_NORM);
  991. self.air_finished = time + 12;
  992. self.dmg = 2;
  993. }
  994. else if (self.air_finished < time)
  995. { // drown!
  996. if (self.pain_finished < time)
  997. {
  998. self.dmg = self.dmg + 2;
  999. if (self.dmg > 15)
  1000. self.dmg = 10;
  1001. T_Damage (self, world, world, self.dmg);
  1002. self.pain_finished = time + 1;
  1003. }
  1004. }
  1005. if (!self.waterlevel)
  1006. {
  1007. if (self.flags & FL_INWATER)
  1008. {
  1009. // play leave water sound
  1010. sound (self, CHAN_BODY, "misc/outwater.wav", 1, ATTN_NORM);
  1011. self.flags = self.flags - FL_INWATER;
  1012. }
  1013. return;
  1014. }
  1015. if (self.watertype == CONTENT_LAVA)
  1016. { // do damage
  1017. if (self.dmgtime < time)
  1018. {
  1019. if (self.radsuit_finished > time)
  1020. self.dmgtime = time + 1;
  1021. else
  1022. self.dmgtime = time + 0.2;
  1023. T_Damage (self, world, world, 10*self.waterlevel);
  1024. }
  1025. }
  1026. else if (self.watertype == CONTENT_SLIME)
  1027. { // do damage
  1028. if (self.dmgtime < time && self.radsuit_finished < time)
  1029. {
  1030. self.dmgtime = time + 1;
  1031. T_Damage (self, world, world, 4*self.waterlevel);
  1032. }
  1033. }
  1034. if ( !(self.flags & FL_INWATER) )
  1035. {
  1036. // player enter water sound
  1037. if (self.watertype == CONTENT_LAVA)
  1038. sound (self, CHAN_BODY, "player/inlava.wav", 1, ATTN_NORM);
  1039. if (self.watertype == CONTENT_WATER)
  1040. sound (self, CHAN_BODY, "player/inh2o.wav", 1, ATTN_NORM);
  1041. if (self.watertype == CONTENT_SLIME)
  1042. sound (self, CHAN_BODY, "player/slimbrn2.wav", 1, ATTN_NORM);
  1043. self.flags = self.flags + FL_INWATER;
  1044. self.dmgtime = 0;
  1045. }
  1046. if (! (self.flags & FL_WATERJUMP) )
  1047. self.velocity = self.velocity - 0.8*self.waterlevel*frametime*self.velocity;
  1048. };
  1049. void() CheckWaterJump =
  1050. {
  1051. local vector start, end;
  1052. // check for a jump-out-of-water
  1053. makevectors (self.angles);
  1054. start = self.origin;
  1055. start_z = start_z + 8;
  1056. v_forward_z = 0;
  1057. normalize(v_forward);
  1058. end = start + v_forward*24;
  1059. traceline (start, end, TRUE, self);
  1060. if (trace_fraction < 1)
  1061. { // solid at waist
  1062. start_z = start_z + self.maxs_z - 8;
  1063. end = start + v_forward*24;
  1064. self.movedir = trace_plane_normal * -50;
  1065. traceline (start, end, TRUE, self);
  1066. if (trace_fraction == 1)
  1067. { // open at eye level
  1068. self.flags = self.flags | FL_WATERJUMP;
  1069. self.velocity_z = 225;
  1070. self.flags = self.flags - (self.flags & FL_JUMPRELEASED);
  1071. self.teleport_time = time + 2; // safety net
  1072. return;
  1073. }
  1074. }
  1075. };
  1076. /*
  1077. ================
  1078. PlayerPreThink
  1079. Called every frame before physics are run
  1080. ================
  1081. */
  1082. void() PlayerPreThink =
  1083. {
  1084. local float mspeed, aspeed;
  1085. local float r;
  1086. if (intermission_running)
  1087. {
  1088. IntermissionThink (); // otherwise a button could be missed between
  1089. return; // the think tics
  1090. }
  1091. if (self.view_ofs == '0 0 0')
  1092. return; // intermission or finale
  1093. if (earthquake_active)
  1094. {
  1095. if ( self.flags & FL_ONGROUND )
  1096. {
  1097. self.velocity_x = self.velocity_x +
  1098. (random() * earthquake_intensity * 2) -
  1099. earthquake_intensity;
  1100. self.velocity_y = self.velocity_y +
  1101. (random() * earthquake_intensity * 2) -
  1102. earthquake_intensity;
  1103. self.velocity_z = self.velocity_z +
  1104. (random() * earthquake_intensity * 2) -
  1105. earthquake_intensity;
  1106. }
  1107. }
  1108. makevectors (self.v_angle); // is this still used
  1109. //ZOID--
  1110. // TeamCheckLock performs all necessary teamlock checking, and performs all
  1111. // actions needed.
  1112. TeamCheckLock();
  1113. //--ZOID
  1114. CheckMOTD();
  1115. CheckRules ();
  1116. WaterMove ();
  1117. if (self.waterlevel == 2)
  1118. CheckWaterJump ();
  1119. if (self.deadflag >= DEAD_DEAD)
  1120. {
  1121. PlayerDeathThink ();
  1122. return;
  1123. }
  1124. if (self.deadflag == DEAD_DYING)
  1125. return; // dying, so do nothing
  1126. if (self.button2)
  1127. {
  1128. PlayerJump ();
  1129. }
  1130. else
  1131. self.flags = self.flags | FL_JUMPRELEASED;
  1132. // teleporters can force a non-moving pause time
  1133. if (time < self.pausetime)
  1134. self.velocity = '0 0 0';
  1135. if (self.items2 & IT2_ANTIGRAV)
  1136. {
  1137. if ( time > self.AGping )
  1138. {
  1139. sound ( self, CHAN_AUTO, "belt/use.wav", 0.4, ATTN_NORM);
  1140. self. AGping = time + 3;
  1141. if(self. AGping >= (self.antigrav_finished - 3))
  1142. self. AGping = self.antigrav_finished + 3;
  1143. }
  1144. }
  1145. RuneApplyElder(self); // regeneration rune
  1146. // Track the grapple
  1147. if (self.hook_out)
  1148. GrappleService();
  1149. };
  1150. /*
  1151. ================
  1152. CheckPowerups
  1153. Check for turning off powerups
  1154. ================
  1155. */
  1156. void() CheckPowerups =
  1157. {
  1158. if (self.health <= 0)
  1159. return;
  1160. // invisibility
  1161. if (self.invisible_finished)
  1162. {
  1163. // sound and screen flash when items starts to run out
  1164. if (self.invisible_sound < time)
  1165. {
  1166. sound (self, CHAN_AUTO, "items/inv3.wav", 0.5, ATTN_IDLE);
  1167. self.invisible_sound = time + ((random() * 3) + 1);
  1168. }
  1169. if (self.invisible_finished < time + 3)
  1170. {
  1171. if (self.invisible_time == 1)
  1172. {
  1173. sprint(self, "$qc_ring_fade");
  1174. stuffcmd (self, "bf\n");
  1175. sound (self, CHAN_AUTO, "items/inv2.wav", 1, ATTN_NORM);
  1176. self.invisible_time = time + 1;
  1177. }
  1178. if (self.invisible_time < time)
  1179. {
  1180. self.invisible_time = time + 1;
  1181. stuffcmd (self, "bf\n");
  1182. }
  1183. }
  1184. if (self.invisible_finished < time)
  1185. { // just stopped
  1186. self.items = self.items - IT_INVISIBILITY;
  1187. self.invisible_finished = 0;
  1188. self.invisible_time = 0;
  1189. }
  1190. // use the eyes
  1191. self.frame = 0;
  1192. self.modelindex = modelindex_eyes;
  1193. }
  1194. else
  1195. self.modelindex = modelindex_player; // don't use eyes
  1196. // invincibility
  1197. if (self.invincible_finished)
  1198. {
  1199. // sound and screen flash when items starts to run out
  1200. if (self.invincible_finished < time + 3)
  1201. {
  1202. if (self.invincible_time == 1)
  1203. {
  1204. sprint(self, "$qc_protection_fade");
  1205. stuffcmd (self, "bf\n");
  1206. sound (self, CHAN_AUTO, "items/protect2.wav", 1, ATTN_NORM);
  1207. self.invincible_time = time + 1;
  1208. }
  1209. if (self.invincible_time < time)
  1210. {
  1211. self.invincible_time = time + 1;
  1212. stuffcmd (self, "bf\n");
  1213. }
  1214. }
  1215. if (self.invincible_finished < time)
  1216. { // just stopped
  1217. self.items = self.items - IT_INVULNERABILITY;
  1218. self.invincible_time = 0;
  1219. self.invincible_finished = 0;
  1220. }
  1221. if (self.invincible_finished > time)
  1222. self.effects = self.effects | EF_PENTALIGHT;
  1223. else
  1224. self.effects = self.effects - (self.effects & EF_PENTALIGHT);
  1225. }
  1226. // super damage
  1227. if (self.super_damage_finished)
  1228. {
  1229. // sound and screen flash when items starts to run out
  1230. if (self.super_damage_finished < time + 3)
  1231. {
  1232. if (self.super_time == 1)
  1233. {
  1234. sprint(self, "$qc_quad_fade");
  1235. stuffcmd (self, "bf\n");
  1236. sound (self, CHAN_AUTO, "items/damage2.wav", 1, ATTN_NORM);
  1237. self.super_time = time + 1;
  1238. }
  1239. if (self.super_time < time)
  1240. {
  1241. self.super_time = time + 1;
  1242. stuffcmd (self, "bf\n");
  1243. }
  1244. }
  1245. if (self.super_damage_finished < time)
  1246. { // just stopped
  1247. self.items = self.items - IT_QUAD;
  1248. self.super_damage_finished = 0;
  1249. self.super_time = 0;
  1250. }
  1251. if (self.super_damage_finished > time)
  1252. self.effects = self.effects | EF_QUADLIGHT;
  1253. else
  1254. self.effects = self.effects - (self.effects & EF_QUADLIGHT);
  1255. }
  1256. // suit
  1257. if (self.radsuit_finished)
  1258. {
  1259. self.air_finished = time + 12; // don't drown
  1260. // sound and screen flash when items starts to run out
  1261. if (self.radsuit_finished < time + 3)
  1262. {
  1263. if (self.rad_time == 1)
  1264. {
  1265. sprint(self, "$qc_biosuit_fade");
  1266. stuffcmd (self, "bf\n");
  1267. sound (self, CHAN_AUTO, "items/suit2.wav", 1, ATTN_NORM);
  1268. self.rad_time = time + 1;
  1269. }
  1270. if (self.rad_time < time)
  1271. {
  1272. self.rad_time = time + 1;
  1273. stuffcmd (self, "bf\n");
  1274. }
  1275. }
  1276. if (self.radsuit_finished < time)
  1277. { // just stopped
  1278. self.items = self.items - IT_SUIT;
  1279. self.rad_time = 0;
  1280. self.radsuit_finished = 0;
  1281. }
  1282. }
  1283. if(self.shield_finished)
  1284. {
  1285. if ( self.shield_finished < time + 3)
  1286. {
  1287. if (self.shield_time == 1)
  1288. {
  1289. sprint (self, "$qc_shield_failing");
  1290. sound (self, CHAN_AUTO, "shield/fadeout.wav", 1, ATTN_NORM);
  1291. self.shield_time = 0;
  1292. }
  1293. if (self.shield_time < time)
  1294. {
  1295. self.shield_time = time + 1;
  1296. stuffcmd (self, "bf\n");
  1297. }
  1298. }
  1299. if ( self.shield_finished < time)
  1300. {
  1301. sprint (self, "$qc_shield_lost");
  1302. self.shield_finished = 0;
  1303. self.items2 = self.items2 - IT2_SHIELD;
  1304. }
  1305. }
  1306. if(self.antigrav_finished)
  1307. {
  1308. if ( self.antigrav_finished < time + 3)
  1309. {
  1310. if (self.antigrav_time == 1)
  1311. {
  1312. sprint (self, "$qc_antigrav_failing");
  1313. self.antigrav_time = 0;
  1314. sound (self, CHAN_AUTO, "belt/fadeout.wav", 1, ATTN_NORM);
  1315. }
  1316. if (self.antigrav_time < time)
  1317. {
  1318. self.antigrav_time = time + 1;
  1319. stuffcmd (self, "bf\n");
  1320. }
  1321. }
  1322. if ( self.antigrav_finished < time)
  1323. {
  1324. sprint (self, "$qc_antigrav_lost");
  1325. self.antigrav_finished = 0;
  1326. self.items2 = self.items2 - IT2_ANTIGRAV;
  1327. self.gravity = 1.0;
  1328. }
  1329. }
  1330. };
  1331. /*
  1332. ================
  1333. PlayerPostThink
  1334. Called every frame after physics are run
  1335. ================
  1336. */
  1337. void() xpackEnding;
  1338. void() PlayerPostThink =
  1339. {
  1340. local float mspeed, aspeed;
  1341. local float r;
  1342. if (self.view_ofs == '0 0 0')
  1343. return; // intermission or finale
  1344. if (self.deadflag)
  1345. return;
  1346. if (cutscene_running)
  1347. {
  1348. xpackEnding();
  1349. }
  1350. // do weapon stuff
  1351. W_WeaponFrame ();
  1352. // check to see if player landed and play landing sound
  1353. if ((self.jump_flag < -300) &&
  1354. (self.flags & FL_ONGROUND) && (self.health > 0))
  1355. {
  1356. if (self.watertype == CONTENT_WATER)
  1357. sound (self, CHAN_BODY, "player/h2ojump.wav", 1, ATTN_NORM);
  1358. else if (self.jump_flag < -650)
  1359. {
  1360. T_Damage (self, world, world, 5);
  1361. sound (self, CHAN_VOICE, "player/land2.wav", 1, ATTN_NORM);
  1362. self.deathtype = "falling";
  1363. }
  1364. else
  1365. sound (self, CHAN_VOICE, "player/land.wav", 1, ATTN_NORM);
  1366. self.jump_flag = 0;
  1367. }
  1368. if (!(self.flags & FL_ONGROUND))
  1369. self.jump_flag = self.velocity_z;
  1370. CheckPowerups ();
  1371. };
  1372. /*
  1373. ===========
  1374. ClientConnect
  1375. called when a player connects to a server
  1376. ============
  1377. */
  1378. void() ClientConnect =
  1379. {
  1380. bprint("$qc_entered", self.netname);
  1381. //ZOID--
  1382. self.suicide_count = 0;
  1383. self.ctf_killed = 0;
  1384. SetMOTD();
  1385. // If this is our first connection, parm14 is < 0
  1386. // Set lastteam negative.
  1387. if (parm14 < 0 && teamplay > 0)
  1388. {
  1389. if (cvar("gamecfg") & GAMECFG_USE_COLOR)
  1390. self.steam = self.team; // accept joining players color if legal
  1391. else
  1392. self.steam = -50; // always reassign
  1393. TeamCheckLock();
  1394. }
  1395. //--ZOID
  1396. // a client connecting during an intermission can cause problems
  1397. if (intermission_running)
  1398. ExitIntermission ();
  1399. };
  1400. /*
  1401. ===========
  1402. ClientDisconnect
  1403. called when a player disconnects from a server
  1404. ============
  1405. */
  1406. void() ClientDisconnect =
  1407. {
  1408. if (gameover)
  1409. return;
  1410. // if the level end trigger has been activated, just return
  1411. // since they aren't *really* leaving
  1412. // let everyone else know
  1413. bprint("$qc_left_game", self.netname, ftos(self.frags));
  1414. sound (self, CHAN_BODY, "player/tornoff2.wav", 1, ATTN_NONE);
  1415. sphere_remove(self);
  1416. if ( tag_token_owner == self)
  1417. tag_token_drop();
  1418. //ZOID--
  1419. TeamDropFlagOfPlayer(self);
  1420. self.steam = -50;
  1421. self.team = 0;
  1422. //--ZOID
  1423. set_suicide_frame ();
  1424. };
  1425. /*
  1426. ===========
  1427. ClientObituary
  1428. called when a player dies
  1429. ============
  1430. */
  1431. void(entity targ, entity attacker) ClientObituary =
  1432. {
  1433. local float rnum;
  1434. local string deathstring, deathstring2;
  1435. rnum = random();
  1436. if (targ.classname == "player")
  1437. {
  1438. // ZOID--
  1439. TeamResetCarrier(targ);
  1440. // --ZOID
  1441. if (attacker.classname == "teledeath")
  1442. {
  1443. bprint("$qc_telefragged", targ.netname, attacker.owner.netname);
  1444. attacker.owner.frags = attacker.owner.frags + 1;
  1445. return;
  1446. }
  1447. if (attacker.classname == "teledeath2")
  1448. {
  1449. bprint("$qc_satans_power", targ.netname);
  1450. targ.frags = targ.frags - 1;
  1451. return;
  1452. }
  1453. if (attacker.classname == "player")
  1454. {
  1455. if (targ == attacker)
  1456. {
  1457. // killed self
  1458. attacker.frags = attacker.frags - 1;
  1459. if (targ.weapon == 64 && targ.waterlevel > 1)
  1460. {
  1461. if (targ.watertype == CONTENT_SLIME)
  1462. bprint("$qc_discharge_slime", targ.netname);
  1463. else if (targ.watertype == CONTENT_LAVA)
  1464. bprint("$qc_discharge_lava", targ.netname);
  1465. else
  1466. bprint("$qc_discharge_water", targ.netname);
  1467. return;
  1468. }
  1469. if (targ.weapon == 16)
  1470. bprint("$qc_suicide_pin", targ.netname);
  1471. else if (rnum < 0.50)
  1472. bprint("$qc_suicide_bored", targ.netname);
  1473. //ZOID--
  1474. //gibbed for changing teams
  1475. else if (teamplay && (targ.team != targ.steam))
  1476. {
  1477. if (cvar("gamecfg") & GAMECFG_ALLOW_CHG)
  1478. bprint("$qc_changed_teams", targ.netname);
  1479. else
  1480. bprint("$qc_tried_change_teams", targ.netname);
  1481. }
  1482. //--ZOID
  1483. else
  1484. bprint("$qc_suicide_loaded", targ.netname);
  1485. return;
  1486. }
  1487. else if ( (teamplay == 2) && (targ.team > 0)&&(targ.team == attacker.team) )
  1488. {
  1489. if (rnum < 0.25)
  1490. bprint("$qc_ff_teammate", attacker.netname);
  1491. else if (rnum < 0.50)
  1492. bprint("$qc_ff_glasses", attacker.netname);
  1493. else if (rnum < 0.75)
  1494. bprint("$qc_ff_otherteam", attacker.netname);
  1495. else
  1496. bprint("$qc_ff_friend", attacker.netname);
  1497. attacker.frags = attacker.frags - 1;
  1498. return;
  1499. }
  1500. else
  1501. {
  1502. if (teamplay == TEAM_DMATCH_TAG)
  1503. dmatch_score (targ, attacker);
  1504. else
  1505. {
  1506. attacker.frags = attacker.frags + 1;
  1507. //ZOID--
  1508. TeamAssists(targ, attacker);
  1509. //--ZOID
  1510. }
  1511. rnum = attacker.weapon;
  1512. if (rnum == IT_AXE)
  1513. {
  1514. bprint("$qc_death_ax", targ.netname, attacker.netname);
  1515. return;
  1516. }
  1517. //ZOID--
  1518. if (rnum == IT_GRAPPLE)
  1519. {
  1520. bprint("$qc_death_grappled", targ.netname, attacker.netname);
  1521. return;
  1522. }
  1523. //--ZOID
  1524. if (rnum == IT_SHOTGUN)
  1525. {
  1526. bprint("$qc_death_sg", targ.netname, attacker.netname);
  1527. return;
  1528. }
  1529. if (rnum == IT_SUPER_SHOTGUN)
  1530. {
  1531. bprint("$qc_death_dbl", targ.netname, attacker.netname);
  1532. return;
  1533. }
  1534. if (rnum == IT_NAILGUN)
  1535. {
  1536. bprint("$qc_death_nail", targ.netname, attacker.netname);
  1537. return;
  1538. }
  1539. if (rnum == IT_SUPER_NAILGUN)
  1540. {
  1541. bprint("$qc_death_sng", targ.netname, attacker.netname);
  1542. return;
  1543. }
  1544. if (rnum == IT_GRENADE_LAUNCHER)
  1545. {
  1546. if (targ.health < -40)
  1547. {
  1548. bprint("$qc_death_gl1", targ.netname, attacker.netname);
  1549. return;
  1550. }
  1551. else
  1552. {
  1553. bprint("$qc_death_gl2", targ.netname, attacker.netname);
  1554. return;
  1555. }
  1556. }
  1557. if (rnum == IT_ROCKET_LAUNCHER)
  1558. {
  1559. if (attacker.super_damage_finished > 0 && targ.health < -40)
  1560. {
  1561. rnum = random();
  1562. if (rnum < 0.3)
  1563. {
  1564. bprint("$qc_death_rl_quad1", targ.netname, attacker.netname);
  1565. return;
  1566. }
  1567. else if (rnum < 0.6)
  1568. {
  1569. bprint("$qc_death_rl_quad2", targ.netname, attacker.netname);
  1570. return;
  1571. }
  1572. else
  1573. {
  1574. bprint("$qc_death_rl1", targ.netname, attacker.netname);
  1575. return;
  1576. }
  1577. }
  1578. else
  1579. {
  1580. if (targ.health < -40)
  1581. {
  1582. bprint("$qc_death_rl2", targ.netname, attacker.netname);
  1583. return;
  1584. }
  1585. else
  1586. {
  1587. bprint("$qc_death_rl3", targ.netname, attacker.netname);
  1588. return;
  1589. }
  1590. }
  1591. }
  1592. if (rnum == IT_LIGHTNING)
  1593. {
  1594. if (attacker.waterlevel > 1)
  1595. {
  1596. bprint("$qc_death_lg1", targ.netname, attacker.netname);
  1597. if (attacker.invincible_finished)
  1598. {
  1599. msg_entity = attacker;
  1600. WriteByte (MSG_ONE, SVC_ACHIEVEMENT);
  1601. WriteString(MSG_ONE, "ACH_SURVIVE_DISCHARGE");
  1602. }
  1603. }
  1604. else
  1605. bprint("$qc_death_lg2", targ.netname, attacker.netname);
  1606. return;
  1607. }
  1608. if (rnum == IT_LAVA_NAILGUN || rnum == IT_LAVA_SUPER_NAILGUN)
  1609. {
  1610. bprint("$qc_death_burned", targ.netname, attacker.netname);
  1611. return;
  1612. }
  1613. else if (rnum == IT_PLASMA_GUN)
  1614. {
  1615. bprint("$qc_death_fused", targ.netname, attacker.netname);
  1616. return;
  1617. }
  1618. else if (rnum == IT_MULTI_GRENADE || rnum == IT_MULTI_ROCKET)
  1619. {
  1620. bprint("$qc_death_blasted", targ.netname, attacker.netname);
  1621. return;
  1622. }
  1623. }
  1624. return;
  1625. }
  1626. else
  1627. {
  1628. targ.frags = targ.frags - 1;
  1629. // killed by a montser?
  1630. if (attacker.flags & FL_MONSTER)
  1631. {
  1632. if (attacker.classname == "monster_army")
  1633. bprint ("$qc_ks_grunt", targ.netname);
  1634. if (attacker.classname == "monster_demon1")
  1635. bprint ("$qc_ks_fiend", targ.netname);
  1636. if (attacker.classname == "monster_dog")
  1637. bprint ("$qc_ks_rottweiler", targ.netname);
  1638. if (attacker.classname == "monster_dragon")
  1639. bprint ("$qc_ks_dragon1", targ.netname);
  1640. if (attacker.classname == "monster_dragon_dead")
  1641. bprint ("$qc_ks_dragon2", targ.netname);
  1642. if (attacker.classname == "monster_enforcer")
  1643. bprint ("$qc_ks_enforcer", targ.netname);
  1644. if (attacker.classname == "monster_fish")
  1645. bprint ("$qc_ks_rotfish", targ.netname);
  1646. if (attacker.classname == "monster_hell_knight")
  1647. bprint ("$qc_ks_deathknight", targ.netname);
  1648. if (attacker.classname == "monster_knight")
  1649. bprint ("$qc_ks_knight", targ.netname);
  1650. if (attacker.classname == "monster_ogre")
  1651. bprint ("$qc_ks_ogre", targ.netname);
  1652. if (attacker.classname == "monster_oldone")
  1653. bprint ("$qc_ks_shub", targ.netname);
  1654. if (attacker.classname == "monster_shalrath")
  1655. bprint ("$qc_ks_vore", targ.netname);
  1656. if (attacker.classname == "monster_shambler")
  1657. bprint ("$qc_ks_shambler", targ.netname);
  1658. if (attacker.classname == "monster_tarbaby")
  1659. bprint ("$qc_ks_spawn", targ.netname);
  1660. if (attacker.classname == "monster_vomit")
  1661. bprint ("$qc_ks_vomitus", targ.netname);
  1662. if (attacker.classname == "monster_wizard")
  1663. bprint ("$qc_ks_scrag", targ.netname);
  1664. if (attacker.classname == "monster_zombie")
  1665. bprint ("$qc_ks_zombie", targ.netname);
  1666. if (attacker.classname == "monster_eel")
  1667. bprint ("$qc_ks_eel", targ.netname);
  1668. if (attacker.classname == "monster_wrath")
  1669. bprint ("$qc_ks_wrath", targ.netname);
  1670. if (attacker.classname == "monster_super_wrath")
  1671. bprint ("$qc_ks_overlord", targ.netname);
  1672. if (attacker.classname == "monster_sword")
  1673. bprint ("$qc_ks_swordsman", targ.netname);
  1674. if (attacker.classname == "monster_lava_man")
  1675. bprint ("$qc_ks_hephaestus", targ.netname);
  1676. if (attacker.classname == "monster_morph")
  1677. bprint ("$qc_ks_guardian", targ.netname);
  1678. if (attacker.classname == "monster_mummy")
  1679. bprint ("$qc_ks_mummy", targ.netname);
  1680. return;
  1681. }
  1682. // tricks and traps
  1683. if (attacker.classname == "explo_box")
  1684. {
  1685. bprint ("$qc_ks_blew_up", targ.netname);
  1686. return;
  1687. }
  1688. if (attacker.solid == SOLID_BSP && attacker != world)
  1689. {
  1690. bprint ("$qc_death_squish", targ.netname);
  1691. return;
  1692. }
  1693. if (attacker.classname == "trap_shooter" || attacker.classname == "trap_spikeshooter")
  1694. {
  1695. bprint ("$qc_ks_spiked", targ.netname);
  1696. return;
  1697. }
  1698. if (attacker.classname == "fireball")
  1699. {
  1700. bprint ("$qc_ks_lavaball", targ.netname);
  1701. return;
  1702. }
  1703. if (attacker.classname == "trigger_changelevel")
  1704. {
  1705. bprint ("$qc_ks_tried_leave", targ.netname);
  1706. return;
  1707. }
  1708. if (attacker.classname == "ltrail_start" ||
  1709. attacker.classname == "ltrail_relay")
  1710. {
  1711. bprint ("$qc_ks_rode_lightning", targ.netname);
  1712. return;
  1713. }
  1714. if (attacker.classname == "pendulum")
  1715. {
  1716. bprint ("$qc_ks_cleaved", targ.netname);
  1717. return;
  1718. }
  1719. if (attacker.classname == "buzzsaw")
  1720. {
  1721. bprint ("$qc_ks_sliced", targ.netname);
  1722. return;
  1723. }
  1724. if (attacker.classname == "plasma")
  1725. {
  1726. bprint ( "$qc_ks_plasma", targ.netname);
  1727. return;
  1728. }
  1729. if (attacker.classname == "Vengeance")
  1730. {
  1731. // vengeance sphere doesn't count as a negative frag
  1732. targ.frags = targ.frags + 1;
  1733. bprint ( "$qc_death_vengeance", targ.netname);
  1734. return;
  1735. }
  1736. if (attacker.classname == "power_shield")
  1737. {
  1738. // shield attacks should count for frags too..
  1739. // shield death doesn't count as a negative frag
  1740. targ.frags = targ.frags + 1;
  1741. attacker.owner.frags = attacker.owner.frags + 1;
  1742. TeamAssists(targ, attacker.owner); //PGM
  1743. bprint("$qc_death_smashed", targ.netname, attacker.owner.netname);
  1744. return;
  1745. }
  1746. // in-water deaths
  1747. rnum = targ.watertype;
  1748. if (rnum == -3)
  1749. {
  1750. if (random() < 0.5)
  1751. bprint("$qc_death_drown1", targ.netname);
  1752. else
  1753. bprint("$qc_death_drown2", targ.netname);
  1754. return;
  1755. }
  1756. else if (rnum == -4)
  1757. {
  1758. if (random() < 0.5)
  1759. bprint("$qc_death_slime1", targ.netname);
  1760. else
  1761. bprint("$qc_death_slime2", targ.netname);
  1762. return;
  1763. }
  1764. else if (rnum == -5)
  1765. {
  1766. if (targ.health < -15)
  1767. {
  1768. bprint("$qc_death_lava1", targ.netname);
  1769. return;
  1770. }
  1771. if (random() < 0.5)
  1772. bprint("$qc_death_lava2", targ.netname);
  1773. else
  1774. bprint("$qc_death_lava3", targ.netname);
  1775. return;
  1776. }
  1777. if (attacker.solid == SOLID_BSP && attacker != world)
  1778. {
  1779. bprint("$qc_death_squish", targ.netname);
  1780. return;
  1781. }
  1782. if (targ.deathtype == "falling")
  1783. {
  1784. targ.deathtype = string_null;
  1785. bprint("$qc_death_fall", targ.netname);
  1786. return;
  1787. }
  1788. bprint("$qc_death_died", targ.netname);
  1789. }
  1790. }
  1791. };