1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 1997, 2005 - 3D Realms Entertainment
4 
5 This file is part of Shadow Warrior version 1.2
6 
7 Shadow Warrior is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
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 Original Source: 1997 - Frank Maddin and Jim Norwood
23 Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
24 */
25 //-------------------------------------------------------------------------
26 #include "build.h"
27 #include "common.h"
28 
29 #include "names2.h"
30 #include "game.h"
31 #include "tags.h"
32 #include "common_game.h"
33 #include "break.h"
34 #include "quake.h"
35 #include "sprite.h"
36 
37 #define QUAKE_Match(sp) (SP_TAG2(sp))
38 #define QUAKE_Zamt(sp) (SP_TAG3(sp))
39 #define QUAKE_Radius(sp) (SP_TAG4(sp))
40 #define QUAKE_Duration(sp) (SP_TAG5(sp))
41 #define QUAKE_WaitSecs(sp) (SP_TAG6(sp))
42 #define QUAKE_AngAmt(sp) (SP_TAG7(sp))
43 #define QUAKE_PosAmt(sp) (SP_TAG8(sp))
44 #define QUAKE_RandomTest(sp) (SP_TAG9(sp))
45 #define QUAKE_WaitTics(sp) (SP_TAG13(sp))
46 
47 #define QUAKE_TestDontTaper(sp) (TEST_BOOL1(sp))
48 #define QUAKE_KillAfterQuake(sp) (TEST_BOOL2(sp))
49 // only for timed quakes
50 #define QUAKE_WaitForTrigger(sp) (TEST_BOOL3(sp))
51 
CopyQuakeSpotToOn(SPRITEp sp)52 short CopyQuakeSpotToOn(SPRITEp sp)
53 {
54     short New;
55     SPRITEp np;
56 
57     New = COVERinsertsprite(sp->sectnum, STAT_QUAKE_SPOT);
58     np = &sprite[New];
59 
60     memcpy(np, sp, sizeof(SPRITE));
61 
62     np->sectnum = sp->sectnum;
63     np->statnum = sp->statnum;
64 
65     np->cstat = 0;
66     np->extra = 0;
67     np->owner = -1;
68 
69     change_sprite_stat(New, STAT_QUAKE_ON);
70 
71     QUAKE_Duration(np) *= 120;
72 
73     return New;
74 }
75 
76 
DoQuakeMatch(short match)77 void DoQuakeMatch(short match)
78 {
79     short i, nexti;
80     SPRITEp sp;
81 
82     TRAVERSE_SPRITE_STAT(headspritestat[STAT_QUAKE_SPOT], i, nexti)
83     {
84         sp = &sprite[i];
85 
86         if (QUAKE_Match(sp) == match)
87         {
88             if ((int16_t)QUAKE_WaitTics(sp) > 0)
89             {
90                 // its not waiting any more
91                 RESET_BOOL3(sp);
92             }
93             else
94             {
95                 CopyQuakeSpotToOn(sp);
96                 if (QUAKE_KillAfterQuake(sp))
97                 {
98                     KillSprite(i);
99                     continue;
100                 }
101             }
102         }
103 
104     }
105 }
106 
ProcessQuakeOn(void)107 void ProcessQuakeOn(void)
108 {
109     short i, nexti;
110     SPRITEp sp;
111 
112     TRAVERSE_SPRITE_STAT(headspritestat[STAT_QUAKE_ON], i, nexti)
113     {
114         sp = &sprite[i];
115 
116         // get rid of quake when timer runs out
117         QUAKE_Duration(sp) -= synctics*4;
118         if (QUAKE_Duration(sp) < 0)
119         {
120             KillSprite(i);
121             continue;
122         }
123     }
124 }
125 
ProcessQuakeSpot(void)126 void ProcessQuakeSpot(void)
127 {
128     short i, nexti;
129     SPRITEp sp;
130     int rand_test;
131 
132     // check timed quakes and random quakes
133     TRAVERSE_SPRITE_STAT(headspritestat[STAT_QUAKE_SPOT], i, nexti)
134     {
135         sp = &sprite[i];
136 
137         // not a timed quake
138         if (!QUAKE_WaitSecs(sp))
139             continue;
140 
141         // don't process unless triggered
142         if (QUAKE_WaitForTrigger(sp))
143             continue;
144 
145         // spawn a quake if time is up
146         //QUAKE_WaitTics(sp) -= 4*synctics;
147         SET_SP_TAG13(sp, (QUAKE_WaitTics(sp)-4*synctics));
148         if ((int16_t)QUAKE_WaitTics(sp) < 0)
149         {
150             // reset timer - add in Duration of quake
151             //QUAKE_WaitTics(sp) = ((QUAKE_WaitSecs(sp)*10L) + QUAKE_Duration(sp)) * 120L;
152             SET_SP_TAG13(sp, (((QUAKE_WaitSecs(sp)*10L) + QUAKE_Duration(sp)) * 120L));
153 
154             // spawn a quake if condition is met
155             rand_test = QUAKE_RandomTest(sp);
156             // wrong - all quakes need to happen at the same time on all computerssg
157             //if (!rand_test || (rand_test && STD_RANDOM_RANGE(128) < rand_test))
158             if (!rand_test || (rand_test && RANDOM_RANGE(128) < rand_test))
159             {
160                 CopyQuakeSpotToOn(sp);
161                 // kill quake spot if needed
162                 if (QUAKE_KillAfterQuake(sp))
163                 {
164                     DeleteNoSoundOwner(i);
165                     KillSprite(i);
166                     continue;
167                 }
168             }
169         }
170     }
171 }
172 
QuakeViewChange(PLAYERp pp,int * z_diff,int * x_diff,int * y_diff,short * ang_diff)173 void QuakeViewChange(PLAYERp pp, int *z_diff, int *x_diff, int *y_diff, short *ang_diff)
174 {
175     short i, nexti;
176     SPRITEp sp;
177     SPRITEp save_sp = NULL;
178     int dist,save_dist = 999999;
179     int dist_diff, scale_value;
180     int ang_amt;
181     int radius;
182     int pos_amt;
183 
184     *z_diff = 0;
185     *x_diff = 0;
186     *y_diff = 0;
187     *ang_diff = 0;
188 
189     if (GamePaused)
190         return;
191 
192     // find the closest quake - should be a strength value
193     TRAVERSE_SPRITE_STAT(headspritestat[STAT_QUAKE_ON], i, nexti)
194     {
195         sp = &sprite[i];
196 
197         dist = FindDistance3D(pp->posx - sp->x, pp->posy - sp->y, pp->posz - sp->z);
198 
199         // shake whole level
200         if (QUAKE_TestDontTaper(sp))
201         {
202             save_dist = dist;
203             save_sp = sp;
204             break;
205         }
206 
207         if (dist < save_dist)
208         {
209             save_dist = dist;
210             save_sp = sp;
211         }
212     }
213 
214     if (!save_sp)
215         return;
216     else
217         sp = save_sp;
218 
219     radius = QUAKE_Radius(sp) * 8L;
220     if (save_dist > radius)
221         return;
222 
223     *z_diff = Z(STD_RANDOM_RANGE(QUAKE_Zamt(sp)) - (QUAKE_Zamt(sp)/2));
224 
225     ang_amt = QUAKE_AngAmt(sp) * 4L;
226     *ang_diff = STD_RANDOM_RANGE(ang_amt) - (ang_amt/2);
227 
228     pos_amt = QUAKE_PosAmt(sp) * 4L;
229     *x_diff = STD_RANDOM_RANGE(pos_amt) - (pos_amt/2);
230     *y_diff = STD_RANDOM_RANGE(pos_amt) - (pos_amt/2);
231 
232     if (!QUAKE_TestDontTaper(sp))
233     {
234         // scale values from epicenter
235         dist_diff = radius - save_dist;
236         scale_value = divscale16(dist_diff, radius);
237 
238         *z_diff = mulscale16(*z_diff, scale_value);
239         *ang_diff = mulscale16(*ang_diff, scale_value);
240         *x_diff = mulscale16(*x_diff, scale_value);
241         *y_diff = mulscale16(*y_diff, scale_value);
242     }
243 }
244 
SpawnQuake(short sectnum,int x,int y,int z,short tics,short amt,int radius)245 int SpawnQuake(short sectnum, int x, int y, int z,
246                short tics, short amt, int radius)
247 {
248     short SpriteNum;
249     SPRITEp sp;
250 
251     SpriteNum = COVERinsertsprite(sectnum, STAT_QUAKE_ON);
252     sp = &sprite[SpriteNum];
253 
254     ASSERT(SpriteNum >= 0);
255 
256     sp->x = x;
257     sp->y = y;
258     sp->z = z;
259     sp->cstat = 0;
260     sp->owner = -1;
261     sp->extra = 0;
262 
263     QUAKE_Match(sp) = -1;
264     QUAKE_Zamt(sp) = amt;
265     QUAKE_Radius(sp) = radius/8;
266     QUAKE_Duration(sp) = tics;
267     QUAKE_AngAmt(sp) = 8;
268     QUAKE_PosAmt(sp) = 0;
269 
270     PlaySound(DIGI_ERUPTION, &sp->x, &sp->y, &sp->z, v3df_follow|v3df_dontpan);
271     Set3DSoundOwner(SpriteNum);
272 
273     return SpriteNum;
274 }
275 
276 SWBOOL
SetQuake(PLAYERp pp,short tics,short amt)277 SetQuake(PLAYERp pp, short tics, short amt)
278 {
279     SpawnQuake(pp->cursectnum, pp->posx, pp->posy, pp->posz,  tics, amt, 30000);
280     return FALSE;
281 }
282 
283 int
SetExpQuake(int16_t Weapon)284 SetExpQuake(int16_t Weapon)
285 {
286     SPRITEp sp = &sprite[Weapon];
287 
288     SpawnQuake(sp->sectnum, sp->x, sp->y, sp->z,  40, 4, 20000); // !JIM! was 8, 40000
289     return 0;
290 }
291 
292 int
SetGunQuake(int16_t SpriteNum)293 SetGunQuake(int16_t SpriteNum)
294 {
295     SPRITEp sp = &sprite[SpriteNum];
296 
297     SpawnQuake(sp->sectnum, sp->x, sp->y, sp->z,  40, 8, 40000);
298 
299     return 0;
300 }
301 
302 int
SetPlayerQuake(PLAYERp pp)303 SetPlayerQuake(PLAYERp pp)
304 {
305     SpawnQuake(pp->cursectnum, pp->posx, pp->posy, pp->posz,  40, 8, 40000);
306 
307     return 0;
308 }
309 
310 int
SetNuclearQuake(int16_t Weapon)311 SetNuclearQuake(int16_t Weapon)
312 {
313     SPRITEp sp = &sprite[Weapon];
314 
315     SpawnQuake(sp->sectnum, sp->x, sp->y, sp->z, 400, 8, 64000);
316     return 0;
317 }
318 
319 int
SetSumoQuake(int16_t SpriteNum)320 SetSumoQuake(int16_t SpriteNum)
321 {
322     SPRITEp sp = &sprite[SpriteNum];
323 
324     SpawnQuake(sp->sectnum, sp->x, sp->y, sp->z,  120, 4, 20000);
325     return 0;
326 }
327 
328 int
SetSumoFartQuake(int16_t SpriteNum)329 SetSumoFartQuake(int16_t SpriteNum)
330 {
331     SPRITEp sp = &sprite[SpriteNum];
332 
333     SpawnQuake(sp->sectnum, sp->x, sp->y, sp->z,  60, 4, 4000);
334     return 0;
335 }
336 
337 
338 #include "saveable.h"
339 
340 static saveable_code saveable_quake_code[] =
341 {
342     SAVE_CODE(CopyQuakeSpotToOn),
343     SAVE_CODE(DoQuakeMatch),
344     SAVE_CODE(ProcessQuakeOn),
345     SAVE_CODE(ProcessQuakeSpot),
346     SAVE_CODE(QuakeViewChange),
347     SAVE_CODE(SpawnQuake),
348     SAVE_CODE(SetQuake),
349     SAVE_CODE(SetExpQuake),
350     SAVE_CODE(SetGunQuake),
351     SAVE_CODE(SetPlayerQuake),
352     SAVE_CODE(SetNuclearQuake),
353     SAVE_CODE(SetSumoQuake),
354     SAVE_CODE(SetSumoFartQuake),
355 };
356 
357 saveable_module saveable_quake =
358 {
359     // code
360     saveable_quake_code,
361     SIZ(saveable_quake_code),
362 
363     // data
364     NULL,0
365 };
366 
367