mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'yeaaaa-bots-lets-go' into 'master'
More Bot Improvements (Again (Again)) See merge request KartKrew/Kart!570
This commit is contained in:
commit
1835605619
11 changed files with 819 additions and 213 deletions
|
|
@ -3413,7 +3413,7 @@ static void Got_AddBot(UINT8 **p, INT32 playernum)
|
||||||
{
|
{
|
||||||
INT16 newplayernum;
|
INT16 newplayernum;
|
||||||
UINT8 skinnum = 0;
|
UINT8 skinnum = 0;
|
||||||
UINT8 difficulty = MAXBOTDIFFICULTY;
|
UINT8 difficulty = DIFFICULTBOT;
|
||||||
|
|
||||||
if (playernum != serverplayer && !IsPlayerAdmin(playernum))
|
if (playernum != serverplayer && !IsPlayerAdmin(playernum))
|
||||||
{
|
{
|
||||||
|
|
@ -5092,6 +5092,8 @@ static void SV_Maketic(void)
|
||||||
{
|
{
|
||||||
INT32 i;
|
INT32 i;
|
||||||
|
|
||||||
|
ps_botticcmd_time = 0;
|
||||||
|
|
||||||
for (i = 0; i < MAXPLAYERS; i++)
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
{
|
{
|
||||||
if (!playeringame[i])
|
if (!playeringame[i])
|
||||||
|
|
@ -5099,7 +5101,9 @@ static void SV_Maketic(void)
|
||||||
|
|
||||||
if (K_PlayerUsesBotMovement(&players[i]))
|
if (K_PlayerUsesBotMovement(&players[i]))
|
||||||
{
|
{
|
||||||
|
precise_t t = I_GetPreciseTime();
|
||||||
K_BuildBotTiccmd(&players[i], &netcmds[maketic%BACKUPTICS][i]);
|
K_BuildBotTiccmd(&players[i], &netcmds[maketic%BACKUPTICS][i]);
|
||||||
|
ps_botticcmd_time += I_GetPreciseTime() - t;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -399,9 +399,13 @@ static CV_PossibleValue_t kartbot_cons_t[] = {
|
||||||
{7, "Lv.7"},
|
{7, "Lv.7"},
|
||||||
{8, "Lv.8"},
|
{8, "Lv.8"},
|
||||||
{9, "Lv.9"},
|
{9, "Lv.9"},
|
||||||
|
{10,"Lv.10"},
|
||||||
|
{11,"Lv.11"},
|
||||||
|
{12,"Lv.12"},
|
||||||
|
{13,"Lv.MAX"},
|
||||||
{0, NULL}
|
{0, NULL}
|
||||||
};
|
};
|
||||||
consvar_t cv_kartbot = CVAR_INIT ("kartbot", "0", CV_NETVAR|CV_CHEAT, kartbot_cons_t, NULL);
|
consvar_t cv_kartbot = CVAR_INIT ("kartbot", "0", CV_NETVAR, kartbot_cons_t, NULL);
|
||||||
|
|
||||||
consvar_t cv_karteliminatelast = CVAR_INIT ("karteliminatelast", "Yes", CV_NETVAR|CV_CHEAT|CV_CALL, CV_YesNo, KartEliminateLast_OnChange);
|
consvar_t cv_karteliminatelast = CVAR_INIT ("karteliminatelast", "Yes", CV_NETVAR|CV_CHEAT|CV_CALL, CV_YesNo, KartEliminateLast_OnChange);
|
||||||
|
|
||||||
|
|
|
||||||
626
src/k_bot.c
626
src/k_bot.c
|
|
@ -167,7 +167,7 @@ void K_UpdateMatchRaceBots(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (difficulty == 0 || bossinfo.boss == true)
|
if (difficulty == 0 || !(gametyperules & GTR_BOTS) || bossinfo.boss == true)
|
||||||
{
|
{
|
||||||
wantedbots = 0;
|
wantedbots = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -294,6 +294,67 @@ boolean K_BotCanTakeCut(player_t *player)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------
|
||||||
|
static fixed_t K_BotSpeedScaled(player_t *player, fixed_t speed)
|
||||||
|
|
||||||
|
Gets the bot's speed value, adjusted for predictions.
|
||||||
|
Mainly to make bots brake earlier when on friction sectors.
|
||||||
|
|
||||||
|
Input Arguments:-
|
||||||
|
player - The bot player to calculate speed for.
|
||||||
|
speed - Raw speed value.
|
||||||
|
|
||||||
|
Return:-
|
||||||
|
The bot's speed value for calculations.
|
||||||
|
--------------------------------------------------*/
|
||||||
|
static fixed_t K_BotSpeedScaled(player_t *player, fixed_t speed)
|
||||||
|
{
|
||||||
|
fixed_t result = speed;
|
||||||
|
|
||||||
|
if (player->mo->movefactor != FRACUNIT)
|
||||||
|
{
|
||||||
|
fixed_t moveFactor = player->mo->movefactor;
|
||||||
|
|
||||||
|
if (moveFactor == 0)
|
||||||
|
{
|
||||||
|
moveFactor = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse against friction. Allows for bots to
|
||||||
|
// acknowledge they'll be moving faster on ice,
|
||||||
|
// and to steer harder / brake earlier.
|
||||||
|
moveFactor = FixedDiv(FRACUNIT, moveFactor);
|
||||||
|
|
||||||
|
// The full value is way too strong, reduce it.
|
||||||
|
moveFactor -= (moveFactor - FRACUNIT)*3/4;
|
||||||
|
|
||||||
|
result = FixedMul(result, moveFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player->mo->standingslope != NULL)
|
||||||
|
{
|
||||||
|
const pslope_t *slope = player->mo->standingslope;
|
||||||
|
|
||||||
|
if (!(slope->flags & SL_NOPHYSICS) && abs(slope->zdelta) >= FRACUNIT/21)
|
||||||
|
{
|
||||||
|
fixed_t slopeMul = FRACUNIT;
|
||||||
|
angle_t angle = K_MomentumAngle(player->mo) - slope->xydirection;
|
||||||
|
|
||||||
|
if (P_MobjFlip(player->mo) * slope->zdelta < 0)
|
||||||
|
angle ^= ANGLE_180;
|
||||||
|
|
||||||
|
// Going uphill: 0
|
||||||
|
// Going downhill: FRACUNIT*2
|
||||||
|
slopeMul = FRACUNIT + FINECOSINE(angle >> ANGLETOFINESHIFT);
|
||||||
|
|
||||||
|
// Range: 0.9 to 1.1
|
||||||
|
result = FixedMul(result, (FRACUNIT*9/10) + (slopeMul/10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
static line_t *K_FindBotController(mobj_t *mo)
|
static line_t *K_FindBotController(mobj_t *mo)
|
||||||
|
|
||||||
|
|
@ -426,7 +487,7 @@ static UINT32 K_BotRubberbandDistance(player_t *player)
|
||||||
fixed_t K_BotRubberband(player_t *player)
|
fixed_t K_BotRubberband(player_t *player)
|
||||||
{
|
{
|
||||||
fixed_t rubberband = FRACUNIT;
|
fixed_t rubberband = FRACUNIT;
|
||||||
fixed_t max, min;
|
fixed_t rubbermax, rubbermin;
|
||||||
player_t *firstplace = NULL;
|
player_t *firstplace = NULL;
|
||||||
line_t *botController = NULL;
|
line_t *botController = NULL;
|
||||||
UINT8 i;
|
UINT8 i;
|
||||||
|
|
@ -477,32 +538,34 @@ fixed_t K_BotRubberband(player_t *player)
|
||||||
if (wanteddist > player->distancetofinish)
|
if (wanteddist > player->distancetofinish)
|
||||||
{
|
{
|
||||||
// Whoa, you're too far ahead! Slow back down a little.
|
// Whoa, you're too far ahead! Slow back down a little.
|
||||||
rubberband += (MAXBOTDIFFICULTY - player->botvars.difficulty) * (distdiff / 3);
|
rubberband += (DIFFICULTBOT - min(DIFFICULTBOT, player->botvars.difficulty)) * (distdiff / 3);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Catch up to your position!
|
// Catch up to your position!
|
||||||
rubberband += (2*player->botvars.difficulty) * distdiff;
|
rubberband += player->botvars.difficulty * distdiff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lv. 1: x1.0 max
|
// Lv. 1: x1.0 max
|
||||||
// Lv. 5: x1.5 max
|
// Lv. 5: x1.4 max
|
||||||
// Lv. 9: x2.0 max
|
// Lv. 9: x1.8 max
|
||||||
max = FRACUNIT + ((FRACUNIT * (player->botvars.difficulty - 1)) / (MAXBOTDIFFICULTY - 1));
|
// Lv. MAX: x2.2 max
|
||||||
|
rubbermax = FRACUNIT + ((FRACUNIT * (player->botvars.difficulty - 1)) / 10);
|
||||||
|
|
||||||
// Lv. 1: x0.75 min
|
// Lv. 1: x0.75 min
|
||||||
// Lv. 5: x0.875 min
|
// Lv. 5: x0.875 min
|
||||||
// Lv. 9: x1.0 min
|
// Lv. 9: x1.0 min
|
||||||
min = FRACUNIT - (((FRACUNIT/4) * (MAXBOTDIFFICULTY - player->botvars.difficulty)) / (MAXBOTDIFFICULTY - 1));
|
// Lv. MAX: x1.0 min
|
||||||
|
rubbermin = FRACUNIT - (((FRACUNIT/4) * (DIFFICULTBOT - min(DIFFICULTBOT, player->botvars.difficulty))) / (DIFFICULTBOT - 1));
|
||||||
|
|
||||||
if (rubberband > max)
|
if (rubberband > rubbermax)
|
||||||
{
|
{
|
||||||
rubberband = max;
|
rubberband = rubbermax;
|
||||||
}
|
}
|
||||||
else if (rubberband < min)
|
else if (rubberband < rubbermin)
|
||||||
{
|
{
|
||||||
rubberband = min;
|
rubberband = rubbermin;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rubberband;
|
return rubberband;
|
||||||
|
|
@ -573,8 +636,9 @@ fixed_t K_BotTopSpeedRubberband(player_t *player)
|
||||||
--------------------------------------------------*/
|
--------------------------------------------------*/
|
||||||
fixed_t K_BotFrictionRubberband(player_t *player, fixed_t frict)
|
fixed_t K_BotFrictionRubberband(player_t *player, fixed_t frict)
|
||||||
{
|
{
|
||||||
|
const fixed_t value = 20776;
|
||||||
fixed_t rubberband = K_BotRubberband(player) - FRACUNIT;
|
fixed_t rubberband = K_BotRubberband(player) - FRACUNIT;
|
||||||
fixed_t origFrict, newFrict;
|
fixed_t newFrict = frict;
|
||||||
|
|
||||||
if (rubberband <= 0)
|
if (rubberband <= 0)
|
||||||
{
|
{
|
||||||
|
|
@ -584,30 +648,11 @@ fixed_t K_BotFrictionRubberband(player_t *player, fixed_t frict)
|
||||||
|
|
||||||
if (player->tiregrease > 0)
|
if (player->tiregrease > 0)
|
||||||
{
|
{
|
||||||
// This isn't great -- it means rubberbanding will slow down when they hit a spring
|
// Bots will lose all of their momentum without this.
|
||||||
// But it's better than the opposite where they accelerate into hyperspace :V
|
|
||||||
// (would appreciate an actual fix though ... could try being additive instead of multiplicative)
|
|
||||||
return frict;
|
return frict;
|
||||||
}
|
}
|
||||||
|
|
||||||
origFrict = FixedDiv(ORIG_FRICTION, FRACUNIT + (rubberband / 2));
|
newFrict = frict - FixedMul(value, rubberband);
|
||||||
|
|
||||||
if (frict == ORIG_FRICTION)
|
|
||||||
{
|
|
||||||
newFrict = origFrict;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Do some mumbo jumbo to make our friction value
|
|
||||||
// relative to what it WOULD be for ORIG_FRICTION.
|
|
||||||
// (I hate multiplicative friction :/)
|
|
||||||
|
|
||||||
fixed_t offset = ORIG_FRICTION - frict;
|
|
||||||
fixed_t ratio = FixedDiv(frict, ORIG_FRICTION);
|
|
||||||
|
|
||||||
offset = FixedDiv(offset, ratio);
|
|
||||||
newFrict = frict + offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newFrict < 0)
|
if (newFrict < 0)
|
||||||
newFrict = 0;
|
newFrict = 0;
|
||||||
|
|
@ -673,7 +718,7 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
||||||
const INT16 normal = KART_FULLTURN; // "Standard" handling to compare to
|
const INT16 normal = KART_FULLTURN; // "Standard" handling to compare to
|
||||||
|
|
||||||
const tic_t futuresight = (TICRATE * normal) / max(1, handling); // How far ahead into the future to try and predict
|
const tic_t futuresight = (TICRATE * normal) / max(1, handling); // How far ahead into the future to try and predict
|
||||||
const fixed_t speed = P_AproxDistance(player->mo->momx, player->mo->momy);
|
const fixed_t speed = K_BotSpeedScaled(player, P_AproxDistance(player->mo->momx, player->mo->momy));
|
||||||
|
|
||||||
const INT32 startDist = (768 * mapobjectscale) / FRACUNIT;
|
const INT32 startDist = (768 * mapobjectscale) / FRACUNIT;
|
||||||
const INT32 distance = ((speed / FRACUNIT) * futuresight) + startDist;
|
const INT32 distance = ((speed / FRACUNIT) * futuresight) + startDist;
|
||||||
|
|
@ -851,7 +896,7 @@ static UINT8 K_TrySpindash(player_t *player)
|
||||||
{
|
{
|
||||||
INT32 boosthold = starttime - K_GetSpindashChargeTime(player);
|
INT32 boosthold = starttime - K_GetSpindashChargeTime(player);
|
||||||
|
|
||||||
boosthold -= (MAXBOTDIFFICULTY - player->botvars.difficulty) * difficultyModifier;
|
boosthold -= (DIFFICULTBOT - min(DIFFICULTBOT, player->botvars.difficulty)) * difficultyModifier;
|
||||||
|
|
||||||
if (leveltime >= (unsigned)boosthold)
|
if (leveltime >= (unsigned)boosthold)
|
||||||
{
|
{
|
||||||
|
|
@ -1017,6 +1062,264 @@ static void K_BotTrick(player_t *player, ticcmd_t *cmd, line_t *botController)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------
|
||||||
|
static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t *predict)
|
||||||
|
|
||||||
|
Determines inputs for standard track driving.
|
||||||
|
|
||||||
|
Input Arguments:-
|
||||||
|
player - Player to generate the ticcmd for.
|
||||||
|
cmd - The player's ticcmd to modify.
|
||||||
|
predict - Pointer to the bot's prediction.
|
||||||
|
|
||||||
|
Return:-
|
||||||
|
New value for turn amount.
|
||||||
|
--------------------------------------------------*/
|
||||||
|
static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t *predict, angle_t destangle)
|
||||||
|
{
|
||||||
|
// Handle steering towards waypoints!
|
||||||
|
INT32 turnamt = 0;
|
||||||
|
SINT8 turnsign = 0;
|
||||||
|
angle_t moveangle, angle;
|
||||||
|
INT16 anglediff;
|
||||||
|
|
||||||
|
I_Assert(predict != NULL);
|
||||||
|
|
||||||
|
moveangle = player->mo->angle;
|
||||||
|
angle = (moveangle - destangle);
|
||||||
|
|
||||||
|
if (angle < ANGLE_180)
|
||||||
|
{
|
||||||
|
turnsign = -1; // Turn right
|
||||||
|
anglediff = AngleFixed(angle)>>FRACBITS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
turnsign = 1; // Turn left
|
||||||
|
anglediff = 360-(AngleFixed(angle)>>FRACBITS);
|
||||||
|
}
|
||||||
|
|
||||||
|
anglediff = abs(anglediff);
|
||||||
|
turnamt = KART_FULLTURN * turnsign;
|
||||||
|
|
||||||
|
if (anglediff > 90)
|
||||||
|
{
|
||||||
|
// Wrong way!
|
||||||
|
cmd->forwardmove = -MAXPLMOVE;
|
||||||
|
cmd->buttons |= BT_BRAKE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const fixed_t playerwidth = (player->mo->radius * 2);
|
||||||
|
fixed_t realrad = predict->radius - (playerwidth * 4); // Remove a "safe" distance away from the edges of the road
|
||||||
|
fixed_t rad = realrad;
|
||||||
|
fixed_t dirdist = K_DistanceOfLineFromPoint(
|
||||||
|
player->mo->x, player->mo->y,
|
||||||
|
player->mo->x + FINECOSINE(moveangle >> ANGLETOFINESHIFT), player->mo->y + FINESINE(moveangle >> ANGLETOFINESHIFT),
|
||||||
|
predict->x, predict->y
|
||||||
|
);
|
||||||
|
|
||||||
|
if (realrad < player->mo->radius)
|
||||||
|
{
|
||||||
|
realrad = player->mo->radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (anglediff > 0)
|
||||||
|
{
|
||||||
|
// Become more precise based on how hard you need to turn
|
||||||
|
// This makes predictions into turns a little nicer
|
||||||
|
// Facing 90 degrees away from the predicted point gives you a 1/3 radius
|
||||||
|
rad = FixedMul(rad, ((135 - anglediff) * FRACUNIT) / 135);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rad > realrad)
|
||||||
|
{
|
||||||
|
rad = realrad;
|
||||||
|
}
|
||||||
|
else if (rad < playerwidth)
|
||||||
|
{
|
||||||
|
rad = playerwidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd->buttons |= BT_ACCELERATE;
|
||||||
|
|
||||||
|
// Full speed ahead!
|
||||||
|
cmd->forwardmove = MAXPLMOVE;
|
||||||
|
|
||||||
|
if (dirdist <= rad)
|
||||||
|
{
|
||||||
|
fixed_t speedmul = FixedDiv(K_BotSpeedScaled(player, player->speed), K_GetKartSpeed(player, false));
|
||||||
|
fixed_t speedrad = rad/4;
|
||||||
|
|
||||||
|
if (speedmul > FRACUNIT)
|
||||||
|
{
|
||||||
|
speedmul = FRACUNIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increase radius with speed
|
||||||
|
// At low speed, the CPU will try to be more accurate
|
||||||
|
// At high speed, they're more likely to lawnmower
|
||||||
|
speedrad += FixedMul(speedmul, rad - speedrad);
|
||||||
|
|
||||||
|
if (speedrad < playerwidth)
|
||||||
|
{
|
||||||
|
speedrad = playerwidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dirdist <= speedrad)
|
||||||
|
{
|
||||||
|
// Don't turn at all
|
||||||
|
turnamt = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return turnamt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------
|
||||||
|
static INT32 K_HandleBotReverse(player_t *player, ticcmd_t *cmd, botprediction_t *predict)
|
||||||
|
|
||||||
|
Determines inputs for reversing.
|
||||||
|
|
||||||
|
Input Arguments:-
|
||||||
|
player - Player to generate the ticcmd for.
|
||||||
|
cmd - The player's ticcmd to modify.
|
||||||
|
predict - Pointer to the bot's prediction.
|
||||||
|
|
||||||
|
Return:-
|
||||||
|
New value for turn amount.
|
||||||
|
--------------------------------------------------*/
|
||||||
|
static INT32 K_HandleBotReverse(player_t *player, ticcmd_t *cmd, botprediction_t *predict, angle_t destangle)
|
||||||
|
{
|
||||||
|
// Handle steering towards waypoints!
|
||||||
|
INT32 turnamt = 0;
|
||||||
|
SINT8 turnsign = 0;
|
||||||
|
angle_t moveangle, angle;
|
||||||
|
INT16 anglediff, momdiff;
|
||||||
|
|
||||||
|
if (predict != NULL)
|
||||||
|
{
|
||||||
|
// TODO: Should we reverse through bot controllers?
|
||||||
|
return K_HandleBotTrack(player, cmd, predict, destangle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player->nextwaypoint == NULL
|
||||||
|
|| player->nextwaypoint->mobj == NULL
|
||||||
|
|| P_MobjWasRemoved(player->nextwaypoint->mobj))
|
||||||
|
{
|
||||||
|
// No data available...
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((player->nextwaypoint->prevwaypoints != NULL)
|
||||||
|
&& (player->nextwaypoint->numprevwaypoints > 0U))
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0U; i < player->nextwaypoint->numprevwaypoints; i++)
|
||||||
|
{
|
||||||
|
if (!K_GetWaypointIsEnabled(player->nextwaypoint->prevwaypoints[i]))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
destangle = R_PointToAngle2(
|
||||||
|
player->nextwaypoint->prevwaypoints[i]->mobj->x, player->nextwaypoint->prevwaypoints[i]->mobj->y,
|
||||||
|
player->nextwaypoint->mobj->x, player->nextwaypoint->mobj->y
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate turn direction first.
|
||||||
|
moveangle = player->mo->angle;
|
||||||
|
angle = (moveangle - destangle);
|
||||||
|
|
||||||
|
if (angle < ANGLE_180)
|
||||||
|
{
|
||||||
|
turnsign = -1; // Turn right
|
||||||
|
anglediff = AngleFixed(angle)>>FRACBITS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
turnsign = 1; // Turn left
|
||||||
|
anglediff = 360-(AngleFixed(angle)>>FRACBITS);
|
||||||
|
}
|
||||||
|
|
||||||
|
anglediff = abs(anglediff);
|
||||||
|
turnamt = KART_FULLTURN * turnsign;
|
||||||
|
|
||||||
|
// Now calculate momentum
|
||||||
|
momdiff = 180;
|
||||||
|
if (player->speed > player->mo->scale)
|
||||||
|
{
|
||||||
|
momdiff = 0;
|
||||||
|
moveangle = K_MomentumAngle(player->mo);
|
||||||
|
angle = (moveangle - destangle);
|
||||||
|
|
||||||
|
if (angle < ANGLE_180)
|
||||||
|
{
|
||||||
|
momdiff = AngleFixed(angle)>>FRACBITS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
momdiff = 360-(AngleFixed(angle)>>FRACBITS);
|
||||||
|
}
|
||||||
|
|
||||||
|
momdiff = abs(momdiff);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (anglediff > 90 || momdiff < 90)
|
||||||
|
{
|
||||||
|
// We're not facing the track,
|
||||||
|
// or we're going too fast.
|
||||||
|
// Let's E-Brake.
|
||||||
|
cmd->forwardmove = 0;
|
||||||
|
cmd->buttons |= BT_ACCELERATE|BT_BRAKE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fixed_t slopeMul = FRACUNIT;
|
||||||
|
|
||||||
|
if (player->mo->standingslope != NULL)
|
||||||
|
{
|
||||||
|
const pslope_t *slope = player->mo->standingslope;
|
||||||
|
|
||||||
|
if (!(slope->flags & SL_NOPHYSICS) && abs(slope->zdelta) >= FRACUNIT/21)
|
||||||
|
{
|
||||||
|
angle_t sangle = player->mo->angle - slope->xydirection;
|
||||||
|
|
||||||
|
if (P_MobjFlip(player->mo) * slope->zdelta < 0)
|
||||||
|
sangle ^= ANGLE_180;
|
||||||
|
|
||||||
|
slopeMul = FRACUNIT - FINECOSINE(sangle >> ANGLETOFINESHIFT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define STEEP_SLOPE (FRACUNIT*11/10)
|
||||||
|
if (slopeMul > STEEP_SLOPE)
|
||||||
|
{
|
||||||
|
// Slope is too steep to reverse -- EBrake.
|
||||||
|
cmd->forwardmove = 0;
|
||||||
|
cmd->buttons |= BT_ACCELERATE|BT_BRAKE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cmd->forwardmove = -MAXPLMOVE;
|
||||||
|
cmd->buttons |= BT_BRAKE; //|BT_LOOKBACK
|
||||||
|
}
|
||||||
|
#undef STEEP_SLOPE
|
||||||
|
|
||||||
|
if (anglediff < 10)
|
||||||
|
{
|
||||||
|
turnamt = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return turnamt;
|
||||||
|
}
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
||||||
|
|
||||||
|
|
@ -1026,6 +1329,7 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
||||||
{
|
{
|
||||||
botprediction_t *predict = NULL;
|
botprediction_t *predict = NULL;
|
||||||
boolean trySpindash = true;
|
boolean trySpindash = true;
|
||||||
|
angle_t destangle = 0;
|
||||||
UINT8 spindash = 0;
|
UINT8 spindash = 0;
|
||||||
INT32 turnamt = 0;
|
INT32 turnamt = 0;
|
||||||
line_t *botController = NULL;
|
line_t *botController = NULL;
|
||||||
|
|
@ -1039,13 +1343,11 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
||||||
// Remove any existing controls
|
// Remove any existing controls
|
||||||
memset(cmd, 0, sizeof(ticcmd_t));
|
memset(cmd, 0, sizeof(ticcmd_t));
|
||||||
|
|
||||||
if (
|
if (gamestate != GS_LEVEL
|
||||||
gamestate != GS_LEVEL
|
|
||||||
|| player->mo->scale <= 1
|
|| player->mo->scale <= 1
|
||||||
|| player->playerstate == PST_DEAD
|
|| player->playerstate == PST_DEAD
|
||||||
|| leveltime <= introtime
|
|| leveltime <= introtime
|
||||||
|| (player->exiting && !(gametyperules & GTR_CIRCUIT))
|
|| !(gametyperules & GTR_BOTS))
|
||||||
)
|
|
||||||
{
|
{
|
||||||
// No need to do anything else.
|
// No need to do anything else.
|
||||||
return;
|
return;
|
||||||
|
|
@ -1067,170 +1369,133 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((player->nextwaypoint != NULL
|
destangle = player->mo->angle;
|
||||||
&& player->nextwaypoint->mobj != NULL
|
|
||||||
&& !P_MobjWasRemoved(player->nextwaypoint->mobj))
|
if (botController != NULL && (botController->flags & ML_EFFECT1))
|
||||||
|| (botController != NULL))
|
|
||||||
{
|
{
|
||||||
// Handle steering towards waypoints!
|
const fixed_t dist = (player->mo->radius * 4);
|
||||||
SINT8 turnsign = 0;
|
|
||||||
angle_t destangle, moveangle, angle;
|
|
||||||
INT16 anglediff;
|
|
||||||
|
|
||||||
if (botController != NULL && (botController->flags & ML_EFFECT1))
|
// X Offset: Movement direction
|
||||||
{
|
destangle = FixedAngle(sides[botController->sidenum[0]].textureoffset);
|
||||||
const fixed_t dist = (player->mo->radius * 4);
|
|
||||||
|
|
||||||
// X Offset: Movement direction
|
// Overwritten prediction
|
||||||
destangle = FixedAngle(sides[botController->sidenum[0]].textureoffset);
|
predict = Z_Calloc(sizeof(botprediction_t), PU_STATIC, NULL);
|
||||||
|
|
||||||
// Overwritten prediction
|
predict->x = player->mo->x + FixedMul(dist, FINECOSINE(destangle >> ANGLETOFINESHIFT));
|
||||||
predict = Z_Calloc(sizeof(botprediction_t), PU_STATIC, NULL);
|
predict->y = player->mo->y + FixedMul(dist, FINESINE(destangle >> ANGLETOFINESHIFT));
|
||||||
|
predict->radius = (DEFAULT_WAYPOINT_RADIUS / 4) * mapobjectscale;
|
||||||
predict->x = player->mo->x + FixedMul(dist, FINECOSINE(destangle >> ANGLETOFINESHIFT));
|
|
||||||
predict->y = player->mo->y + FixedMul(dist, FINESINE(destangle >> ANGLETOFINESHIFT));
|
|
||||||
predict->radius = (DEFAULT_WAYPOINT_RADIUS / 4) * mapobjectscale;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
predict = K_CreateBotPrediction(player);
|
|
||||||
|
|
||||||
K_NudgePredictionTowardsObjects(predict, player);
|
|
||||||
|
|
||||||
destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y);
|
|
||||||
}
|
|
||||||
|
|
||||||
moveangle = player->mo->angle;
|
|
||||||
angle = (moveangle - destangle);
|
|
||||||
|
|
||||||
if (angle < ANGLE_180)
|
|
||||||
{
|
|
||||||
turnsign = -1; // Turn right
|
|
||||||
anglediff = AngleFixed(angle)>>FRACBITS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
turnsign = 1; // Turn left
|
|
||||||
anglediff = 360-(AngleFixed(angle)>>FRACBITS);
|
|
||||||
}
|
|
||||||
|
|
||||||
anglediff = abs(anglediff);
|
|
||||||
turnamt = KART_FULLTURN * turnsign;
|
|
||||||
|
|
||||||
if (anglediff > 90)
|
|
||||||
{
|
|
||||||
// Wrong way!
|
|
||||||
cmd->forwardmove = -MAXPLMOVE;
|
|
||||||
cmd->buttons |= BT_BRAKE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const fixed_t playerwidth = (player->mo->radius * 2);
|
|
||||||
fixed_t realrad = predict->radius - (playerwidth * 4); // Remove a "safe" distance away from the edges of the road
|
|
||||||
fixed_t rad = realrad;
|
|
||||||
fixed_t dirdist = K_DistanceOfLineFromPoint(
|
|
||||||
player->mo->x, player->mo->y,
|
|
||||||
player->mo->x + FINECOSINE(moveangle >> ANGLETOFINESHIFT), player->mo->y + FINESINE(moveangle >> ANGLETOFINESHIFT),
|
|
||||||
predict->x, predict->y
|
|
||||||
);
|
|
||||||
|
|
||||||
if (anglediff > 0)
|
|
||||||
{
|
|
||||||
// Become more precise based on how hard you need to turn
|
|
||||||
// This makes predictions into turns a little nicer
|
|
||||||
// Facing 90 degrees away from the predicted point gives you a 1/3 radius
|
|
||||||
rad = FixedMul(rad, ((135 - anglediff) * FRACUNIT) / 135);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rad > realrad)
|
|
||||||
{
|
|
||||||
rad = realrad;
|
|
||||||
}
|
|
||||||
else if (rad < playerwidth)
|
|
||||||
{
|
|
||||||
rad = playerwidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd->buttons |= BT_ACCELERATE;
|
|
||||||
|
|
||||||
// Full speed ahead!
|
|
||||||
cmd->forwardmove = MAXPLMOVE;
|
|
||||||
|
|
||||||
if (dirdist <= rad)
|
|
||||||
{
|
|
||||||
fixed_t speedmul = FixedDiv(player->speed, K_GetKartSpeed(player, false));
|
|
||||||
fixed_t speedrad = rad/4;
|
|
||||||
|
|
||||||
if (speedmul > FRACUNIT)
|
|
||||||
{
|
|
||||||
speedmul = FRACUNIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increase radius with speed
|
|
||||||
// At low speed, the CPU will try to be more accurate
|
|
||||||
// At high speed, they're more likely to lawnmower
|
|
||||||
speedrad += FixedMul(speedmul, rad - speedrad);
|
|
||||||
|
|
||||||
if (speedrad < playerwidth)
|
|
||||||
{
|
|
||||||
speedrad = playerwidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dirdist <= speedrad)
|
|
||||||
{
|
|
||||||
// Don't turn at all
|
|
||||||
turnamt = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leveltime <= starttime && finishBeamLine != NULL)
|
if (leveltime <= starttime && finishBeamLine != NULL)
|
||||||
{
|
{
|
||||||
|
// Handle POSITION!!
|
||||||
const fixed_t distBase = 384*mapobjectscale;
|
const fixed_t distBase = 384*mapobjectscale;
|
||||||
const fixed_t distAdjust = 64*mapobjectscale;
|
const fixed_t distAdjust = 64*mapobjectscale;
|
||||||
|
|
||||||
const fixed_t closeDist = distBase + (distAdjust * (9 - player->kartweight));
|
const fixed_t closeDist = distBase + (distAdjust * (9 - player->kartweight));
|
||||||
const fixed_t farDist = closeDist + (distAdjust * 2);
|
const fixed_t farDist = closeDist + (distAdjust * 2);
|
||||||
|
|
||||||
|
const tic_t futureSight = (TICRATE >> 1);
|
||||||
|
|
||||||
fixed_t distToFinish = K_DistanceOfLineFromPoint(
|
fixed_t distToFinish = K_DistanceOfLineFromPoint(
|
||||||
finishBeamLine->v1->x, finishBeamLine->v1->y,
|
finishBeamLine->v1->x, finishBeamLine->v1->y,
|
||||||
finishBeamLine->v2->x, finishBeamLine->v2->y,
|
finishBeamLine->v2->x, finishBeamLine->v2->y,
|
||||||
player->mo->x, player->mo->y
|
player->mo->x, player->mo->y
|
||||||
) - player->speed;
|
) - (K_BotSpeedScaled(player, player->speed) * futureSight);
|
||||||
|
|
||||||
// Don't run the spindash code at all until we're in the right place
|
// Don't run the spindash code at all until we're in the right place
|
||||||
trySpindash = false;
|
trySpindash = false;
|
||||||
|
|
||||||
// If you're too far, enable spindash & stay still.
|
|
||||||
// If you're too close, start backing up.
|
|
||||||
|
|
||||||
if (distToFinish < closeDist)
|
if (distToFinish < closeDist)
|
||||||
{
|
{
|
||||||
// Silly way of getting us to reverse, but it respects the above code
|
// We're too close, we need to start backing up.
|
||||||
// where we figure out what the shape of the track looks like.
|
turnamt = K_HandleBotReverse(player, cmd, predict, destangle);
|
||||||
UINT16 oldButtons = cmd->buttons;
|
|
||||||
|
|
||||||
cmd->buttons &= ~(BT_ACCELERATE|BT_BRAKE);
|
|
||||||
|
|
||||||
if (oldButtons & BT_ACCELERATE)
|
|
||||||
{
|
|
||||||
cmd->buttons |= BT_BRAKE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldButtons & BT_BRAKE)
|
|
||||||
{
|
|
||||||
cmd->buttons |= BT_ACCELERATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd->forwardmove = -cmd->forwardmove;
|
|
||||||
}
|
}
|
||||||
else if (distToFinish < farDist)
|
else if (distToFinish < farDist)
|
||||||
{
|
{
|
||||||
// We're in about the right place, spindash now.
|
INT32 bullyTurn = INT32_MAX;
|
||||||
cmd->forwardmove = 0;
|
|
||||||
trySpindash = true;
|
// We're in about the right place, let's do whatever we want to.
|
||||||
|
|
||||||
|
if (player->kartspeed >= 5)
|
||||||
|
{
|
||||||
|
// Faster characters want to spindash.
|
||||||
|
// Slower characters will use their momentum.
|
||||||
|
trySpindash = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for characters to bully.
|
||||||
|
bullyTurn = K_PositionBully(player);
|
||||||
|
if (bullyTurn == INT32_MAX)
|
||||||
|
{
|
||||||
|
// No one to bully, just go for a spindash as anyone.
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
turnamt = K_HandleBotTrack(player, cmd, predict, destangle);
|
||||||
|
cmd->buttons &= ~(BT_ACCELERATE|BT_BRAKE);
|
||||||
|
cmd->forwardmove = 0;
|
||||||
|
trySpindash = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
turnamt = bullyTurn;
|
||||||
|
|
||||||
|
// If already spindashing, wait until we get a relatively OK charge first.
|
||||||
|
if (player->spindash == 0 || player->spindash > TICRATE)
|
||||||
|
{
|
||||||
|
trySpindash = false;
|
||||||
|
cmd->buttons |= BT_ACCELERATE;
|
||||||
|
cmd->forwardmove = MAXPLMOVE;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Too far away, we need to just drive up.
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
turnamt = K_HandleBotTrack(player, cmd, predict, destangle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Handle steering towards waypoints!
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
turnamt = K_HandleBotTrack(player, cmd, predict, destangle);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trySpindash == true)
|
if (trySpindash == true)
|
||||||
|
|
@ -1315,4 +1580,3 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
||||||
Z_Free(predict);
|
Z_Free(predict);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
20
src/k_bot.h
20
src/k_bot.h
|
|
@ -18,7 +18,10 @@
|
||||||
#include "r_defs.h"
|
#include "r_defs.h"
|
||||||
|
|
||||||
// Maximum value of botvars.difficulty
|
// Maximum value of botvars.difficulty
|
||||||
#define MAXBOTDIFFICULTY 9
|
#define MAXBOTDIFFICULTY 13
|
||||||
|
|
||||||
|
// Level of a "difficult" bot. The max bot level was increased, but this keeps all of the same calculations.
|
||||||
|
#define DIFFICULTBOT 9
|
||||||
|
|
||||||
// How many tics in a row do you need to turn in this direction before we'll let you turn.
|
// How many tics in a row do you need to turn in this direction before we'll let you turn.
|
||||||
// Made it as small as possible without making it look like the bots are twitching constantly.
|
// Made it as small as possible without making it look like the bots are twitching constantly.
|
||||||
|
|
@ -220,6 +223,21 @@ boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t
|
||||||
void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player);
|
void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player);
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------
|
||||||
|
INT32 K_PositionBully(player_t *player)
|
||||||
|
|
||||||
|
Calculates a turn value to reach a player that can be bullied.
|
||||||
|
|
||||||
|
Input Arguments:-
|
||||||
|
player - Bot to run this for.
|
||||||
|
|
||||||
|
Return:-
|
||||||
|
INT32_MAX if couldn't find anything, otherwise a steering value.
|
||||||
|
--------------------------------------------------*/
|
||||||
|
|
||||||
|
INT32 K_PositionBully(player_t *player);
|
||||||
|
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd);
|
void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,9 @@ struct globalsmuggle
|
||||||
INT64 avoidAvgX[2], avoidAvgY[2];
|
INT64 avoidAvgX[2], avoidAvgY[2];
|
||||||
UINT32 avoidObjs[2];
|
UINT32 avoidObjs[2];
|
||||||
|
|
||||||
|
fixed_t annoyscore;
|
||||||
|
mobj_t *annoymo;
|
||||||
|
|
||||||
fixed_t closestlinedist;
|
fixed_t closestlinedist;
|
||||||
|
|
||||||
fixed_t eggboxx, eggboxy;
|
fixed_t eggboxx, eggboxy;
|
||||||
|
|
@ -771,3 +774,151 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------
|
||||||
|
static boolean K_FindPlayersToBully(mobj_t *thing)
|
||||||
|
|
||||||
|
Blockmap search function.
|
||||||
|
Finds players around the bot to bump.
|
||||||
|
|
||||||
|
Input Arguments:-
|
||||||
|
thing - Object passed in from iteration.
|
||||||
|
|
||||||
|
Return:-
|
||||||
|
true continues searching, false ends the search early.
|
||||||
|
--------------------------------------------------*/
|
||||||
|
static boolean K_FindPlayersToBully(mobj_t *thing)
|
||||||
|
{
|
||||||
|
INT16 anglediff;
|
||||||
|
fixed_t fulldist;
|
||||||
|
fixed_t ourweight, theirweight, weightdiff;
|
||||||
|
angle_t ourangle, destangle, angle;
|
||||||
|
|
||||||
|
if (!globalsmuggle.botmo || P_MobjWasRemoved(globalsmuggle.botmo) || !globalsmuggle.botmo->player)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thing->health <= 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!thing->player)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (globalsmuggle.botmo == thing)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fulldist = R_PointToDist2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, thing->x, thing->y) - thing->radius;
|
||||||
|
|
||||||
|
if (fulldist > globalsmuggle.distancetocheck)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (P_CheckSight(globalsmuggle.botmo, thing) == false)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ourangle = globalsmuggle.botmo->angle;
|
||||||
|
destangle = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, thing->x, thing->y);
|
||||||
|
angle = (ourangle - destangle);
|
||||||
|
|
||||||
|
if (angle < ANGLE_180)
|
||||||
|
{
|
||||||
|
anglediff = AngleFixed(angle)>>FRACBITS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
anglediff = 360-(AngleFixed(angle)>>FRACBITS);
|
||||||
|
}
|
||||||
|
|
||||||
|
anglediff = abs(anglediff);
|
||||||
|
|
||||||
|
ourweight = K_GetMobjWeight(globalsmuggle.botmo, thing);
|
||||||
|
theirweight = K_GetMobjWeight(thing, globalsmuggle.botmo);
|
||||||
|
weightdiff = 0;
|
||||||
|
|
||||||
|
if (anglediff >= 90)
|
||||||
|
{
|
||||||
|
weightdiff = theirweight - ourweight;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
weightdiff = ourweight - theirweight;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weightdiff > mapobjectscale && weightdiff > globalsmuggle.annoyscore)
|
||||||
|
{
|
||||||
|
globalsmuggle.annoyscore = weightdiff;
|
||||||
|
globalsmuggle.annoymo = thing;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------
|
||||||
|
INT32 K_PositionBully(player_t *player)
|
||||||
|
|
||||||
|
See header file for description.
|
||||||
|
--------------------------------------------------*/
|
||||||
|
INT32 K_PositionBully(player_t *player)
|
||||||
|
{
|
||||||
|
INT32 xl, xh, yl, yh, bx, by;
|
||||||
|
|
||||||
|
angle_t ourangle, destangle, angle;
|
||||||
|
INT16 anglediff;
|
||||||
|
|
||||||
|
globalsmuggle.botmo = player->mo;
|
||||||
|
globalsmuggle.distancetocheck = 1024*player->mo->scale;
|
||||||
|
|
||||||
|
globalsmuggle.annoymo = NULL;
|
||||||
|
globalsmuggle.annoyscore = 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;
|
||||||
|
|
||||||
|
BMBOUNDFIX(xl, xh, yl, yh);
|
||||||
|
|
||||||
|
for (bx = xl; bx <= xh; bx++)
|
||||||
|
{
|
||||||
|
for (by = yl; by <= yh; by++)
|
||||||
|
{
|
||||||
|
P_BlockThingsIterator(bx, by, K_FindPlayersToBully);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (globalsmuggle.annoymo == NULL)
|
||||||
|
{
|
||||||
|
return INT32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
ourangle = globalsmuggle.botmo->angle;
|
||||||
|
destangle = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, globalsmuggle.annoymo->x, globalsmuggle.annoymo->y);
|
||||||
|
angle = (ourangle - destangle);
|
||||||
|
|
||||||
|
if (angle < ANGLE_180)
|
||||||
|
{
|
||||||
|
anglediff = AngleFixed(angle)>>FRACBITS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
anglediff = 360-(AngleFixed(angle)>>FRACBITS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (anglediff < 30)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (anglediff < 0)
|
||||||
|
return -KART_FULLTURN;
|
||||||
|
|
||||||
|
return KART_FULLTURN;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,25 @@ INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers)
|
||||||
return points;
|
return points;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------
|
||||||
|
SINT8 K_BotDefaultSkin(void)
|
||||||
|
|
||||||
|
See header file for description.
|
||||||
|
--------------------------------------------------*/
|
||||||
|
SINT8 K_BotDefaultSkin(void)
|
||||||
|
{
|
||||||
|
const char *defaultbotskinname = "eggrobo";
|
||||||
|
SINT8 defaultbotskin = R_SkinAvailable(defaultbotskinname);
|
||||||
|
|
||||||
|
if (defaultbotskin == -1)
|
||||||
|
{
|
||||||
|
// This shouldn't happen, but just in case
|
||||||
|
defaultbotskin = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultbotskin;
|
||||||
|
}
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
void K_InitGrandPrixBots(void)
|
void K_InitGrandPrixBots(void)
|
||||||
|
|
||||||
|
|
@ -102,8 +121,7 @@ INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers)
|
||||||
--------------------------------------------------*/
|
--------------------------------------------------*/
|
||||||
void K_InitGrandPrixBots(void)
|
void K_InitGrandPrixBots(void)
|
||||||
{
|
{
|
||||||
const char *defaultbotskinname = "eggrobo";
|
const SINT8 defaultbotskin = K_BotDefaultSkin();
|
||||||
SINT8 defaultbotskin = R_SkinAvailable(defaultbotskinname);
|
|
||||||
|
|
||||||
const UINT8 startingdifficulty = K_BotStartingDifficulty(grandprixinfo.gamespeed);
|
const UINT8 startingdifficulty = K_BotStartingDifficulty(grandprixinfo.gamespeed);
|
||||||
UINT8 difficultylevels[MAXPLAYERS];
|
UINT8 difficultylevels[MAXPLAYERS];
|
||||||
|
|
@ -121,12 +139,6 @@ void K_InitGrandPrixBots(void)
|
||||||
UINT8 newplayernum = 0;
|
UINT8 newplayernum = 0;
|
||||||
UINT8 i, j;
|
UINT8 i, j;
|
||||||
|
|
||||||
if (defaultbotskin == -1)
|
|
||||||
{
|
|
||||||
// This shouldn't happen, but just in case
|
|
||||||
defaultbotskin = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(competitors, MAXPLAYERS, sizeof (competitors));
|
memset(competitors, MAXPLAYERS, sizeof (competitors));
|
||||||
memset(botskinlist, defaultbotskin, sizeof (botskinlist));
|
memset(botskinlist, defaultbotskin, sizeof (botskinlist));
|
||||||
|
|
||||||
|
|
@ -144,7 +156,7 @@ void K_InitGrandPrixBots(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MAXPLAYERS != 16
|
#if MAXPLAYERS != 16
|
||||||
I_Error("GP bot difficulty levels need rebalacned for the new player count!\n");
|
I_Error("GP bot difficulty levels need rebalanced for the new player count!\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (grandprixinfo.masterbots)
|
if (grandprixinfo.masterbots)
|
||||||
|
|
@ -500,6 +512,126 @@ void K_IncreaseBotDifficulty(player_t *bot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------
|
||||||
|
void K_RetireBots(void)
|
||||||
|
|
||||||
|
See header file for description.
|
||||||
|
--------------------------------------------------*/
|
||||||
|
void K_RetireBots(void)
|
||||||
|
{
|
||||||
|
const SINT8 defaultbotskin = K_BotDefaultSkin();
|
||||||
|
SINT8 newDifficulty;
|
||||||
|
|
||||||
|
boolean skinusable[MAXSKINS];
|
||||||
|
|
||||||
|
UINT8 i;
|
||||||
|
|
||||||
|
if (grandprixinfo.gp == true && grandprixinfo.roundnum >= grandprixinfo.cup->numlevels)
|
||||||
|
{
|
||||||
|
// Was last map, no replacement.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// init usable bot skins list
|
||||||
|
for (i = 0; i < MAXSKINS; i++)
|
||||||
|
{
|
||||||
|
if (i < numskins)
|
||||||
|
{
|
||||||
|
skinusable[i] = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
skinusable[i] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
|
{
|
||||||
|
if (playeringame[i] && !players[i].spectator)
|
||||||
|
{
|
||||||
|
skinusable[players[i].skin] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!grandprixinfo.gp) // Sure, let's let this happen all the time :)
|
||||||
|
{
|
||||||
|
newDifficulty = cv_kartbot.value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const UINT8 startingdifficulty = K_BotStartingDifficulty(grandprixinfo.gamespeed);
|
||||||
|
newDifficulty = startingdifficulty - 4 + grandprixinfo.roundnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newDifficulty > MAXBOTDIFFICULTY)
|
||||||
|
{
|
||||||
|
newDifficulty = MAXBOTDIFFICULTY;
|
||||||
|
}
|
||||||
|
else if (newDifficulty < 1)
|
||||||
|
{
|
||||||
|
newDifficulty = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
|
{
|
||||||
|
player_t *bot = NULL;
|
||||||
|
|
||||||
|
if (!playeringame[i] || !players[i].bot)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bot = &players[i];
|
||||||
|
|
||||||
|
if (bot->spectator)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bot->pflags & PF_NOCONTEST)
|
||||||
|
{
|
||||||
|
UINT8 skinnum = P_RandomKey(numskins);
|
||||||
|
UINT8 loops = 0;
|
||||||
|
|
||||||
|
while (!skinusable[skinnum])
|
||||||
|
{
|
||||||
|
if (loops >= numskins)
|
||||||
|
{
|
||||||
|
// no more skins
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
skinnum++;
|
||||||
|
|
||||||
|
if (skinnum >= numskins)
|
||||||
|
{
|
||||||
|
skinnum = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
loops++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loops >= numskins)
|
||||||
|
{
|
||||||
|
// Use default skin
|
||||||
|
skinnum = defaultbotskin;
|
||||||
|
}
|
||||||
|
|
||||||
|
skinusable[skinnum] = false;
|
||||||
|
|
||||||
|
bot->botvars.difficulty = newDifficulty;
|
||||||
|
bot->botvars.diffincrease = 0;
|
||||||
|
|
||||||
|
SetPlayerSkinByNum(bot - players, skinnum);
|
||||||
|
bot->skincolor = skins[skinnum].prefcolor;
|
||||||
|
sprintf(player_names[bot - players], "%s", skins[skinnum].realname);
|
||||||
|
|
||||||
|
bot->score = 0;
|
||||||
|
bot->pflags &= ~PF_NOCONTEST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
void K_FakeBotResults(player_t *bot)
|
void K_FakeBotResults(player_t *bot)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,16 @@ UINT8 K_BotStartingDifficulty(SINT8 value);
|
||||||
INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers);
|
INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers);
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------
|
||||||
|
SINT8 K_BotDefaultSkin(void);
|
||||||
|
|
||||||
|
Returns the skin number of the skin the game
|
||||||
|
uses as a fallback option.
|
||||||
|
--------------------------------------------------*/
|
||||||
|
|
||||||
|
SINT8 K_BotDefaultSkin(void);
|
||||||
|
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
void K_InitGrandPrixBots(void);
|
void K_InitGrandPrixBots(void);
|
||||||
|
|
||||||
|
|
@ -95,6 +105,16 @@ void K_UpdateGrandPrixBots(void);
|
||||||
void K_IncreaseBotDifficulty(player_t *bot);
|
void K_IncreaseBotDifficulty(player_t *bot);
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------
|
||||||
|
void K_RetireBots(void);
|
||||||
|
|
||||||
|
Replaces PF_NOCONTEST bots, by refreshing their difficulty
|
||||||
|
and changing their skin.
|
||||||
|
--------------------------------------------------*/
|
||||||
|
|
||||||
|
void K_RetireBots(void);
|
||||||
|
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
void K_FakeBotResults(player_t *bot);
|
void K_FakeBotResults(player_t *bot);
|
||||||
|
|
||||||
|
|
@ -136,7 +156,7 @@ void K_PlayerLoseLife(player_t *player);
|
||||||
None
|
None
|
||||||
|
|
||||||
Return:-
|
Return:-
|
||||||
None
|
true if can change important gameplay rules, otherwise false.
|
||||||
--------------------------------------------------*/
|
--------------------------------------------------*/
|
||||||
|
|
||||||
boolean K_CanChangeRules(void);
|
boolean K_CanChangeRules(void);
|
||||||
|
|
|
||||||
|
|
@ -3105,7 +3105,7 @@ fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower)
|
||||||
if (K_PlayerUsesBotMovement(player))
|
if (K_PlayerUsesBotMovement(player))
|
||||||
{
|
{
|
||||||
// Increase bot speed by 1-10% depending on difficulty
|
// Increase bot speed by 1-10% depending on difficulty
|
||||||
fixed_t add = (player->botvars.difficulty * (FRACUNIT/10)) / MAXBOTDIFFICULTY;
|
fixed_t add = (player->botvars.difficulty * (FRACUNIT/10)) / DIFFICULTBOT;
|
||||||
finalspeed = FixedMul(finalspeed, FRACUNIT + add);
|
finalspeed = FixedMul(finalspeed, FRACUNIT + add);
|
||||||
|
|
||||||
if (player->botvars.rival == true)
|
if (player->botvars.rival == true)
|
||||||
|
|
@ -8046,7 +8046,7 @@ INT32 K_GetKartRingPower(player_t *player, boolean boosted)
|
||||||
if (boosted == true && K_PlayerUsesBotMovement(player))
|
if (boosted == true && K_PlayerUsesBotMovement(player))
|
||||||
{
|
{
|
||||||
// Double for Lv. 9
|
// Double for Lv. 9
|
||||||
ringPower += (player->botvars.difficulty * ringPower) / MAXBOTDIFFICULTY;
|
ringPower += (player->botvars.difficulty * ringPower) / DIFFICULTBOT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ringPower;
|
return ringPower;
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ static precise_t ps_frametime = 0;
|
||||||
precise_t ps_tictime = 0;
|
precise_t ps_tictime = 0;
|
||||||
|
|
||||||
precise_t ps_playerthink_time = 0;
|
precise_t ps_playerthink_time = 0;
|
||||||
|
precise_t ps_botticcmd_time = 0;
|
||||||
precise_t ps_thinkertime = 0;
|
precise_t ps_thinkertime = 0;
|
||||||
|
|
||||||
precise_t ps_thlist_times[NUM_THINKERLISTS];
|
precise_t ps_thlist_times[NUM_THINKERLISTS];
|
||||||
|
|
@ -363,6 +364,7 @@ static void M_DrawTickStats(void)
|
||||||
|
|
||||||
perfstatrow_t extra_thinker_time_row[] = {
|
perfstatrow_t extra_thinker_time_row[] = {
|
||||||
{"lthinkf", "LUAh_ThinkFrame:", &ps_lua_thinkframe_time},
|
{"lthinkf", "LUAh_ThinkFrame:", &ps_lua_thinkframe_time},
|
||||||
|
{"botcmd ", "Bot logic: ", &ps_botticcmd_time},
|
||||||
{"other ", "Other: ", &extratime},
|
{"other ", "Other: ", &extratime},
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
extern precise_t ps_tictime;
|
extern precise_t ps_tictime;
|
||||||
|
|
||||||
extern precise_t ps_playerthink_time;
|
extern precise_t ps_playerthink_time;
|
||||||
|
extern precise_t ps_botticcmd_time;
|
||||||
extern precise_t ps_thinkertime;
|
extern precise_t ps_thinkertime;
|
||||||
|
|
||||||
extern precise_t ps_thlist_times[];
|
extern precise_t ps_thlist_times[];
|
||||||
|
|
|
||||||
|
|
@ -316,25 +316,27 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
|
||||||
data.pos[data.numplayers] = data.numplayers+1;
|
data.pos[data.numplayers] = data.numplayers+1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((powertype == PWRLV_DISABLED)
|
if (!rankingsmode)
|
||||||
&& (!rankingsmode)
|
|
||||||
&& !(players[i].pflags & PF_NOCONTEST)
|
|
||||||
&& (data.pos[data.numplayers] < (numplayersingame + numgriefers)))
|
|
||||||
{
|
{
|
||||||
// Online rank is handled further below in this file.
|
if ((powertype == PWRLV_DISABLED)
|
||||||
data.increase[i] = K_CalculateGPRankPoints(data.pos[data.numplayers], numplayersingame + numgriefers);
|
&& !(players[i].pflags & PF_NOCONTEST)
|
||||||
players[i].score += data.increase[i];
|
&& (data.pos[data.numplayers] < (numplayersingame + numgriefers)))
|
||||||
}
|
{
|
||||||
|
// Online rank is handled further below in this file.
|
||||||
|
data.increase[i] = K_CalculateGPRankPoints(data.pos[data.numplayers], numplayersingame + numgriefers);
|
||||||
|
players[i].score += data.increase[i];
|
||||||
|
}
|
||||||
|
|
||||||
if (demo.recording && !rankingsmode)
|
if (demo.recording)
|
||||||
{
|
{
|
||||||
G_WriteStanding(
|
G_WriteStanding(
|
||||||
data.pos[data.numplayers],
|
data.pos[data.numplayers],
|
||||||
data.name[data.numplayers],
|
data.name[data.numplayers],
|
||||||
*data.character[data.numplayers],
|
*data.character[data.numplayers],
|
||||||
*data.color[data.numplayers],
|
*data.color[data.numplayers],
|
||||||
data.val[data.numplayers]
|
data.val[data.numplayers]
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data.numplayers++;
|
data.numplayers++;
|
||||||
|
|
@ -582,6 +584,12 @@ void Y_IntermissionDrawer(void)
|
||||||
V_DrawScaledPatch(x+16, y-4, 0, W_CachePatchName(va("K_CHILI%d", cursorframe+1), PU_CACHE));
|
V_DrawScaledPatch(x+16, y-4, 0, W_CachePatchName(va("K_CHILI%d", cursorframe+1), PU_CACHE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((players[data.num[i]].pflags & PF_NOCONTEST) && players[data.num[i]].bot)
|
||||||
|
{
|
||||||
|
// RETIRED!!
|
||||||
|
V_DrawScaledPatch(x+12, y-7, 0, W_CachePatchName("K_NOBLNS", PU_CACHE));
|
||||||
|
}
|
||||||
|
|
||||||
STRBUFCPY(strtime, data.name[i]);
|
STRBUFCPY(strtime, data.name[i]);
|
||||||
|
|
||||||
y2 = y;
|
y2 = y;
|
||||||
|
|
@ -803,6 +811,7 @@ void Y_Ticker(void)
|
||||||
{
|
{
|
||||||
if (!data.rankingsmode && sorttic != -1 && (intertic >= sorttic + 8))
|
if (!data.rankingsmode && sorttic != -1 && (intertic >= sorttic + 8))
|
||||||
{
|
{
|
||||||
|
K_RetireBots();
|
||||||
Y_CalculateMatchData(1, Y_CompareRank);
|
Y_CalculateMatchData(1, Y_CompareRank);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1153,6 +1162,7 @@ void Y_StartIntermission(void)
|
||||||
//
|
//
|
||||||
void Y_EndIntermission(void)
|
void Y_EndIntermission(void)
|
||||||
{
|
{
|
||||||
|
K_RetireBots();
|
||||||
Y_UnloadData();
|
Y_UnloadData();
|
||||||
|
|
||||||
endtic = -1;
|
endtic = -1;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue