build: reworked build and package to simplify process

build: reworked build and package to simplify process
build: windows dll is now compiled by clang, msvc build added to extras package
fix: clear all the implicit conversions in the code (also fixed some bugs)
fix: crash on  never xash3d-fwgs engine
fix: fixed bad bot behaviors on aarch64
fix: crash on some maps due to missing previous node
fix: finally removed memset(this) within bot creatin
This commit is contained in:
jeefo 2023-04-02 12:17:12 +03:00 committed by GitHub
commit 53df621dfc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 1004 additions and 949 deletions

View file

@ -71,8 +71,8 @@ void Bot::pushMsgQueue (int message) {
}
float Bot::isInFOV (const Vector &destination) {
float entityAngle = cr::modAngles (destination.yaw ()); // find yaw angle from source to destination...
float viewAngle = cr::modAngles (pev->v_angle.y); // get bot's current view angle...
float entityAngle = cr::wrapAngle360 (destination.yaw ()); // find yaw angle from source to destination...
float viewAngle = cr::wrapAngle360 (pev->v_angle.y); // get bot's current view angle...
// return the absolute value of angle to destination entity
// zero degrees means straight ahead, 45 degrees to the left or
@ -232,7 +232,8 @@ void Bot::checkGrenadesThrow () {
}
break;
case Weapon::Flashbang: {
case Weapon::Flashbang:
{
int nearest = graph.getNearest ((m_lastEnemy->v.velocity * 0.5f).get2d () + m_lastEnemy->v.origin);
if (nearest != kInvalidNodeIndex) {
@ -339,7 +340,7 @@ void Bot::avoidGrenades () {
if (m_preventFlashing < game.time () && m_personality == Personality::Rusher && m_difficulty == Difficulty::Expert && strcmp (model, "flashbang.mdl") == 0) {
// don't look at flash bang
if (!(m_states & Sense::SeeingEnemy)) {
m_lookAt.y = cr::normalizeAngles ((game.getEntityOrigin (pent) - getEyesPos ()).angles ().y + 180.0f);
m_lookAt.y = cr::wrapAngle ((game.getEntityOrigin (pent) - getEyesPos ()).angles ().y + 180.0f);
m_canChooseAimDirection = false;
m_preventFlashing = game.time () + rg.get (1.0f, 2.0f);
@ -636,6 +637,7 @@ void Bot::updatePickups () {
const auto &config = conf.getWeapons ();
const auto &primary = config[primaryWeaponCarried];
const auto &secondary = config[secondaryWeaponCarried];
const auto &primaryProp = conf.getWeaponProp (primary.id);
const auto &secondaryProp = conf.getWeaponProp (secondary.id);
@ -950,7 +952,7 @@ void Bot::showChaterIcon (bool show) {
return;
}
auto sendBotVoice = [] (bool show, edict_t *ent, int ownId) {
auto sendBotVoice = [&show] (edict_t *ent, int ownId) {
MessageWriter (MSG_ONE, msgs.id (NetMsg::BotVoice), nullptr, ent) // begin message
.writeByte (show) // switch on/off
.writeByte (ownId);
@ -964,13 +966,13 @@ void Bot::showChaterIcon (bool show) {
}
if (!show && (client.iconFlags[ownIndex] & ClientFlags::Icon) && client.iconTimestamp[ownIndex] < game.time ()) {
sendBotVoice (false, client.ent, entindex ());
sendBotVoice (client.ent, entindex ());
client.iconTimestamp[ownIndex] = 0.0f;
client.iconFlags[ownIndex] &= ~ClientFlags::Icon;
}
else if (show && !(client.iconFlags[ownIndex] & ClientFlags::Icon)) {
sendBotVoice (true, client.ent, entindex ());
sendBotVoice (client.ent, entindex ());
}
}
}
@ -1225,43 +1227,36 @@ bool Bot::isWeaponRestrictedAMX (int weaponIndex) {
return false;
}
// check for weapon restrictions
if (cr::bit (weaponIndex) & (kPrimaryWeaponMask | kSecondaryWeaponMask | Weapon::Shield)) {
auto restrictedWeapons = game.findCvar ("amx_restrweapons");
auto checkRestriction = [&weaponIndex] (StringRef cvar, const int *data) -> bool {
auto restrictedWeapons = game.findCvar (cvar);
if (restrictedWeapons.empty ()) {
return false;
}
constexpr int indices[] = { 4, 25, 20, -1, 8, -1, 12, 19, -1, 5, 6, 13, 23, 17, 18, 1, 2, 21, 9, 24, 7, 16, 10, 22, -1, 3, 15, 14, 0, 11 };
// find the weapon index
int index = indices[weaponIndex - 1];
int index = data[weaponIndex - 1];
// validate index range
if (index < 0 || index >= static_cast <int> (restrictedWeapons.length ())) {
return false;
}
return restrictedWeapons[index] != '0';
return restrictedWeapons[static_cast <size_t> (index)] != '0';
};
// check for weapon restrictions
if (cr::bit (weaponIndex) & (kPrimaryWeaponMask | kSecondaryWeaponMask | Weapon::Shield)) {
constexpr int ids[] = { 4, 25, 20, -1, 8, -1, 12, 19, -1, 5, 6, 13, 23, 17, 18, 1, 2, 21, 9, 24, 7, 16, 10, 22, -1, 3, 15, 14, 0, 11 };
// verify restrictions
return checkRestriction ("amx_restrweapons", ids);
}
// check for equipment restrictions
else {
auto restrictedEquipment = game.findCvar ("amx_restrequipammo");
constexpr int ids[] = { -1, -1, -1, 3, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, 0, 1, 5 };
if (restrictedEquipment.empty ()) {
return false;
}
constexpr int indices[] = { -1, -1, -1, 3, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, 0, 1, 5 };
// find the weapon index
int index = indices[weaponIndex - 1];
// validate index range
if (index < 0 || index >= static_cast <int> (restrictedEquipment.length ())) {
return false;
}
return restrictedEquipment[index] != '0';
// verify restrictions
return checkRestriction ("amx_restrequipammo", ids);
}
}
@ -1294,7 +1289,7 @@ int Bot::pickBestWeapon (int *vec, int count, int moneySave) {
bool needMoreRandomWeapon = (m_personality == Personality::Careful) || (rg.chance (25) && m_personality == Personality::Normal);
if (needMoreRandomWeapon) {
auto buyFactor = (m_moneyAmount - static_cast <float> (moneySave)) / (16000.0f - static_cast <float> (moneySave)) * 3.0f;
auto buyFactor = (static_cast <float> (m_moneyAmount) - static_cast <float> (moneySave)) / (16000.0f - static_cast <float> (moneySave)) * 3.0f;
if (buyFactor < 1.0f) {
buyFactor = 1.0f;
@ -1537,7 +1532,7 @@ void Bot::buyStuff () {
break;
case BuyState::ArmorVestHelm: // if armor is damaged and bot has some money, buy some armor
if (pev->armorvalue < rg.get (50, 80) && teamHasGoodEconomics && (isPistolMode || (teamHasGoodEconomics && hasPrimaryWeapon ()))) {
if (pev->armorvalue < rg.get (50.0f, 80.0f) && teamHasGoodEconomics && (isPistolMode || (teamHasGoodEconomics && hasPrimaryWeapon ()))) {
// if bot is rich, buy kevlar + helmet, else buy a single kevlar
if (m_moneyAmount > 1500 && !isWeaponRestricted (Weapon::ArmorHelm)) {
issueCommand ("buyequip;menuselect 2");
@ -1988,7 +1983,7 @@ void Bot::filterTasks () {
timeHeard += 10.0f;
ratio = timeHeard * 0.1f;
}
bool lowAmmo = m_ammoInClip[m_currentWeapon] < conf.findWeaponById (m_currentWeapon).maxClip * 0.18f;
bool lowAmmo = isLowOnAmmo (m_currentWeapon, 0.18f);
bool sniping = m_sniperStopTime <= game.time () && lowAmmo;
if (bots.isBombPlanted () || m_isStuck || usesKnife ()) {
@ -2169,6 +2164,10 @@ BotTask *Bot::getTask () {
return &m_tasks.last ();
}
bool Bot::isLowOnAmmo (const int id, const float factor) const {
return static_cast <float> (m_ammoInClip[id]) < static_cast <float> (conf.findWeaponById (id).maxClip) * factor;
}
void Bot::clearTask (Task id) {
// this function removes one task from the bot task stack.
@ -2868,7 +2867,7 @@ void Bot::updateAimDir () {
auto radius = graph[index].radius;
if (radius > 0.0f) {
return Vector (pev->angles.x, cr::normalizeAngles (pev->angles.y + rg.get (-90.0f, 90.0f)), 0.0f).forward () * rg.get (2.0f, 4.0f);
return Vector (pev->angles.x, cr::wrapAngle (pev->angles.y + rg.get (-90.0f, 90.0f)), 0.0f).forward () * rg.get (2.0f, 4.0f);
}
return nullptr;
};
@ -3952,7 +3951,7 @@ void Bot::defuseBomb_ () {
graph.setBombOrigin (true);
if (m_numFriendsLeft != 0 && rg.chance (50)) {
if (timeToBlowUp <= 3.0) {
if (timeToBlowUp <= 3.0f) {
if (cv_radio_mode.int_ () == 2) {
pushChatterMessage (Chatter::BarelyDefused);
}
@ -4016,7 +4015,7 @@ void Bot::defuseBomb_ () {
selectWeaponByName ("weapon_knife");
if (weaponIndex > 0 && weaponIndex < kNumWeapons) {
selectWeaponById (weaponIndex);
selectWeaponByIndex (weaponIndex);
}
m_isReloading = false;
}
@ -4588,16 +4587,16 @@ void Bot::pickupItem_ () {
if (index < 7) {
// secondary weapon. i.e., pistol
int wid = 0;
int weaponIndex = 0;
for (index = 0; index < 7; ++index) {
if (pev->weapons & cr::bit (info[index].id)) {
wid = index;
weaponIndex = index;
}
}
if (wid > 0) {
selectWeaponById (wid);
if (weaponIndex > 0) {
selectWeaponByIndex (weaponIndex);
issueCommand ("drop");
if (hasShield ()) {
@ -4608,15 +4607,17 @@ void Bot::pickupItem_ () {
}
else {
// primary weapon
int wid = bestWeaponCarried ();
int weaponIndex = bestWeaponCarried ();
bool niceWeapon = rateGroundWeapon (m_pickupItem);
if ((wid == Weapon::Shield || wid > 6 || hasShield ()) && niceWeapon) {
selectWeaponById (wid);
auto tab = conf.getRawWeapons ();
if ((tab->id == Weapon::Shield || weaponIndex > 6 || hasShield ()) && niceWeapon) {
selectWeaponByIndex (weaponIndex);
issueCommand ("drop");
}
if (!wid || !niceWeapon) {
if (!weaponIndex || !niceWeapon) {
m_itemIgnore = m_pickupItem;
m_pickupItem = nullptr;
m_pickupType = Pickup::None;
@ -4640,10 +4641,10 @@ void Bot::pickupItem_ () {
// near to shield?
else if (itemDistance < 50.0f) {
// get current best weapon to check if it's a primary in need to be dropped
int wid = bestWeaponCarried ();
int weaponIndex = bestWeaponCarried ();
if (wid > 6) {
selectWeaponById (wid);
if (weaponIndex > 6) {
selectWeaponByIndex (weaponIndex);
issueCommand ("drop");
}
}
@ -5059,7 +5060,7 @@ void Bot::logic () {
pev->button &= ~IN_DUCK;
m_moveSpeed = -pev->maxspeed;
m_strafeSpeed = pev->maxspeed * m_needAvoidGrenade;
m_strafeSpeed = pev->maxspeed * static_cast <float> (m_needAvoidGrenade);
}
// time to reach waypoint
@ -5222,11 +5223,11 @@ void Bot::showDebugOverlay () {
}
String aimFlags;
for (int i = 0; i < 9; ++i) {
bool hasFlag = m_aimFlags & cr::bit (i);
for (uint32 i = 0u; i < 9u; ++i) {
auto bit = cr::bit (i);
if (hasFlag) {
aimFlags.appendf (" %s", flags[cr::bit (i)]);
if (m_aimFlags & bit) {
aimFlags.appendf (" %s", flags[static_cast <int32> (bit)]);
}
}
auto weapon = util.weaponIdToAlias (m_currentWeapon);
@ -5289,7 +5290,11 @@ bool Bot::hasHostage () {
}
int Bot::getAmmo () {
const auto &prop = conf.getWeaponProp (m_currentWeapon);
return getAmmo (m_currentWeapon);
}
int Bot::getAmmo (int id) {
const auto &prop = conf.getWeaponProp (id);
if (prop.ammo1 == -1 || prop.ammo1 > kMaxWeapons - 1) {
return 0;
@ -5408,11 +5413,12 @@ void Bot::updatePracticeValue (int damage) {
if (graph.length () < 1 || graph.hasChanged () || m_chosenGoalIndex < 0 || m_prevGoalIndex < 0) {
return;
}
auto health = static_cast <int> (m_healthValue);
// only rate goal waypoint if bot died because of the damage
// FIXME: could be done a lot better, however this cares most about damage done by sniping or really deadly weapons
if (m_healthValue - damage <= 0) {
graph.setDangerValue (m_team, m_chosenGoalIndex, m_prevGoalIndex, cr::clamp (graph.getDangerValue (m_team, m_chosenGoalIndex, m_prevGoalIndex) - static_cast <int> (m_healthValue / 20), -kMaxPracticeGoalValue, kMaxPracticeGoalValue));
if (health - damage <= 0) {
graph.setDangerValue (m_team, m_chosenGoalIndex, m_prevGoalIndex, cr::clamp (graph.getDangerValue (m_team, m_chosenGoalIndex, m_prevGoalIndex) - health / 20, -kMaxPracticeGoalValue, kMaxPracticeGoalValue));
}
}
@ -5453,10 +5459,10 @@ void Bot::updatePracticeDamage (edict_t *attacker, int damage) {
graph.setDangerDamage (victimIndex, victimIndex, victimIndex, cr::clamp (graph.getDangerDamage (victimTeam, victimIndex, victimIndex), 0, kMaxPracticeDamageValue));
}
}
float updateDamage = util.isFakeClient (attacker) ? 10.0f : 7.0f;
auto updateDamage = util.isFakeClient (attacker) ? 10 : 7;
// store away the damage done
int damageValue = cr::clamp (graph.getDangerDamage (m_team, victimIndex, attackerIndex) + static_cast <int> (damage / updateDamage), 0, kMaxPracticeDamageValue);
int damageValue = cr::clamp (graph.getDangerDamage (m_team, victimIndex, attackerIndex) + damage / updateDamage, 0, kMaxPracticeDamageValue);
if (damageValue > graph.getHighestDamageForTeam (m_team)) {
graph.setHighestDamageForTeam (m_team, damageValue);
@ -6047,7 +6053,7 @@ float Bot::getShiftSpeed () {
if (getCurrentTaskId () == Task::SeekCover || (pev->flags & FL_DUCKING) || (pev->button & IN_DUCK) || (m_oldButtons & IN_DUCK) || (m_currentTravelFlags & PathFlag::Jump) || (m_path != nullptr && m_path->flags & NodeFlag::Ladder) || isOnLadder () || isInWater () || m_isStuck) {
return pev->maxspeed;
}
return static_cast <float> (pev->maxspeed * 0.4f);
return pev->maxspeed * 0.4f;
}
void Bot::calculateFrustum () {

View file

@ -61,12 +61,12 @@ void BotSupport::addChatErrors (String &line) {
// "length / 2" percent of time drop a character
if (rg.chance (percentile)) {
line.erase (rg.get (length / 8, length - length / 8), 1);
line.erase (static_cast <size_t> (rg.get (length / 8, length - length / 8), 1));
}
// "length" / 4 precent of time swap character
if (rg.chance (percentile / 2)) {
size_t pos = rg.get (length / 8, 3 * length / 8); // choose random position in string
size_t pos = static_cast <size_t> (rg.get (length / 8, 3 * length / 8)); // choose random position in string
cr::swap (line[pos], line[pos + 1]);
}
}
@ -190,7 +190,7 @@ void Bot::prepareChatMessage (StringRef message) {
// get bot's victim
auto getMyVictim = [&] () -> String {;
return humanizedName (game.indexOfPlayer (m_lastVictim));
return humanizedName (game.indexOfPlayer (m_lastVictim));
};
// get the game name alias

View file

@ -461,8 +461,8 @@ Vector Bot::getBodyOffsetError (float distance) {
}
if (m_aimErrorTime < game.time ()) {
const float error = distance / (cr::clamp (m_difficulty, 1, 3) * 1000.0f);
Vector &maxs = m_enemy->v.maxs, &mins = m_enemy->v.mins;
const float error = distance / (cr::clamp (static_cast <float> (m_difficulty), 1.0f, 3.0f) * 1000.0f);
auto &maxs = m_enemy->v.maxs, &mins = m_enemy->v.mins;
m_aimLastError = Vector (rg.get (mins.x * error, maxs.x * error), rg.get (mins.y * error, maxs.y * error), rg.get (mins.z * error, maxs.z * error));
m_aimErrorTime = game.time () + rg.get (1.0f, 1.2f);
@ -728,7 +728,7 @@ bool Bot::needToPauseFiring (float distance) {
const float yPunch = cr::deg2rad (pev->punchangle.y);
const float interval = getFrameInterval ();
const float tolerance = (100.0f - m_difficulty * 25.0f) / 99.0f;
const float tolerance = (100.0f - static_cast <float> (m_difficulty) * 25.0f) / 99.0f;
// check if we need to compensate recoil
if (cr::tanf (cr::sqrtf (cr::abs (xPunch * xPunch) + cr::abs (yPunch * yPunch))) * distance > offset + 30.0f + tolerance) {
@ -848,10 +848,8 @@ void Bot::selectWeapons (float distance, int index, int id, int choosen) {
}
}
else {
const auto &prop = conf.getWeaponProp (tab[index].id);
// if automatic weapon press attack
if (tab[choosen].primaryFireHold && m_ammo[prop.ammo1] > tab[index].minPrimaryAmmo) {
if (tab[choosen].primaryFireHold && getAmmo (tab[index].id) > tab[index].minPrimaryAmmo) {
pev->button |= IN_ATTACK;
}
@ -953,9 +951,7 @@ void Bot::fireWeapons () {
// is the bot carrying this weapon?
if (weapons & cr::bit (id)) {
const auto &prop = conf.getWeaponProp (id);
if (prop.ammo1 != -1 && prop.ammo1 < kMaxWeapons && m_ammo[prop.ammo1] >= tab[selectIndex].minPrimaryAmmo) {
if (getAmmo (id) >= tab[selectIndex].minPrimaryAmmo) {
// available ammo found, reload weapon
if (m_reloadState == Reload::None || m_reloadCheckTime > game.time ()) {
@ -1431,10 +1427,9 @@ void Bot::selectBestWeapon () {
if (tab[selectIndex].id == m_currentWeapon && (getAmmoInClip () < 0 || getAmmoInClip () >= tab[selectIndex].minPrimaryAmmo)) {
ammoLeft = true;
}
const auto &prop = conf.getWeaponProp (id);
// is no ammo required for this weapon OR enough ammo available to fire
if (prop.ammo1 < 0 || (prop.ammo1 < kMaxWeapons && m_ammo[prop.ammo1] >= tab[selectIndex].minPrimaryAmmo)) {
if (getAmmo (id) >= tab[selectIndex].minPrimaryAmmo) {
ammoLeft = true;
}
@ -1485,14 +1480,13 @@ int Bot::bestWeaponCarried () {
return num;
}
void Bot::selectWeaponByName (const char *name) {
issueCommand (name);
void Bot::selectWeaponByName (StringRef name) {
issueCommand (name.chars ());
}
void Bot::selectWeaponById (int num) {
void Bot::selectWeaponByIndex (int index) {
auto tab = conf.getRawWeapons ();
issueCommand (tab[num].name);
issueCommand (tab[index].name);
}
void Bot::decideFollowUser () {
@ -1599,7 +1593,7 @@ void Bot::checkReload () {
m_reloadCheckTime = game.time () + 3.0f;
if (m_reloadState != Reload::None) {
int weaponIndex = 0;
int wid = 0;
int weapons = pev->weapons;
if (m_reloadState == Reload::Primary) {
@ -1620,15 +1614,15 @@ void Bot::checkReload () {
for (int i = 1; i < kMaxWeapons; ++i) {
if (weapons & cr::bit (i)) {
weaponIndex = i;
wid = i;
break;
}
}
const auto &prop = conf.getWeaponProp (weaponIndex);
const auto &prop = conf.getWeaponProp (wid);
if (m_ammoInClip[weaponIndex] < conf.findWeaponById (weaponIndex).maxClip * 0.8f && prop.ammo1 != -1 && prop.ammo1 < kMaxWeapons && m_ammo[prop.ammo1] > 0) {
if (m_currentWeapon != weaponIndex) {
selectWeaponByName (prop.classname.chars ());
if (isLowOnAmmo (prop.id, 0.75f) && getAmmo (prop.id) > 0) {
if (m_currentWeapon != prop.id) {
selectWeaponByName (prop.classname);
}
pev->button &= ~IN_ATTACK;

View file

@ -95,6 +95,9 @@ void BotConfig::loadMainConfig (bool isFirstLoad) {
}
file.close ();
}
else {
game.serverCommand (strings.format ("%s cvars save", product.cmdPri));
}
// android is abit hard to play, lower the difficulty by default
if (plat.android && cv_difficulty.int_ () > 3) {

View file

@ -45,10 +45,10 @@ int BotControl::cmdKickBot () {
enum args { alias = 1, team };
// if team is specified, kick from specified tram
if (strValue (alias).find ("_ct", 0) != String::InvalidIndex || intValue (team) == 2 || strValue (team) == "ct") {
if (strValue (alias).endsWith ("_ct") || intValue (team) == 2 || strValue (team) == "ct") {
bots.kickFromTeam (Team::CT);
}
else if (strValue (alias).find ("_t", 0) != String::InvalidIndex || intValue (team) == 1 || strValue (team) == "t") {
else if (strValue (alias).endsWith ("_t") || intValue (team) == 1 || strValue (team) == "t") {
bots.kickFromTeam (Team::Terrorist);
}
else {
@ -73,10 +73,10 @@ int BotControl::cmdKillBots () {
enum args { alias = 1, team, max };
// if team is specified, kick from specified tram
if (strValue (alias).find ("_ct", 0) != String::InvalidIndex || intValue (team) == 2 || strValue (team) == "ct") {
if (strValue (alias).endsWith ("_ct") || intValue (team) == 2 || strValue (team) == "ct") {
bots.killAllBots (Team::CT);
}
else if (strValue (alias).find ("_t", 0) != String::InvalidIndex || intValue (team) == 1 || strValue (team) == "t") {
else if (strValue (alias).endsWith ("_t") || intValue (team) == 1 || strValue (team) == "t") {
bots.killAllBots (Team::Terrorist);
}
else {
@ -488,7 +488,7 @@ int BotControl::cmdNodeSave () {
else {
if (graph.checkNodes (false)) {
graph.saveGraphData ();
msg ("All nodes has been saved and written to disk.");
msg ("All nodes has been saved and written to disk.\n*** Please don't forget to share your work by typing \"%s g upload\". Thank you! ***", product.cmdPri);
}
else {
msg ("Could not save save nodes to disk. Graph check has failed.");
@ -1943,7 +1943,7 @@ void BotControl::kickBotByMenu (int page) {
for (auto &menu : m_menus) {
if (menu.ident == id) {
menu.slots = menuKeys & static_cast <uint32> (-1);
menu.slots = static_cast <int> (static_cast <uint32> (menuKeys) & static_cast <uint32> (-1));
menu.text = menus;
break;

View file

@ -681,7 +681,7 @@ void Game::checkCvarsBounds () {
if (is (GameFlags::Xash3D)) {
static cvar_t *sv_forcesimulating = engfuncs.pfnCVarGetPointer ("sv_forcesimulating");
if (sv_forcesimulating && sv_forcesimulating->value != 1.0f) {
if (sv_forcesimulating && !cr::fequal (sv_forcesimulating->value, 1.0f)) {
game.print ("Force-enable Xash3D sv_forcesimulating cvar.");
engfuncs.pfnCVarSetFloat ("sv_forcesimulating", 1.0f);
}
@ -798,7 +798,7 @@ bool Game::loadCSBinary () {
auto entity = m_gameLib.resolve <EntityFunction> ("weapon_famas");
// detect xash engine
if (engfuncs.pfnCVarGetPointer ("build") != nullptr) {
if (engfuncs.pfnCVarGetPointer ("host_ver") != nullptr) {
m_gameFlags |= (GameFlags::Legacy | GameFlags::Xash3D);
if (entity != nullptr) {
@ -1035,7 +1035,7 @@ bool Game::isShootableBreakable (edict_t *ent) {
auto limit = cv_breakable_health_limit.float_ ();
if ((strcmp (ent->v.classname.chars (), "func_breakable") == 0 && ent->v.health < limit) || (strcmp (ent->v.classname.chars (), "func_pushable") == 0 && (ent->v.spawnflags & SF_PUSH_BREAKABLE) && ent->v.health < limit) || (strcmp (ent->v.classname.chars (), "func_wall") == 0 && ent->v.health < limit)) {
if (ent->v.takedamage != DAMAGE_NO && ent->v.impulse <= 0 && !(ent->v.flags & FL_WORLDBRUSH) && !(ent->v.spawnflags & SF_BREAK_TRIGGER_ONLY)) {
if (ent->v.takedamage > 0.0f && ent->v.impulse <= 0 && !(ent->v.flags & FL_WORLDBRUSH) && !(ent->v.spawnflags & SF_BREAK_TRIGGER_ONLY)) {
return (ent->v.movetype == MOVETYPE_PUSH || ent->v.movetype == MOVETYPE_PUSHSTEP);
}
}
@ -1112,8 +1112,7 @@ void LightMeasure::animateLight () {
m_lightstyleValue[j] = 256;
continue;
}
int value = m_lightstyle[j].map[index % m_lightstyle[j].length] - 'a';
m_lightstyleValue[j] = value * 22;
m_lightstyleValue[j] = static_cast <uint32> (m_lightstyle[j].map[index % m_lightstyle[j].length] - 'a') * 22u;
}
}

View file

@ -7,7 +7,7 @@
#include <yapb.h>
ConVar cv_graph_fixcamp ("yb_graph_fixcamp", "1", "Specifies whether bot should not 'fix' camp directions of camp waypoints when loading old PWF format.");
ConVar cv_graph_fixcamp ("yb_graph_fixcamp", "0", "Specifies whether bot should not 'fix' camp directions of camp waypoints when loading old PWF format.");
ConVar cv_graph_url ("yb_graph_url", product.download.chars (), "Specifies the URL from bots will be able to download graph in case of missing local one. Set to empty, if no downloads needed.", false, 0.0f, 0.0f);
ConVar cv_graph_auto_save_count ("yb_graph_auto_save_count", "15", "Every N graph nodes placed on map, the graph will be saved automatically (without checks).", true, 0.0f, kMaxNodes);
ConVar cv_graph_draw_distance ("yb_graph_draw_distance", "400", "Maximum distance to draw graph nodes from editor viewport.", true, 64.0f, 3072.0f);
@ -33,7 +33,6 @@ void BotGraph::reset () {
for (int team = Team::Terrorist; team < kGameTeamNum; ++team) {
m_highestDamage[team] = 1;
}
m_graphAuthor.clear ();
m_graphModified.clear ();
}
@ -59,7 +58,7 @@ int BotGraph::clearConnections (int index) {
struct Connection {
int index {};
int number {};
int distance {};
float distance {};
float angles {};
public:
@ -71,7 +70,7 @@ int BotGraph::clearConnections (int index) {
void reset () {
index = kInvalidNodeIndex;
number = kInvalidNodeIndex;
distance = kInfiniteDistanceLong;
distance = kInfiniteDistance;
angles = 0.0f;
}
};
@ -86,14 +85,14 @@ int BotGraph::clearConnections (int index) {
cur.number = i;
cur.index = link.index;
cur.distance = link.distance;
cur.distance = static_cast <float> (link.distance);
if (cur.index == kInvalidNodeIndex) {
cur.distance = kInfiniteDistanceLong;
cur.distance = kInfiniteDistance;
}
if (cur.distance < top.distance) {
top.distance = link.distance;
top.distance = static_cast <float> (link.distance);
top.number = i;
top.index = cur.index;
}
@ -173,7 +172,7 @@ int BotGraph::clearConnections (int index) {
return false;
}
if ((cur.distance + prev2.distance) * 1.1f / 2.0f < static_cast <float> (prev.distance)) {
if ((cur.distance + prev2.distance) * 1.1f / 2.0f < prev.distance) {
if (path.links[prev.number].index == prev.index) {
ctrl.msg ("Removing a useless (P.0.1) connection from index = %d to %d.", index, prev.index);
@ -215,7 +214,7 @@ int BotGraph::clearConnections (int index) {
// check pass 1
if (exists (top.index) && exists (sorted[0].index) && exists (sorted[1].index)) {
if ((sorted[1].angles - top.angles < 80.0f || 360.0f - (sorted[1].angles - top.angles) < 80.0f) && (!(m_paths[sorted[0].index].flags & NodeFlag::Ladder) || !(path.flags & NodeFlag::Ladder)) && !(path.links[sorted[0].number].flags & PathFlag::Jump)) {
if ((sorted[1].distance + top.distance) * 1.1f / 2.0f < static_cast <float> (sorted[0].distance)) {
if ((sorted[1].distance + top.distance) * 1.1f / 2.0f < sorted[0].distance) {
if (path.links[sorted[0].number].index == sorted[0].index) {
ctrl.msg ("Removing a useless (P.1.1) connection from index = %d to %d.", index, sorted[0].index);
@ -257,7 +256,7 @@ int BotGraph::clearConnections (int index) {
}
if (cur.angles - prev.angles < 40.0f) {
if (prev.distance < static_cast <float> (cur.distance * 1.1f)) {
if (prev.distance < cur.distance * 1.1f) {
// leave alone ladder connections and don't remove jump connections..
if (((path.flags & NodeFlag::Ladder) && (m_paths[cur.index].flags & NodeFlag::Ladder)) || (path.links[cur.number].flags & PathFlag::Jump)) {
@ -290,7 +289,7 @@ int BotGraph::clearConnections (int index) {
ctrl.msg ("Failed to remove a useless (P.2) connection from index = %d to %d.", index, cur.index);
}
}
else if (cur.distance < static_cast <float> (prev.distance * 1.1f)) {
else if (cur.distance < prev.distance * 1.1f) {
// leave alone ladder connections and don't remove jump connections..
if (((path.flags & NodeFlag::Ladder) && (m_paths[prev.index].flags & NodeFlag::Ladder)) || (path.links[prev.number].flags & PathFlag::Jump)) {
return false;
@ -338,7 +337,7 @@ int BotGraph::clearConnections (int index) {
// check pass 3
if (exists (top.index) && exists (sorted[0].index)) {
if ((top.angles - sorted[0].angles < 40.0f || (360.0f - top.angles - sorted[0].angles) < 40.0f) && (!(m_paths[sorted[0].index].flags & NodeFlag::Ladder) || !(path.flags & NodeFlag::Ladder)) && !(path.links[sorted[0].number].flags & PathFlag::Jump)) {
if (top.distance * 1.1f < static_cast <float> (sorted[0].distance)) {
if (top.distance * 1.1f < sorted[0].distance) {
if (path.links[sorted[0].number].index == sorted[0].index) {
ctrl.msg ("Removing a useless (P.3.1) connection from index = %d to %d.", index, sorted[0].index);
@ -364,7 +363,7 @@ int BotGraph::clearConnections (int index) {
ctrl.msg ("Failed to remove a useless (P.3) connection from index = %d to %d.", sorted[0].index, index);
}
}
else if (sorted[0].distance * 1.1f < static_cast <float> (top.distance) && !(path.links[top.number].flags & PathFlag::Jump)) {
else if (sorted[0].distance * 1.1f < top.distance && !(path.links[top.number].flags & PathFlag::Jump)) {
if (path.links[top.number].index == top.index) {
ctrl.msg ("Removing a useless (P.3.3) connection from index = %d to %d.", index, sorted[0].index);
@ -903,7 +902,7 @@ void BotGraph::setRadius (int index, float radius) {
int node = exists (index) ? index : getEditorNearest ();
if (node != kInvalidNodeIndex) {
m_paths[node].radius = static_cast <float> (radius);
m_paths[node].radius = radius;
// play "done" sound...
game.playSound (m_editor, "common/wpn_hudon.wav");
@ -1235,7 +1234,7 @@ void BotGraph::calculatePathRadius (int index) {
break;
}
direction.y = cr::normalizeAngles (direction.y + static_cast <float> (circleRadius));
direction.y = cr::wrapAngle (direction.y + static_cast <float> (circleRadius));
}
if (wayBlocked) {
@ -1362,7 +1361,7 @@ bool BotGraph::loadPathMatrix () {
if (distance < (matrix + (i * count) + j)->dist) {
(matrix + (i * count) + j)->dist = static_cast <int16> (distance);
(matrix + (i * count) + j)->index = static_cast <int16> ((matrix + (i * count) + k)->index);
(matrix + (i * count) + j)->index = (matrix + (i * count) + k)->index;
}
}
}
@ -1625,11 +1624,11 @@ template <typename U> bool BotGraph::saveStorage (StringRef ext, StringRef name,
logger.error ("Unable to open %s file for writing (filename: '%s').", name, filename);
return false;
}
int32 rawLength = data.template length <int32> () * sizeof (U);
auto rawLength = data.length () * sizeof (U);
SmallArray <uint8> compressed (rawLength + sizeof (uint8) * ULZ::Excess);
// try to compress
auto compressedLength = ulz.compress (reinterpret_cast <uint8 *> (data.data ()), rawLength, reinterpret_cast <uint8 *> (compressed.data ()));
auto compressedLength = static_cast <size_t> (ulz.compress (reinterpret_cast <uint8 *> (data.data ()), static_cast <int32> (rawLength), reinterpret_cast <uint8 *> (compressed.data ())));
if (compressedLength > 0) {
StorageHeader hdr {};
@ -1638,8 +1637,8 @@ template <typename U> bool BotGraph::saveStorage (StringRef ext, StringRef name,
hdr.version = version;
hdr.options = options;
hdr.length = length ();
hdr.compressed = compressedLength;
hdr.uncompressed = rawLength;
hdr.compressed = static_cast <int32> (compressedLength);
hdr.uncompressed = static_cast <int32> (rawLength);
file.write (&hdr, sizeof (StorageHeader));
file.write (compressed.data (), sizeof (uint8), compressedLength);
@ -1788,15 +1787,18 @@ template <typename U> bool BotGraph::loadStorage (StringRef ext, StringRef name,
if ((hdr.options & options) != options) {
return raiseLoadingError (isGraph, file, "Incorrect storage format for %s (filename: '%s').", name, filename);
}
SmallArray <uint8> compressed (hdr.compressed + sizeof (uint8) * ULZ::Excess);
auto compressedSize = static_cast <size_t> (hdr.compressed);
auto numberNodes = static_cast <size_t> (hdr.length);
SmallArray <uint8> compressed (compressedSize + sizeof (uint8) * ULZ::Excess);
// graph is not resized upon load
if (isGraph) {
resizeData (hdr.length);
resizeData (numberNodes);
}
// read compressed data
if (file.read (compressed.data (), sizeof (uint8), hdr.compressed) == static_cast <size_t> (hdr.compressed)) {
if (file.read (compressed.data (), sizeof (uint8), compressedSize) == compressedSize) {
// try to uncompress
if (ulz.uncompress (compressed.data (), hdr.compressed, reinterpret_cast <uint8 *> (data.data ()), hdr.uncompressed) == ULZ::UncompressFailure) {
@ -1837,6 +1839,7 @@ template <typename U> bool BotGraph::loadStorage (StringRef ext, StringRef name,
else {
return raiseLoadingError (isGraph, file, "Unable to read ULZ data for %s (filename: '%s').", name, filename);
}
return false;
}
bool BotGraph::loadGraphData () {
@ -2031,7 +2034,7 @@ bool BotGraph::isNodeReacheable (const Vector &src, const Vector &destination) {
game.testLine (sourceNew, destinationNew, TraceIgnore::Monsters, m_editor, &tr);
// check if we didn't hit anything, if not then it's in mid-air
if (tr.flFraction >= 1.0) {
if (tr.flFraction >= 1.0f) {
return false; // can't reach this one
}
}
@ -2143,10 +2146,10 @@ void BotGraph::rebuildVisibility () {
res &= 2;
}
}
shift = (path.number % 4) << 1;
shift = static_cast <uint8> ((path.number % 4) << 1);
m_vistable[vis.number * m_paths.length () + path.number] &= ~(3 << shift);
m_vistable[vis.number * m_paths.length () + path.number] |= res << shift;
m_vistable[vis.number * length () + path.number] &= static_cast <uint8> (~(3 << shift));
m_vistable[vis.number * length () + path.number] |= res << shift;
if (!(res & 2)) {
++crouchCount;
@ -2168,7 +2171,7 @@ bool BotGraph::isVisible (int srcIndex, int destIndex) {
return false;
}
uint8 res = m_vistable[srcIndex * m_paths.length () + destIndex];
uint8 res = m_vistable[srcIndex * length () + destIndex];
res >>= (destIndex % 4) << 1;
return !((res & 3) == 3);
@ -2179,7 +2182,7 @@ bool BotGraph::isDuckVisible (int srcIndex, int destIndex) {
return false;
}
uint8 res = m_vistable[srcIndex * m_paths.length () + destIndex];
uint8 res = m_vistable[srcIndex * length () + destIndex];
res >>= (destIndex % 4) << 1;
return !((res & 2) == 2);
@ -2190,7 +2193,7 @@ bool BotGraph::isStandVisible (int srcIndex, int destIndex) {
return false;
}
uint8 res = m_vistable[srcIndex * m_paths.length () + destIndex];
uint8 res = m_vistable[srcIndex * length () + destIndex];
res >>= (destIndex % 4) << 1;
return !((res & 1) == 1);
@ -2498,18 +2501,29 @@ void BotGraph::frame () {
auto getNodeData = [&] (StringRef type, int node) -> String {
String message, flags;
const auto &path = m_paths[node];
const auto &p = m_paths[node];
bool jumpPoint = false;
// iterate through connections and find, if it's a jump path
for (const auto &link : path.links) {
for (const auto &link : p.links) {
// check if we got a valid connection
if (link.index != kInvalidNodeIndex && (link.flags & PathFlag::Jump)) {
jumpPoint = true;
}
}
flags.assignf ("%s%s%s%s%s%s%s%s%s%s%s%s", (path.flags & NodeFlag::Lift) ? " LIFT" : "", (path.flags & NodeFlag::Crouch) ? " CROUCH" : "", (path.flags & NodeFlag::Camp) ? " CAMP" : "", (path.flags & NodeFlag::TerroristOnly) ? " TERRORIST" : "", (path.flags & NodeFlag::CTOnly) ? " CT" : "", (path.flags & NodeFlag::Sniper) ? " SNIPER" : "", (path.flags & NodeFlag::Goal) ? " GOAL" : "", (path.flags & NodeFlag::Ladder) ? " LADDER" : "", (path.flags & NodeFlag::Rescue) ? " RESCUE" : "", (path.flags & NodeFlag::DoubleJump) ? " JUMPHELP" : "", (path.flags & NodeFlag::NoHostage) ? " NOHOSTAGE" : "", jumpPoint ? " JUMP" : "");
flags.assignf ("%s%s%s%s%s%s%s%s%s%s%s%s",
(p.flags & NodeFlag::Lift) ? " LIFT" : "",
(p.flags & NodeFlag::Crouch) ? " CROUCH" : "",
(p.flags & NodeFlag::Camp) ? " CAMP" : "",
(p.flags & NodeFlag::TerroristOnly) ? " TERRORIST" : "",
(p.flags & NodeFlag::CTOnly) ? " CT" : "",
(p.flags & NodeFlag::Sniper) ? " SNIPER" : "",
(p.flags & NodeFlag::Goal) ? " GOAL" : "",
(p.flags & NodeFlag::Ladder) ? " LADDER" : "",
(p.flags & NodeFlag::Rescue) ? " RESCUE" : "",
(p.flags & NodeFlag::DoubleJump) ? " JUMPHELP" : "",
(p.flags & NodeFlag::NoHostage) ? " NOHOSTAGE" : "", jumpPoint ? " JUMP" : "");
if (flags.empty ()) {
flags.assign ("(none)");
@ -2519,7 +2533,7 @@ void BotGraph::frame () {
message.assignf (" %s node:\n"
" Node %d of %d, Radius: %.1f, Light: %.1f\n"
" Flags: %s\n"
" Origin: (%.1f, %.1f, %.1f)\n", type, node, m_paths.length () - 1, path.radius, path.light, flags, path.origin.x, path.origin.y, path.origin.z);
" 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);
return message;
};
@ -2669,11 +2683,16 @@ bool BotGraph::checkNodes (bool teleportPlayer) {
}
// perform DFS instead of floyd-warshall, this shit speedup this process in a bit
auto length = cr::min (static_cast <size_t> (kMaxNodes), m_paths.length ());
// ensure valid capacity
assert (length > 8 && length < static_cast <size_t> (kMaxNodes));
PathWalk walk;
walk.init (m_paths.length ());
walk.init (length);
Array <bool> visited;
visited.resize (m_paths.length ());
visited.resize (length);
// first check incoming connectivity, initialize the "visited" table
for (auto &visit : visited) {
@ -2710,10 +2729,10 @@ bool BotGraph::checkNodes (bool teleportPlayer) {
// then check outgoing connectivity
Array <IntArray> outgoingPaths; // store incoming paths for speedup
outgoingPaths.resize (m_paths.length ());
outgoingPaths.resize (length);
for (const auto &path : m_paths) {
outgoingPaths[path.number].resize (m_paths.length () + 1);
outgoingPaths[path.number].resize (length + 1);
for (const auto &link : path.links) {
if (exists (link.index)) {
@ -3123,8 +3142,8 @@ void BotGraph::convertFromPOD (Path &path, const PODPath &pod) {
path.links[i].flags = pod.conflags[i];
path.links[i].velocity = pod.velocity[i];
}
path.vis.stand = pod.vis.stand;
path.vis.crouch = pod.vis.crouch;
path.vis.stand = 0;
path.vis.crouch = 0;
}
void BotGraph::convertToPOD (const Path &path, PODPath &pod) {

View file

@ -1010,12 +1010,12 @@ CR_EXPORT int Server_GetPhysicsInterface (int version, server_physics_api_t *phy
return HLTrue;
}
DLSYM_RETURN EntityLinkage::lookup (SharedLibrary::Handle module, const char *function) {
SharedLibrary::Func EntityLinkage::lookup (SharedLibrary::Handle module, const char *function) {
static const auto &gamedll = game.lib ().handle ();
static const auto &self = m_self.handle ();
const auto resolve = [&] (SharedLibrary::Handle handle) {
return reinterpret_cast <DLSYM_RETURN> (m_dlsym (static_cast <DLSYM_HANDLE> (handle), function));
return m_dlsym (handle, function);
};
if (ents.needsBypass () && !strcmp (function, "CreateInterface")) {
@ -1028,10 +1028,16 @@ DLSYM_RETURN EntityLinkage::lookup (SharedLibrary::Handle module, const char *fu
}
// if requested module is yapb module, put in cache the looked up symbol
if (self != module || (plat.win && (static_cast <uint16> (reinterpret_cast <unsigned long> (function) >> 16) & 0xffff) == 0)) {
if (self != module) {
return resolve (module);
}
#if defined (CR_WINDOWS)
if (HIWORD (function) == 0) {
return resolve (module);
}
#endif
if (m_exports.has (function)) {
return m_exports[function];
}
@ -1057,7 +1063,7 @@ void EntityLinkage::callPlayerFunction (edict_t *ent) {
playerFunction = game.lib ().resolve <EntityFunction> ("player");
}
else {
playerFunction = reinterpret_cast <EntityFunction> (lookup (game.lib ().handle (), "player"));
playerFunction = reinterpret_cast <EntityFunction> (reinterpret_cast <void *> (lookup (game.lib ().handle (), "player")));
}
if (!playerFunction) {

View file

@ -132,7 +132,7 @@ void BotManager::touchKillerEntity (Bot *bot) {
KeyValueData kv {};
kv.szClassName = const_cast <char *> (prop.classname.chars ());
kv.szKeyName = "damagetype";
kv.szValue = const_cast <char *> (strings.format ("%d", cr::bit (4)));
kv.szValue = strings.format ("%d", cr::bit (4));
kv.fHandled = HLFalse;
MDLL_KeyValue (m_killerEntity, &kv);
@ -782,7 +782,6 @@ void BotManager::listBots () {
ctrl.msg ("%-3.5s\t%-19.16s\t%-10.12s\t%-3.4s\t%-3.4s\t%-3.4s\t%-3.5s\t%-3.8s", "index", "name", "personality", "team", "difficulty", "frags", "alive", "timeleft");
for (const auto &bot : bots) {
;
ctrl.msg ("[%-3.1d]\t%-19.16s\t%-10.12s\t%-3.4s\t%-3.1d\t%-3.1d\t%-3.4s\t%-3.0f secs", bot->index (), bot->pev->netname.chars (), bot->m_personality == Personality::Rusher ? "rusher" : bot->m_personality == Personality::Normal ? "normal" : "careful", bot->m_team == Team::CT ? "CT" : "T", bot->m_difficulty, static_cast <int> (bot->pev->frags), bot->m_notKilled ? "yes" : "no", bot->m_stayTime - game.time ());
}
ctrl.msg ("%d bots", m_bots.length ());
@ -819,7 +818,7 @@ float BotManager::getAverageTeamKPD (bool calcForBots) {
}
if (calc.second > 0) {
return calc.first / calc.second;
return calc.first / static_cast <float> (calc.second);
}
return 0.0f;
}
@ -930,10 +929,10 @@ void BotManager::balanceBotDifficulties () {
float score = bot->m_kpdRatio;
// if kd ratio is going to go to low, we need to try to set higher difficulty
if (score < 0.8 || (score <= 1.2 && ratioBots < ratioPlayer)) {
if (score < 0.8f || (score <= 1.2f && ratioBots < ratioPlayer)) {
updateDifficulty (bot.get (), +1);
}
else if (score > 4.0f || (score >= 2.5 && ratioBots > ratioPlayer)) {
else if (score > 4.0f || (score >= 2.5f && ratioBots > ratioPlayer)) {
updateDifficulty (bot.get (), -1);
}
}
@ -949,9 +948,6 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int skin) {
// this function does core operation of creating bot, it's called by addbot (),
// when bot setup completed, (this is a bot class constructor)
// we're not initializing all the variables in bot class, so do an ugly thing... memset this
plat.bzero (this, sizeof (*this));
int clientIndex = game.indexOfEntity (bot);
pev = &bot->v;
@ -1458,7 +1454,7 @@ void Bot::resetPathSearchType () {
switch (m_personality) {
default:
case Personality::Normal:
m_pathType = morale ? FindPath::Optimal : FindPath::Safe;
m_pathType = morale ? FindPath::Optimal : FindPath::Fast;
break;
case Personality::Rusher:

View file

@ -335,7 +335,7 @@ void MessageDispatcher::netMsgScoreInfo () {
// if we're have bot, set the kd ratio
if (bot != nullptr) {
bot->m_kpdRatio = bot->pev->frags / cr::max <long> (m_args[deaths].long_, 1);
bot->m_kpdRatio = bot->pev->frags / cr::max (static_cast <float> (m_args[deaths].long_), 1.0f);
}
}

View file

@ -23,7 +23,7 @@ private:
public:
// get the bot version string
virtual const char *getBotVersion () override {
return MODULE_BOT_VERSION "." MODULE_BUILD_COUNT;
return MODULE_VERSION "." MODULE_COMMIT_COUNT;
}
// checks if bots are currently in game

View file

@ -82,6 +82,7 @@ int Bot::findBestGoal () {
tactic = 4;
return findGoalPost (tactic, defensiveNodes, offensiveNodes);
}
auto difficulty = static_cast <float> (m_difficulty);
offensive = m_agressionLevel * 100.0f;
defensive = m_fearLevel * 100.0f;
@ -94,8 +95,8 @@ int Bot::findBestGoal () {
else if (m_team == Team::CT) {
// on hostage maps force more bots to save hostages
if (game.mapIs (MapFlags::HostageRescue)) {
defensive -= 25.0f - m_difficulty * 0.5f;
offensive += 25.0f + m_difficulty * 5.0f;
defensive -= 25.0f - difficulty * 0.5f;
offensive += 25.0f + difficulty * 5.0f;
}
else {
defensive -= 25.0f;
@ -112,8 +113,8 @@ int Bot::findBestGoal () {
}
return m_chosenGoalIndex = findBombNode ();
}
defensive += 25.0f + m_difficulty * 4.0f;
offensive -= 25.0f - m_difficulty * 0.5f;
defensive += 25.0f + difficulty * 4.0f;
offensive -= 25.0f - difficulty * 0.5f;
if (m_personality != Personality::Rusher) {
defensive += 10.0f;
@ -121,7 +122,7 @@ int Bot::findBestGoal () {
}
else if (game.mapIs (MapFlags::Demolition) && m_team == Team::Terrorist && bots.getRoundStartTime () + 10.0f < game.time ()) {
// send some terrorists to guard planted bomb
if (!m_defendedBomb && bots.isBombPlanted () && getCurrentTaskId () != Task::EscapeFromBomb && getBombTimeleft () >= 15.0) {
if (!m_defendedBomb && bots.isBombPlanted () && getCurrentTaskId () != Task::EscapeFromBomb && getBombTimeleft () >= 15.0f) {
return pushToHistroy (m_chosenGoalIndex = graph.getNearest (graph.getBombOrigin ()));
}
}
@ -456,21 +457,18 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
// bot is stuc, but not yet decided what to do?
if (m_collisionState == CollisionState::Undecided) {
int bits = 0;
uint32 bits = 0;
if (isOnLadder ()) {
bits |= CollisionProbe::Strafe;
}
else if (isInWater ()) {
bits |= (CollisionProbe::Jump | CollisionProbe::Strafe);
}
else {
bits |= (CollisionProbe::Strafe | CollisionProbe::Jump);
}
// collision check allowed if not flying through the air
if (isOnFloor () || isOnLadder () || isInWater ()) {
int state[kMaxCollideMoves * 2 + 1] {};
uint32 state[kMaxCollideMoves * 2 + 1] {};
int i = 0;
Vector src {}, dst {};
@ -689,7 +687,7 @@ bool Bot::updateNavigation () {
// if graph node radius non zero vary origin a bit depending on the body angles
if (m_path->radius > 0.0f) {
m_pathOrigin += Vector (pev->angles.x, cr::normalizeAngles (pev->angles.y + rg.get (-90.0f, 90.0f)), 0.0f).forward () * rg.get (0.0f, m_path->radius);
m_pathOrigin += Vector (pev->angles.x, cr::wrapAngle (pev->angles.y + rg.get (-90.0f, 90.0f)), 0.0f).forward () * rg.get (0.0f, m_path->radius);
}
m_navTimeset = game.time ();
}
@ -726,7 +724,7 @@ bool Bot::updateNavigation () {
}
}
if (!(graph[m_previousNodes[0]].flags & NodeFlag::Ladder)) {
if (graph.exists (m_previousNodes[0]) && (graph[m_previousNodes[0]].flags & NodeFlag::Ladder)) {
if (cr::abs (m_pathOrigin.z - pev->origin.z) > 5.0f) {
m_pathOrigin.z += pev->origin.z - m_pathOrigin.z;
}
@ -1325,7 +1323,7 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath:
// this function finds a path from srcIndex to destIndex
auto dangerFactor = [&] () -> float {
return rg.get (cv_path_danger_factor_min.float_ (), cv_path_danger_factor_max.float_ ()) * 2.0f / cr::clamp (m_difficulty, 1, 3);
return rg.get (cv_path_danger_factor_min.float_ (), cv_path_danger_factor_max.float_ ()) * 2.0f / cr::clamp (static_cast <float> (m_difficulty), 1.0f, 4.0f);
};
// least kills and number of nodes to goal for a team
@ -1403,11 +1401,13 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath:
for (const auto &link : parent.links) {
if (link.index == currentIndex) {
const auto distance = static_cast <float> (link.distance);
// we don't like ladder or crouch point
if (current.flags & (NodeFlag::Crouch | NodeFlag::Ladder)) {
return link.distance * 1.5f;
return distance * 1.5f;
}
return static_cast <float> (link.distance);
return distance;
}
}
return 65355.0f;
@ -1608,7 +1608,7 @@ void Bot::clearSearchNodes () {
}
void Bot::clearRoute () {
m_routes.resize (graph.length ());
m_routes.resize (static_cast <size_t> (graph.length ()));
for (int i = 0; i < graph.length (); ++i) {
auto route = &m_routes[i];
@ -1633,7 +1633,7 @@ int Bot::findAimingNode (const Vector &to) {
if (destIndex == kInvalidNodeIndex) {
return kInvalidNodeIndex;
}
const float kMaxDistance = ((m_states & Sense::HearingEnemy) || (m_states & Sense::HearingEnemy) || m_seeEnemyTime + 3.0f > game.time ()) ? 0.0f : 512.0f;
const float kMaxDistance = ((m_states & Sense::HearingEnemy) || (m_states & Sense::SuspectEnemy) || m_seeEnemyTime + 3.0f > game.time ()) ? 0.0f : 512.0f;
while (destIndex != m_currentNodeIndex) {
destIndex = (graph.m_matrix.data () + (destIndex * graph.length ()) + m_currentNodeIndex)->index;
@ -2411,7 +2411,7 @@ bool Bot::advanceMovement () {
// if wayzone radius non zero vary origin a bit depending on the body angles
if (m_path->radius > 0.0f) {
m_pathOrigin += Vector (pev->angles.x, cr::normalizeAngles (pev->angles.y + rg.get (-90.0f, 90.0f)), 0.0f).forward () * rg.get (0.0f, m_path->radius);
m_pathOrigin += Vector (pev->angles.x, cr::wrapAngle (pev->angles.y + rg.get (-90.0f, 90.0f)), 0.0f).forward () * rg.get (0.0f, m_path->radius);
}
if (isOnLadder ()) {
@ -2432,17 +2432,17 @@ bool Bot::cantMoveForward (const Vector &normal, TraceResult *tr) {
// use some TraceLines to determine if anything is blocking the current path of the bot.
// first do a trace from the bot's eyes forward...
Vector src = getEyesPos ();
Vector forward = src + normal * 24.0f;
auto src = getEyesPos ();
auto forward = src + normal * 24.0f;
auto right = Vector (0.0f, pev->angles.y, 0.0f).right ();
const auto &right = Vector (0.0f, pev->angles.y, 0.0f).right ();
bool traceResult = false;
auto checkDoor = [&traceResult] (TraceResult *tr) {
auto checkDoor = [&traceResult] (TraceResult *result) {
if (!game.mapIs (MapFlags::HasDoors)) {
return false;
}
return !traceResult && tr->flFraction < 1.0f && strncmp ("func_door", tr->pHit->v.classname.chars (), 9) != 0;
return !traceResult && result->flFraction < 1.0f && strncmp ("func_door", result->pHit->v.classname.chars (), 9) != 0;
};
// trace from the bot's eyes straight forward...
@ -2596,11 +2596,11 @@ bool Bot::canJumpUp (const Vector &normal) {
if (!isOnFloor () && (isOnLadder () || !isInWater ())) {
return false;
}
const auto &right = Vector (0.0f, pev->angles.y, 0.0f).right (); // convert current view angle to vectors for traceline math...
auto right = Vector (0.0f, pev->angles.y, 0.0f).right (); // convert current view angle to vectors for traceline math...
// check for normal jump height first...
Vector src = pev->origin + Vector (0.0f, 0.0f, -36.0f + 45.0f);
Vector dest = src + normal * 32.0f;
auto src = pev->origin + Vector (0.0f, 0.0f, -36.0f + 45.0f);
auto dest = src + normal * 32.0f;
// trace a line forward at maximum jump height...
game.testLine (src, dest, TraceIgnore::Monsters, ent (), &tr);
@ -2762,7 +2762,7 @@ bool Bot::canDuckUnder (const Vector &normal) {
}
// convert current view angle to vectors for TraceLine math...
const auto &right = Vector (0.0f, pev->angles.y, 0.0f).right ();
auto right = Vector (0.0f, pev->angles.y, 0.0f).right ();
// now check same height to one side of the bot...
src = baseHeight + right * 16.0f;
@ -2900,14 +2900,14 @@ bool Bot::isDeadlyMove (const Vector &to) {
void Bot::changePitch (float speed) {
// this function turns a bot towards its ideal_pitch
float idealPitch = cr::normalizeAngles (pev->idealpitch);
float curent = cr::normalizeAngles (pev->v_angle.x);
float idealPitch = cr::wrapAngle (pev->idealpitch);
float curent = cr::wrapAngle (pev->v_angle.x);
// turn from the current v_angle pitch to the idealpitch by selecting
// the quickest way to turn to face that direction
// find the difference in the curent and ideal angle
float normalizePitch = cr::normalizeAngles (idealPitch - curent);
float normalizePitch = cr::wrapAngle (idealPitch - curent);
if (normalizePitch > 0.0f) {
if (normalizePitch > speed) {
@ -2920,7 +2920,7 @@ void Bot::changePitch (float speed) {
}
}
pev->v_angle.x = cr::normalizeAngles (curent + normalizePitch);
pev->v_angle.x = cr::wrapAngle (curent + normalizePitch);
if (pev->v_angle.x > 89.9f) {
pev->v_angle.x = 89.9f;
@ -2935,14 +2935,14 @@ void Bot::changePitch (float speed) {
void Bot::changeYaw (float speed) {
// this function turns a bot towards its ideal_yaw
float idealPitch = cr::normalizeAngles (pev->ideal_yaw);
float curent = cr::normalizeAngles (pev->v_angle.y);
float idealPitch = cr::wrapAngle (pev->ideal_yaw);
float curent = cr::wrapAngle (pev->v_angle.y);
// turn from the current v_angle yaw to the ideal_yaw by selecting
// the quickest way to turn to face that direction
// find the difference in the curent and ideal angle
float normalizePitch = cr::normalizeAngles (idealPitch - curent);
float normalizePitch = cr::wrapAngle (idealPitch - curent);
if (normalizePitch > 0.0f) {
if (normalizePitch > speed) {
@ -2954,7 +2954,7 @@ void Bot::changeYaw (float speed) {
normalizePitch = -speed;
}
}
pev->v_angle.y = cr::normalizeAngles (curent + normalizePitch);
pev->v_angle.y = cr::wrapAngle (curent + normalizePitch);
pev->angles.y = pev->v_angle.y;
}
@ -3084,7 +3084,7 @@ void Bot::updateLookAnglesNewbie (const Vector &direction, float delta) {
Vector spring { 13.0f, 13.0f, 0.0f };
Vector damperCoefficient { 0.22f, 0.22f, 0.0f };
const float offset = cr::clamp (m_difficulty, 1, 4) * 25.0f;
const float offset = cr::clamp (static_cast <float> (m_difficulty), 1.0f, 4.0f) * 25.0f;
Vector influence = Vector (0.25f, 0.17f, 0.0f) * (100.0f - offset) / 100.f;
Vector randomization = Vector (2.0f, 0.18f, 0.0f) * (100.0f - offset) / 100.f;

View file

@ -285,7 +285,7 @@ void BotSupport::checkWelcome () {
bool needToSendMsg = (graph.length () > 0 ? m_needToSendWelcome : true);
auto receiveEntity = game.getLocalEntity ();
if (isAlive (receiveEntity) && m_welcomeReceiveTime < 1.0 && needToSendMsg) {
if (isAlive (receiveEntity) && m_welcomeReceiveTime < 1.0f && needToSendMsg) {
m_welcomeReceiveTime = game.time () + 4.0f; // receive welcome message in four seconds after game has commencing
}
@ -509,7 +509,7 @@ void BotSupport::simulateNoise (int playerIndex) {
}
}
if (noise.dist <= 0.0) {
if (noise.dist <= 0.0f) {
return; // didn't issue sound?
}
@ -613,7 +613,7 @@ void BotSupport::calculatePings () {
if (!bot) {
continue;
}
int part = static_cast <int> (average.first * 0.2f);
int part = static_cast <int> (static_cast <float> (average.first) * 0.2f);
int botPing = bot->m_basePing + rg.get (average.first - part, average.first + part) + rg.get (bot->m_difficulty / 2, bot->m_difficulty);
int botLoss = rg.get (average.second / 2, average.second);