diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6859e27c3..bb4f9a4a6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -150,6 +150,7 @@ set(SRB2_CORE_GAME_SOURCES p_saveg.c p_setup.c p_sight.c + p_slopes.c p_spec.c p_telept.c p_tick.c @@ -162,6 +163,7 @@ set(SRB2_CORE_GAME_SOURCES p_pspr.h p_saveg.h p_setup.h + p_slopes.h p_spec.h p_tick.h ) diff --git a/src/Makefile b/src/Makefile index d4cc64a4b..bee608047 100644 --- a/src/Makefile +++ b/src/Makefile @@ -454,6 +454,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 83702ad75..fe23787a8 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -439,6 +439,9 @@ extern const char *compdate, *comptime, *comprevision; /// Fun experimental slope stuff! //#define SLOPENESS +/// Kalaron/Eternity Engine slope code (SRB2CB ported) +#define ESLOPE + /// Delete file while the game is running. /// \note EXTREMELY buggy, tends to crash game. //#define DELFILE diff --git a/src/f_finale.c b/src/f_finale.c index f541995d4..a85fd11cb 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -982,6 +982,7 @@ static const char *credits[] = { "", "\1Programming", "\1Assistance", + "\"chi.miru\"", // Red's secret weapon, the REAL reason slopes exist (also helped port drawing code from ZDoom) "Andrew \"orospakr\" Clunis", "Gregor \"Oogaland\" Dick", "Julio \"Chaos Zero 64\" Guir", diff --git a/src/m_fixed.c b/src/m_fixed.c index 25a25a966..53974936e 100644 --- a/src/m_fixed.c +++ b/src/m_fixed.c @@ -119,8 +119,6 @@ fixed_t FixedHypot(fixed_t x, fixed_t y) return FixedMul(ax, yx1); // |x|*((1 + (x/y)^2)^1/2) } -#ifdef NEED_FIXED_VECTOR - vector2_t *FV2_Load(vector2_t *vec, fixed_t x, fixed_t y) { vec->x = x; @@ -863,8 +861,6 @@ void FM_Scale(matrix_t *dest, fixed_t x, fixed_t y, fixed_t z) #undef M } -#endif - #ifdef M_TESTCASE //#define MULDIV_TEST #define SQRT_TEST diff --git a/src/m_fixed.h b/src/m_fixed.h index e68de0308..cd22d483f 100644 --- a/src/m_fixed.h +++ b/src/m_fixed.h @@ -357,8 +357,6 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedRound(fixed_t x) return INT32_MAX; } -#ifdef NEED_FIXED_VECTOR - typedef struct { fixed_t x; @@ -437,6 +435,4 @@ void FM_MultMatrix(matrix_t *dest, const matrix_t *multme); void FM_Translate(matrix_t *dest, fixed_t x, fixed_t y, fixed_t z); void FM_Scale(matrix_t *dest, fixed_t x, fixed_t y, fixed_t z); -#endif // defined NEED_FIXED_VECTOR - #endif //m_fixed.h diff --git a/src/p_enemy.c b/src/p_enemy.c index 3cc9aaca2..d5da92e38 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -5606,8 +5606,13 @@ void A_MixUp(mobj_t *actor) P_SetThingPosition(players[i].mo); +#ifdef ESLOPE + players[i].mo->floorz = P_GetFloorZ(players[i].mo, players[i].mo->subsector->sector, players[i].mo->x, players[i].mo->y, NULL); + players[i].mo->ceilingz = P_GetCeilingZ(players[i].mo, players[i].mo->subsector->sector, players[i].mo->x, players[i].mo->y, NULL); +#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 fd85fd2cc..ec52abeb9 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -1174,12 +1174,15 @@ void T_SpikeSector(levelspecthink_t *spikes) if (affectsec == spikes->sector) // Applied to an actual sector { + fixed_t affectfloor = P_GetSpecialBottomZ(thing, affectsec, affectsec); + fixed_t affectceil = P_GetSpecialTopZ(thing, affectsec, affectsec); + if (affectsec->flags & SF_FLIPSPECIAL_FLOOR) { if (!(thing->eflags & MFE_VERTICALFLIP) && thing->momz > 0) continue; - if (thing->z == affectsec->floorheight) + if (thing->z == affectfloor) dothepain = true; } @@ -1188,18 +1191,20 @@ void T_SpikeSector(levelspecthink_t *spikes) if ((thing->eflags & MFE_VERTICALFLIP) && thing->momz < 0) continue; - if (thing->z + thing->height == affectsec->ceilingheight) + if (thing->z + thing->height == affectceil) dothepain = true; } } else { + fixed_t affectfloor = P_GetSpecialBottomZ(thing, affectsec, spikes->sector); + fixed_t affectceil = P_GetSpecialTopZ(thing, affectsec, spikes->sector); if (affectsec->flags & SF_FLIPSPECIAL_FLOOR) { if (!(thing->eflags & MFE_VERTICALFLIP) && thing->momz > 0) continue; - if (thing->z == affectsec->ceilingheight) + if (thing->z == affectceil) dothepain = true; } @@ -1208,7 +1213,7 @@ void T_SpikeSector(levelspecthink_t *spikes) if ((thing->eflags & MFE_VERTICALFLIP) && thing->momz < 0) continue; - if (thing->z + thing->height == affectsec->floorheight) + if (thing->z + thing->height == affectfloor) dothepain = true; } } @@ -2085,6 +2090,7 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) boolean FOFsector = false; boolean inAndOut = false; boolean floortouch = false; + fixed_t bottomheight, topheight; for (i = 0; i < MAXPLAYERS; i++) { @@ -2149,10 +2155,13 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) if (players[j].mo->subsector->sector != targetsec) continue; - if (players[j].mo->z > sec->ceilingheight) + topheight = P_GetSpecialTopZ(players[j].mo, sec, targetsec); + bottomheight = P_GetSpecialBottomZ(players[j].mo, sec, targetsec); + + if (players[j].mo->z > topheight) continue; - if (players[j].mo->z + players[j].mo->height < sec->floorheight) + if (players[j].mo->z + players[j].mo->height < bottomheight) continue; if (floortouch == true && P_IsObjectOnGroundIn(players[j].mo, targetsec)) @@ -2312,7 +2321,7 @@ void T_RaiseSector(levelspecthink_t *raise) if (raise->vars[1] && !(thing->player->pflags & PF_STARTDASH)) continue; - if (!(thing->z == raise->sector->ceilingheight)) + if (!(thing->z == P_GetSpecialTopZ(thing, raise->sector, sector))) continue; playeronme = true; diff --git a/src/p_local.h b/src/p_local.h index 748d616f3..498bf0828 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -217,6 +217,23 @@ boolean P_RailThinker(mobj_t *mobj); void P_PushableThinker(mobj_t *mobj); void P_SceneryThinker(mobj_t *mobj); + +fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect); +fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect); +#define P_GetFloorZ(mobj, sector, x, y, line) P_MobjFloorZ(mobj, sector, NULL, x, y, line, false, false) +#define P_GetCeilingZ(mobj, sector, x, y, line) P_MobjCeilingZ(mobj, sector, NULL, x, y, line, true, false) +#define P_GetFOFTopZ(mobj, sector, fof, x, y, line) P_MobjCeilingZ(mobj, sectors + fof->secnum, sector, x, y, line, false, false) +#define P_GetFOFBottomZ(mobj, sector, fof, x, y, line) P_MobjFloorZ(mobj, sectors + fof->secnum, sector, x, y, line, true, false) +#define P_GetSpecialBottomZ(mobj, src, bound) P_MobjFloorZ(mobj, src, bound, mobj->x, mobj->y, NULL, src != bound, true) +#define P_GetSpecialTopZ(mobj, src, bound) P_MobjCeilingZ(mobj, src, bound, mobj->x, mobj->y, NULL, src == bound, true) + +fixed_t P_CameraFloorZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect); +fixed_t P_CameraCeilingZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect); +#define P_CameraGetFloorZ(mobj, sector, x, y, line) P_CameraFloorZ(mobj, sector, NULL, x, y, line, false, false) +#define P_CameraGetCeilingZ(mobj, sector, x, y, line) P_CameraCeilingZ(mobj, sector, NULL, x, y, line, true, false) +#define P_CameraGetFOFTopZ(mobj, sector, fof, x, y, line) P_CameraCeilingZ(mobj, sectors + fof->secnum, sector, x, y, line, false, false) +#define P_CameraGetFOFBottomZ(mobj, sector, fof, x, y, line) P_CameraFloorZ(mobj, sectors + fof->secnum, sector, x, y, line, true, false) + boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover); boolean P_CheckDeathPitCollide(mobj_t *mo); boolean P_CheckSolidLava(mobj_t *mo, ffloor_t *rover); @@ -278,6 +295,11 @@ extern fixed_t tmfloorz; extern fixed_t tmceilingz; extern mobj_t *tmfloorthing, *tmhitthing, *tmthing; extern camera_t *mapcampointer; +extern fixed_t tmx; +extern fixed_t tmy; +#ifdef ESLOPE +extern pslope_t *tmfloorslope, *tmceilingslope; +#endif /* cphipps 2004/08/30 */ extern void P_MapStart(void); diff --git a/src/p_map.c b/src/p_map.c index b03705a2b..0c79af36e 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" @@ -34,8 +38,8 @@ fixed_t tmbbox[4]; mobj_t *tmthing; static INT32 tmflags; -static fixed_t tmx; -static fixed_t tmy; +fixed_t tmx; +fixed_t tmy; static precipmobj_t *tmprecipthing; static fixed_t preciptmbbox[4]; @@ -48,6 +52,9 @@ fixed_t tmfloorz, tmceilingz; static fixed_t tmdropoffz, tmdrpoffceilz; // drop-off floor/ceiling heights mobj_t *tmfloorthing; // the thing corresponding to tmfloorz or NULL if tmfloorz is from a sector mobj_t *tmhitthing; // the solid thing you bumped into (for collisions) +#ifdef ESLOPE +pslope_t *tmfloorslope, *tmceilingslope; +#endif // keep track of the line that lowers the ceiling, // so missiles don't explode against sky hack walls @@ -967,6 +974,9 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->z + thing->height > tmfloorz) { tmfloorz = thing->z + thing->height; +#ifdef ESLOPE + tmfloorslope = NULL; +#endif } return true; } @@ -985,6 +995,9 @@ static boolean PIT_CheckThing(mobj_t *thing) else if (topz < tmceilingz && tmthing->z+tmthing->height <= thing->z+thing->height) { tmceilingz = topz; +#ifdef ESLOPE + tmceilingslope = NULL; +#endif tmfloorthing = thing; // thing we may stand on } } @@ -998,6 +1011,9 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->z < tmceilingz) { tmceilingz = thing->z; +#ifdef ESLOPE + tmceilingslope = NULL; +#endif } return true; } @@ -1015,6 +1031,9 @@ static boolean PIT_CheckThing(mobj_t *thing) else if (topz > tmfloorz && tmthing->z >= thing->z) { tmfloorz = topz; +#ifdef ESLOPE + tmfloorslope = NULL; +#endif tmfloorthing = thing; // thing we may stand on } } @@ -1137,11 +1156,13 @@ static boolean PIT_CheckLine(line_t *ld) { tmceilingz = opentop; ceilingline = ld; + tmceilingslope = opentopslope; } if (openbottom > tmfloorz) { tmfloorz = openbottom; + tmfloorslope = openbottomslope; } if (highceiling > tmdrpoffceilz) @@ -1218,8 +1239,12 @@ 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. - tmfloorz = tmdropoffz = newsubsec->sector->floorheight; - tmceilingz = tmdrpoffceilz = newsubsec->sector->ceilingheight; + tmfloorz = tmdropoffz = P_GetFloorZ(thing, newsubsec->sector, x, y, NULL); //newsubsec->sector->floorheight; + tmceilingz = P_GetCeilingZ(thing, newsubsec->sector, x, y, NULL); //newsubsec->sector->ceilingheight; +#ifdef ESLOPE + tmfloorslope = newsubsec->sector->f_slope; + tmceilingslope = newsubsec->sector->c_slope; +#endif // Check list of fake floors and see if tmfloorz/tmceilingz need to be altered. if (newsubsec->sector->ffloors) @@ -1233,32 +1258,43 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) if (!(rover->flags & FF_EXISTS)) continue; + fixed_t topheight = P_GetFOFTopZ(thing, newsubsec->sector, rover, x, y, NULL); + fixed_t bottomheight = P_GetFOFBottomZ(thing, newsubsec->sector, rover, x, y, NULL); + 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/9, 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; +#ifdef ESLOPE + tmfloorslope = *rover->t_slope; +#endif + } } - 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; +#ifdef ESLOPE + tmceilingslope = *rover->b_slope; +#endif + } } } continue; @@ -1275,30 +1311,40 @@ 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) + if (tmfloorz < thing->z) { tmfloorz = thing->z; +#ifdef ESLOPE + tmfloorslope = NULL; +#endif + } } // Quicksand blocks never change heights otherwise. 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; +#ifdef ESLOPE + tmfloorslope = *rover->t_slope; +#endif } - 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; +#ifdef ESLOPE + tmceilingslope = *rover->b_slope; +#endif } } } @@ -1371,11 +1417,19 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) delta1 = thing->z - (polybottom + ((polytop - polybottom)/2)); delta2 = thingtop - (polybottom + ((polytop - polybottom)/2)); - if (polytop > tmfloorz && abs(delta1) < abs(delta2)) + if (polytop > tmfloorz && abs(delta1) < abs(delta2)) { tmfloorz = tmdropoffz = polytop; +#ifdef ESLOPE + tmfloorslope = NULL; +#endif + } - if (polybottom < tmceilingz && abs(delta1) >= abs(delta2)) + if (polybottom < tmceilingz && abs(delta1) >= abs(delta2)) { tmceilingz = tmdrpoffceilz = polybottom; +#ifdef ESLOPE + tmceilingslope = NULL; +#endif + } } plink = (polymaplink_t *)(plink->link.next); } @@ -1477,8 +1531,9 @@ 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. - tmfloorz = tmdropoffz = newsubsec->sector->floorheight; - tmceilingz = tmdrpoffceilz = newsubsec->sector->ceilingheight; + tmfloorz = tmdropoffz = P_CameraGetFloorZ(thiscam, newsubsec->sector, x, y, NULL); + + tmceilingz = P_CameraGetCeilingZ(thiscam, newsubsec->sector, x, y, NULL); // 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? @@ -1507,17 +1562,20 @@ 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 = P_CameraGetFOFTopZ(thiscam, newsubsec->sector, rover, x, y, NULL); + fixed_t bottomheight = P_CameraGetFOFBottomZ(thiscam, newsubsec->sector, rover, x, y, NULL); + + 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; } } } @@ -1712,8 +1770,8 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) } else { - tmfloorz = thiscam->subsector->sector->floorheight; - tmceilingz = thiscam->subsector->sector->ceilingheight; + tmfloorz = P_CameraGetFloorZ(thiscam, thiscam->subsector->sector, x, y, NULL); + tmceilingz = P_CameraGetCeilingZ(thiscam, thiscam->subsector->sector, x, y, NULL); } // the move is ok, @@ -1779,6 +1837,10 @@ boolean PIT_PushableMoved(mobj_t *thing) mobj_t *oldthing = tmthing; line_t *oldceilline = ceilingline; line_t *oldblockline = blockingline; +#ifdef ESLOPE + pslope_t *oldfslope = tmfloorslope; + pslope_t *oldcslope = tmceilingslope; +#endif // Move the player P_TryMove(thing, thing->x+stand->momx, thing->y+stand->momy, true); @@ -1791,6 +1853,10 @@ boolean PIT_PushableMoved(mobj_t *thing) P_SetTarget(&tmthing, oldthing); ceilingline = oldceilline; blockingline = oldblockline; +#ifdef ESLOPE + tmfloorslope = oldfslope; + tmceilingslope = oldcslope; +#endif thing->momz = stand->momz; } else @@ -1812,6 +1878,9 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) fixed_t tryy = thing->y; fixed_t radius = thing->radius; fixed_t thingtop = thing->z + thing->height; +#ifdef ESLOPE + fixed_t startingonground = P_IsObjectOnGround(thing); +#endif floatok = false; if (radius < MAXRADIUS/2) @@ -1900,13 +1969,23 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) { if (thingtop == thing->ceilingz && tmceilingz > thingtop && tmceilingz - thingtop <= maxstep) { - thing->z = tmceilingz - thing->height; + thing->z = (thing->ceilingz = thingtop = tmceilingz) - thing->height; + thing->eflags |= MFE_JUSTSTEPPEDDOWN; + } + else if (tmceilingz < thingtop && thingtop - tmceilingz <= maxstep) + { + thing->z = (thing->ceilingz = thingtop = tmceilingz) - thing->height; thing->eflags |= MFE_JUSTSTEPPEDDOWN; } } else if (thing->z == thing->floorz && tmfloorz < thing->z && thing->z - tmfloorz <= maxstep) { - thing->z = tmfloorz; + thing->z = thing->floorz = tmfloorz; + thing->eflags |= MFE_JUSTSTEPPEDDOWN; + } + else if (tmfloorz > thing->z && tmfloorz - thing->z <= maxstep) + { + thing->z = thing->floorz = tmfloorz; thing->eflags |= MFE_JUSTSTEPPEDDOWN; } } @@ -1977,6 +2056,25 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) thing->floorz = tmfloorz; thing->ceilingz = tmceilingz; + +#ifdef ESLOPE + // Assign thing's standingslope if needed + if (thing->z <= tmfloorz && !(thing->eflags & MFE_VERTICALFLIP)) { + if (!startingonground && tmfloorslope) + P_HandleSlopeLanding(thing, tmfloorslope); + + if (thing->momz <= 0) + thing->standingslope = tmfloorslope; + } + else if (thing->z+thing->height >= tmceilingz && (thing->eflags & MFE_VERTICALFLIP)) { + if (!startingonground && tmceilingslope) + P_HandleSlopeLanding(thing, tmceilingslope); + + if (thing->momz >= 0) + thing->standingslope = tmceilingslope; + } +#endif + thing->x = x; thing->y = y; @@ -1992,6 +2090,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 { @@ -2314,15 +2413,25 @@ 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); +#ifdef ESLOPE + floorz = glidesector->sector->f_slope ? P_GetZAt(glidesector->sector->f_slope, player->mo->x, player->mo->y) : glidesector->sector->floorheight; + ceilingz = glidesector->sector->c_slope ? P_GetZAt(glidesector->sector->c_slope, player->mo->x, player->mo->y) : glidesector->sector->ceilingheight; +#else + floorz = glidesector->sector->floorheight; + ceilingz = glidesector->sector->ceilingheight; +#endif + if (glidesector->sector != player->mo->subsector->sector) { boolean floorclimb = false; + fixed_t topheight, bottomheight; if (glidesector->sector->ffloors) { @@ -2332,34 +2441,44 @@ static boolean P_IsClimbingValid(player_t *player, angle_t angle) if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER)) continue; + topheight = *rover->topheight; + 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; } @@ -2372,30 +2491,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; } @@ -2467,6 +2586,7 @@ isblocking: line_t *checkline = li; sector_t *checksector; ffloor_t *rover; + fixed_t topheight, bottomheight; boolean fofline = false; INT32 side = P_PointOnLineSide(slidemo->x, slidemo->y, li); @@ -2482,13 +2602,23 @@ isblocking: if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP)) continue; - if (*rover->topheight < slidemo->z) + topheight = *rover->topheight; + 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]; @@ -3108,6 +3238,7 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush) if (thing->subsector->sector->ffloors && (realcrush || thing->flags & MF_PUSHABLE)) { ffloor_t *rover; + fixed_t topheight, bottomheight; fixed_t delta1, delta2; INT32 thingtop = thing->z + thing->height; @@ -3117,9 +3248,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)) + topheight = *rover->topheight; + 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) { @@ -3790,7 +3931,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) { @@ -3811,9 +3952,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; @@ -3821,10 +3972,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 a65d2fa76..c9a42bd43 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -322,6 +322,9 @@ fixed_t P_InterceptVector(divline_t *v2, divline_t *v1) // OPTIMIZE: keep this precalculated // fixed_t opentop, openbottom, openrange, lowfloor, highceiling; +#ifdef ESLOPE +pslope_t *opentopslope, *openbottomslope; +#endif // P_CameraLineOpening // P_LineOpening, but for camera @@ -348,31 +351,56 @@ 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; + frontfloor = P_CameraGetFloorZ(mapcampointer, front, tmx, tmy, linedef); + frontceiling = P_CameraGetCeilingZ(mapcampointer, front, tmx, tmy, linedef); } 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; + backfloor = P_CameraGetFloorZ(mapcampointer, back, tmx, tmy, linedef); + backceiling = P_CameraGetCeilingZ(mapcampointer, back, tmx, tmy, linedef); } { @@ -417,17 +445,20 @@ 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 = P_CameraGetFOFTopZ(mapcampointer, front, rover, tmx, tmy, linedef); + fixed_t bottomheight = P_CameraGetFOFBottomZ(mapcampointer, front, rover, tmx, tmy, linedef); - if (*rover->topheight > highestfloor && delta1 < delta2) - highestfloor = *rover->topheight; - else if (*rover->topheight > lowestfloor && delta1 < delta2) - lowestfloor = *rover->topheight; + 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 @@ -437,17 +468,20 @@ 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 = P_CameraGetFOFTopZ(mapcampointer, back, rover, tmx, tmy, linedef); + fixed_t bottomheight = P_CameraGetFOFBottomZ(mapcampointer, back, rover, tmx, tmy, linedef); - if (*rover->topheight > highestfloor && delta1 < delta2) - highestfloor = *rover->topheight; - else if (*rover->topheight > lowestfloor && delta1 < delta2) - lowestfloor = *rover->topheight; + 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) @@ -495,26 +529,40 @@ void P_LineOpening(line_t *linedef) I_Assert(front != NULL); I_Assert(back != NULL); - if (front->ceilingheight < back->ceilingheight) - { - opentop = front->ceilingheight; - highceiling = back->ceilingheight; - } - else - { - opentop = back->ceilingheight; - highceiling = front->ceilingheight; - } + { // Set open and high/low values here + fixed_t frontheight, backheight; - if (front->floorheight > back->floorheight) - { - openbottom = front->floorheight; - lowfloor = back->floorheight; - } - else - { - openbottom = back->floorheight; - lowfloor = front->floorheight; + frontheight = P_GetCeilingZ(tmthing, front, tmx, tmy, linedef); + backheight = P_GetCeilingZ(tmthing, back, tmx, tmy, linedef); + + if (frontheight < backheight) + { + opentop = frontheight; + highceiling = backheight; + opentopslope = front->c_slope; + } + else + { + opentop = backheight; + highceiling = frontheight; + opentopslope = back->c_slope; + } + + frontheight = P_GetFloorZ(tmthing, front, tmx, tmy, linedef); + backheight = P_GetFloorZ(tmthing, back, tmx, tmy, linedef); + + if (frontheight > backheight) + { + openbottom = frontheight; + lowfloor = backheight; + openbottomslope = front->f_slope; + } + else + { + openbottom = backheight; + lowfloor = frontheight; + openbottomslope = back->f_slope; + } } if (tmthing) @@ -580,6 +628,10 @@ void P_LineOpening(line_t *linedef) fixed_t highestfloor = openbottom; fixed_t lowestfloor = lowfloor; fixed_t delta1, delta2; +#ifdef ESLOPE + pslope_t *ceilingslope = opentopslope; + pslope_t *floorslope = openbottomslope; +#endif // Check for frontsector's fake floors for (rover = front->ffloors; rover; rover = rover->next) @@ -593,23 +645,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 = P_GetFOFTopZ(tmthing, front, rover, tmx, tmy, linedef); + fixed_t bottomheight = P_GetFOFBottomZ(tmthing, front, rover, tmx, tmy, linedef); + + 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; +#ifdef ESLOPE + ceilingslope = *rover->b_slope; +#endif + } + 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; +#ifdef ESLOPE + floorslope = *rover->t_slope; +#endif + } + else if (topheight > lowestfloor) + lowestfloor = topheight; } } @@ -625,23 +688,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 = P_GetFOFTopZ(tmthing, back, rover, tmx, tmy, linedef); + fixed_t bottomheight = P_GetFOFBottomZ(tmthing, back, rover, tmx, tmy, linedef); + + 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; +#ifdef ESLOPE + ceilingslope = *rover->b_slope; +#endif + } + 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; +#ifdef ESLOPE + floorslope = *rover->t_slope; +#endif + } + else if (topheight > lowestfloor) + lowestfloor = topheight; } } @@ -653,13 +727,21 @@ void P_LineOpening(line_t *linedef) delta1 = abs(tmthing->z - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2))); delta2 = abs(thingtop - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2))); - if (polysec->floorheight < lowestceiling && delta1 >= delta2) + if (polysec->floorheight < lowestceiling && delta1 >= delta2) { lowestceiling = polysec->floorheight; +#ifdef ESLOPE + ceilingslope = NULL; +#endif + } else if (polysec->floorheight < highestceiling && delta1 >= delta2) highestceiling = polysec->floorheight; - if (polysec->ceilingheight > highestfloor && delta1 < delta2) + if (polysec->ceilingheight > highestfloor && delta1 < delta2) { highestfloor = polysec->ceilingheight; +#ifdef ESLOPE + floorslope = NULL; +#endif + } else if (polysec->ceilingheight > lowestfloor && delta1 < delta2) lowestfloor = polysec->ceilingheight; } @@ -667,11 +749,19 @@ void P_LineOpening(line_t *linedef) if (highestceiling < highceiling) highceiling = highestceiling; - if (highestfloor > openbottom) + if (highestfloor > openbottom) { openbottom = highestfloor; +#ifdef ESLOPE + openbottomslope = floorslope; +#endif + } - if (lowestceiling < opentop) + if (lowestceiling < opentop) { opentop = lowestceiling; +#ifdef ESLOPE + opentopslope = ceilingslope; +#endif + } if (lowestfloor > lowfloor) lowfloor = lowestfloor; @@ -769,6 +859,7 @@ void P_SetThingPosition(mobj_t *thing) { // link into subsector subsector_t *ss; sector_t *oldsec = NULL; + fixed_t tfloorz, tceilz; I_Assert(thing != NULL); I_Assert(!P_MobjWasRemoved(thing)); @@ -838,12 +929,15 @@ void P_SetThingPosition(mobj_t *thing) // sector's floor is the same height. if (thing->player && oldsec != NULL && thing->subsector && oldsec != thing->subsector->sector) { + tfloorz = P_GetFloorZ(thing, ss->sector, thing->x, thing->y, NULL); + tceilz = P_GetCeilingZ(thing, ss->sector, thing->x, thing->y, NULL); + 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_maputl.h b/src/p_maputl.h index 66f7db2db..7471899cc 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -55,6 +55,9 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing, fixed_t x,fixed_t y); boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y); extern fixed_t opentop, openbottom, openrange, lowfloor, highceiling; +#ifdef ESLOPE +extern pslope_t *opentopslope, *openbottomslope; +#endif void P_LineOpening(line_t *plinedef); diff --git a/src/p_mobj.c b/src/p_mobj.c index fe8311e23..3a538e96f 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}}; @@ -863,15 +866,441 @@ 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; } +// P_GetFloorZ (and its ceiling counterpart) +// Gets the floor height (or ceiling height) of the mobj's contact point in sector, assuming object's center if moved to [x, y] +// If line is supplied, it's a divider line on the sector. Set it to NULL if you're not checking for collision with a line +// Supply boundsec ONLY when checking for specials! It should be the "in-level" sector, and sector the control sector (if separate). +// If set, then this function will iterate through boundsec's linedefs to find the highest contact point on the slope. Non-special-checking +// usage will handle that later. +static fixed_t HighestOnLine(fixed_t radius, fixed_t x, fixed_t y, line_t *line, pslope_t *slope, boolean actuallylowest) +{ + // Alright, so we're sitting on a line that contains our slope sector, and need to figure out the highest point we're touching... + // The solution is simple! Get the line's vertices, and pull each one in along its line until it touches the object's bounding box + // (assuming it isn't already inside), then test each point's slope Z and return the higher of the two. + vertex_t v1, v2; + v1.x = line->v1->x; + v1.y = line->v1->y; + v2.x = line->v2->x; + v2.y = line->v2->y; + + /*CONS_Printf("BEFORE: v1 = %f %f %f\n", + FIXED_TO_FLOAT(v1.x), + FIXED_TO_FLOAT(v1.y), + FIXED_TO_FLOAT(P_GetZAt(slope, v1.x, v1.y)) + ); + CONS_Printf(" v2 = %f %f %f\n", + FIXED_TO_FLOAT(v2.x), + FIXED_TO_FLOAT(v2.y), + FIXED_TO_FLOAT(P_GetZAt(slope, v2.x, v2.y)) + );*/ + + if (abs(v1.x-x) > radius) { + // v1's x is out of range, so rein it in + fixed_t diff = abs(v1.x-x) - radius; + + if (v1.x < x) { // Moving right + v1.x += diff; + v1.y += FixedMul(diff, FixedDiv(line->dy, line->dx)); + } else { // Moving left + v1.x -= diff; + v1.y -= FixedMul(diff, FixedDiv(line->dy, line->dx)); + } + } + + if (abs(v1.y-y) > radius) { + // v1's y is out of range, so rein it in + fixed_t diff = abs(v1.y-y) - radius; + + if (v1.y < y) { // Moving up + v1.y += diff; + v1.x += FixedMul(diff, FixedDiv(line->dx, line->dy)); + } else { // Moving down + v1.y -= diff; + v1.x -= FixedMul(diff, FixedDiv(line->dx, line->dy)); + } + } + + if (abs(v2.x-x) > radius) { + // v1's x is out of range, so rein it in + fixed_t diff = abs(v2.x-x) - radius; + + if (v2.x < x) { // Moving right + v2.x += diff; + v2.y += FixedMul(diff, FixedDiv(line->dy, line->dx)); + } else { // Moving left + v2.x -= diff; + v2.y -= FixedMul(diff, FixedDiv(line->dy, line->dx)); + } + } + + if (abs(v2.y-y) > radius) { + // v2's y is out of range, so rein it in + fixed_t diff = abs(v2.y-y) - radius; + + if (v2.y < y) { // Moving up + v2.y += diff; + v2.x += FixedMul(diff, FixedDiv(line->dx, line->dy)); + } else { // Moving down + v2.y -= diff; + v2.x -= FixedMul(diff, FixedDiv(line->dx, line->dy)); + } + } + + /*CONS_Printf("AFTER: v1 = %f %f %f\n", + FIXED_TO_FLOAT(v1.x), + FIXED_TO_FLOAT(v1.y), + FIXED_TO_FLOAT(P_GetZAt(slope, v1.x, v1.y)) + ); + CONS_Printf(" v2 = %f %f %f\n", + FIXED_TO_FLOAT(v2.x), + FIXED_TO_FLOAT(v2.y), + FIXED_TO_FLOAT(P_GetZAt(slope, v2.x, v2.y)) + );*/ + + // Return the higher of the two points + if (actuallylowest) + return min( + P_GetZAt(slope, v1.x, v1.y), + P_GetZAt(slope, v2.x, v2.y) + ); + else + return max( + P_GetZAt(slope, v1.x, v1.y), + P_GetZAt(slope, v2.x, v2.y) + ); +} + +fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect) +{ + I_Assert(mobj != NULL); + I_Assert(sector != NULL); +#ifdef ESLOPE + if (sector->f_slope) { + fixed_t testx, testy; + pslope_t *slope = sector->f_slope; + + // Get the corner of the object that should be the highest on the slope + if (slope->d.x < 0) + testx = mobj->radius; + else + testx = -mobj->radius; + + if (slope->d.y < 0) + testy = mobj->radius; + else + testy = -mobj->radius; + + if ((slope->zdelta > 0) ^ !!(lowest)) { + testx = -testx; + testy = -testy; + } + + testx += x; + testy += y; + + // If the highest point is in the sector, then we have it easy! Just get the Z at that point + if (R_PointInSubsector(testx, testy)->sector == (boundsec ?: sector)) + return P_GetZAt(slope, testx, testy); + + // If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point + if (perfect) { + size_t i; + line_t *ld; + fixed_t bbox[4]; + fixed_t finalheight; + + if (lowest) + finalheight = INT32_MAX; + else + finalheight = INT32_MIN; + + bbox[BOXLEFT] = x-mobj->radius; + bbox[BOXRIGHT] = x+mobj->radius; + bbox[BOXTOP] = y+mobj->radius; + bbox[BOXBOTTOM] = y-mobj->radius; + for (i = 0; i < boundsec->linecount; i++) { + ld = boundsec->lines[i]; + + if (bbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || bbox[BOXLEFT] >= ld->bbox[BOXRIGHT] + || bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || bbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) + continue; + + if (P_BoxOnLineSide(bbox, ld) != -1) + continue; + + if (lowest) + finalheight = min(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, true)); + else + finalheight = max(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, false)); + } + + return finalheight; + } + + // If we're just testing for base sector location (no collision line), just go for the center's spot... + // It'll get fixed when we test for collision anyway, and the final result can't be lower than this + if (line == NULL) + return P_GetZAt(slope, x, y); + + return HighestOnLine(mobj->radius, x, y, line, slope, lowest); + } else // Well, that makes it easy. Just get the floor height +#endif + return sector->floorheight; +} + +fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect) +{ + I_Assert(mobj != NULL); + I_Assert(sector != NULL); +#ifdef ESLOPE + if (sector->c_slope) { + fixed_t testx, testy; + pslope_t *slope = sector->c_slope; + + // Get the corner of the object that should be the highest on the slope + if (slope->d.x < 0) + testx = mobj->radius; + else + testx = -mobj->radius; + + if (slope->d.y < 0) + testy = mobj->radius; + else + testy = -mobj->radius; + + if ((slope->zdelta > 0) ^ !!(lowest)) { + testx = -testx; + testy = -testy; + } + + testx += x; + testy += y; + + // If the highest point is in the sector, then we have it easy! Just get the Z at that point + if (R_PointInSubsector(testx, testy)->sector == (boundsec ?: sector)) + return P_GetZAt(slope, testx, testy); + + // If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point + if (perfect) { + size_t i; + line_t *ld; + fixed_t bbox[4]; + fixed_t finalheight; + + if (lowest) + finalheight = INT32_MAX; + else + finalheight = INT32_MIN; + + bbox[BOXLEFT] = x-mobj->radius; + bbox[BOXRIGHT] = x+mobj->radius; + bbox[BOXTOP] = y+mobj->radius; + bbox[BOXBOTTOM] = y-mobj->radius; + for (i = 0; i < boundsec->linecount; i++) { + ld = boundsec->lines[i]; + + if (bbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || bbox[BOXLEFT] >= ld->bbox[BOXRIGHT] + || bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || bbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) + continue; + + if (P_BoxOnLineSide(bbox, ld) != -1) + continue; + + if (lowest) + finalheight = min(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, true)); + else + finalheight = max(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, false)); + } + + return finalheight; + } + + // If we're just testing for base sector location (no collision line), just go for the center's spot... + // It'll get fixed when we test for collision anyway, and the final result can't be lower than this + if (line == NULL) + return P_GetZAt(slope, x, y); + + return HighestOnLine(mobj->radius, x, y, line, slope, lowest); + } else // Well, that makes it easy. Just get the ceiling height +#endif + return sector->ceilingheight; +} + +// Now do the same as all above, but for cameras because apparently cameras are special? +fixed_t P_CameraFloorZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect) +{ + I_Assert(mobj != NULL); + I_Assert(sector != NULL); +#ifdef ESLOPE + if (sector->f_slope) { + fixed_t testx, testy; + pslope_t *slope = sector->f_slope; + + // Get the corner of the object that should be the highest on the slope + if (slope->d.x < 0) + testx = mobj->radius; + else + testx = -mobj->radius; + + if (slope->d.y < 0) + testy = mobj->radius; + else + testy = -mobj->radius; + + if ((slope->zdelta > 0) ^ !!(lowest)) { + testx = -testx; + testy = -testy; + } + + testx += x; + testy += y; + + // If the highest point is in the sector, then we have it easy! Just get the Z at that point + if (R_PointInSubsector(testx, testy)->sector == (boundsec ?: sector)) + return P_GetZAt(slope, testx, testy); + + // If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point + if (perfect) { + size_t i; + line_t *ld; + fixed_t bbox[4]; + fixed_t finalheight; + + if (lowest) + finalheight = INT32_MAX; + else + finalheight = INT32_MIN; + + bbox[BOXLEFT] = x-mobj->radius; + bbox[BOXRIGHT] = x+mobj->radius; + bbox[BOXTOP] = y+mobj->radius; + bbox[BOXBOTTOM] = y-mobj->radius; + for (i = 0; i < boundsec->linecount; i++) { + ld = boundsec->lines[i]; + + if (bbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || bbox[BOXLEFT] >= ld->bbox[BOXRIGHT] + || bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || bbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) + continue; + + if (P_BoxOnLineSide(bbox, ld) != -1) + continue; + + if (lowest) + finalheight = min(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, true)); + else + finalheight = max(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, false)); + } + + return finalheight; + } + + // If we're just testing for base sector location (no collision line), just go for the center's spot... + // It'll get fixed when we test for collision anyway, and the final result can't be lower than this + if (line == NULL) + return P_GetZAt(slope, x, y); + + return HighestOnLine(mobj->radius, x, y, line, slope, lowest); + } else // Well, that makes it easy. Just get the floor height +#endif + return sector->floorheight; +} + +fixed_t P_CameraCeilingZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect) +{ + I_Assert(mobj != NULL); + I_Assert(sector != NULL); +#ifdef ESLOPE + if (sector->c_slope) { + fixed_t testx, testy; + pslope_t *slope = sector->c_slope; + + // Get the corner of the object that should be the highest on the slope + if (slope->d.x < 0) + testx = mobj->radius; + else + testx = -mobj->radius; + + if (slope->d.y < 0) + testy = mobj->radius; + else + testy = -mobj->radius; + + if ((slope->zdelta > 0) ^ !!(lowest)) { + testx = -testx; + testy = -testy; + } + + testx += x; + testy += y; + + // If the highest point is in the sector, then we have it easy! Just get the Z at that point + if (R_PointInSubsector(testx, testy)->sector == (boundsec ?: sector)) + return P_GetZAt(slope, testx, testy); + + // If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point + if (perfect) { + size_t i; + line_t *ld; + fixed_t bbox[4]; + fixed_t finalheight; + + if (lowest) + finalheight = INT32_MAX; + else + finalheight = INT32_MIN; + + bbox[BOXLEFT] = x-mobj->radius; + bbox[BOXRIGHT] = x+mobj->radius; + bbox[BOXTOP] = y+mobj->radius; + bbox[BOXBOTTOM] = y-mobj->radius; + for (i = 0; i < boundsec->linecount; i++) { + ld = boundsec->lines[i]; + + if (bbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || bbox[BOXLEFT] >= ld->bbox[BOXRIGHT] + || bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || bbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) + continue; + + if (P_BoxOnLineSide(bbox, ld) != -1) + continue; + + if (lowest) + finalheight = min(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, true)); + else + finalheight = max(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, false)); + } + + return finalheight; + } + + // If we're just testing for base sector location (no collision line), just go for the center's spot... + // It'll get fixed when we test for collision anyway, and the final result can't be lower than this + if (line == NULL) + return P_GetZAt(slope, x, y); + + return HighestOnLine(mobj->radius, x, y, line, slope, lowest); + } else // Well, that makes it easy. Just get the ceiling height +#endif + return sector->ceilingheight; +} static void P_PlayerFlip(mobj_t *mo) { if (!mo->player) @@ -1138,7 +1567,11 @@ static void P_XYFriction(mobj_t *mo, fixed_t oldx, fixed_t oldy) } else if (abs(player->rmomx) < FixedMul(STOPSPEED, mo->scale) && abs(player->rmomy) < FixedMul(STOPSPEED, mo->scale) - && (!(player->cmd.forwardmove && !(twodlevel || mo->flags2 & MF2_TWOD)) && !player->cmd.sidemove && !(player->pflags & PF_SPINNING))) + && (!(player->cmd.forwardmove && !(twodlevel || mo->flags2 & MF2_TWOD)) && !player->cmd.sidemove && !(player->pflags & PF_SPINNING)) +#ifdef ESLOPE + && !(player->mo->standingslope && abs(player->mo->standingslope->zdelta) >= FRACUNIT/2) +#endif + ) { // if in a walking frame, stop moving if (player->panim == PA_WALK) @@ -1282,6 +1715,11 @@ void P_XYMovement(mobj_t *mo) fixed_t xmove, ymove; fixed_t oldx, oldy; // reducing bobbing/momentum on ice when up against walls boolean moved; +#ifdef ESLOPE + pslope_t *oldslope = NULL; + vector3_t slopemom; + fixed_t predictedz = 0; +#endif I_Assert(mo != NULL); I_Assert(!P_MobjWasRemoved(mo)); @@ -1313,6 +1751,30 @@ void P_XYMovement(mobj_t *mo) oldx = mo->x; oldy = mo->y; +#ifdef ESLOPE + // adjust various things based on slope + if (mo->standingslope && abs(mo->standingslope->zdelta) > FRACUNIT>>8) { + if (!P_IsObjectOnGround(mo)) { // We fell off at some point? Do the twisty thing! + P_SlopeLaunch(mo); + xmove = mo->momx; + ymove = mo->momy; + } else { // Still on the ground. + slopemom.x = xmove; + slopemom.y = ymove; + slopemom.z = 0; + P_QuantizeMomentumToSlope(&slopemom, mo->standingslope); + + xmove = slopemom.x; + ymove = slopemom.y; + + predictedz = mo->z + slopemom.z; // We'll use this later... + + oldslope = mo->standingslope; + } + } else if (P_IsObjectOnGround(mo) && !mo->momz) + predictedz = mo->z; +#endif + // Pushables can break some blocks if (CheckForBustableBlocks && mo->flags & MF_PUSHABLE) P_PushableCheckBustables(mo); @@ -1433,6 +1895,54 @@ void P_XYMovement(mobj_t *mo) if (P_MobjWasRemoved(mo)) // MF_SPECIAL touched a player! O_o;; return; +#ifdef ESLOPE + if (moved && oldslope) { // Check to see if we ran off + + if (oldslope != mo->standingslope) { // First, compare different slopes + angle_t oldangle, newangle; + angle_t moveangle = R_PointToAngle2(0, 0, mo->momx, mo->momy); + + oldangle = FixedMul((signed)oldslope->zangle, FINECOSINE((moveangle - oldslope->xydirection) >> ANGLETOFINESHIFT)); + + if (mo->standingslope) + newangle = FixedMul((signed)mo->standingslope->zangle, FINECOSINE((moveangle - mo->standingslope->xydirection) >> ANGLETOFINESHIFT)); + else + newangle = 0; + + // Now compare the Zs of the different quantizations + if (oldangle-newangle > ANG30 && oldangle-newangle < ANGLE_180) { // Allow for a bit of sticking - this value can be adjusted later + mo->standingslope = oldslope; + P_SlopeLaunch(mo); + + //CONS_Printf("launched off of slope - "); + } + + /*CONS_Printf("old angle %f - new angle %f = %f\n", + FIXED_TO_FLOAT(AngleFixed(oldangle)), + FIXED_TO_FLOAT(AngleFixed(newangle)), + FIXED_TO_FLOAT(AngleFixed(oldangle-newangle)) + );*/ + } else if (predictedz-mo->z > abs(slopemom.z/2)) { // Now check if we were supposed to stick to this slope + //CONS_Printf("%d-%d > %d\n", (predictedz), (mo->z), (slopemom.z/2)); + P_SlopeLaunch(mo); + } + } else if (moved && mo->standingslope && predictedz) { + angle_t moveangle = R_PointToAngle2(0, 0, mo->momx, mo->momy); + angle_t newangle = FixedMul((signed)mo->standingslope->zangle, FINECOSINE((moveangle - mo->standingslope->xydirection) >> ANGLETOFINESHIFT)); + + /*CONS_Printf("flat to angle %f - predicted z of %f\n", + FIXED_TO_FLOAT(AngleFixed(ANGLE_MAX-newangle)), + FIXED_TO_FLOAT(predictedz) + );*/ + if (ANGLE_MAX-newangle > ANG30 && newangle > ANGLE_180) { + mo->momz = P_MobjFlip(mo)*FRACUNIT/2; + mo->z = predictedz + P_MobjFlip(mo); + mo->standingslope = NULL; + //CONS_Printf("Launched off of flat surface running into downward slope\n"); + } + } +#endif + // Check the gravity status. P_CheckGravity(mo, false); @@ -1479,6 +1989,12 @@ void P_XYMovement(mobj_t *mo) if (player && player->homing) // no friction for homing return; +#ifdef ESLOPE + if ((mo->type == MT_BIGTUMBLEWEED || mo->type == MT_LITTLETUMBLEWEED) + && (mo->standingslope && abs(mo->standingslope->zdelta) > FRACUNIT>>8)) // Special exception for tumbleweeds on slopes + return; +#endif + if (((!(mo->eflags & MFE_VERTICALFLIP) && mo->z > mo->floorz) || (mo->eflags & MFE_VERTICALFLIP && mo->z+mo->height < mo->ceilingz)) && !(player && player->pflags & PF_SLIDING)) return; // no friction when airborne @@ -1535,6 +2051,7 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp { ffloor_t *rover; fixed_t delta1, delta2, thingtop; + fixed_t topheight, bottomheight; I_Assert(mo != NULL); I_Assert(!P_MobjWasRemoved(mo)); @@ -1546,6 +2063,9 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp if (!(rover->flags & FF_EXISTS)) continue; + topheight = P_GetFOFTopZ(mo, sector, rover, mo->x, mo->y, NULL); + bottomheight = P_GetFOFBottomZ(mo, sector, rover, mo->x, mo->y, NULL); + if (mo->player && (P_CheckSolidLava(mo, rover) || P_CanRunOnWater(mo->player, rover))) // only the player should be affected ; else if (motype != 0 && rover->flags & FF_SWIMMABLE) // "scenery" only @@ -1560,14 +2080,14 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp switch (motype) { case 2: // scenery does things differently for some reason - if (mo->z < *rover->topheight && *rover->bottomheight < thingtop) + if (mo->z < topheight && bottomheight < thingtop) { mo->floorz = mo->z; continue; } break; default: - if (mo->z < *rover->topheight && *rover->bottomheight < thingtop) + if (mo->z < topheight && bottomheight < thingtop) { if (mo->floorz < mo->z) mo->floorz = mo->z; @@ -1576,17 +2096,17 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp } } - delta1 = mo->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2)); - delta2 = thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2)); - if (*rover->topheight > mo->floorz && abs(delta1) < abs(delta2) + delta1 = mo->z - (bottomheight + ((topheight - bottomheight)/2)); + delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2)); + if (topheight > mo->floorz && abs(delta1) < abs(delta2) && !(rover->flags & FF_REVERSEPLATFORM)) { - mo->floorz = *rover->topheight; + mo->floorz = topheight; } - if (*rover->bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2) + if (bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2) && !(rover->flags & FF_PLATFORM)) { - mo->ceilingz = *rover->bottomheight; + mo->ceilingz = bottomheight; } } } @@ -1718,6 +2238,11 @@ static boolean P_ZMovement(mobj_t *mo) I_Assert(mo != NULL); I_Assert(!P_MobjWasRemoved(mo)); +#ifdef ESLOPE + if (mo->standingslope && !P_IsObjectOnGround(mo)) + P_SlopeLaunch(mo); +#endif + // Intercept the stupid 'fall through 3dfloors' bug if (mo->subsector->sector->ffloors) P_AdjustMobjFloorZ_FFloors(mo, mo->subsector->sector, 0); @@ -1905,14 +2430,31 @@ static boolean P_ZMovement(mobj_t *mo) || (mo->z + mo->height >= mo->ceilingz && mo->eflags & MFE_VERTICALFLIP)) && !(mo->flags & MF_NOCLIPHEIGHT)) { + vector3_t mom; + mom.x = mo->momx; + mom.y = mo->momy; + mom.z = mo->momz; + if (mo->eflags & MFE_VERTICALFLIP) mo->z = mo->ceilingz - mo->height; else mo->z = mo->floorz; +#ifdef ESLOPE + P_CheckPosition(mo, mo->x, mo->y); // Sets mo->standingslope correctly + if ((mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope) { + mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope; + + // Reverse quantizing might could use its own function later + mo->standingslope->zangle = ANGLE_MAX-mo->standingslope->zangle; + P_QuantizeMomentumToSlope(&mom, mo->standingslope); + mo->standingslope->zangle = ANGLE_MAX-mo->standingslope->zangle; + } +#endif + // hit the floor if (mo->type == MT_FIREBALL) // special case for the fireball - mo->momz = P_MobjFlip(mo)*FixedMul(5*FRACUNIT, mo->scale); + mom.z = P_MobjFlip(mo)*FixedMul(5*FRACUNIT, mo->scale); else if (mo->type == MT_SPINFIRE) // elemental shield fire is another exception here ; else if (mo->flags & MF_MISSILE) @@ -1927,12 +2469,12 @@ static boolean P_ZMovement(mobj_t *mo) if (mo->flags & MF_GRENADEBOUNCE) { // Going down? (Or up in reverse gravity?) - if (P_MobjFlip(mo)*mo->momz < 0) + if (P_MobjFlip(mo)*mom.z < 0) { // If going slower than a fracunit, just stop. - if (abs(mo->momz) < FixedMul(FRACUNIT, mo->scale)) + if (abs(mom.z) < FixedMul(FRACUNIT, mo->scale)) { - mo->momx = mo->momy = mo->momz = 0; + mom.x = mom.y = mom.z = 0; // Napalm hack if (mo->type == MT_CYBRAKDEMON_NAPALM_BOMB_LARGE && mo->fuse) @@ -1940,7 +2482,7 @@ static boolean P_ZMovement(mobj_t *mo) } // Otherwise bounce up at half speed. else - mo->momz = -mo->momz/2; + mom.z = -mom.z/2; S_StartSound(mo, mo->info->activesound); } } @@ -1963,14 +2505,14 @@ static boolean P_ZMovement(mobj_t *mo) } } - if (P_MobjFlip(mo)*mo->momz < 0) // falling + if (P_MobjFlip(mo)*mom.z < 0) // falling { if (!tmfloorthing || tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR) || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER) mo->eflags |= MFE_JUSTHITFLOOR; if (mo->flags2 & MF2_SKULLFLY) // the skull slammed into something - mo->momz = -mo->momz; + mom.z = -mom.z; else // Flingrings bounce if (mo->type == MT_FLINGRING @@ -1983,35 +2525,42 @@ static boolean P_ZMovement(mobj_t *mo) || mo->type == MT_FALLINGROCK) { if (maptol & TOL_NIGHTS) - mo->momz = -FixedDiv(mo->momz, 10*FRACUNIT); + mom.z = -FixedDiv(mom.z, 10*FRACUNIT); else - mo->momz = -FixedMul(mo->momz, FixedDiv(17*FRACUNIT,20*FRACUNIT)); + mom.z = -FixedMul(mom.z, FixedDiv(17*FRACUNIT,20*FRACUNIT)); if (mo->type == MT_BIGTUMBLEWEED || mo->type == MT_LITTLETUMBLEWEED) { - if (abs(mo->momx) < FixedMul(STOPSPEED, mo->scale) - && abs(mo->momy) < FixedMul(STOPSPEED, mo->scale) - && abs(mo->momz) < FixedMul(STOPSPEED*3, mo->scale)) + if (abs(mom.x) < FixedMul(STOPSPEED, mo->scale) + && abs(mom.y) < FixedMul(STOPSPEED, mo->scale) + && abs(mom.z) < FixedMul(STOPSPEED*3, mo->scale)) { - if (!(mo->flags & MF_AMBUSH)) - { - mo->momx = mo->momy = mo->momz = 0; - P_SetMobjState(mo, mo->info->spawnstate); - } - else + if (mo->flags & MF_AMBUSH) { // If deafed, give the tumbleweed another random kick if it runs out of steam. - mo->momz += P_MobjFlip(mo)*FixedMul(6*FRACUNIT, mo->scale); + mom.z += P_MobjFlip(mo)*FixedMul(6*FRACUNIT, mo->scale); if (P_Random() & 1) - mo->momx += FixedMul(6*FRACUNIT, mo->scale); + mom.x += FixedMul(6*FRACUNIT, mo->scale); else - mo->momx -= FixedMul(6*FRACUNIT, mo->scale); + mom.x -= FixedMul(6*FRACUNIT, mo->scale); if (P_Random() & 1) - mo->momy += FixedMul(6*FRACUNIT, mo->scale); + mom.y += FixedMul(6*FRACUNIT, mo->scale); else - mo->momy -= FixedMul(6*FRACUNIT, mo->scale); + mom.y -= FixedMul(6*FRACUNIT, mo->scale); + } +#ifdef ESLOPE + else if (mo->standingslope && abs(mo->standingslope->zdelta) > FRACUNIT>>8) + { + // Pop the object up a bit to encourage bounciness + //mom.z = P_MobjFlip(mo)*mo->scale; + } +#endif + else + { + mom.x = mom.y = mom.z = 0; + P_SetMobjState(mo, mo->info->spawnstate); } } @@ -2021,14 +2570,14 @@ static boolean P_ZMovement(mobj_t *mo) } else if (mo->type == MT_FALLINGROCK) { - if (P_MobjFlip(mo)*mo->momz > FixedMul(2*FRACUNIT, mo->scale)) + if (P_MobjFlip(mo)*mom.z > FixedMul(2*FRACUNIT, mo->scale)) S_StartSound(mo, mo->info->activesound + P_RandomKey(mo->info->mass)); - mo->momz /= 2; // Rocks not so bouncy + mom.z /= 2; // Rocks not so bouncy - if (abs(mo->momx) < FixedMul(STOPSPEED, mo->scale) - && abs(mo->momy) < FixedMul(STOPSPEED, mo->scale) - && abs(mo->momz) < FixedMul(STOPSPEED*3, mo->scale)) + if (abs(mom.x) < FixedMul(STOPSPEED, mo->scale) + && abs(mom.y) < FixedMul(STOPSPEED, mo->scale) + && abs(mom.z) < FixedMul(STOPSPEED*3, mo->scale)) { P_RemoveMobj(mo); return false; @@ -2036,20 +2585,30 @@ static boolean P_ZMovement(mobj_t *mo) } else if (mo->type == MT_CANNONBALLDECOR) { - mo->momz /= 2; - if (abs(mo->momz) < FixedMul(STOPSPEED*3, mo->scale)) - mo->momz = 0; + mom.z /= 2; + if (abs(mom.z) < FixedMul(STOPSPEED*3, mo->scale)) + mom.z = 0; } } else if (tmfloorthing && (tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR) || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER)) - mo->momz = tmfloorthing->momz; + mom.z = tmfloorthing->momz; else if (!tmfloorthing) - mo->momz = 0; + mom.z = 0; } else if (tmfloorthing && (tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR) || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER)) - mo->momz = tmfloorthing->momz; + mom.z = tmfloorthing->momz; + +#ifdef ESLOPE + if (mo->standingslope) { + P_QuantizeMomentumToSlope(&mom, mo->standingslope); + } +#endif + + mo->momx = mom.x; + mo->momy = mom.y; + mo->momz = mom.z; if (mo->type == MT_STEAM) return true; @@ -2163,6 +2722,11 @@ static void P_PlayerZMovement(mobj_t *mo) || mo->player->playerstate == PST_REBORN) return; +#ifdef ESLOPE + if (mo->standingslope && !P_IsObjectOnGround(mo)) + P_SlopeLaunch(mo); +#endif + // clip movement if (P_IsObjectOnGround(mo) && !(mo->flags & MF_NOCLIPHEIGHT)) { @@ -2184,6 +2748,13 @@ static void P_PlayerZMovement(mobj_t *mo) if (mo->player->panim == PA_PAIN) P_SetPlayerMobjState(mo, S_PLAY_STND); +#ifdef ESLOPE + if (!mo->standingslope && (mo->eflags & MFE_VERTICALFLIP ? tmceilingslope : tmfloorslope)) { + // Handle landing on slope during Z movement + P_HandleSlopeLanding(mo, (mo->eflags & MFE_VERTICALFLIP ? tmceilingslope : tmfloorslope)); + } +#endif + if (P_MobjFlip(mo)*mo->momz < 0) // falling { mo->pmomz = 0; // We're on a new floor, don't keep doing platform movement. @@ -2591,7 +3162,7 @@ void P_MobjCheckWater(mobj_t *mobj) player_t *p = mobj->player; // Will just be null if not a player. // Default if no water exists. - mobj->watertop = mobj->waterbottom = mobj->subsector->sector->floorheight - 1000*FRACUNIT; + mobj->watertop = mobj->waterbottom = mobj->z - 1000*FRACUNIT; // Reset water state. mobj->eflags &= ~(MFE_UNDERWATER|MFE_TOUCHWATER|MFE_GOOWATER); @@ -2603,34 +3174,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)) @@ -2807,7 +3389,7 @@ static void P_SceneryCheckWater(mobj_t *mobj) sector_t *sector; // Default if no water exists. - mobj->watertop = mobj->waterbottom = mobj->subsector->sector->floorheight - 1000*FRACUNIT; + mobj->watertop = mobj->waterbottom = mobj->z - 1000*FRACUNIT; // see if we are in water, and set some flags for later sector = mobj->subsector->sector; @@ -2815,6 +3397,7 @@ static void P_SceneryCheckWater(mobj_t *mobj) if (sector->ffloors) { ffloor_t *rover; + fixed_t topheight, bottomheight; mobj->eflags &= ~(MFE_UNDERWATER|MFE_TOUCHWATER); @@ -2822,20 +3405,32 @@ static void P_SceneryCheckWater(mobj_t *mobj) { if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE) || rover->flags & FF_BLOCKOTHERS) continue; - if (*rover->topheight <= mobj->z - || *rover->bottomheight > (mobj->z + FixedMul(mobj->info->height >> 1, mobj->scale))) + + topheight = *rover->topheight; + 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 (topheight <= mobj->z + || bottomheight > (mobj->z + FixedMul(mobj->info->height >> 1, mobj->scale))) continue; - if (mobj->z + FixedMul(mobj->info->height, mobj->scale) > *rover->topheight) + if (mobj->z + FixedMul(mobj->info->height, mobj->scale) > topheight) mobj->eflags |= MFE_TOUCHWATER; else mobj->eflags &= ~MFE_TOUCHWATER; // Set the watertop and waterbottom - mobj->watertop = *rover->topheight; - mobj->waterbottom = *rover->bottomheight; + mobj->watertop = topheight; + mobj->waterbottom = bottomheight; - if (mobj->z + FixedMul(mobj->info->height >> 1, mobj->scale) < *rover->topheight) + if (mobj->z + FixedMul(mobj->info->height >> 1, mobj->scale) < topheight) mobj->eflags |= MFE_UNDERWATER; else mobj->eflags &= ~MFE_UNDERWATER; @@ -2865,7 +3460,15 @@ static boolean P_CameraCheckHeat(camera_t *thiscam) if (!(rover->flags & FF_EXISTS)) continue; - if (halfheight >= *rover->topheight || halfheight <= *rover->bottomheight) + if (halfheight >= ( +#ifdef ESLOPE + *rover->t_slope ? P_GetZAt(*rover->t_slope, thiscam->x, thiscam->y) : +#endif + *rover->topheight) || halfheight <= ( +#ifdef ESLOPE + *rover->b_slope ? P_GetZAt(*rover->b_slope, thiscam->x, thiscam->y) : +#endif + *rover->bottomheight)) continue; if (P_FindSpecialLineFromTag(13, rover->master->frontsector->tag, -1) != -1) @@ -2893,7 +3496,15 @@ static boolean P_CameraCheckWater(camera_t *thiscam) if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE) || rover->flags & FF_BLOCKOTHERS) continue; - if (halfheight >= *rover->topheight || halfheight <= *rover->bottomheight) + if (halfheight >= ( +#ifdef ESLOPE + *rover->t_slope ? P_GetZAt(*rover->t_slope, thiscam->x, thiscam->y) : +#endif + *rover->topheight) || halfheight <= ( +#ifdef ESLOPE + *rover->b_slope ? P_GetZAt(*rover->b_slope, thiscam->x, thiscam->y) : +#endif + *rover->bottomheight)) continue; return true; @@ -3064,6 +3675,10 @@ static void P_PlayerMobjThinker(mobj_t *mobj) P_MobjCheckWater(mobj); +#ifdef ESLOPE + P_ButteredSlope(mobj); +#endif + // momentum movement mobj->eflags &= ~MFE_JUSTSTEPPEDDOWN; @@ -3102,6 +3717,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj) // Crumbling platforms for (node = mobj->touching_sectorlist; node; node = node->m_snext) { + fixed_t topheight, bottomheight; ffloor_t *rover; for (rover = node->m_sector->ffloors; rover; rover = rover->next) @@ -3109,8 +3725,11 @@ static void P_PlayerMobjThinker(mobj_t *mobj) if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_CRUMBLE)) continue; - if ((*rover->topheight == mobj->z && !(mobj->eflags & MFE_VERTICALFLIP)) - || (*rover->bottomheight == mobj->z + mobj->height && mobj->eflags & MFE_VERTICALFLIP)) // You nut. + topheight = P_GetSpecialTopZ(mobj, sectors + rover->secnum, node->m_sector); + bottomheight = P_GetSpecialBottomZ(mobj, sectors + rover->secnum, node->m_sector); + + if ((topheight == mobj->z && !(mobj->eflags & MFE_VERTICALFLIP)) + || (bottomheight == mobj->z + mobj->height && mobj->eflags & MFE_VERTICALFLIP)) // You nut. EV_StartCrumble(rover->master->frontsector, rover, (rover->flags & FF_FLOATBOB), mobj->player, rover->alpha, !(rover->flags & FF_NORETURN)); } } @@ -6809,6 +7428,21 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s mobj->eflags &= ~MFE_JUSTHITFLOOR; } +#ifdef ESLOPE // Sliding physics for slidey mobjs! + if (mobj->type == MT_FLINGRING + || mobj->type == MT_FLINGCOIN + || P_WeaponOrPanel(mobj->type) + || mobj->type == MT_FLINGEMERALD + || mobj->type == MT_BIGTUMBLEWEED + || mobj->type == MT_LITTLETUMBLEWEED + || mobj->type == MT_CANNONBALLDECOR + || mobj->type == MT_FALLINGROCK) { + P_TryMove(mobj, mobj->x, mobj->y, true); // Sets mo->standingslope correctly + //if (mobj->standingslope) CONS_Printf("slope physics on mobj\n"); + P_ButteredSlope(mobj); + } +#endif + if (mobj->flags & (MF_ENEMY|MF_BOSS) && mobj->health && P_CheckDeathPitCollide(mobj)) // extra pit check in case these didn't have momz { @@ -7071,8 +7705,16 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) // Make sure scale matches destscale immediately when spawned P_SetScale(mobj, mobj->destscale); - mobj->floorz = mobj->subsector->sector->floorheight; - mobj->ceilingz = mobj->subsector->sector->ceilingheight; + mobj->floorz = +#ifdef ESLOPE + mobj->subsector->sector->f_slope ? P_GetZAt(mobj->subsector->sector->f_slope, x, y) : +#endif + mobj->subsector->sector->floorheight; + mobj->ceilingz = +#ifdef ESLOPE + mobj->subsector->sector->c_slope ? P_GetZAt(mobj->subsector->sector->c_slope, x, y) : +#endif + mobj->subsector->sector->ceilingheight; // Tells MobjCheckWater that the water height was not set. mobj->watertop = INT32_MAX; @@ -8129,7 +8771,11 @@ void P_SpawnMapThing(mapthing_t *mthing) return; ss = R_PointInSubsector(mthing->x << FRACBITS, mthing->y << FRACBITS); - mthing->z = (INT16)((ss->sector->floorheight>>FRACBITS) + (mthing->options >> ZSHIFT)); + mthing->z = (INT16)((( +#ifdef ESLOPE + ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, mthing->x << FRACBITS, mthing->y << FRACBITS) : +#endif + ss->sector->floorheight)>>FRACBITS) + (mthing->options >> ZSHIFT)); if (numhuntemeralds < MAXHUNTEMERALDS) huntemeralds[numhuntemeralds++] = mthing; @@ -8247,14 +8893,22 @@ void P_SpawnMapThing(mapthing_t *mthing) ss = R_PointInSubsector(x, y); if (i == MT_NIGHTSBUMPER) - z = ss->sector->floorheight + ((mthing->options >> ZSHIFT) << FRACBITS); + z = ( +#ifdef ESLOPE + ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) : +#endif + ss->sector->floorheight) + ((mthing->options >> ZSHIFT) << FRACBITS); else if (i == MT_AXIS || i == MT_AXISTRANSFER || i == MT_AXISTRANSFERLINE) z = ONFLOORZ; else if (i == MT_SPECIALSPIKEBALL || P_WeaponOrPanel(i) || i == MT_EMERALDSPAWN || i == MT_EMMY) { if (mthing->options & MTF_OBJECTFLIP) { - z = ss->sector->ceilingheight; + z = ( +#ifdef ESLOPE + ss->sector->c_slope ? P_GetZAt(ss->sector->c_slope, x, y) : +#endif + ss->sector->ceilingheight); if (mthing->options & MTF_AMBUSH) // Special flag for rings z -= 24*FRACUNIT; @@ -8265,7 +8919,11 @@ void P_SpawnMapThing(mapthing_t *mthing) } else { - z = ss->sector->floorheight; + z = ( +#ifdef ESLOPE + ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) : +#endif + ss->sector->floorheight); if (mthing->options & MTF_AMBUSH) // Special flag for rings z += 24*FRACUNIT; @@ -8285,9 +8943,17 @@ void P_SpawnMapThing(mapthing_t *mthing) // base positions if (flip) - z = ss->sector->ceilingheight - mobjinfo[i].height; + z = ( +#ifdef ESLOPE + ss->sector->c_slope ? P_GetZAt(ss->sector->c_slope, x, y) : +#endif + ss->sector->ceilingheight) - mobjinfo[i].height; else - z = ss->sector->floorheight; + z = ( +#ifdef ESLOPE + ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) : +#endif + ss->sector->floorheight); // offsetting if (mthing->options >> ZSHIFT) @@ -8801,7 +9467,11 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) // Screw these damn hoops, I need this thinker. //hoopcenter->flags |= MF_NOTHINK; - z += sec->floorheight; + z += +#ifdef ESLOPE + sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : +#endif + sec->floorheight; hoopcenter->z = z - hoopcenter->height/2; @@ -8934,7 +9604,11 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER); hoopcenter->spawnpoint = mthing; - z += sec->floorheight; + z += +#ifdef ESLOPE + sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : +#endif + sec->floorheight; hoopcenter->z = z - hoopcenter->height/2; P_UnsetThingPosition(hoopcenter); @@ -9046,7 +9720,11 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) // Wing logo item. else if (mthing->type == mobjinfo[MT_NIGHTSWING].doomednum) { - z = sec->floorheight; + z = +#ifdef ESLOPE + sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : +#endif + sec->floorheight; if (mthing->options >> ZSHIFT) z += ((mthing->options >> ZSHIFT) << FRACBITS); @@ -9098,13 +9776,21 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) // Set proper height if (mthing->options & MTF_OBJECTFLIP) { - z = sec->ceilingheight - mobjinfo[ringthing].height; + z = ( +#ifdef ESLOPE + sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : +#endif + sec->ceilingheight) - mobjinfo[ringthing].height; if (mthing->options >> ZSHIFT) z -= ((mthing->options >> ZSHIFT) << FRACBITS); } else { - z = sec->floorheight; + z = +#ifdef ESLOPE + sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : +#endif + sec->floorheight; if (mthing->options >> ZSHIFT) z += ((mthing->options >> ZSHIFT) << FRACBITS); } @@ -9158,13 +9844,21 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) { if (mthing->options & MTF_OBJECTFLIP) { - z = sec->ceilingheight - mobjinfo[ringthing].height - dist*r; + z = ( +#ifdef ESLOPE + sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : +#endif + sec->ceilingheight) - mobjinfo[ringthing].height - dist*r; if (mthing->options >> ZSHIFT) z -= ((mthing->options >> ZSHIFT) << FRACBITS); } else { - z = sec->floorheight + dist*r; + z = ( +#ifdef ESLOPE + sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : +#endif + sec->floorheight) + dist*r; if (mthing->options >> ZSHIFT) z += ((mthing->options >> ZSHIFT) << FRACBITS); } @@ -9210,13 +9904,21 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) if (mthing->options & MTF_OBJECTFLIP) { - z = sec->ceilingheight - mobjinfo[ringthing].height - 64*FRACUNIT*r; + z = ( +#ifdef ESLOPE + sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : +#endif + sec->ceilingheight) - mobjinfo[ringthing].height - 64*FRACUNIT*r; if (mthing->options >> ZSHIFT) z -= ((mthing->options >> ZSHIFT) << FRACBITS); } else { - z = sec->floorheight + 64*FRACUNIT*r; + z = ( +#ifdef ESLOPE + sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : +#endif + sec->floorheight) + 64*FRACUNIT*r; if (mthing->options >> ZSHIFT) z += ((mthing->options >> ZSHIFT) << FRACBITS); } @@ -9247,7 +9949,11 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) size = 192*FRACUNIT; } - z = sec->floorheight; + z = +#ifdef ESLOPE + sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : +#endif + sec->floorheight; if (mthing->options >> ZSHIFT) z += ((mthing->options >> ZSHIFT) << FRACBITS); diff --git a/src/p_mobj.h b/src/p_mobj.h index 62abe4808..76a87096c 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -355,6 +355,10 @@ typedef struct mobj_s INT32 cusval; INT32 cvmem; +#ifdef ESLOPE + struct pslope_s *standingslope; // The slope that the object is standing on (shouldn't need synced in savegames, right?) +#endif + // WARNING: New fields must be added separately to savegame and Lua. } mobj_t; diff --git a/src/p_saveg.c b/src/p_saveg.c index 2afcfd0ef..07e7b3564 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -30,6 +30,9 @@ #include "r_sky.h" #include "p_polyobj.h" #include "lua_script.h" +#ifdef ESLOPE +#include "p_slopes.h" +#endif savedata_t savedata; UINT8 *save_p; @@ -921,7 +924,8 @@ typedef enum MD2_EXTVAL1 = 1<<5, MD2_EXTVAL2 = 1<<6, MD2_HNEXT = 1<<7, - MD2_HPREV = 1<<8 + MD2_HPREV = 1<<8, + MD2_SLOPE = 1<<9 } mobj_diff2_t; typedef enum @@ -1111,6 +1115,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) diff2 |= MD2_HNEXT; if (mobj->hprev) diff2 |= MD2_HPREV; + if (mobj->standingslope) + diff2 |= MD2_SLOPE; if (diff2 != 0) diff |= MD_MORE; @@ -1226,6 +1232,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) WRITEUINT32(save_p, mobj->hnext->mobjnum); if (diff2 & MD2_HPREV) WRITEUINT32(save_p, mobj->hprev->mobjnum); + if (diff2 & MD2_SLOPE) + WRITEUINT16(save_p, mobj->standingslope->id); WRITEUINT32(save_p, mobj->mobjnum); } @@ -2079,6 +2087,9 @@ static void LoadMobjThinker(actionf_p1 thinker) mobj->hnext = (mobj_t *)(size_t)READUINT32(save_p); if (diff2 & MD2_HPREV) mobj->hprev = (mobj_t *)(size_t)READUINT32(save_p); + if (diff2 & MD2_SLOPE) + mobj->standingslope = P_SlopeById(READUINT16(save_p)); + if (diff & MD_REDFLAG) { diff --git a/src/p_setup.c b/src/p_setup.c index f2b0c49d8..3491669c7 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -72,6 +72,10 @@ #include "hardware/hw_light.h" #endif +#ifdef ESLOPE +#include "p_slopes.h" +#endif + // // Map MD5, calculated on level load. // Sent to clients in PT_SERVERINFO. @@ -846,7 +850,7 @@ void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum) // // P_LoadThings // -static void P_LoadThings(lumpnum_t lumpnum) +static void P_PrepareThings(lumpnum_t lumpnum) { size_t i; mapthing_t *mt; @@ -884,13 +888,27 @@ static void P_LoadThings(lumpnum_t lumpnum) } Z_Free(datastart); +} + +static void P_LoadThings(void) +{ + size_t i; + mapthing_t *mt; + + // Loading the things lump itself into memory is now handled in P_PrepareThings, above + mt = mapthings; numhuntemeralds = 0; for (i = 0; i < nummapthings; i++, mt++) { + sector_t *mtsector = R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)->sector; + // Z for objects - mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS) - ->sector->floorheight>>FRACBITS); + mt->z = (INT16)( +#ifdef ESLOPE + mtsector->f_slope ? P_GetZAt(mtsector->f_slope, mt->x << FRACBITS, mt->y << FRACBITS) : +#endif + mtsector->floorheight)>>FRACBITS; if (mt->type == 1700 // MT_AXIS || mt->type == 1701 // MT_AXISTRANSFER @@ -2114,7 +2132,8 @@ void P_LoadThingsOnly(void) P_LevelInitStuff(); - P_LoadThings(lastloadedmaplumpnum + ML_THINGS); + P_PrepareThings(lastloadedmaplumpnum + ML_THINGS); + P_LoadThings(); P_SpawnSecretItems(true); } @@ -2531,7 +2550,13 @@ boolean P_SetupLevel(boolean skipprecip) P_MapStart(); - P_LoadThings(lastloadedmaplumpnum + ML_THINGS); + P_PrepareThings(lastloadedmaplumpnum + ML_THINGS); + +#ifdef ESLOPE + P_ResetDynamicSlopes(); +#endif + + P_LoadThings(); P_SpawnSecretItems(loademblems); diff --git a/src/p_slopes.c b/src/p_slopes.c new file mode 100644 index 000000000..bb150944e --- /dev/null +++ b/src/p_slopes.c @@ -0,0 +1,1135 @@ +// 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 "p_setup.h" +#include "r_main.h" +#include "p_maputl.h" +#include "w_wad.h" + +#ifdef ESLOPE + +static pslope_t *slopelist = NULL; +static UINT16 slopecount = 0; + +// Calculate line normal +void P_CalculateSlopeNormal(pslope_t *slope) { + slope->normal.z = FINECOSINE(slope->zangle>>ANGLETOFINESHIFT); + slope->normal.x = -FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), slope->d.x); + slope->normal.y = -FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), slope->d.y); +} + +// With a vertex slope that has its vertices set, configure relevant slope info +void P_ReconfigureVertexSlope(pslope_t *slope) +{ + vector3_t vec1, vec2; + + // Set slope normal + vec1.x = (slope->vertices[1]->x - slope->vertices[0]->x) << FRACBITS; + vec1.y = (slope->vertices[1]->y - slope->vertices[0]->y) << FRACBITS; + vec1.z = (slope->vertices[1]->z - slope->vertices[0]->z) << FRACBITS; + + vec2.x = (slope->vertices[2]->x - slope->vertices[0]->x) << FRACBITS; + vec2.y = (slope->vertices[2]->y - slope->vertices[0]->y) << FRACBITS; + vec2.z = (slope->vertices[2]->z - slope->vertices[0]->z) << FRACBITS; + + // ugggggggh fixed-point maaaaaaath + slope->extent = max( + max(max(abs(vec1.x), abs(vec1.y)), abs(vec1.z)), + max(max(abs(vec2.x), abs(vec2.y)), abs(vec2.z)) + ) >> (FRACBITS+5); + vec1.x /= slope->extent; + vec1.y /= slope->extent; + vec1.z /= slope->extent; + vec2.x /= slope->extent; + vec2.y /= slope->extent; + vec2.z /= slope->extent; + + FV3_Cross(&vec1, &vec2, &slope->normal); + + slope->extent = R_PointToDist2(0, 0, R_PointToDist2(0, 0, slope->normal.x, slope->normal.y), slope->normal.z); + if (slope->normal.z < 0) + slope->extent = -slope->extent; + + slope->normal.x = FixedDiv(slope->normal.x, slope->extent); + slope->normal.y = FixedDiv(slope->normal.y, slope->extent); + slope->normal.z = FixedDiv(slope->normal.z, slope->extent); + + // Set origin + slope->o.x = slope->vertices[0]->x << FRACBITS; + slope->o.y = slope->vertices[0]->y << FRACBITS; + slope->o.z = slope->vertices[0]->z << FRACBITS; + + if (slope->normal.x == 0 && slope->normal.y == 0) { // Set some defaults for a non-sloped "slope" + slope->zangle = slope->xydirection = 0; + slope->zdelta = slope->d.x = slope->d.y = 0; + } else { + // Get direction vector + slope->extent = R_PointToDist2(0, 0, slope->normal.x, slope->normal.y); + slope->d.x = -FixedDiv(slope->normal.x, slope->extent); + slope->d.y = -FixedDiv(slope->normal.y, slope->extent); + + // Z delta + slope->zdelta = FixedDiv(slope->extent, slope->normal.z); + + // Get angles + slope->xydirection = R_PointToAngle2(0, 0, slope->d.x, slope->d.y)+ANGLE_180; + slope->zangle = -R_PointToAngle2(0, 0, FRACUNIT, slope->zdelta); + } +} + +// Recalculate dynamic slopes +void P_RunDynamicSlopes(void) { + pslope_t *slope; + + for (slope = slopelist; slope; slope = slope->next) { + fixed_t zdelta; + + if (slope->flags & SL_NODYNAMIC) + continue; + + switch(slope->refpos) { + case 1: // front floor + zdelta = slope->sourceline->backsector->floorheight - slope->sourceline->frontsector->floorheight; + slope->o.z = slope->sourceline->frontsector->floorheight; + break; + case 2: // front ceiling + zdelta = slope->sourceline->backsector->ceilingheight - slope->sourceline->frontsector->ceilingheight; + slope->o.z = slope->sourceline->frontsector->ceilingheight; + break; + case 3: // back floor + zdelta = slope->sourceline->frontsector->floorheight - slope->sourceline->backsector->floorheight; + slope->o.z = slope->sourceline->backsector->floorheight; + break; + case 4: // back ceiling + zdelta = slope->sourceline->frontsector->ceilingheight - slope->sourceline->backsector->ceilingheight; + slope->o.z = slope->sourceline->backsector->ceilingheight; + break; + case 5: // vertices + { + mapthing_t *mt; + size_t i, l; + line_t *line; + + for (i = 0; i < 3; i++) { + mt = slope->vertices[i]; + l = P_FindSpecialLineFromTag(799, mt->angle, -1); + if (l != -1) { + line = &lines[l]; + mt->z = line->frontsector->floorheight >> FRACBITS; + } + } + + P_ReconfigureVertexSlope(slope); + } + continue; // TODO + + default: + I_Error("P_RunDynamicSlopes: slope has invalid type!"); + } + + if (slope->zdelta != FixedDiv(zdelta, slope->extent)) { + slope->zdelta = FixedDiv(zdelta, slope->extent); + slope->zangle = R_PointToAngle2(0, 0, slope->extent, -zdelta); + P_CalculateSlopeNormal(slope); + } + } +} + +// +// P_MakeSlope +// +// Alocates and fill the contents of a slope structure. +// +static pslope_t *P_MakeSlope(const vector3_t *o, const vector2_t *d, + const fixed_t zdelta, UINT8 flags) +{ + pslope_t *ret = Z_Malloc(sizeof(pslope_t), PU_LEVEL, NULL); + memset(ret, 0, sizeof(*ret)); + + ret->o.x = o->x; + ret->o.y = o->y; + ret->o.z = o->z; + + ret->d.x = d->x; + ret->d.y = d->y; + + ret->zdelta = zdelta; + + ret->flags = flags; + + // Add to the slope list + ret->next = slopelist; + slopelist = ret; + + slopecount++; + ret->id = slopecount; + + return ret; +} + +// +// 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 fixed_t P_GetExtent(sector_t *sector, line_t *line) +{ + // ZDoom code reference: v3float_t = vertex_t + fixed_t fardist = -FRACUNIT; + 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]; + vertex_t tempv; + fixed_t dist; + + // Don't compare to the slope line. + if(li == line) + continue; + + P_ClosestPointOnLine(li->v1->x, li->v1->y, line, &tempv); + dist = R_PointToDist2(tempv.x, tempv.y, li->v1->x, li->v1->y); + if(dist > fardist) + fardist = dist; + + // Okay, maybe do it for v2 as well? + P_ClosestPointOnLine(li->v2->x, li->v2->y, line, &tempv); + dist = R_PointToDist2(tempv.x, tempv.y, li->v2->x, li->v2->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; + INT16 special = line->special; + pslope_t *fslope = NULL, *cslope = NULL; + vector3_t origin, point; + vector2_t direction; + fixed_t nx, ny, dz, extent; + + boolean frontfloor = (special == 700 || special == 702 || special == 703); + boolean backfloor = (special == 710 || special == 712 || special == 713); + boolean frontceil = (special == 701 || special == 702 || special == 713); + boolean backceil = (special == 711 || special == 712 || special == 703); + + UINT8 flags = 0; // Slope flags + if (line->flags & ML_NOSONIC) + flags |= SL_NOPHYSICS; + if (line->flags & ML_NOTAILS) + flags |= SL_NODYNAMIC; + if (line->flags & ML_NOKNUX) + flags |= SL_ANCHORVERTEX; + + 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; + } + + { + fixed_t len = R_PointToDist2(0, 0, line->dx, line->dy); + nx = FixedDiv(line->dy, len); + ny = -FixedDiv(line->dx, len); + } + + // SRB2CBTODO: Transform origin relative to the bounds of an individual FOF + origin.x = line->v1->x + (line->v2->x - line->v1->x)/2; + origin.y = line->v1->y + (line->v2->y - line->v1->y)/2; + + // 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) + { + line->frontsector->hasslope = true; // Tell the software renderer that we're sloped + + origin.z = line->backsector->floorheight; + direction.x = nx; + direction.y = ny; + + extent = P_GetExtent(line->frontsector, line); + + if(extent < 0) + { + 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 + FixedMul(direction.x, extent); + point.y = origin.y + FixedMul(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 = line->frontsector->floorheight; // Startz + dz = FixedDiv(origin.z - point.z, extent); // Destinationz + + // In P_SpawnSlopeLine the origin is the centerpoint of the sourcelinedef + + fslope = line->frontsector->f_slope = + P_MakeSlope(&point, &direction, dz, flags); + + // Set up some shit + fslope->extent = extent; + fslope->refpos = 1; + + // 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? + fslope->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; + + // Now check to see what the REAL high and low points of the slope inside the sector + // TODO: Is this really needed outside of FOFs? -Red + size_t l; + + for (l = 0; l < line->frontsector->linecount; l++) + { + fixed_t height = P_GetZAt(line->frontsector->f_slope, line->frontsector->lines[l]->v1->x, line->frontsector->lines[l]->v1->y); + + if (height > highest) + highest = height; + + if (height < lowest) + lowest = height; + } + + // Sets extra clipping data for the frontsector's slope + fslope->highz = highest; + fslope->lowz = lowest; + + fslope->zangle = R_PointToAngle2(0, origin.z, extent, point.z); + fslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y); + + P_CalculateSlopeNormal(fslope); + } + if(frontceil) + { + origin.z = line->backsector->ceilingheight; + point.z = line->frontsector->ceilingheight; + dz = FixedDiv(origin.z - point.z, extent); + + cslope = line->frontsector->c_slope = + P_MakeSlope(&point, &direction, dz, flags); + + // Set up some shit + cslope->extent = extent; + cslope->refpos = 2; + + // Sync the linedata of the line that started this slope + // SRB2CBTODO: Anything special for remote(control sector)-based slopes later? + cslope->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; + size_t l; + + for (l = 0; l < line->frontsector->linecount; l++) + { + fixed_t height = P_GetZAt(line->frontsector->c_slope, line->frontsector->lines[l]->v1->x, line->frontsector->lines[l]->v1->y); + + if (height > highest) + highest = height; + + if (height < lowest) + lowest = height; + } + + // This line special sets extra clipping data for the frontsector's slope + cslope->highz = highest; + cslope->lowz = lowest; + + cslope->zangle = R_PointToAngle2(0, origin.z, extent, point.z); + cslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y); + + P_CalculateSlopeNormal(cslope); + } + } + if(backfloor || backceil) + { + line->backsector->hasslope = true; // Tell the software renderer that we're sloped + + origin.z = line->frontsector->floorheight; + // Backsector + direction.x = -nx; + direction.y = -ny; + + extent = P_GetExtent(line->backsector, line); + + if(extent < 0) + { + 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 + FixedMul(direction.x, extent); + point.y = origin.y + FixedMul(direction.y, extent); + direction.x = -direction.x; + direction.y = -direction.y; + + if(backfloor) + { + point.z = line->backsector->floorheight; + dz = FixedDiv(origin.z - point.z, extent); + + fslope = line->backsector->f_slope = + P_MakeSlope(&point, &direction, dz, flags); + + // Set up some shit + fslope->extent = extent; + fslope->refpos = 3; + + // Sync the linedata of the line that started this slope + // SRB2CBTODO: Anything special for remote(control sector)-based slopes later? + fslope->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; + size_t l; + + for (l = 0; l < line->backsector->linecount; l++) + { + fixed_t height = P_GetZAt(line->backsector->f_slope, line->backsector->lines[l]->v1->x, line->backsector->lines[l]->v1->y); + + if (height > highest) + highest = height; + + if (height < lowest) + lowest = height; + } + + // This line special sets extra clipping data for the frontsector's slope + fslope->highz = highest; + fslope->lowz = lowest; + + fslope->zangle = R_PointToAngle2(0, origin.z, extent, point.z); + fslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y); + + P_CalculateSlopeNormal(fslope); + } + if(backceil) + { + origin.z = line->frontsector->ceilingheight; + point.z = line->backsector->ceilingheight; + dz = FixedDiv(origin.z - point.z, extent); + + cslope = line->backsector->c_slope = + P_MakeSlope(&point, &direction, dz, flags); + + // Set up some shit + cslope->extent = extent; + cslope->refpos = 4; + + // Sync the linedata of the line that started this slope + // SRB2CBTODO: Anything special for remote(control sector)-based slopes later? + cslope->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; + + size_t l; + + for (l = 0; l < line->backsector->linecount; l++) + { + fixed_t height = P_GetZAt(line->backsector->c_slope, line->backsector->lines[l]->v1->x, line->backsector->lines[l]->v1->y); + + if (height > highest) + highest = height; + + if (height < lowest) + lowest = height; + } + + // This line special sets extra clipping data for the backsector's slope + cslope->highz = highest; + cslope->lowz = lowest; + + cslope->zangle = R_PointToAngle2(0, origin.z, extent, point.z); + cslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y); + + P_CalculateSlopeNormal(cslope); + } + } + + if(!line->tag) + return; +} + +// +// P_NewVertexSlope +// +// Creates a new slope from three vertices with the specified IDs +// +pslope_t *P_NewVertexSlope(INT16 tag1, INT16 tag2, INT16 tag3, UINT8 flags) +{ + size_t i; + mapthing_t *mt = mapthings; + + pslope_t *ret = Z_Malloc(sizeof(pslope_t), PU_LEVEL, NULL); + memset(ret, 0, sizeof(*ret)); + + // Start by setting flags + ret->flags = flags; + + // Now set up the vertex list + ret->vertices = Z_Malloc(3*sizeof(mapthing_t), PU_LEVEL, NULL); + memset(ret->vertices, 0, 3*sizeof(mapthing_t)); + + // And... look for the vertices in question. + for (i = 0; i < nummapthings; i++, mt++) { + if (mt->type != 750) // Haha, I'm hijacking the old Chaos Spawn thingtype for something! + continue; + + if (!ret->vertices[0] && mt->angle == tag1) + ret->vertices[0] = mt; + else if (!ret->vertices[1] && mt->angle == tag2) + ret->vertices[1] = mt; + else if (!ret->vertices[2] && mt->angle == tag3) + ret->vertices[2] = mt; + } + + if (!ret->vertices[0]) + CONS_Printf("PANIC 0\n"); + if (!ret->vertices[1]) + CONS_Printf("PANIC 1\n"); + if (!ret->vertices[2]) + CONS_Printf("PANIC 2\n"); + + // Now set heights for each vertex, because they haven't been set yet + for (i = 0; i < 3; i++) { + mt = ret->vertices[i]; + if (mt->extrainfo) + mt->z = mt->options; + else + mt->z = (R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)->sector->floorheight >> FRACBITS) + (mt->options >> ZSHIFT); + } + + P_ReconfigureVertexSlope(ret); + ret->refpos = 5; + + // Add to the slope list + ret->next = slopelist; + slopelist = ret; + + slopecount++; + ret->id = slopecount; + + return ret; +} + + + +// +// 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 - 719) & 1 && !fsec->f_slope && srcsec->f_slope) + fsec->f_slope = srcsec->f_slope; //P_CopySlope(srcsec->f_slope); + if((special - 719) & 2 && !fsec->c_slope && srcsec->c_slope) + fsec->c_slope = srcsec->c_slope; //P_CopySlope(srcsec->c_slope); + } + + fsec->hasslope = true; + + line->special = 0; // Linedef was use to set slopes, it finished its job, so now make it a normal linedef +} + +// +// P_SlopeById +// +// Looks in the slope list for a slope with a specified ID. Mostly useful for netgame sync +// +pslope_t *P_SlopeById(UINT16 id) +{ + pslope_t *ret; + for (ret = slopelist; ret && ret->id != id; ret = ret->next); + return ret; +} + +#ifdef SPRINGCLEAN +#include "byteptr.h" + +#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 = FixedDiv(FRACUNIT, 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); + + + + +} +#endif + +// Reset the dynamic slopes pointer, and read all of the fancy schmancy slopes +void P_ResetDynamicSlopes(void) { + size_t i; +#if 1 // Rewrite old specials to new ones, and give a console warning + boolean warned = false; +#endif + + slopelist = NULL; + slopecount = 0; + + // We'll handle copy slopes later, after all the tag lists have been made. + // Yes, this means copied slopes won't affect things' spawning heights. Too bad for you. + for (i = 0; i < numlines; i++) + { + switch (lines[i].special) + { +#if 1 // Rewrite old specials to new ones, and give a console warning +#define WARNME if (!warned) {warned = true; CONS_Alert(CONS_WARNING, "This level uses old slope specials.\nA conversion will be needed before 2.2's release.\n");} + case 386: + case 387: + case 388: + lines[i].special += 700-386; + WARNME + P_SpawnSlope_Line(i); + break; + + case 389: + case 390: + case 391: + case 392: + lines[i].special += 710-389; + WARNME + P_SpawnSlope_Line(i); + break; + + case 393: + lines[i].special = 703; + WARNME + P_SpawnSlope_Line(i); + break; + + case 394: + case 395: + case 396: + lines[i].special += 720-394; + WARNME + break; + +#endif + + case 700: + case 701: + case 702: + case 703: + case 710: + case 711: + case 712: + case 713: + P_SpawnSlope_Line(i); + break; + + case 704: + case 705: + case 714: + case 715: + { + pslope_t **slopetoset; + size_t which = lines[i].special; + + UINT8 flags = SL_VERTEXSLOPE; + if (lines[i].flags & ML_NOSONIC) + flags |= SL_NOPHYSICS; + if (!(lines[i].flags & ML_NOTAILS)) + flags |= SL_NODYNAMIC; + + if (which == 704) + { + slopetoset = &lines[i].frontsector->f_slope; + which = 0; + } + else if (which == 705) + { + slopetoset = &lines[i].frontsector->c_slope; + which = 0; + } + else if (which == 714) + { + slopetoset = &lines[i].backsector->f_slope; + which = 1; + } + else // 715 + { + slopetoset = &lines[i].backsector->c_slope; + which = 1; + } + + if (lines[i].flags & ML_NOKNUX) + *slopetoset = P_NewVertexSlope(lines[i].tag, sides[lines[i].sidenum[which]].textureoffset >> FRACBITS, + sides[lines[i].sidenum[which]].rowoffset >> FRACBITS, flags); + else + *slopetoset = P_NewVertexSlope(lines[i].tag, lines[i].tag, lines[i].tag, flags); + + sides[lines[i].sidenum[which]].sector->hasslope = true; + } + break; + + default: + break; + } + } +} + + + + +// ============================================================================ +// +// 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_QuantizeMomentumToSlope +// +// When given a vector, rotates it and aligns it to a slope +void P_QuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope) +{ + vector3_t axis; + axis.x = -slope->d.y; + axis.y = slope->d.x; + axis.z = 0; + + FV3_Rotate(momentum, &axis, slope->zangle >> ANGLETOFINESHIFT); +} + +// +// P_SlopeLaunch +// +// Handles slope ejection for objects +void P_SlopeLaunch(mobj_t *mo) +{ + // Double the pre-rotation Z, then halve the post-rotation Z. This reduces the + // vertical launch given from slopes while increasing the horizontal launch + // given. Good for SRB2's gravity and horizontal speeds. + vector3_t slopemom; + slopemom.x = mo->momx; + slopemom.y = mo->momy; + slopemom.z = mo->momz*2; + P_QuantizeMomentumToSlope(&slopemom, mo->standingslope); + + mo->momx = slopemom.x; + mo->momy = slopemom.y; + mo->momz = slopemom.z/2; + + //CONS_Printf("Launched off of slope.\n"); + mo->standingslope = NULL; +} + +// Function to help handle landing on slopes +void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope) +{ + vector3_t mom; + mom.x = thing->momx; + mom.y = thing->momy; + mom.z = thing->momz*2; + + //CONS_Printf("langing on slope\n"); + + // Reverse quantizing might could use its own function later + slope->zangle = ANGLE_MAX-slope->zangle; + P_QuantizeMomentumToSlope(&mom, slope); + slope->zangle = ANGLE_MAX-slope->zangle; + + if (P_MobjFlip(thing)*mom.z < 0) { // falling, land on slope + thing->momx = mom.x; + thing->momy = mom.y; + thing->momz = -P_MobjFlip(thing); + + thing->standingslope = slope; + } +} + +// https://yourlogicalfallacyis.com/slippery-slope +// Handles sliding down slopes, like if they were made of butter :) +void P_ButteredSlope(mobj_t *mo) +{ + fixed_t thrust; + + if (!mo->standingslope) + return; + + if (mo->player) { + if (abs(mo->standingslope->zdelta) < FRACUNIT/4 && !(mo->player->pflags & PF_SPINNING)) + return; // Don't slide on non-steep slopes unless spinning + + if (abs(mo->standingslope->zdelta) < FRACUNIT/2 && !(mo->player->rmomx || mo->player->rmomy)) + return; // Allow the player to stand still on slopes below a certain steepness + } + + thrust = FINESINE(mo->standingslope->zangle>>ANGLETOFINESHIFT) * 3 / 2 * (mo->eflags & MFE_VERTICALFLIP ? 1 : -1); + + if (mo->player && (mo->player->pflags & PF_SPINNING)) { + fixed_t mult = 0; + if (mo->momx || mo->momy) { + angle_t angle = R_PointToAngle2(0, 0, mo->momx, mo->momy) - mo->standingslope->xydirection; + + if (P_MobjFlip(mo) * mo->standingslope->zdelta < 0) + angle ^= ANGLE_180; + + mult = FINECOSINE(angle >> ANGLETOFINESHIFT); + } + + //CONS_Printf("%d\n", mult); + + thrust = FixedMul(thrust, FRACUNIT*2/3 + mult/8); + } + + if (mo->momx || mo->momy) // Slightly increase thrust based on the object's speed + thrust = FixedMul(thrust, FRACUNIT+P_AproxDistance(mo->momx, mo->momy)/16); + // This makes it harder to zigzag up steep slopes, as well as allows greater top speed when rolling down + + // Multiply by gravity + thrust = FixedMul(thrust, FRACUNIT/2); // TODO actually get this + + P_Thrust(mo, mo->standingslope->xydirection, thrust); +} + +// EOF +#endif // #ifdef ESLOPE diff --git a/src/p_slopes.h b/src/p_slopes.h new file mode 100644 index 000000000..8d82632ff --- /dev/null +++ b/src/p_slopes.h @@ -0,0 +1,80 @@ +// 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 +void P_ResetDynamicSlopes(void); +void P_RunDynamicSlopes(void); +// P_SpawnSlope_Line +// Creates one or more slopes based on the given line type and front/back +// sectors. +void P_SpawnSlope_Line(int linenum); + +#ifdef SPRINGCLEAN +// 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; +#endif + +// +// P_CopySectorSlope +// +// Searches through tagged sectors and copies +// +void P_CopySectorSlope(line_t *line); + +pslope_t *P_SlopeById(UINT16 id); + +// 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); + +// Lots of physics-based bullshit +void P_QuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope); +void P_SlopeLaunch(mobj_t *mo); +void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope); +void P_ButteredSlope(mobj_t *mo); + +#endif + +// EOF +#endif // #ifdef ESLOPE diff --git a/src/p_spec.c b/src/p_spec.c index cb3340ee4..eeb19476a 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3365,6 +3365,7 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n static boolean P_ThingIsOnThe3DFloor(mobj_t *mo, sector_t *sector, sector_t *targetsec) { ffloor_t *rover; + fixed_t top, bottom; if (!mo->player) // should NEVER happen return false; @@ -3381,6 +3382,9 @@ static boolean P_ThingIsOnThe3DFloor(mobj_t *mo, sector_t *sector, sector_t *tar //if (!(rover->flags & FF_EXISTS)) // return false; + top = P_GetSpecialTopZ(mo, sector, targetsec); + bottom = P_GetSpecialBottomZ(mo, sector, targetsec); + // Check the 3D floor's type... if (rover->flags & FF_BLOCKPLAYER) { @@ -3388,27 +3392,27 @@ static boolean P_ThingIsOnThe3DFloor(mobj_t *mo, sector_t *sector, sector_t *tar if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) && !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)) { - if ((mo->eflags & MFE_VERTICALFLIP) || mo->z != *rover->topheight) + if ((mo->eflags & MFE_VERTICALFLIP) || mo->z != top) return false; } else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) && !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)) { if (!(mo->eflags & MFE_VERTICALFLIP) - || mo->z + mo->height != *rover->bottomheight) + || mo->z + mo->height != bottom) return false; } else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH) { - if (!((mo->eflags & MFE_VERTICALFLIP && mo->z + mo->height == *rover->bottomheight) - || (!(mo->eflags & MFE_VERTICALFLIP) && mo->z == *rover->topheight))) + if (!((mo->eflags & MFE_VERTICALFLIP && mo->z + mo->height == bottom) + || (!(mo->eflags & MFE_VERTICALFLIP) && mo->z == top))) return false; } } else { // Water and intangible FOFs - if (mo->z > *rover->topheight || (mo->z + mo->height) < *rover->bottomheight) + if (mo->z > top || (mo->z + mo->height) < bottom) return false; } @@ -3426,9 +3430,9 @@ static boolean P_ThingIsOnThe3DFloor(mobj_t *mo, sector_t *sector, sector_t *tar static inline boolean P_MobjReadyToTrigger(mobj_t *mo, sector_t *sec) { if (mo->eflags & MFE_VERTICALFLIP) - return (mo->z+mo->height == sec->ceilingheight && sec->flags & SF_FLIPSPECIAL_CEILING); + return (mo->z+mo->height == P_GetSpecialTopZ(mo, sec, sec) && sec->flags & SF_FLIPSPECIAL_CEILING); else - return (mo->z == sec->floorheight && sec->flags & SF_FLIPSPECIAL_FLOOR); + return (mo->z == P_GetSpecialBottomZ(mo, sec, sec) && sec->flags & SF_FLIPSPECIAL_FLOOR); } /** Applies a sector special to a player. @@ -4389,27 +4393,27 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector) if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) && !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)) { - if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != *rover->topheight) + if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != P_GetSpecialTopZ(player->mo, sectors + rover->secnum, sector)) continue; } else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) && !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)) { if (!(player->mo->eflags & MFE_VERTICALFLIP) - || player->mo->z + player->mo->height != *rover->bottomheight) + || player->mo->z + player->mo->height != P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, sector)) continue; } else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH) { - if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == *rover->bottomheight) - || (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == *rover->topheight))) + if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, sector)) + || (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == P_GetSpecialTopZ(player->mo, sectors + rover->secnum, sector)))) continue; } } else { // Water and DEATH FOG!!! heh - if (player->mo->z > *rover->topheight || (player->mo->z + player->mo->height) < *rover->bottomheight) + if (player->mo->z > P_GetSpecialTopZ(player->mo, sectors + rover->secnum, sector) || (player->mo->z + player->mo->height) < P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, sector)) continue; } @@ -4519,6 +4523,7 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector) static void P_RunSpecialSectorCheck(player_t *player, sector_t *sector) { boolean nofloorneeded = false; + fixed_t f_affectpoint, c_affectpoint; if (!sector->special) // nothing special, exit return; @@ -4581,16 +4586,19 @@ static void P_RunSpecialSectorCheck(player_t *player, sector_t *sector) return; } + f_affectpoint = P_GetSpecialBottomZ(player->mo, sector, sector); + c_affectpoint = P_GetSpecialTopZ(player->mo, sector, sector); + // 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); @@ -4751,6 +4759,9 @@ void P_UpdateSpecials(void) // POINT LIMIT P_CheckPointLimit(); + // Dynamic slopeness + P_RunDynamicSlopes(); + // ANIMATE TEXTURES for (anim = anims; anim < lastanim; anim++) { @@ -4894,6 +4905,12 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f ffloor->topyoffs = &sec2->ceiling_yoffs; ffloor->topangle = &sec2->ceilingpic_angle; +#ifdef ESLOPE + // Add slopes + ffloor->t_slope = &sec2->c_slope; + ffloor->b_slope = &sec2->f_slope; +#endif + if ((flags & FF_SOLID) && (master->flags & ML_EFFECT1)) // Block player only flags &= ~FF_BLOCKOTHERS; @@ -5327,6 +5344,7 @@ void T_LaserFlash(laserthink_t *flash) sector_t *sourcesec; ffloor_t *ffloor = flash->ffloor; sector_t *sector = flash->sector; + fixed_t top, bottom; if (!ffloor || !(ffloor->flags & FF_EXISTS)) return; @@ -5350,8 +5368,11 @@ void T_LaserFlash(laserthink_t *flash) && thing->flags & MF_BOSS) continue; // Don't hurt bosses - if (thing->z >= sourcesec->ceilingheight - || thing->z + thing->height <= sourcesec->floorheight) + top = P_GetSpecialTopZ(thing, sourcesec, sector); + bottom = P_GetSpecialBottomZ(thing, sourcesec, sector); + + if (thing->z >= top + || thing->z + thing->height <= bottom) continue; if (thing->flags & MF_SHOOTABLE) @@ -6430,6 +6451,14 @@ void P_SpawnSpecials(INT32 fromnetsave) sectors[s].midmap = lines[i].frontsector->midmap; break; +#ifdef ESLOPE // Slope copy specials. Handled here for sanity. + case 720: + case 721: + case 722: + P_CopySectorSlope(&lines[i]); + break; +#endif + default: break; } @@ -6634,6 +6663,8 @@ void T_Scroll(scroll_t *s) if (thing->eflags & MFE_PUSHED) // Already pushed this tic by an exclusive pusher. continue; + height = P_GetSpecialBottomZ(thing, sec, psec); + if (!(thing->flags & MF_NOCLIP)) // Thing must be clipped if (!(thing->flags & MF_NOGRAVITY || thing->z+thing->height != height)) // Thing must a) be non-floating and have z+height == height { @@ -6654,6 +6685,8 @@ void T_Scroll(scroll_t *s) if (thing->eflags & MFE_PUSHED) continue; + height = P_GetSpecialBottomZ(thing, sec, sec); + if (!(thing->flags & MF_NOCLIP) && (!(thing->flags & MF_NOGRAVITY || thing->z > height))) { @@ -6693,6 +6726,8 @@ void T_Scroll(scroll_t *s) if (thing->eflags & MFE_PUSHED) continue; + height = P_GetSpecialTopZ(thing, sec, psec); + if (!(thing->flags & MF_NOCLIP)) // Thing must be clipped if (!(thing->flags & MF_NOGRAVITY || thing->z != height))// Thing must a) be non-floating and have z == height { @@ -6713,6 +6748,8 @@ void T_Scroll(scroll_t *s) if (thing->eflags & MFE_PUSHED) continue; + height = P_GetSpecialTopZ(thing, sec, sec); + if (!(thing->flags & MF_NOCLIP) && (!(thing->flags & MF_NOGRAVITY || thing->z+thing->height < height))) { @@ -7006,7 +7043,7 @@ static void Add_Friction(INT32 friction, INT32 movefactor, INT32 affectee, INT32 */ void T_Friction(friction_t *f) { - sector_t *sec; + sector_t *sec, *referrer; mobj_t *thing; msecnode_t *node; @@ -7015,7 +7052,7 @@ void T_Friction(friction_t *f) // Make sure the sector type hasn't changed if (f->roverfriction) { - sector_t *referrer = sectors + f->referrer; + referrer = sectors + f->referrer; if (!(GETSECSPECIAL(referrer->special, 3) == 1 || GETSECSPECIAL(referrer->special, 3) == 3)) @@ -7047,9 +7084,7 @@ void T_Friction(friction_t *f) { if (f->roverfriction) { - sector_t *referrer = §ors[f->referrer]; - - if (thing->floorz != referrer->ceilingheight) + if (thing->floorz != P_GetSpecialTopZ(thing, referrer, sec)) { node = node->m_snext; continue; @@ -7062,7 +7097,7 @@ void T_Friction(friction_t *f) thing->movefactor = f->movefactor; } } - else if (sec->floorheight == thing->floorz && (thing->friction == ORIG_FRICTION // normal friction? + else if (P_GetSpecialBottomZ(thing, sec, sec) == thing->floorz && (thing->friction == ORIG_FRICTION // normal friction? || f->friction < thing->friction)) { thing->friction = f->friction; @@ -7336,7 +7371,7 @@ static inline boolean PIT_PushThing(mobj_t *thing) */ void T_Pusher(pusher_t *p) { - sector_t *sec; + sector_t *sec, *referrer; mobj_t *thing; msecnode_t *node; INT32 xspeed = 0,yspeed = 0; @@ -7345,7 +7380,6 @@ void T_Pusher(pusher_t *p) //INT32 ht = 0; boolean inFOF; boolean touching; - boolean foundfloor = false; boolean moved; xspeed = yspeed = 0; @@ -7357,19 +7391,16 @@ void T_Pusher(pusher_t *p) if (p->roverpusher) { - sector_t *referrer = §ors[p->referrer]; + referrer = §ors[p->referrer]; - if (GETSECSPECIAL(referrer->special, 3) == 2 - || GETSECSPECIAL(referrer->special, 3) == 3) - foundfloor = true; + if (!(GETSECSPECIAL(referrer->special, 3) == 2 + || GETSECSPECIAL(referrer->special, 3) == 3)) + return; } else if (!(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. - return; - // For constant pushers (wind/current) there are 3 situations: // // 1) Affected Thing is above the floor. @@ -7444,41 +7475,38 @@ void T_Pusher(pusher_t *p) // Find the area that the 'thing' is in if (p->roverpusher) { - sector_t *referrer = §ors[p->referrer]; - INT32 special; + fixed_t top, bottom; - special = GETSECSPECIAL(referrer->special, 3); - - if (!(special == 2 || special == 3)) - return; + top = P_GetSpecialTopZ(thing, referrer, sec); + bottom = P_GetSpecialBottomZ(thing, referrer, sec); if (thing->eflags & MFE_VERTICALFLIP) { - if (referrer->floorheight > thing->z + thing->height - || referrer->ceilingheight < (thing->z + (thing->height >> 1))) + if (bottom > thing->z + thing->height + || top < (thing->z + (thing->height >> 1))) continue; - if (thing->z < referrer->floorheight) + if (thing->z < bottom) touching = true; - if (thing->z + (thing->height >> 1) > referrer->floorheight) + if (thing->z + (thing->height >> 1) > bottom) inFOF = true; } else { - if (referrer->ceilingheight < thing->z || referrer->floorheight > (thing->z + (thing->height >> 1))) + if (top < thing->z || referrer->floorheight > (thing->z + (thing->height >> 1))) continue; - if (thing->z + thing->height > referrer->ceilingheight) + if (thing->z + thing->height > top) touching = true; - if (thing->z + (thing->height >> 1) < referrer->ceilingheight) + if (thing->z + (thing->height >> 1) < top) inFOF = true; } } else // Treat the entire sector as one big FOF { - if (thing->z == thing->subsector->sector->floorheight) + if (thing->z == P_GetSpecialBottomZ(thing, sec, sec)) touching = true; else if (p->type != p_current) inFOF = true; diff --git a/src/p_user.c b/src/p_user.c index c7d612efc..ef063dab2 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1212,7 +1212,7 @@ boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec) if (mo->eflags & MFE_VERTICALFLIP) { // Detect if the player is on the ceiling. - if (mo->z+mo->height >= sec->ceilingheight) + if (mo->z+mo->height >= P_GetSpecialTopZ(mo, sec, sec)) return true; // Otherwise, detect if the player is on the bottom of a FOF. else @@ -1236,7 +1236,7 @@ boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec) continue; // Actually check if the player is on the suitable FOF. - if (mo->z+mo->height == *rover->bottomheight) + if (mo->z+mo->height == P_GetSpecialBottomZ(mo, sectors + rover->secnum, sec)) return true; } } @@ -1245,7 +1245,7 @@ boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec) else { // Detect if the player is on the floor. - if (mo->z <= sec->floorheight) + if (mo->z <= P_GetSpecialBottomZ(mo, sec, sec)) return true; // Otherwise, detect if the player is on the top of a FOF. else @@ -1269,7 +1269,7 @@ boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec) continue; // Actually check if the player is on the suitable FOF. - if (mo->z == *rover->topheight) + if (mo->z == P_GetSpecialTopZ(mo, sectors + rover->secnum, sec)) return true; } } @@ -1790,6 +1790,9 @@ static void P_CheckBouncySectors(player_t *player) fixed_t oldx; fixed_t oldy; fixed_t oldz; +#ifdef ESLOPE + vector3_t momentum; +#endif oldx = player->mo->x; oldy = player->mo->y; @@ -1810,16 +1813,21 @@ static void P_CheckBouncySectors(player_t *player) { ffloor_t *rover; boolean top = true; + fixed_t topheight, bottomheight; for (rover = node->m_sector->ffloors; rover; rover = rover->next) { - if (player->mo->z > *rover->topheight) + topheight = P_GetFOFTopZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL); + bottomheight = P_GetFOFBottomZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL); + + if (player->mo->z > topheight) continue; - if (player->mo->z + player->mo->height < *rover->bottomheight) + if (player->mo->z + player->mo->height < bottomheight) continue; - if (oldz < *rover->topheight && oldz > *rover->bottomheight) + if (oldz < P_GetFOFTopZ(player->mo, node->m_sector, rover, oldx, oldy, NULL) + && oldz + player->mo->height > P_GetFOFBottomZ(player->mo, node->m_sector, rover, oldx, oldy, NULL)) top = false; if (GETSECSPECIAL(rover->master->frontsector->special, 1) == 15) @@ -1834,7 +1842,29 @@ static void P_CheckBouncySectors(player_t *player) { fixed_t newmom; +#ifdef ESLOPE + pslope_t *slope; + if (abs(oldz - topheight) < abs(oldz + player->mo->height - bottomheight)) { // Hit top + slope = *rover->t_slope; + } else { // Hit bottom + slope = *rover->b_slope; + } + + momentum.x = player->mo->momx; + momentum.y = player->mo->momy; + momentum.z = player->mo->momz*2; + + if (slope) { + // Reverse quantizing might could use its own function later + slope->zangle = ANGLE_MAX-slope->zangle; + P_QuantizeMomentumToSlope(&momentum, slope); + slope->zangle = ANGLE_MAX-slope->zangle; + } + + newmom = momentum.z = -FixedMul(momentum.z,linedist)/2; +#else newmom = -FixedMul(player->mo->momz,linedist); +#endif if (abs(newmom) < (linedist*2)) { @@ -1857,7 +1887,18 @@ static void P_CheckBouncySectors(player_t *player) else if (newmom < -P_GetPlayerHeight(player)/2) newmom = -P_GetPlayerHeight(player)/2; +#ifdef ESLOPE + momentum.z = newmom*2; + + if (slope) + P_QuantizeMomentumToSlope(&momentum, slope); + + player->mo->momx = momentum.x; + player->mo->momy = momentum.y; + player->mo->momz = momentum.z/2; +#else player->mo->momz = newmom; +#endif if (player->pflags & PF_SPINNING) { @@ -2275,10 +2316,23 @@ static void P_DoClimbing(player_t *player) floorclimb = false; boostup = false; skyclimber = false; + fixed_t floorheight, ceilingheight; // ESLOPE + +#ifdef ESLOPE + floorheight = glidesector->sector->f_slope ? P_GetZAt(glidesector->sector->f_slope, player->mo->x, player->mo->y) + : glidesector->sector->floorheight; + ceilingheight = glidesector->sector->c_slope ? P_GetZAt(glidesector->sector->c_slope, player->mo->x, player->mo->y) + : glidesector->sector->ceilingheight; +#else + floorheight = glidesector->sector->floorheight; + ceilingheight = glidesector->sector->ceilingheight; +#endif if (glidesector->sector->ffloors) { ffloor_t *rover; + fixed_t topheight, bottomheight; // ESLOPE + for (rover = glidesector->sector->ffloors; rover; rover = rover->next) { if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP)) @@ -2286,13 +2340,21 @@ static void P_DoClimbing(player_t *player) floorclimb = true; +#ifdef ESLOPE + bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight; + topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight; +#else + bottomheight = *rover->bottomheight; + topheight = *rover->topheight; +#endif + // Only supports rovers that are moving like an 'elevator', not just the top or bottom. if (rover->master->frontsector->floorspeed && rover->master->frontsector->ceilspeed == 42) { - if ((!(player->mo->eflags & MFE_VERTICALFLIP) && (*rover->bottomheight < player->mo->z+player->mo->height) - && (*rover->topheight >= player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale))) - || ((player->mo->eflags & MFE_VERTICALFLIP) && (*rover->topheight > player->mo->z) - && (*rover->bottomheight <= player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale)))) + if ((!(player->mo->eflags & MFE_VERTICALFLIP) && (bottomheight < player->mo->z+player->mo->height) + && (topheight >= player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale))) + || ((player->mo->eflags & MFE_VERTICALFLIP) && (topheight > player->mo->z) + && (bottomheight <= player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale)))) { if (cmd->forwardmove != 0) player->mo->momz += rover->master->frontsector->floorspeed; @@ -2308,8 +2370,9 @@ static void P_DoClimbing(player_t *player) if (player->mo->eflags & MFE_VERTICALFLIP) { // Trying to climb down past the bottom of the FOF - 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)) { + fixed_t bottomheight2; ffloor_t *roverbelow; boolean foundfof = false; floorclimb = true; @@ -2324,7 +2387,13 @@ static void P_DoClimbing(player_t *player) if (roverbelow == rover) continue; - if (*roverbelow->bottomheight < *rover->topheight + FixedMul(16*FRACUNIT, player->mo->scale)) +#ifdef ESLOPE + bottomheight2 = *roverbelow->b_slope ? P_GetZAt(*roverbelow->b_slope, player->mo->x, player->mo->y) : *roverbelow->bottomheight; +#else + bottomheight2 = *roverbelow->bottomheight; +#endif + + if (bottomheight2 < topheight + FixedMul(16*FRACUNIT, player->mo->scale)) foundfof = true; } @@ -2333,7 +2402,7 @@ static void P_DoClimbing(player_t *player) } // Below the FOF - if (*rover->topheight <= player->mo->z) + if (topheight <= player->mo->z) { floorclimb = false; boostup = false; @@ -2341,7 +2410,7 @@ static void P_DoClimbing(player_t *player) } // Above the FOF - 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; thrust = true; @@ -2351,8 +2420,9 @@ static void P_DoClimbing(player_t *player) else { // Trying to climb down past the bottom of a FOF - 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)) { + fixed_t topheight2; ffloor_t *roverbelow; boolean foundfof = false; floorclimb = true; @@ -2367,7 +2437,13 @@ static void P_DoClimbing(player_t *player) if (roverbelow == rover) continue; - if (*roverbelow->topheight > *rover->bottomheight - FixedMul(16*FRACUNIT, player->mo->scale)) +#ifdef ESLOPE + topheight2 = *roverbelow->t_slope ? P_GetZAt(*roverbelow->t_slope, player->mo->x, player->mo->y) : *roverbelow->topheight; +#else + topheight2 = *roverbelow->topheight; +#endif + + if (topheight2 > bottomheight - FixedMul(16*FRACUNIT, player->mo->scale)) foundfof = true; } @@ -2376,7 +2452,7 @@ static void P_DoClimbing(player_t *player) } // Below the FOF - if (*rover->bottomheight >= player->mo->z + player->mo->height) + if (bottomheight >= player->mo->z + player->mo->height) { floorclimb = false; boostup = false; @@ -2384,7 +2460,7 @@ static void P_DoClimbing(player_t *player) } // Above the FOF - 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; thrust = true; @@ -2405,7 +2481,7 @@ static void P_DoClimbing(player_t *player) if (player->mo->eflags & MFE_VERTICALFLIP) { // Trying to climb down past the upper texture area - if ((glidesector->sector->floorheight >= player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) >= glidesector->sector->floorheight)) + if ((floorheight >= player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) >= floorheight)) { boolean foundfof = false; floorclimb = true; @@ -2413,13 +2489,20 @@ static void P_DoClimbing(player_t *player) // Is there a FOF directly below that we can move onto? if (glidesector->sector->ffloors) { + fixed_t bottomheight; ffloor_t *rover; for (rover = glidesector->sector->ffloors; rover; rover = rover->next) { if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP)) continue; - if (*rover->bottomheight < glidesector->sector->floorheight + FixedMul(16*FRACUNIT, player->mo->scale)) +#ifdef ESLOPE + bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight; +#else + bottomheight = *rover->bottomheight; +#endif + + if (bottomheight < floorheight + FixedMul(16*FRACUNIT, player->mo->scale)) { foundfof = true; break; @@ -2432,8 +2515,8 @@ static void P_DoClimbing(player_t *player) } // Reached the top of the lower texture area - if (!floorclimb && glidesector->sector->ceilingheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale) - && (glidesector->sector->ceilingpic == skyflatnum || glidesector->sector->floorheight < (player->mo->z - FixedMul(8*FRACUNIT, player->mo->scale)))) + if (!floorclimb && ceilingheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale) + && (glidesector->sector->ceilingpic == skyflatnum || floorheight < (player->mo->z - FixedMul(8*FRACUNIT, player->mo->scale)))) { thrust = true; boostup = true; @@ -2443,7 +2526,7 @@ static void P_DoClimbing(player_t *player) else { // Trying to climb down past the upper texture area - if ((glidesector->sector->ceilingheight <= player->mo->z) && ((player->mo->z + player->mo->momz) <= glidesector->sector->ceilingheight)) + if ((ceilingheight <= player->mo->z) && ((player->mo->z + player->mo->momz) <= ceilingheight)) { boolean foundfof = false; floorclimb = true; @@ -2457,7 +2540,7 @@ static void P_DoClimbing(player_t *player) if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP)) continue; - if (*rover->topheight > glidesector->sector->ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale)) + if (*rover->topheight > ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale)) { foundfof = true; break; @@ -2470,7 +2553,7 @@ static void P_DoClimbing(player_t *player) } // Allow climbing from a FOF or lower texture onto the upper texture and vice versa. - if (player->mo->z > glidesector->sector->ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale)) + if (player->mo->z > ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale)) { floorclimb = true; thrust = false; @@ -2478,8 +2561,8 @@ static void P_DoClimbing(player_t *player) } // Reached the top of the lower texture area - if (!floorclimb && glidesector->sector->floorheight < player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale) - && (glidesector->sector->ceilingpic == skyflatnum || glidesector->sector->ceilingheight > (player->mo->z + player->mo->height + FixedMul(8*FRACUNIT, player->mo->scale)))) + if (!floorclimb && floorheight < player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale) + && (glidesector->sector->ceilingpic == skyflatnum || ceilingheight > (player->mo->z + player->mo->height + FixedMul(8*FRACUNIT, player->mo->scale)))) { thrust = true; boostup = true; @@ -2488,14 +2571,14 @@ static void P_DoClimbing(player_t *player) } // Trying to climb on the sky - if ((glidesector->sector->ceilingheight < player->mo->z) && glidesector->sector->ceilingpic == skyflatnum) + if ((ceilingheight < player->mo->z) && glidesector->sector->ceilingpic == skyflatnum) { skyclimber = true; } // Climbing on the lower texture area? - if ((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale) < glidesector->sector->floorheight) - || ((player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height <= glidesector->sector->floorheight)) + if ((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale) < floorheight) + || ((player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height <= floorheight)) { floorclimb = true; @@ -2511,8 +2594,8 @@ static void P_DoClimbing(player_t *player) } } // Climbing on the upper texture area? - else if ((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z >= glidesector->sector->ceilingheight) - || ((player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale) > glidesector->sector->ceilingheight)) + else if ((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z >= ceilingheight) + || ((player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale) > ceilingheight)) { floorclimb = true; @@ -3704,7 +3787,11 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd) if ((player->charability2 == CA2_SPINDASH) && !(player->pflags & PF_SLIDING) && !player->exiting && !P_PlayerInPain(player)) // subsequent revs { - if ((cmd->buttons & BT_USE) && player->speed < FixedMul(5<mo->scale) && !player->mo->momz && onground && !(player->pflags & PF_USEDOWN) && !(player->pflags & PF_SPINNING)) + if ((cmd->buttons & BT_USE) && player->speed < FixedMul(5<mo->scale) && !player->mo->momz && onground && !(player->pflags & PF_USEDOWN) && !(player->pflags & PF_SPINNING) +#ifdef ESLOPE + && (!player->mo->standingslope || abs(player->mo->standingslope->zdelta) < FRACUNIT/2) +#endif + ) { player->mo->momx = player->cmomx; player->mo->momy = player->cmomy; @@ -3736,7 +3823,11 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd) // down the spin button and not spinning. // AKA Just go into a spin on the ground, you idiot. ;) else if ((cmd->buttons & BT_USE || ((twodlevel || (player->mo->flags2 & MF2_TWOD)) && cmd->forwardmove < -20)) - && !player->climbing && !player->mo->momz && onground && player->speed > FixedMul(5<mo->scale) && !(player->pflags & PF_USEDOWN) && !(player->pflags & PF_SPINNING)) + && !player->climbing && !player->mo->momz && onground && (player->speed > FixedMul(5<mo->scale) +#ifdef ESLOPE + || (player->mo->standingslope && abs(player->mo->standingslope->zdelta) >= FRACUNIT/2) +#endif + ) && !(player->pflags & PF_USEDOWN) && !(player->pflags & PF_SPINNING)) { player->pflags |= PF_SPINNING; P_SetPlayerMobjState(player->mo, S_PLAY_SPIN); @@ -3748,7 +3839,11 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd) // Rolling normally if (onground && player->pflags & PF_SPINNING && !(player->pflags & PF_STARTDASH) - && player->speed < FixedMul(5*FRACUNIT,player->mo->scale)) + && player->speed < FixedMul(5*FRACUNIT,player->mo->scale) +#ifdef ESLOPE + && (!player->mo->standingslope || abs(player->mo->standingslope->zdelta) < FRACUNIT/2) +#endif + ) { if (GETSECSPECIAL(player->mo->subsector->sector->special, 4) == 7 || (player->mo->ceilingz - player->mo->floorz < P_GetPlayerHeight(player))) P_InstaThrust(player->mo, player->mo->angle, FixedMul(10*FRACUNIT, player->mo->scale)); @@ -4455,12 +4550,16 @@ static void P_3dMovement(player_t *player) angle_t dangle; // replaces old quadrants bits fixed_t normalspd = FixedMul(player->normalspeed, player->mo->scale); boolean analogmove = false; -#ifndef OLD_MOVEMENT_CODE fixed_t oldMagnitude, newMagnitude; +#ifdef ESLOPE + vector3_t totalthrust; + + totalthrust.x = totalthrust.y = 0; // I forget if this is needed + totalthrust.z = FRACUNIT*P_MobjFlip(player->mo)/3; // A bit of extra push-back on slopes +#endif // ESLOPE // Get the old momentum; this will be needed at the end of the function! -SH oldMagnitude = R_PointToDist2(player->mo->momx - player->cmomx, player->mo->momy - player->cmomy, 0, 0); -#endif analogmove = P_AnalogMove(player); @@ -4637,17 +4736,10 @@ static void P_3dMovement(player_t *player) } movepushforward = FixedMul(movepushforward, player->mo->scale); -#ifdef OLD_MOVEMENT_CODE - if (player->speed < topspeed && mforward && cmd->forwardmove > 0) // Sonic's Speed - P_Thrust(player->mo, movepushangle, movepushforward); - else if (mforward && cmd->forwardmove < 0) - P_Thrust(player->mo, movepushangle, movepushforward); - else if (player->speed < topspeed && mbackward && cmd->forwardmove < 0) - P_Thrust(player->mo, movepushangle, movepushforward); - else if (mbackward && cmd->forwardmove > 0) - P_Thrust(player->mo, movepushangle, movepushforward); - else if (!mforward && !mbackward) - P_Thrust(player->mo, movepushangle, movepushforward); + +#ifdef ESLOPE + totalthrust.x += P_ReturnThrustX(player->mo, movepushangle, movepushforward); + totalthrust.y += P_ReturnThrustY(player->mo, movepushangle, movepushforward); #else P_Thrust(player->mo, movepushangle, movepushforward); #endif @@ -4666,33 +4758,12 @@ static void P_3dMovement(player_t *player) if (!(player->pflags & PF_GLIDING || player->exiting || P_PlayerInPain(player))) { angle_t controldirection; -#ifdef OLD_MOVEMENT_CODE - angle_t controlplayerdirection; - boolean cforward; // controls pointing forward from the player - boolean cbackward; // controls pointing backward from the player - angle_t dangle; - cforward = cbackward = false; -#endif // Calculate the angle at which the controls are pointing // to figure out the proper mforward and mbackward. // (Why was it so complicated before? ~Red) controldirection = R_PointToAngle2(0, 0, cmd->forwardmove*FRACUNIT, -cmd->sidemove*FRACUNIT)+movepushangle; -#ifdef OLD_MOVEMENT_CODE - controlplayerdirection = player->mo->angle; - - dangle = controldirection - controlplayerdirection; - - if (dangle > ANGLE_180) //flip to keep to one side - dangle = InvAngle(dangle); - - if (dangle > ANGLE_90) - cbackward = true; // Controls pointing backwards from player - else - cforward = true; // Controls pointing in player's general direction -#endif - movepushforward = max(abs(cmd->sidemove), abs(cmd->forwardmove)) * (thrustfactor * acceleration); // allow very small movement while in air for gameplay @@ -4715,13 +4786,10 @@ static void P_3dMovement(player_t *player) movepushsideangle = controldirection; movepushforward = FixedMul(movepushforward, player->mo->scale); -#ifdef OLD_MOVEMENT_CODE - if (player->speed < topspeed) - P_Thrust(player->mo, controldirection, movepushforward); - else if ((mforward) && (cbackward)) - P_Thrust(player->mo, controldirection, movepushforward); - else if ((mbackward) && (cforward)) - P_Thrust(player->mo, controldirection, movepushforward); + +#ifdef ESLOPE + totalthrust.x += P_ReturnThrustX(player->mo, controldirection, movepushforward); + totalthrust.y += P_ReturnThrustY(player->mo, controldirection, movepushforward); #else P_Thrust(player->mo, controldirection, movepushforward); #endif @@ -4729,29 +4797,6 @@ static void P_3dMovement(player_t *player) } else if (cmd->sidemove && !(player->pflags & PF_GLIDING) && !player->exiting && !P_PlayerInPain(player)) { -#ifdef OLD_MOVEMENT_CODE - boolean mright = 0; - boolean mleft = 0; - angle_t sideangle; - - sideangle = player->mo->angle - ANGLE_90; - - // Monster Iestyn - 04-11-13 - // Quadrants are stupid, excessive and broken, let's do this a much simpler way! - // Get delta angle from rmom angle and player angle first - dangle = R_PointToAngle2(0,0, player->rmomx, player->rmomy) - sideangle; - if (dangle > ANGLE_180) - dangle = InvAngle(dangle); - - // now use it to determine direction! - if (dangle <= ANGLE_45) // angles 0-45 or 315-360 - mright = 1; // going right - else if (dangle >= ANGLE_135) // angles 135-225 - mleft = 1; // going left - - // anything else will leave both at 0, so no need to do anything else -#endif - movepushside = cmd->sidemove * (thrustfactor * acceleration); if (!onground) @@ -4774,19 +4819,37 @@ static void P_3dMovement(player_t *player) // Finally move the player now that his speed/direction has been decided. movepushside = FixedMul(movepushside, player->mo->scale); -#ifdef OLD_MOVEMENT_CODE - if (player->speed < topspeed) - P_Thrust(player->mo, movepushsideangle, movepushside); - else if (mright && cmd->sidemove < 0) - P_Thrust(player->mo, movepushsideangle, movepushside); - else if (mleft && cmd->sidemove > 0) - P_Thrust(player->mo, movepushsideangle, movepushside); + +#ifdef ESLOPE + totalthrust.x += P_ReturnThrustX(player->mo, movepushsideangle, movepushside); + totalthrust.y += P_ReturnThrustY(player->mo, movepushsideangle, movepushside); #else P_Thrust(player->mo, movepushsideangle, movepushside); #endif } -#ifndef OLD_MOVEMENT_CODE +#ifdef ESLOPE + if ((totalthrust.x || totalthrust.y) + && player->mo->standingslope && abs(player->mo->standingslope->zdelta) > FRACUNIT/2) { + // Factor thrust to slope, but only for the part pushing up it! + // The rest is unaffected. + angle_t thrustangle = R_PointToAngle2(0, 0, totalthrust.x, totalthrust.y)-player->mo->standingslope->xydirection; + + if (player->mo->standingslope->zdelta < 0) { // Direction goes down, so thrustangle needs to face toward + if (thrustangle < ANGLE_90 || thrustangle > ANGLE_270) { + P_QuantizeMomentumToSlope(&totalthrust, player->mo->standingslope); + } + } else { // Direction goes up, so thrustangle needs to face away + if (thrustangle > ANGLE_90 && thrustangle < ANGLE_270) { + P_QuantizeMomentumToSlope(&totalthrust, player->mo->standingslope); + } + } + } + + player->mo->momx += totalthrust.x; + player->mo->momy += totalthrust.y; +#endif + // Time to ask three questions: // 1) Are we over topspeed? // 2) If "yes" to 1, were we moving over topspeed to begin with? @@ -4820,7 +4883,6 @@ static void P_3dMovement(player_t *player) player->mo->momy = tempmomy + player->cmomy; } } -#endif } // diff --git a/src/r_bsp.c b/src/r_bsp.c index fb25b8e4d..7d584a976 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -459,6 +459,11 @@ static void R_AddLine(seg_t *line) doorclosed = 0; // Closed door. +#ifdef ESLOPE + // Just don't bother checking this if one side is sloped. This is probably inefficient, but it's better than + // random renderer stopping around slopes... + if (!(frontsector->f_slope || frontsector->c_slope || backsector->f_slope || backsector->c_slope)) +#endif if (backsector->ceilingheight <= frontsector->floorheight || backsector->floorheight >= frontsector->ceilingheight) { @@ -487,6 +492,10 @@ static void R_AddLine(seg_t *line) #endif backsector->ceilingpic == frontsector->ceilingpic && backsector->floorpic == frontsector->floorpic +#ifdef ESLOPE + && backsector->f_slope == frontsector->f_slope + && backsector->c_slope == frontsector->c_slope +#endif && backsector->lightlevel == frontsector->lightlevel && !curline->sidedef->midtexture // Check offsets too! @@ -842,11 +851,19 @@ static void R_Subsector(size_t num) sub->sector->moved = frontsector->moved = false; } - light = R_GetPlaneLight(frontsector, frontsector->floorheight, false); + light = R_GetPlaneLight(frontsector, +#ifdef ESLOPE + frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) : +#endif + frontsector->floorheight, false); if (frontsector->floorlightsec == -1) floorlightlevel = *frontsector->lightlist[light].lightlevel; floorcolormap = frontsector->lightlist[light].extra_colormap; - light = R_GetPlaneLight(frontsector, frontsector->ceilingheight, false); + light = R_GetPlaneLight(frontsector, +#ifdef ESLOPE + frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) : +#endif + frontsector->ceilingheight, false); if (frontsector->ceilinglightsec == -1) ceilinglightlevel = *frontsector->lightlist[light].lightlevel; ceilingcolormap = frontsector->lightlist[light].extra_colormap; @@ -854,32 +871,52 @@ static void R_Subsector(size_t num) sub->sector->extra_colormap = frontsector->extra_colormap; - if ((frontsector->floorheight < viewz || (frontsector->heightsec != -1 + if ((( +#ifdef ESLOPE + frontsector->f_slope ? P_GetZAt(frontsector->f_slope, viewx, viewy) : +#endif + frontsector->floorheight) < viewz || (frontsector->heightsec != -1 && sectors[frontsector->heightsec].ceilingpic == skyflatnum))) { floorplane = R_FindPlane(frontsector->floorheight, frontsector->floorpic, floorlightlevel, - frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle, floorcolormap, NULL); + frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle, floorcolormap, NULL +#ifdef ESLOPE + , frontsector->f_slope +#endif + ); } else floorplane = NULL; - if ((frontsector->ceilingheight > viewz || frontsector->ceilingpic == skyflatnum + if ((( +#ifdef ESLOPE + frontsector->c_slope ? P_GetZAt(frontsector->c_slope, viewx, viewy) : +#endif + frontsector->ceilingheight) > viewz || frontsector->ceilingpic == skyflatnum || (frontsector->heightsec != -1 && sectors[frontsector->heightsec].floorpic == skyflatnum))) { ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic, ceilinglightlevel, frontsector->ceiling_xoffs, frontsector->ceiling_yoffs, frontsector->ceilingpic_angle, - ceilingcolormap, NULL); + ceilingcolormap, NULL +#ifdef ESLOPE + , frontsector->c_slope +#endif + ); } else ceilingplane = NULL; numffloors = 0; +#ifdef ESLOPE + ffloor[numffloors].slope = NULL; +#endif ffloor[numffloors].plane = NULL; ffloor[numffloors].polyobj = NULL; if (frontsector->ffloors) { ffloor_t *rover; + fixed_t heightcheck; for (rover = frontsector->ffloors; rover && numffloors < MAXFFLOORS; rover = rover->next) { @@ -897,18 +934,47 @@ static void R_Subsector(size_t num) ffloor[numffloors].plane = NULL; ffloor[numffloors].polyobj = NULL; + + heightcheck = +#ifdef ESLOPE + *rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) : +#endif + *rover->bottomheight; if (*rover->bottomheight <= frontsector->ceilingheight && *rover->bottomheight >= frontsector->floorheight - && ((viewz < *rover->bottomheight && !(rover->flags & FF_INVERTPLANES)) - || (viewz > *rover->bottomheight && (rover->flags & FF_BOTHPLANES)))) + && ((viewz < heightcheck && !(rover->flags & FF_INVERTPLANES)) + || (viewz > heightcheck && (rover->flags & FF_BOTHPLANES)))) { +#ifdef ESLOPE + light = R_GetPlaneLight(frontsector, + *rover->b_slope ? P_GetZAt(*rover->b_slope, frontsector->soundorg.x, frontsector->soundorg.y) : *rover->bottomheight, + viewz < heightcheck); +#else light = R_GetPlaneLight(frontsector, *rover->bottomheight, viewz < *rover->bottomheight); +#endif ffloor[numffloors].plane = R_FindPlane(*rover->bottomheight, *rover->bottompic, *frontsector->lightlist[light].lightlevel, *rover->bottomxoffs, - *rover->bottomyoffs, *rover->bottomangle, frontsector->lightlist[light].extra_colormap, rover); + *rover->bottomyoffs, *rover->bottomangle, frontsector->lightlist[light].extra_colormap, rover +#ifdef ESLOPE + , *rover->b_slope +#endif + ); + +#ifdef ESLOPE + ffloor[numffloors].slope = *rover->b_slope; + + // Tell the renderer this sector has slopes in it. + if (ffloor[numffloors].slope) + frontsector->hasslope = true; +#endif + + ffloor[numffloors].height = +#ifdef ESLOPE + *rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) : +#endif + *rover->bottomheight; - ffloor[numffloors].height = *rover->bottomheight; ffloor[numffloors].ffloor = rover; numffloors++; } @@ -916,16 +982,46 @@ static void R_Subsector(size_t num) break; ffloor[numffloors].plane = NULL; ffloor[numffloors].polyobj = NULL; + + heightcheck = +#ifdef ESLOPE + *rover->t_slope ? P_GetZAt(*rover->t_slope, viewx, viewy) : +#endif + *rover->topheight; if (*rover->topheight >= frontsector->floorheight && *rover->topheight <= frontsector->ceilingheight - && ((viewz > *rover->topheight && !(rover->flags & FF_INVERTPLANES)) - || (viewz < *rover->topheight && (rover->flags & FF_BOTHPLANES)))) + && ((viewz > heightcheck && !(rover->flags & FF_INVERTPLANES)) + || (viewz < heightcheck && (rover->flags & FF_BOTHPLANES)))) { +#ifdef ESLOPE + light = R_GetPlaneLight(frontsector, + *rover->t_slope ? P_GetZAt(*rover->t_slope, frontsector->soundorg.x, frontsector->soundorg.y) : *rover->topheight, + viewz < heightcheck); +#else light = R_GetPlaneLight(frontsector, *rover->topheight, viewz < *rover->topheight); +#endif ffloor[numffloors].plane = R_FindPlane(*rover->topheight, *rover->toppic, *frontsector->lightlist[light].lightlevel, *rover->topxoffs, *rover->topyoffs, *rover->topangle, - frontsector->lightlist[light].extra_colormap, rover); - ffloor[numffloors].height = *rover->topheight; + frontsector->lightlist[light].extra_colormap, rover +#ifdef ESLOPE + , *rover->t_slope +#endif + ); + +#ifdef ESLOPE + ffloor[numffloors].slope = *rover->t_slope; + + // Tell the renderer this sector has slopes in it. + if (ffloor[numffloors].slope) + frontsector->hasslope = true; +#endif + + ffloor[numffloors].height = +#ifdef ESLOPE + *rover->t_slope ? P_GetZAt(*rover->t_slope, viewx, viewy) : +#endif + *rover->topheight; + ffloor[numffloors].ffloor = rover; numffloors++; } @@ -977,11 +1073,18 @@ static void R_Subsector(size_t num) polysec->lightlevel, xoff, yoff, polysec->floorpic_angle-po->angle, NULL, - NULL); + NULL +#ifdef ESLOPE + , NULL // will ffloors be slopable eventually? +#endif + ); //ffloor[numffloors].plane->polyobj = po; ffloor[numffloors].height = polysec->floorheight; ffloor[numffloors].polyobj = po; +#ifdef ESLOPE + ffloor[numffloors].slope = NULL; +#endif // ffloor[numffloors].ffloor = rover; po->visplane = ffloor[numffloors].plane; numffloors++; @@ -1014,11 +1117,18 @@ static void R_Subsector(size_t num) light = 0; ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic, polysec->lightlevel, xoff, yoff, polysec->ceilingpic_angle-po->angle, - NULL, NULL); + NULL, NULL +#ifdef ESLOPE + , NULL // will ffloors be slopable eventually? +#endif + ); //ffloor[numffloors].plane->polyobj = po; ffloor[numffloors].polyobj = po; ffloor[numffloors].height = polysec->ceilingheight; +#ifdef ESLOPE + ffloor[numffloors].slope = NULL; +#endif // ffloor[numffloors].ffloor = rover; po->visplane = ffloor[numffloors].plane; numffloors++; @@ -1077,6 +1187,11 @@ void R_Prep3DFloors(sector_t *sector) fixed_t bestheight, maxheight; INT32 count, i, mapnum; sector_t *sec; +#ifdef ESLOPE + pslope_t *bestslope; + fixed_t heighttest; // I think it's better to check the Z height at the sector's center + // than assume unsloped heights are accurate indicators of order in sloped sectors. -Red +#endif count = 1; for (rover = sector->ffloors; rover; rover = rover->next) @@ -1099,7 +1214,14 @@ void R_Prep3DFloors(sector_t *sector) else memset(sector->lightlist, 0, sizeof (lightlist_t) * count); +#ifdef ESLOPE + heighttest = sector->c_slope ? P_GetZAt(sector->c_slope, sector->soundorg.x, sector->soundorg.y) : sector->ceilingheight; + + sector->lightlist[0].height = heighttest + 1; + sector->lightlist[0].slope = sector->c_slope; +#else sector->lightlist[0].height = sector->ceilingheight + 1; +#endif sector->lightlist[0].lightlevel = §or->lightlevel; sector->lightlist[0].caster = NULL; sector->lightlist[0].extra_colormap = sector->extra_colormap; @@ -1117,6 +1239,29 @@ void R_Prep3DFloors(sector_t *sector) && !(rover->flags & FF_CUTLEVEL) && !(rover->flags & FF_CUTSPRITES))) continue; +#ifdef ESLOPE + heighttest = *rover->t_slope ? P_GetZAt(*rover->t_slope, sector->soundorg.x, sector->soundorg.y) : *rover->topheight; + + if (heighttest > bestheight && heighttest < maxheight) + { + best = rover; + bestheight = heighttest; + bestslope = *rover->t_slope; + continue; + } + if (rover->flags & FF_DOUBLESHADOW) { + heighttest = *rover->b_slope ? P_GetZAt(*rover->b_slope, sector->soundorg.x, sector->soundorg.y) : *rover->bottomheight; + + if (heighttest > bestheight + && heighttest < maxheight) + { + best = rover; + bestheight = heighttest; + bestslope = *rover->b_slope; + continue; + } + } +#else if (*rover->topheight > bestheight && *rover->topheight < maxheight) { best = rover; @@ -1130,6 +1275,7 @@ void R_Prep3DFloors(sector_t *sector) bestheight = *rover->bottomheight; continue; } +#endif } if (!best) { @@ -1140,6 +1286,9 @@ void R_Prep3DFloors(sector_t *sector) sector->lightlist[i].height = maxheight = bestheight; sector->lightlist[i].caster = best; sector->lightlist[i].flags = best->flags; +#ifdef ESLOPE + sector->lightlist[i].slope = bestslope; +#endif sec = §ors[best->secnum]; mapnum = sec->midmap; if (mapnum >= 0 && (size_t)mapnum < num_extra_colormaps) @@ -1165,7 +1314,12 @@ void R_Prep3DFloors(sector_t *sector) if (best->flags & FF_DOUBLESHADOW) { +#ifdef ESLOPE + heighttest = *best->b_slope ? P_GetZAt(*best->b_slope, sector->soundorg.x, sector->soundorg.y) : *best->bottomheight; + if (bestheight == heighttest) ///TODO: do this in a more efficient way -Red +#else if (bestheight == *best->bottomheight) +#endif { sector->lightlist[i].lightlevel = sector->lightlist[best->lastlight].lightlevel; sector->lightlist[i].extra_colormap = diff --git a/src/r_defs.h b/src/r_defs.h index 7f8bd7e1d..f18410fe8 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -155,6 +155,12 @@ typedef struct ffloor_s fixed_t *bottomyoffs; angle_t *bottomangle; +#ifdef ESLOPE + // Pointers to pointers. Yup. + struct pslope_s **t_slope; + struct pslope_s **b_slope; +#endif + size_t secnum; ffloortype_e flags; struct line_s *master; @@ -184,6 +190,9 @@ typedef struct lightlist_s extracolormap_t *extra_colormap; INT32 flags; ffloor_t *caster; +#ifdef ESLOPE + struct pslope_s *slope; // FF_DOUBLESHADOW makes me have to store this pointer here. Bluh bluh. +#endif } lightlist_t; @@ -224,6 +233,52 @@ typedef struct secplane_t fixed_t a, b, c, d, ic; } secplane_t; +// Slopes +#ifdef ESLOPE +typedef enum { + SL_NOPHYSICS = 1, // Don't do momentum adjustment with this slope + SL_NODYNAMIC = 1<<1, // Slope will never need to move during the level, so don't fuss with recalculating it + SL_ANCHORVERTEX = 1<<2, // Slope is using a Slope Vertex Thing to anchor its position + SL_VERTEXSLOPE = 1<<3, // Slope is built from three Slope Vertex Things +} slopeflags_t; + +typedef struct pslope_s +{ + UINT16 id; // The number of the slope, mostly used for netgame syncing purposes + + // --- Information used in clipping/projection --- + // Origin vector for the plane + vector3_t o; + + // 2-Dimentional vector (x, y) normalized. Used to determine distance from + // the origin in 2d mapspace. (Basically a thrust of FRACUNIT in xydirection angle) + vector2_t d; + + // The rate at which z changes based on distance from the origin plane. + fixed_t zdelta; + + // The normal of the slope; will always point upward, and thus be inverted on ceilings. I think it's only needed for physics? -Red + vector3_t normal; + + // For comparing when a slope should be rendered + fixed_t lowz; + fixed_t highz; + + // This values only check and must be updated if the slope itself is modified + angle_t 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.) + + struct line_s *sourceline; // The line that generated the slope + fixed_t extent; // Distance value used for recalculating zdelta + UINT8 refpos; // 1=front floor 2=front ceiling 3=back floor 4=back ceiling (used for dynamic sloping) + + UINT8 flags; // Slope options + mapthing_t **vertices; // List should be three long for slopes made by vertex things, or one long for slopes using one vertex thing to anchor + + struct pslope_s *next; // Make a linked list of dynamic slopes, for easy reference later +} pslope_t; +#endif + typedef enum { SF_FLIPSPECIAL_FLOOR = 1, @@ -337,6 +392,13 @@ 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 + boolean hasslope; // The sector, or one of its visible FOFs, contains a slope +#endif + // these are saved for netgames, so do not let Lua touch these! // offsets sector spawned with (via linedef type 7) @@ -612,6 +674,12 @@ typedef struct drawseg_s INT16 *thicksidecol; INT32 numthicksides; fixed_t frontscale[MAXVIDWIDTH]; + +#ifdef ESLOPE + fixed_t maskedtextureheight[MAXVIDWIDTH]; // For handling sloped midtextures + + vertex_t leftpos, rightpos; // Used for rendering FOF walls with slopes +#endif } drawseg_t; typedef enum diff --git a/src/r_draw.c b/src/r_draw.c index cd219c15f..766e0428e 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -103,6 +103,12 @@ fixed_t ds_xfrac, ds_yfrac, ds_xstep, ds_ystep; UINT8 *ds_source; // start of a 64*64 tile image UINT8 *ds_transmap; // one of the translucency tables +#ifdef ESLOPE +pslope_t *ds_slope; // Current slope being used +floatv3_t ds_su, ds_sv, ds_sz; // Vectors for... stuff? +float focallengthf, zeroheight; +#endif + /** \brief Variable flat sizes */ diff --git a/src/r_draw.h b/src/r_draw.h index 061a271b1..63fecc046 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -60,6 +60,16 @@ extern fixed_t ds_xfrac, ds_yfrac, ds_xstep, ds_ystep; extern UINT8 *ds_source; // start of a 64*64 tile image extern UINT8 *ds_transmap; +#ifdef ESLOPE +typedef struct { + float x, y, z; +} floatv3_t; + +pslope_t *ds_slope; // Current slope being used +floatv3_t ds_su, ds_sv, ds_sz; // Vectors for... stuff? +float focallengthf, zeroheight; +#endif + // Variable flat sizes extern UINT32 nflatxshift; extern UINT32 nflatyshift; @@ -141,6 +151,11 @@ void ASMCALL R_DrawSpan_8_MMX(void); void R_DrawTranslatedColumn_8(void); void R_DrawTranslatedTranslucentColumn_8(void); void R_DrawSpan_8(void); +#ifdef ESLOPE +void R_DrawTiltedSpan_8(void); +void R_DrawTiltedTranslucentSpan_8(void); +void R_DrawTiltedSplat_8(void); +#endif void R_DrawSplat_8(void); void R_DrawTranslucentSplat_8(void); void R_DrawTranslucentSpan_8(void); diff --git a/src/r_draw8.c b/src/r_draw8.c index e0264ba92..f78f1494b 100644 --- a/src/r_draw8.c +++ b/src/r_draw8.c @@ -526,6 +526,436 @@ void R_DrawSpan_8 (void) } } +#ifdef ESLOPE +// R_CalcTiltedLighting +// Exactly what it says on the tin. I wish I wasn't too lazy to explain things properly. +static size_t tiltlighting[MAXVIDWIDTH]; +void R_CalcTiltedLighting(fixed_t start, fixed_t end) +{ + // ZDoom uses a different lighting setup to us, and I couldn't figure out how to adapt their version + // of this function. Here's my own. + INT32 left = ds_x1, right = ds_x2; + fixed_t step = (end-start)/(ds_x2-ds_x1+1); + size_t i; + + // I wanna do some optimizing by checking for out-of-range segments on either side to fill in all at once, + // but I'm too bad at coding to not crash the game trying to do that. I guess this is fast enough for now... + + for (i = left; i <= right; i++) { + tiltlighting[i] = (start += step) >> FRACBITS; + if (tiltlighting[i] < 0) + tiltlighting[i] = 0; + else if (tiltlighting[i] >= MAXLIGHTSCALE) + tiltlighting[i] = MAXLIGHTSCALE-1; + } +} + + +/** \brief The R_DrawTiltedSpan_8 function + Draw slopes! Holy sheit! +*/ +void R_DrawTiltedSpan_8(void) +{ + // x1, x2 = ds_x1, ds_x2 + int width = ds_x2 - ds_x1; + double iz, uz, vz; + UINT32 u, v; + int i; + + UINT8 *source; + UINT8 *colormap; + UINT8 *dest; + + iz = ds_sz.z + ds_sz.y*(centery-ds_y) + ds_sz.x*(ds_x1-centerx); + + // Lighting is simple. It's just linear interpolation from start to end + { + float planelightfloat = BASEVIDWIDTH*BASEVIDWIDTH/vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f; + float lightstart, lightend; + + lightend = (iz + ds_sz.x*width) * planelightfloat; + lightstart = iz * planelightfloat; + + R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend)); + //CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf); + } + + uz = ds_su.z + ds_su.y*(centery-ds_y) + ds_su.x*(ds_x1-centerx); + vz = ds_sv.z + ds_sv.y*(centery-ds_y) + ds_sv.x*(ds_x1-centerx); + + dest = ylookup[ds_y] + columnofs[ds_x1]; + source = ds_source; + //colormap = ds_colormap; + +#if 0 // The "perfect" reference version of this routine. Pretty slow. + // Use it only to see how things are supposed to look. + i = 0; + do + { + double z = 1.f/iz; + u = (INT64)(uz*z) + viewx; + v = (INT64)(vz*z) + viewy; + + colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); + + *dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]]; + dest++; + iz += ds_sz.x; + uz += ds_su.x; + vz += ds_sv.x; + } while (--width >= 0); +#else +#define SPANSIZE 16 +#define INVSPAN 0.0625f + + double startz = 1.f/iz; + double startu = uz*startz; + double startv = vz*startz; + double izstep, uzstep, vzstep; + + izstep = ds_sz.x * SPANSIZE; + uzstep = ds_su.x * SPANSIZE; + vzstep = ds_sv.x * SPANSIZE; + //x1 = 0; + width++; + + while (width >= SPANSIZE) + { + iz += izstep; + uz += uzstep; + vz += vzstep; + + double endz = 1.f/iz; + double endu = uz*endz; + double endv = vz*endz; + UINT32 stepu = (INT64)((endu - startu) * INVSPAN); + UINT32 stepv = (INT64)((endv - startv) * INVSPAN); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (i = SPANSIZE-1; i >= 0; i--) + { + colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); + *dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]]; + dest++; + u += stepu; + v += stepv; + } + startu = endu; + startv = endv; + width -= SPANSIZE; + } + if (width > 0) + { + if (width == 1) + { + u = (INT64)(startu); + v = (INT64)(startv); + colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); + *dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]]; + } + else + { + double left = width; + iz += ds_sz.x * left; + uz += ds_su.x * left; + vz += ds_sv.x * left; + + double endz = 1.f/iz; + double endu = uz*endz; + double endv = vz*endz; + left = 1.f/left; + UINT32 stepu = (INT64)((endu - startu) * left); + UINT32 stepv = (INT64)((endv - startv) * left); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (; width != 0; width--) + { + colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); + *dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]]; + dest++; + u += stepu; + v += stepv; + } + } + } +#endif +} + + +/** \brief The R_DrawTiltedTranslucentSpan_8 function + Like DrawTiltedSpan, but translucent +*/ +void R_DrawTiltedTranslucentSpan_8(void) +{ + // x1, x2 = ds_x1, ds_x2 + int width = ds_x2 - ds_x1; + double iz, uz, vz; + UINT32 u, v; + int i; + + UINT8 *source; + UINT8 *colormap; + UINT8 *dest; + + iz = ds_sz.z + ds_sz.y*(centery-ds_y) + ds_sz.x*(ds_x1-centerx); + + // Lighting is simple. It's just linear interpolation from start to end + { + float planelightfloat = BASEVIDWIDTH*BASEVIDWIDTH/vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f; + float lightstart, lightend; + + lightend = (iz + ds_sz.x*width) * planelightfloat; + lightstart = iz * planelightfloat; + + R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend)); + //CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf); + } + + uz = ds_su.z + ds_su.y*(centery-ds_y) + ds_su.x*(ds_x1-centerx); + vz = ds_sv.z + ds_sv.y*(centery-ds_y) + ds_sv.x*(ds_x1-centerx); + + dest = ylookup[ds_y] + columnofs[ds_x1]; + source = ds_source; + //colormap = ds_colormap; + +#if 0 // The "perfect" reference version of this routine. Pretty slow. + // Use it only to see how things are supposed to look. + i = 0; + do + { + double z = 1.f/iz; + u = (INT64)(uz*z) + viewx; + v = (INT64)(vz*z) + viewy; + + colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); + + *dest = colormap[*(ds_transmap + (source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)] << 8) + dest[0])]; + dest++; + iz += ds_sz.x; + uz += ds_su.x; + vz += ds_sv.x; + } while (--width >= 0); +#else +#define SPANSIZE 16 +#define INVSPAN 0.0625f + + double startz = 1.f/iz; + double startu = uz*startz; + double startv = vz*startz; + double izstep, uzstep, vzstep; + + izstep = ds_sz.x * SPANSIZE; + uzstep = ds_su.x * SPANSIZE; + vzstep = ds_sv.x * SPANSIZE; + //x1 = 0; + width++; + + while (width >= SPANSIZE) + { + iz += izstep; + uz += uzstep; + vz += vzstep; + + double endz = 1.f/iz; + double endu = uz*endz; + double endv = vz*endz; + UINT32 stepu = (INT64)((endu - startu) * INVSPAN); + UINT32 stepv = (INT64)((endv - startv) * INVSPAN); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (i = SPANSIZE-1; i >= 0; i--) + { + colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); + *dest = colormap[*(ds_transmap + (source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)] << 8) + dest[0])]; + dest++; + u += stepu; + v += stepv; + } + startu = endu; + startv = endv; + width -= SPANSIZE; + } + if (width > 0) + { + if (width == 1) + { + u = (INT64)(startu); + v = (INT64)(startv); + colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); + *dest = colormap[*(ds_transmap + (source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)] << 8) + dest[0])]; + } + else + { + double left = width; + iz += ds_sz.x * left; + uz += ds_su.x * left; + vz += ds_sv.x * left; + + double endz = 1.f/iz; + double endu = uz*endz; + double endv = vz*endz; + left = 1.f/left; + UINT32 stepu = (INT64)((endu - startu) * left); + UINT32 stepv = (INT64)((endv - startv) * left); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (; width != 0; width--) + { + colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); + *dest = colormap[*(ds_transmap + (source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)] << 8) + dest[0])]; + dest++; + u += stepu; + v += stepv; + } + } + } +#endif +} + +void R_DrawTiltedSplat_8(void) +{ + // x1, x2 = ds_x1, ds_x2 + int width = ds_x2 - ds_x1; + double iz, uz, vz; + UINT32 u, v; + int i; + + UINT8 *source; + UINT8 *colormap; + UINT8 *dest; + + UINT8 val; + + iz = ds_sz.z + ds_sz.y*(centery-ds_y) + ds_sz.x*(ds_x1-centerx); + + // Lighting is simple. It's just linear interpolation from start to end + { + float planelightfloat = BASEVIDWIDTH*BASEVIDWIDTH/vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f; + float lightstart, lightend; + + lightend = (iz + ds_sz.x*width) * planelightfloat; + lightstart = iz * planelightfloat; + + R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend)); + //CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf); + } + + uz = ds_su.z + ds_su.y*(centery-ds_y) + ds_su.x*(ds_x1-centerx); + vz = ds_sv.z + ds_sv.y*(centery-ds_y) + ds_sv.x*(ds_x1-centerx); + + dest = ylookup[ds_y] + columnofs[ds_x1]; + source = ds_source; + //colormap = ds_colormap; + +#if 0 // The "perfect" reference version of this routine. Pretty slow. + // Use it only to see how things are supposed to look. + i = 0; + do + { + double z = 1.f/iz; + u = (INT64)(uz*z) + viewx; + v = (INT64)(vz*z) + viewy; + + colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); + + val = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]]; + if (val != TRANSPARENTPIXEL) + *dest = val; + dest++; + iz += ds_sz.x; + uz += ds_su.x; + vz += ds_sv.x; + } while (--width >= 0); +#else +#define SPANSIZE 16 +#define INVSPAN 0.0625f + + double startz = 1.f/iz; + double startu = uz*startz; + double startv = vz*startz; + double izstep, uzstep, vzstep; + + izstep = ds_sz.x * SPANSIZE; + uzstep = ds_su.x * SPANSIZE; + vzstep = ds_sv.x * SPANSIZE; + //x1 = 0; + width++; + + while (width >= SPANSIZE) + { + iz += izstep; + uz += uzstep; + vz += vzstep; + + double endz = 1.f/iz; + double endu = uz*endz; + double endv = vz*endz; + UINT32 stepu = (INT64)((endu - startu) * INVSPAN); + UINT32 stepv = (INT64)((endv - startv) * INVSPAN); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (i = SPANSIZE-1; i >= 0; i--) + { + colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); + val = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]]; + if (val != TRANSPARENTPIXEL) + *dest = val; + dest++; + u += stepu; + v += stepv; + } + startu = endu; + startv = endv; + width -= SPANSIZE; + } + if (width > 0) + { + if (width == 1) + { + u = (INT64)(startu); + v = (INT64)(startv); + colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); + val = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]]; + if (val != TRANSPARENTPIXEL) + *dest = val; + } + else + { + double left = width; + iz += ds_sz.x * left; + uz += ds_su.x * left; + vz += ds_sv.x * left; + + double endz = 1.f/iz; + double endu = uz*endz; + double endv = vz*endz; + left = 1.f/left; + UINT32 stepu = (INT64)((endu - startu) * left); + UINT32 stepv = (INT64)((endv - startv) * left); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (; width != 0; width--) + { + colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); + val = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]]; + if (val != TRANSPARENTPIXEL) + *dest = val; + dest++; + u += stepu; + v += stepv; + } + } + } +#endif +} +#endif // ESLOPE + /** \brief The R_DrawSplat_8 function Just like R_DrawSpan_8, but skips transparent pixels. */ diff --git a/src/r_main.c b/src/r_main.c index 19a6b5cba..1170b3414 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -527,6 +527,8 @@ static void R_InitTextureMapping(void) focallength = FixedDiv(centerxfrac, FINETANGENT(FINEANGLES/4+/*cv_fov.value*/ FIELDOFVIEW/2)); + focallengthf = FIXED_TO_FLOAT(focallength); + for (i = 0; i < FINEANGLES/2; i++) { if (FINETANGENT(i) > FRACUNIT*2) diff --git a/src/r_plane.c b/src/r_plane.c index dcff25c13..406a38d7b 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -74,7 +74,7 @@ static INT32 spanstart[MAXVIDHEIGHT]; // // texture mapping // -static lighttable_t **planezlight; +lighttable_t **planezlight; static fixed_t planeheight; //added : 10-02-98: yslopetab is what yslope used to be, @@ -327,6 +327,11 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2) if (pindex >= MAXLIGHTZ) pindex = MAXLIGHTZ - 1; +#ifdef ESLOPE + if (currentplane->slope) + ds_colormap = colormaps; + else +#endif ds_colormap = planezlight[pindex]; if (currentplane->extra_colormap) @@ -423,11 +428,18 @@ static visplane_t *new_visplane(unsigned hash) // visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, fixed_t xoff, fixed_t yoff, angle_t plangle, extracolormap_t *planecolormap, - ffloor_t *pfloor) + ffloor_t *pfloor +#ifdef ESLOPE + , pslope_t *slope +#endif + ) { visplane_t *check; unsigned hash; +#ifdef ESLOPE + if (slope); else // Don't mess with this right now if a slope is involved +#endif if (plangle != 0) { // Add the view offset, rotated by the plane angle. @@ -462,7 +474,11 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, && xoff == check->xoffs && yoff == check->yoffs && planecolormap == check->extra_colormap && !pfloor && !check->ffloor && check->viewz == viewz - && check->viewangle == viewangle) + && check->viewangle == viewangle +#ifdef ESLOPE + && check->slope == slope +#endif + ) { return check; } @@ -485,6 +501,9 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, #ifdef POLYOBJECTS_PLANES check->polyobj = NULL; #endif +#ifdef ESLOPE + check->slope = slope; +#endif memset(check->top, 0xff, sizeof (check->top)); memset(check->bottom, 0x00, sizeof (check->bottom)); @@ -551,6 +570,9 @@ visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop) new_pl->plangle = pl->plangle; #ifdef POLYOBJECTS_PLANES new_pl->polyobj = pl->polyobj; +#endif +#ifdef ESLOPE + new_pl->slope = pl->slope; #endif pl = new_pl; pl->minx = start; @@ -814,7 +836,11 @@ void R_DrawSinglePlane(visplane_t *pl) else light = (pl->lightlevel >> LIGHTSEGSHIFT); #ifndef NOWATER - if (pl->ffloor->flags & FF_RIPPLE) + if (pl->ffloor->flags & FF_RIPPLE +#ifdef ESLOPE + && !pl->slope +#endif + ) { INT32 top, bottom; @@ -842,6 +868,9 @@ void R_DrawSinglePlane(visplane_t *pl) } else light = (pl->lightlevel >> LIGHTSEGSHIFT); +#ifdef ESLOPE + if (!pl->slope) // Don't mess with angle on slopes! We'll handle this ourselves later +#endif if (viewangle != pl->viewangle) { memset(cachedheight, 0, sizeof (cachedheight)); @@ -915,6 +944,99 @@ void R_DrawSinglePlane(visplane_t *pl) if (light < 0) light = 0; +#ifdef ESLOPE + if (pl->slope) { + // Potentially override other stuff for now cus we're mean. :< But draw a slope plane! + // I copied ZDoom's code and adapted it to SRB2... -Red + floatv3_t p, m, n; + float ang; + float vx, vy, vz; + float fudge; + + xoffs &= ((1 << (32-nflatshiftup))-1); + yoffs &= ((1 << (32-nflatshiftup))-1); + + xoffs -= (pl->slope->o.x + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1); + yoffs += (pl->slope->o.y + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1); + + // Okay, look, don't ask me why this works, but without this setup there's a disgusting-looking misalignment with the textures. -Red + fudge = ((1<slope, viewx, viewy)); + +#define ANG2RAD(angle) ((float)((angle)*M_PI)/ANGLE_180) + + // p is the texture origin in view space + // Don't add in the offsets at this stage, because doing so can result in + // errors if the flat is rotated. + ang = ANG2RAD(ANGLE_270 - viewangle); + p.x = vx * cos(ang) - vy * sin(ang); + p.z = vx * sin(ang) + vy * cos(ang); + p.y = FIXED_TO_FLOAT(P_GetZAt(pl->slope, -xoffs, yoffs)) - vz; + + // m is the v direction vector in view space + ang = ANG2RAD(ANGLE_180 - viewangle - pl->plangle); + m.x = cos(ang); + m.z = sin(ang); + + // n is the u direction vector in view space + n.x = sin(ang); + n.z = -cos(ang); + + ang = ANG2RAD(pl->plangle); + m.y = FIXED_TO_FLOAT(P_GetZAt(pl->slope, viewx + FLOAT_TO_FIXED(sin(ang)), viewy + FLOAT_TO_FIXED(cos(ang)))) - zeroheight; + n.y = FIXED_TO_FLOAT(P_GetZAt(pl->slope, viewx + FLOAT_TO_FIXED(cos(ang)), viewy - FLOAT_TO_FIXED(sin(ang)))) - zeroheight; + + m.x /= fudge; + m.y /= fudge; + m.z /= fudge; + + n.x *= fudge; + n.y *= fudge; + n.z *= fudge; + + // Eh. I tried making this stuff fixed-point and it exploded on me. Here's a macro for the only floating-point vector function I recall using. +#define CROSS(d, v1, v2) \ + d.x = (v1.y * v2.z) - (v1.z * v2.y);\ + d.y = (v1.z * v2.x) - (v1.x * v2.z);\ + d.z = (v1.x * v2.y) - (v1.y * v2.x) + CROSS(ds_su, p, m); + CROSS(ds_sv, p, n); + CROSS(ds_sz, m, n); +#undef CROSS + + ds_su.z *= focallengthf; + ds_sv.z *= focallengthf; + ds_sz.z *= focallengthf; + + // Premultiply the texture vectors with the scale factors +#define SFMULT 65536.f*(1<scale1 + (x1 - ds->x1)*rw_scalestep; } + +#ifndef ESLOPE if (curline->linedef->flags & ML_DONTPEGBOTTOM) { dc_texturemid = front->floorheight > back->floorheight @@ -492,12 +502,21 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) dc_texturemid += (textureheight[texnum])*times; else dc_texturemid -= (textureheight[texnum])*times; +#endif dc_texheight = textureheight[texnum]>>FRACBITS; // draw the columns for (dc_x = x1; dc_x <= x2; dc_x++) { +#ifdef ESLOPE + dc_texturemid = ds->maskedtextureheight[dc_x]; + + if (!!(curline->linedef->flags & ML_DONTPEGBOTTOM) ^ !!(curline->linedef->flags & ML_EFFECT3)) + dc_texturemid += (textureheight[texnum])*times + textureheight[texnum]; + else + dc_texturemid -= (textureheight[texnum])*times; +#endif // calculate lighting if (maskedtexturecol[dc_x] != INT16_MAX) { @@ -679,6 +698,10 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) r_lightlist_t *rlight; fixed_t lheight; line_t *newline = NULL; +#ifdef ESLOPE + // Render FOF sides kinda like normal sides, with the frac and step and everything + fixed_t top_frac, top_step, bottom_frac, bottom_step; +#endif void (*colfunc_2s) (column_t *); @@ -853,6 +876,34 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) column2s_length = textures[texnum]->height; } +#ifdef ESLOPE + // Set heights according to plane, or slope, whichever + { + fixed_t left_top, right_top, left_bottom, right_bottom; + + left_top = *pfloor->t_slope ? P_GetZAt(*pfloor->t_slope, ds->leftpos.x, ds->leftpos.y) : *pfloor->topheight; + right_top = *pfloor->t_slope ? P_GetZAt(*pfloor->t_slope, ds->rightpos.x, ds->rightpos.y) : *pfloor->topheight; + left_bottom = *pfloor->b_slope ? P_GetZAt(*pfloor->b_slope, ds->leftpos.x, ds->leftpos.y) : *pfloor->bottomheight; + right_bottom = *pfloor->b_slope ? P_GetZAt(*pfloor->b_slope, ds->rightpos.x, ds->rightpos.y) : *pfloor->bottomheight; + + left_top -= viewz; + right_top -= viewz; + left_bottom -= viewz; + right_bottom -= viewz; + + top_frac = centeryfrac - FixedMul(left_top, ds->scale1); + bottom_frac = centeryfrac - FixedMul(left_bottom, ds->scale1); + top_step = centeryfrac - FixedMul(right_top, ds->scale2); + bottom_step = centeryfrac - FixedMul(right_bottom, ds->scale2); + + top_step = (top_step-top_frac)/(ds->x2-ds->x1+1); + bottom_step = (bottom_step-bottom_frac)/(ds->x2-ds->x1+1); + + top_frac += top_step * (x1 - ds->x1); + bottom_frac += bottom_step * (x1 - ds->x1); + } +#endif + // draw the columns for (dc_x = x1; dc_x <= x2; dc_x++) { @@ -868,8 +919,16 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) INT32 solid = 0; INT32 lighteffect = 0; +#ifdef ESLOPE + sprtopscreen = windowtop = top_frac; + sprbotscreen = windowbottom = bottom_frac; + + top_frac += top_step; + bottom_frac += bottom_step; +#else sprtopscreen = windowtop = (centeryfrac - FixedMul((dc_texturemid - offsetvalue), spryscale)); sprbotscreen = windowbottom = FixedMul(*pfloor->topheight - *pfloor->bottomheight, spryscale) + sprtopscreen; +#endif // SoM: If column is out of range, why bother with it?? if (windowbottom < topbounds || windowtop > bottombounds) @@ -1011,11 +1070,24 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) || ((signed)dc_texturemid < 0 && (spryscale) && (signed)(dc_texturemid)>>FRACBITS < (INT32_MIN / spryscale))) { spryscale += rw_scalestep; +#ifdef ESLOPE + top_frac += top_step; + bottom_frac += bottom_step; +#endif continue; } +#ifdef ESLOPE + sprtopscreen = windowtop = top_frac; + sprbotscreen = windowbottom = bottom_frac; + + top_frac += top_step; + bottom_frac += bottom_step; +#else sprtopscreen = windowtop = (centeryfrac - FixedMul((dc_texturemid - offsetvalue), spryscale)); sprbotscreen = windowbottom = FixedMul(*pfloor->topheight - *pfloor->bottomheight, spryscale) + sprtopscreen; +#endif + dc_iscale = 0xffffffffu / (unsigned)spryscale; // draw the texture @@ -1061,6 +1133,7 @@ static void R_RenderSegLoop (void) INT32 mid; fixed_t texturecolumn = 0; + fixed_t oldtexturecolumn = -1; INT32 top; INT32 bottom; INT32 i; @@ -1197,6 +1270,17 @@ static void R_RenderSegLoop (void) // calculate texture offset angle = (rw_centerangle + xtoviewangle[rw_x])>>ANGLETOFINESHIFT; texturecolumn = rw_offset-FixedMul(FINETANGENT(angle),rw_distance); + +#ifdef ESLOPE + if (oldtexturecolumn != -1) { + rw_bottomtexturemid += FixedMul(rw_bottomtextureslide, oldtexturecolumn-texturecolumn); + rw_midtexturemid += FixedMul(rw_midtextureslide, oldtexturecolumn-texturecolumn); + rw_toptexturemid += FixedMul(rw_toptextureslide, oldtexturecolumn-texturecolumn); + rw_midtextureback += FixedMul(rw_midtexturebackslide, oldtexturecolumn-texturecolumn); + } + oldtexturecolumn = texturecolumn; +#endif + texturecolumn >>= FRACBITS; // texturecolumn and lighting are independent of wall tiers @@ -1345,6 +1429,14 @@ static void R_RenderSegLoop (void) // save texturecol // for backdrawing of masked mid texture maskedtexturecol[rw_x] = (INT16)texturecolumn; + +#ifdef ESLOPE + if (maskedtextureheight != NULL) { + maskedtextureheight[rw_x] = (!!(curline->linedef->flags & ML_DONTPEGBOTTOM) ^ !!(curline->linedef->flags & ML_EFFECT3) ? + max(rw_midtexturemid, rw_midtextureback) : + min(rw_midtexturemid, rw_midtextureback)); + } +#endif } if (dc_numlights) @@ -1402,8 +1494,14 @@ void R_StoreWallRange(INT32 start, INT32 stop) INT32 i, p; lightlist_t *light; r_lightlist_t *rlight; +#ifdef ESLOPE + vertex_t segleft, segright; + fixed_t ceilingfrontslide, floorfrontslide, ceilingbackslide, floorbackslide; +#endif static size_t maxdrawsegs = 0; + maskedtextureheight = NULL; + if (ds_p == drawsegs+maxdrawsegs) { size_t pos = ds_p - drawsegs; @@ -1502,8 +1600,80 @@ void R_StoreWallRange(INT32 start, INT32 stop) // calculate texture boundaries // and decide if floor / ceiling marks are needed - worldtop = frontsector->ceilingheight - viewz; - worldbottom = frontsector->floorheight - viewz; +#ifdef ESLOPE + // Figure out map coordinates of where start and end are mapping to on seg, so we can clip right for slope bullshit + if (frontsector->hasslope || (backsector && backsector->hasslope)) // Commenting this out for FOFslop. -Red + { + angle_t temp; + + // left + temp = xtoviewangle[start]+viewangle; + + { + // Both lines can be written in slope-intercept form, so figure out line intersection + float a1, b1, c1, a2, b2, c2, det; // 1 is the seg, 2 is the view angle vector... + ///TODO: convert to FPU + + a1 = FIXED_TO_FLOAT(curline->v2->y-curline->v1->y); + b1 = FIXED_TO_FLOAT(curline->v1->x-curline->v2->x); + c1 = a1*FIXED_TO_FLOAT(curline->v1->x) + b1*FIXED_TO_FLOAT(curline->v1->y); + + a2 = -FIXED_TO_FLOAT(FINESINE(temp>>ANGLETOFINESHIFT)); + b2 = FIXED_TO_FLOAT(FINECOSINE(temp>>ANGLETOFINESHIFT)); + c2 = a2*FIXED_TO_FLOAT(viewx) + b2*FIXED_TO_FLOAT(viewy); + + det = a1*b2 - a2*b1; + + ds_p->leftpos.x = segleft.x = FLOAT_TO_FIXED((b2*c1 - b1*c2)/det); + ds_p->leftpos.y = segleft.y = FLOAT_TO_FIXED((a1*c2 - a2*c1)/det); + } + + // right + temp = xtoviewangle[stop]+viewangle; + + { + // Both lines can be written in slope-intercept form, so figure out line intersection + float a1, b1, c1, a2, b2, c2, det; // 1 is the seg, 2 is the view angle vector... + ///TODO: convert to FPU + + a1 = FIXED_TO_FLOAT(curline->v2->y-curline->v1->y); + b1 = FIXED_TO_FLOAT(curline->v1->x-curline->v2->x); + c1 = a1*FIXED_TO_FLOAT(curline->v1->x) + b1*FIXED_TO_FLOAT(curline->v1->y); + + a2 = -FIXED_TO_FLOAT(FINESINE(temp>>ANGLETOFINESHIFT)); + b2 = FIXED_TO_FLOAT(FINECOSINE(temp>>ANGLETOFINESHIFT)); + c2 = a2*FIXED_TO_FLOAT(viewx) + b2*FIXED_TO_FLOAT(viewy); + + det = a1*b2 - a2*b1; + + ds_p->rightpos.x = segright.x = FLOAT_TO_FIXED((b2*c1 - b1*c2)/det); + ds_p->rightpos.y = segright.y = FLOAT_TO_FIXED((a1*c2 - a2*c1)/det); + } + } + + if (frontsector->c_slope) { + worldtop = P_GetZAt(frontsector->c_slope, segleft.x, segleft.y) - viewz; + worldtopslope = P_GetZAt(frontsector->c_slope, segright.x, segright.y) - viewz; + } else { + worldtopslope = +#else + { +#endif + worldtop = frontsector->ceilingheight - viewz; + } + + +#ifdef ESLOPE + if (frontsector->f_slope) { + worldbottom = P_GetZAt(frontsector->f_slope, segleft.x, segleft.y) - viewz; + worldbottomslope = P_GetZAt(frontsector->f_slope, segright.x, segright.y) - viewz; + } else { + worldbottomslope = +#else + { +#endif + worldbottom = frontsector->floorheight - viewz; + } midtexture = toptexture = bottomtexture = maskedtexture = 0; ds_p->maskedtexturecol = NULL; @@ -1524,27 +1694,72 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (ffloor[i].polyobj && (!ds_p->curline->polyseg || ffloor[i].polyobj != ds_p->curline->polyseg)) continue; #endif + +#ifdef ESLOPE + if (ffloor[i].slope) { + ffloor[i].f_pos = P_GetZAt(ffloor[i].slope, segleft.x, segleft.y) - viewz; + ffloor[i].f_pos_slope = P_GetZAt(ffloor[i].slope, segright.x, segright.y) - viewz; + } else + ffloor[i].f_pos_slope = +#endif ffloor[i].f_pos = ffloor[i].height - viewz; } } +#ifdef ESLOPE + // Set up texture Y offset slides for sloped walls + rw_toptextureslide = rw_midtextureslide = rw_bottomtextureslide = 0; + ceilingfrontslide = floorfrontslide = ceilingbackslide = floorbackslide = 0; + + { + angle_t lineangle = R_PointToAngle2(curline->v1->x, curline->v1->y, curline->v2->x, curline->v2->y); + + if (frontsector->f_slope) + floorfrontslide = FixedMul(frontsector->f_slope->zdelta, FINECOSINE((lineangle-frontsector->f_slope->xydirection)>>ANGLETOFINESHIFT)); + + if (frontsector->c_slope) + ceilingfrontslide = FixedMul(frontsector->c_slope->zdelta, FINECOSINE((lineangle-frontsector->c_slope->xydirection)>>ANGLETOFINESHIFT)); + + if (backsector && backsector->f_slope) + floorbackslide = FixedMul(backsector->f_slope->zdelta, FINECOSINE((lineangle-backsector->f_slope->xydirection)>>ANGLETOFINESHIFT)); + + if (backsector && backsector->c_slope) + ceilingbackslide = FixedMul(backsector->c_slope->zdelta, FINECOSINE((lineangle-backsector->c_slope->xydirection)>>ANGLETOFINESHIFT)); + } +#endif + if (!backsector) { // single sided line midtexture = texturetranslation[sidedef->midtexture]; // a single sided line is terminal, so it must mark ends markfloor = markceiling = true; - +#ifdef ESLOPE + if (!(linedef->flags & ML_EFFECT1)) { + if (linedef->flags & ML_DONTPEGBOTTOM) + rw_midtexturemid = frontsector->floorheight + textureheight[sidedef->midtexture] - viewz; + else + rw_midtexturemid = frontsector->ceilingheight; + } +#endif if (linedef->flags & ML_DONTPEGBOTTOM) { +#ifdef ESLOPE + rw_midtexturemid = worldbottom + textureheight[sidedef->midtexture]; + rw_midtextureslide = floorfrontslide; +#else vtop = frontsector->floorheight + textureheight[sidedef->midtexture]; // bottom of texture at bottom rw_midtexturemid = vtop - viewz; +#endif } else { // top of texture at top rw_midtexturemid = worldtop; +#ifdef ESLOPE + rw_midtextureslide = ceilingfrontslide; +#endif } rw_midtexturemid += sidedef->rowoffset; @@ -1557,47 +1772,120 @@ void R_StoreWallRange(INT32 start, INT32 stop) else { // two sided line + +#ifdef ESLOPE + if (backsector->c_slope) { + worldhigh = P_GetZAt(backsector->c_slope, segleft.x, segleft.y) - viewz; + worldhighslope = P_GetZAt(backsector->c_slope, segright.x, segright.y) - viewz; + } else { + worldhighslope = +#else + { +#endif + worldhigh = backsector->ceilingheight - viewz; + } + + +#ifdef ESLOPE + if (backsector->f_slope) { + worldlow = P_GetZAt(backsector->f_slope, segleft.x, segleft.y) - viewz; + worldlowslope = P_GetZAt(backsector->f_slope, segright.x, segright.y) - viewz; + } else { + worldlowslope = +#else + { +#endif + worldlow = backsector->floorheight - viewz; + } + + + // hack to allow height changes in outdoor areas + if (frontsector->ceilingpic == skyflatnum + && backsector->ceilingpic == skyflatnum) + { +#ifdef ESLOPE + worldtopslope = worldhighslope = +#endif + worldtop = worldhigh; + } + ds_p->sprtopclip = ds_p->sprbottomclip = NULL; ds_p->silhouette = 0; - if (frontsector->floorheight > backsector->floorheight) + if ( +#ifdef ESLOPE + worldbottomslope > worldlowslope || +#endif + worldbottom > worldlow) { ds_p->silhouette = SIL_BOTTOM; +#ifdef ESLOPE + ds_p->bsilheight = (frontsector->f_slope ? INT32_MAX : frontsector->floorheight); +#else ds_p->bsilheight = frontsector->floorheight; +#endif } +#ifdef ESLOPE + else if ((backsector->f_slope ? P_GetZAt(backsector->f_slope, viewx, viewy) : backsector->floorheight) > viewz) +#else else if (backsector->floorheight > viewz) +#endif { ds_p->silhouette = SIL_BOTTOM; ds_p->bsilheight = INT32_MAX; // ds_p->sprbottomclip = negonearray; } - if (frontsector->ceilingheight < backsector->ceilingheight) + if ( +#ifdef ESLOPE + worldtopslope < worldhighslope || +#endif + worldtop < worldhigh) { ds_p->silhouette |= SIL_TOP; +#ifdef ESLOPE + ds_p->tsilheight = (frontsector->c_slope ? INT32_MIN : frontsector->ceilingheight); +#else ds_p->tsilheight = frontsector->ceilingheight; +#endif } +#ifdef ESLOPE + else if ((backsector->c_slope ? P_GetZAt(backsector->c_slope, viewx, viewy) : backsector->ceilingheight) < viewz) +#else else if (backsector->ceilingheight < viewz) +#endif { ds_p->silhouette |= SIL_TOP; ds_p->tsilheight = INT32_MIN; // ds_p->sprtopclip = screenheightarray; } - if (backsector->ceilingheight <= frontsector->floorheight) +#ifdef ESLOPE + if (worldhigh <= worldbottom && worldhighslope <= worldbottomslope) +#else + if (worldhigh <= worldbottom) +#endif { ds_p->sprbottomclip = negonearray; ds_p->bsilheight = INT32_MAX; ds_p->silhouette |= SIL_BOTTOM; } - if (backsector->floorheight >= frontsector->ceilingheight) +#ifdef ESLOPE + if (worldlow >= worldtop && worldlowslope >= worldtopslope) +#else + if (worldlow >= worldtop) +#endif { ds_p->sprtopclip = screenheightarray; ds_p->tsilheight = INT32_MIN; ds_p->silhouette |= SIL_TOP; } +#ifdef ESLOPE + // This causes issues with slopes. + if (!(frontsector->f_slope || frontsector->c_slope || backsector->f_slope || backsector->c_slope)) +#endif //SoM: 3/25/2000: This code fixes an automap bug that didn't check // frontsector->ceiling and backsector->floor to see if a door was closed. // Without the following code, sprites get displayed behind closed doors. @@ -1616,17 +1904,11 @@ void R_StoreWallRange(INT32 start, INT32 stop) } } - worldhigh = backsector->ceilingheight - viewz; - worldlow = backsector->floorheight - viewz; - - // hack to allow height changes in outdoor areas - if (frontsector->ceilingpic == skyflatnum - && backsector->ceilingpic == skyflatnum) - { - worldtop = worldhigh; - } - if (worldlow != worldbottom +#ifdef ESLOPE + || worldlowslope != worldbottomslope + || backsector->f_slope != frontsector->f_slope +#endif || backsector->floorpic != frontsector->floorpic || backsector->lightlevel != frontsector->lightlevel //SoM: 3/22/2000: Check floor x and y offsets. @@ -1649,6 +1931,10 @@ void R_StoreWallRange(INT32 start, INT32 stop) } if (worldhigh != worldtop +#ifdef ESLOPE + || worldhighslope != worldtopslope + || backsector->c_slope != frontsector->c_slope +#endif || backsector->ceilingpic != frontsector->ceilingpic || backsector->lightlevel != frontsector->lightlevel //SoM: 3/22/2000: Check floor x and y offsets. @@ -1678,7 +1964,11 @@ void R_StoreWallRange(INT32 start, INT32 stop) } // check TOP TEXTURE - if (worldhigh < worldtop) + if (worldhigh < worldtop +#ifdef ESLOPE + || worldhighslope < worldtopslope +#endif + ) { // top texture if ((linedef->flags & (ML_DONTPEGTOP) && (linedef->flags & ML_DONTPEGBOTTOM)) @@ -1691,49 +1981,100 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (!toptexture) //Second side has no texture, use the first side's instead. toptexture = texturetranslation[sidedef->toptexture]; +#ifdef ESLOPE + if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked + if (linedef->flags & ML_DONTPEGTOP) + rw_toptexturemid = frontsector->ceilingheight - viewz; + else + rw_toptexturemid = backsector->ceilingheight - viewz; + } else +#endif if (linedef->flags & ML_DONTPEGTOP) { // top of texture at top rw_toptexturemid = worldtop; +#ifdef ESLOPE + rw_toptextureslide = ceilingfrontslide; +#endif } else { +#ifdef ESLOPE + rw_toptexturemid = worldhigh + textureheight[def->toptexture]; + rw_toptextureslide = ceilingbackslide; +#else vtop = backsector->ceilingheight + textureheight[def->toptexture]; // bottom of texture rw_toptexturemid = vtop - viewz; +#endif } } else { toptexture = texturetranslation[sidedef->toptexture]; +#ifdef ESLOPE + if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked + if (linedef->flags & ML_DONTPEGTOP) + rw_toptexturemid = frontsector->ceilingheight - viewz; + else + rw_toptexturemid = backsector->ceilingheight - viewz; + } else +#endif if (linedef->flags & ML_DONTPEGTOP) { // top of texture at top rw_toptexturemid = worldtop; +#ifdef ESLOPE + rw_toptextureslide = ceilingfrontslide; +#endif } else { +#ifdef ESLOPE + rw_toptexturemid = worldhigh + textureheight[sidedef->toptexture]; + rw_toptextureslide = ceilingbackslide; +#else vtop = backsector->ceilingheight + textureheight[sidedef->toptexture]; // bottom of texture rw_toptexturemid = vtop - viewz; +#endif } } } // check BOTTOM TEXTURE - if (worldlow > worldbottom) //seulement si VISIBLE!!! + if (worldlow > worldbottom +#ifdef ESLOPE + || worldlowslope > worldbottomslope +#endif + ) //seulement si VISIBLE!!! { // bottom texture bottomtexture = texturetranslation[sidedef->bottomtexture]; +#ifdef ESLOPE + if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked + if (linedef->flags & ML_DONTPEGBOTTOM) + rw_bottomtexturemid = frontsector->floorheight - viewz; + else + rw_bottomtexturemid = backsector->floorheight - viewz; + } else +#endif if (linedef->flags & ML_DONTPEGBOTTOM) { // bottom of texture at bottom // top of texture at top - rw_bottomtexturemid = worldtop; + rw_bottomtexturemid = worldbottom; +#ifdef ESLOPE + rw_bottomtextureslide = floorfrontslide; +#endif } - else // top of texture at top + else { // top of texture at top rw_bottomtexturemid = worldlow; +#ifdef ESLOPE + rw_bottomtextureslide = floorbackslide; +#endif + } } rw_toptexturemid += sidedef->rowoffset; @@ -1745,6 +2086,12 @@ void R_StoreWallRange(INT32 start, INT32 stop) ffloor_t *rover; ffloor_t *r2; fixed_t lowcut, highcut; +#ifdef ESLOPE + fixed_t lowcutslope, highcutslope; + + // Used for height comparisons and etc across FOFs and slopes + fixed_t high1, highslope1, low1, lowslope1, high2, highslope2, low2, lowslope2; +#endif //markceiling = markfloor = true; maskedtexture = true; @@ -1752,8 +2099,12 @@ void R_StoreWallRange(INT32 start, INT32 stop) ds_p->thicksidecol = maskedtexturecol = lastopening - rw_x; lastopening += rw_stopx - rw_x; - lowcut = frontsector->floorheight > backsector->floorheight ? frontsector->floorheight : backsector->floorheight; - highcut = frontsector->ceilingheight < backsector->ceilingheight ? frontsector->ceilingheight : backsector->ceilingheight; + lowcut = max(worldbottom, worldlow) + viewz; + highcut = min(worldtop, worldhigh) + viewz; +#ifdef ESLOPE + lowcutslope = max(worldbottomslope, worldlowslope) + viewz; + highcutslope = min(worldtopslope, worldhighslope) + viewz; +#endif if (frontsector->ffloors && backsector->ffloors) { @@ -1764,16 +2115,33 @@ void R_StoreWallRange(INT32 start, INT32 stop) continue; if (rover->flags & FF_INVERTSIDES) continue; - if (*rover->topheight < lowcut || *rover->bottomheight > highcut) - continue; if (rover->norender == leveltime) continue; +#ifdef ESLOPE + if (*rover->t_slope) { + high1 = P_GetZAt(*rover->t_slope, segleft.x, segleft.y); + highslope1 = P_GetZAt(*rover->t_slope, segright.x, segright.y); + } else + high1 = highslope1 = *rover->topheight; + if (*rover->b_slope) { + low1 = P_GetZAt(*rover->b_slope, segleft.x, segleft.y); + lowslope1 = P_GetZAt(*rover->b_slope, segright.x, segright.y); + } else + low1 = lowslope1 = *rover->bottomheight; + + if ((high1 < lowcut && highslope1 < lowcutslope) || (low1 > highcut && lowslope1 > highcutslope)) + continue; +#else + if (*rover->topheight < lowcut || *rover->bottomheight > highcut) + continue; +#endif + for (r2 = frontsector->ffloors; r2; r2 = r2->next) { if (!(r2->flags & FF_EXISTS) || !(r2->flags & FF_RENDERSIDES) - || *r2->topheight < lowcut || *r2->bottomheight > highcut) + || *r2->topheight < lowcut || *r2->bottomheight > highcut) ///TODO: make these account for slopes -Red continue; if (r2->norender == leveltime) @@ -1793,8 +2161,24 @@ void R_StoreWallRange(INT32 start, INT32 stop) continue; } +#ifdef ESLOPE + if (*r2->t_slope) { + high2 = P_GetZAt(*r2->t_slope, segleft.x, segleft.y); + highslope2 = P_GetZAt(*r2->t_slope, segright.x, segright.y); + } else + high2 = highslope2 = *r2->topheight; + if (*r2->b_slope) { + low2 = P_GetZAt(*r2->b_slope, segleft.x, segleft.y); + lowslope2 = P_GetZAt(*r2->b_slope, segright.x, segright.y); + } else + low2 = lowslope2 = *r2->bottomheight; + + if ((high1 > high2 && highslope1 > highslope2) || (low1 < low2 && lowslope1 < lowslope2)) + continue; +#else if (*rover->topheight > *r2->topheight || *rover->bottomheight < *r2->bottomheight) continue; +#endif break; } @@ -1811,16 +2195,33 @@ void R_StoreWallRange(INT32 start, INT32 stop) continue; if (!(rover->flags & FF_ALLSIDES)) continue; - if (*rover->topheight < lowcut || *rover->bottomheight > highcut) - continue; if (rover->norender == leveltime) continue; +#ifdef ESLOPE + if (*rover->t_slope) { + high1 = P_GetZAt(*rover->t_slope, segleft.x, segleft.y); + highslope1 = P_GetZAt(*rover->t_slope, segright.x, segright.y); + } else + high1 = highslope1 = *rover->topheight; + if (*rover->b_slope) { + low1 = P_GetZAt(*rover->b_slope, segleft.x, segleft.y); + lowslope1 = P_GetZAt(*rover->b_slope, segright.x, segright.y); + } else + low1 = lowslope1 = *rover->bottomheight; + + if ((high1 < lowcut && highslope1 < lowcutslope) || (low1 > highcut && lowslope1 > highcutslope)) + continue; +#else + if (*rover->topheight < lowcut || *rover->bottomheight > highcut) + continue; +#endif + for (r2 = backsector->ffloors; r2; r2 = r2->next) { if (!(r2->flags & FF_EXISTS) || !(r2->flags & FF_RENDERSIDES) - || *r2->topheight < lowcut || *r2->bottomheight > highcut) + || *r2->topheight < lowcut || *r2->bottomheight > highcut) ///TODO: make these account for slopes -Red continue; if (r2->norender == leveltime) @@ -1840,8 +2241,24 @@ void R_StoreWallRange(INT32 start, INT32 stop) continue; } +#ifdef ESLOPE + if (*r2->t_slope) { + high2 = P_GetZAt(*r2->t_slope, segleft.x, segleft.y); + highslope2 = P_GetZAt(*r2->t_slope, segright.x, segright.y); + } else + high2 = highslope2 = *r2->topheight; + if (*r2->b_slope) { + low2 = P_GetZAt(*r2->b_slope, segleft.x, segleft.y); + lowslope2 = P_GetZAt(*r2->b_slope, segright.x, segright.y); + } else + low2 = lowslope2 = *r2->bottomheight; + + if ((high1 > high2 && highslope1 > highslope2) || (low1 < low2 && lowslope1 < lowslope2)) + continue; +#else if (*rover->topheight > *r2->topheight || *rover->bottomheight < *r2->bottomheight) continue; +#endif break; } @@ -1858,11 +2275,21 @@ void R_StoreWallRange(INT32 start, INT32 stop) { if (!(rover->flags & FF_RENDERSIDES) || !(rover->flags & FF_EXISTS) || rover->flags & FF_INVERTSIDES) continue; - if (*rover->topheight <= frontsector->floorheight || *rover->bottomheight >= frontsector->ceilingheight) - continue; if (rover->norender == leveltime) continue; +#ifdef ESLOPE + // Oy vey. + if (( (*rover->t_slope ? P_GetZAt(*rover->t_slope, segleft.x, segleft.y) : *rover->topheight) <= worldbottom+viewz + && (*rover->t_slope ? P_GetZAt(*rover->t_slope, segright.x, segright.y) : *rover->topheight) <= worldbottomslope+viewz) + ||((*rover->b_slope ? P_GetZAt(*rover->b_slope, segleft.x, segleft.y) : *rover->bottomheight) >= worldtop+viewz + && (*rover->b_slope ? P_GetZAt(*rover->b_slope, segright.x, segright.y) : *rover->bottomheight) >= worldtopslope+viewz)) + continue; +#else + if (*rover->topheight <= frontsector->floorheight || *rover->bottomheight >= frontsector->ceilingheight) + continue; +#endif + ds_p->thicksides[i] = rover; i++; } @@ -1873,12 +2300,27 @@ void R_StoreWallRange(INT32 start, INT32 stop) { if (!(rover->flags & FF_RENDERSIDES) || !(rover->flags & FF_EXISTS) || !(rover->flags & FF_ALLSIDES)) continue; + if (rover->norender == leveltime) + continue; +#ifdef ESLOPE + // Oy vey. + if (( (*rover->t_slope ? P_GetZAt(*rover->t_slope, segleft.x, segleft.y) : *rover->topheight) <= worldbottom+viewz + && (*rover->t_slope ? P_GetZAt(*rover->t_slope, segright.x, segright.y) : *rover->topheight) <= worldbottomslope+viewz) + ||((*rover->b_slope ? P_GetZAt(*rover->b_slope, segleft.x, segleft.y) : *rover->bottomheight) >= worldtop+viewz + && (*rover->b_slope ? P_GetZAt(*rover->b_slope, segright.x, segright.y) : *rover->bottomheight) >= worldtopslope+viewz)) + continue; + + if (( (*rover->t_slope ? P_GetZAt(*rover->t_slope, segleft.x, segleft.y) : *rover->topheight) <= worldlow+viewz + && (*rover->t_slope ? P_GetZAt(*rover->t_slope, segright.x, segright.y) : *rover->topheight) <= worldlowslope+viewz) + ||((*rover->b_slope ? P_GetZAt(*rover->b_slope, segleft.x, segleft.y) : *rover->bottomheight) >= worldhigh+viewz + && (*rover->b_slope ? P_GetZAt(*rover->b_slope, segright.x, segright.y) : *rover->bottomheight) >= worldhighslope+viewz)) + continue; +#else if (*rover->topheight <= frontsector->floorheight || *rover->bottomheight >= frontsector->ceilingheight) continue; if (*rover->topheight <= backsector->floorheight || *rover->bottomheight >= backsector->ceilingheight) continue; - if (rover->norender == leveltime) - continue; +#endif ds_p->thicksides[i] = rover; i++; @@ -1898,6 +2340,32 @@ void R_StoreWallRange(INT32 start, INT32 stop) else ds_p->maskedtexturecol = ds_p->thicksidecol; +#ifdef ESLOPE + maskedtextureheight = &(ds_p->maskedtextureheight[0]); // ???? + + // Set midtexture starting height + if (linedef->flags & ML_EFFECT2) { // Ignore slopes when texturing + rw_midtextureslide = rw_midtexturebackslide = 0; + if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) + rw_midtexturemid = rw_midtextureback = max(frontsector->floorheight, backsector->floorheight) - viewz; + else + rw_midtexturemid = rw_midtextureback = min(frontsector->ceilingheight, backsector->ceilingheight) - viewz; + + } else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) { + rw_midtexturemid = worldbottom; + rw_midtextureslide = floorfrontslide; + rw_midtextureback = worldlow; + rw_midtexturebackslide = floorbackslide; + } else { + rw_midtexturemid = worldtop; + rw_midtextureslide = ceilingfrontslide; + rw_midtextureback = worldhigh; + rw_midtexturebackslide = ceilingbackslide; + } + rw_midtexturemid += sidedef->rowoffset; + rw_midtextureback += sidedef->rowoffset; +#endif + maskedtexture = true; } } @@ -1950,13 +2418,21 @@ void R_StoreWallRange(INT32 start, INT32 stop) // and doesn't need to be marked. if (frontsector->heightsec == -1) { - if (frontsector->floorheight >= viewz) + if (( +#ifdef ESLOPE + frontsector->f_slope ? P_GetZAt(frontsector->f_slope, viewx, viewy) : +#endif + frontsector->floorheight) >= viewz) { // above view plane markfloor = false; } - if (frontsector->ceilingheight <= viewz && + if (( +#ifdef ESLOPE + frontsector->c_slope ? P_GetZAt(frontsector->c_slope, viewx, viewy) : +#endif + frontsector->ceilingheight) <= viewz && frontsector->ceilingpic != skyflatnum) { // below view plane @@ -1967,6 +2443,10 @@ void R_StoreWallRange(INT32 start, INT32 stop) // calculate incremental stepping values for texture edges worldtop >>= 4; worldbottom >>= 4; +#ifdef ESLOPE + worldtopslope >>= 4; + worldbottomslope >>= 4; +#endif topstep = -FixedMul (rw_scalestep, worldtop); topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale); @@ -1974,6 +2454,17 @@ void R_StoreWallRange(INT32 start, INT32 stop) bottomstep = -FixedMul (rw_scalestep,worldbottom); bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale); +#ifdef ESLOPE + if (frontsector->c_slope) { + fixed_t topfracend = (centeryfrac>>4) - FixedMul (worldtopslope, ds_p->scale2); + topstep = (topfracend-topfrac)/(stop-start+1); + } + if (frontsector->f_slope) { + fixed_t bottomfracend = (centeryfrac>>4) - FixedMul (worldbottomslope, ds_p->scale2); + bottomstep = (bottomfracend-bottomfrac)/(stop-start+1); + } +#endif + dc_numlights = 0; if (frontsector->numlights) @@ -1987,26 +2478,83 @@ void R_StoreWallRange(INT32 start, INT32 stop) for (i = p = 0; i < dc_numlights; i++) { +#ifdef ESLOPE + fixed_t leftheight, rightheight; +#endif + light = &frontsector->lightlist[i]; rlight = &dc_lightlist[p]; +#ifdef ESLOPE + if (light->slope) { + leftheight = P_GetZAt(light->slope, segleft.x, segleft.y); + rightheight = P_GetZAt(light->slope, segright.x, segright.y); + + // Flag sector as having slopes + frontsector->hasslope = true; + } else + leftheight = rightheight = light->height; + + leftheight -= viewz; + rightheight -= viewz; + + leftheight >>= 4; + rightheight >>= 4; +#endif + if (i != 0) { +#ifdef ESLOPE + if (leftheight < worldbottom && rightheight < worldbottomslope) + continue; + + if (leftheight > worldtop && rightheight > worldtopslope && i+1 < dc_numlights && frontsector->lightlist[i+1].height > frontsector->ceilingheight) + continue; +#else if (light->height < frontsector->floorheight) continue; if (light->height > frontsector->ceilingheight && i+1 < dc_numlights && frontsector->lightlist[i+1].height > frontsector->ceilingheight) continue; +#endif } +#ifdef ESLOPE + rlight->height = (centeryfrac>>4) - FixedMul(leftheight, rw_scale); + rlight->heightstep = (centeryfrac>>4) - FixedMul(rightheight, ds_p->scale2); + rlight->heightstep = (rlight->heightstep-rlight->height)/(stop-start+1); +#else rlight->height = (centeryfrac>>4) - FixedMul((light->height - viewz) >> 4, rw_scale); rlight->heightstep = -FixedMul (rw_scalestep, (light->height - viewz) >> 4); +#endif rlight->flags = light->flags; if (light->caster && light->caster->flags & FF_SOLID) { +#ifdef ESLOPE + if (*light->caster->b_slope) { + leftheight = P_GetZAt(*light->caster->b_slope, segleft.x, segleft.y); + rightheight = P_GetZAt(*light->caster->b_slope, segright.x, segright.y); + + // Flag sector as having slopes + frontsector->hasslope = true; + } else + leftheight = rightheight = *light->caster->bottomheight; + + leftheight -= viewz; + rightheight -= viewz; + + leftheight >>= 4; + rightheight >>= 4; + + rlight->botheight = (centeryfrac>>4) - FixedMul(leftheight, rw_scale); + rlight->botheightstep = (centeryfrac>>4) - FixedMul(rightheight, ds_p->scale2); + rlight->botheightstep = (rlight->botheightstep-rlight->botheight)/(stop-start+1); + +#else rlight->botheight = (centeryfrac >> 4) - FixedMul((*light->caster->bottomheight - viewz) >> 4, rw_scale); rlight->botheightstep = -FixedMul (rw_scalestep, (*light->caster->bottomheight - viewz) >> 4); +#endif } rlight->lightlevel = *light->lightlevel; @@ -2027,8 +2575,14 @@ void R_StoreWallRange(INT32 start, INT32 stop) #endif ffloor[i].f_pos >>= 4; +#ifdef ESLOPE + ffloor[i].f_pos_slope >>= 4; + ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale); + ffloor[i].f_step = ((centeryfrac>>4) - FixedMul(ffloor[i].f_pos_slope, ds_p->scale2) - ffloor[i].f_frac)/(stop-start+1); +#else ffloor[i].f_step = FixedMul(-rw_scalestep, ffloor[i].f_pos); ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale); +#endif } } @@ -2036,22 +2590,51 @@ void R_StoreWallRange(INT32 start, INT32 stop) { worldhigh >>= 4; worldlow >>= 4; +#ifdef ESLOPE + worldhighslope >>= 4; + worldlowslope >>= 4; +#endif - if (worldhigh < worldtop) + if (worldhigh < worldtop +#ifdef ESLOPE + || worldhighslope <= worldtopslope +#endif + ) { pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale); pixhighstep = -FixedMul (rw_scalestep,worldhigh); + +#ifdef ESLOPE + if (backsector->c_slope) { + fixed_t topfracend = (centeryfrac>>4) - FixedMul (worldhighslope, ds_p->scale2); + pixhighstep = (topfracend-pixhigh)/(stop-start+1); + } +#endif } - if (worldlow > worldbottom) + if (worldlow > worldbottom +#ifdef ESLOPE + || worldlowslope >= worldbottomslope +#endif + ) { pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale); pixlowstep = -FixedMul (rw_scalestep,worldlow); +#ifdef ESLOPE + if (backsector->f_slope) { + fixed_t bottomfracend = (centeryfrac>>4) - FixedMul (worldlowslope, ds_p->scale2); + pixlowstep = (bottomfracend-pixlow)/(stop-start+1); + } +#endif } { ffloor_t * rover; i = 0; +#ifdef ESLOPE + fixed_t rovertest; + fixed_t planevistest; +#endif if (backsector->ffloors) { @@ -2062,6 +2645,52 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (rover->norender == leveltime) continue; +#ifdef ESLOPE + // Let the renderer know this sector is sloped. + if (*rover->b_slope || *rover->t_slope) + backsector->hasslope = true; + + rovertest = (*rover->b_slope ? P_GetZAt(*rover->b_slope, backsector->soundorg.x, backsector->soundorg.y) : *rover->bottomheight) - viewz; + planevistest = (*rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) : *rover->bottomheight); + + if (rovertest>>4 <= worldhigh && + rovertest>>4 >= worldlow && + ((viewz < planevistest && !(rover->flags & FF_INVERTPLANES)) || + (viewz > planevistest && (rover->flags & FF_BOTHPLANES)))) + { + //ffloor[i].slope = *rover->b_slope; + ffloor[i].b_pos = (*rover->b_slope ? P_GetZAt(*rover->b_slope, segleft.x, segleft.y) : *rover->bottomheight) - viewz; + ffloor[i].b_pos_slope = (*rover->b_slope ? P_GetZAt(*rover->b_slope, segright.x, segright.y) : *rover->bottomheight) - viewz; + ffloor[i].b_pos >>= 4; + ffloor[i].b_pos_slope >>= 4; + ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); + ffloor[i].b_step = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos_slope, ds_p->scale2); + ffloor[i].b_step = (ffloor[i].b_step-ffloor[i].b_frac)/(stop-start+1); + i++; + } + + if (i >= MAXFFLOORS) + break; + + rovertest = (*rover->t_slope ? P_GetZAt(*rover->t_slope, backsector->soundorg.x, backsector->soundorg.y) : *rover->topheight) - viewz; + planevistest = (*rover->t_slope ? P_GetZAt(*rover->t_slope, viewx, viewy) : *rover->topheight); + + if (rovertest>>4 <= worldhigh && + rovertest>>4 >= worldlow && + ((viewz > planevistest && !(rover->flags & FF_INVERTPLANES)) || + (viewz < planevistest && (rover->flags & FF_BOTHPLANES)))) + { + //ffloor[i].slope = *rover->t_slope; + ffloor[i].b_pos = (*rover->t_slope ? P_GetZAt(*rover->t_slope, segleft.x, segleft.y) : *rover->topheight) - viewz; + ffloor[i].b_pos_slope = (*rover->t_slope ? P_GetZAt(*rover->t_slope, segright.x, segright.y) : *rover->topheight) - viewz; + ffloor[i].b_pos >>= 4; + ffloor[i].b_pos_slope >>= 4; + ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); + ffloor[i].b_step = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos_slope, ds_p->scale2); + ffloor[i].b_step = (ffloor[i].b_step-ffloor[i].b_frac)/(stop-start+1); + i++; + } +#else if (*rover->bottomheight <= backsector->ceilingheight && *rover->bottomheight >= backsector->floorheight && ((viewz < *rover->bottomheight && !(rover->flags & FF_INVERTPLANES)) || @@ -2073,8 +2702,10 @@ void R_StoreWallRange(INT32 start, INT32 stop) ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); i++; } + if (i >= MAXFFLOORS) break; + if (*rover->topheight >= backsector->floorheight && *rover->topheight <= backsector->ceilingheight && ((viewz > *rover->topheight && !(rover->flags & FF_INVERTPLANES)) || @@ -2086,6 +2717,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); i++; } +#endif } } else if (frontsector && frontsector->ffloors) @@ -2097,6 +2729,53 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (rover->norender == leveltime) continue; + +#ifdef ESLOPE + // Let the renderer know this sector is sloped. + if (*rover->b_slope || *rover->t_slope) + frontsector->hasslope = true; + + rovertest = (*rover->b_slope ? P_GetZAt(*rover->b_slope, frontsector->soundorg.x, frontsector->soundorg.y) : *rover->bottomheight) - viewz; + planevistest = (*rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) : *rover->bottomheight); + + if (rovertest>>4 <= worldtop && + rovertest>>4 >= worldbottom && + ((viewz < planevistest && !(rover->flags & FF_INVERTPLANES)) || + (viewz > planevistest && (rover->flags & FF_BOTHPLANES)))) + { + //ffloor[i].slope = *rover->b_slope; + ffloor[i].b_pos = (*rover->b_slope ? P_GetZAt(*rover->b_slope, segleft.x, segleft.y) : *rover->bottomheight) - viewz; + ffloor[i].b_pos_slope = (*rover->b_slope ? P_GetZAt(*rover->b_slope, segright.x, segright.y) : *rover->bottomheight) - viewz; + ffloor[i].b_pos >>= 4; + ffloor[i].b_pos_slope >>= 4; + ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); + ffloor[i].b_step = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos_slope, ds_p->scale2); + ffloor[i].b_step = (ffloor[i].b_step-ffloor[i].b_frac)/(stop-start+1); + i++; + } + + if (i >= MAXFFLOORS) + break; + + rovertest = (*rover->t_slope ? P_GetZAt(*rover->t_slope, frontsector->soundorg.x, frontsector->soundorg.y) : *rover->topheight) - viewz; + planevistest = (*rover->t_slope ? P_GetZAt(*rover->t_slope, viewx, viewy) : *rover->topheight); + + if (rovertest>>4 <= worldtop && + rovertest>>4 >= worldbottom && + ((viewz > planevistest && !(rover->flags & FF_INVERTPLANES)) || + (viewz < planevistest && (rover->flags & FF_BOTHPLANES)))) + { + //ffloor[i].slope = *rover->t_slope; + ffloor[i].b_pos = (*rover->t_slope ? P_GetZAt(*rover->t_slope, segleft.x, segleft.y) : *rover->topheight) - viewz; + ffloor[i].b_pos_slope = (*rover->t_slope ? P_GetZAt(*rover->t_slope, segright.x, segright.y) : *rover->topheight) - viewz; + ffloor[i].b_pos >>= 4; + ffloor[i].b_pos_slope >>= 4; + ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); + ffloor[i].b_step = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos_slope, ds_p->scale2); + ffloor[i].b_step = (ffloor[i].b_step-ffloor[i].b_frac)/(stop-start+1); + i++; + } +#else if (*rover->bottomheight <= frontsector->ceilingheight && *rover->bottomheight >= frontsector->floorheight && ((viewz < *rover->bottomheight && !(rover->flags & FF_INVERTPLANES)) || @@ -2121,6 +2800,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); i++; } +#endif } } #ifdef POLYOBJECTS_PLANES @@ -2137,6 +2817,9 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (ffloor[i].plane->maxx < ds_p->x2) ffloor[i].plane->maxx = ds_p->x2; +#ifdef ESLOPE + ffloor[i].slope = NULL; +#endif ffloor[i].b_pos = backsector->floorheight; ffloor[i].b_pos = (ffloor[i].b_pos - viewz) >> 4; ffloor[i].b_step = FixedMul(-rw_scalestep, ffloor[i].b_pos); @@ -2153,6 +2836,9 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (ffloor[i].plane->maxx < ds_p->x2) ffloor[i].plane->maxx = ds_p->x2; +#ifdef ESLOPE + ffloor[i].slope = NULL; +#endif ffloor[i].b_pos = backsector->ceilingheight; ffloor[i].b_pos = (ffloor[i].b_pos - viewz) >> 4; ffloor[i].b_step = FixedMul(-rw_scalestep, ffloor[i].b_pos); diff --git a/src/r_things.c b/src/r_things.c index 0c93932cb..2247d238e 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -954,12 +954,22 @@ static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing) for (i = 1; i < sector->numlights; i++) { - if (sector->lightlist[i].height >= sprite->gzt || !(sector->lightlist[i].caster->flags & FF_CUTSPRITES)) + fixed_t testheight = sector->lightlist[i].height; + + if (!(sector->lightlist[i].caster->flags & FF_CUTSPRITES)) continue; - if (sector->lightlist[i].height <= sprite->gz) + +#ifdef ESLOPE + if (sector->lightlist[i].slope) + testheight = P_GetZAt(sector->lightlist[i].slope, sprite->gx, sprite->gy); +#endif + + if (testheight >= sprite->gzt) + continue; + if (testheight <= sprite->gz) return; - cutfrac = (INT16)((centeryfrac - FixedMul(sector->lightlist[i].height - viewz, sprite->scale))>>FRACBITS); + cutfrac = (INT16)((centeryfrac - FixedMul(testheight - viewz, sprite->scale))>>FRACBITS); if (cutfrac < 0) continue; if (cutfrac > vid.height) @@ -970,15 +980,15 @@ static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing) newsprite = M_Memcpy(R_NewVisSprite(), sprite, sizeof (vissprite_t)); sprite->cut |= SC_BOTTOM; - sprite->gz = sector->lightlist[i].height; + sprite->gz = testheight; newsprite->gzt = sprite->gz; sprite->sz = cutfrac; newsprite->szt = (INT16)(sprite->sz - 1); - if (sector->lightlist[i].height < sprite->pzt && sector->lightlist[i].height > sprite->pz) - sprite->pz = newsprite->pzt = sector->lightlist[i].height; + if (testheight < sprite->pzt && testheight > sprite->pz) + sprite->pz = newsprite->pzt = testheight; else { newsprite->pz = newsprite->gz; @@ -1200,7 +1210,20 @@ static void R_ProjectSprite(mobj_t *thing) if (thing->subsector->sector->numlights) { INT32 lightnum; +#ifdef ESLOPE // R_GetPlaneLight won't work on sloped lights! + light = thing->subsector->sector->numlights - 1; + + for (lightnum = 1; lightnum < thing->subsector->sector->numlights; lightnum++) { + fixed_t h = thing->subsector->sector->lightlist[lightnum].slope ? P_GetZAt(thing->subsector->sector->lightlist[lightnum].slope, thing->x, thing->y) + : thing->subsector->sector->lightlist[lightnum].height; + if (h <= gzt) { + light = lightnum - 1; + break; + } + } +#else light = R_GetPlaneLight(thing->subsector->sector, gzt, false); +#endif lightnum = (*thing->subsector->sector->lightlist[light].lightlevel >> LIGHTSEGSHIFT); if (lightnum < 0) @@ -1761,24 +1784,34 @@ static void R_CreateDrawNodes(void) { if (r2->plane) { + fixed_t planeobjectz, planecameraz; if (r2->plane->minx > rover->x2 || r2->plane->maxx < rover->x1) continue; if (rover->szt > r2->plane->low || rover->sz < r2->plane->high) continue; +#ifdef ESLOPE + // Effective height may be different for each comparison in the case of slopes + if (r2->plane->slope) { + planeobjectz = P_GetZAt(r2->plane->slope, rover->gx, rover->gy); + planecameraz = P_GetZAt(r2->plane->slope, viewx, viewy); + } else +#endif + planeobjectz = planecameraz = r2->plane->height; + if (rover->mobjflags & MF_NOCLIPHEIGHT) { //Objects with NOCLIPHEIGHT can appear halfway in. - if (r2->plane->height < viewz && rover->pz+(rover->thingheight/2) >= r2->plane->height) + if (planecameraz < viewz && rover->pz+(rover->thingheight/2) >= planeobjectz) continue; - if (r2->plane->height > viewz && rover->pzt-(rover->thingheight/2) <= r2->plane->height) + if (planecameraz > viewz && rover->pzt-(rover->thingheight/2) <= planeobjectz) continue; } else { - if (r2->plane->height < viewz && rover->pz >= r2->plane->height) + if (planecameraz < viewz && rover->pz >= planeobjectz) continue; - if (r2->plane->height > viewz && rover->pzt <= r2->plane->height) + if (planecameraz > viewz && rover->pzt <= planeobjectz) continue; } @@ -1808,6 +1841,7 @@ static void R_CreateDrawNodes(void) } else if (r2->thickseg) { + fixed_t topplaneobjectz, topplanecameraz, botplaneobjectz, botplanecameraz; if (rover->x1 > r2->thickseg->x2 || rover->x2 < r2->thickseg->x1) continue; @@ -1818,9 +1852,25 @@ static void R_CreateDrawNodes(void) if (scale <= rover->scale) continue; - if ((*r2->ffloor->topheight > viewz && *r2->ffloor->bottomheight < viewz) || - (*r2->ffloor->topheight < viewz && rover->gzt < *r2->ffloor->topheight) || - (*r2->ffloor->bottomheight > viewz && rover->gz > *r2->ffloor->bottomheight)) +#ifdef ESLOPE + if (*r2->ffloor->t_slope) { + topplaneobjectz = P_GetZAt(*r2->ffloor->t_slope, rover->gx, rover->gy); + topplanecameraz = P_GetZAt(*r2->ffloor->t_slope, viewx, viewy); + } else +#endif + topplaneobjectz = topplanecameraz = *r2->ffloor->topheight; + +#ifdef ESLOPE + if (*r2->ffloor->b_slope) { + botplaneobjectz = P_GetZAt(*r2->ffloor->b_slope, rover->gx, rover->gy); + botplanecameraz = P_GetZAt(*r2->ffloor->b_slope, viewx, viewy); + } else +#endif + botplaneobjectz = botplanecameraz = *r2->ffloor->bottomheight; + + if ((topplanecameraz > viewz && botplanecameraz < viewz) || + (topplanecameraz < viewz && rover->gzt < topplaneobjectz) || + (botplanecameraz > viewz && rover->gz > botplaneobjectz)) { entry = R_CreateDrawNode(NULL); (entry->prev = r2->prev)->next = entry; @@ -2039,21 +2089,21 @@ void R_ClipSprites(void) if (spr->gzt <= ds->tsilheight) silhouette &= ~SIL_TOP; - if (silhouette == 1) + if (silhouette == SIL_BOTTOM) { // bottom sil for (x = r1; x <= r2; x++) if (spr->clipbot[x] == -2) spr->clipbot[x] = ds->sprbottomclip[x]; } - else if (silhouette == 2) + else if (silhouette == SIL_TOP) { // top sil for (x = r1; x <= r2; x++) if (spr->cliptop[x] == -2) spr->cliptop[x] = ds->sprtopclip[x]; } - else if (silhouette == 3) + else if (silhouette == (SIL_TOP|SIL_BOTTOM)) { // both for (x = r1; x <= r2; x++) diff --git a/src/tables.c b/src/tables.c index 190522a35..6f0446e01 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, @@ -10706,5 +10703,3 @@ void FM_Rotate(matrix_t *dest, angle_t angle, fixed_t x, fixed_t y, fixed_t z) M(3, 3) = FRACUNIT; #undef M } - -#endif diff --git a/src/tables.h b/src/tables.h index 219d668b9..d7ec589da 100644 --- a/src/tables.h +++ b/src/tables.h @@ -96,9 +96,6 @@ 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); @@ -112,8 +109,6 @@ void FV3_Rotate(vector3_t *rotVec, const vector3_t *axisVec, const angle_t angle /// Fixed Point Matrix functions void FM_Rotate(matrix_t *dest, angle_t angle, fixed_t x, fixed_t y, fixed_t z); -#endif // defined NEED_FIXED_VECTOR - // The table values in tables.c are calculated with this many fractional bits. #define FINE_FRACBITS 16 diff --git a/tools/anglechk.c b/tools/anglechk.c index bb9c4d9ea..4a67069bf 100644 --- a/tools/anglechk.c +++ b/tools/anglechk.c @@ -351,6 +351,13 @@ int main(int argc, char** argv) return 0; } +static void *cpu_cpy(void *dest, const void *src, size_t n) +{ + return memcpy(dest, src, n); +} + +void *(*M_Memcpy)(void* dest, const void* src, size_t n) = cpu_cpy; + void I_Error(const char *error, ...) { (void)error;