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
|
|
@ -1637,10 +1637,10 @@ Forces all the bot to vote to specified map.
|
||||||
强制所有人机投票给指定地图。
|
强制所有人机投票给指定地图。
|
||||||
|
|
||||||
[ORIGINAL]
|
[ORIGINAL]
|
||||||
Sets the bots weapon mode to use
|
Sets the bots weapon mode to use.
|
||||||
|
|
||||||
[TRANSLATED]
|
[TRANSLATED]
|
||||||
设置人机的武器模式
|
设置人机的武器模式。
|
||||||
|
|
||||||
[ORIGINAL]
|
[ORIGINAL]
|
||||||
Opens the main bot menu, or command menu if specified.
|
Opens the main bot menu, or command menu if specified.
|
||||||
|
|
|
||||||
|
|
@ -1400,10 +1400,10 @@ Forces all the bot to vote to specified map.
|
||||||
Zwingt alle Bots, für die angegebene Karte zu stimmen.
|
Zwingt alle Bots, für die angegebene Karte zu stimmen.
|
||||||
|
|
||||||
[ORIGINAL]
|
[ORIGINAL]
|
||||||
Sets the bots weapon mode to use
|
Sets the bots weapon mode to use.
|
||||||
|
|
||||||
[TRANSLATED]
|
[TRANSLATED]
|
||||||
Legt den zu verwendenden Waffenmodus des Bots fest
|
Legt den zu verwendenden Waffenmodus des Bots fest.
|
||||||
|
|
||||||
[ORIGINAL]
|
[ORIGINAL]
|
||||||
Opens the main bot menu, or command menu if specified.
|
Opens the main bot menu, or command menu if specified.
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
hoop
|
hoop
|
||||||
-|NoS|-
|
-|NoS|-
|
||||||
Chrono
|
|
||||||
bobjones
|
bobjones
|
||||||
dawgz
|
dawgz
|
||||||
The BiG SMUT
|
The BiG SMUT
|
||||||
|
|
|
||||||
|
|
@ -1636,10 +1636,10 @@ Forces all the bot to vote to specified map.
|
||||||
Принуждает всех ботов голосовать за указанную карту.
|
Принуждает всех ботов голосовать за указанную карту.
|
||||||
|
|
||||||
[ORIGINAL]
|
[ORIGINAL]
|
||||||
Sets the bots weapon mode to use
|
Sets the bots weapon mode to use.
|
||||||
|
|
||||||
[TRANSLATED]
|
[TRANSLATED]
|
||||||
Настроить режим используемого ботами оружия
|
Настроить режим используемого ботами оружия.
|
||||||
|
|
||||||
[ORIGINAL]
|
[ORIGINAL]
|
||||||
Opens the main bot menu, or command menu if specified.
|
Opens the main bot menu, or command menu if specified.
|
||||||
|
|
|
||||||
|
|
@ -157,10 +157,23 @@ private:
|
||||||
int menuGraphPath (int item);
|
int menuGraphPath (int item);
|
||||||
int menuCampDirections (int item);
|
int menuCampDirections (int item);
|
||||||
int menuAutoPathDistance (int item);
|
int menuAutoPathDistance (int item);
|
||||||
int menuKickPage1 (int item);
|
|
||||||
int menuKickPage2 (int item);
|
int menuKickPage1 (int item) {
|
||||||
int menuKickPage3 (int item);
|
return menuKickPage (1, item);
|
||||||
int menuKickPage4 (int item);
|
}
|
||||||
|
|
||||||
|
int menuKickPage2 (int item) {
|
||||||
|
return menuKickPage (2, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
int menuKickPage3 (int item) {
|
||||||
|
return menuKickPage (3, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
int menuKickPage4 (int item) {
|
||||||
|
return menuKickPage (4, item);
|
||||||
|
}
|
||||||
|
int menuKickPage (int page, int item);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createMenus ();
|
void createMenus ();
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,6 @@ public:
|
||||||
|
|
||||||
// bot fakeping manager
|
// bot fakeping manager
|
||||||
class BotFakePingManager final : public Singleton <BotFakePingManager> {
|
class BotFakePingManager final : public Singleton <BotFakePingManager> {
|
||||||
private:
|
|
||||||
mutable Mutex m_cs {};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CountdownTimer m_recalcTime {};
|
CountdownTimer m_recalcTime {};
|
||||||
PingBitMsg m_pbm {};
|
PingBitMsg m_pbm {};
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,8 @@ private:
|
||||||
edict_t *m_killerEntity {}; // killer entity for bots
|
edict_t *m_killerEntity {}; // killer entity for bots
|
||||||
BotTeamData m_teamData[kGameTeamNum] {}; // teams shared data
|
BotTeamData m_teamData[kGameTeamNum] {}; // teams shared data
|
||||||
|
|
||||||
|
CountdownTimer m_holdQuotaManagementTimer {}; // prevent from running quota management for some time
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BotCreateResult create (StringRef name, int difficulty, int personality, int team, int skin);
|
BotCreateResult create (StringRef name, int difficulty, int personality, int team, int skin);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -275,6 +275,10 @@ public:
|
||||||
return m_pathsCheckFailed;
|
return m_pathsCheckFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setPathsCheckFailed (const bool value) {
|
||||||
|
m_pathsCheckFailed = value;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// do the pathfinding
|
// do the pathfinding
|
||||||
bool find (int srcIndex, int destIndex, NodeAdderFn onAddedNode, int *pathDistance = nullptr);
|
bool find (int srcIndex, int destIndex, NodeAdderFn onAddedNode, int *pathDistance = nullptr);
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,6 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void setHighestDamageForTeam (int32_t team, int32_t value) {
|
void setHighestDamageForTeam (int32_t team, int32_t value) {
|
||||||
MutexScopedLock lock (m_damageUpdateLock);
|
|
||||||
m_teamHighestDamage[team] = value;
|
m_teamHighestDamage[team] = value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ public:
|
||||||
~Folders () = default;
|
~Folders () = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CTS_BUILD_STR bot { "yapb" };
|
CTS_BUILD_STR bot { product.nameLower };
|
||||||
CTS_BUILD_STR addons { "addons" };
|
CTS_BUILD_STR addons { "addons" };
|
||||||
CTS_BUILD_STR config { "conf" };
|
CTS_BUILD_STR config { "conf" };
|
||||||
CTS_BUILD_STR data { "data" };
|
CTS_BUILD_STR data { "data" };
|
||||||
|
|
|
||||||
|
|
@ -730,7 +730,6 @@ public:
|
||||||
Array <int32_t> m_goalHist {};
|
Array <int32_t> m_goalHist {};
|
||||||
|
|
||||||
FrameDelay m_thinkTimer {};
|
FrameDelay m_thinkTimer {};
|
||||||
FrameDelay m_fullThinkTimer {};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Bot (edict_t *bot, int difficulty, int personality, int team, int skin);
|
Bot (edict_t *bot, int difficulty, int personality, int team, int skin);
|
||||||
|
|
@ -738,7 +737,6 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void logic (); /// the things that can be executed while skipping frames
|
void logic (); /// the things that can be executed while skipping frames
|
||||||
void upkeep ();
|
|
||||||
void spawned ();
|
void spawned ();
|
||||||
void takeBlind (int alpha);
|
void takeBlind (int alpha);
|
||||||
void takeDamage (edict_t *inflictor, int damage, int armor, int bits);
|
void takeDamage (edict_t *inflictor, int damage, int armor, int bits);
|
||||||
|
|
|
||||||
|
|
@ -149,12 +149,14 @@ if cxx == 'clang' or cxx == 'gcc'
|
||||||
'-fdata-sections',
|
'-fdata-sections',
|
||||||
'-ffunction-sections',
|
'-ffunction-sections',
|
||||||
'-fcf-protection=none',
|
'-fcf-protection=none',
|
||||||
'-fno-plt'
|
'-fno-plt',
|
||||||
|
'-Wa,--noexecstack'
|
||||||
]
|
]
|
||||||
|
|
||||||
ldflags += [
|
ldflags += [
|
||||||
'-Wl,--version-script=' + meson.project_source_root() + '/ext/ldscripts/version.lds',
|
'-Wl,--version-script=' + meson.project_source_root() + '/ext/ldscripts/version.lds',
|
||||||
'-Wl,--gc-sections'
|
'-Wl,--gc-sections',
|
||||||
|
'-Wl,-z,noexecstack'
|
||||||
]
|
]
|
||||||
else
|
else
|
||||||
cxxflags += ['-DLINKENT_STATIC']
|
cxxflags += ['-DLINKENT_STATIC']
|
||||||
|
|
@ -177,7 +179,7 @@ if cxx == 'clang' or cxx == 'gcc'
|
||||||
]
|
]
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
cxxflags += ['-g3', '-ggdb', '-DDEBUG', '-D_FORTIFY_SOURCE=2']
|
cxxflags += ['-g3', '-ggdb', '-DDEBUG']
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# special script for mingw-64 builds
|
# special script for mingw-64 builds
|
||||||
|
|
|
||||||
|
|
@ -3053,13 +3053,8 @@ void Bot::frame () {
|
||||||
if (m_thinkTimer.time < game.time ()) {
|
if (m_thinkTimer.time < game.time ()) {
|
||||||
m_thinkTimer.time = game.time () + m_thinkTimer.interval;
|
m_thinkTimer.time = game.time () + m_thinkTimer.interval;
|
||||||
|
|
||||||
if (m_fullThinkTimer.time < game.time ()) {
|
|
||||||
m_fullThinkTimer.time = game.time () + m_fullThinkTimer.interval;
|
|
||||||
|
|
||||||
update ();
|
update ();
|
||||||
}
|
}
|
||||||
upkeep ();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_slowFrameTimestamp > game.time ()) {
|
if (m_slowFrameTimestamp > game.time ()) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -3182,6 +3177,7 @@ void Bot::update () {
|
||||||
else if (!m_botMovement) {
|
else if (!m_botMovement) {
|
||||||
resetMovement ();
|
resetMovement ();
|
||||||
}
|
}
|
||||||
|
runMovement ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::logicDuringFreezetime () {
|
void Bot::logicDuringFreezetime () {
|
||||||
|
|
@ -3199,7 +3195,7 @@ void Bot::logicDuringFreezetime () {
|
||||||
|
|
||||||
if (rg.chance (15) && m_jumpTime < game.time ()) {
|
if (rg.chance (15) && m_jumpTime < game.time ()) {
|
||||||
pev->button |= IN_JUMP;
|
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 {};
|
static Array <edict_t *> players {};
|
||||||
players.clear ();
|
players.clear ();
|
||||||
|
|
@ -3253,7 +3249,7 @@ void Bot::logicDuringFreezetime () {
|
||||||
m_needToSendWelcomeChat = false;
|
m_needToSendWelcomeChat = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_changeViewTime = game.time () + rg (1.25f, 2.0f);
|
m_changeViewTime = game.time () + rg (1.25f, 3.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::executeTasks () {
|
void Bot::executeTasks () {
|
||||||
|
|
@ -3389,6 +3385,9 @@ void Bot::logic () {
|
||||||
m_isUsingGrenade = false;
|
m_isUsingGrenade = false;
|
||||||
|
|
||||||
executeTasks (); // execute current task
|
executeTasks (); // execute current task
|
||||||
|
setAimDirection (); // choose aim direction
|
||||||
|
updateLookAngles (); // and turn to chosen aim direction
|
||||||
|
doFireWeapons (); // fire the weapons
|
||||||
|
|
||||||
// check for reloading
|
// check for reloading
|
||||||
if (m_reloadCheckTime <= game.time ()) {
|
if (m_reloadCheckTime <= game.time ()) {
|
||||||
|
|
@ -3471,14 +3470,6 @@ void Bot::logic () {
|
||||||
m_lastDamageType = -1; // reset damage
|
m_lastDamageType = -1; // reset damage
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::upkeep () {
|
|
||||||
setAimDirection ();
|
|
||||||
doFireWeapons ();
|
|
||||||
|
|
||||||
updateLookAngles ();
|
|
||||||
runMovement ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Bot::spawned () {
|
void Bot::spawned () {
|
||||||
if (game.is (GameFlags::CSDM | GameFlags::ZombieMod)) {
|
if (game.is (GameFlags::CSDM | GameFlags::ZombieMod)) {
|
||||||
newRound ();
|
newRound ();
|
||||||
|
|
|
||||||
|
|
@ -352,6 +352,7 @@ void BotConfig::loadChatterConfig () {
|
||||||
{ "Chatter_Camp", Chatter::Camping, 10.0f },
|
{ "Chatter_Camp", Chatter::Camping, 10.0f },
|
||||||
{ "Chatter_OnARoll", Chatter::OnARoll, kMaxChatterRepeatInterval},
|
{ "Chatter_OnARoll", Chatter::OnARoll, kMaxChatterRepeatInterval},
|
||||||
};
|
};
|
||||||
|
Array <String> badFiles {};
|
||||||
|
|
||||||
while (file.getLine (line)) {
|
while (file.getLine (line)) {
|
||||||
line.trim ();
|
line.trim ();
|
||||||
|
|
@ -393,7 +394,7 @@ void BotConfig::loadChatterConfig () {
|
||||||
m_chatter[event.code].emplace (cr::move (sound), event.repeat, duration);
|
m_chatter[event.code].emplace (cr::move (sound), event.repeat, duration);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
game.print ("Warning: Couldn't get duration of sound '%s.wav.", sound);
|
badFiles.push (sound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sentences.clear ();
|
sentences.clear ();
|
||||||
|
|
@ -402,6 +403,10 @@ void BotConfig::loadChatterConfig () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file.close ();
|
file.close ();
|
||||||
|
|
||||||
|
if (!badFiles.empty ()) {
|
||||||
|
game.print ("Warning: Couldn't get duration of next chatter sounds: %s.", String::join (badFiles, ","));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cv_radio_mode.set (1);
|
cv_radio_mode.set (1);
|
||||||
|
|
|
||||||
|
|
@ -1742,7 +1742,7 @@ int BotControl::menuAutoPathDistance (int item) {
|
||||||
return BotCommandResult::Handled;
|
return BotCommandResult::Handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
int BotControl::menuKickPage1 (int item) {
|
int BotControl::menuKickPage (int page, int item) {
|
||||||
closeMenu (); // reset menu display
|
closeMenu (); // reset menu display
|
||||||
|
|
||||||
switch (item) {
|
switch (item) {
|
||||||
|
|
@ -1754,93 +1754,21 @@ int BotControl::menuKickPage1 (int item) {
|
||||||
case 6:
|
case 6:
|
||||||
case 7:
|
case 7:
|
||||||
case 8:
|
case 8:
|
||||||
bots.kickBot (item - 1);
|
bots.kickBot (item + (page - 1) * 8 - 1);
|
||||||
kickBotByMenu (1);
|
kickBotByMenu (page);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 9:
|
case 9:
|
||||||
kickBotByMenu (2);
|
kickBotByMenu (page + 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 10:
|
case 10:
|
||||||
|
if (page == 1) {
|
||||||
showMenu (Menu::Control);
|
showMenu (Menu::Control);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return BotCommandResult::Handled;
|
else {
|
||||||
|
kickBotByMenu (page - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return BotCommandResult::Handled;
|
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 ("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 ("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 ("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 ("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 ("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);
|
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 ()) {
|
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;
|
return ent->v.origin;
|
||||||
}
|
}
|
||||||
|
|
@ -935,7 +935,12 @@ bool Game::loadCSBinary () {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entity != nullptr) {
|
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 {
|
else {
|
||||||
m_gameFlags |= GameFlags::Legacy;
|
m_gameFlags |= GameFlags::Legacy;
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,6 @@ void BotFakePingManager::reset (edict_t *to) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotFakePingManager::syncCalculate () {
|
void BotFakePingManager::syncCalculate () {
|
||||||
MutexScopedLock lock (m_cs);
|
|
||||||
|
|
||||||
int averagePing {};
|
int averagePing {};
|
||||||
|
|
||||||
if (cv_ping_count_real_players) {
|
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)) {
|
if (bucket.length () < kMaxNodeLinks || radius > cr::sqrf (256.0f)) {
|
||||||
for (const auto &path : m_paths) {
|
for (const auto &path : m_paths) {
|
||||||
if (maxCount != -1 && static_cast <int> (result.length ()) > maxCount) {
|
if (maxCount != -1 && result.length <int32_t> () > maxCount) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -588,7 +588,7 @@ IntArray BotGraph::getNearestInRadius (const float radius, const Vector &origin,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &at : bucket) {
|
for (const auto &at : bucket) {
|
||||||
if (maxCount != -1 && static_cast <int> (result.length ()) > maxCount) {
|
if (maxCount != -1 && result.length <int32_t> () > maxCount) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1292,6 +1292,7 @@ void BotGraph::showFileInfo () {
|
||||||
msg (" uncompressed_size: %dkB", info.uncompressed / 1024);
|
msg (" uncompressed_size: %dkB", info.uncompressed / 1024);
|
||||||
msg (" options: %d", info.options); // display as string ?
|
msg (" options: %d", info.options); // display as string ?
|
||||||
msg (" analyzed: %s", isAnalyzed () ? conf.translate ("yes") : conf.translate ("no")); // display as string ?
|
msg (" analyzed: %s", isAnalyzed () ? conf.translate ("yes") : conf.translate ("no")); // display as string ?
|
||||||
|
msg (" pathfinder: %s", planner.isPathsCheckFailed () ? "floyd" : "astar");
|
||||||
|
|
||||||
msg ("");
|
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);
|
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
|
return HLFalse; // returning FALSE prevents metamod from unloading this plugin
|
||||||
}
|
}
|
||||||
|
// stop the worker
|
||||||
|
worker.shutdown ();
|
||||||
|
|
||||||
// kick all bots off this server
|
// kick all bots off this server
|
||||||
bots.kickEveryone (true);
|
bots.kickEveryone (true);
|
||||||
|
|
||||||
// save collected practice on shutdown
|
// save collected practice on shutdown
|
||||||
practice.save ();
|
practice.save ();
|
||||||
|
|
||||||
// stop the worker
|
|
||||||
worker.shutdown ();
|
|
||||||
|
|
||||||
// disable hooks
|
// disable hooks
|
||||||
fakequeries.disable ();
|
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
|
// this function keeps number of bots up to date, and don't allow to maintain bot creation
|
||||||
// while creation process in process.
|
// while creation process in process.
|
||||||
|
|
||||||
|
if (!m_holdQuotaManagementTimer.elapsed ()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (graph.length () < 1 || graph.hasChanged ()) {
|
if (graph.length () < 1 || graph.hasChanged ()) {
|
||||||
if (cv_quota.as <int> () > 0) {
|
if (cv_quota.as <int> () > 0) {
|
||||||
ctrl.msg ("There is no graph found. Cannot create bot.");
|
ctrl.msg ("There is no graph found. Cannot create bot.");
|
||||||
|
|
@ -707,8 +711,8 @@ void BotManager::kickBot (int index) {
|
||||||
auto bot = findBotByIndex (index);
|
auto bot = findBotByIndex (index);
|
||||||
|
|
||||||
if (bot) {
|
if (bot) {
|
||||||
decrementQuota ();
|
|
||||||
bot->kick ();
|
bot->kick ();
|
||||||
|
decrementQuota ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -855,10 +859,15 @@ void BotManager::checkBotModel (edict_t *ent, char *infobuffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotManager::checkNeedsToBeKicked () {
|
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) {
|
for (const auto &bot : bots) {
|
||||||
if (bot->m_kickMeFromServer) {
|
if (bot->m_kickMeFromServer) {
|
||||||
|
m_holdQuotaManagementTimer.start (10.0f);
|
||||||
|
m_addRequests.clear ();
|
||||||
|
|
||||||
bot->kick (); // kick bot from server if requested
|
bot->kick (); // kick bot from server if requested
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1118,6 +1127,8 @@ void BotManager::balanceBotDifficulties () {
|
||||||
void BotManager::destroy () {
|
void BotManager::destroy () {
|
||||||
// this function free all bots slots (used on server shutdown)
|
// this function free all bots slots (used on server shutdown)
|
||||||
|
|
||||||
|
m_holdQuotaManagementTimer.invalidate (); // restart quota manager
|
||||||
|
|
||||||
for (auto &bot : m_bots) {
|
for (auto &bot : m_bots) {
|
||||||
bot->markStale ();
|
bot->markStale ();
|
||||||
}
|
}
|
||||||
|
|
@ -1739,15 +1750,12 @@ void Bot::newRound () {
|
||||||
thinkInterval = 1.0f / 50.0f; // xash3d works acceptable at 50fps
|
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
|
// legacy games behaves strange, when this enabled, disable for xash3d as well if requested
|
||||||
if (bots.isFrameSkipDisabled ()) {
|
if (bots.isFrameSkipDisabled ()) {
|
||||||
thinkInterval = 0.0f;
|
thinkInterval = 0.0f;
|
||||||
fullThinkInterval = 0.0f;
|
|
||||||
}
|
}
|
||||||
m_thinkTimer.interval = thinkInterval;
|
m_thinkTimer.interval = thinkInterval;
|
||||||
m_fullThinkTimer.interval = fullThinkInterval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::resetPathSearchType () {
|
void Bot::resetPathSearchType () {
|
||||||
|
|
@ -1804,10 +1812,6 @@ void Bot::kick (bool silent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::markStale () {
|
void Bot::markStale () {
|
||||||
// wait till threads tear down
|
|
||||||
MutexScopedLock lock1 (m_pathFindLock);
|
|
||||||
MutexScopedLock lock2 (m_predictLock);
|
|
||||||
|
|
||||||
// switch chatter icon off
|
// switch chatter icon off
|
||||||
showChatterIcon (false, true);
|
showChatterIcon (false, true);
|
||||||
|
|
||||||
|
|
@ -1817,6 +1821,10 @@ void Bot::markStale () {
|
||||||
// mark bot as leaving
|
// mark bot as leaving
|
||||||
m_isStale = true;
|
m_isStale = true;
|
||||||
|
|
||||||
|
// wait till threads tear down
|
||||||
|
MutexScopedLock lock1 (m_pathFindLock);
|
||||||
|
MutexScopedLock lock2 (m_predictLock);
|
||||||
|
|
||||||
// clear the bot name
|
// clear the bot name
|
||||||
conf.clearUsedName (this);
|
conf.clearUsedName (this);
|
||||||
|
|
||||||
|
|
@ -2397,7 +2405,7 @@ bool BotManager::isLineBlockedBySmoke (const Vector &from, const Vector &to) {
|
||||||
const float maxSmokedLength = 0.7f * kSmokeGrenadeRadius;
|
const float maxSmokedLength = 0.7f * kSmokeGrenadeRadius;
|
||||||
|
|
||||||
// return true if the total length of smoke-covered line-of-sight is too much
|
// return true if the total length of smoke-covered line-of-sight is too much
|
||||||
return (totalSmokedLength > maxSmokedLength);
|
return totalSmokedLength > maxSmokedLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BotManager::isFrameSkipDisabled () {
|
bool BotManager::isFrameSkipDisabled () {
|
||||||
|
|
|
||||||
|
|
@ -552,7 +552,7 @@ void Bot::doPlayerAvoidance (const Vector &normal) {
|
||||||
|
|
||||||
if (graph.exists (destIndex)) {
|
if (graph.exists (destIndex)) {
|
||||||
findPath (m_currentNodeIndex, destIndex, other->m_pathType);
|
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?
|
// not stuck?
|
||||||
if (!m_isStuck) {
|
if (!m_isStuck) {
|
||||||
if (m_probeTime + randomProbeTime < game.time ()) {
|
if (m_probeTime + randomProbeTime < game.time ()) {
|
||||||
|
|
@ -914,6 +907,15 @@ void Bot::checkFall () {
|
||||||
return;
|
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 (!m_checkFall) {
|
||||||
if (isOnFloor ()) {
|
if (isOnFloor ()) {
|
||||||
m_checkFallPoint[0] = pev->origin;
|
m_checkFallPoint[0] = pev->origin;
|
||||||
|
|
@ -948,6 +950,7 @@ void Bot::checkFall () {
|
||||||
&& (nowDistanceSq > baseDistanceSq * 1.2f || nowDistanceSq > baseDistanceSq + 200.0f)
|
&& (nowDistanceSq > baseDistanceSq * 1.2f || nowDistanceSq > baseDistanceSq + 200.0f)
|
||||||
&& baseDistanceSq >= cr::sqrf (80.0f) && nowDistanceSq >= cr::sqrf (100.0f)) {
|
&& baseDistanceSq >= cr::sqrf (80.0f) && nowDistanceSq >= cr::sqrf (100.0f)) {
|
||||||
fixFall = true;
|
fixFall = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (m_checkFallPoint[1].z > pev->origin.z + 128.0f
|
else if (m_checkFallPoint[1].z > pev->origin.z + 128.0f
|
||||||
&& m_checkFallPoint[0].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);
|
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 () {
|
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);
|
game.testLine (pev->origin, pev->origin - pev->angles.right () * distance, TraceIgnore::Monsters, ent (), &tr);
|
||||||
|
|
||||||
// check if the trace hit something...
|
// check if the trace hit something...
|
||||||
if (tr.flFraction < 1.0f) {
|
return tr.flFraction < 1.0f;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::checkWallOnRight (float distance) {
|
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);
|
game.testLine (pev->origin, pev->origin + pev->angles.right () * distance, TraceIgnore::Monsters, ent (), &tr);
|
||||||
|
|
||||||
// check if the trace hit something...
|
// check if the trace hit something...
|
||||||
if (tr.flFraction < 1.0f) {
|
return tr.flFraction < 1.0f;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::checkWallOnBehind (float distance) {
|
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);
|
game.testLine (pev->origin, pev->origin - pev->angles.forward () * distance, TraceIgnore::Monsters, ent (), &tr);
|
||||||
|
|
||||||
// check if the trace hit something...
|
// check if the trace hit something...
|
||||||
if (tr.flFraction < 1.0f) {
|
return tr.flFraction < 1.0f;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::isDeadlyMove (const Vector &to) {
|
bool Bot::isDeadlyMove (const Vector &to) {
|
||||||
|
|
@ -3448,6 +3442,10 @@ bool Bot::isPreviousLadder () const {
|
||||||
void Bot::findShortestPath (int srcIndex, int destIndex) {
|
void Bot::findShortestPath (int srcIndex, int destIndex) {
|
||||||
// this function finds the shortest path from source index to destination index
|
// this function finds the shortest path from source index to destination index
|
||||||
|
|
||||||
|
// stale bots shouldn't do pathfinding
|
||||||
|
if (m_isStale) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
clearSearchNodes ();
|
clearSearchNodes ();
|
||||||
|
|
||||||
m_chosenGoalIndex = srcIndex;
|
m_chosenGoalIndex = srcIndex;
|
||||||
|
|
@ -3472,6 +3470,11 @@ void Bot::syncFindPath (int srcIndex, int destIndex, FindPath pathType) {
|
||||||
}
|
}
|
||||||
ScopedUnlock <Mutex> unlock (m_pathFindLock);
|
ScopedUnlock <Mutex> unlock (m_pathFindLock);
|
||||||
|
|
||||||
|
// stale bots shouldn't do pathfinding
|
||||||
|
if (m_isStale) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!graph.exists (srcIndex)) {
|
if (!graph.exists (srcIndex)) {
|
||||||
srcIndex = changeNodeIndex (graph.getNearestNoBuckets (pev->origin, 256.0f));
|
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...
|
// safes us from bad graph...
|
||||||
if (m_routeQue.length () >= getMaxLength () - 1) {
|
if (m_routeQue.length () >= getMaxLength () - 1) {
|
||||||
|
m_routeQue.clear ();
|
||||||
|
|
||||||
|
// infrom pathfinder to use floyds in that case
|
||||||
|
planner.setPathsCheckFailed (true);
|
||||||
|
|
||||||
return AStarResult::InternalError;
|
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) {
|
if (team != Team::Terrorist && team != Team::CT) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MutexScopedLock lock (m_damageUpdateLock);
|
|
||||||
|
|
||||||
// reliability check
|
// reliability check
|
||||||
if (!graph.exists (start) || !graph.exists (goal) || !graph.exists (value)) {
|
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) {
|
if (team != Team::Terrorist && team != Team::CT) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MutexScopedLock lock (m_damageUpdateLock);
|
|
||||||
|
|
||||||
// reliability check
|
// reliability check
|
||||||
if (!graph.exists (start) || !graph.exists (goal)) {
|
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) {
|
if (team != Team::Terrorist && team != Team::CT) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MutexScopedLock lock (m_damageUpdateLock);
|
|
||||||
|
|
||||||
// reliability check
|
// reliability check
|
||||||
if (!graph.exists (start) || !graph.exists (goal)) {
|
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;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
ScopedUnlock <Mutex> unlock (m_damageUpdateLock);
|
ScopedUnlock <Mutex> unlock (m_damageUpdateLock);
|
||||||
|
|
||||||
auto damage = static_cast <float> (getDamage (team, start, goal));
|
auto damage = static_cast <float> (getDamage (team, start, goal));
|
||||||
|
|
||||||
if (addTeamHighestDamage) {
|
if (addTeamHighestDamage) {
|
||||||
|
|
@ -97,6 +95,8 @@ void BotPractice::syncUpdate () {
|
||||||
}
|
}
|
||||||
auto adjustValues = false;
|
auto adjustValues = false;
|
||||||
|
|
||||||
|
MutexScopedLock lock (m_damageUpdateLock);
|
||||||
|
|
||||||
// get the most dangerous node for this position for both teams
|
// get the most dangerous node for this position for both teams
|
||||||
for (int team = Team::Terrorist; team < kGameTeamNum; ++team) {
|
for (int team = Team::Terrorist; team < kGameTeamNum; ++team) {
|
||||||
auto bestIndex = kInvalidNodeIndex; // best index to store
|
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) {
|
for (int team = Team::Terrorist; team < kGameTeamNum; ++team) {
|
||||||
m_teamHighestDamage[team] = cr::clamp (m_teamHighestDamage[team] - kHalfDamageVal, 1, kFullDamageVal);
|
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
|
// 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
|
// team, live status, search distance etc. if needBot is true, then pvHolder, will
|
||||||
// be filled with bot pointer, else with edict pointer(!).
|
// be filled with bot pointer, else with edict pointer(!).
|
||||||
|
|
||||||
searchDistance = cr::sqrf (searchDistance);
|
searchDistance = cr::sqrf (searchDistance);
|
||||||
|
float nearestPlayerDistanceSq = cr::sqrf (4096.0f); // nearest player
|
||||||
edict_t *survive = nullptr; // pointer to temporally & survive entity
|
|
||||||
float nearestPlayer = 4096.0f; // nearest player
|
|
||||||
|
|
||||||
const int toTeam = game.getTeam (to);
|
|
||||||
|
|
||||||
for (const auto &client : m_clients) {
|
for (const auto &client : m_clients) {
|
||||||
if (!(client.flags & ClientFlags::Used) || client.ent == to) {
|
if (!(client.flags & ClientFlags::Used) || client.ent == to) {
|
||||||
continue;
|
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
|
continue; // filter players with parameters
|
||||||
}
|
}
|
||||||
const float distanceSq = client.ent->v.origin.distanceSq (to->v.origin);
|
const float distanceSq = client.ent->v.origin.distanceSq (to->v.origin);
|
||||||
|
|
||||||
if (distanceSq < nearestPlayer && distanceSq < searchDistance) {
|
if (distanceSq < nearestPlayerDistanceSq && distanceSq < searchDistance) {
|
||||||
nearestPlayer = distanceSq;
|
nearestPlayerDistanceSq = distanceSq;
|
||||||
survive = client.ent;
|
*pvHolder = needBot ? reinterpret_cast <void *> (bots[client.ent]) : reinterpret_cast <void *> (client.ent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return !!*pvHolder;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotSupport::updateClients () {
|
void BotSupport::updateClients () {
|
||||||
|
|
|
||||||
|
|
@ -425,15 +425,24 @@ void Bot::setAimDirection () {
|
||||||
if (!(flags & (AimFlags::Grenade | AimFlags::Enemy | AimFlags::Entity))) {
|
if (!(flags & (AimFlags::Grenade | AimFlags::Enemy | AimFlags::Entity))) {
|
||||||
|
|
||||||
// check if narrow place and we're duck, do not predict enemies in that situation
|
// 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);
|
flags &= ~(AimFlags::LastEnemy | AimFlags::PredictPath);
|
||||||
m_canChooseAimDirection = false;
|
m_canChooseAimDirection = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't switch view right away after loosing focus with current enemy
|
// 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_forgetLastVictimTimer.elapsed ()
|
||||||
&& !m_lastEnemyOrigin.empty ()
|
&& !m_lastEnemyOrigin.empty ()
|
||||||
&& util.isAlive (m_lastEnemy)
|
&& util.isAlive (m_lastEnemy)
|
||||||
|
|
@ -619,7 +628,10 @@ void Bot::setAimDirection () {
|
||||||
if (horizontalMovement && m_pathWalk.hasNext ()) {
|
if (horizontalMovement && m_pathWalk.hasNext ()) {
|
||||||
const auto &nextPath = graph[m_pathWalk.next ()];
|
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;
|
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
|
// 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;
|
m_lookAt = m_lastVictimOrigin + pev->view_ofs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -324,7 +324,7 @@
|
||||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
<DisableLanguageExtensions>false</DisableLanguageExtensions>
|
<DisableLanguageExtensions>false</DisableLanguageExtensions>
|
||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ResourceCompile>
|
<ResourceCompile>
|
||||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue