diff --git a/src/k_bot.c b/src/k_bot.c index 3e490031a..9f7fdc25e 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -439,7 +439,7 @@ static line_t *K_FindBotController(mobj_t *mo) --------------------------------------------------*/ static UINT32 K_BotRubberbandDistance(player_t *player) { - const UINT32 spacing = FixedDiv(640 * FRACUNIT, K_GetKartGameSpeedScalar(gamespeed)) / FRACUNIT; + const UINT32 spacing = FixedDiv(640 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed)) / FRACUNIT; const UINT8 portpriority = player - players; UINT8 pos = 0; UINT8 i; @@ -625,7 +625,7 @@ fixed_t K_DistanceOfLineFromPoint(fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t } /*-------------------------------------------------- - static fixed_t K_GetBotWaypointRadius(waypoint_t *waypoint) + static void K_GetBotWaypointRadius(waypoint_t *waypoint, fixed_t *smallestRadius, fixed_t *smallestScaled) Calculates a new waypoint radius size to use, making it thinner depending on how harsh the turn is. @@ -634,12 +634,12 @@ fixed_t K_DistanceOfLineFromPoint(fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t waypoint - Waypoint to retrieve the radius of. Return:- - New radius value. + N/A --------------------------------------------------*/ -static fixed_t K_GetBotWaypointRadius(waypoint_t *const waypoint) +static void K_GetBotWaypointRadius(waypoint_t *const waypoint, fixed_t *smallestRadius, fixed_t *smallestScaled) { static const fixed_t maxReduce = FRACUNIT/32; - static const angle_t maxDelta = ANGLE_45; + static const angle_t maxDelta = ANGLE_22h; fixed_t radius = waypoint->mobj->radius; fixed_t reduce = FRACUNIT; @@ -675,7 +675,37 @@ static fixed_t K_GetBotWaypointRadius(waypoint_t *const waypoint) reduce = FixedDiv(delta, maxDelta); reduce = FRACUNIT + FixedMul(reduce, maxReduce - FRACUNIT); - return FixedMul(radius, reduce); + *smallestRadius = min(*smallestRadius, radius); + *smallestScaled = min(*smallestScaled, FixedMul(radius, reduce)); +} + +static fixed_t K_ScaleWPDistWithSlope(fixed_t disttonext, angle_t angletonext, const pslope_t *slope, SINT8 flip) +{ + if (slope == NULL) + { + return disttonext; + } + + if ((slope->flags & SL_NOPHYSICS) == 0 && abs(slope->zdelta) >= FRACUNIT/21) + { + // Displace the prediction to go with the slope physics. + fixed_t slopeMul = FRACUNIT; + angle_t angle = angletonext - slope->xydirection; + + if (flip * slope->zdelta < 0) + { + angle ^= ANGLE_180; + } + + // Going uphill: 0 + // Going downhill: FRACUNIT*2 + slopeMul = FRACUNIT + FINECOSINE(angle >> ANGLETOFINESHIFT); + + // Range: 0.25 to 1.75 + return FixedMul(disttonext, (FRACUNIT >> 2) + ((slopeMul * 3) >> 2)); + } + + return disttonext; } /*-------------------------------------------------- @@ -701,17 +731,21 @@ static botprediction_t *K_CreateBotPrediction(player_t *player) const tic_t futuresight = (TICRATE * KART_FULLTURN) / max(1, handling); // How far ahead into the future to try and predict const fixed_t speed = K_BotSpeedScaled(player, P_AproxDistance(player->mo->momx, player->mo->momy)); - const INT32 startDist = (DEFAULT_WAYPOINT_RADIUS * 2 * mapobjectscale) / FRACUNIT; - const INT32 maxDist = startDist * 4; // This function gets very laggy when it goes far distances, and going too far isn't very helpful anyway. + const INT32 startDist = 0; //(DEFAULT_WAYPOINT_RADIUS * mapobjectscale) / FRACUNIT; + const INT32 maxDist = (DEFAULT_WAYPOINT_RADIUS * 3 * mapobjectscale) / FRACUNIT; // This function gets very laggy when it goes far distances, and going too far isn't very helpful anyway. const INT32 distance = min(((speed / FRACUNIT) * (INT32)futuresight) + startDist, maxDist); // Halves radius when encountering a wall on your way to your destination. - fixed_t radreduce = FRACUNIT; + fixed_t radReduce = FRACUNIT; + + fixed_t radius = INT32_MAX; + fixed_t radiusScaled = INT32_MAX; INT32 distanceleft = distance; - fixed_t smallestradius = INT32_MAX; angle_t angletonext = ANGLE_MAX; INT32 disttonext = INT32_MAX; + INT32 distscaled = INT32_MAX; + pslope_t *nextslope = player->mo->standingslope; waypoint_t *wp = player->nextwaypoint; mobj_t *prevwpmobj = player->mo; @@ -721,15 +755,25 @@ static botprediction_t *K_CreateBotPrediction(player_t *player) boolean pathfindsuccess = false; path_t pathtofinish = {0}; - botprediction_t *predict = Z_Calloc(sizeof(botprediction_t), PU_STATIC, NULL); + botprediction_t *predict = NULL; size_t i; + if (wp == NULL || P_MobjWasRemoved(wp->mobj) == true) + { + // Can't do any of this if we don't have a waypoint. + return NULL; + } + + predict = Z_Calloc(sizeof(botprediction_t), PU_STATIC, NULL); + // Init defaults in case of pathfind failure angletonext = R_PointToAngle2(prevwpmobj->x, prevwpmobj->y, wp->mobj->x, wp->mobj->y); - disttonext = P_AproxDistance(prevwpmobj->x - wp->mobj->x, prevwpmobj->y - wp->mobj->y) / FRACUNIT; + disttonext = P_AproxDistance(prevwpmobj->x - wp->mobj->x, prevwpmobj->y - wp->mobj->y); + nextslope = wp->mobj->standingslope; + distscaled = K_ScaleWPDistWithSlope(disttonext, angletonext, nextslope, P_MobjFlip(wp->mobj)) / FRACUNIT; pathfindsuccess = K_PathfindThruCircuit( - player->nextwaypoint, (unsigned)distanceleft, + wp, (unsigned)distanceleft, &pathtofinish, useshortcuts, huntbackwards ); @@ -739,8 +783,6 @@ static botprediction_t *K_CreateBotPrediction(player_t *player) { for (i = 0; i < pathtofinish.numnodes; i++) { - fixed_t radius = 0; - wp = (waypoint_t *)pathtofinish.array[i].nodedata; if (i == 0) @@ -753,22 +795,19 @@ static botprediction_t *K_CreateBotPrediction(player_t *player) } angletonext = R_PointToAngle2(prevwpmobj->x, prevwpmobj->y, wp->mobj->x, wp->mobj->y); - disttonext = P_AproxDistance(prevwpmobj->x - wp->mobj->x, prevwpmobj->y - wp->mobj->y) / FRACUNIT; + disttonext = P_AproxDistance(prevwpmobj->x - wp->mobj->x, prevwpmobj->y - wp->mobj->y); + nextslope = wp->mobj->standingslope; + distscaled = K_ScaleWPDistWithSlope(disttonext, angletonext, nextslope, P_MobjFlip(wp->mobj)) / FRACUNIT; if (P_TraceBotTraversal(player->mo, wp->mobj) == false) { - // If we can't get a direct path to this waypoint, predict less. - distanceleft /= 2; - radreduce = FRACUNIT >> 1; + // If we can't get a direct path to this waypoint, reduce our prediction drastically. + distscaled *= 4; + radReduce = FRACUNIT >> 1; } - radius = K_GetBotWaypointRadius(wp); - if (radius < smallestradius) - { - smallestradius = radius; - } - - distanceleft -= disttonext; + K_GetBotWaypointRadius(wp, &radius, &radiusScaled); + distanceleft -= distscaled; if (distanceleft <= 0) { @@ -784,7 +823,9 @@ static botprediction_t *K_CreateBotPrediction(player_t *player) // and use the smallest radius of all of the waypoints in the chain! predict->x = wp->mobj->x; predict->y = wp->mobj->y; - predict->radius = FixedMul(smallestradius, radreduce); + + predict->baseRadius = radius; + predict->radius = FixedMul(radiusScaled, radReduce); // Set the prediction coordinates between the 2 waypoints if there's still distance left. if (distanceleft > 0) @@ -794,25 +835,6 @@ static botprediction_t *K_CreateBotPrediction(player_t *player) predict->y += P_ReturnThrustY(NULL, angletonext, min(disttonext, distanceleft) * FRACUNIT); } - if (player->mo->standingslope != NULL) - { - const pslope_t *slope = player->mo->standingslope; - - if (!(slope->flags & SL_NOPHYSICS) && abs(slope->zdelta) >= FRACUNIT/21) - { - // Displace the prediction to go against the slope physics. - angle_t angle = slope->xydirection; - - if (P_MobjFlip(player->mo) * slope->zdelta < 0) - { - angle ^= ANGLE_180; - } - - predict->x -= P_ReturnThrustX(NULL, angle, startDist * abs(slope->zdelta)); - predict->y -= P_ReturnThrustY(NULL, angle, startDist * abs(slope->zdelta)); - } - } - ps_bots[player - players].prediction += I_GetPreciseTime() - time; return predict; } @@ -1109,7 +1131,7 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t * anglediff = abs(anglediff); turnamt = KART_FULLTURN * turnsign; - if (anglediff > ANGLE_90) + if (anglediff > ANGLE_67h) { // Wrong way! cmd->forwardmove = -MAXPLMOVE; @@ -1502,18 +1524,13 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) if (predict == NULL) { // Create a prediction. - if (player->nextwaypoint != NULL - && player->nextwaypoint->mobj != NULL - && !P_MobjWasRemoved(player->nextwaypoint->mobj)) - { - predict = K_CreateBotPrediction(player); - K_NudgePredictionTowardsObjects(predict, player); - destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y); - } + predict = K_CreateBotPrediction(player); } if (predict != NULL) { + K_NudgePredictionTowardsObjects(predict, player); + destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y); turnamt = K_HandleBotTrack(player, cmd, predict, destangle); } cmd->buttons &= ~(BT_ACCELERATE|BT_BRAKE); @@ -1539,18 +1556,13 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) if (predict == NULL) { // Create a prediction. - if (player->nextwaypoint != NULL - && player->nextwaypoint->mobj != NULL - && !P_MobjWasRemoved(player->nextwaypoint->mobj)) - { - predict = K_CreateBotPrediction(player); - K_NudgePredictionTowardsObjects(predict, player); - destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y); - } + predict = K_CreateBotPrediction(player); } if (predict != NULL) { + K_NudgePredictionTowardsObjects(predict, player); + destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y); turnamt = K_HandleBotTrack(player, cmd, predict, destangle); } } @@ -1561,18 +1573,13 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) if (predict == NULL) { // Create a prediction. - if (player->nextwaypoint != NULL - && player->nextwaypoint->mobj != NULL - && !P_MobjWasRemoved(player->nextwaypoint->mobj)) - { - predict = K_CreateBotPrediction(player); - K_NudgePredictionTowardsObjects(predict, player); - destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y); - } + predict = K_CreateBotPrediction(player); } if (predict != NULL) { + K_NudgePredictionTowardsObjects(predict, player); + destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y); turnamt = K_HandleBotTrack(player, cmd, predict, destangle); } } diff --git a/src/k_bot.h b/src/k_bot.h index bce0a1655..d98f7a1e9 100644 --- a/src/k_bot.h +++ b/src/k_bot.h @@ -37,7 +37,7 @@ extern "C" { // Point for bots to aim for struct botprediction_t { fixed_t x, y; - fixed_t radius; + fixed_t radius, baseRadius; }; diff --git a/src/k_botsearch.c b/src/k_botsearch.c index f619035e9..6d3e97ed3 100644 --- a/src/k_botsearch.c +++ b/src/k_botsearch.c @@ -142,16 +142,33 @@ UINT8 K_EggboxStealth(fixed_t x, fixed_t y) Return:- true if avoiding this sector special, false otherwise. --------------------------------------------------*/ -static boolean K_BotHatesThisSectorsSpecial(player_t *player, sector_t *sec) +static boolean K_BotHatesThisSectorsSpecial(player_t *player, sector_t *sec, const boolean flip) { - if (sec->damagetype != SD_NONE) - { - return true; - } + terrain_t *terrain = K_GetTerrainForFlatNum(flip ? sec->ceilingpic : sec->floorpic); - if (sec->offroad > 0) + if (terrain != NULL) { - return !K_BotCanTakeCut(player); + if (terrain->damageType != SD_NONE) + { + return true; + } + + if (terrain->offroad > 0) + { + return !K_BotCanTakeCut(player); + } + } + else + { + if (sec->damagetype != SD_NONE) + { + return true; + } + + if (sec->offroad > 0) + { + return !K_BotCanTakeCut(player); + } } return false; @@ -200,7 +217,7 @@ boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t if (!(rover->fofflags & FOF_BLOCKPLAYER)) { if ((top >= player->mo->z) && (bottom <= player->mo->z + player->mo->height) - && K_BotHatesThisSectorsSpecial(player, rover->master->frontsector)) + && K_BotHatesThisSectorsSpecial(player, rover->master->frontsector, flip)) { // Bad intangible sector at our height, so we DEFINITELY want to avoid return true; @@ -236,7 +253,7 @@ boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t return false; } - return K_BotHatesThisSectorsSpecial(player, bestsector); + return K_BotHatesThisSectorsSpecial(player, bestsector, flip); } /*-------------------------------------------------- @@ -254,6 +271,8 @@ boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t --------------------------------------------------*/ static void K_AddAttackObject(mobj_t *thing, UINT8 side, UINT8 weight) { + fixed_t x, y; + angle_t a, dir; UINT8 i; I_Assert(side <= 1); @@ -263,10 +282,21 @@ static void K_AddAttackObject(mobj_t *thing, UINT8 side, UINT8 weight) return; } + x = thing->x; + y = thing->y; + a = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, x, y); + + dir = a + (side ? -ANGLE_90 : ANGLE_90); + x += FixedMul(thing->radius, FINECOSINE(dir >> ANGLETOFINESHIFT)); + y += FixedMul(thing->radius, FINESINE(dir >> ANGLETOFINESHIFT)); + + x /= mapobjectscale; + y /= mapobjectscale; + for (i = 0; i < weight; i++) { - globalsmuggle.gotoAvgX[side] += thing->x / mapobjectscale; - globalsmuggle.gotoAvgY[side] += thing->y / mapobjectscale; + globalsmuggle.gotoAvgX[side] += x; + globalsmuggle.gotoAvgY[side] += y; globalsmuggle.gotoObjs[side]++; } } @@ -286,6 +316,8 @@ static void K_AddAttackObject(mobj_t *thing, UINT8 side, UINT8 weight) --------------------------------------------------*/ static void K_AddDodgeObject(mobj_t *thing, UINT8 side, UINT8 weight) { + fixed_t x, y; + angle_t a, dir; UINT8 i; I_Assert(side <= 1); @@ -295,11 +327,22 @@ static void K_AddDodgeObject(mobj_t *thing, UINT8 side, UINT8 weight) return; } + x = thing->x; + y = thing->y; + a = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, x, y); + + dir = a + (side ? -ANGLE_90 : ANGLE_90); + x += FixedMul(thing->radius, FINECOSINE(dir >> ANGLETOFINESHIFT)); + y += FixedMul(thing->radius, FINESINE(dir >> ANGLETOFINESHIFT)); + + x /= mapobjectscale; + y /= mapobjectscale; + for (i = 0; i < weight; i++) { - globalsmuggle.gotoAvgX[side] += thing->x / mapobjectscale; - globalsmuggle.gotoAvgY[side] += thing->y / mapobjectscale; - globalsmuggle.gotoObjs[side]++; + globalsmuggle.avoidAvgX[side] += x; + globalsmuggle.avoidAvgY[side] += y; + globalsmuggle.avoidObjs[side]++; } } @@ -349,7 +392,7 @@ static boolean K_PlayerAttackSteer(mobj_t *thing, UINT8 side, UINT8 weight, bool --------------------------------------------------*/ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing) { - INT16 anglediff; + INT16 angledelta, anglediff; fixed_t fulldist; angle_t destangle, angle, predictangle; UINT8 side = 0; @@ -387,15 +430,15 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing) if (angle < ANGLE_180) { - anglediff = AngleFixed(angle)>>FRACBITS; + angledelta = AngleFixed(angle)>>FRACBITS; } else { - anglediff = 360-(AngleFixed(angle)>>FRACBITS); + angledelta = 360-(AngleFixed(angle)>>FRACBITS); side = 1; } - anglediff = abs(anglediff); + anglediff = abs(angledelta); switch (thing->type) { @@ -621,23 +664,42 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player) INT32 xl, xh, yl, yh, bx, by; - fixed_t distToPredict = R_PointToDist2(player->mo->x, player->mo->y, predict->x, predict->y); + fixed_t distToPredict = 0; + fixed_t radToPredict = 0; + angle_t angleToPredict = 0; fixed_t avgX = 0, avgY = 0; fixed_t avgDist = 0; - const fixed_t baseNudge = predict->radius; - fixed_t maxNudge = distToPredict; + fixed_t baseNudge = 0; + fixed_t maxNudge = 0; fixed_t nudgeDist = 0; angle_t nudgeDir = 0; SINT8 gotoSide = -1; UINT8 i; + if (predict == NULL) + { + ps_bots[player - players].nudge += I_GetPreciseTime() - time; + return; + } + + distToPredict = R_PointToDist2(player->mo->x, player->mo->y, predict->x, predict->y); + radToPredict = distToPredict >> 1; + angleToPredict = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y); + + globalsmuggle.distancetocheck = distToPredict; + + baseNudge = predict->baseRadius >> 3; + maxNudge = predict->baseRadius - baseNudge; + globalsmuggle.botmo = player->mo; globalsmuggle.predict = predict; - globalsmuggle.distancetocheck = distToPredict; + // silly variable reuse + avgX = globalsmuggle.botmo->x + FixedMul(radToPredict, FINECOSINE(angleToPredict >> ANGLETOFINESHIFT)); + avgY = globalsmuggle.botmo->y + FixedMul(radToPredict, FINESINE(angleToPredict >> ANGLETOFINESHIFT)); for (i = 0; i < 2; i++) { @@ -648,10 +710,10 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player) globalsmuggle.avoidObjs[i] = 0; } - xl = (unsigned)(globalsmuggle.botmo->x - globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT; - xh = (unsigned)(globalsmuggle.botmo->x + globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT; - yl = (unsigned)(globalsmuggle.botmo->y - globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT; - yh = (unsigned)(globalsmuggle.botmo->y + globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT; + xl = (unsigned)(avgX - (distToPredict + MAXRADIUS) - bmaporgx)>>MAPBLOCKSHIFT; + xh = (unsigned)(avgX + (distToPredict + MAXRADIUS) - bmaporgx)>>MAPBLOCKSHIFT; + yl = (unsigned)(avgY - (distToPredict + MAXRADIUS) - bmaporgy)>>MAPBLOCKSHIFT; + yh = (unsigned)(avgY + (distToPredict + MAXRADIUS) - bmaporgy)>>MAPBLOCKSHIFT; BMBOUNDFIX(xl, xh, yl, yh); @@ -685,8 +747,6 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player) // High handling characters dodge better nudgeDist = ((9 - globalsmuggle.botmo->player->kartweight) + 1) * baseNudge; - - maxNudge = max(distToPredict - predict->radius, predict->radius); if (nudgeDist > maxNudge) { nudgeDist = maxNudge; @@ -700,6 +760,7 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player) predict->x += FixedMul(nudgeDist, FINECOSINE(nudgeDir >> ANGLETOFINESHIFT)); predict->y += FixedMul(nudgeDist, FINESINE(nudgeDir >> ANGLETOFINESHIFT)); + predict->radius = max(predict->radius - nudgeDist, baseNudge); distToPredict = R_PointToDist2(player->mo->x, player->mo->y, predict->x, predict->y); @@ -749,8 +810,6 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player) // Acceleration characters are more aggressive nudgeDist = ((9 - globalsmuggle.botmo->player->kartspeed) + 1) * baseNudge; - - maxNudge = max(distToPredict - predict->radius, predict->radius); if (nudgeDist > maxNudge) { nudgeDist = maxNudge; @@ -760,6 +819,7 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player) { predict->x = avgX; predict->y = avgY; + predict->radius = baseNudge; } else { @@ -771,6 +831,7 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player) predict->x += FixedMul(nudgeDist, FINECOSINE(nudgeDir >> ANGLETOFINESHIFT)); predict->y += FixedMul(nudgeDist, FINESINE(nudgeDir >> ANGLETOFINESHIFT)); + predict->radius = max(predict->radius - nudgeDist, baseNudge); //distToPredict = R_PointToDist2(player->mo->x, player->mo->y, predict->x, predict->y); } diff --git a/src/k_kart.c b/src/k_kart.c index 7e9a6b7c0..8f4240414 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8386,7 +8386,12 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player) boolean updaterespawn = false; // Our current waypoint. - player->currentwaypoint = bestwaypoint = waypoint; + bestwaypoint = waypoint; + + if (bestwaypoint != NULL) + { + player->currentwaypoint = bestwaypoint; + } // check the waypoint's location in relation to the player // If it's generally in front, it's fine, otherwise, use the best next/previous waypoint. @@ -10258,22 +10263,23 @@ static void K_AirFailsafe(player_t *player) // fixed_t K_PlayerBaseFriction(player_t *player, fixed_t original) { + const fixed_t factor = FixedDiv(FRACUNIT - original, FRACUNIT - ORIG_FRICTION); fixed_t frict = original; if (K_PodiumSequence() == true) { - frict -= FRACUNIT >> 4; + frict -= FixedMul(FRACUNIT >> 4, factor); } else if (K_PlayerUsesBotMovement(player) == true) { // A bit extra friction to help them without drifting. // Remove this line once they can drift. - frict -= FRACUNIT >> 5; + frict -= FixedMul(FRACUNIT >> 5, factor); // Bots gain more traction as they rubberband. if (player->botvars.rubberband > FRACUNIT) { - static const fixed_t extraFriction = FRACUNIT >> 5; + const fixed_t extraFriction = FixedMul(FRACUNIT >> 5, factor); const fixed_t mul = player->botvars.rubberband - FRACUNIT; frict -= FixedMul(extraFriction, mul); } diff --git a/src/p_map.c b/src/p_map.c index 320760582..5b539ad28 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1671,6 +1671,8 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) // Adjusts tm.floorz and tm.ceilingz as lines are contacted - FOR CAMERA ONLY static BlockItReturn_t PIT_CheckCameraLine(line_t *ld) { + opening_t open = {0}; + if (ld->polyobj && !(ld->polyobj->flags & POF_SOLID)) return BMIT_CONTINUE; @@ -1704,25 +1706,25 @@ static BlockItReturn_t PIT_CheckCameraLine(line_t *ld) } // set openrange, opentop, openbottom - P_CameraLineOpening(ld); + P_CameraLineOpening(ld, &open); // adjust floor / ceiling heights - if (opentop < tm.ceilingz) + if (open.ceiling < tm.ceilingz) { - tm.ceilingz = opentop; + tm.ceilingz = open.ceiling; tm.ceilingline = ld; } - if (openbottom > tm.floorz) + if (open.floor > tm.floorz) { - tm.floorz = openbottom; + tm.floorz = open.floor; } - if (highceiling > tm.drpoffceilz) - tm.drpoffceilz = highceiling; + if (open.highceiling > tm.drpoffceilz) + tm.drpoffceilz = open.highceiling; - if (lowfloor < tm.dropoffz) - tm.dropoffz = lowfloor; + if (open.lowfloor < tm.dropoffz) + tm.dropoffz = open.lowfloor; return BMIT_CONTINUE; } @@ -1773,6 +1775,7 @@ boolean P_IsLineTripWire(const line_t *ld) static BlockItReturn_t PIT_CheckLine(line_t *ld) { const fixed_t thingtop = tm.thing->z + tm.thing->height; + opening_t open = {0}; if (ld->polyobj && !(ld->polyobj->flags & POF_SOLID)) return BMIT_CONTINUE; @@ -1845,41 +1848,41 @@ static BlockItReturn_t PIT_CheckLine(line_t *ld) return BMIT_ABORT; // set openrange, opentop, openbottom - P_LineOpening(ld, tm.thing); + P_LineOpening(ld, tm.thing, &open); // adjust floor / ceiling heights - if (opentop < tm.ceilingz) + if (open.ceiling < tm.ceilingz) { - tm.ceilingz = opentop; + tm.ceilingz = open.ceiling; tm.ceilingline = ld; - tm.ceilingrover = openceilingrover; - tm.ceilingslope = opentopslope; - tm.ceilingpic = opentoppic; - tm.ceilingstep = openceilingstep; + tm.ceilingrover = open.ceilingrover; + tm.ceilingslope = open.ceilingslope; + tm.ceilingpic = open.ceilingpic; + tm.ceilingstep = open.ceilingstep; if (thingtop == tm.thing->ceilingz) { - tm.thing->ceilingdrop = openceilingdrop; + tm.thing->ceilingdrop = open.ceilingdrop; } } - if (openbottom > tm.floorz) + if (open.floor > tm.floorz) { - tm.floorz = openbottom; - tm.floorrover = openfloorrover; - tm.floorslope = openbottomslope; - tm.floorpic = openbottompic; - tm.floorstep = openfloorstep; + tm.floorz = open.floor; + tm.floorrover = open.floorrover; + tm.floorslope = open.floorslope; + tm.floorpic = open.floorpic; + tm.floorstep = open.floorstep; if (tm.thing->z == tm.thing->floorz) { - tm.thing->floordrop = openfloordrop; + tm.thing->floordrop = open.floordrop; } } - if (highceiling > tm.drpoffceilz) - tm.drpoffceilz = highceiling; + if (open.highceiling > tm.drpoffceilz) + tm.drpoffceilz = open.highceiling; - if (lowfloor < tm.dropoffz) - tm.dropoffz = lowfloor; + if (open.lowfloor < tm.dropoffz) + tm.dropoffz = open.lowfloor; // we've crossed the line if (P_SpecialIsLinedefCrossType(ld)) @@ -3462,6 +3465,7 @@ static void P_HitBounceLine(line_t *ld) static boolean PTR_SlideCameraTraverse(intercept_t *in) { line_t *li; + opening_t open = {0}; I_Assert(in->isaline); @@ -3476,15 +3480,15 @@ static boolean PTR_SlideCameraTraverse(intercept_t *in) } // set openrange, opentop, openbottom - P_CameraLineOpening(li); + P_CameraLineOpening(li, &open); - if (openrange < mapcampointer->height) + if (open.range < mapcampointer->height) goto isblocking; // doesn't fit - if (opentop - mapcampointer->z < mapcampointer->height) + if (open.ceiling - mapcampointer->z < mapcampointer->height) goto isblocking; // mobj is too high - if (openbottom - mapcampointer->z > 0) // We don't want to make the camera step up. + if (open.floor - mapcampointer->z > 0) // We don't want to make the camera step up. goto isblocking; // too big a step up // this line doesn't block movement @@ -3509,6 +3513,8 @@ isblocking: /* static boolean PTR_LineIsBlocking(line_t *li) { + opening_t open = {0}; + // one-sided linedefs are always solid to sliding movement. if (!li->backsector) return !P_PointOnLineSide(slidemo->x, slidemo->y, li); @@ -3517,15 +3523,15 @@ static boolean PTR_LineIsBlocking(line_t *li) return true; // set openrange, opentop, openbottom - P_LineOpening(li, slidemo); + P_LineOpening(li, slidemo, &open); - if (openrange < slidemo->height) + if (open.range < slidemo->height) return true; // doesn't fit - if (opentop - slidemo->z < slidemo->height) + if (open.ceiling - slidemo->z < slidemo->height) return true; // mobj is too high - if (openbottom - slidemo->z > P_GetThingStepUp(slidemo, slidemo->x, slidemo->y)) + if (open.floor - slidemo->z > P_GetThingStepUp(slidemo, slidemo->x, slidemo->y)) return true; // too big a step up return false; diff --git a/src/p_maputl.c b/src/p_maputl.c index 1a73ccea9..3ce1729cb 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -335,28 +335,24 @@ line_t * P_FindNearestLine // Sets opentop and openbottom to the window through a two sided line. // OPTIMIZE: keep this precalculated // -fixed_t opentop, openbottom, openrange, lowfloor, highceiling; -pslope_t *opentopslope, *openbottomslope; -ffloor_t *openfloorrover, *openceilingrover; -fixed_t openceilingstep; -fixed_t openceilingdrop; -fixed_t openfloorstep; -fixed_t openfloordrop; -INT32 opentoppic, openbottompic; // P_CameraLineOpening // P_LineOpening, but for camera // Tails 09-29-2002 -void P_CameraLineOpening(line_t *linedef) +void P_CameraLineOpening(line_t *linedef, opening_t *open) { sector_t *front; sector_t *back; fixed_t frontfloor, frontceiling, backfloor, backceiling; + fixed_t thingtop; + + open->ceiling = open->highceiling = INT32_MAX; + open->floor = open->lowfloor = INT32_MIN; + open->range = 0; if (linedef->sidenum[1] == 0xffff) { // single sided line - openrange = 0; return; } @@ -368,14 +364,14 @@ void P_CameraLineOpening(line_t *linedef) if (front->camsec >= 0) { // SRB2CBTODO: ESLOPE (sectors[front->heightsec].f_slope) - frontfloor = P_GetSectorFloorZAt (§ors[front->camsec], camera[0].x, camera[0].y); - frontceiling = P_GetSectorCeilingZAt(§ors[front->camsec], camera[0].x, camera[0].y); + frontfloor = P_GetSectorFloorZAt (§ors[front->camsec], mapcampointer->x, mapcampointer->y); + frontceiling = P_GetSectorCeilingZAt(§ors[front->camsec], mapcampointer->x, mapcampointer->y); } else if (front->heightsec >= 0) { // SRB2CBTODO: ESLOPE (sectors[front->heightsec].f_slope) - frontfloor = P_GetSectorFloorZAt (§ors[front->heightsec], camera[0].x, camera[0].y); - frontceiling = P_GetSectorCeilingZAt(§ors[front->heightsec], camera[0].x, camera[0].y); + frontfloor = P_GetSectorFloorZAt (§ors[front->heightsec], mapcampointer->x, mapcampointer->x); + frontceiling = P_GetSectorCeilingZAt(§ors[front->heightsec], mapcampointer->x, mapcampointer->y); } else { @@ -386,103 +382,101 @@ void P_CameraLineOpening(line_t *linedef) if (back->camsec >= 0) { // SRB2CBTODO: ESLOPE (sectors[back->heightsec].f_slope) - backfloor = P_GetSectorFloorZAt (§ors[back->camsec], camera[0].x, camera[0].y); - backceiling = P_GetSectorCeilingZAt(§ors[back->camsec], camera[0].x, camera[0].y); + backfloor = P_GetSectorFloorZAt (§ors[back->camsec], mapcampointer->x, mapcampointer->y); + backceiling = P_GetSectorCeilingZAt(§ors[back->camsec], mapcampointer->x, mapcampointer->y); } else if (back->heightsec >= 0) { // SRB2CBTODO: ESLOPE (sectors[back->heightsec].f_slope) - backfloor = P_GetSectorFloorZAt (§ors[back->heightsec], camera[0].x, camera[0].y); - backceiling = P_GetSectorCeilingZAt(§ors[back->heightsec], camera[0].x, camera[0].y); + backfloor = P_GetSectorFloorZAt (§ors[back->heightsec], mapcampointer->x, mapcampointer->y); + backceiling = P_GetSectorCeilingZAt(§ors[back->heightsec], mapcampointer->x, mapcampointer->y); } else { - backfloor = P_CameraGetFloorZ(mapcampointer, back, tm.x, tm.y, linedef); + backfloor = P_CameraGetFloorZ (mapcampointer, back, tm.x, tm.y, linedef); backceiling = P_CameraGetCeilingZ(mapcampointer, back, tm.x, tm.y, linedef); } + thingtop = mapcampointer->z + mapcampointer->height; + + if (frontceiling < backceiling) { - fixed_t thingtop = mapcampointer->z + mapcampointer->height; - - if (frontceiling < backceiling) - { - opentop = frontceiling; - highceiling = backceiling; - } - else - { - opentop = backceiling; - highceiling = frontceiling; - } - - if (frontfloor > backfloor) - { - openbottom = frontfloor; - lowfloor = backfloor; - } - else - { - openbottom = backfloor; - lowfloor = frontfloor; - } - - // Check for fake floors in the sector. - if (front->ffloors || back->ffloors) - { - ffloor_t *rover; - fixed_t delta1, delta2; - - // Check for frontsector's fake floors - if (front->ffloors) - for (rover = front->ffloors; rover; rover = rover->next) - { - fixed_t topheight, bottomheight; - if (!(rover->fofflags & FOF_BLOCKOTHERS) || !(rover->fofflags & FOF_RENDERALL) || !(rover->fofflags & FOF_EXISTS) || (rover->master->frontsector->flags & MSF_NOCLIPCAMERA)) - continue; - - topheight = P_CameraGetFOFTopZ(mapcampointer, front, rover, tm.x, tm.y, linedef); - bottomheight = P_CameraGetFOFBottomZ(mapcampointer, front, rover, tm.x, tm.y, linedef); - - delta1 = abs(mapcampointer->z - (bottomheight + ((topheight - bottomheight)/2))); - delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); - if (bottomheight < opentop && delta1 >= delta2) - opentop = bottomheight; - else if (bottomheight < highceiling && delta1 >= delta2) - highceiling = bottomheight; - - if (topheight > openbottom && delta1 < delta2) - openbottom = topheight; - else if (topheight > lowfloor && delta1 < delta2) - lowfloor = topheight; - } - - // Check for backsectors fake floors - if (back->ffloors) - for (rover = back->ffloors; rover; rover = rover->next) - { - fixed_t topheight, bottomheight; - if (!(rover->fofflags & FOF_BLOCKOTHERS) || !(rover->fofflags & FOF_RENDERALL) || !(rover->fofflags & FOF_EXISTS) || (rover->master->frontsector->flags & MSF_NOCLIPCAMERA)) - continue; - - topheight = P_CameraGetFOFTopZ(mapcampointer, back, rover, tm.x, tm.y, linedef); - bottomheight = P_CameraGetFOFBottomZ(mapcampointer, back, rover, tm.x, tm.y, linedef); - - delta1 = abs(mapcampointer->z - (bottomheight + ((topheight - bottomheight)/2))); - delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); - if (bottomheight < opentop && delta1 >= delta2) - opentop = bottomheight; - else if (bottomheight < highceiling && delta1 >= delta2) - highceiling = bottomheight; - - if (topheight > openbottom && delta1 < delta2) - openbottom = topheight; - else if (topheight > lowfloor && delta1 < delta2) - lowfloor = topheight; - } - } - openrange = opentop - openbottom; - return; + open->ceiling = frontceiling; + open->highceiling = backceiling; } + else + { + open->ceiling = backceiling; + open->highceiling = frontceiling; + } + + if (frontfloor > backfloor) + { + open->floor = frontfloor; + open->lowfloor = backfloor; + } + else + { + open->floor = backfloor; + open->lowfloor = frontfloor; + } + + // Check for fake floors in the sector. + if (front->ffloors || back->ffloors) + { + ffloor_t *rover; + fixed_t delta1, delta2; + + // Check for frontsector's fake floors + if (front->ffloors) + for (rover = front->ffloors; rover; rover = rover->next) + { + fixed_t topheight, bottomheight; + if (!(rover->fofflags & FOF_BLOCKOTHERS) || !(rover->fofflags & FOF_RENDERALL) || !(rover->fofflags & FOF_EXISTS) || (rover->master->frontsector->flags & MSF_NOCLIPCAMERA)) + continue; + + topheight = P_CameraGetFOFTopZ(mapcampointer, front, rover, tm.x, tm.y, linedef); + bottomheight = P_CameraGetFOFBottomZ(mapcampointer, front, rover, tm.x, tm.y, linedef); + + delta1 = abs(mapcampointer->z - (bottomheight + ((topheight - bottomheight)/2))); + delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); + if (bottomheight < open->ceiling && delta1 >= delta2) + open->ceiling = bottomheight; + else if (bottomheight < open->highceiling && delta1 >= delta2) + open->highceiling = bottomheight; + + if (topheight > open->floor && delta1 < delta2) + open->floor = topheight; + else if (topheight > open->lowfloor && delta1 < delta2) + open->lowfloor = topheight; + } + + // Check for backsectors fake floors + if (back->ffloors) + for (rover = back->ffloors; rover; rover = rover->next) + { + fixed_t topheight, bottomheight; + if (!(rover->fofflags & FOF_BLOCKOTHERS) || !(rover->fofflags & FOF_RENDERALL) || !(rover->fofflags & FOF_EXISTS) || (rover->master->frontsector->flags & MSF_NOCLIPCAMERA)) + continue; + + topheight = P_CameraGetFOFTopZ(mapcampointer, back, rover, tm.x, tm.y, linedef); + bottomheight = P_CameraGetFOFBottomZ(mapcampointer, back, rover, tm.x, tm.y, linedef); + + delta1 = abs(mapcampointer->z - (bottomheight + ((topheight - bottomheight)/2))); + delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); + if (bottomheight < open->ceiling && delta1 >= delta2) + open->ceiling = bottomheight; + else if (bottomheight < open->highceiling && delta1 >= delta2) + open->highceiling = bottomheight; + + if (topheight > open->floor && delta1 < delta2) + open->floor = topheight; + else if (topheight > open->lowfloor && delta1 < delta2) + open->lowfloor = topheight; + } + } + + open->range = (open->ceiling - open->floor); } boolean @@ -592,7 +586,7 @@ static boolean P_MidtextureIsSolid(line_t *linedef, mobj_t *mobj) return ((linedef->flags & ML_MIDSOLID) == ML_MIDSOLID); } -void P_LineOpening(line_t *linedef, mobj_t *mobj) +void P_LineOpening(line_t *linedef, mobj_t *mobj, opening_t *open) { enum { FRONT, BACK }; @@ -607,10 +601,19 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) int hi = 0; int lo = 0; + // set these defaults so that polyobjects don't interfere with collision above or below them + open->ceiling = open->highceiling = INT32_MAX; + open->floor = open->lowfloor = INT32_MIN; + open->range = 0; + open->ceilingslope = open->floorslope = NULL; + open->ceilingrover = open->floorrover = NULL; + open->ceilingpic = open->floorpic = -1; + open->ceilingstep = open->floorstep = 0; + open->ceilingdrop = open->floordrop = 0; + if (linedef->sidenum[1] == 0xffff) { // single sided line - openrange = 0; return; } @@ -636,23 +639,9 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) thingtop = mobj->z + mobj->height; } - openfloorrover = openceilingrover = NULL; - if (linedef->polyobj) + if (!linedef->polyobj) { - // set these defaults so that polyobjects don't interfere with collision above or below them - opentop = INT32_MAX; - openbottom = INT32_MIN; - highceiling = INT32_MIN; - lowfloor = INT32_MAX; - opentopslope = openbottomslope = NULL; - opentoppic = openbottompic = -1; - openceilingstep = 0; - openceilingdrop = 0; - openfloorstep = 0; - openfloordrop = 0; - } - else - { // Set open and high/low values here + // Set open and high/low values here fixed_t height[2]; const sector_t * sector[2] = { front, back }; @@ -662,18 +651,18 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) hi = ( height[0] < height[1] ); lo = ! hi; - opentop = height[lo]; - highceiling = height[hi]; - opentopslope = sector[lo]->c_slope; - opentoppic = sector[lo]->ceilingpic; + open->ceiling = height[lo]; + open->highceiling = height[hi]; + open->ceilingslope = sector[lo]->c_slope; + open->ceilingpic = sector[lo]->ceilingpic; if (mobj) { topedge[FRONT] = P_GetSectorCeilingZAt(front, cross.x, cross.y); topedge[BACK] = P_GetSectorCeilingZAt(back, cross.x, cross.y); - openceilingstep = ( thingtop - topedge[lo] ); - openceilingdrop = ( topedge[hi] - topedge[lo] ); + open->ceilingstep = ( thingtop - topedge[lo] ); + open->ceilingdrop = ( topedge[hi] - topedge[lo] ); } height[FRONT] = P_GetFloorZ(mobj, front, tm.x, tm.y, linedef); @@ -682,18 +671,18 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) hi = ( height[0] < height[1] ); lo = ! hi; - openbottom = height[hi]; - lowfloor = height[lo]; - openbottomslope = sector[hi]->f_slope; - openbottompic = sector[hi]->floorpic; + open->floor = height[hi]; + open->lowfloor = height[lo]; + open->floorslope = sector[hi]->f_slope; + open->floorpic = sector[hi]->floorpic; if (mobj) { botedge[FRONT] = P_GetSectorFloorZAt(front, cross.x, cross.y); botedge[BACK] = P_GetSectorFloorZAt(back, cross.x, cross.y); - openfloorstep = ( botedge[hi] - mobj->z ); - openfloordrop = ( botedge[hi] - botedge[lo] ); + open->floorstep = ( botedge[hi] - mobj->z ); + open->floordrop = ( botedge[hi] - botedge[lo] ); } } @@ -715,25 +704,25 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) if (delta1 > delta2) { // Below - if (opentop > texbottom) + if (open->ceiling > texbottom) { - topedge[lo] -= ( opentop - texbottom ); + topedge[lo] -= ( open->ceiling - texbottom ); - opentop = texbottom; - openceilingstep = ( thingtop - topedge[lo] ); - openceilingdrop = ( topedge[hi] - topedge[lo] ); + open->ceiling = texbottom; + open->ceilingstep = ( thingtop - topedge[lo] ); + open->ceilingdrop = ( topedge[hi] - topedge[lo] ); } } else { // Above - if (openbottom < textop) + if (open->floor < textop) { - botedge[hi] += ( textop - openbottom ); + botedge[hi] += ( textop - open->floor ); - openbottom = textop; - openfloorstep = ( botedge[hi] - mobj->z ); - openfloordrop = ( botedge[hi] - botedge[lo] ); + open->floor = textop; + open->floorstep = ( botedge[hi] - mobj->z ); + open->floordrop = ( botedge[hi] - botedge[lo] ); } } } @@ -745,7 +734,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) if (linedef->polyobj->flags & POF_TESTHEIGHT) { const sector_t *polysec = linedef->backsector; - fixed_t polytop, polybottom; + fixed_t polytop, polybottom, polymid; fixed_t delta1, delta2; if (linedef->polyobj->flags & POF_CLIPPLANES) @@ -759,25 +748,68 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) polybottom = INT32_MIN; } - delta1 = abs(mobj->z - (polybottom + ((polytop - polybottom)/2))); - delta2 = abs(thingtop - (polybottom + ((polytop - polybottom)/2))); + switch (open->fofType) + { + case LO_FOF_FLOORS: + { + if (mobj->z >= polytop) + { + if (polytop > open->floor) + { + open->floor = polytop; + } + else if (polytop > open->lowfloor) + { + open->lowfloor = polytop; + } + } + break; + } + case LO_FOF_CEILINGS: + { + if (thingtop <= polybottom) + { + if (polybottom < open->ceiling) + { + open->ceiling = polybottom; + } + else if (polybottom < open->highceiling) + { + open->highceiling = polybottom; + } + } + break; + } + default: + { + polymid = polybottom + (polytop - polybottom) / 2; + delta1 = abs(mobj->z - polymid); + delta2 = abs(thingtop - polymid); - if (polybottom < opentop && delta1 >= delta2) - { - opentop = polybottom; - } - else if (polybottom < highceiling && delta1 >= delta2) - { - highceiling = polybottom; - } - - if (polytop > openbottom && delta1 < delta2) - { - openbottom = polytop; - } - else if (polytop > lowfloor && delta1 < delta2) - { - lowfloor = polytop; + if (delta1 > delta2) + { + if (polybottom < open->ceiling) + { + open->ceiling = polybottom; + } + else if (polybottom < open->highceiling) + { + open->highceiling = polybottom; + } + } + else + { + if (polytop > open->floor) + { + open->floor = polytop; + } + else if (polytop > open->lowfloor) + { + open->lowfloor = polytop; + } + } + break; + } } } // otherwise don't do anything special, pretend there's nothing else there @@ -793,22 +825,20 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) /* yuck */ struct { - fixed_t top; - fixed_t bottom; + fixed_t ceiling; + fixed_t floor; ffloor_t * ceilingrover; ffloor_t * floorrover; - } open[2] = { + } fofopen[2] = { { INT32_MAX, INT32_MIN, NULL, NULL }, { INT32_MAX, INT32_MIN, NULL, NULL }, }; - const fixed_t oldopentop = opentop; - const fixed_t oldopenbottom = openbottom; - // Check for frontsector's fake floors for (rover = front->ffloors; rover; rover = rover->next) { - fixed_t topheight, bottomheight; + fixed_t topheight, bottomheight, midheight; + if (!(rover->fofflags & FOF_EXISTS)) continue; @@ -818,41 +848,89 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) || (rover->fofflags & FOF_BLOCKOTHERS && !mobj->player))) continue; - topheight = P_GetFOFTopZ(mobj, front, rover, tm.x, tm.y, linedef); - bottomheight = P_GetFOFBottomZ(mobj, front, rover, tm.x, tm.y, linedef); - - delta1 = abs(mobj->z - (bottomheight + ((topheight - bottomheight)/2))); - delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); - - if (delta1 >= delta2 && (rover->fofflags & FOF_INTANGIBLEFLATS) != FOF_PLATFORM) // thing is below FOF + if (open->fofType != LO_FOF_ANY) { - if (bottomheight < open[FRONT].top) { - open[FRONT].top = bottomheight; - opentopslope = *rover->b_slope; - opentoppic = *rover->bottompic; - open[FRONT].ceilingrover = rover; - } - else if (bottomheight < highceiling) - highceiling = bottomheight; + topheight = P_VeryTopOfFOF(rover); + bottomheight = P_VeryBottomOfFOF(rover); + } + else + { + topheight = P_GetFOFTopZ(mobj, front, rover, tm.x, tm.y, linedef); + bottomheight = P_GetFOFBottomZ(mobj, front, rover, tm.x, tm.y, linedef); } - if (delta1 < delta2 && (rover->fofflags & FOF_INTANGIBLEFLATS) != FOF_REVERSEPLATFORM) // thing is above FOF + switch (open->fofType) { - if (topheight > open[FRONT].bottom) { - open[FRONT].bottom = topheight; - openbottomslope = *rover->t_slope; - openbottompic = *rover->toppic; - open[FRONT].floorrover = rover; + case LO_FOF_FLOORS: + { + if (mobj->z >= topheight) + { + if ((rover->fofflags & FOF_INTANGIBLEFLATS) != FOF_REVERSEPLATFORM) + { + if (topheight > fofopen[FRONT].floor) + { + fofopen[FRONT].floor = topheight; + fofopen[FRONT].floorrover = rover; + } + } + } + break; + } + case LO_FOF_CEILINGS: + { + if (thingtop <= bottomheight) + { + if ((rover->fofflags & FOF_INTANGIBLEFLATS) != FOF_PLATFORM) + { + if (bottomheight < fofopen[FRONT].ceiling) + { + fofopen[FRONT].ceiling = bottomheight; + fofopen[FRONT].ceilingrover = rover; + } + } + } + break; + } + default: + { + midheight = bottomheight + (topheight - bottomheight) / 2; + delta1 = abs(mobj->z - midheight); + delta2 = abs(thingtop - midheight); + + if (delta1 > delta2) + { + // thing is below FOF + if ((rover->fofflags & FOF_INTANGIBLEFLATS) != FOF_PLATFORM) + { + if (bottomheight < fofopen[FRONT].ceiling) + { + fofopen[FRONT].ceiling = bottomheight; + fofopen[FRONT].ceilingrover = rover; + } + } + } + else + { + // thing is above FOF + if ((rover->fofflags & FOF_INTANGIBLEFLATS) != FOF_REVERSEPLATFORM) + { + if (topheight > fofopen[FRONT].floor) + { + fofopen[FRONT].floor = topheight; + fofopen[FRONT].floorrover = rover; + } + } + } + break; } - else if (topheight > lowfloor) - lowfloor = topheight; } } // Check for backsectors fake floors for (rover = back->ffloors; rover; rover = rover->next) { - fixed_t topheight, bottomheight; + fixed_t topheight, bottomheight, midheight; + if (!(rover->fofflags & FOF_EXISTS)) continue; @@ -862,79 +940,146 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) || (rover->fofflags & FOF_BLOCKOTHERS && !mobj->player))) continue; - topheight = P_GetFOFTopZ(mobj, back, rover, tm.x, tm.y, linedef); - bottomheight = P_GetFOFBottomZ(mobj, back, rover, tm.x, tm.y, linedef); - - delta1 = abs(mobj->z - (bottomheight + ((topheight - bottomheight)/2))); - delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); - - if (delta1 >= delta2 && (rover->fofflags & FOF_INTANGIBLEFLATS) != FOF_PLATFORM) // thing is below FOF + if (open->fofType != LO_FOF_ANY) { - if (bottomheight < open[BACK].top) { - open[BACK].top = bottomheight; - opentopslope = *rover->b_slope; - opentoppic = *rover->bottompic; - open[BACK].ceilingrover = rover; - } - else if (bottomheight < highceiling) - highceiling = bottomheight; + topheight = P_VeryTopOfFOF(rover); + bottomheight = P_VeryBottomOfFOF(rover); + } + else + { + topheight = P_GetFOFTopZ(mobj, back, rover, tm.x, tm.y, linedef); + bottomheight = P_GetFOFBottomZ(mobj, back, rover, tm.x, tm.y, linedef); } - if (delta1 < delta2 && (rover->fofflags & FOF_INTANGIBLEFLATS) != FOF_REVERSEPLATFORM) // thing is above FOF + switch (open->fofType) { - if (topheight > open[BACK].bottom) { - open[BACK].bottom = topheight; - openbottomslope = *rover->t_slope; - openbottompic = *rover->toppic; - open[BACK].floorrover = rover; + case LO_FOF_FLOORS: + { + if (mobj->z >= topheight) + { + if ((rover->fofflags & FOF_INTANGIBLEFLATS) != FOF_REVERSEPLATFORM) + { + if (topheight > fofopen[BACK].floor) + { + fofopen[BACK].floor = topheight; + fofopen[BACK].floorrover = rover; + } + } + } + break; + } + case LO_FOF_CEILINGS: + { + if (thingtop <= bottomheight) + { + if ((rover->fofflags & FOF_INTANGIBLEFLATS) != FOF_PLATFORM) + { + if (bottomheight < fofopen[BACK].ceiling) + { + fofopen[BACK].ceiling = bottomheight; + fofopen[BACK].ceilingrover = rover; + } + } + } + break; + } + default: + { + midheight = bottomheight + (topheight - bottomheight) / 2; + delta1 = abs(mobj->z - midheight); + delta2 = abs(thingtop - midheight); + + if (delta1 > delta2) + { + // thing is below FOF + if ((rover->fofflags & FOF_INTANGIBLEFLATS) != FOF_PLATFORM) + { + if (bottomheight < fofopen[BACK].ceiling) + { + fofopen[BACK].ceiling = bottomheight; + fofopen[BACK].ceilingrover = rover; + } + } + } + else + { + // thing is above FOF + if ((rover->fofflags & FOF_INTANGIBLEFLATS) != FOF_REVERSEPLATFORM) + { + if (topheight > fofopen[BACK].floor) + { + fofopen[BACK].floor = topheight; + fofopen[BACK].floorrover = rover; + } + } + } + break; } - else if (topheight > lowfloor) - lowfloor = topheight; } } - lo = ( open[0].top > open[1].top ); + hi = ( fofopen[0].ceiling < fofopen[1].ceiling ); + lo = ! hi; - if (open[lo].top <= oldopentop) + if (fofopen[lo].ceiling <= open->ceiling) { - hi = ! lo; + topedge[lo] = P_GetFFloorBottomZAt(fofopen[lo].ceilingrover, cross.x, cross.y); - topedge[lo] = P_GetFFloorBottomZAt(open[lo].ceilingrover, cross.x, cross.y); - - if (open[hi].top < oldopentop) + if (fofopen[hi].ceiling < open->ceiling) { - topedge[hi] = P_GetFFloorBottomZAt(open[hi].ceilingrover, cross.x, cross.y); + topedge[hi] = P_GetFFloorBottomZAt(fofopen[hi].ceilingrover, cross.x, cross.y); } - opentop = open[lo].top; - openceilingrover = open[lo].ceilingrover; - openceilingstep = ( thingtop - topedge[lo] ); - openceilingdrop = ( topedge[hi] - topedge[lo] ); + open->ceiling = fofopen[lo].ceiling; + open->ceilingrover = fofopen[lo].ceilingrover; + open->ceilingslope = *fofopen[lo].ceilingrover->b_slope; + open->ceilingpic = *fofopen[lo].ceilingrover->bottompic; + open->ceilingstep = ( thingtop - topedge[lo] ); + open->ceilingdrop = ( topedge[hi] - topedge[lo] ); + + if (fofopen[hi].ceiling < open->highceiling) + { + open->highceiling = fofopen[hi].ceiling; + } + } + else if (fofopen[lo].ceiling < open->highceiling) + { + open->highceiling = fofopen[lo].ceiling; } - hi = ( open[0].bottom < open[1].bottom ); + hi = ( fofopen[0].floor < fofopen[1].floor ); + lo = ! hi; - if (open[hi].bottom >= oldopenbottom) + if (fofopen[hi].floor >= open->floor) { - lo = ! hi; + botedge[hi] = P_GetFFloorTopZAt(fofopen[hi].floorrover, cross.x, cross.y); - botedge[hi] = P_GetFFloorTopZAt(open[hi].floorrover, cross.x, cross.y); - - if (open[lo].bottom > oldopenbottom) + if (fofopen[lo].floor > open->floor) { - botedge[lo] = P_GetFFloorTopZAt(open[lo].floorrover, cross.x, cross.y); + botedge[lo] = P_GetFFloorTopZAt(fofopen[lo].floorrover, cross.x, cross.y); } - openbottom = open[hi].bottom; - openfloorrover = open[hi].floorrover; - openfloorstep = ( botedge[hi] - mobj->z ); - openfloordrop = ( botedge[hi] - botedge[lo] ); + open->floor = fofopen[hi].floor; + open->floorrover = fofopen[hi].floorrover; + open->floorslope = *fofopen[hi].floorrover->t_slope; + open->floorpic = *fofopen[hi].floorrover->toppic; + open->floorstep = ( botedge[hi] - mobj->z ); + open->floordrop = ( botedge[hi] - botedge[lo] ); + + if (fofopen[lo].floor > open->lowfloor) + { + open->lowfloor = fofopen[lo].floor; + } + } + else if (fofopen[hi].floor > open->lowfloor) + { + open->lowfloor = fofopen[hi].floor; } } } } - openrange = opentop - openbottom; + open->range = (open->ceiling - open->floor); } diff --git a/src/p_maputl.h b/src/p_maputl.h index 5718afd04..0d6d5a346 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -50,7 +50,7 @@ void P_ClosestPointOnLine(fixed_t x, fixed_t y, line_t *line, vertex_t *result); void P_ClosestPointOnLine3D(const vector3_t *p, const vector3_t *line, vector3_t *result); INT32 P_PointOnLineSide(fixed_t x, fixed_t y, line_t *line); void P_MakeDivline(line_t *li, divline_t *dl); -void P_CameraLineOpening(line_t *plinedef); +void P_CameraLineOpening(line_t *plinedef, opening_t *open); fixed_t P_InterceptVector(divline_t *v2, divline_t *v1); INT32 P_BoxOnLineSide(fixed_t *tmbox, line_t *ld); line_t * P_FindNearestLine(const fixed_t x, const fixed_t y, const sector_t *, const INT32 special); @@ -61,16 +61,23 @@ void P_HitSpecialLines(mobj_t *thing, fixed_t x, fixed_t y, fixed_t momx, fixed_ boolean P_GetMidtextureTopBottom(line_t *linedef, fixed_t x, fixed_t y, fixed_t *return_top, fixed_t *return_bottom); -extern fixed_t opentop, openbottom, openrange, lowfloor, highceiling; -extern pslope_t *opentopslope, *openbottomslope; -extern ffloor_t *openfloorrover, *openceilingrover; -extern fixed_t openceilingstep; -extern fixed_t openceilingdrop; -extern fixed_t openfloorstep; -extern fixed_t openfloordrop; -extern INT32 opentoppic, openbottompic; +struct opening_t +{ + fixed_t ceiling, floor, range; + fixed_t lowfloor, highceiling; + pslope_t *floorslope, *ceilingslope; + ffloor_t *floorrover, *ceilingrover; + fixed_t ceilingstep, ceilingdrop; + fixed_t floorstep, floordrop; + INT32 ceilingpic, floorpic; + UINT8 fofType; // LO_FOF_ types for forcing FOF collide +}; -void P_LineOpening(line_t *plinedef, mobj_t *mobj); +#define LO_FOF_ANY (0) +#define LO_FOF_FLOORS (1) +#define LO_FOF_CEILINGS (2) + +void P_LineOpening(line_t *plinedef, mobj_t *mobj, opening_t *open); typedef enum { diff --git a/src/p_sight.c b/src/p_sight.c index 785f4248a..20d94484d 100644 --- a/src/p_sight.c +++ b/src/p_sight.c @@ -36,6 +36,7 @@ typedef struct mobj_t *t1, *t2; boolean alreadyHates; // For bot traversal, for if the bot is already in a sector it doesn't want to be + UINT8 traversed; } los_t; typedef boolean (*los_init_t)(mobj_t *, mobj_t *, register los_t *); @@ -51,6 +52,8 @@ typedef struct static INT32 sightcounts[2]; +#define TRAVERSE_MAX (2) + // // P_DivlineSide // @@ -360,8 +363,12 @@ static boolean P_CanTraceBlockingLine(seg_t *seg, divline_t *divl, register los_ static boolean P_CanBotTraverse(seg_t *seg, divline_t *divl, register los_t *los) { + const boolean flip = ((los->t1->eflags & MFE_VERTICALFLIP) == MFE_VERTICALFLIP); line_t *line = seg->linedef; + fixed_t frac = 0; + boolean canStepUp, canDropOff; fixed_t maxstep = 0; + opening_t open = {0}; if (P_CanTraceBlockingLine(seg, divl, los) == false) { @@ -369,45 +376,60 @@ static boolean P_CanBotTraverse(seg_t *seg, divline_t *divl, register los_t *los return false; } + // calculate fractional intercept (how far along we are divided by how far we are from t2) + frac = P_InterceptVector2(&los->strace, divl); + + // calculate position at intercept + tm.x = los->strace.x + FixedMul(los->strace.dx, frac); + tm.y = los->strace.y + FixedMul(los->strace.dy, frac); + // set openrange, opentop, openbottom - tm.x = los->t1->x; - tm.y = los->t1->y; - P_LineOpening(line, los->t1); + open.fofType = (flip ? LO_FOF_CEILINGS : LO_FOF_FLOORS); + P_LineOpening(line, los->t1, &open); maxstep = P_GetThingStepUp(los->t1, tm.x, tm.y); - if ((openrange < los->t1->height) // doesn't fit - || (opentop - los->t1->z < los->t1->height) // mobj is too high - || (openbottom - los->t1->z > maxstep)) // too big a step up + if (open.range < los->t1->height) { - // This line situationally blocks us + // Can't fit return false; } - if (los->t1->player != NULL && los->alreadyHates == false) + // If we can step up... + canStepUp = ((flip ? (open.highceiling - open.ceiling) : (open.floor - open.lowfloor)) <= maxstep); + + // Or if we're on the higher side... + canDropOff = (flip ? (los->t1->z + los->t1->height <= open.ceiling) : (los->t1->z >= open.floor)); + + if (canStepUp || canDropOff) { - // Treat damage sectors like walls, if you're not already in a bad sector. - sector_t *front, *back; - vertex_t pos; - - P_ClosestPointOnLine(tm.x, tm.y, line, &pos); - - front = seg->frontsector; - back = seg->backsector; - - if (K_BotHatesThisSector(los->t1->player, front, pos.x, pos.y) - || K_BotHatesThisSector(los->t1->player, back, pos.x, pos.y)) + if (los->t1->player != NULL && los->alreadyHates == false) { - // This line does not block us, but we don't want to be in it. - return false; + // Treat damage / offroad sectors like walls. + UINT8 side = P_DivlineSide(los->t2x, los->t2y, divl) & 1; + sector_t *sector = (side == 1) ? seg->backsector : seg->frontsector; + + if (K_BotHatesThisSector(los->t1->player, sector, tm.x, tm.y)) + { + // This line does not block us, but we don't want to cross it regardless. + return false; + } } + + return true; } - return true; + los->traversed++; + return (los->traversed < TRAVERSE_MAX); } static boolean P_CanWaypointTraverse(seg_t *seg, divline_t *divl, register los_t *los) { + const boolean flip = ((los->t1->eflags & MFE_VERTICALFLIP) == MFE_VERTICALFLIP); line_t *line = seg->linedef; + fixed_t frac = 0; + boolean canStepUp, canDropOff; + fixed_t maxstep = 0; + opening_t open = {0}; if (P_CanTraceBlockingLine(seg, divl, los) == false) { @@ -422,7 +444,65 @@ static boolean P_CanWaypointTraverse(seg_t *seg, divline_t *divl, register los_t return false; } - return true; + // calculate fractional intercept (how far along we are divided by how far we are from t2) + frac = P_InterceptVector2(&los->strace, divl); + + // calculate position at intercept + tm.x = los->strace.x + FixedMul(los->strace.dx, frac); + tm.y = los->strace.y + FixedMul(los->strace.dy, frac); + + // set openrange, opentop, openbottom + open.fofType = (flip ? LO_FOF_CEILINGS : LO_FOF_FLOORS); + P_LineOpening(line, los->t1, &open); + maxstep = P_GetThingStepUp(los->t1, tm.x, tm.y); + +#if 0 + if (los->t2->type == MT_WAYPOINT) + { + waypoint_t *wp = K_SearchWaypointHeapForMobj(los->t2); + + if (wp != NULL) + { + CONS_Printf( + "========\nID: %d\nrange: %.2f >= %.2f\n", + K_GetWaypointID(wp), + FIXED_TO_FLOAT(open.range), + FIXED_TO_FLOAT(los->t1->height) + ); + + if (open.range >= los->t1->height) + { + CONS_Printf( + "floor: %.2f\nlowfloor: %.2f\nstep: %.2f <= %.2f\n", + FIXED_TO_FLOAT(open.floor), + FIXED_TO_FLOAT(open.lowfloor), + FIXED_TO_FLOAT(open.floor - open.lowfloor), + FIXED_TO_FLOAT(maxstep) + ); + } + } + } +#endif + + if (open.range < los->t1->height) + { + // Can't fit + return false; + } + + // If we can step up... + canStepUp = ((flip ? (open.highceiling - open.ceiling) : (open.floor - open.lowfloor)) <= maxstep); + + // Or if we're on the higher side... + canDropOff = (flip ? (los->t1->z + los->t1->height <= open.ceiling) : (los->t1->z >= open.floor)); + + if (canStepUp || canDropOff) + { + return true; + } + + los->traversed++; + return (los->traversed < TRAVERSE_MAX); } // @@ -677,6 +757,7 @@ static boolean P_CompareMobjsAcrossLines(mobj_t *t1, mobj_t *t2, register los_fu los.t1 = t1; los.t2 = t2; los.alreadyHates = false; + los.traversed = 0; los.topslope = (los.bottomslope = t2->z - (los.sightzstart = diff --git a/src/typedef.h b/src/typedef.h index eaddda5e9..4bdb1673d 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -262,6 +262,7 @@ TYPEDEF (BasicFF_t); // p_maputl.h TYPEDEF (divline_t); TYPEDEF (intercept_t); +TYPEDEF (opening_t); // p_mobj.h TYPEDEF (mobj_t);