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