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