Merge branch 'bot-finally' into 'master'

Fix bot memory leak

See merge request KartKrew/Kart!1474
This commit is contained in:
Oni 2023-09-10 23:52:08 +00:00
commit 86ff4f720b
6 changed files with 299 additions and 286 deletions

View file

@ -125,7 +125,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
k_waypoint.cpp
k_pathfind.c
k_bheap.c
k_bot.c
k_bot.cpp
k_botitem.c
k_botsearch.c
k_grandprix.c

View file

@ -4060,10 +4060,10 @@ static void Got_AddBot(UINT8 **p, INT32 playernum)
}
static boolean SV_AddWaitingPlayers(SINT8 node, UINT8 *availabilities,
const char *name, uint8_t *key, UINT16 *pwr,
const char *name2, uint8_t *key2, UINT16 *pwr2,
const char *name3, uint8_t *key3, UINT16 *pwr3,
const char *name4, uint8_t *key4, UINT16 *pwr4)
const char *name, uint8_t *key, UINT16 *pwr,
const char *name2, uint8_t *key2, UINT16 *pwr2,
const char *name3, uint8_t *key3, UINT16 *pwr3,
const char *name4, uint8_t *key4, UINT16 *pwr4)
{
INT32 n, newplayernum, i;
UINT8 buf[4 + MAXPLAYERNAME + PUBKEYLENGTH + MAXAVAILABILITY + sizeof(((serverplayer_t *)0)->powerlevels)];
@ -4172,6 +4172,85 @@ const char *name4, uint8_t *key4, UINT16 *pwr4)
return newplayer;
}
/*--------------------------------------------------
boolean K_AddBotFromServer(UINT8 skin, UINT8 difficulty, botStyle_e style, UINT8 *p)
See header file for description.
--------------------------------------------------*/
boolean K_AddBotFromServer(UINT8 skin, UINT8 difficulty, botStyle_e style, UINT8 *p)
{
UINT8 newplayernum = *p;
// search for a free playernum
// we can't use playeringame since it is not updated here
for (; newplayernum < MAXPLAYERS; newplayernum++)
{
UINT8 n;
for (n = 0; n < MAXNETNODES; n++)
{
if (nodetoplayer[n] == newplayernum
|| nodetoplayer2[n] == newplayernum
|| nodetoplayer3[n] == newplayernum
|| nodetoplayer4[n] == newplayernum)
break;
}
if (n == MAXNETNODES)
break;
}
for (; newplayernum < MAXPLAYERS; newplayernum++)
{
if (playeringame[newplayernum] == false)
{
// free player slot
break;
}
}
if (newplayernum >= MAXPLAYERS)
{
// nothing is free
*p = MAXPLAYERS;
return false;
}
if (server)
{
UINT8 buf[4];
UINT8 *buf_p = buf;
WRITEUINT8(buf_p, newplayernum);
if (skin > numskins)
{
skin = numskins;
}
WRITEUINT8(buf_p, skin);
if (difficulty < 1)
{
difficulty = 1;
}
else if (difficulty > MAXBOTDIFFICULTY)
{
difficulty = MAXBOTDIFFICULTY;
}
WRITEUINT8(buf_p, difficulty);
WRITEUINT8(buf_p, style);
SendNetXCmd(XD_ADDBOT, buf, buf_p - buf);
DEBFILE(va("Server added bot %d\n", newplayernum));
}
// use the next free slot (we can't put playeringame[newplayernum] = true here)
*p = newplayernum+1;
return true;
}
void CL_AddSplitscreenPlayer(void)
{
if (cl_mode == CL_CONNECTED)

View file

@ -588,6 +588,27 @@ void SV_StartSinglePlayerServer(INT32 dogametype, boolean donetgame);
boolean SV_SpawnServer(void);
void SV_StopServer(void);
void SV_ResetServer(void);
/*--------------------------------------------------
boolean K_AddBotFromServer(UINT8 skin, UINT8 difficulty, botStyle_e style, UINT8 *newplayernum);
Adds a new bot, using a server-sided packet sent to all clients.
Using regular K_AddBot wherever possible is better, but this is kept
as a back-up measure if this is the only option.
Input Arguments:-
skin - Skin number that the bot will use.
difficulty - Difficulty level this bot will use.
style - Bot style to spawn this bot with, see botStyle_e.
newplayernum - Pointer to the last valid player slot number.
Is a pointer so that this function can be called multiple times to add more than one bot.
Return:-
true if a bot can be added via a packet later, otherwise false.
--------------------------------------------------*/
boolean K_AddBotFromServer(UINT8 skin, UINT8 difficulty, botStyle_e style, UINT8 *p);
void CL_AddSplitscreenPlayer(void);
void CL_RemoveSplitscreenPlayer(UINT8 p);
void CL_Reset(void);

View file

@ -1,15 +1,19 @@
// SONIC ROBO BLAST 2 KART
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2020 by Sally "TehRealSalt" Cochenour
// Copyright (C) 2018-2020 by Kart Krew
// Copyright (C) by Sally "TehRealSalt" Cochenour
// Copyright (C) by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file k_bot.c
/// \file k_bot.cpp
/// \brief Bot logic & ticcmd generation code
#include <algorithm>
#include "cxxutil.hpp"
#include "doomdef.h"
#include "d_player.h"
#include "g_game.h"
@ -116,85 +120,6 @@ boolean K_AddBot(UINT8 skin, UINT8 difficulty, botStyle_e style, UINT8 *p)
return true;
}
/*--------------------------------------------------
boolean K_AddBotFromServer(UINT8 skin, UINT8 difficulty, botStyle_e style, UINT8 *p)
See header file for description.
--------------------------------------------------*/
boolean K_AddBotFromServer(UINT8 skin, UINT8 difficulty, botStyle_e style, UINT8 *p)
{
UINT8 newplayernum = *p;
// search for a free playernum
// we can't use playeringame since it is not updated here
for (; newplayernum < MAXPLAYERS; newplayernum++)
{
UINT8 n;
for (n = 0; n < MAXNETNODES; n++)
{
if (nodetoplayer[n] == newplayernum
|| nodetoplayer2[n] == newplayernum
|| nodetoplayer3[n] == newplayernum
|| nodetoplayer4[n] == newplayernum)
break;
}
if (n == MAXNETNODES)
break;
}
for (; newplayernum < MAXPLAYERS; newplayernum++)
{
if (playeringame[newplayernum] == false)
{
// free player slot
break;
}
}
if (newplayernum >= MAXPLAYERS)
{
// nothing is free
*p = MAXPLAYERS;
return false;
}
if (server)
{
UINT8 buf[4];
UINT8 *buf_p = buf;
WRITEUINT8(buf_p, newplayernum);
if (skin > numskins)
{
skin = numskins;
}
WRITEUINT8(buf_p, skin);
if (difficulty < 1)
{
difficulty = 1;
}
else if (difficulty > MAXBOTDIFFICULTY)
{
difficulty = MAXBOTDIFFICULTY;
}
WRITEUINT8(buf_p, difficulty);
WRITEUINT8(buf_p, style);
SendNetXCmd(XD_ADDBOT, buf, buf_p - buf);
DEBFILE(va("Server added bot %d\n", newplayernum));
}
// use the next free slot (we can't put playeringame[newplayernum] = true here)
*p = newplayernum+1;
return true;
}
/*--------------------------------------------------
void K_UpdateMatchRaceBots(void)
@ -204,7 +129,7 @@ void K_UpdateMatchRaceBots(void)
{
const UINT8 defaultbotskin = R_BotDefaultSkin();
const UINT8 difficulty = cv_kartbot.value;
UINT8 pmax = min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxconnections.value);
UINT8 pmax = std::min<UINT8>((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), static_cast<UINT8>(cv_maxconnections.value));
UINT8 numplayers = 0;
UINT8 numbots = 0;
UINT8 numwaiting = 0;
@ -222,7 +147,7 @@ void K_UpdateMatchRaceBots(void)
if (cv_maxplayers.value > 0)
{
pmax = min(pmax, cv_maxplayers.value);
pmax = std::min<UINT8>(pmax, static_cast<UINT8>(cv_maxplayers.value));
}
for (i = 0; i < MAXPLAYERS; i++)
@ -429,7 +354,7 @@ static fixed_t K_BotSpeedScaled(player_t *player, fixed_t speed)
result = FixedMul(result, moveFactor);
}
if (player->mo->standingslope != NULL)
if (player->mo->standingslope != nullptr)
{
const pslope_t *slope = player->mo->standingslope;
@ -462,7 +387,7 @@ static fixed_t K_BotSpeedScaled(player_t *player, fixed_t speed)
mo - The bot player's mobj.
Return:-
Linedef of the bot controller. NULL if it doesn't exist.
Linedef of the bot controller. nullptr if it doesn't exist.
--------------------------------------------------*/
static line_t *K_FindBotController(mobj_t *mo)
{
@ -471,7 +396,7 @@ static line_t *K_FindBotController(mobj_t *mo)
INT16 lineNum = -1;
mtag_t tag;
I_Assert(mo != NULL);
I_Assert(mo != nullptr);
I_Assert(!P_MobjWasRemoved(mo));
for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next)
@ -491,7 +416,7 @@ static line_t *K_FindBotController(mobj_t *mo)
for (rover = node->m_sector->ffloors; rover; rover = rover->next)
{
sector_t *rs = NULL;
sector_t *rs = nullptr;
if (!(rover->fofflags & FOF_EXISTS))
{
@ -520,7 +445,7 @@ static line_t *K_FindBotController(mobj_t *mo)
}
else
{
return NULL;
return nullptr;
}
}
@ -595,7 +520,7 @@ fixed_t K_BotRubberband(player_t *player)
const fixed_t rubbermax = Easing_Linear(difficultyEase, FRACUNIT, FRACUNIT * 165 / 100);
fixed_t rubberband = FRACUNIT >> 1;
player_t *firstplace = NULL;
player_t *firstplace = nullptr;
size_t i = SIZE_MAX;
if (player->exiting)
@ -608,7 +533,7 @@ fixed_t K_BotRubberband(player_t *player)
{
const line_t *botController = &lines[player->botvars.controller];
if (botController != NULL)
if (botController != nullptr)
{
// Disable rubberbanding
if (botController->args[1] & TMBOT_NORUBBERBAND)
@ -633,18 +558,18 @@ fixed_t K_BotRubberband(player_t *player)
}
#endif
if (firstplace == NULL || players[i].distancetofinish < firstplace->distancetofinish)
if (firstplace == nullptr || players[i].distancetofinish < firstplace->distancetofinish)
{
firstplace = &players[i];
}
}
if (firstplace != NULL)
if (firstplace != nullptr)
{
// Lv. 1: 5120 units
// Lv. 9: 320 units
const fixed_t spacing = FixedDiv(
max(
std::max<fixed_t>(
80 * mapobjectscale,
Easing_Linear(difficultyEase, 5120 * mapobjectscale, 320 * mapobjectscale)
),
@ -759,7 +684,7 @@ static void K_GetBotWaypointRadius(waypoint_t *const waypoint, fixed_t *smallest
waypoint->mobj->x, waypoint->mobj->y
);
delta = max(delta, AngleDelta(nextAngle, prevAngle));
delta = std::max<angle_t>(delta, AngleDelta(nextAngle, prevAngle));
}
}
@ -771,13 +696,13 @@ static void K_GetBotWaypointRadius(waypoint_t *const waypoint, fixed_t *smallest
reduce = FixedDiv(delta, maxDelta);
reduce = FRACUNIT + FixedMul(reduce, maxReduce - FRACUNIT);
*smallestRadius = min(*smallestRadius, radius);
*smallestScaled = min(*smallestScaled, FixedMul(radius, reduce));
*smallestRadius = std::min<fixed_t>(*smallestRadius, radius);
*smallestScaled = std::min<fixed_t>(*smallestScaled, FixedMul(radius, reduce));
}
static fixed_t K_ScaleWPDistWithSlope(fixed_t disttonext, angle_t angletonext, const pslope_t *slope, SINT8 flip)
{
if (slope == NULL)
if (slope == nullptr)
{
return disttonext;
}
@ -824,12 +749,12 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
const INT16 handling = K_GetKartTurnValue(player, KART_FULLTURN) / jankDiv; // Reduce prediction based on how fast you can turn
const tic_t futuresight = (TICRATE * KART_FULLTURN) / max(1, handling); // How far ahead into the future to try and predict
const tic_t futuresight = (TICRATE * KART_FULLTURN) / std::max<INT16>(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 = 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);
const INT32 distance = std::min<INT32>(((speed / FRACUNIT) * static_cast<INT32>(futuresight)) + startDist, maxDist);
// Halves radius when encountering a wall on your way to your destination.
fixed_t radReduce = FRACUNIT;
@ -851,16 +776,16 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
boolean pathfindsuccess = false;
path_t pathtofinish = {0};
botprediction_t *predict = NULL;
botprediction_t *predict = nullptr;
size_t i;
if (wp == NULL || P_MobjWasRemoved(wp->mobj) == true)
if (wp == nullptr || P_MobjWasRemoved(wp->mobj) == true)
{
// Can't do any of this if we don't have a waypoint.
return NULL;
return nullptr;
}
predict = Z_Calloc(sizeof(botprediction_t), PU_STATIC, NULL);
predict = static_cast<botprediction_t *>(Z_Calloc(sizeof(botprediction_t), PU_LEVEL, nullptr));
// Init defaults in case of pathfind failure
angletonext = R_PointToAngle2(prevwpmobj->x, prevwpmobj->y, wp->mobj->x, wp->mobj->y);
@ -927,8 +852,8 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
if (distanceleft > 0)
{
// Scaled with the leftover anglemul!
predict->x += P_ReturnThrustX(NULL, angletonext, min(disttonext, distanceleft) * FRACUNIT);
predict->y += P_ReturnThrustY(NULL, angletonext, min(disttonext, distanceleft) * FRACUNIT);
predict->x += P_ReturnThrustX(nullptr, angletonext, std::min<fixed_t>(disttonext, distanceleft) * FRACUNIT);
predict->y += P_ReturnThrustY(nullptr, angletonext, std::min<fixed_t>(disttonext, distanceleft) * FRACUNIT);
}
ps_bots[player - players].prediction += I_GetPreciseTime() - time;
@ -976,7 +901,7 @@ static UINT8 K_TrySpindash(player_t *player)
{
INT32 boosthold = starttime - K_GetSpindashChargeTime(player);
boosthold -= (DIFFICULTBOT - min(DIFFICULTBOT, player->botvars.difficulty)) * difficultyModifier;
boosthold -= (DIFFICULTBOT - std::min<UINT8>(DIFFICULTBOT, player->botvars.difficulty)) * difficultyModifier;
if (leveltime >= (unsigned)boosthold)
{
@ -996,7 +921,7 @@ static UINT8 K_TrySpindash(player_t *player)
// Release quicker the higher the difficulty is.
// Sounds counter-productive, but that's actually the best strategy after the race has started.
chargingPoint -= min(DIFFICULTBOT, player->botvars.difficulty) * difficultyModifier;
chargingPoint -= std::min<UINT8>(DIFFICULTBOT, player->botvars.difficulty) * difficultyModifier;
if (player->spindash > chargingPoint)
{
@ -1022,7 +947,7 @@ static UINT8 K_TrySpindash(player_t *player)
} \
}
if (K_SlopeResistance(player) == false && player->mo->standingslope != NULL)
if (K_SlopeResistance(player) == false && player->mo->standingslope != nullptr)
{
const pslope_t *slope = player->mo->standingslope;
@ -1120,13 +1045,13 @@ static boolean K_TryRingShooter(player_t *player)
--------------------------------------------------*/
static void K_DrawPredictionDebug(botprediction_t *predict, player_t *player)
{
mobj_t *debugMobj = NULL;
mobj_t *debugMobj = nullptr;
angle_t sideAngle = ANGLE_MAX;
UINT8 i = UINT8_MAX;
I_Assert(predict != NULL);
I_Assert(player != NULL);
I_Assert(player->mo != NULL && P_MobjWasRemoved(player->mo) == false);
I_Assert(predict != nullptr);
I_Assert(player != nullptr);
I_Assert(player->mo != nullptr && P_MobjWasRemoved(player->mo) == false);
sideAngle = player->mo->angle + ANGLE_90;
@ -1143,7 +1068,7 @@ static void K_DrawPredictionDebug(botprediction_t *predict, player_t *player)
for (i = 0; i < 2; i++)
{
mobj_t *radiusMobj = NULL;
mobj_t *radiusMobj = nullptr;
fixed_t radiusX = predict->x, radiusY = predict->y;
if (i & 1)
@ -1186,7 +1111,7 @@ static void K_DrawPredictionDebug(botprediction_t *predict, player_t *player)
static void K_BotTrick(player_t *player, ticcmd_t *cmd, const line_t *botController)
{
// Trick panel state -- do nothing until a controller line is found, in which case do a trick.
if (botController == NULL)
if (botController == nullptr)
{
return;
}
@ -1232,7 +1157,7 @@ static angle_t K_BotSmoothLanding(player_t *player, angle_t destangle)
angle_t newAngle = destangle;
boolean air = !P_IsObjectOnGround(player->mo);
angle_t steepVal = air ? STUMBLE_STEEP_VAL_AIR : STUMBLE_STEEP_VAL;
angle_t slopeSteep = max(AngleDelta(player->mo->pitch, 0), AngleDelta(player->mo->roll, 0));
angle_t slopeSteep = std::max<angle_t>(AngleDelta(player->mo->pitch, 0), AngleDelta(player->mo->roll, 0));
if (slopeSteep > steepVal)
{
@ -1284,7 +1209,7 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t *
angle_t moveangle;
INT32 anglediff;
I_Assert(predict != NULL);
I_Assert(predict != nullptr);
destangle = K_BotSmoothLanding(player, destangle);
@ -1329,7 +1254,7 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t *
// This makes predictions into turns a little nicer
// Facing 90 degrees away from the predicted point gives you 0 radius
rad = FixedMul(rad,
FixedDiv(max(0, ANGLE_90 - anglediff), ANGLE_90)
FixedDiv(std::max<angle_t>(0, ANGLE_90 - anglediff), ANGLE_90)
);
// Become more precise the slower you're moving
@ -1384,21 +1309,21 @@ static INT32 K_HandleBotReverse(player_t *player, ticcmd_t *cmd, botprediction_t
angle_t moveangle, angle;
INT16 anglediff, momdiff;
if (predict != NULL)
if (predict != nullptr)
{
// TODO: Should we reverse through bot controllers?
return K_HandleBotTrack(player, cmd, predict, destangle);
}
if (player->nextwaypoint == NULL
|| player->nextwaypoint->mobj == NULL
if (player->nextwaypoint == nullptr
|| player->nextwaypoint->mobj == nullptr
|| P_MobjWasRemoved(player->nextwaypoint->mobj))
{
// No data available...
return 0;
}
if ((player->nextwaypoint->prevwaypoints != NULL)
if ((player->nextwaypoint->prevwaypoints != nullptr)
&& (player->nextwaypoint->numprevwaypoints > 0U))
{
size_t i;
@ -1470,7 +1395,7 @@ static INT32 K_HandleBotReverse(player_t *player, ticcmd_t *cmd, botprediction_t
{
fixed_t slopeMul = FRACUNIT;
if (player->mo->standingslope != NULL)
if (player->mo->standingslope != nullptr)
{
const pslope_t *slope = player->mo->standingslope;
@ -1543,7 +1468,7 @@ static void K_BotPodiumTurning(player_t *player, ticcmd_t *cmd)
--------------------------------------------------*/
static void K_BuildBotPodiumTiccmd(player_t *player, ticcmd_t *cmd)
{
if (player->currentwaypoint == NULL)
if (player->currentwaypoint == nullptr)
{
// We've reached the end of our path.
// Simply stop moving.
@ -1573,12 +1498,15 @@ static void K_BuildBotPodiumTiccmd(player_t *player, ticcmd_t *cmd)
static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd)
{
precise_t t = 0;
botprediction_t *predict = NULL;
botprediction_t *predict = nullptr;
auto predict_finally = srb2::finally([&predict]() { Z_Free(predict); });
boolean trySpindash = true;
angle_t destangle = 0;
UINT8 spindash = 0;
INT32 turnamt = 0;
const line_t *botController = player->botvars.controller != UINT16_MAX ? &lines[player->botvars.controller] : NULL;
const line_t *botController = player->botvars.controller != UINT16_MAX ? &lines[player->botvars.controller] : nullptr;
if (!(gametyperules & GTR_BOTS) // No bot behaviors
|| K_GetNumWaypoints() == 0 // No waypoints
@ -1618,7 +1546,7 @@ static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd)
return;
}
if (botController != NULL && (botController->args[1] & TMBOT_NOCONTROL))
if (botController != nullptr && (botController->args[1] & TMBOT_NOCONTROL))
{
// Disable bot controls entirely.
return;
@ -1626,7 +1554,7 @@ static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd)
destangle = player->mo->angle;
if (botController != NULL && (botController->args[1] & TMBOT_FORCEDIR))
if (botController != nullptr && (botController->args[1] & TMBOT_FORCEDIR))
{
const fixed_t dist = DEFAULT_WAYPOINT_RADIUS * player->mo->scale;
@ -1634,14 +1562,14 @@ static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd)
destangle = FixedAngle(botController->args[2] * FRACUNIT);
// Overwritten prediction
predict = Z_Calloc(sizeof(botprediction_t), PU_STATIC, NULL);
predict = static_cast<botprediction_t *>(Z_Calloc(sizeof(botprediction_t), PU_STATIC, nullptr));
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;
}
if (leveltime <= starttime && finishBeamLine != NULL)
if (leveltime <= starttime && finishBeamLine != nullptr)
{
// Handle POSITION!!
const fixed_t distBase = 480*mapobjectscale;
@ -1684,13 +1612,13 @@ static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd)
if (bullyTurn == INT32_MAX)
{
// No one to bully, just go for a spindash as anyone.
if (predict == NULL)
if (predict == nullptr)
{
// Create a prediction.
predict = K_CreateBotPrediction(player);
}
if (predict != NULL)
if (predict != nullptr)
{
K_NudgePredictionTowardsObjects(predict, player);
destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y);
@ -1716,13 +1644,13 @@ static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd)
else
{
// Too far away, we need to just drive up.
if (predict == NULL)
if (predict == nullptr)
{
// Create a prediction.
predict = K_CreateBotPrediction(player);
}
if (predict != NULL)
if (predict != nullptr)
{
K_NudgePredictionTowardsObjects(predict, player);
destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y);
@ -1733,13 +1661,13 @@ static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd)
else
{
// Handle steering towards waypoints!
if (predict == NULL)
if (predict == nullptr)
{
// Create a prediction.
predict = K_CreateBotPrediction(player);
}
if (predict != NULL)
if (predict != nullptr)
{
K_NudgePredictionTowardsObjects(predict, player);
destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y);
@ -1821,14 +1749,12 @@ static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd)
}
// Free the prediction we made earlier
if (predict != NULL)
if (predict != nullptr)
{
if (cv_kartdebugbots.value != 0 && player - players == displayplayers[0])
{
K_DrawPredictionDebug(predict, player);
}
Z_Free(predict);
}
}
@ -1842,7 +1768,7 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
// Remove any existing controls
memset(cmd, 0, sizeof(ticcmd_t));
if (player->mo == NULL
if (player->mo == nullptr
|| player->spectator == true
|| G_GamestateUsesLevel() == false)
{

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 KART
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2020 by Sally "TehRealSalt" Cochenour
// Copyright (C) 2018-2020 by Kart Krew
// Copyright (C) by Sally "TehRealSalt" Cochenour
// Copyright (C) by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
@ -45,7 +45,8 @@ extern "C" {
#define BOT_ITEM_DECISION_TIME (2*TICRATE)
// Point for bots to aim for
struct botprediction_t {
struct botprediction_t
{
fixed_t x, y;
fixed_t radius, baseRadius;
};
@ -180,27 +181,6 @@ boolean K_AddBot(UINT8 skin, UINT8 difficulty, botStyle_e style, UINT8 *p);
void K_SetBot(UINT8 newplayernum, UINT8 skinnum, UINT8 difficulty, botStyle_e style);
/*--------------------------------------------------
boolean K_AddBotFromServer(UINT8 skin, UINT8 difficulty, botStyle_e style, UINT8 *newplayernum);
Adds a new bot, using a server-sided packet sent to all clients.
Using regular K_AddBot wherever possible is better, but this is kept
as a back-up measure if this is the only option.
Input Arguments:-
skin - Skin number that the bot will use.
difficulty - Difficulty level this bot will use.
style - Bot style to spawn this bot with, see botStyle_e.
newplayernum - Pointer to the last valid player slot number.
Is a pointer so that this function can be called multiple times to add more than one bot.
Return:-
true if a bot can be added via a packet later, otherwise false.
--------------------------------------------------*/
boolean K_AddBotFromServer(UINT8 skin, UINT8 difficulty, botStyle_e style, UINT8 *p);
/*--------------------------------------------------
void K_UpdateMatchRaceBots(void);

View file

@ -29,28 +29,6 @@
#include "p_slopes.h" // P_GetZAt
#include "m_perfstats.h"
struct globalsmuggle
{
mobj_t *botmo;
botprediction_t *predict;
fixed_t distancetocheck;
INT64 gotoAvgX[2], gotoAvgY[2];
UINT32 gotoObjs[2];
INT64 avoidAvgX[2], avoidAvgY[2];
UINT32 avoidObjs[2];
fixed_t annoyscore;
mobj_t *annoymo;
fixed_t closestlinedist;
fixed_t eggboxx, eggboxy;
UINT8 randomitems;
UINT8 eggboxes;
} globalsmuggle;
/*--------------------------------------------------
static BlockItReturn_t K_FindEggboxes(mobj_t *thing)
@ -63,6 +41,14 @@ struct globalsmuggle
Return:-
BlockItReturn_t enum, see its definition for more information.
--------------------------------------------------*/
static struct eggboxSearch_s
{
fixed_t distancetocheck;
fixed_t eggboxx, eggboxy;
UINT8 randomitems;
UINT8 eggboxes;
} g_eggboxSearch;
static BlockItReturn_t K_FindEggboxes(mobj_t *thing)
{
fixed_t dist;
@ -77,20 +63,20 @@ static BlockItReturn_t K_FindEggboxes(mobj_t *thing)
return BMIT_CONTINUE;
}
dist = P_AproxDistance(thing->x - globalsmuggle.eggboxx, thing->y - globalsmuggle.eggboxy);
dist = P_AproxDistance(thing->x - g_eggboxSearch.eggboxx, thing->y - g_eggboxSearch.eggboxy);
if (dist > globalsmuggle.distancetocheck)
if (dist > g_eggboxSearch.distancetocheck)
{
return BMIT_CONTINUE;
}
if (thing->type == MT_RANDOMITEM)
{
globalsmuggle.randomitems++;
g_eggboxSearch.randomitems++;
}
else
{
globalsmuggle.eggboxes++;
g_eggboxSearch.eggboxes++;
}
return BMIT_CONTINUE;
@ -105,16 +91,16 @@ UINT8 K_EggboxStealth(fixed_t x, fixed_t y)
{
INT32 xl, xh, yl, yh, bx, by;
globalsmuggle.eggboxx = x;
globalsmuggle.eggboxy = y;
globalsmuggle.distancetocheck = (mapobjectscale * 256);
globalsmuggle.randomitems = 0;
globalsmuggle.eggboxes = 0;
g_eggboxSearch.eggboxx = x;
g_eggboxSearch.eggboxy = y;
g_eggboxSearch.distancetocheck = (mapobjectscale * 256);
g_eggboxSearch.randomitems = 0;
g_eggboxSearch.eggboxes = 0;
xl = (unsigned)(globalsmuggle.eggboxx - globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
xh = (unsigned)(globalsmuggle.eggboxx + globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
yl = (unsigned)(globalsmuggle.eggboxy - globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
yh = (unsigned)(globalsmuggle.eggboxy + globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
xl = (unsigned)(g_eggboxSearch.eggboxx - g_eggboxSearch.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
xh = (unsigned)(g_eggboxSearch.eggboxx + g_eggboxSearch.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
yl = (unsigned)(g_eggboxSearch.eggboxy - g_eggboxSearch.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
yh = (unsigned)(g_eggboxSearch.eggboxy + g_eggboxSearch.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
BMBOUNDFIX(xl, xh, yl, yh);
@ -126,7 +112,7 @@ UINT8 K_EggboxStealth(fixed_t x, fixed_t y)
}
}
return (globalsmuggle.randomitems * (globalsmuggle.eggboxes + 1));
return (g_eggboxSearch.randomitems * (g_eggboxSearch.eggboxes + 1));
}
/*--------------------------------------------------
@ -269,6 +255,19 @@ boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t
Return:-
None
--------------------------------------------------*/
static struct nudgeSearch_s
{
mobj_t *botmo;
angle_t angle;
fixed_t distancetocheck;
INT64 gotoAvgX[2], gotoAvgY[2];
UINT32 gotoObjs[2];
INT64 avoidAvgX[2], avoidAvgY[2];
UINT32 avoidObjs[2];
} g_nudgeSearch;
static void K_AddAttackObject(mobj_t *thing, UINT8 side, UINT8 weight)
{
fixed_t x, y;
@ -284,7 +283,7 @@ static void K_AddAttackObject(mobj_t *thing, UINT8 side, UINT8 weight)
x = thing->x;
y = thing->y;
a = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, x, y);
a = R_PointToAngle2(g_nudgeSearch.botmo->x, g_nudgeSearch.botmo->y, x, y);
dir = a + (side ? -ANGLE_90 : ANGLE_90);
x += FixedMul(thing->radius, FINECOSINE(dir >> ANGLETOFINESHIFT));
@ -295,9 +294,9 @@ static void K_AddAttackObject(mobj_t *thing, UINT8 side, UINT8 weight)
for (i = 0; i < weight; i++)
{
globalsmuggle.gotoAvgX[side] += x;
globalsmuggle.gotoAvgY[side] += y;
globalsmuggle.gotoObjs[side]++;
g_nudgeSearch.gotoAvgX[side] += x;
g_nudgeSearch.gotoAvgY[side] += y;
g_nudgeSearch.gotoObjs[side]++;
}
}
@ -329,7 +328,7 @@ static void K_AddDodgeObject(mobj_t *thing, UINT8 side, UINT8 weight)
x = thing->x;
y = thing->y;
a = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, x, y);
a = R_PointToAngle2(g_nudgeSearch.botmo->x, g_nudgeSearch.botmo->y, x, y);
dir = a + (side ? -ANGLE_90 : ANGLE_90);
x += FixedMul(thing->radius, FINECOSINE(dir >> ANGLETOFINESHIFT));
@ -340,9 +339,9 @@ static void K_AddDodgeObject(mobj_t *thing, UINT8 side, UINT8 weight)
for (i = 0; i < weight; i++)
{
globalsmuggle.avoidAvgX[side] += x;
globalsmuggle.avoidAvgY[side] += y;
globalsmuggle.avoidObjs[side]++;
g_nudgeSearch.avoidAvgX[side] += x;
g_nudgeSearch.avoidAvgY[side] += y;
g_nudgeSearch.avoidObjs[side]++;
}
}
@ -394,10 +393,10 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
{
INT16 angledelta, anglediff;
fixed_t fulldist;
angle_t destangle, angle, predictangle;
angle_t destangle, angle;
UINT8 side = 0;
if (!globalsmuggle.botmo || P_MobjWasRemoved(globalsmuggle.botmo) || !globalsmuggle.botmo->player)
if (!g_nudgeSearch.botmo || P_MobjWasRemoved(g_nudgeSearch.botmo) || !g_nudgeSearch.botmo->player)
{
return BMIT_ABORT;
}
@ -407,26 +406,25 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
return BMIT_CONTINUE;
}
if (globalsmuggle.botmo == thing)
if (g_nudgeSearch.botmo == thing)
{
return BMIT_CONTINUE;
}
fulldist = R_PointToDist2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, thing->x, thing->y) - thing->radius;
fulldist = R_PointToDist2(g_nudgeSearch.botmo->x, g_nudgeSearch.botmo->y, thing->x, thing->y) - thing->radius;
if (fulldist > globalsmuggle.distancetocheck)
if (fulldist > g_nudgeSearch.distancetocheck)
{
return BMIT_CONTINUE;
}
if (P_CheckSight(globalsmuggle.botmo, thing) == false)
if (P_CheckSight(g_nudgeSearch.botmo, thing) == false)
{
return BMIT_CONTINUE;
}
predictangle = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, globalsmuggle.predict->x, globalsmuggle.predict->y);
destangle = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, thing->x, thing->y);
angle = (predictangle - destangle);
destangle = R_PointToAngle2(g_nudgeSearch.botmo->x, g_nudgeSearch.botmo->y, thing->x, thing->y);
angle = (g_nudgeSearch.angle - destangle);
if (angle < ANGLE_180)
{
@ -462,7 +460,7 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
K_AddDodgeObject(thing, side, 20);
break;
case MT_SHRINK_GUN:
if (thing->target == globalsmuggle.botmo)
if (thing->target == g_nudgeSearch.botmo)
{
K_AddAttackObject(thing, side, 20);
}
@ -477,7 +475,7 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
break;
}
if (P_CanPickupItem(globalsmuggle.botmo->player, 1))
if (P_CanPickupItem(g_nudgeSearch.botmo->player, 1))
{
K_AddAttackObject(thing, side, 10);
}
@ -488,10 +486,10 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
break;
}
if (P_CanPickupItem(globalsmuggle.botmo->player, 1)) // Can pick up an actual item
if (P_CanPickupItem(g_nudgeSearch.botmo->player, 1)) // Can pick up an actual item
{
const UINT8 stealth = K_EggboxStealth(thing->x, thing->y);
const UINT8 requiredstealth = (globalsmuggle.botmo->player->botvars.difficulty * globalsmuggle.botmo->player->botvars.difficulty);
const UINT8 requiredstealth = (g_nudgeSearch.botmo->player->botvars.difficulty * g_nudgeSearch.botmo->player->botvars.difficulty);
if (stealth >= requiredstealth)
{
@ -509,7 +507,7 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
break;
}
if (P_CanPickupItem(globalsmuggle.botmo->player, 3))
if (P_CanPickupItem(g_nudgeSearch.botmo->player, 3))
{
K_AddAttackObject(thing, side, 20);
}
@ -521,31 +519,31 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
break;
}
if ((RINGTOTAL(globalsmuggle.botmo->player) < 20 && !(globalsmuggle.botmo->player->pflags & PF_RINGLOCK)
&& P_CanPickupItem(globalsmuggle.botmo->player, 0))
if ((RINGTOTAL(g_nudgeSearch.botmo->player) < 20 && !(g_nudgeSearch.botmo->player->pflags & PF_RINGLOCK)
&& P_CanPickupItem(g_nudgeSearch.botmo->player, 0))
&& !thing->extravalue1
&& (globalsmuggle.botmo->player->itemtype != KITEM_LIGHTNINGSHIELD))
&& (g_nudgeSearch.botmo->player->itemtype != KITEM_LIGHTNINGSHIELD))
{
K_AddAttackObject(thing, side, (RINGTOTAL(globalsmuggle.botmo->player) < 3) ? 5 : 1);
K_AddAttackObject(thing, side, (RINGTOTAL(g_nudgeSearch.botmo->player) < 3) ? 5 : 1);
}
break;
case MT_PLAYER:
if (thing->player
&& !thing->player->hyudorotimer
&& !globalsmuggle.botmo->player->hyudorotimer)
&& !g_nudgeSearch.botmo->player->hyudorotimer)
{
// There REALLY ought to be a better way to handle this logic, right?!
// Squishing
if (K_PlayerAttackSteer(thing, side, 20,
K_IsBigger(globalsmuggle.botmo, thing),
K_IsBigger(thing, globalsmuggle.botmo)
K_IsBigger(g_nudgeSearch.botmo, thing),
K_IsBigger(thing, g_nudgeSearch.botmo)
))
{
break;
}
// Invincibility
else if (K_PlayerAttackSteer(thing, side, 20,
globalsmuggle.botmo->player->invincibilitytimer,
g_nudgeSearch.botmo->player->invincibilitytimer,
thing->player->invincibilitytimer
))
{
@ -553,7 +551,7 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
}
// Lightning Shield
else if (K_PlayerAttackSteer(thing, side, 20,
globalsmuggle.botmo->player->itemtype == KITEM_LIGHTNINGSHIELD,
g_nudgeSearch.botmo->player->itemtype == KITEM_LIGHTNINGSHIELD,
thing->player->itemtype == KITEM_LIGHTNINGSHIELD
))
{
@ -561,7 +559,7 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
}
// Bubble Shield
else if (K_PlayerAttackSteer(thing, side, 20,
globalsmuggle.botmo->player->itemtype == KITEM_BUBBLESHIELD,
g_nudgeSearch.botmo->player->itemtype == KITEM_BUBBLESHIELD,
thing->player->itemtype == KITEM_BUBBLESHIELD
))
{
@ -569,7 +567,7 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
}
// Flame Shield
else if (K_PlayerAttackSteer(thing, side, 20,
globalsmuggle.botmo->player->itemtype == KITEM_FLAMESHIELD,
g_nudgeSearch.botmo->player->itemtype == KITEM_FLAMESHIELD,
thing->player->itemtype == KITEM_FLAMESHIELD
))
{
@ -578,7 +576,7 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
// Has held item shield
else if (K_PlayerAttackSteer(thing, side, 20,
(thing->player->pflags & (PF_ITEMOUT|PF_EGGMANOUT)),
(globalsmuggle.botmo->player->pflags & (PF_ITEMOUT|PF_EGGMANOUT))
(g_nudgeSearch.botmo->player->pflags & (PF_ITEMOUT|PF_EGGMANOUT))
))
{
break;
@ -586,7 +584,7 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
// Ring Sting
else if (K_PlayerAttackSteer(thing, side, 20,
thing->player->rings <= 0,
globalsmuggle.botmo->player->rings <= 0
g_nudgeSearch.botmo->player->rings <= 0
))
{
break;
@ -594,8 +592,8 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
else
{
// After ALL of that, we can do standard bumping
fixed_t ourweight = K_GetMobjWeight(globalsmuggle.botmo, thing);
fixed_t theirweight = K_GetMobjWeight(thing, globalsmuggle.botmo);
fixed_t ourweight = K_GetMobjWeight(g_nudgeSearch.botmo, thing);
fixed_t theirweight = K_GetMobjWeight(thing, g_nudgeSearch.botmo);
fixed_t weightdiff = 0;
if (anglediff >= 90)
@ -699,25 +697,25 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
radToPredict = distToPredict >> 1;
angleToPredict = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y);
globalsmuggle.distancetocheck = distToPredict;
g_nudgeSearch.distancetocheck = distToPredict;
baseNudge = predict->baseRadius >> 3;
maxNudge = predict->baseRadius - baseNudge;
globalsmuggle.botmo = player->mo;
globalsmuggle.predict = predict;
g_nudgeSearch.botmo = player->mo;
g_nudgeSearch.angle = angleToPredict;
// silly variable reuse
avgX = globalsmuggle.botmo->x + FixedMul(radToPredict, FINECOSINE(angleToPredict >> ANGLETOFINESHIFT));
avgY = globalsmuggle.botmo->y + FixedMul(radToPredict, FINESINE(angleToPredict >> ANGLETOFINESHIFT));
avgX = g_nudgeSearch.botmo->x + FixedMul(radToPredict, FINECOSINE(angleToPredict >> ANGLETOFINESHIFT));
avgY = g_nudgeSearch.botmo->y + FixedMul(radToPredict, FINESINE(angleToPredict >> ANGLETOFINESHIFT));
for (i = 0; i < 2; i++)
{
globalsmuggle.gotoAvgX[i] = globalsmuggle.gotoAvgY[i] = 0;
globalsmuggle.gotoObjs[i] = 0;
g_nudgeSearch.gotoAvgX[i] = g_nudgeSearch.gotoAvgY[i] = 0;
g_nudgeSearch.gotoObjs[i] = 0;
globalsmuggle.avoidAvgX[i] = globalsmuggle.avoidAvgY[i] = 0;
globalsmuggle.avoidObjs[i] = 0;
g_nudgeSearch.avoidAvgX[i] = g_nudgeSearch.avoidAvgY[i] = 0;
g_nudgeSearch.avoidObjs[i] = 0;
}
xl = (unsigned)(avgX - (distToPredict + MAXRADIUS) - bmaporgx)>>MAPBLOCKSHIFT;
@ -736,9 +734,9 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
}
// Handle dodge characters
if (globalsmuggle.avoidObjs[1] > 0 || globalsmuggle.avoidObjs[0] > 0)
if (g_nudgeSearch.avoidObjs[1] > 0 || g_nudgeSearch.avoidObjs[0] > 0)
{
if (globalsmuggle.avoidObjs[1] > globalsmuggle.avoidObjs[0])
if (g_nudgeSearch.avoidObjs[1] > g_nudgeSearch.avoidObjs[0])
{
gotoSide = 1;
}
@ -747,8 +745,8 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
gotoSide = 0;
}
avgX = (globalsmuggle.avoidAvgX[gotoSide] / globalsmuggle.avoidObjs[gotoSide]) * mapobjectscale;
avgY = (globalsmuggle.avoidAvgY[gotoSide] / globalsmuggle.avoidObjs[gotoSide]) * mapobjectscale;
avgX = (g_nudgeSearch.avoidAvgX[gotoSide] / g_nudgeSearch.avoidObjs[gotoSide]) * mapobjectscale;
avgY = (g_nudgeSearch.avoidAvgY[gotoSide] / g_nudgeSearch.avoidObjs[gotoSide]) * mapobjectscale;
avgDist = R_PointToDist2(
avgX, avgY,
@ -756,7 +754,7 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
);
// High handling characters dodge better
nudgeDist = ((9 - globalsmuggle.botmo->player->kartweight) + 1) * baseNudge;
nudgeDist = ((9 - g_nudgeSearch.botmo->player->kartweight) + 1) * baseNudge;
if (nudgeDist > maxNudge)
{
nudgeDist = maxNudge;
@ -791,7 +789,7 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
// We don't want to pick contradictory sides, so keep the old side otherwise,
// even if there's more to grab on the other side.
if (globalsmuggle.gotoObjs[1] > globalsmuggle.gotoObjs[0])
if (g_nudgeSearch.gotoObjs[1] > g_nudgeSearch.gotoObjs[0])
{
gotoSide = 1;
}
@ -802,7 +800,7 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
}
// Check if our side is invalid, if so, don't do the code below.
if (gotoSide != -1 && globalsmuggle.gotoObjs[gotoSide] == 0)
if (gotoSide != -1 && g_nudgeSearch.gotoObjs[gotoSide] == 0)
{
// Do not use a side
gotoSide = -1;
@ -810,8 +808,8 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
if (gotoSide != -1)
{
avgX = (globalsmuggle.gotoAvgX[gotoSide] / globalsmuggle.gotoObjs[gotoSide]) * mapobjectscale;
avgY = (globalsmuggle.gotoAvgY[gotoSide] / globalsmuggle.gotoObjs[gotoSide]) * mapobjectscale;
avgX = (g_nudgeSearch.gotoAvgX[gotoSide] / g_nudgeSearch.gotoObjs[gotoSide]) * mapobjectscale;
avgY = (g_nudgeSearch.gotoAvgY[gotoSide] / g_nudgeSearch.gotoObjs[gotoSide]) * mapobjectscale;
avgDist = R_PointToDist2(
predict->x, predict->y,
@ -819,7 +817,7 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
);
// Acceleration characters are more aggressive
nudgeDist = ((9 - globalsmuggle.botmo->player->kartspeed) + 1) * baseNudge;
nudgeDist = ((9 - g_nudgeSearch.botmo->player->kartspeed) + 1) * baseNudge;
if (nudgeDist > maxNudge)
{
nudgeDist = maxNudge;
@ -862,6 +860,15 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
Return:-
BlockItReturn_t enum, see its definition for more information.
--------------------------------------------------*/
static struct bullySearch_s
{
mobj_t *botmo;
fixed_t distancetocheck;
fixed_t annoyscore;
mobj_t *annoymo;
} g_bullySearch;
static BlockItReturn_t K_FindPlayersToBully(mobj_t *thing)
{
INT16 anglediff;
@ -869,7 +876,7 @@ static BlockItReturn_t K_FindPlayersToBully(mobj_t *thing)
fixed_t ourweight, theirweight, weightdiff;
angle_t ourangle, destangle, angle;
if (!globalsmuggle.botmo || P_MobjWasRemoved(globalsmuggle.botmo) || !globalsmuggle.botmo->player)
if (!g_bullySearch.botmo || P_MobjWasRemoved(g_bullySearch.botmo) || !g_bullySearch.botmo->player)
{
return BMIT_ABORT;
}
@ -884,25 +891,25 @@ static BlockItReturn_t K_FindPlayersToBully(mobj_t *thing)
return BMIT_CONTINUE;
}
if (globalsmuggle.botmo == thing)
if (g_bullySearch.botmo == thing)
{
return BMIT_CONTINUE;
}
fulldist = R_PointToDist2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, thing->x, thing->y) - thing->radius;
fulldist = R_PointToDist2(g_bullySearch.botmo->x, g_bullySearch.botmo->y, thing->x, thing->y) - thing->radius;
if (fulldist > globalsmuggle.distancetocheck)
if (fulldist > g_bullySearch.distancetocheck)
{
return BMIT_CONTINUE;
}
if (P_CheckSight(globalsmuggle.botmo, thing) == false)
if (P_CheckSight(g_bullySearch.botmo, thing) == false)
{
return BMIT_CONTINUE;
}
ourangle = globalsmuggle.botmo->angle;
destangle = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, thing->x, thing->y);
ourangle = g_bullySearch.botmo->angle;
destangle = R_PointToAngle2(g_bullySearch.botmo->x, g_bullySearch.botmo->y, thing->x, thing->y);
angle = (ourangle - destangle);
if (angle < ANGLE_180)
@ -916,8 +923,8 @@ static BlockItReturn_t K_FindPlayersToBully(mobj_t *thing)
anglediff = abs(anglediff);
ourweight = K_GetMobjWeight(globalsmuggle.botmo, thing);
theirweight = K_GetMobjWeight(thing, globalsmuggle.botmo);
ourweight = K_GetMobjWeight(g_bullySearch.botmo, thing);
theirweight = K_GetMobjWeight(thing, g_bullySearch.botmo);
weightdiff = 0;
if (anglediff >= 90)
@ -929,10 +936,10 @@ static BlockItReturn_t K_FindPlayersToBully(mobj_t *thing)
weightdiff = ourweight - theirweight;
}
if (weightdiff > mapobjectscale && weightdiff > globalsmuggle.annoyscore)
if (weightdiff > mapobjectscale && weightdiff > g_bullySearch.annoyscore)
{
globalsmuggle.annoyscore = weightdiff;
globalsmuggle.annoymo = thing;
g_bullySearch.annoyscore = weightdiff;
g_bullySearch.annoymo = thing;
}
return BMIT_CONTINUE;
@ -950,16 +957,16 @@ INT32 K_PositionBully(player_t *player)
angle_t ourangle, destangle, angle;
INT16 anglediff;
globalsmuggle.botmo = player->mo;
globalsmuggle.distancetocheck = 1024*player->mo->scale;
g_bullySearch.botmo = player->mo;
g_bullySearch.distancetocheck = 1024*player->mo->scale;
globalsmuggle.annoymo = NULL;
globalsmuggle.annoyscore = 0;
g_bullySearch.annoymo = NULL;
g_bullySearch.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;
xl = (unsigned)(g_bullySearch.botmo->x - g_bullySearch.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
xh = (unsigned)(g_bullySearch.botmo->x + g_bullySearch.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
yl = (unsigned)(g_bullySearch.botmo->y - g_bullySearch.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
yh = (unsigned)(g_bullySearch.botmo->y + g_bullySearch.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
BMBOUNDFIX(xl, xh, yl, yh);
@ -971,13 +978,13 @@ INT32 K_PositionBully(player_t *player)
}
}
if (globalsmuggle.annoymo == NULL)
if (g_bullySearch.annoymo == NULL)
{
return INT32_MAX;
}
ourangle = globalsmuggle.botmo->angle;
destangle = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, globalsmuggle.annoymo->x, globalsmuggle.annoymo->y);
ourangle = g_bullySearch.botmo->angle;
destangle = R_PointToAngle2(g_bullySearch.botmo->x, g_bullySearch.botmo->y, g_bullySearch.annoymo->x, g_bullySearch.annoymo->y);
angle = (ourangle - destangle);
if (angle < ANGLE_180)