nav: fix double jumping when bot gets stuck
bot: restore bot difficulty levels (ref #729) bot: probably fix freezetime accident shooting (ref #729) build: use noexecstack when building library refactor: rework some old code and remove unnecessary things
This commit is contained in:
parent
70a11d6427
commit
95f907434b
26 changed files with 157 additions and 194 deletions
|
|
@ -3053,12 +3053,7 @@ void Bot::frame () {
|
|||
if (m_thinkTimer.time < game.time ()) {
|
||||
m_thinkTimer.time = game.time () + m_thinkTimer.interval;
|
||||
|
||||
if (m_fullThinkTimer.time < game.time ()) {
|
||||
m_fullThinkTimer.time = game.time () + m_fullThinkTimer.interval;
|
||||
|
||||
update ();
|
||||
}
|
||||
upkeep ();
|
||||
update ();
|
||||
}
|
||||
|
||||
if (m_slowFrameTimestamp > game.time ()) {
|
||||
|
|
@ -3182,6 +3177,7 @@ void Bot::update () {
|
|||
else if (!m_botMovement) {
|
||||
resetMovement ();
|
||||
}
|
||||
runMovement ();
|
||||
}
|
||||
|
||||
void Bot::logicDuringFreezetime () {
|
||||
|
|
@ -3199,7 +3195,7 @@ void Bot::logicDuringFreezetime () {
|
|||
|
||||
if (rg.chance (15) && m_jumpTime < game.time ()) {
|
||||
pev->button |= IN_JUMP;
|
||||
m_jumpTime = game.time () + rg (1.0f, 2.0f);
|
||||
m_jumpTime = game.time () + rg (1.0f, 3.0f);
|
||||
}
|
||||
static Array <edict_t *> players {};
|
||||
players.clear ();
|
||||
|
|
@ -3253,7 +3249,7 @@ void Bot::logicDuringFreezetime () {
|
|||
m_needToSendWelcomeChat = false;
|
||||
}
|
||||
}
|
||||
m_changeViewTime = game.time () + rg (1.25f, 2.0f);
|
||||
m_changeViewTime = game.time () + rg (1.25f, 3.0f);
|
||||
}
|
||||
|
||||
void Bot::executeTasks () {
|
||||
|
|
@ -3389,6 +3385,9 @@ void Bot::logic () {
|
|||
m_isUsingGrenade = false;
|
||||
|
||||
executeTasks (); // execute current task
|
||||
setAimDirection (); // choose aim direction
|
||||
updateLookAngles (); // and turn to chosen aim direction
|
||||
doFireWeapons (); // fire the weapons
|
||||
|
||||
// check for reloading
|
||||
if (m_reloadCheckTime <= game.time ()) {
|
||||
|
|
@ -3471,14 +3470,6 @@ void Bot::logic () {
|
|||
m_lastDamageType = -1; // reset damage
|
||||
}
|
||||
|
||||
void Bot::upkeep () {
|
||||
setAimDirection ();
|
||||
doFireWeapons ();
|
||||
|
||||
updateLookAngles ();
|
||||
runMovement ();
|
||||
}
|
||||
|
||||
void Bot::spawned () {
|
||||
if (game.is (GameFlags::CSDM | GameFlags::ZombieMod)) {
|
||||
newRound ();
|
||||
|
|
|
|||
|
|
@ -352,6 +352,7 @@ void BotConfig::loadChatterConfig () {
|
|||
{ "Chatter_Camp", Chatter::Camping, 10.0f },
|
||||
{ "Chatter_OnARoll", Chatter::OnARoll, kMaxChatterRepeatInterval},
|
||||
};
|
||||
Array <String> badFiles {};
|
||||
|
||||
while (file.getLine (line)) {
|
||||
line.trim ();
|
||||
|
|
@ -393,7 +394,7 @@ void BotConfig::loadChatterConfig () {
|
|||
m_chatter[event.code].emplace (cr::move (sound), event.repeat, duration);
|
||||
}
|
||||
else {
|
||||
game.print ("Warning: Couldn't get duration of sound '%s.wav.", sound);
|
||||
badFiles.push (sound);
|
||||
}
|
||||
}
|
||||
sentences.clear ();
|
||||
|
|
@ -402,6 +403,10 @@ void BotConfig::loadChatterConfig () {
|
|||
}
|
||||
}
|
||||
file.close ();
|
||||
|
||||
if (!badFiles.empty ()) {
|
||||
game.print ("Warning: Couldn't get duration of next chatter sounds: %s.", String::join (badFiles, ","));
|
||||
}
|
||||
}
|
||||
else {
|
||||
cv_radio_mode.set (1);
|
||||
|
|
|
|||
|
|
@ -1742,7 +1742,7 @@ int BotControl::menuAutoPathDistance (int item) {
|
|||
return BotCommandResult::Handled;
|
||||
}
|
||||
|
||||
int BotControl::menuKickPage1 (int item) {
|
||||
int BotControl::menuKickPage (int page, int item) {
|
||||
closeMenu (); // reset menu display
|
||||
|
||||
switch (item) {
|
||||
|
|
@ -1754,93 +1754,21 @@ int BotControl::menuKickPage1 (int item) {
|
|||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
bots.kickBot (item - 1);
|
||||
kickBotByMenu (1);
|
||||
bots.kickBot (item + (page - 1) * 8 - 1);
|
||||
kickBotByMenu (page);
|
||||
break;
|
||||
|
||||
case 9:
|
||||
kickBotByMenu (2);
|
||||
kickBotByMenu (page + 1);
|
||||
break;
|
||||
|
||||
case 10:
|
||||
showMenu (Menu::Control);
|
||||
break;
|
||||
}
|
||||
return BotCommandResult::Handled;
|
||||
}
|
||||
|
||||
int BotControl::menuKickPage2 (int item) {
|
||||
closeMenu (); // reset menu display
|
||||
|
||||
switch (item) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
bots.kickBot (item + 8 - 1);
|
||||
kickBotByMenu (2);
|
||||
break;
|
||||
|
||||
case 9:
|
||||
kickBotByMenu (3);
|
||||
break;
|
||||
|
||||
case 10:
|
||||
kickBotByMenu (1);
|
||||
break;
|
||||
}
|
||||
return BotCommandResult::Handled;
|
||||
}
|
||||
|
||||
int BotControl::menuKickPage3 (int item) {
|
||||
closeMenu (); // reset menu display
|
||||
|
||||
switch (item) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
bots.kickBot (item + 16 - 1);
|
||||
kickBotByMenu (3);
|
||||
break;
|
||||
|
||||
case 9:
|
||||
kickBotByMenu (4);
|
||||
break;
|
||||
|
||||
case 10:
|
||||
kickBotByMenu (2);
|
||||
break;
|
||||
}
|
||||
return BotCommandResult::Handled;
|
||||
}
|
||||
|
||||
int BotControl::menuKickPage4 (int item) {
|
||||
closeMenu (); // reset menu display
|
||||
|
||||
switch (item) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
bots.kickBot (item + 24 - 1);
|
||||
kickBotByMenu (4);
|
||||
break;
|
||||
|
||||
case 10:
|
||||
kickBotByMenu (3);
|
||||
if (page == 1) {
|
||||
showMenu (Menu::Control);
|
||||
}
|
||||
else {
|
||||
kickBotByMenu (page - 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return BotCommandResult::Handled;
|
||||
|
|
@ -2229,7 +2157,7 @@ BotControl::BotControl () {
|
|||
m_cmds.emplace ("kill/killbots/killall/kill_ct/kill_t", "kill [team] [silent]", "Kills the specified team / all the bots.", &BotControl::cmdKillBots);
|
||||
m_cmds.emplace ("fill/fillserver", "fill [team] [count] [difficulty] [personality]", "Fill the server (add bots) with specified parameters.", &BotControl::cmdFill);
|
||||
m_cmds.emplace ("vote/votemap", "vote [map_id]", "Forces all the bot to vote to specified map.", &BotControl::cmdVote);
|
||||
m_cmds.emplace ("weapons/weaponmode", "weapons [knife|pistol|shotgun|smg|rifle|sniper|standard]", "Sets the bots weapon mode to use", &BotControl::cmdWeaponMode);
|
||||
m_cmds.emplace ("weapons/weaponmode", "weapons [knife|pistol|shotgun|smg|rifle|sniper|standard]", "Sets the bots weapon mode to use.", &BotControl::cmdWeaponMode);
|
||||
m_cmds.emplace ("menu/botmenu", "menu [cmd]", "Opens the main bot menu, or command menu if specified.", &BotControl::cmdMenu);
|
||||
m_cmds.emplace ("version/ver/about", "version [no arguments]", "Displays version information about bot build.", &BotControl::cmdVersion);
|
||||
m_cmds.emplace ("graphmenu/wpmenu/wptmenu", "graphmenu [noarguments]", "Opens and displays bots graph editor.", &BotControl::cmdNodeMenu);
|
||||
|
|
|
|||
|
|
@ -338,7 +338,7 @@ Vector Game::getEntityOrigin (edict_t *ent) {
|
|||
}
|
||||
|
||||
if (ent->v.origin.empty ()) {
|
||||
return ent->v.absmin + (ent->v.size * 0.5);
|
||||
return ent->v.absmin + ent->v.size * 0.5;
|
||||
}
|
||||
return ent->v.origin;
|
||||
}
|
||||
|
|
@ -935,7 +935,12 @@ bool Game::loadCSBinary () {
|
|||
}
|
||||
|
||||
if (entity != nullptr) {
|
||||
m_gameFlags |= (GameFlags::Modern | GameFlags::HasBotVoice | GameFlags::HasFakePings);
|
||||
m_gameFlags |= (GameFlags::Modern | GameFlags::HasBotVoice);
|
||||
|
||||
// no fake pings on xash3d
|
||||
if (!(m_gameFlags & (GameFlags::Xash3D | GameFlags::Xash3DLegacy))) {
|
||||
m_gameFlags |= GameFlags::HasFakePings;
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_gameFlags |= GameFlags::Legacy;
|
||||
|
|
|
|||
|
|
@ -40,8 +40,6 @@ void BotFakePingManager::reset (edict_t *to) {
|
|||
}
|
||||
|
||||
void BotFakePingManager::syncCalculate () {
|
||||
MutexScopedLock lock (m_cs);
|
||||
|
||||
int averagePing {};
|
||||
|
||||
if (cv_ping_count_real_players) {
|
||||
|
|
|
|||
|
|
@ -576,7 +576,7 @@ IntArray BotGraph::getNearestInRadius (const float radius, const Vector &origin,
|
|||
|
||||
if (bucket.length () < kMaxNodeLinks || radius > cr::sqrf (256.0f)) {
|
||||
for (const auto &path : m_paths) {
|
||||
if (maxCount != -1 && static_cast <int> (result.length ()) > maxCount) {
|
||||
if (maxCount != -1 && result.length <int32_t> () > maxCount) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -588,7 +588,7 @@ IntArray BotGraph::getNearestInRadius (const float radius, const Vector &origin,
|
|||
}
|
||||
|
||||
for (const auto &at : bucket) {
|
||||
if (maxCount != -1 && static_cast <int> (result.length ()) > maxCount) {
|
||||
if (maxCount != -1 && result.length <int32_t> () > maxCount) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1292,6 +1292,7 @@ void BotGraph::showFileInfo () {
|
|||
msg (" uncompressed_size: %dkB", info.uncompressed / 1024);
|
||||
msg (" options: %d", info.options); // display as string ?
|
||||
msg (" analyzed: %s", isAnalyzed () ? conf.translate ("yes") : conf.translate ("no")); // display as string ?
|
||||
msg (" pathfinder: %s", planner.isPathsCheckFailed () ? "floyd" : "astar");
|
||||
|
||||
msg ("");
|
||||
|
||||
|
|
|
|||
|
|
@ -1023,15 +1023,15 @@ CR_EXPORT int Meta_Detach (PLUG_LOADTIME now, PL_UNLOAD_REASON reason) {
|
|||
gpMetaUtilFuncs->pfnLogError (PLID, "%s: plugin NOT detaching (can't unload plugin right now)", Plugin_info.name);
|
||||
return HLFalse; // returning FALSE prevents metamod from unloading this plugin
|
||||
}
|
||||
// stop the worker
|
||||
worker.shutdown ();
|
||||
|
||||
// kick all bots off this server
|
||||
bots.kickEveryone (true);
|
||||
|
||||
// save collected practice on shutdown
|
||||
practice.save ();
|
||||
|
||||
// stop the worker
|
||||
worker.shutdown ();
|
||||
|
||||
// disable hooks
|
||||
fakequeries.disable ();
|
||||
|
||||
|
|
|
|||
|
|
@ -348,6 +348,10 @@ void BotManager::maintainQuota () {
|
|||
// this function keeps number of bots up to date, and don't allow to maintain bot creation
|
||||
// while creation process in process.
|
||||
|
||||
if (!m_holdQuotaManagementTimer.elapsed ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (graph.length () < 1 || graph.hasChanged ()) {
|
||||
if (cv_quota.as <int> () > 0) {
|
||||
ctrl.msg ("There is no graph found. Cannot create bot.");
|
||||
|
|
@ -707,8 +711,8 @@ void BotManager::kickBot (int index) {
|
|||
auto bot = findBotByIndex (index);
|
||||
|
||||
if (bot) {
|
||||
decrementQuota ();
|
||||
bot->kick ();
|
||||
decrementQuota ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -855,10 +859,15 @@ void BotManager::checkBotModel (edict_t *ent, char *infobuffer) {
|
|||
}
|
||||
|
||||
void BotManager::checkNeedsToBeKicked () {
|
||||
// this is called to check if bot is leaving server due to pathfinding error
|
||||
// so this will cause to delay quota management stuff from executing for some time
|
||||
|
||||
for (const auto &bot : bots) {
|
||||
if (bot->m_kickMeFromServer) {
|
||||
m_holdQuotaManagementTimer.start (10.0f);
|
||||
m_addRequests.clear ();
|
||||
|
||||
bot->kick (); // kick bot from server if requested
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1118,6 +1127,8 @@ void BotManager::balanceBotDifficulties () {
|
|||
void BotManager::destroy () {
|
||||
// this function free all bots slots (used on server shutdown)
|
||||
|
||||
m_holdQuotaManagementTimer.invalidate (); // restart quota manager
|
||||
|
||||
for (auto &bot : m_bots) {
|
||||
bot->markStale ();
|
||||
}
|
||||
|
|
@ -1739,15 +1750,12 @@ void Bot::newRound () {
|
|||
thinkInterval = 1.0f / 50.0f; // xash3d works acceptable at 50fps
|
||||
}
|
||||
}
|
||||
auto fullThinkInterval = 1.0f / (thinkFps * 0.5f);
|
||||
|
||||
// legacy games behaves strange, when this enabled, disable for xash3d as well if requested
|
||||
if (bots.isFrameSkipDisabled ()) {
|
||||
thinkInterval = 0.0f;
|
||||
fullThinkInterval = 0.0f;
|
||||
}
|
||||
m_thinkTimer.interval = thinkInterval;
|
||||
m_fullThinkTimer.interval = fullThinkInterval;
|
||||
}
|
||||
|
||||
void Bot::resetPathSearchType () {
|
||||
|
|
@ -1804,10 +1812,6 @@ void Bot::kick (bool silent) {
|
|||
}
|
||||
|
||||
void Bot::markStale () {
|
||||
// wait till threads tear down
|
||||
MutexScopedLock lock1 (m_pathFindLock);
|
||||
MutexScopedLock lock2 (m_predictLock);
|
||||
|
||||
// switch chatter icon off
|
||||
showChatterIcon (false, true);
|
||||
|
||||
|
|
@ -1817,6 +1821,10 @@ void Bot::markStale () {
|
|||
// mark bot as leaving
|
||||
m_isStale = true;
|
||||
|
||||
// wait till threads tear down
|
||||
MutexScopedLock lock1 (m_pathFindLock);
|
||||
MutexScopedLock lock2 (m_predictLock);
|
||||
|
||||
// clear the bot name
|
||||
conf.clearUsedName (this);
|
||||
|
||||
|
|
@ -2397,7 +2405,7 @@ bool BotManager::isLineBlockedBySmoke (const Vector &from, const Vector &to) {
|
|||
const float maxSmokedLength = 0.7f * kSmokeGrenadeRadius;
|
||||
|
||||
// return true if the total length of smoke-covered line-of-sight is too much
|
||||
return (totalSmokedLength > maxSmokedLength);
|
||||
return totalSmokedLength > maxSmokedLength;
|
||||
}
|
||||
|
||||
bool BotManager::isFrameSkipDisabled () {
|
||||
|
|
|
|||
|
|
@ -552,7 +552,7 @@ void Bot::doPlayerAvoidance (const Vector &normal) {
|
|||
|
||||
if (graph.exists (destIndex)) {
|
||||
findPath (m_currentNodeIndex, destIndex, other->m_pathType);
|
||||
other->findPath (m_currentNodeIndex, destIndex);
|
||||
other->findPath (m_currentNodeIndex, destIndex, m_pathType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -646,13 +646,6 @@ void Bot::checkTerrain (const Vector &dirNormal) {
|
|||
}
|
||||
}
|
||||
|
||||
if (m_probeTime >= game.time ()) {
|
||||
m_isStuck = true;
|
||||
}
|
||||
else if (m_probeTime + randomProbeTime < game.time () && !cr::fzero (m_probeTime)) {
|
||||
resetCollision (); // resets its collision state because it was too long time in probing state
|
||||
}
|
||||
|
||||
// not stuck?
|
||||
if (!m_isStuck) {
|
||||
if (m_probeTime + randomProbeTime < game.time ()) {
|
||||
|
|
@ -914,6 +907,15 @@ void Bot::checkFall () {
|
|||
return;
|
||||
}
|
||||
|
||||
// take in account node sequences levels to compensate surface inclining
|
||||
if (m_previousNodes[0] != kInvalidNodeIndex) {
|
||||
const auto &pn = graph[m_previousNodes[0]];
|
||||
|
||||
if (cr::abs (pn.origin.z - m_pathOrigin.z) < cv_graph_analyze_max_jump_height.as <float> ()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_checkFall) {
|
||||
if (isOnFloor ()) {
|
||||
m_checkFallPoint[0] = pev->origin;
|
||||
|
|
@ -948,6 +950,7 @@ void Bot::checkFall () {
|
|||
&& (nowDistanceSq > baseDistanceSq * 1.2f || nowDistanceSq > baseDistanceSq + 200.0f)
|
||||
&& baseDistanceSq >= cr::sqrf (80.0f) && nowDistanceSq >= cr::sqrf (100.0f)) {
|
||||
fixFall = true;
|
||||
|
||||
}
|
||||
else if (m_checkFallPoint[1].z > pev->origin.z + 128.0f
|
||||
&& m_checkFallPoint[0].z > pev->origin.z + 128.0f) {
|
||||
|
|
@ -1988,7 +1991,7 @@ float Bot::getEstimatedNodeReachTime () {
|
|||
}
|
||||
estimatedTime = cr::clamp (estimatedTime, 3.0f, longTermReachability ? 8.0f : 3.5f);
|
||||
}
|
||||
return estimatedTime;
|
||||
return estimatedTime += m_lastDamageTimestamp >= game.time () ? 1.0f : 0.0f;
|
||||
}
|
||||
|
||||
void Bot::findValidNode () {
|
||||
|
|
@ -3148,10 +3151,7 @@ bool Bot::checkWallOnLeft (float distance) {
|
|||
game.testLine (pev->origin, pev->origin - pev->angles.right () * distance, TraceIgnore::Monsters, ent (), &tr);
|
||||
|
||||
// check if the trace hit something...
|
||||
if (tr.flFraction < 1.0f) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return tr.flFraction < 1.0f;
|
||||
}
|
||||
|
||||
bool Bot::checkWallOnRight (float distance) {
|
||||
|
|
@ -3161,10 +3161,7 @@ bool Bot::checkWallOnRight (float distance) {
|
|||
game.testLine (pev->origin, pev->origin + pev->angles.right () * distance, TraceIgnore::Monsters, ent (), &tr);
|
||||
|
||||
// check if the trace hit something...
|
||||
if (tr.flFraction < 1.0f) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return tr.flFraction < 1.0f;
|
||||
}
|
||||
|
||||
bool Bot::checkWallOnBehind (float distance) {
|
||||
|
|
@ -3174,10 +3171,7 @@ bool Bot::checkWallOnBehind (float distance) {
|
|||
game.testLine (pev->origin, pev->origin - pev->angles.forward () * distance, TraceIgnore::Monsters, ent (), &tr);
|
||||
|
||||
// check if the trace hit something...
|
||||
if (tr.flFraction < 1.0f) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return tr.flFraction < 1.0f;
|
||||
}
|
||||
|
||||
bool Bot::isDeadlyMove (const Vector &to) {
|
||||
|
|
@ -3448,6 +3442,10 @@ bool Bot::isPreviousLadder () const {
|
|||
void Bot::findShortestPath (int srcIndex, int destIndex) {
|
||||
// this function finds the shortest path from source index to destination index
|
||||
|
||||
// stale bots shouldn't do pathfinding
|
||||
if (m_isStale) {
|
||||
return;
|
||||
}
|
||||
clearSearchNodes ();
|
||||
|
||||
m_chosenGoalIndex = srcIndex;
|
||||
|
|
@ -3472,6 +3470,11 @@ void Bot::syncFindPath (int srcIndex, int destIndex, FindPath pathType) {
|
|||
}
|
||||
ScopedUnlock <Mutex> unlock (m_pathFindLock);
|
||||
|
||||
// stale bots shouldn't do pathfinding
|
||||
if (m_isStale) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!graph.exists (srcIndex)) {
|
||||
srcIndex = changeNodeIndex (graph.getNearestNoBuckets (pev->origin, 256.0f));
|
||||
|
||||
|
|
|
|||
|
|
@ -274,6 +274,11 @@ AStarResult AStarAlgo::find (int botTeam, int srcIndex, int destIndex, NodeAdder
|
|||
|
||||
// safes us from bad graph...
|
||||
if (m_routeQue.length () >= getMaxLength () - 1) {
|
||||
m_routeQue.clear ();
|
||||
|
||||
// infrom pathfinder to use floyds in that case
|
||||
planner.setPathsCheckFailed (true);
|
||||
|
||||
return AStarResult::InternalError;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ void BotPractice::setIndex (int32_t team, int32_t start, int32_t goal, int32_t v
|
|||
if (team != Team::Terrorist && team != Team::CT) {
|
||||
return;
|
||||
}
|
||||
MutexScopedLock lock (m_damageUpdateLock);
|
||||
|
||||
// reliability check
|
||||
if (!graph.exists (start) || !graph.exists (goal) || !graph.exists (value)) {
|
||||
|
|
@ -38,7 +37,6 @@ void BotPractice::setValue (int32_t team, int32_t start, int32_t goal, int32_t v
|
|||
if (team != Team::Terrorist && team != Team::CT) {
|
||||
return;
|
||||
}
|
||||
MutexScopedLock lock (m_damageUpdateLock);
|
||||
|
||||
// reliability check
|
||||
if (!graph.exists (start) || !graph.exists (goal)) {
|
||||
|
|
@ -58,7 +56,6 @@ void BotPractice::setDamage (int32_t team, int32_t start, int32_t goal, int32_t
|
|||
if (team != Team::Terrorist && team != Team::CT) {
|
||||
return;
|
||||
}
|
||||
MutexScopedLock lock (m_damageUpdateLock);
|
||||
|
||||
// reliability check
|
||||
if (!graph.exists (start) || !graph.exists (goal)) {
|
||||
|
|
@ -72,6 +69,7 @@ float BotPractice::plannerGetDamage (int32_t team, int32_t start, int32_t goal,
|
|||
return 0.0f;
|
||||
}
|
||||
ScopedUnlock <Mutex> unlock (m_damageUpdateLock);
|
||||
|
||||
auto damage = static_cast <float> (getDamage (team, start, goal));
|
||||
|
||||
if (addTeamHighestDamage) {
|
||||
|
|
@ -97,6 +95,8 @@ void BotPractice::syncUpdate () {
|
|||
}
|
||||
auto adjustValues = false;
|
||||
|
||||
MutexScopedLock lock (m_damageUpdateLock);
|
||||
|
||||
// get the most dangerous node for this position for both teams
|
||||
for (int team = Team::Terrorist; team < kGameTeamNum; ++team) {
|
||||
auto bestIndex = kInvalidNodeIndex; // best index to store
|
||||
|
|
@ -142,7 +142,6 @@ void BotPractice::syncUpdate () {
|
|||
}
|
||||
}
|
||||
}
|
||||
MutexScopedLock lock (m_damageUpdateLock);
|
||||
|
||||
for (int team = Team::Terrorist; team < kGameTeamNum; ++team) {
|
||||
m_teamHighestDamage[team] = cr::clamp (m_teamHighestDamage[team] - kHalfDamageVal, 1, kFullDamageVal);
|
||||
|
|
|
|||
|
|
@ -329,46 +329,37 @@ void BotSupport::checkWelcome () {
|
|||
}
|
||||
}
|
||||
|
||||
bool BotSupport::findNearestPlayer (void **pvHolder, edict_t *to, float searchDistance, bool sameTeam, bool needBot, bool needAlive, bool needDrawn, bool needBotWithC4) {
|
||||
bool BotSupport::findNearestPlayer (void **pvHolder, edict_t *to, float searchDistance, bool sameTeam, bool needBot,
|
||||
bool needAlive, bool needDrawn, bool needBotWithC4) {
|
||||
|
||||
// this function finds nearest to to, player with set of parameters, like his
|
||||
// team, live status, search distance etc. if needBot is true, then pvHolder, will
|
||||
// be filled with bot pointer, else with edict pointer(!).
|
||||
|
||||
searchDistance = cr::sqrf (searchDistance);
|
||||
|
||||
edict_t *survive = nullptr; // pointer to temporally & survive entity
|
||||
float nearestPlayer = 4096.0f; // nearest player
|
||||
|
||||
const int toTeam = game.getTeam (to);
|
||||
float nearestPlayerDistanceSq = cr::sqrf (4096.0f); // nearest player
|
||||
|
||||
for (const auto &client : m_clients) {
|
||||
if (!(client.flags & ClientFlags::Used) || client.ent == to) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((sameTeam && client.team != toTeam) || (needAlive && !(client.flags & ClientFlags::Alive)) || (needBot && !bots[client.ent]) || (needDrawn && (client.ent->v.effects & EF_NODRAW)) || (needBotWithC4 && (client.ent->v.weapons & Weapon::C4))) {
|
||||
if ((sameTeam && client.team != game.getTeam (to))
|
||||
|| (needAlive && !(client.flags & ClientFlags::Alive))
|
||||
|| (needBot && !bots[client.ent])
|
||||
|| (needDrawn && (client.ent->v.effects & EF_NODRAW))
|
||||
|| (needBotWithC4 && (client.ent->v.weapons & Weapon::C4))) {
|
||||
|
||||
continue; // filter players with parameters
|
||||
}
|
||||
const float distanceSq = client.ent->v.origin.distanceSq (to->v.origin);
|
||||
|
||||
if (distanceSq < nearestPlayer && distanceSq < searchDistance) {
|
||||
nearestPlayer = distanceSq;
|
||||
survive = client.ent;
|
||||
if (distanceSq < nearestPlayerDistanceSq && distanceSq < searchDistance) {
|
||||
nearestPlayerDistanceSq = distanceSq;
|
||||
*pvHolder = needBot ? reinterpret_cast <void *> (bots[client.ent]) : reinterpret_cast <void *> (client.ent);
|
||||
}
|
||||
}
|
||||
|
||||
if (game.isNullEntity (survive)) {
|
||||
return false; // nothing found
|
||||
}
|
||||
|
||||
// fill the holder
|
||||
if (needBot) {
|
||||
*pvHolder = reinterpret_cast <void *> (bots[survive]);
|
||||
}
|
||||
else {
|
||||
*pvHolder = reinterpret_cast <void *> (survive);
|
||||
}
|
||||
return true;
|
||||
return !!*pvHolder;
|
||||
}
|
||||
|
||||
void BotSupport::updateClients () {
|
||||
|
|
|
|||
|
|
@ -425,15 +425,24 @@ void Bot::setAimDirection () {
|
|||
if (!(flags & (AimFlags::Grenade | AimFlags::Enemy | AimFlags::Entity))) {
|
||||
|
||||
// check if narrow place and we're duck, do not predict enemies in that situation
|
||||
const bool duckedInNarrowPlace = isInNarrowPlace () && ((m_pathFlags & NodeFlag::Crouch) || (pev->button & IN_DUCK));
|
||||
const bool duckedInNarrowPlace = isInNarrowPlace ()
|
||||
&& ((m_pathFlags & NodeFlag::Crouch)
|
||||
|| (pev->button & IN_DUCK));
|
||||
|
||||
if (duckedInNarrowPlace
|
||||
|| isOnLadder ()
|
||||
|| isInWater ()
|
||||
|| (m_pathFlags & NodeFlag::Ladder)
|
||||
|| (m_currentTravelFlags & PathFlag::Jump)) {
|
||||
|
||||
if (duckedInNarrowPlace || isOnLadder () || isInWater () || (m_pathFlags & NodeFlag::Ladder) || (m_currentTravelFlags & PathFlag::Jump)) {
|
||||
flags &= ~(AimFlags::LastEnemy | AimFlags::PredictPath);
|
||||
m_canChooseAimDirection = false;
|
||||
}
|
||||
|
||||
// don't switch view right away after loosing focus with current enemy
|
||||
if ((m_shootTime + rg (1.0f, 1.5f) > game.time () || m_seeEnemyTime + 1.5f > game.time ())
|
||||
if ((m_shootTime + rg (0.75f, 1.25f) > game.time ()
|
||||
|| m_seeEnemyTime + 1.5f > game.time ())
|
||||
|
||||
&& m_forgetLastVictimTimer.elapsed ()
|
||||
&& !m_lastEnemyOrigin.empty ()
|
||||
&& util.isAlive (m_lastEnemy)
|
||||
|
|
@ -619,7 +628,10 @@ void Bot::setAimDirection () {
|
|||
if (horizontalMovement && m_pathWalk.hasNext ()) {
|
||||
const auto &nextPath = graph[m_pathWalk.next ()];
|
||||
|
||||
if ((nextPath.flags & NodeFlag::Ladder) && m_destOrigin.distanceSq (pev->origin) < cr::sqrf (128.0f) && nextPath.origin.z > m_pathOrigin.z + 26.0f) {
|
||||
if ((nextPath.flags & NodeFlag::Ladder)
|
||||
&& m_destOrigin.distanceSq (pev->origin) < cr::sqrf (128.0f)
|
||||
&& nextPath.origin.z > m_pathOrigin.z + 26.0f) {
|
||||
|
||||
m_lookAt = nextPath.origin + pev->view_ofs;
|
||||
}
|
||||
}
|
||||
|
|
@ -630,7 +642,10 @@ void Bot::setAimDirection () {
|
|||
}
|
||||
|
||||
// try to look at last victim for a little, maybe there's some one else
|
||||
if (game.isNullEntity (m_enemy) && m_difficulty >= Difficulty::Normal && !m_forgetLastVictimTimer.elapsed () && !m_lastVictimOrigin.empty ()) {
|
||||
if (game.isNullEntity (m_enemy) && m_difficulty >= Difficulty::Normal
|
||||
&& !m_forgetLastVictimTimer.elapsed ()
|
||||
&& !m_lastVictimOrigin.empty ()) {
|
||||
|
||||
m_lookAt = m_lastVictimOrigin + pev->view_ofs;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue