diff --git a/src/k_bot.c b/src/k_bot.c index be22c6a29..bcf5619d6 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -639,7 +639,7 @@ fixed_t K_DistanceOfLineFromPoint(fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t static fixed_t K_GetBotWaypointRadius(waypoint_t *const waypoint) { 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; @@ -678,6 +678,35 @@ static fixed_t K_GetBotWaypointRadius(waypoint_t *const waypoint) return 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; +} + /*-------------------------------------------------- static botprediction_t *K_CreateBotPrediction(player_t *player) @@ -701,8 +730,8 @@ 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. @@ -712,6 +741,8 @@ static botprediction_t *K_CreateBotPrediction(player_t *player) 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 +752,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 ); @@ -753,12 +794,14 @@ 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; + // If we can't get a direct path to this waypoint, reduce our prediction drastically. + distscaled *= 4; radreduce = FRACUNIT >> 1; } @@ -768,7 +811,7 @@ static botprediction_t *K_CreateBotPrediction(player_t *player) smallestradius = radius; } - distanceleft -= disttonext; + distanceleft -= distscaled; if (distanceleft <= 0) { @@ -794,25 +837,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 +1133,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 +1526,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 +1558,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 +1575,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_botsearch.c b/src/k_botsearch.c index 1dd3132b1..cdb818730 100644 --- a/src/k_botsearch.c +++ b/src/k_botsearch.c @@ -271,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); @@ -280,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]++; } } @@ -303,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); @@ -312,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]++; } } @@ -366,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; @@ -404,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) { @@ -638,23 +664,40 @@ 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; + 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); + angleToPredict = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y); + + globalsmuggle.distancetocheck = distToPredict >> 1; + + baseNudge = predict->radius * 2; + maxNudge = distToPredict; + globalsmuggle.botmo = player->mo; globalsmuggle.predict = predict; - globalsmuggle.distancetocheck = distToPredict; + // silly variable reuse + avgX = globalsmuggle.botmo->x + FixedMul(globalsmuggle.distancetocheck, FINECOSINE(angleToPredict >> ANGLETOFINESHIFT)); + avgY = globalsmuggle.botmo->y + FixedMul(globalsmuggle.distancetocheck, FINESINE(angleToPredict >> ANGLETOFINESHIFT)); for (i = 0; i < 2; i++) { @@ -665,10 +708,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 - (globalsmuggle.distancetocheck + MAXRADIUS) - bmaporgx)>>MAPBLOCKSHIFT; + xh = (unsigned)(avgX + (globalsmuggle.distancetocheck + MAXRADIUS) - bmaporgx)>>MAPBLOCKSHIFT; + yl = (unsigned)(avgY - (globalsmuggle.distancetocheck + MAXRADIUS) - bmaporgy)>>MAPBLOCKSHIFT; + yh = (unsigned)(avgY + (globalsmuggle.distancetocheck + MAXRADIUS) - bmaporgy)>>MAPBLOCKSHIFT; BMBOUNDFIX(xl, xh, yl, yh); diff --git a/src/k_kart.c b/src/k_kart.c index 9685280b2..c6bac7c57 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8352,7 +8352,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.