raze/source/sw/src/mclip.cpp

559 lines
15 KiB
C++
Raw Normal View History

//-------------------------------------------------------------------------
/*
Copyright (C) 1997, 2005 - 3D Realms Entertainment
This file is part of Shadow Warrior version 1.2
Shadow Warrior is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Original Source: 1997 - Frank Maddin and Jim Norwood
Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
*/
//-------------------------------------------------------------------------
#include "ns.h"
#include "build.h"
#include "common.h"
#include "mytypes.h"
#include "keys.h"
#include "names2.h"
#include "panel.h"
#include "game.h"
#include "tags.h"
#include "player.h"
#include "mclip.h"
BEGIN_SW_NS
#if 0
int MultiClipMove(PLAYERp pp, int z, int floor_dist)
{
int i;
int ox[MAX_CLIPBOX],oy[MAX_CLIPBOX];
SPRITEp sp = pp->sop->sp_child;
USERp u = User[sp - sprite];
SECTOR_OBJECTp sop = pp->sop;
short ang;
short min_ndx;
int min_dist = 999999;
int dist;
int ret_start;
int ret[MAX_CLIPBOX];
int x[MAX_CLIPBOX],y[MAX_CLIPBOX];
for (i = 0; i < sop->clipbox_num; i++)
{
ang = NORM_ANGLE(pp->pang + sop->clipbox_ang[i]);
ox[i] = x[i] = pp->posx + (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)] >> 14);
oy[i] = y[i] = pp->posy + (sop->clipbox_vdist[i] * sintable[ang] >> 14);
// move the box
ret[i] = clipmove_old(&x[i], &y[i], &z, &pp->cursectnum, pp->xvect, pp->yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
// save the dist moved
dist = FindDistance2D(x[i] - ox[i], y[i] - oy[i]);
if (dist < min_dist)
{
min_dist = dist;
min_ndx = i;
}
}
// put posx and y off from offset
pp->posx -= ox[min_ndx] - x[min_ndx];
pp->posy -= oy[min_ndx] - y[min_ndx];
return ret[min_ndx];
}
#endif
#if 0
int MultiClipMove(PLAYERp pp, int z, int floor_dist)
{
int i;
int ox[MAX_CLIPBOX],oy[MAX_CLIPBOX];
SPRITEp sp = pp->sop->sp_child;
USERp u = User[sp - sprite];
SECTOR_OBJECTp sop = pp->sop;
short ang;
short min_ndx;
int min_dist = 999999;
int dist;
int ret_start;
int ret[MAX_CLIPBOX];
int x[MAX_CLIPBOX],y[MAX_CLIPBOX];
for (i = 0; i < sop->clipbox_num; i++)
{
ang = NORM_ANGLE(pp->pang + sop->clipbox_ang[i]);
ox[i] = x[i] = pp->posx + (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)] >> 14);
oy[i] = y[i] = pp->posy + (sop->clipbox_vdist[i] * sintable[ang] >> 14);
// move the box
//pushmove_old(&x[i], &y[i], &z, &pp->cursectnum, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
ret[i] = clipmove_old(&x[i], &y[i], &z, &pp->cursectnum, pp->xvect, pp->yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
//pushmove_old(&x[i], &y[i], &z, &pp->cursectnum, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
// save the dist moved
dist = FindDistance2D(x[i] - ox[i], y[i] - oy[i]);
if (dist < min_dist)
{
min_dist = dist;
min_ndx = i;
}
}
// put posx and y off from offset
pp->posx -= ox[min_ndx] - x[min_ndx];
pp->posy -= oy[min_ndx] - y[min_ndx];
return ret[min_ndx];
}
#endif
#if 0
int MultiClipMove(PLAYERp pp, int z, int floor_dist)
{
int i;
int ox[MAX_CLIPBOX],oy[MAX_CLIPBOX];
SPRITEp sp = pp->sop->sp_child;
USERp u = User[sp - sprite];
SECTOR_OBJECTp sop = pp->sop;
short ang;
short min_ndx;
int min_dist = 999999;
int dist;
int ret_start;
int ret[MAX_CLIPBOX];
int x[MAX_CLIPBOX],y[MAX_CLIPBOX];
int xvect,yvect;
int xs,ys;
for (i = 0; i < sop->clipbox_num; i++)
{
// move the box to position instead of using offset- this prevents small rounding errors
// allowing you to move through wall
ang = NORM_ANGLE(pp->pang + sop->clipbox_ang[i]);
xs = pp->posx;
ys = pp->posy;
xvect = (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)]);
yvect = (sop->clipbox_vdist[i] * sintable[ang]);
ret_start = clipmove_old(&xs, &ys, &z, &pp->cursectnum, xvect, yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
// save off the start position
ox[i] = x[i] = xs;
oy[i] = y[i] = ys;
// move the box
ret[i] = clipmove_old(&x[i], &y[i], &z, &pp->cursectnum, pp->xvect, pp->yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
// save the dist moved
dist = ksqrt(SQ(x[i] - ox[i]) + SQ(y[i] - oy[i]));
//dist = FindDistance2D(x[i] - ox[i], y[i] - oy[i]);
if (ret[i])
{
//DSPRINTF(ds,"i %d, ret %d, dist %d",i, ret[i], dist);
//printf("%s\n",ds);
MONO_PRINT(ds);
}
if (dist < min_dist)
{
min_dist = dist;
min_ndx = i;
}
}
// put posx and y off from offset
pp->posx -= ox[min_ndx] - x[min_ndx];
pp->posy -= oy[min_ndx] - y[min_ndx];
return ret[min_ndx];
}
#endif
#if 0
int MultiClipMove(PLAYERp pp, int z, int floor_dist)
{
int i;
int ox[MAX_CLIPBOX],oy[MAX_CLIPBOX];
SPRITEp sp = pp->sop->sp_child;
USERp u = User[sp - sprite];
SECTOR_OBJECTp sop = pp->sop;
short ang;
short min_ndx;
int min_dist = 999999;
int dist;
int ret_start;
int ret[MAX_CLIPBOX];
int x[MAX_CLIPBOX],y[MAX_CLIPBOX];
int xvect,yvect;
int xs,ys;
for (i = 0; i < sop->clipbox_num; i++)
{
// move the box to position instead of using offset- this prevents small rounding errors
// allowing you to move through wall
ang = NORM_ANGLE(pp->pang + sop->clipbox_ang[i]);
xs = pp->posx;
ys = pp->posy;
xvect = (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)]);
yvect = (sop->clipbox_vdist[i] * sintable[ang]);
ret_start = clipmove_old(&xs, &ys, &z, &pp->cursectnum, xvect, yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
if (ret_start)
{
// hit something moving into position
min_dist = 0;
min_ndx = i;
// ox is where it should be
ox[i] = x[i] = pp->posx + (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)] >> 14);
oy[i] = y[i] = pp->posy + (sop->clipbox_vdist[i] * sintable[ang] >> 14);
x[i] = xs;
y[i] = ys;
dist = ksqrt(SQ(x[i] - ox[i]) + SQ(y[i] - oy[i]));
//ox[i] = x[i] = oy[i] = y[i] = 0;
}
else
{
// save off the start position
ox[i] = x[i] = xs;
oy[i] = y[i] = ys;
// move the box
ret[i] = clipmove_old(&x[i], &y[i], &z, &pp->cursectnum, pp->xvect, pp->yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
// save the dist moved
dist = ksqrt(SQ(x[i] - ox[i]) + SQ(y[i] - oy[i]));
//dist = FindDistance2D(x[i] - ox[i], y[i] - oy[i]);
if (ret[i])
{
//DSPRINTF(ds,"i %d, ret %d, dist %d",i, ret[i], dist);
MONO_PRINT(ds);
}
if (dist < min_dist)
{
min_dist = dist;
min_ndx = i;
}
}
}
// put posx and y off from offset
pp->posx -= ox[min_ndx] - x[min_ndx];
pp->posy -= oy[min_ndx] - y[min_ndx];
return ret[min_ndx];
}
#endif
int MultiClipMove(PLAYERp pp, int z, int floor_dist)
{
int i;
int ox[MAX_CLIPBOX],oy[MAX_CLIPBOX];
SECTOR_OBJECTp sop = pp->sop;
short ang;
short min_ndx = 0;
int min_dist = 999999;
int dist;
int ret_start;
int ret;
int min_ret=0;
int x[MAX_CLIPBOX],y[MAX_CLIPBOX];
int xvect,yvect;
int xs,ys;
for (i = 0; i < sop->clipbox_num; i++)
{
// move the box to position instead of using offset- this prevents small rounding errors
// allowing you to move through wall
ang = NORM_ANGLE(pp->pang + sop->clipbox_ang[i]);
xs = pp->posx;
ys = pp->posy;
xvect = (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)]);
yvect = (sop->clipbox_vdist[i] * sintable[ang]);
clipmoveboxtracenum = 1;
ret_start = clipmove_old(&xs, &ys, &z, &pp->cursectnum, xvect, yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
clipmoveboxtracenum = 3;
if (ret_start)
{
// hit something moving into start position
min_dist = 0;
min_ndx = i;
// ox is where it should be
ox[i] = x[i] = pp->posx + (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)] >> 14);
oy[i] = y[i] = pp->posy + (sop->clipbox_vdist[i] * sintable[ang] >> 14);
// xs is where it hit
x[i] = xs;
y[i] = ys;
// see the dist moved
dist = ksqrt(SQ(x[i] - ox[i]) + SQ(y[i] - oy[i]));
// save it off
if (dist < min_dist)
{
min_dist = dist;
min_ndx = i;
min_ret = ret_start;
}
}
else
{
// save off the start position
ox[i] = x[i] = xs;
oy[i] = y[i] = ys;
// move the box
ret = clipmove_old(&x[i], &y[i], &z, &pp->cursectnum, pp->xvect, pp->yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
// save the dist moved
dist = ksqrt(SQ(x[i] - ox[i]) + SQ(y[i] - oy[i]));
if (ret)
{
}
if (dist < min_dist)
{
min_dist = dist;
min_ndx = i;
min_ret = ret;
}
}
}
// put posx and y off from offset
pp->posx += x[min_ndx] - ox[min_ndx];
pp->posy += y[min_ndx] - oy[min_ndx];
return min_ret;
}
short MultiClipTurn(PLAYERp pp, short new_ang, int z, int floor_dist)
{
int i;
SECTOR_OBJECTp sop = pp->sop;
int ret;
int x,y;
short ang;
int xvect, yvect;
short cursectnum = pp->cursectnum;
for (i = 0; i < sop->clipbox_num; i++)
{
ang = NORM_ANGLE(new_ang + sop->clipbox_ang[i]);
x = pp->posx;
y = pp->posy;
xvect = (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)]);
yvect = (sop->clipbox_vdist[i] * sintable[ang]);
// move the box
ret = clipmove_old(&x, &y, &z, &cursectnum, xvect, yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
ASSERT(cursectnum >= 0);
if (ret)
{
// attempt to move a bit when turning against a wall
//ang = NORM_ANGLE(ang + 1024);
//pp->xvect += 20 * sintable[NORM_ANGLE(ang + 512)];
//pp->yvect += 20 * sintable[ang];
return FALSE;
}
}
return TRUE;
}
int testquadinsect(int *point_num, vec2_t const * q, short sectnum)
{
int i,next_i;
*point_num = -1;
for (i=0; i < 4; i++)
{
if (!inside(q[i].x, q[i].y, sectnum))
{
////DSPRINTF(ds,"inside %ld failed",i);
//MONO_PRINT(ds);
*point_num = i;
return FALSE;
}
}
for (i=0; i<4; i++)
{
next_i = MOD4(i+1);
if (!cansee(q[i].x, q[i].y,0x3fffffff, sectnum,
q[next_i].x, q[next_i].y,0x3fffffff, sectnum))
{
DSPRINTF(ds,"cansee %ld failed, x1 %d, y1 %d, x2 %d, y2 %d, sectnum %d",i, q[i].x, q[i].y, q[next_i].x, q[next_i].y, sectnum);
MONO_PRINT(ds);
return FALSE;
}
}
return TRUE;
}
//Ken gives the tank clippin' a try...
int RectClipMove(PLAYERp pp, int *qx, int *qy)
{
int i;
vec2_t xy[4];
int point_num;
for (i = 0; i < 4; i++)
{
xy[i].x = qx[i] + (pp->xvect>>14);
xy[i].y = qy[i] + (pp->yvect>>14);
}
//Given the 4 points: x[4], y[4]
if (testquadinsect(&point_num, xy, pp->cursectnum))
{
pp->posx += (pp->xvect>>14);
pp->posy += (pp->yvect>>14);
return TRUE;
}
if (point_num < 0)
return FALSE;
if ((point_num == 0) || (point_num == 3)) //Left side bad - strafe right
{
for (i = 0; i < 4; i++)
{
xy[i].x = qx[i] - (pp->yvect>>15);
xy[i].y = qy[i] + (pp->xvect>>15);
}
if (testquadinsect(&point_num, xy, pp->cursectnum))
{
pp->posx -= (pp->yvect>>15);
pp->posy += (pp->xvect>>15);
}
return FALSE;
}
if ((point_num == 1) || (point_num == 2)) //Right side bad - strafe left
{
for (i = 0; i < 4; i++)
{
xy[i].x = qx[i] + (pp->yvect>>15);
xy[i].y = qy[i] - (pp->xvect>>15);
}
if (testquadinsect(&point_num, xy, pp->cursectnum))
{
pp->posx += (pp->yvect>>15);
pp->posy -= (pp->xvect>>15);
}
return FALSE;
}
return FALSE;
}
int testpointinquad(int x, int y, int *qx, int *qy)
{
int i, cnt, x1, y1, x2, y2;
cnt = 0;
for (i=0; i<4; i++)
{
y1 = qy[i]-y;
y2 = qy[(i+1)&3]-y;
if ((y1^y2) >= 0) continue;
x1 = qx[i]-x;
x2 = qx[(i+1)&3]-x;
if ((x1^x2) >= 0)
cnt ^= x1;
else
cnt ^= (x1*y2-x2*y1)^y2;
}
return cnt>>31;
}
short RectClipTurn(PLAYERp pp, short new_ang, int *qx, int *qy, int *ox, int *oy)
{
int i;
vec2_t xy[4];
SECTOR_OBJECTp sop = pp->sop;
short rot_ang;
int point_num;
rot_ang = NORM_ANGLE(new_ang + sop->spin_ang - sop->ang_orig);
for (i = 0; i < 4; i++)
{
vec2_t const p = { ox[i], oy[i] };
rotatepoint(*(vec2_t *)&pp->posx, p, rot_ang, &xy[i]);
// cannot use sop->xmid and ymid because the SO is off the map at this point
//rotatepoint(*(vec2_t *)&sop->xmid, p, rot_ang, &xy[i]);
}
//Given the 4 points: x[4], y[4]
if (testquadinsect(&point_num, xy, pp->cursectnum))
{
// move to new pos
for (i = 0; i < 4; i++)
{
qx[i] = xy[i].x;
qy[i] = xy[i].y;
}
return TRUE;
}
if (point_num < 0)
return FALSE;
return FALSE;
}
END_SW_NS