Code: Select all
struct SegHitBox play //functions to check if a line segment intersects a hitbox
{
//returned boolean tells if there was an intersection
//when calcHits is false the returned vectors are undefined
//when calcHits is true the returned vectors are the 2 intersection points
//if there was only 1 intersection, the returned vectors will be equal
//if there were 0 intersections, the returned vectors will be undefined
static
bool, vector3, vector3 CheckIfLineSegHitsActor(vector3 LineStart, vector3 LineStop, actor CheckTarget, bool calcHits = false)
{
return CheckIfLineSegHitsBox
(
LineStart, LineStop,
(CheckTarget.pos.x - CheckTarget.radius, CheckTarget.pos.y - CheckTarget.radius, CheckTarget.pos.z),
(CheckTarget.pos.x + CheckTarget.radius, CheckTarget.pos.y + CheckTarget.radius, CheckTarget.pos.z + CheckTarget.height),
calcHits
);
}
static
bool, vector3, vector3 CheckIfLineSegHitsBox(vector3 LineStart, vector3 LineStop, vector3 corner1, vector3 corner2, bool calcHits = false)
{
//note the orientation: front,left,back,right are the planes at 270,180,90,0 degrees in xy
double aLeft = min(corner1.x, corner2.x);
double aRight = max(corner1.x, corner2.x);
double aFront = min(corner1.y, corner2.y);
double aBack = max(corner1.y, corner2.y);
double aBottom = min(corner1.z, corner2.z);
double aTop = max(corner1.z, corner2.z);
//check for easy misses
if (LineStart.x < aLeft && LineStop.x < aLeft) return false;
if (LineStart.x > aRight && LineStop.x > aRight) return false;
if (LineStart.y < aFront && LineStop.y < aFront) return false;
if (LineStart.y > aBack && LineStop.y > aBack) return false;
if (LineStart.z < aBottom && LineStop.z < aBottom) return false;
if (LineStart.z > aTop && LineStop.z > aTop) return false;
vector3 LineDirection = LineStop - LineStart;
bool didHit1, didHit2;
vector3 Hit1, Hit2;
//check left
if (LineDirection.x != 0)
{
double t = (aLeft - LineStart.x) / LineDirection.x;
if (0 <= t && t <= 1)
{
double y = LineStart.y + LineDirection.y * t;
double z = LineStart.z + LineDirection.z * t;
if (aFront <= y && y <= aBack && aBottom <= z && z <= aTop)
{
if (!calcHits) return true;
if (!didHit1)
{
Hit1=(aLeft, y, z);
didHit1=true;
}
else
{
Hit2=(aLeft, y, z);
didHit2=true;
}
}
}
}
//check right
if (LineDirection.x != 0)
{
double t = (aRight - LineStart.x) / LineDirection.x;
if (0 <= t && t <= 1)
{
double y = LineStart.y + LineDirection.y * t;
double z = LineStart.z + LineDirection.z * t;
if (aFront <= y && y <= aBack && aBottom <= z && z <= aTop)
{
if (!calcHits) return true;
if (!didHit1)
{
Hit1=(aRight, y, z);
didHit1=true;
}
else
{
Hit2=(aRight, y, z);
didHit2=true;
}
}
}
}
//check front
if (LineDirection.y != 0)
{
double t = (aFront - LineStart.y) / LineDirection.y;
if (0 <= t && t <= 1)
{
double x = LineStart.x + LineDirection.x * t;
double z = LineStart.z + LineDirection.z * t;
if (aLeft <= x && x <= aRight && aBottom <= z && z <= aTop)
{
if (!calcHits) return true;
if (!didHit1)
{
Hit1=(x, aFront, z);
didHit1=true;
}
else
{
Hit2=(x, aFront, z);
didHit2=true;
}
}
}
}
//check back
if (LineDirection.y != 0)
{
double t = (aBack - LineStart.y) / LineDirection.y;
if (0 <= t && t <= 1)
{
double x = LineStart.x + LineDirection.x * t;
double z = LineStart.z + LineDirection.z * t;
if (aLeft <= x && x <= aRight && aBottom <= z && z <= aTop)
{
if (!calcHits) return true;
if (!didHit1)
{
Hit1=(x, aBack, z);
didHit1=true;
}
else
{
Hit2=(x, aBack, z);
didHit2=true;
}
}
}
}
//check bottom
if (LineDirection.z != 0)
{
double t = (aBottom - LineStart.z) / LineDirection.z;
if (0 <= t && t <= 1)
{
double x = LineStart.x + LineDirection.x * t;
double y = LineStart.y + LineDirection.y * t;
if (aLeft <= x && x <= aRight && aFront <= y && y <= aBack)
{
if (!calcHits) return true;
if (!didHit1)
{
Hit1=(x, y, aBottom);
didHit1=true;
}
else
{
Hit2=(x, y, aBottom);
didHit2=true;
}
}
}
}
//check top
if (LineDirection.z != 0)
{
double t = (aTop - LineStart.z) / LineDirection.z;
if (0 <= t && t <= 1)
{
double x = LineStart.x + LineDirection.x * t;
double y = LineStart.y + LineDirection.y * t;
if (aLeft <= x && x <= aRight && aFront <= y && y <= aBack)
{
if (!calcHits) return true;
if (!didHit1)
{
Hit1=(x, y, aTop);
didHit1=true;
}
else
{
Hit2=(x, y, aTop);
didHit2=true;
}
}
}
}
if (didHit1 && !didHit2) hit2 = hit1;
return didHit1, hit1, hit2;
}
static
bool CheckIfPlayerIsAimingAtHitbox(actor Observer, actor CheckTarget, double range)
{
if (!Observer || !Observer.player) return false;
vector3 oldVel = Observer.vel; //gotta use vel for some trickery. If there's a proper Vec3DFromAngle then I don't know about it
Observer.Vel3DFromAngle(range, Observer.angle, Observer.pitch);
vector3 useOffset = Observer.vel;
Observer.vel = oldVel; //restore the proper vel
vector3 linestop = Observer.vec3Offset(useOffset.x, useOffset.y, useOffset.z + Observer.player.viewheight); //portal-aware
vector3 linestart = linestop - useOffset; //get a line seg that does NOT cross a portal
return CheckIfLineSegHitsActor(linestart,linestop,CheckTarget);
}
static
bool CheckIfPlayerIsUsingAtHitbox(actor Observer, actor CheckTarget)
{
if (!Observer || !Observer.player || !Observer.player.mo) return false;
return CheckIfPlayerIsAimingAtHitbox(Observer, CheckTarget, Observer.player.mo.userange);
}
}