client.qc 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525
  1. /*
  2. client.qc
  3. client functions
  4. Copyright (C) 1996-1997 Id Software, Inc.
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation; either version 2
  8. of the License, or (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. See the GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to:
  15. Free Software Foundation, Inc.
  16. 59 Temple Place - Suite 330
  17. Boston, MA 02111-1307, USA
  18. */
  19. // prototypes
  20. void () W_WeaponFrame;
  21. void() W_SetCurrentAmmo;
  22. void() player_pain;
  23. void() player_stand1;
  24. void (vector org) spawn_tfog;
  25. void (vector org, entity death_owner) spawn_tdeath;
  26. float modelindex_eyes, modelindex_player;
  27. /*
  28. =============================================================================
  29. LEVEL CHANGING / INTERMISSION
  30. =============================================================================
  31. */
  32. string nextmap;
  33. float intermission_running;
  34. float intermission_exittime;
  35. /*QUAKED info_intermission (1 0.5 0.5) (-16 -16 -16) (16 16 16)
  36. This is the camera point for the intermission.
  37. Use mangle instead of angle, so you can set pitch or roll as well as yaw. 'pitch roll yaw'
  38. */
  39. void() info_intermission =
  40. {
  41. self.angles = self.mangle; // so C can get at it
  42. };
  43. void() SetChangeParms =
  44. {
  45. if (self.health <= 0)
  46. {
  47. SetNewParms ();
  48. return;
  49. }
  50. // remove items
  51. self.items = self.items - (self.items &
  52. (IT_KEY1 | IT_KEY2 | IT_INVISIBILITY | IT_INVULNERABILITY | IT_SUIT | IT_QUAD) );
  53. // cap super health
  54. if (self.health > 100)
  55. self.health = 100;
  56. if (self.health < 50)
  57. self.health = 50;
  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. parm2 = 100;
  75. parm3 = 0;
  76. parm4 = 25;
  77. parm5 = 0;
  78. parm6 = 0;
  79. parm7 = 0;
  80. parm8 = 1;
  81. parm9 = 0;
  82. };
  83. void() DecodeLevelParms =
  84. {
  85. if (serverflags)
  86. {
  87. if (world.model == "maps/start.bsp")
  88. SetNewParms (); // take away all stuff on starting new episode
  89. }
  90. self.items = parm1;
  91. self.health = parm2;
  92. self.armorvalue = parm3;
  93. self.ammo_shells = parm4;
  94. self.ammo_nails = parm5;
  95. self.ammo_rockets = parm6;
  96. self.ammo_cells = parm7;
  97. self.weapon = parm8;
  98. self.armortype = parm9 * 0.01;
  99. };
  100. /*
  101. ============
  102. FindIntermission
  103. Returns the entity to view from
  104. ============
  105. */
  106. entity() FindIntermission =
  107. {
  108. local entity spot;
  109. local float cyc;
  110. // look for info_intermission first
  111. spot = find (world, classname, "info_intermission");
  112. if (spot)
  113. { // pick a random one
  114. cyc = random() * 4;
  115. while (cyc > 1)
  116. {
  117. spot = find (spot, classname, "info_intermission");
  118. if (!spot)
  119. spot = find (spot, classname, "info_intermission");
  120. cyc = cyc - 1;
  121. }
  122. return spot;
  123. }
  124. // then look for the start position
  125. spot = find (world, classname, "info_player_start");
  126. if (spot)
  127. return spot;
  128. objerror ("FindIntermission: no spot");
  129. };
  130. void() GotoNextMap =
  131. {
  132. local string newmap;
  133. //ZOID: 12-13-96, samelevel is overloaded, only 1 works for same level
  134. if (cvar("samelevel") == 1) // if samelevel is set, stay on same level
  135. changelevel (mapname);
  136. else {
  137. // configurable map lists, see if the current map exists as a
  138. // serverinfo/localinfo var
  139. newmap = infokey(world, mapname);
  140. if (newmap != "")
  141. changelevel (newmap);
  142. else
  143. changelevel (nextmap);
  144. }
  145. };
  146. /*
  147. ============
  148. IntermissionThink
  149. When the player presses attack or jump, change to the next level
  150. ============
  151. */
  152. void() IntermissionThink =
  153. {
  154. if (time < intermission_exittime)
  155. return;
  156. if (!self.button0 && !self.button1 && !self.button2)
  157. return;
  158. GotoNextMap ();
  159. };
  160. /*
  161. ============
  162. execute_changelevel
  163. The global "nextmap" has been set previously.
  164. Take the players to the intermission spot
  165. ============
  166. */
  167. void() execute_changelevel =
  168. {
  169. local entity pos;
  170. intermission_running = 1;
  171. // enforce a wait time before allowing changelevel
  172. intermission_exittime = time + 5;
  173. pos = FindIntermission ();
  174. // play intermission music
  175. WriteByte (MSG_ALL, SVC_CDTRACK);
  176. WriteByte (MSG_ALL, 3);
  177. WriteByte (MSG_ALL, SVC_INTERMISSION);
  178. WriteCoord (MSG_ALL, pos.origin_x);
  179. WriteCoord (MSG_ALL, pos.origin_y);
  180. WriteCoord (MSG_ALL, pos.origin_z);
  181. WriteAngle (MSG_ALL, pos.mangle_x);
  182. WriteAngle (MSG_ALL, pos.mangle_y);
  183. WriteAngle (MSG_ALL, pos.mangle_z);
  184. other = find (world, classname, "player");
  185. while (other != world)
  186. {
  187. other.takedamage = DAMAGE_NO;
  188. other.solid = SOLID_NOT;
  189. other.movetype = MOVETYPE_NONE;
  190. other.modelindex = 0;
  191. other = find (other, classname, "player");
  192. }
  193. };
  194. void() changelevel_touch =
  195. {
  196. local entity pos;
  197. if (other.classname != "player")
  198. return;
  199. // if "noexit" is set, blow up the player trying to leave
  200. //ZOID, 12-13-96, noexit isn't supported in QW. Overload samelevel
  201. // if ((cvar("noexit") == 1) || ((cvar("noexit") == 2) && (mapname != "start")))
  202. if ((cvar("samelevel") == 2) || ((cvar("samelevel") == 3) && (mapname != "start")))
  203. {
  204. T_Damage (other, self, self, 50000);
  205. return;
  206. }
  207. bprint (PRINT_HIGH, other.netname);
  208. bprint (PRINT_HIGH," exited the level\n");
  209. nextmap = self.map;
  210. SUB_UseTargets ();
  211. self.touch = SUB_Null;
  212. // we can't move people right now, because touch functions are called
  213. // in the middle of C movement code, so set a think time to do it
  214. self.think = execute_changelevel;
  215. self.nextthink = time + 0.1;
  216. };
  217. /*QUAKED trigger_changelevel (0.5 0.5 0.5) ? NO_INTERMISSION
  218. 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.
  219. */
  220. void() trigger_changelevel =
  221. {
  222. if (!self.map)
  223. objerror ("chagnelevel trigger doesn't have map");
  224. InitTrigger ();
  225. self.touch = changelevel_touch;
  226. };
  227. /*
  228. =============================================================================
  229. PLAYER GAME EDGE FUNCTIONS
  230. =============================================================================
  231. */
  232. void() set_suicide_frame;
  233. // called by ClientKill and DeadThink
  234. void() respawn =
  235. {
  236. // make a copy of the dead body for appearances sake
  237. CopyToBodyQue (self);
  238. // set default spawn parms
  239. SetNewParms ();
  240. // respawn
  241. PutClientInServer ();
  242. };
  243. /*
  244. ============
  245. ClientKill
  246. Player entered the suicide command
  247. ============
  248. */
  249. void() ClientKill =
  250. {
  251. bprint (PRINT_MEDIUM, self.netname);
  252. bprint (PRINT_MEDIUM, " suicides\n");
  253. set_suicide_frame ();
  254. self.modelindex = modelindex_player;
  255. logfrag (self, self);
  256. self.frags = self.frags - 2; // extra penalty
  257. respawn ();
  258. };
  259. float(vector v) CheckSpawnPoint =
  260. {
  261. return FALSE;
  262. };
  263. /*
  264. ============
  265. SelectSpawnPoint
  266. Returns the entity to spawn at
  267. ============
  268. */
  269. entity() SelectSpawnPoint =
  270. {
  271. local entity spot, newspot, thing;
  272. local float numspots, totalspots;
  273. local float rnum, pcount;
  274. local float rs;
  275. local entity spots;
  276. numspots = 0;
  277. totalspots = 0;
  278. // testinfo_player_start is only found in regioned levels
  279. spot = find (world, classname, "testplayerstart");
  280. if (spot)
  281. return spot;
  282. // choose a info_player_deathmatch point
  283. // ok, find all spots that don't have players nearby
  284. spots = world;
  285. spot = find (world, classname, "info_player_deathmatch");
  286. while (spot)
  287. {
  288. totalspots = totalspots + 1;
  289. thing=findradius(spot.origin, 84);
  290. pcount=0;
  291. while (thing)
  292. {
  293. if (thing.classname == "player")
  294. pcount=pcount + 1;
  295. thing=thing.chain;
  296. }
  297. if (pcount == 0) {
  298. spot.goalentity = spots;
  299. spots = spot;
  300. numspots = numspots + 1;
  301. }
  302. // Get the next spot in the chain
  303. spot = find (spot, classname, "info_player_deathmatch");
  304. }
  305. totalspots=totalspots - 1;
  306. if (!numspots) {
  307. // ack, they are all full, just pick one at random
  308. // bprint (PRINT_HIGH, "Ackk! All spots are full. Selecting random spawn spot\n");
  309. totalspots = rint((random() * totalspots));
  310. spot = find (world, classname, "info_player_deathmatch");
  311. while (totalspots > 0) {
  312. totalspots = totalspots - 1;
  313. spot = find (spot, classname, "info_player_deathmatch");
  314. }
  315. return spot;
  316. }
  317. // We now have the number of spots available on the map in numspots
  318. // Generate a random number between 1 and numspots
  319. numspots = numspots - 1;
  320. numspots = rint((random() * numspots ) );
  321. spot = spots;
  322. while (numspots > 0) {
  323. spot = spot.goalentity;
  324. numspots = numspots - 1;
  325. }
  326. return spot;
  327. };
  328. void() DecodeLevelParms;
  329. void() PlayerDie;
  330. /*
  331. ===========
  332. ValidateUser
  333. ============
  334. */
  335. float(entity e) ValidateUser =
  336. {
  337. /*
  338. local string s;
  339. local string userclan;
  340. local float rank, rankmin, rankmax;
  341. //
  342. // if the server has set "clan1" and "clan2", then it
  343. // is a clan match that will allow only those two clans in
  344. //
  345. s = serverinfo("clan1");
  346. if (s)
  347. {
  348. userclan = masterinfo(e,"clan");
  349. if (s == userclan)
  350. return true;
  351. s = serverinfo("clan2");
  352. if (s == userclan)
  353. return true;
  354. return false;
  355. }
  356. //
  357. // if the server has set "rankmin" and/or "rankmax" then
  358. // the users rank must be between those two values
  359. //
  360. s = masterinfo (e, "rank");
  361. rank = stof (s);
  362. s = serverinfo("rankmin");
  363. if (s)
  364. {
  365. rankmin = stof (s);
  366. if (rank < rankmin)
  367. return false;
  368. }
  369. s = serverinfo("rankmax");
  370. if (s)
  371. {
  372. rankmax = stof (s);
  373. if (rankmax < rank)
  374. return false;
  375. }
  376. return true;
  377. */
  378. };
  379. /*
  380. ===========
  381. PutClientInServer
  382. called each time a player enters a new level
  383. ============
  384. */
  385. void() PutClientInServer =
  386. {
  387. local entity spot;
  388. local string s;
  389. self.classname = "player";
  390. self.health = 100;
  391. self.takedamage = DAMAGE_AIM;
  392. self.solid = SOLID_SLIDEBOX;
  393. self.movetype = MOVETYPE_WALK;
  394. self.show_hostile = 0;
  395. self.max_health = 100;
  396. self.flags = FL_CLIENT;
  397. self.air_finished = time + 12;
  398. self.dmg = 2; // initial water damage
  399. self.super_damage_finished = 0;
  400. self.radsuit_finished = 0;
  401. self.invisible_finished = 0;
  402. self.invincible_finished = 0;
  403. self.effects = 0;
  404. self.invincible_time = 0;
  405. DecodeLevelParms ();
  406. W_SetCurrentAmmo ();
  407. self.attack_finished = time;
  408. self.th_pain = player_pain;
  409. self.th_die = PlayerDie;
  410. self.deadflag = DEAD_NO;
  411. // paustime is set by teleporters to keep the player from moving a while
  412. self.pausetime = 0;
  413. spot = SelectSpawnPoint ();
  414. self.origin = spot.origin + '0 0 1';
  415. self.angles = spot.angles;
  416. self.fixangle = TRUE; // turn this way immediately
  417. // oh, this is a hack!
  418. setmodel (self, "progs/eyes.mdl");
  419. modelindex_eyes = self.modelindex;
  420. setmodel (self, "progs/player.mdl");
  421. modelindex_player = self.modelindex;
  422. setsize (self, VEC_HULL_MIN, VEC_HULL_MAX);
  423. self.view_ofs = '0 0 22';
  424. // Mod - Xian (May.20.97)
  425. // Bug where player would have velocity from their last kill
  426. self.velocity = '0 0 0';
  427. player_stand1 ();
  428. makevectors(self.angles);
  429. spawn_tfog (self.origin + v_forward*20);
  430. spawn_tdeath (self.origin, self);
  431. // Set Rocket Jump Modifiers
  432. if (stof(infokey(world, "rj")) != 0)
  433. {
  434. rj = stof(infokey(world, "rj"));
  435. }
  436. if (deathmatch == 4)
  437. {
  438. self.ammo_shells = 0;
  439. if (stof(infokey(world, "axe")) == 0)
  440. {
  441. self.ammo_nails = 255;
  442. self.ammo_shells = 255;
  443. self.ammo_rockets = 255;
  444. self.ammo_cells = 255;
  445. self.items = self.items | IT_NAILGUN;
  446. self.items = self.items | IT_SUPER_NAILGUN;
  447. self.items = self.items | IT_SUPER_SHOTGUN;
  448. self.items = self.items | IT_ROCKET_LAUNCHER;
  449. // self.items = self.items | IT_GRENADE_LAUNCHER;
  450. self.items = self.items | IT_LIGHTNING;
  451. }
  452. self.items = self.items - (self.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) + IT_ARMOR3;
  453. self.armorvalue = 200;
  454. self.armortype = 0.8;
  455. self.health = 250;
  456. self.items = self.items | IT_INVULNERABILITY;
  457. self.invincible_time = 1;
  458. self.invincible_finished = time + 3;
  459. }
  460. if (deathmatch == 5)
  461. {
  462. self.ammo_nails = 80;
  463. self.ammo_shells = 30;
  464. self.ammo_rockets = 10;
  465. self.ammo_cells = 30;
  466. self.items = self.items | IT_NAILGUN;
  467. self.items = self.items | IT_SUPER_NAILGUN;
  468. self.items = self.items | IT_SUPER_SHOTGUN;
  469. self.items = self.items | IT_ROCKET_LAUNCHER;
  470. self.items = self.items | IT_GRENADE_LAUNCHER;
  471. self.items = self.items | IT_LIGHTNING;
  472. self.items = self.items - (self.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) + IT_ARMOR3;
  473. self.armorvalue = 200;
  474. self.armortype = 0.8;
  475. self.health = 200;
  476. self.items = self.items | IT_INVULNERABILITY;
  477. self.invincible_time = 1;
  478. self.invincible_finished = time + 3;
  479. }
  480. };
  481. /*
  482. =============================================================================
  483. QUAKED FUNCTIONS
  484. =============================================================================
  485. */
  486. /*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 24)
  487. The normal starting point for a level.
  488. */
  489. void() info_player_start =
  490. {
  491. };
  492. /*QUAKED info_player_start2 (1 0 0) (-16 -16 -24) (16 16 24)
  493. Only used on start map for the return point from an episode.
  494. */
  495. void() info_player_start2 =
  496. {
  497. };
  498. /*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 24)
  499. potential spawning position for deathmatch games
  500. */
  501. void() info_player_deathmatch =
  502. {
  503. };
  504. /*QUAKED info_player_coop (1 0 1) (-16 -16 -24) (16 16 24)
  505. potential spawning position for coop games
  506. */
  507. void() info_player_coop =
  508. {
  509. };
  510. /*
  511. ===============================================================================
  512. RULES
  513. ===============================================================================
  514. */
  515. /*
  516. go to the next level for deathmatch
  517. */
  518. void() NextLevel =
  519. {
  520. local entity o;
  521. local string newmap;
  522. if (nextmap != "")
  523. return; // already done
  524. if (mapname == "start")
  525. {
  526. if (!cvar("registered"))
  527. {
  528. mapname = "e1m1";
  529. }
  530. else if (!(serverflags & 1))
  531. {
  532. mapname = "e1m1";
  533. serverflags = serverflags | 1;
  534. }
  535. else if (!(serverflags & 2))
  536. {
  537. mapname = "e2m1";
  538. serverflags = serverflags | 2;
  539. }
  540. else if (!(serverflags & 4))
  541. {
  542. mapname = "e3m1";
  543. serverflags = serverflags | 4;
  544. }
  545. else if (!(serverflags & 8))
  546. {
  547. mapname = "e4m1";
  548. serverflags = serverflags - 7;
  549. }
  550. o = spawn();
  551. o.map = mapname;
  552. }
  553. else
  554. {
  555. // find a trigger changelevel
  556. o = find(world, classname, "trigger_changelevel");
  557. if (!o || mapname == "start")
  558. { // go back to same map if no trigger_changelevel
  559. o = spawn();
  560. o.map = mapname;
  561. }
  562. }
  563. nextmap = o.map;
  564. if (o.nextthink < time)
  565. {
  566. o.think = execute_changelevel;
  567. o.nextthink = time + 0.1;
  568. }
  569. };
  570. /*
  571. ============
  572. CheckRules
  573. Exit deathmatch games upon conditions
  574. ============
  575. */
  576. void() CheckRules =
  577. {
  578. if (timelimit && time >= timelimit)
  579. NextLevel ();
  580. if (fraglimit && self.frags >= fraglimit)
  581. NextLevel ();
  582. };
  583. //============================================================================
  584. void() PlayerDeathThink =
  585. {
  586. local entity old_self;
  587. local float forward;
  588. if ((self.flags & FL_ONGROUND))
  589. {
  590. forward = vlen (self.velocity);
  591. forward = forward - 20;
  592. if (forward <= 0)
  593. self.velocity = '0 0 0';
  594. else
  595. self.velocity = forward * normalize(self.velocity);
  596. }
  597. // wait for all buttons released
  598. if (self.deadflag == DEAD_DEAD)
  599. {
  600. if (self.button2 || self.button1 || self.button0)
  601. return;
  602. self.deadflag = DEAD_RESPAWNABLE;
  603. return;
  604. }
  605. // wait for any button down
  606. if (!self.button2 && !self.button1 && !self.button0)
  607. return;
  608. self.button0 = 0;
  609. self.button1 = 0;
  610. self.button2 = 0;
  611. respawn();
  612. };
  613. void() PlayerJump =
  614. {
  615. local vector start, end;
  616. if (self.flags & FL_WATERJUMP)
  617. return;
  618. if (self.waterlevel >= 2)
  619. {
  620. // play swiming sound
  621. if (self.swim_flag < time)
  622. {
  623. self.swim_flag = time + 1;
  624. if (random() < 0.5)
  625. sound (self, CHAN_BODY, "misc/water1.wav", 1, ATTN_NORM);
  626. else
  627. sound (self, CHAN_BODY, "misc/water2.wav", 1, ATTN_NORM);
  628. }
  629. return;
  630. }
  631. if (!(self.flags & FL_ONGROUND))
  632. return;
  633. if ( !(self.flags & FL_JUMPRELEASED) )
  634. return; // don't pogo stick
  635. self.flags = self.flags - (self.flags & FL_JUMPRELEASED);
  636. self.button2 = 0;
  637. // player jumping sound
  638. sound (self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM);
  639. };
  640. /*
  641. ===========
  642. WaterMove
  643. ============
  644. */
  645. .float dmgtime;
  646. void() WaterMove =
  647. {
  648. //dprint (ftos(self.waterlevel));
  649. if (self.movetype == MOVETYPE_NOCLIP)
  650. return;
  651. if (self.health < 0)
  652. return;
  653. if (self.waterlevel != 3)
  654. {
  655. if (self.air_finished < time)
  656. sound (self, CHAN_VOICE, "player/gasp2.wav", 1, ATTN_NORM);
  657. else if (self.air_finished < time + 9)
  658. sound (self, CHAN_VOICE, "player/gasp1.wav", 1, ATTN_NORM);
  659. self.air_finished = time + 12;
  660. self.dmg = 2;
  661. }
  662. else if (self.air_finished < time)
  663. { // drown!
  664. if (self.pain_finished < time)
  665. {
  666. self.dmg = self.dmg + 2;
  667. if (self.dmg > 15)
  668. self.dmg = 10;
  669. T_Damage (self, world, world, self.dmg);
  670. self.pain_finished = time + 1;
  671. }
  672. }
  673. if (!self.waterlevel)
  674. {
  675. if (self.flags & FL_INWATER)
  676. {
  677. // play leave water sound
  678. sound (self, CHAN_BODY, "misc/outwater.wav", 1, ATTN_NORM);
  679. self.flags = self.flags - FL_INWATER;
  680. }
  681. return;
  682. }
  683. if (self.watertype == CONTENT_LAVA)
  684. { // do damage
  685. if (self.dmgtime < time)
  686. {
  687. if (self.radsuit_finished > time)
  688. self.dmgtime = time + 1;
  689. else
  690. self.dmgtime = time + 0.2;
  691. T_Damage (self, world, world, 10*self.waterlevel);
  692. }
  693. }
  694. else if (self.watertype == CONTENT_SLIME)
  695. { // do damage
  696. if (self.dmgtime < time && self.radsuit_finished < time)
  697. {
  698. self.dmgtime = time + 1;
  699. T_Damage (self, world, world, 4*self.waterlevel);
  700. }
  701. }
  702. if ( !(self.flags & FL_INWATER) )
  703. {
  704. // player enter water sound
  705. if (self.watertype == CONTENT_LAVA)
  706. sound (self, CHAN_BODY, "player/inlava.wav", 1, ATTN_NORM);
  707. if (self.watertype == CONTENT_WATER)
  708. sound (self, CHAN_BODY, "player/inh2o.wav", 1, ATTN_NORM);
  709. if (self.watertype == CONTENT_SLIME)
  710. sound (self, CHAN_BODY, "player/slimbrn2.wav", 1, ATTN_NORM);
  711. self.flags = self.flags + FL_INWATER;
  712. self.dmgtime = 0;
  713. }
  714. };
  715. void() CheckWaterJump =
  716. {
  717. local vector start, end;
  718. // check for a jump-out-of-water
  719. makevectors (self.angles);
  720. start = self.origin;
  721. start_z = start_z + 8;
  722. v_forward_z = 0;
  723. normalize(v_forward);
  724. end = start + v_forward*24;
  725. traceline (start, end, TRUE, self);
  726. if (trace_fraction < 1)
  727. { // solid at waist
  728. start_z = start_z + self.maxs_z - 8;
  729. end = start + v_forward*24;
  730. self.movedir = trace_plane_normal * -50;
  731. traceline (start, end, TRUE, self);
  732. if (trace_fraction == 1)
  733. { // open at eye level
  734. self.flags = self.flags | FL_WATERJUMP;
  735. self.velocity_z = 225;
  736. self.flags = self.flags - (self.flags & FL_JUMPRELEASED);
  737. self.teleport_time = time + 2; // safety net
  738. return;
  739. }
  740. }
  741. };
  742. /*
  743. ================
  744. PlayerPreThink
  745. Called every frame before physics are run
  746. ================
  747. */
  748. void() PlayerPreThink =
  749. {
  750. local float mspeed, aspeed;
  751. local float r;
  752. if (intermission_running)
  753. {
  754. IntermissionThink (); // otherwise a button could be missed between
  755. return; // the think tics
  756. }
  757. if (self.view_ofs == '0 0 0')
  758. return; // intermission or finale
  759. makevectors (self.v_angle); // is this still used
  760. self.deathtype = "";
  761. CheckRules ();
  762. WaterMove ();
  763. /*
  764. if (self.waterlevel == 2)
  765. CheckWaterJump ();
  766. */
  767. if (self.deadflag >= DEAD_DEAD)
  768. {
  769. PlayerDeathThink ();
  770. return;
  771. }
  772. if (self.deadflag == DEAD_DYING)
  773. return; // dying, so do nothing
  774. if (self.button2)
  775. {
  776. PlayerJump ();
  777. }
  778. else
  779. self.flags = self.flags | FL_JUMPRELEASED;
  780. // teleporters can force a non-moving pause time
  781. if (time < self.pausetime)
  782. self.velocity = '0 0 0';
  783. if(time > self.attack_finished && self.currentammo == 0 && self.weapon != IT_AXE)
  784. {
  785. self.weapon = W_BestWeapon ();
  786. W_SetCurrentAmmo ();
  787. }
  788. };
  789. /*
  790. ================
  791. CheckPowerups
  792. Check for turning off powerups
  793. ================
  794. */
  795. void() CheckPowerups =
  796. {
  797. if (self.health <= 0)
  798. return;
  799. // invisibility
  800. if (self.invisible_finished)
  801. {
  802. // sound and screen flash when items starts to run out
  803. if (self.invisible_sound < time)
  804. {
  805. sound (self, CHAN_AUTO, "items/inv3.wav", 0.5, ATTN_IDLE);
  806. self.invisible_sound = time + ((random() * 3) + 1);
  807. }
  808. if (self.invisible_finished < time + 3)
  809. {
  810. if (self.invisible_time == 1)
  811. {
  812. sprint (self, PRINT_HIGH, "Ring of Shadows magic is fading\n");
  813. stuffcmd (self, "bf\n");
  814. sound (self, CHAN_AUTO, "items/inv2.wav", 1, ATTN_NORM);
  815. self.invisible_time = time + 1;
  816. }
  817. if (self.invisible_time < time)
  818. {
  819. self.invisible_time = time + 1;
  820. stuffcmd (self, "bf\n");
  821. }
  822. }
  823. if (self.invisible_finished < time)
  824. { // just stopped
  825. self.items = self.items - IT_INVISIBILITY;
  826. self.invisible_finished = 0;
  827. self.invisible_time = 0;
  828. }
  829. // use the eyes
  830. self.frame = 0;
  831. self.modelindex = modelindex_eyes;
  832. }
  833. else
  834. self.modelindex = modelindex_player; // don't use eyes
  835. // invincibility
  836. if (self.invincible_finished)
  837. {
  838. // sound and screen flash when items starts to run out
  839. if (self.invincible_finished < time + 3)
  840. {
  841. if (self.invincible_time == 1)
  842. {
  843. sprint (self, PRINT_HIGH, "Protection is almost burned out\n");
  844. stuffcmd (self, "bf\n");
  845. sound (self, CHAN_AUTO, "items/protect2.wav", 1, ATTN_NORM);
  846. self.invincible_time = time + 1;
  847. }
  848. if (self.invincible_time < time)
  849. {
  850. self.invincible_time = time + 1;
  851. stuffcmd (self, "bf\n");
  852. }
  853. }
  854. if (self.invincible_finished < time)
  855. { // just stopped
  856. self.items = self.items - IT_INVULNERABILITY;
  857. self.invincible_time = 0;
  858. self.invincible_finished = 0;
  859. }
  860. if (self.invincible_finished > time)
  861. {
  862. self.effects = self.effects | EF_DIMLIGHT;
  863. self.effects = self.effects | EF_RED;
  864. }
  865. else
  866. {
  867. self.effects = self.effects - (self.effects & EF_DIMLIGHT);
  868. self.effects = self.effects - (self.effects & EF_RED);
  869. }
  870. }
  871. // super damage
  872. if (self.super_damage_finished)
  873. {
  874. // sound and screen flash when items starts to run out
  875. if (self.super_damage_finished < time + 3)
  876. {
  877. if (self.super_time == 1)
  878. {
  879. if (deathmatch == 4)
  880. sprint (self, PRINT_HIGH, "OctaPower is wearing off\n");
  881. else
  882. sprint (self, PRINT_HIGH, "Quad Damage is wearing off\n");
  883. stuffcmd (self, "bf\n");
  884. sound (self, CHAN_AUTO, "items/damage2.wav", 1, ATTN_NORM);
  885. self.super_time = time + 1;
  886. }
  887. if (self.super_time < time)
  888. {
  889. self.super_time = time + 1;
  890. stuffcmd (self, "bf\n");
  891. }
  892. }
  893. if (self.super_damage_finished < time)
  894. { // just stopped
  895. self.items = self.items - IT_QUAD;
  896. if (deathmatch == 4)
  897. {
  898. self.ammo_cells = 255;
  899. self.armorvalue = 1;
  900. self.armortype = 0.8;
  901. self.health = 100;
  902. }
  903. self.super_damage_finished = 0;
  904. self.super_time = 0;
  905. }
  906. if (self.super_damage_finished > time)
  907. {
  908. self.effects = self.effects | EF_DIMLIGHT;
  909. self.effects = self.effects | EF_BLUE;
  910. }
  911. else
  912. {
  913. self.effects = self.effects - (self.effects & EF_DIMLIGHT);
  914. self.effects = self.effects - (self.effects & EF_BLUE);
  915. }
  916. }
  917. // suit
  918. if (self.radsuit_finished)
  919. {
  920. self.air_finished = time + 12; // don't drown
  921. // sound and screen flash when items starts to run out
  922. if (self.radsuit_finished < time + 3)
  923. {
  924. if (self.rad_time == 1)
  925. {
  926. sprint (self, PRINT_HIGH, "Air supply in Biosuit expiring\n");
  927. stuffcmd (self, "bf\n");
  928. sound (self, CHAN_AUTO, "items/suit2.wav", 1, ATTN_NORM);
  929. self.rad_time = time + 1;
  930. }
  931. if (self.rad_time < time)
  932. {
  933. self.rad_time = time + 1;
  934. stuffcmd (self, "bf\n");
  935. }
  936. }
  937. if (self.radsuit_finished < time)
  938. { // just stopped
  939. self.items = self.items - IT_SUIT;
  940. self.rad_time = 0;
  941. self.radsuit_finished = 0;
  942. }
  943. }
  944. };
  945. /*
  946. ================
  947. PlayerPostThink
  948. Called every frame after physics are run
  949. ================
  950. */
  951. void() PlayerPostThink =
  952. {
  953. local float mspeed, aspeed;
  954. local float r;
  955. //dprint ("post think\n");
  956. if (self.view_ofs == '0 0 0')
  957. return; // intermission or finale
  958. if (self.deadflag)
  959. return;
  960. // check to see if player landed and play landing sound
  961. if ((self.jump_flag < -300) && (self.flags & FL_ONGROUND) )
  962. {
  963. if (self.watertype == CONTENT_WATER)
  964. sound (self, CHAN_BODY, "player/h2ojump.wav", 1, ATTN_NORM);
  965. else if (self.jump_flag < -650)
  966. {
  967. self.deathtype = "falling";
  968. T_Damage (self, world, world, 5);
  969. sound (self, CHAN_VOICE, "player/land2.wav", 1, ATTN_NORM);
  970. }
  971. else
  972. sound (self, CHAN_VOICE, "player/land.wav", 1, ATTN_NORM);
  973. }
  974. self.jump_flag = self.velocity_z;
  975. CheckPowerups ();
  976. W_WeaponFrame ();
  977. };
  978. /*
  979. ===========
  980. ClientConnect
  981. called when a player connects to a server
  982. ============
  983. */
  984. void() ClientConnect =
  985. {
  986. bprint (PRINT_HIGH, self.netname);
  987. bprint (PRINT_HIGH, " entered the game\n");
  988. // a client connecting during an intermission can cause problems
  989. if (intermission_running)
  990. GotoNextMap ();
  991. };
  992. /*
  993. ===========
  994. ClientDisconnect
  995. called when a player disconnects from a server
  996. ============
  997. */
  998. void() ClientDisconnect =
  999. {
  1000. // let everyone else know
  1001. bprint (PRINT_HIGH, self.netname);
  1002. bprint (PRINT_HIGH, " left the game with ");
  1003. bprint (PRINT_HIGH, ftos(self.frags));
  1004. bprint (PRINT_HIGH, " frags\n");
  1005. sound (self, CHAN_BODY, "player/tornoff2.wav", 1, ATTN_NONE);
  1006. set_suicide_frame ();
  1007. };
  1008. /*
  1009. ===========
  1010. ClientObituary
  1011. called when a player dies
  1012. ============
  1013. */
  1014. void(entity targ, entity attacker) ClientObituary =
  1015. {
  1016. local float rnum;
  1017. local string deathstring, deathstring2;
  1018. local string s;
  1019. local string attackerteam, targteam;
  1020. rnum = random();
  1021. //ZOID 12-13-96: self.team doesn't work in QW. Use keys
  1022. attackerteam = infokey(attacker, "team");
  1023. targteam = infokey(targ, "team");
  1024. if (targ.classname == "player")
  1025. {
  1026. if (deathmatch > 3)
  1027. {
  1028. if (targ.deathtype == "selfwater")
  1029. {
  1030. bprint (PRINT_MEDIUM, targ.netname);
  1031. bprint (PRINT_MEDIUM," electrocutes himself.\n ");
  1032. targ.frags = targ.frags - 1;
  1033. return;
  1034. }
  1035. }
  1036. if (attacker.classname == "teledeath")
  1037. {
  1038. bprint (PRINT_MEDIUM,targ.netname);
  1039. bprint (PRINT_MEDIUM," was telefragged by ");
  1040. bprint (PRINT_MEDIUM,attacker.owner.netname);
  1041. bprint (PRINT_MEDIUM,"\n");
  1042. logfrag (attacker.owner, targ);
  1043. attacker.owner.frags = attacker.owner.frags + 1;
  1044. return;
  1045. }
  1046. if (attacker.classname == "teledeath2")
  1047. {
  1048. bprint (PRINT_MEDIUM,"Satan's power deflects ");
  1049. bprint (PRINT_MEDIUM,targ.netname);
  1050. bprint (PRINT_MEDIUM,"'s telefrag\n");
  1051. targ.frags = targ.frags - 1;
  1052. logfrag (targ, targ);
  1053. return;
  1054. }
  1055. // double 666 telefrag (can happen often in deathmatch 4)
  1056. if (attacker.classname == "teledeath3")
  1057. {
  1058. bprint (PRINT_MEDIUM,targ.netname);
  1059. bprint (PRINT_MEDIUM," was telefragged by ");
  1060. bprint (PRINT_MEDIUM,attacker.owner.netname);
  1061. bprint (PRINT_MEDIUM, "'s Satan's power\n");
  1062. targ.frags = targ.frags - 1;
  1063. logfrag (targ, targ);
  1064. return;
  1065. }
  1066. if (targ.deathtype == "squish")
  1067. {
  1068. if (teamplay && targteam == attackerteam && attackerteam != "" && targ != attacker)
  1069. {
  1070. logfrag (attacker, attacker);
  1071. attacker.frags = attacker.frags - 1;
  1072. bprint (PRINT_MEDIUM,attacker.netname);
  1073. bprint (PRINT_MEDIUM," squished a teammate\n");
  1074. return;
  1075. }
  1076. else if (attacker.classname == "player" && attacker != targ)
  1077. {
  1078. bprint (PRINT_MEDIUM, attacker.netname);
  1079. bprint (PRINT_MEDIUM," squishes ");
  1080. bprint (PRINT_MEDIUM,targ.netname);
  1081. bprint (PRINT_MEDIUM,"\n");
  1082. logfrag (attacker, targ);
  1083. attacker.frags = attacker.frags + 1;
  1084. return;
  1085. }
  1086. else
  1087. {
  1088. logfrag (targ, targ);
  1089. targ.frags = targ.frags - 1; // killed self
  1090. bprint (PRINT_MEDIUM,targ.netname);
  1091. bprint (PRINT_MEDIUM," was squished\n");
  1092. return;
  1093. }
  1094. }
  1095. if (attacker.classname == "player")
  1096. {
  1097. if (targ == attacker)
  1098. {
  1099. // killed self
  1100. logfrag (attacker, attacker);
  1101. attacker.frags = attacker.frags - 1;
  1102. bprint (PRINT_MEDIUM,targ.netname);
  1103. if (targ.deathtype == "grenade")
  1104. bprint (PRINT_MEDIUM," tries to put the pin back in\n");
  1105. else if (targ.deathtype == "rocket")
  1106. bprint (PRINT_MEDIUM," becomes bored with life\n");
  1107. else if (targ.weapon == 64 && targ.waterlevel > 1)
  1108. {
  1109. if (targ.watertype == CONTENT_SLIME)
  1110. bprint (PRINT_MEDIUM," discharges into the slime\n");
  1111. else if (targ.watertype == CONTENT_LAVA)
  1112. bprint (PRINT_MEDIUM," discharges into the lava\n");
  1113. else
  1114. bprint (PRINT_MEDIUM," discharges into the water.\n");
  1115. }
  1116. else
  1117. bprint (PRINT_MEDIUM," becomes bored with life\n");
  1118. return;
  1119. }
  1120. else if ( (teamplay == 2) && (targteam == attackerteam) &&
  1121. (attackerteam != "") )
  1122. {
  1123. if (rnum < 0.25)
  1124. deathstring = " mows down a teammate\n";
  1125. else if (rnum < 0.50)
  1126. deathstring = " checks his glasses\n";
  1127. else if (rnum < 0.75)
  1128. deathstring = " gets a frag for the other team\n";
  1129. else
  1130. deathstring = " loses another friend\n";
  1131. bprint (PRINT_MEDIUM, attacker.netname);
  1132. bprint (PRINT_MEDIUM, deathstring);
  1133. attacker.frags = attacker.frags - 1;
  1134. //ZOID 12-13-96: killing a teammate logs as suicide
  1135. logfrag (attacker, attacker);
  1136. return;
  1137. }
  1138. else
  1139. {
  1140. logfrag (attacker, targ);
  1141. attacker.frags = attacker.frags + 1;
  1142. rnum = attacker.weapon;
  1143. if (targ.deathtype == "nail")
  1144. {
  1145. deathstring = " was nailed by ";
  1146. deathstring2 = "\n";
  1147. }
  1148. else if (targ.deathtype == "supernail")
  1149. {
  1150. deathstring = " was punctured by ";
  1151. deathstring2 = "\n";
  1152. }
  1153. else if (targ.deathtype == "grenade")
  1154. {
  1155. deathstring = " eats ";
  1156. deathstring2 = "'s pineapple\n";
  1157. if (targ.health < -40)
  1158. {
  1159. deathstring = " was gibbed by ";
  1160. deathstring2 = "'s grenade\n";
  1161. }
  1162. }
  1163. else if (targ.deathtype == "rocket")
  1164. {
  1165. if (attacker.super_damage_finished > 0 && targ.health < -40)
  1166. {
  1167. rnum = random();
  1168. if (rnum < 0.3)
  1169. deathstring = " was brutalized by ";
  1170. else if (rnum < 0.6)
  1171. deathstring = " was smeared by ";
  1172. else
  1173. {
  1174. bprint (PRINT_MEDIUM, attacker.netname);
  1175. bprint (PRINT_MEDIUM, " rips ");
  1176. bprint (PRINT_MEDIUM, targ.netname);
  1177. bprint (PRINT_MEDIUM, " a new one\n");
  1178. return;
  1179. }
  1180. deathstring2 = "'s quad rocket\n";
  1181. }
  1182. else
  1183. {
  1184. deathstring = " rides ";
  1185. deathstring2 = "'s rocket\n";
  1186. if (targ.health < -40)
  1187. {
  1188. deathstring = " was gibbed by ";
  1189. deathstring2 = "'s rocket\n" ;
  1190. }
  1191. }
  1192. }
  1193. else if (rnum == IT_AXE)
  1194. {
  1195. deathstring = " was ax-murdered by ";
  1196. deathstring2 = "\n";
  1197. }
  1198. else if (rnum == IT_SHOTGUN)
  1199. {
  1200. deathstring = " chewed on ";
  1201. deathstring2 = "'s boomstick\n";
  1202. }
  1203. else if (rnum == IT_SUPER_SHOTGUN)
  1204. {
  1205. deathstring = " ate 2 loads of ";
  1206. deathstring2 = "'s buckshot\n";
  1207. }
  1208. else if (rnum == IT_LIGHTNING)
  1209. {
  1210. deathstring = " accepts ";
  1211. if (attacker.waterlevel > 1)
  1212. deathstring2 = "'s discharge\n";
  1213. else
  1214. deathstring2 = "'s shaft\n";
  1215. }
  1216. bprint (PRINT_MEDIUM,targ.netname);
  1217. bprint (PRINT_MEDIUM,deathstring);
  1218. bprint (PRINT_MEDIUM,attacker.netname);
  1219. bprint (PRINT_MEDIUM,deathstring2);
  1220. }
  1221. return;
  1222. }
  1223. else
  1224. {
  1225. logfrag (targ, targ);
  1226. targ.frags = targ.frags - 1; // killed self
  1227. rnum = targ.watertype;
  1228. bprint (PRINT_MEDIUM,targ.netname);
  1229. if (rnum == -3)
  1230. {
  1231. if (random() < 0.5)
  1232. bprint (PRINT_MEDIUM," sleeps with the fishes\n");
  1233. else
  1234. bprint (PRINT_MEDIUM," sucks it down\n");
  1235. return;
  1236. }
  1237. else if (rnum == -4)
  1238. {
  1239. if (random() < 0.5)
  1240. bprint (PRINT_MEDIUM," gulped a load of slime\n");
  1241. else
  1242. bprint (PRINT_MEDIUM," can't exist on slime alone\n");
  1243. return;
  1244. }
  1245. else if (rnum == -5)
  1246. {
  1247. if (targ.health < -15)
  1248. {
  1249. bprint (PRINT_MEDIUM," burst into flames\n");
  1250. return;
  1251. }
  1252. if (random() < 0.5)
  1253. bprint (PRINT_MEDIUM," turned into hot slag\n");
  1254. else
  1255. bprint (PRINT_MEDIUM," visits the Volcano God\n");
  1256. return;
  1257. }
  1258. if (attacker.classname == "explo_box")
  1259. {
  1260. bprint (PRINT_MEDIUM," blew up\n");
  1261. return;
  1262. }
  1263. if (targ.deathtype == "falling")
  1264. {
  1265. bprint (PRINT_MEDIUM," fell to his death\n");
  1266. return;
  1267. }
  1268. if (targ.deathtype == "nail" || targ.deathtype == "supernail")
  1269. {
  1270. bprint (PRINT_MEDIUM," was spiked\n");
  1271. return;
  1272. }
  1273. if (targ.deathtype == "laser")
  1274. {
  1275. bprint (PRINT_MEDIUM," was zapped\n");
  1276. return;
  1277. }
  1278. if (attacker.classname == "fireball")
  1279. {
  1280. bprint (PRINT_MEDIUM," ate a lavaball\n");
  1281. return;
  1282. }
  1283. if (attacker.classname == "trigger_changelevel")
  1284. {
  1285. bprint (PRINT_MEDIUM," tried to leave\n");
  1286. return;
  1287. }
  1288. bprint (PRINT_MEDIUM," died\n");
  1289. }
  1290. }
  1291. };