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