misc: refactored weapon type recognition.

fix: reverted body offsets from 2.7 version.
fix: do not destroy breakable around if closer than 100 units. (#156 possible can be fixed).
fix: minimum supported hl & cs version display.
fix: csdm respawn outside of waypointed area causing pathfinder errors.
This commit is contained in:
ds 2020-09-13 02:21:15 +03:00
commit a675c40927
10 changed files with 205 additions and 174 deletions

View file

@ -409,18 +409,25 @@ void Bot::checkBreakable (edict_t *touch) {
}
void Bot::checkBreakablesAround () {
if (!cv_destroy_breakables_around.bool_ () || m_currentWeapon == Weapon::Knife || rg.chance (25) || !game.hasBreakables () || m_seeEnemyTime + 4.0f > game.time () || !game.isNullEntity (m_enemy) || !hasPrimaryWeapon ()) {
if (!cv_destroy_breakables_around.bool_ () || usesKnife () || rg.chance (25) || !game.hasBreakables () || m_seeEnemyTime + 4.0f > game.time () || !game.isNullEntity (m_enemy) || !hasPrimaryWeapon ()) {
return;
}
// check if we're have some breakbles in 450 units range
// check if we're have some breakbles in 400 units range
for (const auto &breakable : game.getBreakables ()) {
if (!game.isShootableBreakable (breakable)) {
continue;
}
const auto &origin = game.getEntityWorldOrigin (breakable);
const auto lengthToObstacle = (origin - pev->origin).lengthSq ();
if ((origin - pev->origin).lengthSq () > cr::square (450.0f)) {
// too far, skip it
if (lengthToObstacle > cr::square (400.0f)) {
continue;
}
// too close, skip it
if (lengthToObstacle < cr::square (100.0f)) {
continue;
}
@ -605,11 +612,12 @@ void Bot::updatePickups () {
allowPickup = false;
}
else if (!m_isVIP && primaryWeaponCarried >= 7 && (m_ammo[primary.id] > 0.3 * primaryProp.ammo1Max) && strncmp (model, "w_", 2) == 0) {
auto weaponType = conf.getWeaponType (primaryWeaponCarried);
const bool isSniperRifle = primaryWeaponCarried == Weapon::AWP || primaryWeaponCarried == Weapon::G3SG1 || primaryWeaponCarried == Weapon::SG550;
const bool isSubmachine = primaryWeaponCarried == Weapon::MP5 || primaryWeaponCarried == Weapon::TMP || primaryWeaponCarried == Weapon::P90 || primaryWeaponCarried == Weapon::MAC10 || primaryWeaponCarried == Weapon::UMP45;
const bool isShotgun = primaryWeaponCarried == Weapon::M3;
const bool isRifle = primaryWeaponCarried == Weapon::Famas || primaryWeaponCarried == Weapon::AK47 || primaryWeaponCarried == Weapon::M4A1 || primaryWeaponCarried == Weapon::Galil || primaryWeaponCarried == Weapon::AUG || primaryWeaponCarried == Weapon::SG552;
const bool isSniperRifle = weaponType == WeaponType::Sniper;
const bool isSubmachine = weaponType == WeaponType::SMG;
const bool isShotgun = weaponType == WeaponType::Shotgun;
const bool isRifle = weaponType == WeaponType::Rifle || weaponType == WeaponType::ZoomRifle;
if (strcmp (model, "w_9mmarclip.mdl") == 0 && !isRifle) {
allowPickup = false;
@ -762,7 +770,7 @@ void Bot::updatePickups () {
m_defendedBomb = true;
int index = findDefendNode (origin);
const Path &path = graph[index];
const auto &path = graph[index];
float timeToExplode = bots.getTimeBombPlanted () + mp_c4timer.float_ () - graph.calculateTravelTime (pev->maxspeed, pev->origin, path.origin);
@ -1232,7 +1240,7 @@ bool Bot::canReplaceWeapon () {
else if (m_currentWeapon == Weapon::MP5 && m_moneyAmount > 6000) {
return true;
}
else if ((m_currentWeapon == Weapon::M3 || m_currentWeapon == Weapon::XM1014) && m_moneyAmount > 4000) {
else if (usesShotgun () && m_moneyAmount > 4000) {
return true;
}
return isWeaponRestricted (m_currentWeapon);
@ -1689,7 +1697,7 @@ void Bot::updateEmotions () {
void Bot::overrideConditions () {
if (m_currentWeapon != Weapon::Knife && m_difficulty > Difficulty::Normal && ((m_aimFlags & AimFlags::Enemy) || (m_states & Sense::SeeingEnemy)) && !cv_jasonmode.bool_ () && getCurrentTaskId () != Task::Camp && getCurrentTaskId () != Task::SeekCover && !isOnLadder ()) {
if (!usesKnife () && m_difficulty > Difficulty::Normal && ((m_aimFlags & AimFlags::Enemy) || (m_states & Sense::SeeingEnemy)) && !cv_jasonmode.bool_ () && getCurrentTaskId () != Task::Camp && getCurrentTaskId () != Task::SeekCover && !isOnLadder ()) {
m_moveToGoal = false; // don't move to goal
m_navTimeset = game.time ();
@ -1707,7 +1715,7 @@ void Bot::overrideConditions () {
}
// special handling, if we have a knife in our hands
if ((bots.getRoundStartTime () + 6.0f > game.time () || !hasAnyWeapons ()) && m_currentWeapon == Weapon::Knife && util.isPlayer (m_enemy)) {
if ((bots.getRoundStartTime () + 6.0f > game.time () || !hasAnyWeapons ()) && usesKnife () && util.isPlayer (m_enemy)) {
float length = (pev->origin - m_enemy->v.origin).length2d ();
// do waypoint movement if enemy is not reachable with a knife
@ -1808,7 +1816,7 @@ void Bot::setConditions () {
}
// if no more enemies found AND bomb planted, switch to knife to get to bombplace faster
if (m_team == Team::CT && m_currentWeapon != Weapon::Knife && m_numEnemiesLeft == 0 && bots.isBombPlanted ()) {
if (m_team == Team::CT && !usesKnife () && m_numEnemiesLeft == 0 && bots.isBombPlanted ()) {
selectWeaponByName ("weapon_knife");
m_plantedBombNodeIndex = getNearestToPlantedBomb ();
@ -1945,7 +1953,7 @@ void Bot::filterTasks () {
}
bool lowAmmo = m_ammoInClip[m_currentWeapon] < conf.findWeaponById (m_currentWeapon).maxClip * 0.18f;
if (bots.isBombPlanted () || m_isStuck || m_currentWeapon == Weapon::Knife) {
if (bots.isBombPlanted () || m_isStuck || usesKnife ()) {
ratio /= 3.0f; // reduce the seek cover desire if bomb is planted
}
else if (m_isVIP || m_isReloading || (lowAmmo && usesSniper ())) {
@ -2427,7 +2435,7 @@ void Bot::checkRadioQueue () {
case Radio::RegroupTeam:
// if no more enemies found AND bomb planted, switch to knife to get to bombplace faster
if (m_team == Team::CT && m_currentWeapon != Weapon::Knife && m_numEnemiesLeft == 0 && bots.isBombPlanted () && getCurrentTaskId () != Task::DefuseBomb) {
if (m_team == Team::CT && !usesKnife () && m_numEnemiesLeft == 0 && bots.isBombPlanted () && getCurrentTaskId () != Task::DefuseBomb) {
selectWeaponByName ("weapon_knife");
clearSearchNodes ();
@ -3055,7 +3063,7 @@ void Bot::normal_ () {
}
// bots rushing with knife, when have no enemy (thanks for idea to nicebot project)
if (m_currentWeapon == Weapon::Knife && (game.isNullEntity (m_lastEnemy) || !util.isAlive (m_lastEnemy)) && game.isNullEntity (m_enemy) && m_knifeAttackTime < game.time () && !hasShield () && numFriendsNear (pev->origin, 96.0f) == 0) {
if (usesKnife () && (game.isNullEntity (m_lastEnemy) || !util.isAlive (m_lastEnemy)) && game.isNullEntity (m_enemy) && m_knifeAttackTime < game.time () && !hasShield () && numFriendsNear (pev->origin, 96.0f) == 0) {
if (rg.chance (40)) {
pev->button |= IN_ATTACK;
}
@ -3233,7 +3241,12 @@ void Bot::normal_ () {
ignoreCollision ();
// did we already decide about a goal before?
int destIndex = getTask ()->data != kInvalidNodeIndex ? getTask ()->data : findBestGoal ();
auto destIndex = graph.exists (getTask ()->data) ? getTask ()->data : findBestGoal ();
// check for existance (this is failover, for i.e. csdm, this should be not true with normal gameplay, only when spawned outside of waypointed area)
if (!graph.exists (destIndex)) {
destIndex = graph.getFarest (pev->origin, 512.0f);
}
m_prevGoalIndex = destIndex;
@ -3483,7 +3496,7 @@ void Bot::attackEnemy_ () {
ignoreCollision ();
attackMovement ();
if (m_currentWeapon == Weapon::Knife && !m_lastEnemyOrigin.empty ()) {
if (usesKnife () && !m_lastEnemyOrigin.empty ()) {
m_destOrigin = m_lastEnemyOrigin;
}
}
@ -4348,7 +4361,7 @@ void Bot::escapeFromBomb_ () {
pev->button |= IN_ATTACK2;
}
if (m_currentWeapon != Weapon::Knife && m_numEnemiesLeft == 0) {
if (!usesKnife () && m_numEnemiesLeft == 0) {
selectWeaponByName ("weapon_knife");
}
@ -4423,7 +4436,7 @@ void Bot::shootBreakable_ () {
m_moveSpeed = 0.0f;
m_strafeSpeed = 0.0f;
if (m_currentWeapon == Weapon::Knife) {
if (usesKnife ()) {
selectBestWeapon ();
}
m_wantsToFire = true;
@ -4919,6 +4932,12 @@ void Bot::logic () {
m_lastDamageType = -1; // reset damage
}
void Bot::spawned () {
if (game.is (GameFlags::CSDM)) {
newRound ();
}
}
void Bot::showDebugOverlay () {
bool displayDebugOverlay = false;
@ -5050,7 +5069,6 @@ void Bot::showDebugOverlay () {
for (size_t i = 0; i < m_pathWalk.length () && i + 1 < m_pathWalk.length (); ++i) {
game.drawLine (game.getLocalEntity (), graph[m_pathWalk.at (i)].origin, graph[m_pathWalk.at (i + 1)].origin, 15, 0, { 255, 100, 55 }, 200, 5, 1, DrawLine::Arrow);
}
}
bool Bot::hasHostage () {

View file

@ -461,27 +461,20 @@ const Vector &Bot::getEnemyBodyOffset () {
aimPos += getBodyOffsetError (distance);
}
else {
// now take in account different parts of enemy body
if (m_enemyParts & (Visibility::Head | Visibility::Body)) {
// forced to use body?
bool useBody = !usesPistol () && distance >= kSprayDistance && distance < 3072.0f;
// now check is our skill match to aim at head, else aim at enemy body
if (rg.chance (conf.getDifficultyTweaks (m_difficulty)->headshotPct) && !useBody) {
if (rg.chance (conf.getDifficultyTweaks (m_difficulty)->headshotPct)) {
aimPos.z = headOffset (m_enemy) + getEnemyBodyOffsetCorrection (distance);
}
else {
aimPos.z += getEnemyBodyOffsetCorrection (distance);
if (useBody) {
aimPos.z += 4.5f;
}
aimPos.z += 3.5f;
}
}
else if (m_enemyParts & Visibility::Body) {
aimPos.z += getEnemyBodyOffsetCorrection (distance);
aimPos.z += 3.5f;
}
else if (m_enemyParts & Visibility::Other) {
aimPos = m_enemyOrigin;
@ -502,44 +495,41 @@ const Vector &Bot::getEnemyBodyOffset () {
}
float Bot::getEnemyBodyOffsetCorrection (float distance) {
bool sniper = usesSniper ();
bool pistol = usesPistol ();
bool rifle = usesRifle ();
enum DistanceIndex {
Long, Middle, Short
};
bool zoomableRifle = usesZoomableRifle ();
bool submachine = usesSubmachine ();
bool shotgun = (m_currentWeapon == Weapon::XM1014 || m_currentWeapon == Weapon::M3);
bool m249 = m_currentWeapon == Weapon::M249;
static float offsetRanges[9][3] = {
{ 0.0f, 0.0f, 0.0f }, // none
{ 0.0f, 0.0f, 0.0f }, // melee
{ 6.5f, 6.5f, 4.5f }, // pistol
{ 9.5f, 9.0f, -5.0f }, // shotgun
{ 4.5f, 3.5f, -5.0f }, // zoomrifle
{ 5.5f, 1.0f, -4.5f }, // rifle
{ 5.5f, 3.5f, -4.5f }, // smg
{ 3.5f, 3.5f, 4.5f }, // sniper
{ 2.5f, -2.0f, -6.0f } // heavy
};
float result = -2.0f;
if (distance >= kDoubleSprayDistance) {
if (sniper) {
result = 0.18f;
}
else if (zoomableRifle) {
result = 1.5f;
}
else if (pistol) {
result = 2.5f;
}
else if (submachine) {
result = 1.5f;
}
else if (rifle) {
result = -1.0f;
}
else if (m249) {
result = -5.5f;
}
else if (shotgun) {
result = -4.5f;
}
// only highskilled bots do that
if (m_difficulty < Difficulty::Normal) {
return 0.0f;
}
else {
result = -5.6f;
// default distance index is short
int32 distanceIndex = DistanceIndex::Short;
// set distance index appropriate to distance
if (distance < 3072.0f && distance > kDoubleSprayDistance) {
distanceIndex = DistanceIndex::Long;
}
return result;
else if (distance > kSprayDistance && distance <= kDoubleSprayDistance) {
distanceIndex = DistanceIndex::Middle;
}
else if (distance < kSprayDistance) {
distanceIndex = DistanceIndex::Short;
}
return offsetRanges[m_weaponType][distanceIndex];
}
bool Bot::isFriendInLineOfFire (float distance) {
@ -967,12 +957,12 @@ bool Bot::isWeaponBadAtDistance (int weaponIndex, float distance) {
}
// better use pistol in short range distances, when using sniper weapons
if ((wid == Weapon::Scout || wid == Weapon::AWP || wid == Weapon::G3SG1 || wid == Weapon::SG550) && distance < 450.0f) {
if (m_weaponType == WeaponType::Sniper && distance < 450.0f) {
return true;
}
// shotguns is too inaccurate at long distances, so weapon is bad
if ((wid == Weapon::M3 || wid == Weapon::XM1014) && distance > 750.0f) {
if (m_weaponType == WeaponType::Shotgun && distance > 750.0f) {
return true;
}
return false;
@ -992,7 +982,7 @@ void Bot::focusEnemy () {
float distance = (m_lookAt - getEyesPos ()).length2d (); // how far away is the enemy scum?
if (distance < 128.0f && !usesSniper ()) {
if (m_currentWeapon == Weapon::Knife) {
if (usesKnife ()) {
if (distance < 80.0f) {
m_wantsToFire = true;
}
@ -1039,7 +1029,7 @@ void Bot::attackMovement () {
if (m_lastUsedNodesTime + getFrameInterval () + 0.5f < game.time ()) {
int approach;
if (m_currentWeapon == Weapon::Knife) {
if (usesKnife ()) {
approach = 100;
}
else if ((m_states & Sense::SuspectEnemy) && !(m_states & Sense::SeeingEnemy)) {
@ -1068,7 +1058,7 @@ void Bot::attackMovement () {
m_moveSpeed = pev->maxspeed;
}
if (distance < 96.0f && m_currentWeapon != Weapon::Knife) {
if (distance < 96.0f && !usesKnife ()) {
m_moveSpeed = -pev->maxspeed;
}
@ -1106,7 +1096,7 @@ void Bot::attackMovement () {
m_fightStyle = Fight::Strafe;
}
if (m_fightStyle == Fight::Strafe || ((pev->button & IN_RELOAD) || m_isReloading) || (usesPistol () && distance < 400.0f) || m_currentWeapon == Weapon::Knife) {
if (m_fightStyle == Fight::Strafe || ((pev->button & IN_RELOAD) || m_isReloading) || (usesPistol () && distance < 400.0f) || usesKnife ()) {
if (m_strafeSetTime < game.time ()) {
// to start strafing, we have to first figure out if the target is on the left side or right side
@ -1149,11 +1139,11 @@ void Bot::attackMovement () {
pev->button |= IN_JUMP;
}
if (m_moveSpeed > 0.0f && distance > 100.0f && m_currentWeapon != Weapon::Knife) {
if (m_moveSpeed > 0.0f && distance > 100.0f && !usesKnife ()) {
m_moveSpeed = 0.0f;
}
if (m_currentWeapon == Weapon::Knife) {
if (usesKnife ()) {
m_strafeSpeed = 0.0f;
}
}
@ -1172,7 +1162,7 @@ void Bot::attackMovement () {
}
if (m_fightStyle == Fight::Stay || (m_duckTime > game.time () || m_sniperStopTime > game.time ())) {
if (m_moveSpeed > 0.0f && m_currentWeapon != Weapon::Knife) {
if (m_moveSpeed > 0.0f && !usesKnife ()) {
m_moveSpeed = 0.0f;
}
}
@ -1237,60 +1227,43 @@ bool Bot::isEnemyBehindShield (edict_t *enemy) {
bool Bot::usesSniper () {
// this function returns true, if returns if bot is using a sniper rifle
return m_currentWeapon == Weapon::AWP || m_currentWeapon == Weapon::G3SG1 || m_currentWeapon == Weapon::Scout || m_currentWeapon == Weapon::SG550;
return m_weaponType == WeaponType::Sniper;
}
bool Bot::usesRifle () {
auto tab = conf.getRawWeapons ();
int count = 0;
while (tab->id) {
if (m_currentWeapon == tab->id) {
break;
}
tab++;
count++;
}
if (tab->id && count > 13) {
return true;
}
return false;
}
bool Bot::usesPistol () {
auto tab = conf.getRawWeapons ();
int count = 0;
// loop through all the weapons until terminator is found
while (tab->id) {
if (m_currentWeapon == tab->id) {
break;
}
tab++;
count++;
}
if (tab->id && count < 7) {
return true;
}
return false;
}
bool Bot::usesCampGun () {
return usesSubmachine () || usesRifle () || usesSniper ();
}
bool Bot::usesSubmachine () {
return m_currentWeapon == Weapon::MP5 || m_currentWeapon == Weapon::TMP || m_currentWeapon == Weapon::P90 || m_currentWeapon == Weapon::MAC10 || m_currentWeapon == Weapon::UMP45;
return usesZoomableRifle () || m_weaponType == WeaponType::Rifle;
}
bool Bot::usesZoomableRifle () {
return m_currentWeapon == Weapon::AUG || m_currentWeapon == Weapon::SG552;
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 m_currentWeapon == Weapon::XM1014 || m_currentWeapon == Weapon::M3 || m_currentWeapon == Weapon::UMP45 || m_currentWeapon == Weapon::MAC10 || m_currentWeapon == Weapon::TMP || m_currentWeapon == Weapon::P90;
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 () {
@ -1301,7 +1274,7 @@ int Bot::bestPrimaryCarried () {
int weaponIndex = 0;
int weapons = pev->weapons;
auto &weaponTab = conf.getWeapons ();
const auto &tab = conf.getWeapons ();
// take the shield in account
if (hasShield ()) {
@ -1309,7 +1282,7 @@ int Bot::bestPrimaryCarried () {
}
for (int i = 0; i < kNumWeapons; ++i) {
if (weapons & cr::bit (weaponTab[*pref].id)) {
if (weapons & cr::bit (tab[*pref].id)) {
weaponIndex = i;
}
pref++;
@ -1329,7 +1302,7 @@ int Bot::bestSecondaryCarried () {
if (hasShield ()) {
weapons |= cr::bit (Weapon::Shield);
}
auto tab = conf.getRawWeapons ();
const auto tab = conf.getRawWeapons ();
for (int i = 0; i < kNumWeapons; ++i) {
int id = tab[*pref].id;

View file

@ -696,35 +696,35 @@ void BotConfig::initWeapons () {
m_weapons.clear ();
// fill array with available weapons
m_weapons.emplace (Weapon::Knife, "weapon_knife", "knife.mdl", 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, true);
m_weapons.emplace (Weapon::USP, "weapon_usp", "usp.mdl", 500, 1, -1, -1, 1, 1, 2, 2, 0, 12, false);
m_weapons.emplace (Weapon::Glock18, "weapon_glock18", "glock18.mdl", 400, 1, -1, -1, 1, 2, 1, 1, 0, 20, false);
m_weapons.emplace (Weapon::Deagle, "weapon_deagle", "deagle.mdl", 650, 1, 2, 2, 1, 3, 4, 4, 2, 7, false);
m_weapons.emplace (Weapon::P228, "weapon_p228", "p228.mdl", 600, 1, 2, 2, 1, 4, 3, 3, 0, 13, false);
m_weapons.emplace (Weapon::Elite, "weapon_elite", "elite.mdl", 800, 1, 0, 0, 1, 5, 5, 5, 0, 30, false);
m_weapons.emplace (Weapon::FiveSeven, "weapon_fiveseven", "fiveseven.mdl", 750, 1, 1, 1, 1, 6, 5, 5, 0, 20, false);
m_weapons.emplace (Weapon::M3, "weapon_m3", "m3.mdl", 1700, 1, 2, -1, 2, 1, 1, 1, 0, 8, false);
m_weapons.emplace (Weapon::XM1014, "weapon_xm1014", "xm1014.mdl", 3000, 1, 2, -1, 2, 2, 2, 2, 0, 7, false);
m_weapons.emplace (Weapon::MP5, "weapon_mp5navy", "mp5.mdl", 1500, 1, 2, 1, 3, 1, 2, 2, 0, 30, true);
m_weapons.emplace (Weapon::TMP, "weapon_tmp", "tmp.mdl", 1250, 1, 1, 1, 3, 2, 1, 1, 0, 30, true);
m_weapons.emplace (Weapon::P90, "weapon_p90", "p90.mdl", 2350, 1, 2, 1, 3, 3, 4, 4, 0, 50, true);
m_weapons.emplace (Weapon::MAC10, "weapon_mac10", "mac10.mdl", 1400, 1, 0, 0, 3, 4, 1, 1, 0, 30, true);
m_weapons.emplace (Weapon::UMP45, "weapon_ump45", "ump45.mdl", 1700, 1, 2, 2, 3, 5, 3, 3, 0, 25, true);
m_weapons.emplace (Weapon::AK47, "weapon_ak47", "ak47.mdl", 2500, 1, 0, 0, 4, 1, 2, 2, 2, 30, true);
m_weapons.emplace (Weapon::SG552, "weapon_sg552", "sg552.mdl", 3500, 1, 0, -1, 4, 2, 4, 4, 2, 30, true);
m_weapons.emplace (Weapon::M4A1, "weapon_m4a1", "m4a1.mdl", 3100, 1, 1, 1, 4, 3, 3, 3, 2, 30, true);
m_weapons.emplace (Weapon::Galil, "weapon_galil", "galil.mdl", 2000, 1, 0, 0, 4, -1, 1, 1, 2, 35, true);
m_weapons.emplace (Weapon::Famas, "weapon_famas", "famas.mdl", 2250, 1, 1, 1, 4, -1, 1, 1, 2, 25, true);
m_weapons.emplace (Weapon::AUG, "weapon_aug", "aug.mdl", 3500, 1, 1, 1, 4, 4, 4, 4, 2, 30, true);
m_weapons.emplace (Weapon::Scout, "weapon_scout", "scout.mdl", 2750, 1, 2, 0, 4, 5, 3, 2, 3, 10, false);
m_weapons.emplace (Weapon::AWP, "weapon_awp", "awp.mdl", 4750, 1, 2, 0, 4, 6, 5, 6, 3, 10, false);
m_weapons.emplace (Weapon::G3SG1, "weapon_g3sg1", "g3sg1.mdl", 5000, 1, 0, 2, 4, 7, 6, 6, 3, 20, false);
m_weapons.emplace (Weapon::SG550, "weapon_sg550", "sg550.mdl", 4200, 1, 1, 1, 4, 8, 5, 5, 3, 30, false);
m_weapons.emplace (Weapon::M249, "weapon_m249", "m249.mdl", 5750, 1, 2, 1, 5, 1, 1, 1, 2, 100, true);
m_weapons.emplace (Weapon::Shield, "weapon_shield", "shield.mdl", 2200, 0, 1, 1, 8, -1, 8, 8, 0, 0, false);
m_weapons.emplace (Weapon::Knife, "weapon_knife", "knife.mdl", 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, WeaponType::Melee, true);
m_weapons.emplace (Weapon::USP, "weapon_usp", "usp.mdl", 500, 1, -1, -1, 1, 1, 2, 2, 0, 12, WeaponType::Pistol, false);
m_weapons.emplace (Weapon::Glock18, "weapon_glock18", "glock18.mdl", 400, 1, -1, -1, 1, 2, 1, 1, 0, 20, WeaponType::Pistol, false);
m_weapons.emplace (Weapon::Deagle, "weapon_deagle", "deagle.mdl", 650, 1, 2, 2, 1, 3, 4, 4, 2, 7, WeaponType::Pistol, false);
m_weapons.emplace (Weapon::P228, "weapon_p228", "p228.mdl", 600, 1, 2, 2, 1, 4, 3, 3, 0, 13, WeaponType::Pistol, false);
m_weapons.emplace (Weapon::Elite, "weapon_elite", "elite.mdl", 800, 1, 0, 0, 1, 5, 5, 5, 0, 30, WeaponType::Pistol, false);
m_weapons.emplace (Weapon::FiveSeven, "weapon_fiveseven", "fiveseven.mdl", 750, 1, 1, 1, 1, 6, 5, 5, 0, 20, WeaponType::Pistol, false);
m_weapons.emplace (Weapon::M3, "weapon_m3", "m3.mdl", 1700, 1, 2, -1, 2, 1, 1, 1, 0, 8, WeaponType::Shotgun, false);
m_weapons.emplace (Weapon::XM1014, "weapon_xm1014", "xm1014.mdl", 3000, 1, 2, -1, 2, 2, 2, 2, 0, 7, WeaponType::Shotgun, false);
m_weapons.emplace (Weapon::MP5, "weapon_mp5navy", "mp5.mdl", 1500, 1, 2, 1, 3, 1, 2, 2, 0, 30, WeaponType::SMG, true);
m_weapons.emplace (Weapon::TMP, "weapon_tmp", "tmp.mdl", 1250, 1, 1, 1, 3, 2, 1, 1, 0, 30, WeaponType::SMG, true);
m_weapons.emplace (Weapon::P90, "weapon_p90", "p90.mdl", 2350, 1, 2, 1, 3, 3, 4, 4, 0, 50, WeaponType::SMG, true);
m_weapons.emplace (Weapon::MAC10, "weapon_mac10", "mac10.mdl", 1400, 1, 0, 0, 3, 4, 1, 1, 0, 30, WeaponType::SMG, true);
m_weapons.emplace (Weapon::UMP45, "weapon_ump45", "ump45.mdl", 1700, 1, 2, 2, 3, 5, 3, 3, 0, 25, WeaponType::SMG, true);
m_weapons.emplace (Weapon::AK47, "weapon_ak47", "ak47.mdl", 2500, 1, 0, 0, 4, 1, 2, 2, 2, 30, WeaponType::Rifle, true);
m_weapons.emplace (Weapon::SG552, "weapon_sg552", "sg552.mdl", 3500, 1, 0, -1, 4, 2, 4, 4, 2, 30, WeaponType::ZoomRifle, true);
m_weapons.emplace (Weapon::M4A1, "weapon_m4a1", "m4a1.mdl", 3100, 1, 1, 1, 4, 3, 3, 3, 2, 30, WeaponType::Rifle, true);
m_weapons.emplace (Weapon::Galil, "weapon_galil", "galil.mdl", 2000, 1, 0, 0, 4, -1, 1, 1, 2, 35, WeaponType::Rifle, true);
m_weapons.emplace (Weapon::Famas, "weapon_famas", "famas.mdl", 2250, 1, 1, 1, 4, -1, 1, 1, 2, 25, WeaponType::Rifle, true);
m_weapons.emplace (Weapon::AUG, "weapon_aug", "aug.mdl", 3500, 1, 1, 1, 4, 4, 4, 4, 2, 30, WeaponType::ZoomRifle, true);
m_weapons.emplace (Weapon::Scout, "weapon_scout", "scout.mdl", 2750, 1, 2, 0, 4, 5, 3, 2, 3, 10, WeaponType::Sniper, false);
m_weapons.emplace (Weapon::AWP, "weapon_awp", "awp.mdl", 4750, 1, 2, 0, 4, 6, 5, 6, 3, 10, WeaponType::Sniper, false);
m_weapons.emplace (Weapon::G3SG1, "weapon_g3sg1", "g3sg1.mdl", 5000, 1, 0, 2, 4, 7, 6, 6, 3, 20, WeaponType::Sniper, false);
m_weapons.emplace (Weapon::SG550, "weapon_sg550", "sg550.mdl", 4200, 1, 1, 1, 4, 8, 5, 5, 3, 30, WeaponType::Sniper, false);
m_weapons.emplace (Weapon::M249, "weapon_m249", "m249.mdl", 5750, 1, 2, 1, 5, 1, 1, 1, 2, 100, WeaponType::Heavy, true);
m_weapons.emplace (Weapon::Shield, "weapon_shield", "shield.mdl", 2200, 0, 1, 1, 8, -1, 8, 8, 0, 0, WeaponType::Pistol, false);
// not needed actually, but cause too much refactoring for now. todo
m_weapons.emplace (0, "", "", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false);
m_weapons.emplace (0, "", "", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, WeaponType::None, false);
}
void BotConfig::adjustWeaponPrices () {

View file

@ -137,6 +137,11 @@ void Game::levelInitialize (edict_t *entities, int max) {
}
else if (strcmp (classname, "func_escapezone") == 0) {
m_mapFlags |= MapFlags::Escape;
// strange thing on some ES maps, where hostage entity present there
if (m_mapFlags & MapFlags::HostageRescue) {
m_mapFlags &= ~MapFlags::HostageRescue;
}
}
else if (strncmp (classname, "func_door", 9) == 0) {
m_mapFlags |= MapFlags::HasDoors;
@ -366,7 +371,7 @@ void Game::registerEngineCommand (const char *command, void func ()) {
// check for hl pre 1.1.0.4, as it's doesn't have pfnAddServerCommand
if (!plat.checkPointer (engfuncs.pfnAddServerCommand)) {
logger.fatal ("%s's minimum HL engine version is 1.1.0.6 and minimum Counter-Strike is Beta 7.1. Please update your engine / game version.", product.name);
logger.fatal ("%s's minimum HL engine version is 1.1.0.4 and minimum Counter-Strike is Beta 6.5. Please update your engine / game version.", product.name);
}
engfuncs.pfnAddServerCommand (const_cast <char *> (command), func);
}

View file

@ -133,6 +133,12 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int) {
// Spawn() function is one of the functions any entity is supposed to have in the game DLL,
// and any MOD is supposed to implement one for each of its entities.
auto bot = bots[ent];
if (bot) {
bot->spawned ();
}
if (game.is (GameFlags::Metamod)) {
RETURN_META_VALUE (MRES_IGNORED, 0);
}
@ -954,3 +960,4 @@ DLL_GIVEFNPTRSTODLL GiveFnptrsToDll (enginefuncs_t *functionTable, globalvars_t
// add linkents for android
#include "android.cpp"

View file

@ -958,6 +958,8 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int member) {
plat.bzero (&m_ammo, sizeof (m_ammo));
m_currentWeapon = 0; // current weapon is not assigned at start
m_weaponType = WeaponType::None; // current weapon type is not assigned at start
m_voicePitch = rg.int_ (80, 115); // assign voice pitch
// copy them over to the temp level variables
@ -1255,6 +1257,7 @@ void Bot::newRound () {
plat.bzero (&m_ammo, sizeof (m_ammo));
m_currentWeapon = 0;
m_weaponType = 0;
}
m_flashLevel = 100.0f;
m_checkDarkTime = game.time ();

View file

@ -166,6 +166,7 @@ void MessageDispatcher::netMsgCurWeapon () {
if (m_args[id].long_ < kMaxWeapons) {
if (m_args[state].long_ != 0) {
m_bot->m_currentWeapon = m_args[id].long_;
m_bot->m_weaponType = conf.getWeaponType (m_args[id].long_);
}
// ammo amount decreased ? must have fired a bullet...
@ -329,13 +330,6 @@ void MessageDispatcher::netMsgTeamInfo () {
// update player team
client.team2 = m_teamInfoCache[m_args[team].chars_]; // update real team
client.team = game.is (GameFlags::FreeForAll) ? m_args[index].long_ : client.team2;
auto bot = bots[client.ent];
// clear the routes so we're have no error in pathfinding in case team info update (respawn/change team)
if (bot) {
bot->clearSearchNodes ();
}
}
void MessageDispatcher::netMsgBarTime () {

View file

@ -676,7 +676,7 @@ bool Bot::updateNavigation () {
m_desiredVelocity = nullptr;
}
}
else if (!cv_jasonmode.bool_ () && m_currentWeapon == Weapon::Knife && isOnFloor ()) {
else if (!cv_jasonmode.bool_ () && usesKnife () && isOnFloor ()) {
selectBestWeapon ();
}
}
@ -1176,11 +1176,11 @@ void Bot::findShortestPath (int srcIndex, int destIndex) {
// this function finds the shortest path from source index to destination index
if (!graph.exists (srcIndex)){
logger.error ("Pathfinder source path index not valid (%d).", srcIndex);
logger.error ("%s source path index not valid (%d).", __FUNCTION__, srcIndex);
return;
}
else if (!graph.exists (destIndex)) {
logger.error ("Pathfinder destination path index not valid (%d).", destIndex);
logger.error ("%s destination path index not valid (%d).", __FUNCTION__, destIndex);
return;
}
clearSearchNodes ();
@ -1329,7 +1329,7 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath:
float euclidean = cr::powf (cr::powf (x, 2.0f) + cr::powf (y, 2.0f) + cr::powf (z, 2.0f), 0.5f);
if (cv_debug_heuristic_type.int_ () == 4) {
return 1000.0f *(cr::ceilf (euclidean) - euclidean);
return 1000.0f * (cr::ceilf (euclidean) - euclidean);
}
return euclidean;
}
@ -1348,8 +1348,18 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath:
return hfunctionPathDist (index, startIndex, goalIndex) / 128.0f * 10.0f;
};
if (!graph.exists (srcIndex)) {
logger.error ("%s source path index not valid (%d).", __FUNCTION__, srcIndex);
return;
}
else if (!graph.exists (destIndex)) {
logger.error ("%s destination path index not valid (%d).", __FUNCTION__, destIndex);
return;
}
// holders for heuristic functions
Lambda <float (int, int, int)> gcalc, hcalc;
static Lambda <float (int, int, int)> gcalc, hcalc;
// get correct calculation for heuristic
if (pathType == FindPath::Optimal) {
@ -1382,15 +1392,6 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath:
gcalc = gfunctionPathDist;
}
}
if (!graph.exists (srcIndex)) {
logger.error ("Pathfinder source path index not valid (%d).", srcIndex);
return;
}
else if (!graph.exists (destIndex)) {
logger.error ("Pathfinder destination path index not valid (%d).", destIndex);
return;
}
clearSearchNodes ();
m_chosenGoalIndex = srcIndex;
@ -2182,7 +2183,7 @@ bool Bot::advanceMovement () {
}
// is there a jump node right ahead and do we need to draw out the light weapon ?
if (willJump && m_currentWeapon != Weapon::Knife && m_currentWeapon != Weapon::Scout && !m_isReloading && !usesPistol () && (jumpDistance > 200.0f || (dst.z - 32.0f > src.z && jumpDistance > 150.0f)) && !(m_states & (Sense::SeeingEnemy | Sense::SuspectEnemy))) {
if (willJump && !usesKnife () && m_currentWeapon != Weapon::Scout && !m_isReloading && !usesPistol () && (jumpDistance > 200.0f || (dst.z - 32.0f > src.z && jumpDistance > 150.0f)) && !(m_states & (Sense::SeeingEnemy | Sense::SuspectEnemy))) {
selectWeaponByName ("weapon_knife"); // draw out the knife if we needed
}
@ -2206,7 +2207,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 = m_pathOrigin + Vector (pev->angles.x, cr::normalizeAngles (pev->angles.y + rg.float_ (-90.0f, 90.0f)), 0.0f).forward () * rg.float_ (0.0f, m_path->radius);
m_pathOrigin += Vector (pev->angles.x, cr::normalizeAngles (pev->angles.y + rg.float_ (-90.0f, 90.0f)), 0.0f).forward () * rg.float_ (0.0f, m_path->radius);
}
if (isOnLadder ()) {