mult_wpn.qc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  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. // multi_weapons.qc
  16. // pmack
  17. // sept 96
  18. //=============================================================================
  19. // Multi Grenade Code
  20. //=============================================================================
  21. void() MultiGrenadeTouch;
  22. //================================
  23. //================================
  24. void() MiniGrenadeExplode =
  25. {
  26. if ( self.owner.classname == "player")
  27. T_RadiusDamage (self, self.owner, 90, world);
  28. else
  29. T_RadiusDamage (self, self.owner, 60, world);
  30. WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  31. WriteByte (MSG_BROADCAST, TE_EXPLOSION2);
  32. WriteCoord (MSG_BROADCAST, self.origin_x);
  33. WriteCoord (MSG_BROADCAST, self.origin_y);
  34. WriteCoord (MSG_BROADCAST, self.origin_z);
  35. WriteByte (MSG_BROADCAST, 230);
  36. WriteByte (MSG_BROADCAST, 5);
  37. BecomeExplosion ();
  38. };
  39. //================================
  40. //================================
  41. void(float offsetAngle) MiniGrenadeLaunch =
  42. {
  43. local entity missile, mpuff;
  44. local float tempRand;
  45. missile = spawn ();
  46. missile.owner = self.owner;
  47. missile.movetype = MOVETYPE_BOUNCE;
  48. missile.solid = SOLID_BBOX;
  49. missile.classname = "MiniGrenade";
  50. // set missile speed
  51. missile.v_angle = self.v_angle;
  52. missile.v_angle_y = missile.v_angle_y + offsetAngle;
  53. makevectors (missile.v_angle);
  54. missile.velocity = v_forward*100 + v_up*400;
  55. tempRand = (crandom()*60) - 30;
  56. missile.velocity = missile.velocity + tempRand * v_forward;
  57. tempRand = (crandom()*40) - 20;
  58. missile.velocity = missile.velocity + tempRand * v_right;
  59. tempRand = (crandom()*60) - 30;
  60. missile.velocity = missile.velocity + tempRand * v_up;
  61. missile.avelocity = '300 300 300';
  62. missile.angles = vectoangles(missile.velocity);
  63. missile.touch = MultiGrenadeTouch;
  64. setmodel (missile, "progs/mervup.mdl");
  65. setsize (missile, '0 0 0', '0 0 0');
  66. setorigin (missile, self.origin);
  67. // set missile duration
  68. missile.nextthink = time + 1 + (crandom() * 0.5);
  69. missile.think = MiniGrenadeExplode;
  70. };
  71. //================================
  72. //================================
  73. void() MultiGrenadeExplode =
  74. {
  75. MiniGrenadeLaunch(0);
  76. MiniGrenadeLaunch(72);
  77. MiniGrenadeLaunch(144);
  78. MiniGrenadeLaunch(216);
  79. MiniGrenadeLaunch(288);
  80. remove (self);
  81. };
  82. //================================
  83. //================================
  84. void() MultiGrenadeTouch =
  85. {
  86. if (other == self.owner)
  87. return; // don't explode on owner
  88. if (other.takedamage == DAMAGE_AIM)
  89. {
  90. if (self.classname == "MiniGrenade")
  91. MiniGrenadeExplode();
  92. else
  93. {
  94. if (self.owner.classname == "player")
  95. GrenadeExplode();
  96. else
  97. MiniGrenadeExplode();
  98. }
  99. return;
  100. }
  101. // bounce sound
  102. sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);
  103. if (self.velocity == '0 0 0')
  104. self.avelocity = '0 0 0';
  105. };
  106. //================================
  107. //================================
  108. void() W_FireMultiGrenade =
  109. {
  110. local entity missile, mpuff;
  111. self.currentammo = self.ammo_multi_rockets = self.ammo_multi_rockets - 1;
  112. UpdateAmmoCounts (self);
  113. sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
  114. self.punchangle_x = -2;
  115. missile = spawn ();
  116. missile.owner = self;
  117. missile.movetype = MOVETYPE_BOUNCE;
  118. missile.solid = SOLID_BBOX;
  119. missile.classname = "MultiGrenade";
  120. // set missile speed
  121. makevectors (self.v_angle);
  122. if (self.v_angle_x)
  123. missile.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
  124. else
  125. {
  126. missile.velocity = aim(self, 10000);
  127. missile.velocity = missile.velocity * 600;
  128. missile.velocity_z = 200;
  129. }
  130. missile.avelocity = '300 300 300';
  131. missile.angles = vectoangles(missile.velocity);
  132. missile.touch = MultiGrenadeTouch;
  133. // set missile duration
  134. missile.nextthink = time + 1;
  135. missile.think = MultiGrenadeExplode;
  136. setmodel (missile, "progs/mervup.mdl");
  137. setsize (missile, '0 0 0', '0 0 0');
  138. setorigin (missile, self.origin);
  139. };
  140. //=============================================================================
  141. // Multi Rocket Code
  142. //=============================================================================
  143. //================================
  144. //================================
  145. void() MultiRocketExplode =
  146. {
  147. local float damg;
  148. // Stock Single Rocket Damage...
  149. // damg = 100 + random()*20;
  150. damg = 60 + random()*15;
  151. if (other.health)
  152. {
  153. if (other.classname == "monster_shambler")
  154. damg = damg * 0.5; // mostly immune
  155. if (other.classname == "monster_dragon")
  156. damg = damg * 0.5; // mostly immune
  157. T_Damage (other, self, self.owner, damg );
  158. }
  159. // don't do radius damage to the other, because all the damage
  160. // was done in the impact
  161. // Stock single rocket damage.
  162. // T_RadiusDamage (self, self.owner, 120, other);
  163. T_RadiusDamage (self, self.owner, 75, other);
  164. // sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM);
  165. self.origin = self.origin - 8*normalize(self.velocity);
  166. WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  167. WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  168. WriteCoord (MSG_BROADCAST, self.origin_x);
  169. WriteCoord (MSG_BROADCAST, self.origin_y);
  170. WriteCoord (MSG_BROADCAST, self.origin_z);
  171. BecomeExplosion ();
  172. };
  173. //================================
  174. //================================
  175. void() MultiRocketTouch =
  176. {
  177. if (other == self.owner)
  178. return; // don't explode on owner
  179. if (pointcontents(self.origin) == CONTENT_SKY)
  180. {
  181. remove(self);
  182. return;
  183. }
  184. MultiRocketExplode ();
  185. };
  186. //================================
  187. //================================
  188. void() HomingMissileThink =
  189. {
  190. local vector dir;
  191. if (self.enemy.health < 1)
  192. {
  193. remove(self);
  194. return;
  195. }
  196. dir = normalize(self.enemy.origin - self.origin);
  197. self.velocity = dir * 1000;
  198. self.nextthink = time + 0.1;
  199. self.think = HomingMissileThink;
  200. };
  201. //================================
  202. //================================
  203. void() HomingMissileAcquire =
  204. {
  205. local vector oldVelocity;
  206. local vector aimangle;
  207. if ( self.delay < time )
  208. {
  209. MultiRocketExplode ();
  210. return;
  211. }
  212. oldVelocity = self.velocity;
  213. makevectors (self.v_angle);
  214. self.velocity = aim (self, 1000);
  215. self.velocity = self.velocity * 1000;
  216. aimangle = self.origin + self.velocity;
  217. traceline ( self.origin, aimangle, FALSE, self );
  218. if (trace_fraction < 1)
  219. {
  220. if (trace_ent.flags & FL_MONSTER)
  221. {
  222. self.enemy = trace_ent;
  223. HomingMissileThink();
  224. return;
  225. }
  226. }
  227. self.velocity = oldVelocity;
  228. self.v_angle = vectoangles ( self.velocity );
  229. self.angles = self.v_angle;
  230. self.think = HomingMissileAcquire;
  231. self.nextthink = time + 0.2;
  232. };
  233. //================================
  234. //================================
  235. void(float offset, float frameNum) MultiRocketLaunch =
  236. {
  237. local entity missile, mpuff;
  238. local vector aimangle;
  239. missile = spawn ();
  240. missile.owner = self;
  241. missile.movetype = MOVETYPE_FLYMISSILE;
  242. missile.solid = SOLID_BBOX;
  243. missile.classname = "MultiRocket";
  244. missile.delay = time + 4;
  245. missile.frame = frameNum;
  246. missile.touch = MultiRocketTouch;
  247. if (deathmatch || coop)
  248. setmodel (missile, "progs/rockup_d.mdl");
  249. else
  250. setmodel (missile, "progs/rockup.mdl");
  251. setsize (missile, '0 0 0', '0 0 0');
  252. setorigin (missile, self.origin + v_forward*8 + '0 0 16');
  253. if ( coop || deathmatch)
  254. {
  255. aimangle = self.v_angle;
  256. aimangle_y = aimangle_y + (offset * 0.66);
  257. makevectors (aimangle);
  258. missile.velocity = aim(self, 1000);
  259. missile.velocity = missile.velocity * 1000;
  260. missile.angles = vectoangles(missile.velocity);
  261. missile.think = MultiRocketExplode;
  262. missile.nextthink = time + 4;
  263. }
  264. else
  265. {
  266. makevectors (self.v_angle);
  267. missile.velocity = v_forward * 1000 - v_right*offset*8;
  268. missile.angles = vectoangles(missile.velocity);
  269. missile.v_angle = self.v_angle;
  270. aimangle = missile.origin + missile.velocity;
  271. traceline ( missile.origin, aimangle, FALSE, self );
  272. if (trace_fraction < 1)
  273. {
  274. if (trace_ent.flags & FL_MONSTER)
  275. {
  276. missile.enemy = trace_ent;
  277. missile.think = HomingMissileThink;
  278. return;
  279. }
  280. }
  281. missile.think = HomingMissileAcquire;
  282. missile.nextthink = time + 0.1;
  283. }
  284. };
  285. //================================
  286. //================================
  287. void() W_FireMultiRocket =
  288. {
  289. self.currentammo = self.ammo_multi_rockets = self.ammo_multi_rockets - 1;
  290. UpdateAmmoCounts (self);
  291. sound (self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM);
  292. self.punchangle_x = -2;
  293. MultiRocketLaunch ( -10, 2 );
  294. MultiRocketLaunch ( -5, 3 );
  295. MultiRocketLaunch ( 5, 0 );
  296. MultiRocketLaunch ( 10, 1 );
  297. };
  298. //=============================================================================
  299. // Plasma Gun Code
  300. //=============================================================================
  301. void(vector p1, vector p2, entity from, float damage) PlasmaDamage =
  302. {
  303. local entity e1, e2;
  304. local vector f;
  305. f = p2 - p1;
  306. normalize (f);
  307. f_x = 0 - f_y;
  308. f_y = f_x;
  309. f_z = 0;
  310. f = f*16;
  311. e1 = e2 = world;
  312. traceline (p1, p2, FALSE, self);
  313. if (trace_ent.takedamage)
  314. {
  315. particle (trace_endpos, '0 0 100', 225, damage*4);
  316. T_Damage (trace_ent, from, from.owner, damage);
  317. if (self.classname == "player")
  318. {
  319. if (other.classname == "player")
  320. trace_ent.velocity_z = trace_ent.velocity_z + 400;
  321. }
  322. }
  323. e1 = trace_ent;
  324. traceline (p1 + f, p2 + f, FALSE, self);
  325. if (trace_ent != e1 && trace_ent.takedamage)
  326. {
  327. particle (trace_endpos, '0 0 100', 225, damage*4);
  328. T_Damage (trace_ent, from, from.owner, damage);
  329. }
  330. e2 = trace_ent;
  331. traceline (p1 - f, p2 - f, FALSE, self);
  332. if (trace_ent != e1 && trace_ent != e2 && trace_ent.takedamage)
  333. {
  334. particle (trace_endpos, '0 0 100', 225, damage*4);
  335. T_Damage (trace_ent, from, from.owner, damage);
  336. }
  337. };
  338. //================================
  339. //================================
  340. void(entity current, float doDamage) PlasmaDischarge =
  341. {
  342. WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  343. WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
  344. WriteEntity (MSG_BROADCAST, current);
  345. WriteCoord (MSG_BROADCAST, current.origin_x);
  346. WriteCoord (MSG_BROADCAST, current.origin_y);
  347. WriteCoord (MSG_BROADCAST, current.origin_z);
  348. WriteCoord (MSG_BROADCAST, self.origin_x);
  349. WriteCoord (MSG_BROADCAST, self.origin_y);
  350. WriteCoord (MSG_BROADCAST, self.origin_z);
  351. sound (self, CHAN_VOICE, "weapons/lhit.wav", 1, ATTN_NORM);
  352. if (doDamage == 1)
  353. PlasmaDamage (self.origin, current.origin, self, 50);
  354. };
  355. //================================
  356. //================================
  357. void() PlasmaGroundOut =
  358. {
  359. local entity current, start;
  360. local float monstersHit;
  361. monstersHit = 0;
  362. current = findradius ( self.origin, 320 );
  363. start = current;
  364. while ( monstersHit < 5 )
  365. {
  366. if ( current.flags & FL_MONSTER || current.classname == "player")
  367. {
  368. if ( current != self.owner )
  369. {
  370. traceline ( self.origin, current.origin, TRUE, world );
  371. if (trace_fraction == 1)
  372. {
  373. monstersHit = monstersHit + 1;
  374. PlasmaDischarge ( current, 1 );
  375. }
  376. }
  377. }
  378. current = current.chain;
  379. if (start == current || !current)
  380. return;
  381. }
  382. };
  383. //================================
  384. //================================
  385. void() PlasmaTouch =
  386. {
  387. local float damg;
  388. if (other == self.owner)
  389. return; // don't explode on owner
  390. if (pointcontents(self.origin) == CONTENT_SKY)
  391. {
  392. remove(self);
  393. return;
  394. }
  395. damg = 80 + random()*20;
  396. sound (self, CHAN_WEAPON, "plasma/explode.wav", 1, ATTN_NORM);
  397. if (other.health)
  398. {
  399. if (other.classname == "monster_shambler")
  400. damg = damg * 0.5; // mostly immune
  401. T_Damage (other, self, self.owner, damg );
  402. }
  403. // don't do radius damage to the other, because all the damage
  404. // was done in the impact
  405. T_RadiusDamage (self, self.owner, 70, other);
  406. WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  407. WriteByte (MSG_BROADCAST, TE_EXPLOSION2);
  408. WriteCoord (MSG_BROADCAST, self.origin_x);
  409. WriteCoord (MSG_BROADCAST, self.origin_y);
  410. WriteCoord (MSG_BROADCAST, self.origin_z);
  411. WriteByte (MSG_BROADCAST, 244);
  412. WriteByte (MSG_BROADCAST, 3);
  413. PlasmaGroundOut();
  414. remove (self);
  415. };
  416. //================================
  417. //================================
  418. void() PlasmaLaunch =
  419. {
  420. self.velocity = normalize(self.velocity);
  421. self.velocity = self.velocity * 1250;
  422. self.nextthink = time + 5;
  423. self.think = SUB_Remove;
  424. };
  425. void(vector org, vector dir) launch_plasma =
  426. {
  427. local entity missile, mpuff;
  428. missile = spawn ();
  429. missile.owner = self;
  430. missile.movetype = MOVETYPE_FLYMISSILE;
  431. missile.solid = SOLID_BBOX;
  432. missile.classname = "plasma";
  433. // set missile speed
  434. missile.velocity = dir * 0.01;
  435. missile.avelocity = '300 300 300';
  436. missile.angles = vectoangles(missile.velocity);
  437. missile.touch = PlasmaTouch;
  438. setmodel (missile, "progs/plasma.mdl");
  439. setsize (missile, '0 0 0', '0 0 0');
  440. setorigin (missile, org);
  441. sound (missile, CHAN_WEAPON, "plasma/flight.wav", 1, ATTN_NORM);
  442. if (!deathmatch && !coop)
  443. missile.effects = EF_BRIGHTLIGHT;
  444. // set missile duration
  445. missile.think = PlasmaLaunch;
  446. missile.nextthink = time + 0.1;
  447. };
  448. //================================
  449. //================================
  450. void() W_FirePlasma =
  451. {
  452. local float cells;
  453. local vector dir;
  454. if (self.ammo_plasma < 1)
  455. {
  456. self.weapon = W_BestWeapon ();
  457. W_SetCurrentAmmo ();
  458. return;
  459. }
  460. // explode if under water
  461. if (self.waterlevel > 1)
  462. {
  463. cells = self.ammo_plasma;
  464. self.ammo_plasma = 0;
  465. W_SetCurrentAmmo ();
  466. T_RadiusDamage (self, self, 35*cells, world);
  467. return;
  468. }
  469. self.currentammo = self.ammo_plasma = self.ammo_plasma - 1;
  470. UpdateAmmoCounts (self);
  471. sound (self, CHAN_WEAPON, "plasma/fire.wav", 0.5, ATTN_NORM);
  472. self.punchangle_x = -2;
  473. makevectors (self.v_angle);
  474. dir = aim ( self, 1000 );
  475. launch_plasma (self.origin + v_forward*24 + '0 0 16', dir);
  476. };