From 2191e5b9de6552c97dcc763a7c0cf7379a4502d7 Mon Sep 17 00:00:00 2001 From: ilag11111 Date: Wed, 1 Oct 2014 13:49:44 -0700 Subject: [PATCH 001/383] Each Time Fix: Multiple players simultaneously entering a sector, e.g. Tails carries one in. --- src/p_floor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_floor.c b/src/p_floor.c index 6d28175eb..7edf04bc8 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -2222,7 +2222,7 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) oldPlayersArea = oldPlayersInArea; } - if ((affectPlayer = P_HavePlayersEnteredArea(playersArea, oldPlayersArea, inAndOut)) != -1) + while ((affectPlayer = P_HavePlayersEnteredArea(playersArea, oldPlayersArea, inAndOut)) != -1) { if (GETSECSPECIAL(sec->special, 2) == 2 || GETSECSPECIAL(sec->special, 2) == 3) { @@ -2252,6 +2252,7 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) // This should now run ONLY the stuff for eachtime->sourceline itself, instead of all trigger linedefs sharing the same tag. // Makes much more sense doing it this way, honestly. P_RunTriggerLinedef(eachtime->sourceline, players[affectPlayer].mo, sec); + oldPlayersArea[affectPlayer]=1; } } From 97b61eb66d3aaa426a55f0703fa7cdcfd3da1049 Mon Sep 17 00:00:00 2001 From: ilag11111 Date: Thu, 2 Oct 2014 10:26:12 -0700 Subject: [PATCH 002/383] Each Time Fix Fix: Don't infinite loop when each time is set to trigger on exit. --- src/p_floor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_floor.c b/src/p_floor.c index 7edf04bc8..760664c7b 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -2252,7 +2252,7 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) // This should now run ONLY the stuff for eachtime->sourceline itself, instead of all trigger linedefs sharing the same tag. // Makes much more sense doing it this way, honestly. P_RunTriggerLinedef(eachtime->sourceline, players[affectPlayer].mo, sec); - oldPlayersArea[affectPlayer]=1; + oldPlayersArea[affectPlayer]=playersArea[affectPlayer]; } } From 54f0d0c1104a2f51dced0d58a7a432d9f3c76afb Mon Sep 17 00:00:00 2001 From: Ronald Kinard Date: Tue, 18 Nov 2014 18:45:57 -0600 Subject: [PATCH 003/383] IN PROGRESS: porting eternity slopes from srb2cb --- src/Makefile | 2 + src/doomdef.h | 8 + src/m_fixed.h | 23 + src/m_vector.c | 1160 ++++++++++++++++++++++++++++++++++++++++++++++ src/m_vector.h | 123 +++++ src/p_enemy.c | 13 + src/p_floor.c | 11 +- src/p_local.h | 15 + src/p_map.c | 371 ++++++++++++--- src/p_maputl.c | 205 ++++++-- src/p_mobj.c | 103 +++- src/p_mobj.h | 10 + src/p_slopes.c | 1211 ++++++++++++++++++++++++++++++++++++++++++++++++ src/p_slopes.h | 84 ++++ src/p_spec.c | 90 +++- src/p_spec.h | 5 + src/p_user.c | 81 ++++ src/r_defs.h | 54 +++ src/tables.c | 5 +- src/tables.h | 5 +- 20 files changed, 3450 insertions(+), 129 deletions(-) create mode 100644 src/m_vector.c create mode 100644 src/m_vector.h create mode 100644 src/p_slopes.c create mode 100644 src/p_slopes.h diff --git a/src/Makefile b/src/Makefile index f5d58af3a..3e0ab2f76 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 c4896a764..924d09685 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 e68de0308..8bf160204 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 000000000..af5189853 --- /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 000000000..743a26023 --- /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 54e151123..61c943d02 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 f798174ad..65c4821ca 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 9f8918cd8..9fbab1d85 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 62cbf7b77..f484b6a2e 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 48dd54e8d..f311bffce 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 e85e25b05..9c6ce831f 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 6d120c473..4acdde18c 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 000000000..c448b580c --- /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 000000000..8449c1020 --- /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 323b93c6d..228273de0 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 7b6a5655c..c8cfc76da 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 3c2d34a6e..e095f2a97 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 7f8bd7e1d..251140a3f 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 fa71effef..cfc17c9c9 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 219d668b9..cd6a17ff5 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); From 627889eec183a06f1dc685f3883614bc4b63353e Mon Sep 17 00:00:00 2001 From: Wolfy Date: Fri, 20 Feb 2015 17:25:27 -0600 Subject: [PATCH 004/383] Have super sparks scale with the player Fixes https://mb.srb2.org/showthread.php?t=40279 Should work fine, but do keep in mind that this fix is untested. --- src/p_user.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 6844d2cba..7598272f6 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3330,6 +3330,7 @@ firenormal: // static void P_DoSuperStuff(player_t *player) { + mobj_t *spark; ticcmd_t *cmd = &player->cmd; if (player->mo->state >= &states[S_PLAY_SUPERTRANS1] && player->mo->state <= &states[S_PLAY_SUPERTRANS9]) return; // don't do anything right now, we're in the middle of transforming! @@ -3396,8 +3397,12 @@ static void P_DoSuperStuff(player_t *player) if ((cmd->forwardmove != 0 || cmd->sidemove != 0 || player->pflags & (PF_CARRIED|PF_ROPEHANG|PF_ITEMHANG|PF_MACESPIN)) && !(leveltime % TICRATE) && (player->mo->momx || player->mo->momy)) - P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SUPERSPARK); - + { + spark = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SUPERSPARK); + spark->destscale = player->mo->scale; + P_SetScale(spark, player->mo->scale); + } + G_GhostAddColor(GHC_SUPER); // Ran out of rings while super! From 6513954789e29e63fe0d18f3bc1a345be770ff2f Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Sun, 1 Mar 2015 19:30:22 -0500 Subject: [PATCH 005/383] whitespace cleanup --- src/p_user.c | 2 +- src/sdl/i_system.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 7598272f6..3d77069ac 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3402,7 +3402,7 @@ static void P_DoSuperStuff(player_t *player) spark->destscale = player->mo->scale; P_SetScale(spark, player->mo->scale); } - + G_GhostAddColor(GHC_SUPER); // Ran out of rings while super! diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index fa09dc343..66e1ece18 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2759,8 +2759,8 @@ static const char *locateWad(void) if (isWadPathOk(returnWadPath)) return NULL; #endif - - + + #ifdef CMAKECONFIG #ifndef NDEBUG I_OutputMsg(","CMAKE_ASSETS_DIR); @@ -2771,7 +2771,7 @@ static const char *locateWad(void) } #endif #endif - + #ifdef __APPLE__ OSX_GetResourcesPath(returnWadPath); I_OutputMsg(",%s", returnWadPath); @@ -2779,7 +2779,7 @@ static const char *locateWad(void) { return returnWadPath; } - + #endif // examine default dirs From 8232dbca10181c56a73247cac2464af4465c5481 Mon Sep 17 00:00:00 2001 From: MonsterIestyn Date: Fri, 2 Jan 2015 15:14:22 +0000 Subject: [PATCH 006/383] *Fixed OpenGL's handling of cv_translucency effects (should not remove shadows if off, but perhaps make them use default alpha?), someone was a bit hasty! *De-stupified the MD2 status checks regarding drawing of sprites - if they're already checked before calling HWR_DrawSprite, there's no point doing them WITHIN the function as well *Split off sprite shadow code into HWR_DrawSpriteShadow for convenience git-svn-id: https://code.orospakr.ca/svn/srb2/trunk@8983 6de4a73c-47e2-0310-b8c1-93d6ecd3f8cd --- src/hardware/hw_main.c | 377 +++++++++++++++++++++-------------------- 1 file changed, 191 insertions(+), 186 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index db812c0df..bc86c1295 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -3527,6 +3527,186 @@ static boolean HWR_DoCulling(line_t *cullheight, line_t *viewcullheight, float v return false; } +static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float this_scale) +{ + UINT8 i; + float tr_x, tr_y; + FOutVector *wv; + FOutVector swallVerts[4]; + FSurfaceInfo sSurf; + fixed_t floorheight, mobjfloor; + + mobjfloor = HWR_OpaqueFloorAtPos( + spr->mobj->x, spr->mobj->y, + spr->mobj->z, spr->mobj->height); + if (cv_shadowoffs.value) + { + angle_t shadowdir; + + // Set direction + if (splitscreen && stplyr != &players[displayplayer]) + shadowdir = localangle2 + FixedAngle(cv_cam2_rotate.value); + else + shadowdir = localangle + FixedAngle(cv_cam_rotate.value); + + // Find floorheight + floorheight = HWR_OpaqueFloorAtPos( + spr->mobj->x + P_ReturnThrustX(spr->mobj, shadowdir, spr->mobj->z - mobjfloor), + spr->mobj->y + P_ReturnThrustY(spr->mobj, shadowdir, spr->mobj->z - mobjfloor), + spr->mobj->z, spr->mobj->height); + + // The shadow is falling ABOVE it's mobj? + // Don't draw it, then! + if (spr->mobj->z < floorheight) + return; + else + { + fixed_t floorz; + floorz = HWR_OpaqueFloorAtPos( + spr->mobj->x + P_ReturnThrustX(spr->mobj, shadowdir, spr->mobj->z - floorheight), + spr->mobj->y + P_ReturnThrustY(spr->mobj, shadowdir, spr->mobj->z - floorheight), + spr->mobj->z, spr->mobj->height); + // The shadow would be falling on a wall? Don't draw it, then. + // Would draw midair otherwise. + if (floorz < floorheight) + return; + } + + floorheight = FixedInt(spr->mobj->z - floorheight); + } + else + floorheight = FixedInt(spr->mobj->z - mobjfloor); + + // create the sprite billboard + // + // 3--2 + // | /| + // |/ | + // 0--1 + + // x1/x2 were already scaled in HWR_ProjectSprite + swallVerts[0].x = swallVerts[3].x = spr->x1; + swallVerts[2].x = swallVerts[1].x = spr->x2; + + if (spr->mobj && this_scale != 1.0f) + { + // Always a pixel above the floor, perfectly flat. + swallVerts[0].y = swallVerts[1].y = swallVerts[2].y = swallVerts[3].y = spr->ty - gpatch->topoffset * this_scale - (floorheight+3); + + swallVerts[0].z = swallVerts[1].z = spr->tz - (gpatch->height-gpatch->topoffset) * this_scale; + swallVerts[2].z = swallVerts[3].z = spr->tz + gpatch->topoffset * this_scale; + } + else + { + // Always a pixel above the floor, perfectly flat. + swallVerts[0].y = swallVerts[1].y = swallVerts[2].y = swallVerts[3].y = spr->ty - gpatch->topoffset - (floorheight+3); + + // Spread out top away from the camera. (Fixme: Make it always move out in the same direction!... somehow.) + swallVerts[0].z = swallVerts[1].z = spr->tz - (gpatch->height-gpatch->topoffset); + swallVerts[2].z = swallVerts[3].z = spr->tz + gpatch->topoffset; + } + + // transform + wv = swallVerts; + + for (i = 0; i < 4; i++,wv++) + { + // Offset away from the camera based on height from floor. + if (cv_shadowoffs.value) + wv->z += floorheight; + wv->z += 3; + + //look up/down ----TOTAL SUCKS!!!--- do the 2 in one!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + tr_x = wv->z; + tr_y = wv->y; + wv->y = (tr_x * gr_viewludcos) + (tr_y * gr_viewludsin); + wv->z = (tr_x * gr_viewludsin) - (tr_y * gr_viewludcos); + // ---------------------- mega lame test ---------------------------------- + + //scale y before frustum so that frustum can be scaled to screen height + wv->y *= ORIGINAL_ASPECT * gr_fovlud; + wv->x *= gr_fovlud; + } + + if (spr->flip) + { + swallVerts[0].sow = swallVerts[3].sow = gpatch->max_s; + swallVerts[2].sow = swallVerts[1].sow = 0; + } + else + { + swallVerts[0].sow = swallVerts[3].sow = 0; + swallVerts[2].sow = swallVerts[1].sow = gpatch->max_s; + } + + // flip the texture coords (look familiar?) + if (spr->vflip) + { + swallVerts[3].tow = swallVerts[2].tow = gpatch->max_t; + swallVerts[0].tow = swallVerts[1].tow = 0; + } + else + { + swallVerts[3].tow = swallVerts[2].tow = 0; + swallVerts[0].tow = swallVerts[1].tow = gpatch->max_t; + } + + sSurf.FlatColor.s.red = 0x00; + sSurf.FlatColor.s.blue = 0x00; + sSurf.FlatColor.s.green = 0x00; + + /*if (spr->mobj->frame & FF_TRANSMASK || spr->mobj->flags2 & MF2_SHADOW) + { + sector_t *sector = spr->mobj->subsector->sector; + UINT8 lightlevel = sector->lightlevel; + extracolormap_t *colormap = sector->extra_colormap; + + if (sector->numlights) + { + INT32 light = R_GetPlaneLight(sector, spr->mobj->floorz, false); + + if (!(spr->mobj->frame & FF_FULLBRIGHT)) + lightlevel = *sector->lightlist[light].lightlevel; + else + lightlevel = 255; + + if (sector->lightlist[light].extra_colormap) + colormap = sector->lightlist[light].extra_colormap; + } + else + { + lightlevel = sector->lightlevel; + + if (sector->extra_colormap) + colormap = sector->extra_colormap; + } + + if (colormap) + sSurf.FlatColor.rgba = HWR_Lighting(lightlevel/2, colormap->rgba, colormap->fadergba, false, true); + else + sSurf.FlatColor.rgba = HWR_Lighting(lightlevel/2, NORMALFOG, FADEFOG, false, true); + }*/ + + // shadow is always half as translucent as the sprite itself + if (!cv_translucency.value) // use default translucency (main sprite won't have any translucency) + sSurf.FlatColor.s.alpha = 0x80; // default + else if (spr->mobj->flags2 & MF2_SHADOW) + sSurf.FlatColor.s.alpha = 0x20; + else if (spr->mobj->frame & FF_TRANSMASK) + { + HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &sSurf); + sSurf.FlatColor.s.alpha /= 2; //cut alpha in half! + } + else + sSurf.FlatColor.s.alpha = 0x80; // default + + if (sSurf.FlatColor.s.alpha > floorheight/4) + { + sSurf.FlatColor.s.alpha = (UINT8)(sSurf.FlatColor.s.alpha - floorheight/4); + HWD.pfnDrawPolygon(&sSurf, swallVerts, 4, PF_Translucent|PF_Modulated|PF_Clip); + } +} + // -----------------+ // HWR_DrawSprite : Draw flat sprites // : (monsters, bonuses, weapons, lights, ...) @@ -3629,7 +3809,7 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) // Draw shadow BEFORE sprite if (cv_shadow.value // Shadows enabled - && !(spr->mobj->flags & MF_SCENERY && spr->mobj->flags & MF_SPAWNCEILING && spr->mobj->flags & MF_NOGRAVITY) // Ceiling scenery have no shadow. + && (spr->mobj->flags & (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY)) != (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY) // Ceiling scenery have no shadow. && !(spr->mobj->flags2 & MF2_DEBRIS) // Debris have no corona or shadow. #ifdef ALAM_LIGHTING && !(t_lspr[spr->mobj->sprite]->type // Things with dynamic lights have no shadow. @@ -3640,187 +3820,9 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) //////////////////// // SHADOW SPRITE! // //////////////////// - FOutVector swallVerts[4]; - FSurfaceInfo sSurf; - fixed_t floorheight, mobjfloor; - - mobjfloor = HWR_OpaqueFloorAtPos( - spr->mobj->x, spr->mobj->y, - spr->mobj->z, spr->mobj->height); - if (cv_shadowoffs.value) - { - angle_t shadowdir; - - // Set direction - if (splitscreen && stplyr != &players[displayplayer]) - shadowdir = localangle2 + FixedAngle(cv_cam2_rotate.value); - else - shadowdir = localangle + FixedAngle(cv_cam_rotate.value); - - // Find floorheight - floorheight = HWR_OpaqueFloorAtPos( - spr->mobj->x + P_ReturnThrustX(spr->mobj, shadowdir, spr->mobj->z - mobjfloor), - spr->mobj->y + P_ReturnThrustY(spr->mobj, shadowdir, spr->mobj->z - mobjfloor), - spr->mobj->z, spr->mobj->height); - - // The shadow is falling ABOVE it's mobj? - // Don't draw it, then! - if (spr->mobj->z < floorheight) - goto noshadow; - else - { - fixed_t floorz; - floorz = HWR_OpaqueFloorAtPos( - spr->mobj->x + P_ReturnThrustX(spr->mobj, shadowdir, spr->mobj->z - floorheight), - spr->mobj->y + P_ReturnThrustY(spr->mobj, shadowdir, spr->mobj->z - floorheight), - spr->mobj->z, spr->mobj->height); - // The shadow would be falling on a wall? Don't draw it, then. - // Would draw midair otherwise. - if (floorz < floorheight) - goto noshadow; - } - - floorheight = FixedInt(spr->mobj->z - floorheight); - } - else - floorheight = FixedInt(spr->mobj->z - mobjfloor); - - // create the sprite billboard - // - // 3--2 - // | /| - // |/ | - // 0--1 - - // x1/x2 were already scaled in HWR_ProjectSprite - swallVerts[0].x = swallVerts[3].x = spr->x1; - swallVerts[2].x = swallVerts[1].x = spr->x2; - - if (spr->mobj && this_scale != 1.0f) - { - // Always a pixel above the floor, perfectly flat. - swallVerts[0].y = swallVerts[1].y = swallVerts[2].y = swallVerts[3].y = spr->ty - gpatch->topoffset * this_scale - (floorheight+3); - - swallVerts[0].z = swallVerts[1].z = spr->tz - (gpatch->height-gpatch->topoffset) * this_scale; - swallVerts[2].z = swallVerts[3].z = spr->tz + gpatch->topoffset * this_scale; - } - else - { - // Always a pixel above the floor, perfectly flat. - swallVerts[0].y = swallVerts[1].y = swallVerts[2].y = swallVerts[3].y = spr->ty - gpatch->topoffset - (floorheight+3); - - // Spread out top away from the camera. (Fixme: Make it always move out in the same direction!... somehow.) - swallVerts[0].z = swallVerts[1].z = spr->tz - (gpatch->height-gpatch->topoffset); - swallVerts[2].z = swallVerts[3].z = spr->tz + gpatch->topoffset; - } - - // transform - wv = swallVerts; - - for (i = 0; i < 4; i++,wv++) - { - // Offset away from the camera based on height from floor. - if (cv_shadowoffs.value) - wv->z += floorheight; - wv->z += 3; - - //look up/down ----TOTAL SUCKS!!!--- do the 2 in one!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - tr_x = wv->z; - tr_y = wv->y; - wv->y = (tr_x * gr_viewludcos) + (tr_y * gr_viewludsin); - wv->z = (tr_x * gr_viewludsin) - (tr_y * gr_viewludcos); - // ---------------------- mega lame test ---------------------------------- - - //scale y before frustum so that frustum can be scaled to screen height - wv->y *= ORIGINAL_ASPECT * gr_fovlud; - wv->x *= gr_fovlud; - } - - if (spr->flip) - { - swallVerts[0].sow = swallVerts[3].sow = gpatch->max_s; - swallVerts[2].sow = swallVerts[1].sow = 0; - } - else - { - swallVerts[0].sow = swallVerts[3].sow = 0; - swallVerts[2].sow = swallVerts[1].sow = gpatch->max_s; - } - - // flip the texture coords (look familiar?) - if (spr->vflip) - { - swallVerts[3].tow = swallVerts[2].tow = gpatch->max_t; - swallVerts[0].tow = swallVerts[1].tow = 0; - } - else - { - swallVerts[3].tow = swallVerts[2].tow = 0; - swallVerts[0].tow = swallVerts[1].tow = gpatch->max_t; - } - - sSurf.FlatColor.s.red = 0x00; - sSurf.FlatColor.s.blue = 0x00; - sSurf.FlatColor.s.green = 0x00; - - /*if (spr->mobj->frame & FF_TRANSMASK || spr->mobj->flags2 & MF2_SHADOW) - { - sector_t *sector = spr->mobj->subsector->sector; - UINT8 lightlevel = sector->lightlevel; - extracolormap_t *colormap = sector->extra_colormap; - - if (sector->numlights) - { - INT32 light = R_GetPlaneLight(sector, spr->mobj->floorz, false); - - if (!(spr->mobj->frame & FF_FULLBRIGHT)) - lightlevel = *sector->lightlist[light].lightlevel; - else - lightlevel = 255; - - if (sector->lightlist[light].extra_colormap) - colormap = sector->lightlist[light].extra_colormap; - } - else - { - lightlevel = sector->lightlevel; - - if (sector->extra_colormap) - colormap = sector->extra_colormap; - } - - if (colormap) - sSurf.FlatColor.rgba = HWR_Lighting(lightlevel/2, colormap->rgba, colormap->fadergba, false, true); - else - sSurf.FlatColor.rgba = HWR_Lighting(lightlevel/2, NORMALFOG, FADEFOG, false, true); - }*/ - - // shadow is always half as translucent as the sprite itself - if (!cv_translucency.value) - ; // translucency disabled - else if (spr->mobj->flags2 & MF2_SHADOW) - sSurf.FlatColor.s.alpha = 0x20; - else if (spr->mobj->frame & FF_TRANSMASK) - { - HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &sSurf); - sSurf.FlatColor.s.alpha /= 2; //cut alpha in half! - } - else - sSurf.FlatColor.s.alpha = 0x80; // default - - /// \todo do the test earlier - if (!cv_grmd2.value || (md2_models[spr->mobj->sprite].scale < 0.0f) || (md2_models[spr->mobj->sprite].notfound = true) || (md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f) || (md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound = true)) - { - if (sSurf.FlatColor.s.alpha > floorheight/4) - { - sSurf.FlatColor.s.alpha = (UINT8)(sSurf.FlatColor.s.alpha - floorheight/4); - HWD.pfnDrawPolygon(&sSurf, swallVerts, 4, PF_Translucent|PF_Modulated|PF_Clip); - } - } + HWR_DrawSpriteShadow(spr, gpatch, this_scale); } -noshadow: - // This needs to be AFTER the shadows so that the regular sprites aren't drawn completely black. // sprite lighting by modulating the RGB components /// \todo coloured @@ -3865,11 +3867,14 @@ noshadow: Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false); } - /// \todo do the test earlier - if (!cv_grmd2.value || (md2_models[spr->mobj->sprite].scale < 0.0f)) { FBITFIELD blend = 0; - if (spr->mobj->flags2 & MF2_SHADOW) + if (!cv_translucency.value) // translucency disabled + { + Surf.FlatColor.s.alpha = 0xFF; + blend = PF_Translucent|PF_Occlude; + } + else if (spr->mobj->flags2 & MF2_SHADOW) { Surf.FlatColor.s.alpha = 0x40; blend = PF_Translucent; @@ -4390,10 +4395,10 @@ static void HWR_DrawSprites(void) #endif if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) { - if (!cv_grmd2.value || (cv_grmd2.value && md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound == true)) + if (!cv_grmd2.value || md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound || md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f) HWR_DrawSprite(spr); } - else if (!cv_grmd2.value || (cv_grmd2.value && md2_models[spr->mobj->sprite].notfound == true)) + else if (!cv_grmd2.value || md2_models[spr->mobj->sprite].notfound || md2_models[spr->mobj->sprite].scale < 0.0f) HWR_DrawSprite(spr); } } @@ -4419,7 +4424,7 @@ static void HWR_DrawMD2S(void) #endif if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) { - if ((md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound == false) && (md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale > 0.0f)) + if (md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound == false && md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale > 0.0f) HWR_DrawMD2(spr); } else if (md2_models[spr->mobj->sprite].notfound == false && md2_models[spr->mobj->sprite].scale > 0.0f) From 0a7f3751f6553bf967698afb559c9959261ffc2b Mon Sep 17 00:00:00 2001 From: Matt Walsh Date: Fri, 2 Jan 2015 16:37:13 +0000 Subject: [PATCH 007/383] Add in missing super check git-svn-id: https://code.orospakr.ca/svn/srb2/trunk@8984 6de4a73c-47e2-0310-b8c1-93d6ecd3f8cd --- src/p_enemy.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/p_enemy.c b/src/p_enemy.c index 18a4ec5ff..2a8ab5bb9 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -5660,6 +5660,11 @@ void A_RecyclePowers(mobj_t *actor) if (playeringame[i] && players[i].mo && players[i].mo->health > 0 && players[i].playerstate == PST_LIVE && !players[i].exiting && !((netgame || multiplayer) && players[i].spectator)) { +#ifndef WEIGHTEDRECYCLER + if (players[i].powers[pw_super]) + continue; // Ignore super players +#endif + numplayers++; postscramble[j] = playerslist[j] = (UINT8)i; From f3e6770e9a8fa9aaa27b1cfdb48d5d65ae79f48c Mon Sep 17 00:00:00 2001 From: Matt Walsh Date: Fri, 2 Jan 2015 22:27:43 +0000 Subject: [PATCH 008/383] Well that shows you how much we care about the old special stages *or* race! git-svn-id: https://code.orospakr.ca/svn/srb2/trunk@8985 6de4a73c-47e2-0310-b8c1-93d6ecd3f8cd --- src/g_game.c | 3 +-- src/st_stuff.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index c59f23c07..931388d87 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2180,8 +2180,7 @@ void G_PlayerReborn(INT32 player) p->health = 1; // 0 rings p->panim = PA_IDLE; // standing animation - if ((netgame || multiplayer) && !p->spectator - && gametype != GT_RACE) + if ((netgame || multiplayer) && !p->spectator) p->powers[pw_flashing] = flashingtics-1; // Babysitting deterrent if (p-players == consoleplayer) diff --git a/src/st_stuff.c b/src/st_stuff.c index a9bdacf71..6e19b92ff 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1590,7 +1590,7 @@ static void ST_drawSpecialStageHUD(void) if (sstimer) { V_DrawString(hudinfo[HUD_TIMELEFT].x, STRINGY(hudinfo[HUD_TIMELEFT].y), V_HUDTRANS, M_GetText("TIME LEFT")); - ST_DrawNightsOverlayNum(SCX(hudinfo[HUD_TIMELEFTNUM].x), SCY(hudinfo[HUD_TIMELEFTNUM].y), V_HUDTRANS, sstimer/TICRATE, tallnum, SKINCOLOR_WHITE); + ST_DrawNumFromHud(HUD_TIMELEFTNUM, sstimer/TICRATE); } else ST_DrawPatchFromHud(HUD_TIMEUP, timeup); From 2d8868feca767ffe6cbedc23c2172e1946332d6c Mon Sep 17 00:00:00 2001 From: MonsterIestyn Date: Sat, 10 Jan 2015 20:54:17 +0000 Subject: [PATCH 009/383] Made HWR_InitMD2 and HWR_AddSpriteMD2/HWR_AddPlayerMD2 slightly less stupid with MD2-related searches in md2.dat: *Don't go barmy and search for a player skin called "THOK" when you already found the sprite called "THOK" beforehand! (or any other sprite prefix for that matter) *Don't make errors appear only for the last sprite/skin when it doesn't make sense to do so!! Todo: Stop the redundancy that currently goes on with adding MD2s on game start-up (note that HWR_AddSpriteMD2/HWR_AddPlayerMD2 are run for all sprites/skins BEFORE HWR_InitMD2 is called) git-svn-id: https://code.orospakr.ca/svn/srb2/trunk@8988 6de4a73c-47e2-0310-b8c1-93d6ecd3f8cd --- src/hardware/hw_md2.c | 81 +++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 49 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 02f505351..6d2a1d4a3 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -921,24 +921,25 @@ void HWR_InitMD2(void) } while (fscanf(f, "%19s %31s %f %f", name, filename, &scale, &offset) == 4) { + if (stricmp(name, "PLAY") == 0) + { + CONS_Printf("MD2 for sprite PLAY detected in md2.dat, use a player skin instead!\n"); + continue; + } + for (i = 0; i < NUMSPRITES; i++) { if (stricmp(name, sprnames[i]) == 0) { - if (stricmp(name, "PLAY") == 0) - continue; + //if (stricmp(name, "PLAY") == 0) + //continue; //CONS_Debug(DBG_RENDER, " Found: %s %s %f %f\n", name, filename, scale, offset); md2_models[i].scale = scale; md2_models[i].offset = offset; md2_models[i].notfound = false; strcpy(md2_models[i].filename, filename); - break; - } - if (i == NUMSPRITES) - { - CONS_Printf("MD2 for sprite %s not found\n", name); - md2_models[i].notfound = true; + goto md2found; } } @@ -952,15 +953,14 @@ void HWR_InitMD2(void) md2_playermodels[s].offset = offset; md2_playermodels[s].notfound = false; strcpy(md2_playermodels[s].filename, filename); - break; - } - if (s == MAXSKINS-1) - { - CONS_Printf("MD2 for player skin %s not found\n", name); - md2_playermodels[s].notfound = true; + goto md2found; } } - + // no sprite/player skin name found?!? + CONS_Printf("Unknown sprite/player skin %s detected in md2.dat\n", name); +md2found: + // move on to next line... + continue; } fclose(f); } @@ -996,17 +996,14 @@ void HWR_AddPlayerMD2(int skin) // For MD2's that were added after startup md2_playermodels[skin].offset = offset; md2_playermodels[skin].notfound = false; strcpy(md2_playermodels[skin].filename, filename); - break; - } - if (skin == MAXSKINS-1) - { - CONS_Printf("MD2 for player skin %s not found\n", name); - md2_playermodels[skin].notfound = true; + goto playermd2found; } } + //CONS_Printf("MD2 for player skin %s not found\n", skins[skin].name); + md2_playermodels[skin].notfound = true; +playermd2found: fclose(f); - } @@ -1021,6 +1018,9 @@ void HWR_AddSpriteMD2(size_t spritenum) // For MD2s that were added after startu if (nomd2s) return; + if (spritenum == SPR_PLAY) // Handled already NEWMD2: Per sprite, per-skin check + return; + // Read the md2.dat file f = fopen("md2.dat", "rt"); @@ -1034,27 +1034,19 @@ void HWR_AddSpriteMD2(size_t spritenum) // For MD2s that were added after startu // Check for any MD2s that match the names of player skins! while (fscanf(f, "%19s %31s %f %f", name, filename, &scale, &offset) == 4) { + if (stricmp(name, sprnames[spritenum]) == 0) { - if (stricmp(name, sprnames[spritenum]) == 0) - { - if (stricmp(name, "PLAY") == 0) // Handled already NEWMD2: Per sprite, per-skin check - continue; - - md2_models[spritenum].scale = scale; - md2_models[spritenum].offset = offset; - md2_models[spritenum].notfound = false; - strcpy(md2_models[spritenum].filename, filename); - break; - } - - if (spritenum == NUMSPRITES-1) - { - CONS_Printf("MD2 for sprite %s not found\n", name); - md2_models[spritenum].notfound = true; - } + md2_models[spritenum].scale = scale; + md2_models[spritenum].offset = offset; + md2_models[spritenum].notfound = false; + strcpy(md2_models[spritenum].filename, filename); + goto spritemd2found; } } + //CONS_Printf("MD2 for sprite %s not found\n", sprnames[spritenum]); + md2_models[spritenum].notfound = true; +spritemd2found: fclose(f); } @@ -1094,7 +1086,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) // colormap test { sector_t *sector = spr->mobj->subsector->sector; - UINT8 lightlevel = sector->lightlevel; + UINT8 lightlevel = 255; extracolormap_t *colormap = sector->extra_colormap; if (sector->numlights) @@ -1105,8 +1097,6 @@ void HWR_DrawMD2(gr_vissprite_t *spr) if (!(spr->mobj->frame & FF_FULLBRIGHT)) lightlevel = *sector->lightlist[light].lightlevel; - else - lightlevel = 255; if (sector->lightlist[light].extra_colormap) colormap = sector->lightlist[light].extra_colormap; @@ -1115,16 +1105,11 @@ void HWR_DrawMD2(gr_vissprite_t *spr) { if (!(spr->mobj->frame & FF_FULLBRIGHT)) lightlevel = sector->lightlevel; - else - lightlevel = 255; if (sector->extra_colormap) colormap = sector->extra_colormap; } - if (spr->mobj->frame & FF_FULLBRIGHT) - lightlevel = 255; - if (colormap) Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false); else @@ -1263,8 +1248,6 @@ void HWR_DrawMD2(gr_vissprite_t *spr) p.flip = false; HWD.pfnDrawMD2i(buff, curr, durs, tics, next, &p, finalscale, flip, color); - - } } From ffc1d3cb648ff782e6822d046ede84b10e8f2bbf Mon Sep 17 00:00:00 2001 From: MonsterIestyn Date: Tue, 20 Jan 2015 19:42:10 +0000 Subject: [PATCH 010/383] Correcting a most minor math mistake git-svn-id: https://code.orospakr.ca/svn/srb2/trunk@8992 6de4a73c-47e2-0310-b8c1-93d6ecd3f8cd --- src/p_map.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_map.c b/src/p_map.c index 62cbf7b77..342aa0868 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -875,7 +875,7 @@ static boolean PIT_CheckThing(mobj_t *thing) { // Doesn't matter what gravity player's following! Just do your stuff in YOUR direction only if (tmthing->eflags & MFE_VERTICALFLIP - && (tmthing->z + tmthing->height + tmthing->momz > thing->z + && (tmthing->z + tmthing->height + tmthing->momz < thing->z || tmthing->z + tmthing->height + tmthing->momz >= thing->z + thing->height)) ; else if (!(tmthing->eflags & MFE_VERTICALFLIP) From 0dff0d84de7c5674fa93a0a5a85a489f577d9974 Mon Sep 17 00:00:00 2001 From: JTE Date: Thu, 22 Jan 2015 15:38:13 +0000 Subject: [PATCH 011/383] New HD SRB2 icon by VAdaPEga. git-svn-id: https://code.orospakr.ca/svn/srb2/trunk@8994 6de4a73c-47e2-0310-b8c1-93d6ecd3f8cd --- src/sdl/SDL_icon.xpm | 503 +++++++++++++++++++++++++++++++++------- src/sdl/Srb2SDL.ico | Bin 2238 -> 372798 bytes src/sdl12/SDL_icon.xpm | 503 +++++++++++++++++++++++++++++++++------- src/sdl12/Srb2SDL.ico | Bin 2238 -> 372798 bytes src/win32/Srb2win.ico | Bin 6006 -> 372798 bytes src/win32ce/Srb2win.ico | Bin 2238 -> 372798 bytes 6 files changed, 848 insertions(+), 158 deletions(-) diff --git a/src/sdl/SDL_icon.xpm b/src/sdl/SDL_icon.xpm index 70bb02d3c..cf72960df 100644 --- a/src/sdl/SDL_icon.xpm +++ b/src/sdl/SDL_icon.xpm @@ -1,80 +1,425 @@ /* XPM */ -static const char * SDL_icon_xpm[] = { -"32 32 45 1", -" c None", -". c #6B6BFF", -"+ c #3D00B9", -"@ c #4848FF", -"# c #2525FF", -"$ c #310096", -"% c #003196", -"& c #003DB9", -"* c #620096", -"= c #6E6E6E", -"- c #966200", -"; c #250073", -"> c #626262", -", c #FF8F6B", -"' c #FFC66B", -") c #FFAB8E", -"! c #000080", -"~ c #B6B6B6", -"{ c #929292", -"] c #FFD48E", -"^ c #0000B9", -"/ c #565656", -"( c #868686", -"_ c #808080", -": c #C0C0C0", -"< c #DADADA", -"[ c #F2F2F2", -"} c #FFFFFF", -"| c #CECECE", -"1 c #AAAAAA", -"2 c #E6E6E6", -"3 c #000096", -"4 c #AB8EFF", -"5 c #190050", -"6 c #000000", -"7 c #8E8EFF", -"8 c #3E3E3E", -"9 c #7A7A7A", -"0 c #0E0E0E", -"a c #9E9E9E", -"b c #001950", -"c c #C2C2C2", -"d c #323232", -"e c #002573", -"f c #A0A0A4", -" ", -" ", -" ", -" .+@##@. ", -" @@.@#######@ ", -" @@....######### ", -" .. .@.....@+##$%%%&&% ", -" ..@# @@....@+#*=-;%%%%% ", -" ..@#@......@>,')!%%%$ ", -" ~..$#.........{])^#+%/ ", -" +##@.........()^@@@@@_ ", -" $####@........#=#######+ ", -" +######....@@##^#########_ ", -" +#####=:<<:+##############/ ", -"[<=####{<}}}}|###############= ", -" }1###=2}}}}}}.############### ", -" }<3#3~}}}}}}}4################ ", -" }<5#6:}}}}}}}7################/", -" }:6861}}}}}}}.########$$ 9 .@$", -" }:0a6~}}}}}}}@######5b ", -"22cd262}}}}}}2######5b$ ", -" 2>1a}}}}}}}{(*###%be## ", -" 860)1<[22c1)]]+##be### ", -" ~)]]]))))]]]]]=#bb#### ", -" )]]]]]]]]](]]=eb$#### ", -" :]]]]]]]]]'9bbb$##### ", -" ),'''''( >db+### ", -" =##f ", -" { ", -" ", -" ", -" "}; +static char * C:\Repo\srb2\src\sdl\SDL_icon_xpm[] = { +"32 32 390 2", +" c None", +". c #4F4F70", +"+ c #4D4D87", +"@ c #4D4D84", +"# c #4E4E6C", +"$ c #6C6C95", +"% c #5E5EB2", +"& c #6B6BE7", +"* c #7373F9", +"= c #7C7CFF", +"- c #6F70E7", +"; c #494BB2", +"> c #4F4FA3", +", c #6464D4", +"' c #7979F5", +") c #5F5FCA", +"! c #5D5D93", +"~ c #3A3A9F", +"{ c #6060AC", +"] c #777793", +"^ c #5C5CB3", +"/ c #7373EA", +"( c #7A7AFF", +"_ c #7575FF", +": c #7979FF", +"< c #6264DD", +"[ c #47478C", +"} c #564567", +"| c #4647D0", +"1 c #5C5CAE", +"2 c #5E5EFF", +"3 c #2929FF", +"4 c #1D1DFF", +"5 c #1919D1", +"6 c #4F4F90", +"7 c #1E1ECE", +"8 c #5858FF", +"9 c #6767A8", +"0 c #4949A0", +"a c #7070FB", +"b c #7D7DFF", +"c c #7777FF", +"d c #7373FF", +"e c #7272FF", +"f c #7878FF", +"g c #6465D8", +"h c #363886", +"i c #9F7655", +"j c #C89B5C", +"k c #1D1CB7", +"l c #3031B1", +"m c #1919F4", +"n c #1111FF", +"o c #1818FF", +"p c #1B1BFF", +"q c #1C1CFF", +"r c #2626B3", +"s c #1E1EC8", +"t c #1A1AE8", +"u c #24249F", +"v c #2F2FD2", +"w c #7676FF", +"x c #6869E2", +"y c #414290", +"z c #8C6751", +"A c #FCBA68", +"B c #E9BD7D", +"C c #201EB8", +"D c #090AB8", +"E c #1616EB", +"F c #1818FD", +"G c #1414EE", +"H c #1010E1", +"I c #0E0EE2", +"J c #0E0EF4", +"K c #0606B2", +"L c #7A7A89", +"M c #0C0C9A", +"N c #0A0AA7", +"O c #2424E4", +"P c #6669E6", +"Q c #4F4A8F", +"R c #BF853B", +"S c #FFD98D", +"T c #CDAB76", +"U c #1717C4", +"V c #0F10BA", +"W c #0909B6", +"X c #0505C3", +"Y c #0000B6", +"Z c #0000BE", +"` c #0000AD", +" . c #1D1D83", +".. c #63638E", +"+. c #090975", +"@. c #1414F3", +"#. c #5B5BFF", +"$. c #7B7BFF", +"%. c #7070FF", +"&. c #6E6EFF", +"*. c #7172F6", +"=. c #625DAF", +"-. c #BA9E6C", +";. c #887167", +">. c #090DF2", +",. c #1313BE", +"'. c #000085", +"). c #0000AC", +"!. c #0202AA", +"~. c #242488", +"{. c #1414C7", +"]. c #1717FF", +"^. c #5959FF", +"/. c #7F7FFF", +"(. c #7474FF", +"_. c #7171FF", +":. c #8686FF", +"<. c #7574FF", +"[. c #797CFF", +"}. c #5756B8", +"|. c #1C19A4", +"1. c #1617FF", +"2. c #1212BD", +"3. c #040485", +"4. c #0707A4", +"5. c #1B1B71", +"6. c #373797", +"7. c #1616FF", +"8. c #5050FF", +"9. c #8080FF", +"0. c #AAAAFF", +"a. c #AEAEF6", +"b. c #8A8AEF", +"c. c #6969FB", +"d. c #2728FF", +"e. c #1314FF", +"f. c #1919FF", +"g. c #1313E8", +"h. c #1F1FF4", +"i. c #5454FF", +"j. c #6D6DF0", +"k. c #6868B5", +"l. c #0B0BB8", +"m. c #1212C5", +"n. c #1616FC", +"o. c #1515FF", +"p. c #1212FF", +"q. c #2323FF", +"r. c #3636FF", +"s. c #4040FF", +"t. c #4343F9", +"u. c #5D5DB8", +"v. c #7F7F92", +"w. c #878793", +"x. c #4B4B94", +"y. c #0B0CE2", +"z. c #1313FF", +"A. c #4C4CFF", +"B. c #8282FF", +"C. c #7171ED", +"D. c #636394", +"E. c #575785", +"F. c #A9A99C", +"G. c #1414BC", +"H. c #1414FF", +"I. c #0707FD", +"J. c #2525AA", +"K. c #A8A8A4", +"L. c #EBEBE2", +"M. c #F9F9F2", +"N. c #E1E1CC", +"O. c #4D4D9F", +"P. c #0B0BF7", +"Q. c #2121FF", +"R. c #3232FF", +"S. c #5555FF", +"T. c #6161B4", +"U. c #B5B5B2", +"V. c #FFFFF8", +"W. c #4F4F9A", +"X. c #0B0BF5", +"Y. c #1616C5", +"Z. c #A8A8A1", +"`. c #FFFFFC", +" + c #FFFFFF", +".+ c #C0C0C4", +"++ c #1212D4", +"@+ c #4444FF", +"#+ c #6464FF", +"$+ c #8383FF", +"%+ c #6767C3", +"&+ c #E4E4E4", +"*+ c #9494AE", +"=+ c #0808DF", +"-+ c #0D0DF2", +";+ c #61619A", +">+ c #F1F1E0", +",+ c #E8E8DD", +"'+ c #2424BB", +")+ c #1010FF", +"!+ c #3434FF", +"~+ c #6161FF", +"{+ c #6969D2", +"]+ c #EFEFF0", +"^+ c #C2C2BA", +"/+ c #1010B6", +"(+ c #0909AC", +"_+ c #A4A49A", +":+ c #EAEADE", +"<+ c #2525B8", +"[+ c #2F2FFF", +"}+ c #3C3CB5", +"|+ c #EEEEEE", +"1+ c #BBBBAD", +"2+ c #0B0B56", +"3+ c #0B0BFC", +"4+ c #1212EF", +"5+ c #0C0C3E", +"6+ c #919187", +"7+ c #DEDED6", +"8+ c #1F1FC0", +"9+ c #1A1AFF", +"0+ c #1717FA", +"a+ c #1515F8", +"b+ c #1111FC", +"c+ c #494992", +"d+ c #999998", +"e+ c #3E3E3B", +"f+ c #3C3C99", +"g+ c #535397", +"h+ c #5A5A4D", +"i+ c #6F6F70", +"j+ c #BFBFC9", +"k+ c #1111D6", +"l+ c #1515F1", +"m+ c #0F0FE2", +"n+ c #0D0DD9", +"o+ c #0909CD", +"p+ c #0808C7", +"q+ c #0505C7", +"r+ c #0303CB", +"s+ c #0101C0", +"t+ c #0202AF", +"u+ c #0606AC", +"v+ c #121283", +"w+ c #BBBBBB", +"x+ c #BEBEBE", +"y+ c #2F2F2E", +"z+ c #C7C8BB", +"A+ c #D8DAD1", +"B+ c #272828", +"C+ c #929292", +"D+ c #8688C7", +"E+ c #0506F6", +"F+ c #1616F5", +"G+ c #0B0BD3", +"H+ c #0202B6", +"I+ c #0000AF", +"J+ c #0000B4", +"K+ c #0000BD", +"L+ c #0000BB", +"M+ c #00009E", +"N+ c #2C2C7E", +"O+ c #6A6A8B", +"P+ c #959595", +"Q+ c #F0F0F1", +"R+ c #E1E1E1", +"S+ c #8C8E90", +"T+ c #BEBEBF", +"U+ c #C9C7C5", +"V+ c #939699", +"W+ c #E7EAED", +"X+ c #CBCBC7", +"Y+ c #413B9B", +"Z+ c #0607DD", +"`+ c #0C0CE2", +" @ c #0303B9", +".@ c #0000A8", +"+@ c #181888", +"@@ c #6A6A6A", +"#@ c #626263", +"$@ c #4B4B4C", +"%@ c #3E3B36", +"&@ c #9B805C", +"*@ c #D9B07D", +"=@ c #C9AE89", +"-@ c #B9AF9E", +";@ c #C7C5C4", +">@ c #CBCCCF", +",@ c #C7C6C6", +"'@ c #AEA59A", +")@ c #B69974", +"!@ c #D8B87F", +"~@ c #9B8272", +"{@ c #0E0B9B", +"]@ c #0000B7", +"^@ c #0000B8", +"/@ c #000082", +"(@ c #00007A", +"_@ c #636379", +":@ c #62533E", +"<@ c #B59B6C", +"[@ c #DEB07B", +"}@ c #FECC90", +"|@ c #FFCE92", +"1@ c #FEC98C", +"2@ c #F1BD82", +"3@ c #D1A979", +"4@ c #BC9E73", +"5@ c #CCA777", +"6@ c #EAB980", +"7@ c #FFCD90", +"8@ c #FFD595", +"9@ c #FDD782", +"0@ c #413678", +"a@ c #0000AE", +"b@ c #000077", +"c@ c #010193", +"d@ c #0C0CE4", +"e@ c #38389E", +"f@ c #EEC585", +"g@ c #FFDA9D", +"h@ c #FFC992", +"i@ c #FFC88F", +"j@ c #FFC990", +"k@ c #FFCE93", +"l@ c #FFD094", +"m@ c #FFCC92", +"n@ c #C9A174", +"o@ c #EDBD88", +"p@ c #FAD287", +"q@ c #3A2F7F", +"r@ c #0000BA", +"s@ c #0000B0", +"t@ c #0101B2", +"u@ c #1111ED", +"v@ c #1919C1", +"w@ c #95887C", +"x@ c #DCAC6E", +"y@ c #FFD393", +"z@ c #FFCD94", +"A@ c #FFCA93", +"B@ c #FFC991", +"C@ c #FFC78E", +"D@ c #FFCB91", +"E@ c #E0B581", +"F@ c #BB9A6F", +"G@ c #FFDC97", +"H@ c #C1A173", +"I@ c #0E0B9A", +"J@ c #0000B5", +"K@ c #0101B6", +"L@ c #1010E0", +"M@ c #1616EC", +"N@ c #A68156", +"O@ c #E7AC6B", +"P@ c #FFC582", +"Q@ c #FFCF8F", +"R@ c #FFD195", +"S@ c #FFD296", +"T@ c #FFD396", +"U@ c #FFD193", +"V@ c #FFD28F", +"W@ c #D2A96B", +"X@ c #2F2482", +"Y@ c #0000C1", +"Z@ c #0000C0", +"`@ c #0000BF", +" # c #0101BF", +".# c #1212F0", +"+# c #767698", +"@# c #9C866E", +"## c #A9865D", +"$# c #C0915D", +"%# c #C89760", +"&# c #C29360", +"*# c #AD8A61", +"=# c #9D8971", +"-# c #7F7A7A", +";# c #70708F", +"># c #6F6F91", +",# c #575788", +"'# c #464687", +")# c #2F2F87", +"!# c #15158F", +"~# c #0101A8", +"{# c #1313FB", +"]# c #57579F", +"^# c #343487", +"/# c #434388", +" ", +" ", +" ", +" . + @ # ", +" $ % & * = - ; > , ' ) ! ", +" ~ { ] ^ / = ( _ : < [ } | 1 2 3 4 5 6 ", +" 7 8 9 0 a b c d e f g h i j k l m n o p q r ", +" s t u v _ f d d d w x y z A B C D E F G H I J K L ", +" M N O _ c e d d d _ P Q R S T U V W X Y Z ` ... ", +" +.@.#.$.d d d d %.&._ *.=.-.;.>.,.'.).!.~. ", +" {.].^./.(.d d _.$.:._ <.[.}.|.1.2.3.4.5. ", +" 6.7.7.4 8.e : w 9.0.a.b.c.2 d.e.f.g.h.i.j.k. ", +" l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.o o z.A.B./.b C.D. ", +" E.F.G.].o H.z.I.J.K.L.M.N.O.P.o o o Q.R.S._.b B.T. ", +" U.V.W.X.f.f.7.Y.Z.`. + + +.+++].o o o.n z.q.@+#+$+%+ ", +" &+ +*+=+].o -+;+>+ + + + +,+'+H.o o o o o H.)+o !+~+{+ ", +" ]+ +^+/+H.o.(+_+ + + + + +:+<+z.o o o o o o o 7.n H.[+}+ ", +" |+ +1+2+3+4+5+6+ + + + + +7+8+H.o o f.9+f.9+f.F 0+a+b+o.c+ ", +" &+ +d+e+f+g+h+i+ + + + + +j+k+].f.9+l+m+n+o+p+q+r+s+t+u+v+ ", +" w+ +x+y+z+A+B+C+ + + + + +D+E+9+F+G+H+I+J+K+L+M+N+O+ ", +" P+Q+R+S+T+U+V+W+ + + + +X+Y+Z+`+ @I+J+Z .@+@E. ", +" @@#@$@%@&@*@=@-@;@>@,@'@)@!@~@{@]@^@I+/@(@_@ ", +" :@<@[@}@|@1@2@3@4@5@6@7@8@9@0@L+a@b@c@d@e@ ", +" f@g@h@i@i@j@k@l@|@m@n@o@p@q@r@s@t@u@p v@ ", +" w@x@y@z@A@B@i@C@D@E@F@G@H@I@L+J@K@L@p M@ ", +" N@O@P@Q@R@S@T@U@V@W@X@Y@Z@Y@`@ #.#p +# ", +" @###$#%#&#*#=#-#;#>#,#'#)#!#~#{#]# ", +" ^#/# ", +" ", +" ", +" ", +" "}; diff --git a/src/sdl/Srb2SDL.ico b/src/sdl/Srb2SDL.ico index 5ab791af37f815c0164e6053c34879ecf0c3fff0..700276fd4b9ac2810a6981eb054921f3708c702b 100644 GIT binary patch literal 372798 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 G1OE?SzcGja literal 2238 zcmc)MF-Rj>7{Ku_cLzDP@DL%Qupn6?*P33vQd8Mz`oK0Ph`Dgiyx^jhY&KvZg{5q< z97j^6k=O-`1g@}}N-UNHtTxHa7)=(1cmJ8mME5w$R{Pgigxg5B@1QM4sA*;#Kng;i=JRG^BCe5c{t`$Q_FItBBSZKZ1s) z!+y~6>ElPSY%R66mSaoHc2mn*T}z^Z^P+q$l0O&8oQR}yBFPQ0I`|g8iZ9`F_%wEt zSjR8pm+%Sv9G-b=HT*Gt8^4B6VEr4y3tsSomksIQTlgxzgwNsA_)Yw}T+1?k37^2v z;ca{yZ{eHxI=+Ih;LG?tK7&u;lX#8Sc#YS1jn{auUQ^GhC)6Bu!}m76jkoYkd>!x2 zUO|`9d2|MyLMNHOgKy!h_!2&cPvbZ7>-c5-5S!!vKKhCjw{g; z-@;e%C43H_#&6=+@yo2{604bDHRtd)zKyr=O?(|+!B_BQd>)^{r|?O<#%sLBYrMv5 zJU4XB4V|-HCu~=a?b_H7vGHxZg>T~P_zM1o*GD?|7QTuv;dA&j{)N|vc`d2okMZ01 zHGBg9(gIn!gKy!h_!6F#)@l5|FOa2ed>e1!oA^4O#d%?YEEb|h9248b8j&DgS|HbT z<>ux_uCA`+^72wHE-vKk>`W?^ikzOFO1WH?qoX6q=kv0&vm=>IMz*%LB$Z0Z%F2o) zlSx@zT$K6wd6}A;;*I!!%3$W(>-HTd+7G*&p;F)E<8NlYa(8<>GZ;M63h()5Y zu*}{Ui^VKirJmC9FdMsz#fBe({O%<0c=vZ(yS*>nuI)m&bnydu zH_Z3DBlmVXD1*DVqzWDg(+qp;N;k-Ny_uED6|?tYzCRt+x8jT^FhdZgB|06I2XV)F zBgiY2%?|GeL&MBE)4iNR1!XVHhv%>Mbnl&d=Zy2ehW+80kuL4w_y#BQkMpj4>9H3| z4SL=T{c(4A8giSiw;9Y3?e(HTGt8>5-c$6)o%b_$hRO5oPtvb~hxE70H1?d|4T|zF zhnZ}U!33t4^2=R(-}K6Ou!v(ASrulDK`g$nb_@QMgX!-L!wkopqc^kh?+S%NHpp>g zxT%Jwe*tq>y&b;(jeMaHf{|f(TWth)fKXYo@83^A2!kmm54RWgKb;Zd{Z-~u@AHf&LuPdK7(rJ^eQjQPkQ1 diff --git a/src/sdl12/SDL_icon.xpm b/src/sdl12/SDL_icon.xpm index 70bb02d3c..cf72960df 100644 --- a/src/sdl12/SDL_icon.xpm +++ b/src/sdl12/SDL_icon.xpm @@ -1,80 +1,425 @@ /* XPM */ -static const char * SDL_icon_xpm[] = { -"32 32 45 1", -" c None", -". c #6B6BFF", -"+ c #3D00B9", -"@ c #4848FF", -"# c #2525FF", -"$ c #310096", -"% c #003196", -"& c #003DB9", -"* c #620096", -"= c #6E6E6E", -"- c #966200", -"; c #250073", -"> c #626262", -", c #FF8F6B", -"' c #FFC66B", -") c #FFAB8E", -"! c #000080", -"~ c #B6B6B6", -"{ c #929292", -"] c #FFD48E", -"^ c #0000B9", -"/ c #565656", -"( c #868686", -"_ c #808080", -": c #C0C0C0", -"< c #DADADA", -"[ c #F2F2F2", -"} c #FFFFFF", -"| c #CECECE", -"1 c #AAAAAA", -"2 c #E6E6E6", -"3 c #000096", -"4 c #AB8EFF", -"5 c #190050", -"6 c #000000", -"7 c #8E8EFF", -"8 c #3E3E3E", -"9 c #7A7A7A", -"0 c #0E0E0E", -"a c #9E9E9E", -"b c #001950", -"c c #C2C2C2", -"d c #323232", -"e c #002573", -"f c #A0A0A4", -" ", -" ", -" ", -" .+@##@. ", -" @@.@#######@ ", -" @@....######### ", -" .. .@.....@+##$%%%&&% ", -" ..@# @@....@+#*=-;%%%%% ", -" ..@#@......@>,')!%%%$ ", -" ~..$#.........{])^#+%/ ", -" +##@.........()^@@@@@_ ", -" $####@........#=#######+ ", -" +######....@@##^#########_ ", -" +#####=:<<:+##############/ ", -"[<=####{<}}}}|###############= ", -" }1###=2}}}}}}.############### ", -" }<3#3~}}}}}}}4################ ", -" }<5#6:}}}}}}}7################/", -" }:6861}}}}}}}.########$$ 9 .@$", -" }:0a6~}}}}}}}@######5b ", -"22cd262}}}}}}2######5b$ ", -" 2>1a}}}}}}}{(*###%be## ", -" 860)1<[22c1)]]+##be### ", -" ~)]]]))))]]]]]=#bb#### ", -" )]]]]]]]]](]]=eb$#### ", -" :]]]]]]]]]'9bbb$##### ", -" ),'''''( >db+### ", -" =##f ", -" { ", -" ", -" ", -" "}; +static char * C:\Repo\srb2\src\sdl\SDL_icon_xpm[] = { +"32 32 390 2", +" c None", +". c #4F4F70", +"+ c #4D4D87", +"@ c #4D4D84", +"# c #4E4E6C", +"$ c #6C6C95", +"% c #5E5EB2", +"& c #6B6BE7", +"* c #7373F9", +"= c #7C7CFF", +"- c #6F70E7", +"; c #494BB2", +"> c #4F4FA3", +", c #6464D4", +"' c #7979F5", +") c #5F5FCA", +"! c #5D5D93", +"~ c #3A3A9F", +"{ c #6060AC", +"] c #777793", +"^ c #5C5CB3", +"/ c #7373EA", +"( c #7A7AFF", +"_ c #7575FF", +": c #7979FF", +"< c #6264DD", +"[ c #47478C", +"} c #564567", +"| c #4647D0", +"1 c #5C5CAE", +"2 c #5E5EFF", +"3 c #2929FF", +"4 c #1D1DFF", +"5 c #1919D1", +"6 c #4F4F90", +"7 c #1E1ECE", +"8 c #5858FF", +"9 c #6767A8", +"0 c #4949A0", +"a c #7070FB", +"b c #7D7DFF", +"c c #7777FF", +"d c #7373FF", +"e c #7272FF", +"f c #7878FF", +"g c #6465D8", +"h c #363886", +"i c #9F7655", +"j c #C89B5C", +"k c #1D1CB7", +"l c #3031B1", +"m c #1919F4", +"n c #1111FF", +"o c #1818FF", +"p c #1B1BFF", +"q c #1C1CFF", +"r c #2626B3", +"s c #1E1EC8", +"t c #1A1AE8", +"u c #24249F", +"v c #2F2FD2", +"w c #7676FF", +"x c #6869E2", +"y c #414290", +"z c #8C6751", +"A c #FCBA68", +"B c #E9BD7D", +"C c #201EB8", +"D c #090AB8", +"E c #1616EB", +"F c #1818FD", +"G c #1414EE", +"H c #1010E1", +"I c #0E0EE2", +"J c #0E0EF4", +"K c #0606B2", +"L c #7A7A89", +"M c #0C0C9A", +"N c #0A0AA7", +"O c #2424E4", +"P c #6669E6", +"Q c #4F4A8F", +"R c #BF853B", +"S c #FFD98D", +"T c #CDAB76", +"U c #1717C4", +"V c #0F10BA", +"W c #0909B6", +"X c #0505C3", +"Y c #0000B6", +"Z c #0000BE", +"` c #0000AD", +" . c #1D1D83", +".. c #63638E", +"+. c #090975", +"@. c #1414F3", +"#. c #5B5BFF", +"$. c #7B7BFF", +"%. c #7070FF", +"&. c #6E6EFF", +"*. c #7172F6", +"=. c #625DAF", +"-. c #BA9E6C", +";. c #887167", +">. c #090DF2", +",. c #1313BE", +"'. c #000085", +"). c #0000AC", +"!. c #0202AA", +"~. c #242488", +"{. c #1414C7", +"]. c #1717FF", +"^. c #5959FF", +"/. c #7F7FFF", +"(. c #7474FF", +"_. c #7171FF", +":. c #8686FF", +"<. c #7574FF", +"[. c #797CFF", +"}. c #5756B8", +"|. c #1C19A4", +"1. c #1617FF", +"2. c #1212BD", +"3. c #040485", +"4. c #0707A4", +"5. c #1B1B71", +"6. c #373797", +"7. c #1616FF", +"8. c #5050FF", +"9. c #8080FF", +"0. c #AAAAFF", +"a. c #AEAEF6", +"b. c #8A8AEF", +"c. c #6969FB", +"d. c #2728FF", +"e. c #1314FF", +"f. c #1919FF", +"g. c #1313E8", +"h. c #1F1FF4", +"i. c #5454FF", +"j. c #6D6DF0", +"k. c #6868B5", +"l. c #0B0BB8", +"m. c #1212C5", +"n. c #1616FC", +"o. c #1515FF", +"p. c #1212FF", +"q. c #2323FF", +"r. c #3636FF", +"s. c #4040FF", +"t. c #4343F9", +"u. c #5D5DB8", +"v. c #7F7F92", +"w. c #878793", +"x. c #4B4B94", +"y. c #0B0CE2", +"z. c #1313FF", +"A. c #4C4CFF", +"B. c #8282FF", +"C. c #7171ED", +"D. c #636394", +"E. c #575785", +"F. c #A9A99C", +"G. c #1414BC", +"H. c #1414FF", +"I. c #0707FD", +"J. c #2525AA", +"K. c #A8A8A4", +"L. c #EBEBE2", +"M. c #F9F9F2", +"N. c #E1E1CC", +"O. c #4D4D9F", +"P. c #0B0BF7", +"Q. c #2121FF", +"R. c #3232FF", +"S. c #5555FF", +"T. c #6161B4", +"U. c #B5B5B2", +"V. c #FFFFF8", +"W. c #4F4F9A", +"X. c #0B0BF5", +"Y. c #1616C5", +"Z. c #A8A8A1", +"`. c #FFFFFC", +" + c #FFFFFF", +".+ c #C0C0C4", +"++ c #1212D4", +"@+ c #4444FF", +"#+ c #6464FF", +"$+ c #8383FF", +"%+ c #6767C3", +"&+ c #E4E4E4", +"*+ c #9494AE", +"=+ c #0808DF", +"-+ c #0D0DF2", +";+ c #61619A", +">+ c #F1F1E0", +",+ c #E8E8DD", +"'+ c #2424BB", +")+ c #1010FF", +"!+ c #3434FF", +"~+ c #6161FF", +"{+ c #6969D2", +"]+ c #EFEFF0", +"^+ c #C2C2BA", +"/+ c #1010B6", +"(+ c #0909AC", +"_+ c #A4A49A", +":+ c #EAEADE", +"<+ c #2525B8", +"[+ c #2F2FFF", +"}+ c #3C3CB5", +"|+ c #EEEEEE", +"1+ c #BBBBAD", +"2+ c #0B0B56", +"3+ c #0B0BFC", +"4+ c #1212EF", +"5+ c #0C0C3E", +"6+ c #919187", +"7+ c #DEDED6", +"8+ c #1F1FC0", +"9+ c #1A1AFF", +"0+ c #1717FA", +"a+ c #1515F8", +"b+ c #1111FC", +"c+ c #494992", +"d+ c #999998", +"e+ c #3E3E3B", +"f+ c #3C3C99", +"g+ c #535397", +"h+ c #5A5A4D", +"i+ c #6F6F70", +"j+ c #BFBFC9", +"k+ c #1111D6", +"l+ c #1515F1", +"m+ c #0F0FE2", +"n+ c #0D0DD9", +"o+ c #0909CD", +"p+ c #0808C7", +"q+ c #0505C7", +"r+ c #0303CB", +"s+ c #0101C0", +"t+ c #0202AF", +"u+ c #0606AC", +"v+ c #121283", +"w+ c #BBBBBB", +"x+ c #BEBEBE", +"y+ c #2F2F2E", +"z+ c #C7C8BB", +"A+ c #D8DAD1", +"B+ c #272828", +"C+ c #929292", +"D+ c #8688C7", +"E+ c #0506F6", +"F+ c #1616F5", +"G+ c #0B0BD3", +"H+ c #0202B6", +"I+ c #0000AF", +"J+ c #0000B4", +"K+ c #0000BD", +"L+ c #0000BB", +"M+ c #00009E", +"N+ c #2C2C7E", +"O+ c #6A6A8B", +"P+ c #959595", +"Q+ c #F0F0F1", +"R+ c #E1E1E1", +"S+ c #8C8E90", +"T+ c #BEBEBF", +"U+ c #C9C7C5", +"V+ c #939699", +"W+ c #E7EAED", +"X+ c #CBCBC7", +"Y+ c #413B9B", +"Z+ c #0607DD", +"`+ c #0C0CE2", +" @ c #0303B9", +".@ c #0000A8", +"+@ c #181888", +"@@ c #6A6A6A", +"#@ c #626263", +"$@ c #4B4B4C", +"%@ c #3E3B36", +"&@ c #9B805C", +"*@ c #D9B07D", +"=@ c #C9AE89", +"-@ c #B9AF9E", +";@ c #C7C5C4", +">@ c #CBCCCF", +",@ c #C7C6C6", +"'@ c #AEA59A", +")@ c #B69974", +"!@ c #D8B87F", +"~@ c #9B8272", +"{@ c #0E0B9B", +"]@ c #0000B7", +"^@ c #0000B8", +"/@ c #000082", +"(@ c #00007A", +"_@ c #636379", +":@ c #62533E", +"<@ c #B59B6C", +"[@ c #DEB07B", +"}@ c #FECC90", +"|@ c #FFCE92", +"1@ c #FEC98C", +"2@ c #F1BD82", +"3@ c #D1A979", +"4@ c #BC9E73", +"5@ c #CCA777", +"6@ c #EAB980", +"7@ c #FFCD90", +"8@ c #FFD595", +"9@ c #FDD782", +"0@ c #413678", +"a@ c #0000AE", +"b@ c #000077", +"c@ c #010193", +"d@ c #0C0CE4", +"e@ c #38389E", +"f@ c #EEC585", +"g@ c #FFDA9D", +"h@ c #FFC992", +"i@ c #FFC88F", +"j@ c #FFC990", +"k@ c #FFCE93", +"l@ c #FFD094", +"m@ c #FFCC92", +"n@ c #C9A174", +"o@ c #EDBD88", +"p@ c #FAD287", +"q@ c #3A2F7F", +"r@ c #0000BA", +"s@ c #0000B0", +"t@ c #0101B2", +"u@ c #1111ED", +"v@ c #1919C1", +"w@ c #95887C", +"x@ c #DCAC6E", +"y@ c #FFD393", +"z@ c #FFCD94", +"A@ c #FFCA93", +"B@ c #FFC991", +"C@ c #FFC78E", +"D@ c #FFCB91", +"E@ c #E0B581", +"F@ c #BB9A6F", +"G@ c #FFDC97", +"H@ c #C1A173", +"I@ c #0E0B9A", +"J@ c #0000B5", +"K@ c #0101B6", +"L@ c #1010E0", +"M@ c #1616EC", +"N@ c #A68156", +"O@ c #E7AC6B", +"P@ c #FFC582", +"Q@ c #FFCF8F", +"R@ c #FFD195", +"S@ c #FFD296", +"T@ c #FFD396", +"U@ c #FFD193", +"V@ c #FFD28F", +"W@ c #D2A96B", +"X@ c #2F2482", +"Y@ c #0000C1", +"Z@ c #0000C0", +"`@ c #0000BF", +" # c #0101BF", +".# c #1212F0", +"+# c #767698", +"@# c #9C866E", +"## c #A9865D", +"$# c #C0915D", +"%# c #C89760", +"&# c #C29360", +"*# c #AD8A61", +"=# c #9D8971", +"-# c #7F7A7A", +";# c #70708F", +"># c #6F6F91", +",# c #575788", +"'# c #464687", +")# c #2F2F87", +"!# c #15158F", +"~# c #0101A8", +"{# c #1313FB", +"]# c #57579F", +"^# c #343487", +"/# c #434388", +" ", +" ", +" ", +" . + @ # ", +" $ % & * = - ; > , ' ) ! ", +" ~ { ] ^ / = ( _ : < [ } | 1 2 3 4 5 6 ", +" 7 8 9 0 a b c d e f g h i j k l m n o p q r ", +" s t u v _ f d d d w x y z A B C D E F G H I J K L ", +" M N O _ c e d d d _ P Q R S T U V W X Y Z ` ... ", +" +.@.#.$.d d d d %.&._ *.=.-.;.>.,.'.).!.~. ", +" {.].^./.(.d d _.$.:._ <.[.}.|.1.2.3.4.5. ", +" 6.7.7.4 8.e : w 9.0.a.b.c.2 d.e.f.g.h.i.j.k. ", +" l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.o o z.A.B./.b C.D. ", +" E.F.G.].o H.z.I.J.K.L.M.N.O.P.o o o Q.R.S._.b B.T. ", +" U.V.W.X.f.f.7.Y.Z.`. + + +.+++].o o o.n z.q.@+#+$+%+ ", +" &+ +*+=+].o -+;+>+ + + + +,+'+H.o o o o o H.)+o !+~+{+ ", +" ]+ +^+/+H.o.(+_+ + + + + +:+<+z.o o o o o o o 7.n H.[+}+ ", +" |+ +1+2+3+4+5+6+ + + + + +7+8+H.o o f.9+f.9+f.F 0+a+b+o.c+ ", +" &+ +d+e+f+g+h+i+ + + + + +j+k+].f.9+l+m+n+o+p+q+r+s+t+u+v+ ", +" w+ +x+y+z+A+B+C+ + + + + +D+E+9+F+G+H+I+J+K+L+M+N+O+ ", +" P+Q+R+S+T+U+V+W+ + + + +X+Y+Z+`+ @I+J+Z .@+@E. ", +" @@#@$@%@&@*@=@-@;@>@,@'@)@!@~@{@]@^@I+/@(@_@ ", +" :@<@[@}@|@1@2@3@4@5@6@7@8@9@0@L+a@b@c@d@e@ ", +" f@g@h@i@i@j@k@l@|@m@n@o@p@q@r@s@t@u@p v@ ", +" w@x@y@z@A@B@i@C@D@E@F@G@H@I@L+J@K@L@p M@ ", +" N@O@P@Q@R@S@T@U@V@W@X@Y@Z@Y@`@ #.#p +# ", +" @###$#%#&#*#=#-#;#>#,#'#)#!#~#{#]# ", +" ^#/# ", +" ", +" ", +" ", +" "}; diff --git a/src/sdl12/Srb2SDL.ico b/src/sdl12/Srb2SDL.ico index 5ab791af37f815c0164e6053c34879ecf0c3fff0..700276fd4b9ac2810a6981eb054921f3708c702b 100644 GIT binary patch literal 372798 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 G1OE?SzcGja literal 2238 zcmc)MF-Rj>7{Ku_cLzDP@DL%Qupn6?*P33vQd8Mz`oK0Ph`Dgiyx^jhY&KvZg{5q< z97j^6k=O-`1g@}}N-UNHtTxHa7)=(1cmJ8mME5w$R{Pgigxg5B@1QM4sA*;#Kng;i=JRG^BCe5c{t`$Q_FItBBSZKZ1s) z!+y~6>ElPSY%R66mSaoHc2mn*T}z^Z^P+q$l0O&8oQR}yBFPQ0I`|g8iZ9`F_%wEt zSjR8pm+%Sv9G-b=HT*Gt8^4B6VEr4y3tsSomksIQTlgxzgwNsA_)Yw}T+1?k37^2v z;ca{yZ{eHxI=+Ih;LG?tK7&u;lX#8Sc#YS1jn{auUQ^GhC)6Bu!}m76jkoYkd>!x2 zUO|`9d2|MyLMNHOgKy!h_!2&cPvbZ7>-c5-5S!!vKKhCjw{g; z-@;e%C43H_#&6=+@yo2{604bDHRtd)zKyr=O?(|+!B_BQd>)^{r|?O<#%sLBYrMv5 zJU4XB4V|-HCu~=a?b_H7vGHxZg>T~P_zM1o*GD?|7QTuv;dA&j{)N|vc`d2okMZ01 zHGBg9(gIn!gKy!h_!6F#)@l5|FOa2ed>e1!oA^4O#d%?YEEb|h9248b8j&DgS|HbT z<>ux_uCA`+^72wHE-vKk>`W?^ikzOFO1WH?qoX6q=kv0&vm=>IMz*%LB$Z0Z%F2o) zlSx@zT$K6wd6}A;;*I!!%3$W(>-HTd+7G*&p;F)E<8NlYa(8<>GZ;M63h()5Y zu*}{Ui^VKirJmC9FdMsz#fBe({O%<0c=vZ(yS*>nuI)m&bnydu zH_Z3DBlmVXD1*DVqzWDg(+qp;N;k-Ny_uED6|?tYzCRt+x8jT^FhdZgB|06I2XV)F zBgiY2%?|GeL&MBE)4iNR1!XVHhv%>Mbnl&d=Zy2ehW+80kuL4w_y#BQkMpj4>9H3| z4SL=T{c(4A8giSiw;9Y3?e(HTGt8>5-c$6)o%b_$hRO5oPtvb~hxE70H1?d|4T|zF zhnZ}U!33t4^2=R(-}K6Ou!v(ASrulDK`g$nb_@QMgX!-L!wkopqc^kh?+S%NHpp>g zxT%Jwe*tq>y&b;(jeMaHf{|f(TWth)fKXYo@83^A2!kmm54RWgKb;Zd{Z-~u@AHf&LuPdK7(rJ^eQjQPkQ1 diff --git a/src/win32/Srb2win.ico b/src/win32/Srb2win.ico index e369735effcaec2be38a084c3ce7e89b94c9ee86..700276fd4b9ac2810a6981eb054921f3708c702b 100644 GIT binary patch literal 372798 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 G1OE?SzcGja literal 6006 zcmeI0O=uk15ywlbu}0f7Qd?t7iX0`9N6|`JUv}Lm!>k>&IxI2{&7#4gO99V|9u`a;|vj%}d3$h)3*sy{u`|^9QyJx!P z5B3sBz$Lw|_p1I?^?&txT0IhJlXqlzSd9F+Q{+8nAAAt4yG8C{8)rGp_$i}JFuXy! zySt@||Evti3i=B@9}roPQPv;I!l<@=Br6{Z>lrzI{J4Dak%$@{m6In=%K7u>MSb## z%*@P)%&f@#{JbnKE{eKvL8{fN)M_6#4r@zioGRN}ou7p;L~Hx7$*T{6CESvF^d2u`_Z0AIJ7s zlYfYLZ$z+}Kk|#bKh9a$_K|U2;l0Qlt6oi09|jqU*-6|`H6ZOVbMLT^~0>FysGIZ)6N1&bW*@9(t3SguFLMh@6kF0348psXFm7Y+@N zj=Yo0xsdegsPe$KdVBD(Z*y(((fty)#c}m_&ufCI(w{1shXm^ROs3aewgTY zhx%7_+5X2h$z(Fp$)_Wq&r45FkM#BR$>89i6pKZfn3#}r=g!HQGiPLSa#Bv5I3d+v zDLH#q$?xU9sHcH^d4EgpfBm)m?k|6(g2Qkb9wP{s4mJmygU!)4-bpmX#qKh3vAft^ z>^jWD?qT;>c-TGcC<(9!*aPeVh5)-_tyrtTRCc&JBzH*U5afswQ=W?h2L}!g92__p zN^o%C;K0Fwg98Uc6Alg>95^^|aNuC5!@+@r0|y5V4jdeX4IU0W9L{;W zE?iu=m@UJ_rMOEWm!vLSOdD{zOkB9Qa4~IxhYJrE9xgmwc$ikf!-azj2Nw>ybuK(y zIJj^KsHM1?7E&ktVQt#0y8|m~d!S6KsqMkZqo_v#4^AGnJ)9m%JZgK?HpgLVW2e4H zeUJM3h&<|h^u~jO2M3Qn=wqWRX7^aoT=g;1gMfMg+yZz6)H6q`dC-FZ9)ae;#>{aO z6u>2bO8|+0g60;0OF&=%D8LZFgJMQ=AD0KWkv4Zy(>3w-joLq9>}9dkL2;=$FjM(DLXqmvbVP<+y7SP`+)wQ zKy~v=GCgDHyl5`gTY0$y`Ik+vx8%yc|7venacb)0V%nE0`HjY_@b>hlm0u#2%BNFZ zCMMTaD$Uj!$jkWd(~GN3S*)D4OQp%#*;#UH$)syq)^rogq_VoYxX=SShBwOl@C!-! z>LndLmr3CF_2+a7P5~;+Hwd^E(%DCU`cmbRj;K@?7Qz{e`9`BzAWh%yh27NZ!t(ZW zZtm>XJlR)Q3#2B%6ey+WFJ}+tr%o^IHvb%M5wM^;IP<8o0jz?f&Zq7C!!XIluG4HS>t=lwBYG$@TQ8dMb8ZWaHg?j zEhq5XiTvqlj{MK(2rYdteA%LpyPM?jpYF5@{41Tbxmx1jo~hfWeQvfDu+~JRCgz|I ztF7>OHnZC=!V)|2d8N>BHupt#FEsm`TUmX`FLs*8mBvS(nva|A+Ow>d)@h~i%@0|t zy8qD$w{8nJc5M7j%Nnvl!`x&*CUIA+MT9oi)?)nHTH`lQTKGhAw!9Vw z07p!Ev|pM3gCVxj@RP|6eodz`@aCnmT3PZpG_Oqh{hD^w+uyZoU2U&x{T=UBTJP=CeBU$nIy#Ggzpi4pu_yIVwAT8K(iVC7 zrdZX}SZBjJ!hcKZ+CC(*uJx%%Uk-H}`L$j1uA?;%txrWd=ArFcH2=1Gh}U0a&HmZ2 WwksN-af&abIzIeTs;C}X!!VWr diff --git a/src/win32ce/Srb2win.ico b/src/win32ce/Srb2win.ico index 0036a827a4625745397da1631e48101879a4f212..700276fd4b9ac2810a6981eb054921f3708c702b 100644 GIT binary patch literal 372798 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 G1OE?SzcGja literal 2238 zcmeHJJ#5-Q6#gi|ad5&Vrj83u3)pqB!xZ+Aju|_l&a6l**;w#UF;a{?;SLoO*~!$+;Pxqwa{+2!EbNT>2!e3 z1ifAl{eB<3+lBA@7!HRRkH_Gn5vJ2AzTe+d{D9ePhVD0x`FxHb2rzo!SS%Lk{^VFL zml*xxSglsrY&O_#x8R)9%=Wh5f&C8r?>kU_aRCNn@6rUj>IkDd2`HW@dB#`@w(7At z=Zd1Jgr;#jM(d?|-8ho?uDm92n=GUmOi`YfpCV&d+)K~!E#+ohB3;{ z!c{~`lT4@e%*uQW|d?Z1GbhXg&(j*Zucglk&T-84mLN(EvtmC!q&)iJ*rK)9HU1(>FD31J0jrp0dHRcmerWs-Mz36>`4LaQ=s-`|-a(GqAz{ From 9b0e09877e57ca2bf87fe798dc5d1c5b284e5999 Mon Sep 17 00:00:00 2001 From: MonsterIestyn Date: Thu, 22 Jan 2015 17:57:26 +0000 Subject: [PATCH 012/383] gametype command now prints gametype NAMES instead of numbers. Even prints "Single player" when appropriate! git-svn-id: https://code.orospakr.ca/svn/srb2/trunk@8997 6de4a73c-47e2-0310-b8c1-93d6ecd3f8cd --- src/d_netcmd.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 266161c7c..10605f20f 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3193,7 +3193,27 @@ static void Command_ModDetails_f(void) // static void Command_ShowGametype_f(void) { - CONS_Printf(M_GetText("Current gametype is %d\n"), gametype); + INT32 j; + const char *gametypestr = NULL; + + if (!(netgame || multiplayer)) // print "Single player" instead of "Co-op" + { + CONS_Printf(M_GetText("Current gametype is %s\n"), M_GetText("Single player")); + return; + } + // find name string for current gametype + for (j = 0; gametype_cons_t[j].strvalue; j++) + { + if (gametype_cons_t[j].value == gametype) + { + gametypestr = gametype_cons_t[j].strvalue; + break; + } + } + if (gametypestr) + CONS_Printf(M_GetText("Current gametype is %s\n"), gametypestr); + else // string for current gametype was not found above (should never happen) + CONS_Printf(M_GetText("Unknown gametype set (%d)\n"), gametype); } /** Plays the intro. From 092134ad0c664e30180dc360338c2d33cad4dd78 Mon Sep 17 00:00:00 2001 From: JTE Date: Thu, 22 Jan 2015 19:02:38 +0000 Subject: [PATCH 013/383] Title screen cheat "devmode". Access the benefits of -debug, console devmode, and a complete gamedata.dat (all secrets unlocked) all in one go. Moved "#if 0" and "#if 1" to "#ifdef DEVMODE" so the existance of this cheat and MD5 validation and all that can be toggled in one place too. git-svn-id: https://code.orospakr.ca/svn/srb2/trunk@8998 6de4a73c-47e2-0310-b8c1-93d6ecd3f8cd --- src/d_main.c | 6 +++--- src/doomdef.h | 3 ++- src/m_cheat.c | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index a959a8632..9d0afab81 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -943,9 +943,9 @@ void D_SRB2Main(void) #endif #if defined (_WIN32_WCE) //|| defined (_DEBUG) || defined (GP2X) - devparm = !M_CheckParm("-nodebug"); + devparm = M_CheckParm("-nodebug") == 0; #else - devparm = M_CheckParm("-debug"); + devparm = M_CheckParm("-debug") != 0; #endif // for dedicated server @@ -1118,7 +1118,7 @@ void D_SRB2Main(void) #endif D_CleanFile(); -#if 1 // md5s last updated 12/14/14 +#ifndef DEVMODE // md5s last updated 12/14/14 // Check MD5s of autoloaded files W_VerifyFileMD5(0, ASSET_HASH_SRB2_SRB); // srb2.srb/srb2.wad diff --git a/src/doomdef.h b/src/doomdef.h index 4a6d6e576..d07e50366 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -138,7 +138,8 @@ extern FILE *logstream; #endif -#if 0 +//#define DEVMODE // Disable this for release builds to remove excessive cheat commands and enable MD5 checking and stuff, all in one go. :3 +#ifdef DEVMODE #define VERSION 0 // Game version #define SUBVERSION 0 // more precise version number #define VERSIONSTRING "Trunk" diff --git a/src/m_cheat.c b/src/m_cheat.c index 8cea4c6ae..2fcbe165f 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -91,6 +91,33 @@ static UINT8 cheatf_warp(void) return 1; } +#ifdef DEVMODE +static UINT8 cheatf_devmode(void) +{ + UINT8 i; + + if (modifiedgame) + return 0; + + if (menuactive && currentMenu != &MainDef) + return 0; // Only on the main menu! + + S_StartSound(0, sfx_itemup); + + // Just unlock all the things and turn on -debug and console devmode. + G_SetGameModified(false); + for (i = 0; i < MAXUNLOCKABLES; i++) + unlockables[i].unlocked = true; + devparm = TRUE; + cv_debug |= 0x8000; + + // Refresh secrets menu existing. + M_ClearMenus(true); + M_StartControlPanel(); + return 1; +} +#endif + static cheatseq_t cheat_ultimate = { 0, cheatf_ultimate, { SCRAMBLE('u'), SCRAMBLE('l'), SCRAMBLE('t'), SCRAMBLE('i'), SCRAMBLE('m'), SCRAMBLE('a'), SCRAMBLE('t'), SCRAMBLE('e'), 0xff } @@ -115,6 +142,14 @@ static cheatseq_t cheat_warp_joy = { SCRAMBLE(KEY_LEFTARROW), SCRAMBLE(KEY_UPARROW), SCRAMBLE(KEY_ENTER), 0xff } }; + +#ifdef DEVMODE +static cheatseq_t cheat_devmode = { + 0, cheatf_devmode, + { SCRAMBLE('d'), SCRAMBLE('e'), SCRAMBLE('v'), SCRAMBLE('m'), SCRAMBLE('o'), SCRAMBLE('d'), SCRAMBLE('e'), 0xff } +}; +#endif + // ========================================================================== // CHEAT SEQUENCE PACKAGE // ========================================================================== @@ -221,6 +256,9 @@ boolean cht_Responder(event_t *ev) ret += cht_CheckCheat(&cheat_ultimate_joy, (char)ch); ret += cht_CheckCheat(&cheat_warp, (char)ch); ret += cht_CheckCheat(&cheat_warp_joy, (char)ch); +#ifdef DEVMODE + ret += cht_CheckCheat(&cheat_devmode, (char)ch); +#endif return (ret != 0); } From 8d7b5941a842f609733c269ccff283f3369552ff Mon Sep 17 00:00:00 2001 From: JTE Date: Thu, 22 Jan 2015 19:02:45 +0000 Subject: [PATCH 014/383] Changed super colors to make them pulse instead of flash. Removed alt. supercolors from replay ghost stuff, because that's stupid. :/ git-svn-id: https://code.orospakr.ca/svn/srb2/trunk@8999 6de4a73c-47e2-0310-b8c1-93d6ecd3f8cd --- src/g_game.c | 18 ++++-------------- src/p_user.c | 15 ++++++++++++--- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 931388d87..917a86165 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4329,20 +4329,10 @@ void G_GhostTicker(void) switch(g->color) { case GHC_SUPER: // Super Sonic (P_DoSuperStuff) - // Yousa yellow now! - g->mo->color = SKINCOLOR_SUPER1 + (leveltime/2) % 5; - if (g->mo->skin) - switch (((skin_t*)g->mo->skin)-skins) - { - case 1: // Golden orange supertails. - g->mo->color = SKINCOLOR_TSUPER1 + (leveltime/2) % 5; - break; - case 2: // Pink superknux. - g->mo->color = SKINCOLOR_KSUPER1 + (leveltime/2) % 5; - break; - default: - break; - } + if (leveltime % 9 < 5) + g->mo->color = SKINCOLOR_SUPER1 + leveltime % 9; + else + g->mo->color = SKINCOLOR_SUPER1 + 9 - leveltime % 9; break; case GHC_INVINCIBLE: // Mario invincibility (P_CheckInvincibilityTimer) g->mo->color = (UINT8)(leveltime % MAXSKINCOLORS); diff --git a/src/p_user.c b/src/p_user.c index 3d77069ac..45e661428 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3385,13 +3385,22 @@ static void P_DoSuperStuff(player_t *player) switch (player->skin) { case 1: // Golden orange supertails. - player->mo->color = SKINCOLOR_TSUPER1 + (leveltime/2) % 5; + if (leveltime % 9 < 5) + player->mo->color = SKINCOLOR_TSUPER1 + leveltime % 9; + else + player->mo->color = SKINCOLOR_TSUPER1 + 9 - leveltime % 9; break; case 2: // Pink superknux. - player->mo->color = SKINCOLOR_KSUPER1 + (leveltime/2) % 5; + if (leveltime % 9 < 5) + player->mo->color = SKINCOLOR_KSUPER1 + leveltime % 9; + else + player->mo->color = SKINCOLOR_KSUPER1 + 9 - leveltime % 9; break; default: // Yousa yellow now! - player->mo->color = SKINCOLOR_SUPER1 + (leveltime/2) % 5; + if (leveltime % 9 < 5) + player->mo->color = SKINCOLOR_SUPER1 + leveltime % 9; + else + player->mo->color = SKINCOLOR_SUPER1 + 9 - leveltime % 9; break; } From c1bfde002779e1f67b40e18abb4cfb525d34c69e Mon Sep 17 00:00:00 2001 From: JTE Date: Thu, 22 Jan 2015 19:36:17 +0000 Subject: [PATCH 015/383] Fixed WGL code "device mode" breaking. The devil is in the details. git-svn-id: https://code.orospakr.ca/svn/srb2/trunk@9001 6de4a73c-47e2-0310-b8c1-93d6ecd3f8cd --- src/d_main.c | 2 +- src/doomdef.h | 4 ++-- src/m_cheat.c | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 9d0afab81..61255e272 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1118,7 +1118,7 @@ void D_SRB2Main(void) #endif D_CleanFile(); -#ifndef DEVMODE // md5s last updated 12/14/14 +#ifndef DEVELOP // md5s last updated 12/14/14 // Check MD5s of autoloaded files W_VerifyFileMD5(0, ASSET_HASH_SRB2_SRB); // srb2.srb/srb2.wad diff --git a/src/doomdef.h b/src/doomdef.h index d07e50366..3cea21ffc 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -138,8 +138,8 @@ extern FILE *logstream; #endif -//#define DEVMODE // Disable this for release builds to remove excessive cheat commands and enable MD5 checking and stuff, all in one go. :3 -#ifdef DEVMODE +//#define DEVELOP // Disable this for release builds to remove excessive cheat commands and enable MD5 checking and stuff, all in one go. :3 +#ifdef DEVELOP #define VERSION 0 // Game version #define SUBVERSION 0 // more precise version number #define VERSIONSTRING "Trunk" diff --git a/src/m_cheat.c b/src/m_cheat.c index 2fcbe165f..bc32e6cfa 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -91,7 +91,7 @@ static UINT8 cheatf_warp(void) return 1; } -#ifdef DEVMODE +#ifdef DEVELOP static UINT8 cheatf_devmode(void) { UINT8 i; @@ -143,7 +143,7 @@ static cheatseq_t cheat_warp_joy = { SCRAMBLE(KEY_ENTER), 0xff } }; -#ifdef DEVMODE +#ifdef DEVELOP static cheatseq_t cheat_devmode = { 0, cheatf_devmode, { SCRAMBLE('d'), SCRAMBLE('e'), SCRAMBLE('v'), SCRAMBLE('m'), SCRAMBLE('o'), SCRAMBLE('d'), SCRAMBLE('e'), 0xff } @@ -256,7 +256,7 @@ boolean cht_Responder(event_t *ev) ret += cht_CheckCheat(&cheat_ultimate_joy, (char)ch); ret += cht_CheckCheat(&cheat_warp, (char)ch); ret += cht_CheckCheat(&cheat_warp_joy, (char)ch); -#ifdef DEVMODE +#ifdef DEVELOP ret += cht_CheckCheat(&cheat_devmode, (char)ch); #endif return (ret != 0); From 7964f3b044e6a21db8a78d74410cbdf3915531c6 Mon Sep 17 00:00:00 2001 From: JTE Date: Fri, 23 Jan 2015 01:25:08 +0000 Subject: [PATCH 016/383] Removed the need to add "Status = 1" to all new Character select entries for it to become active. git-svn-id: https://code.orospakr.ca/svn/srb2/trunk@9002 6de4a73c-47e2-0310-b8c1-93d6ecd3f8cd --- src/dehacked.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/dehacked.c b/src/dehacked.c index a332da5df..8576d51f2 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -473,6 +473,7 @@ static void readPlayer(MYFILE *f, INT32 num) if (!slotfound && (slotfound = findFreeSlot(&num)) == false) goto done; + PlayerMenu[num].status = IT_CALL; for (i = 0; i < MAXLINELEN-3; i++) { @@ -545,6 +546,7 @@ static void readPlayer(MYFILE *f, INT32 num) if (!slotfound && (slotfound = findFreeSlot(&num)) == false) goto done; DEH_WriteUndoline(word, &description[num].picname[0], UNDO_NONE); + PlayerMenu[num].status = IT_CALL; strncpy(description[num].picname, word2, 8); } else if (fastcmp(word, "STATUS")) @@ -576,6 +578,8 @@ static void readPlayer(MYFILE *f, INT32 num) if (!slotfound && (slotfound = findFreeSlot(&num)) == false) goto done; DEH_WriteUndoline(word, description[num].skinname, UNDO_NONE); + PlayerMenu[num].status = IT_CALL; + strlcpy(description[num].skinname, word2, sizeof description[num].skinname); strlwr(description[num].skinname); } From 808775de02a9797f42ecc5b8dd7b87a5e2ab9490 Mon Sep 17 00:00:00 2001 From: RedEnchilada Date: Sun, 29 Mar 2015 00:49:27 -0500 Subject: [PATCH 017/383] Effect 4 on a map line now makes the front midtexture solid (Supports Effect 5 repeating of arbitrary lengths, but not of the automatic "top-to-bottom" type; just use Impassible there!) --- src/p_maputl.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/p_maputl.c b/src/p_maputl.c index 48dd54e8d..b909332b6 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -17,6 +17,7 @@ #include "p_local.h" #include "r_main.h" +#include "r_data.h" #include "p_maputl.h" #include "p_polyobj.h" #include "z_zone.h" @@ -520,6 +521,38 @@ void P_LineOpening(line_t *linedef) { fixed_t thingtop = tmthing->z + tmthing->height; + // Check for collision with front side's midtexture if Effect 4 is set + if (linedef->flags & ML_EFFECT4) { + side_t *side = &sides[linedef->sidenum[0]]; + fixed_t textop, texbottom, texheight; + fixed_t texmid, delta1, delta2; + + // Get the midtexture's height + texheight = textures[texturetranslation[side->midtexture]]->height << FRACBITS; + + // Set texbottom and textop to the Z coordinates of the texture's boundaries + if (linedef->flags & ML_DONTPEGBOTTOM) { + texbottom = openbottom + side->rowoffset; + textop = texbottom + texheight*(side->repeatcnt+1); + } else { + textop = opentop - side->rowoffset; + texbottom = textop - texheight*(side->repeatcnt+1); + } + + texmid = texbottom+(textop-texbottom)/2; + + delta1 = abs(tmthing->z - texmid); + delta2 = abs(thingtop - texmid); + + if (delta1 > delta2) { // Below + if (opentop > texbottom) + opentop = texbottom; + } else { // Above + if (openbottom < textop) + openbottom = textop; + } + } + // Check for fake floors in the sector. if (front->ffloors || back->ffloors #ifdef POLYOBJECTS From 70732f6475719fb42c50024739f8fc3ba5fa0cc3 Mon Sep 17 00:00:00 2001 From: RedEnchilada Date: Mon, 30 Mar 2015 13:06:04 -0500 Subject: [PATCH 018/383] Make solid midtexture trick work properly(?) for polyobjects --- src/p_maputl.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/p_maputl.c b/src/p_maputl.c index b909332b6..a65d2fa76 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -531,12 +531,25 @@ void P_LineOpening(line_t *linedef) texheight = textures[texturetranslation[side->midtexture]]->height << FRACBITS; // Set texbottom and textop to the Z coordinates of the texture's boundaries - if (linedef->flags & ML_DONTPEGBOTTOM) { - texbottom = openbottom + side->rowoffset; - textop = texbottom + texheight*(side->repeatcnt+1); - } else { - textop = opentop - side->rowoffset; - texbottom = textop - texheight*(side->repeatcnt+1); +#ifdef POLYOBJECTS + if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) { + if (linedef->flags & ML_DONTPEGBOTTOM) { + texbottom = back->floorheight + side->rowoffset; + textop = texbottom + texheight*(side->repeatcnt+1); + } else { + textop = back->ceilingheight - side->rowoffset; + texbottom = textop - texheight*(side->repeatcnt+1); + } + } else +#endif + { + if (linedef->flags & ML_DONTPEGBOTTOM) { + texbottom = openbottom + side->rowoffset; + textop = texbottom + texheight*(side->repeatcnt+1); + } else { + textop = opentop - side->rowoffset; + texbottom = textop - texheight*(side->repeatcnt+1); + } } texmid = texbottom+(textop-texbottom)/2; From 965bd2f694b661a45c55861cbba013d68c1dc290 Mon Sep 17 00:00:00 2001 From: MonsterIestyn Date: Wed, 28 Jan 2015 15:16:50 +0000 Subject: [PATCH 019/383] Crawlas now use only one state for looking each --- src/dehacked.c | 2 -- src/info.c | 6 ++---- src/info.h | 2 -- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 8576d51f2..0fd914f25 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -3811,7 +3811,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Blue Crawla "S_POSS_STND", - "S_POSS_STND2", "S_POSS_RUN1", "S_POSS_RUN2", "S_POSS_RUN3", @@ -3821,7 +3820,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Red Crawla "S_SPOS_STND", - "S_SPOS_STND2", "S_SPOS_RUN1", "S_SPOS_RUN2", "S_SPOS_RUN3", diff --git a/src/info.c b/src/info.c index fb30258c3..9e04b4e34 100644 --- a/src/info.c +++ b/src/info.c @@ -150,8 +150,7 @@ state_t states[NUMSTATES] = {SPR_PLAY, 34, 1, {NULL}, 0, 24, S_PLAY_SIGN}, // S_PLAY_SIGN // Blue Crawla - {SPR_POSS, 0, 5, {A_Look}, 0, 0, S_POSS_STND2}, // S_POSS_STND - {SPR_POSS, 0, 5, {A_Look}, 0, 0, S_POSS_STND}, // S_POSS_STND2 + {SPR_POSS, 0, 5, {A_Look}, 0, 0, S_POSS_STND}, // S_POSS_STND {SPR_POSS, 0, 3, {A_Chase}, 0, 0, S_POSS_RUN2}, // S_POSS_RUN1 {SPR_POSS, 1, 3, {A_Chase}, 0, 0, S_POSS_RUN3}, // S_POSS_RUN2 {SPR_POSS, 2, 3, {A_Chase}, 0, 0, S_POSS_RUN4}, // S_POSS_RUN3 @@ -160,8 +159,7 @@ state_t states[NUMSTATES] = {SPR_POSS, 5, 3, {A_Chase}, 0, 0, S_POSS_RUN1}, // S_POSS_RUN6 // Red Crawla - {SPR_SPOS, 0, 5, {A_Look}, 0, 0, S_SPOS_STND2}, // S_SPOS_STND - {SPR_SPOS, 0, 5, {A_Look}, 0, 0, S_SPOS_STND}, // S_SPOS_STND2 + {SPR_SPOS, 0, 5, {A_Look}, 0, 0, S_SPOS_STND}, // S_SPOS_STND {SPR_SPOS, 0, 1, {A_Chase}, 0, 0, S_SPOS_RUN2}, // S_SPOS_RUN1 {SPR_SPOS, 1, 1, {A_Chase}, 0, 0, S_SPOS_RUN3}, // S_SPOS_RUN2 {SPR_SPOS, 2, 1, {A_Chase}, 0, 0, S_SPOS_RUN4}, // S_SPOS_RUN3 diff --git a/src/info.h b/src/info.h index 0c73281df..03726260b 100644 --- a/src/info.h +++ b/src/info.h @@ -663,7 +663,6 @@ typedef enum state // Blue Crawla S_POSS_STND, - S_POSS_STND2, S_POSS_RUN1, S_POSS_RUN2, S_POSS_RUN3, @@ -673,7 +672,6 @@ typedef enum state // Red Crawla S_SPOS_STND, - S_SPOS_STND2, S_SPOS_RUN1, S_SPOS_RUN2, S_SPOS_RUN3, From af4c2fe391172646181bc2b6928766dba52404ea Mon Sep 17 00:00:00 2001 From: MonsterIestyn Date: Wed, 28 Jan 2015 15:16:50 +0000 Subject: [PATCH 020/383] Some minor cleanup for OpenGL sprite/MD2 code --- src/hardware/hw_main.c | 13 ++----------- src/hardware/hw_md2.c | 13 +++++++------ 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index bc86c1295..ea0fb6bdb 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -3658,7 +3658,7 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t /*if (spr->mobj->frame & FF_TRANSMASK || spr->mobj->flags2 & MF2_SHADOW) { sector_t *sector = spr->mobj->subsector->sector; - UINT8 lightlevel = sector->lightlevel; + UINT8 lightlevel = 255; extracolormap_t *colormap = sector->extra_colormap; if (sector->numlights) @@ -3667,8 +3667,6 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t if (!(spr->mobj->frame & FF_FULLBRIGHT)) lightlevel = *sector->lightlist[light].lightlevel; - else - lightlevel = 255; if (sector->lightlist[light].extra_colormap) colormap = sector->lightlist[light].extra_colormap; @@ -3830,7 +3828,7 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) // colormap test { sector_t *sector = spr->mobj->subsector->sector; - UINT8 lightlevel = sector->lightlevel; + UINT8 lightlevel = 255; extracolormap_t *colormap = sector->extra_colormap; if (sector->numlights) @@ -3841,8 +3839,6 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) if (!(spr->mobj->frame & FF_FULLBRIGHT)) lightlevel = *sector->lightlist[light].lightlevel; - else - lightlevel = 255; if (sector->lightlist[light].extra_colormap) colormap = sector->lightlist[light].extra_colormap; @@ -3851,16 +3847,11 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) { if (!(spr->mobj->frame & FF_FULLBRIGHT)) lightlevel = sector->lightlevel; - else - lightlevel = 255; if (sector->extra_colormap) colormap = sector->extra_colormap; } - if (spr->mobj->frame & FF_FULLBRIGHT) - lightlevel = 255; - if (colormap) Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false); else diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 6d2a1d4a3..de648f1b9 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1082,6 +1082,12 @@ void HWR_DrawMD2(gr_vissprite_t *spr) md2_t *md2; UINT8 color[4]; + if (!cv_grmd2.value) + return; + + if (!spr->precip) + return; + // MD2 colormap fix // colormap test { @@ -1116,8 +1122,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false); } - // Look at HWR_ProjetctSprite for more - if (cv_grmd2.value && ((md2_models[spr->mobj->sprite].scale > 0.0f) || (md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale > 0.0f)) && !spr->precip) + // Look at HWR_ProjectSprite for more { GLPatch_t *gpatch; INT32 *buff; @@ -1134,15 +1139,11 @@ void HWR_DrawMD2(gr_vissprite_t *spr) //durs = tics; if (spr->mobj->flags2 & MF2_SHADOW) - { Surf.FlatColor.s.alpha = 0x40; - } else if (spr->mobj->frame & FF_TRANSMASK) HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); else - { Surf.FlatColor.s.alpha = 0xFF; - } // dont forget to enabled the depth test because we can't do this like // before: polygons models are not sorted From 474ad01b46ddfc1983203ed006532eed403b6fa2 Mon Sep 17 00:00:00 2001 From: MonsterIestyn Date: Wed, 28 Jan 2015 17:02:50 +0000 Subject: [PATCH 021/383] No more stupidity for No More Enemies special plz NME special now acts similarly to Each Time, checking all sectors sharing the same tag as itself for any enemies/bosses hiding within. This also supports cases where the tagged sectors are FOF control sectors. When the situation is asitsaysonthetin, NME acts like a normal trigger linedef should and executes all linedef execs around the sector it's located in. git-svn-id: https://code.orospakr.ca/svn/srb2/trunk@9005 6de4a73c-47e2-0310-b8c1-93d6ecd3f8cd --- src/p_floor.c | 66 +++++++++++++++++++++++++++++++++------------------ src/p_spec.c | 1 + 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/src/p_floor.c b/src/p_floor.c index 8e9a92859..8fc2b7cc3 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -1968,51 +1968,71 @@ void T_NoEnemiesSector(levelspecthink_t *nobaddies) { size_t i; fixed_t upperbound, lowerbound; - INT32 s; - sector_t *checksector; + sector_t *sec = NULL; + sector_t *targetsec = NULL; + INT32 secnum = -1; msecnode_t *node; mobj_t *thing; - boolean exists = false; + boolean FOFsector = false; - for (i = 0; i < nobaddies->sector->linecount; i++) + while ((secnum = P_FindSectorFromLineTag(nobaddies->sourceline, secnum)) >= 0) { - if (nobaddies->sector->lines[i]->special == 223) + sec = §ors[secnum]; + + FOFsector = false; + + // Check the lines of this sector, to see if it is a FOF control sector. + for (i = 0; i < sec->linecount; i++) { + INT32 targetsecnum = -1; - upperbound = nobaddies->sector->ceilingheight; - lowerbound = nobaddies->sector->floorheight; + if (sec->lines[i]->special < 100 || sec->lines[i]->special >= 300) + continue; - for (s = -1; (s = P_FindSectorFromLineTag(nobaddies->sector->lines[i], s)) >= 0 ;) + FOFsector = true; + + while ((targetsecnum = P_FindSectorFromLineTag(sec->lines[i], targetsecnum)) >= 0) { - checksector = §ors[s]; + targetsec = §ors[targetsecnum]; - node = checksector->touching_thinglist; // things touching this sector + upperbound = targetsec->ceilingheight; + lowerbound = targetsec->floorheight; + node = targetsec->touching_thinglist; // things touching this sector while (node) { thing = node->m_thing; if ((thing->flags & (MF_ENEMY|MF_BOSS)) && thing->health > 0 - && thing->z < upperbound && thing->z+thing->height > lowerbound) - { - exists = true; - goto foundenemy; - } + && thing->z < upperbound && thing->z+thing->height > lowerbound) + return; node = node->m_snext; } } } + + if (!FOFsector) + { + upperbound = sec->ceilingheight; + lowerbound = sec->floorheight; + node = sec->touching_thinglist; // things touching this sector + while (node) + { + thing = node->m_thing; + + if ((thing->flags & (MF_ENEMY|MF_BOSS)) && thing->health > 0 + && thing->z < upperbound && thing->z+thing->height > lowerbound) + return; + + node = node->m_snext; + } + } } -foundenemy: - if (exists) - return; - s = P_AproxDistance(nobaddies->sourceline->dx, nobaddies->sourceline->dy)>>FRACBITS; + CONS_Debug(DBG_GAMELOGIC, "Running no-more-enemies exec with tag of %d\n", nobaddies->sourceline->tag); - CONS_Debug(DBG_GAMELOGIC, "Running no-more-enemies exec with tag of %d\n", s); - - // Otherwise, run the linedef exec and terminate this thinker - P_LinedefExecute((INT16)s, NULL, NULL); + // No enemies found, run the linedef exec and terminate this thinker + P_RunTriggerLinedef(nobaddies->sourceline, NULL, NULL); P_RemoveThinker(&nobaddies->thinker); } diff --git a/src/p_spec.c b/src/p_spec.c index 8228c60b3..616ab3565 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1890,6 +1890,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller || specialtype == 304 // Ring count - Once || specialtype == 307 // Character ability - Once || specialtype == 308 // Race only - Once + || specialtype == 313 // No More Enemies - Once || specialtype == 315 // No of pushables - Once || specialtype == 318 // Unlockable trigger - Once || specialtype == 320 // Unlockable - Once From 2eb6dd4fc26641fe134b9f205f6d347ef5b6bb8b Mon Sep 17 00:00:00 2001 From: JTE Date: Thu, 29 Jan 2015 17:48:05 +0000 Subject: [PATCH 022/383] Prepared SRB2.cbp (Code::Blocks project) for SDL2 development on Windows as best I could. @_@; git-svn-id: https://code.orospakr.ca/svn/srb2/trunk@9006 6de4a73c-47e2-0310-b8c1-93d6ecd3f8cd --- SRB2.cbp | 433 ++++++++++++++++++++----------------------------------- 1 file changed, 160 insertions(+), 273 deletions(-) diff --git a/SRB2.cbp b/SRB2.cbp index 4834563ec..5a03955b8 100644 --- a/SRB2.cbp +++ b/SRB2.cbp @@ -154,8 +154,8 @@ HW3SOUND for 3D hardware sound support - - + + @@ -200,8 +200,8 @@ HW3SOUND for 3D hardware sound support - - + + @@ -4141,283 +4141,170 @@ HW3SOUND for 3D hardware sound support