diff --git a/src/Makefile b/src/Makefile index f5d58af3..3e0ab2f7 100644 --- a/src/Makefile +++ b/src/Makefile @@ -432,6 +432,7 @@ OBJS:=$(i_main_o) \ $(OBJDIR)/m_misc.o \ $(OBJDIR)/m_random.o \ $(OBJDIR)/m_queue.o \ + $(OBJDIR)/m_vector.o \ $(OBJDIR)/info.o \ $(OBJDIR)/p_ceilng.o \ $(OBJDIR)/p_enemy.o \ @@ -450,6 +451,7 @@ OBJS:=$(i_main_o) \ $(OBJDIR)/p_telept.o \ $(OBJDIR)/p_tick.o \ $(OBJDIR)/p_user.o \ + $(OBJDIR)/p_slopes.o \ $(OBJDIR)/tables.o \ $(OBJDIR)/r_bsp.o \ $(OBJDIR)/r_data.o \ diff --git a/src/doomdef.h b/src/doomdef.h index c4896a76..924d0968 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -436,6 +436,14 @@ extern const char *compdate, *comptime, *comprevision; /// Fun experimental slope stuff! //#define SLOPENESS +/// Kalaron/Eternity Engine slope code (SRB2CB ported) +/// Depends on NEED_FIXED_VECTORS? for a few functions. +/// However, uses own vector types for math. +#define ESLOPE + +/// Fixed and float point types +//#define NEED_FIXED_VECTOR + /// Delete file while the game is running. /// \note EXTREMELY buggy, tends to crash game. //#define DELFILE diff --git a/src/m_fixed.h b/src/m_fixed.h index e68de030..8bf16020 100644 --- a/src/m_fixed.h +++ b/src/m_fixed.h @@ -357,6 +357,29 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedRound(fixed_t x) return INT32_MAX; } +/*! + \brief convert a fixed_t number into double floating number + */ +#define FIXED_TO_DOUBLE(f) ((double)((f) / FRACUNIT)) + +/*! + \brief convert a double floating number into fixed_t number + */ +#define DOUBLE_TO_FIXED(f) ((fixed_t)((f) * FRACUNIT)) + +/*! + \brief convert a integer into fixed_t number + */ +#define INT_TO_FIXED(x) ((int)((x) * FRACUNIT)) + +/*! + \brief convert a fixed_t number into integer + */ +#define FIXED_TO_INT(x) (((int)(x)) / (FRACUNIT)) + +static inline int DivScale32 (fixed_t a, fixed_t b) { return (fixed_t)(((INT64)a << 32) / b); } + + #ifdef NEED_FIXED_VECTOR typedef struct diff --git a/src/m_vector.c b/src/m_vector.c new file mode 100644 index 00000000..af518985 --- /dev/null +++ b/src/m_vector.c @@ -0,0 +1,1160 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2004 Stephen McGranahan +// +// This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//-------------------------------------------------------------------------- +// +// DESCRIPTION: +// Vectors +// SoM created 05/18/09 +// +//----------------------------------------------------------------------------- + +#include "doomdef.h" +#include "m_vector.h" +#include "r_main.h" +#include "m_fixed.h" +#include "m_misc.h" +#include "tables.h" + +#ifdef ESLOPE + +v3fixed_t *M_LoadVec(v3fixed_t *vec, fixed_t x, fixed_t y, fixed_t z) +{ + vec->x = x; + vec->y = y; + vec->z = z; + return vec; +} + +v3fixed_t *M_CopyVec(v3fixed_t *a_o, const v3fixed_t *a_i) +{ + return M_Memcpy(a_o, a_i, sizeof(v3fixed_t)); +} + +v3float_t *M_LoadVecf(v3float_t *vec, float x, float y, float z) +{ + vec->x = x; + vec->y = y; + vec->z = z; + return vec; +} + +v3float_t *M_CopyVecf(v3float_t *a_o, const v3float_t *a_i) +{ + return M_Memcpy(a_o, a_i, sizeof(v3float_t)); +} + +// +// M_MakeVec3 +// +// Given two points, create a vector between them. +// +v3fixed_t *M_MakeVec3(const v3fixed_t *point1, const v3fixed_t *point2, v3fixed_t *a_o) +{ + a_o->x = point1->x - point2->x; + a_o->y = point1->y - point2->y; + a_o->z = point1->z - point2->z; + return a_o; +} + + +// +// M_MakeVec3f +// +// Given two points, create a vector between them. +// +v3float_t *M_MakeVec3f(const v3float_t *point1, const v3float_t *point2, v3float_t *a_o) +{ + a_o->x = point1->x - point2->x; + a_o->y = point1->y - point2->y; + a_o->z = point1->z - point2->z; + return a_o; +} + +// +// M_TranslateVec3 +// +// Translates the given vector (in the game's coordinate system) to the camera +// space (in right-handed coordinate system) This function is used for slopes. +// +void M_TranslateVec3(v3fixed_t *vec) +{ + fixed_t tx, ty, tz; + + tx = vec->x - viewx; + ty = viewz - vec->y; + tz = vec->z - viewy; + + // Just like wall projection. + vec->x = (tx * viewcos) - (tz * viewsin); + vec->z = (tz * viewcos) + (tx * viewsin); + vec->y = ty; +} + +// +// M_TranslateVec3f +// +// Translates the given vector (in the game's coordinate system) to the camera +// space (in right-handed coordinate system) This function is used for slopes. +// +void M_TranslateVec3f(v3float_t *vec) +{ + float tx, ty, tz; + + tx = vec->x - viewx; // SRB2CBTODO: This may need float viewxyz + ty = viewz - vec->y; + tz = vec->z - viewy; + + // Just like wall projection. + vec->x = (tx * viewcos) - (tz * viewsin); + vec->z = (tz * viewcos) + (tx * viewsin); + vec->y = ty; +} + +#ifdef SESLOPE +// +// M_TranslateVec3d +// +// Translates the given vector (in the game's coordinate system) to the camera +// space (in right-handed coordinate system) This function is used for slopes. +// +void M_TranslateVec3d(v3double_t *vec) +{ + double tx, ty, tz; + + tx = vec->x - viewx; // SRB2CBTODO: This may need float viewxyz + ty = viewz - vec->y; + tz = vec->z - viewy; + + // Just like wall projection. + vec->x = (tx * viewcos) - (tz * viewsin); + vec->z = (tz * viewcos) + (tx * viewsin); + vec->y = ty; +} +#endif + +// +// M_AddVec3 +// +// Adds v2 to v1 stores in dest +// +void M_AddVec3(v3fixed_t *dest, const v3fixed_t *v1, const v3fixed_t *v2) +{ + dest->x = v1->x + v2->x; + dest->y = v1->y + v2->y; + dest->z = v1->z + v2->z; +} + +// +// M_AddVec3f +// +// Adds v2 to v1 stores in dest +// +void M_AddVec3f(v3float_t *dest, const v3float_t *v1, const v3float_t *v2) +{ + dest->x = v1->x + v2->x; + dest->y = v1->y + v2->y; + dest->z = v1->z + v2->z; +} + +// +// M_SubVec3 +// +// Adds v2 to v1 stores in dest +// +void M_SubVec3(v3fixed_t *dest, const v3fixed_t *v1, const v3fixed_t *v2) // SRB2CBTODO: Make a function that allows the destxyz to equal the change of 2 args +{ + dest->x = v1->x - v2->x; + dest->y = v1->y - v2->y; + dest->z = v1->z - v2->z; +} + +// +// M_SubVec3f +// +// Subtracts v2 from v1 stores in dest +// +void M_SubVec3f(v3float_t *dest, const v3float_t *v1, const v3float_t *v2) +{ + dest->x = v1->x - v2->x; + dest->y = v1->y - v2->y; + dest->z = v1->z - v2->z; +} + +// +// M_DotVec3 +// +// Returns the dot product of v1 and v2 +// +fixed_t M_DotVec3(const v3fixed_t *v1, const v3fixed_t *v2) +{ + return FixedMul(v1->x, v2->x) + FixedMul(v1->y, v2->y) + FixedMul(v1->z, v2->z); +} + +// +// M_DotVec3f +// +// Returns the dot product of v1 and v2 +// +float M_DotVec3f(const v3float_t *v1, const v3float_t *v2) +{ + if (!v1 || !v2) + I_Error("M_DotVec3f: No vertexes!"); + if (!(v1 || v2 || v1->x || v1->y || v1->z || v2->x || v2->y || v2->z)) + I_Error("M_DotVec3f: No vertexes!"); + return (v1->x * v2->x) + (v1->y * v2->y) + (v1->z * v2->z); +} + +#ifdef SESLOPE +// +// M_DotVec3d +// +// Returns the dot product of v1 and v2 +// +double M_DotVec3d(const v3double_t *v1, const v3double_t *v2) +{ + return (v1->x * v2->x) + (v1->y * v2->y) + (v1->z * v2->z); +} +#endif + +// +// M_CrossProduct3 +// +// Gets the cross product of v1 and v2 and stores in dest +// +void M_CrossProduct3(v3fixed_t *dest, const v3fixed_t *v1, const v3fixed_t *v2) +{ + v3fixed_t tmp; + tmp.x = (v1->y * v2->z) - (v1->z * v2->y); + tmp.y = (v1->z * v2->x) - (v1->x * v2->z); + tmp.z = (v1->x * v2->y) - (v1->y * v2->x); + memcpy(dest, &tmp, sizeof(v3fixed_t)); +} + +// +// M_CrossProduct3f +// +// Gets the cross product of v1 and v2 and stores in dest +// +void M_CrossProduct3f(v3float_t *dest, const v3float_t *v1, const v3float_t *v2) +{ + v3float_t tmp; + tmp.x = (v1->y * v2->z) - (v1->z * v2->y); + tmp.y = (v1->z * v2->x) - (v1->x * v2->z); + tmp.z = (v1->x * v2->y) - (v1->y * v2->x); + memcpy(dest, &tmp, sizeof(v3float_t)); +} + +fixed_t FV_Magnitude(const v3fixed_t *a_normal) +{ + fixed_t xs = FixedMul(a_normal->x,a_normal->x); + fixed_t ys = FixedMul(a_normal->y,a_normal->y); + fixed_t zs = FixedMul(a_normal->z,a_normal->z); + return FixedSqrt(xs+ys+zs); +} + +float FV_Magnitudef(const v3float_t *a_normal) +{ + float xs = (a_normal->x * a_normal->x); + float ys = (a_normal->y * a_normal->y); + float zs = (a_normal->z * a_normal->z); + return (float)sqrt(xs+ys+zs); +} + +// Vector Complex Math +v3fixed_t *FV_Midpoint(const v3fixed_t *a_1, const v3fixed_t *a_2, v3fixed_t *a_o) +{ + a_o->x = FixedDiv(a_2->x - a_1->x, 2*FRACUNIT); + a_o->y = FixedDiv(a_2->y - a_1->y, 2*FRACUNIT); + a_o->z = FixedDiv(a_2->z - a_1->z, 2*FRACUNIT); + a_o->x = a_1->x + a_o->x; + a_o->y = a_1->y + a_o->y; + a_o->z = a_1->z + a_o->z; + return a_o; +} + +fixed_t FV_Distance(const v3fixed_t *p1, const v3fixed_t *p2) +{ + fixed_t xs = FixedMul(p2->x-p1->x,p2->x-p1->x); + fixed_t ys = FixedMul(p2->y-p1->y,p2->y-p1->y); + fixed_t zs = FixedMul(p2->z-p1->z,p2->z-p1->z); + return FixedSqrt(xs+ys+zs); +} + +v3float_t *FV_Midpointf(const v3float_t *a_1, const v3float_t *a_2, v3float_t *a_o) +{ + a_o->x = (a_2->x - a_1->x / 2.0f); + a_o->y = (a_2->y - a_1->y / 2.0f); + a_o->z = (a_2->z - a_1->z / 2.0f); + a_o->x = a_1->x + a_o->x; + a_o->y = a_1->y + a_o->y; + a_o->z = a_1->z + a_o->z; + return a_o; +} + + + +// +// AngleBetweenVectors +// +// This checks to see if a point is inside the ranges of a polygon +// +angle_t FV_AngleBetweenVectors(const v3fixed_t *Vector1, const v3fixed_t *Vector2) +{ + // Remember, above we said that the Dot Product of returns the cosine of the angle + // between 2 vectors? Well, that is assuming they are unit vectors (normalize vectors). + // So, if we don't have a unit vector, then instead of just saying arcCos(DotProduct(A, B)) + // We need to divide the dot product by the magnitude of the 2 vectors multiplied by each other. + // Here is the equation: arc cosine of (V . W / || V || * || W || ) + // the || V || means the magnitude of V. This then cancels out the magnitudes dot product magnitudes. + // But basically, if you have normalize vectors already, you can forget about the magnitude part. + + // Get the dot product of the vectors + fixed_t dotProduct = M_DotVec3(Vector1, Vector2); + + // Get the product of both of the vectors magnitudes + fixed_t vectorsMagnitude = FixedMul(FV_Magnitude(Vector1), FV_Magnitude(Vector2)); + + // Return the arc cosine of the (dotProduct / vectorsMagnitude) which is the angle in RADIANS. + return FixedAcos(FixedDiv(dotProduct, vectorsMagnitude)); +} + +float FV_AngleBetweenVectorsf(const v3float_t *Vector1, const v3float_t *Vector2) +{ + // Remember, above we said that the Dot Product of returns the cosine of the angle + // between 2 vectors? Well, that is assuming they are unit vectors (normalize vectors). + // So, if we don't have a unit vector, then instead of just saying arcCos(DotProduct(A, B)) + // We need to divide the dot product by the magnitude of the 2 vectors multiplied by each other. + // Here is the equation: arc cosine of (V . W / || V || * || W || ) + // the || V || means the magnitude of V. This then cancels out the magnitudes dot product magnitudes. + // But basically, if you have normalize vectors already, you can forget about the magnitude part. + + // Get the dot product of the vectors + float dotProduct = M_DotVec3f(Vector1, Vector2); + + // Get the product of both of the vectors magnitudes + float vectorsMagnitude = FV_Magnitudef(Vector1)*FV_Magnitudef(Vector2); + + // Return the arc cosine of the (dotProduct / vectorsMagnitude) which is the angle in RADIANS. + return acos(dotProduct/vectorsMagnitude); +} + + + +// Crazy physics code + +float M_VectorYaw(v3float_t v) +{ + return atan2(v.x, v.z); +} +float M_VectorPitch(v3float_t v) +{ + return -atan2(v.y, sqrt(v.x*v.x+v.z*v.z)); +} + +#include "z_zone.h" + +// Returns pitch roll and yaw values, allows objects to align to a slope +angles3d_t *M_VectorAlignTo(float Pitch, float Yaw, float Roll, v3float_t v, byte AngleAxis, float Rate) +{ + CONS_Printf("P %f\n", Pitch); + CONS_Printf("R %f\n", Roll); + CONS_Printf("Y %f\n", Yaw); + if (AngleAxis == 1) + { + float DestYaw = (atan2(v.z,v.x)* 180 / M_PI); + float DestRoll = (atan2(v.y,v.x)* 180 / M_PI); + + Yaw = Yaw+(DestYaw-Yaw)*Rate; + Roll = Roll+(DestRoll-Roll)*Rate; + } + else if (AngleAxis == 2) + { + float DestPitch = (atan2(v.z,v.y)* 180 / M_PI); + float DestRoll = (-atan2(v.x,v.y)* 180 / M_PI); + + Pitch = Pitch+(DestPitch-Pitch)*Rate; + Roll = Roll+(DestRoll-Roll)*Rate; + } + else if (AngleAxis == 3) + { + float DestPitch = (-atan2(v.y,v.z)* 180 / M_PI); + float DestYaw = (-atan2(v.x,v.z)* 180 / M_PI); + + Pitch = Pitch+(DestPitch-Pitch)*Rate; + Yaw = Yaw+(DestYaw-Yaw)*Rate; + } + + angles3d_t *returnangles = Z_Malloc(sizeof(angles3d_t), PU_LEVEL, NULL); + memset(returnangles, 0, sizeof(*returnangles)); + returnangles->yaw = Yaw; + returnangles->pitch = Pitch; + returnangles->roll = Roll; + + return returnangles; + +} + + + + + +#if 0 // Backport +v3fixed_t *FV_SubO(const v3fixed_t *a_i, const v3fixed_t *a_c, v3fixed_t *a_o) +{ + a_o->x = a_i->x - a_c->x; + a_o->y = a_i->y - a_c->y; + a_o->z = a_i->z - a_c->z; + return a_o; +} + +boolean FV_Equal(const v3fixed_t *a_1, const v3fixed_t *a_2) +{ + fixed_t Epsilon = FRACUNIT/FRACUNIT; + + if ((abs(a_2->x - a_1->x) > Epsilon) || + (abs(a_2->y - a_1->y) > Epsilon) || + (abs(a_2->z - a_1->z) > Epsilon)) + { + return true; + } + + return false; +} + +boolean FV_Equalf(const v3float_t *a_1, const v3float_t *a_2) +{ + float Epsilon = 1.0f/1.0f; + + if ((abs(a_2->x - a_1->x) > Epsilon) || + (abs(a_2->y - a_1->y) > Epsilon) || + (abs(a_2->z - a_1->z) > Epsilon)) + { + return true; + } + + return false; +} + +// +// Normal +// +// Calculates the normal of a polygon. +// +void FV_Normal (const v3fixed_t *a_triangle, v3fixed_t *a_normal) +{ + v3fixed_t a_1; + v3fixed_t a_2; + + FV_Point2Vec(&a_triangle[2], &a_triangle[0], &a_1); + FV_Point2Vec(&a_triangle[1], &a_triangle[0], &a_2); + + FV_Cross(&a_1, &a_2, a_normal); + + FV_NormalizeO(a_normal, a_normal); +} + +// +// PlaneDistance +// +// Calculates distance between a plane and the origin. +// +fixed_t FV_PlaneDistance(const v3fixed_t *a_normal, const v3fixed_t *a_point) +{ + return -(FixedMul(a_normal->x, a_point->x) + FixedMul(a_normal->y, a_point->y) + FixedMul(a_normal->z, a_point->z)); +} + +boolean FV_IntersectedPlane(const v3fixed_t *a_triangle, const v3fixed_t *a_line, v3fixed_t *a_normal, fixed_t *originDistance) +{ + fixed_t distance1 = 0, distance2 = 0; + + FV_Normal(a_triangle, a_normal); + + *originDistance = FV_PlaneDistance(a_normal, &a_triangle[0]); + + distance1 = (FixedMul(a_normal->x, a_line[0].x) + FixedMul(a_normal->y, a_line[0].y) + + FixedMul(a_normal->z, a_line[0].z)) + *originDistance; + + distance2 = (FixedMul(a_normal->x, a_line[1].x) + FixedMul(a_normal->y, a_line[1].y) + + FixedMul(a_normal->z, a_line[1].z)) + *originDistance; + + // Positive or zero number means no intersection + if (FixedMul(distance1, distance2) >= 0) + return false; + + return true; +} + +// +// PlaneIntersection +// +// Returns the distance from +// rOrigin to where the ray +// intersects the plane. Assumes +// you already know it intersects +// the plane. +// +fixed_t FV_PlaneIntersection(const v3fixed_t *pOrigin, const v3fixed_t *pNormal, const v3fixed_t *rOrigin, const v3fixed_t *rVector) +{ + fixed_t d = -(FV_Dot(pNormal, pOrigin)); + fixed_t number = FV_Dot(pNormal,rOrigin) + d; + fixed_t denom = FV_Dot(pNormal,rVector); + return -FixedDiv(number, denom); +} + +// +// IntersectRaySphere +// Input : rO - origin of ray in world space +// rV - vector describing direction of ray in world space +// sO - Origin of sphere +// sR - radius of sphere +// Notes : Normalized directional vectors expected +// Return: distance to sphere in world units, -1 if no intersection. +// +fixed_t FV_IntersectRaySphere(const v3fixed_t *rO, const v3fixed_t *rV, const v3fixed_t *sO, fixed_t sR) +{ + v3fixed_t Q; + fixed_t c, v, d; + FV_SubO(sO, rO, &Q); + + c = FV_Magnitude(&Q); + v = FV_Dot(&Q, rV); + d = FixedMul(sR, sR) - (FixedMul(c,c) - FixedMul(v,v)); + + // If there was no intersection, return -1 + if (d < 0*FRACUNIT) + return (-1*FRACUNIT); + + // Return the distance to the [first] intersecting point + return (v - FixedSqrt(d)); +} + +// +// IntersectionPoint +// +// This returns the intersection point of the line that intersects the plane +// +v3fixed_t *FV_IntersectionPoint(const v3fixed_t *vNormal, const v3fixed_t *vLine, fixed_t distance, v3fixed_t *ReturnVec) +{ + v3fixed_t vLineDir; // Variables to hold the point and the line's direction + fixed_t Numerator = 0, Denominator = 0, dist = 0; + + // Here comes the confusing part. We need to find the 3D point that is actually + // on the plane. Here are some steps to do that: + + // 1) First we need to get the vector of our line, Then normalize it so it's a length of 1 + FV_Point2Vec(&vLine[1], &vLine[0], &vLineDir); // Get the Vector of the line + FV_NormalizeO(&vLineDir, &vLineDir); // Normalize the lines vector + + + // 2) Use the plane equation (distance = Ax + By + Cz + D) to find the distance from one of our points to the plane. + // Here I just chose a arbitrary point as the point to find that distance. You notice we negate that + // distance. We negate the distance because we want to eventually go BACKWARDS from our point to the plane. + // By doing this is will basically bring us back to the plane to find our intersection point. + Numerator = - (FixedMul(vNormal->x, vLine[0].x) + // Use the plane equation with the normal and the line + FixedMul(vNormal->y, vLine[0].y) + + FixedMul(vNormal->z, vLine[0].z) + distance); + + // 3) If we take the dot product between our line vector and the normal of the polygon, + // this will give us the cosine of the angle between the 2 (since they are both normalized - length 1). + // We will then divide our Numerator by this value to find the offset towards the plane from our arbitrary point. + Denominator = FV_Dot(vNormal, &vLineDir); // Get the dot product of the line's vector and the normal of the plane + + // Since we are using division, we need to make sure we don't get a divide by zero error + // If we do get a 0, that means that there are INFINITE points because the the line is + // on the plane (the normal is perpendicular to the line - (Normal.Vector = 0)). + // In this case, we should just return any point on the line. + + if( Denominator == 0*FRACUNIT) // Check so we don't divide by zero + { + ReturnVec->x = vLine[0].x; + ReturnVec->y = vLine[0].y; + ReturnVec->z = vLine[0].z; + return ReturnVec; // Return an arbitrary point on the line + } + + // We divide the (distance from the point to the plane) by (the dot product) + // to get the distance (dist) that we need to move from our arbitrary point. We need + // to then times this distance (dist) by our line's vector (direction). When you times + // a scalar (single number) by a vector you move along that vector. That is what we are + // doing. We are moving from our arbitrary point we chose from the line BACK to the plane + // along the lines vector. It seems logical to just get the numerator, which is the distance + // from the point to the line, and then just move back that much along the line's vector. + // Well, the distance from the plane means the SHORTEST distance. What about in the case that + // the line is almost parallel with the polygon, but doesn't actually intersect it until half + // way down the line's length. The distance from the plane is short, but the distance from + // the actual intersection point is pretty long. If we divide the distance by the dot product + // of our line vector and the normal of the plane, we get the correct length. Cool huh? + + dist = FixedDiv(Numerator, Denominator); // Divide to get the multiplying (percentage) factor + + // Now, like we said above, we times the dist by the vector, then add our arbitrary point. + // This essentially moves the point along the vector to a certain distance. This now gives + // us the intersection point. Yay! + + // Return the intersection point + ReturnVec->x = vLine[0].x + FixedMul(vLineDir.x, dist); + ReturnVec->y = vLine[0].y + FixedMul(vLineDir.y, dist); + ReturnVec->z = vLine[0].z + FixedMul(vLineDir.z, dist); + return ReturnVec; +} + +// +// PointOnLineSide +// +// If on the front side of the line, returns 1. +// If on the back side of the line, returns 0. +// 2D only. +// +unsigned int FV_PointOnLineSide(const v3fixed_t *point, const v3fixed_t *line) +{ + fixed_t s1 = FixedMul((point->y - line[0].y),(line[1].x - line[0].x)); + fixed_t s2 = FixedMul((point->x - line[0].x),(line[1].y - line[0].y)); + return s1 - s2 < 0; +} + +// +// PointInsideBox +// +// Given four points of a box, +// determines if the supplied point is +// inside the box or not. +// +boolean FV_PointInsideBox(const v3fixed_t *point, const v3fixed_t *box) +{ + v3fixed_t lastLine[2]; + + FV_Load(&lastLine[0], box[3].x, box[3].y, box[3].z); + FV_Load(&lastLine[1], box[0].x, box[0].y, box[0].z); + + if (FV_PointOnLineSide(point, &box[0]) + || FV_PointOnLineSide(point, &box[1]) + || FV_PointOnLineSide(point, &box[2]) + || FV_PointOnLineSide(point, lastLine)) + return false; + + return true; +} +// +// LoadIdentity +// +// Loads the identity matrix into a matrix +// +void FM_LoadIdentity(fmatrix_t* matrix) +{ +#define M(row,col) matrix->m[col * 4 + row] + memset(matrix, 0x00, sizeof(fmatrix_t)); + + M(0, 0) = FRACUNIT; + M(1, 1) = FRACUNIT; + M(2, 2) = FRACUNIT; + M(3, 3) = FRACUNIT; +#undef M +} + +// +// CreateObjectMatrix +// +// Creates a matrix that can be used for +// adjusting the position of an object +// +void FM_CreateObjectMatrix(fmatrix_t *matrix, fixed_t x, fixed_t y, fixed_t z, fixed_t anglex, fixed_t angley, fixed_t anglez, fixed_t upx, fixed_t upy, fixed_t upz, fixed_t radius) +{ + v3fixed_t upcross; + v3fixed_t upvec; + v3fixed_t basevec; + + FV_Load(&upvec, upx, upy, upz); + FV_Load(&basevec, anglex, angley, anglez); + FV_Cross(&upvec, &basevec, &upcross); + FV_Normalize(&upcross); + + FM_LoadIdentity(matrix); + + matrix->m[0] = upcross.x; + matrix->m[1] = upcross.y; + matrix->m[2] = upcross.z; + matrix->m[3] = 0*FRACUNIT; + + matrix->m[4] = upx; + matrix->m[5] = upy; + matrix->m[6] = upz; + matrix->m[7] = 0; + + matrix->m[8] = anglex; + matrix->m[9] = angley; + matrix->m[10] = anglez; + matrix->m[11] = 0; + + matrix->m[12] = x - FixedMul(upx,radius); + matrix->m[13] = y - FixedMul(upy,radius); + matrix->m[14] = z - FixedMul(upz,radius); + matrix->m[15] = FRACUNIT; +} + +// +// MultMatrixVec +// +// Multiplies a vector by the specified matrix +// +void FM_MultMatrixVec(const fmatrix_t *matrix, const v3fixed_t *vec, v3fixed_t *out) +{ +#define M(row,col) matrix->m[col * 4 + row] + out->x = FixedMul(vec->x,M(0, 0)) + + FixedMul(vec->y,M(0, 1)) + + FixedMul(vec->z,M(0, 2)) + + M(0, 3); + + out->y = FixedMul(vec->x,M(1, 0)) + + FixedMul(vec->y,M(1, 1)) + + FixedMul(vec->z,M(1, 2)) + + M(1, 3); + + out->z = FixedMul(vec->x,M(2, 0)) + + FixedMul(vec->y,M(2, 1)) + + FixedMul(vec->z,M(2, 2)) + + M(2, 3); +#undef M +} + +// +// MultMatrix +// +// Multiples one matrix into another +// +void FM_MultMatrix(fmatrix_t *dest, const fmatrix_t *multme) +{ + fmatrix_t result; + unsigned int i, j; +#define M(row,col) multme->m[col * 4 + row] +#define D(row,col) dest->m[col * 4 + row] +#define R(row,col) result.m[col * 4 + row] + + for (i = 0; i < 4; i++) + { + for (j = 0; j < 4; j++) + R(i, j) = FixedMul(D(i, 0),M(0, j)) + FixedMul(D(i, 1),M(1, j)) + FixedMul(D(i, 2),M(2, j)) + FixedMul(D(i, 3),M(3, j)); + } + + M_Memcpy(dest, &result, sizeof(fmatrix_t)); + +#undef R +#undef D +#undef M +} + +// +// Translate +// +// Translates a matrix +// +void FM_Translate(fmatrix_t *dest, fixed_t x, fixed_t y, fixed_t z) +{ + fmatrix_t trans; +#define M(row,col) trans.m[col * 4 + row] + + memset(&trans, 0x00, sizeof(fmatrix_t)); + + M(0, 0) = M(1, 1) = M(2, 2) = M(3, 3) = FRACUNIT; + M(0, 3) = x; + M(1, 3) = y; + M(2, 3) = z; + + FM_MultMatrix(dest, &trans); +#undef M +} + +// +// Scale +// +// Scales a matrix +// +void FM_Scale(fmatrix_t *dest, fixed_t x, fixed_t y, fixed_t z) +{ + fmatrix_t scale; +#define M(row,col) scale.m[col * 4 + row] + + memset(&scale, 0x00, sizeof(fmatrix_t)); + + M(3, 3) = FRACUNIT; + M(0, 0) = x; + M(1, 1) = y; + M(2, 2) = z; + + FM_MultMatrix(dest, &scale); +#undef M +} + + +v3fixed_t *FV_Cross(const v3fixed_t *a_1, const v3fixed_t *a_2, v3fixed_t *a_o) +{ + a_o->x = FixedMul(a_1->y, a_2->z) - FixedMul(a_1->z, a_2->y); + a_o->y = FixedMul(a_1->z, a_2->x) - FixedMul(a_1->x, a_2->z); + a_o->z = FixedMul(a_1->x, a_2->y) - FixedMul(a_1->y, a_2->x); + return a_o; +} + +// +// ClosestPointOnLine +// +// Finds the point on a line closest +// to the specified point. +// +v3fixed_t *FV_ClosestPointOnLine(const v3fixed_t *Line, const v3fixed_t *p, v3fixed_t *out) +{ + // Determine t (the length of the vector from √´Line[0]√≠ to √´p√≠) + v3fixed_t c, V; + fixed_t t, d = 0; + FV_SubO(p, &Line[0], &c); + FV_SubO(&Line[1], &Line[0], &V); + FV_NormalizeO(&V, &V); + + d = FV_Distance(&Line[0], &Line[1]); + t = FV_Dot(&V, &c); + + // Check to see if √´t√≠ is beyond the extents of the line segment + if (t < 0) + { + return FV_Copy(out, &Line[0]); + } + if (t > d) + { + return FV_Copy(out, &Line[1]); + } + + // Return the point between √´Line[0]√≠ and √´Line[1]√≠ + FV_Mul(&V, t); + + return FV_AddO(&Line[0], &V, out); +} + +// +// ClosestPointOnTriangle +// +// Given a triangle and a point, +// the closest point on the edge of +// the triangle is returned. +// +void FV_ClosestPointOnTriangle (const v3fixed_t *tri, const v3fixed_t *point, v3fixed_t *result) +{ + unsigned int i; + fixed_t dist, closestdist; + v3fixed_t EdgePoints[3]; + v3fixed_t Line[2]; + + FV_Copy(&Line[0], (v3fixed_t*)&tri[0]); + FV_Copy(&Line[1], (v3fixed_t*)&tri[1]); + FV_ClosestPointOnLine(Line, point, &EdgePoints[0]); + + FV_Copy(&Line[0], (v3fixed_t*)&tri[1]); + FV_Copy(&Line[1], (v3fixed_t*)&tri[2]); + FV_ClosestPointOnLine(Line, point, &EdgePoints[1]); + + FV_Copy(&Line[0], (v3fixed_t*)&tri[2]); + FV_Copy(&Line[1], (v3fixed_t*)&tri[0]); + FV_ClosestPointOnLine(Line, point, &EdgePoints[2]); + + // Find the closest one of the three + FV_Copy(result, &EdgePoints[0]); + closestdist = FV_Distance(point, &EdgePoints[0]); + for (i = 1; i < 3; i++) + { + dist = FV_Distance(point, &EdgePoints[i]); + + if (dist < closestdist) + { + closestdist = dist; + FV_Copy(result, &EdgePoints[i]); + } + } + + // We now have the closest point! Whee! +} + +// +// InsidePolygon +// +// This checks to see if a point is inside the ranges of a polygon +// +boolean FV_InsidePolygon(const fvector_t *vIntersection, const fvector_t *Poly, const int vertexCount) +{ + int i; + UINT64 Angle = 0; // Initialize the angle + fvector_t vA, vB; // Create temp vectors + + // Just because we intersected the plane, doesn't mean we were anywhere near the polygon. + // This functions checks our intersection point to make sure it is inside of the polygon. + // This is another tough function to grasp at first, but let me try and explain. + // It's a brilliant method really, what it does is create triangles within the polygon + // from the intersection point. It then adds up the inner angle of each of those triangles. + // If the angles together add up to 360 degrees (or 2 * PI in radians) then we are inside! + // If the angle is under that value, we must be outside of polygon. To further + // understand why this works, take a pencil and draw a perfect triangle. Draw a dot in + // the middle of the triangle. Now, from that dot, draw a line to each of the vertices. + // Now, we have 3 triangles within that triangle right? Now, we know that if we add up + // all of the angles in a triangle we get 360 right? Well, that is kinda what we are doing, + // but the inverse of that. Say your triangle is an isosceles triangle, so add up the angles + // and you will get 360 degree angles. 90 + 90 + 90 is 360. + + for (i = 0; i < vertexCount; i++) // Go in a circle to each vertex and get the angle between + { + FV_Point2Vec(&Poly[i], vIntersection, &vA); // Subtract the intersection point from the current vertex + // Subtract the point from the next vertex + FV_Point2Vec(&Poly[(i + 1) % vertexCount], vIntersection, &vB); + + Angle += FV_AngleBetweenVectors(&vA, &vB); // Find the angle between the 2 vectors and add them all up as we go along + } + + // Now that we have the total angles added up, we need to check if they add up to 360 degrees. + // Since we are using the dot product, we are working in radians, so we check if the angles + // equals 2*PI. We defined PI in 3DMath.h. You will notice that we use a MATCH_FACTOR + // in conjunction with our desired degree. This is because of the inaccuracy when working + // with floating point numbers. It usually won't always be perfectly 2 * PI, so we need + // to use a little twiddling. I use .9999, but you can change this to fit your own desired accuracy. + + if(Angle >= ANGLE_MAX) // If the angle is greater than 2 PI, (360 degrees) + return 1; // The point is inside of the polygon + + return 0; // If you get here, it obviously wasn't inside the polygon. +} + +// +// IntersectedPolygon +// +// This checks if a line is intersecting a polygon +// +boolean FV_IntersectedPolygon(const fvector_t *vPoly, const fvector_t *vLine, const int vertexCount, fvector_t *collisionPoint) +{ + fvector_t vNormal, vIntersection; + fixed_t originDistance = 0*FRACUNIT; + + + // First we check to see if our line intersected the plane. If this isn't true + // there is no need to go on, so return false immediately. + // We pass in address of vNormal and originDistance so we only calculate it once + + if(!FV_IntersectedPlane(vPoly, vLine, &vNormal, &originDistance)) + return false; + + // Now that we have our normal and distance passed back from IntersectedPlane(), + // we can use it to calculate the intersection point. The intersection point + // is the point that actually is ON the plane. It is between the line. We need + // this point test next, if we are inside the polygon. To get the I-Point, we + // give our function the normal of the plane, the points of the line, and the originDistance. + + FV_IntersectionPoint(&vNormal, vLine, originDistance, &vIntersection); + + // Now that we have the intersection point, we need to test if it's inside the polygon. + // To do this, we pass in : + // (our intersection point, the polygon, and the number of vertices our polygon has) + + if(FV_InsidePolygon(&vIntersection, vPoly, vertexCount)) + { + if (collisionPoint != NULL) // Optional - load the collision point. + { + collisionPoint->x = vIntersection.x; + collisionPoint->y = vIntersection.y; + collisionPoint->z = vIntersection.z; + } + return true; // We collided! + } + + // If we get here, we must have NOT collided + return false; +} + +// +// RotateVector +// +// Rotates a vector around another vector +// +void FV_Rotate(fvector_t *rotVec, const fvector_t *axisVec, const angle_t angle) +{ + // Rotate the point (x,y,z) around the vector (u,v,w) + fixed_t ux = FixedMul(axisVec->x, rotVec->x); + fixed_t uy = FixedMul(axisVec->x, rotVec->y); + fixed_t uz = FixedMul(axisVec->x, rotVec->z); + fixed_t vx = FixedMul(axisVec->y, rotVec->x); + fixed_t vy = FixedMul(axisVec->y, rotVec->y); + fixed_t vz = FixedMul(axisVec->y, rotVec->z); + fixed_t wx = FixedMul(axisVec->z, rotVec->x); + fixed_t wy = FixedMul(axisVec->z, rotVec->y); + fixed_t wz = FixedMul(axisVec->z, rotVec->z); + fixed_t sa = FINESINE(angle); + fixed_t ca = FINECOSINE(angle); + fixed_t ua = ux+vy+wz; + fixed_t ax = FixedMul(axisVec->x,ua); + fixed_t ay = FixedMul(axisVec->y,ua); + fixed_t az = FixedMul(axisVec->z,ua); + fixed_t xs = FixedMul(axisVec->x,axisVec->x); + fixed_t ys = FixedMul(axisVec->y,axisVec->y); + fixed_t zs = FixedMul(axisVec->z,axisVec->z); + fixed_t bx = FixedMul(rotVec->x,ys+zs); + fixed_t by = FixedMul(rotVec->y,xs+zs); + fixed_t bz = FixedMul(rotVec->z,xs+ys); + fixed_t cx = FixedMul(axisVec->x,vy+wz); + fixed_t cy = FixedMul(axisVec->y,ux+wz); + fixed_t cz = FixedMul(axisVec->z,ux+vy); + fixed_t dx = FixedMul(bx-cx, ca); + fixed_t dy = FixedMul(by-cy, ca); + fixed_t dz = FixedMul(bz-cz, ca); + fixed_t ex = FixedMul(vz-wy, sa); + fixed_t ey = FixedMul(wx-uz, sa); + fixed_t ez = FixedMul(uy-vx, sa); + + rotVec->x = ax+dx+ex; + rotVec->y = ay+dy+ey; + rotVec->z = az+dz+ez; +} + +void FM_Rotate(fmatrix_t *dest, angle_t angle, fixed_t x, fixed_t y, fixed_t z) +{ +#define M(row,col) dest->m[row * 4 + col] + const fixed_t sinA = FINESINE(angle>>ANGLETOFINESHIFT); + const fixed_t cosA = FINECOSINE(angle>>ANGLETOFINESHIFT); + const fixed_t invCosA = FRACUNIT - cosA; + fvector_t nrm = {x, y, z}; + fixed_t xSq, ySq, zSq; + fixed_t sx, sy, sz; + fixed_t sxy, sxz, syz; + + FV_Normalize(&nrm); + + x = nrm.x; + y = nrm.y; + z = nrm.z; + + xSq = FixedMul(x, FixedMul(invCosA,x)); + ySq = FixedMul(y, FixedMul(invCosA,y)); + zSq = FixedMul(z, FixedMul(invCosA,z)); + + sx = FixedMul(sinA, x); + sy = FixedMul(sinA, y); + sz = FixedMul(sinA, z); + + sxy = FixedMul(x, FixedMul(invCosA,y)); + sxz = FixedMul(x, FixedMul(invCosA,z)); + syz = FixedMul(y, FixedMul(invCosA,z)); + + + M(0, 0) = xSq + cosA; + M(1, 0) = sxy - sz; + M(2, 0) = sxz + sy; + M(3, 0) = 0; + + M(0, 1) = sxy + sz; + M(1, 1) = ySq + cosA; + M(2, 1) = syz - sx; + M(3, 1) = 0; + + M(0, 2) = sxz - sy; + M(1, 2) = syz + sx; + M(2, 2) = zSq + cosA; + M(3, 2) = 0; + + M(0, 3) = 0; + M(1, 3) = 0; + M(2, 3) = 0; + M(3, 3) = FRACUNIT; +#undef M +} + +#endif + + + + +float FV_Distancef(const v3float_t *p1, const v3float_t *p2) +{ + float xs = (p2->x-p1->x * p2->x-p1->x); + float ys = (p2->y-p1->y * p2->y-p1->y); + float zs = (p2->z-p1->z * p2->z-p1->z); + return sqrt(xs+ys+zs); +} + +// Also returns the magnitude +fixed_t FV_NormalizeO(const v3fixed_t *a_normal, v3fixed_t *a_o) +{ + fixed_t magnitude = FV_Magnitude(a_normal); + a_o->x = FixedDiv(a_normal->x, magnitude); + a_o->y = FixedDiv(a_normal->y, magnitude); + a_o->z = FixedDiv(a_normal->z, magnitude); + return magnitude; +} + +// Also returns the magnitude +float FV_NormalizeOf(const v3float_t *a_normal, v3float_t *a_o) +{ + float magnitude = FV_Magnitudef(a_normal); + a_o->x = (a_normal->x/magnitude); + a_o->y = (a_normal->y/magnitude); + a_o->z = (a_normal->z/magnitude); + return magnitude; +} + +fixed_t FV_Normalize(v3fixed_t *a_normal) +{ + return FV_NormalizeO(a_normal, a_normal); +} + +fixed_t FV_Normalizef(v3float_t *a_normal) +{ + return FV_NormalizeOf(a_normal, a_normal); +} + +// +// FV_Normalf +// +// Calculates the normal of a polygon. +// +void FV_Normal(const v3fixed_t *a_triangle, v3fixed_t *a_normal) +{ + v3fixed_t a_1; + v3fixed_t a_2; + + M_MakeVec3(&a_triangle[2], &a_triangle[0], &a_1); + M_MakeVec3(&a_triangle[1], &a_triangle[0], &a_2); + + M_CrossProduct3(&a_1, &a_2, a_normal); + + FV_NormalizeO(a_normal, a_normal); +} + +// +// FV_Normalf +// +// Calculates the normal of a polygon. +// +void FV_Normalf(const v3float_t *a_triangle, v3float_t *a_normal) +{ + v3float_t a_1; + v3float_t a_2; + + M_MakeVec3f(&a_triangle[2], &a_triangle[0], &a_1); + M_MakeVec3f(&a_triangle[1], &a_triangle[0], &a_2); + + M_CrossProduct3f(&a_1, &a_2, a_normal); + + FV_NormalizeOf(a_normal, a_normal); +} + + +// EOF +#endif // #ifdef ESLOPE + diff --git a/src/m_vector.h b/src/m_vector.h new file mode 100644 index 00000000..743a2602 --- /dev/null +++ b/src/m_vector.h @@ -0,0 +1,123 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2004 Stephen McGranahan +// +// This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//-------------------------------------------------------------------------- +// +// DESCRIPTION: +// Vectors +// SoM created 05/18/09 +// +//----------------------------------------------------------------------------- + +#ifndef M_VECTOR_H__ +#define M_VECTOR_H__ + +#ifdef ESLOPE + +#include "m_fixed.h" +#include "tables.h" + +#define TWOPI M_PI*2.0 +#define HALFPI M_PI*0.5 +#define QUARTERPI M_PI*0.25 +#define EPSILON 0.000001f +#define OMEGA 10000000.0f + +typedef struct +{ + fixed_t x, y, z; +} v3fixed_t; + +typedef struct +{ + fixed_t x, y; +} v2fixed_t; + +typedef struct +{ + float x, y, z; +} v3float_t; + +typedef struct +{ + float yaw, pitch, roll; +} angles3d_t; + +typedef struct +{ + double x, y, z; +} v3double_t; + +typedef struct +{ + float x, y; +} v2float_t; + + +v3fixed_t *M_MakeVec3(const v3fixed_t *point1, const v3fixed_t *point2, v3fixed_t *a_o); +v3float_t *M_MakeVec3f(const v3float_t *point1, const v3float_t *point2, v3float_t *a_o); +void M_TranslateVec3(v3fixed_t *vec); +void M_TranslateVec3f(v3float_t *vec); +void M_AddVec3(v3fixed_t *dest, const v3fixed_t *v1, const v3fixed_t *v2); +void M_AddVec3f(v3float_t *dest, const v3float_t *v1, const v3float_t *v2); +void M_SubVec3(v3fixed_t *dest, const v3fixed_t *v1, const v3fixed_t *v2); +void M_SubVec3f(v3float_t *dest, const v3float_t *v1, const v3float_t *v2); +fixed_t M_DotVec3(const v3fixed_t *v1, const v3fixed_t *v2); +float M_DotVec3f(const v3float_t *v1, const v3float_t *v2); + +#ifdef SESLOPE +v3double_t *M_MakeVec3d(const v3double_t *point1, const v3double_t *point2, v3double_t *a_o); +double M_DotVec3d(const v3double_t *v1, const v3double_t *v2); +void M_TranslateVec3d(v3double_t *vec); +#endif + +void M_CrossProduct3(v3fixed_t *dest, const v3fixed_t *v1, const v3fixed_t *v2); +void M_CrossProduct3f(v3float_t *dest, const v3float_t *v1, const v3float_t *v2); +fixed_t FV_Magnitude(const v3fixed_t *a_normal); +float FV_Magnitudef(const v3float_t *a_normal); +fixed_t FV_NormalizeO(const v3fixed_t *a_normal, v3fixed_t *a_o); +float FV_NormalizeOf(const v3float_t *a_normal, v3float_t *a_o); +fixed_t FV_Normalize(v3fixed_t *a_normal); +fixed_t FV_Normalizef(v3float_t *a_normal); +void FV_Normal(const v3fixed_t *a_triangle, v3fixed_t *a_normal); +void FV_Normalf(const v3float_t *a_triangle, v3float_t *a_normal); +v3fixed_t *M_LoadVec(v3fixed_t *vec, fixed_t x, fixed_t y, fixed_t z); +v3fixed_t *M_CopyVec(v3fixed_t *a_o, const v3fixed_t *a_i); +v3float_t *M_LoadVecf(v3float_t *vec, float x, float y, float z); +v3float_t *M_CopyVecf(v3float_t *a_o, const v3float_t *a_i); +v3fixed_t *FV_Midpoint(const v3fixed_t *a_1, const v3fixed_t *a_2, v3fixed_t *a_o); +fixed_t FV_Distance(const v3fixed_t *p1, const v3fixed_t *p2); +v3float_t *FV_Midpointf(const v3float_t *a_1, const v3float_t *a_2, v3float_t *a_o); +angle_t FV_AngleBetweenVectors(const v3fixed_t *Vector1, const v3fixed_t *Vector2); +float FV_AngleBetweenVectorsf(const v3float_t *Vector1, const v3float_t *Vector2); +float FV_Distancef(const v3float_t *p1, const v3float_t *p2); + + +// Kalaron: something crazy, vector physics +float M_VectorYaw(v3float_t v); +float M_VectorPitch(v3float_t v); +angles3d_t *M_VectorAlignTo(float Pitch, float Yaw, float Roll, v3float_t v, byte AngleAxis, float Rate); + + + +#endif + +// EOF +#endif // #ifdef ESLOPE + diff --git a/src/p_enemy.c b/src/p_enemy.c index 54e15112..61c943d0 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -28,6 +28,10 @@ #include "hardware/hw3sound.h" #endif +#ifdef ESLOPE +#include "p_slopes.h" +#endif + #ifdef HAVE_BLUA boolean LUA_CallAction(const char *action, mobj_t *actor); #endif @@ -5614,8 +5618,17 @@ void A_MixUp(mobj_t *actor) P_SetThingPosition(players[i].mo); +#ifdef ESLOPE + players[i].mo->floorz = (players[i].mo->subsector->sector->f_slope ? + P_GetZAt(players[i].mo->subsector->sector->f_slope, players[i].mo->x, players[i].mo->y) : + players[i].mo->subsector->sector->floorheight); + players[i].mo->ceilingz = (players[i].mo->subsector->sector->c_slope ? + P_GetZAt(players[i].mo->subsector->sector->c_slope, players[i].mo->x, players[i].mo->y) : + players[i].mo->subsector->sector->ceilingheight); +#else players[i].mo->floorz = players[i].mo->subsector->sector->floorheight; players[i].mo->ceilingz = players[i].mo->subsector->sector->ceilingheight; +#endif P_CheckPosition(players[i].mo, players[i].mo->x, players[i].mo->y); } diff --git a/src/p_floor.c b/src/p_floor.c index f798174a..65c4821c 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -19,6 +19,9 @@ #include "z_zone.h" #include "g_game.h" #include "r_main.h" +#ifdef ESLOPE +#include "p_slopes.h" +#endif // ========================================================================== // FLOORS @@ -1174,12 +1177,18 @@ void T_SpikeSector(levelspecthink_t *spikes) if (affectsec == spikes->sector) // Applied to an actual sector { + fixed_t affectpoint = affectsec->floorheight; + +#ifdef ESLOPE + if (affectsec->f_slope) + affectpoint = P_GetZAt(affectsec->f_slope, thing->x, thing->y); +#endif if (affectsec->flags & SF_FLIPSPECIAL_FLOOR) { if (!(thing->eflags & MFE_VERTICALFLIP) && thing->momz > 0) continue; - if (thing->z == affectsec->floorheight) + if (thing->z == affectpoint) dothepain = true; } diff --git a/src/p_local.h b/src/p_local.h index 9f8918cd..9fbab1d8 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -50,6 +50,15 @@ // above this, a height difference is considered as a 'dropoff' #define MAXSTEPMOVE (24*FRACUNIT) +#ifdef ESLOPE +// [RH] Minimum floorplane.c value for walking +// The lower the value, the steeper the slope is +#define SECPLANESTEEPSLOPE 46000 +// ESLOPE stuff - a slope of 4 or lower is so level, treat it as flat +#define LEVELSLOPE 4 +#define STEEPSLOPE 65 +#endif + #define USERANGE (64*FRACUNIT) #define MELEERANGE (64*FRACUNIT) #define MISSILERANGE (32*64*FRACUNIT) @@ -135,6 +144,12 @@ boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec); boolean P_InSpaceSector(mobj_t *mo); boolean P_InQuicksand(mobj_t *mo); +#ifdef ESLOPE +boolean P_IsObjectOnSlope(mobj_t *mo, boolean ceiling); +boolean P_SlopeGreaterThan(mobj_t *mo, boolean ceiling, int value); +boolean P_SlopeLessThan(mobj_t *mo, boolean ceiling, int value); +#endif + void P_SetObjectMomZ(mobj_t *mo, fixed_t value, boolean relative); void P_RestoreMusic(player_t *player); void P_SpawnShieldOrb(player_t *player); diff --git a/src/p_map.c b/src/p_map.c index 62cbf7b7..f484b6a2 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -27,6 +27,10 @@ #include "r_splats.h" +#ifdef ESLOPE +#include "p_slopes.h" +#endif + #include "z_zone.h" #include "lua_hook.h" @@ -1213,8 +1217,21 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) // that contains the point. // Any contacted lines the step closer together // will adjust them. +#ifdef ESLOPE + if (newsubsec->sector->f_slope) + { + tmfloorz = tmdropoffz = P_GetZAt(newsubsec->sector->f_slope, thing->x, thing->y); + } + else +#endif tmfloorz = tmdropoffz = newsubsec->sector->floorheight; - tmceilingz = tmdrpoffceilz = newsubsec->sector->ceilingheight; + +#ifdef ESLOPE + if (newsubsec->sector->c_slope) + tmceilingz = P_GetZAt(newsubsec->sector->c_slope, thing->x, thing->y); + else +#endif + tmceilingz = newsubsec->sector->ceilingheight; // Check list of fake floors and see if tmfloorz/tmceilingz need to be altered. if (newsubsec->sector->ffloors) @@ -1228,32 +1245,42 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) if (!(rover->flags & FF_EXISTS)) continue; + fixed_t topheight = *rover->topheight; + fixed_t bottomheight = *rover->bottomheight; + +/*#ifdef ESLOPE + if (rover->t_slope) + topheight = P_GetZAt(rover->t_slope, thing->x, thing->y); + if (rover->b_slope) + bottomheight = P_GetZAt(rover->b_slope, thing->x, thing->y); +#endif*/ + if (rover->flags & FF_GOOWATER && !(thing->flags & MF_NOGRAVITY)) { // If you're inside goowater and slowing down fixed_t sinklevel = FixedMul(thing->info->height/6, thing->scale); fixed_t minspeed = FixedMul(thing->info->height/12, thing->scale); - if (thing->z < *rover->topheight && *rover->bottomheight < thingtop + if (thing->z < topheight && bottomheight < thingtop && abs(thing->momz) < minspeed) { // Oh no! The object is stick in between the surface of the goo and sinklevel! help them out! - if (!(thing->eflags & MFE_VERTICALFLIP) && thing->z > *rover->topheight - sinklevel + if (!(thing->eflags & MFE_VERTICALFLIP) && thing->z > topheight - sinklevel && thing->momz >= 0 && thing->momz < (minspeed>>2)) thing->momz += minspeed>>2; - else if (thing->eflags & MFE_VERTICALFLIP && thingtop < *rover->bottomheight + sinklevel + else if (thing->eflags & MFE_VERTICALFLIP && thingtop < bottomheight + sinklevel && thing->momz <= 0 && thing->momz > -(minspeed>>2)) thing->momz -= minspeed>>2; // Land on the top or the bottom, depending on gravity flip. - if (!(thing->eflags & MFE_VERTICALFLIP) && thing->z >= *rover->topheight - sinklevel && thing->momz <= 0) + if (!(thing->eflags & MFE_VERTICALFLIP) && thing->z >= topheight - sinklevel && thing->momz <= 0) { - if (tmfloorz < *rover->topheight - sinklevel) - tmfloorz = *rover->topheight - sinklevel; + if (tmfloorz < topheight - sinklevel) + tmfloorz = topheight - sinklevel; } - else if (thing->eflags & MFE_VERTICALFLIP && thingtop <= *rover->bottomheight + sinklevel && thing->momz >= 0) + else if (thing->eflags & MFE_VERTICALFLIP && thingtop <= bottomheight + sinklevel && thing->momz >= 0) { - if (tmceilingz > *rover->bottomheight + sinklevel) - tmceilingz = *rover->bottomheight + sinklevel; + if (tmceilingz > bottomheight + sinklevel) + tmceilingz = bottomheight + sinklevel; } } continue; @@ -1270,7 +1297,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) if (rover->flags & FF_QUICKSAND) { - if (thing->z < *rover->topheight && *rover->bottomheight < thingtop) + if (thing->z < topheight && bottomheight < thingtop) { if (tmfloorz < thing->z) tmfloorz = thing->z; @@ -1279,21 +1306,21 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) continue; } - delta1 = thing->z - (*rover->bottomheight - + ((*rover->topheight - *rover->bottomheight)/2)); - delta2 = thingtop - (*rover->bottomheight - + ((*rover->topheight - *rover->bottomheight)/2)); + delta1 = thing->z - (bottomheight + + ((topheight - bottomheight)/2)); + delta2 = thingtop - (bottomheight + + ((topheight - bottomheight)/2)); - if (*rover->topheight > tmfloorz && abs(delta1) < abs(delta2) + if (topheight > tmfloorz && abs(delta1) < abs(delta2) && !(rover->flags & FF_REVERSEPLATFORM)) { - tmfloorz = tmdropoffz = *rover->topheight; + tmfloorz = tmdropoffz = topheight; } - if (*rover->bottomheight < tmceilingz && abs(delta1) >= abs(delta2) + if (bottomheight < tmceilingz && abs(delta1) >= abs(delta2) && !(rover->flags & FF_PLATFORM) && !(thing->type == MT_SKIM && (rover->flags & FF_SWIMMABLE))) { - tmceilingz = tmdrpoffceilz = *rover->bottomheight; + tmceilingz = tmdrpoffceilz = bottomheight; } } } @@ -1470,8 +1497,21 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) // that contains the point. // Any contacted lines the step closer together // will adjust them. +#ifdef ESLOPE + if (newsubsec->sector->f_slope) + { + tmfloorz = tmdropoffz = P_GetZAt(newsubsec->sector->f_slope, thiscam->x, thiscam->y); + } + else +#endif tmfloorz = tmdropoffz = newsubsec->sector->floorheight; - tmceilingz = tmdrpoffceilz = newsubsec->sector->ceilingheight; + +#ifdef ESLOPE + if (newsubsec->sector->c_slope) + tmceilingz = P_GetZAt(newsubsec->sector->c_slope, thiscam->x, thiscam->y); + else +#endif + tmceilingz = newsubsec->sector->ceilingheight; // Cameras use the heightsec's heights rather then the actual sector heights. // If you can see through it, why not move the camera through it too? @@ -1500,17 +1540,27 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) if (!(rover->flags & FF_BLOCKOTHERS) || !(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERALL) || GETSECSPECIAL(rover->master->frontsector->special, 4) == 12) continue; - delta1 = thiscam->z - (*rover->bottomheight - + ((*rover->topheight - *rover->bottomheight)/2)); - delta2 = thingtop - (*rover->bottomheight - + ((*rover->topheight - *rover->bottomheight)/2)); - if (*rover->topheight > tmfloorz && abs(delta1) < abs(delta2)) + fixed_t topheight = *rover->topheight; + fixed_t bottomheight = *rover->bottomheight; + +/*#ifdef ESLOPE + if (rover->t_slope) + topheight = P_GetZAt(rover->t_slope, thiscam->x, thiscam->y); + if (rover->b_slope) + bottomheight = P_GetZAt(rover->b_slope, thiscam->x, thiscam->y); +#endif*/ + + delta1 = thiscam->z - (bottomheight + + ((topheight - bottomheight)/2)); + delta2 = thingtop - (bottomheight + + ((topheight - bottomheight)/2)); + if (topheight > tmfloorz && abs(delta1) < abs(delta2)) { - tmfloorz = tmdropoffz = *rover->topheight; + tmfloorz = tmdropoffz = topheight; } - if (*rover->bottomheight < tmceilingz && abs(delta1) >= abs(delta2)) + if (bottomheight < tmceilingz && abs(delta1) >= abs(delta2)) { - tmceilingz = tmdrpoffceilz = *rover->bottomheight; + tmceilingz = tmdrpoffceilz = bottomheight; } } } @@ -1703,8 +1753,30 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) } else { - tmfloorz = thiscam->subsector->sector->floorheight; - tmceilingz = thiscam->subsector->sector->ceilingheight; +#ifdef ESLOPE // SRB2CBTODO: Checking the things momx/y help with collision issues, but makes going done slopes not as smooth + if (thiscam->subsector->sector && thiscam->subsector->sector->f_slope) + { + // SRB2CBTODO: Support a mobj's gravity for this too + if (P_GetZAt(thiscam->subsector->sector->f_slope, thiscam->x+thiscam->momx, thiscam->y+thiscam->momy) > P_GetZAt(thiscam->subsector->sector->f_slope, thiscam->x, thiscam->y)) + thiscam->floorz = P_GetZAt(thiscam->subsector->sector->f_slope, thiscam->x+thiscam->momx, thiscam->y+thiscam->momy); + else + thiscam->floorz = P_GetZAt(thiscam->subsector->sector->f_slope, thiscam->x, thiscam->y); + } + else +#endif + tmfloorz = thiscam->subsector->sector->floorheight; +#ifdef ESLOPE + if (thiscam->subsector->sector && thiscam->subsector->sector->c_slope) + { + // SRB2CBTODO: Support a mobj's gravity for this too + if (P_GetZAt(thiscam->subsector->sector->c_slope, thiscam->x+thiscam->momx, thiscam->y+thiscam->momy) < P_GetZAt(thiscam->subsector->sector->c_slope, thiscam->x, thiscam->y)) + thiscam->ceilingz = P_GetZAt(thiscam->subsector->sector->c_slope, thiscam->x, thiscam->y); + else + thiscam->ceilingz = P_GetZAt(thiscam->subsector->sector->c_slope, thiscam->x+thiscam->momx, thiscam->y+thiscam->momy); + } + else +#endif + tmceilingz = thiscam->subsector->sector->ceilingheight; } // the move is ok, @@ -1966,8 +2038,111 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) // Link the thing into its new position P_UnsetThingPosition(thing); - thing->floorz = tmfloorz; - thing->ceilingz = tmceilingz; +#ifdef ESLOPE + // By virtue of being derived from SRB2 code, Kalaron's physics are GPL. + if (P_IsObjectOnSlope(thing, false)) + { + fixed_t thingspeed = P_AproxDistance(thing->momx, thing->momy); + fixed_t predictmomx = x+(thing->momx/2); + fixed_t predictmomy = y+(thing->momy/2); + sector_t *nextsector = R_PointInSubsector(predictmomx, predictmomy)->sector; + sector_t *currentsector = R_PointInSubsector(thing->x, thing->y)->sector; + fixed_t zthrust = 0; + fixed_t slopeang = currentsector->f_slope->zangle; + fixed_t nextz = nextsector->floorheight; + if (nextsector->f_slope) + nextz = P_GetZAt(nextsector->f_slope, thing->x+predictmomx+thing->momx, thing->y+predictmomy+thing->momy); + + if (nextsector != currentsector) + { + // Give a boost up from the slope you came if the next sector is lower than the first + // If your next sector does not have a slope and you're comming off of one + if (currentsector->f_slope) + if (P_GetZAt(currentsector->f_slope, thing->x, thing->y)/FRACUNIT > (nextz/FRACUNIT)+(slopeang*3)) + //&& !nextsector->f_slope // TODO: VPHYSICS height check, not this hacky check? Or is this good enough? + if (currentsector->f_slope->zangle > 9) + { + fixed_t currentz = P_GetZAt(currentsector->f_slope, thing->x, thing->y); + fixed_t predictz = P_GetZAt(currentsector->f_slope, thing->x+thing->momx, thing->y+thing->momy); + + predictz += (((thing->pitchangle/(ANGLE_45/45))+90)/70.0f)+thingspeed/9; + + // Make sure that the z doesn't go too high for steep slopes + + predictz -= ((currentsector->f_slope->zangle)/4)*FRACUNIT; + if (currentsector->f_slope->zangle > 60) // really steep + { + predictz -= ((currentsector->f_slope->zangle)/2)*FRACUNIT; + } + + zthrust = (predictz - currentz)/2; + + if (zthrust > (30*thing->scale/100)*FRACUNIT) + zthrust = (30*thing->scale/100)*FRACUNIT; + + if (zthrust < -(30*thing->scale/100)*FRACUNIT) + zthrust = -(30*thing->scale/100)*FRACUNIT; + + if (currentz/FRACUNIT > (nextz/FRACUNIT)+(slopeang*3)) + { + // Now even out the momx/momy when catapulting off a steep slope + if (currentsector->f_slope->zangle > 65) + { + thing->momx /= 4.0f; + thing->momy /= 4.0f; + } + else if (currentsector->f_slope->zangle > 60) + { + thing->momx /= 3.5f; + thing->momy /= 3.5f; + } + else if (currentsector->f_slope->zangle > 50) + { + thing->momx /= 3.4f; + thing->momy /= 3.4f; + } + else if (currentsector->f_slope->zangle > 40) + { + thing->momx /= 3.3f; + thing->momy /= 3.3f; + } + } + + thing->momz += zthrust; // VPHYSICS TODO: Make a real formula for z trajectory going off a slope + /*CONS_Printf("CurZ %i, PredictZ %i\n", currentz/FRACUNIT, predictz/FRACUNIT); + CONS_Printf("Pitch: %i\n", thing->pitchangle/(ANG45/45)+90); + CONS_Printf("ZThrust: %i\n", zthrust/FRACUNIT);*/ + } + } + } +#endif + + // P_CheckPosition sets the tmfloorz with slopes, but after P_UnsetThingPosition, recheck the function here + // TODO: Make a function for floor/ceilingz auto check with slopes? +#ifdef ESLOPE + if (thing->subsector->sector->f_slope) + { + // TODO: Support a mobj's gravity for this too + if (P_GetZAt(thing->subsector->sector->f_slope, thing->x+thing->momx, thing->y+thing->momy) > P_GetZAt(thing->subsector->sector->f_slope, thing->x, thing->y)) + thing->floorz = P_GetZAt(thing->subsector->sector->f_slope, thing->x+thing->momx, thing->y+thing->momy); + else + thing->floorz = P_GetZAt(thing->subsector->sector->f_slope, thing->x, thing->y); + } + else +#endif + thing->floorz = tmfloorz; +#ifdef ESLOPE + if (thing->subsector->sector->c_slope) + { + // SRB2CBTODO: Support a mobj's gravity for this too + if (P_GetZAt(thing->subsector->sector->c_slope, thing->x+thing->momx, thing->y+thing->momy) < P_GetZAt(thing->subsector->sector->c_slope, thing->x, thing->y)) + thing->ceilingz = P_GetZAt(thing->subsector->sector->c_slope, thing->x, thing->y); + else + thing->ceilingz = P_GetZAt(thing->subsector->sector->c_slope, thing->x+thing->momx, thing->y+thing->momy); + } + else +#endif + thing->ceilingz = tmceilingz; thing->x = x; thing->y = y; @@ -1983,6 +2158,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y) { fixed_t tryx, tryy; + tryx = thing->x; tryy = thing->y; do { @@ -2004,7 +2180,15 @@ boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y) if (!(thing->flags & MF_NOCLIP)) { - const fixed_t maxstep = MAXSTEPMOVE; + fixed_t maxstep = MAXSTEPMOVE; + +#ifdef ESLOPE // TODO: Make this collosion better + // Maxstepmove = 0 means the object bounces like a nut while going down a slope + if (thing->subsector->sector->f_slope) + { + maxstep *= thing->subsector->sector->f_slope->zangle; + } +#endif if (tmceilingz - tmfloorz < thing->height) return false; // doesn't fit @@ -2308,12 +2492,24 @@ static boolean P_IsClimbingValid(player_t *player, angle_t angle) { fixed_t platx, platy; subsector_t *glidesector; + fixed_t floorz, ceilingz; platx = P_ReturnThrustX(player->mo, angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale)); platy = P_ReturnThrustY(player->mo, angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale)); glidesector = R_PointInSubsector(player->mo->x + platx, player->mo->y + platy); + floorz = glidesector->sector->floorheight; +#ifdef ESLOPE + if (glidesector->sector->f_slope) + floorz = P_GetZAt(glidesector->sector->f_slope, player->mo->x + platx, player->mo->y + platy); +#endif + ceilingz = glidesector->sector->ceilingheight; +#ifdef ESLOPE + if (glidesector->sector->c_slope) + ceilingz = P_GetZAt(glidesector->sector->c_slope, player->mo->x + platx, player->mo->y + platy); +#endif + if (glidesector->sector != player->mo->subsector->sector) { boolean floorclimb = false; @@ -2326,34 +2522,44 @@ static boolean P_IsClimbingValid(player_t *player, angle_t angle) if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER)) continue; + fixed_t topheight = *rover->topheight; + fixed_t bottomheight = *rover->bottomheight; + +/*#ifdef ESLOPE + if (rover->t_slope) + topheight = P_GetZAt(rover->t_slope, player->mo->x, player->mo->y); + if (rover->b_slope) + bottomheight = P_GetZAt(rover->b_slope, player->mo->x, player->mo->y); +#endif*/ + floorclimb = true; if (player->mo->eflags & MFE_VERTICALFLIP) { - if ((*rover->topheight < player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) < *rover->topheight)) + if ((topheight < player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) < topheight)) { floorclimb = true; } - if (*rover->topheight < player->mo->z) // Waaaay below the ledge. + if (topheight < player->mo->z) // Waaaay below the ledge. { floorclimb = false; } - if (*rover->bottomheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT,player->mo->scale)) + if (bottomheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT,player->mo->scale)) { floorclimb = false; } } else { - if ((*rover->bottomheight > player->mo->z) && ((player->mo->z - player->mo->momz) > *rover->bottomheight)) + if ((bottomheight > player->mo->z) && ((player->mo->z - player->mo->momz) > bottomheight)) { floorclimb = true; } - if (*rover->bottomheight > player->mo->z + player->mo->height) // Waaaay below the ledge. + if (bottomheight > player->mo->z + player->mo->height) // Waaaay below the ledge. { floorclimb = false; } - if (*rover->topheight < player->mo->z + FixedMul(16*FRACUNIT,player->mo->scale)) + if (topheight < player->mo->z + FixedMul(16*FRACUNIT,player->mo->scale)) { floorclimb = false; } @@ -2366,30 +2572,30 @@ static boolean P_IsClimbingValid(player_t *player, angle_t angle) if (player->mo->eflags & MFE_VERTICALFLIP) { - if ((glidesector->sector->floorheight <= player->mo->z + player->mo->height) - && ((player->mo->z + player->mo->height - player->mo->momz) <= glidesector->sector->floorheight)) + if ((floorz <= player->mo->z + player->mo->height) + && ((player->mo->z + player->mo->height - player->mo->momz) <= floorz)) floorclimb = true; - if ((glidesector->sector->floorheight > player->mo->z) + if ((floorz > player->mo->z) && glidesector->sector->floorpic == skyflatnum) return false; - if ((player->mo->z + player->mo->height - FixedMul(16*FRACUNIT,player->mo->scale) > glidesector->sector->ceilingheight) - || (player->mo->z + player->mo->height <= glidesector->sector->floorheight)) + if ((player->mo->z + player->mo->height - FixedMul(16*FRACUNIT,player->mo->scale) > ceilingz) + || (player->mo->z + player->mo->height <= floorz)) floorclimb = true; } else { - if ((glidesector->sector->ceilingheight >= player->mo->z) - && ((player->mo->z - player->mo->momz) >= glidesector->sector->ceilingheight)) + if ((ceilingz >= player->mo->z) + && ((player->mo->z - player->mo->momz) >= ceilingz)) floorclimb = true; - if ((glidesector->sector->ceilingheight < player->mo->z+player->mo->height) + if ((ceilingz < player->mo->z+player->mo->height) && glidesector->sector->ceilingpic == skyflatnum) return false; - if ((player->mo->z + FixedMul(16*FRACUNIT,player->mo->scale) < glidesector->sector->floorheight) - || (player->mo->z >= glidesector->sector->ceilingheight)) + if ((player->mo->z + FixedMul(16*FRACUNIT,player->mo->scale) < ceilingz) + || (player->mo->z >= ceilingz)) floorclimb = true; } @@ -2408,6 +2614,7 @@ static boolean P_IsClimbingValid(player_t *player, angle_t angle) static boolean PTR_SlideTraverse(intercept_t *in) { line_t *li; + fixed_t maxstep; I_Assert(in->isaline); @@ -2440,7 +2647,17 @@ static boolean PTR_SlideTraverse(intercept_t *in) if (opentop - slidemo->z < slidemo->height) goto isblocking; // mobj is too high - if (openbottom - slidemo->z > FixedMul(MAXSTEPMOVE, slidemo->scale)) + maxstep = FixedMul(MAXSTEPMOVE, slidemo->scale); + +#ifdef ESLOPE // TODO: Make this collosion better + // Maxstepmove = 0 means the object bounces like a nut while going down a slope + if (slidemo->subsector->sector->f_slope) + { + maxstep *= slidemo->subsector->sector->f_slope->zangle; + } +#endif + + if (openbottom - slidemo->z > maxstep) goto isblocking; // too big a step up // this line doesn't block movement @@ -2476,13 +2693,23 @@ isblocking: if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP)) continue; - if (*rover->topheight < slidemo->z) + fixed_t topheight = *rover->topheight; + fixed_t bottomheight = *rover->bottomheight; + +/*#ifdef ESLOPE + if (rover->t_slope) + topheight = P_GetZAt(rover->t_slope, slidemo->x, slidemo->y); + if (rover->b_slope) + bottomheight = P_GetZAt(rover->b_slope, slidemo->x, slidemo->y); +#endif*/ + + if (topheight < slidemo->z) continue; - if (*rover->bottomheight > slidemo->z + slidemo->height) + if (bottomheight > slidemo->z + slidemo->height) continue; - // Got this far, so I guess it's climbable. + // Got this far, so I guess it's climbable. // TODO: Climbing check, also, better method to do this? if (rover->master->flags & ML_TFERLINE) { size_t linenum = li-checksector->lines[0]; @@ -3109,9 +3336,19 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush) || ((rover->flags & FF_BLOCKOTHERS) && !thing->player)) || !(rover->flags & FF_EXISTS)) continue; - delta1 = thing->z - (*rover->bottomheight + *rover->topheight)/2; - delta2 = thingtop - (*rover->bottomheight + *rover->topheight)/2; - if (*rover->bottomheight <= thing->ceilingz && abs(delta1) >= abs(delta2)) + fixed_t topheight = *rover->topheight; + fixed_t bottomheight = *rover->bottomheight; + +/*#ifdef ESLOPE + if (rover->t_slope) + topheight = P_GetZAt(rover->t_slope, thing->x, thing->y); + if (rover->b_slope) + bottomheight = P_GetZAt(rover->b_slope, thing->x, thing->y); +#endif*/ + + delta1 = thing->z - (bottomheight + topheight)/2; + delta2 = thingtop - (bottomheight + topheight)/2; + if (bottomheight <= thing->ceilingz && abs(delta1) >= abs(delta2)) { if (thing->flags & MF_PUSHABLE) { @@ -3785,7 +4022,7 @@ void P_MapEnd(void) } // P_FloorzAtPos -// Returns the floorz of the XYZ position +// Returns the floorz of the XYZ position // TODO: Need ceilingpos function too // Tails 05-26-2003 fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height) { @@ -3806,9 +4043,19 @@ fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height) if ((!(rover->flags & FF_SOLID || rover->flags & FF_QUICKSAND) || (rover->flags & FF_SWIMMABLE))) continue; + fixed_t topheight = *rover->topheight; + fixed_t bottomheight = *rover->bottomheight; + +/*#ifdef ESLOPE + if (rover->t_slope) + topheight = P_GetZAt(rover->t_slope, x, y); + if (rover->b_slope) + bottomheight = P_GetZAt(rover->b_slope, x, y); +#endif*/ + if (rover->flags & FF_QUICKSAND) { - if (z < *rover->topheight && *rover->bottomheight < thingtop) + if (z < topheight && bottomheight < thingtop) { if (floorz < z) floorz = z; @@ -3816,10 +4063,10 @@ fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height) continue; } - delta1 = z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2)); - delta2 = thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2)); - if (*rover->topheight > floorz && abs(delta1) < abs(delta2)) - floorz = *rover->topheight; + delta1 = z - (bottomheight + ((topheight - bottomheight)/2)); + delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2)); + if (topheight > floorz && abs(delta1) < abs(delta2)) + floorz = topheight; } } diff --git a/src/p_maputl.c b/src/p_maputl.c index 48dd54e8..f311bffc 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -20,6 +20,9 @@ #include "p_maputl.h" #include "p_polyobj.h" #include "z_zone.h" +#ifdef ESLOPE +#include "p_slopes.h" +#endif // // P_AproxDistance @@ -347,31 +350,68 @@ void P_CameraLineOpening(line_t *linedef) { frontfloor = sectors[front->camsec].floorheight; frontceiling = sectors[front->camsec].ceilingheight; +#ifdef ESLOPE + if (sectors[front->camsec].f_slope) // SRB2CBTODO: ESLOPE (sectors[front->heightsec].f_slope) + frontfloor = P_GetZAt(sectors[front->camsec].f_slope, camera.x, camera.y); + if (sectors[front->camsec].c_slope) + frontceiling = P_GetZAt(sectors[front->camsec].c_slope, camera.x, camera.y); +#endif + } else if (front->heightsec >= 0) { frontfloor = sectors[front->heightsec].floorheight; frontceiling = sectors[front->heightsec].ceilingheight; +#ifdef ESLOPE + if (sectors[front->heightsec].f_slope) // SRB2CBTODO: ESLOPE (sectors[front->heightsec].f_slope) + frontfloor = P_GetZAt(sectors[front->heightsec].f_slope, camera.x, camera.y); + if (sectors[front->heightsec].c_slope) + frontceiling = P_GetZAt(sectors[front->heightsec].c_slope, camera.x, camera.y); +#endif } else { frontfloor = front->floorheight; frontceiling = front->ceilingheight; +#ifdef ESLOPE + if (front->f_slope) + frontfloor = P_GetZAt(front->f_slope, camera.x, camera.y); + if (front->c_slope) + frontceiling = P_GetZAt(front->c_slope, camera.x, camera.y); +#endif } if (back->camsec >= 0) { backfloor = sectors[back->camsec].floorheight; backceiling = sectors[back->camsec].ceilingheight; +#ifdef ESLOPE + if (sectors[back->camsec].f_slope) // SRB2CBTODO: ESLOPE (sectors[front->heightsec].f_slope) + frontfloor = P_GetZAt(sectors[back->camsec].f_slope, camera.x, camera.y); + if (sectors[back->camsec].c_slope) + frontceiling = P_GetZAt(sectors[back->camsec].c_slope, camera.x, camera.y); +#endif } else if (back->heightsec >= 0) { backfloor = sectors[back->heightsec].floorheight; backceiling = sectors[back->heightsec].ceilingheight; +#ifdef ESLOPE + if (sectors[back->heightsec].f_slope) // SRB2CBTODO: ESLOPE (sectors[front->heightsec].f_slope) + frontfloor = P_GetZAt(sectors[back->heightsec].f_slope, camera.x, camera.y); + if (sectors[back->heightsec].c_slope) + frontceiling = P_GetZAt(sectors[back->heightsec].c_slope, camera.x, camera.y); +#endif } else { backfloor = back->floorheight; backceiling = back->ceilingheight; +#ifdef ESLOPE + if (back->f_slope) + frontfloor = P_GetZAt(back->f_slope, camera.x, camera.y); + if (back->c_slope) + frontceiling = P_GetZAt(back->c_slope, camera.x, camera.y); +#endif } { @@ -416,17 +456,28 @@ void P_CameraLineOpening(line_t *linedef) if (!(rover->flags & FF_BLOCKOTHERS) || !(rover->flags & FF_RENDERALL) || !(rover->flags & FF_EXISTS) || GETSECSPECIAL(rover->master->frontsector->special, 4) == 12) continue; - delta1 = abs(mapcampointer->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); - delta2 = abs(thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); - if (*rover->bottomheight < lowestceiling && delta1 >= delta2) - lowestceiling = *rover->bottomheight; - else if (*rover->bottomheight < highestceiling && delta1 >= delta2) - highestceiling = *rover->bottomheight; + fixed_t topheight = *rover->topheight; + fixed_t bottomheight = *rover->bottomheight; - if (*rover->topheight > highestfloor && delta1 < delta2) - highestfloor = *rover->topheight; - else if (*rover->topheight > lowestfloor && delta1 < delta2) - lowestfloor = *rover->topheight; +/*#ifdef ESLOPE + if (rover->t_slope) + topheight = P_GetZAt(rover->t_slope, camera.x, camera.y); + + if (rover->b_slope) + bottomheight = P_GetZAt(rover->b_slope, camera.x, camera.y); +#endif // ESLOPE*/ + + delta1 = abs(mapcampointer->z - (bottomheight + ((topheight - bottomheight)/2))); + delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); + if (bottomheight < lowestceiling && delta1 >= delta2) + lowestceiling = bottomheight; + else if (bottomheight < highestceiling && delta1 >= delta2) + highestceiling = bottomheight; + + if (topheight > highestfloor && delta1 < delta2) + highestfloor = topheight; + else if (topheight > lowestfloor && delta1 < delta2) + lowestfloor = topheight; } // Check for backsectors fake floors @@ -436,17 +487,28 @@ void P_CameraLineOpening(line_t *linedef) if (!(rover->flags & FF_BLOCKOTHERS) || !(rover->flags & FF_RENDERALL) || !(rover->flags & FF_EXISTS) || GETSECSPECIAL(rover->master->frontsector->special, 4) == 12) continue; - delta1 = abs(mapcampointer->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); - delta2 = abs(thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); - if (*rover->bottomheight < lowestceiling && delta1 >= delta2) - lowestceiling = *rover->bottomheight; - else if (*rover->bottomheight < highestceiling && delta1 >= delta2) - highestceiling = *rover->bottomheight; + fixed_t topheight = *rover->topheight; + fixed_t bottomheight = *rover->bottomheight; - if (*rover->topheight > highestfloor && delta1 < delta2) - highestfloor = *rover->topheight; - else if (*rover->topheight > lowestfloor && delta1 < delta2) - lowestfloor = *rover->topheight; +/*#ifdef ESLOPE + if (rover->t_slope) + topheight = P_GetZAt(rover->t_slope, camera.x, camera.y); + + if (rover->b_slope) + bottomheight = P_GetZAt(rover->b_slope, camera.x, camera.y); +#endif // ESLOPE*/ + + delta1 = abs(mapcampointer->z - (bottomheight + ((topheight - bottomheight)/2))); + delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); + if (bottomheight < lowestceiling && delta1 >= delta2) + lowestceiling = bottomheight; + else if (bottomheight < highestceiling && delta1 >= delta2) + highestceiling = bottomheight; + + if (topheight > highestfloor && delta1 < delta2) + highestfloor = topheight; + else if (topheight > lowestfloor && delta1 < delta2) + lowestfloor = topheight; } if (highestceiling < highceiling) @@ -520,6 +582,33 @@ void P_LineOpening(line_t *linedef) { fixed_t thingtop = tmthing->z + tmthing->height; +#ifdef ESLOPE + // I suspect the math here is wrong and we should be comparing the slope Zs + // if either are slopes. + // -- Fury + if (front->c_slope && front->ceilingheight < back->ceilingheight) + { + opentop = P_GetZAt(front->c_slope, tmthing->x, tmthing->y); + if (back->c_slope) highceiling = P_GetZAt(back->c_slope, tmthing->x, tmthing->y); + } + else if (back->c_slope && front->ceilingheight >= back->ceilingheight) + { + opentop = P_GetZAt(back->c_slope, tmthing->x, tmthing->y); + if (front->c_slope) highceiling = P_GetZAt(front->c_slope, tmthing->x, tmthing->y); + } + + if (front->c_slope && front->floorheight < back->floorheight) + { + openbottom = P_GetZAt(front->f_slope, tmthing->x, tmthing->y); + if (back->f_slope) lowfloor = P_GetZAt(back->f_slope, tmthing->x, tmthing->y); + } + if (back->f_slope && front->floorheight >= back->floorheight) + { + openbottom = P_GetZAt(back->f_slope, tmthing->x, tmthing->y); + if (front->f_slope) lowfloor = P_GetZAt(back->f_slope, tmthing->x, tmthing->y); + } +#endif + // Check for fake floors in the sector. if (front->ffloors || back->ffloors #ifdef POLYOBJECTS @@ -547,23 +636,34 @@ void P_LineOpening(line_t *linedef) || (rover->flags & FF_BLOCKOTHERS && !tmthing->player))) continue; - delta1 = abs(tmthing->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); - delta2 = abs(thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); + fixed_t topheight = *rover->topheight; + fixed_t bottomheight = *rover->bottomheight; + +/*#ifdef ESLOPE + if (rover->t_slope) + topheight = P_GetZAt(rover->t_slope, camera.x, camera.y); + + if (rover->b_slope) + bottomheight = P_GetZAt(rover->b_slope, camera.x, camera.y); +#endif*/ + + delta1 = abs(tmthing->z - (bottomheight + ((topheight - bottomheight)/2))); + delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); if (delta1 >= delta2 && !(rover->flags & FF_PLATFORM)) // thing is below FOF { - if (*rover->bottomheight < lowestceiling) - lowestceiling = *rover->bottomheight; - else if (*rover->bottomheight < highestceiling) - highestceiling = *rover->bottomheight; + if (bottomheight < lowestceiling) + lowestceiling = bottomheight; + else if (bottomheight < highestceiling) + highestceiling = bottomheight; } if (delta1 < delta2 && !(rover->flags & FF_REVERSEPLATFORM)) // thing is above FOF { - if (*rover->topheight > highestfloor) - highestfloor = *rover->topheight; - else if (*rover->topheight > lowestfloor) - lowestfloor = *rover->topheight; + if (topheight > highestfloor) + highestfloor = topheight; + else if (topheight > lowestfloor) + lowestfloor = topheight; } } @@ -579,23 +679,34 @@ void P_LineOpening(line_t *linedef) || (rover->flags & FF_BLOCKOTHERS && !tmthing->player))) continue; - delta1 = abs(tmthing->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); - delta2 = abs(thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); + fixed_t topheight = *rover->topheight; + fixed_t bottomheight = *rover->bottomheight; + +/*#ifdef ESLOPE + if (rover->t_slope) + topheight = P_GetZAt(rover->t_slope, tmthing->x, tmthing->y); + + if (rover->b_slope) + bottomheight = P_GetZAt(rover->b_slope, tmthing->x, tmthing->y); +#endif*/ + + delta1 = abs(tmthing->z - (bottomheight + ((topheight - bottomheight)/2))); + delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); if (delta1 >= delta2 && !(rover->flags & FF_PLATFORM)) // thing is below FOF { - if (*rover->bottomheight < lowestceiling) - lowestceiling = *rover->bottomheight; - else if (*rover->bottomheight < highestceiling) - highestceiling = *rover->bottomheight; + if (bottomheight < lowestceiling) + lowestceiling = bottomheight; + else if (bottomheight < highestceiling) + highestceiling = bottomheight; } if (delta1 < delta2 && !(rover->flags & FF_REVERSEPLATFORM)) // thing is above FOF { - if (*rover->topheight > highestfloor) - highestfloor = *rover->topheight; - else if (*rover->topheight > lowestfloor) - lowestfloor = *rover->topheight; + if (topheight > highestfloor) + highestfloor = topheight; + else if (topheight > lowestfloor) + lowestfloor = topheight; } } @@ -732,6 +843,16 @@ void P_SetThingPosition(mobj_t *thing) ss = thing->subsector = R_PointInSubsector(thing->x, thing->y); + fixed_t tfloorz, tceilz; + tfloorz = ss->sector->floorheight; + tceilz = ss->sector->ceilingheight; +#ifdef ESLOPE + if (ss->sector->f_slope) + tfloorz = P_GetZAt(ss->sector->f_slope, thing->x, thing->y); + if (ss->sector->c_slope) + tceilz = P_GetZAt(ss->sector->c_slope, thing->x, thing->y); +#endif + if (!(thing->flags & MF_NOSECTOR)) { // invisible things don't go into the sector links @@ -794,10 +915,10 @@ void P_SetThingPosition(mobj_t *thing) { if (thing->eflags & MFE_VERTICALFLIP) { - if (thing->z + thing->height >= thing->subsector->sector->ceilingheight) + if (thing->z + thing->height >= tceilz) thing->eflags |= MFE_JUSTSTEPPEDDOWN; } - else if (thing->z <= thing->subsector->sector->floorheight) + else if (thing->z <= tfloorz) thing->eflags |= MFE_JUSTSTEPPEDDOWN; } } diff --git a/src/p_mobj.c b/src/p_mobj.c index e85e25b0..9c6ce831 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -31,6 +31,9 @@ #include "i_video.h" #include "lua_hook.h" #include "b_bot.h" +#ifdef ESLOPE +#include "p_slopes.h" +#endif // protos. static CV_PossibleValue_t viewheight_cons_t[] = {{16, "MIN"}, {56, "MAX"}, {0, NULL}}; @@ -700,15 +703,75 @@ boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover) || ((rover->flags & FF_BLOCKOTHERS) && !mobj->player))) return false; - if (mobj->z > *rover->topheight) + fixed_t topheight = *rover->topheight; + fixed_t bottomheight = *rover->bottomheight; + +/*#ifdef ESLOPE + if (rover->t_slope) + topheight = P_GetZAt(rover->t_slope, mobj->x, mobj->y); + if (rover->b_slope) + bottomheight = P_GetZAt(rover->b_slope, mobj->x, mobj->y); +#endif*/ + + if (mobj->z > topheight) return false; - if (mobj->z + mobj->height < *rover->bottomheight) + if (mobj->z + mobj->height < bottomheight) return false; return true; } +fixed_t P_GetMobjZAtSecF(mobj_t *mobj, sector_t *sector) // SRB2CBTODO: This needs to be over all the code +{ + I_Assert(mobj != NULL); +#ifdef ESLOPE + if (sector->f_slope) + return P_GetZAt(sector->f_slope, mobj->x, mobj->y); + else +#endif + return sector->floorheight; +} + +fixed_t P_GetMobjZAtF(mobj_t *mobj) // SRB2CBTODO: This needs to be over all the code +{ + I_Assert(mobj != NULL); + sector_t *sector; + sector = R_PointInSubsector(mobj->x, mobj->y)->sector; + +#ifdef ESLOPE + if (sector->f_slope) + return P_GetZAt(sector->f_slope, mobj->x, mobj->y); + else +#endif + return sector->floorheight; +} + +fixed_t P_GetMobjZAtSecC(mobj_t *mobj, sector_t *sector) // SRB2CBTODO: This needs to be over all the code +{ + I_Assert(mobj != NULL); +#ifdef ESLOPE + if (sector->c_slope) + return P_GetZAt(sector->c_slope, mobj->x, mobj->y); + else +#endif + return sector->ceilingheight; +} + +fixed_t P_GetMobjZAtC(mobj_t *mobj) // SRB2CBTODO: This needs to be over all the code +{ + I_Assert(mobj != NULL); + sector_t *sector; + sector = R_PointInSubsector(mobj->x, mobj->y)->sector; + +#ifdef ESLOPE + if (sector->c_slope) + return P_GetZAt(sector->c_slope, mobj->x, mobj->y); + else +#endif + return sector->ceilingheight; +} + static void P_PlayerFlip(mobj_t *mo) { if (!mo->player) @@ -2455,6 +2518,11 @@ void P_MobjCheckWater(mobj_t *mobj) // Default if no water exists. mobj->watertop = mobj->waterbottom = mobj->subsector->sector->floorheight - 1000*FRACUNIT; +#ifdef ESLOPE // Set the correct waterbottom/top to be below the lowest point of the slope + if (mobj->subsector->sector->f_slope) + mobj->watertop = mobj->waterbottom = mobj->subsector->sector->f_slope->lowz - 1000*FRACUNIT; +#endif + // Reset water state. mobj->eflags &= ~(MFE_UNDERWATER|MFE_TOUCHWATER|MFE_GOOWATER); @@ -2465,34 +2533,45 @@ void P_MobjCheckWater(mobj_t *mobj) || ((rover->flags & FF_BLOCKOTHERS) && !mobj->player))) continue; + fixed_t topheight = *rover->topheight; + fixed_t bottomheight = *rover->bottomheight; + +/*#ifdef ESLOPE + if (rover->t_slope) + topheight = P_GetZAt(rover->t_slope, mobj->x, mobj->y); + + if (rover->b_slope) + bottomheight = P_GetZAt(rover->b_slope, mobj->x, mobj->y); +#endif*/ + if (mobj->eflags & MFE_VERTICALFLIP) { - if (*rover->topheight < (thingtop - FixedMul(mobj->info->height/2, mobj->scale)) - || *rover->bottomheight > thingtop) + if (topheight < (thingtop - FixedMul(mobj->info->height/2, mobj->scale)) + || bottomheight > thingtop) continue; } else { - if (*rover->topheight < mobj->z - || *rover->bottomheight > (mobj->z + FixedMul(mobj->info->height/2, mobj->scale))) + if (topheight < mobj->z + || bottomheight > (mobj->z + FixedMul(mobj->info->height/2, mobj->scale))) continue; } // Set the watertop and waterbottom - mobj->watertop = *rover->topheight; - mobj->waterbottom = *rover->bottomheight; + mobj->watertop = topheight; + mobj->waterbottom = bottomheight; // Just touching the water? - if (((mobj->eflags & MFE_VERTICALFLIP) && thingtop - FixedMul(mobj->info->height, mobj->scale) < *rover->bottomheight) - || (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z + FixedMul(mobj->info->height, mobj->scale) > *rover->topheight)) + if (((mobj->eflags & MFE_VERTICALFLIP) && thingtop - FixedMul(mobj->info->height, mobj->scale) < bottomheight) + || (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z + FixedMul(mobj->info->height, mobj->scale) > topheight)) { mobj->eflags |= MFE_TOUCHWATER; if (rover->flags & FF_GOOWATER && !(mobj->flags & MF_NOGRAVITY)) mobj->eflags |= MFE_GOOWATER; } // Actually in the water? - if (((mobj->eflags & MFE_VERTICALFLIP) && thingtop - FixedMul(mobj->info->height/2, mobj->scale) > *rover->bottomheight) - || (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z + FixedMul(mobj->info->height/2, mobj->scale) < *rover->topheight)) + if (((mobj->eflags & MFE_VERTICALFLIP) && thingtop - FixedMul(mobj->info->height/2, mobj->scale) > bottomheight) + || (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z + FixedMul(mobj->info->height/2, mobj->scale) < topheight)) { mobj->eflags |= MFE_UNDERWATER; if (rover->flags & FF_GOOWATER && !(mobj->flags & MF_NOGRAVITY)) diff --git a/src/p_mobj.h b/src/p_mobj.h index 6d120c47..4acdde18 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -28,6 +28,11 @@ // Needs precompiled tables/data structures. #include "info.h" +// For slope code, we need v3float_t +#ifdef ESLOPE +#include "m_vector.h" +#endif + // // NOTES: mobj_t // @@ -349,6 +354,11 @@ typedef struct mobj_s INT32 cusval; INT32 cvmem; +#ifdef ESLOPE + angle_t pitchangle; + v3float_t vector; +#endif + // WARNING: New fields must be added separately to savegame and Lua. } mobj_t; diff --git a/src/p_slopes.c b/src/p_slopes.c new file mode 100644 index 00000000..c448b580 --- /dev/null +++ b/src/p_slopes.c @@ -0,0 +1,1211 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2004 Stephen McGranahan +// +// This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//-------------------------------------------------------------------------- +// +// DESCRIPTION: +// Slopes +// SoM created 05/10/09 +// ZDoom + Eternity Engine Slopes, ported and enhanced by Kalaron +// +//----------------------------------------------------------------------------- + + +#include "doomdef.h" +#include "r_defs.h" +#include "r_state.h" +#include "m_bbox.h" +#include "z_zone.h" +#include "p_spec.h" +#include "p_slopes.h" +#include "r_main.h" +#include "p_maputl.h" +#include "w_wad.h" + +#ifdef ESLOPE + +// +// P_MakeSlope +// +// Alocates and fill the contents of a slope structure. +// +static pslope_t *P_MakeSlope(const v3float_t *o, const v2float_t *d, + const float zdelta, boolean isceiling) +{ + pslope_t *ret = Z_Malloc(sizeof(pslope_t), PU_LEVEL, NULL); + memset(ret, 0, sizeof(*ret)); + + ret->o.x = FLOAT_TO_FIXED(ret->of.x = o->x); + ret->o.y = FLOAT_TO_FIXED(ret->of.y = o->y); + ret->o.z = FLOAT_TO_FIXED(ret->of.z = o->z); + + ret->d.x = FLOAT_TO_FIXED(ret->df.x = d->x); + ret->d.y = FLOAT_TO_FIXED(ret->df.y = d->y); + + ret->zdelta = FLOAT_TO_FIXED(ret->zdeltaf = zdelta); + + // d = direction (v2float_t) + // + // direction.x = line->nx; + // direction.y = line->ny; + // + // o = origin (v3float_t) + // origin.x = (FIXED_TO_FLOAT(line->v2->x) + FIXED_TO_FLOAT(line->v1->x)) * 0.5f; + // origin.y = (FIXED_TO_FLOAT(line->v2->y) + FIXED_TO_FLOAT(line->v1->y)) * 0.5f; + + { + // Now calculate the normal of the plane! + v3float_t v1, v2, v3, d1, d2; + float len; + + v1.x = o->x; + v1.y = o->y; + v1.z = o->z; + + v2.x = v1.x; + v2.y = v1.y + 10.0f; + v2.z = P_GetZAtf(ret, v2.x, v2.y); + + v3.x = v1.x + 10.0f; + v3.y = v1.y; + v3.z = P_GetZAtf(ret, v3.x, v3.y); + + if (isceiling) + { + M_SubVec3f(&d1, &v1, &v3); + M_SubVec3f(&d2, &v2, &v3); + } + else + { + M_SubVec3f(&d1, &v1, &v2); + M_SubVec3f(&d2, &v3, &v2); + } + + M_CrossProduct3f(&ret->normalf, &d1, &d2); + + // Cross product length + len = (float)sqrt(ret->normalf.x * ret->normalf.x + + ret->normalf.y * ret->normalf.y + + ret->normalf.z * ret->normalf.z); + +#ifdef SLOPETHINGS + if (len == 0) + { + // Only happens when all vertices in this sector are on the same line. + // Let's just ignore this case. + CONS_Printf("Slope thing at (%d,%d) lies directly on its target line.\n", int(x>>16), int(y>>16)); + return; + } +#endif + + ret->normalf.x /= len; + ret->normalf.y /= len; + ret->normalf.z /= len; + + // ZDoom + // cross = ret->normalf + + // Fix backward normals + if ((ret->normalf.z < 0 && !isceiling) || (ret->normalf.z > 0 && isceiling)) + { + ret->normalf.x = -ret->normalf.x; + ret->normalf.y = -ret->normalf.x; + ret->normalf.z = -ret->normalf.x; + } + + } + + return ret; +} + +// +// P_CopySlope +// +// Allocates and returns a copy of the given slope structure. +// +static pslope_t *P_CopySlope(const pslope_t *src) +{ + pslope_t *ret = Z_Malloc(sizeof(pslope_t), PU_LEVEL, NULL); + memcpy(ret, src, sizeof(*ret)); + + return ret; +} + +// +// P_MakeLineNormal +// +// Calculates a 2D normal for the given line and stores it in the line +// +void P_MakeLineNormal(line_t *line) +{ + float linedx, linedy, length; + + // SRB2CBTODO: Give linedefs an fx+fy(float xy coords)? + // May cause slow downs since the float would always have to be converted/updated + linedx = FIXED_TO_FLOAT(line->v2->x) - FIXED_TO_FLOAT(line->v1->x); + linedy = FIXED_TO_FLOAT(line->v2->y) - FIXED_TO_FLOAT(line->v1->y); + + length = (float)sqrt(linedx * linedx + linedy * linedy); + line->nx = linedy / length; + line->ny = -linedx / length; + line->len = length; +} + +// +// P_GetExtent +// +// Returns the distance to the first line within the sector that +// is intersected by a line parallel to the plane normal with the point (ox, oy) +// +static float P_GetExtent(sector_t *sector, line_t *line, v3float_t *o, v2float_t *d) +{ + // ZDoom code reference: v3float_t = vertex_t + float fardist = -1.0f; + size_t i; + + // Find furthest vertex from the reference line. It, along with the two ends + // of the line, will define the plane. + // SRB2CBTODO: Use a formula to get the slope to slide objects depending on how steep + for(i = 0; i < sector->linecount; i++) + { + line_t *li = sector->lines[i]; + float dist; + + // Don't compare to the slope line. + if(li == line) + continue; + + // ZDoom code in P_AlignPlane + // dist = fabs((double(line->v1->y) - vert->y) * line->dx - (double(line->v1->x) - vert->x) * line->dy); + dist = (float)fabs((FIXED_TO_FLOAT(li->v1->x) - o->x) * d->x + (FIXED_TO_FLOAT(li->v1->y) - o->y) * d->y); + if(dist > fardist) + fardist = dist; + + dist = (float)fabs((FIXED_TO_FLOAT(li->v2->x) - o->x) * d->x + (FIXED_TO_FLOAT(li->v2->y) - o->y) * d->y); + if(dist > fardist) + fardist = dist; + } + + return fardist; +} + + +// +// P_SpawnSlope_Line +// +// Creates one or more slopes based on the given line type and front/back +// sectors. +// Kalaron: Check if dynamic slopes need recalculation +// +void P_SpawnSlope_Line(int linenum) +{ + // With dynamic slopes, it's fine to just leave this function as normal, + // because checking to see if a slope had changed will waste more memory than + // if the slope was just updated when called + line_t *line = lines + linenum; + int special = line->special; + pslope_t *fslope = NULL, *cslope = NULL; + v3float_t origin, point; + v2float_t direction; + float dz, extent; + + boolean frontfloor = (special == 386 || special == 388 || special == 393); + boolean backfloor = (special == 389 || special == 391 || special == 392); + boolean frontceil = (special == 387 || special == 388 || special == 392); + boolean backceil = (special == 390 || special == 391 || special == 393); + + if(!frontfloor && !backfloor && !frontceil && !backceil) + { + CONS_Printf("P_SpawnSlope_Line called with non-slope line special.\n"); + return; + } + + if(!line->frontsector || !line->backsector) + { + CONS_Printf("P_SpawnSlope_Line used on a line without two sides.\n"); + return; + } + + // SRB2CBTODO: Transform origin relative to the bounds of an individual FOF + origin.x = (FIXED_TO_FLOAT(line->v2->x) + FIXED_TO_FLOAT(line->v1->x)) * 0.5f; + origin.y = (FIXED_TO_FLOAT(line->v2->y) + FIXED_TO_FLOAT(line->v1->y)) * 0.5f; + + // For FOF slopes, make a special function to copy to the xy origin & direction relative to the position of the FOF on the map! + if(frontfloor || frontceil) + { + origin.z = FIXED_TO_FLOAT(line->backsector->floorheight); + direction.x = line->nx; + direction.y = line->ny; + + extent = P_GetExtent(line->frontsector, line, &origin, &direction); + + if(extent < 0.0f) + { + CONS_Printf("P_SpawnSlope_Line failed to get frontsector extent on line number %i\n", linenum); + return; + } + + // reposition the origin according to the extent + point.x = origin.x + direction.x * extent; + point.y = origin.y + direction.y * extent; + direction.x = -direction.x; + direction.y = -direction.y; + + // TODO: We take origin and point 's xy values and translate them to the center of an FOF! + + if(frontfloor) + { + + point.z = FIXED_TO_FLOAT(line->frontsector->floorheight); // Startz + dz = (FIXED_TO_FLOAT(line->backsector->floorheight) - point.z) / extent; // Destinationz + + // In P_SpawnSlopeLine the origin is the centerpoint of the sourcelinedef + + int slopeangle = 0; // All floors by default have no slope (an angle of 0, completely flat) + + v3float_t A = origin; // = line source + v3float_t B = point; // destination's value + v3float_t C = origin; // Point used to make a right triangle from A & B + + C.z = point.z; + + // To find the "angle" of a slope, we make a right triangle out of the points we have, + // point A - is point 1 of the hypotenuse, + // point B - is point 2 of the hypotenuse + // point C - has the same Z value as point b, and the same XY value as A + // + // We want to find the angle accross from the right angle + // so we use some triginometry to find the angle(fun, right?) + // We want to find the tanjent of this angle, this is: + // Opposite + // ------- = tan(x) + // Adjecent + // But actually tan doesn't do want we really want, we have to use atan to find the actual angle of the triangle's corner + float triangopplength = abs(B.z - A.z); + float triangadjlength = sqrt((B.x-C.x)*(B.x-C.x) + (B.y - C.y)*(B.y - C.y)); + //float trianghyplength = sqrt(triangopplength*triangopplength + triangadjlength*triangadjlength); // This is the hypotenuse + + // So tanjent = opposite divided by adjecent + float tanrelat = triangopplength/ triangadjlength; // tanjent = opposite / adjecent + slopeangle = atan(tanrelat)* 180 / M_PI; // Now we use atan: *180 /M_PI is needed to convert the value into degrees + + fslope = line->frontsector->f_slope = + P_MakeSlope(&point, &direction, dz, false); + + // Now remember that f_slope IS a vector + // fslope->o = origin 3D point 1 of the vector + // fslope->d = destination 3D point 2 of the vector + // fslope->normal is a 3D line perpendicular to the 3D vector + + // Sync the linedata of the line that started this slope + // SRB2CBTODO: Anything special for remote(control sector)-based slopes later? + line->frontsector->f_slope->sourceline = line; + + // To find the real highz/lowz of a slope, you need to check all the vertexes + // in the slope's sector with P_GetZAt to get the REAL lowz & highz + // Although these slopes are set by floorheights the ANGLE is what a slope is, + // so technically any slope can extend on forever (they are just bound by sectors) + // *You can use sourceline as a reference to see if two slopes really are the same + + // Default points for high and low + fixed_t highest = point.z > origin.z ? point.z : origin.z; + fixed_t lowest = point.z < origin.z ? point.z : origin.z; + highest = FLOAT_TO_FIXED(highest); + lowest = FLOAT_TO_FIXED(lowest); + + // Now check to see what the REAL high and low points of the slope inside the sector + size_t l; + + for (l = 0; l < line->frontsector->linecount; l++) + { + if (P_GetZAt(line->frontsector->f_slope, line->frontsector->lines[l]->v1->x, line->frontsector->lines[l]->v1->y) > highest) + highest = P_GetZAt(line->frontsector->f_slope, line->frontsector->lines[l]->v1->x, line->frontsector->lines[l]->v1->y); + + if (P_GetZAt(line->frontsector->f_slope, line->frontsector->lines[l]->v1->x, line->frontsector->lines[l]->v1->y) < lowest) + lowest = P_GetZAt(line->frontsector->f_slope, line->frontsector->lines[l]->v1->x, line->frontsector->lines[l]->v1->y); + } + + // Sets extra clipping data for the frontsector's slope + fslope->highz = line->frontsector->f_slope->highz = highest; + fslope->lowz = line->frontsector->f_slope->lowz = lowest; + + fslope->zangle = slopeangle; + fslope->xydirection = R_PointToAngle2(FLOAT_TO_FIXED(A.x), FLOAT_TO_FIXED(A.y), FLOAT_TO_FIXED(B.x), FLOAT_TO_FIXED(B.y))/(ANGLE_45/45); + + secplane_t *srcplane = Z_Calloc(sizeof(*srcplane), PU_LEVEL, NULL); + // ZDoom secplane port! YAY + // ret = f_slope or c_slope + srcplane->a = FLOAT_TO_FIXED (fslope->normalf.x); // cross[0] + srcplane->b = FLOAT_TO_FIXED (fslope->normalf.y); // cross[1] + srcplane->c = FLOAT_TO_FIXED (fslope->normalf.z); // cross[2] + srcplane->ic = DivScale32 (1, srcplane->c); // (1 << 32/srcplane->c) or FLOAT_TO_FIXED(1.0f/cross[2]); + + // destheight takes the destination height used in dz + srcplane->d = -TMulScale16 (srcplane->a, line->v1->x, // x + srcplane->b, line->v1->y, // y + srcplane->c, line->backsector->floorheight); // z + + // Sync the secplane! + fslope->secplane = line->frontsector->f_slope->secplane = *srcplane; + + } + if(frontceil) + { + point.z = FIXED_TO_FLOAT(line->frontsector->ceilingheight); + dz = (FIXED_TO_FLOAT(line->backsector->ceilingheight) - point.z) / extent; + + cslope = line->frontsector->c_slope = + P_MakeSlope(&point, &direction, dz, true); + + // Sync the linedata of the line that started this slope + // SRB2CBTODO: Anything special for remote(control sector)-based slopes later? + line->frontsector->c_slope->sourceline = line; + + // Remember the way the slope is formed + fixed_t highest = point.z > origin.z ? point.z : origin.z; + fixed_t lowest = point.z < origin.z ? point.z : origin.z; + highest = FLOAT_TO_FIXED(highest); + lowest = FLOAT_TO_FIXED(lowest); + size_t l; + + for (l = 0; l < line->frontsector->linecount; l++) + { + if (P_GetZAt(line->frontsector->c_slope, line->frontsector->lines[l]->v1->x, line->frontsector->lines[l]->v1->y) > highest) + highest = P_GetZAt(line->frontsector->c_slope, line->frontsector->lines[l]->v1->x, line->frontsector->lines[l]->v1->y); + + if (P_GetZAt(line->frontsector->c_slope, line->frontsector->lines[l]->v1->x, line->frontsector->lines[l]->v1->y) < lowest) + lowest = P_GetZAt(line->frontsector->c_slope, line->frontsector->lines[l]->v1->x, line->frontsector->lines[l]->v1->y); + } + + // This line special sets extra clipping data for the frontsector's slope + cslope->highz = line->frontsector->c_slope->highz = highest; + cslope->lowz = line->frontsector->c_slope->lowz = lowest; + + // SRB2CBTODO: Get XY angle of a slope and then awesome physics! // ESLOPE: + //cslope->zangle = line->frontsector->c_slope->zangle = P_GetSlopezangle(line->frontsector, highvert, lowvert); + //100*(ANG45/45);//R_PointToAngle2(direction.x, direction.y, origin.x, origin.y); + // Get slope XY angle with secplane_t + secplane_t *srcplane = Z_Calloc(sizeof(*srcplane), PU_LEVEL, NULL); + // ZDoom secplane port! + // secplane_t! woot! + // ret = f_slope or c_slope + srcplane->a = FLOAT_TO_FIXED (cslope->normalf.x); // cross[0] + srcplane->b = FLOAT_TO_FIXED (cslope->normalf.y); // cross[1] + srcplane->c = FLOAT_TO_FIXED (cslope->normalf.z); // cross[2] + //plane->ic = FLOAT_TO_FIXED (1.f/cross[2]); + srcplane->ic = DivScale32 (1, srcplane->c); // (1 << 32/srcplane->c) +#ifdef SLOPETHINGS // For setting thing-based slopes + srcplane->d = -TMulScale16 (plane->a, x, + plane->b, y, + plane->c, z); +#endif + //srcheight = isceiling ? sec->GetPlaneTexZ(sector_t::floor) : sec->GetPlaneTexZ(sector_t::ceiling); + //destheight = isceiling ? refsec->GetPlaneTexZ(sector_t::floor) : refsec->GetPlaneTexZ(sector_t::ceiling); + //P_GetZAtf(ret, v2.x, v2.y) + // destheight takes the destination height used in dz + srcplane->d = -TMulScale16 (srcplane->a, line->v1->x, + srcplane->b, line->v1->y, + srcplane->c, line->backsector->ceilingheight); + + // Sync the secplane! + cslope->secplane = line->frontsector->c_slope->secplane = *srcplane; + } + } + if(backfloor || backceil) + { + origin.z = FIXED_TO_FLOAT(line->frontsector->floorheight); + // Backsector + direction.x = -line->nx; + direction.y = -line->ny; + + extent = P_GetExtent(line->backsector, line, &origin, &direction); + + if(extent < 0.0f) + { + CONS_Printf("P_SpawnSlope_Line failed to get backsector extent on line number %i\n", linenum); + return; + } + + // reposition the origin according to the extent + point.x = origin.x + direction.x * extent; + point.y = origin.y + direction.y * extent; + direction.x = -direction.x; + direction.y = -direction.y; + + if(backfloor) + { + point.z = FIXED_TO_FLOAT(line->backsector->floorheight); + dz = (FIXED_TO_FLOAT(line->frontsector->floorheight) - point.z) / extent; + + fslope = line->backsector->f_slope = + P_MakeSlope(&point, &direction, dz, false); + + // Sync the linedata of the line that started this slope + // SRB2CBTODO: Anything special for remote(control sector)-based slopes later? + line->backsector->f_slope->sourceline = line; + + int slopeangle = 0; // All floors by default have no slope (an angle of 0) + + v3float_t A = origin; // = line source + v3float_t B = point; // destination's value + v3float_t C = origin; + + C.z = point.z; + + // To find the "angle" of a slope, we make a right triangle out of the points we have, + // point A - is point 1 of the hypotenuse, + // point B - is point 2 of the hypotenuse + // point C - has the same Z value as point b, and the same XY value as A + // + // We want to find the angle accross from the right angle + // so we use some triginometry to find the angle(fun, right?) + // We want to find the tanjent of this angle, this is: + // Opposite + // ------- = tan(x) + // Adjecent + // But actually tan doesn't do want we really want, we have to use atan to find the actual angle of the triangle's corner + float triangopplength = abs(B.z - A.z); + float triangadjlength = sqrt((B.x-C.x)*(B.x-C.x) + (B.y - C.y)*(B.y - C.y)); + //float trianghyplength = sqrt(triangopplength*triangopplength + triangadjlength*triangadjlength); // This is the hypotenuse + + // So tanjent = opposite divided by adjecent + float tanrelat = triangopplength/ triangadjlength; // tanjent = opposite / adjecent + slopeangle = atan(tanrelat)* 180 / M_PI; // Now we use atan - *180 /M_PI is needed to convert the value into degrees + + // Remember the way the slope is formed + fixed_t highest = point.z > origin.z ? point.z : origin.z; + fixed_t lowest = point.z < origin.z ? point.z : origin.z; + highest = FLOAT_TO_FIXED(highest); + lowest = FLOAT_TO_FIXED(lowest); + size_t l; + + for (l = 0; l < line->backsector->linecount; l++) + { + if (P_GetZAt(line->backsector->f_slope, line->backsector->lines[l]->v1->x, line->backsector->lines[l]->v1->y) > highest) + highest = P_GetZAt(line->backsector->f_slope, line->backsector->lines[l]->v1->x, line->backsector->lines[l]->v1->y); + + if (P_GetZAt(line->backsector->f_slope, line->backsector->lines[l]->v1->x, line->backsector->lines[l]->v1->y) < lowest) + lowest = P_GetZAt(line->backsector->f_slope, line->backsector->lines[l]->v1->x, line->backsector->lines[l]->v1->y); + } + + // This line special sets extra clipping data for the frontsector's slope + fslope->highz = line->backsector->f_slope->highz = highest; + fslope->lowz = line->backsector->f_slope->lowz = lowest; + + fslope->zangle = slopeangle; + // Get slope XY angle with secplane_t + secplane_t *srcplane = Z_Calloc(sizeof(*srcplane), PU_LEVEL, NULL); + // ZDoom secplane port! + // secplane_t! woot! + // ret = f_slope or c_slope + srcplane->a = FLOAT_TO_FIXED (fslope->normalf.x); // cross[0] + srcplane->b = FLOAT_TO_FIXED (fslope->normalf.y); // cross[1] + srcplane->c = FLOAT_TO_FIXED (fslope->normalf.z); // cross[2] + //plane->ic = FLOAT_TO_FIXED (1.f/cross[2]); + srcplane->ic = DivScale32 (1, srcplane->c); // (1 << 32/srcplane->c) +#ifdef SLOPETHINGS // For setting thing-based slopes + srcplane->d = -TMulScale16 (plane->a, x, + plane->b, y, + plane->c, z); +#endif + //srcheight = isceiling ? sec->GetPlaneTexZ(sector_t::floor) : sec->GetPlaneTexZ(sector_t::ceiling); + //destheight = isceiling ? refsec->GetPlaneTexZ(sector_t::floor) : refsec->GetPlaneTexZ(sector_t::ceiling); + //P_GetZAtf(ret, v2.x, v2.y) + // destheight takes the destination height used in dz + srcplane->d = -TMulScale16 (srcplane->a, line->v1->x, + srcplane->b, line->v1->y, + srcplane->c, line->frontsector->floorheight); + + // Sync the secplane! + fslope->secplane = line->backsector->f_slope->secplane = *srcplane; + } + if(backceil) + { + point.z = FIXED_TO_FLOAT(line->backsector->ceilingheight); + dz = (FIXED_TO_FLOAT(line->frontsector->ceilingheight) - point.z) / extent; + + cslope = line->backsector->c_slope = + P_MakeSlope(&point, &direction, dz, true); + + // Sync the linedata of the line that started this slope + // SRB2CBTODO: Anything special for remote(control sector)-based slopes later? + line->backsector->c_slope->sourceline = line; + + // Remember the way the slope is formed + fixed_t highest = point.z > origin.z ? point.z : origin.z; + fixed_t lowest = point.z < origin.z ? point.z : origin.z; + highest = FLOAT_TO_FIXED(highest); + lowest = FLOAT_TO_FIXED(lowest); + + size_t l; + + for (l = 0; l < line->backsector->linecount; l++) + { + if (P_GetZAt(line->backsector->c_slope, line->backsector->lines[l]->v1->x, line->backsector->lines[l]->v1->y) > highest) + highest = P_GetZAt(line->backsector->c_slope, line->backsector->lines[l]->v1->x, line->backsector->lines[l]->v1->y); + + if (P_GetZAt(line->backsector->c_slope, line->backsector->lines[l]->v1->x, line->backsector->lines[l]->v1->y) < lowest) + lowest = P_GetZAt(line->backsector->c_slope, line->backsector->lines[l]->v1->x, line->backsector->lines[l]->v1->y); + } + + // This line special sets extra clipping data for the backsector's slope + cslope->highz = line->backsector->c_slope->highz = highest; + cslope->lowz = line->backsector->c_slope->lowz = lowest; + + // SRB2CBTODO: Get XY angle of a slope and then awesome physics! // ESLOPE: + //cslope->zangle = line->backsector->c_slope->zangle = P_GetSlopezangle(line->backsector, highvert, lowvert); + //100*(ANG45/45);//R_PointToAngle2(direction.x, direction.y, origin.x, origin.y); + // Get slope XY angle with secplane_t + secplane_t *srcplane = Z_Calloc(sizeof(*srcplane), PU_LEVEL, NULL); + // ZDoom secplane port! + // secplane_t! woot! + // ret = f_slope or c_slope + srcplane->a = FLOAT_TO_FIXED (cslope->normalf.x); // cross[0] + srcplane->b = FLOAT_TO_FIXED (cslope->normalf.y); // cross[1] + srcplane->c = FLOAT_TO_FIXED (cslope->normalf.z); // cross[2] + //plane->ic = FLOAT_TO_FIXED (1.f/cross[2]); + srcplane->ic = DivScale32 (1, srcplane->c); // (1 << 32/srcplane->c) +#ifdef SLOPETHINGS // For setting thing-based slopes + srcplane->d = -TMulScale16 (plane->a, x, + plane->b, y, + plane->c, z); +#endif + //srcheight = isceiling ? sec->GetPlaneTexZ(sector_t::floor) : sec->GetPlaneTexZ(sector_t::ceiling); + //destheight = isceiling ? refsec->GetPlaneTexZ(sector_t::floor) : refsec->GetPlaneTexZ(sector_t::ceiling); + //P_GetZAtf(ret, v2.x, v2.y) + // destheight takes the destination height used in dz + srcplane->d = -TMulScale16 (srcplane->a, line->v1->x, + srcplane->b, line->v1->y, + srcplane->c, line->frontsector->ceilingheight); + + // Sync the secplane! + cslope->secplane = line->backsector->c_slope->secplane = *srcplane; + } + } + + if(!line->tag) + return; +} + + + +// +// P_CopySectorSlope +// +// Searches through tagged sectors and copies +// +void P_CopySectorSlope(line_t *line) +{ + sector_t *fsec = line->frontsector; + int i, special = line->special; + + // Check for copy linedefs + for(i = -1; (i = P_FindSectorFromLineTag(line, i)) >= 0;) + { + sector_t *srcsec = sectors + i; + + if((special - 393) & 1 && !fsec->f_slope && srcsec->f_slope) + fsec->f_slope = P_CopySlope(srcsec->f_slope); + if((special - 393) & 2 && !fsec->c_slope && srcsec->c_slope) + fsec->c_slope = P_CopySlope(srcsec->c_slope); + } + + //SRB2CBTODO: ESLOPE: Maybe we do need it for another to check for a plane slope? + line->special = 0; // Linedef was use to set slopes, it finished its job, so now make it a normal linedef +} + + +#include "byteptr.h" + +/* +typedef struct +{ + fixed_t z1; + fixed_t z2; +} mapvert_t;*/ + +#include "p_setup.h" +#include "p_local.h" + +//========================================================================== +// +// P_SetSlopesFromVertexHeights +// +//========================================================================== +void P_SetSlopesFromVertexHeights(lumpnum_t lumpnum) +{ + mapthing_t *mt; + boolean vt_found = false; + size_t i, j, k, l, q; + + //size_t i; + //mapthing_t *mt; + char *data; + char *datastart; + + // SRB2CBTODO: WHAT IS (5 * sizeof (short))?! It = 10 + // anything else seems to make a map not load properly, + // but this hard-coded value MUST have some reason for being what it is + size_t snummapthings = W_LumpLength(lumpnum) / (5 * sizeof (short)); + mapthing_t *smapthings = Z_Calloc(snummapthings * sizeof (*smapthings), PU_LEVEL, NULL); + fixed_t x, y; + sector_t *sector; + // Spawn axis points first so they are + // at the front of the list for fast searching. + data = datastart = W_CacheLumpNum(lumpnum, PU_LEVEL); + mt = smapthings; + for (i = 0; i < snummapthings; i++, mt++) + { + mt->x = READINT16(data); + mt->y = READINT16(data); + mt->angle = READINT16(data); + mt->type = READINT16(data); + mt->options = READINT16(data); + // mt->z hasn't been set yet! + //mt->extrainfo = (byte)(mt->type >> 12); // slope things are special, they have a bigger range of types + + //mt->type &= 4095; // SRB2CBTODO: WHAT IS THIS???? Mobj type limits?!!!! + x = mt->x*FRACUNIT; + y = mt->y*FRACUNIT; + sector = R_PointInSubsector(x, y)->sector; + // Z for objects +#ifdef ESLOPE + if (sector->f_slope) + mt->z = (short)(P_GetZAt(sector->f_slope, x, y)>>FRACBITS); + else +#endif + mt->z = (short)(sector->floorheight>>FRACBITS); + + mt->z = mt->z + (mt->options >> ZSHIFT); + + if (mt->type == THING_VertexFloorZ || mt->type == THING_VertexCeilingZ) // THING_VertexFloorZ + { + for(l = 0; l < numvertexes; l++) + { + if (vertexes[l].x == mt->x*FRACUNIT && vertexes[l].y == mt->y*FRACUNIT) + { + if (mt->type == THING_VertexFloorZ) + { + vertexes[l].z = mt->z*FRACUNIT; + //I_Error("Z value: %i", vertexes[l].z/FRACUNIT); + + } + else + { + vertexes[l].z = mt->z*FRACUNIT; // celing floor + } + vt_found = true; + } + } + //mt->type = 0; // VPHYSICS: Dynamic slopes + + + + + + + if (vt_found) + { + for (k = 0; k < numsectors; k++) + { + sector_t *sec = §ors[k]; + if (sec->linecount != 3) continue; // only works with triangular sectors + + v3float_t vt1, vt2, vt3; // cross = ret->normalf + v3float_t vec1, vec2; + + int vi1, vi2, vi3; + + vi1 = (int)(sec->lines[0]->v1 - vertexes); + vi2 = (int)(sec->lines[0]->v2 - vertexes); + vi3 = (sec->lines[1]->v1 == sec->lines[0]->v1 || sec->lines[1]->v1 == sec->lines[0]->v2)? + (int)(sec->lines[1]->v2 - vertexes) : (int)(sec->lines[1]->v1 - vertexes); + + //if (vertexes[vi1].z) + // I_Error("OSNAP %i", vertexes[vi1].z/FRACUNIT); + //if (vertexes[vi2].z) + // I_Error("OSNAP %i", vertexes[vi2].z/FRACUNIT); + //if (vertexes[vi3].z) + // I_Error("OSNAP %i", vertexes[vi3].z/FRACUNIT); + + //I_Error("%i, %i", mt->z*FRACUNIT, vertexes[vi1].z); + + //I_Error("%i, %i, %i", mt->x, mt->y, mt->z); + //P_SpawnMobj(mt->x*FRACUNIT, mt->y*FRACUNIT, mt->z*FRACUNIT, MT_RING); + + // TODO: Make sure not to spawn in the same place 2x! (we need an object in every vertex of the + // triangle sector to setup the real vertex slopes + // Check for the vertexes of all sectors + for(q = 0; q < numvertexes; q++) + { + if (vertexes[q].x == mt->x*FRACUNIT && vertexes[q].y == mt->y*FRACUNIT) + { + //I_Error("yeah %i", vertexes[q].z); + P_SpawnMobj(vertexes[q].x, vertexes[q].y, vertexes[q].z, MT_RING); +#if 0 + if ((mt->y*FRACUNIT == vertexes[vi1].y && mt->x*FRACUNIT == vertexes[vi1].x && mt->z*FRACUNIT == vertexes[vi1].z) + && !(mt->y*FRACUNIT == vertexes[vi2].y && mt->x*FRACUNIT == vertexes[vi2].x && mt->z*FRACUNIT == vertexes[vi2].z) + && !(mt->y*FRACUNIT == vertexes[vi3].y && mt->x*FRACUNIT == vertexes[vi3].x && mt->z*FRACUNIT == vertexes[vi3].z)) + P_SpawnMobj(vertexes[vi1].x, vertexes[vi1].y, vertexes[vi1].z, MT_RING); + else if ((mt->y*FRACUNIT == vertexes[vi2].y && mt->x*FRACUNIT == vertexes[vi2].x && mt->z*FRACUNIT == vertexes[vi2].z) + && !(mt->y*FRACUNIT == vertexes[vi1].y && mt->x*FRACUNIT == vertexes[vi1].x && mt->z*FRACUNIT == vertexes[vi1].z) + && !(mt->y*FRACUNIT == vertexes[vi3].y && mt->x*FRACUNIT == vertexes[vi3].x && mt->z*FRACUNIT == vertexes[vi3].z)) + P_SpawnMobj(vertexes[vi2].x, vertexes[vi2].y, vertexes[vi2].z, MT_BOUNCETV); + else if ((mt->y*FRACUNIT == vertexes[vi3].y && mt->x*FRACUNIT == vertexes[vi3].x && mt->z*FRACUNIT == vertexes[vi3].z) + && !(mt->y*FRACUNIT == vertexes[vi2].y && mt->x*FRACUNIT == vertexes[vi2].x && mt->z*FRACUNIT == vertexes[vi2].z) + && !(mt->y*FRACUNIT == vertexes[vi1].y && mt->x*FRACUNIT == vertexes[vi1].x && mt->z*FRACUNIT == vertexes[vi1].z)) + P_SpawnMobj(vertexes[vi3].x, vertexes[vi3].y, vertexes[vi3].z, MT_GFZFLOWER1); + else +#endif + continue; + } + } + + vt1.x = FIXED_TO_FLOAT(vertexes[vi1].x); + vt1.y = FIXED_TO_FLOAT(vertexes[vi1].y); + vt2.x = FIXED_TO_FLOAT(vertexes[vi2].x); + vt2.y = FIXED_TO_FLOAT(vertexes[vi2].y); + vt3.x = FIXED_TO_FLOAT(vertexes[vi3].x); + vt3.y = FIXED_TO_FLOAT(vertexes[vi3].y); + + for(j = 0; j < 2; j++) + { + + fixed_t z3; + //I_Error("Lo hicimos"); + + vt1.z = mt->z;//FIXED_TO_FLOAT(j==0 ? sec->floorheight : sec->ceilingheight); + vt2.z = mt->z;//FIXED_TO_FLOAT(j==0? sec->floorheight : sec->ceilingheight); + z3 = mt->z;//j==0? sec->floorheight : sec->ceilingheight; // Destination height + vt3.z = FIXED_TO_FLOAT(z3); + + if (P_PointOnLineSide(vertexes[vi3].x, vertexes[vi3].y, sec->lines[0]) == 0) + { + vec1.x = vt2.x - vt3.x; + vec1.y = vt2.y - vt3.y; + vec1.z = vt2.z - vt3.z; + + vec2.x = vt1.x - vt3.x; + vec2.y = vt1.y - vt3.y; + vec2.z = vt1.z - vt3.z; + } + else + { + vec1.x = vt1.x - vt3.x; + vec1.y = vt1.y - vt3.y; + vec1.z = vt1.z - vt3.z; + + vec2.x = vt2.x - vt3.x; + vec2.y = vt2.y - vt3.y; + vec2.z = vt2.z - vt3.z; + } + + + pslope_t *ret = Z_Malloc(sizeof(pslope_t), PU_LEVEL, NULL); + memset(ret, 0, sizeof(*ret)); + + { + M_CrossProduct3f(&ret->normalf, &vec1, &vec2); + + // Cross product length + float len = (float)sqrt(ret->normalf.x * ret->normalf.x + + ret->normalf.y * ret->normalf.y + + ret->normalf.z * ret->normalf.z); + + if (len == 0) + { + // Only happens when all vertices in this sector are on the same line. + // Let's just ignore this case. + //CONS_Printf("Slope thing at (%d,%d) lies directly on its target line.\n", (int)(x>>16), (int)(y>>16)); + return; + } + // cross/len + ret->normalf.x /= len; + ret->normalf.y /= len; + ret->normalf.z /= len; + + // ZDoom cross = ret->normalf + // Fix backward normals + if ((ret->normalf.z < 0 && j == 0) || (ret->normalf.z > 0 && j == 1)) + { + // cross = -cross + ret->normalf.x = -ret->normalf.x; + ret->normalf.y = -ret->normalf.x; + ret->normalf.z = -ret->normalf.x; + } + } + + secplane_t *srcplane = Z_Calloc(sizeof(*srcplane), PU_LEVEL, NULL); + + srcplane->a = FLOAT_TO_FIXED (ret->normalf.x); + srcplane->b = FLOAT_TO_FIXED (ret->normalf.y); + srcplane->c = FLOAT_TO_FIXED (ret->normalf.z); + //srcplane->ic = DivScale32 (1, srcplane->c); + srcplane->d = -TMulScale16 (srcplane->a, vertexes[vi3].x, + srcplane->b, vertexes[vi3].y, + srcplane->c, z3); + + if (j == 0) + { + sec->f_slope = ret; + sec->f_slope->secplane = *srcplane; + } + else if (j == 1) + { + sec->c_slope = ret; + sec->c_slope->secplane = *srcplane; + } + } + } + } + + + + + + + + + } + } + Z_Free(datastart); + +#if 0 // UDMF support + for(i = 0; i < numvertexdatas; i++) + { + if (vertexdatas[i].flags & VERTEXFLAG_ZCeilingEnabled) + { + vt_heights[1][i] = vertexdatas[i].zCeiling; + vt_found = true; + } + + if (vertexdatas[i].flags & VERTEXFLAG_ZFloorEnabled) + { + vt_heights[0][i] = vertexdatas[i].zFloor; + vt_found = true; + } + } + + // If vertexdata_t is ever extended for non-slope usage, this will obviously have to be deferred or removed. + delete[] vertexdatas; + vertexdatas = NULL; + numvertexdatas = 0; +#endif + + + + +} + +#include "p_maputl.h" + +#if 0 +static void P_SlopeLineToPointo (int lineid, fixed_t x, fixed_t y, fixed_t z, boolean slopeCeil) +{ + int linenum = -1; + + while ((linenum = P_FindLineFromID (lineid, linenum)) != -1) + { + const line_t *line = &lines[linenum]; + sector_t *sec; + secplane_t *plane; + + if (P_PointOnLineSide (x, y, line) == 0) + { + sec = line->frontsector; + } + else + { + sec = line->backsector; + } + if (sec == NULL) + { + continue; + } + if (slopeCeil) + { + plane = &sec->ceilingplane; + } + else + { + plane = &sec->floorplane; + } + + FVector3 p, v1, v2, cross; + + p[0] = FIXED2FLOAT (line->v1->x); + p[1] = FIXED2FLOAT (line->v1->y); + p[2] = FIXED2FLOAT (plane->ZatPoint (line->v1->x, line->v1->y)); + v1[0] = FIXED2FLOAT (line->dx); + v1[1] = FIXED2FLOAT (line->dy); + v1[2] = FIXED2FLOAT (plane->ZatPoint (line->v2->x, line->v2->y)) - p[2]; + v2[0] = FIXED2FLOAT (x - line->v1->x); + v2[1] = FIXED2FLOAT (y - line->v1->y); + v2[2] = FIXED2FLOAT (z) - p[2]; + + cross = v1 ^ v2; + double len = cross.Length(); + if (len == 0) + { + Printf ("Slope thing at (%d,%d) lies directly on its target line.\n", int(x>>16), int(y>>16)); + return; + } + cross /= len; + // Fix backward normals + if ((cross.Z < 0 && !slopeCeil) || (cross.Z > 0 && slopeCeil)) + { + cross = -cross; + } + + plane->a = FLOAT2FIXED (cross[0]); + plane->b = FLOAT2FIXED (cross[1]); + plane->c = FLOAT2FIXED (cross[2]); + //plane->ic = FLOAT2FIXED (1.f/cross[2]); + plane->ic = DivScale32 (1, plane->c); + plane->d = -TMulScale16 (plane->a, x, + plane->b, y, + plane->c, z); + } +} +#else +#if 0 +// P_SlopeLineToPoint, start from a specific linedef number(not tag) and slope to a mapthing with the angle of the linedef +static void P_SlopeLineToPoint(int linenum) +{ + line_t *line = lines + linenum; + int special = line->special; + pslope_t *fslope = NULL, *cslope = NULL; + v3float_t origin, point; + v2float_t direction; + float dz, extent; + + boolean frontfloor = (special == 386 || special == 388 || special == 393); + boolean backfloor = (special == 389 || special == 391 || special == 392); + boolean frontceil = (special == 387 || special == 388 || special == 392); + boolean backceil = (special == 390 || special == 391 || special == 393); + + // SoM: We don't need the line to retain its special type + line->special = 0; //SRB2CBTODO: ESLOPE: Maybe we do need it for another to check for a plane slope? + + if(!frontfloor && !backfloor && !frontceil && !backceil) + { + CONS_Printf("P_SpawnSlope_Line called with non-slope line special.\n"); + return; + } + + if(!line->frontsector || !line->backsector) + { + CONS_Printf("P_SpawnSlope_Line used on a line without two sides.\n"); + return; + } + + origin.x = (FIXED_TO_FLOAT(line->v2->x) + FIXED_TO_FLOAT(line->v1->x)) * 0.5f; + origin.y = (FIXED_TO_FLOAT(line->v2->y) + FIXED_TO_FLOAT(line->v1->y)) * 0.5f; + + if(frontfloor || frontceil) + { + // Do the front sector + direction.x = line->nx; + direction.y = line->ny; + + extent = P_GetExtent(line->frontsector, line, &origin, &direction); + + if(extent < 0.0f) + { + CONS_Printf("P_SpawnSlope_Line failed to get frontsector extent on line number %i\n", linenum); + return; + } + + // reposition the origin according to the extent + point.x = origin.x + direction.x * extent; + point.y = origin.y + direction.y * extent; + direction.x = -direction.x; + direction.y = -direction.y; + + // CONS_Printf("Test: X: %f, Y: %f\n", origin.x, origin.y); + + if(frontfloor) + { + point.z = FIXED_TO_FLOAT(line->frontsector->floorheight); // Startz + dz = (FIXED_TO_FLOAT(line->backsector->floorheight) - point.z) / extent; // Destinationz + + fslope = line->frontsector->f_slope = + P_MakeSlope(&point, &direction, dz, false); + + // Sync the linedata of the line that started this slope + // SRB2CBTODO: Anything special for remote(control sector)-based slopes later? + line->frontsector->f_slope->sourceline = line; + + // Remember the way the slope is formed + fixed_t highest = line->frontsector->floorheight > line->backsector->floorheight ? + line->frontsector->floorheight : line->backsector->floorheight; + fixed_t lowest = line->frontsector->floorheight < line->backsector->floorheight ? + line->frontsector->floorheight : line->backsector->floorheight; + // This line special sets extra clipping data for the frontsector's slope + fslope->highz = line->frontsector->f_slope->highz = highest; + fslope->lowz = line->frontsector->f_slope->lowz = lowest; + + // SRB2CBTODO: Get XY angle of a slope and then awesome physics! // ESLOPE: + //fslope->zangle = line->frontsector->f_slope->zangle = P_GetSlopezangle(line->frontsector, highvert, lowvert); + //100*(ANG45/45);//R_PointToAngle2(direction.x, direction.y, origin.x, origin.y); + // Get slope XY angle with secplane_t + secplane_t *srcplane = Z_Calloc(sizeof(*srcplane), PU_LEVEL, NULL); + // ZDoom secplane port! + // secplane_t! woot! + // ret = f_slope or c_slope + srcplane->a = FLOAT_TO_FIXED (fslope->normalf.x); // cross[0] + srcplane->b = FLOAT_TO_FIXED (fslope->normalf.y); // cross[1] + srcplane->c = FLOAT_TO_FIXED (fslope->normalf.z); // cross[2] + //plane->ic = FLOAT_TO_FIXED (1.f/cross[2]); + srcplane->ic = DivScale32 (1, srcplane->c); // (1 << 32/srcplane->c) +#ifdef SLOPETHINGS // For setting thing-based slopes + srcplane->d = -TMulScale16 (plane->a, x, + plane->b, y, + plane->c, z); +#endif + //srcheight = isceiling ? sec->GetPlaneTexZ(sector_t::floor) : sec->GetPlaneTexZ(sector_t::ceiling); + //destheight = isceiling ? refsec->GetPlaneTexZ(sector_t::floor) : refsec->GetPlaneTexZ(sector_t::ceiling); + //P_GetZAtf(ret, v2.x, v2.y) + // destheight takes the destination height used in dz + srcplane->d = -TMulScale16 (srcplane->a, line->v1->x, + srcplane->b, line->v1->y, + srcplane->c, line->backsector->floorheight); + + // Sync the secplane! + fslope->secplane = line->frontsector->f_slope->secplane = *srcplane; + + } + } +} +#endif +#endif + + + +//=========================================================================== +// +// P_SpawnSlopeMakers +// +//=========================================================================== +#if 0 +void P_SpawnSlopeMakers (FMapThing *firstmt, FMapThing *lastmt) +{ + FMapThing *mt; + + for (mt = firstmt; mt < lastmt; ++mt) + { + if ((mt->type >= THING_SlopeFloorPointLine && + mt->type <= THING_SetCeilingSlope) || + mt->type==THING_VavoomFloor || mt->type==THING_VavoomCeiling) + { + fixed_t x, y, z; + secplane_t *refplane; + sector_t *sec; + + x = mt->x; + y = mt->y; + sec = P_PointInSector (x, y); + if (mt->type & 1) + { + refplane = &sec->ceilingplane; + } + else + { + refplane = &sec->floorplane; + } + z = refplane->ZatPoint (x, y) + (mt->z); + if (mt->type==THING_VavoomFloor || mt->type==THING_VavoomCeiling) + { + P_VavoomSlope(sec, mt->thingid, x, y, mt->z, mt->type & 1); + } + else if (mt->type <= THING_SlopeCeilingPointLine) + { + P_SlopeLineToPoint (mt->args[0], x, y, z, mt->type & 1); + } + else + { + P_SetSlope (refplane, mt->type & 1, mt->angle, mt->args[0], x, y, z); + } + mt->type = 0; + } + } + + for (mt = firstmt; mt < lastmt; ++mt) + { + if (mt->type == THING_CopyFloorPlane || + mt->type == THING_CopyCeilingPlane) + { + P_CopyPlane (mt->args[0], mt->x, mt->y, mt->type & 1); + mt->type = 0; + } + } + + P_SetSlopesFromVertexHeights(firstmt, lastmt); +} +#endif + + + + +// ============================================================================ +// +// Various utilities related to slopes +// + +// +// P_GetZAt +// +// Returns the height of the sloped plane at (x, y) as a fixed_t +// +fixed_t P_GetZAt(pslope_t *slope, fixed_t x, fixed_t y) +{ + fixed_t dist = FixedMul(x - slope->o.x, slope->d.x) + + FixedMul(y - slope->o.y, slope->d.y); + + return slope->o.z + FixedMul(dist, slope->zdelta); +} + +// +// P_GetZAtf +// +// Returns the height of the sloped plane at (x, y) as a float +// +float P_GetZAtf(pslope_t *slope, float x, float y) +{ + //if (!slope) // SRB2CBTODO: keep this when done with debugging + // I_Error("P_GetZAtf: slope parameter is NULL"); + + float dist = (x - slope->of.x) * slope->df.x + (y - slope->of.y) * slope->df.y; + return slope->of.z + (dist * slope->zdeltaf); +} + +// +// P_DistFromPlanef +// +float P_DistFromPlanef(const v3float_t *point, const v3float_t *pori, + const v3float_t *pnormal) +{ + return (point->x - pori->x) * pnormal->x + + (point->y - pori->y) * pnormal->y + + (point->z - pori->z) * pnormal->z; +} + +// EOF +#endif // #ifdef ESLOPE + diff --git a/src/p_slopes.h b/src/p_slopes.h new file mode 100644 index 00000000..8449c102 --- /dev/null +++ b/src/p_slopes.h @@ -0,0 +1,84 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2004 Stephen McGranahan +// +// This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//-------------------------------------------------------------------------- +// +// DESCRIPTION: +// Slopes +// SoM created 05/10/09 +// +//----------------------------------------------------------------------------- + +#ifndef P_SLOPES_H__ +#define P_SLOPES_H__ + +#ifdef ESLOPE +// P_MakeLineNormal +// Calculates a 2D normal for the given line and stores it in the line +void P_MakeLineNormal(line_t *line); + + +// P_SpawnSlope_Line +// Creates one or more slopes based on the given line type and front/back +// sectors. +void P_SpawnSlope_Line(int linenum); + + +// Loads just map objects that make slopes, +// terrain affecting objects have to be spawned first +void P_SetSlopesFromVertexHeights(lumpnum_t lumpnum); + +typedef enum +{ + THING_SlopeFloorPointLine = 9500, + THING_SlopeCeilingPointLine = 9501, + THING_SetFloorSlope = 9502, + THING_SetCeilingSlope = 9503, + THING_CopyFloorPlane = 9510, + THING_CopyCeilingPlane = 9511, + THING_VavoomFloor=1500, + THING_VavoomCeiling=1501, + THING_VertexFloorZ=1504, + THING_VertexCeilingZ=1505, +} slopething_e; + +// +// P_CopySectorSlope +// +// Searches through tagged sectors and copies +// +void P_CopySectorSlope(line_t *line); + +// Returns the height of the sloped plane at (x, y) as a fixed_t +fixed_t P_GetZAt(pslope_t *slope, fixed_t x, fixed_t y); + + +// Returns the height of the sloped plane at (x, y) as a float +float P_GetZAtf(pslope_t *slope, float x, float y); + + +// Returns the distance of the given point from the given origin and normal. +float P_DistFromPlanef(const v3float_t *point, const v3float_t *pori, + const v3float_t *pnormal); + +#endif + +// EOF +#endif // #ifdef ESLOPE + diff --git a/src/p_spec.c b/src/p_spec.c index 323b93c6..228273de 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -33,6 +33,9 @@ #include "m_misc.h" #include "m_cond.h" //unlock triggers #include "lua_hook.h" // LUAh_LinedefExecute +#ifdef ESLOPE +#include "p_slopes.h" +#endif #ifdef HW3SOUND #include "hardware/hw3sound.h" @@ -4579,16 +4582,27 @@ static void P_RunSpecialSectorCheck(player_t *player, sector_t *sector) return; } + fixed_t f_affectpoint = sector->floorheight; + fixed_t c_affectpoint = sector->ceilingheight; + +#ifdef ESLOPE + if (sector->f_slope) + f_affectpoint = P_GetZAt(sector->f_slope, player->mo->x, player->mo->y); + + if (sector->c_slope) + c_affectpoint = P_GetZAt(sector->c_slope, player->mo->x, player->mo->y); +#endif + // Only go further if on the ground - if ((sector->flags & SF_FLIPSPECIAL_FLOOR) && !(sector->flags & SF_FLIPSPECIAL_CEILING) && player->mo->z != sector->floorheight) + if ((sector->flags & SF_FLIPSPECIAL_FLOOR) && !(sector->flags & SF_FLIPSPECIAL_CEILING) && player->mo->z != f_affectpoint) return; - if ((sector->flags & SF_FLIPSPECIAL_CEILING) && !(sector->flags & SF_FLIPSPECIAL_FLOOR) && player->mo->z + player->mo->height != sector->ceilingheight) + if ((sector->flags & SF_FLIPSPECIAL_CEILING) && !(sector->flags & SF_FLIPSPECIAL_FLOOR) && player->mo->z + player->mo->height != c_affectpoint) return; if ((sector->flags & SF_FLIPSPECIAL_BOTH) - && player->mo->z != sector->floorheight - && player->mo->z + player->mo->height != sector->ceilingheight) + && player->mo->z != f_affectpoint + && player->mo->z + player->mo->height != c_affectpoint) return; P_ProcessSpecialSector(player, sector, NULL); @@ -4749,6 +4763,9 @@ void P_UpdateSpecials(void) // POINT LIMIT P_CheckPointLimit(); + // Kalaron: ...We...have dynamic slopes *YESSSS* + P_SpawnDeferredSpecials(); + // ANIMATE TEXTURES for (anim = anims; anim < lastanim; anim++) { @@ -6500,6 +6517,63 @@ void P_SpawnSpecials(INT32 fromnetsave) P_RunLevelLoadExecutors(); } +#ifdef ESLOPE +// +// P_SpawnDeferredSpecials +// +// SoM: Specials that copy slopes, ect., need to be collected in a separate +// pass +// NOTE: SRB2CBTODO: A new function, P_SpawnDeferredSpecials is needed if objects +// are to be needed in this function, because this function currently needs to be +// done before 'things' are loaded, because slopes are part of this function, +// and slope height adjustments are needed for spawning objects +void P_SpawnDeferredSpecials(void) +{ + size_t i; + line_t *line; + + for(i = 0; i < numlines; i++) + { + line = lines + i; + + switch(line->special) + { + // Slopes, Eternity engine + /*{ 386, "Slope_FrontsectorFloor" }, + { 387, "Slope_FrontsectorCeiling" }, + { 388, "Slope_FrontsectorFloorAndCeiling" }, + { 389, "Slope_BacksectorFloor" }, + { 390, "Slope_BacksectorCeiling" }, + { 391, "Slope_BacksectorFloorAndCeiling" }, + { 392, "Slope_BackFloorAndFrontCeiling" }, + { 393, "Slope_BackCeilingAndFrontFloor" }, + + { 394, "Slope_FrontFloorToTaggedSlope" }, + { 395, "Slope_FrontCeilingToTaggedSlope" }, + { 396, "Slope_FrontFloorAndCeilingToTaggedSlope" },*/ + + // SoM 05/10/09: Slopes // SRB2CBTODO:! + case 386: + case 387: + case 388: + case 389: + case 390: + case 391: + case 392: + case 393: + P_SpawnSlope_Line(i); + break; + // SoM: Copy slopes + case 394: + case 395: + case 396: + P_CopySectorSlope(line); + break; + } + } +} +#endif + /** Adds 3Dfloors as appropriate based on a common control linedef. * * \param line Control linedef to use. @@ -7399,8 +7473,12 @@ void T_Pusher(pusher_t *p) || GETSECSPECIAL(referrer->special, 3) == 3) foundfloor = true; } - else if (!(GETSECSPECIAL(sec->special, 3) == 2 - || GETSECSPECIAL(sec->special, 3) == 3)) + else if ( +#ifdef ESLOPE + (!sec->f_slope) && +#endif + (!(GETSECSPECIAL(sec->special, 3) == 2 + || GETSECSPECIAL(sec->special, 3) == 3))) return; if (p->roverpusher && foundfloor == false) // Not even a 3d floor has the PUSH_MASK. diff --git a/src/p_spec.h b/src/p_spec.h index 7b6a5655..c8cfc76d 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -36,6 +36,11 @@ void P_SpawnSpecials(INT32 fromnetsave); // every tic void P_UpdateSpecials(void); + +#ifdef ESLOPE +void P_SpawnDeferredSpecials(void); +#endif + sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 number); void P_PlayerInSpecialSector(player_t *player); void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *roversector); diff --git a/src/p_user.c b/src/p_user.c index 3c2d34a6..e095f2a9 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1201,6 +1201,87 @@ boolean P_IsObjectOnGround(mobj_t *mo) return false; } +#ifdef ESLOPE +// +// P_IsObjectOnSlope +// +// Returns true if the player is +// on a slope. Takes reverse +// gravity into account. +// +boolean P_IsObjectOnSlope(mobj_t *mo, boolean ceiling) +{ + if (ceiling && (mo->eflags & MFE_VERTICALFLIP)) + { + if ((mo->z + mo->height >= mo->ceilingz) && mo->subsector->sector->c_slope) // SRB2CBTODO: allow being on underside of mobj too? + return true; + } + else + { + if (mo->z <= mo->floorz && mo->subsector->sector->f_slope) + return true; + } + + return false; +} + +// +// P_SlopeGreaterThan +// +// Returns true if the object is on a slope +// that has an angle greater than the value +// +boolean P_SlopeGreaterThan(mobj_t *mo, boolean ceiling, int value) +{ + if (ceiling && (mo->eflags & MFE_VERTICALFLIP)) + { + if ((mo->z + mo->height >= mo->ceilingz) && mo->subsector->sector->c_slope) + { + if (value < mo->subsector->sector->c_slope->zangle) + return true; + } + } + else + { + if (mo->z <= mo->floorz && mo->subsector->sector->f_slope) + { + if (value < mo->subsector->sector->f_slope->zangle) + return true; + } + } + + return false; +} + +// +// P_SlopeLessThan +// +// Returns true if the object is on a slope +// that has an angle less than the value +// +boolean P_SlopeLessThan(mobj_t *mo, boolean ceiling, int value) +{ + if (ceiling && (mo->eflags & MFE_VERTICALFLIP)) + { + if ((mo->z + mo->height >= mo->ceilingz) && mo->subsector->sector->c_slope) + { + if (value < mo->subsector->sector->c_slope->zangle) + return true; + } + } + else + { + if (mo->z <= mo->floorz && mo->subsector->sector->f_slope) + { + if (value < mo->subsector->sector->f_slope->zangle) + return true; + } + } + + return false; +} +#endif + // // P_IsObjectOnGroundIn // diff --git a/src/r_defs.h b/src/r_defs.h index 7f8bd7e1..251140a3 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -224,6 +224,49 @@ typedef struct secplane_t fixed_t a, b, c, d, ic; } secplane_t; +// Kalaron Slopes +#ifdef ESLOPE + +#include "m_vector.h" + +typedef struct +{ + // --- Information used in clipping/projection --- + // Origin vector for the plane + // NOTE: All similarly named entries in this struct do the same thing, + // differing with just 'f' in the name for float: + // o = of, d = df, zdelta = zdeltaf; the only difference is that one's fixed, + // and the one with the 'f' is floating point, for easier reference elsewhere in the code + v3fixed_t o; + v3float_t of; + + // The normal of the 3d plane the slope creates. + v3float_t normalf; + + // 2-Dimentional vector (x, y) normalized. Used to determine distance from + // the origin in 2d mapspace. + v2fixed_t d; + v2float_t df; + + // The rate at which z changes based on distance from the origin plane. + fixed_t zdelta; + float zdeltaf; + + // For comparing when a slope should be rendered + fixed_t lowz; + fixed_t highz; + + // SRB2CBTODO: This could be used for something? + // Determining the relative z values in a slope? + struct line_s *sourceline; + + // This values only check and must be updated if the slope itself is modified + USHORT zangle; // Angle of the plane going up from the ground (not mesured in degrees) + angle_t xydirection; // The direction the slope is facing (north, west, south, etc.) + secplane_t secplane; // Extra data for collision and stuff +} pslope_t; +#endif + typedef enum { SF_FLIPSPECIAL_FLOOR = 1, @@ -337,6 +380,11 @@ typedef struct sector_s precipmobj_t *preciplist; struct mprecipsecnode_s *touching_preciplist; +#ifdef ESLOPE + // Eternity engine slope + pslope_t *f_slope; // floor slope + pslope_t *c_slope; // ceiling slope +#endif // these are saved for netgames, so do not let Lua touch these! // offsets sector spawned with (via linedef type 7) @@ -396,6 +444,12 @@ typedef struct line_s char *text; // a concatination of all front and back texture names, for linedef specials that require a string. INT16 callcount; // no. of calls left before triggering, for the "X calls" linedef specials, defaults to 0 + +#ifdef ESLOPE + // SoM 05/11/09: Pre-calculated 2D normal for the line + float nx, ny; + float len; +#endif } line_t; // diff --git a/src/tables.c b/src/tables.c index fa71effe..cfc17c9c 100644 --- a/src/tables.c +++ b/src/tables.c @@ -2225,9 +2225,6 @@ angle_t tantoangle[2049] = 536870912 }; - -#ifdef NEED_FIXED_VECTOR - static angle_t fineacon[65536*2] = { ANGLE_MAX, 2143707442, 2142143280, 2140943052, 2139931208, 2139039753, 2138233813, 2137492672, 2136802831, 2136154917, 2135542102, 2134959233, 2134402306, 2133868139, 2133354148, 2132858208, 2132378539, 2131913638, 2131462220, 2131023174, 2130595537, 2130178462, 2129771202, 2129373097, 2128983555, 2128602046, 2128228092, 2127861261, 2127501162, 2127147436, 2126799757, 2126457825, @@ -10429,6 +10426,8 @@ FUNCMATH angle_t FixedAcos(fixed_t x) return fineacon[((x<<(FINE_FRACBITS-FRACBITS)))+FRACUNIT]; } +#ifdef NEED_FIXED_VECTOR + // // AngleBetweenVectors // diff --git a/src/tables.h b/src/tables.h index 219d668b..cd6a17ff 100644 --- a/src/tables.h +++ b/src/tables.h @@ -96,12 +96,11 @@ FUNCMATH angle_t FixedAngle(fixed_t fa); // and with a factor, with +factor for (fa/factor) and -factor for (fa*factor) FUNCMATH angle_t FixedAngleC(fixed_t fa, fixed_t factor); - -#ifdef NEED_FIXED_VECTOR - /// The FixedAcos function FUNCMATH angle_t FixedAcos(fixed_t x); +#ifdef NEED_FIXED_VECTOR + /// Fixed Point Vector functions angle_t FV2_AngleBetweenVectors(const vector2_t *Vector1, const vector2_t *Vector2); angle_t FV3_AngleBetweenVectors(const vector3_t *Vector1, const vector3_t *Vector2);