graph: move light level calculation to thread worker

fix: nodes with light level 0.0 should trigger bots flashlight now
fix: gcc and msvc builds due to mistake in crlib
refactor: add more const-correctness (ongoing)
This commit is contained in:
jeefo 2023-06-24 03:23:22 +03:00
commit 3d2579c7ea
No known key found for this signature in database
GPG key ID: 927BCA0779BEA8ED
11 changed files with 121 additions and 111 deletions

@ -1 +1 @@
Subproject commit c4815b7445ae0fc509cba511deee0f2c67834704 Subproject commit 60e0b07a5f4cf630cd2ad49112129ac3e5859b5d

View file

@ -436,6 +436,7 @@ struct TaskPri {
}; };
constexpr auto kInfiniteDistance = 9999999.0f; constexpr auto kInfiniteDistance = 9999999.0f;
constexpr auto kInvalidLightLevel = kInfiniteDistance;
constexpr auto kGrenadeCheckTime = 0.6f; constexpr auto kGrenadeCheckTime = 0.6f;
constexpr auto kSprayDistance = 260.0f; constexpr auto kSprayDistance = 260.0f;
constexpr auto kDoubleSprayDistance = kSprayDistance * 2; constexpr auto kDoubleSprayDistance = kSprayDistance * 2;

View file

@ -228,6 +228,7 @@ public:
void reset (); void reset ();
void frame (); void frame ();
void populateNodes (); void populateNodes ();
void syncInitLightLevels ();
void initLightLevels (); void initLightLevels ();
void initNarrowPlaces (); void initNarrowPlaces ();
void addPath (int addIndex, int pathIndex, float distance); void addPath (int addIndex, int pathIndex, float distance);

View file

@ -737,16 +737,6 @@ public:
void sendBotToOrigin (const Vector &origin); void sendBotToOrigin (const Vector &origin);
void markStale (); void markStale ();
bool hasHostage (); bool hasHostage ();
bool usesRifle ();
bool usesPistol ();
bool usesSniper ();
bool usesSubmachine ();
bool usesShotgun ();
bool usesHeavy ();
bool usesZoomableRifle ();
bool usesBadWeapon ();
bool usesCampGun ();
bool usesKnife ();
bool hasPrimaryWeapon (); bool hasPrimaryWeapon ();
bool hasSecondaryWeapon (); bool hasSecondaryWeapon ();
bool hasShield (); bool hasShield ();
@ -809,6 +799,57 @@ public:
debugMsgInternal (strings.format (fmt, cr::forward <Args> (args)...)); debugMsgInternal (strings.format (fmt, cr::forward <Args> (args)...));
} }
private:
// returns true if bot is using a sniper rifle
bool usesSniper () const {
return m_weaponType == WeaponType::Sniper;
}
// returns true if bot is using a rifle
bool usesRifle () const {
return usesZoomableRifle () || m_weaponType == WeaponType::Rifle;
}
// returns true if bot is using a zoomable rifle
bool usesZoomableRifle () const {
return m_weaponType == WeaponType::ZoomRifle;
}
// returns true if bot is using a pistol
bool usesPistol () const {
return m_weaponType == WeaponType::Pistol;
}
// returns true if bot is using a SMG
bool usesSubmachine () const {
return m_weaponType == WeaponType::SMG;
}
// returns true if bot is using a shotgun
bool usesShotgun () const {
return m_weaponType == WeaponType::Shotgun;
}
// returns true if bot is using m249
bool usesHeavy () const {
return m_weaponType == WeaponType::Heavy;
}
// returns true if bot using not very good weapon
bool usesBadWeapon () const {
return usesShotgun () || m_currentWeapon == Weapon::UMP45 || m_currentWeapon == Weapon::MAC10 || m_currentWeapon == Weapon::TMP;
}
// returns true if bot using a camp gun
bool usesCampGun () const {
return usesSubmachine () || usesRifle () || usesSniper () || usesHeavy ();
}
// returns true if bot using knife
bool usesKnife () const {
return m_weaponType == WeaponType::Melee;
}
// execute client command helper // execute client command helper
template <typename ...Args> void issueCommand (const char *fmt, Args &&...args); template <typename ...Args> void issueCommand (const char *fmt, Args &&...args);
}; };

View file

@ -704,9 +704,9 @@ void Bot::ensureEntitiesClear () {
if ((!m_isStuck || m_navTimeset + getEstimatedNodeReachTime () + m_frameInterval * 2.0f > game.time ()) && !(m_states & Sense::SeeingEnemy)) { if ((!m_isStuck || m_navTimeset + getEstimatedNodeReachTime () + m_frameInterval * 2.0f > game.time ()) && !(m_states & Sense::SeeingEnemy)) {
return; return;
} }
const auto currentTask = getCurrentTaskId (); const auto tid = getCurrentTaskId ();
if (currentTask == Task::PickupItem || (m_states & Sense::PickupItem)) { if (tid == Task::PickupItem || (m_states & Sense::PickupItem)) {
if (!game.isNullEntity (m_pickupItem) && !m_hasProgressBar) { if (!game.isNullEntity (m_pickupItem) && !m_hasProgressBar) {
m_itemIgnore = m_pickupItem; // clear these pointers, bot might be stuck getting to them m_itemIgnore = m_pickupItem; // clear these pointers, bot might be stuck getting to them
} }
@ -715,11 +715,11 @@ void Bot::ensureEntitiesClear () {
m_pickupType = Pickup::None; m_pickupType = Pickup::None;
m_pickupItem = nullptr; m_pickupItem = nullptr;
if (currentTask == Task::PickupItem) { if (tid == Task::PickupItem) {
completeTask (); completeTask ();
} }
} }
else if (currentTask == Task::ShootBreakable) { else if (tid == Task::ShootBreakable) {
if (!game.isNullEntity (m_breakableEntity)) { if (!game.isNullEntity (m_breakableEntity)) {
m_ignoredBreakable.emplace (m_breakableEntity); m_ignoredBreakable.emplace (m_breakableEntity);
} }
@ -1511,8 +1511,8 @@ void Bot::buyStuff () {
case BuyState::NightVision: case BuyState::NightVision:
if (teamHasGoodEconomics && m_moneyAmount > 2500 && !m_hasNVG && rg.chance (30) && m_path) { if (teamHasGoodEconomics && m_moneyAmount > 2500 && !m_hasNVG && rg.chance (30) && m_path) {
float skyColor = illum.getSkyColor (); const float skyColor = illum.getSkyColor ();
float lightLevel = m_path->light; const float lightLevel = m_path->light;
// if it's somewhat darkm do buy nightvision goggles // if it's somewhat darkm do buy nightvision goggles
if ((skyColor >= 50.0f && lightLevel <= 15.0f) || (skyColor < 50.0f && lightLevel < 40.0f)) { if ((skyColor >= 50.0f && lightLevel <= 15.0f) || (skyColor < 50.0f && lightLevel < 40.0f)) {
@ -2026,7 +2026,7 @@ void Bot::startTask (Task id, float desire, int data, float time, bool resume) {
clearSearchNodes (); clearSearchNodes ();
ignoreCollision (); ignoreCollision ();
const int tid = getCurrentTaskId (); const auto tid = getCurrentTaskId ();
// leader bot? // leader bot?
if (m_isLeader && tid == Task::SeekCover) { if (m_isLeader && tid == Task::SeekCover) {
@ -2226,9 +2226,9 @@ void Bot::checkRadioQueue () {
m_targetEntity = m_radioEntity; m_targetEntity = m_radioEntity;
// don't pause/camp/follow anymore // don't pause/camp/follow anymore
Task taskID = getCurrentTaskId (); const auto tid = getCurrentTaskId ();
if (taskID == Task::Pause || taskID == Task::Camp) { if (tid == Task::Pause || tid == Task::Camp) {
getTask ()->time = game.time (); getTask ()->time = game.time ();
} }
startTask (Task::FollowUser, TaskPri::FollowUser, kInvalidNodeIndex, 0.0f, true); startTask (Task::FollowUser, TaskPri::FollowUser, kInvalidNodeIndex, 0.0f, true);
@ -2344,9 +2344,9 @@ void Bot::checkRadioQueue () {
} }
} }
else if ((game.isNullEntity (m_enemy) && seesEntity (m_radioEntity->v.origin)) || distanceSq < cr::sqrf (2048.0f)) { else if ((game.isNullEntity (m_enemy) && seesEntity (m_radioEntity->v.origin)) || distanceSq < cr::sqrf (2048.0f)) {
Task taskID = getCurrentTaskId (); const auto tid = getCurrentTaskId ();
if (taskID == Task::Pause || taskID == Task::Camp) { if (tid == Task::Pause || tid == Task::Camp) {
m_fearLevel -= 0.2f; m_fearLevel -= 0.2f;
if (m_fearLevel < 0.0f) { if (m_fearLevel < 0.0f) {
@ -2406,9 +2406,9 @@ void Bot::checkRadioQueue () {
pushRadioMessage (Radio::RogerThat); pushRadioMessage (Radio::RogerThat);
// don't pause/camp anymore // don't pause/camp anymore
Task taskID = getCurrentTaskId (); const auto tid = getCurrentTaskId ();
if (taskID == Task::Pause || taskID == Task::Camp) { if (tid == Task::Pause || tid == Task::Camp) {
getTask ()->time = game.time (); getTask ()->time = game.time ();
} }
m_targetEntity = nullptr; m_targetEntity = nullptr;
@ -2447,9 +2447,9 @@ void Bot::checkRadioQueue () {
} }
else { else {
// don't pause/camp anymore // don't pause/camp anymore
Task taskID = getCurrentTaskId (); const auto tid = getCurrentTaskId ();
if (taskID == Task::Pause) { if (tid == Task::Pause) {
getTask ()->time = game.time (); getTask ()->time = game.time ();
} }
m_targetEntity = nullptr; m_targetEntity = nullptr;
@ -2601,9 +2601,9 @@ void Bot::checkRadioQueue () {
} }
else { else {
// don't pause anymore // don't pause anymore
Task taskID = getCurrentTaskId (); const auto tid = getCurrentTaskId ();
if (taskID == Task::Pause) { if (tid == Task::Pause) {
getTask ()->time = game.time (); getTask ()->time = game.time ();
} }
@ -2621,10 +2621,10 @@ void Bot::checkRadioQueue () {
} }
auto enemy = client.ent; auto enemy = client.ent;
const float distanceSq = m_radioEntity->v.origin.distanceSq (enemy->v.origin); const float enemyDistanceSq = m_radioEntity->v.origin.distanceSq (enemy->v.origin);
if (distanceSq < nearestDistanceSq) { if (enemyDistanceSq < nearestDistanceSq) {
nearestDistanceSq = distanceSq; nearestDistanceSq = enemyDistanceSq;
m_lastEnemy = enemy; m_lastEnemy = enemy;
m_lastEnemyOrigin = enemy->v.origin; m_lastEnemyOrigin = enemy->v.origin;
@ -2633,7 +2633,7 @@ void Bot::checkRadioQueue () {
} }
clearSearchNodes (); clearSearchNodes ();
int index = findDefendNode (m_radioEntity->v.origin); const int index = findDefendNode (m_radioEntity->v.origin);
// push camp task on to stack // push camp task on to stack
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (30.0f, 60.0f), true); startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (30.0f, 60.0f), true);
@ -2651,7 +2651,7 @@ void Bot::checkRadioQueue () {
} }
void Bot::tryHeadTowardRadioMessage () { void Bot::tryHeadTowardRadioMessage () {
const int tid = getCurrentTaskId (); const auto tid = getCurrentTaskId ();
if (tid == Task::MoveToPosition || m_headedTime + 15.0f < game.time () || !util.isAlive (m_radioEntity) || m_hasC4) { if (tid == Task::MoveToPosition || m_headedTime + 15.0f < game.time () || !util.isAlive (m_radioEntity) || m_hasC4) {
return; return;
@ -3098,7 +3098,7 @@ void Bot::showDebugOverlay () {
return; return;
} }
static float timeDebugUpdate = 0.0f; static float timeDebugUpdate = 0.0f;
static int index = kInvalidNodeIndex, goal = kInvalidNodeIndex, taskID = 0; static int index = kInvalidNodeIndex, goal = kInvalidNodeIndex, tid = 0;
static HashMap <int32_t, StringRef> tasks { static HashMap <int32_t, StringRef> tasks {
{ Task::Normal, "Normal" }, { Task::Normal, "Normal" },
@ -3149,8 +3149,8 @@ void Bot::showDebugOverlay () {
return; return;
} }
if (taskID != getCurrentTaskId () || index != m_currentNodeIndex || goal != getTask ()->data || timeDebugUpdate < game.time ()) { if (tid != getCurrentTaskId () || index != m_currentNodeIndex || goal != getTask ()->data || timeDebugUpdate < game.time ()) {
taskID = getCurrentTaskId (); tid = getCurrentTaskId ();
index = m_currentNodeIndex; index = m_currentNodeIndex;
goal = getTask ()->data; goal = getTask ()->data;
@ -3179,7 +3179,7 @@ void Bot::showDebugOverlay () {
auto weapon = util.weaponIdToAlias (m_currentWeapon); auto weapon = util.weaponIdToAlias (m_currentWeapon);
String debugData; String debugData;
debugData.assignf ("\n\n\n\n\n%s (H:%.1f/A:%.1f)- Task: %d=%s Desire:%.02f\nItem: %s Clip: %d Ammo: %d%s Money: %d AimFlags: %s\nSP=%.02f SSP=%.02f I=%d PG=%d G=%d T: %.02f MT: %d\nEnemy=%s Pickup=%s Type=%s Terrain=%s Stuck=%s\n", pev->netname.str (), m_healthValue, pev->armorvalue, taskID, tasks[taskID], getTask ()->desire, weapon, getAmmoInClip (), getAmmo (), m_isReloading ? " (R)" : "", m_moneyAmount, aimFlags.trim (), m_moveSpeed, m_strafeSpeed, index, m_prevGoalIndex, goal, m_navTimeset - game.time (), pev->movetype, enemy, pickup, personalities[m_personality], boolValue (m_checkTerrain), boolValue (m_isStuck)); debugData.assignf ("\n\n\n\n\n%s (H:%.1f/A:%.1f)- Task: %d=%s Desire:%.02f\nItem: %s Clip: %d Ammo: %d%s Money: %d AimFlags: %s\nSP=%.02f SSP=%.02f I=%d PG=%d G=%d T: %.02f MT: %d\nEnemy=%s Pickup=%s Type=%s Terrain=%s Stuck=%s\n", pev->netname.str (), m_healthValue, pev->armorvalue, tid, tasks[tid], getTask ()->desire, weapon, getAmmoInClip (), getAmmo (), m_isReloading ? " (R)" : "", m_moneyAmount, aimFlags.trim (), m_moveSpeed, m_strafeSpeed, index, m_prevGoalIndex, goal, m_navTimeset - game.time (), pev->movetype, enemy, pickup, personalities[m_personality], boolValue (m_checkTerrain), boolValue (m_isStuck));
MessageWriter (MSG_ONE_UNRELIABLE, SVC_TEMPENTITY, nullptr, overlayEntity) MessageWriter (MSG_ONE_UNRELIABLE, SVC_TEMPENTITY, nullptr, overlayEntity)
.writeByte (TE_TEXTMESSAGE) .writeByte (TE_TEXTMESSAGE)

View file

@ -457,11 +457,11 @@ Vector Bot::getBodyOffsetError (float distance) {
if (m_aimErrorTime < game.time ()) { if (m_aimErrorTime < game.time ()) {
const float hitError = distance / (cr::clamp (static_cast <float> (m_difficulty), 1.0f, 4.0f) * 1000.0f); const float hitError = distance / (cr::clamp (static_cast <float> (m_difficulty), 1.0f, 4.0f) * 1000.0f);
auto &maxs = m_enemy->v.maxs, &mins = m_enemy->v.mins; const auto &maxs = m_enemy->v.maxs, &mins = m_enemy->v.mins;
m_aimLastError = Vector (rg.get (mins.x * hitError, maxs.x * hitError), rg.get (mins.y * hitError, maxs.y * hitError), rg.get (mins.z * hitError, maxs.z * hitError)); m_aimLastError = Vector (rg.get (mins.x * hitError, maxs.x * hitError), rg.get (mins.y * hitError, maxs.y * hitError), rg.get (mins.z * hitError, maxs.z * hitError));
auto &aimError = conf.getDifficultyTweaks (m_difficulty) ->aimError; const auto &aimError = conf.getDifficultyTweaks (m_difficulty) ->aimError;
m_aimLastError += Vector (rg.get (-aimError.x, aimError.x), rg.get (-aimError.y, aimError.y), rg.get (-aimError.z, aimError.z)); m_aimLastError += Vector (rg.get (-aimError.x, aimError.x), rg.get (-aimError.y, aimError.y), rg.get (-aimError.z, aimError.z));
m_aimErrorTime = game.time () + rg.get (1.5f, 2.0f); m_aimErrorTime = game.time () + rg.get (1.5f, 2.0f);
@ -656,7 +656,7 @@ bool Bot::isPenetrableObstacle (const Vector &dest) {
obstacleDistanceSq = tr.vecEndPos.distanceSq (source); obstacleDistanceSq = tr.vecEndPos.distanceSq (source);
} }
} }
const float kMaxDistanceSq = cr::sqrf (75.0f); constexpr float kMaxDistanceSq = cr::sqrf (75.0f);
if (obstacleDistanceSq > 0.0f) { if (obstacleDistanceSq > 0.0f) {
while (power > 0) { while (power > 0) {
@ -1031,7 +1031,7 @@ bool Bot::isWeaponBadAtDistance (int weaponIndex, float distance) {
if (m_difficulty < Difficulty::Normal || !hasSecondaryWeapon ()) { if (m_difficulty < Difficulty::Normal || !hasSecondaryWeapon ()) {
return false; return false;
} }
auto weaponType = info[weaponIndex].type; const auto weaponType = info[weaponIndex].type;
if (weaponType == WeaponType::Melee) { if (weaponType == WeaponType::Melee) {
return false; return false;
@ -1358,48 +1358,6 @@ bool Bot::isEnemyBehindShield (edict_t *enemy) {
return false; return false;
} }
bool Bot::usesSniper () {
// this function returns true, if returns if bot is using a sniper rifle
return m_weaponType == WeaponType::Sniper;
}
bool Bot::usesRifle () {
return usesZoomableRifle () || m_weaponType == WeaponType::Rifle;
}
bool Bot::usesZoomableRifle () {
return m_weaponType == WeaponType::ZoomRifle;
}
bool Bot::usesPistol () {
return m_weaponType == WeaponType::Pistol;
}
bool Bot::usesSubmachine () {
return m_weaponType == WeaponType::SMG;
}
bool Bot::usesShotgun () {
return m_weaponType == WeaponType::Shotgun;
}
bool Bot::usesHeavy () {
return m_weaponType == WeaponType::Heavy;
}
bool Bot::usesBadWeapon () {
return usesShotgun () || m_currentWeapon == Weapon::UMP45 || m_currentWeapon == Weapon::MAC10 || m_currentWeapon == Weapon::TMP;
}
bool Bot::usesCampGun () {
return usesSubmachine () || usesRifle () || usesSniper () || usesHeavy ();
}
bool Bot::usesKnife () {
return m_weaponType == WeaponType::Melee;
}
int Bot::bestPrimaryCarried () { int Bot::bestPrimaryCarried () {
// this function returns the best weapon of this bot (based on personality prefs) // this function returns the best weapon of this bot (based on personality prefs)
@ -1673,10 +1631,10 @@ bool Bot::isGroupOfEnemies (const Vector &location, int numEnemies, float radius
void Bot::checkReload () { void Bot::checkReload () {
// check the reload state // check the reload state
const auto task = getCurrentTaskId (); const auto tid = getCurrentTaskId ();
// we're should not reload, while doing next tasks // we're should not reload, while doing next tasks
const bool uninterruptibleTask = (task == Task::PlantBomb || task == Task::DefuseBomb || task == Task::PickupItem || task == Task::ThrowExplosive || task == Task::ThrowFlashbang || task == Task::ThrowSmoke); const bool uninterruptibleTask = (tid == Task::PlantBomb || tid == Task::DefuseBomb || tid == Task::PickupItem || tid == Task::ThrowExplosive || tid == Task::ThrowFlashbang || tid == Task::ThrowSmoke);
// do not check for reload // do not check for reload
if (uninterruptibleTask || m_isUsingGrenade || usesKnife ()) { if (uninterruptibleTask || m_isUsingGrenade || usesKnife ()) {
@ -1939,7 +1897,7 @@ void Bot::checkGrenadesThrow () {
allowThrowing = false; allowThrowing = false;
} }
else { else {
float radius = cr::max (192.0f, m_lastEnemy->v.velocity.length2d ()); const float radius = cr::max (192.0f, m_lastEnemy->v.velocity.length2d ());
const Vector &pos = m_lastEnemy->v.velocity.get2d () + m_lastEnemy->v.origin; const Vector &pos = m_lastEnemy->v.velocity.get2d () + m_lastEnemy->v.origin;
auto predicted = graph.getNarestInRadius (radius, pos, 12); auto predicted = graph.getNarestInRadius (radius, pos, 12);

View file

@ -1745,7 +1745,7 @@ bool BotControl::executeCommands () {
if (prefix != product.cmdPri && prefix != product.cmdSec) { if (prefix != product.cmdPri && prefix != product.cmdSec) {
return false; return false;
} }
auto &client = util.getClient (game.indexOfPlayer (m_ent)); const auto &client = util.getClient (game.indexOfPlayer (m_ent));
// do not allow to execute stuff for non admins // do not allow to execute stuff for non admins
if (m_ent != game.getLocalEntity () && !(client.flags & ClientFlags::Admin)) { if (m_ent != game.getLocalEntity () && !(client.flags & ClientFlags::Admin)) {
@ -1853,7 +1853,7 @@ bool BotControl::executeMenus () {
if (!util.isPlayer (m_ent) || game.isBotCmd ()) { if (!util.isPlayer (m_ent) || game.isBotCmd ()) {
return false; return false;
} }
auto &issuer = util.getClient (game.indexOfPlayer (m_ent)); const auto &issuer = util.getClient (game.indexOfPlayer (m_ent));
// check if it's menu select, and some key pressed // check if it's menu select, and some key pressed
if (strValue (0) != "menuselect" || strValue (1).empty () || issuer.menu == Menu::None) { if (strValue (0) != "menuselect" || strValue (1).empty () || issuer.menu == Menu::None) {

View file

@ -1188,7 +1188,7 @@ template <typename S, typename M> bool LightMeasure::recursiveLightPoint (const
const float front = (start | plane->normal) - plane->dist; const float front = (start | plane->normal) - plane->dist;
const float back = (end | plane->normal) - plane->dist; const float back = (end | plane->normal) - plane->dist;
int side = front < 0.0f; const int side = front < 0.0f;
// if they're both on the same side of the plane, don't bother to split just check the appropriate child // if they're both on the same side of the plane, don't bother to split just check the appropriate child
if ((back < 0.0f) == side) { if ((back < 0.0f) == side) {
@ -1221,8 +1221,8 @@ template <typename S, typename M> bool LightMeasure::recursiveLightPoint (const
auto tex = surf->texinfo; auto tex = surf->texinfo;
// see where in lightmap space our intersection point is // see where in lightmap space our intersection point is
int s = static_cast <int> ((mid | Vector (tex->vecs[0])) + tex->vecs[0][3]); const int s = static_cast <int> ((mid | Vector (tex->vecs[0])) + tex->vecs[0][3]);
int t = static_cast <int> ((mid | Vector (tex->vecs[1])) + tex->vecs[1][3]); const int t = static_cast <int> ((mid | Vector (tex->vecs[1])) + tex->vecs[1][3]);
// not in the bounds of our lightmap? punt... // not in the bounds of our lightmap? punt...
if (s < surf->texturemins[0] || t < surf->texturemins[1]) { if (s < surf->texturemins[0] || t < surf->texturemins[1]) {
@ -1253,7 +1253,7 @@ template <typename S, typename M> bool LightMeasure::recursiveLightPoint (const
// compute the lightmap color at a particular point // compute the lightmap color at a particular point
for (int maps = 0u; maps < MAX_LIGHTMAPS && surf->styles[maps] != 255u; ++maps) { for (int maps = 0u; maps < MAX_LIGHTMAPS && surf->styles[maps] != 255u; ++maps) {
uint32_t scale = m_lightstyleValue[surf->styles[maps]]; const uint32_t scale = m_lightstyleValue[surf->styles[maps]];
m_point.red += lightmap->r * scale; m_point.red += lightmap->r * scale;
m_point.green += lightmap->g * scale; m_point.green += lightmap->g * scale;
@ -1272,11 +1272,11 @@ template <typename S, typename M> bool LightMeasure::recursiveLightPoint (const
float LightMeasure::getLightLevel (const Vector &point) { float LightMeasure::getLightLevel (const Vector &point) {
if (game.is (GameFlags::Legacy)) { if (game.is (GameFlags::Legacy)) {
return 0.0f; return kInvalidLightLevel;
} }
if (!m_worldModel) { if (!m_worldModel) {
return 0.0f; return kInvalidLightLevel;
} }
if (!m_worldModel->lightdata) { if (!m_worldModel->lightdata) {
@ -1293,7 +1293,7 @@ float LightMeasure::getLightLevel (const Vector &point) {
} }
return recursiveLightPoint <msurface_t, mnode_t> (m_worldModel->nodes, point, endPoint); return recursiveLightPoint <msurface_t, mnode_t> (m_worldModel->nodes, point, endPoint);
}; };
return !recursiveCheck () ? 0.0f : 100 * cr::sqrtf (cr::min (75.0f, static_cast <float> (m_point.avg ())) / 75.0f); return !recursiveCheck () ? kInvalidLightLevel : 100 * cr::sqrtf (cr::min (75.0f, static_cast <float> (m_point.avg ())) / 75.0f);
} }
float LightMeasure::getSkyColor () { float LightMeasure::getSkyColor () {

View file

@ -701,7 +701,7 @@ void BotGraph::add (int type, const Vector &pos) {
path->end = nullptr; path->end = nullptr;
path->display = 0.0f; path->display = 0.0f;
path->light = 0.0f; path->light = kInvalidLightLevel;
for (auto &link : path->links) { for (auto &link : path->links) {
link.index = kInvalidNodeIndex; link.index = kInvalidNodeIndex;
@ -1331,11 +1331,11 @@ void BotGraph::calculatePathRadius (int index) {
} }
} }
void BotGraph::initLightLevels () { void BotGraph::syncInitLightLevels () {
// this function get's the light level for each waypoin on the map // this function get's the light level for each waypoin on the map
// no nodes ? no light levels, and only one-time init // no nodes ? no light levels, and only one-time init
if (m_paths.empty () || !cr::fzero (m_paths[0].light)) { if (m_paths.empty () || !cr::fequal (m_paths[0].light, kInvalidLightLevel)) {
return; return;
} }
@ -1347,6 +1347,14 @@ void BotGraph::initLightLevels () {
illum.enableAnimation (false); illum.enableAnimation (false);
} }
void BotGraph::initLightLevels () {
// this function get's the light level for each waypoin on the map
worker.enqueue ([this] () {
syncInitLightLevels ();
});
}
void BotGraph::initNarrowPlaces () { void BotGraph::initNarrowPlaces () {
// this function checks all nodes if they are inside narrow places. this is used to prevent // this function checks all nodes if they are inside narrow places. this is used to prevent
// bots to track hidden enemies in narrow places and prevent bots from throwing flashbangs or // bots to track hidden enemies in narrow places and prevent bots from throwing flashbangs or
@ -2142,9 +2150,9 @@ void BotGraph::frame () {
// show the information about that point // show the information about that point
message.assignf (" %s node:\n" message.assignf (" %s node:\n"
" Node %d of %d, Radius: %.1f, Light: %.1f\n" " Node %d of %d, Radius: %.1f, Light: %s\n"
" Flags: %s\n" " Flags: %s\n"
" Origin: (%.1f, %.1f, %.1f)\n", type, node, m_paths.length () - 1, p.radius, p.light, flags, p.origin.x, p.origin.y, p.origin.z); " Origin: (%.1f, %.1f, %.1f)\n", type, node, m_paths.length () - 1, p.radius, p.light == kInvalidLightLevel ? "Invalid" : strings.format ("%1.f", p.light), flags, p.origin.x, p.origin.y, p.origin.z);
return message; return message;
}; };
@ -2630,7 +2638,7 @@ void BotGraph::convertFromPOD (Path &path, const PODPath &pod) {
convertCampDirection (path); convertCampDirection (path);
} }
path.radius = pod.radius; path.radius = pod.radius;
path.light = 0.0f; path.light = kInvalidLightLevel;
path.display = 0.0f; path.display = 0.0f;
for (int i = 0; i < kMaxNodeLinks; ++i) { for (int i = 0; i < kMaxNodeLinks; ++i) {

View file

@ -2206,7 +2206,7 @@ bool Bot::advanceMovement () {
// helper to change bot's goal // helper to change bot's goal
auto changeNextGoal = [&] { auto changeNextGoal = [&] {
int newGoal = findBestGoal (); const int newGoal = findBestGoal ();
m_prevGoalIndex = newGoal; m_prevGoalIndex = newGoal;
m_chosenGoalIndex = newGoal; m_chosenGoalIndex = newGoal;
@ -2227,10 +2227,10 @@ bool Bot::advanceMovement () {
selectBestNextNode (); selectBestNextNode ();
m_minSpeed = pev->maxspeed; m_minSpeed = pev->maxspeed;
Task taskID = getCurrentTaskId (); const auto tid = getCurrentTaskId ();
// only if we in normal task and bomb is not planted // only if we in normal task and bomb is not planted
if (taskID == Task::Normal && bots.getRoundMidTime () + 5.0f < game.time () && m_timeCamping + 5.0f < game.time () && !bots.isBombPlanted () && m_personality != Personality::Rusher && !m_hasC4 && !m_isVIP && m_loosedBombNodeIndex == kInvalidNodeIndex && !m_hasHostage && !m_isCreature) { if (tid == Task::Normal && bots.getRoundMidTime () + 5.0f < game.time () && m_timeCamping + 5.0f < game.time () && !bots.isBombPlanted () && m_personality != Personality::Rusher && !m_hasC4 && !m_isVIP && m_loosedBombNodeIndex == kInvalidNodeIndex && !m_hasHostage && !m_isCreature) {
m_campButtons = 0; m_campButtons = 0;
const int nextIndex = m_pathWalk.next (); const int nextIndex = m_pathWalk.next ();

View file

@ -243,20 +243,21 @@ void Bot::checkDarkness () {
} }
// do not check every frame // do not check every frame
if (m_checkDarkTime > game.time () || cr::fzero (m_path->light)) { if (m_checkDarkTime > game.time () || cr::fequal (m_path->light, kInvalidLightLevel)) {
return; return;
} }
const auto lightLevel = m_path->light;
const auto skyColor = illum.getSkyColor (); const auto skyColor = illum.getSkyColor ();
const auto flashOn = (pev->effects & EF_DIMLIGHT); const auto flashOn = (pev->effects & EF_DIMLIGHT);
if (mp_flashlight.bool_ () && !m_hasNVG) { if (mp_flashlight.bool_ () && !m_hasNVG) {
const auto task = getCurrentTaskId (); const auto tid = getCurrentTaskId ();
if (!flashOn && task != Task::Camp && task != Task::Attack && m_heardSoundTime + 3.0f < game.time () && m_flashLevel > 30 && ((skyColor > 50.0f && m_path->light < 10.0f) || (skyColor <= 50.0f && m_path->light < 40.0f))) { if (!flashOn && tid != Task::Camp && tid != Task::Attack && m_heardSoundTime + 3.0f < game.time () && m_flashLevel > 30 && ((skyColor > 50.0f && lightLevel < 10.0f) || (skyColor <= 50.0f && lightLevel < 40.0f))) {
pev->impulse = 100; pev->impulse = 100;
} }
else if (flashOn && (((m_path->light > 15.0f && skyColor > 50.0f) || (m_path->light > 45.0f && skyColor <= 50.0f)) || task == Task::Camp || task == Task::Attack || m_flashLevel <= 0 || m_heardSoundTime + 3.0f >= game.time ())) { else if (flashOn && (((lightLevel > 15.0f && skyColor > 50.0f) || (lightLevel > 45.0f && skyColor <= 50.0f)) || tid == Task::Camp || tid == Task::Attack || m_flashLevel <= 0 || m_heardSoundTime + 3.0f >= game.time ())) {
pev->impulse = 100; pev->impulse = 100;
} }
} }
@ -264,10 +265,10 @@ void Bot::checkDarkness () {
if (flashOn) { if (flashOn) {
pev->impulse = 100; pev->impulse = 100;
} }
else if (!m_usesNVG && ((skyColor > 50.0f && m_path->light < 15.0f) || (skyColor <= 50.0f && m_path->light < 40.0f))) { else if (!m_usesNVG && ((skyColor > 50.0f && lightLevel < 15.0f) || (skyColor <= 50.0f && lightLevel < 40.0f))) {
issueCommand ("nightvision"); issueCommand ("nightvision");
} }
else if (m_usesNVG && ((m_path->light > 20.0f && skyColor > 50.0f) || (m_path->light > 45.0f && skyColor <= 50.0f))) { else if (m_usesNVG && ((lightLevel > 20.0f && skyColor > 50.0f) || (lightLevel > 45.0f && skyColor <= 50.0f))) {
issueCommand ("nightvision"); issueCommand ("nightvision");
} }
} }