From 6feb25cefeaad792efa461eaf384d63c0b1f4748 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Thu, 14 Aug 2025 23:00:33 +0200 Subject: [PATCH] (WIP) Rewrite bot code to be much more sane Bot logic is now handled exclusively by the server, now in the actual game loop code, rather than during ticcmd generation. No TICCMD_BOT needed! botdata_t has been added to store any variables that clients don't need. Behavior differences: * Brakedrifting actually works now... to the detriment of the bots * Respawn triggers 1 second sooner (and actually causes braking) * No longer spams respawn when a track lacks waypoints * Turning might be less responsive? `botvars.turnconfirm += cmd.bot.turnconfirm` is gone... who knows * No longer affected by timescale Plus, no more outdated or copy-pasted comment blocks! --- src/d_player.h | 33 +- src/d_ticcmd.h | 7 - src/g_demo.c | 54 +-- src/g_game.c | 10 +- src/k_bot.cpp | 600 ++++++++++++++++--------------- src/k_bot.h | 90 +++-- src/k_botitem.cpp | 840 ++++++++++++++------------------------------ src/k_botsearch.cpp | 52 ++- src/k_hud.c | 29 +- src/k_kart.c | 57 ++- src/p_saveg.c | 16 - src/p_tick.c | 7 + src/typedef.h | 2 +- 13 files changed, 693 insertions(+), 1104 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 1282b4ad8..8f4478ae7 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -419,17 +419,6 @@ typedef enum // for kickstartaccel #define ACCEL_KICKSTART (TICRATE) -// Minimum percentage for a (non-auto) drift to begin. -#define BOTDRIFTPERCENT (10) - -// Minimum turning percentage for an auto drift to begin. -#define DRIFTSTARTPCT (45) - -#define BOTDRIFTTICS (2*TICRATE/3) -#define BOTDRIFTLOCKOUT (TICRATE/2) - -#define MAXDRIFTSKILL (FRACUNIT/2) - typedef enum { BOT_STYLE_NORMAL, @@ -439,15 +428,6 @@ typedef enum BOT_STYLE__MAX } botStyle_e; -typedef enum -{ - DRIFTSTATE_AUTO, - DRIFTSTATE_STARTING, - DRIFTSTATE_ACTIVE, - DRIFTSTATE_ENDING, - NUMDRIFTSTATES -} botdrift_t; - // player_t struct for all bot variables struct botvars_t { @@ -460,19 +440,8 @@ struct botvars_t fixed_t rubberband; // Bot rubberband value UINT16 controller; // Special bot controller linedef ID - tic_t itemdelay; // Delay before using item at all - tic_t itemconfirm; // When high enough, they will use their item - - SINT8 turnconfirm; // Confirm turn direction - UINT32 respawnconfirm; // Confirm when respawn is needed. - - // Drift-relevant data below: fixed_t driftskill; // The bot's "skill" at drifts. - // Determines how soon a bot starts to drift. - botdrift_t driftstate; // Drifting state - SINT8 driftturn; // Drifting turn direction - tic_t drifttime; // Time spent drifting - tic_t driftlockout; // do not allow drifting for this many tics + // Determines how soon a bot starts to drift. }; struct sonicloopcamvars_t diff --git a/src/d_ticcmd.h b/src/d_ticcmd.h index da14ded9e..b4137c712 100644 --- a/src/d_ticcmd.h +++ b/src/d_ticcmd.h @@ -57,7 +57,6 @@ typedef enum #define TICCMD_RECEIVED (0x01) /* Actual tic recieved from client */ #define TICCMD_TYPING (0x02) /* chat window or console open */ #define TICCMD_KEYSTROKE (0x04) /* chat character input */ -#define TICCMD_BOT (0x80) /* generated by bot, demos write bot variables */ #if defined(_MSC_VER) #pragma pack(1) @@ -74,12 +73,6 @@ struct ticcmd_t UINT16 buttons; UINT8 latency; // Netgames: how many tics ago was this ticcmd generated from this player's end? UINT8 flags; - struct - { - SINT8 turnconfirm; - SINT8 itemconfirm; - SINT8 respawnconfirm; - } bot; } ATTRPACK; #if defined(_MSC_VER) diff --git a/src/g_demo.c b/src/g_demo.c index f2ea59870..aa890f090 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -146,13 +146,8 @@ demoghost *ghosts = NULL; #define ZT_AIMING 0x0040 #define ZT_LATENCY 0x0080 #define ZT_FLAGS 0x0100 -#define ZT_BOT 0x8000 // Ziptics are UINT16 now, go nuts -#define ZT_BOT_TURN 0x0001 -#define ZT_BOT_ITEM 0x0002 -#define ZT_BOT_RESPAWN 0x0004 - #define DEMOMARKER 0x80 // demobuf.end UINT8 demo_extradata[MAXPLAYERS]; @@ -398,16 +393,12 @@ static UINT8 *G_ReadZipTic(ticcmd_t *cmd, UINT8 *dp, UINT16 version) if (ziptic & ZT_FLAGS) cmd->flags = READUINT8(dp); - if (ziptic & ZT_BOT) + if (version < 0x0009 && ziptic & 0x8000) // ZT_BOT { UINT16 botziptic = READUINT16(dp); - - if (botziptic & ZT_BOT_TURN) - cmd->bot.turnconfirm = READSINT8(dp); - if (botziptic & ZT_BOT_ITEM) - cmd->bot.itemconfirm = READSINT8(dp); - if (botziptic & ZT_BOT_RESPAWN) - cmd->bot.respawnconfirm = READSINT8(dp); + if (botziptic & 1) READSINT8(dp); + if (botziptic & 2) READSINT8(dp); + if (botziptic & 4) READSINT8(dp); } return dp; } @@ -1403,45 +1394,8 @@ void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum) ziptic |= ZT_FLAGS; } - if (cmd->flags & TICCMD_BOT) - { - ziptic |= ZT_BOT; - } - WRITEUINT16(ziptic_p, ziptic); - if (ziptic & ZT_BOT) - { - UINT16 botziptic = 0; - UINT8 *botziptic_p; - - botziptic_p = demobuf.p; // the ziptic, written at the end of this function - demobuf.p += 2; - - if (cmd->bot.turnconfirm != oldcmd[playernum].bot.turnconfirm) - { - WRITESINT8(demobuf.p, cmd->bot.turnconfirm); - oldcmd[playernum].bot.turnconfirm = cmd->bot.turnconfirm; - botziptic |= ZT_BOT_TURN; - } - - if (cmd->bot.itemconfirm != oldcmd[playernum].bot.itemconfirm) - { - WRITESINT8(demobuf.p, cmd->bot.itemconfirm); - oldcmd[playernum].bot.itemconfirm = cmd->bot.itemconfirm; - botziptic |= ZT_BOT_ITEM; - } - - if (cmd->bot.respawnconfirm != oldcmd[playernum].bot.respawnconfirm) - { - WRITESINT8(demobuf.p, cmd->bot.respawnconfirm); - oldcmd[playernum].bot.respawnconfirm = cmd->bot.respawnconfirm; - botziptic |= ZT_BOT_RESPAWN; - } - - WRITEUINT16(botziptic_p, botziptic); - } - // attention here for the ticcmd size! // latest demos with mouse aiming byte in ticcmd if (!(demoflags & DF_GHOST) && ziptic_p > demobuf.end - 9) diff --git a/src/g_game.c b/src/g_game.c index b1a2d075a..c69297469 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1363,13 +1363,6 @@ ticcmd_t *G_MoveTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n) dest[i].buttons = (UINT16)SHORT(src[i].buttons); dest[i].latency = src[i].latency; dest[i].flags = src[i].flags; - - if (dest[i].flags & TICCMD_BOT) - { - dest[i].bot.itemconfirm = src[i].bot.itemconfirm; - dest[i].bot.turnconfirm = src[i].bot.turnconfirm; - dest[i].bot.respawnconfirm = src[i].bot.respawnconfirm; - } } return dest; } @@ -2670,7 +2663,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) p->botvars.controller = UINT16_MAX; p->botvars.driftskill = FixedMul(MAXDRIFTSKILL, K_BotDetermineDriftSkill(p)); - p->botvars.driftstate = DRIFTSTATE_AUTO; + + K_BotRespawn(p); if (follower) P_RemoveMobj(follower); diff --git a/src/k_bot.cpp b/src/k_bot.cpp index f042699c9..06b3a3579 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -42,10 +42,46 @@ #endif #include "i_net.h" // doomcom #include "blan/b_soc.h" +#include "v_video.h" // for debugging consvar_t cv_forcebots = CVAR_INIT ("kartforcebots", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); consvar_t cv_botcontrol = CVAR_INIT ("kartbotcontrol", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); +botdata_t botdata[MAXPLAYERS]; + +void K_DrawBotDebugger(const player_t *player) +{ + INT32 vflags = V_6WIDTHSPACE|V_ALLOWLOWERCASE|V_30TRANS; + botdata_t *bd = &botdata[player - players]; + + static const char *driftstates[] = { + "auto", // DRIFTSTATE_AUTO + "starting", // DRIFTSTATE_STARTING + "active", // DRIFTSTATE_ACTIVE + "ending", // DRIFTSTATE_ENDING + }; + + if (!cv_kartdebugbot.value || !player->bot) + return; + + INT32 x1 = 26, x2 = 99, y = 92; + + V_DrawThinString(x1, y+0, vflags, va("predict.x: %d", bd->predict.x/FRACUNIT)); + V_DrawThinString(x2, y+0, vflags, va("predict.y: %d", bd->predict.y/FRACUNIT)); + V_DrawThinString(x1, y+8, vflags, va("predict.radius: %d", bd->predict.radius/FRACUNIT)); + V_DrawThinString(x2, y+8, vflags, va("predict.baseradius: %d", bd->predict.baseRadius/FRACUNIT)); + + V_DrawThinString(x1, y+16, vflags, va("itemconfirm: %d", bd->itemconfirm)); + V_DrawThinString(x2, y+16, vflags, va("itemdelay: %d", bd->itemdelay)); + V_DrawThinString(x1, y+24, vflags, va("turnconfirm: %d", bd->turnconfirm)); + V_DrawThinString(x2, y+24, vflags, va("respawnconfirm: %d", bd->respawnconfirm)); + + V_DrawThinString(x1, y+32, vflags, va("driftstate: %s", driftstates[bd->driftstate])); + V_DrawThinString(x2, y+32, vflags|(bd->driftlockout ? V_ORANGEMAP : 0), va("driftlockout: %d", bd->driftlockout)); + V_DrawThinString(x1, y+40, vflags, va("driftturn: %d", bd->driftturn)); + V_DrawThinString(x2, y+40, vflags, va("drifttime: %d", bd->drifttime)); +} + /*-------------------------------------------------- void K_SetNameForBot(UINT8 playerNum, const char *realname) @@ -838,18 +874,8 @@ static fixed_t K_ScaleWPDistWithSlope(fixed_t disttonext, angle_t angletonext, c return disttonext; } -/*-------------------------------------------------- - static botprediction_t *K_CreateBotPrediction(const player_t *player) - - Calculates a point further along the track to attempt to drive towards. - - Input Arguments:- - player - Player to compare. - - Return:- - Bot prediction struct. ---------------------------------------------------*/ -static botprediction_t *K_CreateBotPrediction(player_t *player) +// Calculates a point further along the track to attempt to drive towards. +static boolean K_CreateBotPrediction(botdata_t *bd, player_t *player) { ZoneScoped; @@ -884,17 +910,14 @@ static botprediction_t *K_CreateBotPrediction(player_t *player) boolean pathfindsuccess = false; path_t pathtofinish = {0}; - botprediction_t *predict = nullptr; size_t i; if (wp == nullptr || P_MobjWasRemoved(wp->mobj) == true) { // Can't do any of this if we don't have a waypoint. - return nullptr; + return false; } - predict = static_cast(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); disttonext = P_AproxDistance(prevwpmobj->x - wp->mobj->x, prevwpmobj->y - wp->mobj->y); @@ -950,22 +973,22 @@ static botprediction_t *K_CreateBotPrediction(player_t *player) // Set our predicted point's coordinates, // and use the smallest radius of all of the waypoints in the chain! - predict->x = wp->mobj->x; - predict->y = wp->mobj->y; + bd->predict.x = wp->mobj->x; + bd->predict.y = wp->mobj->y; - predict->baseRadius = radius; - predict->radius = FixedMul(radiusScaled, radReduce); + bd->predict.baseRadius = radius; + bd->predict.radius = FixedMul(radiusScaled, radReduce); // Set the prediction coordinates between the 2 waypoints if there's still distance left. if (distanceleft > 0) { // Scaled with the leftover anglemul! - predict->x += P_ReturnThrustX(nullptr, angletonext, std::min(disttonext, distanceleft) * FRACUNIT); - predict->y += P_ReturnThrustY(nullptr, angletonext, std::min(disttonext, distanceleft) * FRACUNIT); + bd->predict.x += P_ReturnThrustX(nullptr, angletonext, std::min(disttonext, distanceleft) * FRACUNIT); + bd->predict.y += P_ReturnThrustY(nullptr, angletonext, std::min(disttonext, distanceleft) * FRACUNIT); } ps_bots[player - players].prediction += I_GetPreciseTime() - time; - return predict; + return true; } /*-------------------------------------------------- @@ -980,19 +1003,18 @@ static botprediction_t *K_CreateBotPrediction(player_t *player) Return:- None --------------------------------------------------*/ -static void K_DrawPredictionDebug(botprediction_t *predict, const player_t *player) +static void K_DrawPredictionDebug(botdata_t *bd, const player_t *player) { mobj_t *debugMobj = nullptr; angle_t sideAngle = ANGLE_MAX; UINT8 i = UINT8_MAX; - I_Assert(predict != nullptr); I_Assert(player != nullptr); I_Assert(player->mo != nullptr && P_MobjWasRemoved(player->mo) == false); sideAngle = player->mo->angle + ANGLE_90; - debugMobj = P_SpawnMobj(predict->x, predict->y, player->mo->z, MT_SPARK); + debugMobj = P_SpawnMobj(bd->predict.x, bd->predict.y, player->mo->z, MT_SPARK); P_SetMobjState(debugMobj, S_THOK); debugMobj->frame &= ~FF_TRANSMASK; @@ -1001,22 +1023,22 @@ static void K_DrawPredictionDebug(botprediction_t *predict, const player_t *play debugMobj->color = SKINCOLOR_ORANGE; P_SetScale(debugMobj, debugMobj->destscale * 2); - debugMobj->tics = 2; + debugMobj->tics = 1; for (i = 0; i < 2; i++) { mobj_t *radiusMobj = nullptr; - fixed_t radiusX = predict->x, radiusY = predict->y; + fixed_t radiusX = bd->predict.x, radiusY = bd->predict.y; if (i & 1) { - radiusX -= FixedMul(predict->radius, FINECOSINE(sideAngle >> ANGLETOFINESHIFT)); - radiusY -= FixedMul(predict->radius, FINESINE(sideAngle >> ANGLETOFINESHIFT)); + radiusX -= FixedMul(bd->predict.radius, FINECOSINE(sideAngle >> ANGLETOFINESHIFT)); + radiusY -= FixedMul(bd->predict.radius, FINESINE(sideAngle >> ANGLETOFINESHIFT)); } else { - radiusX += FixedMul(predict->radius, FINECOSINE(sideAngle >> ANGLETOFINESHIFT)); - radiusY += FixedMul(predict->radius, FINESINE(sideAngle >> ANGLETOFINESHIFT)); + radiusX += FixedMul(bd->predict.radius, FINECOSINE(sideAngle >> ANGLETOFINESHIFT)); + radiusY += FixedMul(bd->predict.radius, FINESINE(sideAngle >> ANGLETOFINESHIFT)); } radiusMobj = P_SpawnMobj(radiusX, radiusY, player->mo->z, MT_SPARK); @@ -1028,7 +1050,7 @@ static void K_DrawPredictionDebug(botprediction_t *predict, const player_t *play radiusMobj->color = SKINCOLOR_YELLOW; P_SetScale(debugMobj, debugMobj->destscale / 2); - radiusMobj->tics = 2; + radiusMobj->tics = 1; } } @@ -1069,32 +1091,24 @@ static void K_WaypointGetDirectionVector(waypoint_t *wp1, waypoint_t *wp2, vecto See header file for description. --------------------------------------------------*/ -void K_BotSetDriftState(player_t *player, botdrift_t newstate, tic_t lockout) +void K_BotSetDriftState(player_t *player, botdrift_e newstate, tic_t lockout) { - if (newstate != player->botvars.driftstate) + botdata_t *bd = &botdata[player - players]; + + if (newstate != bd->driftstate) { - player->botvars.driftstate = newstate; - player->botvars.drifttime = 0; + bd->driftstate = newstate; + bd->drifttime = 0; } - if (lockout > player->botvars.driftlockout) - player->botvars.driftlockout = lockout; + if (lockout > bd->driftlockout) + bd->driftlockout = lockout; } #define MINBOTDRIFT (KART_FULLTURN * 2) / 3 // 0.66 -/*-------------------------------------------------- - static INT32 K_BotStartDrift(player_t* player) - - Begins and ends "forced" drifts on a per-waypoint basis. - - Input Arguments:- - player - Player to begin the drift for. - - Return:- - Override value for turn amount. ---------------------------------------------------*/ -static void K_BotStartDrift(player_t* player) +// Begins and ends "forced" drifts on a per-waypoint basis. +static void K_BotStartDrift(botdata_t *bd, player_t* player) { // Handle DRIFTING towards waypoints! boolean shouldDrift; @@ -1116,17 +1130,17 @@ static void K_BotStartDrift(player_t* player) return; } - if (player->botvars.driftlockout) + if (bd->driftlockout) { // things are not working out in our favor - player->botvars.driftlockout--; + bd->driftlockout--; return; } // check for waypoints ahead of us with drift settings, based on our current speed path_t path = {0}; INT32 maxdist = FixedInt(cv_test1.value) + gamespeed*50; - maxdist = FixedMul(maxdist, speedfactor * (player->botvars.driftstate == DRIFTSTATE_ACTIVE ? 1 : 2)); + maxdist = FixedMul(maxdist, speedfactor * (bd->driftstate == DRIFTSTATE_ACTIVE ? 1 : 2)); if (maxdist >= 0 && K_PathfindThruCircuit(player->currentwaypoint, maxdist, &path, false, false)) { @@ -1156,11 +1170,11 @@ static void K_BotStartDrift(player_t* player) if (driftsetting == DRIFT_END) { - if (player->botvars.driftstate != DRIFTSTATE_AUTO) + if (bd->driftstate != DRIFTSTATE_AUTO) K_BotSetDriftState(player, DRIFTSTATE_ENDING, 0); } else if (driftsetting > DRIFT_NONE && driftsetting < DRIFT_END - && player->botvars.driftstate == DRIFTSTATE_AUTO) + && bd->driftstate == DRIFTSTATE_AUTO) { // Randomly decide to drift based on our skill at drifting, // and how fast we're moving. @@ -1195,26 +1209,14 @@ static void K_BotStartDrift(player_t* player) break; } - player->botvars.driftturn = driftturn; + bd->driftturn = driftturn; K_BotSetDriftState(player, DRIFTSTATE_STARTING, 0); } } } -/*-------------------------------------------------- - static INT32 K_HandleBotTrack(const 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) +// Determines inputs for standard track driving. +static INT32 K_HandleBotTrack(botdata_t *bd, player_t *player, angle_t destangle) { ZoneScoped; @@ -1225,15 +1227,13 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t * INT32 anglediff, anglediff2; fixed_t speedfactor = FixedDiv(player->speed, K_GetKartSpeed(player, false, false)); - I_Assert(predict != nullptr); - moveangle = player->mo->angle; anglediff = AngleDeltaSigned(moveangle, destangle); // line up for an incoming drift - if (player->botvars.driftstate == DRIFTSTATE_STARTING) + if (bd->driftstate == DRIFTSTATE_STARTING) { - anglediff += FixedMul(ANG10-ANG2, speedfactor) * player->botvars.driftturn; + anglediff += FixedMul(ANG10-ANG2, speedfactor) * bd->driftturn; } if (anglediff < 0) @@ -1252,18 +1252,18 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t * if (anglediff > ANGLE_67h) { // Wrong way! - cmd->forwardmove = -MAXPLMOVE; - cmd->buttons |= BT_BRAKE; + bd->acceldown = false; + bd->brakedown = true; } else { const fixed_t playerwidth = (player->mo->radius * 2); - fixed_t realrad = predict->radius*3/4; // Remove a "safe" distance away from the edges of the road + fixed_t realrad = bd->predict.radius*3/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 + bd->predict.x, bd->predict.y ); if (realrad < playerwidth) @@ -1296,11 +1296,11 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t * } // Full speed ahead! - cmd->buttons |= BT_ACCELERATE; - cmd->forwardmove = MAXPLMOVE; + bd->acceldown = true; + bd->brakedown = false; if (dirdist <= rad - && player->botvars.driftstate != DRIFTSTATE_STARTING) // steer towards waypoints when starting drift + && bd->driftstate != DRIFTSTATE_STARTING) // steer towards waypoints when starting drift { // Going the right way, don't turn at all. turnamt = 0; @@ -1310,11 +1310,11 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t * //INT32 mindriftamt = FixedMul(MINBOTDRIFT * (cv_kartspeed.value + 1), 2 * FRACUNIT); // Start or continue a drift. - if (player->botvars.driftstate == DRIFTSTATE_ACTIVE || player->botvars.driftstate == DRIFTSTATE_ENDING) + if (bd->driftstate == DRIFTSTATE_ACTIVE || bd->driftstate == DRIFTSTATE_ENDING) { - cmd->buttons |= BT_DRIFT; + bd->driftdown = true; - fixed_t angofs = K_GetKartSpeedFromStat(5 - (player->kartspeed - 5), false) * -player->botvars.driftturn; + fixed_t angofs = K_GetKartSpeedFromStat(5 - (player->kartspeed - 5), false) * -bd->driftturn; // adjust for speed angofs = FixedMul(angofs, speedfactor - (2-gamespeed)*FRACUNIT/4); @@ -1326,16 +1326,16 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t * // brakedrift if we're steering too hard if (abs(driftpower) >= FRACUNIT) - cmd->buttons |= BT_BRAKE; + bd->brakedown = true; // get the raw turn value and "invert" it (higher weight needs harder steering!) - INT16 turnvalue = abs(K_GetKartTurnValue(player, KART_FULLTURN * (player->botvars.driftturn < 0 ? 1 : -1))); + INT16 turnvalue = abs(K_GetKartTurnValue(player, KART_FULLTURN * (bd->driftturn < 0 ? 1 : -1))); turnvalue = 541 - (turnvalue - 541); // weight 5 = 541 turnamt = std::clamp(FixedMul(driftpower, turnvalue), -KART_FULLTURN, KART_FULLTURN); } /* - else if ((turnamt) && (player->botvars.driftstate == DRIFTSTATE_AUTO) && + else if ((turnamt) && (bd->driftstate == DRIFTSTATE_AUTO) && (turnpower > FixedPercentage(DRIFTSTARTPCT))) { // TODO: Figure out a drift prediction system. @@ -1348,6 +1348,38 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t * #undef MINBOTDRIFT +static void K_IncrementBotRespawn(player_t *player, UINT8 *respawn, const UINT8 respawnmax) +{ + const fixed_t requireDist = (12*player->mo->scale) / FRACUNIT; + INT32 progress = player->distancetofinishprev - player->distancetofinish; + boolean exceptions = ( + (leveltime < starttime) + || player->flashing != 0 + || player->spinouttimer != 0 + || player->airtime > 3*TICRATE/2 + || (player->justbumped > 0 && player->justbumped < bumptime-1) + ); + + if (!exceptions && (progress < requireDist)) + { + if (*respawn < respawnmax) + { + // Making no progress, start counting against you. + *respawn = *respawn + 1; + if (progress < -requireDist && *respawn < respawnmax) + { + // Making NEGATIVE progress? Start counting even harder. + *respawn = *respawn + 1; + } + } + } + else if (*respawn > 0) + { + // Playing normally. + *respawn = *respawn - 1; + } +} + /*-------------------------------------------------- static INT32 K_HandleBotReverse(const player_t *player, ticcmd_t *cmd, botprediction_t *predict) @@ -1493,26 +1525,24 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t * return turnamt; }*/ -/*-------------------------------------------------- - static void K_BuildBotTiccmdNormal(const player_t *player, ticcmd_t *cmd) - - Build ticcmd for bots with a style of BOT_STYLE_NORMAL ---------------------------------------------------*/ -static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd) +// updates server-sided bot logic +void K_BotTicker(player_t *player) { - precise_t t = 0; - - botprediction_t *predict = nullptr; - auto predict_finally = srb2::finally([&predict]() { Z_Free(predict); }); - angle_t destangle = 0; INT32 turnamt = 0; + botdata_t *bd = &botdata[player - players]; + bd->itemwasdown = bd->itemdown; + bd->acceldown = bd->brakedown = bd->driftdown = bd->itemdown = false; + bd->dolookback = false; + bd->itemthrow = 0; + if (!(gametyperules & GTR_BOTS) // No bot behaviors || K_GetNumWaypoints() == 0 // No waypoints || leveltime <= introtime // During intro camera || player->playerstate == PST_DEAD // Dead, respawning. - || player->mo->scale <= 1) // Post-finish "death" animation + || player->mo->scale <= 1 // Post-finish "death" animation + || player->spectator) // spectating { // No need to do anything else. return; @@ -1539,53 +1569,57 @@ static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd) if (player->exiting) { - //Bot finish // TODO: Make bots spin around like a player would based on random chance return; } - if (player->botvars.respawnconfirm >= BOTRESPAWNCONFIRM) + // Is a bot not making any progress? Kill it and respawn at next waypoint. + K_IncrementBotRespawn(player, &bd->respawnconfirm, BOTRESPAWNCONFIRM); + + if (bd->respawnconfirm > BOTRESPAWNCONFIRM - TICRATE) { // We want to respawn. Simply hold brake and stop here! - cmd->buttons &= ~BT_ACCELERATE|BT_DRIFT|BT_ATTACK; + bd->acceldown = false; + K_BotSetDriftState(player, DRIFTSTATE_AUTO, TICRATE); if (player->speed > 0) - { - cmd->buttons |= (BT_BRAKE); - cmd->bot.respawnconfirm++; - } + bd->brakedown = true; - if ((player->speed < 10*FRACUNIT)) + if (bd->respawnconfirm >= BOTRESPAWNCONFIRM || player->speed < 10*FRACUNIT) { - cmd->bot.respawnconfirm = TICRATE; + // Now a clean function! Neat, eh? + K_SetRespawnAtNextWaypoint(player); + + // WHAT ARE YOU DOING??? RACE ALREADY! + P_DamageMobj(player->mo, NULL, NULL, 1, DMG_INSTAKILL); } return; } - else - { - cmd->bot.respawnconfirm = 0; - } + destangle = player->mo->angle; + // it's time to start predicting + memset(&bd->predict, 0, sizeof(bd->predict)); + boolean forcedDir = false; if (botController != nullptr && (botController->flags & TMBOT_FORCEDIR) == TMBOT_FORCEDIR) { const fixed_t dist = DEFAULT_WAYPOINT_RADIUS * player->mo->scale; // Overwritten prediction - predict = static_cast(Z_Calloc(sizeof(botprediction_t), PU_STATIC, nullptr)); - - predict->x = player->mo->x + FixedMul(dist, FINECOSINE(botController->forceAngle >> ANGLETOFINESHIFT)); - predict->y = player->mo->y + FixedMul(dist, FINESINE(botController->forceAngle >> ANGLETOFINESHIFT)); - predict->radius = (DEFAULT_WAYPOINT_RADIUS / 4) * mapobjectscale; + bd->predict = { + .x = player->mo->x + FixedMul(dist, FINECOSINE(botController->forceAngle >> ANGLETOFINESHIFT)), + .y = player->mo->y + FixedMul(dist, FINESINE(botController->forceAngle >> ANGLETOFINESHIFT)), + .radius = (DEFAULT_WAYPOINT_RADIUS / 4) * mapobjectscale, + }; forcedDir = true; } if (forcedDir == true) { - destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y); - turnamt = K_HandleBotTrack(player, cmd, predict, destangle); + destangle = R_PointToAngle2(player->mo->x, player->mo->y, bd->predict.x, bd->predict.y); + turnamt = K_HandleBotTrack(bd, player, destangle); } else if (leveltime <= starttime) { @@ -1594,210 +1628,69 @@ static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd) if (player->botvars.difficulty > 4) { if (leveltime >= starttime-TICRATE-TICRATE/7+finaltiming) - { - cmd->buttons |= BT_ACCELERATE; - cmd->forwardmove = MAXPLMOVE; - } + bd->acceldown = true; } } else { - // Handle steering towards waypoints! - if (predict == nullptr) + // Create a prediction. + if (K_CreateBotPrediction(bd, player)) { - // Create a prediction. - predict = K_CreateBotPrediction(player); - } - - if (predict != nullptr) - { - K_NudgePredictionTowardsObjects(predict, player); - destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y); - turnamt = K_HandleBotTrack(player, cmd, predict, destangle); + K_NudgePredictionTowardsObjects(bd, player); + destangle = R_PointToAngle2(player->mo->x, player->mo->y, bd->predict.x, bd->predict.y); + turnamt = K_HandleBotTrack(bd, player, destangle); } } + if (turnamt > KART_FULLTURN) + { + turnamt = KART_FULLTURN; + } + else if (turnamt < -KART_FULLTURN) + { + turnamt = -KART_FULLTURN; + } + + bd->turnamt = turnamt; + if (player->exiting == 0) { // TODO: Allowing projectile items like orbinaut while e-braking would be nice, maybe just pass in the spindash variable? - t = I_GetPreciseTime(); - K_BotItemUsage(player, cmd, turnamt); + precise_t t = I_GetPreciseTime(); + K_BotItemUsage(bd, player); ps_bots[player - players].item = I_GetPreciseTime() - t; } - if (turnamt != 0) + if (turnamt > 0) { - if (turnamt > KART_FULLTURN) + // Count up + if (bd->turnconfirm < BOTTURNCONFIRM) { - turnamt = KART_FULLTURN; + bd->turnconfirm++; } - else if (turnamt < -KART_FULLTURN) + } + else if (turnamt < 0) + { + // Count down + if (bd->turnconfirm > -BOTTURNCONFIRM) { - turnamt = -KART_FULLTURN; + bd->turnconfirm--; } - - if (turnamt > 0) + } + else + { + // Back to neutral + if (bd->turnconfirm < 0) { - // Count up - if (player->botvars.turnconfirm < BOTTURNCONFIRM) - { - cmd->bot.turnconfirm++; - } + bd->turnconfirm++; } - else if (turnamt < 0) + else if (bd->turnconfirm > 0) { - // Count down - if (player->botvars.turnconfirm > -BOTTURNCONFIRM) - { - cmd->bot.turnconfirm--; - } - } - else - { - // Back to neutral - if (player->botvars.turnconfirm < 0) - { - cmd->bot.turnconfirm++; - } - else if (player->botvars.turnconfirm > 0) - { - cmd->bot.turnconfirm--; - } - } - - if (abs(player->botvars.turnconfirm) >= BOTTURNCONFIRM) - { - // You're commiting to your turn, you're allowed! - cmd->turning = turnamt; - if (P_CanPlayerTurn(player, cmd)) - cmd->angle += K_GetKartTurnValue(player, turnamt); + bd->turnconfirm--; } } - // Free the prediction we made earlier - if (predict != nullptr) - { - if (cv_kartdebugbot.value != 0 && player - players == displayplayers[0] && !(paused || P_AutoPause())) - { - K_DrawPredictionDebug(predict, player); - } - } -} - -/*-------------------------------------------------- - void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) - - See header file for description. ---------------------------------------------------*/ -void K_BuildBotTiccmd( - player_t *player, // annoyingly NOT const because of LUA_HookTiccmd... grumble grumble - ticcmd_t *cmd) -{ - ZoneScoped; - - // Remove any existing controls - memset(cmd, 0, sizeof(ticcmd_t)); - - if (player->mo == nullptr - || player->spectator == true - || G_GamestateUsesLevel() == false) - { - // Not in the level. - return; - } - - cmd->angle = player->mo->angle >> TICCMD_REDUCE; - - // Complete override of all ticcmd functionality. - // May add more hooks to individual pieces of bot ticcmd, - // but this should always be here so anyone can roll - // their own :) - if (LUA_HookTiccmd(player, cmd, HOOK(BotTiccmd)) == true) - { - cmd->flags |= TICCMD_BOT; - return; - } - - cmd->flags |= TICCMD_BOT; - - switch (player->botvars.style) - { - case BOT_STYLE_STAY: - { - // Hey, this one's pretty easy :P - break; - } - default: - { - K_BuildBotTiccmdNormal(player, cmd); - break; - } - } -} - -static void K_IncrementBotRespawn(player_t *player, UINT32 *respawn, const UINT32 respawnmax) -{ - const fixed_t requireDist = (12*player->mo->scale) / FRACUNIT; - INT32 progress = player->distancetofinishprev - player->distancetofinish; - boolean exceptions = ( - (leveltime < starttime) - || player->flashing != 0 - || player->spinouttimer != 0 - || player->airtime > 3*TICRATE/2 - || (player->justbumped > 0 && player->justbumped < bumptime-1) - ); - - if (!exceptions && (progress < requireDist)) - { - if (*respawn < respawnmax) - { - // Making no progress, start counting against you. - *respawn = *respawn + 1; - if (progress < -requireDist && *respawn < respawnmax) - { - // Making NEGATIVE progress? Start counting even harder. - *respawn = *respawn + 1; - } - } - } - else if (*respawn > 0) - { - // Playing normally. - *respawn = *respawn - 1; - } -} - -/*-------------------------------------------------- - void K_UpdateBotGameplayVars(player_t *player); - - See header file for description. ---------------------------------------------------*/ -void K_UpdateBotGameplayVars(player_t *player) -{ - if (gamestate != GS_LEVEL || !player->mo) - { - // Not in the level. - return; - } - - player->botvars.rubberband = K_UpdateRubberband(player); - - player->botvars.turnconfirm += player->cmd.bot.turnconfirm; - - // Is a bot not making any progress? Kill it and respawn at next waypoint. - K_IncrementBotRespawn(player, &player->botvars.respawnconfirm, BOTRESPAWNCONFIRM); - - if ((player->cmd.bot.respawnconfirm >= TICRATE) && (player->botvars.respawnconfirm >= BOTRESPAWNCONFIRM)) - { - // Now a clean function! Neat, eh? - K_SetRespawnAtNextWaypoint(player); - - // WHAT ARE YOU DOING??? RACE ALREADY! - P_DamageMobj(player->mo, NULL, NULL, 1, DMG_INSTAKILL); - - player->botvars.respawnconfirm = 0; - } - else if (player->cmd.forwardmove < 0) + if (!bd->acceldown && bd->brakedown) { // stop drifting if we're reversing K_BotSetDriftState(player, DRIFTSTATE_AUTO, BOTDRIFTLOCKOUT); @@ -1807,15 +1700,15 @@ void K_UpdateBotGameplayVars(player_t *player) // Figure out if we need to drift. // Drift-ending waypoints will kill the drift timer, // so no need to worry about doing that ourselves. - K_BotStartDrift(player); + K_BotStartDrift(bd, player); INT32 limit = FixedInt(cv_test3.value) - gamespeed*5; - INT32 dtime = ++player->botvars.drifttime; + INT32 dtime = ++bd->drifttime; // the faster we are going, the sooner we need to drift fixed_t speedfactor = FixedDiv(player->speed, K_GetKartSpeed(player, false, false)); - switch (player->botvars.driftstate) + switch (bd->driftstate) { case DRIFTSTATE_STARTING: limit = std::max(0, limit - FixedMul(TICRATE/5, speedfactor)); @@ -1838,5 +1731,108 @@ void K_UpdateBotGameplayVars(player_t *player) } } + if (cv_kartdebugbot.value != 0 && player - players == displayplayers[0] && !(paused || P_AutoPause())) + { + K_DrawPredictionDebug(bd, player); + } +} + +/*-------------------------------------------------- + void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) + + See header file for description. +--------------------------------------------------*/ +void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) +{ + ZoneScoped; + + botdata_t *bd = &botdata[player - players]; + + // Remove any existing controls + memset(cmd, 0, sizeof(ticcmd_t)); + + if (player->mo == nullptr + || player->spectator == true + || G_GamestateUsesLevel() == false) + { + // Not in the level. + return; + } + + cmd->angle = player->mo->angle >> TICCMD_REDUCE; + + // Complete override of all ticcmd functionality. + // May add more hooks to individual pieces of bot ticcmd, + // but this should always be here so anyone can roll + // their own :) + if (LUA_HookTiccmd(player, cmd, HOOK(BotTiccmd)) == true) + return; + + if (player->botvars.style == BOT_STYLE_STAY) + { + // Hey, this one's pretty easy :P + return; + } + + // BOT_STYLE_NORMAL is the only other style, so... + cmd->forwardmove = !!bd->acceldown * MAXPLMOVE - !!bd->brakedown * MAXPLMOVE/2; + if (bd->itemthrow != 0) + { + cmd->throwdir = bd->itemthrow * KART_FULLTURN; + cmd->buttons |= bd->itemthrow > 0 ? BT_FORWARD : BT_BACKWARD; + } + + if (bd->acceldown) + cmd->buttons |= BT_ACCELERATE; + if (bd->brakedown) + cmd->buttons |= BT_BRAKE; + if (bd->driftdown) + cmd->buttons |= BT_DRIFT; + if (bd->itemdown) + cmd->buttons |= BT_ATTACK; + + if (bd->dolookback) + cmd->buttons |= BT_LOOKBACK; + + if (abs(bd->turnconfirm) >= BOTTURNCONFIRM) + { + // You're commiting to your turn, you're allowed! + cmd->turning = bd->turnamt; + if (P_CanPlayerTurn(player, cmd)) + cmd->angle += K_GetKartTurnValue(player, bd->turnamt); + } +} + +/*-------------------------------------------------- + void K_UpdateBotGameplayVars(player_t *player); + + See header file for description. +--------------------------------------------------*/ +void K_UpdateBotGameplayVars(player_t *player) +{ + if (gamestate != GS_LEVEL || !player->mo) + { + // Not in the level. + return; + } + + player->botvars.rubberband = K_UpdateRubberband(player); + K_UpdateBotGameplayVarsItemUsage(player); } + +// resets some botdata stuff after respawning +void K_BotRespawn(player_t *player) +{ + botdata_t *bd = &botdata[player - players]; + memset(bd, 0, sizeof(*bd)); + bd->driftstate = DRIFTSTATE_AUTO; +} + +void K_BotResetItemConfirm(player_t *player, boolean setdelay) +{ + botdata_t *bd = &botdata[player - players]; + bd->itemconfirm = 0; + if (setdelay) + bd->itemdelay = TICRATE; +} diff --git a/src/k_bot.h b/src/k_bot.h index 139b0d46e..ddfbe368e 100644 --- a/src/k_bot.h +++ b/src/k_bot.h @@ -44,15 +44,60 @@ extern consvar_t cv_botcontrol; // How long it takes for a Lv.1 bot to decide to pick an item. #define BOT_ITEM_DECISION_TIME (2*TICRATE) -// Point for bots to aim for -struct botprediction_t +// Minimum percentage for a (non-auto) drift to begin. +#define BOTDRIFTPERCENT (10) + +// Minimum turning percentage for an auto drift to begin. +#define DRIFTSTARTPCT (45) + +#define BOTDRIFTTICS (2*TICRATE/3) +#define BOTDRIFTLOCKOUT (TICRATE/2) + +#define MAXDRIFTSKILL (FRACUNIT/2) + +typedef enum { - fixed_t x, y; - fixed_t radius, baseRadius; + DRIFTSTATE_AUTO, + DRIFTSTATE_STARTING, + DRIFTSTATE_ACTIVE, + DRIFTSTATE_ENDING, + NUMDRIFTSTATES +} ATTRPACK botdrift_e; + +// unsynced bot variables, exclusively for use by bot logic and ticcmd generation +// nobody except the server cares about this stuff! +struct botdata_t +{ + // Point for bots to aim for + struct + { + fixed_t x, y; + fixed_t radius, baseRadius; + } predict; + + tic_t itemdelay; // Delay before using item at all + tic_t itemconfirm; // When high enough, they will use their item + + SINT8 turnconfirm; // Confirm turn direction + UINT8 respawnconfirm; // Confirm when respawn is needed. + + botdrift_e driftstate; // Drifting state + SINT8 driftturn; // Drifting turn direction + tic_t drifttime; // Time spent drifting + tic_t driftlockout; // do not allow drifting for this many tics + + boolean acceldown, brakedown, driftdown, itemdown; // buttons + boolean dolookback; // look out behind you + boolean itemwasdown; // last tic's item button + SINT8 itemthrow; // throwdir + INT16 turnamt; // turning }; // AVAILABLE FOR LUA +void K_BotTicker(player_t *player); + +void K_DrawBotDebugger(const player_t *player); /*-------------------------------------------------- boolean K_PlayerUsesBotMovement(const player_t *player); @@ -278,21 +323,8 @@ UINT8 K_EggboxStealth(fixed_t x, fixed_t y); boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t y); - -/*-------------------------------------------------- - void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player); - - Moves the bot's prediction, based on objects around the bot. - - Input Arguments:- - predict - The bot's prediction to nudge. - player - Player to compare. - - Return:- - None ---------------------------------------------------*/ - -void K_NudgePredictionTowardsObjects(botprediction_t *predict, const player_t *player); +// Moves the bot's prediction, based on objects around the bot. +void K_NudgePredictionTowardsObjects(botdata_t *bd, const player_t *player); /*-------------------------------------------------- @@ -359,22 +391,12 @@ void K_UpdateBotGameplayVarsItemUsage(player_t *player); void K_UpdateBotGameplayVars(player_t *player); +// Item usage part of ticcmd generation. +void K_BotItemUsage(botdata_t *bd, player_t *player); -/*-------------------------------------------------- - void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt); +void K_BotRespawn(player_t *player); - Item usage part of ticcmd generation. - - Input Arguments:- - player - Player to generate the ticcmd for. - cmd - The player's ticcmd to modify. - turnamt - How hard the bot is turning. - - Return:- - None ---------------------------------------------------*/ - -void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt); +void K_BotResetItemConfirm(player_t *player, boolean setdelay); /*-------------------------------------------------- fixed_t K_BotDetermineDriftSkill(player_t *player) @@ -405,7 +427,7 @@ fixed_t K_BotDetermineDriftSkill(player_t *player); None --------------------------------------------------*/ -void K_BotSetDriftState(player_t *player, botdrift_t newstate, tic_t lockout); +void K_BotSetDriftState(player_t *player, botdrift_e newstate, tic_t lockout); #ifdef __cplusplus diff --git a/src/k_botitem.cpp b/src/k_botitem.cpp index d4529bcc7..a4cc8854d 100644 --- a/src/k_botitem.cpp +++ b/src/k_botitem.cpp @@ -24,52 +24,22 @@ #include "byteptr.h" #include "d_net.h" // nodetoplayer #include "k_kart.h" -#include "z_zone.h" #include "i_system.h" #include "p_maputl.h" -#include "d_ticcmd.h" #include "m_random.h" #include "r_things.h" // numskins #include "m_easing.h" -/*-------------------------------------------------- - static inline boolean K_ItemButtonWasDown(const player_t *player) - - Looks for players around the bot, and presses the item button - if there is one in range. - - Input Arguments:- - player - Bot to check. - - Return:- - true if the item button was pressed last tic, otherwise false. ---------------------------------------------------*/ -static inline boolean K_ItemButtonWasDown(const player_t *player) -{ - return (player->oldcmd.buttons & BT_ATTACK); -} - -/*-------------------------------------------------- - static boolean K_BotUseItemNearPlayer(const player_t *player, ticcmd_t *cmd, fixed_t radius) - - Looks for players around the bot, and presses the item button - if there is one in range. - - Input Arguments:- - player - Bot to compare against. - cmd - The bot's ticcmd. - radius - The radius to look for players in. - - Return:- - true if a player was found & we can press the item button, otherwise false. ---------------------------------------------------*/ -static boolean K_BotUseItemNearPlayer(const player_t *player, ticcmd_t *cmd, fixed_t radius) +// Looks for players around the bot, and presses the item button +// if there is one in range. +// Returns true if a player was found & we can press the item button, otherwise false. +static boolean K_BotUseItemNearPlayer(botdata_t *bd, const player_t *player, fixed_t radius) { ZoneScoped; UINT8 i; - if (K_ItemButtonWasDown(player) == true) + if (bd->itemwasdown) { return false; } @@ -101,7 +71,7 @@ static boolean K_BotUseItemNearPlayer(const player_t *player, ticcmd_t *cmd, fix if (dist <= radius) { - cmd->buttons |= BT_ATTACK; + bd->itemdown = true; return true; } } @@ -311,21 +281,10 @@ static boolean K_RivalBotAggression(const player_t *bot, const player_t *target) return false; } -/*-------------------------------------------------- - static void K_ItemConfirmForTarget(const player_t *bot, ticcmd_t *cmd, const player_t *target, UINT16 amount) - - Handles updating item confirm values for offense items. - - Input Arguments:- - bot - Bot to check. - cmd - Bot's ticcmd to edit. - target - Who the bot wants to attack. - amount - Amount to increase item confirm time by. - - Return:- - None ---------------------------------------------------*/ -static void K_ItemConfirmForTarget(const player_t *bot, ticcmd_t *cmd, const player_t *target, UINT16 amount) +// Handles updating item confirm values for offense items. +// target - Who the bot wants to attack. +// amount - Amount to increase item confirm time by. +static void K_ItemConfirmForTarget(botdata_t *bd, const player_t *bot, const player_t *target, UINT16 amount) { if (bot == NULL || target == NULL) { @@ -335,86 +294,55 @@ static void K_ItemConfirmForTarget(const player_t *bot, ticcmd_t *cmd, const pla if (K_RivalBotAggression(bot, target) == true) { // Double the rate when you're aggressive. - cmd->bot.itemconfirm += amount << 1; + bd->itemconfirm += amount << 1; } else { // Do as normal. - cmd->bot.itemconfirm += amount; + bd->itemconfirm += amount; } } -/*-------------------------------------------------- - static boolean K_BotGenericPressItem(const player_t *player, ticcmd_t *cmd, SINT8 dir) - Presses the item button & aim buttons for the bot. - - Input Arguments:- - player - Bot to do this for. - cmd - Bot's ticcmd to edit. - dir - Aiming direction: 1 for forwards, -1 for backwards, 0 for neutral. - - Return:- - true if we could press, false if not. ---------------------------------------------------*/ -static boolean K_BotGenericPressItem(const player_t *player, ticcmd_t *cmd, SINT8 dir) +// Presses the item button & aim buttons for the bot. +// dir - Aiming direction: 1 for forwards, -1 for backwards, 0 for neutral. +// Returns true if we could press, false if not. +static boolean K_BotGenericPressItem(botdata_t *bd, SINT8 dir) { ZoneScoped; - if (K_ItemButtonWasDown(player) == true) + if (bd->itemwasdown) { return false; } - cmd->throwdir = KART_FULLTURN * dir; - cmd->buttons |= BT_ATTACK; - //player->botvars.itemconfirm = 0; + bd->itemthrow = dir; + bd->itemdown = true; + //bd->itemconfirm = 0; return true; } -/*-------------------------------------------------- - static void K_BotItemGenericTap(const player_t *player, ticcmd_t *cmd) - - Item usage for generic items that you need to tap. - - Input Arguments:- - player - Bot to do this for. - cmd - Bot's ticcmd to edit. - - Return:- - None ---------------------------------------------------*/ -static void K_BotItemGenericTap(const player_t *player, ticcmd_t *cmd) +// Item usage for generic items that you need to tap. +static void K_BotItemGenericTap(botdata_t *bd) { ZoneScoped; - if (K_ItemButtonWasDown(player) == false) + if (!bd->itemwasdown) { - cmd->buttons |= BT_ATTACK; - //player->botvars.itemconfirm = 0; + bd->itemdown = true; + //bd->itemconfirm = 0; } } -/*-------------------------------------------------- - static boolean K_BotRevealsGenericTrap(const player_t *player, INT16 turnamt, boolean mine) - - Decides if a bot is ready to reveal their trap item or not. - - Input Arguments:- - player - Bot that has the banana. - turnamt - How hard they currently are turning. - mine - Set to true to handle Mine-specific behaviors. - - Return:- - true if we want the bot to reveal their banana, otherwise false. ---------------------------------------------------*/ -static boolean K_BotRevealsGenericTrap(const player_t *player, INT16 turnamt, boolean mine) +// Decides if a bot is ready to reveal their trap item or not. +// mine - Set to true to handle Mine-specific behaviors. +static boolean K_BotRevealsGenericTrap(botdata_t *bd, const player_t *player, boolean mine) { ZoneScoped; const fixed_t coneDist = FixedMul(1280 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed)); - if (abs(turnamt) >= KART_FULLTURN/2) + if (abs(bd->turnamt) >= KART_FULLTURN/2) { // DON'T reveal on turns, we can place bananas on turns whenever we have multiple to spare, // or if you missed your intentioned throw/place on a player. @@ -444,21 +372,9 @@ static boolean K_BotRevealsGenericTrap(const player_t *player, INT16 turnamt, bo return false; } -/*-------------------------------------------------- - static void K_BotItemGenericTrapShield(const player_t *player, ticcmd_t *cmd, INT16 turnamt, boolean mine) - - Item usage for Eggman shields. - - Input Arguments:- - player - Bot to do this for. - cmd - Bot's ticcmd to edit. - turnamt - How hard they currently are turning. - mine - Set to true to handle Mine-specific behaviors. - - Return:- - None ---------------------------------------------------*/ -static void K_BotItemGenericTrapShield(const player_t *player, ticcmd_t *cmd, INT16 turnamt, boolean mine) +// Item usage for Eggman shields. +// mine - Set to true to handle Mine-specific behaviors. +static void K_BotItemGenericTrapShield(botdata_t *bd, player_t *player, boolean mine) { ZoneScoped; @@ -467,27 +383,16 @@ static void K_BotItemGenericTrapShield(const player_t *player, ticcmd_t *cmd, IN return; } - cmd->bot.itemconfirm++; + bd->itemconfirm++; - if (K_BotRevealsGenericTrap(player, turnamt, mine) || (player->botvars.itemconfirm > 5*TICRATE)) + if (K_BotRevealsGenericTrap(bd, player, mine) || (bd->itemconfirm > 5*TICRATE)) { - K_BotGenericPressItem(player, cmd, 0); + K_BotGenericPressItem(bd, 0); } } -/*-------------------------------------------------- - static void K_BotItemGenericOrbitShield(const player_t *player, ticcmd_t *cmd) - - Item usage for orbitting shields. - - Input Arguments:- - player - Bot to do this for. - cmd - Bot's ticcmd to edit. - - Return:- - None ---------------------------------------------------*/ -static void K_BotItemGenericOrbitShield(const player_t *player, ticcmd_t *cmd) +// Item usage for orbitting shields. +static void K_BotItemGenericOrbitShield(botdata_t *bd, player_t *player) { ZoneScoped; @@ -496,22 +401,11 @@ static void K_BotItemGenericOrbitShield(const player_t *player, ticcmd_t *cmd) return; } - K_BotGenericPressItem(player, cmd, 0); + K_BotGenericPressItem(bd, 0); } -/*-------------------------------------------------- - static void K_BotItemSneaker(const player_t *player, ticcmd_t *cmd) - - Item usage for sneakers. - - Input Arguments:- - player - Bot to do this for. - cmd - Bot's ticcmd to edit. - - Return:- - None ---------------------------------------------------*/ -static void K_BotItemSneaker(player_t *player, ticcmd_t *cmd) +// Item usage for sneakers. +static void K_BotItemSneaker(botdata_t *bd, player_t *player) { ZoneScoped; @@ -525,33 +419,22 @@ static void K_BotItemSneaker(player_t *player, ticcmd_t *cmd) || K_GetWaypointIsShortcut(player->nextwaypoint) == true // Going toward a shortcut! || player->speed < K_GetKartSpeed(player, false, true) / 2 // Being slowed down too much || player->speedboost > (FRACUNIT/8) // Have another type of boost (tethering) - || player->botvars.itemconfirm > 4*TICRATE) // Held onto it for too long + || bd->itemconfirm > 4*TICRATE) // Held onto it for too long { - if (player->sneakertimer == 0 && K_ItemButtonWasDown(player) == false) + if (player->sneakertimer == 0 && !bd->itemwasdown) { - cmd->buttons |= BT_ATTACK; - //player->botvars.itemconfirm = 2*TICRATE; + bd->itemdown = true; + //bd->itemconfirm = 2*TICRATE; } } else { - cmd->bot.itemconfirm++; + bd->itemconfirm++; } } -/*-------------------------------------------------- - static void K_BotItemRocketSneaker(player_t *player, ticcmd_t *cmd) - - Item usage for rocket sneakers. - - Input Arguments:- - player - Bot to do this for. - cmd - Bot's ticcmd to edit. - - Return:- - None ---------------------------------------------------*/ -static void K_BotItemRocketSneaker(const player_t *player, ticcmd_t *cmd) +// Item usage for rocket sneakers. +static void K_BotItemRocketSneaker(botdata_t *bd, player_t *player) { ZoneScoped; @@ -561,34 +444,22 @@ static void K_BotItemRocketSneaker(const player_t *player, ticcmd_t *cmd) return; } - if (player->botvars.itemconfirm > TICRATE) + if (bd->itemconfirm > TICRATE) { - if (player->sneakertimer == 0 && K_ItemButtonWasDown(player) == false) + if (player->sneakertimer == 0 && !bd->itemwasdown) { - cmd->buttons |= BT_ATTACK; - //player->botvars.itemconfirm = 0; + bd->itemdown = true; + //bd->itemconfirm = 0; } } else { - cmd->bot.itemconfirm++; + bd->itemconfirm++; } } -/*-------------------------------------------------- - static void K_BotItemBanana(player_t *player, ticcmd_t *cmd, INT16 turnamt) - - Item usage for trap item throwing. - - Input Arguments:- - player - Bot to do this for. - cmd - Bot's ticcmd to edit. - turnamt - How hard they currently are turning. - - Return:- - None ---------------------------------------------------*/ -static void K_BotItemBanana(const player_t *player, ticcmd_t *cmd, INT16 turnamt) +// Item usage for trap item throwing. +static void K_BotItemBanana(botdata_t *bd, player_t *player) { ZoneScoped; @@ -597,19 +468,19 @@ static void K_BotItemBanana(const player_t *player, ticcmd_t *cmd, INT16 turnamt boolean tryLookback = false; player_t *target = NULL; - cmd->bot.itemconfirm++; + bd->itemconfirm++; target = K_PlayerInCone(player, coneDist, 15, true); if (target != NULL) { - K_ItemConfirmForTarget(player, cmd, target, player->botvars.difficulty); + K_ItemConfirmForTarget(bd, player, target, player->botvars.difficulty); throwdir = -1; tryLookback = true; } - if (abs(turnamt) >= KART_FULLTURN/2) + if (abs(bd->turnamt) >= KART_FULLTURN/2) { - cmd->bot.itemconfirm += player->botvars.difficulty / 2; + bd->itemconfirm += player->botvars.difficulty / 2; throwdir = -1; } else @@ -618,36 +489,24 @@ static void K_BotItemBanana(const player_t *player, ticcmd_t *cmd, INT16 turnamt if (target != NULL) { - K_ItemConfirmForTarget(player, cmd, target, player->botvars.difficulty * 2); + K_ItemConfirmForTarget(bd, player, target, player->botvars.difficulty * 2); throwdir = 1; } } if (tryLookback == true && throwdir == -1) { - cmd->buttons |= BT_LOOKBACK; + bd->dolookback = true; } - if (player->botvars.itemconfirm > 10*TICRATE || player->bananadrag >= TICRATE) + if (bd->itemconfirm > 10*TICRATE || player->bananadrag >= TICRATE) { - K_BotGenericPressItem(player, cmd, throwdir); + K_BotGenericPressItem(bd, throwdir); } } -/*-------------------------------------------------- - static void K_BotItemMine(player_t *player, ticcmd_t *cmd, INT16 turnamt) - - Item usage for trap item throwing. - - Input Arguments:- - player - Bot to do this for. - cmd - Bot's ticcmd to edit. - turnamt - How hard they currently are turning. - - Return:- - None ---------------------------------------------------*/ -static void K_BotItemMine(const player_t *player, ticcmd_t *cmd, INT16 turnamt) +// Item usage for trap item throwing. +static void K_BotItemMine(botdata_t *bd, player_t *player) { ZoneScoped; @@ -656,18 +515,18 @@ static void K_BotItemMine(const player_t *player, ticcmd_t *cmd, INT16 turnamt) boolean tryLookback = false; player_t *target = NULL; - cmd->bot.itemconfirm++; + bd->itemconfirm++; target = K_PlayerInCone(player, coneDist, 15, true); if (target != NULL) { - K_ItemConfirmForTarget(player, cmd, target, player->botvars.difficulty); + K_ItemConfirmForTarget(bd, player, target, player->botvars.difficulty); throwdir = -1; } - if (abs(turnamt) >= KART_FULLTURN/2) + if (abs(bd->turnamt) >= KART_FULLTURN/2) { - cmd->bot.itemconfirm += player->botvars.difficulty / 2; + bd->itemconfirm += player->botvars.difficulty / 2; throwdir = -1; tryLookback = true; } @@ -676,82 +535,59 @@ static void K_BotItemMine(const player_t *player, ticcmd_t *cmd, INT16 turnamt) target = K_PlayerPredictThrow(player, 0); if (target != NULL) { - K_ItemConfirmForTarget(player, cmd, target, player->botvars.difficulty * 2); + K_ItemConfirmForTarget(bd, player, target, player->botvars.difficulty * 2); throwdir = 0; } target = K_PlayerPredictThrow(player, 1); if (target != NULL) { - K_ItemConfirmForTarget(player, cmd, target, player->botvars.difficulty * 2); + K_ItemConfirmForTarget(bd, player, target, player->botvars.difficulty * 2); throwdir = 1; } } if (tryLookback == true && throwdir == -1) { - cmd->buttons |= BT_LOOKBACK; + bd->dolookback = true; } - if (player->botvars.itemconfirm > 10*TICRATE || player->bananadrag >= TICRATE) + if (bd->itemconfirm > 10*TICRATE || player->bananadrag >= TICRATE) { - K_BotGenericPressItem(player, cmd, throwdir); + K_BotGenericPressItem(bd, throwdir); } } -/*-------------------------------------------------- - static void K_BotItemLandmine(player_t *player, ticcmd_t *cmd, INT16 turnamt) - - Item usage for landmine tossing. - - Input Arguments:- - player - Bot to do this for. - cmd - Bot's ticcmd to edit. - turnamt - How hard they currently are turning. - - Return:- - None ---------------------------------------------------*/ -static void K_BotItemLandmine(const player_t *player, ticcmd_t *cmd, INT16 turnamt) +// Item usage for landmine tossing. +static void K_BotItemLandmine(botdata_t *bd, player_t *player) { ZoneScoped; const fixed_t coneDist = FixedMul(1280 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed)); player_t *target = NULL; - cmd->bot.itemconfirm++; + bd->itemconfirm++; - if (abs(turnamt) >= KART_FULLTURN/2) + if (abs(bd->turnamt) >= KART_FULLTURN/2) { - cmd->bot.itemconfirm += player->botvars.difficulty / 2; + bd->itemconfirm += player->botvars.difficulty / 2; } target = K_PlayerInCone(player, coneDist, 15, true); if (target != NULL) { - K_ItemConfirmForTarget(player, cmd, target, player->botvars.difficulty); - cmd->buttons |= BT_LOOKBACK; + K_ItemConfirmForTarget(bd, player, target, player->botvars.difficulty); + bd->dolookback = true; } - if (player->botvars.itemconfirm > 10*TICRATE) + if (bd->itemconfirm > 10*TICRATE) { - K_BotGenericPressItem(player, cmd, -1); + K_BotGenericPressItem(bd, -1); } } -/*-------------------------------------------------- - static void K_BotItemEggman(player_t *player, ticcmd_t *cmd) - - Item usage for Eggman item throwing. - - Input Arguments:- - player - Bot to do this for. - cmd - Bot's ticcmd to edit. - - Return:- - None ---------------------------------------------------*/ -static void K_BotItemEggman(const player_t *player, ticcmd_t *cmd) +// Item usage for Eggman item throwing. +static void K_BotItemEggman(botdata_t *bd, player_t *player) { ZoneScoped; @@ -761,37 +597,37 @@ static void K_BotItemEggman(const player_t *player, ticcmd_t *cmd) boolean tryLookback = false; player_t *target = NULL; - cmd->bot.itemconfirm++; + bd->itemconfirm++; target = K_PlayerPredictThrow(player, 0); if (target != NULL) { - K_ItemConfirmForTarget(player, cmd, target, player->botvars.difficulty / 2); + K_ItemConfirmForTarget(bd, player, target, player->botvars.difficulty / 2); throwdir = 1; } target = K_PlayerInCone(player, coneDist, 15, true); if (target != NULL) { - K_ItemConfirmForTarget(player, cmd, target, player->botvars.difficulty); + K_ItemConfirmForTarget(bd, player, target, player->botvars.difficulty); throwdir = -1; tryLookback = true; } if (stealth > 1 || player->itemroulette) { - cmd->bot.itemconfirm += player->botvars.difficulty * 4; + bd->itemconfirm += player->botvars.difficulty * 4; throwdir = -1; } if (tryLookback == true && throwdir == -1) { - cmd->buttons |= BT_LOOKBACK; + bd->dolookback = true; } - if (player->botvars.itemconfirm > 10*TICRATE || player->bananadrag >= TICRATE) + if (bd->itemconfirm > 10*TICRATE || player->bananadrag >= TICRATE) { - K_BotGenericPressItem(player, cmd, throwdir); + K_BotGenericPressItem(bd, throwdir); } } @@ -837,19 +673,8 @@ static boolean K_BotRevealsEggbox(const player_t *player) return false; } -/*-------------------------------------------------- - static void K_BotItemEggmanShield(const player_t *player, ticcmd_t *cmd) - - Item usage for Eggman shields. - - Input Arguments:- - player - Bot to do this for. - cmd - Bot's ticcmd to edit. - - Return:- - None ---------------------------------------------------*/ -static void K_BotItemEggmanShield(const player_t *player, ticcmd_t *cmd) +// Item usage for Eggman shields. +static void K_BotItemEggmanShield(botdata_t *bd, player_t *player) { ZoneScoped; @@ -858,53 +683,31 @@ static void K_BotItemEggmanShield(const player_t *player, ticcmd_t *cmd) return; } - cmd->bot.itemconfirm++; + bd->itemconfirm++; - if (K_BotRevealsEggbox(player) == true || (player->botvars.itemconfirm > 20*TICRATE)) + if (K_BotRevealsEggbox(player) == true || (bd->itemconfirm > 20*TICRATE)) { - K_BotGenericPressItem(player, cmd, 0); + K_BotGenericPressItem(bd, 0); } } -/*-------------------------------------------------- - static void K_BotItemEggmanExplosion(const player_t *player, ticcmd_t *cmd) - - Item usage for Eggman explosions. - - Input Arguments:- - player - Bot to do this for. - cmd - Bot's ticcmd to edit. - - Return:- - None ---------------------------------------------------*/ -static void K_BotItemEggmanExplosion(const player_t *player, ticcmd_t *cmd) +// Item usage for Eggman explosions. +static void K_BotItemEggmanExplosion(botdata_t *bd, player_t *player) { ZoneScoped; - if (player->position == 1) + if (player->position == 1 && bd->acceldown) { // Hey, we aren't gonna find anyone up here... // why don't we slow down a bit? :) - cmd->forwardmove /= 2; + bd->brakedown = true; } - K_BotUseItemNearPlayer(player, cmd, 128*player->mo->scale); + K_BotUseItemNearPlayer(bd, player, 128*player->mo->scale); } -/*-------------------------------------------------- - static void K_BotItemOrbinaut(const player_t *player, ticcmd_t *cmd) - - Item usage for Orbinaut throwing. - - Input Arguments:- - player - Bot to do this for. - cmd - Bot's ticcmd to edit. - - Return:- - None ---------------------------------------------------*/ -static void K_BotItemOrbinaut(player_t *player, ticcmd_t *cmd) +// Item usage for Orbinaut throwing. +static void K_BotItemOrbinaut(botdata_t *bd, player_t *player) { ZoneScoped; @@ -921,12 +724,12 @@ static void K_BotItemOrbinaut(player_t *player, ticcmd_t *cmd) snipeMul = 3; // Confirm faster when you'll throw it with a bunch of extra speed!! } - cmd->bot.itemconfirm++; + bd->itemconfirm++; target = K_PlayerInCone(player, radius, 15, false); if (target != NULL) { - K_ItemConfirmForTarget(player, cmd, target, player->botvars.difficulty * snipeMul); + K_ItemConfirmForTarget(bd, player, target, player->botvars.difficulty * snipeMul); throwdir = 1; } else @@ -935,7 +738,7 @@ static void K_BotItemOrbinaut(player_t *player, ticcmd_t *cmd) if (target != NULL) { - K_ItemConfirmForTarget(player, cmd, target, player->botvars.difficulty); + K_ItemConfirmForTarget(bd, player, target, player->botvars.difficulty); throwdir = -1; tryLookback = true; } @@ -943,28 +746,17 @@ static void K_BotItemOrbinaut(player_t *player, ticcmd_t *cmd) if (tryLookback == true && throwdir == -1) { - cmd->buttons |= BT_LOOKBACK; + bd->dolookback = true; } - if (player->botvars.itemconfirm > 25*TICRATE) + if (bd->itemconfirm > 25*TICRATE) { - K_BotGenericPressItem(player, cmd, throwdir); + K_BotGenericPressItem(bd, throwdir); } } -/*-------------------------------------------------- - static void K_BotItemBallhog(const player_t *player, ticcmd_t *cmd) - - Item usage for Ballhog throwing. - - Input Arguments:- - player - Bot to do this for. - cmd - Bot's ticcmd to edit. - - Return:- - None ---------------------------------------------------*/ -static void K_BotItemBallhog(player_t *player, ticcmd_t *cmd) +// Item usage for Ballhog throwing. +static void K_BotItemBallhog(botdata_t *bd, player_t *player) { ZoneScoped; @@ -985,7 +777,7 @@ static void K_BotItemBallhog(player_t *player, ticcmd_t *cmd) target = K_PlayerInCone(player, radius, 15, false); if (target != NULL) { - K_ItemConfirmForTarget(player, cmd, target, player->botvars.difficulty * snipeMul); + K_ItemConfirmForTarget(bd, player, target, player->botvars.difficulty * snipeMul); throwdir = 1; } else @@ -994,7 +786,7 @@ static void K_BotItemBallhog(player_t *player, ticcmd_t *cmd) if (target != NULL) { - K_ItemConfirmForTarget(player, cmd, target, player->botvars.difficulty); + K_ItemConfirmForTarget(bd, player, target, player->botvars.difficulty); throwdir = -1; tryLookback = true; } @@ -1002,7 +794,7 @@ static void K_BotItemBallhog(player_t *player, ticcmd_t *cmd) if (tryLookback == true && throwdir == -1) { - cmd->buttons |= BT_LOOKBACK; + bd->dolookback = true; } if (target != NULL) @@ -1017,30 +809,19 @@ static void K_BotItemBallhog(player_t *player, ticcmd_t *cmd) // If we've been waiting for too long though, then // we'll go for the full charge :) - cmd->bot.itemconfirm++; - hold = (player->botvars.itemconfirm > 10*TICRATE); + bd->itemconfirm++; + hold = (bd->itemconfirm > 10*TICRATE); } if (hold == true) { - cmd->throwdir = KART_FULLTURN * throwdir; - cmd->buttons |= BT_ATTACK; + bd->itemthrow = throwdir; + bd->itemdown = true; } } -/*-------------------------------------------------- - static void K_BotItemJawz(const player_t *player, ticcmd_t *cmd) - - Item usage for Jawz throwing. - - Input Arguments:- - player - Bot to do this for. - cmd - Bot's ticcmd to edit. - - Return:- - None ---------------------------------------------------*/ -static void K_BotItemJawz(player_t *player, ticcmd_t *cmd) +// Item usage for Jawz throwing. +static void K_BotItemJawz(botdata_t *bd, player_t *player) { ZoneScoped; @@ -1058,12 +839,12 @@ static void K_BotItemJawz(player_t *player, ticcmd_t *cmd) snipeMul = 3; // Confirm faster when you'll throw it with a bunch of extra speed!! } - cmd->bot.itemconfirm++; + bd->itemconfirm++; target = K_PlayerInCone(player, radius, 15, true); if (target != NULL) { - K_ItemConfirmForTarget(player, cmd, target, player->botvars.difficulty); + K_ItemConfirmForTarget(bd, player, target, player->botvars.difficulty); throwdir = -1; tryLookback = true; } @@ -1094,67 +875,45 @@ static void K_BotItemJawz(player_t *player, ticcmd_t *cmd) if (targettedAlready == false) { - K_ItemConfirmForTarget(player, cmd, target, player->botvars.difficulty * snipeMul); + K_ItemConfirmForTarget(bd, player, target, player->botvars.difficulty * snipeMul); throwdir = 1; } } if (tryLookback == true && throwdir == -1) { - cmd->buttons |= BT_LOOKBACK; + bd->dolookback = true; } - if (player->botvars.itemconfirm > 25*TICRATE) + if (bd->itemconfirm > 25*TICRATE) { - K_BotGenericPressItem(player, cmd, throwdir); + K_BotGenericPressItem(bd, throwdir); } } -/*-------------------------------------------------- - static void K_BotItemLightning(const player_t *player, ticcmd_t *cmd) - - Item usage for Lightning Shield. - - Input Arguments:- - player - Bot to do this for. - cmd - Bot's ticcmd to edit. - - Return:- - None ---------------------------------------------------*/ -static void K_BotItemLightning(const player_t *player, ticcmd_t *cmd) +// Item usage for Lightning Shield. +static void K_BotItemLightning(botdata_t *bd, player_t *player) { ZoneScoped; fixed_t radius = 192 * player->mo->scale; radius = Easing_Linear(FRACUNIT * player->botvars.difficulty / MAXBOTDIFFICULTY, 2*radius, radius); - if (K_BotUseItemNearPlayer(player, cmd, radius) == false) + if (K_BotUseItemNearPlayer(bd, player, radius) == false) { - if (player->botvars.itemconfirm > 10*TICRATE) + if (bd->itemconfirm > 10*TICRATE) { - K_BotGenericPressItem(player, cmd, 0); + K_BotGenericPressItem(bd, 0); } else { - cmd->bot.itemconfirm++; + bd->itemconfirm++; } } } -/*-------------------------------------------------- - static void K_BotItemBubble(const player_t *player, ticcmd_t *cmd) - - Item usage for Bubble Shield. - - Input Arguments:- - player - Bot to do this for. - cmd - Bot's ticcmd to edit. - - Return:- - None ---------------------------------------------------*/ -static void K_BotItemBubble(const player_t *player, ticcmd_t *cmd) +// Item usage for Bubble Shield. +static void K_BotItemBubble(botdata_t *bd, player_t *player) { ZoneScoped; @@ -1164,7 +923,7 @@ static void K_BotItemBubble(const player_t *player, ticcmd_t *cmd) { UINT8 i; - cmd->bot.itemconfirm++; + bd->itemconfirm++; if (player->bubblecool <= 0) { @@ -1206,7 +965,7 @@ static void K_BotItemBubble(const player_t *player, ticcmd_t *cmd) } else if (player->bubbleblowup >= bubbletime) { - if (player->botvars.itemconfirm > 10*TICRATE) + if (bd->itemconfirm > 10*TICRATE) { hold = true; } @@ -1218,23 +977,12 @@ static void K_BotItemBubble(const player_t *player, ticcmd_t *cmd) if (hold && (player->itemflags & IF_HOLDREADY)) { - cmd->buttons |= BT_ATTACK; + bd->itemdown = true; } } -/*-------------------------------------------------- - static void K_BotItemFlame(const player_t *player, ticcmd_t *cmd) - - Item usage for Flame Shield. - - Input Arguments:- - player - Bot to do this for. - cmd - Bot's ticcmd to edit. - - Return:- - None ---------------------------------------------------*/ -static void K_BotItemFlame(const player_t *player, ticcmd_t *cmd) +// Item usage for Flame Shield. +static void K_BotItemFlame(botdata_t *bd, player_t *player) { ZoneScoped; @@ -1244,24 +992,24 @@ static void K_BotItemFlame(const player_t *player, ticcmd_t *cmd) return; } - if (player->botvars.itemconfirm > TICRATE) + if (bd->itemconfirm > TICRATE) { if (player->botvars.difficulty >= 6 && player->flametimer <= 2*TICRATE) { - cmd->buttons |= BT_ATTACK; - cmd->bot.itemconfirm = 0; + bd->itemdown = true; + bd->itemconfirm = 0; } else if (player->flametimer > 0) { if (player->botvars.difficulty < 6 || player->flamestore < FLAMESTOREMAX - TICRATE/4) { - cmd->buttons |= BT_ATTACK; - cmd->bot.itemconfirm = 0; + bd->itemdown = true; + bd->itemconfirm = 0; } else { UINT8 difficultyadjust = MAXBOTDIFFICULTY - player->botvars.difficulty; - cmd->bot.itemconfirm = (-TICRATE/2) - difficultyadjust; + bd->itemconfirm = (-TICRATE/2) - difficultyadjust; } } } @@ -1269,26 +1017,15 @@ static void K_BotItemFlame(const player_t *player, ticcmd_t *cmd) { if (player->botvars.difficulty >= 6 && player->flametimer <= 2*TICRATE) { - cmd->bot.itemconfirm = 0; + bd->itemconfirm = 0; } - cmd->bot.itemconfirm++; + bd->itemconfirm++; } } -/*-------------------------------------------------- - static void K_BotItemRings(const player_t *player, ticcmd_t *cmd) - - Item usage for rings. - - Input Arguments:- - player - Bot to do this for. - cmd - Bot's ticcmd to edit. - - Return:- - None ---------------------------------------------------*/ -static void K_BotItemRings(player_t *player, ticcmd_t *cmd) +// Item usage for rings. +static void K_BotItemRings(botdata_t *bd, player_t *player) { ZoneScoped; @@ -1300,7 +1037,7 @@ static void K_BotItemRings(player_t *player, ticcmd_t *cmd) return; } - if ((cmd->buttons & BT_ACCELERATE) == 0) + if (!bd->acceldown) { // Don't use rings if you're not trying to accelerate. return; @@ -1335,7 +1072,7 @@ static void K_BotItemRings(player_t *player, ticcmd_t *cmd) if (player->rings > saferingsval) { - cmd->buttons |= BT_ATTACK; + bd->itemdown = true; } } @@ -1396,24 +1133,13 @@ static UINT32 K_BotCalculateUseodds(player_t *player) return K_FindUseodds(player, 0, pdis, bestbumper, spbrush); } -/*-------------------------------------------------- - static void K_BotItemRouletteMash(const player_t *player, ticcmd_t *cmd) - - Item usage for item roulette mashing. - - Input Arguments:- - player - Bot to do this for. - cmd - Bot's ticcmd to edit. - - Return:- - None ---------------------------------------------------*/ -static void K_BotItemRouletteMash(player_t *player, ticcmd_t *cmd) +// Item usage for item roulette mashing. +static void K_BotItemRouletteMash(botdata_t *bd, player_t *player) { boolean mash = false; UINT32 useodds = 0; - if (K_ItemButtonWasDown(player) == true) + if (bd->itemwasdown) { return; } @@ -1455,16 +1181,12 @@ static void K_BotItemRouletteMash(player_t *player, ticcmd_t *cmd) if (mash == true) { - cmd->buttons |= BT_ATTACK; + bd->itemdown = true; } } -/*-------------------------------------------------- - void K_BotItemUsage(const player_t *player, ticcmd_t *cmd, INT16 turnamt) - - See header file for description. ---------------------------------------------------*/ -void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt) +// See header file for description. +void K_BotItemUsage(botdata_t *bd, player_t *player) { ZoneScoped; @@ -1473,142 +1195,139 @@ void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt) if (player->rings > 0) { // Use rings! - K_BotItemRings(player, cmd); + K_BotItemRings(bd, player); } + return; + } + + if (bd->itemdelay) + { + bd->itemdelay--; + bd->itemconfirm = 0; + return; + } + + if (player->itemroulette) + { + // Mashing behaviors + K_BotItemRouletteMash(bd, player); + return; + } + + if (player->stealingtimer != 0) + return; + + if (player->eggmanexplode) + { + K_BotItemEggmanExplosion(bd, player); + } + else if (player->itemflags & IF_EGGMANOUT) + { + K_BotItemEggman(bd, player); + } + else if (player->rocketsneakertimer > 0) + { + K_BotItemRocketSneaker(bd, player); + } + else if (player->flametimer > 0) + { + K_BotItemFlame(bd, player); } else { - if (player->botvars.itemdelay) + switch (player->itemtype) { - return; - } + default: + if (player->itemtype != KITEM_NONE) + { + K_BotItemGenericTap(bd); + } - if (player->itemroulette) - { - // Mashing behaviors - K_BotItemRouletteMash(player, cmd); - return; - } - - if (player->stealingtimer == 0) - { - if (player->eggmanexplode) + //bd->itemconfirm = 0; + break; + case KITEM_INVINCIBILITY: + case KITEM_SPB: + case KITEM_GROW: + case KITEM_SHRINK: + case KITEM_SUPERRING: + K_BotItemGenericTap(bd); + break; + case KITEM_ROCKETSNEAKER: + if (player->rocketsneakertimer <= 0) { - K_BotItemEggmanExplosion(player, cmd); + K_BotItemGenericTap(bd); } - else if (player->itemflags & IF_EGGMANOUT) + break; + case KITEM_FLAMESHIELD: + if (player->flametimer <= 0) { - K_BotItemEggman(player, cmd); + K_BotItemGenericTap(bd); } - else if (player->rocketsneakertimer > 0) + break; + case KITEM_SNEAKER: + K_BotItemSneaker(bd, player); + break; + case KITEM_BANANA: + if (!(player->itemflags & IF_ITEMOUT)) { - K_BotItemRocketSneaker(player, cmd); - } - else if (player->flametimer > 0) - { - K_BotItemFlame(player, cmd); + K_BotItemGenericTrapShield(bd, player, false); } else { - switch (player->itemtype) - { - default: - if (player->itemtype != KITEM_NONE) - { - K_BotItemGenericTap(player, cmd); - } - - //player->botvars.itemconfirm = 0; - break; - case KITEM_INVINCIBILITY: - case KITEM_SPB: - case KITEM_GROW: - case KITEM_SHRINK: - case KITEM_SUPERRING: - K_BotItemGenericTap(player, cmd); - break; - case KITEM_ROCKETSNEAKER: - if (player->rocketsneakertimer <= 0) - { - K_BotItemGenericTap(player, cmd); - } - break; - case KITEM_FLAMESHIELD: - if (player->flametimer <= 0) - { - K_BotItemGenericTap(player, cmd); - } - break; - case KITEM_SNEAKER: - K_BotItemSneaker(player, cmd); - break; - case KITEM_BANANA: - if (!(player->itemflags & IF_ITEMOUT)) - { - K_BotItemGenericTrapShield(player, cmd, turnamt, false); - } - else - { - K_BotItemBanana(player, cmd, turnamt); - } - break; - case KITEM_EGGMAN: - K_BotItemEggmanShield(player, cmd); - break; - case KITEM_ORBINAUT: - if (!(player->itemflags & IF_ITEMOUT)) - { - K_BotItemGenericOrbitShield(player, cmd); - } - else if (player->position != 1) // Hold onto orbiting items when in 1st :) - { - K_BotItemOrbinaut(player, cmd); - } - break; - case KITEM_JAWZ: - if (!(player->itemflags & IF_ITEMOUT)) - { - K_BotItemGenericOrbitShield(player, cmd); - } - else if (player->position != 1) // Hold onto orbiting items when in 1st :) - { - K_BotItemJawz(player, cmd); - } - break; - case KITEM_MINE: - if (!(player->itemflags & IF_ITEMOUT)) - { - K_BotItemGenericTrapShield(player, cmd, turnamt, true); - } - else - { - K_BotItemMine(player, cmd, turnamt); - } - break; - case KITEM_LANDMINE: - case KITEM_HYUDORO: // Function re-use, as they have about the same usage. - K_BotItemLandmine(player, cmd, turnamt); - break; - case KITEM_BALLHOG: - K_BotItemBallhog(player, cmd); - break; - case KITEM_THUNDERSHIELD: - K_BotItemLightning(player, cmd); - break; - case KITEM_BUBBLESHIELD: - K_BotItemBubble(player, cmd); - break; - } + K_BotItemBanana(bd, player); } + break; + case KITEM_EGGMAN: + K_BotItemEggmanShield(bd, player); + break; + case KITEM_ORBINAUT: + if (!(player->itemflags & IF_ITEMOUT)) + { + K_BotItemGenericOrbitShield(bd, player); + } + else if (player->position != 1) // Hold onto orbiting items when in 1st :) + { + K_BotItemOrbinaut(bd, player); + } + break; + case KITEM_JAWZ: + if (!(player->itemflags & IF_ITEMOUT)) + { + K_BotItemGenericOrbitShield(bd, player); + } + else if (player->position != 1) // Hold onto orbiting items when in 1st :) + { + K_BotItemJawz(bd, player); + } + break; + case KITEM_MINE: + if (!(player->itemflags & IF_ITEMOUT)) + { + K_BotItemGenericTrapShield(bd, player, true); + } + else + { + K_BotItemMine(bd, player); + } + break; + case KITEM_LANDMINE: + case KITEM_HYUDORO: // Function re-use, as they have about the same usage. + K_BotItemLandmine(bd, player); + break; + case KITEM_BALLHOG: + K_BotItemBallhog(bd, player); + break; + case KITEM_THUNDERSHIELD: + K_BotItemLightning(bd, player); + break; + case KITEM_BUBBLESHIELD: + K_BotItemBubble(bd, player); + break; } } } -/*-------------------------------------------------- - void K_UpdateBotGameplayVarsItemUsage(player_t *player) - - See header file for description. ---------------------------------------------------*/ +// See header file for description. void K_UpdateBotGameplayVarsItemUsage(player_t *player) { if (player->itemflags & IF_USERINGS) @@ -1616,22 +1335,6 @@ void K_UpdateBotGameplayVarsItemUsage(player_t *player) return; } - if (player->botvars.itemdelay) - { - player->botvars.itemdelay--; - player->botvars.itemconfirm = 0; - return; - } - - if (player->cmd.bot.itemconfirm < 0 && abs(player->cmd.bot.itemconfirm) > player->botvars.itemconfirm) - { - player->botvars.itemconfirm = 0; - } - else - { - player->botvars.itemconfirm += player->cmd.bot.itemconfirm; - } - if (player->itemflags & IF_USERINGS) { ; @@ -1641,7 +1344,6 @@ void K_UpdateBotGameplayVarsItemUsage(player_t *player) if (player->itemroulette) { // Mashing behaviors - K_BotItemRouletteMash(player, &player->cmd); return; } diff --git a/src/k_botsearch.cpp b/src/k_botsearch.cpp index 3aa10d022..a9f730f87 100644 --- a/src/k_botsearch.cpp +++ b/src/k_botsearch.cpp @@ -644,12 +644,8 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing) return BMIT_CONTINUE; } -/*-------------------------------------------------- - void K_NudgePredictionTowardsObjects(botprediction_t *predict, const player_t *player) - - See header file for description. ---------------------------------------------------*/ -void K_NudgePredictionTowardsObjects(botprediction_t *predict, const player_t *player) +// See header file for description. +void K_NudgePredictionTowardsObjects(botdata_t *bd, const player_t *player) { ZoneScoped; @@ -672,20 +668,14 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, const player_t *p SINT8 gotoSide = -1; UINT8 i; - if (predict == NULL) - { - ps_bots[player - players].nudge += I_GetPreciseTime() - time; - return; - } - - distToPredict = R_PointToDist2(player->mo->x, player->mo->y, predict->x, predict->y); - angleToPredict = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y); + distToPredict = R_PointToDist2(player->mo->x, player->mo->y, bd->predict.x, bd->predict.y); + angleToPredict = R_PointToAngle2(player->mo->x, player->mo->y, bd->predict.x, bd->predict.y); radToPredict = distToPredict >> 1; g_nudgeSearch.distancetocheck = FixedMul(radToPredict, radToPredict); - baseNudge = predict->baseRadius >> 3; - maxNudge = predict->baseRadius - baseNudge; + baseNudge = bd->predict.baseRadius >> 3; + maxNudge = bd->predict.baseRadius - baseNudge; g_nudgeSearch.botmo = player->mo; g_nudgeSearch.angle = angleToPredict; @@ -735,7 +725,7 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, const player_t *p avgDist = R_PointToDist2( avgX, avgY, - predict->x, predict->y + bd->predict.x, bd->predict.y ); // High handling characters dodge better @@ -748,14 +738,14 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, const player_t *p // Point away nudgeDir = R_PointToAngle2( avgX, avgY, - predict->x, predict->y + bd->predict.x, bd->predict.y ); - predict->x += FixedMul(nudgeDist, FINECOSINE(nudgeDir >> ANGLETOFINESHIFT)); - predict->y += FixedMul(nudgeDist, FINESINE(nudgeDir >> ANGLETOFINESHIFT)); - predict->radius = std::max(predict->radius - nudgeDist, baseNudge); + bd->predict.x += FixedMul(nudgeDist, FINECOSINE(nudgeDir >> ANGLETOFINESHIFT)); + bd->predict.y += FixedMul(nudgeDist, FINESINE(nudgeDir >> ANGLETOFINESHIFT)); + bd->predict.radius = std::max(bd->predict.radius - nudgeDist, baseNudge); - distToPredict = R_PointToDist2(player->mo->x, player->mo->y, predict->x, predict->y); + distToPredict = R_PointToDist2(player->mo->x, player->mo->y, bd->predict.x, bd->predict.y); // Flip side, since we want to check for objects to steer towards on the side we're NOT dodging. if (gotoSide == 0) @@ -797,7 +787,7 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, const player_t *p avgY = (g_nudgeSearch.gotoAvgY[gotoSide] / g_nudgeSearch.gotoObjs[gotoSide]) * mapobjectscale; avgDist = R_PointToDist2( - predict->x, predict->y, + bd->predict.x, bd->predict.y, avgX, avgY ); @@ -810,23 +800,23 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, const player_t *p if (avgDist <= nudgeDist) { - predict->x = avgX; - predict->y = avgY; - predict->radius = baseNudge; + bd->predict.x = avgX; + bd->predict.y = avgY; + bd->predict.radius = baseNudge; } else { // Point towards nudgeDir = R_PointToAngle2( - predict->x, predict->y, + bd->predict.x, bd->predict.y, avgX, avgY ); - predict->x += FixedMul(nudgeDist, FINECOSINE(nudgeDir >> ANGLETOFINESHIFT)); - predict->y += FixedMul(nudgeDist, FINESINE(nudgeDir >> ANGLETOFINESHIFT)); - predict->radius = std::max(predict->radius - nudgeDist, baseNudge); + bd->predict.x += FixedMul(nudgeDist, FINECOSINE(nudgeDir >> ANGLETOFINESHIFT)); + bd->predict.y += FixedMul(nudgeDist, FINESINE(nudgeDir >> ANGLETOFINESHIFT)); + bd->predict.radius = std::max(bd->predict.radius - nudgeDist, baseNudge); - //distToPredict = R_PointToDist2(player->mo->x, player->mo->y, predict->x, predict->y); + //distToPredict = R_PointToDist2(player->mo->x, player->mo->y, bd->predict.x, bd->predict.y); } } diff --git a/src/k_hud.c b/src/k_hud.c index 10efcb213..920931ebb 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -40,7 +40,7 @@ #include "m_random.h" #include "g_party.h" #include "h_timers.h" -#include "v_video.h" +#include "k_bot.h" // K_DrawBotDebugger #define NUMPOSNUMS 10 #define NUMPOSFRAMES 7 // White, three blues, three reds @@ -5068,29 +5068,6 @@ static void K_DrawClusterDebugger(void) } } -static void K_DrawBotDebugger(void) -{ - if (!cv_kartdebugbot.value || !stplyr->bot) - return; - - if (stplyrnum != 0) // only for p1 - return; - - INT32 vflags = V_6WIDTHSPACE|V_ALLOWLOWERCASE; - - static const char *driftstates[] = { - [DRIFTSTATE_AUTO] = "Auto", - [DRIFTSTATE_STARTING] = "Starting", - [DRIFTSTATE_ACTIVE] = "Active", - [DRIFTSTATE_ENDING] = "Ending", - }; - - V_DrawThinString(24, 100, vflags, va("Drift state: %s", driftstates[stplyr->botvars.driftstate])); - V_DrawThinString(24, 108, vflags|(stplyr->botvars.driftlockout ? V_ORANGEMAP : 0), va("Drift lockout: %d", stplyr->botvars.driftlockout)); - V_DrawThinString(24, 116, vflags, va("Drift turn: %d", stplyr->botvars.driftturn)); - V_DrawThinString(24, 124, vflags, va("Drift timer: %d", stplyr->botvars.drifttime)); -} - void K_drawKartHUD(void) { boolean islonesome = false; @@ -5332,9 +5309,11 @@ void K_drawKartHUD(void) } K_DrawWaypointDebugger(); - K_DrawBotDebugger(); K_DrawClusterDebugger(); K_DrawDirectorDebugger(); + + if (stplyrnum == 0) + K_DrawBotDebugger(stplyr); } // Thank you Haya.... diff --git a/src/k_kart.c b/src/k_kart.c index 64aa29424..f48b1b1c8 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -647,8 +647,7 @@ static void K_KartGetItemResult(player_t *player, SINT8 getitem) if (getitem == KITEM_HYUDORO) // Hyudoro cooldown hyubgone = 20*TICRATE; - player->botvars.itemdelay = TICRATE; - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, true); player->itemtype = K_ItemResultToType(getitem); UINT8 itemamount = K_ItemResultToAmount(getitem); @@ -11161,7 +11160,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (ATTACK_IS_DOWN && player->eggmanexplode <= 3*TICRATE && player->eggmanexplode > 1) { player->eggmanexplode = 1; - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } } // Eggman Monitor throwing @@ -11173,7 +11172,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_PlayAttackTaunt(player->mo); player->itemflags &= ~IF_EGGMANOUT; K_UpdateHnextList(player, true); - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } } // Rocket Sneaker usage @@ -11187,7 +11186,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->rocketsneakertimer = 1; else player->rocketsneakertimer -= 2*TICRATE; - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } } // Flame Shield Usage @@ -11300,7 +11299,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_DoSneaker(player, SNEAKERTYPE_SNEAKER); K_PlayBoostTaunt(player->mo); player->itemamount--; - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } break; case KITEM_ROCKETSNEAKER: @@ -11334,7 +11333,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) P_SetTarget(&prev->hnext, mo); prev = mo; } - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } break; case KITEM_INVINCIBILITY: @@ -11343,7 +11342,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_DoInvincibility(player, K_GetInvincibilityTime(player)); K_PlayPowerGloatSound(player->mo); player->itemamount--; - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } break; case KITEM_BANANA: @@ -11374,7 +11373,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) P_SetTarget(&prev->hnext, mo); prev = mo; } - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } else if (ATTACK_IS_DOWN && (player->itemflags & IF_ITEMOUT)) // Banana x3 thrown @@ -11383,7 +11382,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_ThrowKartItem(player, false, MT_BANANA, -1, 0); K_PlayAttackTaunt(player->mo); K_UpdateHnextList(player, false); - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } break; case KITEM_EGGMAN: @@ -11404,7 +11403,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) P_SetTarget(&mo->target, player->mo); P_SetTarget(&player->mo->hnext, mo); } - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } break; case KITEM_ORBINAUT: @@ -11439,7 +11438,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) P_SetTarget(&prev->hnext, mo); prev = mo; } - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } else if (ATTACK_IS_DOWN && (player->itemflags & IF_ITEMOUT)) // Orbinaut x3 thrown { @@ -11447,7 +11446,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_ThrowKartItem(player, true, MT_ORBINAUT, 1, 0); K_PlayAttackTaunt(player->mo); K_UpdateHnextList(player, false); - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } break; case KITEM_JAWZ: @@ -11481,7 +11480,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) P_SetTarget(&prev->hnext, mo); prev = mo; } - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } else if (ATTACK_IS_DOWN && HOLDING_ITEM && (player->itemflags & IF_ITEMOUT)) // Jawz thrown { @@ -11492,7 +11491,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_ThrowKartItem(player, true, MT_JAWZ_DUD, -1, 0); K_PlayAttackTaunt(player->mo); K_UpdateHnextList(player, false); - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } break; case KITEM_MINE: @@ -11511,7 +11510,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) P_SetTarget(&mo->target, player->mo); P_SetTarget(&player->mo->hnext, mo); } - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } else if (ATTACK_IS_DOWN && (player->itemflags & IF_ITEMOUT)) { @@ -11520,7 +11519,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_PlayAttackTaunt(player->mo); player->itemflags &= ~IF_ITEMOUT; K_UpdateHnextList(player, true); - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } break; case KITEM_LANDMINE: @@ -11529,7 +11528,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->itemamount--; K_ThrowLandMine(player); K_PlayAttackTaunt(player->mo); - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } break; case KITEM_BALLHOG: @@ -11538,7 +11537,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->itemamount--; K_ThrowKartItem(player, true, MT_BALLHOG, 1, 0); K_PlayAttackTaunt(player->mo); - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } break; case KITEM_SPB: @@ -11547,7 +11546,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->itemamount--; K_ThrowKartItem(player, true, MT_SPB, 1, 0); K_PlayAttackTaunt(player->mo); - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } break; case KITEM_GROW: @@ -11591,7 +11590,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) S_StartSound(player->mo, sfx_kc5a); } - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } break; case KITEM_SHRINK: @@ -11600,7 +11599,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_DoShrink(player); player->itemamount--; K_PlayPowerGloatSound(player->mo); - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } break; case KITEM_THUNDERSHIELD: @@ -11625,7 +11624,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) // ...:dumbestass: player->itemamount--; K_PlayAttackTaunt(player->mo); - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } } break; @@ -11715,7 +11714,7 @@ bubbledeflate: player->itemamount--; K_DoHyudoroSteal(player); // yes. yes they do. K_PlayAttackTaunt(player->mo); - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } break; case KITEM_POGOSPRING: @@ -11725,7 +11724,7 @@ bubbledeflate: K_PlayBoostTaunt(player->mo); K_DoPogoSpring(player->mo, 32<pogospring = 1; - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } break; case KITEM_SUPERRING: @@ -11733,7 +11732,7 @@ bubbledeflate: { player->itemamount--; K_AwardScaledPlayerRings(player, ASR_SUPERRING); - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } break; case KITEM_KITCHENSINK: @@ -11752,7 +11751,7 @@ bubbledeflate: P_SetTarget(&mo->target, player->mo); P_SetTarget(&player->mo->hnext, mo); } - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } else if (ATTACK_IS_DOWN && HOLDING_ITEM && (player->itemflags & IF_ITEMOUT)) // Sink thrown { @@ -11761,7 +11760,7 @@ bubbledeflate: K_PlayAttackTaunt(player->mo); player->itemflags &= ~IF_ITEMOUT; K_UpdateHnextList(player, true); - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } break; case KITEM_SAD: @@ -11770,7 +11769,7 @@ bubbledeflate: { player->sadtimer = stealtime; player->itemamount--; - player->botvars.itemconfirm = 0; + K_BotResetItemConfirm(player, false); } break; default: diff --git a/src/p_saveg.c b/src/p_saveg.c index d64c624a6..d40572f1e 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -401,15 +401,7 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT8(save->p, players[i].botvars.rival); WRITEFIXED(save->p, players[i].botvars.rubberband); WRITEUINT16(save->p, players[i].botvars.controller); - WRITEUINT32(save->p, players[i].botvars.itemdelay); - WRITEUINT32(save->p, players[i].botvars.itemconfirm); - WRITESINT8(save->p, players[i].botvars.turnconfirm); - WRITEUINT32(save->p, players[i].botvars.respawnconfirm); WRITEFIXED(save->p, players[i].botvars.driftskill); - WRITEINT32(save->p, players[i].botvars.driftstate); - WRITESINT8(save->p, players[i].botvars.driftturn); - WRITEUINT32(save->p, players[i].botvars.drifttime); - WRITEUINT32(save->p, players[i].botvars.driftlockout); WRITEFIXED(save->p, players[i].outrun); WRITEUINT8(save->p, players[i].outruntime); @@ -756,15 +748,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].botvars.rival = (boolean)READUINT8(save->p); players[i].botvars.rubberband = READFIXED(save->p); players[i].botvars.controller = READUINT16(save->p); - players[i].botvars.itemdelay = READUINT32(save->p); - players[i].botvars.itemconfirm = READUINT32(save->p); - players[i].botvars.turnconfirm = READSINT8(save->p); - players[i].botvars.respawnconfirm = READUINT32(save->p); players[i].botvars.driftskill = READFIXED(save->p); - players[i].botvars.driftstate = READINT32(save->p); - players[i].botvars.driftturn = READSINT8(save->p); - players[i].botvars.drifttime = READUINT32(save->p); - players[i].botvars.driftlockout = READUINT32(save->p); players[i].outrun = READFIXED(save->p); players[i].outruntime = READUINT8(save->p); diff --git a/src/p_tick.c b/src/p_tick.c index 67e11ccdd..ec780568f 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -40,6 +40,7 @@ #include "k_waypoint.h" #include "k_director.h" #include "acs/interface.h" +#include "k_bot.h" // K_BotTicker #ifdef PARANOIA #include "deh_tables.h" // MOBJTYPE_LIST @@ -767,6 +768,12 @@ void P_Ticker(boolean run) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) P_PlayerAfterThink(&players[i]); + // run all the bot tickers + if (server) + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && players[i].bot && players[i].mo && !P_MobjWasRemoved(players[i].mo)) + K_BotTicker(&players[i]); + // Bosses have a punchy start, so no position. if (bossinfo.boss == true) { diff --git a/src/typedef.h b/src/typedef.h index 424858d4a..72323f202 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -164,7 +164,7 @@ TYPEDEF (bheap_t); TYPEDEF (weakspot_t); // k_bot.h -TYPEDEF (botprediction_t); +TYPEDEF (botdata_t); TYPEDEF (botcontroller_t); // k_brightmap.h