weapons.qc 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428
  1. /*
  2. weapons.qc
  3. weapon and weapon hit 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. void (entity targ, entity inflictor, entity attacker, float damage) T_Damage;
  20. void () player_run;
  21. void(entity bomb, entity attacker, float rad, entity ignore, string dtype) T_RadiusDamage;
  22. void(vector org, float damage) SpawnBlood;
  23. void() SuperDamageSound;
  24. // called by worldspawn
  25. void() W_Precache =
  26. {
  27. precache_sound ("weapons/r_exp3.wav"); // new rocket explosion
  28. precache_sound ("weapons/rocket1i.wav"); // spike gun
  29. precache_sound ("weapons/sgun1.wav");
  30. precache_sound ("weapons/guncock.wav"); // player shotgun
  31. precache_sound ("weapons/ric1.wav"); // ricochet (used in c code)
  32. precache_sound ("weapons/ric2.wav"); // ricochet (used in c code)
  33. precache_sound ("weapons/ric3.wav"); // ricochet (used in c code)
  34. precache_sound ("weapons/spike2.wav"); // super spikes
  35. precache_sound ("weapons/tink1.wav"); // spikes tink (used in c code)
  36. precache_sound ("weapons/grenade.wav"); // grenade launcher
  37. precache_sound ("weapons/bounce.wav"); // grenade bounce
  38. precache_sound ("weapons/shotgn2.wav"); // super shotgun
  39. };
  40. float() crandom =
  41. {
  42. return 2*(random() - 0.5);
  43. };
  44. /*
  45. ================
  46. W_FireAxe
  47. ================
  48. */
  49. void() W_FireAxe =
  50. {
  51. local vector source;
  52. local vector org;
  53. makevectors (self.v_angle);
  54. source = self.origin + '0 0 16';
  55. traceline (source, source + v_forward*64, FALSE, self);
  56. if (trace_fraction == 1.0)
  57. return;
  58. org = trace_endpos - v_forward*4;
  59. if (trace_ent.takedamage)
  60. {
  61. trace_ent.axhitme = 1;
  62. SpawnBlood (org, 20);
  63. if (deathmatch > 3)
  64. T_Damage (trace_ent, self, self, 75);
  65. else
  66. T_Damage (trace_ent, self, self, 20);
  67. }
  68. else
  69. { // hit wall
  70. sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
  71. WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
  72. WriteByte (MSG_MULTICAST, TE_GUNSHOT);
  73. WriteByte (MSG_MULTICAST, 3);
  74. WriteCoord (MSG_MULTICAST, org_x);
  75. WriteCoord (MSG_MULTICAST, org_y);
  76. WriteCoord (MSG_MULTICAST, org_z);
  77. multicast (org, MULTICAST_PVS);
  78. }
  79. };
  80. //============================================================================
  81. vector() wall_velocity =
  82. {
  83. local vector vel;
  84. vel = normalize (self.velocity);
  85. vel = normalize(vel + v_up*(random()- 0.5) + v_right*(random()- 0.5));
  86. vel = vel + 2*trace_plane_normal;
  87. vel = vel * 200;
  88. return vel;
  89. };
  90. /*
  91. ================
  92. SpawnMeatSpray
  93. ================
  94. */
  95. void(vector org, vector vel) SpawnMeatSpray =
  96. {
  97. local entity missile;
  98. local vector org;
  99. missile = spawn ();
  100. missile.owner = self;
  101. missile.movetype = MOVETYPE_BOUNCE;
  102. missile.solid = SOLID_NOT;
  103. makevectors (self.angles);
  104. missile.velocity = vel;
  105. missile.velocity_z = missile.velocity_z + 250 + 50*random();
  106. missile.avelocity = '3000 1000 2000';
  107. // set missile duration
  108. missile.nextthink = time + 1;
  109. missile.think = SUB_Remove;
  110. setmodel (missile, "progs/zom_gib.mdl");
  111. setsize (missile, '0 0 0', '0 0 0');
  112. setorigin (missile, org);
  113. };
  114. /*
  115. ================
  116. SpawnBlood
  117. ================
  118. */
  119. void(vector org, float damage) SpawnBlood =
  120. {
  121. WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
  122. WriteByte (MSG_MULTICAST, TE_BLOOD);
  123. WriteByte (MSG_MULTICAST, 1);
  124. WriteCoord (MSG_MULTICAST, org_x);
  125. WriteCoord (MSG_MULTICAST, org_y);
  126. WriteCoord (MSG_MULTICAST, org_z);
  127. multicast (org, MULTICAST_PVS);
  128. };
  129. /*
  130. ================
  131. spawn_touchblood
  132. ================
  133. */
  134. void(float damage) spawn_touchblood =
  135. {
  136. local vector vel;
  137. vel = wall_velocity () * 0.2;
  138. SpawnBlood (self.origin + vel*0.01, damage);
  139. };
  140. /*
  141. ==============================================================================
  142. MULTI-DAMAGE
  143. Collects multiple small damages into a single damage
  144. ==============================================================================
  145. */
  146. entity multi_ent;
  147. float multi_damage;
  148. vector blood_org;
  149. float blood_count;
  150. vector puff_org;
  151. float puff_count;
  152. void() ClearMultiDamage =
  153. {
  154. multi_ent = world;
  155. multi_damage = 0;
  156. blood_count = 0;
  157. puff_count = 0;
  158. };
  159. void() ApplyMultiDamage =
  160. {
  161. if (!multi_ent)
  162. return;
  163. T_Damage (multi_ent, self, self, multi_damage);
  164. };
  165. void(entity hit, float damage) AddMultiDamage =
  166. {
  167. if (!hit)
  168. return;
  169. if (hit != multi_ent)
  170. {
  171. ApplyMultiDamage ();
  172. multi_damage = damage;
  173. multi_ent = hit;
  174. }
  175. else
  176. multi_damage = multi_damage + damage;
  177. };
  178. void() Multi_Finish =
  179. {
  180. if (puff_count)
  181. {
  182. WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
  183. WriteByte (MSG_MULTICAST, TE_GUNSHOT);
  184. WriteByte (MSG_MULTICAST, puff_count);
  185. WriteCoord (MSG_MULTICAST, puff_org_x);
  186. WriteCoord (MSG_MULTICAST, puff_org_y);
  187. WriteCoord (MSG_MULTICAST, puff_org_z);
  188. multicast (puff_org, MULTICAST_PVS);
  189. }
  190. if (blood_count)
  191. {
  192. WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
  193. WriteByte (MSG_MULTICAST, TE_BLOOD);
  194. WriteByte (MSG_MULTICAST, blood_count);
  195. WriteCoord (MSG_MULTICAST, blood_org_x);
  196. WriteCoord (MSG_MULTICAST, blood_org_y);
  197. WriteCoord (MSG_MULTICAST, blood_org_z);
  198. multicast (puff_org, MULTICAST_PVS);
  199. }
  200. };
  201. /*
  202. ==============================================================================
  203. BULLETS
  204. ==============================================================================
  205. */
  206. /*
  207. ================
  208. TraceAttack
  209. ================
  210. */
  211. void(float damage, vector dir) TraceAttack =
  212. {
  213. local vector vel, org;
  214. vel = normalize(dir + v_up*crandom() + v_right*crandom());
  215. vel = vel + 2*trace_plane_normal;
  216. vel = vel * 200;
  217. org = trace_endpos - dir*4;
  218. if (trace_ent.takedamage)
  219. {
  220. blood_count = blood_count + 1;
  221. blood_org = org;
  222. AddMultiDamage (trace_ent, damage);
  223. }
  224. else
  225. {
  226. puff_count = puff_count + 1;
  227. }
  228. };
  229. /*
  230. ================
  231. FireBullets
  232. Used by shotgun, super shotgun, and enemy soldier firing
  233. Go to the trouble of combining multiple pellets into a single damage call.
  234. ================
  235. */
  236. void(float shotcount, vector dir, vector spread) FireBullets =
  237. {
  238. local vector direction;
  239. local vector src;
  240. makevectors(self.v_angle);
  241. src = self.origin + v_forward*10;
  242. src_z = self.absmin_z + self.size_z * 0.7;
  243. ClearMultiDamage ();
  244. traceline (src, src + dir*2048, FALSE, self);
  245. puff_org = trace_endpos - dir*4;
  246. while (shotcount > 0)
  247. {
  248. direction = dir + crandom()*spread_x*v_right + crandom()*spread_y*v_up;
  249. traceline (src, src + direction*2048, FALSE, self);
  250. if (trace_fraction != 1.0)
  251. TraceAttack (4, direction);
  252. shotcount = shotcount - 1;
  253. }
  254. ApplyMultiDamage ();
  255. Multi_Finish ();
  256. };
  257. /*
  258. ================
  259. W_FireShotgun
  260. ================
  261. */
  262. void() W_FireShotgun =
  263. {
  264. local vector dir;
  265. sound (self, CHAN_WEAPON, "weapons/guncock.wav", 1, ATTN_NORM);
  266. msg_entity = self;
  267. WriteByte (MSG_ONE, SVC_SMALLKICK);
  268. if (deathmatch != 4 )
  269. self.currentammo = self.ammo_shells = self.ammo_shells - 1;
  270. dir = aim (self, 100000);
  271. FireBullets (6, dir, '0.04 0.04 0');
  272. };
  273. /*
  274. ================
  275. W_FireSuperShotgun
  276. ================
  277. */
  278. void() W_FireSuperShotgun =
  279. {
  280. local vector dir;
  281. if (self.currentammo == 1)
  282. {
  283. W_FireShotgun ();
  284. return;
  285. }
  286. sound (self ,CHAN_WEAPON, "weapons/shotgn2.wav", 1, ATTN_NORM);
  287. msg_entity = self;
  288. WriteByte (MSG_ONE, SVC_BIGKICK);
  289. if (deathmatch != 4)
  290. self.currentammo = self.ammo_shells = self.ammo_shells - 2;
  291. dir = aim (self, 100000);
  292. FireBullets (14, dir, '0.14 0.08 0');
  293. };
  294. /*
  295. ==============================================================================
  296. ROCKETS
  297. ==============================================================================
  298. */
  299. void() T_MissileTouch =
  300. {
  301. local float damg;
  302. // if (deathmatch == 4)
  303. // {
  304. // if ( ((other.weapon == 32) || (other.weapon == 16)))
  305. // {
  306. // if (random() < 0.1)
  307. // {
  308. // if (other != world)
  309. // {
  310. // // bprint (PRINT_HIGH, "Got here\n");
  311. // other.deathtype = "blaze";
  312. // T_Damage (other, self, self.owner, 1000 );
  313. // T_RadiusDamage (self, self.owner, 1000, other);
  314. // }
  315. // }
  316. // }
  317. // }
  318. if (other == self.owner)
  319. return; // don't explode on owner
  320. if (self.voided) {
  321. return;
  322. }
  323. self.voided = 1;
  324. if (pointcontents(self.origin) == CONTENT_SKY)
  325. {
  326. remove(self);
  327. return;
  328. }
  329. damg = 100 + random()*20;
  330. if (other.health)
  331. {
  332. other.deathtype = "rocket";
  333. T_Damage (other, self, self.owner, damg );
  334. }
  335. // don't do radius damage to the other, because all the damage
  336. // was done in the impact
  337. T_RadiusDamage (self, self.owner, 120, other, "rocket");
  338. // sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM);
  339. self.origin = self.origin - 8 * normalize(self.velocity);
  340. WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
  341. WriteByte (MSG_MULTICAST, TE_EXPLOSION);
  342. WriteCoord (MSG_MULTICAST, self.origin_x);
  343. WriteCoord (MSG_MULTICAST, self.origin_y);
  344. WriteCoord (MSG_MULTICAST, self.origin_z);
  345. multicast (self.origin, MULTICAST_PHS);
  346. remove(self);
  347. };
  348. /*
  349. ================
  350. W_FireRocket
  351. ================
  352. */
  353. void() W_FireRocket =
  354. {
  355. if (deathmatch != 4)
  356. self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
  357. sound (self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM);
  358. msg_entity = self;
  359. WriteByte (MSG_ONE, SVC_SMALLKICK);
  360. newmis = spawn ();
  361. newmis.owner = self;
  362. newmis.movetype = MOVETYPE_FLYMISSILE;
  363. newmis.solid = SOLID_BBOX;
  364. // set newmis speed
  365. makevectors (self.v_angle);
  366. newmis.velocity = aim(self, 1000);
  367. newmis.velocity = newmis.velocity * 1000;
  368. newmis.angles = vectoangles(newmis.velocity);
  369. newmis.touch = T_MissileTouch;
  370. newmis.voided = 0;
  371. // set newmis duration
  372. newmis.nextthink = time + 5;
  373. newmis.think = SUB_Remove;
  374. newmis.classname = "rocket";
  375. setmodel (newmis, "progs/missile.mdl");
  376. setsize (newmis, '0 0 0', '0 0 0');
  377. setorigin (newmis, self.origin + v_forward*8 + '0 0 16');
  378. };
  379. /*
  380. ===============================================================================
  381. LIGHTNING
  382. ===============================================================================
  383. */
  384. void(entity from, float damage) LightningHit =
  385. {
  386. WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
  387. WriteByte (MSG_MULTICAST, TE_LIGHTNINGBLOOD);
  388. WriteCoord (MSG_MULTICAST, trace_endpos_x);
  389. WriteCoord (MSG_MULTICAST, trace_endpos_y);
  390. WriteCoord (MSG_MULTICAST, trace_endpos_z);
  391. multicast (trace_endpos, MULTICAST_PVS);
  392. T_Damage (trace_ent, from, from, damage);
  393. };
  394. /*
  395. =================
  396. LightningDamage
  397. =================
  398. */
  399. void(vector p1, vector p2, entity from, float damage) LightningDamage =
  400. {
  401. local entity e1, e2;
  402. local vector f;
  403. f = p2 - p1;
  404. normalize (f);
  405. f_x = 0 - f_y;
  406. f_y = f_x;
  407. f_z = 0;
  408. f = f*16;
  409. e1 = e2 = world;
  410. traceline (p1, p2, FALSE, self);
  411. if (trace_ent.takedamage)
  412. {
  413. LightningHit (from, damage);
  414. if (self.classname == "player")
  415. {
  416. if (other.classname == "player")
  417. trace_ent.velocity_z = trace_ent.velocity_z + 400;
  418. }
  419. }
  420. e1 = trace_ent;
  421. traceline (p1 + f, p2 + f, FALSE, self);
  422. if (trace_ent != e1 && trace_ent.takedamage)
  423. {
  424. LightningHit (from, damage);
  425. }
  426. e2 = trace_ent;
  427. traceline (p1 - f, p2 - f, FALSE, self);
  428. if (trace_ent != e1 && trace_ent != e2 && trace_ent.takedamage)
  429. {
  430. LightningHit (from, damage);
  431. }
  432. };
  433. void() W_FireLightning =
  434. {
  435. local vector org;
  436. local float cells;
  437. if (self.ammo_cells < 1)
  438. {
  439. self.weapon = W_BestWeapon ();
  440. W_SetCurrentAmmo ();
  441. return;
  442. }
  443. // explode if under water
  444. if (self.waterlevel > 1)
  445. {
  446. if (deathmatch > 3)
  447. {
  448. if (random() <= 0.5)
  449. {
  450. self.deathtype = "selfwater";
  451. T_Damage (self, self, self.owner, 4000 );
  452. }
  453. else
  454. {
  455. cells = self.ammo_cells;
  456. self.ammo_cells = 0;
  457. W_SetCurrentAmmo ();
  458. T_RadiusDamage (self, self, 35*cells, world, "");
  459. return;
  460. }
  461. }
  462. else
  463. {
  464. cells = self.ammo_cells;
  465. self.ammo_cells = 0;
  466. W_SetCurrentAmmo ();
  467. T_RadiusDamage (self, self, 35*cells, world,"");
  468. return;
  469. }
  470. }
  471. if (self.t_width < time)
  472. {
  473. sound (self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM);
  474. self.t_width = time + 0.6;
  475. }
  476. msg_entity = self;
  477. WriteByte (MSG_ONE, SVC_SMALLKICK);
  478. if (deathmatch != 4)
  479. self.currentammo = self.ammo_cells = self.ammo_cells - 1;
  480. org = self.origin + '0 0 16';
  481. traceline (org, org + v_forward*600, TRUE, self);
  482. WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
  483. WriteByte (MSG_MULTICAST, TE_LIGHTNING2);
  484. WriteEntity (MSG_MULTICAST, self);
  485. WriteCoord (MSG_MULTICAST, org_x);
  486. WriteCoord (MSG_MULTICAST, org_y);
  487. WriteCoord (MSG_MULTICAST, org_z);
  488. WriteCoord (MSG_MULTICAST, trace_endpos_x);
  489. WriteCoord (MSG_MULTICAST, trace_endpos_y);
  490. WriteCoord (MSG_MULTICAST, trace_endpos_z);
  491. multicast (org, MULTICAST_PHS);
  492. LightningDamage (self.origin, trace_endpos + v_forward*4, self, 30);
  493. };
  494. //=============================================================================
  495. void() GrenadeExplode =
  496. {
  497. if (self.voided) {
  498. return;
  499. }
  500. self.voided = 1;
  501. T_RadiusDamage (self, self.owner, 120, world, "grenade");
  502. WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
  503. WriteByte (MSG_MULTICAST, TE_EXPLOSION);
  504. WriteCoord (MSG_MULTICAST, self.origin_x);
  505. WriteCoord (MSG_MULTICAST, self.origin_y);
  506. WriteCoord (MSG_MULTICAST, self.origin_z);
  507. multicast (self.origin, MULTICAST_PHS);
  508. remove (self);
  509. };
  510. void() GrenadeTouch =
  511. {
  512. if (other == self.owner)
  513. return; // don't explode on owner
  514. if (other.takedamage == DAMAGE_AIM)
  515. {
  516. GrenadeExplode();
  517. return;
  518. }
  519. sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); // bounce sound
  520. if (self.velocity == '0 0 0')
  521. self.avelocity = '0 0 0';
  522. };
  523. /*
  524. ================
  525. W_FireGrenade
  526. ================
  527. */
  528. void() W_FireGrenade =
  529. {
  530. if (deathmatch != 4)
  531. self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
  532. sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
  533. msg_entity = self;
  534. WriteByte (MSG_ONE, SVC_SMALLKICK);
  535. newmis = spawn ();
  536. newmis.voided=0;
  537. newmis.owner = self;
  538. newmis.movetype = MOVETYPE_BOUNCE;
  539. newmis.solid = SOLID_BBOX;
  540. newmis.classname = "grenade";
  541. // set newmis speed
  542. makevectors (self.v_angle);
  543. if (self.v_angle_x)
  544. newmis.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
  545. else
  546. {
  547. newmis.velocity = aim(self, 10000);
  548. newmis.velocity = newmis.velocity * 600;
  549. newmis.velocity_z = 200;
  550. }
  551. newmis.avelocity = '300 300 300';
  552. newmis.angles = vectoangles(newmis.velocity);
  553. newmis.touch = GrenadeTouch;
  554. // set newmis duration
  555. if (deathmatch == 4)
  556. {
  557. newmis.nextthink = time + 2.5;
  558. self.attack_finished = time + 1.1;
  559. // self.health = self.health - 1;
  560. T_Damage (self, self, self.owner, 10 );
  561. }
  562. else
  563. newmis.nextthink = time + 2.5;
  564. newmis.think = GrenadeExplode;
  565. setmodel (newmis, "progs/grenade.mdl");
  566. setsize (newmis, '0 0 0', '0 0 0');
  567. setorigin (newmis, self.origin);
  568. };
  569. //=============================================================================
  570. void() spike_touch;
  571. void() superspike_touch;
  572. /*
  573. ===============
  574. launch_spike
  575. Used for both the player and the ogre
  576. ===============
  577. */
  578. void(vector org, vector dir) launch_spike =
  579. {
  580. newmis = spawn ();
  581. newmis.voided=0;
  582. newmis.owner = self;
  583. newmis.movetype = MOVETYPE_FLYMISSILE;
  584. newmis.solid = SOLID_BBOX;
  585. newmis.angles = vectoangles(dir);
  586. newmis.touch = spike_touch;
  587. newmis.classname = "spike";
  588. newmis.think = SUB_Remove;
  589. newmis.nextthink = time + 6;
  590. setmodel (newmis, "progs/spike.mdl");
  591. setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
  592. setorigin (newmis, org);
  593. newmis.velocity = dir * 1000;
  594. };
  595. void() W_FireSuperSpikes =
  596. {
  597. local vector dir;
  598. local entity old;
  599. sound (self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM);
  600. self.attack_finished = time + 0.2;
  601. if (deathmatch != 4)
  602. self.currentammo = self.ammo_nails = self.ammo_nails - 2;
  603. dir = aim (self, 1000);
  604. launch_spike (self.origin + '0 0 16', dir);
  605. newmis.touch = superspike_touch;
  606. setmodel (newmis, "progs/s_spike.mdl");
  607. setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
  608. msg_entity = self;
  609. WriteByte (MSG_ONE, SVC_SMALLKICK);
  610. };
  611. void(float ox) W_FireSpikes =
  612. {
  613. local vector dir;
  614. local entity old;
  615. makevectors (self.v_angle);
  616. if (self.ammo_nails >= 2 && self.weapon == IT_SUPER_NAILGUN)
  617. {
  618. W_FireSuperSpikes ();
  619. return;
  620. }
  621. if (self.ammo_nails < 1)
  622. {
  623. self.weapon = W_BestWeapon ();
  624. W_SetCurrentAmmo ();
  625. return;
  626. }
  627. sound (self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM);
  628. self.attack_finished = time + 0.2;
  629. if (deathmatch != 4)
  630. self.currentammo = self.ammo_nails = self.ammo_nails - 1;
  631. dir = aim (self, 1000);
  632. launch_spike (self.origin + '0 0 16' + v_right*ox, dir);
  633. msg_entity = self;
  634. WriteByte (MSG_ONE, SVC_SMALLKICK);
  635. };
  636. .float hit_z;
  637. void() spike_touch =
  638. {
  639. local float rand;
  640. if (other == self.owner)
  641. return;
  642. if (self.voided) {
  643. return;
  644. }
  645. self.voided = 1;
  646. if (other.solid == SOLID_TRIGGER)
  647. return; // trigger field, do nothing
  648. if (pointcontents(self.origin) == CONTENT_SKY)
  649. {
  650. remove(self);
  651. return;
  652. }
  653. // hit something that bleeds
  654. if (other.takedamage)
  655. {
  656. spawn_touchblood (9);
  657. other.deathtype = "nail";
  658. T_Damage (other, self, self.owner, 9);
  659. }
  660. else
  661. {
  662. WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
  663. if (self.classname == "wizspike")
  664. WriteByte (MSG_MULTICAST, TE_WIZSPIKE);
  665. else if (self.classname == "knightspike")
  666. WriteByte (MSG_MULTICAST, TE_KNIGHTSPIKE);
  667. else
  668. WriteByte (MSG_MULTICAST, TE_SPIKE);
  669. WriteCoord (MSG_MULTICAST, self.origin_x);
  670. WriteCoord (MSG_MULTICAST, self.origin_y);
  671. WriteCoord (MSG_MULTICAST, self.origin_z);
  672. multicast (self.origin, MULTICAST_PHS);
  673. }
  674. remove(self);
  675. };
  676. void() superspike_touch =
  677. {
  678. local float rand;
  679. if (other == self.owner)
  680. return;
  681. if (self.voided) {
  682. return;
  683. }
  684. self.voided = 1;
  685. if (other.solid == SOLID_TRIGGER)
  686. return; // trigger field, do nothing
  687. if (pointcontents(self.origin) == CONTENT_SKY)
  688. {
  689. remove(self);
  690. return;
  691. }
  692. // hit something that bleeds
  693. if (other.takedamage)
  694. {
  695. spawn_touchblood (18);
  696. other.deathtype = "supernail";
  697. T_Damage (other, self, self.owner, 18);
  698. }
  699. else
  700. {
  701. WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
  702. WriteByte (MSG_MULTICAST, TE_SUPERSPIKE);
  703. WriteCoord (MSG_MULTICAST, self.origin_x);
  704. WriteCoord (MSG_MULTICAST, self.origin_y);
  705. WriteCoord (MSG_MULTICAST, self.origin_z);
  706. multicast (self.origin, MULTICAST_PHS);
  707. }
  708. remove(self);
  709. };
  710. /*
  711. ===============================================================================
  712. PLAYER WEAPON USE
  713. ===============================================================================
  714. */
  715. void() W_SetCurrentAmmo =
  716. {
  717. player_run (); // get out of any weapon firing states
  718. self.items = self.items - ( self.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS) );
  719. if (self.weapon == IT_AXE)
  720. {
  721. self.currentammo = 0;
  722. self.weaponmodel = "progs/v_axe.mdl";
  723. self.weaponframe = 0;
  724. }
  725. else if (self.weapon == IT_SHOTGUN)
  726. {
  727. self.currentammo = self.ammo_shells;
  728. self.weaponmodel = "progs/v_shot.mdl";
  729. self.weaponframe = 0;
  730. self.items = self.items | IT_SHELLS;
  731. }
  732. else if (self.weapon == IT_SUPER_SHOTGUN)
  733. {
  734. self.currentammo = self.ammo_shells;
  735. self.weaponmodel = "progs/v_shot2.mdl";
  736. self.weaponframe = 0;
  737. self.items = self.items | IT_SHELLS;
  738. }
  739. else if (self.weapon == IT_NAILGUN)
  740. {
  741. self.currentammo = self.ammo_nails;
  742. self.weaponmodel = "progs/v_nail.mdl";
  743. self.weaponframe = 0;
  744. self.items = self.items | IT_NAILS;
  745. }
  746. else if (self.weapon == IT_SUPER_NAILGUN)
  747. {
  748. self.currentammo = self.ammo_nails;
  749. self.weaponmodel = "progs/v_nail2.mdl";
  750. self.weaponframe = 0;
  751. self.items = self.items | IT_NAILS;
  752. }
  753. else if (self.weapon == IT_GRENADE_LAUNCHER)
  754. {
  755. self.currentammo = self.ammo_rockets;
  756. self.weaponmodel = "progs/v_rock.mdl";
  757. self.weaponframe = 0;
  758. self.items = self.items | IT_ROCKETS;
  759. }
  760. else if (self.weapon == IT_ROCKET_LAUNCHER)
  761. {
  762. self.currentammo = self.ammo_rockets;
  763. self.weaponmodel = "progs/v_rock2.mdl";
  764. self.weaponframe = 0;
  765. self.items = self.items | IT_ROCKETS;
  766. }
  767. else if (self.weapon == IT_LIGHTNING)
  768. {
  769. self.currentammo = self.ammo_cells;
  770. self.weaponmodel = "progs/v_light.mdl";
  771. self.weaponframe = 0;
  772. self.items = self.items | IT_CELLS;
  773. }
  774. else
  775. {
  776. self.currentammo = 0;
  777. self.weaponmodel = "";
  778. self.weaponframe = 0;
  779. }
  780. };
  781. float() W_BestWeapon =
  782. {
  783. local float it;
  784. it = self.items;
  785. if (self.waterlevel <= 1 && self.ammo_cells >= 1 && (it & IT_LIGHTNING) )
  786. return IT_LIGHTNING;
  787. else if(self.ammo_nails >= 2 && (it & IT_SUPER_NAILGUN) )
  788. return IT_SUPER_NAILGUN;
  789. else if(self.ammo_shells >= 2 && (it & IT_SUPER_SHOTGUN) )
  790. return IT_SUPER_SHOTGUN;
  791. else if(self.ammo_nails >= 1 && (it & IT_NAILGUN) )
  792. return IT_NAILGUN;
  793. else if(self.ammo_shells >= 1 && (it & IT_SHOTGUN) )
  794. return IT_SHOTGUN;
  795. /*
  796. if(self.ammo_rockets >= 1 && (it & IT_ROCKET_LAUNCHER) )
  797. return IT_ROCKET_LAUNCHER;
  798. else if(self.ammo_rockets >= 1 && (it & IT_GRENADE_LAUNCHER) )
  799. return IT_GRENADE_LAUNCHER;
  800. */
  801. return IT_AXE;
  802. };
  803. float() W_CheckNoAmmo =
  804. {
  805. if (self.currentammo > 0)
  806. return TRUE;
  807. if (self.weapon == IT_AXE)
  808. return TRUE;
  809. self.weapon = W_BestWeapon ();
  810. W_SetCurrentAmmo ();
  811. // drop the weapon down
  812. return FALSE;
  813. };
  814. /*
  815. ============
  816. W_Attack
  817. An attack impulse can be triggered now
  818. ============
  819. */
  820. void() player_axe1;
  821. void() player_axeb1;
  822. void() player_axec1;
  823. void() player_axed1;
  824. void() player_shot1;
  825. void() player_nail1;
  826. void() player_light1;
  827. void() player_rocket1;
  828. void() W_Attack =
  829. {
  830. local float r;
  831. if (!W_CheckNoAmmo ())
  832. return;
  833. makevectors (self.v_angle); // calculate forward angle for velocity
  834. self.show_hostile = time + 1; // wake monsters up
  835. if (self.weapon == IT_AXE)
  836. {
  837. self.attack_finished = time + 0.5;
  838. sound (self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM);
  839. r = random();
  840. if (r < 0.25)
  841. player_axe1 ();
  842. else if (r<0.5)
  843. player_axeb1 ();
  844. else if (r<0.75)
  845. player_axec1 ();
  846. else
  847. player_axed1 ();
  848. }
  849. else if (self.weapon == IT_SHOTGUN)
  850. {
  851. player_shot1 ();
  852. self.attack_finished = time + 0.5;
  853. W_FireShotgun ();
  854. }
  855. else if (self.weapon == IT_SUPER_SHOTGUN)
  856. {
  857. player_shot1 ();
  858. self.attack_finished = time + 0.7;
  859. W_FireSuperShotgun ();
  860. }
  861. else if (self.weapon == IT_NAILGUN)
  862. {
  863. player_nail1 ();
  864. }
  865. else if (self.weapon == IT_SUPER_NAILGUN)
  866. {
  867. player_nail1 ();
  868. }
  869. else if (self.weapon == IT_GRENADE_LAUNCHER)
  870. {
  871. player_rocket1();
  872. self.attack_finished = time + 0.6;
  873. W_FireGrenade();
  874. }
  875. else if (self.weapon == IT_ROCKET_LAUNCHER)
  876. {
  877. player_rocket1();
  878. self.attack_finished = time + 0.8;
  879. W_FireRocket();
  880. }
  881. else if (self.weapon == IT_LIGHTNING)
  882. {
  883. self.attack_finished = time + 0.1;
  884. sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);
  885. player_light1();
  886. }
  887. };
  888. /*
  889. ============
  890. W_ChangeWeapon
  891. ============
  892. */
  893. void() W_ChangeWeapon =
  894. {
  895. local float it, am, fl;
  896. it = self.items;
  897. am = 0;
  898. if (self.impulse == 1)
  899. {
  900. fl = IT_AXE;
  901. }
  902. else if (self.impulse == 2)
  903. {
  904. fl = IT_SHOTGUN;
  905. if (self.ammo_shells < 1)
  906. am = 1;
  907. }
  908. else if (self.impulse == 3)
  909. {
  910. fl = IT_SUPER_SHOTGUN;
  911. if (self.ammo_shells < 2)
  912. am = 1;
  913. }
  914. else if (self.impulse == 4)
  915. {
  916. fl = IT_NAILGUN;
  917. if (self.ammo_nails < 1)
  918. am = 1;
  919. }
  920. else if (self.impulse == 5)
  921. {
  922. fl = IT_SUPER_NAILGUN;
  923. if (self.ammo_nails < 2)
  924. am = 1;
  925. }
  926. else if (self.impulse == 6)
  927. {
  928. fl = IT_GRENADE_LAUNCHER;
  929. if (self.ammo_rockets < 1)
  930. am = 1;
  931. }
  932. else if (self.impulse == 7)
  933. {
  934. fl = IT_ROCKET_LAUNCHER;
  935. if (self.ammo_rockets < 1)
  936. am = 1;
  937. }
  938. else if (self.impulse == 8)
  939. {
  940. fl = IT_LIGHTNING;
  941. if (self.ammo_cells < 1)
  942. am = 1;
  943. }
  944. self.impulse = 0;
  945. if (!(self.items & fl))
  946. { // don't have the weapon or the ammo
  947. sprint (self, PRINT_HIGH, "no weapon.\n");
  948. return;
  949. }
  950. if (am)
  951. { // don't have the ammo
  952. sprint (self, PRINT_HIGH, "not enough ammo.\n");
  953. return;
  954. }
  955. //
  956. // set weapon, set ammo
  957. //
  958. self.weapon = fl;
  959. W_SetCurrentAmmo ();
  960. };
  961. /*
  962. ============
  963. CheatCommand
  964. ============
  965. */
  966. void() CheatCommand =
  967. {
  968. // if (deathmatch || coop)
  969. return;
  970. self.ammo_rockets = 100;
  971. self.ammo_nails = 200;
  972. self.ammo_shells = 100;
  973. self.items = self.items |
  974. IT_AXE |
  975. IT_SHOTGUN |
  976. IT_SUPER_SHOTGUN |
  977. IT_NAILGUN |
  978. IT_SUPER_NAILGUN |
  979. IT_GRENADE_LAUNCHER |
  980. IT_ROCKET_LAUNCHER |
  981. IT_KEY1 | IT_KEY2;
  982. self.ammo_cells = 200;
  983. self.items = self.items | IT_LIGHTNING;
  984. self.weapon = IT_ROCKET_LAUNCHER;
  985. self.impulse = 0;
  986. W_SetCurrentAmmo ();
  987. };
  988. /*
  989. ============
  990. CycleWeaponCommand
  991. Go to the next weapon with ammo
  992. ============
  993. */
  994. void() CycleWeaponCommand =
  995. {
  996. local float it, am;
  997. it = self.items;
  998. self.impulse = 0;
  999. while (1)
  1000. {
  1001. am = 0;
  1002. if (self.weapon == IT_LIGHTNING)
  1003. {
  1004. self.weapon = IT_AXE;
  1005. }
  1006. else if (self.weapon == IT_AXE)
  1007. {
  1008. self.weapon = IT_SHOTGUN;
  1009. if (self.ammo_shells < 1)
  1010. am = 1;
  1011. }
  1012. else if (self.weapon == IT_SHOTGUN)
  1013. {
  1014. self.weapon = IT_SUPER_SHOTGUN;
  1015. if (self.ammo_shells < 2)
  1016. am = 1;
  1017. }
  1018. else if (self.weapon == IT_SUPER_SHOTGUN)
  1019. {
  1020. self.weapon = IT_NAILGUN;
  1021. if (self.ammo_nails < 1)
  1022. am = 1;
  1023. }
  1024. else if (self.weapon == IT_NAILGUN)
  1025. {
  1026. self.weapon = IT_SUPER_NAILGUN;
  1027. if (self.ammo_nails < 2)
  1028. am = 1;
  1029. }
  1030. else if (self.weapon == IT_SUPER_NAILGUN)
  1031. {
  1032. self.weapon = IT_GRENADE_LAUNCHER;
  1033. if (self.ammo_rockets < 1)
  1034. am = 1;
  1035. }
  1036. else if (self.weapon == IT_GRENADE_LAUNCHER)
  1037. {
  1038. self.weapon = IT_ROCKET_LAUNCHER;
  1039. if (self.ammo_rockets < 1)
  1040. am = 1;
  1041. }
  1042. else if (self.weapon == IT_ROCKET_LAUNCHER)
  1043. {
  1044. self.weapon = IT_LIGHTNING;
  1045. if (self.ammo_cells < 1)
  1046. am = 1;
  1047. }
  1048. if ( (self.items & self.weapon) && am == 0)
  1049. {
  1050. W_SetCurrentAmmo ();
  1051. return;
  1052. }
  1053. }
  1054. };
  1055. /*
  1056. ============
  1057. CycleWeaponReverseCommand
  1058. Go to the prev weapon with ammo
  1059. ============
  1060. */
  1061. void() CycleWeaponReverseCommand =
  1062. {
  1063. local float it, am;
  1064. it = self.items;
  1065. self.impulse = 0;
  1066. while (1)
  1067. {
  1068. am = 0;
  1069. if (self.weapon == IT_LIGHTNING)
  1070. {
  1071. self.weapon = IT_ROCKET_LAUNCHER;
  1072. if (self.ammo_rockets < 1)
  1073. am = 1;
  1074. }
  1075. else if (self.weapon == IT_ROCKET_LAUNCHER)
  1076. {
  1077. self.weapon = IT_GRENADE_LAUNCHER;
  1078. if (self.ammo_rockets < 1)
  1079. am = 1;
  1080. }
  1081. else if (self.weapon == IT_GRENADE_LAUNCHER)
  1082. {
  1083. self.weapon = IT_SUPER_NAILGUN;
  1084. if (self.ammo_nails < 2)
  1085. am = 1;
  1086. }
  1087. else if (self.weapon == IT_SUPER_NAILGUN)
  1088. {
  1089. self.weapon = IT_NAILGUN;
  1090. if (self.ammo_nails < 1)
  1091. am = 1;
  1092. }
  1093. else if (self.weapon == IT_NAILGUN)
  1094. {
  1095. self.weapon = IT_SUPER_SHOTGUN;
  1096. if (self.ammo_shells < 2)
  1097. am = 1;
  1098. }
  1099. else if (self.weapon == IT_SUPER_SHOTGUN)
  1100. {
  1101. self.weapon = IT_SHOTGUN;
  1102. if (self.ammo_shells < 1)
  1103. am = 1;
  1104. }
  1105. else if (self.weapon == IT_SHOTGUN)
  1106. {
  1107. self.weapon = IT_AXE;
  1108. }
  1109. else if (self.weapon == IT_AXE)
  1110. {
  1111. self.weapon = IT_LIGHTNING;
  1112. if (self.ammo_cells < 1)
  1113. am = 1;
  1114. }
  1115. if ( (it & self.weapon) && am == 0)
  1116. {
  1117. W_SetCurrentAmmo ();
  1118. return;
  1119. }
  1120. }
  1121. };
  1122. /*
  1123. ============
  1124. ServerflagsCommand
  1125. Just for development
  1126. ============
  1127. */
  1128. void() ServerflagsCommand =
  1129. {
  1130. serverflags = serverflags * 2 + 1;
  1131. };
  1132. /*
  1133. ============
  1134. ImpulseCommands
  1135. ============
  1136. */
  1137. void() ImpulseCommands =
  1138. {
  1139. if (self.impulse >= 1 && self.impulse <= 8)
  1140. W_ChangeWeapon ();
  1141. if (self.impulse == 9)
  1142. CheatCommand ();
  1143. if (self.impulse == 10)
  1144. CycleWeaponCommand ();
  1145. if (self.impulse == 11)
  1146. ServerflagsCommand ();
  1147. if (self.impulse == 12)
  1148. CycleWeaponReverseCommand ();
  1149. self.impulse = 0;
  1150. };
  1151. /*
  1152. ============
  1153. W_WeaponFrame
  1154. Called every frame so impulse events can be handled as well as possible
  1155. ============
  1156. */
  1157. void() W_WeaponFrame =
  1158. {
  1159. if (time < self.attack_finished)
  1160. return;
  1161. ImpulseCommands ();
  1162. // check for attack
  1163. if (self.button0)
  1164. {
  1165. SuperDamageSound ();
  1166. W_Attack ();
  1167. }
  1168. };
  1169. /*
  1170. ========
  1171. SuperDamageSound
  1172. Plays sound if needed
  1173. ========
  1174. */
  1175. void() SuperDamageSound =
  1176. {
  1177. if (self.super_damage_finished > time)
  1178. {
  1179. if (self.super_sound < time)
  1180. {
  1181. self.super_sound = time + 1;
  1182. sound (self, CHAN_BODY, "items/damage3.wav", 1, ATTN_NORM);
  1183. }
  1184. }
  1185. return;
  1186. };