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