fix: problems with breakable on cs_mari (ref #686)

fix: goal selection on some zombie  maps (ref #684)
This commit is contained in:
jeefo 2025-04-03 15:12:06 +03:00
commit d6d76e136d
No known key found for this signature in database
GPG key ID: D696786B81B667C8
12 changed files with 95 additions and 86 deletions

View file

@ -2651,7 +2651,7 @@ Weapon configuration file not found. Loading defaults.
未找到武器配置文件。加载默认值。
[ORIGINAL]
Couldn't open chatter system configuration
Couldn't open chatter configuration.
[TRANSLATED]
无法打开聊天系统配置
@ -2669,7 +2669,7 @@ Bots chatter communication disabled.
已禁用人机聊天通信。
[ORIGINAL]
Chat file not found.
Couldn't open chat configuration.
[TRANSLATED]
未找到聊天文件。
@ -2687,7 +2687,7 @@ Specified language not found.
未找到指定语言。
[ORIGINAL]
Couldn't load language configuration
Couldn't load language configuration.
[TRANSLATED]
无法加载语言配置

View file

@ -2650,10 +2650,10 @@ Weapon configuration file not found. Loading defaults.
Оружейный конфигурационный файл не найден. Загружаем стандартные значения.
[ORIGINAL]
Couldn't open chatter system configuration
Couldn't open chat configuration.
[TRANSLATED]
Не удалось открыть конфигурацию системы переговоров
Не удалось открыть конфигурацию переговоров.
[ORIGINAL]
Error in chatter config file syntax... Please correct all errors.
@ -2686,7 +2686,7 @@ Specified language not found.
Указанный язык не найден.
[ORIGINAL]
Couldn't load language configuration
Couldn't load language configuration.
[TRANSLATED]
Не удалось загрузить языковую конфигурацию

View file

@ -223,11 +223,11 @@ public:
bool isNodeReacheableWithJump (const Vector &src, const Vector &destination);
bool checkNodes (bool teleportPlayer, bool onlyPaths = false);
bool isVisited (int index);
bool isAnalyzed () const;
bool saveGraphData ();
bool loadGraphData ();
bool canDownload ();
bool isAnalyzed () const;
void saveOldFormat ();
void reset ();
@ -251,8 +251,7 @@ public:
void startLearnJump ();
void setVisited (int index);
void clearVisited ();
void initBuckets ();
void addToBucket (const Vector &pos, int index);
void eraseFromBucket (const Vector &pos, int index);
void setBombOrigin (bool reset = false, const Vector &pos = nullptr);
void unassignPath (int from, int to);
@ -267,7 +266,6 @@ public:
void collectOnline ();
IntArray getNearestInRadius (float radius, const Vector &origin, int maxCount = -1);
const IntArray &getNodesInBucket (const Vector &pos);
public:
StringRef getAuthor () const {
@ -353,6 +351,21 @@ public:
return m_nodeNumbers;
}
// reinitialize buckets
void initBuckets () {
m_hashTable.clear ();
}
// get the bucket of nodes near position
const IntArray &getNodesInBucket (const Vector &pos) {
return m_hashTable[locateBucket (pos)];
}
// add a node to position bucket
void addToBucket (const Vector &pos, int index) {
m_hashTable[locateBucket (pos)].emplace (index);
}
public:
// graph helper for sending message to correct channel
template <typename ...Args> void msg (const char *fmt, Args &&...args);

View file

@ -154,7 +154,7 @@ public:
private:
void reset () {
m_current = NetMsg::None;
stopCollection ();
m_bot = nullptr;
}
};

View file

@ -520,6 +520,7 @@ private:
void updateRightRef ();
void donateC4ToHuman ();
void clearAmmoInfo ();
void handleChatterTaskChange (Task tid);
void completeTask ();
void executeTasks ();

View file

@ -2146,6 +2146,7 @@ void Bot::filterTasks () {
// zombie bots has more hunt desire
if (m_isCreature && huntEnemyDesire > 16.0f) {
huntEnemyDesire = TaskPri::Attack;
seekCoverDesire = 0.0f;
}
// blinded behavior
@ -2250,37 +2251,9 @@ void Bot::startTask (Task id, float desire, int data, float time, bool resume) {
selectBestWeapon ();
}
// this is best place to handle some voice commands report team some info
// this is best place to handle some chatter commands report team some info
if (cv_radio_mode.as <int> () > 1) {
if (rg.chance (90)) {
if (tid == Task::Blind) {
pushChatterMessage (Chatter::Blind);
}
else if (tid == Task::PlantBomb) {
pushChatterMessage (Chatter::PlantingBomb);
}
}
if (rg.chance (25) && tid == Task::Camp) {
if (game.mapIs (MapFlags::Demolition) && bots.isBombPlanted ()) {
pushChatterMessage (Chatter::GuardingPlantedC4);
}
else {
pushChatterMessage (Chatter::GoingToCamp);
}
}
if (rg.chance (75) && tid == Task::Camp && m_team == Team::CT && m_inEscapeZone) {
pushChatterMessage (Chatter::GoingToGuardEscapeZone);
}
if (rg.chance (75) && tid == Task::Camp && m_team == Team::Terrorist && m_inRescueZone) {
pushChatterMessage (Chatter::GoingToGuardRescueZone);
}
if (rg.chance (75) && tid == Task::Camp && m_team == Team::Terrorist && m_inVIPZone) {
pushChatterMessage (Chatter::GoingToGuardVIPSafety);
}
handleChatterTaskChange (tid);
}
if (cv_debug_goal.as <int> () != kInvalidNodeIndex) {
@ -2419,10 +2392,41 @@ bool Bot::lastEnemyShootable () {
return util.getConeDeviation (ent (), m_lastEnemyOrigin) >= 0.90f && isPenetrableObstacle (m_lastEnemyOrigin);
}
void Bot::handleChatterTaskChange (Task tid) {
if (rg.chance (90)) {
if (tid == Task::Blind) {
pushChatterMessage (Chatter::Blind);
}
else if (tid == Task::PlantBomb) {
pushChatterMessage (Chatter::PlantingBomb);
}
}
if (rg.chance (25) && tid == Task::Camp) {
if (game.mapIs (MapFlags::Demolition) && bots.isBombPlanted ()) {
pushChatterMessage (Chatter::GuardingPlantedC4);
}
else {
pushChatterMessage (Chatter::GoingToCamp);
}
}
if (rg.chance (75) && tid == Task::Camp && m_team == Team::CT && m_inEscapeZone) {
pushChatterMessage (Chatter::GoingToGuardEscapeZone);
}
if (rg.chance (75) && tid == Task::Camp && m_team == Team::Terrorist && m_inRescueZone) {
pushChatterMessage (Chatter::GoingToGuardRescueZone);
}
if (rg.chance (75) && tid == Task::Camp && m_team == Team::Terrorist && m_inVIPZone) {
pushChatterMessage (Chatter::GoingToGuardVIPSafety);
}
}
void Bot::checkRadioQueue () {
// this function handling radio and reacting to it
// don't allow bot listen you if bot is busy
if (m_radioOrder != Radio::ReportInTeam
&& (getCurrentTaskId () == Task::DefuseBomb

View file

@ -208,28 +208,29 @@ void BotConfig::loadWeaponsConfig () {
trim.trim ();
}
auto splitted = pair[1].split (",");
auto key = pair[0];
if (pair[0].startsWith ("MapStandard")) {
addWeaponEntries (m_weapons, false, pair[0], splitted);
if (key.startsWith ("MapStandard")) {
addWeaponEntries (m_weapons, false, key, splitted);
}
else if (pair[0].startsWith ("MapAS")) {
addWeaponEntries (m_weapons, true, pair[0], splitted);
else if (key.startsWith ("MapAS")) {
addWeaponEntries (m_weapons, true, key, splitted);
}
else if (pair[0].startsWith ("GrenadePercent")) {
addIntEntries (m_grenadeBuyPrecent, pair[0], splitted);
else if (key.startsWith ("GrenadePercent")) {
addIntEntries (m_grenadeBuyPrecent, key, splitted);
}
else if (pair[0].startsWith ("Economics")) {
addIntEntries (m_botBuyEconomyTable, pair[0], splitted);
else if (key.startsWith ("Economics")) {
addIntEntries (m_botBuyEconomyTable, key, splitted);
}
else if (pair[0].startsWith ("PersonalityNormal")) {
addIntEntries (m_normalWeaponPrefs, pair[0], splitted);
else if (key.startsWith ("PersonalityNormal")) {
addIntEntries (m_normalWeaponPrefs, key, splitted);
}
else if (pair[0].startsWith ("PersonalityRusher")) {
addIntEntries (m_rusherWeaponPrefs, pair[0], splitted);
else if (key.startsWith ("PersonalityRusher")) {
addIntEntries (m_rusherWeaponPrefs, key, splitted);
}
else if (pair[0].startsWith ("PersonalityCareful")) {
addIntEntries (m_carefulWeaponPrefs, pair[0], splitted);
else if (key.startsWith ("PersonalityCareful")) {
addIntEntries (m_carefulWeaponPrefs, key, splitted);
}
}
file.close ();
@ -244,7 +245,7 @@ void BotConfig::loadChatterConfig () {
// chatter initialization
if (game.is (GameFlags::HasBotVoice) && cv_radio_mode.as <int> () == 2
&& openConfig ("chatter", "Couldn't open chatter system configuration", &file)) {
&& openConfig ("chatter", "Couldn't open chatter configuration.", &file)) {
m_chatter.clear ();
@ -402,7 +403,7 @@ void BotConfig::loadChatConfig () {
MemFile file {};
// chat config initialization
if (openConfig ("chat", "Chat file not found.", &file, true)) {
if (openConfig ("chat", "Couldn't open chat configuration.", &file, true)) {
StringArray *chat = nullptr;
StringArray keywords {};
@ -549,7 +550,7 @@ void BotConfig::loadLanguageConfig () {
file.close ();
}
else if (cv_language.as <StringRef> () != "en") {
logger.error ("Couldn't load language configuration");
logger.error ("Couldn't load language configuration.");
}
}

View file

@ -599,6 +599,10 @@ IntArray BotGraph::getNearestInRadius (float radius, const Vector &origin, int m
return result;
}
bool BotGraph::isAnalyzed () const {
return (m_info.header.options & StorageOption::Analyzed);
}
void BotGraph::add (int type, const Vector &pos) {
if (!hasEditor () && !analyzer.isAnalyzing ()) {
return;
@ -2836,22 +2840,6 @@ BotGraph::BotGraph () {
m_editor = nullptr;
}
void BotGraph::initBuckets () {
m_hashTable.clear ();
}
void BotGraph::addToBucket (const Vector &pos, int index) {
m_hashTable[locateBucket (pos)].emplace (index);
}
const Array <int32_t> &BotGraph::getNodesInBucket (const Vector &pos) {
return m_hashTable[locateBucket (pos)];
}
bool BotGraph::isAnalyzed () const {
return (m_info.header.options & StorageOption::Analyzed);
}
void BotGraph::eraseFromBucket (const Vector &pos, int index) {
auto &data = m_hashTable[locateBucket (pos)];

View file

@ -459,7 +459,7 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int interfaceVersion) {
// would all have the dull "models/player.mdl" one). The entity for which the keyvalue data
// pointer is requested is pentKeyvalue, the pointer to the keyvalue data structure pkvd.
if (game.isNullEntity (ent) && strcmp (ent->v.classname.chars (), "func_breakable") == 0) {
if (!game.isNullEntity (ent) && strcmp (ent->v.classname.chars (), "func_breakable") == 0) {
if (kvd && kvd->szKeyName && strcmp (kvd->szKeyName, "material") == 0) {
if (atoi (kvd->szValue) == 7) {
game.markBreakableAsInvalid (ent);

View file

@ -549,7 +549,7 @@ void MessageDispatcher::start (edict_t *ent, int32_t type) {
m_bot = bots[ent];
if (!m_bot) {
m_current = NetMsg::None;
stopCollection ();
return;
}
}
@ -561,7 +561,8 @@ void MessageDispatcher::stop () {
return;
}
(this->*m_handlers[m_current]) ();
m_current = NetMsg::None;
stopCollection ();
}
void MessageDispatcher::ensureMessages () {

View file

@ -11,12 +11,13 @@ ConVar cv_has_team_semiclip ("has_team_semiclip", "0", "When enabled, bots will
ConVar cv_graph_slope_height ("graph_slope_height", "24.0", "Determines the maximum slope height change between the current and next node to consider the current link as a jump link. Only for generated graphs.", true, 12.0f, 48.0f);
int Bot::findBestGoal () {
if (m_isCreature) {
if (!graph.m_terrorPoints.empty ()) {
if (game.is (GameFlags::ZombieMod) && m_isCreature) {
const auto &players = bots.countTeamPlayers ();
if (players.first < graph.m_terrorPoints.length <int> ()) {
return graph.m_terrorPoints.random ();
}
if (!graph.m_goalPoints.empty ()) {
else if (players.first < graph.m_goalPoints.length <int> ()) {
return graph.m_goalPoints.random ();
}
return graph.random ();

View file

@ -1473,9 +1473,9 @@ void Bot::shootBreakable_ () {
}
else {
TraceResult tr {};
game.testLine (pev->origin, m_breakableOrigin, TraceIgnore::None, ent (), &tr);
game.testLine (pev->origin, m_breakableOrigin, TraceIgnore::Monsters , ent (), &tr);
if (tr.pHit != m_breakableEntity || !util.isVisible (tr.vecEndPos, ent ())) {
if (tr.pHit != m_breakableEntity && !cr::fequal (tr.flFraction, 1.0f)) {
m_ignoredBreakable.push (tr.pHit);
m_breakableEntity = nullptr;
@ -1494,8 +1494,6 @@ void Bot::shootBreakable_ () {
m_navTimeset = game.time ();
m_lookAtSafe = m_breakableOrigin;
const float distToObstacle = pev->origin.distanceSq (m_lookAtSafe);
// is bot facing the breakable?
if (util.getConeDeviation (ent (), m_lookAtSafe) >= 0.90f) {
m_moveSpeed = 0.0f;
@ -1510,6 +1508,7 @@ void Bot::shootBreakable_ () {
pev->button |= IN_ATTACK;
}
}
const float distToObstacle = pev->origin.distanceSq (m_lookAtSafe);
// if with knife with no ammo, recompute breakable distance
if (!hasAnyAmmoInClip ()
@ -1703,6 +1702,7 @@ void Bot::pickupItem_ () {
for (const auto &client : util.getClients ()) {
if ((client.flags & ClientFlags::Used) && !(client.ent->v.flags & FL_FAKECLIENT) && (client.flags & ClientFlags::Alive) &&
client.team == m_team && client.ent->v.origin.distanceSq (ent->v.origin) <= cr::sqrf (240.0f)) {
return EntitySearchResult::Continue;
}
}