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 
32 #include "warp.h"
33 
34 ////////////////////////////////////////////////////////////////////////////////
35 //
36 // WARPING - PLANE STYLE
37 //
38 ////////////////////////////////////////////////////////////////////////////////
39 
40 extern SWBOOL Prediction;
41 
42 SWBOOL
WarpPlaneSectorInfo(short sectnum,SPRITEp * sp_ceiling,SPRITEp * sp_floor)43 WarpPlaneSectorInfo(short sectnum, SPRITEp *sp_ceiling, SPRITEp *sp_floor)
44 {
45     int i,nexti;
46     SPRITEp sp;
47 
48     *sp_floor = NULL;
49     *sp_ceiling = NULL;
50 
51     if (Prediction)
52         return FALSE;
53 
54     if (sectnum < 0 || !TEST(sector[sectnum].extra, SECTFX_WARP_SECTOR))
55         return FALSE;
56 
57     TRAVERSE_SPRITE_STAT(headspritestat[STAT_WARP], i, nexti)
58     {
59         sp = &sprite[i];
60 
61         if (sp->sectnum == sectnum)
62         {
63             // skip - don't teleport
64             if (SP_TAG10(sp) == 1)
65                 continue;
66 
67             if (sp->hitag == WARP_CEILING_PLANE)
68             {
69                 *sp_ceiling = sp;
70             }
71             else if (sp->hitag == WARP_FLOOR_PLANE)
72             {
73                 *sp_floor = sp;
74             }
75         }
76     }
77 
78     return TRUE;
79 }
80 
81 SPRITEp
WarpPlane(int32_t * x,int32_t * y,int32_t * z,int16_t * sectnum)82 WarpPlane(int32_t* x, int32_t* y, int32_t* z, int16_t* sectnum)
83 {
84     SPRITEp sp_floor, sp_ceiling;
85 
86     if (Prediction)
87         return NULL;
88 
89     if (!WarpPlaneSectorInfo(*sectnum, &sp_ceiling, &sp_floor))
90         return NULL;
91 
92     if (sp_ceiling)
93     {
94         if (*z <= sp_ceiling->z)
95         {
96             return WarpToArea(sp_ceiling, x, y, z, sectnum);
97         }
98     }
99 
100     if (sp_floor)
101     {
102         if (*z >= sp_floor->z)
103         {
104             return WarpToArea(sp_floor, x, y, z, sectnum);
105         }
106     }
107 
108     return NULL;
109 }
110 
111 SPRITEp
WarpToArea(SPRITEp sp_from,int32_t * x,int32_t * y,int32_t * z,int16_t * sectnum)112 WarpToArea(SPRITEp sp_from, int32_t* x, int32_t* y, int32_t* z, int16_t* sectnum)
113 {
114     int xoff;
115     int yoff;
116     int zoff;
117     short i, nexti;
118     SPRITEp sp = sp_from;
119     short match;
120     short to_tag = 0;
121     short match_rand[16];
122     int z_adj = 0;
123 
124     xoff = *x - sp->x;
125     yoff = *y - sp->y;
126     zoff = *z - sp->z;
127     match = sp->lotag;
128 
129 #if 0
130     TAG 2 = match
131             TAG 3 = Type
132                     Sprite - 0,32 always teleports you to the center at the angle the sprite is facing
133     Offset - 1 always teleports you by the offset.Does not touch the angle
134     TAG 4 = angle
135             TAG 5 to 8 = random match locations
136 #endif
137 
138     memset(match_rand,0,sizeof(match_rand));
139 
140     switch (sp->hitag)
141     {
142     case WARP_TELEPORTER:
143         to_tag = WARP_TELEPORTER;
144 
145         // if tag 5 has something this is a random teleporter
146         if (SP_TAG5(sp))
147         {
148             short ndx = 0;
149             match_rand[ndx++] = SP_TAG2(sp);
150             match_rand[ndx++] = SP_TAG5(sp);
151             if (SP_TAG6(sp))
152                 match_rand[ndx++] = SP_TAG6(sp);
153             if (SP_TAG7(sp))
154                 match_rand[ndx++] = SP_TAG7(sp);
155             if (SP_TAG8(sp))
156                 match_rand[ndx++] = SP_TAG8(sp);
157 
158             // reset the match you are looking for
159             match = match_rand[RANDOM_RANGE(ndx)];
160         }
161         break;
162     case WARP_CEILING_PLANE:
163         to_tag = WARP_FLOOR_PLANE;
164         // make sure you warp outside of warp plane
165         z_adj = -Z(2);
166         break;
167     case WARP_FLOOR_PLANE:
168         to_tag = WARP_CEILING_PLANE;
169         // make sure you warp outside of warp plane
170         z_adj = Z(2);
171         break;
172     }
173 
174     TRAVERSE_SPRITE_STAT(headspritestat[STAT_WARP], i, nexti)
175     {
176         SPRITEp sp = &sprite[i];
177 
178         if (sp->lotag == match && sp != sp_from)
179         {
180             // exp: WARP_CEILING or WARP_CEILING_PLANE
181             if (sp->hitag == to_tag)
182             {
183                 if ((unsigned)sp->sectnum >= MAXSECTORS)
184                     return nullptr;
185 
186                 // determine new x,y,z position
187                 *x = sp->x + xoff;
188                 *y = sp->y + yoff;
189                 *z = sp->z + zoff;
190 
191                 // make sure you warp outside of warp plane
192                 *z += z_adj;
193 
194                 // get new sector
195                 *sectnum = sp->sectnum;
196                 updatesector(*x, *y, sectnum);
197 
198                 return sp;
199             }
200         }
201     }
202 
203     return NULL;
204 }
205 
206 ////////////////////////////////////////////////////////////////////////////////
207 //
208 // Warp - Teleporter style
209 //
210 ////////////////////////////////////////////////////////////////////////////////
211 
212 SWBOOL
WarpSectorInfo(short sectnum,SPRITEp * sp_warp)213 WarpSectorInfo(short sectnum, SPRITEp *sp_warp)
214 {
215     int i,nexti;
216     SPRITEp sp;
217 
218     *sp_warp = NULL;
219 
220     if (!TEST(sector[sectnum].extra, SECTFX_WARP_SECTOR))
221         return FALSE;
222 
223     TRAVERSE_SPRITE_STAT(headspritestat[STAT_WARP], i, nexti)
224     {
225         sp = &sprite[i];
226 
227         if (sp->sectnum == sectnum)
228         {
229             // skip - don't teleport
230             if (SP_TAG10(sp) == 1)
231                 continue;
232 
233             if (sp->hitag == WARP_TELEPORTER)
234             {
235                 *sp_warp = sp;
236             }
237         }
238     }
239 
240     return TRUE;
241 }
242 
243 SPRITEp
Warp(int32_t * x,int32_t * y,int32_t * z,int16_t * sectnum)244 Warp(int32_t* x, int32_t* y, int32_t* z, int16_t* sectnum)
245 {
246     SPRITEp sp_warp;
247 
248     if (Prediction)
249         return NULL;
250 
251     if (!WarpSectorInfo(*sectnum, &sp_warp))
252         return NULL;
253 
254     if (sp_warp)
255     {
256         return WarpToArea(sp_warp, x, y, z, sectnum);
257     }
258 
259     return NULL;
260 }
261