mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'bot-maint' into 'master'
Bot maintenance See merge request KartKrew/Kart!489
This commit is contained in:
commit
d7829334d3
11 changed files with 654 additions and 387 deletions
287
src/k_bot.c
287
src/k_bot.c
|
|
@ -273,16 +273,94 @@ boolean K_PlayerUsesBotMovement(player_t *player)
|
|||
--------------------------------------------------*/
|
||||
boolean K_BotCanTakeCut(player_t *player)
|
||||
{
|
||||
if (!K_ApplyOffroad(player)
|
||||
if (
|
||||
#if 1
|
||||
K_TripwirePass(player) == true
|
||||
#else
|
||||
K_ApplyOffroad(player) == false
|
||||
#endif
|
||||
|| player->itemtype == KITEM_SNEAKER
|
||||
|| player->itemtype == KITEM_ROCKETSNEAKER
|
||||
|| player->itemtype == KITEM_INVINCIBILITY
|
||||
|| player->itemtype == KITEM_HYUDORO)
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static line_t *K_FindBotController(mobj_t *mo)
|
||||
|
||||
Finds if any bot controller linedefs are tagged to the bot's sector.
|
||||
|
||||
Input Arguments:-
|
||||
mo - The bot player's mobj.
|
||||
|
||||
Return:-
|
||||
Linedef of the bot controller. NULL if it doesn't exist.
|
||||
--------------------------------------------------*/
|
||||
static line_t *K_FindBotController(mobj_t *mo)
|
||||
{
|
||||
msecnode_t *node;
|
||||
ffloor_t *rover;
|
||||
INT16 lineNum = -1;
|
||||
mtag_t tag;
|
||||
|
||||
I_Assert(mo != NULL);
|
||||
I_Assert(!P_MobjWasRemoved(mo));
|
||||
|
||||
for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next)
|
||||
{
|
||||
if (!node->m_sector)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
tag = Tag_FGet(&node->m_sector->tags);
|
||||
lineNum = P_FindSpecialLineFromTag(2004, tag, -1); // todo: needs to not use P_FindSpecialLineFromTag
|
||||
|
||||
if (lineNum != -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
for (rover = node->m_sector->ffloors; rover; rover = rover->next)
|
||||
{
|
||||
sector_t *rs = NULL;
|
||||
|
||||
if (!(rover->flags & FF_EXISTS))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mo->z > *rover->topheight || mo->z + mo->height < *rover->bottomheight)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
rs = §ors[rover->secnum];
|
||||
tag = Tag_FGet(&rs->tags);
|
||||
lineNum = P_FindSpecialLineFromTag(2004, tag, -1);
|
||||
|
||||
if (lineNum != -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lineNum != -1)
|
||||
{
|
||||
return &lines[lineNum];
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static UINT32 K_BotRubberbandDistance(player_t *player)
|
||||
|
||||
|
|
@ -346,6 +424,7 @@ fixed_t K_BotRubberband(player_t *player)
|
|||
fixed_t rubberband = FRACUNIT;
|
||||
fixed_t max, min;
|
||||
player_t *firstplace = NULL;
|
||||
line_t *botController = NULL;
|
||||
UINT8 i;
|
||||
|
||||
if (player->exiting)
|
||||
|
|
@ -354,6 +433,17 @@ fixed_t K_BotRubberband(player_t *player)
|
|||
return FRACUNIT;
|
||||
}
|
||||
|
||||
botController = K_FindBotController(player->mo);
|
||||
|
||||
if (botController != NULL)
|
||||
{
|
||||
// No Climb Flag: Disable rubberbanding
|
||||
if (botController->flags & ML_NOCLIMB)
|
||||
{
|
||||
return FRACUNIT;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || players[i].spectator)
|
||||
|
|
@ -430,8 +520,8 @@ fixed_t K_BotTopSpeedRubberband(player_t *player)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Max at +10% for level 9 bots
|
||||
rubberband = FRACUNIT + ((rubberband - FRACUNIT) / 10);
|
||||
// Max at +20% for level 9 bots
|
||||
rubberband = FRACUNIT + ((rubberband - FRACUNIT) / 5);
|
||||
}
|
||||
|
||||
// Only allow you to go faster than your regular top speed if you're facing the right direction
|
||||
|
|
@ -488,6 +578,14 @@ fixed_t K_BotFrictionRubberband(player_t *player, fixed_t frict)
|
|||
return frict;
|
||||
}
|
||||
|
||||
if (player->tiregrease > 0)
|
||||
{
|
||||
// This isn't great -- it means rubberbanding will slow down when they hit a spring
|
||||
// But it's better than the opposite where they accelerate into hyperspace :V
|
||||
// (would appreciate an actual fix though ... could try being additive instead of multiplicative)
|
||||
return frict;
|
||||
}
|
||||
|
||||
origFrict = FixedDiv(ORIG_FRICTION, FRACUNIT + (rubberband / 2));
|
||||
|
||||
if (frict == ORIG_FRICTION)
|
||||
|
|
@ -567,14 +665,11 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
|||
const INT16 handling = K_GetKartTurnValue(player, KART_FULLTURN); // Reduce prediction based on how fast you can turn
|
||||
const INT16 normal = KART_FULLTURN; // "Standard" handling to compare to
|
||||
|
||||
const fixed_t distreduce = K_BotReducePrediction(player);
|
||||
const fixed_t radreduce = min(distreduce + FRACUNIT/4, FRACUNIT);
|
||||
|
||||
const tic_t futuresight = (TICRATE * normal) / max(1, handling); // How far ahead into the future to try and predict
|
||||
const fixed_t speed = max(P_AproxDistance(player->mo->momx, player->mo->momy), K_GetKartSpeed(player, false) / 4);
|
||||
const fixed_t speed = P_AproxDistance(player->mo->momx, player->mo->momy);
|
||||
|
||||
const INT32 startDist = (768 * mapobjectscale) / FRACUNIT;
|
||||
const INT32 distance = ((FixedMul(speed, distreduce) / FRACUNIT) * futuresight) + startDist;
|
||||
const INT32 distance = ((speed / FRACUNIT) * futuresight) + startDist;
|
||||
|
||||
botprediction_t *predict = Z_Calloc(sizeof(botprediction_t), PU_STATIC, NULL);
|
||||
waypoint_t *wp = player->nextwaypoint;
|
||||
|
|
@ -583,6 +678,9 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
|||
fixed_t smallestradius = INT32_MAX;
|
||||
angle_t angletonext = ANGLE_MAX;
|
||||
|
||||
// Halves radius when encountering a wall on your way to your destination.
|
||||
fixed_t radreduce = FRACUNIT;
|
||||
|
||||
size_t nwp;
|
||||
size_t i;
|
||||
|
||||
|
|
@ -595,7 +693,7 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
|||
{
|
||||
predict->x = wp->mobj->x;
|
||||
predict->y = wp->mobj->y;
|
||||
predict->radius = FixedMul(wp->mobj->radius, radreduce);
|
||||
predict->radius = wp->mobj->radius;
|
||||
return predict;
|
||||
}
|
||||
|
||||
|
|
@ -635,12 +733,12 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
|||
|
||||
for (i = 0; i < wp->numnextwaypoints; i++)
|
||||
{
|
||||
if (!K_GetWaypointIsEnabled(wp->nextwaypoints[i]))
|
||||
if (K_GetWaypointIsEnabled(wp->nextwaypoints[i]) == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (K_GetWaypointIsShortcut(wp->nextwaypoints[i]) && !K_BotCanTakeCut(player))
|
||||
if (K_GetWaypointIsShortcut(wp->nextwaypoints[i]) == true && K_BotCanTakeCut(player) == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -673,6 +771,13 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
|||
|
||||
disttonext = (INT32)wp->nextwaypointdistances[nwp];
|
||||
|
||||
if (P_TraceBotTraversal(player->mo, wp->nextwaypoints[nwp]->mobj) == false)
|
||||
{
|
||||
// If we can't get a direct path to this waypoint, we don't want to check much further...
|
||||
disttonext *= 2;
|
||||
radreduce = FRACUNIT/2;
|
||||
}
|
||||
|
||||
if (disttonext > distanceleft)
|
||||
{
|
||||
break;
|
||||
|
|
@ -761,7 +866,7 @@ static UINT8 K_TrySpindash(player_t *player)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (speedDiff < (3 * baseAccel / 4))
|
||||
if (speedDiff < (baseAccel / 4))
|
||||
{
|
||||
if (player->botvars.spindashconfirm < BOTSPINDASHCONFIRM)
|
||||
{
|
||||
|
|
@ -797,70 +902,6 @@ static UINT8 K_TrySpindash(player_t *player)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static INT16 K_FindBotController(mobj_t *mo)
|
||||
|
||||
Finds if any bot controller linedefs are tagged to the bot's sector.
|
||||
|
||||
Input Arguments:-
|
||||
mo - The bot player's mobj.
|
||||
|
||||
Return:-
|
||||
Line number of the bot controller. -1 if it doesn't exist.
|
||||
--------------------------------------------------*/
|
||||
static INT16 K_FindBotController(mobj_t *mo)
|
||||
{
|
||||
msecnode_t *node;
|
||||
ffloor_t *rover;
|
||||
INT16 lineNum = -1;
|
||||
mtag_t tag;
|
||||
|
||||
I_Assert(mo != NULL);
|
||||
I_Assert(!P_MobjWasRemoved(mo));
|
||||
|
||||
for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next)
|
||||
{
|
||||
if (!node->m_sector)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
tag = Tag_FGet(&node->m_sector->tags);
|
||||
lineNum = P_FindSpecialLineFromTag(2004, tag, -1); // todo: needs to not use P_FindSpecialLineFromTag
|
||||
|
||||
if (lineNum != -1)
|
||||
{
|
||||
return lineNum;
|
||||
}
|
||||
|
||||
for (rover = node->m_sector->ffloors; rover; rover = rover->next)
|
||||
{
|
||||
sector_t *rs = NULL;
|
||||
|
||||
if (!(rover->flags & FF_EXISTS))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mo->z > *rover->topheight || mo->z + mo->height < *rover->bottomheight)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
rs = §ors[rover->secnum];
|
||||
tag = Tag_FGet(&rs->tags);
|
||||
lineNum = P_FindSpecialLineFromTag(2004, tag, -1);
|
||||
|
||||
if (lineNum != -1)
|
||||
{
|
||||
return lineNum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static void K_DrawPredictionDebug(botprediction_t *predict, player_t *player)
|
||||
|
||||
|
|
@ -925,6 +966,50 @@ static void K_DrawPredictionDebug(botprediction_t *predict, player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static void K_BotTrick(player_t *player, ticcmd_t *cmd, line_t *botController)
|
||||
|
||||
Determines inputs for trick panels.
|
||||
|
||||
Input Arguments:-
|
||||
player - Player to generate the ticcmd for.
|
||||
cmd - The player's ticcmd to modify.
|
||||
botController - Linedef for the bot controller.
|
||||
|
||||
Return:-
|
||||
None
|
||||
--------------------------------------------------*/
|
||||
static void K_BotTrick(player_t *player, ticcmd_t *cmd, line_t *botController)
|
||||
{
|
||||
// Trick panel state -- do nothing until a controller line is found, in which case do a trick.
|
||||
if (botController == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (player->trickpanel == 1)
|
||||
{
|
||||
INT32 type = (sides[botController->sidenum[0]].rowoffset / FRACUNIT);
|
||||
|
||||
// Y Offset: Trick type
|
||||
switch (type)
|
||||
{
|
||||
case 1:
|
||||
cmd->turning = KART_FULLTURN;
|
||||
break;
|
||||
case 2:
|
||||
cmd->turning = -KART_FULLTURN;
|
||||
break;
|
||||
case 3:
|
||||
cmd->buttons |= BT_FORWARD;
|
||||
break;
|
||||
case 4:
|
||||
cmd->buttons |= BT_BACKWARD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
||||
|
||||
|
|
@ -936,7 +1021,7 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
|||
boolean trySpindash = true;
|
||||
UINT8 spindash = 0;
|
||||
INT32 turnamt = 0;
|
||||
INT16 botController = -1;
|
||||
line_t *botController = NULL;
|
||||
|
||||
// Can't build a ticcmd if we aren't spawned...
|
||||
if (!player->mo)
|
||||
|
|
@ -959,7 +1044,7 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
|||
}
|
||||
|
||||
// Complete override of all ticcmd functionality
|
||||
if (LUAh_BotTiccmd(player, cmd))
|
||||
if (LUAh_BotTiccmd(player, cmd) == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -968,30 +1053,7 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
|||
|
||||
if (player->trickpanel != 0)
|
||||
{
|
||||
// Trick panel state -- do nothing until a controller line is found, in which case do a trick.
|
||||
|
||||
if (player->trickpanel == 1 && botController != -1)
|
||||
{
|
||||
line_t *controllerLine = &lines[botController];
|
||||
INT32 type = (sides[controllerLine->sidenum[0]].rowoffset / FRACUNIT);
|
||||
|
||||
// Y Offset: Trick type
|
||||
switch (type)
|
||||
{
|
||||
case 1:
|
||||
cmd->turning = KART_FULLTURN;
|
||||
break;
|
||||
case 2:
|
||||
cmd->turning = -KART_FULLTURN;
|
||||
break;
|
||||
case 3:
|
||||
cmd->buttons |= BT_FORWARD;
|
||||
break;
|
||||
case 4:
|
||||
cmd->buttons |= BT_BACKWARD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
K_BotTrick(player, cmd, botController);
|
||||
|
||||
// Don't do anything else.
|
||||
return;
|
||||
|
|
@ -1000,20 +1062,19 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
|||
if ((player->nextwaypoint != NULL
|
||||
&& player->nextwaypoint->mobj != NULL
|
||||
&& !P_MobjWasRemoved(player->nextwaypoint->mobj))
|
||||
|| (botController != -1))
|
||||
|| (botController != NULL))
|
||||
{
|
||||
// Handle steering towards waypoints!
|
||||
SINT8 turnsign = 0;
|
||||
angle_t destangle, moveangle, angle;
|
||||
INT16 anglediff;
|
||||
|
||||
if (botController != -1)
|
||||
if (botController != NULL && (botController->flags & ML_EFFECT1))
|
||||
{
|
||||
const fixed_t dist = (player->mo->radius * 4);
|
||||
line_t *controllerLine = &lines[botController];
|
||||
|
||||
// X Offset: Movement direction
|
||||
destangle = FixedAngle(sides[controllerLine->sidenum[0]].textureoffset);
|
||||
destangle = FixedAngle(sides[botController->sidenum[0]].textureoffset);
|
||||
|
||||
// Overwritten prediction
|
||||
predict = Z_Calloc(sizeof(botprediction_t), PU_STATIC, NULL);
|
||||
|
|
@ -1112,18 +1173,6 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
|||
// Don't turn at all
|
||||
turnamt = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make minor adjustments
|
||||
turnamt /= 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (anglediff > 60)
|
||||
{
|
||||
// Actually, don't go too fast...
|
||||
cmd->forwardmove /= 2;
|
||||
cmd->buttons |= BT_BRAKE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
20
src/k_bot.h
20
src/k_bot.h
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "k_waypoint.h"
|
||||
#include "d_player.h"
|
||||
#include "r_defs.h"
|
||||
|
||||
// Maximum value of botvars.difficulty
|
||||
#define MAXBOTDIFFICULTY 9
|
||||
|
|
@ -185,19 +186,22 @@ UINT8 K_EggboxStealth(fixed_t x, fixed_t y);
|
|||
|
||||
|
||||
/*--------------------------------------------------
|
||||
fixed_t K_BotReducePrediction(player_t *player);
|
||||
boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t y)
|
||||
|
||||
Finds walls nearby the specified player, to create a multiplier
|
||||
to pull bot predictions back by.
|
||||
Tells us if a bot will play more careful around
|
||||
this sector. Checks FOFs in the sector, as well.
|
||||
|
||||
Input Arguments:-
|
||||
player - Player to compare.
|
||||
player - Player to check against.
|
||||
sec - Sector to check against.
|
||||
x - Linedef cross X position, for slopes
|
||||
y - Linedef cross Y position, for slopes
|
||||
|
||||
Return:-
|
||||
Multiplier in fixed point scale.
|
||||
true if avoiding this sector, false otherwise.
|
||||
--------------------------------------------------*/
|
||||
|
||||
fixed_t K_BotReducePrediction(player_t *player);
|
||||
boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t y);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
@ -219,8 +223,8 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
|
|||
/*--------------------------------------------------
|
||||
void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd);
|
||||
|
||||
Gives a multiplier for a bot's rubberbanding. Meant to be used for top speed,
|
||||
acceleration, and handling.
|
||||
Creates a bot's ticcmd, looking at its surroundings to
|
||||
try and figure out what it should do.
|
||||
|
||||
Input Arguments:-
|
||||
player - Player to generate the ticcmd for.
|
||||
|
|
|
|||
265
src/k_botitem.c
265
src/k_botitem.c
|
|
@ -86,7 +86,7 @@ static boolean K_BotUseItemNearPlayer(player_t *player, ticcmd_t *cmd, fixed_t r
|
|||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static boolean K_PlayerNearSpot(player_t *player, fixed_t x, fixed_t y, fixed_t radius)
|
||||
static player_t *K_PlayerNearSpot(player_t *player, fixed_t x, fixed_t y, fixed_t radius)
|
||||
|
||||
Looks for players around a specified x/y coordinate.
|
||||
|
||||
|
|
@ -97,9 +97,9 @@ static boolean K_BotUseItemNearPlayer(player_t *player, ticcmd_t *cmd, fixed_t r
|
|||
radius - The radius to look for players in.
|
||||
|
||||
Return:-
|
||||
true if a player was found around the coordinate, otherwise false.
|
||||
The player we found, NULL if nothing was found.
|
||||
--------------------------------------------------*/
|
||||
static boolean K_PlayerNearSpot(player_t *player, fixed_t x, fixed_t y, fixed_t radius)
|
||||
static player_t *K_PlayerNearSpot(player_t *player, fixed_t x, fixed_t y, fixed_t radius)
|
||||
{
|
||||
UINT8 i;
|
||||
|
||||
|
|
@ -129,15 +129,15 @@ static boolean K_PlayerNearSpot(player_t *player, fixed_t x, fixed_t y, fixed_t
|
|||
|
||||
if (dist <= radius)
|
||||
{
|
||||
return true;
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static boolean K_PlayerPredictThrow(player_t *player, UINT8 extra)
|
||||
static player_t *K_PlayerPredictThrow(player_t *player, UINT8 extra)
|
||||
|
||||
Looks for players around the predicted coordinates of their thrown item.
|
||||
|
||||
|
|
@ -146,9 +146,9 @@ static boolean K_PlayerNearSpot(player_t *player, fixed_t x, fixed_t y, fixed_t
|
|||
extra - Extra throwing distance, for aim forward on mines.
|
||||
|
||||
Return:-
|
||||
true if a player was found around the coordinate, otherwise false.
|
||||
The player we're trying to throw at, NULL if none was found.
|
||||
--------------------------------------------------*/
|
||||
static boolean K_PlayerPredictThrow(player_t *player, UINT8 extra)
|
||||
static player_t *K_PlayerPredictThrow(player_t *player, UINT8 extra)
|
||||
{
|
||||
const fixed_t dist = (30 + (extra * 10)) * player->mo->scale;
|
||||
const UINT32 airtime = FixedDiv(dist + player->mo->momz, gravity);
|
||||
|
|
@ -159,7 +159,7 @@ static boolean K_PlayerPredictThrow(player_t *player, UINT8 extra)
|
|||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static boolean K_PlayerInCone(player_t *player, UINT16 cone, boolean flip)
|
||||
static player_t *K_PlayerInCone(player_t *player, UINT16 cone, boolean flip)
|
||||
|
||||
Looks for players in the .
|
||||
|
||||
|
|
@ -172,7 +172,7 @@ static boolean K_PlayerPredictThrow(player_t *player, UINT8 extra)
|
|||
Return:-
|
||||
true if a player was found in the cone, otherwise false.
|
||||
--------------------------------------------------*/
|
||||
static boolean K_PlayerInCone(player_t *player, fixed_t radius, UINT16 cone, boolean flip)
|
||||
static player_t *K_PlayerInCone(player_t *player, fixed_t radius, UINT16 cone, boolean flip)
|
||||
{
|
||||
UINT8 i;
|
||||
|
||||
|
|
@ -222,22 +222,96 @@ static boolean K_PlayerInCone(player_t *player, fixed_t radius, UINT16 cone, boo
|
|||
{
|
||||
if (ad >= 180-cone)
|
||||
{
|
||||
return true;
|
||||
return target;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ad <= cone)
|
||||
{
|
||||
return true;
|
||||
return target;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static boolean K_RivalBotAggression(player_t *bot, player_t *target)
|
||||
|
||||
Returns if a bot is a rival & wants to be aggressive to a player.
|
||||
|
||||
Input Arguments:-
|
||||
bot - Bot to check.
|
||||
target - Who the bot wants to attack.
|
||||
|
||||
Return:-
|
||||
false if not the rival. false if the target is another bot. Otherwise, true.
|
||||
--------------------------------------------------*/
|
||||
static boolean K_RivalBotAggression(player_t *bot, player_t *target)
|
||||
{
|
||||
if (bot == NULL || target == NULL)
|
||||
{
|
||||
// Invalid.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bot->bot == false)
|
||||
{
|
||||
// lol
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bot->botvars.rival == false)
|
||||
{
|
||||
// Not the rival, we aren't self-aware.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target->bot == false)
|
||||
{
|
||||
// This bot knows that the real threat is the player.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Calling them your friends is misleading, but you'll at least spare them.
|
||||
return false;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static void K_ItemConfirmForTarget(player_t *bot, player_t *target, UINT16 amount)
|
||||
|
||||
Handles updating item confirm values for offense items.
|
||||
|
||||
Input Arguments:-
|
||||
bot - Bot to check.
|
||||
target - Who the bot wants to attack.
|
||||
amount - Amount to increase item confirm time by.
|
||||
|
||||
Return:-
|
||||
None
|
||||
--------------------------------------------------*/
|
||||
static void K_ItemConfirmForTarget(player_t *bot, player_t *target, UINT16 amount)
|
||||
{
|
||||
if (bot == NULL || target == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (K_RivalBotAggression(bot, target) == true)
|
||||
{
|
||||
// Double the rate when you're aggressive.
|
||||
bot->botvars.itemconfirm += amount << 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do as normal.
|
||||
bot->botvars.itemconfirm += amount;
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static boolean K_BotGenericPressItem(player_t *player, ticcmd_t *cmd, SINT8 dir)
|
||||
|
||||
|
|
@ -316,21 +390,21 @@ static boolean K_BotRevealsGenericTrap(player_t *player, INT16 turnamt, boolean
|
|||
}
|
||||
|
||||
// Check the predicted throws.
|
||||
if (K_PlayerPredictThrow(player, 0))
|
||||
if (K_PlayerPredictThrow(player, 0) != NULL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mine)
|
||||
{
|
||||
if (K_PlayerPredictThrow(player, 1))
|
||||
if (K_PlayerPredictThrow(player, 1) != NULL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check your behind.
|
||||
if (K_PlayerInCone(player, player->mo->radius * 16, 10, true))
|
||||
if (K_PlayerInCone(player, player->mo->radius * 16, 10, true) != NULL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -447,7 +521,6 @@ static void K_BotItemRocketSneaker(player_t *player, ticcmd_t *cmd)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
static void K_BotItemBanana(player_t *player, ticcmd_t *cmd, INT16 turnamt)
|
||||
|
||||
|
|
@ -464,9 +537,17 @@ static void K_BotItemRocketSneaker(player_t *player, ticcmd_t *cmd)
|
|||
static void K_BotItemBanana(player_t *player, ticcmd_t *cmd, INT16 turnamt)
|
||||
{
|
||||
SINT8 throwdir = -1;
|
||||
player_t *target = NULL;
|
||||
|
||||
player->botvars.itemconfirm++;
|
||||
|
||||
target = K_PlayerInCone(player, player->mo->radius * 16, 10, true);
|
||||
if (target != NULL)
|
||||
{
|
||||
K_ItemConfirmForTarget(player, target, player->botvars.difficulty);
|
||||
throwdir = -1;
|
||||
}
|
||||
|
||||
if (abs(turnamt) >= KART_FULLTURN/2)
|
||||
{
|
||||
player->botvars.itemconfirm += player->botvars.difficulty / 2;
|
||||
|
|
@ -474,19 +555,15 @@ static void K_BotItemBanana(player_t *player, ticcmd_t *cmd, INT16 turnamt)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (K_PlayerPredictThrow(player, 0))
|
||||
target = K_PlayerPredictThrow(player, 0);
|
||||
|
||||
if (target != NULL)
|
||||
{
|
||||
player->botvars.itemconfirm += player->botvars.difficulty * 2;
|
||||
K_ItemConfirmForTarget(player, target, player->botvars.difficulty * 2);
|
||||
throwdir = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (K_PlayerInCone(player, player->mo->radius * 16, 10, true))
|
||||
{
|
||||
player->botvars.itemconfirm += player->botvars.difficulty;
|
||||
throwdir = -1;
|
||||
}
|
||||
|
||||
if (player->botvars.itemconfirm > 2*TICRATE || player->bananadrag >= TICRATE)
|
||||
{
|
||||
K_BotGenericPressItem(player, cmd, throwdir);
|
||||
|
|
@ -509,12 +586,14 @@ static void K_BotItemBanana(player_t *player, ticcmd_t *cmd, INT16 turnamt)
|
|||
static void K_BotItemMine(player_t *player, ticcmd_t *cmd, INT16 turnamt)
|
||||
{
|
||||
SINT8 throwdir = 0;
|
||||
player_t *target = NULL;
|
||||
|
||||
player->botvars.itemconfirm++;
|
||||
|
||||
if (K_PlayerInCone(player, player->mo->radius * 16, 10, true))
|
||||
target = K_PlayerInCone(player, player->mo->radius * 16, 10, true);
|
||||
if (target != NULL)
|
||||
{
|
||||
player->botvars.itemconfirm += player->botvars.difficulty;
|
||||
K_ItemConfirmForTarget(player, target, player->botvars.difficulty);
|
||||
throwdir = -1;
|
||||
}
|
||||
|
||||
|
|
@ -525,27 +604,63 @@ static void K_BotItemMine(player_t *player, ticcmd_t *cmd, INT16 turnamt)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (K_PlayerPredictThrow(player, 0))
|
||||
target = K_PlayerPredictThrow(player, 0);
|
||||
if (target != NULL)
|
||||
{
|
||||
player->botvars.itemconfirm += player->botvars.difficulty * 2;
|
||||
K_ItemConfirmForTarget(player, target, player->botvars.difficulty * 2);
|
||||
throwdir = 0;
|
||||
}
|
||||
|
||||
if (K_PlayerPredictThrow(player, 1))
|
||||
target = K_PlayerPredictThrow(player, 1);
|
||||
if (target != NULL)
|
||||
{
|
||||
player->botvars.itemconfirm += player->botvars.difficulty * 2;
|
||||
K_ItemConfirmForTarget(player, target, player->botvars.difficulty * 2);
|
||||
throwdir = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (player->botvars.itemconfirm > 2*TICRATE || player->bananadrag >= TICRATE)
|
||||
{
|
||||
K_BotGenericPressItem(player, cmd, 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(player_t *player, ticcmd_t *cmd, INT16 turnamt)
|
||||
{
|
||||
player_t *target = NULL;
|
||||
|
||||
player->botvars.itemconfirm++;
|
||||
|
||||
if (abs(turnamt) >= KART_FULLTURN/2)
|
||||
{
|
||||
player->botvars.itemconfirm += player->botvars.difficulty / 2;
|
||||
}
|
||||
|
||||
target = K_PlayerInCone(player, player->mo->radius * 16, 10, true);
|
||||
if (target != NULL)
|
||||
{
|
||||
K_ItemConfirmForTarget(player, target, player->botvars.difficulty);
|
||||
}
|
||||
|
||||
if (player->botvars.itemconfirm > 2*TICRATE)
|
||||
{
|
||||
K_BotGenericPressItem(player, cmd, -1);
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static void K_BotItemEggman(player_t *player, ticcmd_t *cmd)
|
||||
|
||||
|
|
@ -562,18 +677,21 @@ static void K_BotItemEggman(player_t *player, ticcmd_t *cmd)
|
|||
{
|
||||
const UINT8 stealth = K_EggboxStealth(player->mo->x, player->mo->y);
|
||||
SINT8 throwdir = -1;
|
||||
player_t *target = NULL;
|
||||
|
||||
player->botvars.itemconfirm++;
|
||||
|
||||
if (K_PlayerPredictThrow(player, 0))
|
||||
target = K_PlayerPredictThrow(player, 0);
|
||||
if (target != NULL)
|
||||
{
|
||||
player->botvars.itemconfirm += player->botvars.difficulty / 2;
|
||||
K_ItemConfirmForTarget(player, target, player->botvars.difficulty / 2);
|
||||
throwdir = 1;
|
||||
}
|
||||
|
||||
if (K_PlayerInCone(player, player->mo->radius * 16, 10, true))
|
||||
target = K_PlayerInCone(player, player->mo->radius * 16, 10, true);
|
||||
if (target != NULL)
|
||||
{
|
||||
player->botvars.itemconfirm += player->botvars.difficulty;
|
||||
K_ItemConfirmForTarget(player, target, player->botvars.difficulty);
|
||||
throwdir = -1;
|
||||
}
|
||||
|
||||
|
|
@ -603,6 +721,7 @@ static void K_BotItemEggman(player_t *player, ticcmd_t *cmd)
|
|||
static boolean K_BotRevealsEggbox(player_t *player)
|
||||
{
|
||||
const UINT8 stealth = K_EggboxStealth(player->mo->x, player->mo->y);
|
||||
player_t *target = NULL;
|
||||
|
||||
// This is a stealthy spot for an eggbox, lets reveal it!
|
||||
if (stealth > 1)
|
||||
|
|
@ -611,13 +730,15 @@ static boolean K_BotRevealsEggbox(player_t *player)
|
|||
}
|
||||
|
||||
// Check the predicted throws.
|
||||
if (K_PlayerPredictThrow(player, 0))
|
||||
target = K_PlayerPredictThrow(player, 0);
|
||||
if (target != NULL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check your behind.
|
||||
if (K_PlayerInCone(player, player->mo->radius * 16, 10, true))
|
||||
target = K_PlayerInCone(player, player->mo->radius * 16, 10, true);
|
||||
if (target != NULL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -644,7 +765,7 @@ static void K_BotItemEggmanShield(player_t *player, ticcmd_t *cmd)
|
|||
return;
|
||||
}
|
||||
|
||||
if (K_BotRevealsEggbox(player) || (player->botvars.itemconfirm++ > 20*TICRATE))
|
||||
if (K_BotRevealsEggbox(player) == true || (player->botvars.itemconfirm++ > 20*TICRATE))
|
||||
{
|
||||
K_BotGenericPressItem(player, cmd, 0);
|
||||
}
|
||||
|
|
@ -666,8 +787,9 @@ static void K_BotItemEggmanExplosion(player_t *player, ticcmd_t *cmd)
|
|||
{
|
||||
if (player->position == 1)
|
||||
{
|
||||
// Hey, we aren't gonna find anyone up here...
|
||||
// why don't we slow down a bit? :)
|
||||
cmd->forwardmove /= 2;
|
||||
cmd->buttons |= BT_BRAKE;
|
||||
}
|
||||
|
||||
K_BotUseItemNearPlayer(player, cmd, 128*player->mo->scale);
|
||||
|
|
@ -690,23 +812,32 @@ static void K_BotItemOrbinaut(player_t *player, ticcmd_t *cmd)
|
|||
const fixed_t topspeed = K_GetKartSpeed(player, false);
|
||||
fixed_t radius = (player->mo->radius * 32);
|
||||
SINT8 throwdir = -1;
|
||||
UINT8 snipeMul = 2;
|
||||
player_t *target = NULL;
|
||||
|
||||
if (player->speed > topspeed)
|
||||
{
|
||||
radius = FixedMul(radius, FixedDiv(player->speed, topspeed));
|
||||
snipeMul = 3; // Confirm faster when you'll throw it with a bunch of extra speed!!
|
||||
}
|
||||
|
||||
player->botvars.itemconfirm++;
|
||||
|
||||
if (K_PlayerInCone(player, radius, 10, false))
|
||||
target = K_PlayerInCone(player, radius, 10, false);
|
||||
if (target != NULL)
|
||||
{
|
||||
player->botvars.itemconfirm += player->botvars.difficulty * 2;
|
||||
K_ItemConfirmForTarget(player, target, player->botvars.difficulty * snipeMul);
|
||||
throwdir = 1;
|
||||
}
|
||||
else if (K_PlayerInCone(player, radius, 10, true))
|
||||
{
|
||||
player->botvars.itemconfirm += player->botvars.difficulty;
|
||||
throwdir = -1;
|
||||
target = K_PlayerInCone(player, radius, 10, true);
|
||||
|
||||
if (target != NULL)
|
||||
{
|
||||
K_ItemConfirmForTarget(player, target, player->botvars.difficulty);
|
||||
throwdir = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (player->botvars.itemconfirm > 5*TICRATE)
|
||||
|
|
@ -732,24 +863,54 @@ static void K_BotItemJawz(player_t *player, ticcmd_t *cmd)
|
|||
const fixed_t topspeed = K_GetKartSpeed(player, false);
|
||||
fixed_t radius = (player->mo->radius * 32);
|
||||
SINT8 throwdir = 1;
|
||||
UINT8 snipeMul = 2;
|
||||
INT32 lastTarg = player->lastjawztarget;
|
||||
player_t *target = NULL;
|
||||
|
||||
if (player->speed > topspeed)
|
||||
{
|
||||
radius = FixedMul(radius, FixedDiv(player->speed, topspeed));
|
||||
snipeMul = 3; // Confirm faster when you'll throw it with a bunch of extra speed!!
|
||||
}
|
||||
|
||||
player->botvars.itemconfirm++;
|
||||
|
||||
if (K_PlayerInCone(player, radius, 10, true))
|
||||
target = K_PlayerInCone(player, radius, 10, true);
|
||||
if (target != NULL)
|
||||
{
|
||||
player->botvars.itemconfirm += player->botvars.difficulty;
|
||||
K_ItemConfirmForTarget(player, target, player->botvars.difficulty);
|
||||
throwdir = -1;
|
||||
}
|
||||
|
||||
if (player->lastjawztarget != -1)
|
||||
if (lastTarg != -1
|
||||
&& playeringame[lastTarg] == true
|
||||
&& players[lastTarg].spectator == false
|
||||
&& players[lastTarg].mo != NULL
|
||||
&& P_MobjWasRemoved(players[lastTarg].mo) == false)
|
||||
{
|
||||
player->botvars.itemconfirm += player->botvars.difficulty * 2;
|
||||
throwdir = 1;
|
||||
mobj_t *targMo = players[lastTarg].mo;
|
||||
mobj_t *mobj = NULL, *next = NULL;
|
||||
boolean targettedAlready = false;
|
||||
|
||||
target = &players[lastTarg];
|
||||
|
||||
// Make sure no other Jawz are targetting this player.
|
||||
for (mobj = kitemcap; mobj; mobj = next)
|
||||
{
|
||||
next = mobj->itnext;
|
||||
|
||||
if (mobj->type == MT_JAWZ && mobj->target == targMo)
|
||||
{
|
||||
targettedAlready = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (targettedAlready == false)
|
||||
{
|
||||
K_ItemConfirmForTarget(player, target, player->botvars.difficulty * snipeMul);
|
||||
throwdir = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (player->botvars.itemconfirm > 5*TICRATE)
|
||||
|
|
@ -772,7 +933,7 @@ static void K_BotItemJawz(player_t *player, ticcmd_t *cmd)
|
|||
--------------------------------------------------*/
|
||||
static void K_BotItemThunder(player_t *player, ticcmd_t *cmd)
|
||||
{
|
||||
if (!K_BotUseItemNearPlayer(player, cmd, 192*player->mo->scale))
|
||||
if (K_BotUseItemNearPlayer(player, cmd, 192*player->mo->scale) == false)
|
||||
{
|
||||
if (player->botvars.itemconfirm > 10*TICRATE)
|
||||
{
|
||||
|
|
@ -1036,7 +1197,6 @@ void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt)
|
|||
K_BotItemSneaker(player, cmd);
|
||||
break;
|
||||
case KITEM_BANANA:
|
||||
case KITEM_LANDMINE:
|
||||
if (!(player->pflags & PF_ITEMOUT))
|
||||
{
|
||||
K_BotItemGenericTrapShield(player, cmd, turnamt, false);
|
||||
|
|
@ -1081,6 +1241,9 @@ void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt)
|
|||
K_BotItemMine(player, cmd, turnamt);
|
||||
}
|
||||
break;
|
||||
case KITEM_LANDMINE:
|
||||
K_BotItemLandmine(player, cmd, turnamt);
|
||||
break;
|
||||
case KITEM_THUNDERSHIELD:
|
||||
K_BotItemThunder(player, cmd);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ UINT8 K_EggboxStealth(fixed_t x, fixed_t y)
|
|||
}
|
||||
}
|
||||
|
||||
return (globalsmuggle.randomitems * globalsmuggle.eggboxes);
|
||||
return (globalsmuggle.randomitems * (globalsmuggle.eggboxes + 1));
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
@ -162,21 +162,11 @@ static boolean K_BotHatesThisSectorsSpecial(player_t *player, sector_t *sec)
|
|||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t y)
|
||||
boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t y)
|
||||
|
||||
Tells us if a bot will play more careful around
|
||||
this sector. Checks FOFs in the sector, as well.
|
||||
|
||||
Input Arguments:-
|
||||
player - Player to check against.
|
||||
sec - Sector to check against.
|
||||
x - Linedef cross X position, for slopes
|
||||
y - Linedef cross Y position, for slopes
|
||||
|
||||
Return:-
|
||||
true if avoiding this sector, false otherwise.
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
static boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t y)
|
||||
boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t y)
|
||||
{
|
||||
const boolean flip = (player->mo->eflags & MFE_VERTICALFLIP);
|
||||
INT32 specialflag = 0;
|
||||
|
|
@ -257,171 +247,6 @@ static boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x,
|
|||
return K_BotHatesThisSectorsSpecial(player, bestsector);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static boolean K_FindBlockingWalls(line_t *line)
|
||||
|
||||
Blockmap search function.
|
||||
Reels the bot prediction back in based on solid walls
|
||||
or other obstacles surrounding the bot.
|
||||
|
||||
Input Arguments:-
|
||||
line - Linedef passed in from iteration.
|
||||
|
||||
Return:-
|
||||
true continues searching, false ends the search early.
|
||||
--------------------------------------------------*/
|
||||
static boolean K_FindBlockingWalls(line_t *line)
|
||||
{
|
||||
// Condensed version of PIT_CheckLine
|
||||
const fixed_t maxstepmove = FixedMul(MAXSTEPMOVE, mapobjectscale);
|
||||
fixed_t maxstep = maxstepmove;
|
||||
fixed_t linedist = INT32_MAX;
|
||||
INT32 lineside = 0;
|
||||
vertex_t pos;
|
||||
|
||||
if (!globalsmuggle.botmo || P_MobjWasRemoved(globalsmuggle.botmo) || !globalsmuggle.botmo->player)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (line->polyobj && !(line->polyobj->flags & POF_SOLID))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (tmbbox[BOXRIGHT] <= line->bbox[BOXLEFT] || tmbbox[BOXLEFT] >= line->bbox[BOXRIGHT]
|
||||
|| tmbbox[BOXTOP] <= line->bbox[BOXBOTTOM] || tmbbox[BOXBOTTOM] >= line->bbox[BOXTOP])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (P_BoxOnLineSide(tmbbox, line) != -1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
lineside = P_PointOnLineSide(globalsmuggle.botmo->x, globalsmuggle.botmo->y, line);
|
||||
|
||||
// one sided line
|
||||
if (!line->backsector)
|
||||
{
|
||||
if (lineside)
|
||||
{
|
||||
// don't hit the back side
|
||||
return true;
|
||||
}
|
||||
|
||||
goto blocked;
|
||||
}
|
||||
|
||||
if ((line->flags & ML_IMPASSABLE) || (line->flags & ML_BLOCKPLAYERS))
|
||||
{
|
||||
goto blocked;
|
||||
}
|
||||
|
||||
// set openrange, opentop, openbottom
|
||||
P_LineOpening(line, globalsmuggle.botmo);
|
||||
|
||||
if (globalsmuggle.botmo->player->waterskip)
|
||||
maxstep += maxstepmove;
|
||||
|
||||
if (P_MobjTouchingSectorSpecial(globalsmuggle.botmo, 1, 13, false))
|
||||
maxstep <<= 1;
|
||||
else if (P_MobjTouchingSectorSpecial(globalsmuggle.botmo, 1, 12, false))
|
||||
maxstep = 0;
|
||||
|
||||
if ((openrange < globalsmuggle.botmo->height) // doesn't fit
|
||||
|| (opentop - globalsmuggle.botmo->z < globalsmuggle.botmo->height) // mobj is too high
|
||||
|| (openbottom - globalsmuggle.botmo->z > maxstep)) // too big a step up
|
||||
{
|
||||
goto blocked;
|
||||
}
|
||||
|
||||
// Treat damage sectors like walls
|
||||
P_ClosestPointOnLine(globalsmuggle.botmo->x, globalsmuggle.botmo->y, line, &pos);
|
||||
|
||||
if (lineside)
|
||||
{
|
||||
if (K_BotHatesThisSector(globalsmuggle.botmo->player, line->frontsector, pos.x, pos.y))
|
||||
goto blocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (K_BotHatesThisSector(globalsmuggle.botmo->player, line->backsector, pos.x, pos.y))
|
||||
goto blocked;
|
||||
}
|
||||
|
||||
// We weren't blocked!
|
||||
return true;
|
||||
|
||||
blocked:
|
||||
linedist = K_DistanceOfLineFromPoint(line->v1->x, line->v1->y, line->v2->x, line->v2->y, globalsmuggle.botmo->x, globalsmuggle.botmo->y);
|
||||
linedist -= (globalsmuggle.botmo->radius * 8); // Maintain a reasonable distance away from it
|
||||
|
||||
if (linedist > globalsmuggle.distancetocheck)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (linedist <= 0)
|
||||
{
|
||||
globalsmuggle.closestlinedist = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (linedist < globalsmuggle.closestlinedist)
|
||||
{
|
||||
globalsmuggle.closestlinedist = linedist;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
fixed_t K_BotReducePrediction(player_t *player)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
fixed_t K_BotReducePrediction(player_t *player)
|
||||
{
|
||||
INT32 xl, xh, yl, yh, bx, by;
|
||||
|
||||
globalsmuggle.botmo = player->mo;
|
||||
globalsmuggle.distancetocheck = (player->mo->radius * 32);
|
||||
globalsmuggle.closestlinedist = INT32_MAX;
|
||||
|
||||
tmx = player->mo->x;
|
||||
tmy = player->mo->y;
|
||||
|
||||
xl = (unsigned)(tmx - globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
|
||||
xh = (unsigned)(tmx + globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
|
||||
yl = (unsigned)(tmy - globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
|
||||
yh = (unsigned)(tmy + globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
|
||||
|
||||
BMBOUNDFIX(xl, xh, yl, yh);
|
||||
|
||||
tmbbox[BOXTOP] = tmy + globalsmuggle.distancetocheck;
|
||||
tmbbox[BOXBOTTOM] = tmy - globalsmuggle.distancetocheck;
|
||||
tmbbox[BOXRIGHT] = tmx + globalsmuggle.distancetocheck;
|
||||
tmbbox[BOXLEFT] = tmx - globalsmuggle.distancetocheck;
|
||||
|
||||
// Check for lines that the bot might collide with
|
||||
for (bx = xl; bx <= xh; bx++)
|
||||
{
|
||||
for (by = yl; by <= yh; by++)
|
||||
{
|
||||
P_BlockLinesIterator(bx, by, K_FindBlockingWalls);
|
||||
}
|
||||
}
|
||||
|
||||
if (globalsmuggle.closestlinedist == INT32_MAX)
|
||||
{
|
||||
return FRACUNIT;
|
||||
}
|
||||
|
||||
return (FRACUNIT/2) + (FixedDiv(globalsmuggle.closestlinedist, globalsmuggle.distancetocheck) / 2);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static void K_AddAttackObject(mobj_t *thing, UINT8 side, UINT8 weight)
|
||||
|
||||
|
|
|
|||
|
|
@ -8634,8 +8634,6 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
boolean HOLDING_ITEM = (player->pflags & (PF_ITEMOUT|PF_EGGMANOUT));
|
||||
boolean NO_HYUDORO = (player->stealingtimer == 0);
|
||||
|
||||
player->pflags &= ~PF_HITFINISHLINE;
|
||||
|
||||
if (!player->exiting)
|
||||
{
|
||||
if (player->oldposition < player->position) // But first, if you lost a place,
|
||||
|
|
|
|||
|
|
@ -404,6 +404,8 @@ boolean P_IsLineBlocking(const line_t *ld, const mobj_t *thing);
|
|||
boolean P_IsLineTripWire(const line_t *ld);
|
||||
boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y);
|
||||
boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam);
|
||||
fixed_t P_BaseStepUp(void);
|
||||
fixed_t P_GetThingStepUp(mobj_t *thing);
|
||||
boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff);
|
||||
boolean P_Move(mobj_t *actor, fixed_t speed);
|
||||
boolean P_SetOrigin(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z);
|
||||
|
|
@ -413,6 +415,7 @@ void P_BouncePlayerMove(mobj_t *mo);
|
|||
void P_BounceMove(mobj_t *mo);
|
||||
boolean P_CheckSight(mobj_t *t1, mobj_t *t2);
|
||||
boolean P_TraceBlockingLines(mobj_t *t1, mobj_t *t2);
|
||||
boolean P_TraceBotTraversal(mobj_t *t1, mobj_t *t2);
|
||||
void P_CheckHoopPosition(mobj_t *hoopthing, fixed_t x, fixed_t y, fixed_t z, fixed_t radius);
|
||||
|
||||
boolean P_CheckSector(sector_t *sector, boolean crunch);
|
||||
|
|
|
|||
56
src/p_map.c
56
src/p_map.c
|
|
@ -2431,6 +2431,42 @@ static boolean P_WaterStepUp(mobj_t *thing)
|
|||
P_WaterRunning(thing);
|
||||
}
|
||||
|
||||
fixed_t P_BaseStepUp(void)
|
||||
{
|
||||
return FixedMul(MAXSTEPMOVE, mapobjectscale);
|
||||
}
|
||||
|
||||
fixed_t P_GetThingStepUp(mobj_t *thing)
|
||||
{
|
||||
const fixed_t maxstepmove = P_BaseStepUp();
|
||||
fixed_t maxstep = maxstepmove;
|
||||
|
||||
if (thing->type == MT_SKIM)
|
||||
{
|
||||
// Skim special (not needed for kart?)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (P_WaterStepUp(thing) == true)
|
||||
{
|
||||
// Add some extra stepmove when waterskipping
|
||||
maxstep += maxstepmove;
|
||||
}
|
||||
|
||||
if (P_MobjTouchingSectorSpecial(thing, 1, 13, false))
|
||||
{
|
||||
// If using type Section1:13, double the maxstep.
|
||||
maxstep <<= 1;
|
||||
}
|
||||
else if (P_MobjTouchingSectorSpecial(thing, 1, 12, false))
|
||||
{
|
||||
// If using type Section1:12, no maxstep. For short walls, like Egg Zeppelin
|
||||
maxstep = 0;
|
||||
}
|
||||
|
||||
return maxstep;
|
||||
}
|
||||
|
||||
//
|
||||
// P_TryMove
|
||||
// Attempt to move to a new position.
|
||||
|
|
@ -2492,21 +2528,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
|
|||
if (!(thing->flags & MF_NOCLIP))
|
||||
{
|
||||
//All things are affected by their scale.
|
||||
const fixed_t maxstepmove = FixedMul(MAXSTEPMOVE, mapobjectscale);
|
||||
fixed_t maxstep = maxstepmove;
|
||||
|
||||
if (thing->player && P_WaterStepUp(thing))
|
||||
maxstep += maxstepmove; // Add some extra stepmove when waterskipping
|
||||
|
||||
// If using type Section1:13, double the maxstep.
|
||||
if (P_MobjTouchingSectorSpecial(thing, 1, 13, false))
|
||||
maxstep <<= 1;
|
||||
// If using type Section1:12, no maxstep. For short walls, like Egg Zeppelin
|
||||
else if (P_MobjTouchingSectorSpecial(thing, 1, 12, false))
|
||||
maxstep = 0;
|
||||
|
||||
if (thing->type == MT_SKIM)
|
||||
maxstep = 0;
|
||||
fixed_t maxstep = P_GetThingStepUp(thing);
|
||||
|
||||
if (tmceilingz - tmfloorz < thing->height)
|
||||
{
|
||||
|
|
@ -2743,7 +2765,7 @@ boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y)
|
|||
|
||||
if (!(thing->flags & MF_NOCLIP))
|
||||
{
|
||||
const fixed_t maxstep = FixedMul(MAXSTEPMOVE, mapobjectscale);
|
||||
const fixed_t maxstep = P_BaseStepUp();
|
||||
|
||||
if (tmceilingz - tmfloorz < thing->height)
|
||||
return false; // doesn't fit
|
||||
|
|
@ -3205,7 +3227,7 @@ static boolean PTR_LineIsBlocking(line_t *li)
|
|||
if (opentop - slidemo->z < slidemo->height)
|
||||
return true; // mobj is too high
|
||||
|
||||
if (openbottom - slidemo->z > FixedMul(MAXSTEPMOVE, mapobjectscale))
|
||||
if (openbottom - slidemo->z > P_GetThingStepUp(slidemo))
|
||||
return true; // too big a step up
|
||||
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -4095,7 +4095,7 @@ boolean P_BossTargetPlayer(mobj_t *actor, boolean closest)
|
|||
|
||||
player = &players[actor->lastlook];
|
||||
|
||||
if (player->bot || player->spectator)
|
||||
if (player->spectator)
|
||||
continue; // ignore notarget
|
||||
|
||||
if (!player->mo || P_MobjWasRemoved(player->mo))
|
||||
|
|
|
|||
194
src/p_sight.c
194
src/p_sight.c
|
|
@ -18,6 +18,9 @@
|
|||
#include "r_main.h"
|
||||
#include "r_state.h"
|
||||
|
||||
#include "k_bot.h" // K_BotHatesThisSector
|
||||
#include "k_kart.h" // K_TripwirePass
|
||||
|
||||
//
|
||||
// P_CheckSight
|
||||
//
|
||||
|
|
@ -572,7 +575,7 @@ static boolean P_CrossBlockingSubsector(size_t num, register traceblocking_t *tb
|
|||
|
||||
if (P_IsLineBlocking(line, tb->compareThing) == true)
|
||||
{
|
||||
// This line will block us
|
||||
// This line will always block us
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -656,3 +659,192 @@ boolean P_TraceBlockingLines(mobj_t *t1, mobj_t *t2)
|
|||
// the head node is the last node output
|
||||
return P_CrossBSPNodeBlocking((INT32)numnodes - 1, &tb);
|
||||
}
|
||||
|
||||
//
|
||||
// ANOTHER version, this time for bot traversal.
|
||||
// (TODO: since we have so many versions of this function, the differences
|
||||
// should maybe just be a function var that gets called?)
|
||||
//
|
||||
|
||||
static boolean P_CrossBotTraversalSubsector(size_t num, register traceblocking_t *tb)
|
||||
{
|
||||
seg_t *seg;
|
||||
INT32 count;
|
||||
|
||||
#ifdef RANGECHECK
|
||||
if (num >= numsubsectors)
|
||||
I_Error("P_CrossBotTraversalSubsector: ss %s with numss = %s\n", sizeu1(num), sizeu2(numsubsectors));
|
||||
#endif
|
||||
|
||||
// haleyjd 02/23/06: this assignment should be after the above check
|
||||
seg = segs + subsectors[num].firstline;
|
||||
|
||||
for (count = subsectors[num].numlines; --count >= 0; seg++) // check lines
|
||||
{
|
||||
line_t *line = seg->linedef;
|
||||
divline_t divl;
|
||||
const vertex_t *v1,*v2;
|
||||
fixed_t maxstep = INT32_MAX;
|
||||
|
||||
if (seg->glseg)
|
||||
continue;
|
||||
|
||||
// already checked other side?
|
||||
if (line->validcount == validcount)
|
||||
continue;
|
||||
|
||||
line->validcount = validcount;
|
||||
|
||||
// OPTIMIZE: killough 4/20/98: Added quick bounding-box rejection test
|
||||
if (line->bbox[BOXLEFT ] > tb->bbox[BOXRIGHT ] ||
|
||||
line->bbox[BOXRIGHT ] < tb->bbox[BOXLEFT ] ||
|
||||
line->bbox[BOXBOTTOM] > tb->bbox[BOXTOP ] ||
|
||||
line->bbox[BOXTOP] < tb->bbox[BOXBOTTOM])
|
||||
continue;
|
||||
|
||||
v1 = line->v1;
|
||||
v2 = line->v2;
|
||||
|
||||
// line isn't crossed?
|
||||
if (P_DivlineSide(v1->x, v1->y, &tb->strace) ==
|
||||
P_DivlineSide(v2->x, v2->y, &tb->strace))
|
||||
continue;
|
||||
|
||||
// stop because it is not two sided anyway
|
||||
if (!(line->flags & ML_TWOSIDED))
|
||||
return false;
|
||||
|
||||
divl.dx = v2->x - (divl.x = v1->x);
|
||||
divl.dy = v2->y - (divl.y = v1->y);
|
||||
|
||||
// line isn't crossed?
|
||||
if (P_DivlineSide(tb->strace.x, tb->strace.y, &divl) ==
|
||||
P_DivlineSide(tb->t2x, tb->t2y, &divl))
|
||||
continue;
|
||||
|
||||
if (P_IsLineBlocking(line, tb->compareThing) == true)
|
||||
{
|
||||
// This line will always block us
|
||||
return false;
|
||||
}
|
||||
|
||||
// set openrange, opentop, openbottom
|
||||
P_LineOpening(line, tb->compareThing);
|
||||
maxstep = P_GetThingStepUp(tb->compareThing);
|
||||
|
||||
if ((openrange < tb->compareThing->height) // doesn't fit
|
||||
|| (opentop - tb->compareThing->z < tb->compareThing->height) // mobj is too high
|
||||
|| (openbottom - tb->compareThing->z > maxstep)) // too big a step up
|
||||
{
|
||||
// This line situationally blocks us
|
||||
return false;
|
||||
}
|
||||
|
||||
// Treat damage sectors like walls
|
||||
if (tb->compareThing->player != NULL)
|
||||
{
|
||||
boolean alreadyHates = K_BotHatesThisSector(tb->compareThing->player, tb->compareThing->subsector->sector, tb->compareThing->x, tb->compareThing->y);
|
||||
|
||||
if (alreadyHates == false)
|
||||
{
|
||||
INT32 lineside = 0;
|
||||
vertex_t pos;
|
||||
|
||||
P_ClosestPointOnLine(tb->compareThing->x, tb->compareThing->y, line, &pos);
|
||||
lineside = P_PointOnLineSide(tb->compareThing->x, tb->compareThing->y, line);
|
||||
|
||||
if (K_BotHatesThisSector(tb->compareThing->player, ((lineside == 1) ? line->frontsector : line->backsector), pos.x, pos.y))
|
||||
{
|
||||
// This line does not block us, but we don't want to be in it.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (P_IsLineTripWire(line) == true && K_TripwirePass(tb->compareThing->player) == false)
|
||||
{
|
||||
// Can't go through trip wire.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// passed the subsector ok
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean P_CrossBSPNodeBotTraversal(INT32 bspnum, register traceblocking_t *tb)
|
||||
{
|
||||
while (!(bspnum & NF_SUBSECTOR))
|
||||
{
|
||||
register node_t *bsp = nodes + bspnum;
|
||||
INT32 side = P_DivlineSide(tb->strace.x,tb->strace.y,(divline_t *)bsp)&1;
|
||||
if (side == P_DivlineSide(tb->t2x, tb->t2y, (divline_t *) bsp))
|
||||
bspnum = bsp->children[side]; // doesn't touch the other side
|
||||
else // the partition plane is crossed here
|
||||
{
|
||||
if (!P_CrossBSPNodeBotTraversal(bsp->children[side], tb))
|
||||
return false; // cross the starting side
|
||||
else
|
||||
bspnum = bsp->children[side^1]; // cross the ending side
|
||||
}
|
||||
}
|
||||
|
||||
return P_CrossBotTraversalSubsector((bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR), tb);
|
||||
}
|
||||
|
||||
boolean P_TraceBotTraversal(mobj_t *t1, mobj_t *t2)
|
||||
{
|
||||
const sector_t *s1, *s2;
|
||||
size_t pnum;
|
||||
traceblocking_t tb;
|
||||
|
||||
// First check for trivial rejection.
|
||||
if (!t1 || !t2)
|
||||
return false;
|
||||
|
||||
I_Assert(!P_MobjWasRemoved(t1));
|
||||
I_Assert(!P_MobjWasRemoved(t2));
|
||||
|
||||
if (!t1->subsector || !t2->subsector
|
||||
|| !t1->subsector->sector || !t2->subsector->sector)
|
||||
return false;
|
||||
|
||||
s1 = t1->subsector->sector;
|
||||
s2 = t2->subsector->sector;
|
||||
pnum = (s1-sectors)*numsectors + (s2-sectors);
|
||||
|
||||
if (rejectmatrix != NULL)
|
||||
{
|
||||
// Check in REJECT table.
|
||||
if (rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected
|
||||
return false;
|
||||
}
|
||||
|
||||
// killough 11/98: shortcut for melee situations
|
||||
// same subsector? obviously visible
|
||||
// haleyjd 02/23/06: can't do this if there are polyobjects in the subsec
|
||||
if (!t1->subsector->polyList &&
|
||||
t1->subsector == t2->subsector)
|
||||
return true;
|
||||
|
||||
validcount++;
|
||||
|
||||
tb.strace.dx = (tb.t2x = t2->x) - (tb.strace.x = t1->x);
|
||||
tb.strace.dy = (tb.t2y = t2->y) - (tb.strace.y = t1->y);
|
||||
|
||||
if (t1->x > t2->x)
|
||||
tb.bbox[BOXRIGHT] = t1->x, tb.bbox[BOXLEFT] = t2->x;
|
||||
else
|
||||
tb.bbox[BOXRIGHT] = t2->x, tb.bbox[BOXLEFT] = t1->x;
|
||||
|
||||
if (t1->y > t2->y)
|
||||
tb.bbox[BOXTOP] = t1->y, tb.bbox[BOXBOTTOM] = t2->y;
|
||||
else
|
||||
tb.bbox[BOXTOP] = t2->y, tb.bbox[BOXBOTTOM] = t1->y;
|
||||
|
||||
tb.compareThing = t1;
|
||||
|
||||
// the head node is the last node output
|
||||
return P_CrossBSPNodeBotTraversal((INT32)numnodes - 1, &tb);
|
||||
}
|
||||
|
||||
|
|
|
|||
24
src/p_user.c
24
src/p_user.c
|
|
@ -2502,6 +2502,8 @@ static void P_ConsiderAllGone(void)
|
|||
//
|
||||
static void P_DeathThink(player_t *player)
|
||||
{
|
||||
boolean playerGone = false;
|
||||
|
||||
player->deltaviewheight = 0;
|
||||
|
||||
if (player->deadtimer < INT32_MAX)
|
||||
|
|
@ -2522,7 +2524,19 @@ static void P_DeathThink(player_t *player)
|
|||
|
||||
K_KartPlayerHUDUpdate(player);
|
||||
|
||||
if (player->lives > 0 && !(player->pflags & PF_NOCONTEST) && player->deadtimer > TICRATE)
|
||||
if (player->pflags & PF_NOCONTEST)
|
||||
{
|
||||
playerGone = true;
|
||||
}
|
||||
else if (player->bot == false)
|
||||
{
|
||||
if (G_GametypeUsesLives() == true && player->lives == 0)
|
||||
{
|
||||
playerGone = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (playerGone == false && player->deadtimer > TICRATE)
|
||||
{
|
||||
player->playerstate = PST_REBORN;
|
||||
}
|
||||
|
|
@ -4222,9 +4236,6 @@ void P_PlayerThink(player_t *player)
|
|||
ticcmd_t *cmd;
|
||||
const size_t playeri = (size_t)(player - players);
|
||||
|
||||
player->old_drawangle = player->drawangle;
|
||||
player->old_viewrollangle = player->viewrollangle;
|
||||
|
||||
#ifdef PARANOIA
|
||||
if (!player->mo)
|
||||
I_Error("p_playerthink: players[%s].mo == NULL", sizeu1(playeri));
|
||||
|
|
@ -4237,6 +4248,11 @@ void P_PlayerThink(player_t *player)
|
|||
player->playerstate = PST_DEAD;
|
||||
}
|
||||
|
||||
player->old_drawangle = player->drawangle;
|
||||
player->old_viewrollangle = player->viewrollangle;
|
||||
|
||||
player->pflags &= ~PF_HITFINISHLINE;
|
||||
|
||||
if (player->awayviewmobj && P_MobjWasRemoved(player->awayviewmobj))
|
||||
{
|
||||
P_SetTarget(&player->awayviewmobj, NULL); // remove awayviewmobj asap if invalid
|
||||
|
|
|
|||
|
|
@ -311,11 +311,6 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
|
|||
}
|
||||
|
||||
player->skincolor = newcolor = skin->prefcolor;
|
||||
if (player->bot && botingame)
|
||||
{
|
||||
botskin = (UINT8)(skinnum + 1);
|
||||
botcolor = skin->prefcolor;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue