Improve general bot handling
- Their waypoint radius gets thinner quicker - Waypoint distance is scaled with each ones' floor slope, instead of done once at the end of the prediction. - Prediction is pulled back further when it goes through a wall - Prediction starts earlier and goes less far - Bots will brake at shallower angles (allows them to brake-turn more often) - K_AddDodgeObject and K_AddAttackObject now adjust based on the radius of the object - Fixed K_AddDodgeObject adding to the goto objects instead of avoid objects - Optimized blockmap search size for K_FindObjectsForNudging - Current waypoint is no longer cleared each frame
This commit is contained in:
parent
4aed50f673
commit
d3cb825d65
3 changed files with 122 additions and 56 deletions
100
src/k_bot.c
100
src/k_bot.c
|
|
@ -647,7 +647,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;
|
||||
|
|
@ -686,6 +686,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)
|
||||
|
||||
|
|
@ -706,8 +735,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.
|
||||
|
|
@ -717,6 +746,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;
|
||||
|
|
@ -726,15 +757,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
|
||||
);
|
||||
|
|
@ -758,12 +799,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 -= disttonext;
|
||||
// If we can't get a direct path to this waypoint, reduce our prediction drastically.
|
||||
distscaled *= 4;
|
||||
radreduce = FRACUNIT >> 1;
|
||||
}
|
||||
|
||||
|
|
@ -773,7 +816,7 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
|||
smallestradius = radius;
|
||||
}
|
||||
|
||||
distanceleft -= disttonext;
|
||||
distanceleft -= distscaled;
|
||||
|
||||
if (distanceleft <= 0)
|
||||
{
|
||||
|
|
@ -799,25 +842,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;
|
||||
}
|
||||
|
|
@ -968,7 +992,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;
|
||||
|
|
@ -1260,17 +1284,15 @@ 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);
|
||||
}
|
||||
|
||||
turnamt = K_HandleBotTrack(player, cmd, predict, destangle);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
|||
|
|
@ -262,6 +262,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);
|
||||
|
|
@ -271,10 +273,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]++;
|
||||
}
|
||||
}
|
||||
|
|
@ -294,6 +307,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);
|
||||
|
|
@ -303,11 +318,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]++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -357,7 +383,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;
|
||||
|
|
@ -395,15 +421,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)
|
||||
{
|
||||
|
|
@ -618,23 +644,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++)
|
||||
{
|
||||
|
|
@ -645,10 +688,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);
|
||||
|
||||
|
|
|
|||
|
|
@ -7042,6 +7042,7 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player)
|
|||
waypoint_t *waypoint = K_GetBestWaypointForMobj(player->mo);
|
||||
boolean updaterespawn = false;
|
||||
|
||||
// Our current waypoint.
|
||||
bestwaypoint = waypoint;
|
||||
|
||||
// check the waypoint's location in relation to the player
|
||||
|
|
|
|||
Loading…
Reference in a new issue