p_weapon.c 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868
  1. // Copyright (c) ZeniMax Media Inc.
  2. // Licensed under the GNU General Public License 2.0.
  3. // g_weapon.c
  4. #include "g_local.h"
  5. #include "m_player.h"
  6. static qboolean is_quad;
  7. // RAFAEL
  8. static qboolean is_quadfire;
  9. static byte is_silenced;
  10. void weapon_grenade_fire (edict_t *ent, qboolean held);
  11. // RAFAEL
  12. void weapon_trap_fire (edict_t *ent, qboolean held);
  13. static void P_ProjectSource (gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
  14. {
  15. vec3_t _distance;
  16. VectorCopy (distance, _distance);
  17. if (client->pers.hand == LEFT_HANDED)
  18. _distance[1] *= -1;
  19. else if (client->pers.hand == CENTER_HANDED)
  20. _distance[1] = 0;
  21. G_ProjectSource (point, _distance, forward, right, result);
  22. }
  23. /*
  24. ===============
  25. PlayerNoise
  26. Each player can have two noise objects associated with it:
  27. a personal noise (jumping, pain, weapon firing), and a weapon
  28. target noise (bullet wall impacts)
  29. Monsters that don't directly see the player can move
  30. to a noise in hopes of seeing the player from there.
  31. ===============
  32. */
  33. void PlayerNoise(edict_t *who, vec3_t where, int type)
  34. {
  35. edict_t *noise;
  36. if (type == PNOISE_WEAPON)
  37. {
  38. if (who->client->silencer_shots)
  39. {
  40. who->client->silencer_shots--;
  41. return;
  42. }
  43. }
  44. if (deathmatch->value)
  45. return;
  46. if (who->flags & FL_NOTARGET)
  47. return;
  48. if (!who->mynoise)
  49. {
  50. noise = G_Spawn();
  51. noise->classname = "player_noise";
  52. VectorSet (noise->mins, -8, -8, -8);
  53. VectorSet (noise->maxs, 8, 8, 8);
  54. noise->owner = who;
  55. noise->svflags = SVF_NOCLIENT;
  56. who->mynoise = noise;
  57. noise = G_Spawn();
  58. noise->classname = "player_noise";
  59. VectorSet (noise->mins, -8, -8, -8);
  60. VectorSet (noise->maxs, 8, 8, 8);
  61. noise->owner = who;
  62. noise->svflags = SVF_NOCLIENT;
  63. who->mynoise2 = noise;
  64. }
  65. if (type == PNOISE_SELF || type == PNOISE_WEAPON)
  66. {
  67. noise = who->mynoise;
  68. level.sound_entity = noise;
  69. level.sound_entity_framenum = level.framenum;
  70. }
  71. else // type == PNOISE_IMPACT
  72. {
  73. noise = who->mynoise2;
  74. level.sound2_entity = noise;
  75. level.sound2_entity_framenum = level.framenum;
  76. }
  77. VectorCopy (where, noise->s.origin);
  78. VectorSubtract (where, noise->maxs, noise->absmin);
  79. VectorAdd (where, noise->maxs, noise->absmax);
  80. noise->teleport_time = level.time;
  81. gi.linkentity (noise);
  82. }
  83. qboolean Pickup_Weapon (edict_t *ent, edict_t *other)
  84. {
  85. int index;
  86. gitem_t *ammo;
  87. index = ITEM_INDEX(ent->item);
  88. if ( ( ((int)(dmflags->value) & DF_WEAPONS_STAY) || coop->value)
  89. && other->client->pers.inventory[index])
  90. {
  91. if (!(ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM) ) )
  92. return false; // leave the weapon for others to pickup
  93. }
  94. other->client->pers.inventory[index]++;
  95. if (!(ent->spawnflags & DROPPED_ITEM) )
  96. {
  97. // give them some ammo with it
  98. ammo = FindItem (ent->item->ammo);
  99. // Don't get infinite ammo with trap
  100. if ( ((int)dmflags->value & DF_INFINITE_AMMO) && Q_stricmp(ent->item->pickup_name, "ammo_trap") )
  101. Add_Ammo (other, ammo, 1000);
  102. else
  103. Add_Ammo (other, ammo, ammo->quantity);
  104. if (! (ent->spawnflags & DROPPED_PLAYER_ITEM) )
  105. {
  106. if (deathmatch->value)
  107. {
  108. if ((int)(dmflags->value) & DF_WEAPONS_STAY)
  109. ent->flags |= FL_RESPAWN;
  110. else
  111. SetRespawn (ent, 30);
  112. }
  113. if (coop->value)
  114. ent->flags |= FL_RESPAWN;
  115. }
  116. }
  117. if (other->client->pers.weapon != ent->item &&
  118. (other->client->pers.inventory[index] == 1) &&
  119. ( !deathmatch->value || other->client->pers.weapon == FindItem("blaster") ) )
  120. other->client->newweapon = ent->item;
  121. return true;
  122. }
  123. /*
  124. ===============
  125. ChangeWeapon
  126. The old weapon has been dropped all the way, so make the new one
  127. current
  128. ===============
  129. */
  130. void ChangeWeapon (edict_t *ent)
  131. {
  132. int i;
  133. if (ent->client->grenade_time)
  134. {
  135. ent->client->grenade_time = level.time;
  136. ent->client->weapon_sound = 0;
  137. weapon_grenade_fire (ent, false);
  138. ent->client->grenade_time = 0;
  139. }
  140. ent->client->pers.lastweapon = ent->client->pers.weapon;
  141. ent->client->pers.weapon = ent->client->newweapon;
  142. ent->client->newweapon = NULL;
  143. ent->client->machinegun_shots = 0;
  144. // set visible model
  145. if (ent->s.modelindex == 255)
  146. {
  147. if (ent->client->pers.weapon)
  148. i = ((ent->client->pers.weapon->weapmodel & 0xff) << 8);
  149. else
  150. i = 0;
  151. ent->s.skinnum = (ent - g_edicts - 1) | i;
  152. }
  153. if (ent->client->pers.weapon && ent->client->pers.weapon->ammo)
  154. ent->client->ammo_index = ITEM_INDEX(FindItem(ent->client->pers.weapon->ammo));
  155. else
  156. ent->client->ammo_index = 0;
  157. if (!ent->client->pers.weapon)
  158. { // dead
  159. ent->client->ps.gunindex = 0;
  160. return;
  161. }
  162. ent->client->weaponstate = WEAPON_ACTIVATING;
  163. ent->client->ps.gunframe = 0;
  164. ent->client->ps.gunindex = gi.modelindex(ent->client->pers.weapon->view_model);
  165. ent->client->anim_priority = ANIM_PAIN;
  166. if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  167. {
  168. ent->s.frame = FRAME_crpain1;
  169. ent->client->anim_end = FRAME_crpain4;
  170. }
  171. else
  172. {
  173. ent->s.frame = FRAME_pain301;
  174. ent->client->anim_end = FRAME_pain304;
  175. }
  176. }
  177. /*
  178. =================
  179. NoAmmoWeaponChange
  180. =================
  181. */
  182. void NoAmmoWeaponChange (edict_t *ent)
  183. {
  184. if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("slugs"))]
  185. && ent->client->pers.inventory[ITEM_INDEX(FindItem("railgun"))] )
  186. {
  187. ent->client->newweapon = FindItem ("railgun");
  188. return;
  189. }
  190. // RAFAEL
  191. if ( ent->client->pers.inventory[ITEM_INDEX (FindItem ("mag slug"))]
  192. && ent->client->pers.inventory[ITEM_INDEX (FindItem ("phalanx"))])
  193. {
  194. ent->client->newweapon = FindItem ("phalanx");
  195. }
  196. // RAFAEL
  197. if ( ent->client->pers.inventory[ITEM_INDEX (FindItem ("cells"))]
  198. && ent->client->pers.inventory[ITEM_INDEX (FindItem ("ionripper"))])
  199. {
  200. ent->client->newweapon = FindItem ("ionrippergun");
  201. }
  202. if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("cells"))]
  203. && ent->client->pers.inventory[ITEM_INDEX(FindItem("hyperblaster"))] )
  204. {
  205. ent->client->newweapon = FindItem ("hyperblaster");
  206. return;
  207. }
  208. if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
  209. && ent->client->pers.inventory[ITEM_INDEX(FindItem("chaingun"))] )
  210. {
  211. ent->client->newweapon = FindItem ("chaingun");
  212. return;
  213. }
  214. if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
  215. && ent->client->pers.inventory[ITEM_INDEX(FindItem("machinegun"))] )
  216. {
  217. ent->client->newweapon = FindItem ("machinegun");
  218. return;
  219. }
  220. if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))] > 1
  221. && ent->client->pers.inventory[ITEM_INDEX(FindItem("super shotgun"))] )
  222. {
  223. ent->client->newweapon = FindItem ("super shotgun");
  224. return;
  225. }
  226. if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))]
  227. && ent->client->pers.inventory[ITEM_INDEX(FindItem("shotgun"))] )
  228. {
  229. ent->client->newweapon = FindItem ("shotgun");
  230. return;
  231. }
  232. ent->client->newweapon = FindItem ("blaster");
  233. }
  234. /*
  235. =================
  236. Think_Weapon
  237. Called by ClientBeginServerFrame and ClientThink
  238. =================
  239. */
  240. void Think_Weapon (edict_t *ent)
  241. {
  242. // if just died, put the weapon away
  243. if (ent->health < 1)
  244. {
  245. ent->client->newweapon = NULL;
  246. ChangeWeapon (ent);
  247. }
  248. // call active weapon think routine
  249. if (ent->client->pers.weapon && ent->client->pers.weapon->weaponthink)
  250. {
  251. is_quad = (ent->client->quad_framenum > level.framenum);
  252. // RAFAEL
  253. is_quadfire = (ent->client->quadfire_framenum > level.framenum);
  254. if (ent->client->silencer_shots)
  255. is_silenced = MZ_SILENCED;
  256. else
  257. is_silenced = 0;
  258. ent->client->pers.weapon->weaponthink (ent);
  259. }
  260. }
  261. /*
  262. ================
  263. Use_Weapon
  264. Make the weapon ready if there is ammo
  265. ================
  266. */
  267. void Use_Weapon (edict_t *ent, gitem_t *item)
  268. {
  269. int ammo_index;
  270. gitem_t *ammo_item;
  271. // see if we're already using it
  272. if (item == ent->client->pers.weapon)
  273. return;
  274. if (item->ammo && !g_select_empty->value && !(item->flags & IT_AMMO))
  275. {
  276. ammo_item = FindItem(item->ammo);
  277. ammo_index = ITEM_INDEX(ammo_item);
  278. if (!ent->client->pers.inventory[ammo_index])
  279. {
  280. gi.cprintf (ent, PRINT_HIGH, "No %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
  281. return;
  282. }
  283. if (ent->client->pers.inventory[ammo_index] < item->quantity)
  284. {
  285. gi.cprintf (ent, PRINT_HIGH, "Not enough %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
  286. return;
  287. }
  288. }
  289. // change to this weapon when down
  290. ent->client->newweapon = item;
  291. }
  292. // RAFAEL 14-APR-98
  293. void Use_Weapon2 (edict_t *ent, gitem_t *item)
  294. {
  295. int ammo_index;
  296. gitem_t *ammo_item;
  297. gitem_t *nextitem;
  298. int index;
  299. if (strcmp (item->pickup_name, "HyperBlaster") == 0)
  300. {
  301. if (item == ent->client->pers.weapon)
  302. {
  303. item = FindItem ("Ionripper");
  304. index = ITEM_INDEX (item);
  305. if (!ent->client->pers.inventory[index])
  306. {
  307. item = FindItem ("HyperBlaster");
  308. }
  309. }
  310. }
  311. else if (strcmp (item->pickup_name, "Railgun") == 0)
  312. {
  313. ammo_item = FindItem(item->ammo);
  314. ammo_index = ITEM_INDEX(ammo_item);
  315. if (!ent->client->pers.inventory[ammo_index])
  316. {
  317. nextitem = FindItem ("Phalanx");
  318. ammo_item = FindItem(nextitem->ammo);
  319. ammo_index = ITEM_INDEX(ammo_item);
  320. if (ent->client->pers.inventory[ammo_index])
  321. {
  322. item = FindItem ("Phalanx");
  323. index = ITEM_INDEX (item);
  324. if (!ent->client->pers.inventory[index])
  325. {
  326. item = FindItem ("Railgun");
  327. }
  328. }
  329. }
  330. else if (item == ent->client->pers.weapon)
  331. {
  332. item = FindItem ("Phalanx");
  333. index = ITEM_INDEX (item);
  334. if (!ent->client->pers.inventory[index])
  335. {
  336. item = FindItem ("Railgun");
  337. }
  338. }
  339. }
  340. // see if we're already using it
  341. if (item == ent->client->pers.weapon)
  342. return;
  343. if (item->ammo)
  344. {
  345. ammo_item = FindItem(item->ammo);
  346. ammo_index = ITEM_INDEX(ammo_item);
  347. if (!ent->client->pers.inventory[ammo_index] && !g_select_empty->value)
  348. {
  349. gi.cprintf (ent, PRINT_HIGH, "No %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
  350. return;
  351. }
  352. }
  353. // change to this weapon when down
  354. ent->client->newweapon = item;
  355. }
  356. // END 14-APR-98
  357. /*
  358. ================
  359. Drop_Weapon
  360. ================
  361. */
  362. void Drop_Weapon (edict_t *ent, gitem_t *item)
  363. {
  364. int index;
  365. if ((int)(dmflags->value) & DF_WEAPONS_STAY)
  366. return;
  367. index = ITEM_INDEX(item);
  368. // see if we're already using it
  369. if ( ((item == ent->client->pers.weapon) || (item == ent->client->newweapon))&& (ent->client->pers.inventory[index] == 1) )
  370. {
  371. gi.cprintf (ent, PRINT_HIGH, "Can't drop current weapon\n");
  372. return;
  373. }
  374. Drop_Item (ent, item);
  375. ent->client->pers.inventory[index]--;
  376. }
  377. /*
  378. ================
  379. Weapon_Generic
  380. A generic function to handle the basics of weapon thinking
  381. ================
  382. */
  383. #define FRAME_FIRE_FIRST (FRAME_ACTIVATE_LAST + 1)
  384. #define FRAME_IDLE_FIRST (FRAME_FIRE_LAST + 1)
  385. #define FRAME_DEACTIVATE_FIRST (FRAME_IDLE_LAST + 1)
  386. 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))
  387. {
  388. int n;
  389. if (ent->client->weaponstate == WEAPON_DROPPING)
  390. {
  391. if (ent->client->ps.gunframe == FRAME_DEACTIVATE_LAST)
  392. {
  393. ChangeWeapon (ent);
  394. return;
  395. }
  396. else if ((FRAME_DEACTIVATE_LAST - ent->client->ps.gunframe) == 4)
  397. {
  398. ent->client->anim_priority = ANIM_REVERSE;
  399. if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  400. {
  401. ent->s.frame = FRAME_crpain4+1;
  402. ent->client->anim_end = FRAME_crpain1;
  403. }
  404. else
  405. {
  406. ent->s.frame = FRAME_pain304+1;
  407. ent->client->anim_end = FRAME_pain301;
  408. }
  409. }
  410. ent->client->ps.gunframe++;
  411. return;
  412. }
  413. if (ent->client->weaponstate == WEAPON_ACTIVATING)
  414. {
  415. if (ent->client->ps.gunframe == FRAME_ACTIVATE_LAST)
  416. {
  417. ent->client->weaponstate = WEAPON_READY;
  418. ent->client->ps.gunframe = FRAME_IDLE_FIRST;
  419. return;
  420. }
  421. ent->client->ps.gunframe++;
  422. return;
  423. }
  424. if ((ent->client->newweapon) && (ent->client->weaponstate != WEAPON_FIRING))
  425. {
  426. ent->client->weaponstate = WEAPON_DROPPING;
  427. ent->client->ps.gunframe = FRAME_DEACTIVATE_FIRST;
  428. if ((FRAME_DEACTIVATE_LAST - FRAME_DEACTIVATE_FIRST) < 4)
  429. {
  430. ent->client->anim_priority = ANIM_REVERSE;
  431. if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  432. {
  433. ent->s.frame = FRAME_crpain4+1;
  434. ent->client->anim_end = FRAME_crpain1;
  435. }
  436. else
  437. {
  438. ent->s.frame = FRAME_pain304+1;
  439. ent->client->anim_end = FRAME_pain301;
  440. }
  441. }
  442. return;
  443. }
  444. if (ent->client->weaponstate == WEAPON_READY)
  445. {
  446. if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
  447. {
  448. ent->client->latched_buttons &= ~BUTTON_ATTACK;
  449. if ((!ent->client->ammo_index) ||
  450. ( ent->client->pers.inventory[ent->client->ammo_index] >= ent->client->pers.weapon->quantity))
  451. {
  452. ent->client->ps.gunframe = FRAME_FIRE_FIRST;
  453. ent->client->weaponstate = WEAPON_FIRING;
  454. // start the animation
  455. ent->client->anim_priority = ANIM_ATTACK;
  456. if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  457. {
  458. ent->s.frame = FRAME_crattak1-1;
  459. ent->client->anim_end = FRAME_crattak9;
  460. }
  461. else
  462. {
  463. ent->s.frame = FRAME_attack1-1;
  464. ent->client->anim_end = FRAME_attack8;
  465. }
  466. }
  467. else
  468. {
  469. if (level.time >= ent->pain_debounce_time)
  470. {
  471. gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
  472. ent->pain_debounce_time = level.time + 1;
  473. }
  474. NoAmmoWeaponChange (ent);
  475. }
  476. }
  477. else
  478. {
  479. if (ent->client->ps.gunframe == FRAME_IDLE_LAST)
  480. {
  481. ent->client->ps.gunframe = FRAME_IDLE_FIRST;
  482. return;
  483. }
  484. if (pause_frames)
  485. {
  486. for (n = 0; pause_frames[n]; n++)
  487. {
  488. if (ent->client->ps.gunframe == pause_frames[n])
  489. {
  490. if (rand()&15)
  491. return;
  492. }
  493. }
  494. }
  495. ent->client->ps.gunframe++;
  496. return;
  497. }
  498. }
  499. if (ent->client->weaponstate == WEAPON_FIRING)
  500. {
  501. for (n = 0; fire_frames[n]; n++)
  502. {
  503. if (ent->client->ps.gunframe == fire_frames[n])
  504. {
  505. if (ent->client->quad_framenum > level.framenum)
  506. gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage3.wav"), 1, ATTN_NORM, 0);
  507. fire (ent);
  508. break;
  509. }
  510. }
  511. if (!fire_frames[n])
  512. ent->client->ps.gunframe++;
  513. if (ent->client->ps.gunframe == FRAME_IDLE_FIRST+1)
  514. ent->client->weaponstate = WEAPON_READY;
  515. }
  516. }
  517. /*
  518. ======================================================================
  519. GRENADE
  520. ======================================================================
  521. */
  522. #define GRENADE_TIMER 3.0
  523. #define GRENADE_MINSPEED 400
  524. #define GRENADE_MAXSPEED 800
  525. void weapon_grenade_fire (edict_t *ent, qboolean held)
  526. {
  527. vec3_t offset;
  528. vec3_t forward, right;
  529. vec3_t start;
  530. int damage = 125;
  531. float timer;
  532. int speed;
  533. float radius;
  534. radius = damage+40;
  535. if (is_quad)
  536. damage *= 4;
  537. VectorSet(offset, 8, 8, ent->viewheight-8);
  538. AngleVectors (ent->client->v_angle, forward, right, NULL);
  539. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  540. timer = ent->client->grenade_time - level.time;
  541. speed = GRENADE_MINSPEED + (GRENADE_TIMER - timer) * ((GRENADE_MAXSPEED - GRENADE_MINSPEED) / GRENADE_TIMER);
  542. fire_grenade2 (ent, start, forward, damage, speed, timer, radius, held);
  543. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  544. ent->client->pers.inventory[ent->client->ammo_index]--;
  545. ent->client->grenade_time = level.time + 1.0;
  546. if (ent->health <= 0)
  547. return;
  548. if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  549. {
  550. ent->client->anim_priority = ANIM_ATTACK;
  551. ent->s.frame = FRAME_crattak1-1;
  552. ent->client->anim_end = FRAME_crattak3;
  553. }
  554. else
  555. {
  556. ent->client->anim_priority = ANIM_REVERSE;
  557. ent->s.frame = FRAME_wave08;
  558. ent->client->anim_end = FRAME_wave01;
  559. }
  560. }
  561. void Weapon_Grenade (edict_t *ent)
  562. {
  563. if ((ent->client->newweapon) && (ent->client->weaponstate == WEAPON_READY))
  564. {
  565. ChangeWeapon (ent);
  566. return;
  567. }
  568. if (ent->client->weaponstate == WEAPON_ACTIVATING)
  569. {
  570. ent->client->weaponstate = WEAPON_READY;
  571. ent->client->ps.gunframe = 16;
  572. return;
  573. }
  574. if (ent->client->weaponstate == WEAPON_READY)
  575. {
  576. if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
  577. {
  578. ent->client->latched_buttons &= ~BUTTON_ATTACK;
  579. if (ent->client->pers.inventory[ent->client->ammo_index])
  580. {
  581. ent->client->ps.gunframe = 1;
  582. ent->client->weaponstate = WEAPON_FIRING;
  583. ent->client->grenade_time = 0;
  584. }
  585. else
  586. {
  587. if (level.time >= ent->pain_debounce_time)
  588. {
  589. gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
  590. ent->pain_debounce_time = level.time + 1;
  591. }
  592. NoAmmoWeaponChange (ent);
  593. }
  594. return;
  595. }
  596. if ((ent->client->ps.gunframe == 29) || (ent->client->ps.gunframe == 34) || (ent->client->ps.gunframe == 39) || (ent->client->ps.gunframe == 48))
  597. {
  598. if (rand()&15)
  599. return;
  600. }
  601. if (++ent->client->ps.gunframe > 48)
  602. ent->client->ps.gunframe = 16;
  603. return;
  604. }
  605. if (ent->client->weaponstate == WEAPON_FIRING)
  606. {
  607. if (ent->client->ps.gunframe == 5)
  608. gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/hgrena1b.wav"), 1, ATTN_NORM, 0);
  609. if (ent->client->ps.gunframe == 11)
  610. {
  611. if (!ent->client->grenade_time)
  612. {
  613. ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2;
  614. ent->client->weapon_sound = gi.soundindex("weapons/hgrenc1b.wav");
  615. }
  616. // they waited too long, detonate it in their hand
  617. if (!ent->client->grenade_blew_up && level.time >= ent->client->grenade_time)
  618. {
  619. ent->client->weapon_sound = 0;
  620. weapon_grenade_fire (ent, true);
  621. ent->client->grenade_blew_up = true;
  622. }
  623. if (ent->client->buttons & BUTTON_ATTACK)
  624. return;
  625. if (ent->client->grenade_blew_up)
  626. {
  627. if (level.time >= ent->client->grenade_time)
  628. {
  629. ent->client->ps.gunframe = 15;
  630. ent->client->grenade_blew_up = false;
  631. }
  632. else
  633. {
  634. return;
  635. }
  636. }
  637. }
  638. if (ent->client->ps.gunframe == 12)
  639. {
  640. ent->client->weapon_sound = 0;
  641. weapon_grenade_fire (ent, false);
  642. }
  643. if ((ent->client->ps.gunframe == 15) && (level.time < ent->client->grenade_time))
  644. return;
  645. ent->client->ps.gunframe++;
  646. if (ent->client->ps.gunframe == 16)
  647. {
  648. ent->client->grenade_time = 0;
  649. ent->client->weaponstate = WEAPON_READY;
  650. }
  651. }
  652. }
  653. /*
  654. ======================================================================
  655. GRENADE LAUNCHER
  656. ======================================================================
  657. */
  658. void weapon_grenadelauncher_fire (edict_t *ent)
  659. {
  660. vec3_t offset;
  661. vec3_t forward, right;
  662. vec3_t start;
  663. int damage = 120;
  664. float radius;
  665. radius = damage+40;
  666. if (is_quad)
  667. damage *= 4;
  668. VectorSet(offset, 8, 8, ent->viewheight-8);
  669. AngleVectors (ent->client->v_angle, forward, right, NULL);
  670. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  671. VectorScale (forward, -2, ent->client->kick_origin);
  672. ent->client->kick_angles[0] = -1;
  673. fire_grenade (ent, start, forward, damage, 600, 2.5, radius);
  674. gi.WriteByte (svc_muzzleflash);
  675. gi.WriteShort (ent-g_edicts);
  676. gi.WriteByte (MZ_GRENADE | is_silenced);
  677. gi.multicast (ent->s.origin, MULTICAST_PVS);
  678. ent->client->ps.gunframe++;
  679. PlayerNoise(ent, start, PNOISE_WEAPON);
  680. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  681. ent->client->pers.inventory[ent->client->ammo_index]--;
  682. }
  683. void Weapon_GrenadeLauncher (edict_t *ent)
  684. {
  685. static int pause_frames[] = {34, 51, 59, 0};
  686. static int fire_frames[] = {6, 0};
  687. Weapon_Generic (ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire);
  688. // RAFAEL
  689. if (is_quadfire)
  690. Weapon_Generic (ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire);
  691. }
  692. /*
  693. ======================================================================
  694. ROCKET
  695. ======================================================================
  696. */
  697. void Weapon_RocketLauncher_Fire (edict_t *ent)
  698. {
  699. vec3_t offset, start;
  700. vec3_t forward, right;
  701. int damage;
  702. float damage_radius;
  703. int radius_damage;
  704. damage = 100 + (int)(random() * 20.0);
  705. radius_damage = 120;
  706. damage_radius = 120;
  707. if (is_quad)
  708. {
  709. damage *= 4;
  710. radius_damage *= 4;
  711. }
  712. AngleVectors (ent->client->v_angle, forward, right, NULL);
  713. VectorScale (forward, -2, ent->client->kick_origin);
  714. ent->client->kick_angles[0] = -1;
  715. VectorSet(offset, 8, 8, ent->viewheight-8);
  716. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  717. fire_rocket (ent, start, forward, damage, 650, damage_radius, radius_damage);
  718. // send muzzle flash
  719. gi.WriteByte (svc_muzzleflash);
  720. gi.WriteShort (ent-g_edicts);
  721. gi.WriteByte (MZ_ROCKET | is_silenced);
  722. gi.multicast (ent->s.origin, MULTICAST_PVS);
  723. ent->client->ps.gunframe++;
  724. PlayerNoise(ent, start, PNOISE_WEAPON);
  725. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  726. ent->client->pers.inventory[ent->client->ammo_index]--;
  727. }
  728. void Weapon_RocketLauncher (edict_t *ent)
  729. {
  730. static int pause_frames[] = {25, 33, 42, 50, 0};
  731. static int fire_frames[] = {5, 0};
  732. Weapon_Generic (ent, 4, 12, 50, 54, pause_frames, fire_frames, Weapon_RocketLauncher_Fire);
  733. // RAFAEL
  734. if (is_quadfire)
  735. Weapon_Generic (ent, 4, 12, 50, 54, pause_frames, fire_frames, Weapon_RocketLauncher_Fire);
  736. }
  737. /*
  738. ======================================================================
  739. BLASTER / HYPERBLASTER
  740. ======================================================================
  741. */
  742. void Blaster_Fire (edict_t *ent, vec3_t g_offset, int damage, qboolean hyper, int effect)
  743. {
  744. vec3_t forward, right;
  745. vec3_t start;
  746. vec3_t offset;
  747. if (is_quad)
  748. damage *= 4;
  749. AngleVectors (ent->client->v_angle, forward, right, NULL);
  750. VectorSet(offset, 24, 8, ent->viewheight-8);
  751. VectorAdd (offset, g_offset, offset);
  752. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  753. VectorScale (forward, -2, ent->client->kick_origin);
  754. ent->client->kick_angles[0] = -1;
  755. fire_blaster (ent, start, forward, damage, 1000, effect, hyper);
  756. // send muzzle flash
  757. gi.WriteByte (svc_muzzleflash);
  758. gi.WriteShort (ent-g_edicts);
  759. if (hyper)
  760. gi.WriteByte (MZ_HYPERBLASTER | is_silenced);
  761. else
  762. gi.WriteByte (MZ_BLASTER | is_silenced);
  763. gi.multicast (ent->s.origin, MULTICAST_PVS);
  764. PlayerNoise(ent, start, PNOISE_WEAPON);
  765. }
  766. void Weapon_Blaster_Fire (edict_t *ent)
  767. {
  768. int damage;
  769. if (deathmatch->value)
  770. damage = 15;
  771. else
  772. damage = 10;
  773. Blaster_Fire (ent, vec3_origin, damage, false, EF_BLASTER);
  774. ent->client->ps.gunframe++;
  775. }
  776. void Weapon_Blaster (edict_t *ent)
  777. {
  778. static int pause_frames[] = {19, 32, 0};
  779. static int fire_frames[] = {5, 0};
  780. Weapon_Generic (ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire);
  781. // RAFAEL
  782. if (is_quadfire)
  783. Weapon_Generic (ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire);
  784. }
  785. void Weapon_HyperBlaster_Fire (edict_t *ent)
  786. {
  787. float rotation;
  788. vec3_t offset;
  789. int effect;
  790. int damage;
  791. ent->client->weapon_sound = gi.soundindex("weapons/hyprbl1a.wav");
  792. if (!(ent->client->buttons & BUTTON_ATTACK))
  793. {
  794. ent->client->ps.gunframe++;
  795. }
  796. else
  797. {
  798. if (! ent->client->pers.inventory[ent->client->ammo_index] )
  799. {
  800. if (level.time >= ent->pain_debounce_time)
  801. {
  802. gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
  803. ent->pain_debounce_time = level.time + 1;
  804. }
  805. NoAmmoWeaponChange (ent);
  806. }
  807. else
  808. {
  809. rotation = (ent->client->ps.gunframe - 5) * 2*M_PI/6;
  810. offset[0] = -4 * sin(rotation);
  811. offset[1] = 0;
  812. offset[2] = 4 * cos(rotation);
  813. if ((ent->client->ps.gunframe == 6) || (ent->client->ps.gunframe == 9))
  814. effect = EF_HYPERBLASTER;
  815. else
  816. effect = 0;
  817. if (deathmatch->value)
  818. damage = 15;
  819. else
  820. damage = 20;
  821. Blaster_Fire (ent, offset, damage, true, effect);
  822. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  823. ent->client->pers.inventory[ent->client->ammo_index]--;
  824. ent->client->anim_priority = ANIM_ATTACK;
  825. if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  826. {
  827. ent->s.frame = FRAME_crattak1 - 1;
  828. ent->client->anim_end = FRAME_crattak9;
  829. }
  830. else
  831. {
  832. ent->s.frame = FRAME_attack1 - 1;
  833. ent->client->anim_end = FRAME_attack8;
  834. }
  835. }
  836. ent->client->ps.gunframe++;
  837. if (ent->client->ps.gunframe == 12 && ent->client->pers.inventory[ent->client->ammo_index])
  838. ent->client->ps.gunframe = 6;
  839. }
  840. if (ent->client->ps.gunframe == 12)
  841. {
  842. gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/hyprbd1a.wav"), 1, ATTN_NORM, 0);
  843. ent->client->weapon_sound = 0;
  844. }
  845. }
  846. void Weapon_HyperBlaster (edict_t *ent)
  847. {
  848. static int pause_frames[] = {0};
  849. static int fire_frames[] = {6, 7, 8, 9, 10, 11, 0};
  850. Weapon_Generic (ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire);
  851. // RAFAEL
  852. if (is_quadfire)
  853. Weapon_Generic (ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire);
  854. }
  855. /*
  856. ======================================================================
  857. MACHINEGUN / CHAINGUN
  858. ======================================================================
  859. */
  860. void Machinegun_Fire (edict_t *ent)
  861. {
  862. int i;
  863. vec3_t start;
  864. vec3_t forward, right;
  865. vec3_t angles;
  866. int damage = 8;
  867. int kick = 2;
  868. vec3_t offset;
  869. if (!(ent->client->buttons & BUTTON_ATTACK))
  870. {
  871. ent->client->machinegun_shots = 0;
  872. ent->client->ps.gunframe++;
  873. return;
  874. }
  875. if (ent->client->ps.gunframe == 5)
  876. ent->client->ps.gunframe = 4;
  877. else
  878. ent->client->ps.gunframe = 5;
  879. if (ent->client->pers.inventory[ent->client->ammo_index] < 1)
  880. {
  881. ent->client->ps.gunframe = 6;
  882. if (level.time >= ent->pain_debounce_time)
  883. {
  884. gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
  885. ent->pain_debounce_time = level.time + 1;
  886. }
  887. NoAmmoWeaponChange (ent);
  888. return;
  889. }
  890. if (is_quad)
  891. {
  892. damage *= 4;
  893. kick *= 4;
  894. }
  895. for (i=1 ; i<3 ; i++)
  896. {
  897. ent->client->kick_origin[i] = crandom() * 0.35;
  898. ent->client->kick_angles[i] = crandom() * 0.7;
  899. }
  900. ent->client->kick_origin[0] = crandom() * 0.35;
  901. ent->client->kick_angles[0] = ent->client->machinegun_shots * -1.5;
  902. // raise the gun as it is firing
  903. if (!deathmatch->value)
  904. {
  905. ent->client->machinegun_shots++;
  906. if (ent->client->machinegun_shots > 9)
  907. ent->client->machinegun_shots = 9;
  908. }
  909. // get start / end positions
  910. VectorAdd (ent->client->v_angle, ent->client->kick_angles, angles);
  911. AngleVectors (angles, forward, right, NULL);
  912. VectorSet(offset, 0, 8, ent->viewheight-8);
  913. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  914. fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_MACHINEGUN);
  915. gi.WriteByte (svc_muzzleflash);
  916. gi.WriteShort (ent-g_edicts);
  917. gi.WriteByte (MZ_MACHINEGUN | is_silenced);
  918. gi.multicast (ent->s.origin, MULTICAST_PVS);
  919. PlayerNoise(ent, start, PNOISE_WEAPON);
  920. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  921. ent->client->pers.inventory[ent->client->ammo_index]--;
  922. ent->client->anim_priority = ANIM_ATTACK;
  923. if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  924. {
  925. ent->s.frame = FRAME_crattak1 - (int) (random()+0.25);
  926. ent->client->anim_end = FRAME_crattak9;
  927. }
  928. else
  929. {
  930. ent->s.frame = FRAME_attack1 - (int) (random()+0.25);
  931. ent->client->anim_end = FRAME_attack8;
  932. }
  933. }
  934. void Weapon_Machinegun (edict_t *ent)
  935. {
  936. static int pause_frames[] = {23, 45, 0};
  937. static int fire_frames[] = {4, 5, 0};
  938. Weapon_Generic (ent, 3, 5, 45, 49, pause_frames, fire_frames, Machinegun_Fire);
  939. // RAFAEL
  940. if (is_quadfire)
  941. Weapon_Generic (ent, 3, 5, 45, 49, pause_frames, fire_frames, Machinegun_Fire);
  942. }
  943. void Chaingun_Fire (edict_t *ent)
  944. {
  945. int i;
  946. int shots;
  947. vec3_t start;
  948. vec3_t forward, right, up;
  949. float r, u;
  950. vec3_t offset;
  951. int damage;
  952. int kick = 2;
  953. if (deathmatch->value)
  954. damage = 6;
  955. else
  956. damage = 8;
  957. if (ent->client->ps.gunframe == 5)
  958. gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnu1a.wav"), 1, ATTN_IDLE, 0);
  959. if ((ent->client->ps.gunframe == 14) && !(ent->client->buttons & BUTTON_ATTACK))
  960. {
  961. ent->client->ps.gunframe = 32;
  962. ent->client->weapon_sound = 0;
  963. return;
  964. }
  965. else if ((ent->client->ps.gunframe == 21) && (ent->client->buttons & BUTTON_ATTACK)
  966. && ent->client->pers.inventory[ent->client->ammo_index])
  967. {
  968. ent->client->ps.gunframe = 15;
  969. }
  970. else
  971. {
  972. ent->client->ps.gunframe++;
  973. }
  974. if (ent->client->ps.gunframe == 22)
  975. {
  976. ent->client->weapon_sound = 0;
  977. gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnd1a.wav"), 1, ATTN_IDLE, 0);
  978. }
  979. else
  980. {
  981. ent->client->weapon_sound = gi.soundindex("weapons/chngnl1a.wav");
  982. }
  983. ent->client->anim_priority = ANIM_ATTACK;
  984. if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  985. {
  986. ent->s.frame = FRAME_crattak1 - (ent->client->ps.gunframe & 1);
  987. ent->client->anim_end = FRAME_crattak9;
  988. }
  989. else
  990. {
  991. ent->s.frame = FRAME_attack1 - (ent->client->ps.gunframe & 1);
  992. ent->client->anim_end = FRAME_attack8;
  993. }
  994. if (ent->client->ps.gunframe <= 9)
  995. shots = 1;
  996. else if (ent->client->ps.gunframe <= 14)
  997. {
  998. if (ent->client->buttons & BUTTON_ATTACK)
  999. shots = 2;
  1000. else
  1001. shots = 1;
  1002. }
  1003. else
  1004. shots = 3;
  1005. if (ent->client->pers.inventory[ent->client->ammo_index] < shots)
  1006. shots = ent->client->pers.inventory[ent->client->ammo_index];
  1007. if (!shots)
  1008. {
  1009. if (level.time >= ent->pain_debounce_time)
  1010. {
  1011. gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
  1012. ent->pain_debounce_time = level.time + 1;
  1013. }
  1014. NoAmmoWeaponChange (ent);
  1015. return;
  1016. }
  1017. if (is_quad)
  1018. {
  1019. damage *= 4;
  1020. kick *= 4;
  1021. }
  1022. for (i=0 ; i<3 ; i++)
  1023. {
  1024. ent->client->kick_origin[i] = crandom() * 0.35;
  1025. ent->client->kick_angles[i] = crandom() * 0.7;
  1026. }
  1027. for (i=0 ; i<shots ; i++)
  1028. {
  1029. // get start / end positions
  1030. AngleVectors (ent->client->v_angle, forward, right, up);
  1031. r = 7 + crandom()*4;
  1032. u = crandom()*4;
  1033. VectorSet(offset, 0, r, u + ent->viewheight-8);
  1034. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1035. fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_CHAINGUN);
  1036. }
  1037. // send muzzle flash
  1038. gi.WriteByte (svc_muzzleflash);
  1039. gi.WriteShort (ent-g_edicts);
  1040. gi.WriteByte ((MZ_CHAINGUN1 + shots - 1) | is_silenced);
  1041. gi.multicast (ent->s.origin, MULTICAST_PVS);
  1042. PlayerNoise(ent, start, PNOISE_WEAPON);
  1043. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  1044. ent->client->pers.inventory[ent->client->ammo_index] -= shots;
  1045. }
  1046. void Weapon_Chaingun (edict_t *ent)
  1047. {
  1048. static int pause_frames[] = {38, 43, 51, 61, 0};
  1049. static int fire_frames[] = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0};
  1050. Weapon_Generic (ent, 4, 31, 61, 64, pause_frames, fire_frames, Chaingun_Fire);
  1051. // RAFAEL
  1052. if (is_quadfire)
  1053. Weapon_Generic (ent, 4, 31, 61, 64, pause_frames, fire_frames, Chaingun_Fire);
  1054. }
  1055. /*
  1056. ======================================================================
  1057. SHOTGUN / SUPERSHOTGUN
  1058. ======================================================================
  1059. */
  1060. void weapon_shotgun_fire (edict_t *ent)
  1061. {
  1062. vec3_t start;
  1063. vec3_t forward, right;
  1064. vec3_t offset;
  1065. int damage = 4;
  1066. int kick = 8;
  1067. if (ent->client->ps.gunframe == 9)
  1068. {
  1069. ent->client->ps.gunframe++;
  1070. return;
  1071. }
  1072. AngleVectors (ent->client->v_angle, forward, right, NULL);
  1073. VectorScale (forward, -2, ent->client->kick_origin);
  1074. ent->client->kick_angles[0] = -2;
  1075. VectorSet(offset, 0, 8, ent->viewheight-8);
  1076. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1077. if (is_quad)
  1078. {
  1079. damage *= 4;
  1080. kick *= 4;
  1081. }
  1082. if (deathmatch->value)
  1083. fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_DEATHMATCH_SHOTGUN_COUNT, MOD_SHOTGUN);
  1084. else
  1085. fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_SHOTGUN_COUNT, MOD_SHOTGUN);
  1086. // send muzzle flash
  1087. gi.WriteByte (svc_muzzleflash);
  1088. gi.WriteShort (ent-g_edicts);
  1089. gi.WriteByte (MZ_SHOTGUN | is_silenced);
  1090. gi.multicast (ent->s.origin, MULTICAST_PVS);
  1091. ent->client->ps.gunframe++;
  1092. PlayerNoise(ent, start, PNOISE_WEAPON);
  1093. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  1094. ent->client->pers.inventory[ent->client->ammo_index]--;
  1095. }
  1096. void Weapon_Shotgun (edict_t *ent)
  1097. {
  1098. static int pause_frames[] = {22, 28, 34, 0};
  1099. static int fire_frames[] = {8, 9, 0};
  1100. Weapon_Generic (ent, 7, 18, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire);
  1101. // RAFAEL
  1102. if (is_quadfire)
  1103. Weapon_Generic (ent, 7, 18, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire);
  1104. }
  1105. void weapon_supershotgun_fire (edict_t *ent)
  1106. {
  1107. vec3_t start;
  1108. vec3_t forward, right;
  1109. vec3_t offset;
  1110. vec3_t v;
  1111. int damage = 6;
  1112. int kick = 12;
  1113. AngleVectors (ent->client->v_angle, forward, right, NULL);
  1114. VectorScale (forward, -2, ent->client->kick_origin);
  1115. ent->client->kick_angles[0] = -2;
  1116. VectorSet(offset, 0, 8, ent->viewheight-8);
  1117. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1118. if (is_quad)
  1119. {
  1120. damage *= 4;
  1121. kick *= 4;
  1122. }
  1123. v[PITCH] = ent->client->v_angle[PITCH];
  1124. v[YAW] = ent->client->v_angle[YAW] - 5;
  1125. v[ROLL] = ent->client->v_angle[ROLL];
  1126. AngleVectors (v, forward, NULL, NULL);
  1127. fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
  1128. v[YAW] = ent->client->v_angle[YAW] + 5;
  1129. AngleVectors (v, forward, NULL, NULL);
  1130. fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
  1131. // send muzzle flash
  1132. gi.WriteByte (svc_muzzleflash);
  1133. gi.WriteShort (ent-g_edicts);
  1134. gi.WriteByte (MZ_SSHOTGUN | is_silenced);
  1135. gi.multicast (ent->s.origin, MULTICAST_PVS);
  1136. ent->client->ps.gunframe++;
  1137. PlayerNoise(ent, start, PNOISE_WEAPON);
  1138. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  1139. ent->client->pers.inventory[ent->client->ammo_index] -= 2;
  1140. }
  1141. void Weapon_SuperShotgun (edict_t *ent)
  1142. {
  1143. static int pause_frames[] = {29, 42, 57, 0};
  1144. static int fire_frames[] = {7, 0};
  1145. Weapon_Generic (ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire);
  1146. // RAFAEL
  1147. if (is_quadfire)
  1148. Weapon_Generic (ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire);
  1149. }
  1150. /*
  1151. ======================================================================
  1152. RAILGUN
  1153. ======================================================================
  1154. */
  1155. void weapon_railgun_fire (edict_t *ent)
  1156. {
  1157. vec3_t start;
  1158. vec3_t forward, right;
  1159. vec3_t offset;
  1160. int damage;
  1161. int kick;
  1162. if (deathmatch->value)
  1163. { // normal damage is too extreme in dm
  1164. damage = 100;
  1165. kick = 200;
  1166. }
  1167. else
  1168. {
  1169. damage = 150;
  1170. kick = 250;
  1171. }
  1172. if (is_quad)
  1173. {
  1174. damage *= 4;
  1175. kick *= 4;
  1176. }
  1177. AngleVectors (ent->client->v_angle, forward, right, NULL);
  1178. VectorScale (forward, -3, ent->client->kick_origin);
  1179. ent->client->kick_angles[0] = -3;
  1180. VectorSet(offset, 0, 7, ent->viewheight-8);
  1181. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1182. fire_rail (ent, start, forward, damage, kick);
  1183. // send muzzle flash
  1184. gi.WriteByte (svc_muzzleflash);
  1185. gi.WriteShort (ent-g_edicts);
  1186. gi.WriteByte (MZ_RAILGUN | is_silenced);
  1187. gi.multicast (ent->s.origin, MULTICAST_PVS);
  1188. ent->client->ps.gunframe++;
  1189. PlayerNoise(ent, start, PNOISE_WEAPON);
  1190. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  1191. ent->client->pers.inventory[ent->client->ammo_index]--;
  1192. }
  1193. void Weapon_Railgun (edict_t *ent)
  1194. {
  1195. static int pause_frames[] = {56, 0};
  1196. static int fire_frames[] = {4, 0};
  1197. Weapon_Generic (ent, 3, 18, 56, 61, pause_frames, fire_frames, weapon_railgun_fire);
  1198. // RAFAEL
  1199. if (is_quadfire)
  1200. Weapon_Generic (ent, 3, 18, 56, 61, pause_frames, fire_frames, weapon_railgun_fire);
  1201. }
  1202. /*
  1203. ======================================================================
  1204. BFG10K
  1205. ======================================================================
  1206. */
  1207. void weapon_bfg_fire (edict_t *ent)
  1208. {
  1209. vec3_t offset, start;
  1210. vec3_t forward, right;
  1211. int damage;
  1212. float damage_radius = 1000;
  1213. if (deathmatch->value)
  1214. damage = 200;
  1215. else
  1216. damage = 500;
  1217. if (ent->client->ps.gunframe == 9)
  1218. {
  1219. // send muzzle flash
  1220. gi.WriteByte (svc_muzzleflash);
  1221. gi.WriteShort (ent-g_edicts);
  1222. gi.WriteByte (MZ_BFG | is_silenced);
  1223. gi.multicast (ent->s.origin, MULTICAST_PVS);
  1224. ent->client->ps.gunframe++;
  1225. PlayerNoise(ent, start, PNOISE_WEAPON);
  1226. return;
  1227. }
  1228. // cells can go down during windup (from power armor hits), so
  1229. // check again and abort firing if we don't have enough now
  1230. if (ent->client->pers.inventory[ent->client->ammo_index] < 50)
  1231. {
  1232. ent->client->ps.gunframe++;
  1233. return;
  1234. }
  1235. if (is_quad)
  1236. damage *= 4;
  1237. AngleVectors (ent->client->v_angle, forward, right, NULL);
  1238. VectorScale (forward, -2, ent->client->kick_origin);
  1239. // make a big pitch kick with an inverse fall
  1240. ent->client->v_dmg_pitch = -40;
  1241. ent->client->v_dmg_roll = crandom()*8;
  1242. ent->client->v_dmg_time = level.time + DAMAGE_TIME;
  1243. VectorSet(offset, 8, 8, ent->viewheight-8);
  1244. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1245. fire_bfg (ent, start, forward, damage, 400, damage_radius);
  1246. ent->client->ps.gunframe++;
  1247. PlayerNoise(ent, start, PNOISE_WEAPON);
  1248. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  1249. ent->client->pers.inventory[ent->client->ammo_index] -= 50;
  1250. }
  1251. void Weapon_BFG (edict_t *ent)
  1252. {
  1253. static int pause_frames[] = {39, 45, 50, 55, 0};
  1254. static int fire_frames[] = {9, 17, 0};
  1255. Weapon_Generic (ent, 8, 32, 55, 58, pause_frames, fire_frames, weapon_bfg_fire);
  1256. // RAFAEL
  1257. if (is_quadfire)
  1258. Weapon_Generic (ent, 8, 32, 55, 58, pause_frames, fire_frames, weapon_bfg_fire);
  1259. }
  1260. //======================================================================
  1261. // RAFAEL
  1262. /*
  1263. RipperGun
  1264. */
  1265. void weapon_ionripper_fire (edict_t *ent)
  1266. {
  1267. vec3_t start;
  1268. vec3_t forward, right;
  1269. vec3_t offset;
  1270. vec3_t tempang;
  1271. int damage;
  1272. int kick;
  1273. if (deathmatch->value)
  1274. {
  1275. // tone down for deathmatch
  1276. damage = 30;
  1277. kick = 40;
  1278. }
  1279. else
  1280. {
  1281. damage = 50;
  1282. kick = 60;
  1283. }
  1284. if (is_quad)
  1285. {
  1286. damage *= 4;
  1287. kick *= 4;
  1288. }
  1289. VectorCopy (ent->client->v_angle, tempang);
  1290. tempang[YAW] += crandom();
  1291. AngleVectors (tempang, forward, right, NULL);
  1292. VectorScale (forward, -3, ent->client->kick_origin);
  1293. ent->client->kick_angles[0] = -3;
  1294. // VectorSet (offset, 0, 7, ent->viewheight - 8);
  1295. VectorSet (offset, 16, 7, ent->viewheight - 8);
  1296. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1297. fire_ionripper (ent, start, forward, damage, 500, EF_IONRIPPER);
  1298. // send muzzle flash
  1299. gi.WriteByte (svc_muzzleflash);
  1300. gi.WriteShort (ent - g_edicts);
  1301. gi.WriteByte (MZ_IONRIPPER | is_silenced);
  1302. gi.multicast (ent->s.origin, MULTICAST_PVS);
  1303. ent->client->ps.gunframe++;
  1304. PlayerNoise (ent, start, PNOISE_WEAPON);
  1305. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  1306. ent->client->pers.inventory[ent->client->ammo_index] -= ent->client->pers.weapon->quantity;
  1307. if (ent->client->pers.inventory[ent->client->ammo_index] < 0)
  1308. ent->client->pers.inventory[ent->client->ammo_index] = 0;
  1309. }
  1310. void Weapon_Ionripper (edict_t *ent)
  1311. {
  1312. static int pause_frames[] = {36, 0};
  1313. static int fire_frames[] = {5, 0};
  1314. Weapon_Generic (ent, 4, 6, 36, 39, pause_frames, fire_frames, weapon_ionripper_fire);
  1315. if (is_quadfire)
  1316. Weapon_Generic (ent, 4, 6, 36, 39, pause_frames, fire_frames, weapon_ionripper_fire);
  1317. }
  1318. //
  1319. // Phalanx
  1320. //
  1321. void weapon_phalanx_fire (edict_t *ent)
  1322. {
  1323. vec3_t start;
  1324. vec3_t forward, right, up;
  1325. vec3_t offset;
  1326. vec3_t v;
  1327. int kick = 12;
  1328. int damage;
  1329. float damage_radius;
  1330. int radius_damage;
  1331. damage = 70 + (int)(random() * 10.0);
  1332. radius_damage = 120;
  1333. damage_radius = 120;
  1334. if (is_quad)
  1335. {
  1336. damage *= 4;
  1337. radius_damage *= 4;
  1338. }
  1339. AngleVectors (ent->client->v_angle, forward, right, NULL);
  1340. VectorScale (forward, -2, ent->client->kick_origin);
  1341. ent->client->kick_angles[0] = -2;
  1342. VectorSet(offset, 0, 8, ent->viewheight-8);
  1343. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1344. if (ent->client->ps.gunframe == 8)
  1345. {
  1346. v[PITCH] = ent->client->v_angle[PITCH];
  1347. v[YAW] = ent->client->v_angle[YAW] - 1.5;
  1348. v[ROLL] = ent->client->v_angle[ROLL];
  1349. AngleVectors (v, forward, right, up);
  1350. radius_damage = 30;
  1351. damage_radius = 120;
  1352. fire_plasma (ent, start, forward, damage, 725, damage_radius, radius_damage);
  1353. if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  1354. ent->client->pers.inventory[ent->client->ammo_index]--;
  1355. }
  1356. else
  1357. {
  1358. v[PITCH] = ent->client->v_angle[PITCH];
  1359. v[YAW] = ent->client->v_angle[YAW] + 1.5;
  1360. v[ROLL] = ent->client->v_angle[ROLL];
  1361. AngleVectors (v, forward, right, up);
  1362. fire_plasma (ent, start, forward, damage, 725, damage_radius, radius_damage);
  1363. // send muzzle flash
  1364. gi.WriteByte (svc_muzzleflash);
  1365. gi.WriteShort (ent-g_edicts);
  1366. gi.WriteByte (MZ_PHALANX | is_silenced);
  1367. gi.multicast (ent->s.origin, MULTICAST_PVS);
  1368. PlayerNoise(ent, start, PNOISE_WEAPON);
  1369. }
  1370. ent->client->ps.gunframe++;
  1371. }
  1372. void Weapon_Phalanx (edict_t *ent)
  1373. {
  1374. static int pause_frames[] = {29, 42, 55, 0};
  1375. static int fire_frames[] = {7, 8, 0};
  1376. Weapon_Generic (ent, 5, 20, 58, 63, pause_frames, fire_frames, weapon_phalanx_fire);
  1377. if (is_quadfire)
  1378. Weapon_Generic (ent, 5, 20, 58, 63, pause_frames, fire_frames, weapon_phalanx_fire);
  1379. }
  1380. /*
  1381. ======================================================================
  1382. TRAP
  1383. ======================================================================
  1384. */
  1385. #define TRAP_TIMER 5.0
  1386. #define TRAP_MINSPEED 300
  1387. #define TRAP_MAXSPEED 700
  1388. void weapon_trap_fire (edict_t *ent, qboolean held)
  1389. {
  1390. vec3_t offset;
  1391. vec3_t forward, right;
  1392. vec3_t start;
  1393. int damage = 125;
  1394. float timer;
  1395. int speed;
  1396. float radius;
  1397. radius = damage+40;
  1398. if (is_quad)
  1399. damage *= 4;
  1400. VectorSet(offset, 8, 8, ent->viewheight-8);
  1401. AngleVectors (ent->client->v_angle, forward, right, NULL);
  1402. P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1403. timer = ent->client->grenade_time - level.time;
  1404. speed = GRENADE_MINSPEED + (GRENADE_TIMER - timer) * ((GRENADE_MAXSPEED - GRENADE_MINSPEED) / GRENADE_TIMER);
  1405. // fire_grenade2 (ent, start, forward, damage, speed, timer, radius, held);
  1406. fire_trap (ent, start, forward, damage, speed, timer, radius, held);
  1407. // you don't get infinite traps! ZOID
  1408. // if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  1409. ent->client->pers.inventory[ent->client->ammo_index]--;
  1410. ent->client->grenade_time = level.time + 1.0;
  1411. }
  1412. void Weapon_Trap (edict_t *ent)
  1413. {
  1414. if ((ent->client->newweapon) && (ent->client->weaponstate == WEAPON_READY))
  1415. {
  1416. ChangeWeapon (ent);
  1417. return;
  1418. }
  1419. if (ent->client->weaponstate == WEAPON_ACTIVATING)
  1420. {
  1421. ent->client->weaponstate = WEAPON_READY;
  1422. ent->client->ps.gunframe = 16;
  1423. return;
  1424. }
  1425. if (ent->client->weaponstate == WEAPON_READY)
  1426. {
  1427. if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
  1428. {
  1429. ent->client->latched_buttons &= ~BUTTON_ATTACK;
  1430. if (ent->client->pers.inventory[ent->client->ammo_index])
  1431. {
  1432. ent->client->ps.gunframe = 1;
  1433. ent->client->weaponstate = WEAPON_FIRING;
  1434. ent->client->grenade_time = 0;
  1435. }
  1436. else
  1437. {
  1438. if (level.time >= ent->pain_debounce_time)
  1439. {
  1440. gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
  1441. ent->pain_debounce_time = level.time + 1;
  1442. }
  1443. NoAmmoWeaponChange (ent);
  1444. }
  1445. return;
  1446. }
  1447. if ((ent->client->ps.gunframe == 29) || (ent->client->ps.gunframe == 34) || (ent->client->ps.gunframe == 39) || (ent->client->ps.gunframe == 48))
  1448. {
  1449. if (rand()&15)
  1450. return;
  1451. }
  1452. if (++ent->client->ps.gunframe > 48)
  1453. ent->client->ps.gunframe = 16;
  1454. return;
  1455. }
  1456. if (ent->client->weaponstate == WEAPON_FIRING)
  1457. {
  1458. if (ent->client->ps.gunframe == 5)
  1459. // RAFAEL 16-APR-98
  1460. // gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/hgrena1b.wav"), 1, ATTN_NORM, 0);
  1461. gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/trapcock.wav"), 1, ATTN_NORM, 0);
  1462. // END 16-APR-98
  1463. if (ent->client->ps.gunframe == 11)
  1464. {
  1465. if (!ent->client->grenade_time)
  1466. {
  1467. ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2;
  1468. // RAFAEL 16-APR-98
  1469. ent->client->weapon_sound = gi.soundindex("weapons/traploop.wav");
  1470. // END 16-APR-98
  1471. }
  1472. // they waited too long, detonate it in their hand
  1473. if (!ent->client->grenade_blew_up && level.time >= ent->client->grenade_time)
  1474. {
  1475. ent->client->weapon_sound = 0;
  1476. weapon_trap_fire (ent, true);
  1477. ent->client->grenade_blew_up = true;
  1478. }
  1479. if (ent->client->buttons & BUTTON_ATTACK)
  1480. return;
  1481. if (ent->client->grenade_blew_up)
  1482. {
  1483. if (level.time >= ent->client->grenade_time)
  1484. {
  1485. ent->client->ps.gunframe = 15;
  1486. ent->client->grenade_blew_up = false;
  1487. }
  1488. else
  1489. {
  1490. return;
  1491. }
  1492. }
  1493. }
  1494. if (ent->client->ps.gunframe == 12)
  1495. {
  1496. ent->client->weapon_sound = 0;
  1497. weapon_trap_fire (ent, false);
  1498. if (ent->client->pers.inventory[ent->client->ammo_index] == 0)
  1499. NoAmmoWeaponChange (ent);
  1500. }
  1501. if ((ent->client->ps.gunframe == 15) && (level.time < ent->client->grenade_time))
  1502. return;
  1503. ent->client->ps.gunframe++;
  1504. if (ent->client->ps.gunframe == 16)
  1505. {
  1506. ent->client->grenade_time = 0;
  1507. ent->client->weaponstate = WEAPON_READY;
  1508. }
  1509. }
  1510. }