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 "panel.h"
30 #include "game.h"
31 #include "net.h"
32 #include "tags.h"
33 #include "sector.h"
34 #include "text.h"
35 #include "interp.h"
36 #include "sprite.h"
37
38 short DoRotatorMatch(PLAYERp pp, short match, BOOL);
39 BOOL TestRotatorMatchActive(short match);
40 VOID InterpSectorSprites(short sectnum, BOOL state);
41 VOID DoMatchEverything(PLAYERp pp, short match, short state);
42 void DoRotatorSetInterp(short SpriteNum);
43 void DoRotatorStopInterp(short SpriteNum);
44
ReverseRotator(short SpriteNum)45 void ReverseRotator(short SpriteNum)
46 {
47 USERp u = User[SpriteNum];
48 SPRITEp sp = u->SpriteP;
49 ROTATORp r;
50
51 r = u->rotator;
52
53 // if paused go ahead and start it up again
54 if (u->Tics)
55 {
56 u->Tics = 0;
57 SetRotatorActive(SpriteNum);
58 return;
59 }
60
61 // moving toward to OFF pos
62 if (r->tgt == 0)
63 {
64 r->tgt = r->open_dest;
65 }
66 else
67 if (r->tgt == r->open_dest)
68 {
69 r->tgt = 0;
70 }
71
72 r->vel = -r->vel;
73 }
74
75 BOOL
RotatorSwitch(short match,short setting)76 RotatorSwitch(short match, short setting)
77 {
78 SPRITEp sp;
79 short i,nexti;
80 BOOL found = FALSE;
81
82 TRAVERSE_SPRITE_STAT(headspritestat[STAT_DEFAULT], i, nexti)
83 {
84 sp = &sprite[i];
85
86 if (sp->lotag == TAG_SPRITE_SWITCH_VATOR && sp->hitag == match)
87 {
88 found = TRUE;
89 AnimateSwitch(sp, setting);
90 }
91 }
92
93 return(found);
94 }
95
SetRotatorActive(short SpriteNum)96 void SetRotatorActive(short SpriteNum)
97 {
98 USERp u = User[SpriteNum];
99 SPRITEp sp = u->SpriteP;
100 SECTORp sectp = §or[sp->sectnum];
101 ROTATORp r;
102
103 r = u->rotator;
104
105 DoRotatorSetInterp(SpriteNum);
106
107 // play activate sound
108 DoSoundSpotMatch(SP_TAG2(sp), 1, SOUND_OBJECT_TYPE);
109
110 SET(u->Flags, SPR_ACTIVE);
111 u->Tics = 0;
112
113 // moving to the OFF position
114 if (r->tgt == 0)
115 VatorSwitch(SP_TAG2(sp), OFF);
116 else
117 VatorSwitch(SP_TAG2(sp), ON);
118 }
119
SetRotatorInactive(short SpriteNum)120 void SetRotatorInactive(short SpriteNum)
121 {
122 USERp u = User[SpriteNum];
123 SPRITEp sp = u->SpriteP;
124 SECTORp sectp = §or[sp->sectnum];
125
126 DoRotatorStopInterp(SpriteNum);
127
128 // play inactivate sound
129 DoSoundSpotMatch(SP_TAG2(sp), 2, SOUND_OBJECT_TYPE);
130
131 RESET(u->Flags, SPR_ACTIVE);
132 }
133
134 // called for operation from the space bar
DoRotatorOperate(PLAYERp pp,short sectnum)135 short DoRotatorOperate(PLAYERp pp, short sectnum)
136 {
137 USERp fu;
138 SPRITEp fsp;
139 short match;
140 short i,nexti;
141
142 match = sector[sectnum].hitag;
143
144 if (match > 0)
145 {
146 if (TestRotatorMatchActive(match))
147 return(-1);
148 else
149 return(DoRotatorMatch(pp, match, TRUE));
150 }
151
152 return(-1);
153 }
154
155 // called from switches and triggers
156 // returns first vator found
157 short
DoRotatorMatch(PLAYERp pp,short match,BOOL manual)158 DoRotatorMatch(PLAYERp pp, short match, BOOL manual)
159 {
160 USERp fu;
161 SPRITEp fsp;
162 short sectnum;
163 short first_vator = -1;
164
165 short i,nexti;
166
167 //RotatorSwitch(match, ON);
168
169 TRAVERSE_SPRITE_STAT(headspritestat[STAT_ROTATOR], i, nexti)
170 {
171 fsp = &sprite[i];
172
173 if (SP_TAG1(fsp) == SECT_ROTATOR && SP_TAG2(fsp) == match)
174 {
175 fu = User[i];
176
177 // single play only vator
178 // BOOL 8 must be set for message to display
179 if (TEST_BOOL4(fsp) && (gNet.MultiGameType == MULTI_GAME_COMMBAT || gNet.MultiGameType == MULTI_GAME_AI_BOTS))
180 {
181 if (pp && TEST_BOOL11(fsp)) PutStringInfo(pp,"This only opens in single play.");
182 continue;
183 }
184
185 // switch trigger only
186 if (SP_TAG3(fsp) == 1)
187 {
188 // tried to manually operat a switch/trigger only
189 if (manual)
190 continue;
191 }
192
193 if (first_vator == -1)
194 first_vator = i;
195
196 sectnum = fsp->sectnum;
197
198 if (pp && SectUser[sectnum] && SectUser[sectnum]->stag == SECT_LOCK_DOOR && SectUser[sectnum]->number)
199 {
200 short key_num;
201
202 key_num = SectUser[sectnum]->number;
203
204 #if 0
205 if (pp->HasKey[key_num - 1])
206 {
207 int i;
208 for(i=0; i<numsectors; i++)
209 {
210 if (SectUser[i] && SectUser[i]->stag == SECT_LOCK_DOOR && SectUser[i]->number == key_num)
211 SectUser[i]->number = 0; // unlock all doors of this type
212 }
213 UnlockKeyLock(key_num);
214 }
215 else
216 #endif
217 {
218 PutStringInfo(pp, KeyDoorMessage[key_num - 1]);
219 return (-1);
220 }
221 }
222
223 if (TEST(fu->Flags, SPR_ACTIVE))
224 {
225 ReverseRotator(i);
226 continue;
227 }
228
229 SetRotatorActive(i);
230 }
231 }
232
233 return(first_vator);
234 }
235
236
237 BOOL
TestRotatorMatchActive(short match)238 TestRotatorMatchActive(short match)
239 {
240 USERp fu;
241 SPRITEp fsp;
242 short sectnum;
243
244 short i,nexti;
245
246 TRAVERSE_SPRITE_STAT(headspritestat[STAT_ROTATOR], i, nexti)
247 {
248 fsp = &sprite[i];
249
250 if (SP_TAG1(fsp) == SECT_ROTATOR && SP_TAG2(fsp) == match)
251 {
252 fu = User[i];
253
254 // Does not have to be inactive to be operated
255 if (TEST_BOOL6(fsp))
256 continue;
257
258 if (TEST(fu->Flags, SPR_ACTIVE) || fu->Tics)
259 return(TRUE);
260 }
261 }
262
263 return(FALSE);
264 }
265
266
DoRotatorSetInterp(short SpriteNum)267 void DoRotatorSetInterp(short SpriteNum)
268 {
269 SPRITEp sp = &sprite[SpriteNum];
270 short w,startwall,endwall;
271
272 startwall = sector[sp->sectnum].wallptr;
273 endwall = startwall + sector[sp->sectnum].wallnum - 1;
274
275 // move points
276 for (w = startwall; w <= endwall; w++)
277 {
278 setinterpolation(&wall[w].x);
279 setinterpolation(&wall[w].y);
280
281 setinterpolation(&wall[DRAG_WALL(w)].x);
282 setinterpolation(&wall[DRAG_WALL(w)].y);
283 }
284 }
285
DoRotatorStopInterp(short SpriteNum)286 void DoRotatorStopInterp(short SpriteNum)
287 {
288 SPRITEp sp = &sprite[SpriteNum];
289 short w,startwall,endwall;
290
291 startwall = sector[sp->sectnum].wallptr;
292 endwall = startwall + sector[sp->sectnum].wallnum - 1;
293
294 // move points
295 for (w = startwall; w <= endwall; w++)
296 {
297 stopinterpolation(&wall[w].x);
298 stopinterpolation(&wall[w].y);
299
300 stopinterpolation(&wall[DRAG_WALL(w)].x);
301 stopinterpolation(&wall[DRAG_WALL(w)].y);
302 }
303 }
304
DoRotatorMove(short SpriteNum)305 int DoRotatorMove(short SpriteNum)
306 {
307 USERp u = User[SpriteNum];
308 SPRITEp sp = u->SpriteP;
309 ROTATORp r;
310 short ndx,w,startwall,endwall;
311 SPRITEp pivot = NULL;
312 int i, nexti;
313 int nx,ny;
314 int dist,closest;
315 BOOL kill = FALSE;
316
317 r = u->rotator;
318
319 // Example - ang pos moves from 0 to 512 <<OR>> from 0 to -512
320
321 // control SPEED of swinging
322 if (r->pos < r->tgt)
323 {
324 // Increment swing angle
325 r->pos += r->speed;
326 r->speed += r->vel;
327
328 // if the other way make it equal
329 if (r->pos > r->tgt)
330 r->pos = r->tgt;
331 }
332
333 if (r->pos > r->tgt)
334 {
335 // Increment swing angle
336 r->pos -= r->speed;
337 r->speed += r->vel;
338
339 // if the other way make it equal
340 if (r->pos < r->tgt)
341 r->pos = r->tgt;
342 }
343
344 if (r->pos == r->tgt)
345 {
346 // If ang is OPEN
347 if (r->pos == r->open_dest)
348 {
349 // new tgt is CLOSED (0)
350 r->tgt = 0;
351 r->vel = -r->vel;
352 SetRotatorInactive(SpriteNum);
353
354 if (SP_TAG6(sp))
355 DoMatchEverything(NULL, SP_TAG6(sp), -1);
356
357 // wait a bit and close it
358 if (u->WaitTics)
359 u->Tics = u->WaitTics;
360 }
361 else
362 // If ang is CLOSED then
363 if (r->pos == 0)
364 {
365 short match = SP_TAG2(sp);
366
367 // new tgt is OPEN (open)
368 r->tgt = r->open_dest;
369 r->speed = r->orig_speed;
370 r->vel = labs(r->vel);
371
372 SetRotatorInactive(SpriteNum);
373
374 // set owner swith back to OFF
375 // only if ALL vators are inactive
376 if (!TestRotatorMatchActive(match))
377 {
378 //RotatorSwitch(match, OFF);
379 }
380
381 if (SP_TAG6(sp) && TEST_BOOL5(sp))
382 DoMatchEverything(NULL, SP_TAG6(sp), -1);
383 }
384
385 if (TEST_BOOL2(sp))
386 kill = TRUE;
387 }
388
389 closest = 99999;
390 TRAVERSE_SPRITE_STAT(headspritestat[STAT_ROTATOR_PIVOT], i, nexti)
391 {
392 if (sprite[i].lotag == sp->lotag)
393 {
394 dist = Distance(sp->x, sp->y, sprite[i].x, sprite[i].y);
395 if (dist < closest)
396 {
397 closest = dist;
398 pivot = &sprite[i];
399 }
400 }
401 }
402
403 if (!pivot)
404 return(0);
405
406 startwall = sector[sp->sectnum].wallptr;
407 endwall = startwall + sector[sp->sectnum].wallnum - 1;
408
409 // move points
410 for (w = startwall, ndx = 0; w <= endwall; w++)
411 {
412 rotatepoint(pivot->x, pivot->y,
413 r->origx[ndx], r->origy[ndx],
414 r->pos, &nx, &ny);
415
416 dragpoint(w, nx, ny);
417 ndx++;
418 }
419
420 if (kill)
421 {
422 SetRotatorInactive(SpriteNum);
423 KillSprite(SpriteNum);
424 return(0);
425 }
426
427 return(0);
428 }
429
DoRotator(short SpriteNum)430 int DoRotator(short SpriteNum)
431 {
432 USERp u = User[SpriteNum];
433 SPRITEp sp = u->SpriteP;
434 SECTORp sectp = §or[sp->sectnum];
435 int *lptr;
436 int amt;
437
438 // could move this inside sprite control
439 DoRotatorMove(SpriteNum);
440
441 return(0);
442 }
443
444 #include "saveable.h"
445
446 static saveable_code saveable_rotator_code[] = {
447 SAVE_CODE(ReverseRotator),
448 SAVE_CODE(RotatorSwitch),
449 SAVE_CODE(SetRotatorActive),
450 SAVE_CODE(SetRotatorInactive),
451 SAVE_CODE(DoRotatorOperate),
452 SAVE_CODE(DoRotatorMatch),
453 SAVE_CODE(TestRotatorMatchActive),
454 SAVE_CODE(DoRotatorSetInterp),
455 SAVE_CODE(DoRotatorStopInterp),
456 SAVE_CODE(DoRotatorMove),
457 SAVE_CODE(DoRotator)
458 };
459
460 saveable_module saveable_rotator = {
461 // code
462 saveable_rotator_code,
463 SIZ(saveable_rotator_code),
464
465 // data
466 NULL,0
467 };
468
469