mirror of
https://github.com/ENSL/NS.git
synced 2025-04-20 16:30:56 +00:00
Improved bot understanding of door triggers and weldables
This commit is contained in:
parent
efcd2cb03a
commit
f8951d672b
19 changed files with 894 additions and 344 deletions
|
@ -32,6 +32,7 @@ static const unsigned char DT_TILECACHE_CLIMBABLE_AREA = 4;
|
|||
static const unsigned char DT_TILECACHE_LADDER_AREA = 5;
|
||||
static const unsigned char DT_TILECACHE_MSTRUCTURE_AREA = 12;
|
||||
static const unsigned char DT_TILECACHE_ASTRUCTURE_AREA = 13;
|
||||
static const unsigned char DT_TILECACHE_WELD_AREA = 15;
|
||||
static const unsigned char DT_TILECACHE_WALKABLE_AREA = 63;
|
||||
static const unsigned short DT_TILECACHE_NULL_IDX = 0xffff;
|
||||
|
||||
|
|
|
@ -35,22 +35,6 @@
|
|||
|
||||
#define SF_GLOBAL_SET 1 // Set global state to initial state on spawn
|
||||
|
||||
class CEnvGlobal : public CPointEntity
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
void KeyValue( KeyValueData *pkvd );
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
|
||||
virtual int Save( CSave &save );
|
||||
virtual int Restore( CRestore &restore );
|
||||
|
||||
static TYPEDESCRIPTION m_SaveData[];
|
||||
|
||||
string_t m_globalstate;
|
||||
int m_triggermode;
|
||||
int m_initialstate;
|
||||
};
|
||||
|
||||
TYPEDESCRIPTION CEnvGlobal::m_SaveData[] =
|
||||
{
|
||||
|
|
|
@ -458,6 +458,22 @@ public:
|
|||
string_t m_globalstate;
|
||||
};
|
||||
|
||||
class CEnvGlobal : public CPointEntity
|
||||
{
|
||||
public:
|
||||
void Spawn(void);
|
||||
void KeyValue(KeyValueData* pkvd);
|
||||
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value);
|
||||
|
||||
virtual int Save(CSave& save);
|
||||
virtual int Restore(CRestore& restore);
|
||||
|
||||
static TYPEDESCRIPTION m_SaveData[];
|
||||
|
||||
string_t m_globalstate;
|
||||
int m_triggermode;
|
||||
int m_initialstate;
|
||||
};
|
||||
|
||||
//
|
||||
// generic Delay entity.
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -39,6 +39,8 @@ constexpr auto LERK_FLYING_NAV_PROFILE = 9;
|
|||
|
||||
constexpr auto GORGE_BUILD_NAV_PROFILE = 10;
|
||||
|
||||
constexpr auto MARINE_WELD_NAV_PROFILE = 11;
|
||||
|
||||
constexpr auto MIN_PATH_RECALC_TIME = 0.33f; // How frequently can a bot recalculate its path? Default to max 3 times per second
|
||||
|
||||
constexpr auto MAX_BOT_STUCK_TIME = 30.0f; // How long a bot can be stuck, unable to move, before giving up and suiciding
|
||||
|
@ -49,52 +51,50 @@ constexpr auto MAX_BOT_STUCK_TIME = 30.0f; // How long a bot can be stuck, unabl
|
|||
// Possible area types. Water, Road, Door and Grass are not used (left-over from Detour library)
|
||||
enum SamplePolyAreas
|
||||
{
|
||||
SAMPLE_POLYAREA_GROUND = 0,
|
||||
SAMPLE_POLYAREA_CROUCH = 1,
|
||||
SAMPLE_POLYAREA_WATER = 2,
|
||||
SAMPLE_POLYAREA_BLOCKED = 3,
|
||||
SAMPLE_POLYAREA_WALLCLIMB = 4,
|
||||
SAMPLE_POLYAREA_LADDER = 5,
|
||||
SAMPLE_POLYAREA_DOOR = 6,
|
||||
SAMPLE_POLYAREA_JUMP = 7,
|
||||
SAMPLE_POLYAREA_HIGHJUMP = 8,
|
||||
SAMPLE_POLYAREA_FALL = 9,
|
||||
SAMPLE_POLYAREA_HIGHFALL = 10,
|
||||
SAMPLE_POLYAREA_PHASEGATE = 11,
|
||||
SAMPLE_POLYAREA_MSTRUCTURE = 12,
|
||||
SAMPLE_POLYAREA_ASTRUCTURE = 13,
|
||||
SAMPLE_POLYAREA_FLY = 14
|
||||
SAMPLE_POLYAREA_GROUND = 0, // Regular ground movement
|
||||
SAMPLE_POLYAREA_CROUCH = 1, // Requires crouched movement
|
||||
SAMPLE_POLYAREA_WATER = 2, // Swimming (NOT USED)
|
||||
SAMPLE_POLYAREA_BLOCKED = 3, // Requires a jump to get over
|
||||
SAMPLE_POLYAREA_WALLCLIMB = 4, // Requires the ability to wall climb (i.e. skulks/fades/lerks only)
|
||||
SAMPLE_POLYAREA_LADDER = 5, // Requires climbing a ladder (ignored by skulks)
|
||||
SAMPLE_POLYAREA_DOOR = 6, // Requires moving through a door (NOT USED)
|
||||
SAMPLE_POLYAREA_JUMP = 7, // Requires a jump to get through
|
||||
SAMPLE_POLYAREA_HIGHJUMP = 8, // Requires jumping from a great height
|
||||
SAMPLE_POLYAREA_FALL = 9, // Requires dropping down from a higher elevation
|
||||
SAMPLE_POLYAREA_HIGHFALL = 10, // Requires a large drop from a high height
|
||||
SAMPLE_POLYAREA_PHASEGATE = 11, // Requires accessing a phase gate (i.e. marines only)
|
||||
SAMPLE_POLYAREA_MSTRUCTURE = 12, // Requires bypassing a marine structure
|
||||
SAMPLE_POLYAREA_ASTRUCTURE = 13, // Requires bypassing an alien structure
|
||||
SAMPLE_POLYAREA_FLY = 14, // Requires the ability to fly (currently lerks only)
|
||||
};
|
||||
|
||||
// Possible movement types. Swim and door are not used
|
||||
enum SamplePolyFlags
|
||||
{
|
||||
SAMPLE_POLYFLAGS_WALK = 1 << 0, // Simple walk to traverse
|
||||
SAMPLE_POLYFLAGS_CROUCH = 1 << 1, // Required crouching to traverse
|
||||
SAMPLE_POLYFLAGS_SWIM = 1 << 2, // Requires swimming to traverse (not used)
|
||||
SAMPLE_POLYFLAGS_BLOCKED = 1 << 3, // Blocked by an obstruction, but can be jumped over
|
||||
SAMPLE_POLYFLAGS_WALLCLIMB = 1 << 4, // Requires climbing a wall to traverse
|
||||
SAMPLE_POLYFLAGS_LADDER = 1 << 5, // Requires climbing a ladder to traverse
|
||||
SAMPLE_POLYFLAGS_DOOR = 1 << 6, // Requires opening a door to traverse (not used)
|
||||
SAMPLE_POLYFLAGS_JUMP = 1 << 7, // Requires a jump to traverse
|
||||
SAMPLE_POLYFLAGS_HIGHJUMP = 1 << 8, // Requires a jump from a high height to traverse
|
||||
SAMPLE_POLYFLAGS_FALL = 1 << 9, // Requires dropping down from a safe height to traverse
|
||||
SAMPLE_POLYFLAGS_HIGHFALL = 1 << 10, // Requires dropping from a high height to traverse
|
||||
SAMPLE_POLYFLAGS_DISABLED = 1 << 11, // Disabled, not usable by anyone
|
||||
SAMPLE_POLYFLAGS_NOONOS = 1 << 12, // This movement is not allowed by onos
|
||||
SAMPLE_POLYFLAGS_PHASEGATE = 1 << 13, // Requires using a phase gate to traverse
|
||||
SAMPLE_POLYFLAGS_MSTRUCTURE = 1 << 14, // Marine Structure in the way, must be destroyed if alien, or impassable if marine
|
||||
SAMPLE_POLYFLAGS_ASTRUCTURE = 1 << 15, // Structure in the way, must be destroyed if marine, or impassable if alien
|
||||
SAMPLE_POLYFLAGS_FLY = 1 << 16, // Structure in the way, must be destroyed if marine, or impassable if alien
|
||||
SAMPLE_POLYFLAGS_ALL = 0xffff // All abilities.
|
||||
SAMPLE_POLYFLAGS_WALK = 1 << 0, // Simple walk to traverse
|
||||
SAMPLE_POLYFLAGS_BLOCKED = 1 << 1, // Blocked by an obstruction, but can be jumped over
|
||||
SAMPLE_POLYFLAGS_WALLCLIMB = 1 << 2, // Requires climbing a wall to traverse
|
||||
SAMPLE_POLYFLAGS_LADDER = 1 << 3, // Requires climbing a ladder to traverse
|
||||
SAMPLE_POLYFLAGS_DOOR = 1 << 4, // Requires opening a door to traverse (not used)
|
||||
SAMPLE_POLYFLAGS_JUMP = 1 << 5, // Requires a jump to traverse
|
||||
SAMPLE_POLYFLAGS_HIGHJUMP = 1 << 6, // Requires a jump from a high height to traverse
|
||||
SAMPLE_POLYFLAGS_FALL = 1 << 7, // Requires dropping down from a safe height to traverse
|
||||
SAMPLE_POLYFLAGS_HIGHFALL = 1 << 8, // Requires dropping from a high height to traverse
|
||||
SAMPLE_POLYFLAGS_DISABLED = 1 << 9, // Disabled, not usable by anyone
|
||||
SAMPLE_POLYFLAGS_NOONOS = 1 << 10, // This movement is not allowed by onos
|
||||
SAMPLE_POLYFLAGS_PHASEGATE = 1 << 11, // Requires using a phase gate to traverse
|
||||
SAMPLE_POLYFLAGS_MSTRUCTURE = 1 << 12, // Marine Structure in the way, must be destroyed if alien, or impassable if marine
|
||||
SAMPLE_POLYFLAGS_ASTRUCTURE = 1 << 13, // Structure in the way, must be destroyed if marine, or impassable if alien
|
||||
SAMPLE_POLYFLAGS_WELD = 1 << 14, // Requires a welder to get through here
|
||||
SAMPLE_POLYFLAGS_ALL = 0xffff // All abilities.
|
||||
};
|
||||
|
||||
// Door type. Not currently used, future feature so bots know how to open a door
|
||||
enum DoorActivationType
|
||||
{
|
||||
DOOR_NONE, // No type
|
||||
DOOR_USE, // Door activated by using it
|
||||
DOOR_TRIGGER,// Door activated by trigger_once or trigger_multiple
|
||||
DOOR_NONE, // No type, cannot be activated (permanently open/shut)
|
||||
DOOR_USE, // Door activated by using it directly
|
||||
DOOR_TRIGGER,// Door activated by touching a trigger_once or trigger_multiple
|
||||
DOOR_BUTTON, // Door activated by pressing a button
|
||||
DOOR_WELD, // Door activated by welding something
|
||||
DOOR_SHOOT // Door activated by being shot
|
||||
|
@ -103,23 +103,22 @@ enum DoorActivationType
|
|||
typedef struct _DOOR_TRIGGER
|
||||
{
|
||||
CBaseEntity* Entity = nullptr;
|
||||
CBaseToggle* ToggleEnt = nullptr;
|
||||
edict_t* Edict = nullptr;
|
||||
DoorActivationType TriggerType = DOOR_NONE;
|
||||
bool bIsActivated = false;
|
||||
} DoorTrigger;
|
||||
|
||||
// Door reference. Not used, but is a future feature to allow bots to track if a door is open or not, and how to open it etc.
|
||||
typedef struct _NAV_DOOR
|
||||
{
|
||||
CBaseEntity* DoorEntity = nullptr;
|
||||
CBaseToggle* DoorEntity = nullptr;
|
||||
edict_t* DoorEdict = nullptr; // Reference to the func_door
|
||||
unsigned int ObstacleRefs[32][8]; // Dynamic obstacle ref. Used to add/remove the obstacle as the door is opened/closed
|
||||
int NumObstacles = 0;
|
||||
DoorTrigger TriggerEnts[8]; // Reference to the trigger edicts (e.g. func_trigger, func_button etc.)
|
||||
int NumTriggers = 0; // How many triggers can activate the door (bot will pick best one)
|
||||
vector<DoorTrigger> TriggerEnts; // Reference to the trigger edicts (e.g. func_trigger, func_button etc.)
|
||||
DoorActivationType ActivationType = DOOR_NONE; // How the door should be opened
|
||||
Vector PositionOne = g_vecZero; // Door's starting position
|
||||
Vector PositionTwo = g_vecZero; // Door's open/close position (depending on if it starts open or not)
|
||||
Vector CurrentPosition = g_vecZero; // Current world position
|
||||
bool bStartOpen = false; // Does the door start open? (PositionOne = open position, not close position)
|
||||
TOGGLE_STATE CurrentState = TS_AT_BOTTOM;
|
||||
float OpenDelay = 0.0f; // How long the door takes to start opening after activation
|
||||
} nav_door;
|
||||
|
||||
|
@ -463,6 +462,8 @@ void ClearBotPath(AvHAIPlayer* pBot);
|
|||
// Clears just the bot's current stuck movement attempt (see PerformUnstuckMove())
|
||||
void ClearBotStuckMovement(AvHAIPlayer* pBot);
|
||||
|
||||
void UTIL_ClearDoorData();
|
||||
|
||||
// Based on the direction the bot wants to move and it's current facing angle, sets the forward and side move, and the directional buttons to make the bot actually move
|
||||
void BotMovementInputs(AvHAIPlayer* pBot);
|
||||
|
||||
|
@ -474,14 +475,15 @@ void OnBotEndLadder(AvHAIPlayer* pBot);
|
|||
// Tracks all doors and their current status
|
||||
void UTIL_PopulateDoors();
|
||||
|
||||
// Mark the door with the matching target name as weldable. Weld-activated doors leave permanent markers on the nav mesh to block movement since they can only be triggered once
|
||||
void UTIL_MarkDoorWeldable(const char* DoorTargetName);
|
||||
|
||||
void UTIL_UpdateWeldableDoors();
|
||||
void UTIL_UpdateWeldableObstacles();
|
||||
void UTIL_UpdateDoors(bool bInitial = false);
|
||||
void UTIL_UpdateDoorTriggers(nav_door* Door);
|
||||
void UTIL_PopulateTriggersForEntity(edict_t* Entity, vector<DoorTrigger>& TriggerList);
|
||||
|
||||
void UTIL_PopulateWeldableObstacles();
|
||||
|
||||
void UTIL_ApplyTempObstaclesToDoor(nav_door* DoorRef, const int Area);
|
||||
|
||||
nav_door* UTIL_GetNavDoorByEdict(const edict_t* DoorEdict);
|
||||
|
||||
Vector UTIL_AdjustPointAwayFromNavWall(const Vector Location, const float MaxDistanceFromWall);
|
||||
|
|
|
@ -1451,6 +1451,18 @@ void StartNewBotFrame(AvHAIPlayer* pBot)
|
|||
|
||||
}
|
||||
|
||||
void DroneThink(AvHAIPlayer* pBot)
|
||||
{
|
||||
AITASK_BotUpdateAndClearTasks(pBot);
|
||||
|
||||
pBot->CurrentTask = &pBot->PrimaryBotTask;
|
||||
|
||||
if (pBot->PrimaryBotTask.TaskType != TASK_NONE)
|
||||
{
|
||||
BotProgressTask(pBot, &pBot->PrimaryBotTask);
|
||||
}
|
||||
}
|
||||
|
||||
void TestNavThink(AvHAIPlayer* pBot)
|
||||
{
|
||||
AITASK_BotUpdateAndClearTasks(pBot);
|
||||
|
@ -1487,4 +1499,10 @@ void TestNavThink(AvHAIPlayer* pBot)
|
|||
AITASK_ClearBotTask(pBot, &pBot->PrimaryBotTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BotSwitchToWeapon(AvHAIPlayer* pBot, AvHAIWeapon NewWeaponSlot)
|
||||
{
|
||||
char* WeaponName = UTIL_WeaponTypeToClassname(NewWeaponSlot);
|
||||
pBot->Player->SwitchWeapon(WeaponName);
|
||||
}
|
|
@ -53,5 +53,8 @@ void UpdateBotChat(AvHAIPlayer* pBot);
|
|||
void StartNewBotFrame(AvHAIPlayer* pBot);
|
||||
|
||||
void TestNavThink(AvHAIPlayer* pBot);
|
||||
void DroneThink(AvHAIPlayer* pBot);
|
||||
|
||||
void BotSwitchToWeapon(AvHAIPlayer* pBot, AvHAIWeapon NewWeaponSlot);
|
||||
|
||||
#endif
|
|
@ -4,6 +4,7 @@
|
|||
#include "AvHAITactical.h"
|
||||
#include "AvHAINavigation.h"
|
||||
#include "AvHAIConfig.h"
|
||||
#include "AvHAIWeaponHelper.h"
|
||||
#include "../AvHGamerules.h"
|
||||
#include "../dlls/client.h"
|
||||
#include <time.h>
|
||||
|
@ -489,8 +490,8 @@ void AIMGR_UpdateAIPlayers()
|
|||
|
||||
float FrameDelta = CurrTime - PrevTime;
|
||||
float ThinkDelta = CurrTime - LastThinkTime;
|
||||
|
||||
for (int bot_index = 0; bot_index < MAX_PLAYERS; bot_index++)
|
||||
|
||||
for (int bot_index = 0; bot_index < gpGlobals->maxClients; bot_index++)
|
||||
{
|
||||
if (!ActiveAIPlayers[bot_index].Player) { continue; } // Slot isn't filled
|
||||
|
||||
|
@ -506,7 +507,14 @@ void AIMGR_UpdateAIPlayers()
|
|||
|
||||
UpdateBotChat(bot);
|
||||
|
||||
TestNavThink(bot);
|
||||
DroneThink(bot);
|
||||
|
||||
AvHAIWeapon DesiredWeapon = (bot->DesiredMoveWeapon != WEAPON_NONE) ? bot->DesiredMoveWeapon : bot->DesiredCombatWeapon;
|
||||
|
||||
if (DesiredWeapon != WEAPON_NONE && GetBotCurrentWeapon(bot) != DesiredWeapon)
|
||||
{
|
||||
BotSwitchToWeapon(bot, DesiredWeapon);
|
||||
}
|
||||
|
||||
BotUpdateDesiredViewRotation(bot);
|
||||
|
||||
|
@ -706,5 +714,6 @@ AvHAIPlayer* AIMGR_GetAIPlayerAtIndex(const int Index)
|
|||
|
||||
void AIMGR_UpdateAIMapData()
|
||||
{
|
||||
UTIL_UpdateTileCache();
|
||||
AITAC_UpdateMapAIData();
|
||||
}
|
|
@ -164,6 +164,35 @@ AvHAIBuildableStructure* AITAC_FindClosestDeployableToLocation(const Vector& Loc
|
|||
return Result;
|
||||
}
|
||||
|
||||
AvHAIDroppedItem* AITAC_FindClosestItemToLocation(const Vector& Location, const AvHAIDeployableItemType ItemType, float MinRadius, float MaxRadius, bool bConsiderPhaseDistance)
|
||||
{
|
||||
AvHAIDroppedItem* Result = NULL;
|
||||
float CurrMinDist = 0.0f;
|
||||
|
||||
float MinDistSq = sqrf(MinRadius);
|
||||
float MaxDistSq = sqrf(MaxRadius);
|
||||
|
||||
bool bUseMinDist = MinDistSq > 0.1f;
|
||||
bool bUseMaxDist = MaxDistSq > 0.1f;
|
||||
|
||||
for (auto& it : MarineDroppedItemMap)
|
||||
{
|
||||
if (!it.second.bIsReachableMarine) { continue; }
|
||||
if (it.second.ItemType != ItemType) { continue; }
|
||||
|
||||
float DistSq = (bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
|
||||
|
||||
if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq) && (!Result || DistSq < CurrMinDist))
|
||||
{
|
||||
Result = &it.second;
|
||||
CurrMinDist = DistSq;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
AvHAIBuildableStructure* AITAC_GetDeployableRefFromEdict(const edict_t* Structure)
|
||||
{
|
||||
if (FNullEnt(Structure)) { return nullptr; }
|
||||
|
@ -551,6 +580,8 @@ void AITAC_UpdateMapAIData()
|
|||
last_item_refresh_time = gpGlobals->time;
|
||||
}
|
||||
|
||||
UTIL_UpdateDoors(false);
|
||||
|
||||
AITAC_RefreshHiveData();
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,8 @@ Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team);
|
|||
|
||||
AvHAIResourceNode* AITAC_GetRandomResourceNode();
|
||||
|
||||
AvHAIDroppedItem* AITAC_FindClosestItemToLocation(const Vector& Location, const AvHAIDeployableItemType ItemType, float MinRadius, float MaxRadius, bool bConsiderPhaseDistance);
|
||||
|
||||
Vector AITAC_GetFloorLocationForHive(const AvHAIHiveDefinition* Hive);
|
||||
|
||||
int AITAC_GetNumHives();
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "../AvHSharedUtil.h"
|
||||
#include "../AvHAlienWeaponConstants.h"
|
||||
#include "../AvHGamerules.h"
|
||||
#include "../AvHWeldable.h"
|
||||
|
||||
void AITASK_ClearAllBotTasks(AvHAIPlayer* pBot)
|
||||
{
|
||||
|
@ -365,7 +366,22 @@ bool AITASK_IsWeldTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
if (!Task) { return false; }
|
||||
if (FNullEnt(Task->TaskTarget)) { return false; }
|
||||
if (Task->TaskTarget == pBot->Edict) { return false; }
|
||||
if (!PlayerHasWeapon(pBot->Player, WEAPON_MARINE_WELDER)) { return false; }
|
||||
if (!PlayerHasWeapon(pBot->Player, WEAPON_MARINE_WELDER))
|
||||
{
|
||||
if (FNullEnt(Task->TaskSecondaryTarget))
|
||||
{
|
||||
AvHAIDroppedItem* NearestWelder = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_WELDER, 0.0f, 0.0f, true);
|
||||
|
||||
if (NearestWelder)
|
||||
{
|
||||
Task->TaskSecondaryTarget = NearestWelder->edict;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsEdictPlayer(Task->TaskTarget))
|
||||
{
|
||||
|
@ -374,10 +390,22 @@ bool AITASK_IsWeldTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!UTIL_IsBuildableStructureStillReachable(pBot, Task->TaskTarget)) { return false; }
|
||||
if (IsEdictStructure(Task->TaskTarget))
|
||||
{
|
||||
if (!UTIL_IsBuildableStructureStillReachable(pBot, Task->TaskTarget)) { return false; }
|
||||
|
||||
return (Task->TaskTarget->v.health < Task->TaskTarget->v.max_health);
|
||||
return (Task->TaskTarget->v.health < Task->TaskTarget->v.max_health);
|
||||
}
|
||||
|
||||
AvHWeldable* WeldableRef = dynamic_cast<AvHWeldable*>(CBaseEntity::Instance(Task->TaskTarget));
|
||||
|
||||
if (WeldableRef)
|
||||
{
|
||||
return !WeldableRef->GetIsWelded();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AITASK_IsAmmoPickupTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||
|
@ -2125,7 +2153,7 @@ void BotProgressTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
}
|
||||
break;
|
||||
case TASK_WELD:
|
||||
MarineProgressWeldTask(pBot, Task);
|
||||
BotProgressWeldTask(pBot, Task);
|
||||
break;
|
||||
case TASK_DEFEND:
|
||||
BotProgressDefendTask(pBot, Task);
|
||||
|
@ -2156,10 +2184,18 @@ void BotProgressTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
}
|
||||
}
|
||||
|
||||
void MarineProgressWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||
void BotProgressWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||
{
|
||||
//float DistFromWeldLocation = vDist2DSq(pBot->Edict->v.origin, Task->TaskTarget->v.origin);
|
||||
|
||||
if (!PlayerHasWeapon(pBot->Player, WEAPON_MARINE_WELDER))
|
||||
{
|
||||
if (!FNullEnt(Task->TaskSecondaryTarget))
|
||||
{
|
||||
MoveTo(pBot, Task->TaskSecondaryTarget->v.origin, MOVESTYLE_NORMAL);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsPlayerInUseRange(pBot->Edict, Task->TaskTarget))
|
||||
{
|
||||
|
@ -2177,42 +2213,17 @@ void MarineProgressWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
}
|
||||
else
|
||||
{
|
||||
MoveTo(pBot, Task->TaskTarget->v.origin, MOVESTYLE_NORMAL);
|
||||
if (IsEdictPlayer(Task->TaskTarget) || IsEdictStructure(Task->TaskTarget))
|
||||
{
|
||||
MoveTo(pBot, Task->TaskTarget->v.origin, MOVESTYLE_NORMAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
MoveTo(pBot, Task->TaskLocation, MOVESTYLE_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
if (vDist2DSq(pBot->Edict->v.origin, Task->TaskTarget->v.origin) > sqrf(UTIL_MetresToGoldSrcUnits(2.0f)))
|
||||
{
|
||||
MoveTo(pBot, Task->TaskTarget->v.origin, MOVESTYLE_NORMAL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!UTIL_PlayerHasLOSToEntity(pBot->Edict, Task->TaskTarget, 9999.0f, false))
|
||||
{
|
||||
BotLookAt(pBot, UTIL_GetCentreOfEntity(Task->TaskTarget));
|
||||
|
||||
Vector WeldLocation = pBot->BotNavInfo.TargetDestination;
|
||||
|
||||
if (vIsZero(WeldLocation) || vDist2DSq(pBot->Edict->v.origin, Task->TaskTarget->v.origin) > sqrf(UTIL_MetresToGoldSrcUnits(1.5f)))
|
||||
{
|
||||
int MoveProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL);
|
||||
WeldLocation = UTIL_GetRandomPointOnNavmeshInDonut(MoveProfile, Task->TaskTarget->v.origin, UTIL_MetresToGoldSrcUnits(1.0f), UTIL_MetresToGoldSrcUnits(1.5f));
|
||||
|
||||
if (vIsZero(WeldLocation))
|
||||
{
|
||||
WeldLocation = Task->TaskTarget->v.origin;
|
||||
}
|
||||
}
|
||||
|
||||
MoveTo(pBot, WeldLocation, MOVESTYLE_NORMAL);
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
MoveTo(pBot, Task->TaskTarget->v.origin, MOVESTYLE_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
void MarineProgressSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||
|
@ -2615,6 +2626,61 @@ char* AITASK_TaskTypeToChar(const BotTaskType TaskType)
|
|||
}
|
||||
}
|
||||
|
||||
void AITASK_SetWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const bool bIsUrgent)
|
||||
{
|
||||
if (FNullEnt(Target) || (Target->v.deadflag != DEAD_NO))
|
||||
{
|
||||
AITASK_ClearBotTask(pBot, Task);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Task->TaskType == TASK_WELD && Task->TaskTarget == Target)
|
||||
{
|
||||
Task->bTaskIsUrgent = bIsUrgent;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PlayerHasWeapon(pBot->Player, WEAPON_MARINE_WELDER))
|
||||
{
|
||||
AvHAIDroppedItem* NearestWelder = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_WELDER, 0.0f, 0.0f, true);
|
||||
|
||||
if (!NearestWelder)
|
||||
{
|
||||
AITASK_ClearBotTask(pBot, Task);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Task->TaskSecondaryTarget = NearestWelder->edict;
|
||||
}
|
||||
}
|
||||
|
||||
Task->TaskTarget = Target;
|
||||
Task->TaskType = TASK_WELD;
|
||||
Task->bTaskIsUrgent = bIsUrgent;
|
||||
|
||||
if (IsEdictPlayer(Target) || IsEdictStructure(Target)) { return; }
|
||||
|
||||
Vector TargetLocation = UTIL_GetButtonFloorLocation(pBot->Edict->v.origin, Task->TaskTarget);
|
||||
|
||||
if (vIsZero(TargetLocation))
|
||||
{
|
||||
TargetLocation = Task->TaskTarget->v.origin;
|
||||
}
|
||||
|
||||
int MoveProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL);
|
||||
|
||||
Vector TaskLocation = FindClosestNavigablePointToDestination(MoveProfile, pBot->Edict->v.origin, TargetLocation, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
|
||||
if (vIsZero(TaskLocation))
|
||||
{
|
||||
AITASK_ClearBotTask(pBot, Task);
|
||||
return;
|
||||
}
|
||||
|
||||
Task->TaskLocation = TaskLocation;
|
||||
}
|
||||
|
||||
void AITASK_SetAttackTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const bool bIsUrgent)
|
||||
{
|
||||
// Don't set the task if the target is invalid, dead or on the same team as the bot (can't picture a situation where you want them to teamkill...)
|
||||
|
|
|
@ -65,6 +65,7 @@ void AITASK_SetReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task,
|
|||
void AITASK_SetReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const AvHAIDeployableStructureType FirstStructureType, bool bIsUrgent);
|
||||
void AITASK_SetSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const Vector WaitLocation, bool bIsUrgent);
|
||||
void AITASK_SetMineStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, bool bIsUrgent);
|
||||
void AITASK_SetWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const bool bIsUrgent);
|
||||
|
||||
void BotProgressTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
||||
|
||||
|
@ -83,7 +84,7 @@ void BotProgressEvolveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
|||
|
||||
void MarineProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
||||
void MarineProgressCapResNodeTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
||||
void MarineProgressWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
||||
void BotProgressWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
||||
|
||||
void MarineProgressSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "../AvHGamerules.h"
|
||||
#include "../AvHAlienWeaponConstants.h"
|
||||
#include "../AvHAlienWeapons.h"
|
||||
#include "../AvHMarineEquipmentConstants.h"
|
||||
#include "../AvHServerUtil.h"
|
||||
|
||||
int BotGetCurrentWeaponClipAmmo(const AvHAIPlayer* pBot)
|
||||
|
@ -985,4 +986,78 @@ float UTIL_GetProjectileVelocityForWeapon(const AvHAIWeapon Weapon)
|
|||
default:
|
||||
return 0.0f; // Hitscan.
|
||||
}
|
||||
}
|
||||
|
||||
char* UTIL_WeaponTypeToClassname(const AvHAIWeapon WeaponType)
|
||||
{
|
||||
switch (WeaponType)
|
||||
{
|
||||
case WEAPON_MARINE_MG:
|
||||
return kwsMachineGun;
|
||||
case WEAPON_MARINE_PISTOL:
|
||||
return kwsPistol;
|
||||
case WEAPON_MARINE_KNIFE:
|
||||
return kwsKnife;
|
||||
case WEAPON_MARINE_SHOTGUN:
|
||||
return kwsShotGun;
|
||||
case WEAPON_MARINE_HMG:
|
||||
return kwsHeavyMachineGun;
|
||||
case WEAPON_MARINE_WELDER:
|
||||
return kwsWelder;
|
||||
case WEAPON_MARINE_MINES:
|
||||
return kwsMine;
|
||||
case WEAPON_MARINE_GRENADE:
|
||||
return kwsGrenade;
|
||||
case WEAPON_MARINE_GL:
|
||||
return kwsGrenadeGun;
|
||||
|
||||
case WEAPON_SKULK_BITE:
|
||||
return kwsBiteGun;
|
||||
case WEAPON_SKULK_PARASITE:
|
||||
return kwsParasiteGun;
|
||||
case WEAPON_SKULK_LEAP:
|
||||
return kwsLeap;
|
||||
case WEAPON_SKULK_XENOCIDE:
|
||||
return kwsDivineWind;
|
||||
|
||||
case WEAPON_GORGE_SPIT:
|
||||
return kwsSpitGun;
|
||||
case WEAPON_GORGE_HEALINGSPRAY:
|
||||
return kwsHealingSpray;
|
||||
case WEAPON_GORGE_BILEBOMB:
|
||||
return kwsBileBombGun;
|
||||
case WEAPON_GORGE_WEB:
|
||||
return kwsWebSpinner;
|
||||
|
||||
case WEAPON_LERK_BITE:
|
||||
return kwsBite2Gun;
|
||||
case WEAPON_LERK_SPORES:
|
||||
return kwsSporeGun;
|
||||
case WEAPON_LERK_UMBRA:
|
||||
return kwsUmbraGun;
|
||||
case WEAPON_LERK_PRIMALSCREAM:
|
||||
return kwsPrimalScream;
|
||||
|
||||
case WEAPON_FADE_SWIPE:
|
||||
return kwsSwipe;
|
||||
case WEAPON_FADE_BLINK:
|
||||
return kwsBlinkGun;
|
||||
case WEAPON_FADE_METABOLIZE:
|
||||
return kwsMetabolize;
|
||||
case WEAPON_FADE_ACIDROCKET:
|
||||
return kwsAcidRocketGun;
|
||||
|
||||
case WEAPON_ONOS_GORE:
|
||||
return kwsClaws;
|
||||
case WEAPON_ONOS_DEVOUR:
|
||||
return kwsDevour;
|
||||
case WEAPON_ONOS_STOMP:
|
||||
return kwsStomp;
|
||||
case WEAPON_ONOS_CHARGE:
|
||||
return kwsCharge;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
|
@ -63,4 +63,6 @@ BotAttackResult PerformAttackLOSCheck(AvHAIPlayer* pBot, const AvHAIWeapon Weapo
|
|||
float UTIL_GetProjectileVelocityForWeapon(const AvHAIWeapon Weapon);
|
||||
bool IsAreaAffectedBySpores(const Vector Location);
|
||||
|
||||
char* UTIL_WeaponTypeToClassname(const AvHAIWeapon WeaponType);
|
||||
|
||||
#endif
|
|
@ -271,8 +271,15 @@ BOOL AvHAlienWeapon::IsUseable(void)
|
|||
float theLatency = 0.0f;
|
||||
#ifdef AVH_CLIENT
|
||||
// : 991 -- added latency-based prediction for the ammount of energy available to the alien
|
||||
//net_status_s current_status;
|
||||
//gEngfuncs.pNetAPI->Status(¤t_status);
|
||||
net_status_s current_status;
|
||||
gEngfuncs.pNetAPI->Status(¤t_status);
|
||||
char TestStruct[256]; // Allocate lots of memory to anticipate Svengine's larger size
|
||||
gEngfuncs.pNetAPI->Status((net_status_s*)&TestStruct);
|
||||
|
||||
memcpy(¤t_status, TestStruct, sizeof(net_status_s)); // Now copy back the original struct size. This only works if Svengine added to the struct rather than changed it completely
|
||||
|
||||
|
||||
theLatency = max(0.0f, current_status.latency);
|
||||
|
||||
int theNumLevels = AvHGetAlienUpgradeLevel(this->m_pPlayer->pev->iuser4, MASK_UPGRADE_5);
|
||||
|
|
|
@ -106,7 +106,12 @@
|
|||
#include "AvHNetworkMessages.h"
|
||||
#include "AvHNexusServer.h"
|
||||
|
||||
#include "AIPlayers/AvHAIPlayerUtil.h"
|
||||
#include "AIPlayers/AvHAIHelper.h"
|
||||
#include "AIPlayers/AvHAIMath.h"
|
||||
#include "AIPlayers/AvHAINavigation.h"
|
||||
#include "AIPlayers/AvHAIPlayerManager.h"
|
||||
#include "AIPlayers/AvHAITask.h"
|
||||
|
||||
extern AvHParticleTemplateListServer gParticleTemplateList;
|
||||
extern CVoiceGameMgr g_VoiceGameMgr;
|
||||
|
@ -1408,6 +1413,41 @@ BOOL AvHGamerules::ClientCommand( CBasePlayer *pPlayer, const char *pcmd )
|
|||
theSuccess = true;
|
||||
}
|
||||
}
|
||||
else if (FStrEq(pcmd, "tracedoor"))
|
||||
{
|
||||
Vector TraceStart = GetPlayerEyePosition(theAvHPlayer->edict()); // origin + pev->view_ofs
|
||||
Vector LookDir = UTIL_GetForwardVector(theAvHPlayer->edict()->v.v_angle); // Converts view angles to normalized unit vector
|
||||
|
||||
Vector TraceEnd = TraceStart + (LookDir * 1000.0f);
|
||||
|
||||
edict_t* TracedEntity = UTIL_TraceEntity(theAvHPlayer->edict(), TraceStart, TraceEnd);
|
||||
|
||||
if (!FNullEnt(TracedEntity))
|
||||
{
|
||||
const nav_door* Door = UTIL_GetNavDoorByEdict(TracedEntity);
|
||||
|
||||
if (Door)
|
||||
{
|
||||
bool bThing = true;
|
||||
}
|
||||
}
|
||||
|
||||
theSuccess = true;
|
||||
}
|
||||
else if (FStrEq(pcmd, "cometome"))
|
||||
{
|
||||
for (int i = 0; i < AIMGR_GetNumAIPlayers(); i++)
|
||||
{
|
||||
AvHAIPlayer* thisBot = AIMGR_GetAIPlayerAtIndex(i);
|
||||
|
||||
if (thisBot)
|
||||
{
|
||||
AITASK_SetMoveTask(thisBot, &thisBot->PrimaryBotTask, theAvHPlayer->pev->origin, true);
|
||||
}
|
||||
}
|
||||
|
||||
theSuccess = true;
|
||||
}
|
||||
else if( FStrEq( pcmd, kcRemoveUpgrade) )
|
||||
{
|
||||
// Allow even with cheats off right now, put this back in for first beta
|
||||
|
|
|
@ -3608,12 +3608,12 @@ void AvHGamerules::Think(void)
|
|||
|
||||
if (avh_botsenabled.value > 0)
|
||||
{
|
||||
AIMGR_UpdateAIPlayers();
|
||||
|
||||
if (this->GetGameStarted())
|
||||
{
|
||||
AIMGR_UpdateAIMapData();
|
||||
}
|
||||
|
||||
AIMGR_UpdateAIPlayers();
|
||||
}
|
||||
|
||||
if(!this->GetGameStarted())
|
||||
|
|
|
@ -101,6 +101,11 @@ bool AvHWeldable::GetWeldOpens() const
|
|||
return this->mWeldOpens;
|
||||
}
|
||||
|
||||
string AvHWeldable::GetTargetOnFinish() const
|
||||
{
|
||||
return this->mTargetOnFinish;
|
||||
}
|
||||
|
||||
void AvHWeldable::KeyValue( KeyValueData* pkvd )
|
||||
{
|
||||
// "Health to destroy once welded (-1 infinite)" : "-1"
|
||||
|
|
|
@ -43,6 +43,8 @@ public:
|
|||
|
||||
bool GetWeldOpens() const;
|
||||
|
||||
string GetTargetOnFinish() const;
|
||||
|
||||
virtual void KeyValue( KeyValueData* pkvd );
|
||||
|
||||
virtual void Killed( entvars_t *pevAttacker, int iGib );
|
||||
|
|
Loading…
Reference in a new issue