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
28 #include "names2.h"
29 #include "panel.h"
30 #include "game.h"
31 #include "tags.h"
32 #include "sector.h"
33 #include "sprite.h"
34
35 short DoSpikeMatch(short match);
36 SWBOOL TestSpikeMatchActive(short match);
37 int DoVatorMove(short SpriteNum, int *lptr);
38 void InterpSectorSprites(short sectnum, SWBOOL state);
39
ReverseSpike(short SpriteNum)40 void ReverseSpike(short SpriteNum)
41 {
42 USERp u = User[SpriteNum];
43 SPRITEp sp = u->SpriteP;
44
45 // if paused go ahead and start it up again
46 if (u->Tics)
47 {
48 u->Tics = 0;
49 SetSpikeActive(SpriteNum);
50 return;
51 }
52
53 // moving toward to OFF pos
54 if (u->z_tgt == u->oz)
55 {
56 if (sp->z == u->oz)
57 u->z_tgt = u->sz;
58 else if (u->sz == u->oz)
59 u->z_tgt = sp->z;
60 }
61 else if (u->z_tgt == u->sz)
62 {
63 if (sp->z == u->oz)
64 u->z_tgt = sp->z;
65 else if (u->sz == u->oz)
66 u->z_tgt = u->sz;
67 }
68
69 u->vel_rate = -u->vel_rate;
70 }
71
72 SWBOOL
SpikeSwitch(short match,short setting)73 SpikeSwitch(short match, short setting)
74 {
75 SPRITEp sp;
76 short i,nexti;
77 SWBOOL found = FALSE;
78
79 TRAVERSE_SPRITE_STAT(headspritestat[STAT_DEFAULT], i, nexti)
80 {
81 sp = &sprite[i];
82
83 if (sp->lotag == TAG_SPRITE_SWITCH_VATOR && sp->hitag == match)
84 {
85 found = TRUE;
86 AnimateSwitch(sp, setting);
87 }
88 }
89
90 return found;
91 }
92
SetSpikeActive(short SpriteNum)93 void SetSpikeActive(short SpriteNum)
94 {
95 USERp u = User[SpriteNum];
96 SPRITEp sp = u->SpriteP;
97 SECTORp sectp = §or[sp->sectnum];
98
99 if (TEST(sp->cstat, CSTAT_SPRITE_YFLIP))
100 short_setinterpolation(§p->ceilingheinum);
101 else
102 short_setinterpolation(§p->floorheinum);
103
104 InterpSectorSprites(sp->sectnum, ON);
105
106 // play activate sound
107 DoSoundSpotMatch(SP_TAG2(sp), 1, SOUND_OBJECT_TYPE);
108
109 SET(u->Flags, SPR_ACTIVE);
110 u->Tics = 0;
111
112 // moving to the ON position
113 if (u->z_tgt == sp->z)
114 VatorSwitch(SP_TAG2(sp), ON);
115 else
116 // moving to the OFF position
117 if (u->z_tgt == u->sz)
118 VatorSwitch(SP_TAG2(sp), OFF);
119 }
120
SetSpikeInactive(short SpriteNum)121 void SetSpikeInactive(short SpriteNum)
122 {
123 USERp u = User[SpriteNum];
124 SPRITEp sp = u->SpriteP;
125 SECTORp sectp = §or[sp->sectnum];
126
127 if (TEST(sp->cstat, CSTAT_SPRITE_YFLIP))
128 short_stopinterpolation(§p->ceilingheinum);
129 else
130 short_stopinterpolation(§p->floorheinum);
131
132 InterpSectorSprites(sp->sectnum, OFF);
133
134 // play activate sound
135 DoSoundSpotMatch(SP_TAG2(sp), 2, SOUND_OBJECT_TYPE);
136
137 RESET(u->Flags, SPR_ACTIVE);
138 }
139
140 // called for operation from the space bar
DoSpikeOperate(short sectnum)141 short DoSpikeOperate(short sectnum)
142 {
143 SPRITEp fsp;
144 short match;
145 short i,nexti;
146
147 TRAVERSE_SPRITE_SECT(headspritesect[sectnum], i, nexti)
148 {
149 fsp = &sprite[i];
150
151 if (fsp->statnum == STAT_SPIKE && SP_TAG1(fsp) == SECT_SPIKE && SP_TAG3(fsp) == 0)
152 {
153 sectnum = fsp->sectnum;
154
155 match = SP_TAG2(fsp);
156 if (match > 0)
157 {
158 if (TestSpikeMatchActive(match))
159 return -1;
160 else
161 return DoSpikeMatch(match);
162 }
163
164 SetSpikeActive(i);
165 break;
166 }
167 }
168
169 return i;
170 }
171
172 // called from switches and triggers
173 // returns first spike found
174 short
DoSpikeMatch(short match)175 DoSpikeMatch(short match)
176 {
177 USERp fu;
178 SPRITEp fsp;
179 short first_spike = -1;
180
181 short i,nexti;
182
183 //SpikeSwitch(match, ON);
184
185 TRAVERSE_SPRITE_STAT(headspritestat[STAT_SPIKE], i, nexti)
186 {
187 fsp = &sprite[i];
188
189 if (SP_TAG1(fsp) == SECT_SPIKE && SP_TAG2(fsp) == match)
190 {
191 fu = User[i];
192
193 if (first_spike == -1)
194 first_spike = i;
195
196 if (TEST(fu->Flags, SPR_ACTIVE))
197 {
198 ReverseSpike(i);
199 continue;
200 }
201
202 SetSpikeActive(i);
203 }
204 }
205
206 return first_spike;
207 }
208
209
210 SWBOOL
TestSpikeMatchActive(short match)211 TestSpikeMatchActive(short match)
212 {
213 USERp fu;
214 SPRITEp fsp;
215
216 short i,nexti;
217
218 TRAVERSE_SPRITE_STAT(headspritestat[STAT_SPIKE], i, nexti)
219 {
220 fsp = &sprite[i];
221
222 if (SP_TAG1(fsp) == SECT_SPIKE && SP_TAG2(fsp) == match)
223 {
224 fu = User[i];
225
226 // door war
227 if (TEST_BOOL6(fsp))
228 continue;
229
230 if (TEST(fu->Flags, SPR_ACTIVE) || fu->Tics)
231 return TRUE;
232 }
233 }
234
235 return FALSE;
236 }
237
DoSpikeMove(short SpriteNum,int * lptr)238 int DoSpikeMove(short SpriteNum, int *lptr)
239 {
240 USERp u = User[SpriteNum];
241 int zval;
242
243 zval = *lptr;
244
245 // if LESS THAN goal
246 if (zval < u->z_tgt)
247 {
248 // move it DOWN
249 zval += (synctics * u->jump_speed);
250
251 u->jump_speed += u->vel_rate * synctics;
252
253 // if the other way make it equal
254 if (zval > u->z_tgt)
255 zval = u->z_tgt;
256 }
257
258 // if GREATER THAN goal
259 if (zval > u->z_tgt)
260 {
261 // move it UP
262 zval -= (synctics * u->jump_speed);
263
264 u->jump_speed += u->vel_rate * synctics;
265
266 if (zval < u->z_tgt)
267 zval = u->z_tgt;
268 }
269
270 *lptr = zval;
271
272 return 0;
273 }
274
SpikeAlign(short SpriteNum)275 void SpikeAlign(short SpriteNum)
276 {
277 USERp u = User[SpriteNum];
278 SPRITEp sp = u->SpriteP;
279
280 // either work on single sector or all tagged in SOBJ
281 if ((int8_t)SP_TAG7(sp) < 0)
282 {
283 if (TEST(sp->cstat, CSTAT_SPRITE_YFLIP))
284 alignceilslope(sp->sectnum, sp->x, sp->y, u->zclip);
285 else
286 alignflorslope(sp->sectnum, sp->x, sp->y, u->zclip);
287 }
288 else
289 {
290 if (TEST(sp->cstat, CSTAT_SPRITE_YFLIP))
291 SOBJ_AlignCeilingToPoint(&SectorObject[SP_TAG7(sp)], sp->x, sp->y, u->zclip);
292 else
293 SOBJ_AlignFloorToPoint(&SectorObject[SP_TAG7(sp)], sp->x, sp->y, u->zclip);
294 }
295 }
296
MoveSpritesWithSpike(short sectnum)297 void MoveSpritesWithSpike(short sectnum)
298 {
299 SPRITEp sp;
300 short i,nexti;
301 int cz,fz;
302
303 TRAVERSE_SPRITE_SECT(headspritesect[sectnum], i, nexti)
304 {
305 sp = &sprite[i];
306
307 if (User[i])
308 continue;
309
310 if (TEST(sp->extra, SPRX_STAY_PUT_VATOR))
311 continue;
312
313 getzsofslope(sectnum, sp->x, sp->y, &cz, &fz);
314 sp->z = fz;
315 }
316 }
317
DoSpike(short SpriteNum)318 int DoSpike(short SpriteNum)
319 {
320 USERp u = User[SpriteNum];
321 SPRITEp sp = u->SpriteP;
322 int *lptr;
323
324 // zclip = floor or ceiling z
325 // oz = original z
326 // z_tgt = target z - on pos
327 // sz = starting z - off pos
328
329 lptr = &u->zclip;
330
331 DoSpikeMove(SpriteNum, lptr);
332 MoveSpritesWithSpike(sp->sectnum);
333 SpikeAlign(SpriteNum);
334
335 // EQUAL this entry has finished
336 if (*lptr == u->z_tgt)
337 {
338 // in the ON position
339 if (u->z_tgt == sp->z)
340 {
341 // change target
342 u->z_tgt = u->sz;
343 u->vel_rate = -u->vel_rate;
344
345 SetSpikeInactive(SpriteNum);
346
347 if (SP_TAG6(sp))
348 DoMatchEverything(NULL, SP_TAG6(sp), -1);
349 }
350 else
351 // in the OFF position
352 if (u->z_tgt == u->sz)
353 {
354 short match = SP_TAG2(sp);
355
356 // change target
357 u->jump_speed = u->vel_tgt;
358 u->vel_rate = labs(u->vel_rate);
359 u->z_tgt = sp->z;
360
361 SetSpikeInactive(SpriteNum);
362
363 // set owner swith back to OFF
364 // only if ALL spikes are inactive
365 if (!TestSpikeMatchActive(match))
366 {
367 //SpikeSwitch(match, OFF);
368 }
369
370 if (SP_TAG6(sp) && TEST_BOOL5(sp))
371 DoMatchEverything(NULL, SP_TAG6(sp), -1);
372 }
373
374 // operate only once
375 if (TEST_BOOL2(sp))
376 {
377 SetSpikeInactive(SpriteNum);
378 KillSprite(SpriteNum);
379 return 0;
380 }
381
382 // setup to go back to the original z
383 if (*lptr != u->oz)
384 {
385 if (u->WaitTics)
386 u->Tics = u->WaitTics;
387 }
388 }
389 else // if (*lptr == u->z_tgt)
390 {
391 // if heading for the OFF (original) position and should NOT CRUSH
392 if (TEST_BOOL3(sp) && u->z_tgt == u->oz)
393 {
394 int i,nexti;
395 SPRITEp bsp;
396 USERp bu;
397 SWBOOL found = FALSE;
398
399 TRAVERSE_SPRITE_SECT(headspritesect[sp->sectnum], i, nexti)
400 {
401 bsp = &sprite[i];
402 bu = User[i];
403
404 if (bu && TEST(bsp->cstat, CSTAT_SPRITE_BLOCK) && TEST(bsp->extra, SPRX_PLAYER_OR_ENEMY))
405 {
406 ReverseSpike(SpriteNum);
407 found = TRUE;
408 break;
409 }
410 }
411
412 if (!found)
413 {
414 short pnum;
415 PLAYERp pp;
416 // go ahead and look for players clip box bounds
417 TRAVERSE_CONNECT(pnum)
418 {
419 pp = Player + pnum;
420
421 if (pp->lo_sectp == §or[sp->sectnum] ||
422 pp->hi_sectp == §or[sp->sectnum])
423 {
424 ReverseSpike(SpriteNum);
425 found = TRUE;
426 }
427 }
428 }
429 }
430 }
431
432 return 0;
433 }
434
DoSpikeAuto(short SpriteNum)435 int DoSpikeAuto(short SpriteNum)
436 {
437 USERp u = User[SpriteNum];
438 SPRITEp sp = u->SpriteP;
439 int *lptr;
440
441 lptr = &u->zclip;
442
443 DoSpikeMove(SpriteNum, lptr);
444 MoveSpritesWithSpike(sp->sectnum);
445 SpikeAlign(SpriteNum);
446
447 // EQUAL this entry has finished
448 if (*lptr == u->z_tgt)
449 {
450 // in the UP position
451 if (u->z_tgt == sp->z)
452 {
453 // change target
454 u->z_tgt = u->sz;
455 u->vel_rate = -u->vel_rate;
456 u->Tics = u->WaitTics;
457
458 if (SP_TAG6(sp))
459 DoMatchEverything(NULL, SP_TAG6(sp), -1);
460 }
461 else
462 // in the DOWN position
463 if (u->z_tgt == u->sz)
464 {
465 // change target
466 u->jump_speed = u->vel_tgt;
467 u->vel_rate = labs(u->vel_rate);
468 u->z_tgt = sp->z;
469 u->Tics = u->WaitTics;
470
471 if (SP_TAG6(sp) && TEST_BOOL5(sp))
472 DoMatchEverything(NULL, SP_TAG6(sp), -1);
473 }
474 }
475
476 return 0;
477 }
478
479
480 #include "saveable.h"
481
482 static saveable_code saveable_spike_code[] =
483 {
484 SAVE_CODE(ReverseSpike),
485 SAVE_CODE(SpikeSwitch),
486 SAVE_CODE(SetSpikeActive),
487 SAVE_CODE(SetSpikeInactive),
488 SAVE_CODE(DoSpikeOperate),
489 SAVE_CODE(DoSpikeMatch),
490 SAVE_CODE(TestSpikeMatchActive),
491 SAVE_CODE(DoSpikeMove),
492 SAVE_CODE(SpikeAlign),
493 SAVE_CODE(MoveSpritesWithSpike),
494 SAVE_CODE(DoSpike),
495 SAVE_CODE(DoSpikeAuto),
496 };
497
498 saveable_module saveable_spike =
499 {
500 // code
501 saveable_spike_code,
502 SIZ(saveable_spike_code),
503
504 // data
505 NULL,0
506 };
507