Fixed crash in message dispatcher after 'meta unload'.

Various cosmetic changes.
This commit is contained in:
jeefo 2019-09-14 23:13:55 +03:00
commit ff6c56aeac
37 changed files with 949 additions and 602 deletions

View file

@ -21,7 +21,7 @@ CR_EXPORT int Server_GetBlendingInterface (int version, struct sv_blending_inter
if (!api_GetBlendingInterface) {
logger.error ("Could not resolve symbol \"%s\" in the game dll. Continuing...", __FUNCTION__);
return FALSE;
return false;
}
return api_GetBlendingInterface (version, ppinterface, pstudio, rotationmatrix, bonetransform);
}

View file

@ -100,7 +100,7 @@ bool Bot::seesItem (const Vector &destination, const char *itemName) {
// check if line of sight to object is not blocked (i.e. visible)
if (tr.flFraction != 1.0f) {
return strcmp (STRING (tr.pHit->v.classname), itemName) == 0;
return strcmp (tr.pHit->v.classname.chars (), itemName) == 0;
}
return true;
}
@ -330,7 +330,7 @@ void Bot::avoidGrenades () {
if (!seesEntity (pent->v.origin) && isInFOV (pent->v.origin - getEyesPos ()) > pev->fov * 0.5f) {
continue;
}
auto model = STRING (pent->v.model) + 9;
auto model = pent->v.model.chars () + 9;
if (m_preventFlashing < game.time () && m_personality == Personality::Rusher && m_difficulty == 4 && strcmp (model, "flashbang.mdl") == 0) {
// don't look at flash bang
@ -500,7 +500,7 @@ void Bot::updatePickups () {
}
if (ent == pickupItem) {
if (seesItem (origin, STRING (ent->v.classname))) {
if (seesItem (origin, ent->v.classname.chars ())) {
itemExists = true;
}
@ -538,8 +538,8 @@ void Bot::updatePickups () {
continue;
}
auto classname = STRING (ent->v.classname);
auto model = STRING (ent->v.model) + 9;
auto classname = ent->v.classname.chars ();
auto model = ent->v.model.chars () + 9;
// check if line of sight to object is not blocked (i.e. visible)
if (seesItem (origin, classname)) {
@ -1089,19 +1089,19 @@ void Bot::checkMsgQueue () {
if (m_radioSelect != -1) {
if ((m_radioSelect != Radio::ReportingIn && m_forceRadio) || yb_radio_mode.int_ () != 2 || !conf.hasChatterBank (m_radioSelect) || !game.is (GameFlags::HasBotVoice)) {
if (m_radioSelect < Radio::GoGoGo) {
game.botCommand (ent (), "radio1");
issueCommand ("radio1");
}
else if (m_radioSelect < Radio::RogerThat) {
m_radioSelect -= Radio::GoGoGo - 1;
game.botCommand (ent (), "radio2");
issueCommand ("radio2");
}
else {
m_radioSelect -= Radio::RogerThat - 1;
game.botCommand (ent (), "radio3");
issueCommand ("radio3");
}
// select correct menu item for this radio message
game.botCommand (ent (), "menuselect %d", m_radioSelect);
issueCommand ("menuselect %d", m_radioSelect);
}
else if (m_radioSelect != Radio::ReportingIn) {
instantChatter (m_radioSelect);
@ -1136,13 +1136,12 @@ bool Bot::isWeaponRestricted (int weaponIndex) {
if (strings.isEmpty (yb_restricted_weapons.str ())) {
return isWeaponRestrictedAMX (weaponIndex); // no banned weapons
}
auto bannedWeapons = String (yb_restricted_weapons.str ()).split (";");
for (auto &ban : bannedWeapons) {
const char *banned = STRING (util.getWeaponAlias (true, nullptr, weaponIndex));
const auto &bannedWeapons = String (yb_restricted_weapons.str ()).split (";");
const auto &alias = util.weaponIdToAlias (weaponIndex);
for (const auto &ban : bannedWeapons) {
// check is this weapon is banned
if (strncmp (ban.chars (), banned, ban.length ()) == 0) {
if (ban == alias) {
return true;
}
}
@ -1154,7 +1153,7 @@ bool Bot::isWeaponRestrictedAMX (int weaponIndex) {
// check for weapon restrictions
if (cr::bit (weaponIndex) & (kPrimaryWeaponMask | kSecondaryWeaponMask | Weapon::Shield)) {
const char *restrictedWeapons = engfuncs.pfnCVarGetString ("amx_restrweapons");
auto restrictedWeapons = engfuncs.pfnCVarGetString ("amx_restrweapons");
if (strings.isEmpty (restrictedWeapons)) {
return false;
@ -1173,7 +1172,7 @@ bool Bot::isWeaponRestrictedAMX (int weaponIndex) {
// check for equipment restrictions
else {
const char *restrictedEquipment = engfuncs.pfnCVarGetString ("amx_restrequipammo");
auto restrictedEquipment = engfuncs.pfnCVarGetString ("amx_restrequipammo");
if (strings.isEmpty (restrictedEquipment)) {
return false;
@ -1202,17 +1201,6 @@ bool Bot::canReplaceWeapon () {
return false;
}
if (!strings.isEmpty (yb_restricted_weapons.str ())) {
auto bannedWeapons = String (yb_restricted_weapons.str ()).split (";");
// check if its banned
for (auto &ban : bannedWeapons) {
if (m_currentWeapon == util.getWeaponAlias (false, ban.chars ())) {
return true;
}
}
}
if (m_currentWeapon == Weapon::Scout && m_moneyAmount > 5000) {
return true;
}
@ -1222,7 +1210,7 @@ bool Bot::canReplaceWeapon () {
else if ((m_currentWeapon == Weapon::M3 || m_currentWeapon == Weapon::XM1014) && m_moneyAmount > 4000) {
return true;
}
return false;
return isWeaponRestricted (m_currentWeapon);
}
int Bot::pickBestWeapon (int *vec, int count, int moneySave) {
@ -1458,17 +1446,17 @@ void Bot::buyStuff () {
}
if (selectedWeapon != nullptr) {
game.botCommand (ent (), "buy;menuselect %d", selectedWeapon->buyGroup);
issueCommand ("buy;menuselect %d", selectedWeapon->buyGroup);
if (isOldGame) {
game.botCommand (ent (), "menuselect %d", selectedWeapon->buySelect);
issueCommand ("menuselect %d", selectedWeapon->buySelect);
}
else {
if (m_team == Team::Terrorist) {
game.botCommand (ent (), "menuselect %d", selectedWeapon->buySelectT);
issueCommand ("menuselect %d", selectedWeapon->buySelectT);
}
else {
game.botCommand (ent (), "menuselect %d", selectedWeapon->buySelectCT);
issueCommand ("menuselect %d", selectedWeapon->buySelectCT);
}
}
}
@ -1487,10 +1475,10 @@ void Bot::buyStuff () {
if (pev->armorvalue < rg.int_ (50, 80) && (isPistolMode || (teamEcoValid && hasPrimaryWeapon ()))) {
// if bot is rich, buy kevlar + helmet, else buy a single kevlar
if (m_moneyAmount > 1500 && !isWeaponRestricted (Weapon::ArmorHelm)) {
game.botCommand (ent (), "buyequip;menuselect 2");
issueCommand ("buyequip;menuselect 2");
}
else if (!isWeaponRestricted (Weapon::Armor)) {
game.botCommand (ent (), "buyequip;menuselect 1");
issueCommand ("buyequip;menuselect 1");
}
}
break;
@ -1552,17 +1540,17 @@ void Bot::buyStuff () {
}
if (selectedWeapon != nullptr) {
game.botCommand (ent (), "buy;menuselect %d", selectedWeapon->buyGroup);
issueCommand ("buy;menuselect %d", selectedWeapon->buyGroup);
if (isOldGame) {
game.botCommand (ent (), "menuselect %d", selectedWeapon->buySelect);
issueCommand ("menuselect %d", selectedWeapon->buySelect);
}
else {
if (m_team == Team::Terrorist) {
game.botCommand (ent (), "menuselect %d", selectedWeapon->buySelectT);
issueCommand ("menuselect %d", selectedWeapon->buySelectT);
}
else {
game.botCommand (ent (), "menuselect %d", selectedWeapon->buySelectCT);
issueCommand ("menuselect %d", selectedWeapon->buySelectCT);
}
}
}
@ -1573,30 +1561,30 @@ void Bot::buyStuff () {
// buy a he grenade
if (conf.chanceToBuyGrenade (0) && m_moneyAmount >= 400 && !isWeaponRestricted (Weapon::Explosive)) {
game.botCommand (ent (), "buyequip");
game.botCommand (ent (), "menuselect 4");
issueCommand ("buyequip");
issueCommand ("menuselect 4");
}
// buy a concussion grenade, i.e., 'flashbang'
if (conf.chanceToBuyGrenade (1) && m_moneyAmount >= 300 && teamEcoValid && !isWeaponRestricted (Weapon::Flashbang)) {
game.botCommand (ent (), "buyequip");
game.botCommand (ent (), "menuselect 3");
issueCommand ("buyequip");
issueCommand ("menuselect 3");
}
// buy a smoke grenade
if (conf.chanceToBuyGrenade (2) && m_moneyAmount >= 400 && teamEcoValid && !isWeaponRestricted (Weapon::Smoke)) {
game.botCommand (ent (), "buyequip");
game.botCommand (ent (), "menuselect 5");
issueCommand ("buyequip");
issueCommand ("menuselect 5");
}
break;
case BuyState::DefusalKit: // if bot is CT and we're on a bomb map, randomly buy the defuse kit
if (game.mapIs (MapFlags::Demolition) && m_team == Team::CT && rg.chance (80) && m_moneyAmount > 200 && !isWeaponRestricted (Weapon::Defuser)) {
if (isOldGame) {
game.botCommand (ent (), "buyequip;menuselect 6");
issueCommand ("buyequip;menuselect 6");
}
else {
game.botCommand (ent (), "defuser"); // use alias in steamcs
issueCommand ("defuser"); // use alias in steamcs
}
}
break;
@ -1609,10 +1597,10 @@ void Bot::buyStuff () {
// if it's somewhat darkm do buy nightvision goggles
if ((skyColor >= 50.0f && lightLevel <= 15.0f) || (skyColor < 50.0f && lightLevel < 40.0f)) {
if (isOldGame) {
game.botCommand (ent (), "buyequip;menuselect 7");
issueCommand ("buyequip;menuselect 7");
}
else {
game.botCommand (ent (), "nvgs"); // use alias in steamcs
issueCommand ("nvgs"); // use alias in steamcs
}
}
}
@ -1620,16 +1608,16 @@ void Bot::buyStuff () {
case BuyState::Ammo: // buy enough primary & secondary ammo (do not check for money here)
for (int i = 0; i <= 5; ++i) {
game.botCommand (ent (), "buyammo%d", rg.int_ (1, 2)); // simulate human
issueCommand ("buyammo%d", rg.int_ (1, 2)); // simulate human
}
// buy enough secondary ammo
if (hasPrimaryWeapon ()) {
game.botCommand (ent (), "buy;menuselect 7");
issueCommand ("buy;menuselect 7");
}
// buy enough primary ammo
game.botCommand (ent (), "buy;menuselect 6");
issueCommand ("buy;menuselect 6");
// try to reload secondary weapon
if (m_reloadState != Reload::Primary) {
@ -2827,10 +2815,10 @@ void Bot::checkDarkness () {
pev->impulse = 100;
}
else if (!m_usesNVG && ((skyColor > 50.0f && m_path->light < 15.0f) || (skyColor <= 50.0f && m_path->light < 40.0f))) {
game.botCommand (ent (), "nightvision");
issueCommand ("nightvision");
}
else if (m_usesNVG && ((m_path->light > 20.0f && skyColor > 50.0f) || (m_path->light > 45.0f && skyColor <= 50.0f))) {
game.botCommand (ent (), "nightvision");
issueCommand ("nightvision");
}
}
m_checkDarkTime = game.time ();
@ -2926,7 +2914,7 @@ void Bot::update () {
else if (!m_notKilled) {
// we got a teamkiller? vote him away...
if (m_voteKickIndex != m_lastVoteKick && yb_tkpunish.bool_ ()) {
game.botCommand (ent (), "vote %d", m_voteKickIndex);
issueCommand ("vote %d", m_voteKickIndex);
m_lastVoteKick = m_voteKickIndex;
// if bot tk punishment is enabled slay the tk
@ -2941,7 +2929,7 @@ void Bot::update () {
// host wants us to kick someone
else if (m_voteMap != 0) {
game.botCommand (ent (), "votemap %d", m_voteMap);
issueCommand ("votemap %d", m_voteMap);
m_voteMap = 0;
}
}
@ -4386,7 +4374,7 @@ void Bot::pickupItem_ () {
auto &info = conf.getWeapons ();
for (index = 0; index < 7; ++index) {
if (strcmp (info[index].model, STRING (m_pickupItem->v.model) + 9) == 0) {
if (strcmp (info[index].model, m_pickupItem->v.model.chars () + 9) == 0) {
break;
}
}
@ -4403,10 +4391,10 @@ void Bot::pickupItem_ () {
if (wid > 0) {
selectWeaponById (wid);
game.botCommand (ent (), "drop");
issueCommand ("drop");
if (hasShield ()) {
game.botCommand (ent (), "drop"); // discard both shield and pistol
issueCommand ("drop"); // discard both shield and pistol
}
}
enteredBuyZone (BuyState::PrimaryWeapon);
@ -4417,7 +4405,7 @@ void Bot::pickupItem_ () {
if (wid == Weapon::Shield || wid > 6 || hasShield ()) {
selectWeaponById (wid);
game.botCommand (ent (), "drop");
issueCommand ("drop");
}
if (!wid) {
@ -4448,7 +4436,7 @@ void Bot::pickupItem_ () {
if (wid > 6) {
selectWeaponById (wid);
game.botCommand (ent (), "drop");
issueCommand ("drop");
}
}
break;
@ -4666,7 +4654,7 @@ void Bot::checkSpawnConditions () {
if (m_difficulty >= 2 && rg.chance (m_personality == Personality::Rusher ? 99 : 50) && !m_isReloading && game.mapIs (MapFlags::HostageRescue | MapFlags::Demolition | MapFlags::Escape | MapFlags::Assassination)) {
if (yb_jasonmode.bool_ ()) {
selectSecondary ();
game.botCommand (ent (), "drop");
issueCommand ("drop");
}
else {
selectWeaponByName ("weapon_knife");
@ -4944,9 +4932,9 @@ void Bot::showDebugOverlay () {
static float timeDebugUpdate = 0.0f;
static int index, goal, taskID;
static Dictionary <int, String, IntHash <int>> tasks;
static Dictionary <int, String, IntHash <int>> personalities;
static Dictionary <int, String, IntHash <int>> flags;
static Dictionary <int32, String, IntHash <int32>> tasks;
static Dictionary <int32, String, IntHash <int32>> personalities;
static Dictionary <int32, String, IntHash <int32>> flags;
if (tasks.empty ()) {
tasks.push (Task::Normal, "Normal");
@ -4993,15 +4981,15 @@ void Bot::showDebugOverlay () {
String enemy = "(none)";
if (!game.isNullEntity (m_enemy)) {
enemy = STRING (m_enemy->v.netname);
enemy = m_enemy->v.netname.chars ();
}
else if (!game.isNullEntity (m_lastEnemy)) {
enemy.assignf ("%s (L)", STRING (m_lastEnemy->v.netname));
enemy.assignf ("%s (L)", m_lastEnemy->v.netname.chars ());
}
String pickup = "(none)";
if (!game.isNullEntity (m_pickupItem)) {
pickup = STRING (m_pickupItem->v.netname);
pickup = m_pickupItem->v.netname.chars ();
}
String aimFlags;
@ -5012,10 +5000,10 @@ void Bot::showDebugOverlay () {
aimFlags.appendf (" %s", flags[cr::bit (i)].chars ());
}
}
String weapon = STRING (util.getWeaponAlias (true, nullptr, m_currentWeapon));
const String &weapon = util.weaponIdToAlias (m_currentWeapon);
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\n", STRING (pev->netname), pev->health, pev->armorvalue, taskID, tasks[taskID].chars (), getTask ()->desire, weapon.chars (), getAmmoInClip (), getAmmo (), m_isReloading ? " (R)" : "", m_moneyAmount, aimFlags.trim ().chars (), m_moveSpeed, m_strafeSpeed, index, m_prevGoalIndex, goal, m_navTimeset - game.time (), pev->movetype, enemy.chars (), pickup.chars (), personalities[m_personality].chars ());
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\n", pev->netname.chars (), pev->health, pev->armorvalue, taskID, tasks[taskID].chars (), getTask ()->desire, weapon.chars (), getAmmoInClip (), getAmmo (), m_isReloading ? " (R)" : "", m_moneyAmount, aimFlags.trim ().chars (), m_moveSpeed, m_strafeSpeed, index, m_prevGoalIndex, goal, m_navTimeset - game.time (), pev->movetype, enemy.chars (), pickup.chars (), personalities[m_personality].chars ());
MessageWriter (MSG_ONE_UNRELIABLE, SVC_TEMPENTITY, nullptr, game.getLocalEntity ())
.writeByte (TE_TEXTMESSAGE)
@ -5288,11 +5276,11 @@ void Bot::dropWeaponForUser (edict_t *user, bool discardC4) {
if (discardC4) {
selectWeaponByName ("weapon_c4");
game.botCommand (ent (), "drop");
issueCommand ("drop");
}
else {
selectBestWeapon ();
game.botCommand (ent (), "drop");
issueCommand ("drop");
}
m_pickupItem = nullptr;
@ -5317,7 +5305,7 @@ void Bot::startDoubleJump (edict_t *ent) {
m_doubleJumpEntity = ent;
startTask (Task::DoubleJump, TaskPri::DoubleJump, kInvalidNodeIndex, game.time (), true);
sayTeam (strings.format ("Ok %s, i will help you!", STRING (ent->v.netname)));
sayTeam (strings.format ("Ok %s, i will help you!", ent->v.netname.chars ()));
}
void Bot::resetDoubleJump () {
@ -5330,7 +5318,7 @@ void Bot::resetDoubleJump () {
m_jumpReady = false;
}
void Bot::sayDebug (const char *format, ...) {
void Bot::debugMsgInternal (const char *str) {
if (game.isDedicated ()) {
return;
}
@ -5339,15 +5327,8 @@ void Bot::sayDebug (const char *format, ...) {
if (level <= 2) {
return;
}
va_list ap;
auto result = strings.chars ();
va_start (ap, format);
vsnprintf (result, StringBuffer::StaticBufferSize, format, ap);
va_end (ap);
String printBuf;
printBuf.assignf ("%s: %s", STRING (pev->netname), result);
printBuf.assignf ("%s: %s", pev->netname.chars (), str);
bool playMessage = false;
@ -5462,7 +5443,7 @@ edict_t *Bot::correctGrenadeVelocity (const char *model) {
edict_t *result = nullptr;
game.searchEntities ("classname", "grenade", [&] (edict_t *ent) {
if (ent->v.owner == this->ent () && strcmp (STRING (ent->v.model) + 9, model) == 0) {
if (ent->v.owner == this->ent () && strcmp (ent->v.model.chars () + 9, model) == 0) {
result = ent;
// set the correct velocity for the grenade

View file

@ -152,7 +152,7 @@ void Bot::prepareChatMessage (const String &message) {
if (!util.isPlayer (ent)) {
return "unknown";
}
String playerName = STRING (ent->v.netname);
String playerName = ent->v.netname.chars ();
util.humanizePlayerName (playerName);
return playerName;
@ -361,7 +361,7 @@ void Bot::say (const char *text) {
if (strings.isEmpty (text) || !yb_chat.bool_ ()) {
return;
}
game.botCommand (ent (), "say \"%s\"", text);
issueCommand ("say \"%s\"", text);
}
void Bot::sayTeam (const char *text) {
@ -370,5 +370,5 @@ void Bot::sayTeam (const char *text) {
if (strings.isEmpty (text) || !yb_chat.bool_ ()) {
return;
}
game.botCommand (ent (), "say_team \"%s\"", text);
issueCommand ("say_team \"%s\"", text);
}

View file

@ -1196,7 +1196,7 @@ bool Bot::hasSecondaryWeapon () {
bool Bot::hasShield () {
// this function returns true, if bot has a tactical shield
return strncmp (STRING (pev->viewmodel), "models/shield/v_shield_", 23) == 0;
return strncmp (pev->viewmodel.chars (), "models/shield/v_shield_", 23) == 0;
}
bool Bot::isShieldDrawn () {
@ -1216,7 +1216,7 @@ bool Bot::isEnemyBehindShield (edict_t *enemy) {
}
// check if enemy has shield and this shield is drawn
if ((enemy->v.weaponanim == 6 || enemy->v.weaponanim == 7) && strncmp (STRING (enemy->v.viewmodel), "models/shield/v_shield_", 23) == 0) {
if ((enemy->v.weaponanim == 6 || enemy->v.weaponanim == 7) && strncmp (enemy->v.viewmodel.chars (), "models/shield/v_shield_", 23) == 0) {
if (util.isInViewCone (pev->origin, enemy)) {
return true;
}
@ -1355,7 +1355,7 @@ bool Bot::rateGroundWeapon (edict_t *ent) {
auto tab = conf.getRawWeapons ();
for (int i = 0; i < kNumWeapons; ++i) {
if (strcmp (tab[*pref].model, STRING (ent->v.model) + 9) == 0) {
if (strcmp (tab[*pref].model, ent->v.model.chars () + 9) == 0) {
groundIndex = i;
break;
}
@ -1464,13 +1464,13 @@ int Bot::bestWeaponCarried () {
}
void Bot::selectWeaponByName (const char *name) {
game.botCommand (ent (), name);
issueCommand (name);
}
void Bot::selectWeaponById (int num) {
auto tab = conf.getRawWeapons ();
game.botCommand (ent (), tab[num].name);
issueCommand (tab[num].name);
}
void Bot::decideFollowUser () {

View file

@ -790,7 +790,7 @@ int BotControl::cmdNodeAcquireEditor () {
}
if (graph.hasEditor ()) {
msg ("Sorry, players \"%s\" already acquired rights to edit graph on this server.", STRING (graph.getEditor ()->v.netname));
msg ("Sorry, players \"%s\" already acquired rights to edit graph on this server.", graph.getEditor ()->v.netname.chars ());
return BotCommandResult::Handled;
}
graph.setEditor (m_ent);
@ -1854,7 +1854,7 @@ void BotControl::kickBotByMenu (int page) {
// check for fakeclient bit, since we're clear it upon kick, but actual bot struct destroyed after client disconnected
if (bot != nullptr && (bot->pev->flags & FL_FAKECLIENT)) {
menuKeys |= cr::bit (cr::abs (i - menuKey));
menus.appendf ("%1.1d. %s%s\n", i - menuKey + 1, STRING (bot->pev->netname), bot->m_team == Team::CT ? " \\y(CT)\\w" : " \\r(T)\\w");
menus.appendf ("%1.1d. %s%s\n", i - menuKey + 1, bot->pev->netname.chars (), bot->m_team == Team::CT ? " \\y(CT)\\w" : " \\r(T)\\w");
}
else {
menus.appendf ("\\d %1.1d. Not a Bot\\w\n", i - menuKey + 1);
@ -1915,13 +1915,13 @@ void BotControl::maintainAdminRights () {
}
else if (!!strcmp (yb_password.str (), engfuncs.pfnInfoKeyValue (engfuncs.pfnGetInfoKeyBuffer (client.ent), const_cast <char *> (yb_password_key.str ())))) {
client.flags &= ~ClientFlags::Admin;
game.print ("Player %s had lost remote access to %s.", STRING (player->v.netname), PRODUCT_SHORT_NAME);
game.print ("Player %s had lost remote access to %s.", player->v.netname.chars (), PRODUCT_SHORT_NAME);
}
}
else if (!(client.flags & ClientFlags::Admin) && !strings.isEmpty (yb_password_key.str ()) && !strings.isEmpty (yb_password.str ())) {
if (strcmp (yb_password.str (), engfuncs.pfnInfoKeyValue (engfuncs.pfnGetInfoKeyBuffer (client.ent), const_cast <char *> (yb_password_key.str ()))) == 0) {
client.flags |= ClientFlags::Admin;
game.print ("Player %s had gained full remote access to %s.", STRING (player->v.netname), PRODUCT_SHORT_NAME);
game.print ("Player %s had gained full remote access to %s.", player->v.netname.chars (), PRODUCT_SHORT_NAME);
}
}
}

View file

@ -38,15 +38,17 @@ void Game::precache () {
}
m_precached = true;
m_drawModels[DrawLine::Simple] = engfuncs.pfnPrecacheModel (ENGINE_STR ("sprites/laserbeam.spr"));
m_drawModels[DrawLine::Arrow] = engfuncs.pfnPrecacheModel (ENGINE_STR ("sprites/arrow1.spr"));
engfuncs.pfnPrecacheSound (ENGINE_STR ("weapons/xbow_hit1.wav")); // waypoint add
engfuncs.pfnPrecacheSound (ENGINE_STR ("weapons/mine_activate.wav")); // waypoint delete
engfuncs.pfnPrecacheSound (ENGINE_STR ("common/wpn_hudoff.wav")); // path add/delete start
engfuncs.pfnPrecacheSound (ENGINE_STR ("common/wpn_hudon.wav")); // path add/delete done
engfuncs.pfnPrecacheSound (ENGINE_STR ("common/wpn_moveselect.wav")); // path add/delete cancel
engfuncs.pfnPrecacheSound (ENGINE_STR ("common/wpn_denyselect.wav")); // path add/delete error
m_drawModels[DrawLine::Simple] = m_engineWrap.precacheModel ("sprites/laserbeam.spr");
m_drawModels[DrawLine::Arrow] = m_engineWrap.precacheModel ("sprites/arrow1.spr");
m_engineWrap.precacheSound ("weapons/xbow_hit1.wav"); // waypoint add
m_engineWrap.precacheSound ("weapons/mine_activate.wav"); // waypoint delete
m_engineWrap.precacheSound ("common/wpn_hudoff.wav"); // path add/delete start
m_engineWrap.precacheSound ("common/wpn_hudon.wav"); // path add/delete done
m_engineWrap.precacheSound ("common/wpn_moveselect.wav"); // path add/delete cancel
m_engineWrap.precacheSound ("common/wpn_denyselect.wav"); // path add/delete error
m_mapFlags = 0; // reset map type as worldspawn is the first entity spawned
@ -74,7 +76,7 @@ void Game::levelInitialize (edict_t *entities, int max) {
if (!ent || ent->free || ent->v.classname == 0) {
continue;
}
auto classname = STRING (ent->v.classname);
auto classname = ent->v.classname.chars ();
if (strcmp (classname, "worldspawn") == 0) {
m_startEntity = ent;
@ -86,7 +88,7 @@ void Game::levelInitialize (edict_t *entities, int max) {
util.installSendTo ();
}
else if (strcmp (classname, "player_weaponstrip") == 0) {
if ((is (GameFlags::Legacy)) && (STRING (ent->v.target))[0] == '\0') {
if (is (GameFlags::Legacy) && ent->v.target.chars ()[0] == '\0') {
ent->v.target = ent->v.targetname = engfuncs.pfnAllocString ("fake");
}
else {
@ -94,7 +96,7 @@ void Game::levelInitialize (edict_t *entities, int max) {
}
}
else if (strcmp (classname, "info_player_start") == 0) {
engfuncs.pfnSetModel (ent, ENGINE_STR ("models/player/urban/urban.mdl"));
m_engineWrap.setModel (ent, "models/player/urban/urban.mdl");
ent->v.rendermode = kRenderTransAlpha; // set its render mode to transparency
ent->v.renderamt = 127; // set its transparency amount
@ -103,7 +105,7 @@ void Game::levelInitialize (edict_t *entities, int max) {
++m_spawnCount[Team::CT];
}
else if (strcmp (classname, "info_player_deathmatch") == 0) {
engfuncs.pfnSetModel (ent, ENGINE_STR ("models/player/terror/terror.mdl"));
m_engineWrap.setModel (ent, "models/player/terror/terror.mdl");
ent->v.rendermode = kRenderTransAlpha; // set its render mode to transparency
ent->v.renderamt = 127; // set its transparency amount
@ -113,7 +115,7 @@ void Game::levelInitialize (edict_t *entities, int max) {
}
else if (strcmp (classname, "info_vip_start") == 0) {
engfuncs.pfnSetModel (ent, ENGINE_STR ("models/player/vip/vip.mdl"));
m_engineWrap.setModel (ent, "models/player/vip/vip.mdl");
ent->v.rendermode = kRenderTransAlpha; // set its render mode to transparency
ent->v.renderamt = 127; // set its transparency amount
@ -306,7 +308,7 @@ const char *Game::getModName () {
const char *Game::getMapName () {
// this function gets the map name and store it in the map_name global string variable.
return strings.format ("%s", STRING (globals->mapname));
return strings.format ("%s", globals->mapname.chars ());
}
Vector Game::getEntityWorldOrigin (edict_t *ent) {
@ -465,7 +467,7 @@ bool Game::isSoftwareRenderer () {
}
// and on only windows version you can use software-render game. Linux, OSX always defaults to OpenGL
if (plat.isWindows) {
if (plat.win32) {
return plat.hasModule ("sw");
}
return false;
@ -577,15 +579,15 @@ bool Game::loadCSBinary () {
}
StringArray libs;
if (plat.isWindows) {
if (plat.win32) {
libs.push ("mp.dll");
libs.push ("cs.dll");
}
else if (plat.isLinux) {
else if (plat.linux) {
libs.push ("cs.so");
libs.push ("cs_i386.so");
}
else if (plat.isOSX) {
else if (plat.osx) {
libs.push ("cs.dylib");
}
@ -739,13 +741,13 @@ bool Game::postload () {
print ("%s v%s.0.%d successfully loaded for game: Counter-Strike %s (%s).\n", PRODUCT_SHORT_NAME, PRODUCT_VERSION, util.buildNumber (), gameVersionStr.chars (), String::join (gameVersionFlags, ", ").chars ());
};
if (plat.isAndroid) {
if (plat.android) {
m_gameFlags |= (GameFlags::Xash3D | GameFlags::Mobility | GameFlags::HasBotVoice | GameFlags::ReGameDLL);
if (is (GameFlags::Metamod)) {
return true; // we should stop the attempt for loading the real gamedll, since metamod handle this for us
}
auto gamedll = strings.format ("%s/%s", getenv ("XASH3D_GAMELIBDIR"), plat.isAndroidHardFP ? "libserver_hardfp.so" : "libserver.so");
auto gamedll = strings.format ("%s/%s", getenv ("XASH3D_GAMELIBDIR"), plat.hfp ? "libserver_hardfp.so" : "libserver.so");
if (!m_gameLib.load (gamedll)) {
logger.fatal ("Unable to load gamedll \"%s\". Exiting... (gamedir: %s)", gamedll, getModName ());
@ -879,9 +881,8 @@ bool Game::isShootableBreakable (edict_t *ent) {
if (isNullEntity (ent)) {
return false;
}
auto classname = STRING (ent->v.classname);
if (strcmp (classname, "func_breakable") == 0 || (strcmp (classname, "func_pushable") == 0 && (ent->v.spawnflags & SF_PUSH_BREAKABLE))) {
if (strcmp (ent->v.classname.chars (), "func_breakable") == 0 || (strcmp (ent->v.classname.chars (), "func_pushable") == 0 && (ent->v.spawnflags & SF_PUSH_BREAKABLE))) {
return ent->v.takedamage != DAMAGE_NO && ent->v.impulse <= 0 && !(ent->v.flags & FL_WORLDBRUSH) && !(ent->v.spawnflags & SF_BREAK_TRIGGER_ONLY) && ent->v.health < 500.0f;
}
return false;

View file

@ -1098,7 +1098,7 @@ void BotGraph::calculatePathRadius (int index) {
if (tr.flFraction < 1.0f) {
game.testLine (radiusStart, radiusEnd, TraceIgnore::Monsters, nullptr, &tr);
if (strncmp ("func_door", STRING (tr.pHit->v.classname), 9) == 0) {
if (strncmp ("func_door", tr.pHit->v.classname.chars (), 9) == 0) {
path.radius = 0.0f;
wayBlocked = true;
@ -1676,7 +1676,7 @@ bool BotGraph::saveGraphData () {
options |= StorageOption::Recovered;
}
else if (!game.isNullEntity (m_editor)) {
author = STRING (m_editor->v.netname);
author = m_editor->v.netname.chars ();
}
else {
author = "YAPB";
@ -1691,9 +1691,10 @@ bool BotGraph::saveGraphData () {
}
void BotGraph::saveOldFormat () {
PODGraphHeader header;
PODGraphHeader header {};
strcpy (header.header, kPodbotMagic);
strncpy (header.author, STRING (m_editor->v.netname), cr::bufsize (header.author));
strncpy (header.author, m_editor->v.netname.chars (), cr::bufsize (header.author));
strncpy (header.mapName, game.getMapName (), cr::bufsize (header.mapName));
header.mapName[31] = 0;
@ -1750,7 +1751,7 @@ bool BotGraph::isNodeReacheable (const Vector &src, const Vector &destination) {
// check if we go through a func_illusionary, in which case return false
game.testHull (src, destination, TraceIgnore::Monsters, head_hull, m_editor, &tr);
if (!game.isNullEntity (tr.pHit) && strcmp ("func_illusionary", STRING (tr.pHit->v.classname)) == 0) {
if (!game.isNullEntity (tr.pHit) && strcmp ("func_illusionary", tr.pHit->v.classname.chars ()) == 0) {
return false; // don't add pathnodes through func_illusionaries
}
@ -1758,9 +1759,9 @@ bool BotGraph::isNodeReacheable (const Vector &src, const Vector &destination) {
game.testLine (src, destination, TraceIgnore::Monsters, m_editor, &tr);
// if node is visible from current position (even behind head)...
if (tr.flFraction >= 1.0f || strncmp ("func_door", STRING (tr.pHit->v.classname), 9) == 0) {
if (tr.flFraction >= 1.0f || strncmp ("func_door", tr.pHit->v.classname.chars (), 9) == 0) {
// if it's a door check if nothing blocks behind
if (strncmp ("func_door", STRING (tr.pHit->v.classname), 9) == 0) {
if (strncmp ("func_door", tr.pHit->v.classname.chars (), 9) == 0) {
game.testLine (tr.vecEndPos, destination, TraceIgnore::Monsters, tr.pHit, &tr);
if (tr.flFraction < 1.0f) {
@ -2649,7 +2650,7 @@ void BotGraph::setBombOrigin (bool reset, const Vector &pos) {
}
game.searchEntities ("classname", "grenade", [&] (edict_t *ent) {
if (strcmp (STRING (ent->v.model) + 9, "c4.mdl") == 0) {
if (strcmp (ent->v.model.chars () + 9, "c4.mdl") == 0) {
m_bombOrigin = game.getEntityWorldOrigin (ent);
return EntitySearchResult::Break;
}

View file

@ -53,12 +53,14 @@ namespace variadic {
auto buffer = strings.chars ();
va_start (ap, format);
_vsnprintf (buffer, StringBuffer::StaticBufferSize, format, ap);
vsnprintf (buffer, StringBuffer::StaticBufferSize, format, ap);
va_end (ap);
if (ent && (ent->v.flags & (FL_FAKECLIENT | FL_DORMANT))) {
if (bots[ent]) {
game.botCommand (ent, buffer);
auto bot = bots[ent];
if (bot) {
bot->issueCommand (buffer);
}
if (game.is (GameFlags::Metamod)) {
@ -441,7 +443,7 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *table, int *) {
}
dllapi.pfnPM_Move (playerMove, server);
};
return TRUE;
return true;
}
CR_LINKAGE_C int GetEntityAPI2_Post (gamefuncs_t *table, int *) {
@ -498,7 +500,7 @@ CR_LINKAGE_C int GetEntityAPI2_Post (gamefuncs_t *table, int *) {
RETURN_META (MRES_IGNORED);
};
return TRUE;
return true;
}
CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
@ -787,7 +789,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
table->pfnClientCommand = variadic::clientCommand;
return TRUE;
return true;
}
CR_EXPORT int GetNewDLLFunctions (newgamefuncs_t *table, int *interfaceVersion) {
@ -801,11 +803,11 @@ CR_EXPORT int GetNewDLLFunctions (newgamefuncs_t *table, int *interfaceVersion)
if (!api_GetNewDLLFunctions || !api_GetNewDLLFunctions (table, interfaceVersion)) {
logger.error ("Could not resolve symbol \"%s\" in the game dll. Continuing...", __FUNCTION__);
return FALSE;
return false;
}
dllfuncs.newapi_table = table;
return TRUE;
return true;
}
CR_LINKAGE_C int GetEngineFunctions_Post (enginefuncs_t *table, int *) {
@ -834,7 +836,7 @@ CR_LINKAGE_C int GetEngineFunctions_Post (enginefuncs_t *table, int *) {
RETURN_META_VALUE (MRES_IGNORED, 0);
};
return TRUE;
return true;
}
CR_EXPORT int Meta_Query (char *, plugin_info_t **pPlugInfo, mutil_funcs_t *pMetaUtilFuncs) {
@ -845,7 +847,7 @@ CR_EXPORT int Meta_Query (char *, plugin_info_t **pPlugInfo, mutil_funcs_t *pMet
gpMetaUtilFuncs = pMetaUtilFuncs;
*pPlugInfo = &Plugin_info;
return TRUE; // tell metamod this plugin looks safe
return true; // tell metamod this plugin looks safe
}
CR_EXPORT int Meta_Attach (PLUG_LOADTIME now, metamod_funcs_t *functionTable, meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs) {
@ -867,7 +869,7 @@ CR_EXPORT int Meta_Attach (PLUG_LOADTIME now, metamod_funcs_t *functionTable, me
if (now > Plugin_info.loadable) {
logger.error ("%s: plugin NOT attaching (can't load plugin right now)", Plugin_info.name);
return FALSE; // returning FALSE prevents metamod from attaching this plugin
return false; // returning FALSE prevents metamod from attaching this plugin
}
// keep track of the pointers to engine function tables metamod gives us
@ -875,7 +877,7 @@ CR_EXPORT int Meta_Attach (PLUG_LOADTIME now, metamod_funcs_t *functionTable, me
memcpy (functionTable, &metamodFunctionTable, sizeof (metamod_funcs_t));
gpGamedllFuncs = pGamedllFuncs;
return TRUE; // returning true enables metamod to attach this plugin
return true; // returning true enables metamod to attach this plugin
}
CR_EXPORT int Meta_Detach (PLUG_LOADTIME now, PL_UNLOAD_REASON reason) {
@ -884,7 +886,7 @@ CR_EXPORT int Meta_Detach (PLUG_LOADTIME now, PL_UNLOAD_REASON reason) {
if (now > Plugin_info.unloadable && reason != PNL_CMD_FORCED) {
logger.error ("%s: plugin NOT detaching (can't unload plugin right now)", Plugin_info.name);
return FALSE; // returning FALSE prevents metamod from unloading this plugin
return false; // returning FALSE prevents metamod from unloading this plugin
}
bots.kickEveryone (true); // kick all bots off this server
@ -892,7 +894,7 @@ CR_EXPORT int Meta_Detach (PLUG_LOADTIME now, PL_UNLOAD_REASON reason) {
graph.savePractice ();
util.disableSendTo ();
return TRUE;
return true;
}
CR_EXPORT void Meta_Init () {

View file

@ -47,12 +47,16 @@ BotManager::BotManager () {
m_bombPlanted = false;
m_botsCanPause = false;
m_roundEnded = false;
m_bombSayStatus = BombPlantedSay::ChatSay | BombPlantedSay::Chatter;
for (int i = 0; i < kGameTeamNum; ++i) {
m_leaderChoosen[i] = false;
m_economicsGood[i] = true;
m_lastRadioTime[i] = 0.0f;
m_lastRadio[i] = -1;
}
reset ();
@ -106,7 +110,7 @@ void BotManager::touchKillerEntity (Bot *bot) {
kv.szClassName = const_cast <char *> (prop.classname.chars ());
kv.szKeyName = "damagetype";
kv.szValue = const_cast <char *> (strings.format ("%d", cr::bit (4)));
kv.fHandled = FALSE;
kv.fHandled = false;
MDLL_KeyValue (m_killerEntity, &kv);
MDLL_Touch (m_killerEntity, bot->ent ());
@ -205,7 +209,7 @@ BotCreateResult BotManager::create (const String &name, int difficulty, int pers
ctrl.msg ("Maximum players reached (%d/%d). Unable to create Bot.", game.maxClients (), game.maxClients ());
return BotCreateResult::MaxPlayersReached;
}
auto object = cr::createUnique <Bot> (bot, difficulty, personality, team, member);
auto object = cr::makeUnique <Bot> (bot, difficulty, personality, team, member);
auto index = object->index ();
// assign owner of bot name
@ -660,7 +664,7 @@ 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", "index", "name", "personality", "team", "difficulty", "frags", "alive");
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", bot->index (), STRING (bot->pev->netname), 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");
ctrl.msg ("[%-3.1d]\t%-19.16s\t%-10.12s\t%-3.4s\t%-3.1d\t%-3.1d\t%-3.4s", 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");
}
ctrl.msg ("%d bots", m_bots.length ());
}
@ -816,11 +820,11 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int member) {
}
char reject[256] = {0, };
MDLL_ClientConnect (bot, STRING (bot->v.netname), strings.format ("127.0.0.%d", clientIndex + 100), reject);
MDLL_ClientConnect (bot, bot->v.netname.chars (), strings.format ("127.0.0.%d", clientIndex + 100), reject);
if (!strings.isEmpty (reject)) {
logger.error ("Server refused '%s' connection (%s)", STRING (bot->v.netname), reject);
game.serverCommand ("kick \"%s\"", STRING (bot->v.netname)); // kick the bot player if the server refused it
logger.error ("Server refused '%s' connection (%s)", bot->v.netname.chars (), reject);
game.serverCommand ("kick \"%s\"", bot->v.netname.chars ()); // kick the bot player if the server refused it
bot->v.flags |= FL_KILLME;
return;
@ -1246,7 +1250,7 @@ void Bot::kill () {
void Bot::kick () {
// this function kick off one bot from the server.
auto username = STRING (pev->netname);
auto username = pev->netname.chars ();
if (!(pev->flags & FL_FAKECLIENT) || strings.isEmpty (username)) {
return;
@ -1304,7 +1308,7 @@ void Bot::updateTeamJoin () {
}
// select the team the bot wishes to join...
game.botCommand (ent (), "menuselect %d", m_wantedTeam);
issueCommand ("menuselect %d", m_wantedTeam);
}
else if (m_startAction == BotMsg::ClassSelect) {
m_startAction = BotMsg::None; // switch back to idle
@ -1317,7 +1321,7 @@ void Bot::updateTeamJoin () {
}
// select the class the bot wishes to use...
game.botCommand (ent (), "menuselect %d", m_wantedClass);
issueCommand ("menuselect %d", m_wantedClass);
// bot has now joined the game (doesn't need to be started)
m_notStarted = false;
@ -1409,7 +1413,7 @@ void BotManager::updateActiveGrenade () {
// search the map for any type of grenade
game.searchEntities ("classname", "grenade", [&] (edict_t *e) {
// do not count c4 as a grenade
if (strcmp (STRING (e->v.model) + 9, "c4.mdl") == 0) {
if (strcmp (e->v.model.chars () + 9, "c4.mdl") == 0) {
return EntitySearchResult::Continue;
}
m_activeGrenades.push (e);
@ -1430,7 +1434,7 @@ void BotManager::updateIntrestingEntities () {
// search the map for any type of grenade
game.searchEntities (nullptr, kInfiniteDistance, [&] (edict_t *e) {
auto classname = STRING (e->v.classname);
auto classname = e->v.classname.chars ();
// search for grenades, weaponboxes, weapons, items and armoury entities
if (strncmp ("weapon", classname, 6) == 0 || strncmp ("grenade", classname, 7) == 0 || strncmp ("item", classname, 4) == 0 || strncmp ("armoury", classname, 7) == 0) {
@ -1689,7 +1693,7 @@ void BotConfig::loadMainConfig () {
firstLoad = false;
// android is abit hard to play, lower the difficulty by default
if (plat.isAndroid && yb_difficulty.int_ () > 3) {
if (plat.android && yb_difficulty.int_ () > 3) {
yb_difficulty.set (3);
}
return;

View file

@ -507,3 +507,25 @@ void MessageDispatcher::stop () {
(this->*m_handlers[m_current]) ();
m_current = NetMsg::None;
}
void MessageDispatcher::ensureMessages () {
// we're getting messages ids in regusermsg for metamod, but when we're unloaded, we're lost our ids on next 'meta load'.
// this function tries to associate appropriate message ids.
// check if we're have one
if (m_maps.exists (NetMsg::Money)) {
return;
}
// re-register our message
for (const auto &msg : m_wanted) {
add (msg.key, GET_USER_MSG_ID (PLID, msg.key.chars (), nullptr));
}
}
int32 MessageDispatcher::id (NetMsg msg) {
if (game.is (GameFlags::Metamod)) {
ensureMessages ();
}
return m_maps[msg];
}

View file

@ -19,7 +19,7 @@ int Bot::findBestGoal () {
int result = kInvalidNodeIndex;
game.searchEntities ("classname", "weaponbox", [&] (edict_t *ent) {
if (strcmp (STRING (ent->v.model), "models/w_backpack.mdl") == 0) {
if (strcmp (ent->v.model.chars () + 9, "backpack.mdl") == 0) {
result = graph.getNearest (game.getEntityWorldOrigin (ent));
if (graph.exists (result)) {
@ -708,7 +708,7 @@ bool Bot::updateNavigation () {
if (game.mapIs (MapFlags::HasDoors)) {
game.testLine (pev->origin, m_pathOrigin, TraceIgnore::Monsters, ent (), &tr);
if (!game.isNullEntity (tr.pHit) && game.isNullEntity (m_liftEntity) && strncmp (STRING (tr.pHit->v.classname), "func_door", 9) == 0) {
if (!game.isNullEntity (tr.pHit) && game.isNullEntity (m_liftEntity) && strncmp (tr.pHit->v.classname.chars (), "func_door", 9) == 0) {
// if the door is near enough...
if ((game.getEntityWorldOrigin (tr.pHit) - pev->origin).lengthSq () < 2500.0f) {
ignoreCollision (); // don't consider being stuck
@ -728,7 +728,7 @@ bool Bot::updateNavigation () {
m_aimFlags &= ~(AimFlags::LastEnemy | AimFlags::PredictPath);
m_canChooseAimDirection = false;
auto button = lookupButton (STRING (tr.pHit->v.targetname));
auto button = lookupButton (tr.pHit->v.targetname.chars ());
// check if we got valid button
if (!game.isNullEntity (button)) {
@ -849,7 +849,7 @@ bool Bot::updateLiftHandling () {
// update node time set
m_navTimeset = game.time ();
TraceResult tr, tr2;
TraceResult tr;
// wait for something about for lift
auto wait = [&] () {
@ -865,9 +865,9 @@ bool Bot::updateLiftHandling () {
};
// trace line to door
game.testLine (pev->origin, m_path->origin, TraceIgnore::Everything, ent (), &tr2);
game.testLine (pev->origin, m_path->origin, TraceIgnore::Everything, ent (), &tr);
if (tr2.flFraction < 1.0f && strcmp (STRING (tr2.pHit->v.classname), "func_door") == 0 && (m_liftState == LiftState::None || m_liftState == LiftState::WaitingFor || m_liftState == LiftState::LookingButtonOutside) && pev->groundentity != tr2.pHit) {
if (tr.flFraction < 1.0f && strcmp (tr.pHit->v.classname.chars (), "func_door") == 0 && (m_liftState == LiftState::None || m_liftState == LiftState::WaitingFor || m_liftState == LiftState::LookingButtonOutside) && pev->groundentity != tr.pHit) {
if (m_liftState == LiftState::None) {
m_liftState = LiftState::LookingButtonOutside;
m_liftUsageTime = game.time () + 7.0f;
@ -879,8 +879,8 @@ bool Bot::updateLiftHandling () {
game.testLine (m_path->origin, m_path->origin + Vector (0.0f, 0.0f, -50.0f), TraceIgnore::Everything, ent (), &tr);
// if trace result shows us that it is a lift
if (!game.isNullEntity (tr.pHit) && !m_pathWalk.empty () && (strcmp (STRING (tr.pHit->v.classname), "func_door") == 0 || strcmp (STRING (tr.pHit->v.classname), "func_plat") == 0 || strcmp (STRING (tr.pHit->v.classname), "func_train") == 0) && !liftClosedDoorExists) {
if ((m_liftState == LiftState::None || m_liftState == LiftState::WaitingFor || m_liftState == LiftState::LookingButtonOutside) && tr.pHit->v.velocity.z == 0.0f) {
if (!game.isNullEntity (tr.pHit) && !m_pathWalk.empty () && (strcmp (tr.pHit->v.classname.chars (), "func_door") == 0 || strcmp (tr.pHit->v.classname.chars (), "func_plat") == 0 || strcmp (tr.pHit->v.classname.chars (), "func_train") == 0) && !liftClosedDoorExists) {
if ((m_liftState == LiftState::None || m_liftState == LiftState::WaitingFor || m_liftState == LiftState::LookingButtonOutside) && cr::fzero (tr.pHit->v.velocity.z)) {
if (cr::abs (pev->origin.z - tr.vecEndPos.z) < 70.0f) {
m_liftEntity = tr.pHit;
m_liftState = LiftState::EnteringIn;
@ -901,7 +901,7 @@ bool Bot::updateLiftHandling () {
if (graph.exists (nextNode) && (graph[nextNode].flags & NodeFlag::Lift)) {
game.testLine (m_path->origin, graph[nextNode].origin, TraceIgnore::Everything, ent (), &tr);
if (!game.isNullEntity (tr.pHit) && (strcmp (STRING (tr.pHit->v.classname), "func_door") == 0 || strcmp (STRING (tr.pHit->v.classname), "func_plat") == 0 || strcmp (STRING (tr.pHit->v.classname), "func_train") == 0)) {
if (!game.isNullEntity (tr.pHit) && (strcmp (tr.pHit->v.classname.chars (), "func_door") == 0 || strcmp (tr.pHit->v.classname.chars (), "func_plat") == 0 || strcmp (tr.pHit->v.classname.chars (), "func_train") == 0)) {
m_liftEntity = tr.pHit;
}
}
@ -983,7 +983,7 @@ bool Bot::updateLiftHandling () {
// bot is trying to find button inside a lift
if (m_liftState == LiftState::LookingButtonInside) {
auto button = lookupButton (STRING (m_liftEntity->v.targetname));
auto button = lookupButton (m_liftEntity->v.targetname.chars ());
// got a valid button entity ?
if (!game.isNullEntity (button) && pev->groundentity == m_liftEntity && m_buttonPushTime + 1.0f < game.time () && m_liftEntity->v.velocity.z == 0.0f && isOnFloor ()) {
@ -1032,7 +1032,7 @@ bool Bot::updateLiftHandling () {
}
}
else if (!game.isNullEntity (m_liftEntity)) {
auto button = lookupButton (STRING (m_liftEntity->v.targetname));
auto button = lookupButton (m_liftEntity->v.targetname.chars ());
// if we got a valid button entity
if (!game.isNullEntity (button)) {
@ -1331,63 +1331,40 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath:
return hfunctionPathDist (index, startIndex, goalIndex) / 128.0f * 10.0f;
};
// holders for heuristic functions
Lambda <float (int, int, int)> gcalc, hcalc;
// get correct calculation for heuristic
auto calculate = [&] (bool hfun, int a, int b, int c) -> float {
if (pathType == FindPath::Optimal) {
if (game.mapIs (MapFlags::HostageRescue) && hasHostage ()) {
if (hfun) {
return hfunctionPathDistWithHostage (a, b, c);
}
else {
return gfunctionKillsDistCTWithHostage (a, b, c);
}
}
else {
if (hfun) {
return hfunctionPathDist (a, b, c);
}
else {
return gfunctionKillsDist (a, b, c);
}
}
}
else if (pathType == FindPath::Safe) {
if (game.mapIs (MapFlags::HostageRescue) && hasHostage ()) {
if (hfun) {
return hfunctionNone (a, b, c);
}
else {
return gfunctionKillsCTWithHostage (a, b, c);
}
}
else {
if (hfun) {
return hfunctionNone (a, b, c);
}
else {
return gfunctionKills (a, b, c);
}
}
if (pathType == FindPath::Optimal) {
if (game.mapIs (MapFlags::HostageRescue) && hasHostage ()) {
hcalc = hfunctionPathDistWithHostage;
gcalc = gfunctionKillsDistCTWithHostage;
}
else {
if (game.mapIs (MapFlags::HostageRescue) && hasHostage ()) {
if (hfun) {
return hfunctionPathDistWithHostage (a, b, c);
}
else {
return gfunctionPathDistWithHostage (a, b, c);
}
}
else {
if (hfun) {
return hfunctionPathDist (a, b, c);
}
else {
return gfunctionPathDist (a, b, c);
}
}
hcalc = hfunctionPathDist;
gcalc = gfunctionKillsDist;
}
};
}
else if (pathType == FindPath::Safe) {
if (game.mapIs (MapFlags::HostageRescue) && hasHostage ()) {
hcalc = hfunctionNone;
gcalc = gfunctionKillsCTWithHostage;
}
else {
hcalc = hfunctionNone;
gcalc = gfunctionKills;
}
}
else {
if (game.mapIs (MapFlags::HostageRescue) && hasHostage ()) {
hcalc = hfunctionPathDistWithHostage;
gcalc = gfunctionPathDistWithHostage;
}
else {
hcalc = hfunctionPathDist;
gcalc = gfunctionPathDist;
}
}
if (!graph.exists (srcIndex)) {
logger.error ("Pathfinder source path index not valid (%d)", srcIndex);
@ -1406,8 +1383,8 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath:
auto srcRoute = &m_routes[srcIndex];
// put start node into open list
srcRoute->g = calculate (false, m_team, srcIndex, kInvalidNodeIndex);
srcRoute->f = srcRoute->g + calculate (true, srcIndex, srcIndex, destIndex);
srcRoute->g = gcalc (m_team, srcIndex, kInvalidNodeIndex);
srcRoute->f = srcRoute->g + hcalc (srcIndex, srcIndex, destIndex);
srcRoute->state = RouteState::Open;
m_routeQue.clear ();
@ -1419,7 +1396,7 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath:
// safes us from bad graph...
if (m_routeQue.length () >= kMaxRouteLength - 1) {
logger.error ("A* Search for bots \"%s\" has tried to build path with at least %d nodes. Seems to be graph is broken.", STRING (pev->netname), m_routeQue.length ());
logger.error ("A* Search for bot \"%s\" has tried to build path with at least %d nodes. Seems to be graph is broken.", pev->netname.chars (), m_routeQue.length ());
// bail out to shortest path
findShortestPath (srcIndex, destIndex);
@ -1458,8 +1435,8 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath:
auto childRoute = &m_routes[child.index];
// calculate the F value as F = G + H
float g = curRoute->g + calculate (false, m_team, child.index, currentIndex);
float h = calculate (true, child.index, srcIndex, destIndex);
float g = curRoute->g + gcalc (m_team, child.index, currentIndex);
float h = hcalc (child.index, srcIndex, destIndex);
float f = g + h;
if (childRoute->state == RouteState::New || childRoute->f > f) {
@ -1474,6 +1451,9 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath:
}
}
}
logger.error ("A* Search for bot \"%s\" has failed. Falling back to shortest-path algorithm. Seems to be graph is broken.", pev->netname.chars ());
// fallback to shortest path
findShortestPath (srcIndex, destIndex); // A* found no path, try floyd pathfinder instead
}
@ -2098,6 +2078,22 @@ bool Bot::advanceMovement () {
m_pathWalk.shift (); // advance in list
m_currentTravelFlags = 0; // reset travel flags (jumping etc)
// helper to change bot's goal
auto changeNextGoal = [&] {
int newGoal = findBestGoal ();
m_prevGoalIndex = newGoal;
m_chosenGoalIndex = newGoal;
// remember index
getTask ()->data = newGoal;
// do path finding if it's not the current node
if (newGoal != m_currentNodeIndex) {
findPath (m_currentNodeIndex, newGoal, m_pathType);
}
};
// we're not at the end of the list?
if (!m_pathWalk.empty ()) {
// if in between a route, postprocess the node (find better alternatives)...
@ -2142,22 +2138,15 @@ bool Bot::advanceMovement () {
// force terrorist bot to plant bomb
if (m_inBombZone && !m_hasProgressBar && m_hasC4) {
int newGoal = findBestGoal ();
m_prevGoalIndex = newGoal;
m_chosenGoalIndex = newGoal;
// remember index
getTask ()->data = newGoal;
// do path finding if it's not the current node
if (newGoal != m_currentNodeIndex) {
findPath (m_currentNodeIndex, newGoal, m_pathType);
}
changeNextGoal ();
return false;
}
}
}
else if (m_pathWalk.hasNext () && m_pathWalk.next () == m_pathWalk.last () && isOccupiedNode (m_pathWalk.last ())) {
changeNextGoal ();
return false;
}
if (!m_pathWalk.empty ()) {
const int destIndex = m_pathWalk.first ();
@ -2192,7 +2181,7 @@ bool Bot::advanceMovement () {
src = path.origin;
dst = next.origin;
jumpDistance = (src - dst).length ();
jumpDistance = (path.origin - next.origin).length ();
willJump = true;
break;
@ -2255,7 +2244,7 @@ bool Bot::cantMoveForward (const Vector &normal, TraceResult *tr) {
if (!game.mapIs (MapFlags::HasDoors)) {
return false;
}
return tr->flFraction < 1.0f && strncmp ("func_door", STRING (tr->pHit->v.classname), 9) != 0;
return tr->flFraction < 1.0f && strncmp ("func_door", tr->pHit->v.classname.chars (), 9) != 0;
};
// trace from the bot's eyes straight forward...
@ -2263,7 +2252,7 @@ bool Bot::cantMoveForward (const Vector &normal, TraceResult *tr) {
// check if the trace hit something...
if (tr->flFraction < 1.0f) {
if (game.mapIs (MapFlags::HasDoors) && strncmp ("func_door", STRING (tr->pHit->v.classname), 9) == 0) {
if (game.mapIs (MapFlags::HasDoors) && strncmp ("func_door", tr->pHit->v.classname.chars (), 9) == 0) {
return false;
}
return true; // bot's head will hit something
@ -2614,7 +2603,7 @@ bool Bot::isBlockedLeft () {
game.testLine (pev->origin, forward * direction - right * 48.0f, TraceIgnore::Monsters, ent (), &tr);
// check if the trace hit something...
if (game.mapIs (MapFlags::HasDoors) && tr.flFraction < 1.0f && strncmp ("func_door", STRING (tr.pHit->v.classname), 9) != 0) {
if (game.mapIs (MapFlags::HasDoors) && tr.flFraction < 1.0f && strncmp ("func_door", tr.pHit->v.classname.chars (), 9) != 0) {
return true; // bot's body will hit something
}
return false;
@ -2634,7 +2623,7 @@ bool Bot::isBlockedRight () {
game.testLine (pev->origin, pev->origin + forward * direction + right * 48.0f, TraceIgnore::Monsters, ent (), &tr);
// check if the trace hit something...
if (game.mapIs (MapFlags::HasDoors) && tr.flFraction < 1.0f && (strncmp ("func_door", STRING (tr.pHit->v.classname), 9) != 0)) {
if (game.mapIs (MapFlags::HasDoors) && tr.flFraction < 1.0f && (strncmp ("func_door", tr.pHit->v.classname.chars (), 9) != 0)) {
return true; // bot's body will hit something
}
return false;
@ -2995,7 +2984,7 @@ int Bot::getNearestToPlantedBomb () {
// search the bomb on the map
game.searchEntities ("classname", "grenade", [&result] (edict_t *ent) {
if (strcmp (STRING (ent->v.model) + 9, "c4.mdl") == 0) {
if (strcmp (ent->v.model.chars () + 9, "c4.mdl") == 0) {
result = graph.getNearest (game.getEntityWorldOrigin (ent));
if (graph.exists (result)) {

View file

@ -67,6 +67,40 @@ BotUtils::BotUtils () {
m_noiseCache["debris/bust"] = Noise::NeedHandle | Noise::Broke;
m_noiseCache["doors/doorm"] = Noise::NeedHandle | Noise::Door;
// register weapon aliases
m_weaponAlias.push (Weapon::USP, "usp"); // HK USP .45 Tactical
m_weaponAlias.push (Weapon::Glock18, "glock"); // Glock18 Select Fire
m_weaponAlias.push (Weapon::Deagle, "deagle"); // Desert Eagle .50AE
m_weaponAlias.push (Weapon::P228, "p228"); // SIG P228
m_weaponAlias.push (Weapon::Elite, "elite"); // Dual Beretta 96G Elite
m_weaponAlias.push (Weapon::FiveSeven, "fn57"); // FN Five-Seven
m_weaponAlias.push (Weapon::M3, "m3"); // Benelli M3 Super90
m_weaponAlias.push (Weapon::XM1014, "xm1014"); // Benelli XM1014
m_weaponAlias.push (Weapon::MP5, "mp5"); // HK MP5-Navy
m_weaponAlias.push (Weapon::TMP, "tmp"); // Steyr Tactical Machine Pistol
m_weaponAlias.push (Weapon::P90, "p90"); // FN P90
m_weaponAlias.push (Weapon::MAC10, "mac10"); // Ingram MAC-10
m_weaponAlias.push (Weapon::UMP45, "ump45"); // HK UMP45
m_weaponAlias.push (Weapon::AK47, "ak47"); // Automat Kalashnikov AK-47
m_weaponAlias.push (Weapon::Galil, "galil"); // IMI Galil
m_weaponAlias.push (Weapon::Famas, "famas"); // GIAT FAMAS
m_weaponAlias.push (Weapon::SG552, "sg552"); // Sig SG-552 Commando
m_weaponAlias.push (Weapon::M4A1, "m4a1"); // Colt M4A1 Carbine
m_weaponAlias.push (Weapon::AUG, "aug"); // Steyr Aug
m_weaponAlias.push (Weapon::Scout, "scout"); // Steyr Scout
m_weaponAlias.push (Weapon::AWP, "awp"); // AI Arctic Warfare/Magnum
m_weaponAlias.push (Weapon::G3SG1, "g3sg1"); // HK G3/SG-1 Sniper Rifle
m_weaponAlias.push (Weapon::SG550, "sg550"); // Sig SG-550 Sniper
m_weaponAlias.push (Weapon::M249, "m249"); // FN M249 Para
m_weaponAlias.push (Weapon::Flashbang, "flash"); // Concussion Grenade
m_weaponAlias.push (Weapon::Explosive, "hegren"); // High-Explosive Grenade
m_weaponAlias.push (Weapon::Smoke, "sgren"); // Smoke Grenade
m_weaponAlias.push (Weapon::Armor, "vest"); // Kevlar Vest
m_weaponAlias.push (Weapon::ArmorHelm, "vesthelm"); // Kevlar Vest and Helmet
m_weaponAlias.push (Weapon::Defuser, "defuser"); // Defuser Kit
m_weaponAlias.push (Weapon::Shield, "shield"); // Tactical Shield
m_weaponAlias.push (Weapon::Knife, "knife"); // Knife
m_clients.resize (kGameMaxPlayers + 1);
}
@ -169,7 +203,7 @@ bool BotUtils::isPlayer (edict_t *ent) {
}
if ((ent->v.flags & (FL_CLIENT | FL_FAKECLIENT)) || bots[ent] != nullptr) {
return !strings.isEmpty (STRING (ent->v.netname));
return !strings.isEmpty (ent->v.netname.chars ());
}
return false;
}
@ -609,7 +643,7 @@ void BotUtils::installSendTo () {
}
// enable only on modern games
if (game.is (GameFlags::Modern) && (plat.isLinux || plat.isWindows) && !plat.isArm && !m_sendToHook.enabled ()) {
if (game.is (GameFlags::Modern) && (plat.linux || plat.win32) && !plat.arm && !m_sendToHook.enabled ()) {
m_sendToHook.patch (reinterpret_cast <void *> (&sendto), reinterpret_cast <void *> (&BotUtils::sendTo));
}
}
@ -709,66 +743,11 @@ int BotUtils::buildNumber () {
return buildNumber;
}
int BotUtils::getWeaponAlias (bool needString, const char *weaponAlias, int weaponIndex) {
// this function returning weapon id from the weapon alias and vice versa.
const String &BotUtils::weaponIdToAlias (const int32 id) {
static const String &none = "none";
// structure definition for weapon tab
struct WeaponTab_t {
Weapon weaponIndex; // weapon id
const char *alias; // weapon alias
};
// weapon enumeration
WeaponTab_t weaponTab[] = {
{Weapon::USP, "usp"}, // HK USP .45 Tactical
{Weapon::Glock18, "glock"}, // Glock18 Select Fire
{Weapon::Deagle, "deagle"}, // Desert Eagle .50AE
{Weapon::P228, "p228"}, // SIG P228
{Weapon::Elite, "elite"}, // Dual Beretta 96G Elite
{Weapon::FiveSeven, "fn57"}, // FN Five-Seven
{Weapon::M3, "m3"}, // Benelli M3 Super90
{Weapon::XM1014, "xm1014"}, // Benelli XM1014
{Weapon::MP5, "mp5"}, // HK MP5-Navy
{Weapon::TMP, "tmp"}, // Steyr Tactical Machine Pistol
{Weapon::P90, "p90"}, // FN P90
{Weapon::MAC10, "mac10"}, // Ingram MAC-10
{Weapon::UMP45, "ump45"}, // HK UMP45
{Weapon::AK47, "ak47"}, // Automat Kalashnikov AK-47
{Weapon::Galil, "galil"}, // IMI Galil
{Weapon::Famas, "famas"}, // GIAT FAMAS
{Weapon::SG552, "sg552"}, // Sig SG-552 Commando
{Weapon::M4A1, "m4a1"}, // Colt M4A1 Carbine
{Weapon::AUG, "aug"}, // Steyr Aug
{Weapon::Scout, "scout"}, // Steyr Scout
{Weapon::AWP, "awp"}, // AI Arctic Warfare/Magnum
{Weapon::G3SG1, "g3sg1"}, // HK G3/SG-1 Sniper Rifle
{Weapon::SG550, "sg550"}, // Sig SG-550 Sniper
{Weapon::M249, "m249"}, // FN M249 Para
{Weapon::Flashbang, "flash"}, // Concussion Grenade
{Weapon::Explosive, "hegren"}, // High-Explosive Grenade
{Weapon::Smoke, "sgren"}, // Smoke Grenade
{Weapon::Armor, "vest"}, // Kevlar Vest
{Weapon::ArmorHelm, "vesthelm"}, // Kevlar Vest and Helmet
{Weapon::Defuser, "defuser"}, // Defuser Kit
{Weapon::Shield, "shield"}, // Tactical Shield
{Weapon::Knife, "knife"} // Knife
};
// if we need to return the string, find by weapon id
if (needString && weaponIndex != -1) {
for (auto &tab : weaponTab) {
if (tab.weaponIndex == weaponIndex) { // is weapon id found?
return MAKE_STRING (tab.alias);
}
}
return MAKE_STRING ("(none)"); // return none
if (m_weaponAlias.exists (id)) {
return m_weaponAlias[id];
}
// else search weapon by name and return weapon id
for (auto &tab : weaponTab) {
if (strncmp (tab.alias, weaponAlias, strlen (tab.alias)) == 0) {
return tab.weaponIndex;
}
}
return -1; // no weapon was found return -1
}
return none;
}