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 = §or[gHitInfo.hitsect];
541 sectortype *pSectorNext = §or[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