diff --git a/src/d_player.h b/src/d_player.h index e9f166399..a6aa69675 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -332,6 +332,10 @@ struct botvars_t SINT8 turnconfirm; // Confirm turn direction tic_t spindashconfirm; // When high enough, they will try spindashing + UINT32 respawnconfirm; // When high enough, they will use Ring Shooter + + UINT8 roulettePriority; // What items to go for on the roulette + tic_t rouletteTimeout; // If it takes too long to decide, try lowering priority until we find something valid. }; // player_t struct for round-specific condition tracking @@ -398,6 +402,23 @@ struct itemroulette_t boolean eggman; }; +// enum for bot item priorities +typedef enum +{ + BOT_ITEM_PR__FALLBACK, // Priority decrement fallback -- end the bot's roulette asap + BOT_ITEM_PR_NEUTRAL, // Default priority + BOT_ITEM_PR_FRONTRUNNER, + BOT_ITEM_PR_SPEED, + // Priorities beyond this point are explicitly + // used when any item from their priority group + // exists in the roulette at all. + BOT_ITEM_PR__OVERRIDES, + BOT_ITEM_PR_RINGDEBT = BOT_ITEM_PR__OVERRIDES, + BOT_ITEM_PR_POWER, + BOT_ITEM_PR_SPB, + BOT_ITEM_PR__MAX +} botItemPriority_e; + // player_t struct for loop state typedef struct { fixed_t radius; diff --git a/src/k_bot.c b/src/k_bot.c index 9f7fdc25e..7756c7fe6 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -29,6 +29,7 @@ #include "k_race.h" // finishBeamLine #include "m_perfstats.h" #include "k_podium.h" +#include "k_respawn.h" /*-------------------------------------------------- boolean K_AddBot(UINT8 skin, UINT8 difficulty, UINT8 *p) @@ -859,10 +860,10 @@ static UINT8 K_TrySpindash(player_t *player) const fixed_t baseAccel = K_GetNewSpeed(player) - oldSpeed; const fixed_t speedDiff = player->speed - player->lastspeed; - const INT32 angleDiff = AngleDelta(player->mo->angle, K_MomentumAngle(player->mo)); + const INT32 angleDiff = AngleDelta(player->mo->angle, K_MomentumAngleReal(player->mo)); if (player->spindashboost || player->tiregrease // You just released a spindash, you don't need to try again yet, jeez. - || P_PlayerInPain(player) || !P_IsObjectOnGround(player->mo)) // Not in a state where we want 'em to spindash. + || P_IsObjectOnGround(player->mo) == false) // Not in a state where we want 'em to spindash. { player->botvars.spindashconfirm = 0; return 0; @@ -913,15 +914,53 @@ static UINT8 K_TrySpindash(player_t *player) else { // Logic for normal racing. - if (speedDiff < (baseAccel / 8) // Moving too slowly - || angleDiff > ANG60) // Being pushed backwards + boolean anyCondition = false; + boolean uphill = false; + +#define AddForCondition(x) \ + if (x) \ + { \ + anyCondition = true;\ + if (player->botvars.spindashconfirm < BOTSPINDASHCONFIRM) \ + { \ + player->botvars.spindashconfirm++; \ + } \ + } + + if (K_SlopeResistance(player) == false && player->mo->standingslope != NULL) { - if (player->botvars.spindashconfirm < BOTSPINDASHCONFIRM) + const pslope_t *slope = player->mo->standingslope; + + if ((slope->flags & SL_NOPHYSICS) == 0 && abs(slope->zdelta) >= FRACUNIT/21) { - player->botvars.spindashconfirm++; + const fixed_t speedPercent = FixedDiv(player->speed, 20 * player->mo->scale); + fixed_t slopeDot = 0; + angle_t angle = K_MomentumAngle(player->mo) - slope->xydirection; + + if (P_MobjFlip(player->mo) * slope->zdelta < 0) + { + angle ^= ANGLE_180; + } + + slopeDot = FINECOSINE(angle >> ANGLETOFINESHIFT); + uphill = ((slopeDot + (speedPercent / 2)) < -FRACUNIT/2); } } - else if (player->botvars.spindashconfirm >= BOTSPINDASHCONFIRM) + + AddForCondition(K_ApplyOffroad(player) == true && player->offroad > 0); // Slowed by offroad + AddForCondition(speedDiff < (baseAccel >> 3)); // Accelerating slower than expected + AddForCondition(angleDiff > ANG60); // Being pushed backwards + AddForCondition(uphill == true); // Going up a steep slope without speed + + if (player->cmomx || player->cmomy) + { + angle_t cAngle = R_PointToDist2(0, 0, player->cmomx, player->cmomy); + angle_t cDelta = AngleDelta(player->mo->angle, cAngle); + + AddForCondition(cDelta > ANGLE_90); // Conveyor going against you + } + + if (anyCondition == false) { if (player->botvars.spindashconfirm > 0) { @@ -934,6 +973,38 @@ static UINT8 K_TrySpindash(player_t *player) return 0; } +/*-------------------------------------------------- + static boolean K_TryRingShooter(player_t *player) + + Determines conditions where the bot should attempt to respawn. + + Input Arguments:- + player - Bot player to check. + + Return:- + true if we want to hold the respawn button, otherwise false. +--------------------------------------------------*/ +static boolean K_TryRingShooter(player_t *player) +{ + if (player->respawn.state != RESPAWNST_NONE) + { + // We're already respawning! + return false; + } + + if ((gametyperules & GTR_CIRCUIT) == 0 || (leveltime <= starttime)) + { + // Only do this during a Race that has started. + return false; + } + + // Our anti-grief system is already a perfect system + // for determining if we're not making progress, so + // lets reuse it for bot respawning! + P_IncrementGriefValue(player, &player->botvars.respawnconfirm, BOTRESPAWNCONFIRM); + return (player->botvars.respawnconfirm >= BOTRESPAWNCONFIRM); +} + /*-------------------------------------------------- static void K_DrawPredictionDebug(botprediction_t *predict, player_t *player) @@ -1447,6 +1518,13 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) return; } + if (K_TryRingShooter(player) == true) + { + // We want to respawn. Simply hold Y and stop here! + cmd->buttons |= (BT_RESPAWN | BT_EBRAKEMASK); + return; + } + if (player->trickpanel != 0) { K_BotTrick(player, cmd, botController); diff --git a/src/k_bot.h b/src/k_bot.h index d98f7a1e9..e0d175aa5 100644 --- a/src/k_bot.h +++ b/src/k_bot.h @@ -31,8 +31,14 @@ extern "C" { // Made it as small as possible without making it look like the bots are twitching constantly. #define BOTTURNCONFIRM 4 -// How many tics without being able to accelerate before we'll let you spindash. -#define BOTSPINDASHCONFIRM (2*TICRATE) +// How many tics with only one spindash-viable condition before we'll let you spindash. +#define BOTSPINDASHCONFIRM (4*TICRATE) + +// How many tics without being able to make progress before we'll let you respawn. +#define BOTRESPAWNCONFIRM (5*TICRATE) + +// 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 { @@ -274,6 +280,25 @@ void K_UpdateBotGameplayVars(player_t *player); void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt); + +/*-------------------------------------------------- + void K_BotPickItemPriority(player_t *player) + + Sets a bot's desired item classification + based on what is happening around them, + and delays based on their difficulty + intended to be run when starting a roulette. + + Input Arguments:- + player - Bot to set the item classification for. + + Return:- + N/A +--------------------------------------------------*/ + +void K_BotPickItemPriority(player_t *player); + + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/k_botitem.c b/src/k_botitem.c index 58e448d1f..8758db8dc 100644 --- a/src/k_botitem.c +++ b/src/k_botitem.c @@ -1394,15 +1394,54 @@ static void K_BotItemRings(player_t *player, ticcmd_t *cmd) --------------------------------------------------*/ static void K_BotItemRouletteMash(player_t *player, ticcmd_t *cmd) { + // 12 tics late for Lv.1, frame-perfect for Lv.MAX + const tic_t confirmTime = (MAXBOTDIFFICULTY - player->botvars.difficulty); + if (K_ItemButtonWasDown(player) == true) { return; } - // TODO: Would be nice to implement smarter behavior - // for selecting items. + if (player->botvars.roulettePriority == BOT_ITEM_PR__FALLBACK) + { + // No items were part of our list, so set immediately. + player->botvars.itemconfirm = confirmTime + 1; + } + else if (player->botvars.itemconfirm > 0) + { + // Delaying our reaction time a bit... + player->botvars.itemconfirm++; + } + else + { + botItemPriority_e currentPriority = K_GetBotItemPriority( + player->itemRoulette.itemList[ player->itemRoulette.index ] + ); - cmd->buttons |= BT_ATTACK; + if (player->botvars.roulettePriority == currentPriority) + { + // This is the item we want! Start timing! + player->botvars.itemconfirm++; + } + else + { + // Not the time we want... if we take too long, + // reduce priority until we get to a valid one. + player->botvars.rouletteTimeout++; + + if (player->botvars.rouletteTimeout > player->itemRoulette.itemListLen * player->itemRoulette.speed) + { + player->botvars.roulettePriority--; + player->botvars.rouletteTimeout = 0; + } + } + } + + if (player->botvars.itemconfirm > confirmTime) + { + // We've waited out our reaction time -- press the button now! + cmd->buttons |= BT_ATTACK; + } } /*-------------------------------------------------- @@ -1568,3 +1607,101 @@ void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt) } } } + +/*-------------------------------------------------- + void K_BotPickItemPriority(player_t *player) + + See header file for description. +--------------------------------------------------*/ +void K_BotPickItemPriority(player_t *player) +{ + const fixed_t closeDistance = FixedMul(1280 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed)); + size_t i; + + // Roulette reaction time. This is how long to wait before considering items. + // Takes 3 seconds for Lv.1, is instant for Lv.MAX + player->botvars.itemdelay = ((MAXBOTDIFFICULTY - player->botvars.difficulty) * BOT_ITEM_DECISION_TIME) / (MAXBOTDIFFICULTY - 1); + player->botvars.itemconfirm = 0; + + // Set neutral items by default. + player->botvars.roulettePriority = BOT_ITEM_PR_NEUTRAL; + player->botvars.rouletteTimeout = 0; + + // Check for items that are extremely high priority. + for (i = 0; i < player->itemRoulette.itemListLen; i++) + { + botItemPriority_e priority = K_GetBotItemPriority( player->itemRoulette.itemList[i] ); + + if (priority < BOT_ITEM_PR__OVERRIDES) + { + // Not high enough to override. + continue; + } + + if (priority == BOT_ITEM_PR_RINGDEBT) + { + if (player->rings > 0) + { + // Only consider this priority when in ring debt. + continue; + } + } + + player->botvars.roulettePriority = max( player->botvars.roulettePriority, priority ); + } + + if (player->botvars.roulettePriority >= BOT_ITEM_PR__OVERRIDES) + { + // Selected a priority in the loop above. + return; + } + + for (i = 0; i < MAXPLAYERS; i++) + { + player_t *other = NULL; + fixed_t distance = INT32_MAX; + + if (playeringame[i] == false) + { + continue; + } + + other = &players[i]; + if (other->spectator == true || P_MobjWasRemoved(other->mo) == true) + { + continue; + } + + distance = P_AproxDistance( + P_AproxDistance( + other->mo->x - player->mo->x, + other->mo->y - player->mo->y + ), + other->mo->z - player->mo->z + ); + + if (distance < closeDistance) + { + // A player is relatively close. + break; + } + } + + if (i == MAXPLAYERS) + { + // Players are nearby, stay as neutral priority. + return; + } + + // Players are far away enough to give you breathing room. + if (player->position == 1) + { + // Frontrunning, so pick frontrunner items! + player->botvars.roulettePriority = BOT_ITEM_PR_FRONTRUNNER; + } + else + { + // Behind, so pick speed items! + player->botvars.roulettePriority = BOT_ITEM_PR_SPEED; + } +} diff --git a/src/k_botsearch.c b/src/k_botsearch.c index 6d3e97ed3..4d5088aa7 100644 --- a/src/k_botsearch.c +++ b/src/k_botsearch.c @@ -642,6 +642,16 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing) } } break; + case MT_RINGSHOOTER: + if (anglediff >= 45) + { + break; + } + else + { + K_AddAttackObject(thing, side, 50); + } + break; default: if (thing->flags & (MF_SOLID|MF_ENEMY|MF_BOSS|MF_PAIN|MF_MISSILE)) { diff --git a/src/k_grandprix.c b/src/k_grandprix.c index 52c82d7a3..6b19b8f06 100644 --- a/src/k_grandprix.c +++ b/src/k_grandprix.c @@ -469,8 +469,22 @@ static UINT8 K_BotExpectedStanding(player_t *bot) --------------------------------------------------*/ void K_IncreaseBotDifficulty(player_t *bot) { - UINT8 expectedstanding; - INT16 standingdiff; + UINT8 playerCount = 0; + UINT8 wonCount = 0; + + UINT8 humanThatBeatUs = 0; + INT16 beatenDelta = 0; + + UINT8 winnerHuman = UINT8_MAX; + INT16 winnerDelta = 0; + + UINT8 statusQuo = 1; + INT16 disruptDelta = 0; + + INT16 increase = 1; + size_t i = SIZE_MAX; + + bot->botvars.diffincrease = 0; if (bot->botvars.difficulty >= MAXBOTDIFFICULTY) { @@ -478,33 +492,65 @@ void K_IncreaseBotDifficulty(player_t *bot) return; } - // Increment bot difficulty based on what position you were meant to come in! - expectedstanding = K_BotExpectedStanding(bot); - standingdiff = expectedstanding - bot->position; + // Increment bot difficulty based on + // how much they were beaten by a player! - if (standingdiff >= -2) + // Find the worst-placing player that still beat us. + for (i = 0; i < MAXPLAYERS; i++) { - UINT8 increase; + player_t *other = NULL; - if (standingdiff > 5) + if (playeringame[i] == false) { - increase = 3; - } - else if (standingdiff > 2) - { - increase = 2; - } - else - { - increase = 1; + continue; } - bot->botvars.diffincrease = increase; + other = &players[i]; + if (other->spectator == true) + { + continue; + } + + playerCount++; + if (other->bot == true) + { + continue; + } + + if (other->position <= bot->position && other->position > humanThatBeatUs) + { + humanThatBeatUs = other->position; + } + + if (other->position < winnerHuman) + { + winnerHuman = other->position; + } } - else + + wonCount = playerCount / 2; + if (playerCount & 1) { - bot->botvars.diffincrease = 0; + // Round up + wonCount++; } + + statusQuo = K_BotExpectedStanding(bot); + + // How many levels they gain depends on how hard they beat us, + // and how much the status quo was disturbed. + beatenDelta = bot->position - humanThatBeatUs; + winnerDelta = wonCount - winnerHuman; + disruptDelta = abs(statusQuo - bot->position); + + increase = (beatenDelta + winnerDelta + disruptDelta - 2) / 3; + if (increase <= 0) + { + // No increase... + return; + } + + bot->botvars.diffincrease = increase; } /*-------------------------------------------------- diff --git a/src/k_kart.c b/src/k_kart.c index 8f4240414..91b2802ee 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2622,7 +2622,7 @@ static void K_HandleDelayedHitByEm(player_t *player) void K_MomentumToFacing(player_t *player) { - angle_t dangle = player->mo->angle - K_MomentumAngle(player->mo); + angle_t dangle = player->mo->angle - K_MomentumAngleReal(player->mo); if (dangle > ANGLE_180) dangle = InvAngle(dangle); @@ -3468,14 +3468,21 @@ fixed_t K_3dKartMovement(player_t *player) return finalspeed; } -fixed_t K_MomentumThreshold(const mobj_t *mo) +angle_t K_MomentumAngleEx(const mobj_t *mo, const fixed_t threshold) { - return 6 * mo->scale; + if (FixedHypot(mo->momx, mo->momy) > threshold) + { + return R_PointToAngle2(0, 0, mo->momx, mo->momy); + } + else + { + return mo->angle; // default to facing angle, rather than 0 + } } -angle_t K_MomentumAngle(mobj_t *mo) +angle_t K_MomentumAngleReal(const mobj_t *mo) { - if (FixedHypot(mo->momx, mo->momy) > K_MomentumThreshold(mo)) + if (mo->momx || mo->momy) { return R_PointToAngle2(0, 0, mo->momx, mo->momy); } @@ -3530,8 +3537,8 @@ void K_SetHitLagForObjects(mobj_t *mo1, mobj_t *mo2, INT32 tics, boolean fromDam const fixed_t scaleDiff = abs(mo2->scale - mo1->scale); - angle_t mo1angle = K_MomentumAngle(mo1); - angle_t mo2angle = K_MomentumAngle(mo2); + angle_t mo1angle = K_MomentumAngleReal(mo1); + angle_t mo2angle = K_MomentumAngleReal(mo2); INT32 angleDiff = 0; if (mo1speed > 0 && mo2speed > 0) @@ -10229,7 +10236,7 @@ boolean K_FastFallBounce(player_t *player) static void K_AirFailsafe(player_t *player) { - const fixed_t maxSpeed = K_MomentumThreshold(player->mo); + const fixed_t maxSpeed = 6*player->mo->scale; const fixed_t thrustSpeed = 6*player->mo->scale; // 10*player->mo->scale if (player->speed > maxSpeed // Above the max speed that you're allowed to use this technique. diff --git a/src/k_kart.h b/src/k_kart.h index bddba4024..839cadc6c 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -83,8 +83,9 @@ void K_KartResetPlayerColor(player_t *player); boolean K_PressingEBrake(player_t *player); void K_KartPlayerThink(player_t *player, ticcmd_t *cmd); void K_KartPlayerAfterThink(player_t *player); -fixed_t K_MomentumThreshold(const mobj_t *mo); -angle_t K_MomentumAngle(mobj_t *mo); +angle_t K_MomentumAngleEx(const mobj_t *mo, const fixed_t threshold); +angle_t K_MomentumAngleReal(const mobj_t *mo); +#define K_MomentumAngle(mo) K_MomentumAngleEx(mo, 6 * mo->scale) void K_AddHitLag(mobj_t *mo, INT32 tics, boolean fromDamage); void K_SetHitLagForObjects(mobj_t *mo1, mobj_t *mo2, INT32 tics, boolean fromDamage); void K_AwardPlayerRings(player_t *player, INT32 rings, boolean overload); diff --git a/src/k_respawn.c b/src/k_respawn.c index 8f0c756f1..46851a02f 100644 --- a/src/k_respawn.c +++ b/src/k_respawn.c @@ -147,7 +147,6 @@ void K_DoIngameRespawn(player_t *player) K_DoFault(player); } - player->ringboost = 0; player->driftboost = player->strongdriftboost = 0; player->gateBoost = 0; @@ -292,6 +291,8 @@ void K_DoIngameRespawn(player_t *player) player->respawn.airtimer = player->airtime; player->respawn.truedeath = !!(player->pflags & PF_FAULT); + player->botvars.respawnconfirm = 0; + player->mo->flags |= MF_NOCLIPTHING; } diff --git a/src/k_roulette.c b/src/k_roulette.c index 4efa164a4..5a6f79dda 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -262,6 +262,74 @@ boolean K_ItemSingularity(kartitems_t item) } } +/*-------------------------------------------------- + botItemPriority_e K_GetBotItemPriority(kartitems_t result) + + See header file for description. +--------------------------------------------------*/ +botItemPriority_e K_GetBotItemPriority(kartitems_t result) +{ + result = K_ItemResultToType(result); + + switch (result) + { + case KITEM_SPB: + { + // Items that are intended to improve the game balance for everyone. + return BOT_ITEM_PR_SPB; + } + case KITEM_INVINCIBILITY: + case KITEM_GROW: + case KITEM_SHRINK: + case KITEM_LIGHTNINGSHIELD: + case KITEM_BUBBLESHIELD: + case KITEM_FLAMESHIELD: + { + // Items that drastically improve your own defense and/or speed. + return BOT_ITEM_PR_POWER; + } + case KITEM_SUPERRING: + { + // Items that get you out of ring debt. + return BOT_ITEM_PR_RINGDEBT; + } + case KITEM_SNEAKER: + case KITEM_ROCKETSNEAKER: + case KITEM_GARDENTOP: + case KITEM_POGOSPRING: + { + // Used when not in 1st place and relatively far from players. + // Items that give you speed with no protection. + return BOT_ITEM_PR_SPEED; + } + case KITEM_HYUDORO: + case KITEM_LANDMINE: + case KITEM_DROPTARGET: + case KITEM_EGGMAN: + case KITEM_GACHABOM: + case KITEM_KITCHENSINK: + { + // Used when in 1st place and relatively far from players. + // Typically attack items that don't give you protection. + return BOT_ITEM_PR_FRONTRUNNER; + } + case KITEM_ORBINAUT: + case KITEM_BALLHOG: + case KITEM_JAWZ: + case KITEM_BANANA: + case KITEM_MINE: + { + // Used in all other instances (close to other players, no priority override) + // Typically attack items that give you protection. + return BOT_ITEM_PR_NEUTRAL; + } + default: + { + return BOT_ITEM_PR__FALLBACK; + } + } +} + /*-------------------------------------------------- static fixed_t K_ItemOddsScale(UINT8 playerCount) @@ -1351,9 +1419,10 @@ void K_StartItemRoulette(player_t *const player) K_FillItemRouletteData(player, roulette); - // Make the bots select their item after a little while. - // One of the few instances of bot RNG, would be nice to remove it. - player->botvars.itemdelay = P_RandomRange(PR_UNDEFINED, TICRATE, TICRATE*3); + if (K_PlayerUsesBotMovement(player) == true) + { + K_BotPickItemPriority(player); + } // Prevent further duplicates of items that // are intended to only have one out at a time. diff --git a/src/k_roulette.h b/src/k_roulette.h index f4afb4988..61624525d 100644 --- a/src/k_roulette.h +++ b/src/k_roulette.h @@ -57,6 +57,23 @@ boolean K_ItemEnabled(kartitems_t item); boolean K_ItemSingularity(kartitems_t item); +/*-------------------------------------------------- + botItemPriority_e K_GetBotItemPriority(kartitems_t result) + + Returns an item's priority value, which + bots use to determine what kind of item they + want when the roulette is started. + + Input Arguments:- + result - The item result type to check. + + Return:- + The item's priority type. +--------------------------------------------------*/ + +botItemPriority_e K_GetBotItemPriority(kartitems_t result); + + /*-------------------------------------------------- INT32 K_KartGetItemOdds(const player_t *player, itemroulette_t *const roulette, UINT8 pos, kartitems_t item); diff --git a/src/k_waypoint.cpp b/src/k_waypoint.cpp index 0e6919915..377593798 100644 --- a/src/k_waypoint.cpp +++ b/src/k_waypoint.cpp @@ -327,6 +327,13 @@ static void K_CompareOverlappingWaypoint boolean pathfindsuccess = false; path_t pathtofinish = {0}; + if (K_GetWaypointIsShortcut(*bestwaypoint) == false + && K_GetWaypointIsShortcut(checkwaypoint) == true) + { + // If it's a shortcut, don't use it. + return; + } + pathfindsuccess = K_PathfindToWaypoint(checkwaypoint, finishline, &pathtofinish, useshortcuts, huntbackwards); diff --git a/src/p_local.h b/src/p_local.h index 59e9c0315..738faffd3 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -209,6 +209,7 @@ void P_PlayerAfterThink(player_t *player); void P_DoPlayerExit(player_t *player, pflags_t flags); void P_DoAllPlayersExit(pflags_t flags, boolean givelife); void P_DoTimeOver(player_t *player); +void P_IncrementGriefValue(player_t *player, UINT32 *grief, const UINT32 griefMax); void P_CheckRaceGriefing(player_t *player, boolean dopunishment); void P_ResetPlayerCheats(void); diff --git a/src/p_saveg.c b/src/p_saveg.c index c44ca34d1..70ccf1624 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -443,6 +443,9 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT32(save->p, players[i].botvars.itemconfirm); WRITESINT8(save->p, players[i].botvars.turnconfirm); WRITEUINT32(save->p, players[i].botvars.spindashconfirm); + WRITEUINT32(save->p, players[i].botvars.respawnconfirm); + WRITEUINT8(save->p, players[i].botvars.roulettePriority); + WRITEUINT32(save->p, players[i].botvars.rouletteTimeout); // itemroulette_t WRITEUINT8(save->p, players[i].itemRoulette.active); @@ -825,6 +828,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].botvars.itemconfirm = READUINT32(save->p); players[i].botvars.turnconfirm = READSINT8(save->p); players[i].botvars.spindashconfirm = READUINT32(save->p); + players[i].botvars.respawnconfirm = READUINT32(save->p); + players[i].botvars.roulettePriority = READUINT8(save->p); + players[i].botvars.rouletteTimeout = READUINT32(save->p); // itemroulette_t players[i].itemRoulette.active = (boolean)READUINT8(save->p); diff --git a/src/p_user.c b/src/p_user.c index a3ac135a6..3afb5b7bf 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4640,11 +4640,8 @@ void P_PlayerAfterThink(player_t *player) player->mo->pmomz = 0; } -void P_CheckRaceGriefing(player_t *player, boolean dopunishment) +void P_IncrementGriefValue(player_t *player, UINT32 *grief, const UINT32 griefMax) { - const UINT32 griefMax = cv_antigrief.value * TICRATE; - const UINT8 n = player - players; - const fixed_t requireDist = (12*player->mo->scale) / FRACUNIT; INT32 progress = player->distancetofinishprev - player->distancetofinish; boolean exceptions = ( @@ -4654,6 +4651,34 @@ void P_CheckRaceGriefing(player_t *player, boolean dopunishment) || (player->justbumped > 0 && player->justbumped < bumptime-1) ); + if (!exceptions && (progress < requireDist)) + { + // If antigrief is disabled, we don't want the + // player getting into a hole so deep no amount + // of good behaviour could ever make up for it. + if (*grief < griefMax) + { + // Making no progress, start counting against you. + *grief = *grief + 1; + if (progress < -requireDist && *grief < griefMax) + { + // Making NEGATIVE progress? Start counting even harder. + *grief = *grief + 1; + } + } + } + else if (*grief > 0) + { + // Playing normally. + *grief = *grief - 1; + } +} + +void P_CheckRaceGriefing(player_t *player, boolean dopunishment) +{ + const UINT32 griefMax = cv_antigrief.value * TICRATE; + const UINT8 n = player - players; + // Don't punish if the cvar is turned off, // otherwise NOBODY would be able to play! if (griefMax == 0) @@ -4661,27 +4686,7 @@ void P_CheckRaceGriefing(player_t *player, boolean dopunishment) dopunishment = false; } - if (!exceptions && (progress < requireDist)) - { - // If antigrief is disabled, we don't want the - // player getting into a hole so deep no amount - // of good behaviour could ever make up for it. - if (player->griefValue < griefMax) - { - // Making no progress, start counting against you. - player->griefValue++; - if (progress < -requireDist && player->griefValue < griefMax) - { - // Making NEGATIVE progress? Start counting even harder. - player->griefValue++; - } - } - } - else if (player->griefValue > 0) - { - // Playing normally. - player->griefValue--; - } + P_IncrementGriefValue(player, &player->griefValue, griefMax); if (dopunishment && player->griefValue >= griefMax) {