client.qc 46 KB

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