1 // g_weapon.c
2
3 #include "g_local.h"
4 #include "m_player.h"
5
6
7 static qboolean is_quad;
8 static byte is_silenced;
9
10 //PGM
11 static byte damage_multiplier;
12 //PGM
13
14 void weapon_grenade_fire (edict_t *ent, qboolean held);
15
16 //========
17 //ROGUE
P_DamageModifier(edict_t * ent)18 byte P_DamageModifier(edict_t *ent)
19 {
20 is_quad = 0;
21 damage_multiplier = 1;
22
23 if(ent->client->quad_framenum > level.framenum)
24 {
25 damage_multiplier *= 4;
26 is_quad = 1;
27
28 // if we're quad and DF_NO_STACK_DOUBLE is on, return now.
29 if(((int)(dmflags->value) & DF_NO_STACK_DOUBLE))
30 return damage_multiplier;
31 }
32 if(ent->client->double_framenum > level.framenum)
33 {
34 if ((deathmatch->value) || (damage_multiplier == 1))
35 {
36 damage_multiplier *= 2;
37 is_quad = 1;
38 }
39 }
40
41 return damage_multiplier;
42 }
43 //ROGUE
44 //========
45
P_ProjectSource(gclient_t * client,vec3_t point,vec3_t distance,vec3_t forward,vec3_t right,vec3_t result)46 static void P_ProjectSource (gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
47 {
48 vec3_t _distance;
49
50 VectorCopy (distance, _distance);
51 if (client->pers.hand == LEFT_HANDED)
52 _distance[1] *= -1;
53 else if (client->pers.hand == CENTER_HANDED)
54 _distance[1] = 0;
55 G_ProjectSource (point, _distance, forward, right, result);
56 }
57
P_ProjectSource2(gclient_t * client,vec3_t point,vec3_t distance,vec3_t forward,vec3_t right,vec3_t up,vec3_t result)58 static void P_ProjectSource2 (gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward,
59 vec3_t right, vec3_t up, vec3_t result)
60 {
61 vec3_t _distance;
62
63 VectorCopy (distance, _distance);
64 if (client->pers.hand == LEFT_HANDED)
65 _distance[1] *= -1;
66 else if (client->pers.hand == CENTER_HANDED)
67 _distance[1] = 0;
68 G_ProjectSource2 (point, _distance, forward, right, up, result);
69 }
70
71 /*
72 ===============
73 PlayerNoise
74
75 Each player can have two noise objects associated with it:
76 a personal noise (jumping, pain, weapon firing), and a weapon
77 target noise (bullet wall impacts)
78
79 Monsters that don't directly see the player can move
80 to a noise in hopes of seeing the player from there.
81 ===============
82 */
PlayerNoise(edict_t * who,vec3_t where,int type)83 void PlayerNoise(edict_t *who, vec3_t where, int type)
84 {
85 edict_t *noise;
86
87 if (type == PNOISE_WEAPON)
88 {
89 if (who->client->silencer_shots)
90 {
91 who->client->silencer_shots--;
92 return;
93 }
94 }
95
96 if (deathmatch->value)
97 return;
98
99 if (who->flags & FL_NOTARGET)
100 return;
101
102 if (who->flags & FL_DISGUISED)
103 {
104 if (type == PNOISE_WEAPON)
105 {
106 level.disguise_violator = who;
107 level.disguise_violation_framenum = level.framenum + 5;
108 }
109 else
110 return;
111 }
112
113 if (!who->mynoise)
114 {
115 noise = G_Spawn();
116 noise->classname = "player_noise";
117 VectorSet (noise->mins, -8, -8, -8);
118 VectorSet (noise->maxs, 8, 8, 8);
119 noise->owner = who;
120 noise->svflags = SVF_NOCLIENT;
121 who->mynoise = noise;
122
123 noise = G_Spawn();
124 noise->classname = "player_noise";
125 VectorSet (noise->mins, -8, -8, -8);
126 VectorSet (noise->maxs, 8, 8, 8);
127 noise->owner = who;
128 noise->svflags = SVF_NOCLIENT;
129 who->mynoise2 = noise;
130 }
131
132 if (type == PNOISE_SELF || type == PNOISE_WEAPON)
133 {
134 noise = who->mynoise;
135 level.sound_entity = noise;
136 level.sound_entity_framenum = level.framenum;
137 }
138 else // type == PNOISE_IMPACT
139 {
140 noise = who->mynoise2;
141 level.sound2_entity = noise;
142 level.sound2_entity_framenum = level.framenum;
143 }
144
145 VectorCopy (where, noise->s.origin);
146 VectorSubtract (where, noise->maxs, noise->absmin);
147 VectorAdd (where, noise->maxs, noise->absmax);
148 noise->teleport_time = level.time;
149 gi.linkentity (noise);
150 }
151
152
Pickup_Weapon(edict_t * ent,edict_t * other)153 qboolean Pickup_Weapon (edict_t *ent, edict_t *other)
154 {
155 int index;
156 gitem_t *ammo;
157
158 index = ITEM_INDEX(ent->item);
159
160 if ( ( ((int)(dmflags->value) & DF_WEAPONS_STAY) || coop->value)
161 && other->client->pers.inventory[index])
162 {
163 if (!(ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM) ) )
164 return false; // leave the weapon for others to pickup
165 }
166
167 other->client->pers.inventory[index]++;
168
169 if (!(ent->spawnflags & DROPPED_ITEM) )
170 {
171 // give them some ammo with it
172 // PGM -- IF APPROPRIATE!
173 if(ent->item->ammo) //PGM
174 {
175 ammo = FindItem (ent->item->ammo);
176 if ( (int)dmflags->value & DF_INFINITE_AMMO )
177 Add_Ammo (other, ammo, 1000);
178 else
179 Add_Ammo (other, ammo, ammo->quantity);
180 }
181
182 if (! (ent->spawnflags & DROPPED_PLAYER_ITEM) )
183 {
184 if (deathmatch->value)
185 {
186 if ((int)(dmflags->value) & DF_WEAPONS_STAY)
187 ent->flags |= FL_RESPAWN;
188 else
189 SetRespawn (ent, 30);
190 }
191 if (coop->value)
192 ent->flags |= FL_RESPAWN;
193 }
194 }
195
196 if (other->client->pers.weapon != ent->item &&
197 (other->client->pers.inventory[index] == 1) &&
198 ( !deathmatch->value || other->client->pers.weapon == FindItem("blaster") ) )
199 other->client->newweapon = ent->item;
200
201 return true;
202 }
203
204
205 /*
206 ===============
207 ChangeWeapon
208
209 The old weapon has been dropped all the way, so make the new one
210 current
211 ===============
212 */
ChangeWeapon(edict_t * ent)213 void ChangeWeapon (edict_t *ent)
214 {
215 int i;
216
217 if (ent->client->grenade_time)
218 {
219 ent->client->grenade_time = level.time;
220 ent->client->weapon_sound = 0;
221 weapon_grenade_fire (ent, false);
222 ent->client->grenade_time = 0;
223 }
224
225 ent->client->pers.lastweapon = ent->client->pers.weapon;
226 ent->client->pers.weapon = ent->client->newweapon;
227 ent->client->newweapon = NULL;
228 ent->client->machinegun_shots = 0;
229
230 // set visible model
231 if (ent->s.modelindex == 255)
232 {
233 if (ent->client->pers.weapon)
234 i = ((ent->client->pers.weapon->weapmodel & 0xff) << 8);
235 else
236 i = 0;
237 ent->s.skinnum = (ent - g_edicts - 1) | i;
238 }
239
240 if (ent->client->pers.weapon && ent->client->pers.weapon->ammo)
241 ent->client->ammo_index = ITEM_INDEX(FindItem(ent->client->pers.weapon->ammo));
242 else
243 ent->client->ammo_index = 0;
244
245 if (!ent->client->pers.weapon)
246 { // dead
247 ent->client->ps.gunindex = 0;
248 return;
249 }
250
251 ent->client->weaponstate = WEAPON_ACTIVATING;
252 ent->client->ps.gunframe = 0;
253 ent->client->ps.gunindex = gi.modelindex(ent->client->pers.weapon->view_model);
254
255 ent->client->anim_priority = ANIM_PAIN;
256 if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
257 {
258 ent->s.frame = FRAME_crpain1;
259 ent->client->anim_end = FRAME_crpain4;
260 }
261 else
262 {
263 ent->s.frame = FRAME_pain301;
264 ent->client->anim_end = FRAME_pain304;
265
266 }
267 }
268
269 /*
270 =================
271 NoAmmoWeaponChange
272 =================
273 */
274
275 // PMM - added rogue weapons to the list
276
NoAmmoWeaponChange(edict_t * ent)277 void NoAmmoWeaponChange (edict_t *ent)
278 {
279 if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("slugs"))]
280 && ent->client->pers.inventory[ITEM_INDEX(FindItem("railgun"))] )
281 {
282 ent->client->newweapon = FindItem ("railgun");
283 return;
284 }
285 // ROGUE
286 if ( (ent->client->pers.inventory[ITEM_INDEX(FindItem("cells"))] >= 2)
287 && ent->client->pers.inventory[ITEM_INDEX(FindItem("Plasma Beam"))] )
288 {
289 ent->client->newweapon = FindItem ("Plasma Beam");
290 return;
291 }
292 // -ROGUE
293 /*
294 if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("cells"))]
295 && ent->client->pers.inventory[ITEM_INDEX(FindItem("hyperblaster"))] )
296 {
297 ent->client->newweapon = FindItem ("hyperblaster");
298 return;
299 }
300 */
301 // ROGUE
302 if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("flechettes"))]
303 && ent->client->pers.inventory[ITEM_INDEX(FindItem("etf rifle"))] )
304 {
305 ent->client->newweapon = FindItem ("etf rifle");
306 return;
307 }
308 // -ROGUE
309 if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
310 && ent->client->pers.inventory[ITEM_INDEX(FindItem("chaingun"))] )
311 {
312 ent->client->newweapon = FindItem ("chaingun");
313 return;
314 }
315 if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
316 && ent->client->pers.inventory[ITEM_INDEX(FindItem("machinegun"))] )
317 {
318 ent->client->newweapon = FindItem ("machinegun");
319 return;
320 }
321 if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))] > 1
322 && ent->client->pers.inventory[ITEM_INDEX(FindItem("super shotgun"))] )
323 {
324 ent->client->newweapon = FindItem ("super shotgun");
325 return;
326 }
327 if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))]
328 && ent->client->pers.inventory[ITEM_INDEX(FindItem("shotgun"))] )
329 {
330 ent->client->newweapon = FindItem ("shotgun");
331 return;
332 }
333 ent->client->newweapon = FindItem ("blaster");
334 }
335
336 /*
337 =================
338 Think_Weapon
339
340 Called by ClientBeginServerFrame and ClientThink
341 =================
342 */
Think_Weapon(edict_t * ent)343 void Think_Weapon (edict_t *ent)
344 {
345 // if just died, put the weapon away
346 if (ent->health < 1)
347 {
348 ent->client->newweapon = NULL;
349 ChangeWeapon (ent);
350 }
351
352 // call active weapon think routine
353 if (ent->client->pers.weapon && ent->client->pers.weapon->weaponthink)
354 {
355 //PGM
356 P_DamageModifier(ent);
357 // is_quad = (ent->client->quad_framenum > level.framenum);
358 //PGM
359 if (ent->client->silencer_shots)
360 is_silenced = MZ_SILENCED;
361 else
362 is_silenced = 0;
363 ent->client->pers.weapon->weaponthink (ent);
364 }
365 }
366
367
368 /*
369 ================
370 Use_Weapon
371
372 Make the weapon ready if there is ammo
373 ================
374 */
Use_Weapon(edict_t * ent,gitem_t * item)375 void Use_Weapon (edict_t *ent, gitem_t *item)
376 {
377 int ammo_index;
378 gitem_t *ammo_item;
379
380 // see if we're already using it
381 if (item == ent->client->pers.weapon)
382 return;
383
384 if (item->ammo && !g_select_empty->value && !(item->flags & IT_AMMO))
385 {
386 ammo_item = FindItem(item->ammo);
387 ammo_index = ITEM_INDEX(ammo_item);
388
389 if (!ent->client->pers.inventory[ammo_index])
390 {
391 gi.cprintf (ent, PRINT_HIGH, "No %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
392 return;
393 }
394
395 if (ent->client->pers.inventory[ammo_index] < item->quantity)
396 {
397 gi.cprintf (ent, PRINT_HIGH, "Not enough %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
398 return;
399 }
400 }
401
402 // change to this weapon when down
403 ent->client->newweapon = item;
404 }
405
406
407
408 /*
409 ================
410 Drop_Weapon
411 ================
412 */
Drop_Weapon(edict_t * ent,gitem_t * item)413 void Drop_Weapon (edict_t *ent, gitem_t *item)
414 {
415 int index;
416
417 if ((int)(dmflags->value) & DF_WEAPONS_STAY)
418 return;
419
420 index = ITEM_INDEX(item);
421 // see if we're already using it
422 if ( ((item == ent->client->pers.weapon) || (item == ent->client->newweapon))&& (ent->client->pers.inventory[index] == 1) )
423 {
424 gi.cprintf (ent, PRINT_HIGH, "Can't drop current weapon\n");
425 return;
426 }
427
428 Drop_Item (ent, item);
429 ent->client->pers.inventory[index]--;
430 }
431
432
433 /*
434 ================
435 Weapon_Generic
436
437 A generic function to handle the basics of weapon thinking
438 ================
439 */
440 #define FRAME_FIRE_FIRST (FRAME_ACTIVATE_LAST + 1)
441 #define FRAME_IDLE_FIRST (FRAME_FIRE_LAST + 1)
442 #define FRAME_DEACTIVATE_FIRST (FRAME_IDLE_LAST + 1)
443
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))444 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))
445 {
446 int n;
447
448 if(ent->deadflag || ent->s.modelindex != 255) // VWep animations screw up corpses
449 {
450 return;
451 }
452
453 if (ent->client->weaponstate == WEAPON_DROPPING)
454 {
455 if (ent->client->ps.gunframe == FRAME_DEACTIVATE_LAST)
456 {
457 ChangeWeapon (ent);
458 return;
459 }
460 else if ((FRAME_DEACTIVATE_LAST - ent->client->ps.gunframe) == 4)
461 {
462 ent->client->anim_priority = ANIM_REVERSE;
463 if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
464 {
465 ent->s.frame = FRAME_crpain4+1;
466 ent->client->anim_end = FRAME_crpain1;
467 }
468 else
469 {
470 ent->s.frame = FRAME_pain304+1;
471 ent->client->anim_end = FRAME_pain301;
472
473 }
474 }
475
476 ent->client->ps.gunframe++;
477 return;
478 }
479
480 if (ent->client->weaponstate == WEAPON_ACTIVATING)
481 {
482 if (ent->client->ps.gunframe == FRAME_ACTIVATE_LAST)
483 {
484 ent->client->weaponstate = WEAPON_READY;
485 ent->client->ps.gunframe = FRAME_IDLE_FIRST;
486 return;
487 }
488
489 ent->client->ps.gunframe++;
490 return;
491 }
492
493 if ((ent->client->newweapon) && (ent->client->weaponstate != WEAPON_FIRING))
494 {
495 ent->client->weaponstate = WEAPON_DROPPING;
496 ent->client->ps.gunframe = FRAME_DEACTIVATE_FIRST;
497
498 if ((FRAME_DEACTIVATE_LAST - FRAME_DEACTIVATE_FIRST) < 4)
499 {
500 ent->client->anim_priority = ANIM_REVERSE;
501 if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
502 {
503 ent->s.frame = FRAME_crpain4+1;
504 ent->client->anim_end = FRAME_crpain1;
505 }
506 else
507 {
508 ent->s.frame = FRAME_pain304+1;
509 ent->client->anim_end = FRAME_pain301;
510
511 }
512 }
513 return;
514 }
515
516 if (ent->client->weaponstate == WEAPON_READY)
517 {
518 if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
519 {
520 ent->client->latched_buttons &= ~BUTTON_ATTACK;
521 if ((!ent->client->ammo_index) ||
522 ( ent->client->pers.inventory[ent->client->ammo_index] >= ent->client->pers.weapon->quantity))
523 {
524 ent->client->ps.gunframe = FRAME_FIRE_FIRST;
525 ent->client->weaponstate = WEAPON_FIRING;
526
527 // start the animation
528 ent->client->anim_priority = ANIM_ATTACK;
529 if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
530 {
531 ent->s.frame = FRAME_crattak1-1;
532 ent->client->anim_end = FRAME_crattak9;
533 }
534 else
535 {
536 ent->s.frame = FRAME_attack1-1;
537 ent->client->anim_end = FRAME_attack8;
538 }
539 }
540 else
541 {
542 if (level.time >= ent->pain_debounce_time)
543 {
544 gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
545 ent->pain_debounce_time = level.time + 1;
546 }
547 NoAmmoWeaponChange (ent);
548 }
549 }
550 else
551 {
552 if (ent->client->ps.gunframe == FRAME_IDLE_LAST)
553 {
554 ent->client->ps.gunframe = FRAME_IDLE_FIRST;
555 return;
556 }
557
558 if (pause_frames)
559 {
560 for (n = 0; pause_frames[n]; n++)
561 {
562 if (ent->client->ps.gunframe == pause_frames[n])
563 {
564 if (rand()&15)
565 return;
566 }
567 }
568 }
569
570 ent->client->ps.gunframe++;
571 return;
572 }
573 }
574
575 if (ent->client->weaponstate == WEAPON_FIRING)
576 {
577 for (n = 0; fire_frames[n]; n++)
578 {
579 if (ent->client->ps.gunframe == fire_frames[n])
580 {
581 // FIXME - double should use different sound
582 if (ent->client->quad_framenum > level.framenum)
583 gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage3.wav"), 1, ATTN_NORM, 0);
584 else if (ent->client->double_framenum > level.framenum)
585 gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/ddamage3.wav"), 1, ATTN_NORM, 0);
586
587 fire (ent);
588 break;
589 }
590 }
591
592 if (!fire_frames[n])
593 ent->client->ps.gunframe++;
594
595 if (ent->client->ps.gunframe == FRAME_IDLE_FIRST+1)
596 ent->client->weaponstate = WEAPON_READY;
597 }
598 }
599
600
601 /*
602 ======================================================================
603
604 GRENADE
605
606 ======================================================================
607 */
608
609 #define GRENADE_TIMER 3.0
610 #define GRENADE_MINSPEED 400
611 #define GRENADE_MAXSPEED 800
612
weapon_grenade_fire(edict_t * ent,qboolean held)613 void weapon_grenade_fire (edict_t *ent, qboolean held)
614 {
615 vec3_t offset;
616 vec3_t forward, right, up;
617 vec3_t start;
618 int damage = 125;
619 float timer;
620 int speed;
621 float radius;
622
623 radius = damage+40;
624 if (is_quad)
625 // damage *= 4;
626 damage *= damage_multiplier; // PGM
627
628 AngleVectors (ent->client->v_angle, forward, right, up);
629 if (ent->client->pers.weapon->tag == AMMO_TESLA)
630 {
631 // VectorSet(offset, 0, -12, ent->viewheight-26);
632 VectorSet(offset, 0, -4, ent->viewheight-22);
633 }
634 else
635 {
636 // VectorSet(offset, 8, 8, ent->viewheight-8);
637 VectorSet(offset, 2, 6, ent->viewheight-14);
638 }
639 P_ProjectSource2 (ent->client, ent->s.origin, offset, forward, right, up, start);
640
641 timer = ent->client->grenade_time - level.time;
642 speed = GRENADE_MINSPEED + (GRENADE_TIMER - timer) * ((GRENADE_MAXSPEED - GRENADE_MINSPEED) / GRENADE_TIMER);
643 if (speed > GRENADE_MAXSPEED)
644 speed = GRENADE_MAXSPEED;
645
646 // fire_grenade2 (ent, start, forward, damage, speed, timer, radius, held);
647
648 // ============
649 // PGM
650 switch(ent->client->pers.weapon->tag)
651 {
652 case AMMO_GRENADES:
653 fire_grenade2 (ent, start, forward, damage, speed, timer, radius, held);
654 break;
655 case AMMO_TESLA:
656 fire_tesla (ent, start, forward, damage_multiplier, speed);
657 break;
658 default:
659 fire_prox (ent, start, forward, damage_multiplier, speed);
660 break;
661 }
662 // PGM
663 // ============
664
665 if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
666 ent->client->pers.inventory[ent->client->ammo_index]--;
667
668 ent->client->grenade_time = level.time + 1.0;
669
670 if(ent->deadflag || ent->s.modelindex != 255) // VWep animations screw up corpses
671 {
672 return;
673 }
674
675 if (ent->health <= 0)
676 return;
677
678 if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
679 {
680 ent->client->anim_priority = ANIM_ATTACK;
681 ent->s.frame = FRAME_crattak1-1;
682 ent->client->anim_end = FRAME_crattak3;
683 }
684 else
685 {
686 ent->client->anim_priority = ANIM_REVERSE;
687 ent->s.frame = FRAME_wave08;
688 ent->client->anim_end = FRAME_wave01;
689 }
690 }
691 /*
692 void Weapon_Grenade (edict_t *ent)
693 {
694 if ((ent->client->newweapon) && (ent->client->weaponstate == WEAPON_READY))
695 {
696 ChangeWeapon (ent);
697 return;
698 }
699
700 if (ent->client->weaponstate == WEAPON_ACTIVATING)
701 {
702 ent->client->weaponstate = WEAPON_READY;
703 ent->client->ps.gunframe = 16;
704 return;
705 }
706
707 if (ent->client->weaponstate == WEAPON_READY)
708 {
709 if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
710 {
711 ent->client->latched_buttons &= ~BUTTON_ATTACK;
712 if (ent->client->pers.inventory[ent->client->ammo_index])
713 {
714 ent->client->ps.gunframe = 1;
715 ent->client->weaponstate = WEAPON_FIRING;
716 ent->client->grenade_time = 0;
717 }
718 else
719 {
720 if (level.time >= ent->pain_debounce_time)
721 {
722 gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
723 ent->pain_debounce_time = level.time + 1;
724 }
725 NoAmmoWeaponChange (ent);
726 }
727 return;
728 }
729
730 if ((ent->client->ps.gunframe == 29) || (ent->client->ps.gunframe == 34) || (ent->client->ps.gunframe == 39) || (ent->client->ps.gunframe == 48))
731 {
732 if (rand()&15)
733 return;
734 }
735
736 if (++ent->client->ps.gunframe > 48)
737 ent->client->ps.gunframe = 16;
738 return;
739 }
740
741 if (ent->client->weaponstate == WEAPON_FIRING)
742 {
743 if (ent->client->ps.gunframe == 5)
744 gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/hgrena1b.wav"), 1, ATTN_NORM, 0);
745
746 if (ent->client->ps.gunframe == 11)
747 {
748 if (!ent->client->grenade_time)
749 {
750 ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2;
751 ent->client->weapon_sound = gi.soundindex("weapons/hgrenc1b.wav");
752 }
753
754 // they waited too long, detonate it in their hand
755 if (!ent->client->grenade_blew_up && level.time >= ent->client->grenade_time)
756 {
757 ent->client->weapon_sound = 0;
758 weapon_grenade_fire (ent, true);
759 ent->client->grenade_blew_up = true;
760 }
761
762 if (ent->client->buttons & BUTTON_ATTACK)
763 return;
764
765 if (ent->client->grenade_blew_up)
766 {
767 if (level.time >= ent->client->grenade_time)
768 {
769 ent->client->ps.gunframe = 15;
770 ent->client->grenade_blew_up = false;
771 }
772 else
773 {
774 return;
775 }
776 }
777 }
778
779 if (ent->client->ps.gunframe == 12)
780 {
781 ent->client->weapon_sound = 0;
782 weapon_grenade_fire (ent, false);
783 }
784
785 if ((ent->client->ps.gunframe == 15) && (level.time < ent->client->grenade_time))
786 return;
787
788 ent->client->ps.gunframe++;
789
790 if (ent->client->ps.gunframe == 16)
791 {
792 ent->client->grenade_time = 0;
793 ent->client->weaponstate = WEAPON_READY;
794 }
795 }
796 }
797 */
798
799 #define FRAME_IDLE_FIRST (FRAME_FIRE_LAST + 1)
800
801 //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))
802 // 15 48 5 11 12 29,34,39,48
Throw_Generic(edict_t * ent,int FRAME_FIRE_LAST,int FRAME_IDLE_LAST,int FRAME_THROW_SOUND,int FRAME_THROW_HOLD,int FRAME_THROW_FIRE,int * pause_frames,int EXPLODE,void (* fire)(edict_t * ent,qboolean held))803 void Throw_Generic (edict_t *ent, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int FRAME_THROW_SOUND,
804 int FRAME_THROW_HOLD, int FRAME_THROW_FIRE, int *pause_frames, int EXPLODE,
805 void (*fire)(edict_t *ent, qboolean held))
806 {
807 int n;
808
809 if ((ent->client->newweapon) && (ent->client->weaponstate == WEAPON_READY))
810 {
811 ChangeWeapon (ent);
812 return;
813 }
814
815 if (ent->client->weaponstate == WEAPON_ACTIVATING)
816 {
817 ent->client->weaponstate = WEAPON_READY;
818 ent->client->ps.gunframe = FRAME_IDLE_FIRST;
819 return;
820 }
821
822 if (ent->client->weaponstate == WEAPON_READY)
823 {
824 if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
825 {
826 ent->client->latched_buttons &= ~BUTTON_ATTACK;
827 if (ent->client->pers.inventory[ent->client->ammo_index])
828 {
829 ent->client->ps.gunframe = 1;
830 ent->client->weaponstate = WEAPON_FIRING;
831 ent->client->grenade_time = 0;
832 }
833 else
834 {
835 if (level.time >= ent->pain_debounce_time)
836 {
837 gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
838 ent->pain_debounce_time = level.time + 1;
839 }
840 NoAmmoWeaponChange (ent);
841 }
842 return;
843 }
844
845 if (ent->client->ps.gunframe == FRAME_IDLE_LAST)
846 {
847 ent->client->ps.gunframe = FRAME_IDLE_FIRST;
848 return;
849 }
850
851 if (pause_frames)
852 {
853 for (n = 0; pause_frames[n]; n++)
854 {
855 if (ent->client->ps.gunframe == pause_frames[n])
856 {
857 if (rand()&15)
858 return;
859 }
860 }
861 }
862
863 ent->client->ps.gunframe++;
864 return;
865 }
866
867 if (ent->client->weaponstate == WEAPON_FIRING)
868 {
869 if (ent->client->ps.gunframe == FRAME_THROW_SOUND)
870 gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/hgrena1b.wav"), 1, ATTN_NORM, 0);
871
872 if (ent->client->ps.gunframe == FRAME_THROW_HOLD)
873 {
874 if (!ent->client->grenade_time)
875 {
876 ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2;
877 switch(ent->client->pers.weapon->tag)
878 {
879 case AMMO_GRENADES:
880 ent->client->weapon_sound = gi.soundindex("weapons/hgrenc1b.wav");
881 break;
882 }
883 }
884
885 // they waited too long, detonate it in their hand
886 if (EXPLODE && !ent->client->grenade_blew_up && level.time >= ent->client->grenade_time)
887 {
888 ent->client->weapon_sound = 0;
889 fire (ent, true);
890 ent->client->grenade_blew_up = true;
891 }
892
893 if (ent->client->buttons & BUTTON_ATTACK)
894 return;
895
896 if (ent->client->grenade_blew_up)
897 {
898 if (level.time >= ent->client->grenade_time)
899 {
900 ent->client->ps.gunframe = FRAME_FIRE_LAST;
901 ent->client->grenade_blew_up = false;
902 }
903 else
904 {
905 return;
906 }
907 }
908 }
909
910 if (ent->client->ps.gunframe == FRAME_THROW_FIRE)
911 {
912 ent->client->weapon_sound = 0;
913 fire (ent, true);
914 }
915
916 if ((ent->client->ps.gunframe == FRAME_FIRE_LAST) && (level.time < ent->client->grenade_time))
917 return;
918
919 ent->client->ps.gunframe++;
920
921 if (ent->client->ps.gunframe == FRAME_IDLE_FIRST)
922 {
923 ent->client->grenade_time = 0;
924 ent->client->weaponstate = WEAPON_READY;
925 }
926 }
927 }
928
929 //void Throw_Generic (edict_t *ent, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int FRAME_THROW_SOUND,
930 // int FRAME_THROW_HOLD, int FRAME_THROW_FIRE, int *pause_frames,
931 // int EXPLOSION_TIME, void (*fire)(edict_t *ent))
932
Weapon_Grenade(edict_t * ent)933 void Weapon_Grenade (edict_t *ent)
934 {
935 static int pause_frames[] = {29,34,39,48,0};
936
937 Throw_Generic (ent, 15, 48, 5, 11, 12, pause_frames, GRENADE_TIMER, weapon_grenade_fire);
938 }
939
Weapon_Prox(edict_t * ent)940 void Weapon_Prox (edict_t *ent)
941 {
942 static int pause_frames[] = {22, 29, 0};
943
944 Throw_Generic (ent, 7, 27, 99, 2, 4, pause_frames, 0, weapon_grenade_fire);
945 }
946
Weapon_Tesla(edict_t * ent)947 void Weapon_Tesla (edict_t *ent)
948 {
949 static int pause_frames[] = {21, 0};
950
951 if ((ent->client->ps.gunframe > 1) && (ent->client->ps.gunframe < 9))
952 {
953 ent->client->ps.gunindex = gi.modelindex ("models/weapons/v_tesla2/tris.md2");
954 }
955 else
956 {
957 ent->client->ps.gunindex = gi.modelindex ("models/weapons/v_tesla/tris.md2");
958 }
959
960 Throw_Generic (ent, 8, 32, 99, 1, 2, pause_frames, 0, weapon_grenade_fire);
961 }
962
963
964
965 /*
966 ======================================================================
967
968 GRENADE LAUNCHER
969
970 ======================================================================
971 */
972
weapon_grenadelauncher_fire(edict_t * ent)973 void weapon_grenadelauncher_fire (edict_t *ent)
974 {
975 vec3_t offset;
976 vec3_t forward, right;
977 vec3_t start;
978 // int damage = 120;
979 int damage; // PGM
980 float radius;
981
982 // =====
983 // PGM
984 switch(ent->client->pers.weapon->tag)
985 {
986 case AMMO_PROX:
987 damage = 90;
988 break;
989 default:
990 damage = 120;
991 break;
992 }
993 // PGM
994 // =====
995
996 radius = damage+40;
997 if (is_quad)
998 // damage *= 4;
999 damage *= damage_multiplier; //pgm
1000
1001 VectorSet(offset, 8, 8, ent->viewheight-8);
1002 AngleVectors (ent->client->v_angle, forward, right, NULL);
1003 P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1004
1005 VectorScale (forward, -2, ent->client->kick_origin);
1006 ent->client->kick_angles[0] = -1;
1007
1008 // fire_grenade (ent, start, forward, damage, 600, 2.5, radius);
1009 // =====
1010 // PGM
1011 switch(ent->client->pers.weapon->tag)
1012 {
1013 case AMMO_PROX:
1014 fire_prox (ent, start, forward, damage_multiplier, 600);
1015 break;
1016 default:
1017 fire_grenade (ent, start, forward, damage, 600, 2.5, radius);
1018 break;
1019 }
1020 // PGM
1021 // =====
1022
1023 gi.WriteByte (svc_muzzleflash);
1024 gi.WriteShort (ent-g_edicts);
1025 gi.WriteByte (MZ_GRENADE | is_silenced);
1026 gi.multicast (ent->s.origin, MULTICAST_PVS);
1027
1028 ent->client->ps.gunframe++;
1029
1030 PlayerNoise(ent, start, PNOISE_WEAPON);
1031
1032 if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1033 ent->client->pers.inventory[ent->client->ammo_index]--;
1034 }
1035
Weapon_GrenadeLauncher(edict_t * ent)1036 void Weapon_GrenadeLauncher (edict_t *ent)
1037 {
1038 static int pause_frames[] = {34, 51, 59, 0};
1039 static int fire_frames[] = {6, 0};
1040
1041 Weapon_Generic (ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire);
1042 }
1043
1044 //==========
1045 //PGM
Weapon_ProxLauncher(edict_t * ent)1046 void Weapon_ProxLauncher (edict_t *ent)
1047 {
1048 static int pause_frames[] = {34, 51, 59, 0};
1049 static int fire_frames[] = {6, 0};
1050
1051 Weapon_Generic (ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire);
1052 }
1053 //PGM
1054 //==========
1055
1056 /*
1057 ======================================================================
1058
1059 ROCKET
1060
1061 ======================================================================
1062 */
1063
Weapon_RocketLauncher_Fire(edict_t * ent)1064 void Weapon_RocketLauncher_Fire (edict_t *ent)
1065 {
1066 vec3_t offset, start;
1067 vec3_t forward, right;
1068 int damage;
1069 float damage_radius;
1070 int radius_damage;
1071
1072 damage = 100 + (int)(random() * 20.0);
1073 radius_damage = 120;
1074 damage_radius = 120;
1075 if (is_quad)
1076 {
1077 //PGM
1078 // damage *= 4;
1079 damage *= damage_multiplier;
1080 // radius_damage *= 4;
1081 radius_damage *= damage_multiplier;
1082 //PGM
1083 }
1084
1085 AngleVectors (ent->client->v_angle, forward, right, NULL);
1086
1087 VectorScale (forward, -2, ent->client->kick_origin);
1088 ent->client->kick_angles[0] = -1;
1089
1090 VectorSet(offset, 8, 8, ent->viewheight-8);
1091 P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1092 fire_rocket (ent, start, forward, damage, 650, damage_radius, radius_damage);
1093
1094 // send muzzle flash
1095 gi.WriteByte (svc_muzzleflash);
1096 gi.WriteShort (ent-g_edicts);
1097 gi.WriteByte (MZ_ROCKET | is_silenced);
1098 gi.multicast (ent->s.origin, MULTICAST_PVS);
1099
1100 ent->client->ps.gunframe++;
1101
1102 PlayerNoise(ent, start, PNOISE_WEAPON);
1103
1104 if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1105 ent->client->pers.inventory[ent->client->ammo_index]--;
1106 }
1107
Weapon_RocketLauncher(edict_t * ent)1108 void Weapon_RocketLauncher (edict_t *ent)
1109 {
1110 static int pause_frames[] = {25, 33, 42, 50, 0};
1111 static int fire_frames[] = {5, 0};
1112
1113 Weapon_Generic (ent, 4, 12, 50, 54, pause_frames, fire_frames, Weapon_RocketLauncher_Fire);
1114 }
1115
1116
1117 /*
1118 ======================================================================
1119
1120 BLASTER / HYPERBLASTER
1121
1122 ======================================================================
1123 */
1124
Blaster_Fire(edict_t * ent,vec3_t g_offset,int damage,qboolean hyper,int effect)1125 void Blaster_Fire (edict_t *ent, vec3_t g_offset, int damage, qboolean hyper, int effect)
1126 {
1127 vec3_t forward, right;
1128 vec3_t start;
1129 vec3_t offset;
1130
1131 if (is_quad)
1132 // damage *= 4;
1133 damage *= damage_multiplier; //pgm
1134
1135 AngleVectors (ent->client->v_angle, forward, right, NULL);
1136 VectorSet(offset, 24, 8, ent->viewheight-8);
1137 VectorAdd (offset, g_offset, offset);
1138 P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1139
1140 VectorScale (forward, -2, ent->client->kick_origin);
1141 ent->client->kick_angles[0] = -1;
1142
1143 fire_blaster (ent, start, forward, damage, 1000, effect, hyper);
1144
1145 // send muzzle flash
1146 gi.WriteByte (svc_muzzleflash);
1147 gi.WriteShort (ent-g_edicts);
1148 if (hyper)
1149 gi.WriteByte (MZ_HYPERBLASTER | is_silenced);
1150 else
1151 gi.WriteByte (MZ_BLASTER | is_silenced);
1152 gi.multicast (ent->s.origin, MULTICAST_PVS);
1153
1154 PlayerNoise(ent, start, PNOISE_WEAPON);
1155 }
1156
1157
Weapon_Blaster_Fire(edict_t * ent)1158 void Weapon_Blaster_Fire (edict_t *ent)
1159 {
1160 int damage;
1161
1162 if (deathmatch->value)
1163 damage = 15;
1164 else
1165 damage = 10;
1166 Blaster_Fire (ent, vec3_origin, damage, false, EF_BLASTER);
1167 ent->client->ps.gunframe++;
1168 }
1169
Weapon_Blaster(edict_t * ent)1170 void Weapon_Blaster (edict_t *ent)
1171 {
1172 static int pause_frames[] = {19, 32, 0};
1173 static int fire_frames[] = {5, 0};
1174
1175 Weapon_Generic (ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire);
1176 }
1177
1178
Weapon_HyperBlaster_Fire(edict_t * ent)1179 void Weapon_HyperBlaster_Fire (edict_t *ent)
1180 {
1181 float rotation;
1182 vec3_t offset;
1183 int effect;
1184 int damage;
1185
1186 ent->client->weapon_sound = gi.soundindex("weapons/hyprbl1a.wav");
1187
1188 if (!(ent->client->buttons & BUTTON_ATTACK))
1189 {
1190 ent->client->ps.gunframe++;
1191 }
1192 else
1193 {
1194 if (! ent->client->pers.inventory[ent->client->ammo_index] )
1195 {
1196 if (level.time >= ent->pain_debounce_time)
1197 {
1198 gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
1199 ent->pain_debounce_time = level.time + 1;
1200 }
1201 NoAmmoWeaponChange (ent);
1202 }
1203 else
1204 {
1205 rotation = (ent->client->ps.gunframe - 5) * 2*M_PI/6;
1206 offset[0] = -4 * sin(rotation);
1207 offset[1] = 0;
1208 offset[2] = 4 * cos(rotation);
1209
1210 if ((ent->client->ps.gunframe == 6) || (ent->client->ps.gunframe == 9))
1211 effect = EF_HYPERBLASTER;
1212 else
1213 effect = 0;
1214 if (deathmatch->value)
1215 damage = 15;
1216 else
1217 damage = 20;
1218 Blaster_Fire (ent, offset, damage, true, effect);
1219 if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1220 ent->client->pers.inventory[ent->client->ammo_index]--;
1221
1222 ent->client->anim_priority = ANIM_ATTACK;
1223 if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
1224 {
1225 ent->s.frame = FRAME_crattak1 - 1;
1226 ent->client->anim_end = FRAME_crattak9;
1227 }
1228 else
1229 {
1230 ent->s.frame = FRAME_attack1 - 1;
1231 ent->client->anim_end = FRAME_attack8;
1232 }
1233 }
1234
1235 ent->client->ps.gunframe++;
1236 if (ent->client->ps.gunframe == 12 && ent->client->pers.inventory[ent->client->ammo_index])
1237 ent->client->ps.gunframe = 6;
1238 }
1239
1240 if (ent->client->ps.gunframe == 12)
1241 {
1242 gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/hyprbd1a.wav"), 1, ATTN_NORM, 0);
1243 ent->client->weapon_sound = 0;
1244 }
1245
1246 }
1247
Weapon_HyperBlaster(edict_t * ent)1248 void Weapon_HyperBlaster (edict_t *ent)
1249 {
1250 static int pause_frames[] = {0};
1251 static int fire_frames[] = {6, 7, 8, 9, 10, 11, 0};
1252
1253 Weapon_Generic (ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire);
1254 }
1255
1256 /*
1257 ======================================================================
1258
1259 MACHINEGUN / CHAINGUN
1260
1261 ======================================================================
1262 */
1263
Machinegun_Fire(edict_t * ent)1264 void Machinegun_Fire (edict_t *ent)
1265 {
1266 int i;
1267 vec3_t start;
1268 vec3_t forward, right;
1269 vec3_t angles;
1270 int damage = 8;
1271 int kick = 2;
1272 vec3_t offset;
1273
1274 if (!(ent->client->buttons & BUTTON_ATTACK))
1275 {
1276 ent->client->machinegun_shots = 0;
1277 ent->client->ps.gunframe++;
1278 return;
1279 }
1280
1281 if (ent->client->ps.gunframe == 5)
1282 ent->client->ps.gunframe = 4;
1283 else
1284 ent->client->ps.gunframe = 5;
1285
1286 if (ent->client->pers.inventory[ent->client->ammo_index] < 1)
1287 {
1288 ent->client->ps.gunframe = 6;
1289 if (level.time >= ent->pain_debounce_time)
1290 {
1291 gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
1292 ent->pain_debounce_time = level.time + 1;
1293 }
1294 NoAmmoWeaponChange (ent);
1295 return;
1296 }
1297
1298 if (is_quad)
1299 {
1300 //PGM
1301 // damage *= 4;
1302 damage *= damage_multiplier;
1303 // kick *= 4;
1304 kick *= damage_multiplier;
1305 //PGM
1306 }
1307
1308 for (i=1 ; i<3 ; i++)
1309 {
1310 ent->client->kick_origin[i] = crandom() * 0.35;
1311 ent->client->kick_angles[i] = crandom() * 0.7;
1312 }
1313 ent->client->kick_origin[0] = crandom() * 0.35;
1314 ent->client->kick_angles[0] = ent->client->machinegun_shots * -1.5;
1315
1316 // raise the gun as it is firing
1317 if (!deathmatch->value)
1318 {
1319 ent->client->machinegun_shots++;
1320 if (ent->client->machinegun_shots > 9)
1321 ent->client->machinegun_shots = 9;
1322 }
1323
1324 // get start / end positions
1325 VectorAdd (ent->client->v_angle, ent->client->kick_angles, angles);
1326 AngleVectors (angles, forward, right, NULL);
1327 VectorSet(offset, 0, 8, ent->viewheight-8);
1328 P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1329 fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_MACHINEGUN);
1330
1331 gi.WriteByte (svc_muzzleflash);
1332 gi.WriteShort (ent-g_edicts);
1333 gi.WriteByte (MZ_MACHINEGUN | is_silenced);
1334 gi.multicast (ent->s.origin, MULTICAST_PVS);
1335
1336 PlayerNoise(ent, start, PNOISE_WEAPON);
1337
1338 if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1339 ent->client->pers.inventory[ent->client->ammo_index]--;
1340
1341 ent->client->anim_priority = ANIM_ATTACK;
1342 if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
1343 {
1344 ent->s.frame = FRAME_crattak1 - (int) (random()+0.25);
1345 ent->client->anim_end = FRAME_crattak9;
1346 }
1347 else
1348 {
1349 ent->s.frame = FRAME_attack1 - (int) (random()+0.25);
1350 ent->client->anim_end = FRAME_attack8;
1351 }
1352 }
1353
Weapon_Machinegun(edict_t * ent)1354 void Weapon_Machinegun (edict_t *ent)
1355 {
1356 static int pause_frames[] = {23, 45, 0};
1357 static int fire_frames[] = {4, 5, 0};
1358
1359 Weapon_Generic (ent, 3, 5, 45, 49, pause_frames, fire_frames, Machinegun_Fire);
1360 }
1361
Chaingun_Fire(edict_t * ent)1362 void Chaingun_Fire (edict_t *ent)
1363 {
1364 int i;
1365 int shots;
1366 vec3_t start;
1367 vec3_t forward, right, up;
1368 float r, u;
1369 vec3_t offset;
1370 int damage;
1371 int kick = 2;
1372
1373 if (deathmatch->value)
1374 damage = 6;
1375 else
1376 damage = 8;
1377
1378 if (ent->client->ps.gunframe == 5)
1379 gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnu1a.wav"), 1, ATTN_IDLE, 0);
1380
1381 if ((ent->client->ps.gunframe == 14) && !(ent->client->buttons & BUTTON_ATTACK))
1382 {
1383 ent->client->ps.gunframe = 32;
1384 ent->client->weapon_sound = 0;
1385 return;
1386 }
1387 else if ((ent->client->ps.gunframe == 21) && (ent->client->buttons & BUTTON_ATTACK)
1388 && ent->client->pers.inventory[ent->client->ammo_index])
1389 {
1390 ent->client->ps.gunframe = 15;
1391 }
1392 else
1393 {
1394 ent->client->ps.gunframe++;
1395 }
1396
1397 if (ent->client->ps.gunframe == 22)
1398 {
1399 ent->client->weapon_sound = 0;
1400 gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnd1a.wav"), 1, ATTN_IDLE, 0);
1401 }
1402 else
1403 {
1404 ent->client->weapon_sound = gi.soundindex("weapons/chngnl1a.wav");
1405 }
1406
1407 ent->client->anim_priority = ANIM_ATTACK;
1408 if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
1409 {
1410 ent->s.frame = FRAME_crattak1 - (ent->client->ps.gunframe & 1);
1411 ent->client->anim_end = FRAME_crattak9;
1412 }
1413 else
1414 {
1415 ent->s.frame = FRAME_attack1 - (ent->client->ps.gunframe & 1);
1416 ent->client->anim_end = FRAME_attack8;
1417 }
1418
1419 if (ent->client->ps.gunframe <= 9)
1420 shots = 1;
1421 else if (ent->client->ps.gunframe <= 14)
1422 {
1423 if (ent->client->buttons & BUTTON_ATTACK)
1424 shots = 2;
1425 else
1426 shots = 1;
1427 }
1428 else
1429 shots = 3;
1430
1431 if (ent->client->pers.inventory[ent->client->ammo_index] < shots)
1432 shots = ent->client->pers.inventory[ent->client->ammo_index];
1433
1434 if (!shots)
1435 {
1436 if (level.time >= ent->pain_debounce_time)
1437 {
1438 gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
1439 ent->pain_debounce_time = level.time + 1;
1440 }
1441 NoAmmoWeaponChange (ent);
1442 return;
1443 }
1444
1445 if (is_quad)
1446 {
1447 //PGM
1448 // damage *= 4;
1449 damage *= damage_multiplier;
1450 // kick *= 4;
1451 kick *= damage_multiplier;
1452 //PGM
1453 }
1454
1455 for (i=0 ; i<3 ; i++)
1456 {
1457 ent->client->kick_origin[i] = crandom() * 0.35;
1458 ent->client->kick_angles[i] = crandom() * 0.7;
1459 }
1460
1461 for (i=0 ; i<shots ; i++)
1462 {
1463 // get start / end positions
1464 AngleVectors (ent->client->v_angle, forward, right, up);
1465 r = 7 + crandom()*4;
1466 u = crandom()*4;
1467 VectorSet(offset, 0, r, u + ent->viewheight-8);
1468 P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1469
1470 fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_CHAINGUN);
1471 }
1472
1473 // send muzzle flash
1474 gi.WriteByte (svc_muzzleflash);
1475 gi.WriteShort (ent-g_edicts);
1476 gi.WriteByte ((MZ_CHAINGUN1 + shots - 1) | is_silenced);
1477 gi.multicast (ent->s.origin, MULTICAST_PVS);
1478
1479 PlayerNoise(ent, start, PNOISE_WEAPON);
1480
1481 if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1482 ent->client->pers.inventory[ent->client->ammo_index] -= shots;
1483 }
1484
1485
Weapon_Chaingun(edict_t * ent)1486 void Weapon_Chaingun (edict_t *ent)
1487 {
1488 static int pause_frames[] = {38, 43, 51, 61, 0};
1489 static int fire_frames[] = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0};
1490
1491 Weapon_Generic (ent, 4, 31, 61, 64, pause_frames, fire_frames, Chaingun_Fire);
1492 }
1493
1494
1495 /*
1496 ======================================================================
1497
1498 SHOTGUN / SUPERSHOTGUN
1499
1500 ======================================================================
1501 */
1502
weapon_shotgun_fire(edict_t * ent)1503 void weapon_shotgun_fire (edict_t *ent)
1504 {
1505 vec3_t start;
1506 vec3_t forward, right;
1507 vec3_t offset;
1508 int damage = 4;
1509 int kick = 8;
1510
1511 if (ent->client->ps.gunframe == 9)
1512 {
1513 ent->client->ps.gunframe++;
1514 return;
1515 }
1516
1517 AngleVectors (ent->client->v_angle, forward, right, NULL);
1518
1519 VectorScale (forward, -2, ent->client->kick_origin);
1520 ent->client->kick_angles[0] = -2;
1521
1522 VectorSet(offset, 0, 8, ent->viewheight-8);
1523 P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1524
1525 if (is_quad)
1526 {
1527 //PGM
1528 // damage *= 4;
1529 damage *= damage_multiplier;
1530 // kick *= 4;
1531 kick *= damage_multiplier;
1532 //PGM
1533 }
1534
1535 if (deathmatch->value)
1536 fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_DEATHMATCH_SHOTGUN_COUNT, MOD_SHOTGUN);
1537 else
1538 fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_SHOTGUN_COUNT, MOD_SHOTGUN);
1539
1540 // send muzzle flash
1541 gi.WriteByte (svc_muzzleflash);
1542 gi.WriteShort (ent-g_edicts);
1543 gi.WriteByte (MZ_SHOTGUN | is_silenced);
1544 gi.multicast (ent->s.origin, MULTICAST_PVS);
1545
1546 ent->client->ps.gunframe++;
1547 PlayerNoise(ent, start, PNOISE_WEAPON);
1548
1549 if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1550 ent->client->pers.inventory[ent->client->ammo_index]--;
1551 }
1552
Weapon_Shotgun(edict_t * ent)1553 void Weapon_Shotgun (edict_t *ent)
1554 {
1555 static int pause_frames[] = {22, 28, 34, 0};
1556 static int fire_frames[] = {8, 9, 0};
1557
1558 Weapon_Generic (ent, 7, 18, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire);
1559 }
1560
1561
weapon_supershotgun_fire(edict_t * ent)1562 void weapon_supershotgun_fire (edict_t *ent)
1563 {
1564 vec3_t start;
1565 vec3_t forward, right;
1566 vec3_t offset;
1567 vec3_t v;
1568 int damage = 6;
1569 int kick = 12;
1570
1571 AngleVectors (ent->client->v_angle, forward, right, NULL);
1572
1573 VectorScale (forward, -2, ent->client->kick_origin);
1574 ent->client->kick_angles[0] = -2;
1575
1576 VectorSet(offset, 0, 8, ent->viewheight-8);
1577 P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1578
1579 if (is_quad)
1580 {
1581 //PGM
1582 // damage *= 4;
1583 damage *= damage_multiplier;
1584 // kick *= 4;
1585 kick *= damage_multiplier;
1586 //PGM
1587 }
1588
1589 v[PITCH] = ent->client->v_angle[PITCH];
1590 v[YAW] = ent->client->v_angle[YAW] - 5;
1591 v[ROLL] = ent->client->v_angle[ROLL];
1592 AngleVectors (v, forward, NULL, NULL);
1593 fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
1594 v[YAW] = ent->client->v_angle[YAW] + 5;
1595 AngleVectors (v, forward, NULL, NULL);
1596 fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
1597
1598 // send muzzle flash
1599 gi.WriteByte (svc_muzzleflash);
1600 gi.WriteShort (ent-g_edicts);
1601 gi.WriteByte (MZ_SSHOTGUN | is_silenced);
1602 gi.multicast (ent->s.origin, MULTICAST_PVS);
1603
1604 ent->client->ps.gunframe++;
1605 PlayerNoise(ent, start, PNOISE_WEAPON);
1606
1607 if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1608 ent->client->pers.inventory[ent->client->ammo_index] -= 2;
1609 }
1610
Weapon_SuperShotgun(edict_t * ent)1611 void Weapon_SuperShotgun (edict_t *ent)
1612 {
1613 static int pause_frames[] = {29, 42, 57, 0};
1614 static int fire_frames[] = {7, 0};
1615
1616 Weapon_Generic (ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire);
1617 }
1618
1619
1620
1621 /*
1622 ======================================================================
1623
1624 RAILGUN
1625
1626 ======================================================================
1627 */
1628
weapon_railgun_fire(edict_t * ent)1629 void weapon_railgun_fire (edict_t *ent)
1630 {
1631 vec3_t start;
1632 vec3_t forward, right;
1633 vec3_t offset;
1634 int damage;
1635 int kick;
1636
1637 if (deathmatch->value)
1638 { // normal damage is too extreme in dm
1639 damage = 100;
1640 kick = 200;
1641 }
1642 else
1643 {
1644 damage = 150;
1645 kick = 250;
1646 }
1647
1648 if (is_quad)
1649 {
1650 //PGM
1651 // damage *= 4;
1652 damage *= damage_multiplier;
1653 // kick *= 4;
1654 kick *= damage_multiplier;
1655 //PGM
1656 }
1657
1658 AngleVectors (ent->client->v_angle, forward, right, NULL);
1659
1660 VectorScale (forward, -3, ent->client->kick_origin);
1661 ent->client->kick_angles[0] = -3;
1662
1663 VectorSet(offset, 0, 7, ent->viewheight-8);
1664 P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1665 fire_rail (ent, start, forward, damage, kick);
1666
1667 // send muzzle flash
1668 gi.WriteByte (svc_muzzleflash);
1669 gi.WriteShort (ent-g_edicts);
1670 gi.WriteByte (MZ_RAILGUN | is_silenced);
1671 gi.multicast (ent->s.origin, MULTICAST_PVS);
1672
1673 ent->client->ps.gunframe++;
1674 PlayerNoise(ent, start, PNOISE_WEAPON);
1675
1676 if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1677 ent->client->pers.inventory[ent->client->ammo_index]--;
1678 }
1679
1680
Weapon_Railgun(edict_t * ent)1681 void Weapon_Railgun (edict_t *ent)
1682 {
1683 static int pause_frames[] = {56, 0};
1684 static int fire_frames[] = {4, 0};
1685
1686 Weapon_Generic (ent, 3, 18, 56, 61, pause_frames, fire_frames, weapon_railgun_fire);
1687 }
1688
1689
1690 /*
1691 ======================================================================
1692
1693 BFG10K
1694
1695 ======================================================================
1696 */
1697
weapon_bfg_fire(edict_t * ent)1698 void weapon_bfg_fire (edict_t *ent)
1699 {
1700 vec3_t offset, start;
1701 vec3_t forward, right;
1702 int damage;
1703 float damage_radius = 1000;
1704
1705 if (deathmatch->value)
1706 damage = 200;
1707 else
1708 damage = 500;
1709
1710 if (ent->client->ps.gunframe == 9)
1711 {
1712 // send muzzle flash
1713 gi.WriteByte (svc_muzzleflash);
1714 gi.WriteShort (ent-g_edicts);
1715 gi.WriteByte (MZ_BFG | is_silenced);
1716 gi.multicast (ent->s.origin, MULTICAST_PVS);
1717
1718 ent->client->ps.gunframe++;
1719
1720 PlayerNoise(ent, start, PNOISE_WEAPON);
1721 return;
1722 }
1723
1724 // cells can go down during windup (from power armor hits), so
1725 // check again and abort firing if we don't have enough now
1726 if (ent->client->pers.inventory[ent->client->ammo_index] < 50)
1727 {
1728 ent->client->ps.gunframe++;
1729 return;
1730 }
1731
1732 if (is_quad)
1733 //PGM
1734 // damage *= 4;
1735 damage *= damage_multiplier;
1736 //PGM
1737
1738 AngleVectors (ent->client->v_angle, forward, right, NULL);
1739
1740 VectorScale (forward, -2, ent->client->kick_origin);
1741
1742 // make a big pitch kick with an inverse fall
1743 ent->client->v_dmg_pitch = -40;
1744 ent->client->v_dmg_roll = crandom()*8;
1745 ent->client->v_dmg_time = level.time + DAMAGE_TIME;
1746
1747 VectorSet(offset, 8, 8, ent->viewheight-8);
1748 P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1749 fire_bfg (ent, start, forward, damage, 400, damage_radius);
1750
1751 ent->client->ps.gunframe++;
1752
1753 PlayerNoise(ent, start, PNOISE_WEAPON);
1754
1755 if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1756 ent->client->pers.inventory[ent->client->ammo_index] -= 50;
1757 }
1758
Weapon_BFG(edict_t * ent)1759 void Weapon_BFG (edict_t *ent)
1760 {
1761 static int pause_frames[] = {39, 45, 50, 55, 0};
1762 static int fire_frames[] = {9, 17, 0};
1763
1764 Weapon_Generic (ent, 8, 32, 55, 58, pause_frames, fire_frames, weapon_bfg_fire);
1765 }
1766
1767
1768 //======================================================================
1769 // ROGUE MODS BELOW
1770 //======================================================================
1771
1772
1773 //
1774 // CHAINFIST
1775 //
1776 #define CHAINFIST_REACH 64
1777
weapon_chainfist_fire(edict_t * ent)1778 void weapon_chainfist_fire (edict_t *ent)
1779 {
1780 vec3_t offset;
1781 vec3_t forward, right, up;
1782 vec3_t start;
1783 int damage;
1784
1785 damage = 15;
1786 if(deathmatch->value)
1787 damage = 30;
1788
1789 if (is_quad)
1790 damage *= damage_multiplier;
1791
1792 AngleVectors (ent->client->v_angle, forward, right, up);
1793
1794 // kick back
1795 VectorScale (forward, -2, ent->client->kick_origin);
1796 ent->client->kick_angles[0] = -1;
1797
1798 // set start point
1799 VectorSet(offset, 0, 8, ent->viewheight-4);
1800 P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1801
1802 fire_player_melee (ent, start, forward, CHAINFIST_REACH, damage, 100, 1, MOD_CHAINFIST);
1803
1804 PlayerNoise(ent, start, PNOISE_WEAPON);
1805
1806 ent->client->ps.gunframe++;
1807 ent->client->pers.inventory[ent->client->ammo_index] -= ent->client->pers.weapon->quantity;
1808 }
1809
1810 // this spits out some smoke from the motor. it's a two-stroke, you know.
chainfist_smoke(edict_t * ent)1811 void chainfist_smoke (edict_t *ent)
1812 {
1813 vec3_t tempVec, forward, right, up;
1814 vec3_t offset;
1815
1816 AngleVectors(ent->client->v_angle, forward, right, up);
1817 VectorSet(offset, 8, 8, ent->viewheight -4);
1818 P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, tempVec);
1819
1820 gi.WriteByte (svc_temp_entity);
1821 gi.WriteByte (TE_CHAINFIST_SMOKE);
1822 gi.WritePosition (tempVec);
1823 gi.unicast (ent, 0);
1824 // gi.multicast (tempVec, MULTICAST_PVS);
1825 }
1826
1827 #define HOLD_FRAMES 0
1828
Weapon_ChainFist(edict_t * ent)1829 void Weapon_ChainFist (edict_t *ent)
1830 {
1831 static int pause_frames[] = {0};
1832 static int fire_frames[] = {8, 9, 16, 17, 18, 30, 31, 0};
1833
1834 // these are caches for the sound index. there's probably a better way to do this.
1835 // static int idle_index;
1836 // static int attack_index;
1837 float chance;
1838 int last_sequence;
1839
1840 last_sequence = 0;
1841
1842 // load chainsaw sounds and store the indexes for later use.
1843 // if(!idle_index && !attack_index)
1844 // {
1845 // idle_index = gi.soundindex("weapons/sawidle.wav");
1846 // attack_index = gi.soundindex("weapons/sawhit.wav");
1847 // }
1848
1849 if(ent->client->ps.gunframe == 13 ||
1850 ent->client->ps.gunframe == 23) // end of attack, go idle
1851 ent->client->ps.gunframe = 32;
1852
1853 #if HOLD_FRAMES
1854 else if(ent->client->ps.gunframe == 9 && ((ent->client->buttons) & BUTTON_ATTACK))
1855 ent->client->ps.gunframe = 7;
1856 else if(ent->client->ps.gunframe == 18 && ((ent->client->buttons) & BUTTON_ATTACK))
1857 ent->client->ps.gunframe = 16;
1858 #endif
1859
1860 // holds for idle sequence
1861 else if(ent->client->ps.gunframe == 42 && (rand()&7))
1862 {
1863 if((ent->client->pers.hand != CENTER_HANDED) && random() < 0.4)
1864 chainfist_smoke(ent);
1865 // ent->client->ps.gunframe = 40;
1866 }
1867 else if(ent->client->ps.gunframe == 51 && (rand()&7))
1868 {
1869 if((ent->client->pers.hand != CENTER_HANDED) && random() < 0.4)
1870 chainfist_smoke(ent);
1871 // ent->client->ps.gunframe = 49;
1872 }
1873
1874 // set the appropriate weapon sound.
1875 if(ent->client->weaponstate == WEAPON_FIRING)
1876 // ent->client->weapon_sound = attack_index;
1877 ent->client->weapon_sound = gi.soundindex("weapons/sawhit.wav");
1878 else if(ent->client->weaponstate == WEAPON_DROPPING)
1879 ent->client->weapon_sound = 0;
1880 else
1881 // ent->client->weapon_sound = idle_index;
1882 ent->client->weapon_sound = gi.soundindex("weapons/sawidle.wav");
1883
1884 Weapon_Generic (ent, 4, 32, 57, 60, pause_frames, fire_frames, weapon_chainfist_fire);
1885
1886 // gi.dprintf("chainfist %d\n", ent->client->ps.gunframe);
1887 if((ent->client->buttons) & BUTTON_ATTACK)
1888 {
1889 if(ent->client->ps.gunframe == 13 ||
1890 ent->client->ps.gunframe == 23 ||
1891 ent->client->ps.gunframe == 32)
1892 {
1893 last_sequence = ent->client->ps.gunframe;
1894 ent->client->ps.gunframe = 6;
1895 }
1896 }
1897
1898 if (ent->client->ps.gunframe == 6)
1899 {
1900 chance = random();
1901 if(last_sequence == 13) // if we just did sequence 1, do 2 or 3.
1902 chance -= 0.34;
1903 else if(last_sequence == 23) // if we just did sequence 2, do 1 or 3
1904 chance += 0.33;
1905 else if(last_sequence == 32) // if we just did sequence 3, do 1 or 2
1906 {
1907 if(chance >= 0.33)
1908 chance += 0.34;
1909 }
1910
1911 if(chance < 0.33)
1912 ent->client->ps.gunframe = 14;
1913 else if(chance < 0.66)
1914 ent->client->ps.gunframe = 24;
1915 }
1916
1917 }
1918
1919 //
1920 // Disintegrator
1921 //
1922
weapon_tracker_fire(edict_t * self)1923 void weapon_tracker_fire (edict_t *self)
1924 {
1925 vec3_t forward, right;
1926 vec3_t start;
1927 vec3_t end;
1928 vec3_t offset;
1929 edict_t *enemy;
1930 trace_t tr;
1931 int damage;
1932 vec3_t mins, maxs;
1933
1934 // PMM - felt a little high at 25
1935 if(deathmatch->value)
1936 damage = 30;
1937 else
1938 damage = 45;
1939
1940 if (is_quad)
1941 damage *= damage_multiplier; //pgm
1942
1943 VectorSet(mins, -16, -16, -16);
1944 VectorSet(maxs, 16, 16, 16);
1945 AngleVectors (self->client->v_angle, forward, right, NULL);
1946 VectorSet(offset, 24, 8, self->viewheight-8);
1947 P_ProjectSource (self->client, self->s.origin, offset, forward, right, start);
1948
1949 // FIXME - can we shorten this? do we need to?
1950 VectorMA (start, 8192, forward, end);
1951 enemy = NULL;
1952 //PMM - doing two traces .. one point and one box.
1953 tr = gi.trace (start, vec3_origin, vec3_origin, end, self, MASK_SHOT);
1954 if(tr.ent != world)
1955 {
1956 if(tr.ent->svflags & SVF_MONSTER || tr.ent->client || tr.ent->svflags & SVF_DAMAGEABLE)
1957 {
1958 if(tr.ent->health > 0)
1959 enemy = tr.ent;
1960 }
1961 }
1962 else
1963 {
1964 tr = gi.trace (start, mins, maxs, end, self, MASK_SHOT);
1965 if(tr.ent != world)
1966 {
1967 if(tr.ent->svflags & SVF_MONSTER || tr.ent->client || tr.ent->svflags & SVF_DAMAGEABLE)
1968 {
1969 if(tr.ent->health > 0)
1970 enemy = tr.ent;
1971 }
1972 }
1973 }
1974
1975 VectorScale (forward, -2, self->client->kick_origin);
1976 self->client->kick_angles[0] = -1;
1977
1978 fire_tracker (self, start, forward, damage, 1000, enemy);
1979
1980 // send muzzle flash
1981 gi.WriteByte (svc_muzzleflash);
1982 gi.WriteShort (self-g_edicts);
1983 gi.WriteByte (MZ_TRACKER);
1984 gi.multicast (self->s.origin, MULTICAST_PVS);
1985
1986 PlayerNoise(self, start, PNOISE_WEAPON);
1987
1988 self->client->ps.gunframe++;
1989 self->client->pers.inventory[self->client->ammo_index] -= self->client->pers.weapon->quantity;
1990 }
1991
Weapon_Disintegrator(edict_t * ent)1992 void Weapon_Disintegrator (edict_t *ent)
1993 {
1994 static int pause_frames[] = {14, 19, 23, 0};
1995 // static int fire_frames[] = {7, 0};
1996 static int fire_frames[] = {5, 0};
1997
1998 Weapon_Generic (ent, 4, 9, 29, 34, pause_frames, fire_frames, weapon_tracker_fire);
1999 }
2000
2001 /*
2002 ======================================================================
2003
2004 ETF RIFLE
2005
2006 ======================================================================
2007 */
weapon_etf_rifle_fire(edict_t * ent)2008 void weapon_etf_rifle_fire (edict_t *ent)
2009 {
2010 vec3_t forward, right, up;
2011 vec3_t start, tempPt;
2012 int damage;
2013 int kick = 3;
2014 int i;
2015 vec3_t angles;
2016 vec3_t offset;
2017
2018 if(deathmatch->value)
2019 damage = 10;
2020 else
2021 damage = 10;
2022
2023 // PGM - adjusted to use the quantity entry in the weapon structure.
2024 if(ent->client->pers.inventory[ent->client->ammo_index] < ent->client->pers.weapon->quantity)
2025 {
2026 VectorClear (ent->client->kick_origin);
2027 VectorClear (ent->client->kick_angles);
2028 ent->client->ps.gunframe = 8;
2029
2030 if (level.time >= ent->pain_debounce_time)
2031 {
2032 gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
2033 ent->pain_debounce_time = level.time + 1;
2034 }
2035 NoAmmoWeaponChange (ent);
2036 return;
2037 }
2038
2039 if (is_quad)
2040 {
2041 damage *= damage_multiplier;
2042 kick *= damage_multiplier;
2043 }
2044
2045 for(i=0;i<3;i++)
2046 {
2047 ent->client->kick_origin[i] = crandom() * 0.85;
2048 ent->client->kick_angles[i] = crandom() * 0.85;
2049 }
2050
2051 // get start / end positions
2052 VectorAdd (ent->client->v_angle, ent->client->kick_angles, angles);
2053 // AngleVectors (angles, forward, right, NULL);
2054 // gi.dprintf("v_angle: %s\n", vtos(ent->client->v_angle));
2055 AngleVectors (ent->client->v_angle, forward, right, up);
2056
2057 // FIXME - set correct frames for different offsets.
2058
2059 if(ent->client->ps.gunframe == 6) // right barrel
2060 {
2061 // gi.dprintf("right\n");
2062 VectorSet(offset, 15, 8, -8);
2063 }
2064 else // left barrel
2065 {
2066 // gi.dprintf("left\n");
2067 VectorSet(offset, 15, 6, -8);
2068 }
2069
2070 VectorCopy (ent->s.origin, tempPt);
2071 tempPt[2] += ent->viewheight;
2072 P_ProjectSource2 (ent->client, tempPt, offset, forward, right, up, start);
2073 // gi.dprintf("start: %s\n", vtos(start));
2074 fire_flechette (ent, start, forward, damage, 750, kick);
2075
2076 // send muzzle flash
2077 gi.WriteByte (svc_muzzleflash);
2078 gi.WriteShort (ent-g_edicts);
2079 gi.WriteByte (MZ_ETF_RIFLE);
2080 gi.multicast (ent->s.origin, MULTICAST_PVS);
2081
2082 PlayerNoise(ent, start, PNOISE_WEAPON);
2083
2084 ent->client->ps.gunframe++;
2085 ent->client->pers.inventory[ent->client->ammo_index] -= ent->client->pers.weapon->quantity;
2086
2087 ent->client->anim_priority = ANIM_ATTACK;
2088 if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
2089 {
2090 ent->s.frame = FRAME_crattak1 - 1;
2091 ent->client->anim_end = FRAME_crattak9;
2092 }
2093 else
2094 {
2095 ent->s.frame = FRAME_attack1 - 1;
2096 ent->client->anim_end = FRAME_attack8;
2097 }
2098
2099 }
2100
Weapon_ETF_Rifle(edict_t * ent)2101 void Weapon_ETF_Rifle (edict_t *ent)
2102 {
2103 static int pause_frames[] = {18, 28, 0};
2104 static int fire_frames[] = {6, 7, 0};
2105 // static int idle_seq;
2106
2107 // note - if you change the fire frame number, fix the offset in weapon_etf_rifle_fire.
2108
2109 // if (!(ent->client->buttons & BUTTON_ATTACK))
2110 // ent->client->machinegun_shots = 0;
2111
2112 if (ent->client->weaponstate == WEAPON_FIRING)
2113 {
2114 if (ent->client->pers.inventory[ent->client->ammo_index] <= 0)
2115 ent->client->ps.gunframe = 8;
2116 }
2117
2118 Weapon_Generic (ent, 4, 7, 37, 41, pause_frames, fire_frames, weapon_etf_rifle_fire);
2119
2120 if(ent->client->ps.gunframe == 8 && (ent->client->buttons & BUTTON_ATTACK))
2121 ent->client->ps.gunframe = 6;
2122
2123 // gi.dprintf("etf rifle %d\n", ent->client->ps.gunframe);
2124 }
2125
2126 // pgm - this now uses ent->client->pers.weapon->quantity like all the other weapons
2127 //#define HEATBEAM_AMMO_USE 2
2128 #define HEATBEAM_DM_DMG 15
2129 #define HEATBEAM_SP_DMG 15
2130
Heatbeam_Fire(edict_t * ent)2131 void Heatbeam_Fire (edict_t *ent)
2132 {
2133 vec3_t start;
2134 vec3_t forward, right, up;
2135 vec3_t offset;
2136 int damage;
2137 int kick;
2138
2139 // for comparison, the hyperblaster is 15/20
2140 // jim requested more damage, so try 15/15 --- PGM 07/23/98
2141 if (deathmatch->value)
2142 damage = HEATBEAM_DM_DMG;
2143 else
2144 damage = HEATBEAM_SP_DMG;
2145
2146 if (deathmatch->value) // really knock 'em around in deathmatch
2147 kick = 75;
2148 else
2149 kick = 30;
2150
2151 // if(ent->client->pers.inventory[ent->client->ammo_index] < HEATBEAM_AMMO_USE)
2152 // {
2153 // NoAmmoWeaponChange (ent);
2154 // return;
2155 // }
2156
2157 ent->client->ps.gunframe++;
2158 ent->client->ps.gunindex = gi.modelindex ("models/weapons/v_beamer2/tris.md2");
2159
2160 if (is_quad)
2161 {
2162 damage *= damage_multiplier;
2163 kick *= damage_multiplier;
2164 }
2165
2166 VectorClear (ent->client->kick_origin);
2167 VectorClear (ent->client->kick_angles);
2168
2169 // get start / end positions
2170 AngleVectors (ent->client->v_angle, forward, right, up);
2171
2172 // This offset is the "view" offset for the beam start (used by trace)
2173
2174 VectorSet(offset, 7, 2, ent->viewheight-3);
2175 P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
2176
2177 // This offset is the entity offset
2178 VectorSet(offset, 2, 7, -3);
2179
2180 fire_heat (ent, start, forward, offset, damage, kick, false);
2181
2182 // send muzzle flash
2183 gi.WriteByte (svc_muzzleflash);
2184 gi.WriteShort (ent-g_edicts);
2185 gi.WriteByte (MZ_HEATBEAM | is_silenced);
2186 gi.multicast (ent->s.origin, MULTICAST_PVS);
2187
2188 PlayerNoise(ent, start, PNOISE_WEAPON);
2189
2190 if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
2191 ent->client->pers.inventory[ent->client->ammo_index] -= ent->client->pers.weapon->quantity;
2192
2193 ent->client->anim_priority = ANIM_ATTACK;
2194 if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
2195 {
2196 ent->s.frame = FRAME_crattak1 - 1;
2197 ent->client->anim_end = FRAME_crattak9;
2198 }
2199 else
2200 {
2201 ent->s.frame = FRAME_attack1 - 1;
2202 ent->client->anim_end = FRAME_attack8;
2203 }
2204
2205 }
2206
Weapon_Heatbeam(edict_t * ent)2207 void Weapon_Heatbeam (edict_t *ent)
2208 {
2209 // static int pause_frames[] = {38, 43, 51, 61, 0};
2210 // static int fire_frames[] = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0};
2211 static int pause_frames[] = {35, 0};
2212 // static int fire_frames[] = {9, 0};
2213 static int fire_frames[] = {9, 10, 11, 12, 0};
2214 // static int attack_index;
2215 // static int off_model, on_model;
2216
2217 // if ((g_showlogic) && (g_showlogic->value)) {
2218 // gi.dprintf ("Frame %d, skin %d\n", ent->client->ps.gunframe, ent->client->ps.gunskin);
2219 // }
2220
2221 // if (!attack_index)
2222 // {
2223 // attack_index = gi.soundindex ("weapons/bfg__l1a.wav");
2224 // off_model = gi.modelindex ("models/weapons/v_beamer/tris.md2");
2225 // on_model = gi.modelindex ("models/weapons/v_beamer2/tris.md2");
2226 //ent->client->ps.gunindex = gi.modelindex(ent->client->pers.weapon->view_model);
2227 // }
2228
2229 if (ent->client->weaponstate == WEAPON_FIRING)
2230 {
2231 // ent->client->weapon_sound = attack_index;
2232 ent->client->weapon_sound = gi.soundindex ("weapons/bfg__l1a.wav");
2233 if ((ent->client->pers.inventory[ent->client->ammo_index] >= 2) && ((ent->client->buttons) & BUTTON_ATTACK))
2234 {
2235 // if(ent->client->ps.gunframe >= 9 && ((ent->client->buttons) & BUTTON_ATTACK))
2236 // if(ent->client->ps.gunframe >= 12 && ((ent->client->buttons) & BUTTON_ATTACK))
2237 if(ent->client->ps.gunframe >= 13)
2238 {
2239 ent->client->ps.gunframe = 9;
2240 // ent->client->ps.gunframe = 8;
2241 // ent->client->ps.gunskin = 0;
2242 // ent->client->ps.gunindex = on_model;
2243 ent->client->ps.gunindex = gi.modelindex ("models/weapons/v_beamer2/tris.md2");
2244 }
2245 else
2246 {
2247 // ent->client->ps.gunskin = 1;
2248 // ent->client->ps.gunindex = on_model;
2249 ent->client->ps.gunindex = gi.modelindex ("models/weapons/v_beamer2/tris.md2");
2250 }
2251 }
2252 else
2253 {
2254 // ent->client->ps.gunframe = 10;
2255 ent->client->ps.gunframe = 13;
2256 // ent->client->ps.gunskin = 1;
2257 // ent->client->ps.gunindex = off_model;
2258 ent->client->ps.gunindex = gi.modelindex ("models/weapons/v_beamer/tris.md2");
2259 }
2260 }
2261 else
2262 {
2263 // ent->client->ps.gunskin = 1;
2264 // ent->client->ps.gunindex = off_model;
2265 ent->client->ps.gunindex = gi.modelindex ("models/weapons/v_beamer/tris.md2");
2266 ent->client->weapon_sound = 0;
2267 }
2268
2269 // Weapon_Generic (ent, 8, 9, 39, 44, pause_frames, fire_frames, Heatbeam_Fire);
2270 Weapon_Generic (ent, 8, 12, 39, 44, pause_frames, fire_frames, Heatbeam_Fire);
2271 }
2272