2018-11-05 07:28:01 +00:00
|
|
|
// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
|
|
|
|
// Ken Silverman's official web site: "http://www.advsys.net/ken"
|
|
|
|
// See the included license file "BUILDLIC.TXT" for license info.
|
|
|
|
//
|
|
|
|
// This file has been modified from Ken Silverman's original release
|
|
|
|
// by Jonathon Fowler (jf@jonof.id.au)
|
|
|
|
// by the EDuke32 team (development@voidpoint.com)
|
|
|
|
|
2016-06-21 00:33:30 +00:00
|
|
|
#include "build.h"
|
2019-04-10 09:31:01 +00:00
|
|
|
#include "clip.h"
|
2016-06-21 00:33:30 +00:00
|
|
|
#include "engine_priv.h"
|
2020-08-28 07:06:49 +00:00
|
|
|
#include "printf.h"
|
2021-03-20 11:47:51 +00:00
|
|
|
#include "gamefuncs.h"
|
2021-12-03 23:47:08 +00:00
|
|
|
#include "coreactor.h"
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2021-03-20 15:46:06 +00:00
|
|
|
enum { MAXCLIPDIST = 1024 };
|
2020-04-11 22:04:02 +00:00
|
|
|
|
2021-11-11 19:20:00 +00:00
|
|
|
static int clipnum;
|
2019-04-10 09:31:01 +00:00
|
|
|
static linetype clipit[MAXCLIPNUM];
|
|
|
|
static int32_t clipsectnum, origclipsectnum, clipspritenum;
|
2021-11-11 19:20:00 +00:00
|
|
|
int clipsectorlist[MAXCLIPSECTORS];
|
|
|
|
static int origclipsectorlist[MAXCLIPSECTORS];
|
2021-12-04 00:05:18 +00:00
|
|
|
static CollisionBase clipobjectval[MAXCLIPNUM];
|
2019-07-24 12:56:44 +00:00
|
|
|
static uint8_t clipignore[(MAXCLIPNUM+7)>>3];
|
2021-03-27 14:03:57 +00:00
|
|
|
static int32_t rxi[8], ryi[8];
|
|
|
|
|
2021-12-06 19:08:32 +00:00
|
|
|
BitArray clipsectormap;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
|
|
|
int32_t quickloadboard=0;
|
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
vec2_t hitscangoal = { (1<<29)-1, (1<<29)-1 };
|
2019-03-19 17:08:59 +00:00
|
|
|
int32_t hitallsprites = 0;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
|
|
|
////////// CLIPMOVE //////////
|
2021-12-06 19:08:32 +00:00
|
|
|
inline char bitmap_test(uint8_t const* const ptr, int const n) { return ptr[n >> 3] & (1 << (n & 7)); }
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2021-03-27 14:03:57 +00:00
|
|
|
|
|
|
|
// x1, y1: in/out
|
|
|
|
// rest x/y: out
|
|
|
|
template <typename T>
|
|
|
|
static inline void get_wallspr_points(T const * const spr, int32_t *x1, int32_t *x2,
|
|
|
|
int32_t *y1, int32_t *y2)
|
|
|
|
{
|
|
|
|
//These lines get the 2 points of the rotated sprite
|
|
|
|
//Given: (x1, y1) starts out as the center point
|
|
|
|
|
|
|
|
const int32_t tilenum=spr->picnum, ang=spr->ang;
|
|
|
|
const int32_t xrepeat = spr->xrepeat;
|
|
|
|
int32_t xoff = tileLeftOffset(tilenum) + spr->xoffset;
|
|
|
|
int32_t k, l, dax, day;
|
|
|
|
|
2021-12-18 15:45:05 +00:00
|
|
|
if (spr->cstat & CSTAT_SPRITE_XFLIP)
|
2021-03-27 14:03:57 +00:00
|
|
|
xoff = -xoff;
|
|
|
|
|
|
|
|
dax = bsin(ang) * xrepeat;
|
|
|
|
day = -bcos(ang) * xrepeat;
|
|
|
|
|
|
|
|
l = tileWidth(tilenum);
|
|
|
|
k = (l>>1)+xoff;
|
|
|
|
|
|
|
|
*x1 -= MulScale(dax,k, 16);
|
|
|
|
*x2 = *x1 + MulScale(dax,l, 16);
|
|
|
|
|
|
|
|
*y1 -= MulScale(day,k, 16);
|
|
|
|
*y2 = *y1 + MulScale(day,l, 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
// x1, y1: in/out
|
|
|
|
// rest x/y: out
|
2021-12-20 19:27:12 +00:00
|
|
|
static inline void get_floorspr_points(spritetype const * const spr, int32_t px, int32_t py,
|
2021-03-27 14:03:57 +00:00
|
|
|
int32_t *x1, int32_t *x2, int32_t *x3, int32_t *x4,
|
2021-12-20 19:27:12 +00:00
|
|
|
int32_t *y1, int32_t *y2, int32_t *y3, int32_t *y4, int heinum = 0)
|
2021-03-27 14:03:57 +00:00
|
|
|
{
|
|
|
|
const int32_t tilenum = spr->picnum;
|
|
|
|
const int32_t cosang = bcos(spr->ang);
|
|
|
|
const int32_t sinang = bsin(spr->ang);
|
|
|
|
|
|
|
|
vec2_t const span = { tileWidth(tilenum), tileHeight(tilenum)};
|
|
|
|
vec2_t const repeat = { spr->xrepeat, spr->yrepeat };
|
|
|
|
|
|
|
|
vec2_t adjofs = { tileLeftOffset(tilenum) + spr->xoffset, tileTopOffset(tilenum) + spr->yoffset };
|
|
|
|
|
2021-12-20 19:27:12 +00:00
|
|
|
int32_t const ratio = ksqrt(heinum * heinum + 4096 * 4096);
|
|
|
|
|
2021-12-18 15:09:58 +00:00
|
|
|
if (spr->cstat & CSTAT_SPRITE_XFLIP)
|
2021-12-22 09:26:51 +00:00
|
|
|
adjofs.X = -adjofs.X;
|
2021-03-27 14:03:57 +00:00
|
|
|
|
2021-12-18 15:09:58 +00:00
|
|
|
if (spr->cstat & CSTAT_SPRITE_YFLIP)
|
2021-03-27 14:03:57 +00:00
|
|
|
adjofs.y = -adjofs.y;
|
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
vec2_t const center = { ((span.X >> 1) + adjofs.X) * repeat.X, ((span.y >> 1) + adjofs.y) * repeat.y };
|
|
|
|
vec2_t const rspan = { span.X * repeat.X, span.y * repeat.y };
|
2021-12-20 19:27:12 +00:00
|
|
|
vec2_t const ofs = { -DivScale(MulScale(cosang, rspan.y, 16), ratio, 12), -DivScale(MulScale(sinang, rspan.y, 16), ratio, 12) };
|
|
|
|
vec2_t const cossinslope = { DivScale(cosang, ratio, 12), DivScale(sinang, ratio, 12) };
|
2021-03-27 14:03:57 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
*x1 += DMulScale(sinang, center.X, cossinslope.X, center.y, 16) - px;
|
|
|
|
*y1 += DMulScale(cossinslope.y, center.y, -cosang, center.X, 16) - py;
|
2021-03-27 14:03:57 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
*x2 = *x1 - MulScale(sinang, rspan.X, 16);
|
|
|
|
*y2 = *y1 + MulScale(cosang, rspan.X, 16);
|
2021-03-27 14:03:57 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
*x3 = *x2 + ofs.X, *x4 = *x1 + ofs.X;
|
2021-03-27 14:03:57 +00:00
|
|
|
*y3 = *y2 + ofs.y, *y4 = *y1 + ofs.y;
|
|
|
|
}
|
|
|
|
|
2016-06-21 00:33:30 +00:00
|
|
|
//
|
|
|
|
// clipinsidebox
|
|
|
|
//
|
2016-08-27 01:41:33 +00:00
|
|
|
int clipinsidebox(vec2_t *vect, int wallnum, int walldist)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2019-04-18 17:25:24 +00:00
|
|
|
int const r = walldist << 1;
|
|
|
|
|
|
|
|
auto const wal1 = (uwallptr_t)&wall[wallnum];
|
2021-12-01 23:54:11 +00:00
|
|
|
auto const wal2 = (uwallptr_t)wal1->point2Wall();
|
2019-04-18 17:25:24 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
vec2_t const v1 = { wal1->x + walldist - vect->X, wal1->y + walldist - vect->y };
|
|
|
|
vec2_t v2 = { wal2->x + walldist - vect->X, wal2->y + walldist - vect->y };
|
2016-08-27 01:41:33 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
if (((v1.X < 0) && (v2.X < 0)) || ((v1.y < 0) && (v2.y < 0)) || ((v1.X >= r) && (v2.X >= r)) || ((v1.y >= r) && (v2.y >= r)))
|
2016-06-21 00:33:35 +00:00
|
|
|
return 0;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
v2.X -= v1.X; v2.y -= v1.y;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
if (v2.X * (walldist - v1.y) >= v2.y * (walldist - v1.X)) // Front
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2021-12-22 09:26:51 +00:00
|
|
|
v2.X *= ((v2.X > 0) ? (0 - v1.y) : (r - v1.y));
|
|
|
|
v2.y *= ((v2.y > 0) ? (r - v1.X) : (0 - v1.X));
|
|
|
|
return v2.X < v2.y;
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
v2.X *= ((v2.X > 0) ? (r - v1.y) : (0 - v1.y));
|
|
|
|
v2.y *= ((v2.y > 0) ? (0 - v1.X) : (r - v1.X));
|
|
|
|
return (v2.X >= v2.y) << 1;
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
|
|
|
|
2021-12-20 19:27:12 +00:00
|
|
|
static int32_t spriteGetZOfSlope(const spritetype* spr, int32_t dax, int32_t day)
|
|
|
|
{
|
|
|
|
int16_t const heinum = spriteGetSlope(spr);
|
|
|
|
if (heinum == 0)
|
|
|
|
return spr->z;
|
|
|
|
|
|
|
|
int const j = DMulScale(bsin(spr->ang + 1024), day - spr->y, -bsin(spr->ang + 512), dax - spr->x, 4);
|
|
|
|
return spr->z + MulScale(heinum, j, 18);
|
|
|
|
}
|
|
|
|
|
2016-06-21 00:33:30 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// clipinsideboxline
|
|
|
|
//
|
2016-08-27 01:41:33 +00:00
|
|
|
int clipinsideboxline(int x, int y, int x1, int y1, int x2, int y2, int walldist)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2016-08-27 01:41:33 +00:00
|
|
|
int const r = walldist << 1;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2016-08-27 01:41:33 +00:00
|
|
|
x1 += walldist - x;
|
|
|
|
x2 += walldist - x;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
|
|
|
if (((x1 < 0) && (x2 < 0)) || ((x1 >= r) && (x2 >= r)))
|
2016-06-21 00:33:35 +00:00
|
|
|
return 0;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2016-08-27 01:41:33 +00:00
|
|
|
y1 += walldist - y;
|
|
|
|
y2 += walldist - y;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
|
|
|
if (((y1 < 0) && (y2 < 0)) || ((y1 >= r) && (y2 >= r)))
|
2016-06-21 00:33:35 +00:00
|
|
|
return 0;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2016-08-27 01:41:33 +00:00
|
|
|
x2 -= x1;
|
|
|
|
y2 -= y1;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2016-08-27 01:41:33 +00:00
|
|
|
if (x2 * (walldist - y1) >= y2 * (walldist - x1)) // Front
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2016-08-27 01:41:33 +00:00
|
|
|
x2 *= ((x2 > 0) ? (0 - y1) : (r - y1));
|
|
|
|
y2 *= ((y2 > 0) ? (r - x1) : (0 - x1));
|
2016-06-21 00:33:30 +00:00
|
|
|
return x2 < y2;
|
|
|
|
}
|
|
|
|
|
2016-08-27 01:41:33 +00:00
|
|
|
x2 *= ((x2 > 0) ? (r - y1) : (0 - y1));
|
|
|
|
y2 *= ((y2 > 0) ? (0 - x1) : (r - x1));
|
|
|
|
return (x2 >= y2) << 1;
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
|
|
|
|
2019-04-18 17:23:42 +00:00
|
|
|
static int32_t clipmove_warned;
|
|
|
|
|
|
|
|
static inline void addclipsect(int const sectnum)
|
|
|
|
{
|
2019-08-27 06:52:30 +00:00
|
|
|
if (clipsectnum < MAXCLIPSECTORS)
|
2019-04-18 17:23:42 +00:00
|
|
|
{
|
2021-12-06 19:08:32 +00:00
|
|
|
clipsectormap.Set(sectnum);
|
2019-04-18 17:23:42 +00:00
|
|
|
clipsectorlist[clipsectnum++] = sectnum;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
clipmove_warned |= 1;
|
|
|
|
}
|
2016-06-21 00:33:30 +00:00
|
|
|
|
|
|
|
|
2021-12-04 00:05:18 +00:00
|
|
|
static void addclipline(int32_t dax1, int32_t day1, int32_t dax2, int32_t day2, const CollisionBase& daoval, int nofix)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2019-08-27 06:52:30 +00:00
|
|
|
if (clipnum >= MAXCLIPNUM)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2019-07-24 12:56:44 +00:00
|
|
|
clipmove_warned |= 2;
|
|
|
|
return;
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
2019-07-24 12:56:44 +00:00
|
|
|
|
|
|
|
clipit[clipnum].x1 = dax1; clipit[clipnum].y1 = day1;
|
|
|
|
clipit[clipnum].x2 = dax2; clipit[clipnum].y2 = day2;
|
2019-07-26 21:54:52 +00:00
|
|
|
clipobjectval[clipnum] = daoval;
|
2019-07-24 12:56:44 +00:00
|
|
|
|
2021-03-24 19:37:20 +00:00
|
|
|
uint32_t const mask = (1 << (clipnum&7));
|
2019-08-04 02:51:50 +00:00
|
|
|
uint8_t &value = clipignore[clipnum>>3];
|
2019-07-26 21:54:52 +00:00
|
|
|
value = (value & ~mask) | (-nofix & mask);
|
2019-07-24 12:56:44 +00:00
|
|
|
|
|
|
|
clipnum++;
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
|
|
|
|
2021-03-24 20:43:36 +00:00
|
|
|
inline void clipmove_tweak_pos(const vec3_t *pos, int32_t gx, int32_t gy, int32_t x1, int32_t y1, int32_t x2,
|
2016-06-21 00:33:35 +00:00
|
|
|
int32_t y2, int32_t *daxptr, int32_t *dayptr)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
|
|
|
int32_t daz;
|
|
|
|
|
2019-11-08 16:15:00 +00:00
|
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_19950829 ||
|
|
|
|
rintersect(pos->x, pos->y, 0, gx, gy, 0, x1, y1, x2, y2, daxptr, dayptr, &daz) == -1)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
|
|
|
*daxptr = pos->x;
|
|
|
|
*dayptr = pos->y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns: should clip?
|
2019-08-27 06:52:42 +00:00
|
|
|
static int cliptestsector(int const dasect, int const nextsect, int32_t const flordist, int32_t const ceildist, vec2_t const pos, int32_t const posz)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2021-11-07 17:09:19 +00:00
|
|
|
assert(validSectorIndex(dasect) && validSectorIndex(nextsect));
|
2019-08-27 06:52:42 +00:00
|
|
|
|
2019-04-19 08:31:54 +00:00
|
|
|
auto const sec2 = (usectorptr_t)§or[nextsect];
|
2019-08-27 06:52:42 +00:00
|
|
|
|
2019-09-22 19:26:07 +00:00
|
|
|
switch (enginecompatibility_mode)
|
|
|
|
{
|
|
|
|
case ENGINECOMPATIBILITY_NONE:
|
|
|
|
break;
|
|
|
|
default:
|
2019-07-29 11:12:06 +00:00
|
|
|
{
|
2021-12-22 09:26:51 +00:00
|
|
|
int32_t daz = getflorzofslopeptr(§or[dasect], pos.X, pos.y);
|
|
|
|
int32_t daz2 = getflorzofslopeptr(sec2, pos.X, pos.y);
|
2019-07-29 11:12:06 +00:00
|
|
|
|
2021-12-18 12:14:56 +00:00
|
|
|
if (daz2 < daz-(1<<8) && (sec2->floorstat & CSTAT_SECTOR_SKY) == 0)
|
2019-09-21 11:02:17 +00:00
|
|
|
if (posz >= daz2-(flordist-1)) return 1;
|
2021-12-22 09:26:51 +00:00
|
|
|
daz = getceilzofslopeptr(§or[dasect], pos.X, pos.y);
|
|
|
|
daz2 = getceilzofslopeptr(sec2, pos.X, pos.y);
|
2021-12-18 12:14:56 +00:00
|
|
|
if (daz2 > daz+(1<<8) && (sec2->ceilingstat & CSTAT_SECTOR_SKY) == 0)
|
2019-09-21 11:02:17 +00:00
|
|
|
if (posz <= daz2+(ceildist-1)) return 1;
|
2019-07-29 11:12:06 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2019-09-22 19:26:07 +00:00
|
|
|
}
|
2019-07-29 11:12:06 +00:00
|
|
|
|
2019-08-27 06:52:42 +00:00
|
|
|
int32_t daz2 = sec2->floorz;
|
2019-07-24 01:37:43 +00:00
|
|
|
int32_t dacz2 = sec2->ceilingz;
|
2019-04-19 08:31:54 +00:00
|
|
|
|
2021-12-18 12:14:56 +00:00
|
|
|
if ((sec2->floorstat|sec2->ceilingstat) & CSTAT_SECTOR_SLOPE)
|
2021-12-22 09:26:51 +00:00
|
|
|
getcorrectzsofslope(nextsect, pos.X, pos.y, &dacz2, &daz2);
|
2019-07-24 01:37:43 +00:00
|
|
|
|
2019-07-24 10:56:20 +00:00
|
|
|
if (daz2 <= dacz2)
|
2019-07-24 01:37:43 +00:00
|
|
|
return 1;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2019-07-24 01:37:43 +00:00
|
|
|
auto const sec = (usectorptr_t)§or[dasect];
|
2019-09-22 19:26:07 +00:00
|
|
|
|
2019-08-27 06:52:42 +00:00
|
|
|
int32_t daz = sec->floorz;
|
2019-07-24 01:37:43 +00:00
|
|
|
int32_t dacz = sec->ceilingz;
|
|
|
|
|
2021-12-18 12:14:56 +00:00
|
|
|
if ((sec->floorstat|sec->ceilingstat) & CSTAT_SECTOR_SLOPE)
|
2021-12-22 09:26:51 +00:00
|
|
|
getcorrectzsofslope(dasect, pos.X, pos.y, &dacz, &daz);
|
2019-07-24 01:37:43 +00:00
|
|
|
|
2021-01-04 12:02:00 +00:00
|
|
|
int32_t const sec2height = abs(daz2-dacz2);
|
2019-08-01 06:49:47 +00:00
|
|
|
|
2021-01-04 12:02:00 +00:00
|
|
|
return ((abs(daz-dacz) > sec2height && // clip if the current sector is taller and the next is too small
|
2019-09-17 03:21:14 +00:00
|
|
|
sec2height < (ceildist+(CLIPCURBHEIGHT<<1))) ||
|
2019-08-01 06:49:47 +00:00
|
|
|
|
2021-12-18 12:14:56 +00:00
|
|
|
((sec2->floorstat & CSTAT_SECTOR_SKY) == 0 && // parallaxed floor curbs don't clip
|
2019-08-01 06:49:47 +00:00
|
|
|
posz >= daz2-(flordist-1) && // also account for desired z distance tolerance
|
|
|
|
daz2 < daz-CLIPCURBHEIGHT) || // curbs less tall than 256 z units don't clip
|
|
|
|
|
2021-12-18 12:14:56 +00:00
|
|
|
((sec2->ceilingstat & CSTAT_SECTOR_SKY) == 0 &&
|
2019-08-01 06:49:47 +00:00
|
|
|
posz <= dacz2+(ceildist-1) &&
|
2020-02-11 09:21:52 +00:00
|
|
|
dacz2 > dacz+CLIPCURBHEIGHT)); // ceilings check the same conditions ^^^^^
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// raytrace (internal)
|
|
|
|
//
|
2019-08-27 06:52:42 +00:00
|
|
|
static inline int32_t cliptrace(vec2_t const pos, vec2_t * const goal)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
|
|
|
int32_t hitwall = -1;
|
|
|
|
|
2021-05-11 23:29:18 +00:00
|
|
|
for (int z=clipnum-1; z>=0; z--)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2019-07-24 01:38:08 +00:00
|
|
|
vec2_t const p1 = { clipit[z].x1, clipit[z].y1 };
|
|
|
|
vec2_t const p2 = { clipit[z].x2, clipit[z].y2 };
|
2021-12-22 09:26:51 +00:00
|
|
|
vec2_t const area = { p2.X-p1.X, p2.y-p1.y };
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
int32_t topu = area.X*(pos.y-p1.y) - (pos.X-p1.X)*area.y;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
if (topu <= 0 || area.X*(goal->y-p1.y) > (goal->X-p1.X)*area.y)
|
2016-06-21 00:33:30 +00:00
|
|
|
continue;
|
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
vec2_t const diff = { goal->X-pos.X, goal->y-pos.y };
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
if (diff.X*(p1.y-pos.y) > (p1.X-pos.X)*diff.y || diff.X*(p2.y-pos.y) <= (p2.X-pos.X)*diff.y)
|
2016-06-21 00:33:30 +00:00
|
|
|
continue;
|
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
int32_t const bot = diff.X*area.y - area.X*diff.y;
|
2021-12-14 09:15:58 +00:00
|
|
|
int cnt = 256;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2019-07-24 01:38:08 +00:00
|
|
|
if (!bot)
|
2016-06-21 00:33:30 +00:00
|
|
|
continue;
|
|
|
|
|
2019-07-24 01:38:08 +00:00
|
|
|
vec2_t n;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
|
|
|
do
|
|
|
|
{
|
2019-07-24 01:38:08 +00:00
|
|
|
if (--cnt < 0)
|
|
|
|
{
|
|
|
|
*goal = pos;
|
|
|
|
return z;
|
|
|
|
}
|
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
n = { pos.X+Scale(diff.X, topu, bot), pos.y+Scale(diff.y, topu, bot) };
|
2016-06-21 00:33:30 +00:00
|
|
|
topu--;
|
2021-12-22 09:26:51 +00:00
|
|
|
} while (area.X*(n.y-p1.y) <= (n.X-p1.X)*area.y);
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
if (abs(pos.X-n.X)+abs(pos.y-n.y) < abs(pos.X-goal->X)+abs(pos.y-goal->y))
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2019-07-24 01:38:08 +00:00
|
|
|
*goal = n;
|
|
|
|
hitwall = z;
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return hitwall;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// keepaway (internal)
|
|
|
|
//
|
|
|
|
static inline void keepaway(int32_t *x, int32_t *y, int32_t w)
|
|
|
|
{
|
|
|
|
const int32_t x1 = clipit[w].x1, dx = clipit[w].x2-x1;
|
|
|
|
const int32_t y1 = clipit[w].y1, dy = clipit[w].y2-y1;
|
2021-01-04 12:35:33 +00:00
|
|
|
const int32_t ox = Sgn(-dy), oy = Sgn(dx);
|
2021-01-04 12:02:00 +00:00
|
|
|
char first = (abs(dx) <= abs(dy));
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2019-03-30 19:35:54 +00:00
|
|
|
do
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
|
|
|
if (dx*(*y-y1) > (*x-x1)*dy)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (first == 0)
|
|
|
|
*x += ox;
|
|
|
|
else
|
|
|
|
*y += oy;
|
|
|
|
|
|
|
|
first ^= 1;
|
|
|
|
}
|
2019-03-30 19:35:54 +00:00
|
|
|
while (1);
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
|
|
|
|
2019-08-27 06:52:42 +00:00
|
|
|
static int get_floorspr_clipyou(vec2_t const v1, vec2_t const v2, vec2_t const v3, vec2_t const v4)
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2019-08-27 06:52:42 +00:00
|
|
|
int clipyou = 0;
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2019-08-27 06:52:42 +00:00
|
|
|
if ((v1.y^v2.y) < 0)
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-12-22 09:26:51 +00:00
|
|
|
if ((v1.X^v2.X) < 0) clipyou ^= (v1.X*v2.y < v2.X*v1.y)^(v1.y<v2.y);
|
|
|
|
else if (v1.X >= 0) clipyou ^= 1;
|
2019-03-19 17:08:59 +00:00
|
|
|
}
|
2019-08-27 06:52:42 +00:00
|
|
|
if ((v2.y^v3.y) < 0)
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-12-22 09:26:51 +00:00
|
|
|
if ((v2.X^v3.X) < 0) clipyou ^= (v2.X*v3.y < v3.X*v2.y)^(v2.y<v3.y);
|
|
|
|
else if (v2.X >= 0) clipyou ^= 1;
|
2019-03-19 17:08:59 +00:00
|
|
|
}
|
2019-08-27 06:52:42 +00:00
|
|
|
if ((v3.y^v4.y) < 0)
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-12-22 09:26:51 +00:00
|
|
|
if ((v3.X^v4.X) < 0) clipyou ^= (v3.X*v4.y < v4.X*v3.y)^(v3.y<v4.y);
|
|
|
|
else if (v3.X >= 0) clipyou ^= 1;
|
2019-03-19 17:08:59 +00:00
|
|
|
}
|
2019-08-27 06:52:42 +00:00
|
|
|
if ((v4.y^v1.y) < 0)
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-12-22 09:26:51 +00:00
|
|
|
if ((v4.X^v1.X) < 0) clipyou ^= (v4.X*v1.y < v1.X*v4.y)^(v4.y<v1.y);
|
|
|
|
else if (v4.X >= 0) clipyou ^= 1;
|
2019-03-19 17:08:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return clipyou;
|
|
|
|
}
|
|
|
|
|
2021-11-07 18:21:46 +00:00
|
|
|
static void clipupdatesector(vec2_t const pos, int * const sectnum, int walldist)
|
2019-04-18 17:23:50 +00:00
|
|
|
{
|
2020-09-10 19:39:52 +00:00
|
|
|
#if 0
|
2019-09-22 19:26:07 +00:00
|
|
|
if (enginecompatibility_mode != ENGINECOMPATIBILITY_NONE)
|
2019-07-29 11:12:06 +00:00
|
|
|
{
|
|
|
|
updatesector(pos.x, pos.y, sectnum);
|
|
|
|
return;
|
|
|
|
}
|
2020-09-10 19:39:52 +00:00
|
|
|
#endif
|
2019-07-29 11:12:06 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
if (inside_p(pos.X, pos.y, *sectnum))
|
2019-04-09 19:21:22 +00:00
|
|
|
return;
|
|
|
|
|
2019-10-20 17:55:20 +00:00
|
|
|
int16_t nsecs = min<int16_t>(getsectordist(pos, *sectnum), INT16_MAX);
|
|
|
|
|
|
|
|
if (nsecs > (walldist + 8))
|
|
|
|
{
|
2021-12-22 09:26:51 +00:00
|
|
|
Printf("%s(): initial position (%d, %d) not within initial sector %d; shortest distance %d.\n", __func__, pos.X, pos.y, *sectnum, nsecs);
|
2019-10-20 17:55:20 +00:00
|
|
|
walldist = 0x7fff;
|
|
|
|
}
|
|
|
|
|
2019-04-09 19:21:22 +00:00
|
|
|
{
|
2021-12-21 09:51:41 +00:00
|
|
|
BFSSearch search(sector.Size(), *sectnum);
|
2019-04-18 17:25:11 +00:00
|
|
|
|
2021-11-16 23:13:34 +00:00
|
|
|
for (unsigned listsectnum; (listsectnum = search.GetNext()) != BFSSearch::EOL;)
|
|
|
|
{
|
2021-12-22 09:26:51 +00:00
|
|
|
if (inside_p(pos.X, pos.y, listsectnum))
|
2021-11-16 23:13:34 +00:00
|
|
|
{
|
|
|
|
*sectnum = listsectnum;
|
|
|
|
return;
|
|
|
|
}
|
2019-04-09 19:21:22 +00:00
|
|
|
|
2021-11-16 23:13:34 +00:00
|
|
|
for (auto& wal : wallsofsector(listsectnum))
|
|
|
|
{
|
2021-12-06 19:08:32 +00:00
|
|
|
if (wal.nextsector >= 0 && clipsectormap[wal.nextsector])
|
2021-11-16 23:13:34 +00:00
|
|
|
search.Add(wal.nextsector);
|
|
|
|
}
|
|
|
|
}
|
2019-04-09 19:21:22 +00:00
|
|
|
}
|
|
|
|
|
2019-04-10 09:31:09 +00:00
|
|
|
{
|
2021-12-21 09:51:41 +00:00
|
|
|
BFSSearch search(sector.Size(), *sectnum);
|
2019-04-18 17:25:11 +00:00
|
|
|
|
2021-11-16 23:13:34 +00:00
|
|
|
for (unsigned listsectnum; (listsectnum = search.GetNext()) != BFSSearch::EOL;)
|
2019-04-10 09:31:09 +00:00
|
|
|
{
|
2021-12-22 09:26:51 +00:00
|
|
|
if (inside_p(pos.X, pos.y, listsectnum))
|
2021-11-16 23:13:34 +00:00
|
|
|
{
|
|
|
|
*sectnum = listsectnum;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (auto& wal : wallsofsector(listsectnum))
|
|
|
|
{
|
|
|
|
if (wal.nextsector >= 0 && getwalldist(pos, wallnum(&wal)) <= (walldist + 8))
|
|
|
|
search.Add(wal.nextsector);
|
|
|
|
}
|
2019-04-10 09:31:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-09 19:21:22 +00:00
|
|
|
*sectnum = -1;
|
|
|
|
}
|
|
|
|
|
2016-06-21 00:33:30 +00:00
|
|
|
//
|
|
|
|
// clipmove
|
|
|
|
//
|
2021-12-04 00:05:18 +00:00
|
|
|
CollisionBase clipmove_(vec3_t * const pos, int * const sectnum, int32_t xvect, int32_t yvect,
|
2021-11-07 19:00:22 +00:00
|
|
|
int32_t const walldist, int32_t const ceildist, int32_t const flordist, uint32_t const cliptype, int clipmoveboxtracenum)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2021-12-04 00:05:18 +00:00
|
|
|
CollisionBase b{};
|
2016-06-21 00:33:35 +00:00
|
|
|
if ((xvect|yvect) == 0 || *sectnum < 0)
|
2021-12-04 00:05:18 +00:00
|
|
|
return b;
|
2016-06-21 00:33:35 +00:00
|
|
|
|
2021-12-04 00:05:18 +00:00
|
|
|
DCoreActor* curspr=NULL; // non-NULL when handling sprite with sector-like clipping
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2019-04-19 08:31:50 +00:00
|
|
|
int const initialsectnum = *sectnum;
|
|
|
|
|
2021-12-18 14:36:50 +00:00
|
|
|
int32_t const dawalclipmask = (cliptype & 65535); // CLIPMASK0 = 0x00010001 (in desperate need of getting fixed!)
|
2021-07-04 11:05:33 +00:00
|
|
|
int32_t const dasprclipmask = (cliptype >> 16); // CLIPMASK1 = 0x01000040
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2019-03-30 19:36:18 +00:00
|
|
|
vec2_t const move = { xvect, yvect };
|
|
|
|
vec2_t goal = { pos->x + (xvect >> 14), pos->y + (yvect >> 14) };
|
2021-12-22 09:26:51 +00:00
|
|
|
vec2_t const cent = { (pos->x + goal.X) >> 1, (pos->y + goal.y) >> 1 };
|
2016-06-21 00:33:30 +00:00
|
|
|
|
|
|
|
//Extra walldist for sprites on sector lines
|
2021-12-22 09:26:51 +00:00
|
|
|
vec2_t const diff = { goal.X - (pos->x), goal.y - (pos->y) };
|
|
|
|
int32_t const rad = ksqrt(compat_maybe_truncate_to_int32(uhypsq(diff.X, diff.y))) + MAXCLIPDIST + walldist + 8;
|
|
|
|
vec2_t const clipMin = { cent.X - rad, cent.y - rad };
|
|
|
|
vec2_t const clipMax = { cent.X + rad, cent.y + rad };
|
2019-03-30 19:36:18 +00:00
|
|
|
|
|
|
|
int clipsectcnt = 0;
|
|
|
|
int clipspritecnt = 0;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2019-03-30 19:36:18 +00:00
|
|
|
clipsectorlist[0] = *sectnum;
|
|
|
|
|
|
|
|
clipsectnum = 1;
|
|
|
|
clipnum = 0;
|
|
|
|
clipspritenum = 0;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
|
|
|
clipmove_warned = 0;
|
|
|
|
|
2021-12-06 19:08:32 +00:00
|
|
|
clipsectormap.Zero();
|
|
|
|
clipsectormap.Set(*sectnum);
|
2019-04-10 09:31:12 +00:00
|
|
|
|
2016-06-21 00:33:30 +00:00
|
|
|
do
|
|
|
|
{
|
2019-03-30 19:36:18 +00:00
|
|
|
int const dasect = clipsectorlist[clipsectcnt++];
|
2016-06-21 00:33:30 +00:00
|
|
|
//if (curspr)
|
2020-04-11 21:45:45 +00:00
|
|
|
// Printf("sprite %d/%d: sect %d/%d (%d)\n", clipspritecnt,clipspritenum, clipsectcnt,clipsectnum,dasect);
|
2016-06-21 00:33:30 +00:00
|
|
|
|
|
|
|
////////// Walls //////////
|
|
|
|
|
2019-04-18 17:25:24 +00:00
|
|
|
auto const sec = (usectorptr_t)§or[dasect];
|
2019-03-30 19:36:29 +00:00
|
|
|
int const startwall = sec->wallptr;
|
|
|
|
int const endwall = startwall + sec->wallnum;
|
2019-04-18 17:25:24 +00:00
|
|
|
auto wal = (uwallptr_t)&wall[startwall];
|
2019-03-30 19:36:18 +00:00
|
|
|
|
2021-12-14 09:15:58 +00:00
|
|
|
for (int j=startwall; j<endwall; j++, wal++)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2021-11-26 19:55:13 +00:00
|
|
|
auto const wal2 = (uwallptr_t)wal->point2Wall();
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
if ((wal->x < clipMin.X && wal2->x < clipMin.X) || (wal->x > clipMax.X && wal2->x > clipMax.X) ||
|
2019-03-30 19:36:18 +00:00
|
|
|
(wal->y < clipMin.y && wal2->y < clipMin.y) || (wal->y > clipMax.y && wal2->y > clipMax.y))
|
2016-06-21 00:33:35 +00:00
|
|
|
continue;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2019-07-24 01:38:08 +00:00
|
|
|
vec2_t p1 = wal->pos;
|
|
|
|
vec2_t p2 = wal2->pos;
|
2021-12-22 09:26:51 +00:00
|
|
|
vec2_t d = { p2.X-p1.X, p2.y-p1.y };
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
if (d.X * (pos->y-p1.y) < (pos->x-p1.X) * d.y)
|
2019-03-30 19:36:18 +00:00
|
|
|
continue; //If wall's not facing you
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
vec2_t const r = { (d.y > 0) ? clipMax.X : clipMin.X, (d.X > 0) ? clipMin.y : clipMax.y };
|
|
|
|
vec2_t v = { d.X * (r.y - p1.y), d.y * (r.X - p1.X) };
|
2019-03-30 19:36:18 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
if (v.X >= v.y)
|
2019-03-30 19:36:18 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
int clipyou = 0;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2021-12-18 14:36:50 +00:00
|
|
|
if (wal->nextsector < 0 || (wal->cstat & EWallFlags::FromInt(dawalclipmask)))
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
|
|
|
clipyou = 1;
|
|
|
|
}
|
2021-03-19 14:12:54 +00:00
|
|
|
else
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2021-12-22 09:26:51 +00:00
|
|
|
clipmove_tweak_pos(pos, diff.X, diff.y, p1.X, p1.y, p2.X, p2.y, &v.X, &v.y);
|
2019-07-24 01:37:43 +00:00
|
|
|
clipyou = cliptestsector(dasect, wal->nextsector, flordist, ceildist, v, pos->z);
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
|
|
|
|
2019-07-24 01:37:54 +00:00
|
|
|
// We're not interested in any sector reached by portal traversal that we're "inside" of.
|
2019-09-22 19:26:07 +00:00
|
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE && !curspr && dasect != initialsectnum
|
2021-12-06 17:17:45 +00:00
|
|
|
&& inside(pos->x, pos->y, sec) == 1)
|
2019-07-24 01:37:54 +00:00
|
|
|
{
|
|
|
|
int k;
|
|
|
|
for (k=startwall; k<endwall; k++)
|
|
|
|
if (wall[k].nextsector == initialsectnum)
|
|
|
|
break;
|
|
|
|
if (k == endwall)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (clipyou)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2021-12-04 00:05:18 +00:00
|
|
|
CollisionBase objtype;
|
|
|
|
if (curspr) objtype.setSprite(curspr);
|
|
|
|
else objtype.setWall(j);
|
2016-06-21 00:33:30 +00:00
|
|
|
|
|
|
|
//Add 2 boxes at endpoints
|
2021-12-22 09:26:51 +00:00
|
|
|
int32_t bsz = walldist; if (diff.X < 0) bsz = -bsz;
|
|
|
|
addclipline(p1.X-bsz, p1.y-bsz, p1.X-bsz, p1.y+bsz, objtype, false);
|
|
|
|
addclipline(p2.X-bsz, p2.y-bsz, p2.X-bsz, p2.y+bsz, objtype, false);
|
2019-03-30 19:36:18 +00:00
|
|
|
bsz = walldist; if (diff.y < 0) bsz = -bsz;
|
2021-12-22 09:26:51 +00:00
|
|
|
addclipline(p1.X+bsz, p1.y-bsz, p1.X-bsz, p1.y-bsz, objtype, false);
|
|
|
|
addclipline(p2.X+bsz, p2.y-bsz, p2.X-bsz, p2.y-bsz, objtype, false);
|
2019-03-30 19:36:18 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
v.X = walldist; if (d.y > 0) v.X = -v.X;
|
|
|
|
v.y = walldist; if (d.X < 0) v.y = -v.y;
|
2019-07-24 05:23:43 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE && d.X * (pos->y-p1.y-v.y) < (pos->x-p1.X-v.X) * d.y)
|
|
|
|
v.X >>= 1, v.y >>= 1;
|
2019-07-24 05:23:43 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
addclipline(p1.X+v.X, p1.y+v.y, p2.X+v.X, p2.y+v.y, objtype, false);
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
2019-03-30 19:35:54 +00:00
|
|
|
else if (wal->nextsector>=0)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2021-12-06 19:08:32 +00:00
|
|
|
if (!clipsectormap[wal->nextsector])
|
2019-04-10 09:31:12 +00:00
|
|
|
addclipsect(wal->nextsector);
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-27 06:52:30 +00:00
|
|
|
if (clipmove_warned & 1)
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("clipsectnum >= MAXCLIPSECTORS!\n");
|
2019-04-10 09:31:05 +00:00
|
|
|
|
2019-08-27 06:52:30 +00:00
|
|
|
if (clipmove_warned & 2)
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("clipnum >= MAXCLIPNUM!\n");
|
2019-04-10 09:31:05 +00:00
|
|
|
|
2016-06-21 00:33:30 +00:00
|
|
|
////////// Sprites //////////
|
|
|
|
|
|
|
|
if (dasprclipmask==0)
|
|
|
|
continue;
|
|
|
|
|
2021-12-04 00:05:18 +00:00
|
|
|
TSectIterator<DCoreActor> it(dasect);
|
|
|
|
while (auto actor = it.Next())
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2021-12-04 00:05:18 +00:00
|
|
|
auto const spr = &actor->s();
|
2016-06-21 00:33:30 +00:00
|
|
|
const int32_t cstat = spr->cstat;
|
|
|
|
|
|
|
|
if ((cstat&dasprclipmask) == 0)
|
|
|
|
continue;
|
|
|
|
|
2021-03-20 11:47:51 +00:00
|
|
|
auto p1 = spr->pos.vec2;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2021-12-04 00:05:18 +00:00
|
|
|
CollisionBase obj;
|
|
|
|
obj.setSprite(actor);
|
|
|
|
|
2021-12-20 19:27:12 +00:00
|
|
|
switch (cstat & (CSTAT_SPRITE_ALIGNMENT_MASK))
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2018-04-06 01:42:38 +00:00
|
|
|
case CSTAT_SPRITE_ALIGNMENT_FACING:
|
2021-12-22 09:26:51 +00:00
|
|
|
if (p1.X >= clipMin.X && p1.X <= clipMax.X && p1.y >= clipMin.y && p1.y <= clipMax.y)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2021-12-03 23:51:06 +00:00
|
|
|
int32_t height, daz = spr->z+spriteheightofsptr(spr, &height, 1);
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2019-03-30 19:36:18 +00:00
|
|
|
if (pos->z > daz-height-flordist && pos->z < daz+ceildist)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2019-03-30 19:36:18 +00:00
|
|
|
int32_t bsz = (spr->clipdist << 2)+walldist;
|
2021-12-22 09:26:51 +00:00
|
|
|
if (diff.X < 0) bsz = -bsz;
|
|
|
|
addclipline(p1.X-bsz, p1.y-bsz, p1.X-bsz, p1.y+bsz, obj, false);
|
2019-03-30 19:36:18 +00:00
|
|
|
bsz = (spr->clipdist << 2)+walldist;
|
|
|
|
if (diff.y < 0) bsz = -bsz;
|
2021-12-22 09:26:51 +00:00
|
|
|
addclipline(p1.X+bsz, p1.y-bsz, p1.X-bsz, p1.y-bsz, obj, false);
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2018-04-06 01:42:38 +00:00
|
|
|
case CSTAT_SPRITE_ALIGNMENT_WALL:
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2021-12-03 23:51:06 +00:00
|
|
|
int32_t height, daz = spr->z+spriteheightofsptr(spr, &height, 1);
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2021-03-27 14:03:57 +00:00
|
|
|
if (pos->z > daz-height-flordist && pos->z < daz+ceildist)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2021-03-27 14:03:57 +00:00
|
|
|
vec2_t p2;
|
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
get_wallspr_points(spr, &p1.X, &p2.X, &p1.y, &p2.y);
|
2019-03-30 19:36:18 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
if (clipinsideboxline(cent.X, cent.y, p1.X, p1.y, p2.X, p2.y, rad) != 0)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2021-01-04 11:36:54 +00:00
|
|
|
vec2_t v = { MulScale(bcos(spr->ang + 256), walldist, 14),
|
|
|
|
MulScale(bsin(spr->ang + 256), walldist, 14) };
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
if ((p1.X-pos->x) * (p2.y-pos->y) >= (p2.X-pos->x) * (p1.y-pos->y)) // Front
|
|
|
|
addclipline(p1.X+v.X, p1.y+v.y, p2.X+v.y, p2.y-v.X, obj, false);
|
2016-06-21 00:33:30 +00:00
|
|
|
else
|
|
|
|
{
|
2021-12-18 15:39:44 +00:00
|
|
|
if ((cstat & CSTAT_SPRITE_ONE_SIDE) != 0)
|
2019-03-30 19:36:18 +00:00
|
|
|
continue;
|
2021-12-22 09:26:51 +00:00
|
|
|
addclipline(p2.X-v.X, p2.y-v.y, p1.X-v.y, p1.y+v.X, obj, false);
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//Side blocker
|
2021-12-22 09:26:51 +00:00
|
|
|
if ((p2.X-p1.X) * (pos->x-p1.X)+(p2.y-p1.y) * (pos->y-p1.y) < 0)
|
|
|
|
addclipline(p1.X-v.y, p1.y+v.X, p1.X+v.X, p1.y+v.y, obj, true);
|
|
|
|
else if ((p1.X-p2.X) * (pos->x-p2.X)+(p1.y-p2.y) * (pos->y-p2.y) < 0)
|
|
|
|
addclipline(p2.X+v.y, p2.y-v.X, p2.X-v.X, p2.y-v.y, obj, true);
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-04-06 01:42:38 +00:00
|
|
|
case CSTAT_SPRITE_ALIGNMENT_FLOOR:
|
2021-12-20 19:27:12 +00:00
|
|
|
case CSTAT_SPRITE_ALIGNMENT_SLOPE:
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2021-12-20 19:27:12 +00:00
|
|
|
int heinum, sz;
|
|
|
|
|
|
|
|
if ((cstat & (CSTAT_SPRITE_ALIGNMENT_MASK)) == CSTAT_SPRITE_ALIGNMENT_SLOPE)
|
|
|
|
{
|
|
|
|
heinum = spriteGetSlope(spr);
|
|
|
|
sz = spriteGetZOfSlope(spr, pos->x, pos->y);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
heinum = 0;
|
|
|
|
sz = spr->z;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pos->z > sz - flordist && pos->z < sz + ceildist)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2021-12-18 15:39:44 +00:00
|
|
|
if ((cstat & CSTAT_SPRITE_ONE_SIDE) != 0)
|
2021-12-20 19:27:12 +00:00
|
|
|
if ((pos->z > sz) == ((cstat & CSTAT_SPRITE_YFLIP)==0))
|
2016-06-21 00:33:30 +00:00
|
|
|
continue;
|
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
rxi[0] = p1.X;
|
2021-03-27 14:03:57 +00:00
|
|
|
ryi[0] = p1.y;
|
|
|
|
|
2021-12-20 19:27:12 +00:00
|
|
|
get_floorspr_points(spr, 0, 0, &rxi[0], &rxi[1], &rxi[2], &rxi[3],
|
|
|
|
&ryi[0], &ryi[1], &ryi[2], &ryi[3], heinum);
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2021-01-04 11:36:54 +00:00
|
|
|
vec2_t v = { MulScale(bcos(spr->ang - 256), walldist, 14),
|
|
|
|
MulScale(bsin(spr->ang - 256), walldist, 14) };
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2021-03-27 14:03:57 +00:00
|
|
|
if ((rxi[0]-pos->x) * (ryi[1]-pos->y) < (rxi[1]-pos->x) * (ryi[0]-pos->y))
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2021-12-22 09:26:51 +00:00
|
|
|
if (clipinsideboxline(cent.X, cent.y, rxi[1], ryi[1], rxi[0], ryi[0], rad) != 0)
|
|
|
|
addclipline(rxi[1]-v.y, ryi[1]+v.X, rxi[0]+v.X, ryi[0]+v.y, obj, false);
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
2021-03-27 14:03:57 +00:00
|
|
|
else if ((rxi[2]-pos->x) * (ryi[3]-pos->y) < (rxi[3]-pos->x) * (ryi[2]-pos->y))
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2021-12-22 09:26:51 +00:00
|
|
|
if (clipinsideboxline(cent.X, cent.y, rxi[3], ryi[3], rxi[2], ryi[2], rad) != 0)
|
|
|
|
addclipline(rxi[3]+v.y, ryi[3]-v.X, rxi[2]-v.X, ryi[2]-v.y, obj, false);
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
|
|
|
|
2021-03-27 14:03:57 +00:00
|
|
|
if ((rxi[1]-pos->x) * (ryi[2]-pos->y) < (rxi[2]-pos->x) * (ryi[1]-pos->y))
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2021-12-22 09:26:51 +00:00
|
|
|
if (clipinsideboxline(cent.X, cent.y, rxi[2], ryi[2], rxi[1], ryi[1], rad) != 0)
|
|
|
|
addclipline(rxi[2]-v.X, ryi[2]-v.y, rxi[1]-v.y, ryi[1]+v.X, obj, false);
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
2021-03-27 14:03:57 +00:00
|
|
|
else if ((rxi[3]-pos->x) * (ryi[0]-pos->y) < (rxi[0]-pos->x) * (ryi[3]-pos->y))
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2021-12-22 09:26:51 +00:00
|
|
|
if (clipinsideboxline(cent.X, cent.y, rxi[0], ryi[0], rxi[3], ryi[3], rad) != 0)
|
|
|
|
addclipline(rxi[0]+v.X, ryi[0]+v.y, rxi[3]+v.y, ryi[3]-v.X, obj, false);
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
|
|
|
}
|
2021-12-20 19:27:12 +00:00
|
|
|
|
|
|
|
if (heinum == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// the rest is for slope sprites only.
|
|
|
|
const int32_t tilenum = spr->picnum;
|
|
|
|
const int32_t cosang = bcos(spr->ang);
|
|
|
|
const int32_t sinang = bsin(spr->ang);
|
|
|
|
vec2_t const span = { tileWidth(tilenum), tileHeight(tilenum) };
|
|
|
|
vec2_t const repeat = { spr->xrepeat, spr->yrepeat };
|
|
|
|
vec2_t adjofs = { tileLeftOffset(tilenum), tileTopOffset(tilenum) };
|
|
|
|
|
|
|
|
if (spr->cstat & CSTAT_SPRITE_XFLIP)
|
2021-12-22 09:26:51 +00:00
|
|
|
adjofs.X = -adjofs.X;
|
2021-12-20 19:27:12 +00:00
|
|
|
|
|
|
|
if (spr->cstat & CSTAT_SPRITE_YFLIP)
|
|
|
|
adjofs.y = -adjofs.y;
|
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
int32_t const centerx = ((span.X >> 1) + adjofs.X) * repeat.X;
|
2021-12-20 19:27:12 +00:00
|
|
|
int32_t const centery = ((span.y >> 1) + adjofs.y) * repeat.y;
|
2021-12-22 09:26:51 +00:00
|
|
|
int32_t const rspanx = span.X * repeat.X;
|
2021-12-20 19:27:12 +00:00
|
|
|
int32_t const rspany = span.y * repeat.y;
|
|
|
|
int32_t const ratio = ksqrt(heinum * heinum + 4096 * 4096);
|
|
|
|
int32_t zz[3] = { pos->z, pos->z + flordist, pos->z - ceildist };
|
|
|
|
for (int k = 0; k < 3; k++)
|
|
|
|
{
|
|
|
|
int32_t jj = DivScale(spr->z - zz[k], heinum, 18);
|
|
|
|
int32_t jj2 = MulScale(jj, ratio, 12);
|
|
|
|
if (jj2 > (centery << 8) || jj2 < ((centery - rspany) << 8))
|
|
|
|
continue;
|
|
|
|
int32_t x1 = spr->x + MulScale(sinang, centerx, 16) + MulScale(jj, cosang, 24);
|
|
|
|
int32_t y1 = spr->y - MulScale(cosang, centerx, 16) + MulScale(jj, sinang, 24);
|
|
|
|
int32_t x2 = x1 - MulScale(sinang, rspanx, 16);
|
|
|
|
int32_t y2 = y1 + MulScale(cosang, rspanx, 16);
|
|
|
|
|
|
|
|
vec2_t const v = { MulScale(bcos(spr->ang - 256), walldist, 14),
|
|
|
|
MulScale(bsin(spr->ang - 256), walldist, 14) };
|
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
if (clipinsideboxline(cent.X, cent.y, x1, y1, x2, y2, rad) != 0)
|
2021-12-20 19:27:12 +00:00
|
|
|
{
|
|
|
|
if ((x1 - pos->x) * (y2 - pos->y) >= (x2 - pos->x) * (y1 - pos->y))
|
|
|
|
{
|
2021-12-22 09:26:51 +00:00
|
|
|
addclipline(x1 + v.X, y1 + v.y, x2 + v.y, y2 - v.X, obj, false);
|
2021-12-20 19:27:12 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ((cstat & CSTAT_SPRITE_ONE_SIDE) != 0)
|
|
|
|
continue;
|
2021-12-22 09:26:51 +00:00
|
|
|
addclipline(x2 - v.X, y2 - v.y, x1 - v.y, y1 + v.X, obj, false);
|
2021-12-20 19:27:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-06-21 00:33:30 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (clipsectcnt < clipsectnum || clipspritecnt < clipspritenum);
|
|
|
|
|
2019-07-24 01:37:57 +00:00
|
|
|
int32_t hitwalls[4], hitwall;
|
2021-12-04 00:05:18 +00:00
|
|
|
CollisionBase clipReturn{};
|
2019-03-30 19:36:18 +00:00
|
|
|
|
2021-05-11 23:29:18 +00:00
|
|
|
int cnt = clipmoveboxtracenum;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
|
|
|
do
|
|
|
|
{
|
2020-01-29 11:36:13 +00:00
|
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE && (xvect|yvect))
|
|
|
|
{
|
2021-05-11 23:29:18 +00:00
|
|
|
for (int i=clipnum-1;i>=0;--i)
|
2019-07-24 01:38:01 +00:00
|
|
|
{
|
2019-09-21 11:02:17 +00:00
|
|
|
if (!bitmap_test(clipignore, i) && clipinsideboxline(pos->x, pos->y, clipit[i].x1, clipit[i].y1, clipit[i].x2, clipit[i].y2, walldist))
|
|
|
|
{
|
|
|
|
vec2_t const vec = pos->vec2;
|
|
|
|
keepaway(&pos->x, &pos->y, i);
|
2021-12-06 17:17:45 +00:00
|
|
|
if (inside_p(pos->x,pos->y, *sectnum) != 1)
|
2019-09-21 11:02:17 +00:00
|
|
|
pos->vec2 = vec;
|
|
|
|
break;
|
|
|
|
}
|
2019-07-24 01:38:01 +00:00
|
|
|
}
|
2020-01-29 11:36:13 +00:00
|
|
|
}
|
2019-07-24 01:38:01 +00:00
|
|
|
|
2019-03-30 19:36:18 +00:00
|
|
|
vec2_t vec = goal;
|
2020-02-11 09:21:28 +00:00
|
|
|
|
2019-07-24 01:38:08 +00:00
|
|
|
if ((hitwall = cliptrace(pos->vec2, &vec)) >= 0)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2019-07-24 01:38:01 +00:00
|
|
|
vec2_t const clipr = { clipit[hitwall].x2 - clipit[hitwall].x1, clipit[hitwall].y2 - clipit[hitwall].y1 };
|
2020-02-11 09:21:28 +00:00
|
|
|
// clamp to the max value we can utilize without reworking the scaling below
|
|
|
|
// this works around the overflow issue that affects dukedc2.map
|
2021-12-22 09:26:51 +00:00
|
|
|
int32_t const templl = (int32_t)clamp<int64_t>(compat_maybe_truncate_to_int32((int64_t)clipr.X * clipr.X + (int64_t)clipr.y * clipr.y), INT32_MIN, INT32_MAX);
|
2019-07-29 11:12:06 +00:00
|
|
|
|
2020-02-11 17:26:58 +00:00
|
|
|
if (templl > 0)
|
2019-09-21 11:02:17 +00:00
|
|
|
{
|
2020-02-11 09:21:28 +00:00
|
|
|
// I don't know if this one actually overflows or not, but I highly doubt it hurts to check
|
|
|
|
int32_t const templl2
|
2021-12-22 09:26:51 +00:00
|
|
|
= (int32_t)clamp<int64_t>(compat_maybe_truncate_to_int32((int64_t)(goal.X - vec.X) * clipr.X + (int64_t)(goal.y - vec.y) * clipr.y), INT32_MIN, INT32_MAX);
|
2021-01-04 12:02:00 +00:00
|
|
|
int32_t const i = (enginecompatibility_mode == ENGINECOMPATIBILITY_19950829 || (abs(templl2)>>11) < templl) ?
|
2021-05-11 23:29:18 +00:00
|
|
|
(int)DivScaleL(templl2, templl, 20) : 0;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
goal = { MulScale(clipr.X, i, 20)+vec.X, MulScale(clipr.y, i, 20)+vec.y };
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
|
|
|
|
2019-09-22 19:26:07 +00:00
|
|
|
int32_t tempint;
|
|
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_19950829)
|
2021-12-22 09:26:51 +00:00
|
|
|
tempint = clipr.X*(move.X>>6)+clipr.y*(move.y>>6);
|
2019-09-22 19:26:07 +00:00
|
|
|
else
|
2021-12-22 09:26:51 +00:00
|
|
|
tempint = DMulScale(clipr.X, move.X, clipr.y, move.y, 6);
|
2019-03-30 19:36:18 +00:00
|
|
|
|
2021-12-14 09:15:58 +00:00
|
|
|
for (int i=cnt+1, j; i<=clipmoveboxtracenum; ++i)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2019-05-27 05:45:41 +00:00
|
|
|
j = hitwalls[i];
|
2019-03-30 19:36:18 +00:00
|
|
|
|
2019-09-22 19:26:07 +00:00
|
|
|
int32_t tempint2;
|
|
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_19950829)
|
2021-12-22 09:26:51 +00:00
|
|
|
tempint2 = (clipit[j].x2-clipit[j].x1)*(move.X>>6)+(clipit[j].y2-clipit[j].y1)*(move.y>>6);
|
2019-09-22 19:26:07 +00:00
|
|
|
else
|
2021-12-22 09:26:51 +00:00
|
|
|
tempint2 = DMulScale(clipit[j].x2-clipit[j].x1, move.X, clipit[j].y2-clipit[j].y1, move.y, 6);
|
2019-09-22 19:26:07 +00:00
|
|
|
|
|
|
|
if ((tempint ^ tempint2) < 0)
|
2019-07-29 11:12:06 +00:00
|
|
|
{
|
2019-09-22 19:26:07 +00:00
|
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_19961112)
|
2019-07-29 11:12:06 +00:00
|
|
|
updatesector(pos->x, pos->y, sectnum);
|
2019-03-30 19:36:18 +00:00
|
|
|
return clipReturn;
|
2019-09-21 11:02:17 +00:00
|
|
|
}
|
2019-07-29 11:12:06 +00:00
|
|
|
}
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
keepaway(&goal.X, &goal.y, hitwall);
|
|
|
|
xvect = (goal.X-vec.X)<<14;
|
2019-03-30 19:36:18 +00:00
|
|
|
yvect = (goal.y-vec.y)<<14;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
|
|
|
if (cnt == clipmoveboxtracenum)
|
2021-12-04 00:05:18 +00:00
|
|
|
clipReturn = clipobjectval[hitwall];
|
2016-06-21 00:33:30 +00:00
|
|
|
hitwalls[cnt] = hitwall;
|
|
|
|
}
|
|
|
|
|
2019-09-22 19:26:07 +00:00
|
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE)
|
2021-11-07 17:20:41 +00:00
|
|
|
{
|
2021-11-07 18:21:46 +00:00
|
|
|
clipupdatesector(vec, sectnum, rad);
|
2021-11-07 17:20:41 +00:00
|
|
|
}
|
2019-03-30 19:35:54 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
pos->x = vec.X;
|
2019-07-24 01:38:01 +00:00
|
|
|
pos->y = vec.y;
|
|
|
|
cnt--;
|
2016-06-21 00:33:30 +00:00
|
|
|
} while ((xvect|yvect) != 0 && hitwall >= 0 && cnt > 0);
|
|
|
|
|
2019-09-22 19:26:07 +00:00
|
|
|
if (enginecompatibility_mode != ENGINECOMPATIBILITY_NONE)
|
2019-07-29 11:12:06 +00:00
|
|
|
{
|
2021-12-14 09:15:58 +00:00
|
|
|
for (int j=0; j<clipsectnum; j++)
|
2021-12-06 17:17:45 +00:00
|
|
|
if (inside_p(pos->x, pos->y, clipsectorlist[j]) == 1)
|
2019-07-29 11:12:06 +00:00
|
|
|
{
|
|
|
|
*sectnum = clipsectorlist[j];
|
2019-09-21 11:02:17 +00:00
|
|
|
return clipReturn;
|
2019-07-29 11:12:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int32_t tempint2, tempint1 = INT32_MAX;
|
|
|
|
*sectnum = -1;
|
2021-12-21 09:51:41 +00:00
|
|
|
for (int j = (int)sector.Size() - 1; j >= 0; j--)
|
2021-12-17 20:42:57 +00:00
|
|
|
{
|
|
|
|
auto sect = §or[j];
|
|
|
|
if (inside(pos->x, pos->y, sect) == 1)
|
2019-07-29 11:12:06 +00:00
|
|
|
{
|
2021-12-17 20:42:57 +00:00
|
|
|
if (enginecompatibility_mode != ENGINECOMPATIBILITY_19950829 && (sect->ceilingstat & CSTAT_SECTOR_SLOPE))
|
|
|
|
tempint2 = getceilzofslopeptr(sect, pos->x, pos->y) - pos->z;
|
2019-07-29 11:12:06 +00:00
|
|
|
else
|
2021-12-17 20:42:57 +00:00
|
|
|
tempint2 = sect->ceilingz - pos->z;
|
2019-07-29 11:12:06 +00:00
|
|
|
|
|
|
|
if (tempint2 > 0)
|
|
|
|
{
|
|
|
|
if (tempint2 < tempint1)
|
|
|
|
{
|
2021-12-17 20:42:57 +00:00
|
|
|
*sectnum = (int16_t)j;
|
2021-05-11 23:29:18 +00:00
|
|
|
tempint1 = tempint2;
|
2019-07-29 11:12:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-12-17 20:42:57 +00:00
|
|
|
if (enginecompatibility_mode != ENGINECOMPATIBILITY_19950829 && (sect->ceilingstat & CSTAT_SECTOR_SLOPE))
|
|
|
|
tempint2 = pos->z - getflorzofslopeptr(sect, pos->x, pos->y);
|
2019-07-29 11:12:06 +00:00
|
|
|
else
|
2021-12-17 20:42:57 +00:00
|
|
|
tempint2 = pos->z - sect->floorz;
|
2019-07-29 11:12:06 +00:00
|
|
|
|
|
|
|
if (tempint2 <= 0)
|
|
|
|
{
|
2021-05-11 23:29:18 +00:00
|
|
|
*sectnum = (int16_t)j;
|
2019-07-29 11:12:06 +00:00
|
|
|
return clipReturn;
|
|
|
|
}
|
|
|
|
if (tempint2 < tempint1)
|
|
|
|
{
|
2021-05-11 23:29:18 +00:00
|
|
|
*sectnum = (int16_t)j;
|
|
|
|
tempint1 = tempint2;
|
2019-07-29 11:12:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-12-17 20:42:57 +00:00
|
|
|
}
|
2019-07-29 11:12:06 +00:00
|
|
|
}
|
|
|
|
|
2019-03-30 19:36:18 +00:00
|
|
|
return clipReturn;
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// pushmove
|
|
|
|
//
|
2021-11-26 19:41:03 +00:00
|
|
|
int pushmove_(vec3_t *const vect, int *const sectnum,
|
2019-07-24 01:37:47 +00:00
|
|
|
int32_t const walldist, int32_t const ceildist, int32_t const flordist, uint32_t const cliptype, bool clear /*= true*/)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2019-07-24 01:37:47 +00:00
|
|
|
int bad;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
|
|
|
const int32_t dawalclipmask = (cliptype&65535);
|
2021-07-04 11:05:33 +00:00
|
|
|
// const int32_t dasprclipmask = (cliptype >> 16);
|
2016-06-21 00:33:30 +00:00
|
|
|
|
|
|
|
if (*sectnum < 0)
|
|
|
|
return -1;
|
|
|
|
|
2019-07-24 01:37:47 +00:00
|
|
|
int32_t k = 32;
|
|
|
|
|
|
|
|
int dir = 1;
|
2016-06-21 00:33:30 +00:00
|
|
|
do
|
|
|
|
{
|
2019-07-24 01:37:47 +00:00
|
|
|
int32_t clipsectcnt = 0;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
|
|
|
bad = 0;
|
|
|
|
|
2019-07-24 01:37:47 +00:00
|
|
|
if (clear)
|
|
|
|
{
|
2020-01-26 13:26:08 +00:00
|
|
|
if (enginecompatibility_mode != ENGINECOMPATIBILITY_NONE && *sectnum < 0)
|
|
|
|
return 0;
|
2019-07-24 01:37:47 +00:00
|
|
|
clipsectorlist[0] = *sectnum;
|
|
|
|
clipsectnum = 1;
|
2019-04-10 09:31:12 +00:00
|
|
|
|
2021-12-06 19:08:32 +00:00
|
|
|
clipsectormap.Zero();
|
|
|
|
clipsectormap.Set(*sectnum);
|
2019-07-24 01:37:47 +00:00
|
|
|
}
|
2019-04-10 09:31:12 +00:00
|
|
|
|
2016-06-21 00:33:30 +00:00
|
|
|
do
|
|
|
|
{
|
2019-04-18 17:25:24 +00:00
|
|
|
uwallptr_t wal;
|
2019-04-18 17:23:30 +00:00
|
|
|
int32_t startwall, endwall;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2019-07-24 01:37:47 +00:00
|
|
|
auto sec = (usectorptr_t)§or[clipsectorlist[clipsectcnt]];
|
2016-06-21 00:33:30 +00:00
|
|
|
if (dir > 0)
|
|
|
|
startwall = sec->wallptr, endwall = startwall + sec->wallnum;
|
|
|
|
else
|
2021-12-20 22:56:39 +00:00
|
|
|
endwall = sec->wallptr, startwall = endwall + sec->wallnum - 1;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2019-07-24 01:37:47 +00:00
|
|
|
int i;
|
|
|
|
|
2019-04-18 17:25:24 +00:00
|
|
|
for (i=startwall, wal=(uwallptr_t)&wall[startwall]; i!=endwall; i+=dir, wal+=dir)
|
2019-08-13 14:44:00 +00:00
|
|
|
if (clipinsidebox(&vect->vec2, i, walldist-4) == 1)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
2019-07-24 01:37:47 +00:00
|
|
|
int j = 0;
|
2021-12-18 14:36:50 +00:00
|
|
|
if (wal->nextsector < 0 || wal->cstat & EWallFlags::FromInt(dawalclipmask)) j = 1;
|
2019-07-24 01:37:47 +00:00
|
|
|
else
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
|
|
|
int32_t daz2;
|
2019-09-22 19:26:07 +00:00
|
|
|
vec2_t closest;
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2019-09-22 19:26:07 +00:00
|
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_19950829)
|
|
|
|
closest = vect->vec2;
|
2016-06-21 00:33:30 +00:00
|
|
|
else
|
|
|
|
{
|
2019-09-22 19:26:07 +00:00
|
|
|
//Find closest point on wall (dax, day) to (vect->x, vect->y)
|
2021-11-26 19:55:13 +00:00
|
|
|
int32_t dax = wal->point2Wall()->x-wal->x;
|
|
|
|
int32_t day = wal->point2Wall()->y-wal->y;
|
2019-09-22 19:26:07 +00:00
|
|
|
int32_t daz = dax*((vect->x)-wal->x) + day*((vect->y)-wal->y);
|
|
|
|
int32_t t;
|
|
|
|
if (daz <= 0)
|
|
|
|
t = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
daz2 = dax*dax+day*day;
|
2021-01-04 11:51:41 +00:00
|
|
|
if (daz >= daz2) t = (1<<30); else t = DivScale(daz, daz2, 30);
|
2019-09-22 19:26:07 +00:00
|
|
|
}
|
2021-01-04 11:36:54 +00:00
|
|
|
dax = wal->x + MulScale(dax, t, 30);
|
|
|
|
day = wal->y + MulScale(day, t, 30);
|
2016-06-21 00:33:30 +00:00
|
|
|
|
2019-09-22 19:26:07 +00:00
|
|
|
closest = { dax, day };
|
|
|
|
}
|
2019-07-24 01:37:47 +00:00
|
|
|
|
|
|
|
j = cliptestsector(clipsectorlist[clipsectcnt], wal->nextsector, flordist, ceildist, closest, vect->z);
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (j != 0)
|
|
|
|
{
|
2021-11-26 19:55:13 +00:00
|
|
|
j = getangle(wal->point2Wall()->x-wal->x, wal->point2Wall()->y-wal->y);
|
2020-11-14 09:00:37 +00:00
|
|
|
int32_t dx = -bsin(j, -11);
|
|
|
|
int32_t dy = bcos(j, -11);
|
2019-07-24 01:37:47 +00:00
|
|
|
int bad2 = 16;
|
2016-06-21 00:33:30 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
vect->x = (vect->x) + dx; vect->y = (vect->y) + dy;
|
|
|
|
bad2--; if (bad2 == 0) break;
|
2019-08-13 14:44:00 +00:00
|
|
|
} while (clipinsidebox(&vect->vec2, i, walldist-4) != 0);
|
2016-06-21 00:33:30 +00:00
|
|
|
bad = -1;
|
2016-06-21 00:34:41 +00:00
|
|
|
k--; if (k <= 0) return bad;
|
2019-08-13 14:44:00 +00:00
|
|
|
clipupdatesector(vect->vec2, sectnum, walldist);
|
2021-12-20 16:32:11 +00:00
|
|
|
if (*sectnum < 0) return -1;
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
2021-12-06 19:08:32 +00:00
|
|
|
else if (!clipsectormap[wal->nextsector])
|
2019-04-10 09:31:12 +00:00
|
|
|
addclipsect(wal->nextsector);
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
clipsectcnt++;
|
|
|
|
} while (clipsectcnt < clipsectnum);
|
|
|
|
dir = -dir;
|
|
|
|
} while (bad != 0);
|
|
|
|
|
2016-06-21 00:34:41 +00:00
|
|
|
return bad;
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
2019-03-19 17:08:59 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// getzrange
|
|
|
|
//
|
2021-12-04 14:37:08 +00:00
|
|
|
|
|
|
|
void getzrange(const vec3_t& pos, sectortype* sect, int32_t* ceilz, CollisionBase& ceilhit, int32_t* florz, CollisionBase& florhit, int32_t walldist, uint32_t cliptype)
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-12-04 14:37:08 +00:00
|
|
|
if (sect == nullptr)
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-12-04 00:14:57 +00:00
|
|
|
*ceilz = INT32_MIN; ceilhit.setVoid();
|
|
|
|
*florz = INT32_MAX; florhit.setVoid();
|
2019-03-19 17:08:59 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t clipsectcnt = 0;
|
|
|
|
|
2021-11-14 14:03:50 +00:00
|
|
|
int32_t clipspritecnt = 0;
|
2019-03-19 17:08:59 +00:00
|
|
|
|
|
|
|
//Extra walldist for sprites on sector lines
|
|
|
|
const int32_t extradist = walldist+MAXCLIPDIST+1;
|
2021-12-04 14:37:08 +00:00
|
|
|
const int32_t xmin = pos.x-extradist, ymin = pos.y-extradist;
|
|
|
|
const int32_t xmax = pos.x+extradist, ymax = pos.y+extradist;
|
2019-03-19 17:08:59 +00:00
|
|
|
|
|
|
|
const int32_t dawalclipmask = (cliptype&65535);
|
2021-07-04 11:05:33 +00:00
|
|
|
const int32_t dasprclipmask = (cliptype >> 16);
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2021-12-04 14:37:08 +00:00
|
|
|
vec2_t closest = pos.vec2;
|
|
|
|
int sectnum = ::sectnum(sect);
|
2019-09-22 19:26:07 +00:00
|
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE)
|
2019-07-29 15:12:01 +00:00
|
|
|
getsectordist(closest, sectnum, &closest);
|
2019-09-22 19:26:07 +00:00
|
|
|
else
|
2021-12-22 09:26:51 +00:00
|
|
|
getzsofslopeptr(sect,closest.X,closest.y,ceilz,florz);
|
2021-12-04 14:37:08 +00:00
|
|
|
ceilhit.setSector(sect);
|
|
|
|
florhit.setSector(sect);
|
2019-03-19 17:08:59 +00:00
|
|
|
|
|
|
|
clipsectorlist[0] = sectnum;
|
|
|
|
clipsectnum = 1;
|
|
|
|
clipspritenum = 0;
|
2021-12-06 19:08:32 +00:00
|
|
|
clipsectormap.Zero();
|
|
|
|
clipsectormap.Set(sectnum);
|
2019-03-19 17:08:59 +00:00
|
|
|
|
|
|
|
do //Collect sectors inside your square first
|
|
|
|
{
|
|
|
|
////////// Walls //////////
|
|
|
|
|
2019-04-18 17:25:24 +00:00
|
|
|
auto const startsec = (usectorptr_t)§or[clipsectorlist[clipsectcnt]];
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2021-12-04 15:07:56 +00:00
|
|
|
for(auto&wal : wallsofsector(startsec))
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-12-04 15:07:56 +00:00
|
|
|
if (wal.twoSided())
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-12-04 15:07:56 +00:00
|
|
|
auto nextsect = wal.nextSector();
|
|
|
|
vec2_t const v1 = wal.pos;
|
|
|
|
vec2_t const v2 = wal.point2Wall()->pos;
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
if ((v1.X < xmin && (v2.X < xmin)) || (v1.X > xmax && v2.X > xmax) ||
|
2019-03-19 17:08:59 +00:00
|
|
|
(v1.y < ymin && (v2.y < ymin)) || (v1.y > ymax && v2.y > ymax))
|
|
|
|
continue;
|
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
vec2_t const d = { v2.X-v1.X, v2.y-v1.y };
|
|
|
|
if (d.X*(pos.y-v1.y) < (pos.x-v1.X)*d.y) continue; //back
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
vec2_t da = { (d.X > 0) ? d.X*(ymin-v1.y) : d.X*(ymax-v1.y),
|
|
|
|
(d.y > 0) ? d.y*(xmax-v1.X) : d.y*(xmin-v1.X) };
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
if (da.X >= da.y)
|
2019-03-19 17:08:59 +00:00
|
|
|
continue;
|
|
|
|
|
2021-12-18 14:36:50 +00:00
|
|
|
if (wal.cstat & EWallFlags::FromInt(dawalclipmask)) continue; // XXX?
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2021-12-18 12:14:56 +00:00
|
|
|
if (((nextsect->ceilingstat & CSTAT_SECTOR_SKY) == 0) && (pos.z <= nextsect->ceilingz+(3<<8))) continue;
|
|
|
|
if (((nextsect->floorstat & CSTAT_SECTOR_SKY) == 0) && (pos.z >= nextsect->floorz-(3<<8))) continue;
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2021-12-04 15:07:56 +00:00
|
|
|
int nextsectno = ::sectnum(nextsect);
|
2021-12-06 19:08:32 +00:00
|
|
|
if (!clipsectormap[nextsectno])
|
2021-12-04 15:07:56 +00:00
|
|
|
addclipsect(nextsectno);
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
if (((v1.X < xmin + MAXCLIPDIST) && (v2.X < xmin + MAXCLIPDIST)) ||
|
|
|
|
((v1.X > xmax - MAXCLIPDIST) && (v2.X > xmax - MAXCLIPDIST)) ||
|
2019-03-19 17:08:59 +00:00
|
|
|
((v1.y < ymin + MAXCLIPDIST) && (v2.y < ymin + MAXCLIPDIST)) ||
|
|
|
|
((v1.y > ymax - MAXCLIPDIST) && (v2.y > ymax - MAXCLIPDIST)))
|
|
|
|
continue;
|
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
if (d.X > 0) da.X += d.X*MAXCLIPDIST; else da.X -= d.X*MAXCLIPDIST;
|
2019-03-19 17:08:59 +00:00
|
|
|
if (d.y > 0) da.y -= d.y*MAXCLIPDIST; else da.y += d.y*MAXCLIPDIST;
|
2021-12-22 09:26:51 +00:00
|
|
|
if (da.X >= da.y)
|
2019-03-19 17:08:59 +00:00
|
|
|
continue;
|
|
|
|
//It actually got here, through all the continue's!!!
|
2021-10-08 17:06:41 +00:00
|
|
|
int32_t daz = 0, daz2 = 0;
|
2021-12-04 14:37:08 +00:00
|
|
|
closest = pos.vec2;
|
2019-09-22 19:26:07 +00:00
|
|
|
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE)
|
2021-12-04 15:07:56 +00:00
|
|
|
getsectordist(closest, nextsectno, &closest);
|
2019-09-22 19:26:07 +00:00
|
|
|
else
|
2021-12-22 09:26:51 +00:00
|
|
|
getzsofslopeptr(nextsect, closest.X,closest.y, &daz,&daz2);
|
2019-03-19 17:08:59 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
if (daz > *ceilz)
|
2021-12-04 15:07:56 +00:00
|
|
|
*ceilz = daz, ceilhit.setSector(nextsect);
|
2019-03-19 17:08:59 +00:00
|
|
|
|
|
|
|
if (daz2 < *florz)
|
2021-12-04 15:07:56 +00:00
|
|
|
*florz = daz2, florhit.setSector(nextsect);
|
2019-03-19 17:08:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
clipsectcnt++;
|
|
|
|
}
|
|
|
|
while (clipsectcnt < clipsectnum || clipspritecnt < clipspritenum);
|
|
|
|
|
|
|
|
////////// Sprites //////////
|
|
|
|
|
2019-03-19 17:09:40 +00:00
|
|
|
if (dasprclipmask)
|
2021-12-14 09:15:58 +00:00
|
|
|
for (int i=0; i<clipsectnum; i++)
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-11-11 19:20:00 +00:00
|
|
|
if (!validSectorIndex(clipsectorlist[i])) continue; // we got a deleted sprite in here somewhere. Skip this entry.
|
2021-12-04 00:14:57 +00:00
|
|
|
TSectIterator<DCoreActor> it(clipsectorlist[i]);
|
|
|
|
while (auto actor = it.Next())
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-12-04 00:14:57 +00:00
|
|
|
auto spr = &actor->s();
|
2021-11-26 19:55:13 +00:00
|
|
|
const int32_t cstat = spr->cstat;
|
2021-11-14 14:03:50 +00:00
|
|
|
int32_t daz = 0, daz2 = 0;
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2021-11-26 19:55:13 +00:00
|
|
|
if (spr->cstat2 & CSTAT2_SPRITE_NOFIND) continue;
|
2019-03-19 17:08:59 +00:00
|
|
|
if (cstat&dasprclipmask)
|
|
|
|
{
|
|
|
|
int32_t clipyou = 0;
|
|
|
|
|
2021-11-26 19:55:13 +00:00
|
|
|
vec2_t v1 = spr->pos.vec2;
|
2019-03-19 17:08:59 +00:00
|
|
|
|
|
|
|
switch (cstat & CSTAT_SPRITE_ALIGNMENT_MASK)
|
|
|
|
{
|
|
|
|
case CSTAT_SPRITE_ALIGNMENT_FACING:
|
|
|
|
{
|
2021-11-26 19:55:13 +00:00
|
|
|
int32_t k = walldist+(spr->clipdist<<2)+1;
|
2021-12-22 09:26:51 +00:00
|
|
|
if ((abs(v1.X-pos.x) <= k) && (abs(v1.y-pos.y) <= k))
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-12-03 23:51:06 +00:00
|
|
|
daz = spr->z + spriteheightofsptr(spr, &k, 1);
|
2019-03-19 17:08:59 +00:00
|
|
|
daz2 = daz - k;
|
|
|
|
clipyou = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case CSTAT_SPRITE_ALIGNMENT_WALL:
|
|
|
|
{
|
2021-03-27 14:03:57 +00:00
|
|
|
vec2_t v2;
|
2021-12-22 09:26:51 +00:00
|
|
|
get_wallspr_points(spr, &v1.X, &v2.X, &v1.y, &v2.y);
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
if (clipinsideboxline(pos.x,pos.y,v1.X,v1.y,v2.X,v2.y,walldist+1) != 0)
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
|
|
|
int32_t k;
|
2021-12-03 23:51:06 +00:00
|
|
|
daz = spr->z + spriteheightofsptr(spr, &k, 1);
|
2021-03-27 14:03:57 +00:00
|
|
|
daz2 = daz-k;
|
2019-03-19 17:08:59 +00:00
|
|
|
clipyou = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case CSTAT_SPRITE_ALIGNMENT_FLOOR:
|
2021-12-20 19:27:12 +00:00
|
|
|
case CSTAT_SPRITE_ALIGNMENT_SLOPE:
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-12-20 19:27:12 +00:00
|
|
|
if ((cstat & CSTAT_SPRITE_ALIGNMENT_MASK) == CSTAT_SPRITE_ALIGNMENT_FLOOR) daz = spr->z;
|
|
|
|
else daz = spriteGetZOfSlope(spr, pos.x, pos.y);
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2021-12-18 15:39:44 +00:00
|
|
|
if ((cstat & CSTAT_SPRITE_ONE_SIDE) != 0 && (pos.z > daz) == ((cstat & CSTAT_SPRITE_YFLIP)==0))
|
2019-03-19 17:08:59 +00:00
|
|
|
continue;
|
|
|
|
|
2021-03-27 14:03:57 +00:00
|
|
|
vec2_t v2, v3, v4;
|
2021-12-22 09:26:51 +00:00
|
|
|
get_floorspr_points((uspriteptr_t) spr, pos.x, pos.y, &v1.X, &v2.X, &v3.X, &v4.X,
|
2021-12-20 19:27:12 +00:00
|
|
|
&v1.y, &v2.y, &v3.y, &v4.y, spriteGetSlope(spr));
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2021-11-26 19:55:13 +00:00
|
|
|
vec2_t const da = { MulScale(bcos(spr->ang - 256), walldist + 4, 14),
|
|
|
|
MulScale(bsin(spr->ang - 256), walldist + 4, 14) };
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
v1.X += da.X; v2.X -= da.y; v3.X -= da.X; v4.X += da.y;
|
|
|
|
v1.y += da.y; v2.y += da.X; v3.y -= da.y; v4.y -= da.X;
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2021-03-27 14:03:57 +00:00
|
|
|
clipyou = get_floorspr_clipyou(v1, v2, v3, v4);
|
2019-03-19 17:08:59 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (clipyou != 0)
|
|
|
|
{
|
2021-12-04 14:37:08 +00:00
|
|
|
if ((pos.z > daz) && (daz > *ceilz))
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
|
|
|
*ceilz = daz;
|
2021-12-04 00:14:57 +00:00
|
|
|
ceilhit.setSprite(actor);
|
2019-03-19 17:08:59 +00:00
|
|
|
}
|
|
|
|
|
2021-12-04 14:37:08 +00:00
|
|
|
if ((pos.z < daz2) && (daz2 < *florz))
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
|
|
|
*florz = daz2;
|
2021-12-04 00:14:57 +00:00
|
|
|
florhit.setSprite(actor);
|
2019-03-19 17:08:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// intp: point of currently best (closest) intersection
|
2019-08-09 09:28:27 +00:00
|
|
|
int32_t try_facespr_intersect(uspriteptr_t const spr, vec3_t const in,
|
|
|
|
int32_t vx, int32_t vy, int32_t vz,
|
|
|
|
vec3_t * const intp, int32_t strictly_smaller_than_p)
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2019-08-09 09:28:27 +00:00
|
|
|
vec3_t const sprpos = spr->pos;
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2019-08-09 09:28:27 +00:00
|
|
|
int32_t const topt = vx * (sprpos.x - in.x) + vy * (sprpos.y - in.y);
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2019-08-09 09:28:27 +00:00
|
|
|
if (topt <= 0) return 0;
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2019-08-09 09:28:27 +00:00
|
|
|
int32_t const bot = vx * vx + vy * vy;
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2019-08-09 09:28:27 +00:00
|
|
|
if (!bot) return 0;
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2021-01-04 12:34:55 +00:00
|
|
|
vec3_t newpos = { 0, 0, in.z + Scale(vz, topt, bot) };
|
2019-08-09 09:28:27 +00:00
|
|
|
int32_t siz;
|
|
|
|
int32_t const z1 = sprpos.z + spriteheightofsptr(spr, &siz, 1);
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2019-08-09 09:28:27 +00:00
|
|
|
if (newpos.z < z1 - siz || newpos.z > z1)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
int32_t const topu = vx * (sprpos.y - in.y) - vy * (sprpos.x - in.x);
|
2021-01-04 12:34:55 +00:00
|
|
|
vec2_t const off = { Scale(vx, topu, bot), Scale(vy, topu, bot) };
|
2021-12-22 09:26:51 +00:00
|
|
|
int32_t const dist = off.X * off.X + off.y * off.y;
|
2019-08-09 09:28:27 +00:00
|
|
|
|
2020-11-22 23:18:07 +00:00
|
|
|
siz = tileWidth(spr->picnum) * spr->xrepeat;
|
2019-08-09 09:28:27 +00:00
|
|
|
|
2021-01-04 11:36:54 +00:00
|
|
|
if (dist > MulScale(siz, siz, 7)) return 0;
|
2019-08-09 09:28:27 +00:00
|
|
|
|
2021-01-04 12:34:55 +00:00
|
|
|
newpos.vec2 = { in.x + Scale(vx, topt, bot), in.y + Scale(vy, topt, bot) };
|
2019-08-09 09:28:27 +00:00
|
|
|
|
2021-01-04 12:02:00 +00:00
|
|
|
if (abs(newpos.x - in.x) + abs(newpos.y - in.y) + strictly_smaller_than_p >
|
|
|
|
abs(intp->x - in.x) + abs(intp->y - in.y))
|
2019-08-09 09:28:27 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
*intp = newpos;
|
|
|
|
return 1;
|
2019-03-19 17:08:59 +00:00
|
|
|
}
|
|
|
|
|
2021-12-03 23:47:08 +00:00
|
|
|
static inline void hit_set(HitInfoBase *hit, sectortype* sect, walltype* wal, DCoreActor* actor, int32_t x, int32_t y, int32_t z)
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-12-03 23:47:08 +00:00
|
|
|
hit->hitSector = sect;
|
|
|
|
hit->hitWall = wal;
|
|
|
|
hit->hitActor = actor;
|
|
|
|
hit->hitpos.x = x;
|
|
|
|
hit->hitpos.y = y;
|
|
|
|
hit->hitpos.z = z;
|
2019-03-19 17:08:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int32_t hitscan_hitsectcf=-1;
|
|
|
|
|
|
|
|
// stat, heinum, z: either ceiling- or floor-
|
|
|
|
// how: -1: behave like ceiling, 1: behave like floor
|
2021-12-03 23:47:08 +00:00
|
|
|
static int32_t hitscan_trysector(const vec3_t *sv, sectortype* sec, HitInfoBase *hit,
|
2019-03-19 17:08:59 +00:00
|
|
|
int32_t vx, int32_t vy, int32_t vz,
|
2021-12-03 23:47:08 +00:00
|
|
|
uint16_t stat, int16_t heinum, int32_t z, int32_t how)
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-11-14 14:03:50 +00:00
|
|
|
int32_t x1 = INT32_MAX, y1 = 0, z1 = 0;
|
2019-03-19 17:08:59 +00:00
|
|
|
int32_t i;
|
|
|
|
|
|
|
|
if (stat&2)
|
|
|
|
{
|
2021-11-26 19:55:13 +00:00
|
|
|
auto const wal = (uwallptr_t)sec->firstWall();
|
|
|
|
auto const wal2 = (uwallptr_t)wal->point2Wall();
|
2019-03-19 17:08:59 +00:00
|
|
|
int32_t j, dax=wal2->x-wal->x, day=wal2->y-wal->y;
|
|
|
|
|
2021-03-14 22:38:39 +00:00
|
|
|
i = ksqrt(compat_maybe_truncate_to_int32(uhypsq(dax,day))); if (i == 0) return 1; //continue;
|
2021-01-04 11:51:41 +00:00
|
|
|
i = DivScale(heinum,i, 15);
|
2019-03-19 17:08:59 +00:00
|
|
|
dax *= i; day *= i;
|
|
|
|
|
2021-01-04 10:40:08 +00:00
|
|
|
j = (vz<<8)-DMulScale(dax,vy,-day,vx, 15);
|
2019-03-19 17:08:59 +00:00
|
|
|
if (j != 0)
|
|
|
|
{
|
2021-01-04 10:40:08 +00:00
|
|
|
i = ((z - sv->z)<<8)+DMulScale(dax,sv->y-wal->y,-day,sv->x-wal->x, 15);
|
2021-01-04 12:02:00 +00:00
|
|
|
if (((i^j) >= 0) && ((abs(i)>>1) < abs(j)))
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-01-04 11:51:41 +00:00
|
|
|
i = DivScale(i,j, 30);
|
2021-01-04 11:36:54 +00:00
|
|
|
x1 = sv->x + MulScale(vx,i, 30);
|
|
|
|
y1 = sv->y + MulScale(vy,i, 30);
|
|
|
|
z1 = sv->z + MulScale(vz,i, 30);
|
2019-03-19 17:08:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ((how*vz > 0) && (how*sv->z <= how*z))
|
|
|
|
{
|
|
|
|
z1 = z; i = z1-sv->z;
|
2021-01-04 12:02:00 +00:00
|
|
|
if ((abs(i)>>1) < vz*how)
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-01-04 11:51:41 +00:00
|
|
|
i = DivScale(i,vz, 30);
|
2021-01-04 11:36:54 +00:00
|
|
|
x1 = sv->x + MulScale(vx,i, 30);
|
|
|
|
y1 = sv->y + MulScale(vy,i, 30);
|
2019-03-19 17:08:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-03 23:47:08 +00:00
|
|
|
if ((x1 != INT32_MAX) && (abs(x1-sv->x)+abs(y1-sv->y) < abs((hit->hitpos.x)-sv->x)+abs((hit->hitpos.y)-sv->y)))
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-12-06 17:17:45 +00:00
|
|
|
if (inside(x1,y1,sec) == 1)
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-12-03 23:47:08 +00:00
|
|
|
hit_set(hit, sec, nullptr, nullptr, x1, y1, z1);
|
|
|
|
hitscan_hitsectcf = (how+1)>>1;
|
2019-03-19 17:08:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-12-03 23:47:08 +00:00
|
|
|
|
2019-03-19 17:08:59 +00:00
|
|
|
//
|
|
|
|
// hitscan
|
|
|
|
//
|
2021-12-03 23:47:08 +00:00
|
|
|
|
|
|
|
int hitscan(const vec3_t& start, const sectortype* startsect, const vec3_t& direction, HitInfoBase& hitinfo, unsigned cliptype)
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-12-03 23:47:08 +00:00
|
|
|
auto const sv = &start;
|
|
|
|
int const vx = direction.x, vy = direction.y, vz = direction.z;
|
2019-03-19 17:08:59 +00:00
|
|
|
int32_t x1, y1=0, z1=0, x2, y2, intx, inty, intz;
|
|
|
|
int32_t i, k, daz;
|
|
|
|
|
2019-04-18 17:25:24 +00:00
|
|
|
uspriteptr_t curspr = NULL;
|
2019-03-19 17:08:59 +00:00
|
|
|
// tmp: { (int32_t)curidx, (spritetype *)curspr, (!=0 if outer sector) }
|
|
|
|
const int32_t dawalclipmask = (cliptype&65535);
|
2021-07-04 11:05:33 +00:00
|
|
|
const int32_t dasprclipmask = (cliptype >> 16);
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2021-12-03 23:47:08 +00:00
|
|
|
hitinfo.clearObj(); // note that this case leaves hitpos untouched.
|
|
|
|
if (startsect == nullptr)
|
2019-03-19 17:08:59 +00:00
|
|
|
return -1;
|
|
|
|
|
2021-12-03 23:47:08 +00:00
|
|
|
hitinfo.hitpos.vec2 = hitscangoal;
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2021-12-03 23:47:08 +00:00
|
|
|
BFSSectorSearch search(startsect);
|
|
|
|
while (auto sec = search.GetNext())
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
|
|
|
i = 1;
|
2021-12-04 13:41:07 +00:00
|
|
|
if (hitscan_trysector(sv, sec, &hitinfo, vx,vy,vz, sec->ceilingstat, sec->ceilingheinum, sec->ceilingz, -i))
|
|
|
|
continue;
|
|
|
|
if (hitscan_trysector(sv, sec, &hitinfo, vx,vy,vz, sec->floorstat, sec->floorheinum, sec->floorz, i))
|
|
|
|
continue;
|
2019-03-19 17:08:59 +00:00
|
|
|
|
|
|
|
////////// Walls //////////
|
|
|
|
|
2021-12-03 23:47:08 +00:00
|
|
|
for(auto& w : wallsofsector(sec))
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-12-03 23:47:08 +00:00
|
|
|
auto wal = &w;
|
|
|
|
auto wal2 = wal->point2Wall();
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2021-12-03 23:47:08 +00:00
|
|
|
auto const nextsect = wal->nextSector();
|
|
|
|
if (curspr && !wal->twoSided()) continue;
|
2019-03-19 17:08:59 +00:00
|
|
|
|
|
|
|
x1 = wal->x; y1 = wal->y; x2 = wal2->x; y2 = wal2->y;
|
|
|
|
|
2019-09-22 19:26:07 +00:00
|
|
|
if (compat_maybe_truncate_to_int32((coord_t)(x1-sv->x)*(y2-sv->y))
|
|
|
|
< compat_maybe_truncate_to_int32((coord_t)(x2-sv->x)*(y1-sv->y))) continue;
|
2019-03-19 17:08:59 +00:00
|
|
|
if (rintersect(sv->x,sv->y,sv->z, vx,vy,vz, x1,y1, x2,y2, &intx,&inty,&intz) == -1) continue;
|
|
|
|
|
2021-12-04 13:41:07 +00:00
|
|
|
if (abs(intx-sv->x)+abs(inty-sv->y) >= abs((hitinfo.hitpos.x)-sv->x)+abs((hitinfo.hitpos.y)-sv->y))
|
2019-03-19 17:08:59 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!curspr)
|
|
|
|
{
|
2021-12-18 14:36:50 +00:00
|
|
|
if ((!wal->twoSided()) || (wal->cstat & EWallFlags::FromInt(dawalclipmask)))
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-12-04 13:41:07 +00:00
|
|
|
hit_set(&hitinfo, sec, wal, nullptr, intx, inty, intz);
|
|
|
|
continue;
|
2019-09-22 19:26:07 +00:00
|
|
|
}
|
|
|
|
|
2021-12-04 13:41:07 +00:00
|
|
|
int32_t daz2;
|
|
|
|
getzsofslopeptr(nextsect,intx,inty,&daz,&daz2);
|
|
|
|
if (intz <= daz || intz >= daz2)
|
|
|
|
{
|
|
|
|
hit_set(&hitinfo, sec, wal, nullptr, intx, inty, intz);
|
|
|
|
continue;
|
2019-03-19 17:08:59 +00:00
|
|
|
}
|
|
|
|
}
|
2021-12-03 23:47:08 +00:00
|
|
|
search.Add(nextsect);
|
2019-03-19 17:08:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
////////// Sprites //////////
|
|
|
|
|
|
|
|
if (dasprclipmask==0)
|
|
|
|
continue;
|
|
|
|
|
2021-12-03 23:47:08 +00:00
|
|
|
TSectIterator<DCoreActor> it(sec);
|
|
|
|
while (auto actor = it.Next())
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-12-03 23:47:08 +00:00
|
|
|
auto const spr = &actor->s();
|
2019-08-09 09:28:27 +00:00
|
|
|
uint32_t const cstat = spr->cstat;
|
2021-04-17 07:37:38 +00:00
|
|
|
|
2021-09-05 10:25:52 +00:00
|
|
|
if (spr->cstat2 & CSTAT2_SPRITE_NOFIND)
|
2021-04-17 07:37:38 +00:00
|
|
|
continue;
|
|
|
|
|
2019-03-19 17:08:59 +00:00
|
|
|
#ifdef USE_OPENGL
|
|
|
|
if (!hitallsprites)
|
|
|
|
#endif
|
|
|
|
if ((cstat&dasprclipmask) == 0)
|
|
|
|
continue;
|
|
|
|
|
2021-03-27 14:03:57 +00:00
|
|
|
x1 = spr->x; y1 = spr->y; z1 = spr->z;
|
2021-12-18 15:39:44 +00:00
|
|
|
switch (cstat&CSTAT_SPRITE_ALIGNMENT_MASK)
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
{
|
2021-12-03 23:47:08 +00:00
|
|
|
if (try_facespr_intersect(spr, *sv, vx, vy, vz, &hitinfo.hitpos, 0))
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-12-03 23:47:08 +00:00
|
|
|
hitinfo.hitSector = sec;
|
|
|
|
hitinfo.hitWall = nullptr;
|
|
|
|
hitinfo.hitActor = actor;
|
2019-03-19 17:08:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-03-30 19:36:21 +00:00
|
|
|
case CSTAT_SPRITE_ALIGNMENT_WALL:
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
|
|
|
int32_t ucoefup16;
|
|
|
|
int32_t tilenum = spr->picnum;
|
|
|
|
|
2021-03-27 14:03:57 +00:00
|
|
|
get_wallspr_points(spr, &x1, &x2, &y1, &y2);
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2021-12-18 15:39:44 +00:00
|
|
|
if ((cstat & CSTAT_SPRITE_ONE_SIDE) != 0) //back side of 1-way sprite
|
2021-03-27 14:03:57 +00:00
|
|
|
if (compat_maybe_truncate_to_int32((coord_t)(x1-sv->x)*(y2-sv->y))
|
|
|
|
< compat_maybe_truncate_to_int32((coord_t)(x2-sv->x)*(y1-sv->y))) continue;
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2021-03-27 14:03:57 +00:00
|
|
|
ucoefup16 = rintersect(sv->x,sv->y,sv->z,vx,vy,vz,x1,y1,x2,y2,&intx,&inty,&intz);
|
2019-03-19 17:08:59 +00:00
|
|
|
if (ucoefup16 == -1) continue;
|
|
|
|
|
2021-12-03 23:47:08 +00:00
|
|
|
if (abs(intx-sv->x)+abs(inty-sv->y) > abs((hitinfo.hitpos.x)-sv->x)+abs((hitinfo.hitpos.y)-sv->y))
|
2019-03-19 17:08:59 +00:00
|
|
|
continue;
|
|
|
|
|
2021-12-03 23:47:08 +00:00
|
|
|
daz = spr->z + spriteheightofsptr(&actor->s(), &k, 1);
|
2019-03-19 17:08:59 +00:00
|
|
|
if (intz > daz-k && intz < daz)
|
|
|
|
{
|
|
|
|
if (picanm[tilenum].sf&PICANM_TEXHITSCAN_BIT)
|
|
|
|
{
|
2021-03-15 22:46:03 +00:00
|
|
|
tileUpdatePicnum(&tilenum, 0, 0);
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2019-10-15 21:18:52 +00:00
|
|
|
if (tileLoad(tilenum))
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
|
|
|
// daz-intz > 0 && daz-intz < k
|
2021-01-04 11:36:54 +00:00
|
|
|
int32_t xtex = MulScale(ucoefup16, tileWidth(tilenum), 16);
|
2021-01-04 11:51:41 +00:00
|
|
|
int32_t vcoefup16 = 65536-DivScale(daz-intz, k, 16);
|
2021-01-04 11:36:54 +00:00
|
|
|
int32_t ytex = MulScale(vcoefup16, tileHeight(tilenum), 16);
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2020-11-20 07:18:26 +00:00
|
|
|
auto texel = (tilePtr(tilenum) + tileHeight(tilenum)*xtex + ytex);
|
2020-04-11 22:04:02 +00:00
|
|
|
if (*texel == TRANSPARENT_INDEX)
|
2019-03-19 17:08:59 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-03 23:47:08 +00:00
|
|
|
hit_set(&hitinfo, sec, nullptr, actor, intx, inty, intz);
|
2019-03-19 17:08:59 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-03-30 19:36:21 +00:00
|
|
|
case CSTAT_SPRITE_ALIGNMENT_FLOOR:
|
2019-03-19 17:08:59 +00:00
|
|
|
{
|
2021-12-04 13:41:07 +00:00
|
|
|
int32_t x3, y3, x4, y4;
|
2019-03-19 17:08:59 +00:00
|
|
|
intz = z1;
|
2019-08-27 06:52:42 +00:00
|
|
|
|
|
|
|
if (vz == 0 || ((intz-sv->z)^vz) < 0) continue;
|
|
|
|
|
2021-12-18 15:39:44 +00:00
|
|
|
if ((cstat & CSTAT_SPRITE_ONE_SIDE) != 0)
|
|
|
|
if ((sv->z > intz) == ((cstat & CSTAT_SPRITE_YFLIP)==0)) continue;
|
2021-12-04 13:41:07 +00:00
|
|
|
|
|
|
|
// avoid overflow errors by using 64 bit math.
|
|
|
|
intx = int(sv->x + (int64_t(intz) - sv->z) * vx / vz);
|
|
|
|
inty = int(sv->y + (int64_t(intz) - sv->z) * vy / vz);
|
2019-07-29 15:43:16 +00:00
|
|
|
|
2021-12-03 23:47:08 +00:00
|
|
|
if (abs(intx-sv->x)+abs(inty-sv->y) > abs((hitinfo.hitpos.x)-sv->x)+abs((hitinfo.hitpos.y)-sv->y))
|
2019-03-19 17:08:59 +00:00
|
|
|
continue;
|
|
|
|
|
2021-03-27 14:03:57 +00:00
|
|
|
get_floorspr_points((uspriteptr_t)spr, intx, inty, &x1, &x2, &x3, &x4,
|
2021-12-20 19:27:12 +00:00
|
|
|
&y1, &y2, &y3, &y4, spriteGetSlope(spr));
|
2019-03-19 17:08:59 +00:00
|
|
|
|
2021-03-27 14:03:57 +00:00
|
|
|
if (get_floorspr_clipyou({x1, y1}, {x2, y2}, {x3, y3}, {x4, y4}))
|
2021-12-03 23:47:08 +00:00
|
|
|
hit_set(&hitinfo, sec, nullptr, actor, intx, inty, intz);
|
2019-03-19 17:08:59 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2021-12-20 19:27:12 +00:00
|
|
|
|
|
|
|
case CSTAT_SPRITE_ALIGNMENT_SLOPE:
|
|
|
|
{
|
2021-12-21 12:46:11 +00:00
|
|
|
int32_t x3, y3, x4, y4;
|
2021-12-20 19:27:12 +00:00
|
|
|
int32_t const heinum = spriteGetSlope(spr);
|
|
|
|
int32_t const dax = (heinum * sintable[(spr->ang + 1024) & 2047]) << 1;
|
|
|
|
int32_t const day = (heinum * sintable[(spr->ang + 512) & 2047]) << 1;
|
|
|
|
int32_t const j = (vz << 8) - DMulScale(dax, vy, -day, vx, 15);
|
|
|
|
if (j == 0) continue;
|
|
|
|
if ((cstat & 64) != 0)
|
|
|
|
if ((j < 0) == ((cstat & 8) == 0)) continue;
|
|
|
|
int32_t i = ((spr->z - sv->z) << 8) + DMulScale(dax, sv->y - spr->y, -day, sv->x - spr->x, 15);
|
|
|
|
if ((i ^ j) < 0 || (abs(i) >> 1) >= abs(j)) continue;
|
|
|
|
|
|
|
|
i = DivScale(i, j, 30);
|
|
|
|
intx = sv->x + MulScale(vx, i, 30);
|
|
|
|
inty = sv->y + MulScale(vy, i, 30);
|
|
|
|
intz = sv->z + MulScale(vz, i, 30);
|
|
|
|
|
|
|
|
if (abs(intx - sv->x) + abs(inty - sv->y) > abs((hitinfo.hitpos.x) - sv->x) + abs((hitinfo.hitpos.y) - sv->y))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
get_floorspr_points((uspriteptr_t)spr, intx, inty, &x1, &x2, &x3, &x4,
|
|
|
|
&y1, &y2, &y3, &y4, spriteGetSlope(spr));
|
|
|
|
|
|
|
|
if (get_floorspr_clipyou({ x1, y1 }, { x2, y2 }, { x3, y3 }, { x4, y4 }))
|
|
|
|
hit_set(&hitinfo, sec, nullptr, actor, intx, inty, intz);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-03-19 17:08:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|