p_weapon.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470
  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. // g_weapon.c
  16. #include "g_local.h"
  17. #include "m_player.h"
  18. static qboolean is_quad;
  19. static byte is_silenced;
  20. void weapon_grenade_fire (edict_t *ent, qboolean held);
  21. void P_ProjectSource (gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
  22. {
  23. vec3_t _distance;
  24. VectorCopy (distance, _distance);
  25. if (client->pers.hand == LEFT_HANDED)
  26. _distance[1] *= -1;
  27. else if (client->pers.hand == CENTER_HANDED)
  28. _distance[1] = 0;
  29. G_ProjectSource (point, _distance, forward, right, result);
  30. }
  31. /*
  32. ===============
  33. PlayerNoise
  34. Each player can have two noise objects associated with it:
  35. a personal noise (jumping, pain, weapon firing), and a weapon
  36. target noise (bullet wall impacts)
  37. Monsters that don't directly see the player can move
  38. to a noise in hopes of seeing the player from there.
  39. ===============
  40. */
  41. void PlayerNoise(edict_t *who, vec3_t where, int type)
  42. {
  43. edict_t *noise;
  44. if (type == PNOISE_WEAPON)
  45. {
  46. if (who->client->silencer_shots)
  47. {
  48. who->client->silencer_shots--;
  49. return;
  50. }
  51. }
  52. if (deathmatch->value)
  53. return;
  54. if (who->flags & FL_NOTARGET)
  55. return;
  56. if (!who->mynoise)
  57. {
  58. noise = G_Spawn();
  59. noise->classname = "player_noise";
  60. VectorSet (noise->mins, -8, -8, -8);
  61. VectorSet (noise->maxs, 8, 8, 8);
  62. noise->owner = who;
  63. noise->svflags = SVF_NOCLIENT;
  64. who->mynoise = noise;
  65. noise = G_Spawn();
  66. noise->classname = "player_noise";
  67. VectorSet (noise->mins, -8, -8, -8);
  68. VectorSet (noise->maxs, 8, 8, 8);
  69. noise->owner = who;
  70. noise->svflags = SVF_NOCLIENT;
  71. who->mynoise2 = noise;
  72. }
  73. if (type == PNOISE_SELF || type == PNOISE_WEAPON)
  74. {
  75. noise = who->mynoise;
  76. level.sound_entity = noise;
  77. level.sound_entity_framenum = level.framenum;
  78. }
  79. else // type == PNOISE_IMPACT
  80. {
  81. noise = who->mynoise2;
  82. level.sound2_entity = noise;
  83. level.sound2_entity_framenum = level.framenum;
  84. }
  85. VectorCopy (where, noise->s.origin);
  86. VectorSubtract (where, noise->maxs, noise->absmin);
  87. VectorAdd (where, noise->maxs, noise->absmax);
  88. noise->teleport_time = level.time;
  89. gi.linkentity (noise);
  90. }
  91. qboolean Pickup_Weapon (edict_t *ent, edict_t *other)
  92. {
  93. int index;
  94. gitem_t *ammo;
  95. index = ITEM_INDEX(ent->item);
  96. if ( ( ((int)(dmflags->value) & DF_WEAPONS_STAY) || coop->value)
  97. && other->client->pers.inventory[index])
  98. {
  99. if (!(ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM) ) )
  100. return false; // leave the weapon for others to pickup
  101. }
  102. other->client->pers.inventory[index]++;
  103. if (!(ent->spawnflags & DROPPED_ITEM) )
  104. {
  105. // give them some ammo with it
  106. ammo = FindItem (ent->item->ammo);
  107. if ( (int)dmflags->value & DF_INFINITE_AMMO )
  108. Add_Ammo (other, ammo, 1000);
  109. else
  110. Add_Ammo (other, ammo, ammo->quantity);
  111. if (! (ent->spawnflags & DROPPED_PLAYER_ITEM) )
  112. {
  113. if (deathmatch->value)
  114. {
  115. if ((int)(dmflags->value) & DF_WEAPONS_STAY)
  116. ent->flags |= FL_RESPAWN;
  117. else
  118. SetRespawn (ent, 30);
  119. }
  120. if (coop->value)
  121. ent->flags |= FL_RESPAWN;
  122. }
  123. }
  124. if (other->client->pers.weapon != ent->item &&
  125. (other->client->pers.inventory[index] == 1) &&
  126. ( !deathmatch->value || other->client->pers.weapon == FindItem("blaster") ) )
  127. other->client->newweapon = ent->item;
  128. return true;
  129. }
  130. /*
  131. ===============
  132. ChangeWeapon
  133. The old weapon has been dropped all the way, so make the new one
  134. current
  135. ===============
  136. */
  137. void ChangeWeapon (edict_t *ent)
  138. {
  139. int i;
  140. if (ent->client->grenade_time)
  141. {
  142. ent->client->grenade_time = level.time;
  143. ent->client->weapon_sound = 0;
  144. weapon_grenade_fire (ent, false);
  145. ent->client->grenade_time = 0;
  146. }
  147. ent->client->pers.lastweapon = ent->client->pers.weapon;
  148. ent->client->pers.weapon = ent->client->newweapon;
  149. ent->client->newweapon = NULL;
  150. ent->client->machinegun_shots = 0;
  151. // set visible model
  152. if (ent->s.modelindex == 255) {
  153. if (ent->client->pers.weapon)
  154. i = ((ent->client->pers.weapon->weapmodel & 0xff) << 8);
  155. else
  156. i = 0;
  157. ent->s.skinnum = (ent - g_edicts - 1) | i;
  158. }
  159. if (ent->client->pers.weapon && ent->client->pers.weapon->ammo)
  160. ent->client->ammo_index = ITEM_INDEX(FindItem(ent->client->pers.weapon->ammo));
  161. else
  162. ent->client->ammo_index = 0;
  163. if (!ent->client->pers.weapon)
  164. { // dead
  165. ent->client->ps.gunindex = 0;
  166. return;
  167. }
  168. ent->client->weaponstate = WEAPON_ACTIVATING;
  169. ent->client->ps.gunframe = 0;
  170. ent->client->ps.gunindex = gi.modelindex(ent->client->pers.weapon->view_model);
  171. ent->client->anim_priority = ANIM_PAIN;
  172. if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  173. {
  174. ent->s.frame = FRAME_crpain1;
  175. ent->client->anim_end = FRAME_crpain4;
  176. }
  177. else
  178. {
  179. ent->s.frame = FRAME_pain301;
  180. ent->client->anim_end = FRAME_pain304;
  181. }
  182. }
  183. /*
  184. =================
  185. NoAmmoWeaponChange
  186. =================
  187. */
  188. void NoAmmoWeaponChange (edict_t *ent)
  189. {
  190. if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("slugs"))]
  191. && ent->client->pers.inventory[ITEM_INDEX(FindItem("railgun"))] )
  192. {
  193. ent->client->newweapon = FindItem ("railgun");
  194. return;
  195. }
  196. if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("cells"))]
  197. && ent->client->pers.inventory[ITEM_INDEX(FindItem("hyperblaster"))] )
  198. {
  199. ent->client->newweapon = FindItem ("hyperblaster");
  200. return;
  201. }
  202. if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
  203. && ent->client->pers.inventory[ITEM_INDEX(FindItem("chaingun"))] )
  204. {
  205. ent->client->newweapon = FindItem ("chaingun");
  206. return;
  207. }
  208. if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
  209. && ent->client->pers.inventory[ITEM_INDEX(FindItem("machinegun"))] )
  210. {
  211. ent->client->newweapon = FindItem ("machinegun");
  212. return;
  213. }
  214. if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))] > 1
  215. && ent->client->pers.inventory[ITEM_INDEX(FindItem("super shotgun"))] )
  216. {
  217. ent->client->newweapon = FindItem ("super shotgun");
  218. return;
  219. }
  220. if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))]
  221. && ent->client->pers.inventory[ITEM_INDEX(FindItem("shotgun"))] )
  222. {
  223. ent->client->newweapon = FindItem ("shotgun");
  224. return;
  225. }
  226. ent->client->newweapon = FindItem ("blaster");
  227. }
  228. /*
  229. =================
  230. Think_Weapon
  231. Called by ClientBeginServerFrame and ClientThink
  232. =================
  233. */
  234. void Think_Weapon (edict_t *ent)
  235. {
  236. // if just died, put the weapon away
  237. if (ent->health < 1)
  238. {
  239. ent->client->newweapon = NULL;
  240. ChangeWeapon (ent);
  241. }
  242. // call active weapon think routine
  243. if (ent->client->pers.weapon && ent->client->pers.weapon->weaponthink)
  244. {
  245. is_quad = (ent->client->quad_framenum > level.framenum);
  246. if (ent->client->silencer_shots)
  247. is_silenced = MZ_SILENCED;
  248. else
  249. is_silenced = 0;
  250. ent->client->pers.weapon->weaponthink (ent);
  251. }
  252. }
  253. /*
  254. ================
  255. Use_Weapon
  256. Make the weapon ready if there is ammo
  257. ================
  258. */
  259. void Use_Weapon (edict_t *ent, gitem_t *item)
  260. {
  261. int ammo_index;
  262. gitem_t *ammo_item;
  263. // see if we're already using it
  264. if (item == ent->client->pers.weapon)
  265. return;
  266. if (item->ammo && !g_select_empty->value && !(item->flags & IT_AMMO))
  267. {
  268. ammo_item = FindItem(item->ammo);
  269. ammo_index = ITEM_INDEX(ammo_item);
  270. if (!ent->client->pers.inventory[ammo_index])
  271. {
  272. gi.cprintf (ent, PRINT_HIGH, "No %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
  273. return;
  274. }
  275. if (ent->client->pers.inventory[ammo_index] < item->quantity)
  276. {
  277. gi.cprintf (ent, PRINT_HIGH, "Not enough %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
  278. return;
  279. }
  280. }
  281. // change to this weapon when down
  282. ent->client->newweapon = item;
  283. }
  284. /*
  285. ================
  286. Drop_Weapon
  287. ================
  288. */
  289. void Drop_Weapon (edict_t *ent, gitem_t *item)
  290. {
  291. int index;
  292. if ((int)(dmflags->value) & DF_WEAPONS_STAY)
  293. return;
  294. index = ITEM_INDEX(item);
  295. // see if we're already using it
  296. if ( ((item == ent->client->pers.weapon) || (item == ent->client->newweapon))&& (ent->client->pers.inventory[index] == 1) )
  297. {
  298. gi.cprintf (ent, PRINT_HIGH, "Can't drop current weapon\n");
  299. return;
  300. }
  301. Drop_Item (ent, item);
  302. ent->client->pers.inventory[index]--;
  303. }
  304. /*
  305. ================
  306. Weapon_Generic
  307. A generic function to handle the basics of weapon thinking
  308. ================
  309. */
  310. #define FRAME_FIRE_FIRST (FRAME_ACTIVATE_LAST + 1)
  311. #define FRAME_IDLE_FIRST (FRAME_FIRE_LAST + 1)
  312. #define FRAME_DEACTIVATE_FIRST (FRAME_IDLE_LAST + 1)
  313. static void Weapon_Generic2 (edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int FRAME_DEACTIVATE_LAST, int *pause_frames, int *fire_frames, void (*fire)(edict_t *ent))
  314. {
  315. int n;
  316. if(ent->deadflag || ent->s.modelindex != 255) // VWep animations screw up corpses
  317. {
  318. return;
  319. }
  320. if (ent->client->weaponstate == WEAPON_DROPPING)
  321. {
  322. if (ent->client->ps.gunframe == FRAME_DEACTIVATE_LAST)
  323. {
  324. ChangeWeapon (ent);
  325. return;
  326. }
  327. else if ((FRAME_DEACTIVATE_LAST - ent->client->ps.gunframe) == 4)
  328. {
  329. ent->client->anim_priority = ANIM_REVERSE;
  330. if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  331. {
  332. ent->s.frame = FRAME_crpain4+1;
  333. ent->client->anim_end = FRAME_crpain1;
  334. }
  335. else
  336. {
  337. ent->s.frame = FRAME_pain304+1;
  338. ent->client->anim_end = FRAME_pain301;
  339. }
  340. }
  341. ent->client->ps.gunframe++;
  342. return;
  343. }
  344. if (ent->client->weaponstate == WEAPON_ACTIVATING)
  345. {
  346. if (ent->client->ps.gunframe == FRAME_ACTIVATE_LAST || instantweap->value)
  347. {
  348. ent->client->weaponstate = WEAPON_READY;
  349. ent->client->ps.gunframe = FRAME_IDLE_FIRST;
  350. // we go recursive here to instant ready the weapon
  351. Weapon_Generic2 (ent, FRAME_ACTIVATE_LAST, FRAME_FIRE_LAST,
  352. FRAME_IDLE_LAST, FRAME_DEACTIVATE_LAST, pause_frames,
  353. fire_frames, fire);
  354. return;
  355. }
  356. ent->client->ps.gunframe++;
  357. return;
  358. }
  359. if ((ent->client->newweapon) && (ent->client->weaponstate != WEAPON_FIRING))
  360. {
  361. ent->client->weaponstate = WEAPON_DROPPING;
  362. if (instantweap->value) {
  363. ChangeWeapon(ent);
  364. return;
  365. } else
  366. ent->client->ps.gunframe = FRAME_DEACTIVATE_FIRST;
  367. if ((FRAME_DEACTIVATE_LAST - FRAME_DEACTIVATE_FIRST) < 4)
  368. {
  369. ent->client->anim_priority = ANIM_REVERSE;
  370. if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  371. {
  372. ent->s.frame = FRAME_crpain4+1;
  373. ent->client->anim_end = FRAME_crpain1;
  374. }
  375. else
  376. {
  377. ent->s.frame = FRAME_pain304+1;
  378. ent->client->anim_end = FRAME_pain301;
  379. }
  380. }
  381. return;
  382. }
  383. if (ent->client->weaponstate == WEAPON_READY)
  384. {
  385. if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
  386. {
  387. ent->client->latched_buttons &= ~BUTTON_ATTACK;
  388. if ((!ent->client->ammo_index) ||
  389. ( ent->client->pers.inventory[ent->client->ammo_index] >= ent->client->pers.weapon->quantity))
  390. {
  391. ent->client->ps.gunframe = FRAME_FIRE_FIRST;
  392. ent->client->weaponstate = WEAPON_FIRING;
  393. // start the animation
  394. ent->client->anim_priority = ANIM_ATTACK;
  395. if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  396. {
  397. ent->s.frame = FRAME_crattak1-1;
  398. ent->client->anim_end = FRAME_crattak9;
  399. }
  400. else
  401. {
  402. ent->s.frame = FRAME_attack1-1;
  403. ent->client->anim_end = FRAME_attack8;
  404. }
  405. }
  406. else
  407. {
  408. if (level.time >= ent->pain_debounce_time)
  409. {
  410. gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
  411. ent->pain_debounce_time = level.time + 1;
  412. }
  413. NoAmmoWeaponChange (ent);
  414. }
  415. }
  416. else
  417. {
  418. if (ent->client->ps.gunframe == FRAME_IDLE_LAST)
  419. {
  420. ent->client->ps.gunframe = FRAME_IDLE_FIRST;
  421. return;
  422. }
  423. if (pause_frames)
  424. {
  425. for (n = 0; pause_frames[n]; n++)
  426. {
  427. if (ent->client->ps.gunframe == pause_frames[n])
  428. {
  429. if (rand()&15)
  430. return;
  431. }
  432. }
  433. }
  434. ent->client->ps.gunframe++;
  435. return;
  436. }
  437. }
  438. if (ent->client->weaponstate == WEAPON_FIRING)
  439. {
  440. for (n = 0; fire_frames[n]; n++)
  441. {
  442. if (ent->client->ps.gunframe == fire_frames[n])
  443. {
  444. //ZOID
  445. if (!CTFApplyStrengthSound(ent))
  446. //ZOID
  447. if (ent->client->quad_framenum > level.framenum)
  448. gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage3.wav"), 1, ATTN_NORM, 0);
  449. //ZOID
  450. CTFApplyHasteSound(ent);
  451. //ZOID
  452. fire (ent);
  453. break;
  454. }
  455. }
  456. if (!fire_frames[n])
  457. ent->client->ps.gunframe++;
  458. if (ent->client->ps.gunframe == FRAME_IDLE_FIRST+1)
  459. ent->client->weaponstate = WEAPON_READY;
  460. }
  461. }
  462. //ZOID
  463. void Weapon_Generic (edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int FRAME_DEACTIVATE_LAST, int *pause_frames, int *fire_frames, void (*fire)(edict_t *ent))
  464. {
  465. int oldstate = ent->client->weaponstate;
  466. Weapon_Generic2 (ent, FRAME_ACTIVATE_LAST, FRAME_FIRE_LAST,
  467. FRAME_IDLE_LAST, FRAME_DEACTIVATE_LAST, pause_frames,
  468. fire_frames, fire);
  469. // run the weapon frame again if hasted
  470. if (stricmp(ent->client->pers.weapon->pickup_name, "Grapple") == 0 &&
  471. ent->client->weaponstate == WEAPON_FIRING)
  472. return;
  473. if ((CTFApplyHaste(ent) ||
  474. (Q_stricmp(ent->client->pers.weapon->pickup_name, "Grapple") == 0 &&
  475. ent->client->weaponstate != WEAPON_FIRING))
  476. && oldstate == ent->client->weaponstate) {
  477. Weapon_Generic2 (ent, FRAME_ACTIVATE_LAST, FRAME_FIRE_LAST,
  478. FRAME_IDLE_LAST, FRAME_DEACTIVATE_LAST, pause_frames,
  479. fire_frames, fire);
  480. }
  481. }
  482. //ZOID
  483. /*
  484. ======================================================================
  485. GRENADE
  486. ======================================================================
  487. */
  488. #define GRENADE_TIMER 3.0
  489. #define GRENADE_MINSPEED 400
  490. #define GRENADE_MAXSPEED 800
  491. void weapon_grenade_fire (edict_t *ent, qboolean held)
  492. {
  493. vec3_t offset;
  494. vec3_t forward, right;
  495. vec3_t start;
  496. int damage = 125;
  497. float timer;
  498. int speed;
  499. float radius;
  500. radius = damage+40;
  501. if (is_quad)
  502. damage *= 4;
  503. VectorSet(offset, 8, 8, ent->viewheight-8);
  504. AngleVectors (ent->client->v_angle, forward, right, NULL);
  505. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  506. timer = ent->client->grenade_time - level.time;
  507. speed = GRENADE_MINSPEED + (GRENADE_TIMER - timer) * ((GRENADE_MAXSPEED - GRENADE_MINSPEED) / GRENADE_TIMER);
  508. fire_grenade2 (ent, start, forward, damage, speed, timer, radius, held);
  509. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  510. ent->client->pers.inventory[ent->client->ammo_index]--;
  511. ent->client->grenade_time = level.time + 1.0;
  512. if(ent->deadflag || ent->s.modelindex != 255) // VWep animations screw up corpses
  513. {
  514. return;
  515. }
  516. if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  517. {
  518. ent->client->anim_priority = ANIM_ATTACK;
  519. ent->s.frame = FRAME_crattak1-1;
  520. ent->client->anim_end = FRAME_crattak3;
  521. }
  522. else
  523. {
  524. ent->client->anim_priority = ANIM_REVERSE;
  525. ent->s.frame = FRAME_wave08;
  526. ent->client->anim_end = FRAME_wave01;
  527. }
  528. }
  529. void Weapon_Grenade (edict_t *ent)
  530. {
  531. if ((ent->client->newweapon) && (ent->client->weaponstate == WEAPON_READY))
  532. {
  533. ChangeWeapon (ent);
  534. return;
  535. }
  536. if (ent->client->weaponstate == WEAPON_ACTIVATING)
  537. {
  538. ent->client->weaponstate = WEAPON_READY;
  539. ent->client->ps.gunframe = 16;
  540. return;
  541. }
  542. if (ent->client->weaponstate == WEAPON_READY)
  543. {
  544. if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
  545. {
  546. ent->client->latched_buttons &= ~BUTTON_ATTACK;
  547. if (ent->client->pers.inventory[ent->client->ammo_index])
  548. {
  549. ent->client->ps.gunframe = 1;
  550. ent->client->weaponstate = WEAPON_FIRING;
  551. ent->client->grenade_time = 0;
  552. }
  553. else
  554. {
  555. if (level.time >= ent->pain_debounce_time)
  556. {
  557. gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
  558. ent->pain_debounce_time = level.time + 1;
  559. }
  560. NoAmmoWeaponChange (ent);
  561. }
  562. return;
  563. }
  564. if ((ent->client->ps.gunframe == 29) || (ent->client->ps.gunframe == 34) || (ent->client->ps.gunframe == 39) || (ent->client->ps.gunframe == 48))
  565. {
  566. if (rand()&15)
  567. return;
  568. }
  569. if (++ent->client->ps.gunframe > 48)
  570. ent->client->ps.gunframe = 16;
  571. return;
  572. }
  573. if (ent->client->weaponstate == WEAPON_FIRING)
  574. {
  575. if (ent->client->ps.gunframe == 5)
  576. gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/hgrena1b.wav"), 1, ATTN_NORM, 0);
  577. if (ent->client->ps.gunframe == 11)
  578. {
  579. if (!ent->client->grenade_time)
  580. {
  581. ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2;
  582. ent->client->weapon_sound = gi.soundindex("weapons/hgrenc1b.wav");
  583. }
  584. // they waited too long, detonate it in their hand
  585. if (!ent->client->grenade_blew_up && level.time >= ent->client->grenade_time)
  586. {
  587. ent->client->weapon_sound = 0;
  588. weapon_grenade_fire (ent, true);
  589. ent->client->grenade_blew_up = true;
  590. }
  591. if (ent->client->buttons & BUTTON_ATTACK)
  592. return;
  593. if (ent->client->grenade_blew_up)
  594. {
  595. if (level.time >= ent->client->grenade_time)
  596. {
  597. ent->client->ps.gunframe = 15;
  598. ent->client->grenade_blew_up = false;
  599. }
  600. else
  601. {
  602. return;
  603. }
  604. }
  605. }
  606. if (ent->client->ps.gunframe == 12)
  607. {
  608. ent->client->weapon_sound = 0;
  609. weapon_grenade_fire (ent, false);
  610. }
  611. if ((ent->client->ps.gunframe == 15) && (level.time < ent->client->grenade_time))
  612. return;
  613. ent->client->ps.gunframe++;
  614. if (ent->client->ps.gunframe == 16)
  615. {
  616. ent->client->grenade_time = 0;
  617. ent->client->weaponstate = WEAPON_READY;
  618. }
  619. }
  620. }
  621. /*
  622. ======================================================================
  623. GRENADE LAUNCHER
  624. ======================================================================
  625. */
  626. void weapon_grenadelauncher_fire (edict_t *ent)
  627. {
  628. vec3_t offset;
  629. vec3_t forward, right;
  630. vec3_t start;
  631. int damage = 120;
  632. float radius;
  633. radius = damage+40;
  634. if (is_quad)
  635. damage *= 4;
  636. VectorSet(offset, 8, 8, ent->viewheight-8);
  637. AngleVectors (ent->client->v_angle, forward, right, NULL);
  638. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  639. VectorScale (forward, -2, ent->client->kick_origin);
  640. ent->client->kick_angles[0] = -1;
  641. fire_grenade (ent, start, forward, damage, 600, 2.5, radius);
  642. gi.WriteByte (svc_muzzleflash);
  643. gi.WriteShort (ent-g_edicts);
  644. gi.WriteByte (MZ_GRENADE | is_silenced);
  645. gi.multicast (ent->s.origin, MULTICAST_PVS);
  646. ent->client->ps.gunframe++;
  647. PlayerNoise(ent, start, PNOISE_WEAPON);
  648. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  649. ent->client->pers.inventory[ent->client->ammo_index]--;
  650. }
  651. void Weapon_GrenadeLauncher (edict_t *ent)
  652. {
  653. static int pause_frames[] = {34, 51, 59, 0};
  654. static int fire_frames[] = {6, 0};
  655. Weapon_Generic (ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire);
  656. }
  657. /*
  658. ======================================================================
  659. ROCKET
  660. ======================================================================
  661. */
  662. void Weapon_RocketLauncher_Fire (edict_t *ent)
  663. {
  664. vec3_t offset, start;
  665. vec3_t forward, right;
  666. int damage;
  667. float damage_radius;
  668. int radius_damage;
  669. damage = 100 + (int)(random() * 20.0);
  670. radius_damage = 120;
  671. damage_radius = 120;
  672. if (is_quad)
  673. {
  674. damage *= 4;
  675. radius_damage *= 4;
  676. }
  677. AngleVectors (ent->client->v_angle, forward, right, NULL);
  678. VectorScale (forward, -2, ent->client->kick_origin);
  679. ent->client->kick_angles[0] = -1;
  680. VectorSet(offset, 8, 8, ent->viewheight-8);
  681. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  682. fire_rocket (ent, start, forward, damage, 650, damage_radius, radius_damage);
  683. // send muzzle flash
  684. gi.WriteByte (svc_muzzleflash);
  685. gi.WriteShort (ent-g_edicts);
  686. gi.WriteByte (MZ_ROCKET | is_silenced);
  687. gi.multicast (ent->s.origin, MULTICAST_PVS);
  688. ent->client->ps.gunframe++;
  689. PlayerNoise(ent, start, PNOISE_WEAPON);
  690. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  691. ent->client->pers.inventory[ent->client->ammo_index]--;
  692. }
  693. void Weapon_RocketLauncher (edict_t *ent)
  694. {
  695. static int pause_frames[] = {25, 33, 42, 50, 0};
  696. static int fire_frames[] = {5, 0};
  697. Weapon_Generic (ent, 4, 12, 50, 54, pause_frames, fire_frames, Weapon_RocketLauncher_Fire);
  698. }
  699. /*
  700. ======================================================================
  701. BLASTER / HYPERBLASTER
  702. ======================================================================
  703. */
  704. void Blaster_Fire (edict_t *ent, vec3_t g_offset, int damage, qboolean hyper, int effect)
  705. {
  706. vec3_t forward, right;
  707. vec3_t start;
  708. vec3_t offset;
  709. if (is_quad)
  710. damage *= 4;
  711. AngleVectors (ent->client->v_angle, forward, right, NULL);
  712. VectorSet(offset, 24, 8, ent->viewheight-8);
  713. VectorAdd (offset, g_offset, offset);
  714. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  715. VectorScale (forward, -2, ent->client->kick_origin);
  716. ent->client->kick_angles[0] = -1;
  717. fire_blaster (ent, start, forward, damage, 1000, effect, hyper);
  718. // send muzzle flash
  719. gi.WriteByte (svc_muzzleflash);
  720. gi.WriteShort (ent-g_edicts);
  721. if (hyper)
  722. gi.WriteByte (MZ_HYPERBLASTER | is_silenced);
  723. else
  724. gi.WriteByte (MZ_BLASTER | is_silenced);
  725. gi.multicast (ent->s.origin, MULTICAST_PVS);
  726. PlayerNoise(ent, start, PNOISE_WEAPON);
  727. }
  728. void Weapon_Blaster_Fire (edict_t *ent)
  729. {
  730. int damage;
  731. if (deathmatch->value)
  732. damage = 15;
  733. else
  734. damage = 10;
  735. Blaster_Fire (ent, vec3_origin, damage, false, EF_BLASTER);
  736. ent->client->ps.gunframe++;
  737. }
  738. void Weapon_Blaster (edict_t *ent)
  739. {
  740. static int pause_frames[] = {19, 32, 0};
  741. static int fire_frames[] = {5, 0};
  742. Weapon_Generic (ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire);
  743. }
  744. void Weapon_HyperBlaster_Fire (edict_t *ent)
  745. {
  746. float rotation;
  747. vec3_t offset;
  748. int effect;
  749. int damage;
  750. ent->client->weapon_sound = gi.soundindex("weapons/hyprbl1a.wav");
  751. if (!(ent->client->buttons & BUTTON_ATTACK))
  752. {
  753. ent->client->ps.gunframe++;
  754. }
  755. else
  756. {
  757. if (! ent->client->pers.inventory[ent->client->ammo_index] )
  758. {
  759. if (level.time >= ent->pain_debounce_time)
  760. {
  761. gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
  762. ent->pain_debounce_time = level.time + 1;
  763. }
  764. NoAmmoWeaponChange (ent);
  765. }
  766. else
  767. {
  768. rotation = (ent->client->ps.gunframe - 5) * 2*M_PI/6;
  769. offset[0] = -4 * sin(rotation);
  770. offset[1] = 0;
  771. offset[2] = 4 * cos(rotation);
  772. if ((ent->client->ps.gunframe == 6) || (ent->client->ps.gunframe == 9))
  773. effect = EF_HYPERBLASTER;
  774. else
  775. effect = 0;
  776. if (deathmatch->value)
  777. damage = 15;
  778. else
  779. damage = 20;
  780. Blaster_Fire (ent, offset, damage, true, effect);
  781. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  782. ent->client->pers.inventory[ent->client->ammo_index]--;
  783. ent->client->anim_priority = ANIM_ATTACK;
  784. if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  785. {
  786. ent->s.frame = FRAME_crattak1 - 1;
  787. ent->client->anim_end = FRAME_crattak9;
  788. }
  789. else
  790. {
  791. ent->s.frame = FRAME_attack1 - 1;
  792. ent->client->anim_end = FRAME_attack8;
  793. }
  794. }
  795. ent->client->ps.gunframe++;
  796. if (ent->client->ps.gunframe == 12 && ent->client->pers.inventory[ent->client->ammo_index])
  797. ent->client->ps.gunframe = 6;
  798. }
  799. if (ent->client->ps.gunframe == 12)
  800. {
  801. gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/hyprbd1a.wav"), 1, ATTN_NORM, 0);
  802. ent->client->weapon_sound = 0;
  803. }
  804. }
  805. void Weapon_HyperBlaster (edict_t *ent)
  806. {
  807. static int pause_frames[] = {0};
  808. static int fire_frames[] = {6, 7, 8, 9, 10, 11, 0};
  809. Weapon_Generic (ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire);
  810. }
  811. /*
  812. ======================================================================
  813. MACHINEGUN / CHAINGUN
  814. ======================================================================
  815. */
  816. void Machinegun_Fire (edict_t *ent)
  817. {
  818. int i;
  819. vec3_t start;
  820. vec3_t forward, right;
  821. vec3_t angles;
  822. int damage = 8;
  823. int kick = 2;
  824. vec3_t offset;
  825. if (!(ent->client->buttons & BUTTON_ATTACK))
  826. {
  827. ent->client->machinegun_shots = 0;
  828. ent->client->ps.gunframe++;
  829. return;
  830. }
  831. if (ent->client->ps.gunframe == 5)
  832. ent->client->ps.gunframe = 4;
  833. else
  834. ent->client->ps.gunframe = 5;
  835. if (ent->client->pers.inventory[ent->client->ammo_index] < 1)
  836. {
  837. ent->client->ps.gunframe = 6;
  838. if (level.time >= ent->pain_debounce_time)
  839. {
  840. gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
  841. ent->pain_debounce_time = level.time + 1;
  842. }
  843. NoAmmoWeaponChange (ent);
  844. return;
  845. }
  846. if (is_quad)
  847. {
  848. damage *= 4;
  849. kick *= 4;
  850. }
  851. for (i=1 ; i<3 ; i++)
  852. {
  853. ent->client->kick_origin[i] = crandom() * 0.35;
  854. ent->client->kick_angles[i] = crandom() * 0.7;
  855. }
  856. ent->client->kick_origin[0] = crandom() * 0.35;
  857. ent->client->kick_angles[0] = ent->client->machinegun_shots * -1.5;
  858. // raise the gun as it is firing
  859. if (!deathmatch->value)
  860. {
  861. ent->client->machinegun_shots++;
  862. if (ent->client->machinegun_shots > 9)
  863. ent->client->machinegun_shots = 9;
  864. }
  865. // get start / end positions
  866. VectorAdd (ent->client->v_angle, ent->client->kick_angles, angles);
  867. AngleVectors (angles, forward, right, NULL);
  868. VectorSet(offset, 0, 8, ent->viewheight-8);
  869. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  870. fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_MACHINEGUN);
  871. gi.WriteByte (svc_muzzleflash);
  872. gi.WriteShort (ent-g_edicts);
  873. gi.WriteByte (MZ_MACHINEGUN | is_silenced);
  874. gi.multicast (ent->s.origin, MULTICAST_PVS);
  875. PlayerNoise(ent, start, PNOISE_WEAPON);
  876. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  877. ent->client->pers.inventory[ent->client->ammo_index]--;
  878. ent->client->anim_priority = ANIM_ATTACK;
  879. if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  880. {
  881. ent->s.frame = FRAME_crattak1 - (int) (random()+0.25);
  882. ent->client->anim_end = FRAME_crattak9;
  883. }
  884. else
  885. {
  886. ent->s.frame = FRAME_attack1 - (int) (random()+0.25);
  887. ent->client->anim_end = FRAME_attack8;
  888. }
  889. }
  890. void Weapon_Machinegun (edict_t *ent)
  891. {
  892. static int pause_frames[] = {23, 45, 0};
  893. static int fire_frames[] = {4, 5, 0};
  894. Weapon_Generic (ent, 3, 5, 45, 49, pause_frames, fire_frames, Machinegun_Fire);
  895. }
  896. void Chaingun_Fire (edict_t *ent)
  897. {
  898. int i;
  899. int shots;
  900. vec3_t start;
  901. vec3_t forward, right, up;
  902. float r, u;
  903. vec3_t offset;
  904. int damage;
  905. int kick = 2;
  906. if (deathmatch->value)
  907. damage = 6;
  908. else
  909. damage = 8;
  910. if (ent->client->ps.gunframe == 5)
  911. gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnu1a.wav"), 1, ATTN_IDLE, 0);
  912. if ((ent->client->ps.gunframe == 14) && !(ent->client->buttons & BUTTON_ATTACK))
  913. {
  914. ent->client->ps.gunframe = 32;
  915. ent->client->weapon_sound = 0;
  916. return;
  917. }
  918. else if ((ent->client->ps.gunframe == 21) && (ent->client->buttons & BUTTON_ATTACK)
  919. && ent->client->pers.inventory[ent->client->ammo_index])
  920. {
  921. ent->client->ps.gunframe = 15;
  922. }
  923. else
  924. {
  925. ent->client->ps.gunframe++;
  926. }
  927. if (ent->client->ps.gunframe == 22)
  928. {
  929. ent->client->weapon_sound = 0;
  930. gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnd1a.wav"), 1, ATTN_IDLE, 0);
  931. }
  932. else
  933. {
  934. ent->client->weapon_sound = gi.soundindex("weapons/chngnl1a.wav");
  935. }
  936. ent->client->anim_priority = ANIM_ATTACK;
  937. if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  938. {
  939. ent->s.frame = FRAME_crattak1 - (ent->client->ps.gunframe & 1);
  940. ent->client->anim_end = FRAME_crattak9;
  941. }
  942. else
  943. {
  944. ent->s.frame = FRAME_attack1 - (ent->client->ps.gunframe & 1);
  945. ent->client->anim_end = FRAME_attack8;
  946. }
  947. if (ent->client->ps.gunframe <= 9)
  948. shots = 1;
  949. else if (ent->client->ps.gunframe <= 14)
  950. {
  951. if (ent->client->buttons & BUTTON_ATTACK)
  952. shots = 2;
  953. else
  954. shots = 1;
  955. }
  956. else
  957. shots = 3;
  958. if (ent->client->pers.inventory[ent->client->ammo_index] < shots)
  959. shots = ent->client->pers.inventory[ent->client->ammo_index];
  960. if (!shots)
  961. {
  962. if (level.time >= ent->pain_debounce_time)
  963. {
  964. gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
  965. ent->pain_debounce_time = level.time + 1;
  966. }
  967. NoAmmoWeaponChange (ent);
  968. return;
  969. }
  970. if (is_quad)
  971. {
  972. damage *= 4;
  973. kick *= 4;
  974. }
  975. for (i=0 ; i<3 ; i++)
  976. {
  977. ent->client->kick_origin[i] = crandom() * 0.35;
  978. ent->client->kick_angles[i] = crandom() * 0.7;
  979. }
  980. for (i=0 ; i<shots ; i++)
  981. {
  982. // get start / end positions
  983. AngleVectors (ent->client->v_angle, forward, right, up);
  984. r = 7 + crandom()*4;
  985. u = crandom()*4;
  986. VectorSet(offset, 0, r, u + ent->viewheight-8);
  987. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  988. fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_CHAINGUN);
  989. }
  990. // send muzzle flash
  991. gi.WriteByte (svc_muzzleflash);
  992. gi.WriteShort (ent-g_edicts);
  993. gi.WriteByte ((MZ_CHAINGUN1 + shots - 1) | is_silenced);
  994. gi.multicast (ent->s.origin, MULTICAST_PVS);
  995. PlayerNoise(ent, start, PNOISE_WEAPON);
  996. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  997. ent->client->pers.inventory[ent->client->ammo_index] -= shots;
  998. }
  999. void Weapon_Chaingun (edict_t *ent)
  1000. {
  1001. static int pause_frames[] = {38, 43, 51, 61, 0};
  1002. static int fire_frames[] = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0};
  1003. Weapon_Generic (ent, 4, 31, 61, 64, pause_frames, fire_frames, Chaingun_Fire);
  1004. }
  1005. /*
  1006. ======================================================================
  1007. SHOTGUN / SUPERSHOTGUN
  1008. ======================================================================
  1009. */
  1010. void weapon_shotgun_fire (edict_t *ent)
  1011. {
  1012. vec3_t start;
  1013. vec3_t forward, right;
  1014. vec3_t offset;
  1015. int damage = 4;
  1016. int kick = 8;
  1017. if (ent->client->ps.gunframe == 9)
  1018. {
  1019. ent->client->ps.gunframe++;
  1020. return;
  1021. }
  1022. AngleVectors (ent->client->v_angle, forward, right, NULL);
  1023. VectorScale (forward, -2, ent->client->kick_origin);
  1024. ent->client->kick_angles[0] = -2;
  1025. VectorSet(offset, 0, 8, ent->viewheight-8);
  1026. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1027. if (is_quad)
  1028. {
  1029. damage *= 4;
  1030. kick *= 4;
  1031. }
  1032. if (deathmatch->value)
  1033. fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_DEATHMATCH_SHOTGUN_COUNT, MOD_SHOTGUN);
  1034. else
  1035. fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_SHOTGUN_COUNT, MOD_SHOTGUN);
  1036. // send muzzle flash
  1037. gi.WriteByte (svc_muzzleflash);
  1038. gi.WriteShort (ent-g_edicts);
  1039. gi.WriteByte (MZ_SHOTGUN | is_silenced);
  1040. gi.multicast (ent->s.origin, MULTICAST_PVS);
  1041. ent->client->ps.gunframe++;
  1042. PlayerNoise(ent, start, PNOISE_WEAPON);
  1043. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  1044. ent->client->pers.inventory[ent->client->ammo_index]--;
  1045. }
  1046. void Weapon_Shotgun (edict_t *ent)
  1047. {
  1048. static int pause_frames[] = {22, 28, 34, 0};
  1049. static int fire_frames[] = {8, 9, 0};
  1050. Weapon_Generic (ent, 7, 18, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire);
  1051. }
  1052. void weapon_supershotgun_fire (edict_t *ent)
  1053. {
  1054. vec3_t start;
  1055. vec3_t forward, right;
  1056. vec3_t offset;
  1057. vec3_t v;
  1058. int damage = 6;
  1059. int kick = 12;
  1060. AngleVectors (ent->client->v_angle, forward, right, NULL);
  1061. VectorScale (forward, -2, ent->client->kick_origin);
  1062. ent->client->kick_angles[0] = -2;
  1063. VectorSet(offset, 0, 8, ent->viewheight-8);
  1064. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1065. if (is_quad)
  1066. {
  1067. damage *= 4;
  1068. kick *= 4;
  1069. }
  1070. v[PITCH] = ent->client->v_angle[PITCH];
  1071. v[YAW] = ent->client->v_angle[YAW] - 5;
  1072. v[ROLL] = ent->client->v_angle[ROLL];
  1073. AngleVectors (v, forward, NULL, NULL);
  1074. fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
  1075. v[YAW] = ent->client->v_angle[YAW] + 5;
  1076. AngleVectors (v, forward, NULL, NULL);
  1077. fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
  1078. // send muzzle flash
  1079. gi.WriteByte (svc_muzzleflash);
  1080. gi.WriteShort (ent-g_edicts);
  1081. gi.WriteByte (MZ_SSHOTGUN | is_silenced);
  1082. gi.multicast (ent->s.origin, MULTICAST_PVS);
  1083. ent->client->ps.gunframe++;
  1084. PlayerNoise(ent, start, PNOISE_WEAPON);
  1085. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  1086. ent->client->pers.inventory[ent->client->ammo_index] -= 2;
  1087. }
  1088. void Weapon_SuperShotgun (edict_t *ent)
  1089. {
  1090. static int pause_frames[] = {29, 42, 57, 0};
  1091. static int fire_frames[] = {7, 0};
  1092. Weapon_Generic (ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire);
  1093. }
  1094. /*
  1095. ======================================================================
  1096. RAILGUN
  1097. ======================================================================
  1098. */
  1099. void weapon_railgun_fire (edict_t *ent)
  1100. {
  1101. vec3_t start;
  1102. vec3_t forward, right;
  1103. vec3_t offset;
  1104. int damage;
  1105. int kick;
  1106. if (deathmatch->value)
  1107. { // normal damage is too extreme in dm
  1108. damage = 100;
  1109. kick = 200;
  1110. }
  1111. else
  1112. {
  1113. damage = 150;
  1114. kick = 250;
  1115. }
  1116. if (is_quad)
  1117. {
  1118. damage *= 4;
  1119. kick *= 4;
  1120. }
  1121. AngleVectors (ent->client->v_angle, forward, right, NULL);
  1122. VectorScale (forward, -3, ent->client->kick_origin);
  1123. ent->client->kick_angles[0] = -3;
  1124. VectorSet(offset, 0, 7, ent->viewheight-8);
  1125. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1126. fire_rail (ent, start, forward, damage, kick);
  1127. // send muzzle flash
  1128. gi.WriteByte (svc_muzzleflash);
  1129. gi.WriteShort (ent-g_edicts);
  1130. gi.WriteByte (MZ_RAILGUN | is_silenced);
  1131. gi.multicast (ent->s.origin, MULTICAST_PVS);
  1132. ent->client->ps.gunframe++;
  1133. PlayerNoise(ent, start, PNOISE_WEAPON);
  1134. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  1135. ent->client->pers.inventory[ent->client->ammo_index]--;
  1136. }
  1137. void Weapon_Railgun (edict_t *ent)
  1138. {
  1139. static int pause_frames[] = {56, 0};
  1140. static int fire_frames[] = {4, 0};
  1141. Weapon_Generic (ent, 3, 18, 56, 61, pause_frames, fire_frames, weapon_railgun_fire);
  1142. }
  1143. /*
  1144. ======================================================================
  1145. BFG10K
  1146. ======================================================================
  1147. */
  1148. void weapon_bfg_fire (edict_t *ent)
  1149. {
  1150. vec3_t offset, start;
  1151. vec3_t forward, right;
  1152. int damage;
  1153. float damage_radius = 1000;
  1154. if (deathmatch->value)
  1155. damage = 200;
  1156. else
  1157. damage = 500;
  1158. if (ent->client->ps.gunframe == 9)
  1159. {
  1160. // send muzzle flash
  1161. gi.WriteByte (svc_muzzleflash);
  1162. gi.WriteShort (ent-g_edicts);
  1163. gi.WriteByte (MZ_BFG | is_silenced);
  1164. gi.multicast (ent->s.origin, MULTICAST_PVS);
  1165. ent->client->ps.gunframe++;
  1166. PlayerNoise(ent, ent->s.origin, PNOISE_WEAPON);
  1167. return;
  1168. }
  1169. // cells can go down during windup (from power armor hits), so
  1170. // check again and abort firing if we don't have enough now
  1171. if (ent->client->pers.inventory[ent->client->ammo_index] < 50)
  1172. {
  1173. ent->client->ps.gunframe++;
  1174. return;
  1175. }
  1176. if (is_quad)
  1177. damage *= 4;
  1178. AngleVectors (ent->client->v_angle, forward, right, NULL);
  1179. VectorScale (forward, -2, ent->client->kick_origin);
  1180. // make a big pitch kick with an inverse fall
  1181. ent->client->v_dmg_pitch = -40;
  1182. ent->client->v_dmg_roll = crandom()*8;
  1183. ent->client->v_dmg_time = level.time + DAMAGE_TIME;
  1184. VectorSet(offset, 8, 8, ent->viewheight-8);
  1185. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1186. fire_bfg (ent, start, forward, damage, 400, damage_radius);
  1187. ent->client->ps.gunframe++;
  1188. PlayerNoise(ent, start, PNOISE_WEAPON);
  1189. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  1190. ent->client->pers.inventory[ent->client->ammo_index] -= 50;
  1191. }
  1192. void Weapon_BFG (edict_t *ent)
  1193. {
  1194. static int pause_frames[] = {39, 45, 50, 55, 0};
  1195. static int fire_frames[] = {9, 17, 0};
  1196. Weapon_Generic (ent, 8, 32, 55, 58, pause_frames, fire_frames, weapon_bfg_fire);
  1197. }
  1198. //======================================================================