mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'bot-new-stuff' into 'master'
Bots: New Features / Improvements See merge request KartKrew/Kart!1237
This commit is contained in:
commit
fdda4df9ae
15 changed files with 502 additions and 71 deletions
|
|
@ -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;
|
||||
|
|
|
|||
92
src/k_bot.c
92
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);
|
||||
|
|
|
|||
29
src/k_bot.h
29
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
|
||||
|
|
|
|||
143
src/k_botitem.c
143
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
|
|||
23
src/k_kart.c
23
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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
55
src/p_user.c
55
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)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue