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