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 <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "build.h"
28 #include "common_game.h"
29 
30 #include "actor.h"
31 #include "db.h"
32 #include "gameutil.h"
33 #include "globals.h"
34 #include "tile.h"
35 #include "trig.h"
36 
37 POINT2D baseWall[kMaxWalls];
38 POINT3D baseSprite[kMaxSprites];
39 int baseFloor[kMaxSectors];
40 int baseCeil[kMaxSectors];
41 int velFloor[kMaxSectors];
42 int velCeil[kMaxSectors];
43 short gUpperLink[kMaxSectors];
44 short gLowerLink[kMaxSectors];
45 HITINFO gHitInfo;
46 
AreSectorsNeighbors(int sect1,int sect2)47 bool AreSectorsNeighbors(int sect1, int sect2)
48 {
49     dassert(sect1 >= 0 && sect1 < kMaxSectors);
50     dassert(sect2 >= 0 && sect2 < kMaxSectors);
51     if (sector[sect1].wallnum < sector[sect2].wallnum)
52     {
53         for (int i = 0; i < sector[sect1].wallnum; i++)
54         {
55             if (wall[sector[sect1].wallptr+i].nextsector == sect2)
56             {
57                 return 1;
58             }
59         }
60     }
61     else
62     {
63         for (int i = 0; i < sector[sect2].wallnum; i++)
64         {
65             if (wall[sector[sect2].wallptr+i].nextsector == sect1)
66             {
67                 return 1;
68             }
69         }
70     }
71     return 0;
72 }
73 
FindSector(int nX,int nY,int nZ,int * nSector)74 bool FindSector(int nX, int nY, int nZ, int *nSector)
75 {
76     int32_t nZFloor, nZCeil;
77     dassert(*nSector >= 0 && *nSector < kMaxSectors);
78     if (inside(nX, nY, *nSector))
79     {
80         getzsofslope(*nSector, nX, nY, &nZCeil, &nZFloor);
81         if (nZ >= nZCeil && nZ <= nZFloor)
82         {
83             return 1;
84         }
85     }
86     walltype *pWall = &wall[sector[*nSector].wallptr];
87     for (int i = sector[*nSector].wallnum; i > 0; i--, pWall++)
88     {
89         int nOSector = pWall->nextsector;
90         if (nOSector >= 0 && inside(nX, nY, nOSector))
91         {
92             getzsofslope(nOSector, nX, nY, &nZCeil, &nZFloor);
93             if (nZ >= nZCeil && nZ <= nZFloor)
94             {
95                 *nSector = nOSector;
96                 return 1;
97             }
98         }
99     }
100     for (int i = 0; i < numsectors; i++)
101     {
102         if (inside(nX, nY, i))
103         {
104             getzsofslope(i, nX, nY, &nZCeil, &nZFloor);
105             if (nZ >= nZCeil && nZ <= nZFloor)
106             {
107                 *nSector = i;
108                 return 1;
109             }
110         }
111     }
112     return 0;
113 }
114 
FindSector(int nX,int nY,int * nSector)115 bool FindSector(int nX, int nY, int *nSector)
116 {
117     dassert(*nSector >= 0 && *nSector < kMaxSectors);
118     if (inside(nX, nY, *nSector))
119     {
120         return 1;
121     }
122     walltype *pWall = &wall[sector[*nSector].wallptr];
123     for (int i = sector[*nSector].wallnum; i > 0; i--, pWall++)
124     {
125         int nOSector = pWall->nextsector;
126         if (nOSector >= 0 && inside(nX, nY, nOSector))
127         {
128             *nSector = nOSector;
129             return 1;
130         }
131     }
132     for (int i = 0; i < numsectors; i++)
133     {
134         if (inside(nX, nY, i))
135         {
136             *nSector = i;
137             return 1;
138         }
139     }
140     return 0;
141 }
142 
CalcFrameRate(void)143 void CalcFrameRate(void)
144 {
145     static int ticks[64];
146     static int index;
147     if (ticks[index] != gFrameClock)
148     {
149         gFrameRate = (120*64)/((int)gFrameClock-ticks[index]);
150         ticks[index] = (int)gFrameClock;
151     }
152     index = (index+1) & 63;
153 }
154 
CheckProximity(spritetype * pSprite,int nX,int nY,int nZ,int nSector,int nDist)155 bool CheckProximity(spritetype *pSprite, int nX, int nY, int nZ, int nSector, int nDist)
156 {
157     dassert(pSprite != NULL);
158     int oX = klabs(nX-pSprite->x)>>4;
159     if (oX >= nDist) return 0;
160 
161     int oY = klabs(nY-pSprite->y)>>4;
162     if (oY >= nDist) return 0;
163 
164     int oZ = klabs(nZ-pSprite->z)>>8;
165     if (oZ >= nDist) return 0;
166 
167     if (approxDist(oX, oY) >= nDist) return 0;
168 
169     int bottom, top;
170     GetSpriteExtents(pSprite, &top, &bottom);
171     if (cansee(pSprite->x, pSprite->y, pSprite->z, pSprite->sectnum, nX, nY, nZ, nSector))
172         return 1;
173     if (cansee(pSprite->x, pSprite->y, bottom, pSprite->sectnum, nX, nY, nZ, nSector))
174         return 1;
175     if (cansee(pSprite->x, pSprite->y, top, pSprite->sectnum, nX, nY, nZ, nSector))
176         return 1;
177     return 0;
178 }
179 
CheckProximityPoint(int nX1,int nY1,int nZ1,int nX2,int nY2,int nZ2,int nDist)180 bool CheckProximityPoint(int nX1, int nY1, int nZ1, int nX2, int nY2, int nZ2, int nDist)
181 {
182     int oX = klabs(nX2-nX1)>>4;
183     if (oX >= nDist)
184         return 0;
185     int oY = klabs(nY2-nY1)>>4;
186     if (oY >= nDist)
187         return 0;
188     int oZ = klabs(nZ2-nZ1)>>4;
189     if (oZ >= nDist)
190         return 0;
191     if (approxDist(oX, oY) >= nDist) return 0;
192     return 1;
193 }
194 
CheckProximityWall(int nWall,int x,int y,int nDist)195 bool CheckProximityWall(int nWall, int x, int y, int nDist)
196 {
197     int x1 = wall[nWall].x;
198     int y1 = wall[nWall].y;
199     int x2 = wall[wall[nWall].point2].x;
200     int y2 = wall[wall[nWall].point2].y;
201     nDist <<= 4;
202     if (x1 < x2)
203     {
204         if (x <= x1 - nDist || x >= x2 + nDist)
205         {
206             return 0;
207         }
208     }
209     else
210     {
211         if (x <= x2 - nDist || x >= x1 + nDist)
212         {
213             return 0;
214         }
215         if (x1 == x2)
216         {
217             int px1 = x - x1;
218             int py1 = y - y1;
219             int px2 = x - x2;
220             int py2 = y - y2;
221             int dist1 = px1 * px1 + py1 * py1;
222             int dist2 = px2 * px2 + py2 * py2;
223             if (y1 < y2)
224             {
225                 if (y <= y1 - nDist || y >= y2 + nDist)
226                 {
227                     return 0;
228                 }
229                 if (y < y1)
230                 {
231                     return dist1 < nDist * nDist;
232                 }
233                 if (y > y2)
234                 {
235                     return dist2 < nDist * nDist;
236                 }
237             }
238             else
239             {
240                 if (y <= y2 - nDist || y >= y1 + nDist)
241                 {
242                     return 0;
243                 }
244                 if (y < y2)
245                 {
246                     return dist2 < nDist * nDist;
247                 }
248                 if (y > y1)
249                 {
250                     return dist1 < nDist * nDist;
251                 }
252             }
253             return 1;
254         }
255     }
256     if (y1 < y2)
257     {
258         if (y <= y1 - nDist || y >= y2 + nDist)
259         {
260             return 0;
261         }
262     }
263     else
264     {
265         if (y <= y2 - nDist || y >= y1 + nDist)
266         {
267             return 0;
268         }
269         if (y1 == y2)
270         {
271             int px1 = x - x1;
272             int py1 = y - y1;
273             int px2 = x - x2;
274             int py2 = y - y2;
275             int check1 = px1 * px1 + py1 * py1;
276             int check2 = px2 * px2 + py2 * py2;
277             if (x1 < x2)
278             {
279                 if (x <= x1 - nDist || x >= x2 + nDist)
280                 {
281                     return 0;
282                 }
283                 if (x < x1)
284                 {
285                     return check1 < nDist * nDist;
286                 }
287                 if (x > x2)
288                 {
289                     return check2 < nDist * nDist;
290                 }
291             }
292             else
293             {
294                 if (x <= x2 - nDist || x >= x1 + nDist)
295                 {
296                     return 0;
297                 }
298                 if (x < x2)
299                 {
300                     return check2 < nDist * nDist;
301                 }
302                 if (x > x1)
303                 {
304                     return check1 < nDist * nDist;
305                 }
306             }
307         }
308     }
309 
310     int dx = x2 - x1;
311     int dy = y2 - y1;
312     int px = x - x2;
313     int py = y - y2;
314     int side = px * dx + dy * py;
315     if (side >= 0)
316     {
317         return px * px + py * py < nDist * nDist;
318     }
319     px = x - x1;
320     py = y - y1;
321     side = px * dx + dy * py;
322     if (side <= 0)
323     {
324         return px * px + py * py < nDist * nDist;
325     }
326     int check1 = px * dy - dx * py;
327     int check2 = dy * dy + dx * dx;
328     return check1 * check1 < check2 * nDist * nDist;
329 }
330 
GetWallAngle(int nWall)331 int GetWallAngle(int nWall)
332 {
333     int nWall2 = wall[nWall].point2;
334     return getangle(wall[nWall2].x - wall[nWall].x, wall[nWall2].y - wall[nWall].y);
335 }
336 
GetWallNormal(int nWall,int * pX,int * pY)337 void GetWallNormal(int nWall, int *pX, int *pY)
338 {
339     dassert(nWall >= 0 && nWall < kMaxWalls);
340     int nWall2 = wall[nWall].point2;
341     int dX = -(wall[nWall2].y - wall[nWall].y);
342     dX >>= 4;
343     int dY = wall[nWall2].x - wall[nWall].x;
344     dY >>= 4;
345     int nLength = ksqrt(dX*dX+dY*dY);
346     if (nLength <= 0)
347         nLength = 1;
348     *pX = divscale16(dX, nLength);
349     *pY = divscale16(dY, nLength);
350 }
351 
IntersectRay(int wx,int wy,int wdx,int wdy,int x1,int y1,int z1,int x2,int y2,int z2,int * ix,int * iy,int * iz)352 bool IntersectRay(int wx, int wy, int wdx, int wdy, int x1, int y1, int z1, int x2, int y2, int z2, int *ix, int *iy, int *iz)
353 {
354     int dX = x1 - x2;
355     int dY = y1 - y2;
356     int dZ = z1 - z2;
357     int side = wdx * dY - wdy * dX;
358     int dX2 = x1 - wx;
359     int dY2 = y1 - wy;
360     int check1 = dX2 * dY - dY2 * dX;
361     int check2 = wdx * dY2 - wdy * dX2;
362     if (side >= 0)
363     {
364         if (!side)
365             return 0;
366         if (check1 < 0)
367             return 0;
368         if (check2 < 0 || check2 >= side)
369             return 0;
370     }
371     else
372     {
373         if (check1 > 0)
374             return 0;
375         if (check2 > 0 || check2 <= side)
376             return 0;
377     }
378     int nScale = divscale16(check2, side);
379     *ix = x1 + mulscale16(dX, nScale);
380     *iy = y1 + mulscale16(dY, nScale);
381     *iz = z1 + mulscale16(dZ, nScale);
382     return 1;
383 }
384 
HitScan(spritetype * pSprite,int z,int dx,int dy,int dz,unsigned int nMask,int nRange)385 int HitScan(spritetype *pSprite, int z, int dx, int dy, int dz, unsigned int nMask, int nRange)
386 {
387     dassert(pSprite != NULL);
388     dassert(dx != 0 || dy != 0);
389     gHitInfo.hitsect = -1;
390     gHitInfo.hitwall = -1;
391     gHitInfo.hitsprite = -1;
392     int x = pSprite->x;
393     int y = pSprite->y;
394     int nSector = pSprite->sectnum;
395     int bakCstat = pSprite->cstat;
396     pSprite->cstat &= ~256;
397     if (nRange)
398     {
399         hitscangoal.x = x + mulscale30(nRange << 4, Cos(pSprite->ang));
400         hitscangoal.y = y + mulscale30(nRange << 4, Sin(pSprite->ang));
401     }
402     else
403     {
404         hitscangoal.x = hitscangoal.y = 0x1ffffff;
405     }
406     vec3_t pos = { x, y, z };
407     hitdata_t hitData;
408     hitData.pos.z = gHitInfo.hitz;
409     hitscan(&pos, nSector, dx, dy, dz << 4, &hitData, nMask);
410     gHitInfo.hitsect = hitData.sect;
411     gHitInfo.hitwall = hitData.wall;
412     gHitInfo.hitsprite = hitData.sprite;
413     gHitInfo.hitx = hitData.pos.x;
414     gHitInfo.hity = hitData.pos.y;
415     gHitInfo.hitz = hitData.pos.z;
416     hitscangoal.x = hitscangoal.y = 0x1ffffff;
417     pSprite->cstat = bakCstat;
418     if (gHitInfo.hitsprite >= kMaxSprites || gHitInfo.hitwall >= kMaxWalls || gHitInfo.hitsect >= kMaxSectors)
419         return -1;
420     if (gHitInfo.hitsprite >= 0)
421         return 3;
422     if (gHitInfo.hitwall >= 0)
423     {
424         if (wall[gHitInfo.hitwall].nextsector == -1)
425             return 0;
426         int nZCeil, nZFloor;
427         getzsofslope(wall[gHitInfo.hitwall].nextsector, gHitInfo.hitx, gHitInfo.hity, &nZCeil, &nZFloor);
428         if (gHitInfo.hitz <= nZCeil || gHitInfo.hitz >= nZFloor)
429             return 0;
430         return 4;
431     }
432     if (gHitInfo.hitsect >= 0)
433         return 1 + (z < gHitInfo.hitz);
434     return -1;
435 }
436 
VectorScan(spritetype * pSprite,int nOffset,int nZOffset,int dx,int dy,int dz,int nRange,int ac)437 int VectorScan(spritetype *pSprite, int nOffset, int nZOffset, int dx, int dy, int dz, int nRange, int ac)
438 {
439     int nNum = 256;
440     dassert(pSprite != NULL);
441     gHitInfo.hitsect = -1;
442     gHitInfo.hitwall = -1;
443     gHitInfo.hitsprite = -1;
444     int x1 = pSprite->x+mulscale30(nOffset, Cos(pSprite->ang+512));
445     int y1 = pSprite->y+mulscale30(nOffset, Sin(pSprite->ang+512));
446     int z1 = pSprite->z+nZOffset;
447     int bakCstat = pSprite->cstat;
448     pSprite->cstat &= ~256;
449     int nSector = pSprite->sectnum;
450     if (nRange)
451     {
452         hitscangoal.x = x1+mulscale30(nRange<<4, Cos(pSprite->ang));
453         hitscangoal.y = y1+mulscale30(nRange<<4, Sin(pSprite->ang));
454     }
455     else
456     {
457         hitscangoal.x = hitscangoal.y = 0x1fffffff;
458     }
459     vec3_t pos = { x1, y1, z1 };
460     hitdata_t hitData;
461     hitData.pos.z = gHitInfo.hitz;
462     hitscan(&pos, nSector, dx, dy, dz << 4, &hitData, CLIPMASK1);
463     gHitInfo.hitsect = hitData.sect;
464     gHitInfo.hitwall = hitData.wall;
465     gHitInfo.hitsprite = hitData.sprite;
466     gHitInfo.hitx = hitData.pos.x;
467     gHitInfo.hity = hitData.pos.y;
468     gHitInfo.hitz = hitData.pos.z;
469     hitscangoal.x = hitscangoal.y = 0x1ffffff;
470     pSprite->cstat = bakCstat;
471     while (nNum--)
472     {
473         if (gHitInfo.hitsprite >= kMaxSprites || gHitInfo.hitwall >= kMaxWalls || gHitInfo.hitsect >= kMaxSectors)
474             return -1;
475         if (nRange && approxDist(gHitInfo.hitx - pSprite->x, gHitInfo.hity - pSprite->y) > nRange)
476             return -1;
477         if (gHitInfo.hitsprite >= 0)
478         {
479             spritetype *pOther = &sprite[gHitInfo.hitsprite];
480             if ((pOther->flags & 8) && !(ac & 1))
481                 return 3;
482             if ((pOther->cstat & 0x30) != 0)
483                 return 3;
484             int nPicnum = pOther->picnum;
485             if (tilesiz[nPicnum].x == 0 || tilesiz[nPicnum].y == 0)
486                 return 3;
487             int height = (tilesiz[nPicnum].y*pOther->yrepeat)<<2;
488             int otherZ = pOther->z;
489             if (pOther->cstat & 0x80)
490                 otherZ += height / 2;
491             int nOffset = picanm[nPicnum].yofs;
492             if (nOffset)
493                 otherZ -= (nOffset*pOther->yrepeat)<<2;
494             dassert(height > 0);
495             int height2 = scale(otherZ-gHitInfo.hitz, tilesiz[nPicnum].y, height);
496             if (!(pOther->cstat & 8))
497                 height2 = tilesiz[nPicnum].y-height2;
498             if (height2 >= 0 && height2 < tilesiz[nPicnum].y)
499             {
500                 int width = (tilesiz[nPicnum].x*pOther->xrepeat)>>2;
501                 width = (width*3)/4;
502                 int check1 = ((y1 - pOther->y)*dx - (x1 - pOther->x)*dy) / ksqrt(dx*dx+dy*dy);
503                 dassert(width > 0);
504                 int width2 = scale(check1, tilesiz[nPicnum].x, width);
505                 int nOffset = picanm[nPicnum].xofs;
506                 width2 += nOffset + tilesiz[nPicnum].x / 2;
507                 if (width2 >= 0 && width2 < tilesiz[nPicnum].x)
508                 {
509                     char *pData = tileLoadTile(nPicnum);
510                     if (pData[width2*tilesiz[nPicnum].y+height2] != (char)255)
511                         return 3;
512                 }
513             }
514             int bakCstat = pOther->cstat;
515             pOther->cstat &= ~256;
516             gHitInfo.hitsect = -1;
517             gHitInfo.hitwall = -1;
518             gHitInfo.hitsprite = -1;
519             x1 = gHitInfo.hitx;
520             y1 = gHitInfo.hity;
521             z1 = gHitInfo.hitz;
522             pos = { x1, y1, z1 };
523             hitData.pos.z = gHitInfo.hitz;
524             hitscan(&pos, pOther->sectnum,
525                 dx, dy, dz << 4, &hitData, CLIPMASK1);
526             gHitInfo.hitsect = hitData.sect;
527             gHitInfo.hitwall = hitData.wall;
528             gHitInfo.hitsprite = hitData.sprite;
529             gHitInfo.hitx = hitData.pos.x;
530             gHitInfo.hity = hitData.pos.y;
531             gHitInfo.hitz = hitData.pos.z;
532             pOther->cstat = bakCstat;
533             continue;
534         }
535         if (gHitInfo.hitwall >= 0)
536         {
537             walltype *pWall = &wall[gHitInfo.hitwall];
538             if (pWall->nextsector == -1)
539                 return 0;
540             sectortype *pSector = &sector[gHitInfo.hitsect];
541             sectortype *pSectorNext = &sector[pWall->nextsector];
542             int nZCeil, nZFloor;
543             getzsofslope(pWall->nextsector, gHitInfo.hitx, gHitInfo.hity, &nZCeil, &nZFloor);
544             if (gHitInfo.hitz <= nZCeil)
545                 return 0;
546             if (gHitInfo.hitz >= nZFloor)
547             {
548                 if (!(pSector->floorstat&1) || !(pSectorNext->floorstat&1))
549                     return 0;
550                 return 2;
551             }
552             if (!(pWall->cstat & 0x30))
553                 return 0;
554             int nOffset;
555             if (pWall->cstat & 4)
556                 nOffset = ClipHigh(pSector->floorz, pSectorNext->floorz);
557             else
558                 nOffset = ClipLow(pSector->ceilingz, pSectorNext->ceilingz);
559             nOffset = (gHitInfo.hitz - nOffset) >> 8;
560             if (pWall->cstat & 256)
561                 nOffset = -nOffset;
562 
563             int nPicnum = pWall->overpicnum;
564             int nSizX = tilesiz[nPicnum].x;
565             int nSizY = tilesiz[nPicnum].y;
566             if (!nSizX || !nSizY)
567                 return 0;
568 
569             int potX = nSizX == (1<<(picsiz[nPicnum]&15));
570             int potY = nSizY == (1<<(picsiz[nPicnum]>>4));
571 
572             nOffset = (nOffset*pWall->yrepeat) / 8;
573             nOffset += (nSizY*pWall->ypanning) / 256;
574             int nLength = approxDist(pWall->x - wall[pWall->point2].x, pWall->y - wall[pWall->point2].y);
575             int nHOffset;
576             if (pWall->cstat & 8)
577                 nHOffset = approxDist(gHitInfo.hitx - wall[pWall->point2].x, gHitInfo.hity - wall[pWall->point2].y);
578             else
579                 nHOffset = approxDist(gHitInfo.hitx - pWall->x, gHitInfo.hity - pWall->y);
580 
581             nHOffset = pWall->xpanning + ((nHOffset*pWall->xrepeat) << 3) / nLength;
582             if (potX)
583                 nHOffset &= nSizX - 1;
584             else
585                 nHOffset %= nSizX;
586             if (potY)
587                 nOffset &= nSizY - 1;
588             else
589                 nOffset %= nSizY;
590             char *pData = tileLoadTile(nPicnum);
591             int nPixel;
592             if (potY)
593                 nPixel = (nHOffset<<(picsiz[nPicnum]>>4)) + nOffset;
594             else
595                 nPixel = nHOffset*nSizY + nOffset;
596 
597             if (pData[nPixel] == (char)255)
598             {
599                 int bakCstat = pWall->cstat;
600                 pWall->cstat &= ~64;
601                 int bakCstat2 = wall[pWall->nextwall].cstat;
602                 wall[pWall->nextwall].cstat &= ~64;
603                 gHitInfo.hitsect = -1;
604                 gHitInfo.hitwall = -1;
605                 gHitInfo.hitsprite = -1;
606                 x1 = gHitInfo.hitx;
607                 y1 = gHitInfo.hity;
608                 z1 = gHitInfo.hitz;
609                 pos = { x1, y1, z1 };
610                 hitData.pos.z = gHitInfo.hitz;
611                 hitscan(&pos, pWall->nextsector,
612                     dx, dy, dz << 4, &hitData, CLIPMASK1);
613                 gHitInfo.hitsect = hitData.sect;
614                 gHitInfo.hitwall = hitData.wall;
615                 gHitInfo.hitsprite = hitData.sprite;
616                 gHitInfo.hitx = hitData.pos.x;
617                 gHitInfo.hity = hitData.pos.y;
618                 gHitInfo.hitz = hitData.pos.z;
619                 pWall->cstat = bakCstat;
620                 wall[pWall->nextwall].cstat = bakCstat2;
621                 continue;
622             }
623             return 4;
624         }
625         if (gHitInfo.hitsect >= 0)
626         {
627             if (dz > 0)
628             {
629                 if (gUpperLink[gHitInfo.hitsect] < 0)
630                     return 2;
631                 int nSprite = gUpperLink[gHitInfo.hitsect];
632                 int nLink = sprite[nSprite].owner & 0xfff;
633                 gHitInfo.hitsect = -1;
634                 gHitInfo.hitwall = -1;
635                 gHitInfo.hitsprite = -1;
636                 x1 = gHitInfo.hitx + sprite[nLink].x - sprite[nSprite].x;
637                 y1 = gHitInfo.hity + sprite[nLink].y - sprite[nSprite].y;
638                 z1 = gHitInfo.hitz + sprite[nLink].z - sprite[nSprite].z;
639                 pos = { x1, y1, z1 };
640                 hitData.pos.z = gHitInfo.hitz;
641                 hitscan(&pos, sprite[nLink].sectnum, dx, dy, dz<<4, &hitData, CLIPMASK1);
642                 gHitInfo.hitsect = hitData.sect;
643                 gHitInfo.hitwall = hitData.wall;
644                 gHitInfo.hitsprite = hitData.sprite;
645                 gHitInfo.hitx = hitData.pos.x;
646                 gHitInfo.hity = hitData.pos.y;
647                 gHitInfo.hitz = hitData.pos.z;
648                 continue;
649             }
650             else
651             {
652                 if (gLowerLink[gHitInfo.hitsect] < 0)
653                     return 1;
654                 int nSprite = gLowerLink[gHitInfo.hitsect];
655                 int nLink = sprite[nSprite].owner & 0xfff;
656                 gHitInfo.hitsect = -1;
657                 gHitInfo.hitwall = -1;
658                 gHitInfo.hitsprite = -1;
659                 x1 = gHitInfo.hitx + sprite[nLink].x - sprite[nSprite].x;
660                 y1 = gHitInfo.hity + sprite[nLink].y - sprite[nSprite].y;
661                 z1 = gHitInfo.hitz + sprite[nLink].z - sprite[nSprite].z;
662                 pos = { x1, y1, z1 };
663                 hitData.pos.z = gHitInfo.hitz;
664                 hitscan(&pos, sprite[nLink].sectnum, dx, dy, dz<<4, &hitData, CLIPMASK1);
665                 gHitInfo.hitsect = hitData.sect;
666                 gHitInfo.hitwall = hitData.wall;
667                 gHitInfo.hitsprite = hitData.sprite;
668                 gHitInfo.hitx = hitData.pos.x;
669                 gHitInfo.hity = hitData.pos.y;
670                 gHitInfo.hitz = hitData.pos.z;
671                 continue;
672             }
673         }
674         return -1;
675     }
676     return -1;
677 }
678 
GetZRange(spritetype * pSprite,int * ceilZ,int * ceilHit,int * floorZ,int * floorHit,int nDist,unsigned int nMask,unsigned int nClipParallax)679 void GetZRange(spritetype *pSprite, int *ceilZ, int *ceilHit, int *floorZ, int *floorHit, int nDist, unsigned int nMask, unsigned int nClipParallax)
680 {
681     dassert(pSprite != NULL);
682     int bakCstat = pSprite->cstat;
683     int32_t nTemp1, nTemp2;
684     pSprite->cstat &= ~257;
685     getzrange_old(pSprite->x, pSprite->y, pSprite->z, pSprite->sectnum, (int32_t*)ceilZ, (int32_t*)ceilHit, (int32_t*)floorZ, (int32_t*)floorHit, nDist, nMask);
686     if (((*floorHit) & 0xc000) == 0x4000)
687     {
688         int nSector = (*floorHit) & 0x3fff;
689         if ((nClipParallax & PARALLAXCLIP_FLOOR) == 0 && (sector[nSector].floorstat & 1))
690             *floorZ = 0x7fffffff;
691         if (sector[nSector].extra > 0)
692         {
693             XSECTOR *pXSector = &xsector[sector[nSector].extra];
694             *floorZ += pXSector->Depth << 10;
695         }
696         if (gUpperLink[nSector] >= 0)
697         {
698             int nSprite = gUpperLink[nSector];
699             int nLink = sprite[nSprite].owner & 0xfff;
700             getzrange_old(pSprite->x+sprite[nLink].x-sprite[nSprite].x, pSprite->y+sprite[nLink].y-sprite[nSprite].y,
701                 pSprite->z+sprite[nLink].z-sprite[nSprite].z, sprite[nLink].sectnum, &nTemp1, &nTemp2, (int32_t*)floorZ, (int32_t*)floorHit,
702                 nDist, nMask);
703             *floorZ -= sprite[nLink].z - sprite[nSprite].z;
704         }
705     }
706     if (((*ceilHit) & 0xc000) == 0x4000)
707     {
708         int nSector = (*ceilHit) & 0x3fff;
709         if ((nClipParallax & PARALLAXCLIP_CEILING) == 0 && (sector[nSector].ceilingstat & 1))
710             *ceilZ = 0x80000000;
711         if (gLowerLink[nSector] >= 0)
712         {
713             int nSprite = gLowerLink[nSector];
714             int nLink = sprite[nSprite].owner & 0xfff;
715             getzrange_old(pSprite->x+sprite[nLink].x-sprite[nSprite].x, pSprite->y+sprite[nLink].y-sprite[nSprite].y,
716                 pSprite->z+sprite[nLink].z-sprite[nSprite].z, sprite[nLink].sectnum, (int32_t*)ceilZ, (int32_t*)ceilHit, &nTemp1, &nTemp2,
717                 nDist, nMask);
718             *ceilZ -= sprite[nLink].z - sprite[nSprite].z;
719         }
720     }
721     pSprite->cstat = bakCstat;
722 }
723 
GetZRangeAtXYZ(int x,int y,int z,int nSector,int * ceilZ,int * ceilHit,int * floorZ,int * floorHit,int nDist,unsigned int nMask,unsigned int nClipParallax)724 void GetZRangeAtXYZ(int x, int y, int z, int nSector, int *ceilZ, int *ceilHit, int *floorZ, int *floorHit, int nDist, unsigned int nMask, unsigned int nClipParallax)
725 {
726     int32_t nTemp1, nTemp2;
727     getzrange_old(x, y, z, nSector, (int32_t*)ceilZ, (int32_t*)ceilHit, (int32_t*)floorZ, (int32_t*)floorHit, nDist, nMask);
728     if (((*floorHit) & 0xc000) == 0x4000)
729     {
730         int nSector = (*floorHit) & 0x3fff;
731         if ((nClipParallax & PARALLAXCLIP_FLOOR) == 0 && (sector[nSector].floorstat & 1))
732             *floorZ = 0x7fffffff;
733         if (sector[nSector].extra > 0)
734         {
735             XSECTOR *pXSector = &xsector[sector[nSector].extra];
736             *floorZ += pXSector->Depth << 10;
737         }
738         if (gUpperLink[nSector] >= 0)
739         {
740             int nSprite = gUpperLink[nSector];
741             int nLink = sprite[nSprite].owner & 0xfff;
742             getzrange_old(x+sprite[nLink].x-sprite[nSprite].x, y+sprite[nLink].y-sprite[nSprite].y,
743                 z+sprite[nLink].z-sprite[nSprite].z, sprite[nLink].sectnum, &nTemp1, &nTemp2, (int32_t*)floorZ, (int32_t*)floorHit,
744                 nDist, nMask);
745             *floorZ -= sprite[nLink].z - sprite[nSprite].z;
746         }
747     }
748     if (((*ceilHit) & 0xc000) == 0x4000)
749     {
750         int nSector = (*ceilHit) & 0x3fff;
751         if ((nClipParallax & PARALLAXCLIP_CEILING) == 0 && (sector[nSector].ceilingstat & 1))
752             *ceilZ = 0x80000000;
753         if (gLowerLink[nSector] >= 0)
754         {
755             int nSprite = gLowerLink[nSector];
756             int nLink = sprite[nSprite].owner & 0xfff;
757             getzrange_old(x+sprite[nLink].x-sprite[nSprite].x, y+sprite[nLink].y-sprite[nSprite].y,
758                 z+sprite[nLink].z-sprite[nSprite].z, sprite[nLink].sectnum, (int32_t*)ceilZ, (int32_t*)ceilHit, &nTemp1, &nTemp2,
759                 nDist, nMask);
760             *ceilZ -= sprite[nLink].z - sprite[nSprite].z;
761         }
762     }
763 }
764 
GetDistToLine(int x1,int y1,int x2,int y2,int x3,int y3)765 int GetDistToLine(int x1, int y1, int x2, int y2, int x3, int y3)
766 {
767     int check = (y1-y3)*(x3-x2);
768     int check2 = (x1-x2)*(y3-y2);
769     if (check2 > check)
770         return -1;
771     int v8 = dmulscale(x1-x2,x3-x2,y1-y3,y3-y2,4);
772     int vv = dmulscale(x3-x2,x3-x2,y3-y2,y3-y2,4);
773     int t1, t2;
774     if (v8 <= 0)
775     {
776         t1 = x2;
777         t2 = y2;
778     }
779     else if (vv > v8)
780     {
781         t1 = x2+scale(x3-x2,v8,vv);
782         t2 = y2+scale(y3-y2,v8,vv);
783     }
784     else
785     {
786         t1 = x3;
787         t2 = y3;
788     }
789     return approxDist(t1-x1, t2-y1);
790 }
791 
ClipMove(int * x,int * y,int * z,int * nSector,int xv,int yv,int wd,int cd,int fd,unsigned int nMask)792 unsigned int ClipMove(int *x, int *y, int *z, int *nSector, int xv, int yv, int wd, int cd, int fd, unsigned int nMask)
793 {
794     int bakX = *x;
795     int bakY = *y;
796     int bakZ = *z;
797     short bakSect = *nSector;
798     unsigned int nRes = clipmove_old((int32_t*)x, (int32_t*)y, (int32_t*)z, &bakSect, xv<<14, yv<<14, wd, cd, fd, nMask);
799     if (bakSect == -1)
800     {
801         *x = bakX; *y = bakY; *z = bakZ;
802     }
803     else
804     {
805         *nSector = bakSect;
806     }
807     return nRes;
808 }
809 
GetClosestSectors(int nSector,int x,int y,int nDist,short * pSectors,char * pSectBit)810 int GetClosestSectors(int nSector, int x, int y, int nDist, short *pSectors, char *pSectBit)
811 {
812     char sectbits[(kMaxSectors+7)>>3];
813     dassert(pSectors != NULL);
814     memset(sectbits, 0, sizeof(sectbits));
815     pSectors[0] = nSector;
816     SetBitString(sectbits, nSector);
817     int n = 1;
818     int i = 0;
819     if (pSectBit)
820     {
821         memset(pSectBit, 0, (kMaxSectors+7)>>3);
822         SetBitString(pSectBit, nSector);
823     }
824     while (i < n)
825     {
826         int nCurSector = pSectors[i];
827         int nStartWall = sector[nCurSector].wallptr;
828         int nEndWall = nStartWall + sector[nCurSector].wallnum;
829         walltype *pWall = &wall[nStartWall];
830         for (int j = nStartWall; j < nEndWall; j++, pWall++)
831         {
832             int nNextSector = pWall->nextsector;
833             if (nNextSector < 0)
834                 continue;
835             if (TestBitString(sectbits, nNextSector))
836                 continue;
837             SetBitString(sectbits, nNextSector);
838             int dx = klabs(wall[pWall->point2].x - x)>>4;
839             int dy = klabs(wall[pWall->point2].y - y)>>4;
840             if (dx < nDist && dy < nDist)
841             {
842                 if (approxDist(dx, dy) < nDist)
843                 {
844                     if (pSectBit)
845                         SetBitString(pSectBit, nNextSector);
846                     pSectors[n++] = nNextSector;
847                 }
848             }
849         }
850         i++;
851     }
852     pSectors[n] = -1;
853     return n;
854 }
855 
GetClosestSpriteSectors(int nSector,int x,int y,int nDist,short * pSectors,char * pSectBit,short * a8)856 int GetClosestSpriteSectors(int nSector, int x, int y, int nDist, short *pSectors, char *pSectBit, short *a8)
857 {
858     char sectbits[(kMaxSectors+7)>>3];
859     dassert(pSectors != NULL);
860     memset(sectbits, 0, sizeof(sectbits));
861     pSectors[0] = nSector;
862     SetBitString(sectbits, nSector);
863     int n = 1, m = 0;
864     int i = 0;
865     if (pSectBit)
866     {
867         memset(pSectBit, 0, (kMaxSectors+7)>>3);
868         SetBitString(pSectBit, nSector);
869     }
870     while (i < n)
871     {
872         int nCurSector = pSectors[i];
873         int nStartWall = sector[nCurSector].wallptr;
874         int nEndWall = nStartWall + sector[nCurSector].wallnum;
875         walltype *pWall = &wall[nStartWall];
876         for (int j = nStartWall; j < nEndWall; j++, pWall++)
877         {
878             int nNextSector = pWall->nextsector;
879             if (nNextSector < 0)
880                 continue;
881             if (TestBitString(sectbits, nNextSector))
882                 continue;
883             SetBitString(sectbits, nNextSector);
884             if (CheckProximityWall(wall[j].point2, x, y, nDist))
885             {
886                 if (pSectBit)
887                     SetBitString(pSectBit, nNextSector);
888                 pSectors[n++] = nNextSector;
889                 if (a8 && pWall->extra > 0)
890                 {
891                     XWALL *pXWall = &xwall[pWall->extra];
892                     if (pXWall->triggerVector && !pXWall->isTriggered && !pXWall->state)
893                         a8[m++] = j;
894                 }
895             }
896         }
897         i++;
898     }
899     pSectors[n] = -1;
900     if (a8)
901     {
902         a8[m] = -1;
903     }
904     return n;
905 }
906 
picWidth(short nPic,short repeat)907 int picWidth(short nPic, short repeat) {
908     return ClipLow((tilesiz[nPic].x * repeat) << 2, 0);
909 }
910 
picHeight(short nPic,short repeat)911 int picHeight(short nPic, short repeat) {
912     return ClipLow((tilesiz[nPic].y * repeat) << 2, 0);
913 }
914 
915 
916