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 = &sector[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 = &sector[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 = &sector[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