Merge branch 'bot-new-stuff' into 'master'

Bots: New Features / Improvements

See merge request KartKrew/Kart!1237
This commit is contained in:
Sal 2023-05-16 00:33:41 +00:00
commit fdda4df9ae
15 changed files with 502 additions and 71 deletions

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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;
}
}

View file

@ -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))
{

View file

@ -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;
}
/*--------------------------------------------------

View file

@ -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.

View file

@ -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);

View file

@ -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;
}

View file

@ -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.

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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)
{