1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 2010-2019 EDuke32 developers and contributors
4 Copyright (C) 2019 Nuke.YKT
5 
6 This file is part of NBlood.
7 
8 NBlood is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License version 2
10 as published by the Free Software Foundation.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 
16 See the GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 */
22 //-------------------------------------------------------------------------
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include "compat.h"
27 #include "build.h"
28 #include "mmulti.h"
29 #include "common_game.h"
30 #include "actor.h"
31 #include "blood.h"
32 #include "db.h"
33 #include "callback.h"
34 #include "config.h"
35 #include "eventq.h"
36 #include "fx.h"
37 #include "gameutil.h"
38 #include "globals.h"
39 #include "levels.h"
40 #include "loadsave.h"
41 #include "player.h"
42 #include "qav.h"
43 #include "resource.h"
44 #include "seq.h"
45 #include "sfx.h"
46 #include "sound.h"
47 #include "trig.h"
48 #ifdef NOONE_EXTENSIONS
49 #include "nnexts.h"
50 #endif
51 #include "view.h"
52 
53 #define kQAVEnd 125
54 
55 void FirePitchfork(int, PLAYER *pPlayer);
56 void FireSpray(int, PLAYER *pPlayer);
57 void ThrowCan(int, PLAYER *pPlayer);
58 void DropCan(int, PLAYER *pPlayer);
59 void ExplodeCan(int, PLAYER *pPlayer);
60 void ThrowBundle(int, PLAYER *pPlayer);
61 void DropBundle(int, PLAYER *pPlayer);
62 void ExplodeBundle(int, PLAYER *pPlayer);
63 void ThrowProx(int, PLAYER *pPlayer);
64 void DropProx(int, PLAYER *pPlayer);
65 void ThrowRemote(int, PLAYER *pPlayer);
66 void DropRemote(int, PLAYER *pPlayer);
67 void FireRemote(int, PLAYER *pPlayer);
68 void FireShotgun(int nTrigger, PLAYER *pPlayer);
69 void EjectShell(int, PLAYER *pPlayer);
70 void FireTommy(int nTrigger, PLAYER *pPlayer);
71 void FireSpread(int nTrigger, PLAYER *pPlayer);
72 void AltFireSpread(int nTrigger, PLAYER *pPlayer);
73 void AltFireSpread2(int nTrigger, PLAYER *pPlayer);
74 void FireFlare(int nTrigger, PLAYER *pPlayer);
75 void AltFireFlare(int nTrigger, PLAYER *pPlayer);
76 void FireVoodoo(int nTrigger, PLAYER *pPlayer);
77 void AltFireVoodoo(int nTrigger, PLAYER *pPlayer);
78 void DropVoodoo(int nTrigger, PLAYER *pPlayer);
79 void FireTesla(int nTrigger, PLAYER *pPlayer);
80 void AltFireTesla(int nTrigger, PLAYER *pPlayer);
81 void FireNapalm(int nTrigger, PLAYER *pPlayer);
82 void FireNapalm2(int nTrigger, PLAYER *pPlayer);
83 void AltFireNapalm(int nTrigger, PLAYER *pPlayer);
84 void FireLifeLeech(int nTrigger, PLAYER *pPlayer);
85 void AltFireLifeLeech(int nTrigger, PLAYER *pPlayer);
86 void FireBeast(int nTrigger, PLAYER * pPlayer);
87 
88 typedef void(*QAVTypeCast)(int, void *);
89 
90 int nClientFirePitchfork = qavRegisterClient((QAVTypeCast)FirePitchfork);
91 int nClientFireSpray = qavRegisterClient((QAVTypeCast)FireSpray);
92 int nClientThrowCan = qavRegisterClient((QAVTypeCast)ThrowCan);
93 int nClientDropCan = qavRegisterClient((QAVTypeCast)DropCan);
94 int nClientExplodeCan = qavRegisterClient((QAVTypeCast)ExplodeCan);
95 int nClientThrowBundle = qavRegisterClient((QAVTypeCast)ThrowBundle);
96 int nClientDropBundle = qavRegisterClient((QAVTypeCast)DropBundle);
97 int nClientExplodeBundle = qavRegisterClient((QAVTypeCast)ExplodeBundle);
98 int nClientThrowProx = qavRegisterClient((QAVTypeCast)ThrowProx);
99 int nClientDropProx = qavRegisterClient((QAVTypeCast)DropProx);
100 int nClientThrowRemote = qavRegisterClient((QAVTypeCast)ThrowRemote);
101 int nClientDropRemote = qavRegisterClient((QAVTypeCast)DropRemote);
102 int nClientFireRemote = qavRegisterClient((QAVTypeCast)FireRemote);
103 int nClientFireShotgun = qavRegisterClient((QAVTypeCast)FireShotgun);
104 int nClientEjectShell = qavRegisterClient((QAVTypeCast)EjectShell);
105 int nClientFireTommy = qavRegisterClient((QAVTypeCast)FireTommy);
106 int nClientAltFireSpread2 = qavRegisterClient((QAVTypeCast)AltFireSpread2);
107 int nClientFireSpread = qavRegisterClient((QAVTypeCast)FireSpread);
108 int nClientAltFireSpread = qavRegisterClient((QAVTypeCast)AltFireSpread);
109 int nClientFireFlare = qavRegisterClient((QAVTypeCast)FireFlare);
110 int nClientAltFireFlare = qavRegisterClient((QAVTypeCast)AltFireFlare);
111 int nClientFireVoodoo = qavRegisterClient((QAVTypeCast)FireVoodoo);
112 int nClientAltFireVoodoo = qavRegisterClient((QAVTypeCast)AltFireVoodoo);
113 int nClientFireTesla = qavRegisterClient((QAVTypeCast)FireTesla);
114 int nClientAltFireTesla = qavRegisterClient((QAVTypeCast)AltFireTesla);
115 int nClientFireNapalm = qavRegisterClient((QAVTypeCast)FireNapalm);
116 int nClientFireNapalm2 = qavRegisterClient((QAVTypeCast)FireNapalm2);
117 int nClientFireLifeLeech = qavRegisterClient((QAVTypeCast)FireLifeLeech);
118 int nClientFireBeast = qavRegisterClient((QAVTypeCast)FireBeast);
119 int nClientAltFireLifeLeech = qavRegisterClient((QAVTypeCast)AltFireLifeLeech);
120 int nClientDropVoodoo = qavRegisterClient((QAVTypeCast)DropVoodoo);
121 int nClientAltFireNapalm = qavRegisterClient((QAVTypeCast)AltFireNapalm);
122 
123 QAV *weaponQAV[kQAVEnd];
124 
PlaySound(int nSound)125 void QAV::PlaySound(int nSound)
126 {
127     sndStartSample(nSound, -1, -1, 0);
128 }
129 
PlaySound3D(spritetype * pSprite,int nSound,int a3,int a4)130 void QAV::PlaySound3D(spritetype *pSprite, int nSound, int a3, int a4)
131 {
132     sfxPlay3DSound(pSprite, nSound, a3, a4);
133 }
134 
sub_4B1A4(PLAYER * pPlayer)135 char sub_4B1A4(PLAYER *pPlayer)
136 {
137     switch (pPlayer->curWeapon)
138     {
139     case 7:
140         switch (pPlayer->weaponState)
141         {
142         case 5:
143         case 6:
144             return 1;
145         }
146         break;
147     case 6:
148         switch (pPlayer->weaponState)
149         {
150         case 4:
151         case 5:
152         case 6:
153             return 1;
154         }
155         break;
156     }
157     return 0;
158 }
159 
BannedUnderwater(int nWeapon)160 char BannedUnderwater(int nWeapon)
161 {
162     return nWeapon == 7 || nWeapon == 6;
163 }
164 
sub_4B1FC(PLAYER * pPlayer,int a2,int a3,int a4)165 char sub_4B1FC(PLAYER *pPlayer, int a2, int a3, int a4)
166 {
167     if (gInfiniteAmmo)
168         return 1;
169     if (a3 == -1)
170         return 1;
171     if (a2 == 12 && pPlayer->weaponAmmo == 11 && pPlayer->weaponState == 11)
172         return 1;
173     if (a2 == 9 && pPlayer->pXSprite->health > 0)
174         return 1;
175     return pPlayer->ammoCount[a3] >= a4;
176 }
177 
CheckAmmo(PLAYER * pPlayer,int a2,int a3)178 char CheckAmmo(PLAYER *pPlayer, int a2, int a3)
179 {
180     if (gInfiniteAmmo)
181         return 1;
182     if (a2 == -1)
183         return 1;
184     if (pPlayer->curWeapon == 12 && pPlayer->weaponAmmo == 11 && pPlayer->weaponState == 11)
185         return 1;
186     if (pPlayer->curWeapon == 9 && pPlayer->pXSprite->health >= (a3<<4))
187         return 1;
188     return pPlayer->ammoCount[a2] >= a3;
189 }
190 
sub_4B2C8(PLAYER * pPlayer,int a2,int a3)191 char sub_4B2C8(PLAYER *pPlayer, int a2, int a3)
192 {
193     if (gInfiniteAmmo)
194         return 1;
195     if (a2 == -1)
196         return 1;
197     return pPlayer->ammoCount[a2] >= a3;
198 }
199 
SpawnBulletEject(PLAYER * pPlayer,int a2,int a3)200 void SpawnBulletEject(PLAYER *pPlayer, int a2, int a3)
201 {
202     POSTURE *pPosture = &pPlayer->pPosture[pPlayer->lifeMode][pPlayer->posture];
203     pPlayer->zView = pPlayer->pSprite->z-pPosture->eyeAboveZ;
204     int dz = pPlayer->zWeapon-(pPlayer->zWeapon-pPlayer->zView)/2;
205     fxSpawnEjectingBrass(pPlayer->pSprite, dz, a2, a3);
206 }
207 
SpawnShellEject(PLAYER * pPlayer,int a2,int a3)208 void SpawnShellEject(PLAYER *pPlayer, int a2, int a3)
209 {
210     POSTURE *pPosture = &pPlayer->pPosture[pPlayer->lifeMode][pPlayer->posture];
211     pPlayer->zView = pPlayer->pSprite->z-pPosture->eyeAboveZ;
212     int t = pPlayer->zWeapon - pPlayer->zView;
213     int dz = pPlayer->zWeapon-t+(t>>2);
214     fxSpawnEjectingShell(pPlayer->pSprite, dz, a2, a3);
215 }
216 
WeaponInit(void)217 void WeaponInit(void)
218 {
219     for (int i = 0; i < kQAVEnd; i++)
220     {
221         DICTNODE *hRes = gSysRes.Lookup(i, "QAV");
222         if (!hRes)
223             ThrowError("Could not load QAV %d\n", i);
224         weaponQAV[i] = (QAV*)gSysRes.Lock(hRes);
225         weaponQAV[i]->nSprite = -1;
226     }
227 }
228 
WeaponPrecache(void)229 void WeaponPrecache(void)
230 {
231     for (int i = 0; i < kQAVEnd; i++)
232     {
233         if (weaponQAV[i])
234             weaponQAV[i]->Precache();
235     }
236 }
237 
WeaponDraw(PLAYER * pPlayer,int a2,int a3,int a4,int a5)238 void WeaponDraw(PLAYER *pPlayer, int a2, int a3, int a4, int a5)
239 {
240     dassert(pPlayer != NULL);
241     if (pPlayer->weaponQav == -1)
242         return;
243     QAV * pQAV = weaponQAV[pPlayer->weaponQav];
244     int v4;
245     if (pPlayer->weaponTimer == 0)
246         v4 = (int)totalclock % pQAV->at10;
247     else
248         v4 = pQAV->at10 - pPlayer->weaponTimer;
249     pQAV->x = a3;
250     pQAV->y = a4;
251     int flags = 2;
252     int nInv = powerupCheck(pPlayer, kPwUpShadowCloak);
253     if (nInv >= 120 * 8 || (nInv != 0 && ((int)totalclock & 32)))
254     {
255         a2 = -128;
256         flags |= 1;
257     }
258     pQAV->Draw(v4, flags, a2, a5);
259 }
260 
WeaponPlay(PLAYER * pPlayer)261 void WeaponPlay(PLAYER *pPlayer)
262 {
263     dassert(pPlayer != NULL);
264     if (pPlayer->weaponQav == -1)
265         return;
266     QAV *pQAV = weaponQAV[pPlayer->weaponQav];
267     pQAV->nSprite = pPlayer->pSprite->index;
268     int nTicks = pQAV->at10 - pPlayer->weaponTimer;
269     pQAV->Play(nTicks-4, nTicks, pPlayer->qavCallback, pPlayer);
270 }
271 
StartQAV(PLAYER * pPlayer,int nWeaponQAV,int a3=-1,char a4=0)272 void StartQAV(PLAYER *pPlayer, int nWeaponQAV, int a3 = -1, char a4 = 0)
273 {
274     dassert(nWeaponQAV < kQAVEnd);
275     pPlayer->weaponQav = nWeaponQAV;
276     pPlayer->weaponTimer = weaponQAV[nWeaponQAV]->at10;
277     pPlayer->qavCallback = a3;
278     pPlayer->qavLoop = a4;
279     weaponQAV[nWeaponQAV]->Preload();
280     WeaponPlay(pPlayer);
281     pPlayer->weaponTimer -= 4;
282 }
283 
284 struct WEAPONTRACK
285 {
286     int at0; // x aim speed
287     int at4; // y aim speed
288     int at8; // angle range
289     int atc;
290     int at10; // predict
291     bool bIsProjectile;
292 };
293 
294 WEAPONTRACK gWeaponTrack[] = {
295     { 0, 0, 0, 0, 0, false },
296     { 0x6000, 0x6000, 0x71, 0x55, 0x111111, false },
297     { 0x8000, 0x8000, 0x71, 0x55, 0x2aaaaa, true },
298     { 0x10000, 0x10000, 0x38, 0x1c, 0, false },
299     { 0x6000, 0x8000, 0x38, 0x1c, 0, false },
300     { 0x6000, 0x6000, 0x38, 0x1c, 0x2aaaaa, true },
301     { 0x6000, 0x6000, 0x71, 0x55, 0, true },
302     { 0x6000, 0x6000, 0x71, 0x38, 0, true },
303     { 0x8000, 0x10000, 0x71, 0x55, 0x255555, true },
304     { 0x10000, 0x10000, 0x71, 0, 0, true },
305     { 0x10000, 0x10000, 0xaa, 0, 0, false },
306     { 0x6000, 0x6000, 0x71, 0x55, 0, true },
307     { 0x6000, 0x6000, 0x71, 0x55, 0, true },
308     { 0x6000, 0x6000, 0x71, 0x55, 0, false },
309 };
310 
UpdateAimVector(PLAYER * pPlayer)311 void UpdateAimVector(PLAYER * pPlayer)
312 {
313     short nSprite;
314     spritetype *pSprite;
315     dassert(pPlayer != NULL);
316     spritetype *pPSprite = pPlayer->pSprite;
317     int x = pPSprite->x;
318     int y = pPSprite->y;
319     int z = pPlayer->zWeapon;
320     Aim aim;
321     aim.dx = Cos(pPSprite->ang)>>16;
322     aim.dy = Sin(pPSprite->ang)>>16;
323     aim.dz = pPlayer->slope;
324     WEAPONTRACK *pWeaponTrack = &gWeaponTrack[pPlayer->curWeapon];
325     int nTarget = -1;
326     pPlayer->aimTargetsCount = 0;
327     if (gProfile[pPlayer->nPlayer].nAutoAim == 1 || (gProfile[pPlayer->nPlayer].nAutoAim == 2 && !pWeaponTrack->bIsProjectile) || pPlayer->curWeapon == 10 || pPlayer->curWeapon == 9)
328     {
329         int nClosest = 0x7fffffff;
330         for (nSprite = headspritestat[kStatDude]; nSprite >= 0; nSprite = nextspritestat[nSprite])
331         {
332             pSprite = &sprite[nSprite];
333             if (pSprite == pPSprite)
334                 continue;
335             if (!gGameOptions.bFriendlyFire && IsTargetTeammate(pPlayer, pSprite))
336                 continue;
337             if (pSprite->flags&32)
338                 continue;
339             if (!(pSprite->flags&8))
340                 continue;
341             int x2 = pSprite->x;
342             int y2 = pSprite->y;
343             int z2 = pSprite->z;
344             int nDist = approxDist(x2-x, y2-y);
345             if (nDist == 0 || nDist > 51200)
346                 continue;
347             if (pWeaponTrack->at10)
348             {
349                 int t = divscale(nDist,pWeaponTrack->at10, 12);
350                 x2 += (xvel[nSprite]*t)>>12;
351                 y2 += (yvel[nSprite]*t)>>12;
352                 z2 += (zvel[nSprite]*t)>>8;
353             }
354             int lx = x + mulscale30(Cos(pPSprite->ang), nDist);
355             int ly = y + mulscale30(Sin(pPSprite->ang), nDist);
356             int lz = z + mulscale(pPlayer->slope, nDist, 10);
357             int zRange = mulscale(9460, nDist, 10);
358             int top, bottom;
359             GetSpriteExtents(pSprite, &top, &bottom);
360             if (lz-zRange>bottom || lz+zRange<top)
361                 continue;
362             int angle = getangle(x2-x,y2-y);
363             if (klabs(((angle-pPSprite->ang+1024)&2047)-1024) > pWeaponTrack->at8)
364                 continue;
365             if (pPlayer->aimTargetsCount < 16 && cansee(x,y,z,pPSprite->sectnum,x2,y2,z2,pSprite->sectnum))
366                 pPlayer->aimTargets[pPlayer->aimTargetsCount++] = nSprite;
367             // Inlined?
368             int dz = (lz-z2)>>8;
369             int dy = (ly-y2)>>4;
370             int dx = (lx-x2)>>4;
371             int nDist2 = ksqrt(dx*dx+dy*dy+dz*dz);
372             if (nDist2 >= nClosest)
373                 continue;
374             DUDEINFO *pDudeInfo = getDudeInfo(pSprite->type);
375             int center = (pSprite->yrepeat*pDudeInfo->aimHeight)<<2;
376             int dzCenter = (z2-center)-z;
377             if (cansee(x, y, z, pPSprite->sectnum, x2, y2, z2, pSprite->sectnum))
378             {
379                 nClosest = nDist2;
380                 aim.dx = Cos(angle)>>16;
381                 aim.dy = Sin(angle)>>16;
382                 aim.dz = divscale(dzCenter, nDist, 10);
383                 nTarget = nSprite;
384             }
385         }
386         if (pWeaponTrack->atc > 0)
387         {
388             for (nSprite = headspritestat[kStatThing]; nSprite >= 0; nSprite = nextspritestat[nSprite])
389             {
390                 pSprite = &sprite[nSprite];
391                 if (!gGameOptions.bFriendlyFire && IsTargetTeammate(pPlayer, pSprite))
392                     continue;
393                 if (!(pSprite->flags&8))
394                     continue;
395                 int x2 = pSprite->x;
396                 int y2 = pSprite->y;
397                 int z2 = pSprite->z;
398                 int dx = x2-x;
399                 int dy = y2-y;
400                 int dz = z2-z;
401                 int nDist = approxDist(dx, dy);
402                 if (nDist == 0 || nDist > 51200)
403                     continue;
404                 int lx = x + mulscale30(Cos(pPSprite->ang), nDist);
405                 int ly = y + mulscale30(Sin(pPSprite->ang), nDist);
406                 int lz = z + mulscale(pPlayer->slope, nDist, 10);
407                 int zRange = mulscale10(9460, nDist);
408                 int top, bottom;
409                 GetSpriteExtents(pSprite, &top, &bottom);
410                 if (lz-zRange>bottom || lz+zRange<top)
411                     continue;
412                 int angle = getangle(dx,dy);
413                 if (klabs(((angle-pPSprite->ang+1024)&2047)-1024) > pWeaponTrack->atc)
414                     continue;
415                 if (pPlayer->aimTargetsCount < 16 && cansee(x,y,z,pPSprite->sectnum,pSprite->x,pSprite->y,pSprite->z,pSprite->sectnum))
416                     pPlayer->aimTargets[pPlayer->aimTargetsCount++] = nSprite;
417                 // Inlined?
418                 int dz2 = (lz-z2)>>8;
419                 int dy2 = (ly-y2)>>4;
420                 int dx2 = (lx-x2)>>4;
421                 int nDist2 = ksqrt(dx2*dx2+dy2*dy2+dz2*dz2);
422                 if (nDist2 >= nClosest)
423                     continue;
424                 if (cansee(x, y, z, pPSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, pSprite->sectnum))
425                 {
426                     nClosest = nDist2;
427                     aim.dx = Cos(angle)>>16;
428                     aim.dy = Sin(angle)>>16;
429                     aim.dz = divscale(dz, nDist, 10);
430                     nTarget = nSprite;
431                 }
432             }
433         }
434     }
435     Aim aim2;
436     aim2 = aim;
437     RotateVector((int*)&aim2.dx, (int*)&aim2.dy, -pPSprite->ang);
438     aim2.dz -= pPlayer->slope;
439     pPlayer->relAim.dx = interpolate(pPlayer->relAim.dx, aim2.dx, pWeaponTrack->at0);
440     pPlayer->relAim.dy = interpolate(pPlayer->relAim.dy, aim2.dy, pWeaponTrack->at0);
441     pPlayer->relAim.dz = interpolate(pPlayer->relAim.dz, aim2.dz, pWeaponTrack->at4);
442     pPlayer->aim = pPlayer->relAim;
443     RotateVector((int*)&pPlayer->aim.dx, (int*)&pPlayer->aim.dy, pPSprite->ang);
444     pPlayer->aim.dz += pPlayer->slope;
445     pPlayer->aimTarget = nTarget;
446 }
447 
448 struct t_WeaponModes
449 {
450     int at0;
451     int at4;
452 };
453 
454 t_WeaponModes weaponModes[] = {
455     { 0, -1 },
456     { 1, -1 },
457     { 1, 1 },
458     { 1, 2 },
459     { 1, 3 },
460     { 1, 4 },
461     { 1, 5 },
462     { 1, 6 },
463     { 1, 7 },
464     { 1, 8 },
465     { 1, 9 },
466     { 1, 10 },
467     { 1, 11 },
468     { 0, -1 },
469 };
470 
WeaponRaise(PLAYER * pPlayer)471 void WeaponRaise(PLAYER *pPlayer)
472 {
473     dassert(pPlayer != NULL);
474     int prevWeapon = pPlayer->curWeapon;
475     pPlayer->curWeapon = pPlayer->input.newWeapon;
476     pPlayer->input.newWeapon = 0;
477     pPlayer->weaponAmmo = weaponModes[pPlayer->curWeapon].at4;
478     switch (pPlayer->curWeapon)
479     {
480     case 1: // pitchfork
481         pPlayer->weaponState = 0;
482         StartQAV(pPlayer, 0, -1, 0);
483         break;
484     case 7: // spraycan
485         if (pPlayer->weaponState == 2)
486         {
487             pPlayer->weaponState = 3;
488             StartQAV(pPlayer, 8, -1, 0);
489         }
490         else
491         {
492             pPlayer->weaponState = 0;
493             StartQAV(pPlayer, 4, -1, 0);
494         }
495         break;
496     case 6: // dynamite
497         if (gInfiniteAmmo || sub_4B2C8(pPlayer, 5, 1))
498         {
499             pPlayer->weaponState = 3;
500             if (prevWeapon == 7)
501                 StartQAV(pPlayer, 16, -1, 0);
502             else
503                 StartQAV(pPlayer, 18, -1, 0);
504         }
505         break;
506     case 11: // proximity
507         if (gInfiniteAmmo || sub_4B2C8(pPlayer, 10, 1))
508         {
509             pPlayer->weaponState = 7;
510             StartQAV(pPlayer, 25, -1, 0);
511         }
512         break;
513     case 12: // remote
514         if (gInfiniteAmmo || sub_4B2C8(pPlayer, 11, 1))
515         {
516             pPlayer->weaponState = 10;
517             StartQAV(pPlayer, 31, -1, 0);
518         }
519         else
520         {
521             StartQAV(pPlayer, 32, -1, 0);
522             pPlayer->weaponState = 11;
523         }
524         break;
525     case 3: // sawed off
526         if (powerupCheck(pPlayer, kPwUpTwoGuns))
527         {
528             if (gInfiniteAmmo || pPlayer->ammoCount[2] >= 4)
529                 StartQAV(pPlayer, 59, -1, 0);
530             else
531                 StartQAV(pPlayer, 50, -1, 0);
532             if (gInfiniteAmmo || pPlayer->ammoCount[2] >= 4)
533                 pPlayer->weaponState = 7;
534             else if (pPlayer->ammoCount[2] > 1)
535                 pPlayer->weaponState = 3;
536             else if (pPlayer->ammoCount[2] > 0)
537                 pPlayer->weaponState = 2;
538             else
539                 pPlayer->weaponState = 1;
540         }
541         else
542         {
543             if (gInfiniteAmmo || pPlayer->ammoCount[2] > 1)
544                 pPlayer->weaponState = 3;
545             else if (pPlayer->ammoCount[2] > 0)
546                 pPlayer->weaponState = 2;
547             else
548                 pPlayer->weaponState = 1;
549             StartQAV(pPlayer, 50, -1, 0);
550         }
551         break;
552     case 4: // tommy gun
553         if (powerupCheck(pPlayer, kPwUpTwoGuns) && sub_4B2C8(pPlayer, 3, 2))
554         {
555             pPlayer->weaponState = 1;
556             StartQAV(pPlayer, 69, -1, 0);
557         }
558         else
559         {
560             pPlayer->weaponState = 0;
561             StartQAV(pPlayer, 64, -1, 0);
562         }
563         break;
564     case 10: // voodoo
565         if (gInfiniteAmmo || sub_4B2C8(pPlayer, 9, 1))
566         {
567             pPlayer->weaponState = 2;
568             StartQAV(pPlayer, 100, -1, 0);
569         }
570         break;
571     case 2: // flaregun
572         if (powerupCheck(pPlayer, kPwUpTwoGuns) && sub_4B2C8(pPlayer, 1, 2))
573         {
574             StartQAV(pPlayer, 45, -1, 0);
575             pPlayer->weaponState = 3;
576         }
577         else
578         {
579             StartQAV(pPlayer, 41, -1, 0);
580             pPlayer->weaponState = 2;
581         }
582         break;
583     case 8: // tesla cannon
584         if (sub_4B2C8(pPlayer, 7, 1))
585         {
586             pPlayer->weaponState = 2;
587             if (powerupCheck(pPlayer, kPwUpTwoGuns))
588                 StartQAV(pPlayer, 82, -1, 0);
589             else
590                 StartQAV(pPlayer, 74, -1, 0);
591         }
592         else
593         {
594             pPlayer->weaponState = 3;
595             StartQAV(pPlayer, 74, -1, 0);
596         }
597         break;
598     case 5: // napalm
599         if (powerupCheck(pPlayer, kPwUpTwoGuns))
600         {
601             StartQAV(pPlayer, 120, -1, 0);
602             pPlayer->weaponState = 3;
603         }
604         else
605         {
606             StartQAV(pPlayer, 89, -1, 0);
607             pPlayer->weaponState = 2;
608         }
609         break;
610     case 9: // life leech
611         pPlayer->weaponState = 2;
612         StartQAV(pPlayer, 111, -1, 0);
613         break;
614     case 13: // beast
615         pPlayer->weaponState = 2;
616         StartQAV(pPlayer, 93, -1, 0);
617         break;
618     }
619 }
620 
WeaponLower(PLAYER * pPlayer)621 void WeaponLower(PLAYER *pPlayer)
622 {
623     dassert(pPlayer != NULL);
624     if (sub_4B1A4(pPlayer))
625         return;
626     pPlayer->throwPower = 0;
627     int prevState = pPlayer->weaponState;
628     switch (pPlayer->curWeapon)
629     {
630     case 1:
631         StartQAV(pPlayer, 3, -1, 0);
632         break;
633     case 7:
634         sfxKill3DSound(pPlayer->pSprite, -1, 441);
635         switch (prevState)
636         {
637         case 1:
638             if (VanillaMode())
639             {
640                 StartQAV(pPlayer, 7, -1, 0);
641             }
642             else
643             {
644                 if (pPlayer->input.newWeapon == 6)
645                 {
646                     pPlayer->weaponState = 2;
647                     StartQAV(pPlayer, 11, -1, 0);
648                     WeaponRaise(pPlayer);
649                     return;
650                 }
651             }
652             break;
653         case 2:
654             pPlayer->weaponState = 1;
655             WeaponRaise(pPlayer);
656             return;
657         case 4:
658             pPlayer->weaponState = 1;
659             StartQAV(pPlayer, 11, -1, 0);
660             if (VanillaMode())
661             {
662                 pPlayer->input.newWeapon = 0;
663                 WeaponLower(pPlayer);
664             }
665             else
666             {
667                 if (pPlayer->input.newWeapon == 6)
668                 {
669                     pPlayer->weaponState = 2;
670                     StartQAV(pPlayer, 11, -1, 0);
671                     return;
672                 }
673                 else
674                 {
675                     WeaponLower(pPlayer);
676                 }
677             }
678             break;
679         case 3:
680             if (pPlayer->input.newWeapon == 6)
681             {
682                 pPlayer->weaponState = 2;
683                 StartQAV(pPlayer, 11, -1, 0);
684                 return;
685             }
686             else if (pPlayer->input.newWeapon == 7)
687             {
688                 pPlayer->weaponState = 1;
689                 StartQAV(pPlayer, 11, -1, 0);
690                 pPlayer->input.newWeapon = 0;
691                 WeaponLower(pPlayer);
692             }
693             else
694             {
695                 pPlayer->weaponState = 1;
696                 StartQAV(pPlayer, 11, -1, 0);
697             }
698             break;
699         }
700         break;
701     case 6:
702         switch (prevState)
703         {
704         case 1:
705             if (VanillaMode())
706             {
707                 StartQAV(pPlayer, 7, -1, 0);
708             }
709             else
710             {
711                 if (pPlayer->input.newWeapon == 7)
712                 {
713                     pPlayer->weaponState = 2;
714                     StartQAV(pPlayer, 17, -1, 0);
715                     WeaponRaise(pPlayer);
716                     return;
717                 }
718             }
719             break;
720         case 2:
721             WeaponRaise(pPlayer);
722             break;
723         case 3:
724             if (pPlayer->input.newWeapon == 7)
725             {
726                 pPlayer->weaponState = 2;
727                 StartQAV(pPlayer, 17, -1, 0);
728             }
729             else
730             {
731                 StartQAV(pPlayer, 19, -1, 0);
732             }
733             break;
734         default:
735             break;
736         }
737         break;
738     case 11:
739         switch (prevState)
740         {
741         case 7:
742             StartQAV(pPlayer, 26, -1, 0);
743             break;
744         }
745         break;
746     case 12:
747         switch (prevState)
748         {
749         case 10:
750             StartQAV(pPlayer, 34, -1, 0);
751             break;
752         case 11:
753             StartQAV(pPlayer, 35, -1, 0);
754             break;
755         }
756         break;
757     case 3:
758         if (powerupCheck(pPlayer, kPwUpTwoGuns))
759             StartQAV(pPlayer, 63, -1, 0);
760         else
761             StartQAV(pPlayer, 58, -1, 0);
762         break;
763     case 4:
764         if (powerupCheck(pPlayer, kPwUpTwoGuns) && pPlayer->weaponState == 1)
765             StartQAV(pPlayer, 72, -1, 0);
766         else
767             StartQAV(pPlayer, 68, -1, 0);
768         break;
769     case 2:
770         if (powerupCheck(pPlayer, kPwUpTwoGuns) && pPlayer->weaponState == 3)
771             StartQAV(pPlayer, 49, -1, 0);
772         else
773             StartQAV(pPlayer, 44, -1, 0);
774         break;
775     case 10:
776         StartQAV(pPlayer, 109, -1, 0);
777         break;
778     case 8:
779         if (sub_4B2C8(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns))
780             StartQAV(pPlayer, 88, -1, 0);
781         else
782             StartQAV(pPlayer, 81, -1, 0);
783         break;
784     case 5:
785         if (powerupCheck(pPlayer, kPwUpTwoGuns))
786             StartQAV(pPlayer, 124, -1, 0);
787         else
788             StartQAV(pPlayer, 92, -1, 0);
789         break;
790     case 9:
791         StartQAV(pPlayer, 119, -1, 0);
792         break;
793     case 13:
794         StartQAV(pPlayer, 99, -1, 0);
795         break;
796     }
797     pPlayer->curWeapon = 0;
798     pPlayer->qavLoop = 0;
799 }
800 
WeaponUpdateState(PLAYER * pPlayer)801 void WeaponUpdateState(PLAYER *pPlayer)
802 {
803     static int lastWeapon = 0;
804     static int lastState = 0;
805     XSPRITE *pXSprite = pPlayer->pXSprite;
806     int va = pPlayer->curWeapon;
807     int vb = pPlayer->weaponState;
808     if (va != lastWeapon || vb != lastState)
809     {
810         lastWeapon = va;
811         lastState = vb;
812     }
813     switch (lastWeapon)
814     {
815     case 1:
816         pPlayer->weaponQav = 1;
817         break;
818     case 7:
819         switch (vb)
820         {
821         case 0:
822             pPlayer->weaponState = 1;
823             StartQAV(pPlayer, 5, -1, 0);
824             break;
825         case 1:
826             if (CheckAmmo(pPlayer, 6, 1))
827             {
828                 pPlayer->weaponState = 3;
829                 StartQAV(pPlayer, 8, -1, 0);
830             }
831             else
832                 pPlayer->weaponQav = 6;
833             break;
834         case 3:
835             pPlayer->weaponQav = 9;
836             break;
837         case 4:
838             if (CheckAmmo(pPlayer, 6, 1))
839             {
840                 pPlayer->weaponQav = 9;
841                 pPlayer->weaponState = 3;
842             }
843             else
844             {
845                 pPlayer->weaponState = 1;
846                 StartQAV(pPlayer, 11, -1, 0);
847             }
848             sfxKill3DSound(pPlayer->pSprite, -1, 441);
849             break;
850         }
851         break;
852     case 6:
853         switch (vb)
854         {
855         case 1:
856             if (pPlayer->weaponAmmo == 5 && CheckAmmo(pPlayer, 5, 1))
857             {
858                 pPlayer->weaponState = 3;
859                 StartQAV(pPlayer, 16, -1, 0);
860             }
861             break;
862         case 0:
863             pPlayer->weaponState = 1;
864             StartQAV(pPlayer, 5, -1, 0);
865             break;
866         case 2:
867             if (pPlayer->ammoCount[5] > 0)
868             {
869                 pPlayer->weaponState = 3;
870                 StartQAV(pPlayer, 16, -1, 0);
871             }
872             else
873                 pPlayer->weaponQav = 6;
874             break;
875         case 3:
876             pPlayer->weaponQav = 20;
877             break;
878         }
879         break;
880     case 11:
881         switch (vb)
882         {
883         case 7:
884             pPlayer->weaponQav = 27;
885             break;
886         case 8:
887             pPlayer->weaponState = 7;
888             StartQAV(pPlayer, 25, -1, 0);
889             break;
890         }
891         break;
892     case 12:
893         switch (vb)
894         {
895         case 10:
896             pPlayer->weaponQav = 36;
897             break;
898         case 11:
899             pPlayer->weaponQav = 37;
900             break;
901         case 12:
902             if (pPlayer->ammoCount[11] > 0)
903             {
904                 pPlayer->weaponState = 10;
905                 StartQAV(pPlayer, 31, -1, 0);
906             }
907             else
908                 pPlayer->weaponState = -1;
909             break;
910         }
911         break;
912     case 3:
913         switch (vb)
914         {
915         case 6:
916             if (powerupCheck(pPlayer, kPwUpTwoGuns) && (gInfiniteAmmo || CheckAmmo(pPlayer, 2, 4)))
917                 pPlayer->weaponState = 7;
918             else
919                 pPlayer->weaponState = 1;
920             break;
921         case 7:
922             pPlayer->weaponQav = 60;
923             break;
924         case 1:
925             if (CheckAmmo(pPlayer, 2, 1))
926             {
927                 sfxPlay3DSound(pPlayer->pSprite, 410, 3, 2);
928                 StartQAV(pPlayer, 57, nClientEjectShell, 0);
929                 if (gInfiniteAmmo || pPlayer->ammoCount[2] > 1)
930                     pPlayer->weaponState = 3;
931                 else
932                     pPlayer->weaponState = 2;
933             }
934             else
935                 pPlayer->weaponQav = 51;
936             break;
937         case 2:
938             pPlayer->weaponQav = 52;
939             break;
940         case 3:
941             pPlayer->weaponQav = 53;
942             break;
943         }
944         break;
945     case 4:
946         if (powerupCheck(pPlayer, kPwUpTwoGuns) && sub_4B2C8(pPlayer, 3, 2))
947         {
948             pPlayer->weaponQav = 70;
949             pPlayer->weaponState = 1;
950         }
951         else
952         {
953             pPlayer->weaponQav = 65;
954             pPlayer->weaponState = 0;
955         }
956         break;
957     case 2:
958         if (powerupCheck(pPlayer, kPwUpTwoGuns))
959         {
960             if (vb == 3 && sub_4B2C8(pPlayer, 1, 2))
961                 pPlayer->weaponQav = 46;
962             else
963             {
964                 pPlayer->weaponQav = 42;
965                 pPlayer->weaponState = 2;
966             }
967         }
968         else
969             pPlayer->weaponQav = 42;
970         break;
971     case 10:
972         if (pXSprite->height < 256 && klabs(pPlayer->swayHeight) > 768)
973             pPlayer->weaponQav = 102;
974         else
975             pPlayer->weaponQav = 101;
976         break;
977     case 8:
978         switch (vb)
979         {
980         case 2:
981             if (sub_4B2C8(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns))
982                 pPlayer->weaponQav = 83;
983             else
984                 pPlayer->weaponQav = 75;
985             break;
986         case 3:
987             pPlayer->weaponQav = 76;
988             break;
989         }
990         break;
991     case 5:
992         switch (vb)
993         {
994         case 3:
995             if (powerupCheck(pPlayer, kPwUpTwoGuns) && (gInfiniteAmmo || CheckAmmo(pPlayer,4, 4)))
996                 pPlayer->weaponQav = 121;
997             else
998                 pPlayer->weaponQav = 90;
999             break;
1000         case 2:
1001             pPlayer->weaponQav = 90;
1002             break;
1003         }
1004         break;
1005     case 9:
1006         switch (vb)
1007         {
1008         case 2:
1009             pPlayer->weaponQav = 112;
1010             break;
1011         }
1012         break;
1013     case 13:
1014         pPlayer->weaponQav = 94;
1015         break;
1016     }
1017 }
1018 
FirePitchfork(int,PLAYER * pPlayer)1019 void FirePitchfork(int, PLAYER *pPlayer)
1020 {
1021     Aim *aim = &pPlayer->aim;
1022     int r1 = Random2(2000);
1023     int r2 = Random2(2000);
1024     int r3 = Random2(2000);
1025     for (int i = 0; i < 4; i++)
1026         actFireVector(pPlayer->pSprite, (2*i-3)*40, pPlayer->zWeapon-pPlayer->pSprite->z, aim->dx+r1, aim->dy+r2, aim->dz+r3, kVectorTine);
1027 }
1028 
FireSpray(int,PLAYER * pPlayer)1029 void FireSpray(int, PLAYER *pPlayer)
1030 {
1031     playerFireMissile(pPlayer, 0, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, kMissileFlameSpray);
1032     UseAmmo(pPlayer, 6, 4);
1033     if (CheckAmmo(pPlayer, 6, 1))
1034         sfxPlay3DSound(pPlayer->pSprite, 441, 1, 2);
1035     else
1036         sfxKill3DSound(pPlayer->pSprite, -1, 441);
1037 }
1038 
ThrowCan(int,PLAYER * pPlayer)1039 void ThrowCan(int, PLAYER *pPlayer)
1040 {
1041     sfxKill3DSound(pPlayer->pSprite, -1, 441);
1042     int nSpeed = mulscale16(pPlayer->throwPower, 0x177777)+0x66666;
1043     sfxPlay3DSound(pPlayer->pSprite, 455, 1, 0);
1044     spritetype *pSprite = playerFireThing(pPlayer, 0, -9460, kThingArmedSpray, nSpeed);
1045     if (pSprite)
1046     {
1047         sfxPlay3DSound(pSprite, 441, 0, 0);
1048         evPost(pSprite->index, 3, pPlayer->fuseTime, kCmdOn);
1049         int nXSprite = pSprite->extra;
1050         XSPRITE *pXSprite = &xsprite[nXSprite];
1051         pXSprite->Impact = 1;
1052         UseAmmo(pPlayer, 6, gAmmoItemData[0].count);
1053         pPlayer->throwPower = 0;
1054     }
1055 }
1056 
DropCan(int,PLAYER * pPlayer)1057 void DropCan(int, PLAYER *pPlayer)
1058 {
1059     sfxKill3DSound(pPlayer->pSprite, -1, 441);
1060     spritetype *pSprite = playerFireThing(pPlayer, 0, 0, kThingArmedSpray, 0);
1061     if (pSprite)
1062     {
1063         evPost(pSprite->index, 3, pPlayer->fuseTime, kCmdOn);
1064         UseAmmo(pPlayer, 6, gAmmoItemData[0].count);
1065     }
1066 }
1067 
ExplodeCan(int,PLAYER * pPlayer)1068 void ExplodeCan(int, PLAYER *pPlayer)
1069 {
1070     sfxKill3DSound(pPlayer->pSprite, -1, 441);
1071     spritetype *pSprite = playerFireThing(pPlayer, 0, 0, kThingArmedSpray, 0);
1072     evPost(pSprite->index, 3, 0, kCmdOn);
1073     UseAmmo(pPlayer, 6, gAmmoItemData[0].count);
1074     StartQAV(pPlayer, 15, -1);
1075     pPlayer->curWeapon = 0;
1076     pPlayer->throwPower = 0;
1077 }
1078 
ThrowBundle(int,PLAYER * pPlayer)1079 void ThrowBundle(int, PLAYER *pPlayer)
1080 {
1081     sfxKill3DSound(pPlayer->pSprite, 16, -1);
1082     int nSpeed = mulscale16(pPlayer->throwPower, 0x177777)+0x66666;
1083     sfxPlay3DSound(pPlayer->pSprite, 455, 1, 0);
1084     spritetype *pSprite = playerFireThing(pPlayer, 0, -9460, kThingArmedTNTBundle, nSpeed);
1085     int nXSprite = pSprite->extra;
1086     XSPRITE *pXSprite = &xsprite[nXSprite];
1087     if (pPlayer->fuseTime < 0)
1088         pXSprite->Impact = 1;
1089     else
1090         evPost(pSprite->index, 3, pPlayer->fuseTime, kCmdOn);
1091     UseAmmo(pPlayer, 5, 1);
1092     pPlayer->throwPower = 0;
1093 }
1094 
DropBundle(int,PLAYER * pPlayer)1095 void DropBundle(int, PLAYER *pPlayer)
1096 {
1097     sfxKill3DSound(pPlayer->pSprite, 16, -1);
1098     spritetype *pSprite = playerFireThing(pPlayer, 0, 0, kThingArmedTNTBundle, 0);
1099     evPost(pSprite->index, 3, pPlayer->fuseTime, kCmdOn);
1100     UseAmmo(pPlayer, 5, 1);
1101 }
1102 
ExplodeBundle(int,PLAYER * pPlayer)1103 void ExplodeBundle(int, PLAYER *pPlayer)
1104 {
1105     sfxKill3DSound(pPlayer->pSprite, 16, -1);
1106     spritetype *pSprite = playerFireThing(pPlayer, 0, 0, kThingArmedTNTBundle, 0);
1107     evPost(pSprite->index, 3, 0, kCmdOn);
1108     UseAmmo(pPlayer, 5, 1);
1109     StartQAV(pPlayer, 24, -1, 0);
1110     pPlayer->curWeapon = 0;
1111     pPlayer->throwPower = 0;
1112 }
1113 
ThrowProx(int,PLAYER * pPlayer)1114 void ThrowProx(int, PLAYER *pPlayer)
1115 {
1116     int nSpeed = mulscale16(pPlayer->throwPower, 0x177777)+0x66666;
1117     sfxPlay3DSound(pPlayer->pSprite, 455, 1, 0);
1118     spritetype *pSprite = playerFireThing(pPlayer, 0, -9460, kThingArmedProxBomb, nSpeed);
1119     evPost(pSprite->index, 3, 240, kCmdOn);
1120     UseAmmo(pPlayer, 10, 1);
1121     pPlayer->throwPower = 0;
1122 }
1123 
DropProx(int,PLAYER * pPlayer)1124 void DropProx(int, PLAYER *pPlayer)
1125 {
1126     spritetype *pSprite = playerFireThing(pPlayer, 0, 0, kThingArmedProxBomb, 0);
1127     evPost(pSprite->index, 3, 240, kCmdOn);
1128     UseAmmo(pPlayer, 10, 1);
1129 }
1130 
ThrowRemote(int,PLAYER * pPlayer)1131 void ThrowRemote(int, PLAYER *pPlayer)
1132 {
1133     int nSpeed = mulscale16(pPlayer->throwPower, 0x177777)+0x66666;
1134     sfxPlay3DSound(pPlayer->pSprite, 455, 1, 0);
1135     spritetype *pSprite = playerFireThing(pPlayer, 0, -9460, kThingArmedRemoteBomb, nSpeed);
1136     int nXSprite = pSprite->extra;
1137     XSPRITE *pXSprite = &xsprite[nXSprite];
1138     pXSprite->rxID = 90+(pPlayer->pSprite->type-kDudePlayer1);
1139     UseAmmo(pPlayer, 11, 1);
1140     pPlayer->throwPower = 0;
1141 }
1142 
DropRemote(int,PLAYER * pPlayer)1143 void DropRemote(int, PLAYER *pPlayer)
1144 {
1145     spritetype *pSprite = playerFireThing(pPlayer, 0, 0, kThingArmedRemoteBomb, 0);
1146     int nXSprite = pSprite->extra;
1147     XSPRITE *pXSprite = &xsprite[nXSprite];
1148     pXSprite->rxID = 90+(pPlayer->pSprite->type-kDudePlayer1);
1149     UseAmmo(pPlayer, 11, 1);
1150 }
1151 
FireRemote(int,PLAYER * pPlayer)1152 void FireRemote(int, PLAYER *pPlayer)
1153 {
1154     evSend(0, 0, 90+(pPlayer->pSprite->type-kDudePlayer1), kCmdOn);
1155 }
1156 
1157 #define kMaxShotgunBarrels 4
1158 
FireShotgun(int nTrigger,PLAYER * pPlayer)1159 void FireShotgun(int nTrigger, PLAYER *pPlayer)
1160 {
1161     dassert(nTrigger > 0 && nTrigger <= kMaxShotgunBarrels);
1162     if (nTrigger == 1)
1163     {
1164         sfxPlay3DSound(pPlayer->pSprite, 411, 2, 0);
1165         pPlayer->tiltEffect = 30;
1166         pPlayer->visibility = 20;
1167     }
1168     else
1169     {
1170         sfxPlay3DSound(pPlayer->pSprite, 412, 2, 0);
1171         pPlayer->tiltEffect = 50;
1172         pPlayer->visibility = 40;
1173     }
1174     int n = nTrigger<<4;
1175     for (int i = 0; i < n; i++)
1176     {
1177         int r1, r2, r3;
1178         VECTOR_TYPE nType;
1179         if (nTrigger == 1)
1180         {
1181             r1 = Random3(1500);
1182             r2 = Random3(1500);
1183             r3 = Random3(500);
1184             nType = kVectorShell;
1185         }
1186         else
1187         {
1188             r1 = Random3(2500);
1189             r2 = Random3(2500);
1190             r3 = Random3(1500);
1191             nType = kVectorShellAP;
1192         }
1193         actFireVector(pPlayer->pSprite, 0, pPlayer->zWeapon-pPlayer->pSprite->z, pPlayer->aim.dx+r1, pPlayer->aim.dy+r2, pPlayer->aim.dz+r3, nType);
1194     }
1195     UseAmmo(pPlayer, pPlayer->weaponAmmo, nTrigger);
1196     pPlayer->flashEffect = 1;
1197 }
1198 
EjectShell(int,PLAYER * pPlayer)1199 void EjectShell(int, PLAYER *pPlayer)
1200 {
1201     SpawnShellEject(pPlayer, 25, 35);
1202     SpawnShellEject(pPlayer, 48, 35);
1203 }
1204 
FireTommy(int nTrigger,PLAYER * pPlayer)1205 void FireTommy(int nTrigger, PLAYER *pPlayer)
1206 {
1207     Aim *aim = &pPlayer->aim;
1208     sfxPlay3DSound(pPlayer->pSprite, 431, -1, 0);
1209     switch (nTrigger)
1210     {
1211     case 1:
1212     {
1213         int r1 = Random3(400);
1214         int r2 = Random3(1200);
1215         int r3 = Random3(1200);
1216         actFireVector(pPlayer->pSprite, 0, pPlayer->zWeapon-pPlayer->pSprite->z, aim->dx+r3, aim->dy+r2, aim->dz+r1, kVectorTommyregular);
1217         SpawnBulletEject(pPlayer, -15, -45);
1218         pPlayer->visibility = 20;
1219         break;
1220     }
1221     case 2:
1222     {
1223         int r1 = Random3(400);
1224         int r2 = Random3(1200);
1225         int r3 = Random3(1200);
1226         actFireVector(pPlayer->pSprite, -120, pPlayer->zWeapon-pPlayer->pSprite->z, aim->dx+r3, aim->dy+r2, aim->dz+r1, kVectorTommyregular);
1227         SpawnBulletEject(pPlayer, -140, -45);
1228         r1 = Random3(400);
1229         r2 = Random3(1200);
1230         r3 = Random3(1200);
1231         actFireVector(pPlayer->pSprite, 120, pPlayer->zWeapon-pPlayer->pSprite->z, aim->dx+r3, aim->dy+r2, aim->dz+r1, kVectorTommyregular);
1232         SpawnBulletEject(pPlayer, 140, 45);
1233         pPlayer->visibility = 30;
1234         break;
1235     }
1236     }
1237     UseAmmo(pPlayer, pPlayer->weaponAmmo, nTrigger);
1238     pPlayer->flashEffect = 1;
1239 }
1240 
1241 #define kMaxSpread 14
1242 
FireSpread(int nTrigger,PLAYER * pPlayer)1243 void FireSpread(int nTrigger, PLAYER *pPlayer)
1244 {
1245     dassert(nTrigger > 0 && nTrigger <= kMaxSpread);
1246     Aim *aim = &pPlayer->aim;
1247     int angle = (getangle(aim->dx, aim->dy)+((112*(nTrigger-1))/14-56))&2047;
1248     int dx = Cos(angle)>>16;
1249     int dy = Sin(angle)>>16;
1250     sfxPlay3DSound(pPlayer->pSprite, 431, -1, 0);
1251     int r1, r2, r3;
1252     r1 = Random3(300);
1253     r2 = Random3(600);
1254     r3 = Random3(600);
1255     actFireVector(pPlayer->pSprite, 0, pPlayer->zWeapon-pPlayer->pSprite->z, dx+r3, dy+r2, aim->dz+r1, kVectorTommyAP);
1256     r1 = Random2(90);
1257     r2 = Random2(30);
1258     SpawnBulletEject(pPlayer, r2, r1);
1259     pPlayer->visibility = 20;
1260     UseAmmo(pPlayer, pPlayer->weaponAmmo, 1);
1261     pPlayer->flashEffect = 1;
1262 }
1263 
AltFireSpread(int nTrigger,PLAYER * pPlayer)1264 void AltFireSpread(int nTrigger, PLAYER *pPlayer)
1265 {
1266     dassert(nTrigger > 0 && nTrigger <= kMaxSpread);
1267     Aim *aim = &pPlayer->aim;
1268     int angle = (getangle(aim->dx, aim->dy)+((112*(nTrigger-1))/14-56))&2047;
1269     int dx = Cos(angle)>>16;
1270     int dy = Sin(angle)>>16;
1271     sfxPlay3DSound(pPlayer->pSprite, 431, -1, 0);
1272     int r1, r2, r3;
1273     r1 = Random3(300);
1274     r2 = Random3(600);
1275     r3 = Random3(600);
1276     actFireVector(pPlayer->pSprite, -120, pPlayer->zWeapon-pPlayer->pSprite->z, dx+r3, dy+r2, aim->dz+r1, kVectorTommyAP);
1277     r1 = Random2(45);
1278     r2 = Random2(120);
1279     SpawnBulletEject(pPlayer, r2, r1);
1280     r1 = Random3(300);
1281     r2 = Random3(600);
1282     r3 = Random3(600);
1283     actFireVector(pPlayer->pSprite, 120, pPlayer->zWeapon-pPlayer->pSprite->z, dx+r3, dy+r2, aim->dz+r1, kVectorTommyAP);
1284     r1 = Random2(-45);
1285     r2 = Random2(-120);
1286     SpawnBulletEject(pPlayer, r2, r1);
1287     pPlayer->tiltEffect = 20;
1288     pPlayer->visibility = 30;
1289     UseAmmo(pPlayer, pPlayer->weaponAmmo, 2);
1290     pPlayer->flashEffect = 1;
1291 }
1292 
AltFireSpread2(int nTrigger,PLAYER * pPlayer)1293 void AltFireSpread2(int nTrigger, PLAYER *pPlayer)
1294 {
1295     dassert(nTrigger > 0 && nTrigger <= kMaxSpread);
1296     Aim *aim = &pPlayer->aim;
1297     int angle = (getangle(aim->dx, aim->dy)+((112*(nTrigger-1))/14-56))&2047;
1298     int dx = Cos(angle)>>16;
1299     int dy = Sin(angle)>>16;
1300     sfxPlay3DSound(pPlayer->pSprite, 431, -1, 0);
1301     if (powerupCheck(pPlayer, kPwUpTwoGuns) && sub_4B2C8(pPlayer, 3, 2))
1302     {
1303         int r1, r2, r3;
1304         r1 = Random3(300);
1305         r2 = Random3(600);
1306         r3 = Random3(600);
1307         actFireVector(pPlayer->pSprite, -120, pPlayer->zWeapon-pPlayer->pSprite->z, dx+r3, dy+r2, aim->dz+r1, kVectorTommyAP);
1308         r1 = Random2(45);
1309         r2 = Random2(120);
1310         SpawnBulletEject(pPlayer, r2, r1);
1311         r1 = Random3(300);
1312         r2 = Random3(600);
1313         r3 = Random3(600);
1314         actFireVector(pPlayer->pSprite, 120, pPlayer->zWeapon-pPlayer->pSprite->z, dx+r3, dy+r2, aim->dz+r1, kVectorTommyAP);
1315         r1 = Random2(-45);
1316         r2 = Random2(-120);
1317         SpawnBulletEject(pPlayer, r2, r1);
1318         pPlayer->tiltEffect = 30;
1319         pPlayer->visibility = 45;
1320         UseAmmo(pPlayer, pPlayer->weaponAmmo, 2);
1321     }
1322     else
1323     {
1324         int r1, r2, r3;
1325         r1 = Random3(300);
1326         r2 = Random3(600);
1327         r3 = Random3(600);
1328         actFireVector(pPlayer->pSprite, 0, pPlayer->zWeapon-pPlayer->pSprite->z, dx+r3, dy+r2, aim->dz+r1, kVectorTommyAP);
1329         r1 = Random2(90);
1330         r2 = Random2(30);
1331         SpawnBulletEject(pPlayer, r2, r1);
1332         pPlayer->tiltEffect = 20;
1333         pPlayer->visibility = 30;
1334         UseAmmo(pPlayer, pPlayer->weaponAmmo, 1);
1335     }
1336     pPlayer->flashEffect = 1;
1337     if (!sub_4B2C8(pPlayer, 3, 1))
1338     {
1339         WeaponLower(pPlayer);
1340         pPlayer->weaponState = -1;
1341     }
1342 }
1343 
FireFlare(int nTrigger,PLAYER * pPlayer)1344 void FireFlare(int nTrigger, PLAYER *pPlayer)
1345 {
1346     spritetype *pSprite = pPlayer->pSprite;
1347     int offset = 0;
1348     switch (nTrigger)
1349     {
1350     case 2:
1351         offset = -120;
1352         break;
1353     case 3:
1354         offset = 120;
1355         break;
1356     }
1357     playerFireMissile(pPlayer, offset, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, kMissileFlareRegular);
1358     UseAmmo(pPlayer, 1, 1);
1359     sfxPlay3DSound(pSprite, 420, 2, 0);
1360     pPlayer->visibility = 30;
1361     pPlayer->flashEffect = 1;
1362 }
1363 
AltFireFlare(int nTrigger,PLAYER * pPlayer)1364 void AltFireFlare(int nTrigger, PLAYER *pPlayer)
1365 {
1366     spritetype *pSprite = pPlayer->pSprite;
1367     int offset = 0;
1368     switch (nTrigger)
1369     {
1370     case 2:
1371         offset = -120;
1372         break;
1373     case 3:
1374         offset = 120;
1375         break;
1376     }
1377     playerFireMissile(pPlayer, offset, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, kMissileFlareAlt);
1378     UseAmmo(pPlayer, 1, 8);
1379     sfxPlay3DSound(pSprite, 420, 2, 0);
1380     pPlayer->visibility = 45;
1381     pPlayer->flashEffect = 1;
1382 }
1383 
FireVoodoo(int nTrigger,PLAYER * pPlayer)1384 void FireVoodoo(int nTrigger, PLAYER *pPlayer)
1385 {
1386     nTrigger--;
1387     int nSprite = pPlayer->nSprite;
1388     spritetype *pSprite = pPlayer->pSprite;
1389     if (nTrigger == 4)
1390     {
1391         actDamageSprite(nSprite, pSprite, kDamageBullet, 1<<4);
1392         return;
1393     }
1394     dassert(pPlayer->voodooTarget >= 0);
1395     spritetype *pTarget = &sprite[pPlayer->voodooTarget];
1396     if (!gGameOptions.bFriendlyFire && IsTargetTeammate(pPlayer, pTarget))
1397         return;
1398     switch (nTrigger)
1399     {
1400     case 0:
1401     {
1402         sfxPlay3DSound(pSprite, 460, 2, 0);
1403         fxSpawnBlood(pTarget, 17<<4);
1404         int nDamage = actDamageSprite(nSprite, pTarget, kDamageSpirit, 17<<4);
1405         UseAmmo(pPlayer, 9, nDamage/4);
1406         break;
1407     }
1408     case 1:
1409     {
1410         sfxPlay3DSound(pSprite, 460, 2, 0);
1411         fxSpawnBlood(pTarget, 17<<4);
1412         int nDamage = actDamageSprite(nSprite, pTarget, kDamageSpirit, 9<<4);
1413         if (IsPlayerSprite(pTarget))
1414             WeaponLower(&gPlayer[pTarget->type-kDudePlayer1]);
1415         UseAmmo(pPlayer, 9, nDamage/4);
1416         break;
1417     }
1418     case 3:
1419     {
1420         sfxPlay3DSound(pSprite, 463, 2, 0);
1421         fxSpawnBlood(pTarget, 17<<4);
1422         int nDamage = actDamageSprite(nSprite, pTarget, kDamageSpirit, 49<<4);
1423         UseAmmo(pPlayer, 9, nDamage/4);
1424         break;
1425     }
1426     case 2:
1427     {
1428         sfxPlay3DSound(pSprite, 460, 2, 0);
1429         fxSpawnBlood(pTarget, 17<<4);
1430         int nDamage = actDamageSprite(nSprite, pTarget, kDamageSpirit, 11<<4);
1431         if (IsPlayerSprite(pTarget))
1432         {
1433             PLAYER *pOtherPlayer = &gPlayer[pTarget->type - kDudePlayer1];
1434             pOtherPlayer->blindEffect = 128;
1435         }
1436         UseAmmo(pPlayer, 9, nDamage/4);
1437         break;
1438     }
1439     }
1440 }
1441 
AltFireVoodoo(int nTrigger,PLAYER * pPlayer)1442 void AltFireVoodoo(int nTrigger, PLAYER *pPlayer)
1443 {
1444     if (nTrigger == 2) {
1445 
1446         // by NoOne: trying to simulate v1.0x voodoo here.
1447         // dunno how exactly it works, but at least it not spend all the ammo on alt fire
1448         if (gGameOptions.weaponsV10x && !VanillaMode() && !DemoRecordStatus()) {
1449             int nCount = ClipHigh(pPlayer->ammoCount[9], pPlayer->aimTargetsCount);
1450             if (nCount > 0)
1451             {
1452                 for (int i = 0; i < pPlayer->aimTargetsCount; i++)
1453                 {
1454                     int nTarget = pPlayer->aimTargets[i];
1455                     spritetype* pTarget = &sprite[nTarget];
1456                     if (!gGameOptions.bFriendlyFire && IsTargetTeammate(pPlayer, pTarget))
1457                         continue;
1458                     int nDist = approxDist(pTarget->x - pPlayer->pSprite->x, pTarget->y - pPlayer->pSprite->y);
1459                     if (nDist > 0 && nDist < 51200)
1460                     {
1461                         int vc = pPlayer->ammoCount[9] >> 3;
1462                         int v8 = pPlayer->ammoCount[9] << 1;
1463                         int nDamage = (v8 + Random(vc)) << 4;
1464                         nDamage = (nDamage * ((51200 - nDist) + 1)) / 51200;
1465                         nDamage = actDamageSprite(pPlayer->nSprite, pTarget, kDamageSpirit, nDamage);
1466 
1467                         if (IsPlayerSprite(pTarget))
1468                         {
1469                             PLAYER* pOtherPlayer = &gPlayer[pTarget->type - kDudePlayer1];
1470                             if (!pOtherPlayer->godMode || !powerupCheck(pOtherPlayer, kPwUpDeathMask))
1471                                 powerupActivate(pOtherPlayer, kPwUpDeliriumShroom);
1472                         }
1473                         fxSpawnBlood(pTarget, 0);
1474                     }
1475                 }
1476             }
1477 
1478             UseAmmo(pPlayer, 9, 20);
1479             pPlayer->weaponState = 0;
1480             return;
1481         }
1482 
1483         //int nAmmo = pPlayer->ammCount[9];
1484         int nCount = ClipHigh(pPlayer->ammoCount[9], pPlayer->aimTargetsCount);
1485         if (nCount > 0)
1486         {
1487             int v4 = pPlayer->ammoCount[9] - (pPlayer->ammoCount[9] / nCount) * nCount;
1488             for (int i = 0; i < pPlayer->aimTargetsCount; i++)
1489             {
1490                 int nTarget = pPlayer->aimTargets[i];
1491                 spritetype* pTarget = &sprite[nTarget];
1492                 if (!gGameOptions.bFriendlyFire && IsTargetTeammate(pPlayer, pTarget))
1493                     continue;
1494                 if (v4 > 0)
1495                     v4--;
1496                 int nDist = approxDist(pTarget->x - pPlayer->pSprite->x, pTarget->y - pPlayer->pSprite->y);
1497                 if (nDist > 0 && nDist < 51200)
1498                 {
1499                     int vc = pPlayer->ammoCount[9] >> 3;
1500                     int v8 = pPlayer->ammoCount[9] << 1;
1501                     int nDamage = (v8 + Random2(vc)) << 4;
1502                     nDamage = (nDamage * ((51200 - nDist) + 1)) / 51200;
1503                     nDamage = actDamageSprite(pPlayer->nSprite, pTarget, kDamageSpirit, nDamage);
1504                     UseAmmo(pPlayer, 9, nDamage);
1505                     if (IsPlayerSprite(pTarget))
1506                     {
1507                         PLAYER* pOtherPlayer = &gPlayer[pTarget->type - kDudePlayer1];
1508                         if (!pOtherPlayer->godMode || !powerupCheck(pOtherPlayer, kPwUpDeathMask))
1509                             powerupActivate(pOtherPlayer, kPwUpDeliriumShroom);
1510                     }
1511                     fxSpawnBlood(pTarget, 0);
1512                 }
1513             }
1514         }
1515         UseAmmo(pPlayer, 9, pPlayer->ammoCount[9]);
1516         pPlayer->hasWeapon[10] = 0;
1517         pPlayer->weaponState = -1;
1518     }
1519 }
1520 
DropVoodoo(int nTrigger,PLAYER * pPlayer)1521 void DropVoodoo(int nTrigger, PLAYER *pPlayer)
1522 {
1523     UNREFERENCED_PARAMETER(nTrigger);
1524     sfxPlay3DSound(pPlayer->pSprite, 455, 2, 0);
1525     spritetype *pSprite = playerFireThing(pPlayer, 0, -4730, kThingVoodooHead, 0xccccc);
1526     if (pSprite)
1527     {
1528         int nXSprite = pSprite->extra;
1529         XSPRITE *pXSprite = &xsprite[nXSprite];
1530         pXSprite->data1 = pPlayer->ammoCount[9];
1531         evPost(pSprite->index, 3, 90, kCallbackDropVoodoo);
1532         UseAmmo(pPlayer, 6, gAmmoItemData[0].count);
1533         UseAmmo(pPlayer, 9, pPlayer->ammoCount[9]);
1534         pPlayer->hasWeapon[10] = 0;
1535     }
1536 }
1537 
1538 struct TeslaMissile
1539 {
1540     int at0; // offset
1541     int at4; // id
1542     int at8; // ammo use
1543     int atc; // sound
1544     int at10; // light
1545     int at14; // weapon flash
1546 };
1547 
FireTesla(int nTrigger,PLAYER * pPlayer)1548 void FireTesla(int nTrigger, PLAYER *pPlayer)
1549 {
1550     TeslaMissile teslaMissile[6] =
1551     {
1552         { 0, 306, 1, 470, 20, 1 },
1553         { -140, 306, 1, 470, 30, 1 },
1554         { 140, 306, 1, 470, 30, 1 },
1555         { 0, 302, 35, 471, 40, 1 },
1556         { -140, 302, 35, 471, 50, 1 },
1557         { 140, 302, 35, 471, 50, 1 },
1558     };
1559     if (nTrigger > 0 && nTrigger <= 6)
1560     {
1561         nTrigger--;
1562         spritetype *pSprite = pPlayer->pSprite;
1563         TeslaMissile *pMissile = &teslaMissile[nTrigger];
1564         if (!sub_4B2C8(pPlayer, 7, pMissile->at8))
1565         {
1566             pMissile = &teslaMissile[0];
1567             if (!sub_4B2C8(pPlayer, 7, pMissile->at8))
1568             {
1569                 pPlayer->weaponState = -1;
1570                 pPlayer->weaponQav = 76;
1571                 pPlayer->flashEffect = 0;
1572                 return;
1573             }
1574         }
1575         playerFireMissile(pPlayer, pMissile->at0, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, pMissile->at4);
1576         UseAmmo(pPlayer, 7, pMissile->at8);
1577         sfxPlay3DSound(pSprite, pMissile->atc, 1, 0);
1578         pPlayer->visibility = pMissile->at10;
1579         pPlayer->flashEffect = pMissile->at14;
1580     }
1581 }
1582 
AltFireTesla(int nTrigger,PLAYER * pPlayer)1583 void AltFireTesla(int nTrigger, PLAYER *pPlayer)
1584 {
1585     UNREFERENCED_PARAMETER(nTrigger);
1586     spritetype *pSprite = pPlayer->pSprite;
1587     playerFireMissile(pPlayer, 0, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, kMissileTeslaAlt);
1588     UseAmmo(pPlayer, pPlayer->weaponAmmo, 35);
1589     sfxPlay3DSound(pSprite, 471, 2, 0);
1590     pPlayer->visibility = 40;
1591     pPlayer->flashEffect = 1;
1592 }
1593 
FireNapalm(int nTrigger,PLAYER * pPlayer)1594 void FireNapalm(int nTrigger, PLAYER *pPlayer)
1595 {
1596     spritetype *pSprite = pPlayer->pSprite;
1597     int offset = 0;
1598     switch (nTrigger)
1599     {
1600     case 2:
1601         offset = -50;
1602         break;
1603     case 3:
1604         offset = 50;
1605         break;
1606     }
1607     playerFireMissile(pPlayer, offset, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, kMissileFireballNapam);
1608     sfxPlay3DSound(pSprite, 480, 2, 0);
1609     UseAmmo(pPlayer, 4, 1);
1610     pPlayer->flashEffect = 1;
1611 }
1612 
FireNapalm2(int nTrigger,PLAYER * pPlayer)1613 void FireNapalm2(int nTrigger, PLAYER *pPlayer)
1614 {
1615     UNREFERENCED_PARAMETER(nTrigger);
1616     spritetype *pSprite = pPlayer->pSprite;
1617     playerFireMissile(pPlayer, -120, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, kMissileFireballNapam);
1618     playerFireMissile(pPlayer, 120, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, kMissileFireballNapam);
1619     sfxPlay3DSound(pSprite, 480, 2, 0);
1620     UseAmmo(pPlayer, 4, 2);
1621     pPlayer->flashEffect = 1;
1622 }
1623 
AltFireNapalm(int nTrigger,PLAYER * pPlayer)1624 void AltFireNapalm(int nTrigger, PLAYER *pPlayer)
1625 {
1626     UNREFERENCED_PARAMETER(nTrigger);
1627     char UNUSED(bAkimbo) = powerupCheck(pPlayer, kPwUpTwoGuns);
1628     int nSpeed = mulscale16(0x8000, 0x177777)+0x66666;
1629     spritetype *pMissile = playerFireThing(pPlayer, 0, -4730, kThingNapalmBall, nSpeed);
1630     if (pMissile)
1631     {
1632         XSPRITE *pXSprite = &xsprite[pMissile->extra];
1633         pXSprite->data4 = ClipHigh(pPlayer->ammoCount[4], 12);
1634         UseAmmo(pPlayer, 4, pXSprite->data4);
1635         seqSpawn(22, 3, pMissile->extra, -1);
1636         actBurnSprite(actSpriteIdToOwnerId(pPlayer->pSprite->index), pXSprite, 600);
1637         evPost(pMissile->index, 3, 0, kCallbackFXFlameLick);
1638         sfxPlay3DSound(pMissile, 480, 2, 0);
1639         pPlayer->visibility = 30;
1640         pPlayer->flashEffect = 1;
1641     }
1642 }
1643 
FireLifeLeech(int nTrigger,PLAYER * pPlayer)1644 void FireLifeLeech(int nTrigger, PLAYER *pPlayer)
1645 {
1646     if (!CheckAmmo(pPlayer, 8, 1))
1647         return;
1648     int r1 = Random2(2000);
1649     int r2 = Random2(2000);
1650     int r3 = Random2(1000);
1651     spritetype *pMissile = playerFireMissile(pPlayer, 0, pPlayer->aim.dx+r1, pPlayer->aim.dy+r2, pPlayer->aim.dz+r3, 315);
1652     if (pMissile)
1653     {
1654         XSPRITE *pXSprite = &xsprite[pMissile->extra];
1655         pXSprite->target = pPlayer->aimTarget;
1656         pMissile->ang = (nTrigger==2) ? 1024 : 0;
1657     }
1658     if (sub_4B2C8(pPlayer, 8, 1))
1659         UseAmmo(pPlayer, 8, 1);
1660     else
1661         actDamageSprite(pPlayer->nSprite, pPlayer->pSprite, kDamageSpirit, 16);
1662     pPlayer->visibility = ClipHigh(pPlayer->visibility+5, 50);
1663 }
1664 
AltFireLifeLeech(int nTrigger,PLAYER * pPlayer)1665 void AltFireLifeLeech(int nTrigger, PLAYER *pPlayer)
1666 {
1667     UNREFERENCED_PARAMETER(nTrigger);
1668     sfxPlay3DSound(pPlayer->pSprite, 455, 2, 0);
1669     spritetype *pMissile = playerFireThing(pPlayer, 0, -4730, kThingDroppedLifeLeech, 0x19999);
1670     if (pMissile)
1671     {
1672         pMissile->cstat |= 4096;
1673         XSPRITE *pXSprite = &xsprite[pMissile->extra];
1674         pXSprite->Push = 1;
1675         pXSprite->Proximity = 1;
1676         pXSprite->DudeLockout = 1;
1677         pXSprite->data4 = ClipHigh(pPlayer->ammoCount[4], 12);
1678         pXSprite->stateTimer = 1;
1679         evPost(pMissile->index, 3, 120, kCallbackLeechStateTimer);
1680         if (gGameOptions.nGameType <= 1)
1681         {
1682             int nAmmo = pPlayer->ammoCount[8];
1683             if (nAmmo < 25 && pPlayer->pXSprite->health > ((25-nAmmo)<<4))
1684             {
1685                 actDamageSprite(pPlayer->nSprite, pPlayer->pSprite, kDamageSpirit, ((25-nAmmo)<<4));
1686                 nAmmo = 25;
1687             }
1688             pXSprite->data3 = nAmmo;
1689             UseAmmo(pPlayer, 8, nAmmo);
1690         }
1691         else
1692         {
1693             pXSprite->data3 = pPlayer->ammoCount[8];
1694             pPlayer->ammoCount[8] = 0;
1695         }
1696         pPlayer->hasWeapon[9] = 0;
1697     }
1698 }
1699 
FireBeast(int nTrigger,PLAYER * pPlayer)1700 void FireBeast(int nTrigger, PLAYER * pPlayer)
1701 {
1702     UNREFERENCED_PARAMETER(nTrigger);
1703     int r1 = Random2(2000);
1704     int r2 = Random2(2000);
1705     int r3 = Random2(2000);
1706     actFireVector(pPlayer->pSprite, 0, pPlayer->zWeapon-pPlayer->pSprite->z, pPlayer->aim.dx+r1, pPlayer->aim.dy+r2, pPlayer->aim.dz+r3, kVectorBeastSlash);
1707 }
1708 
1709 char gWeaponUpgrade[][13] = {
1710     { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
1711     { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
1712     { 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
1713     { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
1714     { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
1715     { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 },
1716     { 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0 },
1717     { 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 },
1718     { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
1719     { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0 },
1720     { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0 },
1721     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 },
1722     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
1723 };
1724 
WeaponUpgrade(PLAYER * pPlayer,char newWeapon)1725 char WeaponUpgrade(PLAYER *pPlayer, char newWeapon)
1726 {
1727     char weapon = pPlayer->curWeapon;
1728     if (!sub_4B1A4(pPlayer) && (gProfile[pPlayer->nPlayer].nWeaponSwitch&1) && (gWeaponUpgrade[pPlayer->curWeapon][newWeapon] || (gProfile[pPlayer->nPlayer].nWeaponSwitch&2)))
1729         weapon = newWeapon;
1730     return weapon;
1731 }
1732 
1733 int OrderNext[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 1 };
1734 int OrderPrev[] = { 12, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1 };
1735 
WeaponFindNext(PLAYER * pPlayer,int * a2,char bDir)1736 char WeaponFindNext(PLAYER *pPlayer, int *a2, char bDir)
1737 {
1738     int weapon = pPlayer->curWeapon;
1739     do
1740     {
1741         if (bDir)
1742             weapon = OrderNext[weapon];
1743         else
1744             weapon = OrderPrev[weapon];
1745         if (weaponModes[weapon].at0 && pPlayer->hasWeapon[weapon])
1746         {
1747             if (weapon == 9)
1748             {
1749                 if (CheckAmmo(pPlayer, weaponModes[weapon].at4, 1))
1750                     break;
1751             }
1752             else
1753             {
1754                 if (sub_4B2C8(pPlayer, weaponModes[weapon].at4, 1))
1755                     break;
1756             }
1757         }
1758     } while (weapon != pPlayer->curWeapon);
1759     if (weapon == pPlayer->curWeapon)
1760     {
1761         if (!weaponModes[weapon].at0 || !CheckAmmo(pPlayer, weaponModes[weapon].at4, 1))
1762             weapon = 1;
1763     }
1764     if (a2)
1765         *a2 = 0;
1766     return weapon;
1767 }
1768 
WeaponFindLoaded(PLAYER * pPlayer,int * a2)1769 char WeaponFindLoaded(PLAYER *pPlayer, int *a2)
1770 {
1771     char v4 = 1;
1772     int v14 = 0;
1773     if (weaponModes[pPlayer->curWeapon].at0 > 1)
1774     {
1775         for (int i = 0; i < weaponModes[pPlayer->curWeapon].at0; i++)
1776         {
1777             if (CheckAmmo(pPlayer, weaponModes[pPlayer->curWeapon].at4, 1))
1778             {
1779                 v14 = i;
1780                 v4 = pPlayer->curWeapon;
1781                 break;
1782             }
1783         }
1784     }
1785     if (v4 == 1)
1786     {
1787         int vc = 0;
1788         for (int i = 0; i < 14; i++)
1789         {
1790             int weapon = pPlayer->weaponOrder[vc][i];
1791             if (pPlayer->hasWeapon[weapon])
1792             {
1793                 for (int j = 0; j < weaponModes[weapon].at0; j++)
1794                 {
1795                     if (sub_4B1FC(pPlayer, weapon, weaponModes[weapon].at4, 1))
1796                     {
1797                         if (a2)
1798                             *a2 = j;
1799                         return weapon;
1800                     }
1801                 }
1802             }
1803         }
1804     }
1805     else if (a2)
1806         *a2 = v14;
1807     return v4;
1808 }
1809 
sub_4F0E0(PLAYER * pPlayer)1810 char sub_4F0E0(PLAYER *pPlayer)
1811 {
1812     switch (pPlayer->weaponState)
1813     {
1814     case 5:
1815         if (!pPlayer->input.buttonFlags.shoot2)
1816             pPlayer->weaponState = 6;
1817         return 1;
1818     case 6:
1819         if (pPlayer->input.buttonFlags.shoot2)
1820         {
1821             pPlayer->weaponState = 3;
1822             pPlayer->fuseTime = pPlayer->weaponTimer;
1823             StartQAV(pPlayer, 13, nClientDropCan, 0);
1824         }
1825         else if (pPlayer->input.buttonFlags.shoot)
1826         {
1827             pPlayer->weaponState = 7;
1828             pPlayer->fuseTime = 0;
1829             pPlayer->throwTime = (int)gFrameClock;
1830         }
1831         return 1;
1832     case 7:
1833     {
1834         pPlayer->throwPower = ClipHigh(divscale16((int)gFrameClock-pPlayer->throwTime,240), 65536);
1835         if (!pPlayer->input.buttonFlags.shoot)
1836         {
1837             if (!pPlayer->fuseTime)
1838                 pPlayer->fuseTime = pPlayer->weaponTimer;
1839             pPlayer->weaponState = 1;
1840             StartQAV(pPlayer, 14, nClientThrowCan, 0);
1841         }
1842         return 1;
1843     }
1844     }
1845     return 0;
1846 }
1847 
sub_4F200(PLAYER * pPlayer)1848 char sub_4F200(PLAYER *pPlayer)
1849 {
1850     switch (pPlayer->weaponState)
1851     {
1852     case 4:
1853         if (!pPlayer->input.buttonFlags.shoot2)
1854             pPlayer->weaponState = 5;
1855         return 1;
1856     case 5:
1857         if (pPlayer->input.buttonFlags.shoot2)
1858         {
1859             pPlayer->weaponState = 1;
1860             pPlayer->fuseTime = pPlayer->weaponTimer;
1861             StartQAV(pPlayer, 22, nClientDropBundle, 0);
1862         }
1863         else if (pPlayer->input.buttonFlags.shoot)
1864         {
1865             pPlayer->weaponState = 6;
1866             pPlayer->fuseTime = 0;
1867             pPlayer->throwTime = (int)gFrameClock;
1868         }
1869         return 1;
1870     case 6:
1871     {
1872         pPlayer->throwPower = ClipHigh(divscale16((int)gFrameClock-pPlayer->throwTime,240), 65536);
1873         if (!pPlayer->input.buttonFlags.shoot)
1874         {
1875             if (!pPlayer->fuseTime)
1876                 pPlayer->fuseTime = pPlayer->weaponTimer;
1877             pPlayer->weaponState = 1;
1878             StartQAV(pPlayer, 23, nClientThrowBundle, 0);
1879         }
1880         return 1;
1881     }
1882     }
1883     return 0;
1884 }
1885 
sub_4F320(PLAYER * pPlayer)1886 char sub_4F320(PLAYER *pPlayer)
1887 {
1888     switch (pPlayer->weaponState)
1889     {
1890     case 9:
1891         pPlayer->throwPower = ClipHigh(divscale16((int)gFrameClock-pPlayer->throwTime,240), 65536);
1892         pPlayer->weaponTimer = 0;
1893         if (!pPlayer->input.buttonFlags.shoot)
1894         {
1895             pPlayer->weaponState = 8;
1896             StartQAV(pPlayer, 29, nClientThrowProx, 0);
1897         }
1898         break;
1899     }
1900     return 0;
1901 }
1902 
sub_4F3A0(PLAYER * pPlayer)1903 char sub_4F3A0(PLAYER *pPlayer)
1904 {
1905     switch (pPlayer->weaponState)
1906     {
1907     case 13:
1908         pPlayer->throwPower = ClipHigh(divscale16((int)gFrameClock-pPlayer->throwTime,240), 65536);
1909         if (!pPlayer->input.buttonFlags.shoot)
1910         {
1911             pPlayer->weaponState = 11;
1912             StartQAV(pPlayer, 39, nClientThrowRemote, 0);
1913         }
1914         break;
1915     }
1916     return 0;
1917 }
1918 
sub_4F414(PLAYER * pPlayer)1919 char sub_4F414(PLAYER *pPlayer)
1920 {
1921     switch (pPlayer->weaponState)
1922     {
1923     case 4:
1924         pPlayer->weaponState = 6;
1925         StartQAV(pPlayer, 114, nClientFireLifeLeech, 1);
1926         return 1;
1927     case 6:
1928         if (!pPlayer->input.buttonFlags.shoot2)
1929         {
1930             pPlayer->weaponState = 2;
1931             StartQAV(pPlayer, 118, -1, 0);
1932             return 1;
1933         }
1934         break;
1935     case 8:
1936         pPlayer->weaponState = 2;
1937         StartQAV(pPlayer, 118, -1, 0);
1938         return 1;
1939     }
1940     return 0;
1941 }
1942 
sub_4F484(PLAYER * pPlayer)1943 char sub_4F484(PLAYER *pPlayer)
1944 {
1945     switch (pPlayer->weaponState)
1946     {
1947     case 4:
1948         pPlayer->weaponState = 5;
1949         if (sub_4B2C8(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns))
1950             StartQAV(pPlayer, 84, nClientFireTesla, 1);
1951         else
1952             StartQAV(pPlayer, 77, nClientFireTesla, 1);
1953         return 1;
1954     case 5:
1955         if (!pPlayer->input.buttonFlags.shoot)
1956         {
1957             pPlayer->weaponState = 2;
1958             if (sub_4B2C8(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns))
1959                 StartQAV(pPlayer, 87, -1, 0);
1960             else
1961                 StartQAV(pPlayer, 80, -1, 0);
1962             return 1;
1963         }
1964         break;
1965     case 7:
1966         pPlayer->weaponState = 2;
1967         if (sub_4B2C8(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns))
1968             StartQAV(pPlayer, 87, -1, 0);
1969         else
1970             StartQAV(pPlayer, 80, -1, 0);
1971         return 1;
1972     }
1973     return 0;
1974 }
1975 
WeaponProcess(PLAYER * pPlayer)1976 void WeaponProcess(PLAYER *pPlayer) {
1977 
1978     pPlayer->flashEffect = ClipLow(pPlayer->flashEffect - 1, 0);
1979 
1980     #ifdef NOONE_EXTENSIONS
1981     if (gPlayerCtrl[pPlayer->nPlayer].qavScene.index >= 0 && pPlayer->pXSprite->health > 0) {
1982         playerQavSceneProcess(pPlayer, &gPlayerCtrl[pPlayer->nPlayer].qavScene);
1983         UpdateAimVector(pPlayer);
1984         return;
1985     }
1986     #endif
1987 
1988     if (pPlayer->pXSprite->health == 0)
1989     {
1990         pPlayer->qavLoop = 0;
1991         sfxKill3DSound(pPlayer->pSprite, 1, -1);
1992     }
1993     if (pPlayer->isUnderwater && BannedUnderwater(pPlayer->curWeapon))
1994     {
1995         if (sub_4B1A4(pPlayer))
1996         {
1997             if (pPlayer->curWeapon == 7)
1998             {
1999                 pPlayer->fuseTime = pPlayer->weaponTimer;
2000                 DropCan(1, pPlayer);
2001                 pPlayer->weaponState = 3;
2002             }
2003             else if (pPlayer->curWeapon == 6)
2004             {
2005                 pPlayer->fuseTime = pPlayer->weaponTimer;
2006                 DropBundle(1, pPlayer);
2007                 pPlayer->weaponState = 1;
2008             }
2009         }
2010         WeaponLower(pPlayer);
2011         pPlayer->throwPower = 0;
2012     }
2013     WeaponPlay(pPlayer);
2014     UpdateAimVector(pPlayer);
2015     pPlayer->weaponTimer -= 4;
2016     char bShoot = pPlayer->input.buttonFlags.shoot;
2017     char bShoot2 = pPlayer->input.buttonFlags.shoot2;
2018     if (pPlayer->qavLoop && pPlayer->pXSprite->health > 0)
2019     {
2020         if (bShoot && CheckAmmo(pPlayer, pPlayer->weaponAmmo, 1))
2021         {
2022             while (pPlayer->weaponTimer <= 0)
2023                 pPlayer->weaponTimer += weaponQAV[pPlayer->weaponQav]->at10;
2024         }
2025         else
2026         {
2027             pPlayer->weaponTimer = 0;
2028             pPlayer->qavLoop = 0;
2029         }
2030         return;
2031     }
2032     pPlayer->weaponTimer = ClipLow(pPlayer->weaponTimer, 0);
2033     switch (pPlayer->curWeapon)
2034     {
2035     case 7:
2036         if (sub_4F0E0(pPlayer))
2037             return;
2038         break;
2039     case 6:
2040         if (sub_4F200(pPlayer))
2041             return;
2042         break;
2043     case 11:
2044         if (sub_4F320(pPlayer))
2045             return;
2046         break;
2047     case 12:
2048         if (sub_4F3A0(pPlayer))
2049             return;
2050         break;
2051     }
2052     if (pPlayer->weaponTimer > 0)
2053         return;
2054     if (pPlayer->pXSprite->health == 0 || pPlayer->curWeapon == 0)
2055         pPlayer->weaponQav = -1;
2056     switch (pPlayer->curWeapon)
2057     {
2058     case 9:
2059         if (sub_4F414(pPlayer))
2060             return;
2061         break;
2062     case 8:
2063         if (sub_4F484(pPlayer))
2064             return;
2065         break;
2066     }
2067     if (VanillaMode())
2068     {
2069         if (pPlayer->nextWeapon)
2070         {
2071             sfxKill3DSound(pPlayer->pSprite, -1, 441);
2072             pPlayer->weaponState = 0;
2073             pPlayer->input.newWeapon = pPlayer->nextWeapon;
2074             pPlayer->nextWeapon = 0;
2075         }
2076     }
2077     if (pPlayer->input.keyFlags.nextWeapon)
2078     {
2079         pPlayer->input.keyFlags.nextWeapon = 0;
2080         if (VanillaMode())
2081         {
2082             pPlayer->weaponState = 0;
2083         }
2084         pPlayer->nextWeapon = 0;
2085         int t;
2086         char weapon = WeaponFindNext(pPlayer, &t, 1);
2087         pPlayer->weaponMode[weapon] = t;
2088         if (VanillaMode())
2089         {
2090             if (pPlayer->curWeapon)
2091             {
2092                 WeaponLower(pPlayer);
2093                 pPlayer->nextWeapon = weapon;
2094                 return;
2095             }
2096         }
2097         pPlayer->input.newWeapon = weapon;
2098     }
2099     if (pPlayer->input.keyFlags.prevWeapon)
2100     {
2101         pPlayer->input.keyFlags.prevWeapon = 0;
2102         if (VanillaMode())
2103         {
2104             pPlayer->weaponState = 0;
2105         }
2106         pPlayer->nextWeapon = 0;
2107         int t;
2108         char weapon = WeaponFindNext(pPlayer, &t, 0);
2109         pPlayer->weaponMode[weapon] = t;
2110         if (VanillaMode())
2111         {
2112             if (pPlayer->curWeapon)
2113             {
2114                 WeaponLower(pPlayer);
2115                 pPlayer->nextWeapon = weapon;
2116                 return;
2117             }
2118         }
2119         pPlayer->input.newWeapon = weapon;
2120     }
2121     if (!VanillaMode())
2122     {
2123         if (pPlayer->nextWeapon)
2124         {
2125             sfxKill3DSound(pPlayer->pSprite, -1, 441);
2126             pPlayer->input.newWeapon = pPlayer->nextWeapon;
2127             pPlayer->nextWeapon = 0;
2128         }
2129     }
2130     if (pPlayer->weaponState == -1)
2131     {
2132         pPlayer->weaponState = 0;
2133         int t;
2134         char weapon = WeaponFindLoaded(pPlayer, &t);
2135         pPlayer->weaponMode[weapon] = t;
2136         if (pPlayer->curWeapon)
2137         {
2138             WeaponLower(pPlayer);
2139             pPlayer->nextWeapon = weapon;
2140             return;
2141         }
2142         pPlayer->input.newWeapon = weapon;
2143     }
2144     if (pPlayer->input.newWeapon)
2145     {
2146         if (pPlayer->input.newWeapon == 6)
2147         {
2148             if (pPlayer->curWeapon == 6)
2149             {
2150                 if (sub_4B2C8(pPlayer, 10, 1))
2151                     pPlayer->input.newWeapon = 11;
2152                 else if (sub_4B2C8(pPlayer, 11, 1))
2153                     pPlayer->input.newWeapon = 12;
2154             }
2155             else if (pPlayer->curWeapon == 11)
2156             {
2157                 if (sub_4B2C8(pPlayer, 11, 1))
2158                     pPlayer->input.newWeapon = 12;
2159                 else if (sub_4B2C8(pPlayer, 5, 1) && pPlayer->isUnderwater == 0)
2160                     pPlayer->input.newWeapon = 6;
2161             }
2162             else if (pPlayer->curWeapon == 12)
2163             {
2164                 if (sub_4B2C8(pPlayer, 5, 1) && pPlayer->isUnderwater == 0)
2165                     pPlayer->input.newWeapon = 6;
2166                 else if (sub_4B2C8(pPlayer, 10, 1))
2167                     pPlayer->input.newWeapon = 11;
2168             }
2169             else
2170             {
2171                 if (sub_4B2C8(pPlayer, 5, 1) && pPlayer->isUnderwater == 0)
2172                     pPlayer->input.newWeapon = 6;
2173                 else if (sub_4B2C8(pPlayer, 10, 1))
2174                     pPlayer->input.newWeapon = 11;
2175                 else if (sub_4B2C8(pPlayer, 11, 1))
2176                     pPlayer->input.newWeapon = 12;
2177             }
2178         }
2179         if (pPlayer->pXSprite->health == 0 || pPlayer->hasWeapon[pPlayer->input.newWeapon] == 0)
2180         {
2181             pPlayer->input.newWeapon = 0;
2182             return;
2183         }
2184         if (pPlayer->isUnderwater && BannedUnderwater(pPlayer->input.newWeapon) && !sub_4B1A4(pPlayer))
2185         {
2186             pPlayer->input.newWeapon = 0;
2187             return;
2188         }
2189         int nWeapon = pPlayer->input.newWeapon;
2190         int v4c = weaponModes[nWeapon].at0;
2191         if (!pPlayer->curWeapon)
2192         {
2193             int nAmmoType = weaponModes[nWeapon].at4;
2194             if (v4c > 1)
2195             {
2196                 if (CheckAmmo(pPlayer, nAmmoType, 1) || nAmmoType == 11)
2197                     WeaponRaise(pPlayer);
2198                 pPlayer->input.newWeapon = 0;
2199             }
2200             else
2201             {
2202                 if (sub_4B1FC(pPlayer, nWeapon, nAmmoType, 1))
2203                     WeaponRaise(pPlayer);
2204                 else
2205                 {
2206                     pPlayer->weaponState = 0;
2207                     int t;
2208                     char weapon = WeaponFindLoaded(pPlayer, &t);
2209                     pPlayer->weaponMode[weapon] = t;
2210                     if (pPlayer->curWeapon)
2211                     {
2212                         WeaponLower(pPlayer);
2213                         pPlayer->nextWeapon = weapon;
2214                         return;
2215                     }
2216                     pPlayer->input.newWeapon = weapon;
2217                 }
2218             }
2219             return;
2220         }
2221         if (nWeapon == pPlayer->curWeapon && v4c <= 1)
2222         {
2223             pPlayer->input.newWeapon = 0;
2224             return;
2225         }
2226         int i = 0;
2227         if (nWeapon == pPlayer->curWeapon)
2228             i = 1;
2229         for (; i <= v4c; i++)
2230         {
2231             int v6c = (pPlayer->weaponMode[nWeapon]+i)%v4c;
2232             if (sub_4B1FC(pPlayer, nWeapon, weaponModes[nWeapon].at4, 1))
2233             {
2234                 WeaponLower(pPlayer);
2235                 pPlayer->weaponMode[nWeapon] = v6c;
2236                 return;
2237             }
2238         }
2239         pPlayer->input.newWeapon = 0;
2240         return;
2241     }
2242     if (pPlayer->curWeapon && !CheckAmmo(pPlayer, pPlayer->weaponAmmo, 1) && pPlayer->weaponAmmo != 11)
2243     {
2244         pPlayer->weaponState = -1;
2245         return;
2246     }
2247     if (bShoot)
2248     {
2249         switch (pPlayer->curWeapon)
2250         {
2251         case 1:
2252             StartQAV(pPlayer, 2, nClientFirePitchfork, 0);
2253             return;
2254         case 7:
2255             switch (pPlayer->weaponState)
2256             {
2257             case 3:
2258                 pPlayer->weaponState = 4;
2259                 StartQAV(pPlayer, 10, nClientFireSpray, 1);
2260                 return;
2261             }
2262             break;
2263         case 6:
2264             switch (pPlayer->weaponState)
2265             {
2266             case 3:
2267                 pPlayer->weaponState = 6;
2268                 pPlayer->fuseTime = -1;
2269                 pPlayer->throwTime = (int)gFrameClock;
2270                 StartQAV(pPlayer, 21, nClientExplodeBundle, 0);
2271                 return;
2272             }
2273             break;
2274         case 11:
2275             switch (pPlayer->weaponState)
2276             {
2277             case 7:
2278                 pPlayer->weaponQav = 27;
2279                 pPlayer->weaponState = 9;
2280                 pPlayer->throwTime = (int)gFrameClock;
2281                 return;
2282             }
2283             break;
2284         case 12:
2285             switch (pPlayer->weaponState)
2286             {
2287             case 10:
2288                 pPlayer->weaponQav = 36;
2289                 pPlayer->weaponState = 13;
2290                 pPlayer->throwTime = (int)gFrameClock;
2291                 return;
2292             case 11:
2293                 pPlayer->weaponState = 12;
2294                 StartQAV(pPlayer, 40, nClientFireRemote, 0);
2295                 return;
2296             }
2297             break;
2298         case 3:
2299             switch (pPlayer->weaponState)
2300             {
2301             case 7:
2302                 pPlayer->weaponState = 6;
2303                 StartQAV(pPlayer, 61, nClientFireShotgun, 0);
2304                 return;
2305             case 3:
2306                 pPlayer->weaponState = 2;
2307                 StartQAV(pPlayer, 54, nClientFireShotgun, 0);
2308                 return;
2309             case 2:
2310                 pPlayer->weaponState = 1;
2311                 StartQAV(pPlayer, 55, nClientFireShotgun, 0);
2312                 return;
2313             }
2314             break;
2315         case 4:
2316             if (powerupCheck(pPlayer, kPwUpTwoGuns) && sub_4B2C8(pPlayer, 3, 2))
2317                 StartQAV(pPlayer, 71, nClientFireTommy, 1);
2318             else
2319                 StartQAV(pPlayer, 66, nClientFireTommy, 1);
2320             return;
2321         case 2:
2322             if (powerupCheck(pPlayer, kPwUpTwoGuns) && sub_4B2C8(pPlayer, 1, 2))
2323                 StartQAV(pPlayer, 48, nClientFireFlare, 0);
2324             else
2325                 StartQAV(pPlayer, 43, nClientFireFlare, 0);
2326             return;
2327         case 10:
2328         {
2329             static int nChance[] = { 0xa000, 0xc000, 0xe000, 0x10000 };
2330             int nRand = wrand()*2;
2331             int i;
2332             for (i = 0; nChance[i] < nRand; i++)
2333             {
2334             }
2335             pPlayer->voodooTarget = pPlayer->aimTarget;
2336             if (pPlayer->voodooTarget == -1 || sprite[pPlayer->voodooTarget].statnum != kStatDude)
2337                 i = 4;
2338             StartQAV(pPlayer,103+i, nClientFireVoodoo, 0);
2339             return;
2340         }
2341         case 8:
2342             switch (pPlayer->weaponState)
2343             {
2344             case 2:
2345                 pPlayer->weaponState = 4;
2346                 if (sub_4B2C8(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns))
2347                     StartQAV(pPlayer, 84, nClientFireTesla, 0);
2348                 else
2349                     StartQAV(pPlayer, 77, nClientFireTesla, 0);
2350                 return;
2351             case 5:
2352                 if (sub_4B2C8(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns))
2353                     StartQAV(pPlayer, 84, nClientFireTesla, 0);
2354                 else
2355                     StartQAV(pPlayer, 77, nClientFireTesla, 0);
2356                 return;
2357             }
2358             break;
2359         case 5:
2360             if (powerupCheck(pPlayer, kPwUpTwoGuns))
2361                 StartQAV(pPlayer, 122, nClientFireNapalm, 0);
2362             else
2363                 StartQAV(pPlayer, 91, nClientFireNapalm, 0);
2364             return;
2365         case 9:
2366             sfxPlay3DSound(pPlayer->pSprite, 494, 2, 0);
2367             StartQAV(pPlayer, 116, nClientFireLifeLeech, 0);
2368             return;
2369         case 13:
2370             StartQAV(pPlayer, 95+Random(4), nClientFireBeast, 0);
2371             return;
2372         }
2373     }
2374     if (bShoot2)
2375     {
2376         switch (pPlayer->curWeapon)
2377         {
2378         case 1:
2379             StartQAV(pPlayer, 2, nClientFirePitchfork, 0);
2380             return;
2381         case 7:
2382             switch (pPlayer->weaponState)
2383             {
2384             case 3:
2385                 pPlayer->weaponState = 5;
2386                 StartQAV(pPlayer, 12, nClientExplodeCan, 0);
2387                 return;
2388             }
2389             break;
2390         case 6:
2391             switch (pPlayer->weaponState)
2392             {
2393             case 3:
2394                 pPlayer->weaponState = 4;
2395                 StartQAV(pPlayer, 21, nClientExplodeBundle, 0);
2396                 return;
2397             case 7:
2398                 pPlayer->weaponState = 8;
2399                 StartQAV(pPlayer, 28, nClientDropProx, 0);
2400                 return;
2401             case 10:
2402                 pPlayer->weaponState = 11;
2403                 StartQAV(pPlayer, 38, nClientDropRemote, 0);
2404                 return;
2405             case 11:
2406                 if (pPlayer->ammoCount[11] > 0)
2407                 {
2408                     pPlayer->weaponState = 10;
2409                     StartQAV(pPlayer, 30, -1, 0);
2410                 }
2411                 return;
2412             }
2413             break;
2414         case 11:
2415             switch (pPlayer->weaponState)
2416             {
2417             case 7:
2418                 pPlayer->weaponState = 8;
2419                 StartQAV(pPlayer, 28, nClientDropProx, 0);
2420                 return;
2421             }
2422             break;
2423         case 12:
2424             switch (pPlayer->weaponState)
2425             {
2426             case 10:
2427                 pPlayer->weaponState = 11;
2428                 StartQAV(pPlayer, 38, nClientDropRemote, 0);
2429                 return;
2430             case 11:
2431                 if (pPlayer->ammoCount[11] > 0)
2432                 {
2433                     pPlayer->weaponState = 10;
2434                     StartQAV(pPlayer, 30, -1, 0);
2435                 }
2436                 return;
2437             }
2438             break;
2439         case 3:
2440             switch (pPlayer->weaponState)
2441             {
2442             case 7:
2443                 pPlayer->weaponState = 6;
2444                 StartQAV(pPlayer, 62, nClientFireShotgun, 0);
2445                 return;
2446             case 3:
2447                 pPlayer->weaponState = 1;
2448                 StartQAV(pPlayer, 56, nClientFireShotgun, 0);
2449                 return;
2450             case 2:
2451                 pPlayer->weaponState = 1;
2452                 StartQAV(pPlayer, 55, nClientFireShotgun, 0);
2453                 return;
2454             }
2455             break;
2456         case 4:
2457             if (powerupCheck(pPlayer, kPwUpTwoGuns) && sub_4B2C8(pPlayer, 3, 2))
2458                 StartQAV(pPlayer, 73, nClientAltFireSpread2, 0);
2459             else
2460                 StartQAV(pPlayer, 67, nClientAltFireSpread2, 0);
2461             return;
2462         case 10:
2463             sfxPlay3DSound(pPlayer->pSprite, 461, 2, 0);
2464             StartQAV(pPlayer, 110, nClientAltFireVoodoo, 0);
2465             return;
2466 #if 0
2467         case 2:
2468             if (powerupCheck(pPlayer, kPwUpTwoGuns) && sub_4B2C8(pPlayer, 1, 2))
2469                 StartQAV(pPlayer, 48, nClientFireFlare, 0);
2470             else
2471                 StartQAV(pPlayer, 43, nClientFireFlare, 0);
2472             return;
2473 #endif
2474         case 8:
2475             if (sub_4B2C8(pPlayer, 7, 35))
2476             {
2477                 if (sub_4B2C8(pPlayer, 7, 70) && powerupCheck(pPlayer, kPwUpTwoGuns))
2478                     StartQAV(pPlayer, 85, nClientFireTesla, 0);
2479                 else
2480                     StartQAV(pPlayer, 78, nClientFireTesla, 0);
2481             }
2482             else
2483             {
2484                 if (sub_4B2C8(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns))
2485                     StartQAV(pPlayer, 84, nClientFireTesla, 0);
2486                 else
2487                     StartQAV(pPlayer, 77, nClientFireTesla, 0);
2488             }
2489             return;
2490         case 5:
2491             if (powerupCheck(pPlayer, kPwUpTwoGuns))
2492                 // by NoOne: allow napalm launcher alt fire act like in v1.0x versions
2493                 if (gGameOptions.weaponsV10x && !VanillaMode() && !DemoRecordStatus()) StartQAV(pPlayer, 123, nClientFireNapalm2, 0);
2494                 else StartQAV(pPlayer, 122, nClientAltFireNapalm, 0);
2495             else
2496                 StartQAV(pPlayer, 91, (gGameOptions.weaponsV10x && !VanillaMode() && !DemoRecordStatus()) ? nClientFireNapalm : nClientAltFireNapalm, 0);
2497             return;
2498         case 2:
2499             if (CheckAmmo(pPlayer, 1, 8))
2500             {
2501                 if (powerupCheck(pPlayer, kPwUpTwoGuns) && sub_4B2C8(pPlayer, 1, 16))
2502                     StartQAV(pPlayer, 48, nClientAltFireFlare, 0);
2503                 else
2504                     StartQAV(pPlayer, 43, nClientAltFireFlare, 0);
2505             }
2506             else
2507             {
2508                 if (powerupCheck(pPlayer, kPwUpTwoGuns) && sub_4B2C8(pPlayer, 1, 2))
2509                     StartQAV(pPlayer, 48, nClientFireFlare, 0);
2510                 else
2511                     StartQAV(pPlayer, 43, nClientFireFlare, 0);
2512             }
2513             return;
2514         case 9:
2515             if (gGameOptions.nGameType <= 1 && !sub_4B2C8(pPlayer, 8, 1) && pPlayer->pXSprite->health < (25 << 4))
2516             {
2517                 sfxPlay3DSound(pPlayer->pSprite, 494, 2, 0);
2518                 StartQAV(pPlayer, 116, nClientFireLifeLeech, 0);
2519             }
2520             else
2521             {
2522                 StartQAV(pPlayer, 119, -1, 0);
2523                 AltFireLifeLeech(1, pPlayer);
2524                 pPlayer->weaponState = -1;
2525             }
2526             return;
2527         }
2528     }
2529     WeaponUpdateState(pPlayer);
2530 }
2531 
sub_51340(spritetype * pMissile,int a2)2532 void sub_51340(spritetype *pMissile, int a2)
2533 {
2534     char va4[(kMaxSectors+7)>>3];
2535     int x = pMissile->x;
2536     int y = pMissile->y;
2537     int z = pMissile->z;
2538     int nDist = 300;
2539     int nSector = pMissile->sectnum;
2540     int nOwner = actSpriteOwnerToSpriteId(pMissile);
2541     gAffectedSectors[0] = -1;
2542     gAffectedXWalls[0] = -1;
2543     GetClosestSpriteSectors(nSector, x, y, nDist, gAffectedSectors, va4, gAffectedXWalls);
2544     char v4 = 1;
2545     int v24 = -1;
2546     actHitcodeToData(a2, &gHitInfo, &v24, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2547     if (a2 == 3 && v24 >= 0 && sprite[v24].statnum == kStatDude)
2548         v4 = 0;
2549     for (int nSprite = headspritestat[kStatDude]; nSprite >= 0; nSprite = nextspritestat[nSprite])
2550     {
2551         if (nSprite != nOwner || v4)
2552         {
2553             spritetype *pSprite = &sprite[nSprite];
2554             if (pSprite->flags&32)
2555                 continue;
2556             if (TestBitString(va4, pSprite->sectnum) && CheckProximity(pSprite, x, y, z, nSector, nDist))
2557             {
2558                 int dx = pMissile->x-pSprite->x;
2559                 int dy = pMissile->y-pSprite->y;
2560                 int nDamage = ClipLow((nDist-(ksqrt(dx*dx+dy*dy)>>4)+20)>>1, 10);
2561                 if (nSprite == nOwner)
2562                     nDamage /= 2;
2563                 actDamageSprite(nOwner, pSprite, kDamageTesla, nDamage<<4);
2564             }
2565         }
2566     }
2567     for (int nSprite = headspritestat[kStatThing]; nSprite >= 0; nSprite = nextspritestat[nSprite])
2568     {
2569         spritetype *pSprite = &sprite[nSprite];
2570         if (pSprite->flags&32)
2571             continue;
2572         if (TestBitString(va4, pSprite->sectnum) && CheckProximity(pSprite, x, y, z, nSector, nDist))
2573         {
2574             XSPRITE *pXSprite = &xsprite[pSprite->extra];
2575             if (!pXSprite->locked)
2576             {
2577                 int dx = pMissile->x-pSprite->x;
2578                 int dy = pMissile->y-pSprite->y;
2579                 int nDamage = ClipLow(nDist-(ksqrt(dx*dx+dy*dy)>>4)+20, 20);
2580                 actDamageSprite(nOwner, pSprite, kDamageTesla, nDamage<<4);
2581             }
2582         }
2583     }
2584 }
2585 
2586 class WeaponLoadSave : public LoadSave
2587 {
2588 public:
2589     virtual void Load();
2590     virtual void Save();
2591 };
2592 
Load()2593 void WeaponLoadSave::Load()
2594 {
2595 }
2596 
Save()2597 void WeaponLoadSave::Save()
2598 {
2599 }
2600 
2601 static WeaponLoadSave *myLoadSave;
2602 
WeaponLoadSaveConstruct(void)2603 void WeaponLoadSaveConstruct(void)
2604 {
2605     myLoadSave = new WeaponLoadSave();
2606 }
2607 
2608