savepoint, changelog later..

This commit is contained in:
Dmitry 2019-07-27 17:36:24 +03:00 committed by jeefo
commit 1bc1fd1913
45 changed files with 12866 additions and 10981 deletions

View file

@ -19,11 +19,11 @@ void BotUtils::stripTags (String &line) {
for (const auto &tag : m_tags) {
const size_t start = line.find (tag.first, 0);
if (start != String::INVALID_INDEX) {
if (start != String::kInvalidIndex) {
const size_t end = line.find (tag.second, start);
const size_t diff = end - start;
if (end != String::INVALID_INDEX && end > start && diff < 32 && diff > 4) {
if (end != String::kInvalidIndex && end > start && diff < 32 && diff > 4) {
line.erase (start, diff + tag.second.length ());
break;
}
@ -37,7 +37,7 @@ void BotUtils::humanizePlayerName (String &playerName) {
}
// drop tag marks, 80 percent of time
if (rng.chance (80)) {
if (rg.chance (80)) {
stripTags (playerName);
}
else {
@ -45,14 +45,14 @@ void BotUtils::humanizePlayerName (String &playerName) {
}
// sometimes switch name to lower characters, only valid for the english languge
if (rng.chance (15) && strcmp (yb_language.str (), "en") == 0) {
if (rg.chance (8) && strcmp (yb_language.str (), "en") == 0) {
playerName.lowercase ();
}
}
void BotUtils::addChatErrors (String &line) {
// sometimes switch name to lower characters, only valid for the english languge
if (rng.chance (15) && strcmp (yb_language.str (), "en") == 0) {
if (rg.chance (8) && strcmp (yb_language.str (), "en") == 0) {
line.lowercase ();
}
auto length = line.length ();
@ -61,13 +61,13 @@ void BotUtils::addChatErrors (String &line) {
size_t percentile = line.length () / 2;
// "length / 2" percent of time drop a character
if (rng.chance (percentile)) {
line.erase (rng.getInt (length / 8, length - length / 8));
if (rg.chance (percentile)) {
line.erase (rg.int_ (length / 8, length - length / 8), 1);
}
// "length" / 4 precent of time swap character
if (rng.chance (percentile / 2)) {
size_t pos = rng.getInt (length / 8, 3 * length / 8); // choose random position in string
if (rg.chance (percentile / 2)) {
size_t pos = rg.int_ (length / 8, 3 * length / 8); // choose random position in string
cr::swap (line[pos], line[pos + 1]);
}
}
@ -76,7 +76,7 @@ void BotUtils::addChatErrors (String &line) {
bool BotUtils::checkKeywords (const String &line, String &reply) {
// this function checks is string contain keyword, and generates reply to it
if (!yb_chat.boolean () || line.empty ()) {
if (!yb_chat.bool_ () || line.empty ()) {
return false;
}
@ -84,7 +84,7 @@ bool BotUtils::checkKeywords (const String &line, String &reply) {
for (const auto &keyword : factory.keywords) {
// check is keyword has occurred in message
if (line.find (keyword, 0) != String::INVALID_INDEX) {
if (line.find (keyword) != String::kInvalidIndex) {
StringArray &usedReplies = factory.usedReplies;
if (usedReplies.length () >= factory.replies.length () / 4) {
@ -113,11 +113,9 @@ bool BotUtils::checkKeywords (const String &line, String &reply) {
}
}
}
auto &chat = conf.getChat ();
// didn't find a keyword? 70% of the time use some universal reply
if (rng.chance (70) && !chat[CHAT_NOKW].empty ()) {
reply.assign (chat[CHAT_NOKW].random ());
if (rg.chance (70) && conf.hasChatBank (Chat::NoKeyword)) {
reply.assign (conf.pickRandomFromChatBank (Chat::NoKeyword));
return true;
}
return false;
@ -126,47 +124,49 @@ bool BotUtils::checkKeywords (const String &line, String &reply) {
void Bot::prepareChatMessage (const String &message) {
// this function parses messages from the botchat, replaces keywords and converts names into a more human style
if (!yb_chat.boolean () || message.empty ()) {
if (!yb_chat.bool_ () || message.empty ()) {
return;
}
m_chatBuffer = message;
m_chatBuffer.assign (message.chars ());
// must be called before return or on the end
auto finishPreparation = [&] (void) {
auto finishPreparation = [&] () {
if (!m_chatBuffer.empty ()) {
util.addChatErrors (m_chatBuffer);
}
};
// need to check if we're have special symbols
size_t pos = message.find ('%', 0);
size_t pos = message.find ('%');
// nothing found, bail out
if (pos == String::INVALID_INDEX || pos >= message.length ()) {
if (pos == String::kInvalidIndex || pos >= message.length ()) {
finishPreparation ();
return;
}
// get the humanized name out of client
auto humanizedName = [] (const Client &client) -> String {
if (!util.isPlayer (client.ent)) {
return cr::move (String ("unknown"));
auto humanizedName = [] (int index) -> String {
auto ent = game.playerOfIndex (index);
if (!util.isPlayer (ent)) {
return "unknown";
}
String playerName = STRING (client.ent->v.netname);
String playerName = STRING (ent->v.netname);
util.humanizePlayerName (playerName);
return cr::move (playerName);
return playerName;
};
// find highfrag player
auto getHighfragPlayer = [&] (void) -> String {
auto getHighfragPlayer = [&] () -> String {
int highestFrags = -1;
int index = 0;
for (int i = 0; i < game.maxClients (); i++) {
for (int i = 0; i < game.maxClients (); ++i) {
const Client &client = util.getClient (i);
if (!(client.flags & CF_USED) || client.ent == ent ()) {
if (!(client.flags & ClientFlags::Used) || client.ent == ent ()) {
continue;
}
int frags = static_cast <int> (client.ent->v.frags);
@ -176,147 +176,116 @@ void Bot::prepareChatMessage (const String &message) {
index = i;
}
}
return humanizedName (util.getClient (index));
return humanizedName (index);
};
// get roundtime
auto getRoundTime = [] (void) -> String {
auto getRoundTime = [] () -> String {
auto roundTimeSecs = static_cast <int> (bots.getRoundEndTime () - game.timebase ());
String roundTime;
roundTime.assign ("%02d:%02d", cr::clamp (roundTimeSecs / 60, 0, 59), cr::clamp (cr::abs (roundTimeSecs % 60), 0, 59));
roundTime.assignf ("%02d:%02d", cr::clamp (roundTimeSecs / 60, 0, 59), cr::clamp (cr::abs (roundTimeSecs % 60), 0, 59));
return cr::move (roundTime);
return roundTime;
};
// get bot's victim
auto getMyVictim = [&] (void) -> String {
for (const Client &client : util.getClients ()) {
if (client.ent == m_lastVictim) {
return humanizedName (client);
}
}
return cr::move (String ("unknown"));
auto getMyVictim = [&] () -> String {;
return humanizedName (game.indexOfPlayer (m_lastVictim));
};
// get the game name alias
auto getGameName = [] (void) -> String {
auto getGameName = [] () -> String {
String gameName;
if (game.is (GAME_CZERO)) {
if (rng.chance (30)) {
if (game.is (GameFlags::ConditionZero)) {
if (rg.chance (30)) {
gameName = "CZ";
}
else {
gameName = "Condition Zero";
}
}
else if (game.is (GAME_CSTRIKE16) || game.is (GAME_LEGACY)) {
if (rng.chance (30)) {
else if (game.is (GameFlags::Modern) || game.is (GameFlags::Legacy)) {
if (rg.chance (30)) {
gameName = "CS";
}
else {
gameName = "Counter-Strike";
}
}
return cr::move (gameName);
return gameName;
};
// get enemy or teammate alive
auto getPlayerAlive = [&] (bool needsEnemy) -> String {
int index;
for (index = 0; index < game.maxClients (); index++) {
const Client &client = util.getClient (index);
if (!(client.flags & CF_USED) || !(client.flags & CF_ALIVE) || client.ent == ent ()) {
for (const auto &client : util.getClients ()) {
if (!(client.flags & ClientFlags::Used) || !(client.flags & ClientFlags::Alive) || client.ent == ent ()) {
continue;
}
if ((needsEnemy && m_team == client.team) || (!needsEnemy && m_team != client.team)) {
continue;
if (needsEnemy && m_team != client.team) {
return humanizedName (game.indexOfPlayer (client.ent));
}
else if (!needsEnemy && m_team == client.team) {
return humanizedName (game.indexOfPlayer (client.ent));
}
break;
}
return "UnknowPA";
};
size_t replaceCounter = 0;
if (index < game.maxClients ()) {
if (!needsEnemy && util.isPlayer (pev->dmg_inflictor) && m_team == game.getTeam (pev->dmg_inflictor)) {
return humanizedName (util.getClient (game.indexOfEntity (pev->dmg_inflictor) - 1));
while (replaceCounter < 6 && (pos = m_chatBuffer.find ('%')) != String::kInvalidIndex) {
// found one, let's do replace
switch (message[pos + 1]) {
// the highest frag player
case 'f':
m_chatBuffer.replace ("%f", getHighfragPlayer ());
break;
// current map name
case 'm':
m_chatBuffer.replace ("%m", game.getMapName ());
break;
// round time
case 'r':
m_chatBuffer.replace ("%r", getRoundTime ());
break;
// chat reply
case 's':
if (m_sayTextBuffer.entityIndex != -1) {
m_chatBuffer.replace ("%s", humanizedName (m_sayTextBuffer.entityIndex));
}
else {
return humanizedName (util.getClient (index));
m_chatBuffer.replace ("%s", getHighfragPlayer ());
}
}
else {
for (index = 0; index < game.maxClients (); index++) {
const Client &client = util.getClient (index);
break;
if (!(client.flags & CF_USED) || client.team != m_team || client.ent == ent ()) {
continue;
}
// last bot victim
case 'v':
m_chatBuffer.replace ("%v", getMyVictim ());
break;
if ((needsEnemy && m_team != client.team) || (!needsEnemy && m_team == client.team)) {
continue;
}
break;
}
// game name
case 'd':
m_chatBuffer.replace ("%d", getGameName ());
break;
if (index < game.maxClients ()) {
return humanizedName (util.getClient (index));
}
}
return cr::move (String ("unknown"));
};
// teammate alive
case 't':
m_chatBuffer.replace ("%t", getPlayerAlive (false));
break;
// found one, let's do replace
switch (message[pos + 1]) {
// the highest frag player
case 'f':
m_chatBuffer.replace ("%f", getHighfragPlayer ());
break;
// current map name
case 'm':
m_chatBuffer.replace ("%m", game.getMapName ());
break;
// round time
case 'r':
m_chatBuffer.replace ("%r", getRoundTime ());
break;
// chat reply
case 's':
if (m_sayTextBuffer.entityIndex != -1) {
m_chatBuffer.replace ("%s", humanizedName (util.getClient (m_sayTextBuffer.entityIndex)));
}
else {
m_chatBuffer.replace ("%s", getHighfragPlayer ());
}
break;
// last bot victim
case 'v':
m_chatBuffer.replace ("%v", getMyVictim ());
break;
// game name
case 'd':
m_chatBuffer.replace ("%d", getGameName ());
break;
// teammate alive
case 't':
m_chatBuffer.replace ("%t", getPlayerAlive (false));
break;
// enemy alive
case 'e':
m_chatBuffer.replace ("%e", getPlayerAlive (true));
break;
};
// enemy alive
case 'e':
m_chatBuffer.replace ("%e", getPlayerAlive (true));
break;
};
replaceCounter++;
}
finishPreparation ();
}
@ -327,18 +296,17 @@ bool Bot::checkChatKeywords (String &reply) {
return util.checkKeywords (message.uppercase (), reply);
}
bool Bot::isReplyingToChat (void) {
bool Bot::isReplyingToChat () {
// this function sends reply to a player
if (m_sayTextBuffer.entityIndex != -1 && !m_sayTextBuffer.sayText.empty ()) {
// check is time to chat is good
if (m_sayTextBuffer.timeNextChat < game.timebase ()) {
if (m_sayTextBuffer.timeNextChat < game.timebase () + rg.float_ (m_sayTextBuffer.chatDelay / 2, m_sayTextBuffer.chatDelay)) {
String replyText;
if (rng.chance (m_sayTextBuffer.chatProbability + rng.getInt (25, 45)) && checkChatKeywords (replyText)) {
if (rg.chance (m_sayTextBuffer.chatProbability + rg.int_ (20, 50)) && checkChatKeywords (replyText)) {
prepareChatMessage (replyText);
pushMsgQueue (GAME_MSG_SAY_CMD);
pushMsgQueue (BotMsg::Say);
m_sayTextBuffer.entityIndex = -1;
m_sayTextBuffer.timeNextChat = game.timebase () + m_sayTextBuffer.chatDelay;
@ -353,19 +321,17 @@ bool Bot::isReplyingToChat (void) {
return false;
}
void Bot::checkForChat (void) {
void Bot::checkForChat () {
// say a text every now and then
if (rng.chance (35) || m_notKilled || !yb_chat.boolean ()) {
if (rg.chance (30) || m_notKilled || !yb_chat.bool_ ()) {
return;
}
// bot chatting turned on?
if (m_lastChatTime + 10.0 < game.timebase () && bots.getLastChatTimestamp () + 5.0f < game.timebase () && !isReplyingToChat ()) {
auto &chat = conf.getChat ();
if (!chat[CHAT_DEAD].empty ()) {
const String &phrase = chat[CHAT_DEAD].random ();
if (m_lastChatTime + rg.float_ (6.0f, 10.0f) < game.timebase () && bots.getLastChatTimestamp () + rg.float_ (2.5f, 5.0f) < game.timebase () && !isReplyingToChat ()) {
if (conf.hasChatBank (Chat::Dead)) {
const auto &phrase = conf.pickRandomFromChatBank (Chat::Dead);
bool sayBufferExists = false;
// search for last messages, sayed
@ -375,9 +341,10 @@ void Bot::checkForChat (void) {
break;
}
}
if (!sayBufferExists) {
prepareChatMessage (phrase);
pushMsgQueue (GAME_MSG_SAY_CMD);
pushMsgQueue (BotMsg::Say);
m_lastChatTime = game.timebase ();
bots.setLastChatTimestamp (game.timebase ());
@ -388,7 +355,7 @@ void Bot::checkForChat (void) {
}
// clear the used line buffer every now and then
if (static_cast <int> (m_sayTextBuffer.lastUsedSentences.length ()) > rng.getInt (4, 6)) {
if (static_cast <int> (m_sayTextBuffer.lastUsedSentences.length ()) > rg.int_ (4, 6)) {
m_sayTextBuffer.lastUsedSentences.clear ();
}
}
@ -397,17 +364,17 @@ void Bot::checkForChat (void) {
void Bot::say (const char *text) {
// this function prints saytext message to all players
if (util.isEmptyStr (text) || !yb_chat.boolean ()) {
if (util.isEmptyStr (text) || !yb_chat.bool_ ()) {
return;
}
game.execBotCmd (ent (), "say \"%s\"", text);
game.botCommand (ent (), "say \"%s\"", text);
}
void Bot::sayTeam (const char *text) {
// this function prints saytext message only for teammates
if (util.isEmptyStr (text) || !yb_chat.boolean ()) {
if (util.isEmptyStr (text) || !yb_chat.bool_ ()) {
return;
}
game.execBotCmd (ent (), "say_team \"%s\"", text);
game.botCommand (ent (), "say_team \"%s\"", text);
}