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