1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 2010-2019 EDuke32 developers and contributors
4 Copyright (C) 2019 Nuke.YKT
5
6 This file is part of NBlood.
7
8 NBlood is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License version 2
10 as published by the Free Software Foundation.
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 //-------------------------------------------------------------------------
23 #include "build.h"
24 #include "compat.h"
25 #include "common_game.h"
26 #include "blood.h"
27 #include "db.h"
28 #include "gameutil.h"
29 #include "levels.h"
30 #include "loadsave.h"
31 #include "view.h"
32 #include "warp.h"
33 #ifdef NOONE_EXTENSIONS
34 #include "nnexts.h"
35 #endif
36
37 ZONE gStartZone[8];
38 #ifdef NOONE_EXTENSIONS
39 ZONE gStartZoneTeam1[8];
40 ZONE gStartZoneTeam2[8];
41 bool gTeamsSpawnUsed = false;
42 #endif
warpInit(void)43 void warpInit(void)
44 {
45 for (int i = 0; i < kMaxSectors; i++)
46 {
47 gUpperLink[i] = -1;
48 gLowerLink[i] = -1;
49 }
50 #ifdef NOONE_EXTENSIONS
51 int team1 = 0; int team2 = 0; gTeamsSpawnUsed = false; // increment if team start positions specified.
52 #endif
53 for (int nSprite = 0; nSprite < kMaxSprites; nSprite++)
54 {
55 if (sprite[nSprite].statnum < kMaxStatus) {
56 spritetype *pSprite = &sprite[nSprite];
57 int nXSprite = pSprite->extra;
58 if (nXSprite > 0) {
59 XSPRITE *pXSprite = &xsprite[nXSprite];
60 switch (pSprite->type) {
61 case kMarkerSPStart:
62 if (gGameOptions.nGameType < 2 && pXSprite->data1 >= 0 && pXSprite->data1 < kMaxPlayers) {
63 ZONE *pZone = &gStartZone[pXSprite->data1];
64 pZone->x = pSprite->x;
65 pZone->y = pSprite->y;
66 pZone->z = pSprite->z;
67 pZone->sectnum = pSprite->sectnum;
68 pZone->ang = pSprite->ang;
69 }
70 DeleteSprite(nSprite);
71 break;
72 case kMarkerMPStart:
73 if (pXSprite->data1 >= 0 && pXSprite->data2 < kMaxPlayers) {
74 if (gGameOptions.nGameType >= 2) {
75 // default if BB or teams without data2 specified
76 ZONE* pZone = &gStartZone[pXSprite->data1];
77 pZone->x = pSprite->x;
78 pZone->y = pSprite->y;
79 pZone->z = pSprite->z;
80 pZone->sectnum = pSprite->sectnum;
81 pZone->ang = pSprite->ang;
82
83 #ifdef NOONE_EXTENSIONS
84 // fill player spawn position according team of player in TEAMS mode.
85 if (gModernMap && gGameOptions.nGameType == 3) {
86 if (pXSprite->data2 == 1) {
87 pZone = &gStartZoneTeam1[team1];
88 pZone->x = pSprite->x;
89 pZone->y = pSprite->y;
90 pZone->z = pSprite->z;
91 pZone->sectnum = pSprite->sectnum;
92 pZone->ang = pSprite->ang;
93 team1++;
94
95 } else if (pXSprite->data2 == 2) {
96 pZone = &gStartZoneTeam2[team2];
97 pZone->x = pSprite->x;
98 pZone->y = pSprite->y;
99 pZone->z = pSprite->z;
100 pZone->sectnum = pSprite->sectnum;
101 pZone->ang = pSprite->ang;
102 team2++;
103 }
104 }
105 #endif
106
107 }
108 DeleteSprite(nSprite);
109 }
110 break;
111 case kMarkerUpLink:
112 gUpperLink[pSprite->sectnum] = nSprite;
113 pSprite->cstat |= 32768;
114 pSprite->cstat &= ~257;
115 break;
116 case kMarkerLowLink:
117 gLowerLink[pSprite->sectnum] = nSprite;
118 pSprite->cstat |= 32768;
119 pSprite->cstat &= ~257;
120 break;
121 case kMarkerUpWater:
122 case kMarkerUpStack:
123 case kMarkerUpGoo:
124 gUpperLink[pSprite->sectnum] = nSprite;
125 pSprite->cstat |= 32768;
126 pSprite->cstat &= ~257;
127 pSprite->z = getflorzofslope(pSprite->sectnum, pSprite->x, pSprite->y);
128 break;
129 case kMarkerLowWater:
130 case kMarkerLowStack:
131 case kMarkerLowGoo:
132 gLowerLink[pSprite->sectnum] = nSprite;
133 pSprite->cstat |= 32768;
134 pSprite->cstat &= ~257;
135 pSprite->z = getceilzofslope(pSprite->sectnum, pSprite->x, pSprite->y);
136 break;
137 }
138 }
139 }
140 }
141
142 #ifdef NOONE_EXTENSIONS
143 // check if there is enough start positions for teams, if any used
144 if (team1 > 0 || team2 > 0) {
145 gTeamsSpawnUsed = true;
146 if (team1 < kMaxPlayers / 2 || team2 < kMaxPlayers / 2) {
147 viewSetSystemMessage("At least 4 spawn positions for each team is recommended.");
148 viewSetSystemMessage("Team A positions: %d, Team B positions: %d.", team1, team2);
149 }
150 }
151 #endif
152
153 for (int i = 0; i < kMaxSectors; i++)
154 {
155 int nSprite = gUpperLink[i];
156 if (nSprite >= 0)
157 {
158 spritetype *pSprite = &sprite[nSprite];
159 int nXSprite = pSprite->extra;
160 dassert(nXSprite > 0 && nXSprite < kMaxXSprites);
161 XSPRITE *pXSprite = &xsprite[nXSprite];
162 int nLink = pXSprite->data1;
163 for (int j = 0; j < kMaxSectors; j++)
164 {
165 int nSprite2 = gLowerLink[j];
166 if (nSprite2 >= 0)
167 {
168 spritetype *pSprite2 = &sprite[nSprite2];
169 int nXSprite = pSprite2->extra;
170 dassert(nXSprite > 0 && nXSprite < kMaxXSprites);
171 XSPRITE *pXSprite2 = &xsprite[nXSprite];
172 if (pXSprite2->data1 == nLink)
173 {
174 pSprite->owner = gLowerLink[j];
175 pSprite2->owner = gUpperLink[i];
176 }
177 }
178 }
179 }
180 }
181 }
182
CheckLink(spritetype * pSprite)183 int CheckLink(spritetype *pSprite)
184 {
185 int nSector = pSprite->sectnum;
186 int nUpper = gUpperLink[nSector];
187 int nLower = gLowerLink[nSector];
188 if (nUpper >= 0)
189 {
190 spritetype *pUpper = &sprite[nUpper];
191 int z;
192 if (pUpper->type == kMarkerUpLink)
193 z = pUpper->z;
194 else
195 z = getflorzofslope(pSprite->sectnum, pSprite->x, pSprite->y);
196 if (z <= pSprite->z)
197 {
198 nLower = pUpper->owner;
199 dassert(nLower >= 0 && nLower < kMaxSprites);
200 spritetype *pLower = &sprite[nLower];
201 dassert(pLower->sectnum >= 0 && pLower->sectnum < kMaxSectors);
202 ChangeSpriteSect(pSprite->index, pLower->sectnum);
203 pSprite->x += pLower->x-pUpper->x;
204 pSprite->y += pLower->y-pUpper->y;
205 int z2;
206 if (pLower->type == kMarkerLowLink)
207 z2 = pLower->z;
208 else
209 z2 = getceilzofslope(pSprite->sectnum, pSprite->x, pSprite->y);
210 pSprite->z += z2-z;
211 ClearBitString(gInterpolateSprite, pSprite->index);
212 return pUpper->type;
213 }
214 }
215 if (nLower >= 0)
216 {
217 spritetype *pLower = &sprite[nLower];
218 int z;
219 if (pLower->type == kMarkerLowLink)
220 z = pLower->z;
221 else
222 z = getceilzofslope(pSprite->sectnum, pSprite->x, pSprite->y);
223 if (z >= pSprite->z)
224 {
225 nUpper = pLower->owner;
226 dassert(nUpper >= 0 && nUpper < kMaxSprites);
227 spritetype *pUpper = &sprite[nUpper];
228 dassert(pUpper->sectnum >= 0 && pUpper->sectnum < kMaxSectors);
229 ChangeSpriteSect(pSprite->index, pUpper->sectnum);
230 pSprite->x += pUpper->x-pLower->x;
231 pSprite->y += pUpper->y-pLower->y;
232 int z2;
233 if (pUpper->type == kMarkerUpLink)
234 z2 = pUpper->z;
235 else
236 z2 = getflorzofslope(pSprite->sectnum, pSprite->x, pSprite->y);
237 pSprite->z += z2-z;
238 ClearBitString(gInterpolateSprite, pSprite->index);
239 return pLower->type;
240 }
241 }
242 return 0;
243 }
244
CheckLink(int * x,int * y,int * z,int * nSector)245 int CheckLink(int *x, int *y, int *z, int *nSector)
246 {
247 int nUpper = gUpperLink[*nSector];
248 int nLower = gLowerLink[*nSector];
249 if (nUpper >= 0)
250 {
251 spritetype *pUpper = &sprite[nUpper];
252 int z1;
253 if (pUpper->type == kMarkerUpLink)
254 z1 = pUpper->z;
255 else
256 z1 = getflorzofslope(*nSector, *x, *y);
257 if (z1 <= *z)
258 {
259 nLower = pUpper->owner;
260 dassert(nLower >= 0 && nLower < kMaxSprites);
261 spritetype *pLower = &sprite[nLower];
262 dassert(pLower->sectnum >= 0 && pLower->sectnum < kMaxSectors);
263 *nSector = pLower->sectnum;
264 *x += pLower->x-pUpper->x;
265 *y += pLower->y-pUpper->y;
266 int z2;
267 if (pUpper->type == kMarkerLowLink)
268 z2 = pLower->z;
269 else
270 z2 = getceilzofslope(*nSector, *x, *y);
271 *z += z2-z1;
272 return pUpper->type;
273 }
274 }
275 if (nLower >= 0)
276 {
277 spritetype *pLower = &sprite[nLower];
278 int z1;
279 if (pLower->type == kMarkerLowLink)
280 z1 = pLower->z;
281 else
282 z1 = getceilzofslope(*nSector, *x, *y);
283 if (z1 >= *z)
284 {
285 nUpper = pLower->owner;
286 dassert(nUpper >= 0 && nUpper < kMaxSprites);
287 spritetype *pUpper = &sprite[nUpper];
288 dassert(pUpper->sectnum >= 0 && pUpper->sectnum < kMaxSectors);
289 *nSector = pUpper->sectnum;
290 *x += pUpper->x-pLower->x;
291 *y += pUpper->y-pLower->y;
292 int z2;
293 if (pLower->type == kMarkerUpLink)
294 z2 = pUpper->z;
295 else
296 z2 = getflorzofslope(*nSector, *x, *y);
297 *z += z2-z1;
298 return pLower->type;
299 }
300 }
301 return 0;
302 }
303
304 class WarpLoadSave : public LoadSave
305 {
306 public:
307 virtual void Load();
308 virtual void Save();
309 };
310
Load()311 void WarpLoadSave::Load()
312 {
313 Read(gStartZone, sizeof(gStartZone));
314 Read(gUpperLink, sizeof(gUpperLink));
315 Read(gLowerLink, sizeof(gLowerLink));
316 }
317
Save()318 void WarpLoadSave::Save()
319 {
320 Write(gStartZone, sizeof(gStartZone));
321 Write(gUpperLink, sizeof(gUpperLink));
322 Write(gLowerLink, sizeof(gLowerLink));
323 }
324
325 static WarpLoadSave *myLoadSave;
326
WarpLoadSaveConstruct(void)327 void WarpLoadSaveConstruct(void)
328 {
329 myLoadSave = new WarpLoadSave();
330 }
331