mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
779 lines
19 KiB
C
779 lines
19 KiB
C
// SONIC ROBO BLAST 2 KART
|
|
//-----------------------------------------------------------------------------
|
|
// Copyright (C) 2018-2020 by Sally "TehRealSalt" Cochenour
|
|
// Copyright (C) 2018-2020 by Kart Krew
|
|
//
|
|
// This program is free software distributed under the
|
|
// terms of the GNU General Public License, version 2.
|
|
// See the 'LICENSE' file for more details.
|
|
//-----------------------------------------------------------------------------
|
|
/// \file k_botsearch.c
|
|
/// \brief Bot blockmap search functions
|
|
|
|
#include "doomdef.h"
|
|
#include "d_player.h"
|
|
#include "g_game.h"
|
|
#include "r_main.h"
|
|
#include "p_local.h"
|
|
#include "k_bot.h"
|
|
#include "lua_hook.h"
|
|
#include "byteptr.h"
|
|
#include "d_net.h" // nodetoplayer
|
|
#include "k_kart.h"
|
|
#include "z_zone.h"
|
|
#include "i_system.h"
|
|
#include "p_maputl.h"
|
|
#include "d_ticcmd.h"
|
|
#include "m_random.h"
|
|
#include "r_things.h" // numskins
|
|
#include "p_slopes.h" // P_GetZAt
|
|
|
|
struct globalsmuggle
|
|
{
|
|
mobj_t *botmo;
|
|
botprediction_t *predict;
|
|
fixed_t distancetocheck;
|
|
|
|
INT64 gotoAvgX, gotoAvgY;
|
|
UINT32 gotoObjs;
|
|
|
|
INT64 avoidAvgX, avoidAvgY;
|
|
UINT32 avoidObjs;
|
|
|
|
fixed_t closestlinedist;
|
|
|
|
fixed_t eggboxx, eggboxy;
|
|
UINT8 randomitems;
|
|
UINT8 eggboxes;
|
|
} globalsmuggle;
|
|
|
|
/*--------------------------------------------------
|
|
static boolean K_FindEggboxes(mobj_t *thing)
|
|
|
|
Blockmap search function.
|
|
Increments the random items and egg boxes counters.
|
|
|
|
Input Arguments:-
|
|
thing - Object passed in from iteration.
|
|
|
|
Return:-
|
|
true continues searching, false ends the search early.
|
|
--------------------------------------------------*/
|
|
static boolean K_FindEggboxes(mobj_t *thing)
|
|
{
|
|
fixed_t dist;
|
|
|
|
if (thing->type != MT_RANDOMITEM && thing->type != MT_EGGMANITEM)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (!thing->health)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
dist = P_AproxDistance(thing->x - globalsmuggle.eggboxx, thing->y - globalsmuggle.eggboxy);
|
|
|
|
if (dist > globalsmuggle.distancetocheck)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (thing->type == MT_RANDOMITEM)
|
|
{
|
|
globalsmuggle.randomitems++;
|
|
}
|
|
else
|
|
{
|
|
globalsmuggle.eggboxes++;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
UINT8 K_EggboxStealth(fixed_t x, fixed_t y)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
UINT8 K_EggboxStealth(fixed_t x, fixed_t y)
|
|
{
|
|
INT32 xl, xh, yl, yh, bx, by;
|
|
|
|
globalsmuggle.eggboxx = x;
|
|
globalsmuggle.eggboxy = y;
|
|
globalsmuggle.distancetocheck = (mapobjectscale * 256);
|
|
globalsmuggle.randomitems = 0;
|
|
globalsmuggle.eggboxes = 0;
|
|
|
|
xl = (unsigned)(globalsmuggle.eggboxx - globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
|
|
xh = (unsigned)(globalsmuggle.eggboxx + globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
|
|
yl = (unsigned)(globalsmuggle.eggboxy - globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
|
|
yh = (unsigned)(globalsmuggle.eggboxy + globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
|
|
|
|
BMBOUNDFIX(xl, xh, yl, yh);
|
|
|
|
for (bx = xl; bx <= xh; bx++)
|
|
{
|
|
for (by = yl; by <= yh; by++)
|
|
{
|
|
P_BlockThingsIterator(bx, by, K_FindEggboxes);
|
|
}
|
|
}
|
|
|
|
return (globalsmuggle.randomitems * globalsmuggle.eggboxes);
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static boolean K_BotHatesThisSectorsSpecial(player_t *player, sector_t *sec)
|
|
|
|
Tells us if a bot will play more careful around
|
|
this sector's special type.
|
|
|
|
Input Arguments:-
|
|
player - Player to check against.
|
|
sec - Sector to check the specials of.
|
|
|
|
Return:-
|
|
true if avoiding this sector special, false otherwise.
|
|
--------------------------------------------------*/
|
|
static boolean K_BotHatesThisSectorsSpecial(player_t *player, sector_t *sec)
|
|
{
|
|
switch (GETSECSPECIAL(sec->special, 1))
|
|
{
|
|
case 1: // Damage
|
|
case 5: // Spikes
|
|
case 6: case 7: // Death Pit
|
|
case 8: // Instant Kill
|
|
return true;
|
|
//case 2: case 3: // Offroad (let's let them lawnmower)
|
|
case 4: // Offroad (Strong)
|
|
if (!K_BotCanTakeCut(player))
|
|
{
|
|
return true;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static 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.
|
|
--------------------------------------------------*/
|
|
static 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;
|
|
fixed_t highestfloor = INT32_MAX;
|
|
sector_t *bestsector = NULL;
|
|
ffloor_t *rover;
|
|
|
|
if (flip == true)
|
|
{
|
|
specialflag = SF_FLIPSPECIAL_CEILING;
|
|
highestfloor = P_GetZAt(sec->c_slope, x, y, sec->ceilingheight);
|
|
}
|
|
else
|
|
{
|
|
specialflag = SF_FLIPSPECIAL_FLOOR;
|
|
highestfloor = P_GetZAt(sec->f_slope, x, y, sec->floorheight);
|
|
}
|
|
|
|
if (sec->flags & specialflag)
|
|
{
|
|
bestsector = sec;
|
|
}
|
|
|
|
for (rover = sec->ffloors; rover; rover = rover->next)
|
|
{
|
|
fixed_t top = INT32_MAX;
|
|
fixed_t bottom = INT32_MAX;
|
|
|
|
if (!(rover->flags & FF_EXISTS))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
top = P_GetZAt(*rover->t_slope, x, y, *rover->topheight);
|
|
bottom = P_GetZAt(*rover->b_slope, x, y, *rover->bottomheight);
|
|
|
|
if (!(rover->flags & FF_BLOCKPLAYER))
|
|
{
|
|
if ((top >= player->mo->z) && (bottom <= player->mo->z + player->mo->height)
|
|
&& K_BotHatesThisSectorsSpecial(player, rover->master->frontsector))
|
|
{
|
|
// Bad intangible sector at our height, so we DEFINITELY want to avoid
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if ((rover->flags & FF_BLOCKPLAYER) && !(rover->master->frontsector->flags & specialflag))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Find the highest FOF floor beneath the player, and check it at the end.
|
|
if (flip == true)
|
|
{
|
|
if (bottom < highestfloor
|
|
&& bottom >= player->mo->z + player->mo->height)
|
|
{
|
|
bestsector = rover->master->frontsector;
|
|
highestfloor = bottom;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (top > highestfloor
|
|
&& top <= player->mo->z)
|
|
{
|
|
bestsector = rover->master->frontsector;
|
|
highestfloor = top;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bestsector == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
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->kartstuff[k_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 * 16);
|
|
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 FixedDiv(globalsmuggle.closestlinedist, globalsmuggle.distancetocheck);
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static boolean K_FindObjectsForNudging(mobj_t *thing)
|
|
|
|
Blockmap search function.
|
|
Finds objects around the bot to steer towards/away from.
|
|
|
|
Input Arguments:-
|
|
thing - Object passed in from iteration.
|
|
|
|
Return:-
|
|
true continues searching, false ends the search early.
|
|
--------------------------------------------------*/
|
|
static boolean K_FindObjectsForNudging(mobj_t *thing)
|
|
{
|
|
INT16 anglediff;
|
|
fixed_t fulldist;
|
|
angle_t destangle, angle, predictangle;
|
|
|
|
if (!globalsmuggle.botmo || P_MobjWasRemoved(globalsmuggle.botmo) || !globalsmuggle.botmo->player)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (thing->health <= 0)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (globalsmuggle.botmo == thing)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
fulldist = R_PointToDist2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, thing->x, thing->y);
|
|
|
|
if (fulldist > globalsmuggle.distancetocheck)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (P_CheckSight(globalsmuggle.botmo, thing) == false)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
predictangle = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, globalsmuggle.predict->x, globalsmuggle.predict->y);
|
|
destangle = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, thing->x, thing->y);
|
|
angle = (predictangle - destangle);
|
|
|
|
if (angle < ANGLE_180)
|
|
{
|
|
anglediff = AngleFixed(angle)>>FRACBITS;
|
|
}
|
|
else
|
|
{
|
|
anglediff = 360-(AngleFixed(angle)>>FRACBITS);
|
|
}
|
|
|
|
anglediff = abs(anglediff);
|
|
|
|
#define AddAttackObj(thing) \
|
|
globalsmuggle.gotoAvgX += thing->x / mapobjectscale; \
|
|
globalsmuggle.gotoAvgY += thing->y / mapobjectscale; \
|
|
globalsmuggle.gotoObjs++;
|
|
|
|
#define AddDodgeObj(thing) \
|
|
globalsmuggle.avoidAvgX += thing->x / mapobjectscale; \
|
|
globalsmuggle.avoidAvgY += thing->y / mapobjectscale; \
|
|
globalsmuggle.avoidObjs++;
|
|
|
|
#define PlayerAttackSteer(botcond, thingcond) \
|
|
if ((botcond) && !(thingcond)) \
|
|
{ \
|
|
AddAttackObj(thing) \
|
|
} \
|
|
else if ((thingcond) && !(botcond)) \
|
|
{ \
|
|
AddDodgeObj(thing) \
|
|
}
|
|
|
|
switch (thing->type)
|
|
{
|
|
case MT_BANANA:
|
|
case MT_BANANA_SHIELD:
|
|
case MT_EGGMANITEM_SHIELD:
|
|
case MT_ORBINAUT:
|
|
case MT_ORBINAUT_SHIELD:
|
|
case MT_JAWZ:
|
|
case MT_JAWZ_DUD:
|
|
case MT_JAWZ_SHIELD:
|
|
case MT_SSMINE:
|
|
case MT_SSMINE_SHIELD:
|
|
case MT_LANDMINE:
|
|
case MT_BALLHOG:
|
|
case MT_SPB:
|
|
case MT_BUBBLESHIELDTRAP:
|
|
AddDodgeObj(thing)
|
|
break;
|
|
case MT_RANDOMITEM:
|
|
if (anglediff >= 60)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (P_CanPickupItem(globalsmuggle.botmo->player, 1))
|
|
{
|
|
AddAttackObj(thing)
|
|
}
|
|
break;
|
|
case MT_EGGMANITEM:
|
|
if (anglediff >= 60)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (P_CanPickupItem(globalsmuggle.botmo->player, 1)) // Can pick up an actual item
|
|
{
|
|
const UINT8 stealth = K_EggboxStealth(thing->x, thing->y);
|
|
const UINT8 requiredstealth = (globalsmuggle.botmo->player->botvars.difficulty * globalsmuggle.botmo->player->botvars.difficulty);
|
|
|
|
if (stealth >= requiredstealth)
|
|
{
|
|
AddAttackObj(thing)
|
|
}
|
|
else
|
|
{
|
|
AddDodgeObj(thing)
|
|
}
|
|
}
|
|
break;
|
|
case MT_FLOATINGITEM:
|
|
if (anglediff >= 60)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (P_CanPickupItem(globalsmuggle.botmo->player, 3))
|
|
{
|
|
AddAttackObj(thing)
|
|
}
|
|
break;
|
|
case MT_RING:
|
|
case MT_FLINGRING:
|
|
if (anglediff >= 60)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if ((RINGTOTAL(globalsmuggle.botmo->player) < 20 && !globalsmuggle.botmo->player->kartstuff[k_ringlock]
|
|
&& P_CanPickupItem(globalsmuggle.botmo->player, 0))
|
|
&& !thing->extravalue1
|
|
&& (globalsmuggle.botmo->player->kartstuff[k_itemtype] != KITEM_THUNDERSHIELD))
|
|
{
|
|
AddAttackObj(thing)
|
|
}
|
|
break;
|
|
case MT_PLAYER:
|
|
if (thing->player
|
|
&& !thing->player->kartstuff[k_hyudorotimer]
|
|
&& !globalsmuggle.botmo->player->kartstuff[k_hyudorotimer])
|
|
{
|
|
// There REALLY ought to be a better way to handle this logic, right?!
|
|
// Squishing
|
|
PlayerAttackSteer(
|
|
globalsmuggle.botmo->scale > thing->scale + (mapobjectscale/8),
|
|
thing->scale > globalsmuggle.botmo->scale + (mapobjectscale/8)
|
|
)
|
|
// Invincibility
|
|
else PlayerAttackSteer(
|
|
globalsmuggle.botmo->player->kartstuff[k_invincibilitytimer],
|
|
thing->player->kartstuff[k_invincibilitytimer]
|
|
)
|
|
// Thunder Shield
|
|
else PlayerAttackSteer(
|
|
globalsmuggle.botmo->player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD,
|
|
thing->player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD
|
|
)
|
|
// Bubble Shield
|
|
else PlayerAttackSteer(
|
|
globalsmuggle.botmo->player->kartstuff[k_itemtype] == KITEM_BUBBLESHIELD,
|
|
thing->player->kartstuff[k_itemtype] == KITEM_BUBBLESHIELD
|
|
)
|
|
// Flame Shield
|
|
else PlayerAttackSteer(
|
|
globalsmuggle.botmo->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD,
|
|
thing->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD
|
|
)
|
|
// Has held item shield
|
|
else PlayerAttackSteer(
|
|
(globalsmuggle.botmo->player->kartstuff[k_itemheld] || globalsmuggle.botmo->player->kartstuff[k_eggmanheld]),
|
|
(thing->player->kartstuff[k_itemheld] || thing->player->kartstuff[k_eggmanheld])
|
|
)
|
|
// Ring Sting
|
|
else PlayerAttackSteer(
|
|
thing->player->rings <= 0,
|
|
globalsmuggle.botmo->player->rings <= 0
|
|
)
|
|
else
|
|
{
|
|
// After ALL of that, we can do standard bumping
|
|
fixed_t ourweight = K_GetMobjWeight(globalsmuggle.botmo, thing);
|
|
fixed_t theirweight = K_GetMobjWeight(thing, globalsmuggle.botmo);
|
|
fixed_t weightdiff = 0;
|
|
|
|
if (anglediff >= 90)
|
|
{
|
|
weightdiff = theirweight - ourweight;
|
|
}
|
|
else
|
|
{
|
|
weightdiff = ourweight - theirweight;
|
|
}
|
|
|
|
if (weightdiff > mapobjectscale)
|
|
{
|
|
AddAttackObj(thing)
|
|
}
|
|
else
|
|
{
|
|
AddDodgeObj(thing)
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case MT_BOTHINT:
|
|
if (anglediff >= 60)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (thing->extravalue1 == 0)
|
|
{
|
|
AddDodgeObj(thing)
|
|
}
|
|
{
|
|
AddAttackObj(thing)
|
|
}
|
|
break;
|
|
default:
|
|
if (thing->flags & (MF_SOLID|MF_ENEMY|MF_BOSS|MF_PAIN|MF_MISSILE))
|
|
{
|
|
AddDodgeObj(thing)
|
|
}
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
|
|
{
|
|
INT32 xl, xh, yl, yh, bx, by;
|
|
|
|
fixed_t avgX = 0, avgY = 0;
|
|
fixed_t avgDist = 0;
|
|
|
|
const fixed_t baseNudge = 48 * mapobjectscale;
|
|
fixed_t nudgeDist = 0;
|
|
angle_t nudgeDir = 0;
|
|
|
|
globalsmuggle.botmo = player->mo;
|
|
globalsmuggle.predict = predict;
|
|
|
|
globalsmuggle.distancetocheck = R_PointToDist2(player->mo->x, player->mo->y, predict->x, predict->y);
|
|
|
|
globalsmuggle.gotoAvgX = globalsmuggle.gotoAvgY = 0;
|
|
globalsmuggle.gotoObjs = 0;
|
|
|
|
globalsmuggle.avoidAvgX = globalsmuggle.avoidAvgY = 0;
|
|
globalsmuggle.avoidObjs = 0;
|
|
|
|
xl = (unsigned)(globalsmuggle.botmo->x - globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
|
|
xh = (unsigned)(globalsmuggle.botmo->x + globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
|
|
yl = (unsigned)(globalsmuggle.botmo->y - globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
|
|
yh = (unsigned)(globalsmuggle.botmo->y + globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
|
|
|
|
BMBOUNDFIX(xl, xh, yl, yh);
|
|
|
|
for (bx = xl; bx <= xh; bx++)
|
|
{
|
|
for (by = yl; by <= yh; by++)
|
|
{
|
|
P_BlockThingsIterator(bx, by, K_FindObjectsForNudging);
|
|
}
|
|
}
|
|
|
|
if (globalsmuggle.avoidObjs > 0)
|
|
{
|
|
avgX = (globalsmuggle.avoidAvgX / globalsmuggle.avoidObjs) * mapobjectscale;
|
|
avgY = (globalsmuggle.avoidAvgY / globalsmuggle.avoidObjs) * mapobjectscale;
|
|
|
|
avgDist = R_PointToDist2(
|
|
avgX, avgY,
|
|
predict->x, predict->y
|
|
);
|
|
|
|
// Light-weight characters dodge better
|
|
nudgeDist = ((9 - globalsmuggle.botmo->player->kartweight) + 1) * baseNudge;
|
|
|
|
if (nudgeDist > predict->radius)
|
|
{
|
|
nudgeDist = predict->radius;
|
|
}
|
|
|
|
// Point away
|
|
nudgeDir = R_PointToAngle2(
|
|
avgX, avgY,
|
|
predict->x, predict->y
|
|
);
|
|
|
|
predict->x += FixedMul(nudgeDist, FINECOSINE(nudgeDir >> ANGLETOFINESHIFT));
|
|
predict->y += FixedMul(nudgeDist, FINESINE(nudgeDir >> ANGLETOFINESHIFT));
|
|
}
|
|
|
|
if (globalsmuggle.gotoObjs > 0)
|
|
{
|
|
avgX = (globalsmuggle.gotoAvgX / globalsmuggle.gotoObjs) * mapobjectscale;
|
|
avgY = (globalsmuggle.gotoAvgY / globalsmuggle.gotoObjs) * mapobjectscale;
|
|
|
|
avgDist = R_PointToDist2(
|
|
predict->x, predict->y,
|
|
avgX, avgY
|
|
);
|
|
|
|
// Acceleration characters are more aggressive
|
|
nudgeDist = ((9 - globalsmuggle.botmo->player->kartspeed) + 1) * baseNudge;
|
|
|
|
if (nudgeDist > predict->radius)
|
|
{
|
|
nudgeDist = predict->radius;
|
|
}
|
|
|
|
if (avgDist <= nudgeDist)
|
|
{
|
|
predict->x = avgX;
|
|
predict->y = avgY;
|
|
}
|
|
else
|
|
{
|
|
// Point towards
|
|
nudgeDir = R_PointToAngle2(
|
|
predict->x, predict->y,
|
|
avgX, avgY
|
|
);
|
|
|
|
predict->x += FixedMul(nudgeDist, FINECOSINE(nudgeDir >> ANGLETOFINESHIFT));
|
|
predict->y += FixedMul(nudgeDist, FINESINE(nudgeDir >> ANGLETOFINESHIFT));
|
|
}
|
|
}
|
|
}
|