savepoint, changelog later..
This commit is contained in:
parent
7d3c4a0be0
commit
1bc1fd1913
45 changed files with 12866 additions and 10981 deletions
|
|
@ -1,7 +1,6 @@
|
|||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
include $(XASH3D_CONFIG)
|
||||
|
||||
LOCAL_MODULE := yapb
|
||||
|
|
@ -25,9 +24,10 @@ LOCAL_SRC_FILES := \
|
|||
interface.cpp \
|
||||
navigate.cpp \
|
||||
support.cpp \
|
||||
waypoint.cpp \
|
||||
graph.cpp \
|
||||
|
||||
LOCAL_CFLAGS += -O2 -std=c++11 -DLINUX -D_LINUX -DPOSIX -pipe -fno-strict-aliasing -Wall -Werror
|
||||
LOCAL_CFLAGS += -O3 -std=c++11 -DLINUX -D_LINUX -DPOSIX -pipe -fno-strict-aliasing -Wall -Werror -Wno-array-bounds
|
||||
LOCAL_CPPFLAGS += -fno-exceptions -fno-rtti
|
||||
LOCAL_LDLIBS := -llog
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
|
|
|||
2524
source/basecode.cpp
2524
source/basecode.cpp
File diff suppressed because it is too large
Load diff
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
1205
source/control.cpp
1205
source/control.cpp
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
2940
source/graph.cpp
Normal file
2940
source/graph.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include <yapb.h>
|
||||
|
||||
ConVar yb_version ("yb_version", PRODUCT_VERSION, VT_READONLY);
|
||||
ConVar yb_version ("yb_version", PRODUCT_VERSION, Var::ReadOnly);
|
||||
|
||||
gamefuncs_t dllapi;
|
||||
enginefuncs_t engfuncs;
|
||||
|
|
@ -33,7 +33,7 @@ plugin_info_t Plugin_info = {
|
|||
PT_ANYTIME, // when unloadable
|
||||
};
|
||||
|
||||
namespace VariadicCallbacks {
|
||||
namespace variadic {
|
||||
void clientCommand (edict_t *ent, char const *format, ...) {
|
||||
// this function forces the client whose player entity is ent to issue a client command.
|
||||
// How it works is that clients all have a argv global string in their client DLL that
|
||||
|
|
@ -50,31 +50,31 @@ namespace VariadicCallbacks {
|
|||
// case it's a bot asking for a client command, we handle it like we do for bot commands
|
||||
|
||||
va_list ap;
|
||||
char buffer[MAX_PRINT_BUFFER];
|
||||
auto buffer = strings.chars ();
|
||||
|
||||
va_start (ap, format);
|
||||
_vsnprintf (buffer, cr::bufsize (buffer), format, ap);
|
||||
_vsnprintf (buffer, StringBuffer::StaticBufferSize, format, ap);
|
||||
va_end (ap);
|
||||
|
||||
if (ent && (ent->v.flags & (FL_FAKECLIENT | FL_DORMANT))) {
|
||||
if (bots.getBot (ent)) {
|
||||
game.execBotCmd (ent, buffer);
|
||||
if (bots[ent]) {
|
||||
game.botCommand (ent, buffer);
|
||||
}
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_SUPERCEDE); // prevent bots to be forced to issue client commands
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
engfuncs.pfnClientCommand (ent, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||
CR_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||
// this function is called right after GiveFnptrsToDll() by the engine in the game DLL (or
|
||||
// what it BELIEVES to be the game DLL), in order to copy the list of MOD functions that can
|
||||
// be called by the engine, into a memory block pointed to by the functionTable pointer
|
||||
|
|
@ -87,13 +87,12 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
|
||||
memset (functionTable, 0, sizeof (gamefuncs_t));
|
||||
|
||||
if (!(game.is (GAME_METAMOD))) {
|
||||
auto api_GetEntityAPI = game.getLib ().resolve <int (*) (gamefuncs_t *, int)> ("GetEntityAPI");
|
||||
if (!(game.is (GameFlags::Metamod))) {
|
||||
auto api_GetEntityAPI = game.lib ().resolve <int (*) (gamefuncs_t *, int)> ("GetEntityAPI");
|
||||
|
||||
// pass other DLLs engine callbacks to function table...
|
||||
if (api_GetEntityAPI (&dllapi, INTERFACE_VERSION) == 0) {
|
||||
util.logEntry (true, LL_FATAL, "GetEntityAPI2: ERROR - Not Initialized.");
|
||||
return FALSE; // error initializing function table!!!
|
||||
if (!api_GetEntityAPI || api_GetEntityAPI (&dllapi, INTERFACE_VERSION) == 0) {
|
||||
logger.fatal ("Could not resolve symbol \"%s\" in the game dll.", "GetEntityAPI");
|
||||
}
|
||||
dllfuncs.dllapi_table = &dllapi;
|
||||
gpGamedllFuncs = &dllfuncs;
|
||||
|
|
@ -101,7 +100,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
memcpy (functionTable, &dllapi, sizeof (gamefuncs_t));
|
||||
}
|
||||
|
||||
functionTable->pfnGameInit = [] (void) {
|
||||
functionTable->pfnGameInit = [] () {
|
||||
// this function is a one-time call, and appears to be the second function called in the
|
||||
// DLL after GiveFntprsToDll() has been called. Its purpose is to tell the MOD DLL to
|
||||
// initialize the game before the engine actually hooks into it with its video frames and
|
||||
|
|
@ -110,6 +109,14 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
// server is enabled. Here is a good place to do our own game session initialization, and
|
||||
// to register by the engine side the server commands we need to administrate our bots.
|
||||
|
||||
// register bot cvars
|
||||
game.registerCvars ();
|
||||
|
||||
// register logger
|
||||
logger.initialize (strings.format ("%slogs/yapb.log", graph.getDataDirectory (false)), [] (const char *msg) {
|
||||
game.print (msg);
|
||||
});
|
||||
|
||||
conf.initWeapons ();
|
||||
|
||||
// register server command(s)
|
||||
|
|
@ -117,20 +124,20 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
game.registerCmd ("yb", BotControl::handleEngineCommands);
|
||||
|
||||
// set correct version string
|
||||
yb_version.set (util.format ("%d.%d.%d", PRODUCT_VERSION_DWORD_INTERNAL, util.buildNumber ()));
|
||||
yb_version.set (strings.format ("%d.%d.%d", PRODUCT_VERSION_DWORD_INTERNAL, util.buildNumber ()));
|
||||
|
||||
// execute main config
|
||||
conf.load (true);
|
||||
conf.loadMainConfig ();
|
||||
|
||||
// register fake metamod command handler if we not! under mm
|
||||
if (!(game.is (GAME_METAMOD))) {
|
||||
game.registerCmd ("meta", [] (void) {
|
||||
if (!(game.is (GameFlags::Metamod))) {
|
||||
game.registerCmd ("meta", [] () {
|
||||
game.print ("You're launched standalone version of yapb. Metamod is not installed or not enabled!");
|
||||
});
|
||||
}
|
||||
conf.adjustWeaponPrices ();
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
dllapi.pfnGameInit ();
|
||||
|
|
@ -144,7 +151,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
|
||||
game.precache ();
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META_VALUE (MRES_IGNORED, 0);
|
||||
}
|
||||
int result = dllapi.pfnSpawn (ent); // get result
|
||||
|
|
@ -168,7 +175,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
// is called twice, once for each entity moving.
|
||||
|
||||
if (!game.isNullEntity (pentTouched) && pentOther != game.getStartEntity ()) {
|
||||
Bot *bot = bots.getBot (pentTouched);
|
||||
auto bot = bots[pentTouched];
|
||||
|
||||
if (bot != nullptr && pentOther != bot->ent ()) {
|
||||
|
||||
|
|
@ -181,7 +188,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
}
|
||||
}
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
dllapi.pfnTouch (pentTouched, pentOther);
|
||||
|
|
@ -212,13 +219,13 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
if (strcmp (addr, "loopback") == 0) {
|
||||
game.setLocalEntity (ent); // save the edict of the listen server client...
|
||||
|
||||
// if not dedicated set the default editor for waypoints
|
||||
// if not dedicated set the default editor for graph
|
||||
if (!game.isDedicated ()) {
|
||||
waypoints.setEditor (ent);
|
||||
graph.setEditor (ent);
|
||||
}
|
||||
}
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META_VALUE (MRES_IGNORED, 0);
|
||||
}
|
||||
return dllapi.pfnClientConnect (ent, name, addr, rejectReason);
|
||||
|
|
@ -236,18 +243,18 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
// to reset his entity pointer for safety. There are still a few server frames to go once a
|
||||
// listen server client disconnects, and we don't want to send him any sort of message then.
|
||||
|
||||
int index = game.indexOfEntity (ent) - 1;
|
||||
|
||||
if (index >= 0 && index < MAX_ENGINE_PLAYERS) {
|
||||
auto bot = bots.getBot (index);
|
||||
|
||||
// check if its a bot
|
||||
if (bot != nullptr && bot->pev == &ent->v) {
|
||||
for (auto &bot : bots) {
|
||||
if (bot->pev == &ent->v) {
|
||||
bot->showChaterIcon (false);
|
||||
bots.destroy (index);
|
||||
|
||||
conf.clearUsedName (bot.get ()); // clear the bot name
|
||||
bots.erase (bot.get ()); // remove the bot from bots array
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
dllapi.pfnClientDisconnect (ent);
|
||||
|
|
@ -261,7 +268,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
|
||||
ctrl.assignAdminRights (ent, infobuffer);
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
dllapi.pfnClientUserInfoChanged (ent, infobuffer);
|
||||
|
|
@ -282,14 +289,14 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
// clients. Hence it can lack of commenting a bit, since this code is very subject to change.
|
||||
|
||||
if (ctrl.handleClientCommands (ent)) {
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_SUPERCEDE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
else if (ctrl.handleMenuCommands (ent)) {
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_SUPERCEDE);
|
||||
}
|
||||
return;
|
||||
|
|
@ -298,7 +305,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
// record stuff about radio and chat
|
||||
bots.captureChatRadio (engfuncs.pfnCmd_Argv (0), engfuncs.pfnCmd_Argv (1), ent);
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
dllapi.pfnClientCommand (ent);
|
||||
|
|
@ -312,8 +319,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
// loading the bot profiles, and drawing the world map (ie, filling the navigation hashtable).
|
||||
// Once this function has been called, the server can be considered as "running".
|
||||
|
||||
bots.destroy ();
|
||||
conf.load (false); // initialize all config files
|
||||
conf.loadConfigs (); // initialize all config files
|
||||
|
||||
// do a level initialization
|
||||
game.levelInitialize (pentEdictList, edictCount);
|
||||
|
|
@ -322,27 +328,26 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
illum.resetWorldModel ();
|
||||
|
||||
// do level initialization stuff here...
|
||||
waypoints.init ();
|
||||
waypoints.load ();
|
||||
graph.loadGraphData ();
|
||||
|
||||
// execute main config
|
||||
conf.load (true);
|
||||
conf.loadMainConfig ();
|
||||
|
||||
if (File::exists (util.format ("%s/maps/%s_yapb.cfg", game.getModName (), game.getMapName ()))) {
|
||||
game.execCmd ("exec maps/%s_yapb.cfg", game.getMapName ());
|
||||
if (File::exists (strings.format ("%s/maps/%s_yapb.cfg", game.getModName (), game.getMapName ()))) {
|
||||
game.serverCommand ("exec maps/%s_yapb.cfg", game.getMapName ());
|
||||
game.print ("Executing Map-Specific config file");
|
||||
}
|
||||
bots.initQuota ();
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
dllapi.pfnServerActivate (pentEdictList, edictCount, clientMax);
|
||||
|
||||
waypoints.rebuildVisibility ();
|
||||
graph.rebuildVisibility ();
|
||||
};
|
||||
|
||||
functionTable->pfnServerDeactivate = [] (void) {
|
||||
functionTable->pfnServerDeactivate = [] () {
|
||||
// this function is called when the server is shutting down. A particular note about map
|
||||
// changes: changing the map means shutting down the server and starting a new one. Of course
|
||||
// this process is transparent to the user, but either in single player when the hero reaches
|
||||
|
|
@ -354,8 +359,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
// the loading of new bots and the new BSP data parsing there.
|
||||
|
||||
// save collected experience on shutdown
|
||||
waypoints.saveExperience ();
|
||||
waypoints.saveVisibility ();
|
||||
graph.savePractice ();
|
||||
|
||||
// destroy global killer entity
|
||||
bots.destroyKillerEntity ();
|
||||
|
|
@ -370,19 +374,21 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
util.setNeedForWelcome (false);
|
||||
|
||||
// xash is not kicking fakeclients on changelevel
|
||||
if (game.is (GAME_XASH_ENGINE)) {
|
||||
if (game.is (GameFlags::Xash3D)) {
|
||||
bots.kickEveryone (true, false);
|
||||
bots.destroy ();
|
||||
}
|
||||
waypoints.init ();
|
||||
graph.initGraph ();
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
// clear all the bots
|
||||
bots.destroy ();
|
||||
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
dllapi.pfnServerDeactivate ();
|
||||
};
|
||||
|
||||
functionTable->pfnStartFrame = [] (void) {
|
||||
functionTable->pfnStartFrame = [] () {
|
||||
// this function starts a video frame. It is called once per video frame by the game. If
|
||||
// you run Half-Life at 90 fps, this function will then be called 90 times per second. By
|
||||
// placing a hook on it, we have a good place to do things that should be done continuously
|
||||
|
|
@ -400,10 +406,9 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
// update some stats for clients
|
||||
util.updateClients ();
|
||||
|
||||
if (waypoints.hasEditFlag (WS_EDIT_ENABLED) && waypoints.hasEditor ()) {
|
||||
waypoints.frame ();
|
||||
if (graph.hasEditFlag (GraphEdit::On) && graph.hasEditor ()) {
|
||||
graph.frame ();
|
||||
}
|
||||
bots.updateDeathMsgState (false);
|
||||
|
||||
// run stuff periodically
|
||||
game.slowFrame ();
|
||||
|
|
@ -419,7 +424,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
// keep bot number up to date
|
||||
bots.maintainQuota ();
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
dllapi.pfnStartFrame ();
|
||||
|
|
@ -428,17 +433,24 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
bots.slowFrame ();
|
||||
};
|
||||
|
||||
functionTable->pfnUpdateClientData = [] (const struct edict_s *ent, int sendweapons, struct clientdata_s *cd) {
|
||||
extern ConVar yb_latency_display;
|
||||
functionTable->pfnCmdStart = [] (const edict_t *player, usercmd_t *cmd, unsigned int random_seed) {
|
||||
auto ent = const_cast <edict_t *> (player);
|
||||
|
||||
if (game.is (GAME_SUPPORT_SVC_PINGS) && yb_latency_display.integer () == 2 && bots.hasBotsOnline ()) {
|
||||
bots.sendPingOffsets (const_cast <edict_t *> (ent));
|
||||
// if we're handle pings for bots and clients, clear IN_SCORE button so SV_ShouldUpdatePing engine function return false
|
||||
// and SV_EmitPings will not overwrite our results
|
||||
if (game.is (GameFlags::HasFakePings) && yb_show_latency.int_ () == 2) {
|
||||
if ((cmd->buttons & IN_SCORE) || (ent->v.oldbuttons & IN_SCORE)) {
|
||||
cmd->buttons &= ~IN_SCORE;
|
||||
|
||||
// send our version of pings
|
||||
util.sendPings (ent);
|
||||
}
|
||||
}
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
dllapi.pfnUpdateClientData (ent, sendweapons, cd);
|
||||
dllapi.pfnCmdStart (player, cmd, random_seed);
|
||||
};
|
||||
|
||||
functionTable->pfnPM_Move = [] (playermove_t *playerMove, int server) {
|
||||
|
|
@ -449,7 +461,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
|
||||
illum.setWorldModel (playerMove->physents[0].model);
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
dllapi.pfnPM_Move (playerMove, server);
|
||||
|
|
@ -457,8 +469,8 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
SHARED_LIBRARAY_EXPORT int GetEntityAPI2_Post (gamefuncs_t *functionTable, int *) {
|
||||
// this function is called right after FuncPointers_t() by the engine in the game DLL (or
|
||||
CR_EXPORT int GetEntityAPI2_Post (gamefuncs_t *table, int *) {
|
||||
// this function is called right after GiveFnptrsToDll() by the engine in the game DLL (or
|
||||
// what it BELIEVES to be the game DLL), in order to copy the list of MOD functions that can
|
||||
// be called by the engine, into a memory block pointed to by the functionTable pointer
|
||||
// that is passed into this function (explanation comes straight from botman). This allows
|
||||
|
|
@ -468,9 +480,9 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2_Post (gamefuncs_t *functionTable, int *
|
|||
// engine, and then calls the MOD DLL's version of GetEntityAPI to get the REAL gamedll
|
||||
// functions this time (to use in the bot code). Post version, called only by metamod.
|
||||
|
||||
memset (functionTable, 0, sizeof (gamefuncs_t));
|
||||
memset (table, 0, sizeof (gamefuncs_t));
|
||||
|
||||
functionTable->pfnSpawn = [] (edict_t *ent) {
|
||||
table->pfnSpawn = [] (edict_t *ent) {
|
||||
// this function asks the game DLL to spawn (i.e, give a physical existence in the virtual
|
||||
// world, in other words to 'display') the entity pointed to by ent in the game. The
|
||||
// Spawn() function is one of the functions any entity is supposed to have in the game DLL,
|
||||
|
|
@ -484,7 +496,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2_Post (gamefuncs_t *functionTable, int *
|
|||
RETURN_META_VALUE (MRES_IGNORED, 0);
|
||||
};
|
||||
|
||||
functionTable->pfnStartFrame = [] (void) {
|
||||
table->pfnStartFrame = [] () {
|
||||
// this function starts a video frame. It is called once per video frame by the game. If
|
||||
// you run Half-Life at 90 fps, this function will then be called 90 times per second. By
|
||||
// placing a hook on it, we have a good place to do things that should be done continuously
|
||||
|
|
@ -496,7 +508,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2_Post (gamefuncs_t *functionTable, int *
|
|||
RETURN_META (MRES_IGNORED);
|
||||
};
|
||||
|
||||
functionTable->pfnServerActivate = [] (edict_t *, int, int) {
|
||||
table->pfnServerActivate = [] (edict_t *, int, int) {
|
||||
// this function is called when the server has fully loaded and is about to manifest itself
|
||||
// on the network as such. Since a mapchange is actually a server shutdown followed by a
|
||||
// restart, this function is also called when a new map is being loaded. Hence it's the
|
||||
|
|
@ -505,7 +517,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2_Post (gamefuncs_t *functionTable, int *
|
|||
// Once this function has been called, the server can be considered as "running". Post version
|
||||
// called only by metamod.
|
||||
|
||||
waypoints.rebuildVisibility ();
|
||||
graph.rebuildVisibility ();
|
||||
|
||||
RETURN_META (MRES_IGNORED);
|
||||
};
|
||||
|
|
@ -513,21 +525,21 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2_Post (gamefuncs_t *functionTable, int *
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
SHARED_LIBRARAY_EXPORT int GetNewDLLFunctions (newgamefuncs_t *functionTable, int *interfaceVersion) {
|
||||
CR_EXPORT int GetNewDLLFunctions (newgamefuncs_t *functionTable, int *interfaceVersion) {
|
||||
// it appears that an extra function table has been added in the engine to gamedll interface
|
||||
// since the date where the first enginefuncs table standard was frozen. These ones are
|
||||
// facultative and we don't hook them, but since some MODs might be featuring it, we have to
|
||||
// pass them too, else the DLL interfacing wouldn't be complete and the game possibly wouldn't
|
||||
// run properly.
|
||||
|
||||
auto api_GetNewDLLFunctions = game.getLib ().resolve <int (*) (newgamefuncs_t *, int *)> ("GetNewDLLFunctions");
|
||||
auto api_GetNewDLLFunctions = game.lib ().resolve <int (*) (newgamefuncs_t *, int *)> (__FUNCTION__);
|
||||
|
||||
if (api_GetNewDLLFunctions == nullptr) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!api_GetNewDLLFunctions (functionTable, interfaceVersion)) {
|
||||
util.logEntry (true, LL_ERROR, "GetNewDLLFunctions: ERROR - Not Initialized.");
|
||||
if (!api_GetNewDLLFunctions || !api_GetNewDLLFunctions (functionTable, interfaceVersion)) {
|
||||
logger.error ("Could not resolve symbol \"%s\" in the game dll. Continuing...", __FUNCTION__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -535,8 +547,8 @@ SHARED_LIBRARAY_EXPORT int GetNewDLLFunctions (newgamefuncs_t *functionTable, in
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
memset (functionTable, 0, sizeof (enginefuncs_t));
|
||||
}
|
||||
|
||||
|
|
@ -551,10 +563,9 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
|||
// spawn point named "tr_2lm".
|
||||
|
||||
// save collected experience on map change
|
||||
waypoints.saveExperience ();
|
||||
waypoints.saveVisibility ();
|
||||
graph.savePractice ();
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
engfuncs.pfnChangeLevel (s1, s2);
|
||||
|
|
@ -565,7 +576,7 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
|||
|
||||
illum.updateLight (style, val);
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
engfuncs.pfnLightStyle (style, val);
|
||||
|
|
@ -573,11 +584,11 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
|||
|
||||
functionTable->pfnFindEntityByString = [] (edict_t *edictStartSearchAfter, const char *field, const char *value) {
|
||||
// round starts in counter-strike 1.5
|
||||
if ((game.is (GAME_LEGACY)) && strcmp (value, "info_map_parameters") == 0) {
|
||||
if ((game.is (GameFlags::Legacy)) && strcmp (value, "info_map_parameters") == 0) {
|
||||
bots.initRound ();
|
||||
}
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META_VALUE (MRES_IGNORED, static_cast <edict_t *> (nullptr));
|
||||
}
|
||||
return engfuncs.pfnFindEntityByString (edictStartSearchAfter, field, value);
|
||||
|
|
@ -596,7 +607,7 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
|||
|
||||
util.attachSoundsToClients (entity, sample, volume);
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
engfuncs.pfnEmitSound (entity, channel, sample, volume, attenuation, flags, pitch);
|
||||
|
|
@ -607,29 +618,26 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
|||
|
||||
game.beginMessage (ed, msgDest, msgType);
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
engfuncs.pfnMessageBegin (msgDest, msgType, origin, ed);
|
||||
};
|
||||
|
||||
functionTable->pfnMessageEnd = [] (void) {
|
||||
functionTable->pfnMessageEnd = [] () {
|
||||
game.resetMessages ();
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
engfuncs.pfnMessageEnd ();
|
||||
|
||||
// send latency fix
|
||||
bots.sendDeathMsgFix ();
|
||||
};
|
||||
|
||||
functionTable->pfnWriteByte = [] (int value) {
|
||||
// if this message is for a bot, call the client message function...
|
||||
game.processMessages ((void *) &value);
|
||||
game.processMessages (reinterpret_cast <void *> (&value));
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
engfuncs.pfnWriteByte (value);
|
||||
|
|
@ -637,9 +645,9 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
|||
|
||||
functionTable->pfnWriteChar = [] (int value) {
|
||||
// if this message is for a bot, call the client message function...
|
||||
game.processMessages ((void *) &value);
|
||||
game.processMessages (reinterpret_cast <void *> (&value));
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
engfuncs.pfnWriteChar (value);
|
||||
|
|
@ -647,9 +655,9 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
|||
|
||||
functionTable->pfnWriteShort = [] (int value) {
|
||||
// if this message is for a bot, call the client message function...
|
||||
game.processMessages ((void *) &value);
|
||||
game.processMessages (reinterpret_cast <void *> (&value));
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
engfuncs.pfnWriteShort (value);
|
||||
|
|
@ -657,9 +665,9 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
|||
|
||||
functionTable->pfnWriteLong = [] (int value) {
|
||||
// if this message is for a bot, call the client message function...
|
||||
game.processMessages ((void *) &value);
|
||||
game.processMessages (reinterpret_cast <void *> (&value));
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
engfuncs.pfnWriteLong (value);
|
||||
|
|
@ -667,9 +675,9 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
|||
|
||||
functionTable->pfnWriteAngle = [] (float value) {
|
||||
// if this message is for a bot, call the client message function...
|
||||
game.processMessages ((void *) &value);
|
||||
game.processMessages (reinterpret_cast <void *> (&value));
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
engfuncs.pfnWriteAngle (value);
|
||||
|
|
@ -677,9 +685,9 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
|||
|
||||
functionTable->pfnWriteCoord = [] (float value) {
|
||||
// if this message is for a bot, call the client message function...
|
||||
game.processMessages ((void *) &value);
|
||||
game.processMessages (reinterpret_cast <void *> (&value));
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
engfuncs.pfnWriteCoord (value);
|
||||
|
|
@ -687,9 +695,9 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
|||
|
||||
functionTable->pfnWriteString = [] (const char *sz) {
|
||||
// if this message is for a bot, call the client message function...
|
||||
game.processMessages ((void *) sz);
|
||||
game.processMessages (reinterpret_cast <void *> (const_cast <char *> (sz)));
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
engfuncs.pfnWriteString (sz);
|
||||
|
|
@ -697,9 +705,9 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
|||
|
||||
functionTable->pfnWriteEntity = [] (int value) {
|
||||
// if this message is for a bot, call the client message function...
|
||||
game.processMessages ((void *) &value);
|
||||
game.processMessages (reinterpret_cast <void *> (&value));
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
engfuncs.pfnWriteEntity (value);
|
||||
|
|
@ -716,76 +724,76 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
|||
// using pfnMessageBegin (), it will know what message ID number to send, and the engine will
|
||||
// know what to do, only for non-metamod version
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META_VALUE (MRES_IGNORED, 0);
|
||||
}
|
||||
int message = engfuncs.pfnRegUserMsg (name, size);
|
||||
|
||||
if (strcmp (name, "VGUIMenu") == 0) {
|
||||
game.setMessageId (NETMSG_VGUI, message);
|
||||
game.setMessageId (NetMsg::VGUI, message);
|
||||
}
|
||||
else if (strcmp (name, "ShowMenu") == 0) {
|
||||
game.setMessageId (NETMSG_SHOWMENU, message);
|
||||
game.setMessageId (NetMsg::ShowMenu, message);
|
||||
}
|
||||
else if (strcmp (name, "WeaponList") == 0) {
|
||||
game.setMessageId (NETMSG_WEAPONLIST, message);
|
||||
game.setMessageId (NetMsg::WeaponList, message);
|
||||
}
|
||||
else if (strcmp (name, "CurWeapon") == 0) {
|
||||
game.setMessageId (NETMSG_CURWEAPON, message);
|
||||
game.setMessageId (NetMsg::CurWeapon, message);
|
||||
}
|
||||
else if (strcmp (name, "AmmoX") == 0) {
|
||||
game.setMessageId (NETMSG_AMMOX, message);
|
||||
game.setMessageId (NetMsg::AmmoX, message);
|
||||
}
|
||||
else if (strcmp (name, "AmmoPickup") == 0) {
|
||||
game.setMessageId (NETMSG_AMMOPICKUP, message);
|
||||
game.setMessageId (NetMsg::AmmoPickup, message);
|
||||
}
|
||||
else if (strcmp (name, "Damage") == 0) {
|
||||
game.setMessageId (NETMSG_DAMAGE, message);
|
||||
game.setMessageId (NetMsg::Damage, message);
|
||||
}
|
||||
else if (strcmp (name, "Money") == 0) {
|
||||
game.setMessageId (NETMSG_MONEY, message);
|
||||
game.setMessageId (NetMsg::Money, message);
|
||||
}
|
||||
else if (strcmp (name, "StatusIcon") == 0) {
|
||||
game.setMessageId (NETMSG_STATUSICON, message);
|
||||
game.setMessageId (NetMsg::StatusIcon, message);
|
||||
}
|
||||
else if (strcmp (name, "DeathMsg") == 0) {
|
||||
game.setMessageId (NETMSG_DEATH, message);
|
||||
game.setMessageId (NetMsg::DeathMsg, message);
|
||||
}
|
||||
else if (strcmp (name, "ScreenFade") == 0) {
|
||||
game.setMessageId (NETMSG_SCREENFADE, message);
|
||||
game.setMessageId (NetMsg::ScreenFade, message);
|
||||
}
|
||||
else if (strcmp (name, "HLTV") == 0) {
|
||||
game.setMessageId (NETMSG_HLTV, message);
|
||||
game.setMessageId (NetMsg::HLTV, message);
|
||||
}
|
||||
else if (strcmp (name, "TextMsg") == 0) {
|
||||
game.setMessageId (NETMSG_TEXTMSG, message);
|
||||
game.setMessageId (NetMsg::TextMsg, message);
|
||||
}
|
||||
else if (strcmp (name, "TeamInfo") == 0) {
|
||||
game.setMessageId (NETMSG_TEAMINFO, message);
|
||||
game.setMessageId (NetMsg::TeamInfo, message);
|
||||
}
|
||||
else if (strcmp (name, "BarTime") == 0) {
|
||||
game.setMessageId (NETMSG_BARTIME, message);
|
||||
game.setMessageId (NetMsg::BarTime, message);
|
||||
}
|
||||
else if (strcmp (name, "SendAudio") == 0) {
|
||||
game.setMessageId (NETMSG_SENDAUDIO, message);
|
||||
game.setMessageId (NetMsg::SendAudio, message);
|
||||
}
|
||||
else if (strcmp (name, "SayText") == 0) {
|
||||
game.setMessageId (NETMSG_SAYTEXT, message);
|
||||
game.setMessageId (NetMsg::SayText, message);
|
||||
}
|
||||
else if (strcmp (name, "BotVoice") == 0) {
|
||||
game.setMessageId (NETMSG_BOTVOICE, message);
|
||||
game.setMessageId (NetMsg::BotVoice, message);
|
||||
}
|
||||
else if (strcmp (name, "NVGToggle") == 0) {
|
||||
game.setMessageId (NETMSG_NVGTOGGLE, message);
|
||||
game.setMessageId (NetMsg::NVGToggle, message);
|
||||
}
|
||||
else if (strcmp (name, "FlashBat") == 0) {
|
||||
game.setMessageId (NETMSG_FLASHBAT, message);
|
||||
game.setMessageId (NetMsg::FlashBat, message);
|
||||
}
|
||||
else if (strcmp (name, "Flashlight") == 0) {
|
||||
game.setMessageId (NETMSG_FLASHLIGHT, message);
|
||||
game.setMessageId (NetMsg::Fashlight, message);
|
||||
}
|
||||
else if (strcmp (name, "ItemStatus") == 0) {
|
||||
game.setMessageId (NETMSG_ITEMSTATUS, message);
|
||||
game.setMessageId (NetMsg::ItemStatus, message);
|
||||
}
|
||||
return message;
|
||||
};
|
||||
|
|
@ -798,19 +806,19 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
|||
// we know, right ? But since stupidity rules this world, we do a preventive check :)
|
||||
|
||||
if (util.isFakeClient (ent)) {
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_SUPERCEDE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
engfuncs.pfnClientPrintf (ent, printType, message);
|
||||
};
|
||||
|
||||
functionTable->pfnCmd_Args = [] (void) {
|
||||
functionTable->pfnCmd_Args = [] () {
|
||||
// this function returns a pointer to the whole current client command string. Since bots
|
||||
// have no client DLL and we may want a bot to execute a client command, we had to implement
|
||||
// a argv string in the bot DLL for holding the bots' commands, and also keep track of the
|
||||
|
|
@ -820,13 +828,13 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
|||
|
||||
// is this a bot issuing that client command?
|
||||
if (game.isBotCmd ()) {
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META_VALUE (MRES_SUPERCEDE, game.botArgs ());
|
||||
}
|
||||
return game.botArgs (); // else return the whole bot client command string we know
|
||||
}
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META_VALUE (MRES_IGNORED, static_cast <const char *> (nullptr));
|
||||
}
|
||||
return engfuncs.pfnCmd_Args (); // ask the client command string to the engine
|
||||
|
|
@ -842,19 +850,19 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
|||
|
||||
// is this a bot issuing that client command?
|
||||
if (game.isBotCmd ()) {
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META_VALUE (MRES_SUPERCEDE, game.botArgv (argc));
|
||||
}
|
||||
return game.botArgv (argc); // if so, then return the wanted argument we know
|
||||
}
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META_VALUE (MRES_IGNORED, static_cast <const char *> (nullptr));
|
||||
}
|
||||
return engfuncs.pfnCmd_Argv (argc); // ask the argument number "argc" to the engine
|
||||
};
|
||||
|
||||
functionTable->pfnCmd_Argc = [] (void) {
|
||||
functionTable->pfnCmd_Argc = [] () {
|
||||
// this function returns the number of arguments the current client command string has. Since
|
||||
// bots have no client DLL and we may want a bot to execute a client command, we had to
|
||||
// implement a argv string in the bot DLL for holding the bots' commands, and also keep
|
||||
|
|
@ -864,61 +872,52 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
|||
|
||||
// is this a bot issuing that client command?
|
||||
if (game.isBotCmd ()) {
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META_VALUE (MRES_SUPERCEDE, game.botArgc ());
|
||||
}
|
||||
return game.botArgc (); // if so, then return the argument count we know
|
||||
}
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META_VALUE (MRES_IGNORED, 0);
|
||||
}
|
||||
return engfuncs.pfnCmd_Argc (); // ask the engine how many arguments there are
|
||||
};
|
||||
|
||||
functionTable->pfnSetClientMaxspeed = [] (const edict_t *ent, float newMaxspeed) {
|
||||
Bot *bot = bots.getBot (const_cast <edict_t *> (ent));
|
||||
auto bot = bots[const_cast <edict_t *> (ent)];
|
||||
|
||||
// check wether it's not a bot
|
||||
if (bot != nullptr) {
|
||||
bot->pev->maxspeed = newMaxspeed;
|
||||
}
|
||||
|
||||
if (game.is (GAME_METAMOD)) {
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
engfuncs.pfnSetClientMaxspeed (ent, newMaxspeed);
|
||||
};
|
||||
|
||||
functionTable->pfnClientCommand = variadic::clientCommand;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
SHARED_LIBRARAY_EXPORT int GetEngineFunctions_Post (enginefuncs_t *functionTable, int *) {
|
||||
|
||||
memset (functionTable, 0, sizeof (enginefuncs_t));
|
||||
|
||||
functionTable->pfnMessageEnd = [] (void) {
|
||||
// send latency fix
|
||||
bots.sendDeathMsgFix ();
|
||||
|
||||
RETURN_META (MRES_IGNORED);
|
||||
};
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
SHARED_LIBRARAY_EXPORT int Server_GetBlendingInterface (int version, void **ppinterface, void *pstudio, float (*rotationmatrix)[3][4], float (*bonetransform)[128][3][4]) {
|
||||
CR_EXPORT int Server_GetBlendingInterface (int version, void **ppinterface, void *pstudio, float (*rotationmatrix)[3][4], float (*bonetransform)[128][3][4]) {
|
||||
// this function synchronizes the studio model animation blending interface (i.e, what parts
|
||||
// of the body move, which bones, which hitboxes and how) between the server and the game DLL.
|
||||
// some MODs can be using a different hitbox scheme than the standard one.
|
||||
|
||||
auto api_GetBlendingInterface = game.getLib ().resolve <int (*) (int, void **, void *, float(*)[3][4], float(*)[128][3][4])> ("Server_GetBlendingInterface");
|
||||
auto api_GetBlendingInterface = game.lib ().resolve <int (*) (int, void **, void *, float(*)[3][4], float(*)[128][3][4])> (__FUNCTION__);
|
||||
|
||||
if (api_GetBlendingInterface == nullptr) {
|
||||
if (!api_GetBlendingInterface) {
|
||||
logger.error ("Could not resolve symbol \"%s\" in the game dll. Continuing...", __FUNCTION__);
|
||||
return FALSE;
|
||||
}
|
||||
return api_GetBlendingInterface (version, ppinterface, pstudio, rotationmatrix, bonetransform);
|
||||
}
|
||||
|
||||
SHARED_LIBRARAY_EXPORT int Meta_Query (char *, plugin_info_t **pPlugInfo, mutil_funcs_t *pMetaUtilFuncs) {
|
||||
CR_EXPORT int Meta_Query (char *, plugin_info_t **pPlugInfo, mutil_funcs_t *pMetaUtilFuncs) {
|
||||
// this function is the first function ever called by metamod in the plugin DLL. Its purpose
|
||||
// is for metamod to retrieve basic information about the plugin, such as its meta-interface
|
||||
// version, for ensuring compatibility with the current version of the running metamod.
|
||||
|
|
@ -929,7 +928,7 @@ SHARED_LIBRARAY_EXPORT int Meta_Query (char *, plugin_info_t **pPlugInfo, mutil_
|
|||
return TRUE; // tell metamod this plugin looks safe
|
||||
}
|
||||
|
||||
SHARED_LIBRARAY_EXPORT int Meta_Attach (PLUG_LOADTIME, metamod_funcs_t *functionTable, meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs) {
|
||||
CR_EXPORT int Meta_Attach (PLUG_LOADTIME, metamod_funcs_t *functionTable, meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs) {
|
||||
// this function is called when metamod attempts to load the plugin. Since it's the place
|
||||
// where we can tell if the plugin will be allowed to run or not, we wait until here to make
|
||||
// our initialization stuff, like registering CVARs and dedicated server commands.
|
||||
|
|
@ -943,7 +942,7 @@ SHARED_LIBRARAY_EXPORT int Meta_Attach (PLUG_LOADTIME, metamod_funcs_t *function
|
|||
nullptr, // pfnGetNewDLLFunctions ()
|
||||
nullptr, // pfnGetNewDLLFunctions_Post ()
|
||||
GetEngineFunctions, // pfnGetEngineFunctions ()
|
||||
GetEngineFunctions_Post, // pfnGetEngineFunctions_Post ()
|
||||
nullptr, // pfnGetEngineFunctions_Post ()
|
||||
};
|
||||
|
||||
// keep track of the pointers to engine function tables metamod gives us
|
||||
|
|
@ -954,23 +953,44 @@ SHARED_LIBRARAY_EXPORT int Meta_Attach (PLUG_LOADTIME, metamod_funcs_t *function
|
|||
return TRUE; // returning true enables metamod to attach this plugin
|
||||
}
|
||||
|
||||
SHARED_LIBRARAY_EXPORT int Meta_Detach (PLUG_LOADTIME, PL_UNLOAD_REASON) {
|
||||
CR_EXPORT int Meta_Detach (PLUG_LOADTIME, PL_UNLOAD_REASON) {
|
||||
// this function is called when metamod unloads the plugin. A basic check is made in order
|
||||
// to prevent unloading the plugin if its processing should not be interrupted.
|
||||
|
||||
bots.kickEveryone (true); // kick all bots off this server
|
||||
waypoints.init ();
|
||||
|
||||
// save collected experience on shutdown
|
||||
graph.savePractice ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
SHARED_LIBRARAY_EXPORT void Meta_Init (void) {
|
||||
CR_EXPORT void Meta_Init () {
|
||||
// this function is called by metamod, before any other interface functions. Purpose of this
|
||||
// function to give plugin a chance to determine is plugin running under metamod or not.
|
||||
|
||||
game.addGameFlag (GAME_METAMOD);
|
||||
game.addGameFlag (GameFlags::Metamod);
|
||||
}
|
||||
|
||||
// games GiveFnptrsToDll is a bit tricky
|
||||
#if defined(CR_WINDOWS)
|
||||
# if defined(CR_CXX_MSVC) || defined (CR_CXX_MSVC)
|
||||
# if defined (CR_ARCH_X86)
|
||||
# pragma comment(linker, "/EXPORT:GiveFnptrsToDll=_GiveFnptrsToDll@8,@1")
|
||||
# endif
|
||||
# pragma comment(linker, "/SECTION:.data,RW")
|
||||
# endif
|
||||
# define DLL_STDCALL __stdcall
|
||||
# if defined(CR_CXX_MSVC) && !defined(CR_ARCH_X64)
|
||||
# define DLL_GIVEFNPTRSTODLL extern "C" void DLL_STDCALL
|
||||
# elif defined(CR_CXX_CLANG) || defined(CR_ARCH_X64)
|
||||
# define DLL_GIVEFNPTRSTODLL CR_EXPORT void DLL_STDCALL
|
||||
# endif
|
||||
#elif defined(CR_LINUX) || defined (CR_OSX) || defined (CR_ANDROID)
|
||||
# define DLL_GIVEFNPTRSTODLL CR_EXPORT void
|
||||
# define DLL_STDCALL
|
||||
#endif
|
||||
|
||||
DLL_GIVEFNPTRSTODLL GiveFnptrsToDll (enginefuncs_t *functionTable, globalvars_t *pGlobals) {
|
||||
// this is the very first function that is called in the game DLL by the game. Its purpose
|
||||
// is to set the functions interfacing up, by exchanging the functionTable function list
|
||||
|
|
@ -990,30 +1010,22 @@ DLL_GIVEFNPTRSTODLL GiveFnptrsToDll (enginefuncs_t *functionTable, globalvars_t
|
|||
if (game.postload ()) {
|
||||
return;
|
||||
}
|
||||
auto api_GiveFnptrsToDll = game.getLib ().resolve <void (STD_CALL *) (enginefuncs_t *, globalvars_t *)> ("GiveFnptrsToDll");
|
||||
|
||||
assert (api_GiveFnptrsToDll != nullptr);
|
||||
auto api_GiveFnptrsToDll = game.lib ().resolve <void (DLL_STDCALL *) (enginefuncs_t *, globalvars_t *)> (__FUNCTION__);
|
||||
|
||||
if (!api_GiveFnptrsToDll) {
|
||||
logger.fatal ("Could not resolve symbol \"%s\" in the game dll.", __FUNCTION__);
|
||||
}
|
||||
GetEngineFunctions (functionTable, nullptr);
|
||||
|
||||
// give the engine functions to the other DLL...
|
||||
api_GiveFnptrsToDll (functionTable, pGlobals);
|
||||
}
|
||||
|
||||
DLL_ENTRYPOINT {
|
||||
// dynamic library entry point, can be used for uninitialization stuff. NOT for initializing
|
||||
// anything because if you ever attempt to wander outside the scope of this function on a
|
||||
// DLL attach, LoadLibrary() will simply fail. And you can't do I/Os here either.
|
||||
|
||||
// dynamic library detaching ??
|
||||
if (DLL_DETACHING) {
|
||||
waypoints.init (); // free everything that's freeable
|
||||
if (api_GiveFnptrsToDll) {
|
||||
api_GiveFnptrsToDll (functionTable, pGlobals);
|
||||
}
|
||||
DLL_RETENTRY; // the return data type is OS specific too
|
||||
}
|
||||
|
||||
void helper_LinkEntity (EntityFunction &addr, const char *name, entvars_t *pev) {
|
||||
if (addr == nullptr) {
|
||||
addr = game.getLib ().resolve <EntityFunction> (name);
|
||||
addr = game.lib ().resolve <EntityFunction> (name);
|
||||
}
|
||||
|
||||
if (addr == nullptr) {
|
||||
|
|
@ -1022,10 +1034,10 @@ void helper_LinkEntity (EntityFunction &addr, const char *name, entvars_t *pev)
|
|||
addr (pev);
|
||||
}
|
||||
|
||||
#define LINK_ENTITY(entityName) \
|
||||
SHARED_LIBRARAY_EXPORT void entityName (entvars_t *pev) { \
|
||||
static EntityFunction addr; \
|
||||
helper_LinkEntity (addr, #entityName, pev); \
|
||||
#define LINK_ENTITY(entityName) \
|
||||
CR_EXPORT void entityName (entvars_t *pev) { \
|
||||
static EntityFunction addr; \
|
||||
helper_LinkEntity (addr, #entityName, pev); \
|
||||
}
|
||||
|
||||
// entities in counter-strike...
|
||||
|
|
|
|||
1801
source/manager.cpp
1801
source/manager.cpp
File diff suppressed because it is too large
Load diff
1362
source/navigate.cpp
1362
source/navigate.cpp
File diff suppressed because it is too large
Load diff
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
ConVar yb_display_welcome_text ("yb_display_welcome_text", "1");
|
||||
|
||||
BotUtils::BotUtils (void) {
|
||||
BotUtils::BotUtils () {
|
||||
m_needToSendWelcome = false;
|
||||
m_welcomeReceiveTime = 0.0f;
|
||||
|
||||
|
|
@ -32,47 +32,30 @@ BotUtils::BotUtils (void) {
|
|||
m_sentences.push ("attention, expect experimental armed hostile presence");
|
||||
m_sentences.push ("warning, medical attention required");
|
||||
|
||||
m_tags.push ({ "[[", "]]" });
|
||||
m_tags.push ({ "-=", "=-" });
|
||||
m_tags.push ({ "-[", "]-" });
|
||||
m_tags.push ({ "-]", "[-" });
|
||||
m_tags.push ({ "-}", "{-" });
|
||||
m_tags.push ({ "-{", "}-" });
|
||||
m_tags.push ({ "<[", "]>" });
|
||||
m_tags.push ({ "<]", "[>" });
|
||||
m_tags.push ({ "[-", "-]" });
|
||||
m_tags.push ({ "]-", "-[" });
|
||||
m_tags.push ({ "{-", "-}" });
|
||||
m_tags.push ({ "}-", "-{" });
|
||||
m_tags.push ({ "[", "]" });
|
||||
m_tags.push ({ "{", "}" });
|
||||
m_tags.push ({ "<", "[" });
|
||||
m_tags.push ({ ">", "<" });
|
||||
m_tags.push ({ "-", "-" });
|
||||
m_tags.push ({ "|", "|" });
|
||||
m_tags.push ({ "=", "=" });
|
||||
m_tags.push ({ "+", "+" });
|
||||
m_tags.push ({ "(", ")" });
|
||||
m_tags.push ({ ")", "(" });
|
||||
m_tags.emplace ("[[", "]]");
|
||||
m_tags.emplace ("-=", "=-");
|
||||
m_tags.emplace ("-[", "]-");
|
||||
m_tags.emplace ("-]", "[-");
|
||||
m_tags.emplace ("-}", "{-");
|
||||
m_tags.emplace ("-{", "}-");
|
||||
m_tags.emplace ("<[", "]>");
|
||||
m_tags.emplace ("<]", "[>");
|
||||
m_tags.emplace ("[-", "-]");
|
||||
m_tags.emplace ("]-", "-[");
|
||||
m_tags.emplace ("{-", "-}");
|
||||
m_tags.emplace ("}-", "-{");
|
||||
m_tags.emplace ("[", "]");
|
||||
m_tags.emplace ("{", "}");
|
||||
m_tags.emplace ("<", "[");
|
||||
m_tags.emplace (">", "<");
|
||||
m_tags.emplace ("-", "-");
|
||||
m_tags.emplace ("|", "|");
|
||||
m_tags.emplace ("=", "=");
|
||||
m_tags.emplace ("+", "+");
|
||||
m_tags.emplace ("(", ")");
|
||||
m_tags.emplace (")", "(");
|
||||
|
||||
m_clients.resize (MAX_ENGINE_PLAYERS + 1);
|
||||
}
|
||||
|
||||
const char *BotUtils::format (const char *format, ...) {
|
||||
static char strBuffer[2][MAX_PRINT_BUFFER];
|
||||
static int rotator = 0;
|
||||
|
||||
if (format == nullptr) {
|
||||
return strBuffer[rotator];
|
||||
}
|
||||
static char *ptr = strBuffer[rotator ^= 1];
|
||||
|
||||
va_list ap;
|
||||
va_start (ap, format);
|
||||
vsnprintf (ptr, MAX_PRINT_BUFFER - 1, format, ap);
|
||||
va_end (ap);
|
||||
|
||||
return ptr;
|
||||
m_clients.resize (kGameMaxPlayers + 1);
|
||||
}
|
||||
|
||||
bool BotUtils::isAlive (edict_t *ent) {
|
||||
|
|
@ -90,7 +73,7 @@ float BotUtils::getShootingCone (edict_t *ent, const Vector &position) {
|
|||
}
|
||||
|
||||
bool BotUtils::isInViewCone (const Vector &origin, edict_t *ent) {
|
||||
return getShootingCone (ent, origin) >= cr::cosf (cr::deg2rad ((ent->v.fov > 0 ? ent->v.fov : 90.0f) * 0.5f));
|
||||
return getShootingCone (ent, origin) >= cr::cosf (cr::degreesToRadians ((ent->v.fov > 0 ? ent->v.fov : 90.0f) * 0.5f));
|
||||
}
|
||||
|
||||
bool BotUtils::isVisible (const Vector &origin, edict_t *ent) {
|
||||
|
|
@ -98,7 +81,7 @@ bool BotUtils::isVisible (const Vector &origin, edict_t *ent) {
|
|||
return false;
|
||||
}
|
||||
TraceResult tr;
|
||||
game.testLine (ent->v.origin + ent->v.view_ofs, origin, TRACE_IGNORE_EVERYTHING, ent, &tr);
|
||||
game.testLine (ent->v.origin + ent->v.view_ofs, origin, TraceIgnore::Everything, ent, &tr);
|
||||
|
||||
if (tr.flFraction != 1.0f) {
|
||||
return false;
|
||||
|
|
@ -109,13 +92,10 @@ bool BotUtils::isVisible (const Vector &origin, edict_t *ent) {
|
|||
void BotUtils::traceDecals (entvars_t *pev, TraceResult *trace, int logotypeIndex) {
|
||||
// this function draw spraypaint depending on the tracing results.
|
||||
|
||||
static StringArray logotypes;
|
||||
auto logo = conf.getRandomLogoName (logotypeIndex);
|
||||
|
||||
if (logotypes.empty ()) {
|
||||
logotypes = String ("{biohaz;{graf003;{graf004;{graf005;{lambda06;{target;{hand1;{spit2;{bloodhand6;{foot_l;{foot_r").split (";");
|
||||
}
|
||||
int entityIndex = -1, message = TE_DECAL;
|
||||
int decalIndex = engfuncs.pfnDecalIndex (logotypes[logotypeIndex].chars ());
|
||||
int decalIndex = engfuncs.pfnDecalIndex (logo.chars ());
|
||||
|
||||
if (decalIndex < 0) {
|
||||
decalIndex = engfuncs.pfnDecalIndex ("{lambda06");
|
||||
|
|
@ -151,7 +131,7 @@ void BotUtils::traceDecals (entvars_t *pev, TraceResult *trace, int logotypeInde
|
|||
}
|
||||
}
|
||||
|
||||
if (logotypes[logotypeIndex].contains ("{")) {
|
||||
if (logo.startsWith ("{")) {
|
||||
MessageWriter (MSG_BROADCAST, SVC_TEMPENTITY)
|
||||
.writeByte (TE_PLAYERDECAL)
|
||||
.writeByte (game.indexOfEntity (pev->pContainingEntity))
|
||||
|
|
@ -187,14 +167,14 @@ bool BotUtils::isPlayer (edict_t *ent) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if ((ent->v.flags & (FL_CLIENT | FL_FAKECLIENT)) || bots.getBot (ent) != nullptr) {
|
||||
if ((ent->v.flags & (FL_CLIENT | FL_FAKECLIENT)) || bots[ent] != nullptr) {
|
||||
return !isEmptyStr (STRING (ent->v.netname));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BotUtils::isPlayerVIP (edict_t *ent) {
|
||||
if (!game.mapIs (MAP_AS)) {
|
||||
if (!game.mapIs (MapFlags::Assassination)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -205,14 +185,14 @@ bool BotUtils::isPlayerVIP (edict_t *ent) {
|
|||
}
|
||||
|
||||
bool BotUtils::isFakeClient (edict_t *ent) {
|
||||
if (bots.getBot (ent) != nullptr || (!game.isNullEntity (ent) && (ent->v.flags & FL_FAKECLIENT))) {
|
||||
if (bots[ent] != nullptr || (!game.isNullEntity (ent) && (ent->v.flags & FL_FAKECLIENT))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BotUtils::openConfig (const char *fileName, const char *errorIfNotExists, MemFile *outFile, bool languageDependant /*= false*/) {
|
||||
if (outFile->isValid ()) {
|
||||
if (*outFile) {
|
||||
outFile->close ();
|
||||
}
|
||||
|
||||
|
|
@ -225,165 +205,75 @@ bool BotUtils::openConfig (const char *fileName, const char *errorIfNotExists, M
|
|||
if (strcmp (fileName, "lang.cfg") == 0 && strcmp (yb_language.str (), "en") == 0) {
|
||||
return false;
|
||||
}
|
||||
const char *langConfig = format ("%s/lang/%s_%s", configDir, yb_language.str (), fileName);
|
||||
|
||||
// check file existence
|
||||
int size = 0;
|
||||
uint8 *buffer = nullptr;
|
||||
auto langConfig = strings.format ("%s/lang/%s_%s", configDir, yb_language.str (), fileName);
|
||||
|
||||
// check is file is exists for this language
|
||||
if ((buffer = MemoryLoader::ref ().load (langConfig, &size)) != nullptr) {
|
||||
MemoryLoader::ref ().unload (buffer);
|
||||
|
||||
// unload and reopen file using MemoryFile
|
||||
outFile->open (langConfig);
|
||||
}
|
||||
else {
|
||||
outFile->open (format ("%s/lang/en_%s", configDir, fileName));
|
||||
if (!outFile->open (langConfig)) {
|
||||
outFile->open (strings.format ("%s/lang/en_%s", configDir, fileName));
|
||||
}
|
||||
}
|
||||
else {
|
||||
outFile->open (format ("%s/%s", configDir, fileName));
|
||||
outFile->open (strings.format ("%s/%s", configDir, fileName));
|
||||
}
|
||||
|
||||
if (!outFile->isValid ()) {
|
||||
logEntry (true, LL_ERROR, errorIfNotExists);
|
||||
if (!*outFile) {
|
||||
logger.error (errorIfNotExists);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BotUtils::checkWelcome (void) {
|
||||
void BotUtils::checkWelcome () {
|
||||
// the purpose of this function, is to send quick welcome message, to the listenserver entity.
|
||||
|
||||
if (game.isDedicated () || !yb_display_welcome_text.boolean () || !m_needToSendWelcome) {
|
||||
if (game.isDedicated () || !yb_display_welcome_text.bool_ () || !m_needToSendWelcome) {
|
||||
return;
|
||||
}
|
||||
m_welcomeReceiveTime = 0.0f;
|
||||
|
||||
if (game.is (GAME_LEGACY)) {
|
||||
m_needToSendWelcome = true;
|
||||
return;
|
||||
}
|
||||
bool needToSendMsg = (waypoints.length () > 0 ? m_needToSendWelcome : true);
|
||||
|
||||
if (isAlive (game.getLocalEntity ()) && m_welcomeReceiveTime < 1.0 && needToSendMsg) {
|
||||
bool needToSendMsg = (graph.length () > 0 ? m_needToSendWelcome : true);
|
||||
auto receiveEntity = game.getLocalEntity ();
|
||||
|
||||
if (isAlive (receiveEntity) && m_welcomeReceiveTime < 1.0 && needToSendMsg) {
|
||||
m_welcomeReceiveTime = game.timebase () + 4.0f; // receive welcome message in four seconds after game has commencing
|
||||
}
|
||||
|
||||
if (m_welcomeReceiveTime > 0.0f && needToSendMsg) {
|
||||
if (!game.is (GAME_MOBILITY | GAME_XASH_ENGINE)) {
|
||||
game.execCmd ("speak \"%s\"", m_sentences.random ().chars ());
|
||||
}
|
||||
game.chatPrint ("----- %s v%s (Build: %u), {%s}, (c) %s, by %s (%s)-----", PRODUCT_SHORT_NAME, PRODUCT_VERSION, buildNumber (), PRODUCT_DATE, PRODUCT_END_YEAR, PRODUCT_AUTHOR, PRODUCT_URL);
|
||||
|
||||
MessageWriter (MSG_ONE, SVC_TEMPENTITY, Vector::null (), game.getLocalEntity ())
|
||||
if (m_welcomeReceiveTime > 0.0f && needToSendMsg) {
|
||||
if (!game.is (GameFlags::Mobility | GameFlags::Xash3D)) {
|
||||
game.serverCommand ("speak \"%s\"", m_sentences.random ().chars ());
|
||||
}
|
||||
|
||||
MessageWriter (MSG_ONE, game.getMessageId (NetMsg::TextMsg), nullvec, receiveEntity)
|
||||
.writeByte (HUD_PRINTTALK)
|
||||
.writeString (strings.format ("----- %s v%s (Build: %u), {%s}, (c) %s, by %s (%s)-----", PRODUCT_SHORT_NAME, PRODUCT_VERSION, buildNumber (), PRODUCT_DATE, PRODUCT_END_YEAR, PRODUCT_AUTHOR, PRODUCT_URL));
|
||||
|
||||
MessageWriter (MSG_ONE, SVC_TEMPENTITY, nullvec, receiveEntity)
|
||||
.writeByte (TE_TEXTMESSAGE)
|
||||
.writeByte (1)
|
||||
.writeShort (MessageWriter::fs16 (-1, 1 << 13))
|
||||
.writeShort (MessageWriter::fs16 (-1, 1 << 13))
|
||||
.writeShort (MessageWriter::fs16 (-1.0f, 13.0f))
|
||||
.writeShort (MessageWriter::fs16 (-1.0f, 13.0f))
|
||||
.writeByte (2)
|
||||
.writeByte (rng.getInt (33, 255))
|
||||
.writeByte (rng.getInt (33, 255))
|
||||
.writeByte (rng.getInt (33, 255))
|
||||
.writeByte (rg.int_ (33, 255))
|
||||
.writeByte (rg.int_ (33, 255))
|
||||
.writeByte (rg.int_ (33, 255))
|
||||
.writeByte (0)
|
||||
.writeByte (rng.getInt (230, 255))
|
||||
.writeByte (rng.getInt (230, 255))
|
||||
.writeByte (rng.getInt (230, 255))
|
||||
.writeByte (rg.int_ (230, 255))
|
||||
.writeByte (rg.int_ (230, 255))
|
||||
.writeByte (rg.int_ (230, 255))
|
||||
.writeByte (200)
|
||||
.writeShort (MessageWriter::fu16 (0.0078125f, 1 << 8))
|
||||
.writeShort (MessageWriter::fu16 (2.0f, 1 << 8))
|
||||
.writeShort (MessageWriter::fu16 (6.0f, 1 << 8))
|
||||
.writeShort (MessageWriter::fu16 (0.1f, 1 << 8))
|
||||
.writeString (format ("\nServer is running %s v%s (Build: %u)\nDeveloped by %s\n\n%s", PRODUCT_SHORT_NAME, PRODUCT_VERSION, buildNumber (), PRODUCT_AUTHOR, waypoints.getAuthor ()));
|
||||
.writeShort (MessageWriter::fu16 (0.0078125f, 8.0f))
|
||||
.writeShort (MessageWriter::fu16 (2.0f, 8.0f))
|
||||
.writeShort (MessageWriter::fu16 (6.0f, 8.0f))
|
||||
.writeShort (MessageWriter::fu16 (0.1f, 8.0f))
|
||||
.writeString (strings.format ("\nServer is running %s v%s (Build: %u)\nDeveloped by %s\n\n%s", PRODUCT_SHORT_NAME, PRODUCT_VERSION, buildNumber (), PRODUCT_AUTHOR, graph.getAuthor ()));
|
||||
|
||||
m_welcomeReceiveTime = 0.0f;
|
||||
m_needToSendWelcome = false;
|
||||
}
|
||||
}
|
||||
|
||||
void BotUtils::logEntry (bool outputToConsole, int logLevel, const char *format, ...) {
|
||||
// this function logs a message to the message log file root directory.
|
||||
|
||||
va_list ap;
|
||||
char buffer[MAX_PRINT_BUFFER] = { 0, }, levelString[32] = { 0, };
|
||||
|
||||
va_start (ap, format);
|
||||
vsnprintf (buffer, cr::bufsize (buffer), format, ap);
|
||||
va_end (ap);
|
||||
|
||||
switch (logLevel) {
|
||||
case LL_DEFAULT:
|
||||
strcpy (levelString, "LOG: ");
|
||||
break;
|
||||
|
||||
case LL_WARNING:
|
||||
strcpy (levelString, "WARN: ");
|
||||
break;
|
||||
|
||||
case LL_ERROR:
|
||||
strcpy (levelString, "ERROR: ");
|
||||
break;
|
||||
|
||||
case LL_FATAL:
|
||||
strcpy (levelString, "FATAL: ");
|
||||
break;
|
||||
}
|
||||
|
||||
if (outputToConsole) {
|
||||
game.print ("%s%s", levelString, buffer);
|
||||
}
|
||||
|
||||
// now check if logging disabled
|
||||
if (!(logLevel & LL_IGNORE)) {
|
||||
extern ConVar yb_debug;
|
||||
|
||||
if (logLevel == LL_DEFAULT && yb_debug.integer () < 3) {
|
||||
return; // no log, default logging is disabled
|
||||
}
|
||||
|
||||
if (logLevel == LL_WARNING && yb_debug.integer () < 2) {
|
||||
return; // no log, warning logging is disabled
|
||||
}
|
||||
|
||||
if (logLevel == LL_ERROR && yb_debug.integer () < 1) {
|
||||
return; // no log, error logging is disabled
|
||||
}
|
||||
}
|
||||
|
||||
// open file in a standard stream
|
||||
File fp ("yapb.txt", "at");
|
||||
|
||||
// check if we got a valid handle
|
||||
if (!fp.isValid ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
time_t tickTime = time (&tickTime);
|
||||
tm *time = localtime (&tickTime);
|
||||
|
||||
fp.writeFormat ("%02d:%02d:%02d --> %s%s\n", time->tm_hour, time->tm_min, time->tm_sec, levelString, buffer);
|
||||
fp.close ();
|
||||
|
||||
if (logLevel == LL_FATAL) {
|
||||
bots.kickEveryone (true);
|
||||
waypoints.init ();
|
||||
|
||||
#if defined(PLATFORM_WIN32)
|
||||
DestroyWindow (GetForegroundWindow ());
|
||||
MessageBoxA (GetActiveWindow (), buffer, "YaPB Error", MB_ICONSTOP);
|
||||
#else
|
||||
printf ("%s\n", buffer);
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_WIN32)
|
||||
_exit (1);
|
||||
#else
|
||||
exit (1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool BotUtils::findNearestPlayer (void **pvHolder, edict_t *to, float searchDistance, bool sameTeam, bool needBot, bool needAlive, bool needDrawn, bool needBotWithC4) {
|
||||
// this function finds nearest to to, player with set of parameters, like his
|
||||
// team, live status, search distance etc. if needBot is true, then pvHolder, will
|
||||
|
|
@ -395,11 +285,11 @@ bool BotUtils::findNearestPlayer (void **pvHolder, edict_t *to, float searchDist
|
|||
int toTeam = game.getTeam (to);
|
||||
|
||||
for (const auto &client : m_clients) {
|
||||
if (!(client.flags & CF_USED) || client.ent == to) {
|
||||
if (!(client.flags & ClientFlags::Used) || client.ent == to) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((sameTeam && client.team != toTeam) || (needAlive && !(client.flags & CF_ALIVE)) || (needBot && !isFakeClient (client.ent)) || (needDrawn && (client.ent->v.effects & EF_NODRAW)) || (needBotWithC4 && (client.ent->v.weapons & WEAPON_C4))) {
|
||||
if ((sameTeam && client.team != toTeam) || (needAlive && !(client.flags & ClientFlags::Alive)) || (needBot && !isFakeClient (client.ent)) || (needDrawn && (client.ent->v.effects & EF_NODRAW)) || (needBotWithC4 && (client.ent->v.weapons & Weapon::C4))) {
|
||||
continue; // filter players with parameters
|
||||
}
|
||||
float distance = (client.ent->v.origin - to->v.origin).length ();
|
||||
|
|
@ -416,7 +306,7 @@ bool BotUtils::findNearestPlayer (void **pvHolder, edict_t *to, float searchDist
|
|||
|
||||
// fill the holder
|
||||
if (needBot) {
|
||||
*pvHolder = reinterpret_cast <void *> (bots.getBot (survive));
|
||||
*pvHolder = reinterpret_cast <void *> (bots[survive]);
|
||||
}
|
||||
else {
|
||||
*pvHolder = reinterpret_cast <void *> (survive);
|
||||
|
|
@ -436,16 +326,16 @@ void BotUtils::attachSoundsToClients (edict_t *ent, const char *sample, float vo
|
|||
if (origin.empty ()) {
|
||||
return;
|
||||
}
|
||||
int index = game.indexOfEntity (ent) - 1;
|
||||
int index = game.indexOfPlayer (ent);
|
||||
|
||||
if (index < 0 || index >= game.maxClients ()) {
|
||||
float nearestDistance = 99999.0f;
|
||||
|
||||
// loop through all players
|
||||
for (int i = 0; i < game.maxClients (); i++) {
|
||||
for (int i = 0; i < game.maxClients (); ++i) {
|
||||
const Client &client = m_clients[i];
|
||||
|
||||
if (!(client.flags & CF_USED) || !(client.flags & CF_ALIVE)) {
|
||||
if (!(client.flags & ClientFlags::Used) || !(client.flags & ClientFlags::Alive)) {
|
||||
continue;
|
||||
}
|
||||
float distance = (client.origin - origin).length ();
|
||||
|
|
@ -545,9 +435,9 @@ void BotUtils::simulateSoundUpdates (int playerIndex) {
|
|||
else {
|
||||
extern ConVar mp_footsteps;
|
||||
|
||||
if (mp_footsteps.boolean ()) {
|
||||
if (mp_footsteps.bool_ ()) {
|
||||
// moves fast enough?
|
||||
hearDistance = 1280.0f * (client.ent->v.velocity.length2D () / 260.0f);
|
||||
hearDistance = 1280.0f * (client.ent->v.velocity.length2d () / 260.0f);
|
||||
timeSound = game.timebase () + 0.3f;
|
||||
}
|
||||
}
|
||||
|
|
@ -573,36 +463,129 @@ void BotUtils::simulateSoundUpdates (int playerIndex) {
|
|||
}
|
||||
}
|
||||
|
||||
void BotUtils::updateClients (void) {
|
||||
void BotUtils::updateClients () {
|
||||
|
||||
// record some stats of all players on the server
|
||||
for (int i = 0; i < game.maxClients (); i++) {
|
||||
edict_t *player = game.entityOfIndex (i + 1);
|
||||
for (int i = 0; i < game.maxClients (); ++i) {
|
||||
edict_t *player = game.playerOfIndex (i);
|
||||
Client &client = m_clients[i];
|
||||
|
||||
if (!game.isNullEntity (player) && (player->v.flags & FL_CLIENT)) {
|
||||
client.ent = player;
|
||||
client.flags |= CF_USED;
|
||||
client.flags |= ClientFlags::Used;
|
||||
|
||||
if (util.isAlive (player)) {
|
||||
client.flags |= CF_ALIVE;
|
||||
client.flags |= ClientFlags::Alive;
|
||||
}
|
||||
else {
|
||||
client.flags &= ~CF_ALIVE;
|
||||
client.flags &= ~ClientFlags::Alive;
|
||||
}
|
||||
|
||||
if (client.flags & CF_ALIVE) {
|
||||
if (client.flags & ClientFlags::Alive) {
|
||||
client.origin = player->v.origin;
|
||||
simulateSoundUpdates (i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
client.flags &= ~(CF_USED | CF_ALIVE);
|
||||
client.flags &= ~(ClientFlags::Used | ClientFlags::Alive);
|
||||
client.ent = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int BotUtils::buildNumber (void) {
|
||||
int BotUtils::getPingBitmask (edict_t *ent, int loss, int ping) {
|
||||
// this function generats bitmask for SVC_PINGS engine message. See SV_EmitPings from engine for details
|
||||
|
||||
const auto emit = [] (int s0, int s1, int s2) {
|
||||
return (s0 & (cr::bit (s1) - 1)) << s2;
|
||||
};
|
||||
return emit (loss, 7, 18) | emit (ping, 12, 6) | emit (game.indexOfPlayer (ent), 5, 1) | 1;
|
||||
}
|
||||
|
||||
void BotUtils::calculatePings () {
|
||||
if (!game.is (GameFlags::HasFakePings) || yb_show_latency.int_ () != 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
Twin <int, int> average { 0, 0 };
|
||||
int numHumans = 0;
|
||||
|
||||
// first get average ping on server, and store real client pings
|
||||
for (auto &client : m_clients) {
|
||||
if (!(client.flags & ClientFlags::Used) || isFakeClient (client.ent)) {
|
||||
continue;
|
||||
}
|
||||
int ping, loss;
|
||||
engfuncs.pfnGetPlayerStats (client.ent, &ping, &loss);
|
||||
|
||||
// store normal client ping
|
||||
client.ping = getPingBitmask (client.ent, loss, ping > 0 ? ping / 2 : rg.int_ (8, 16)); // getting player ping sometimes fails
|
||||
client.pingUpdate = true; // force resend ping
|
||||
|
||||
numHumans++;
|
||||
|
||||
average.first += ping;
|
||||
average.second += loss;
|
||||
}
|
||||
|
||||
if (numHumans > 0) {
|
||||
average.first /= numHumans;
|
||||
average.second /= numHumans;
|
||||
}
|
||||
else {
|
||||
average.first = rg.int_ (30, 40);
|
||||
average.second = rg.int_ (5, 10);
|
||||
}
|
||||
|
||||
// now calculate bot ping based on average from players
|
||||
for (auto &client : m_clients) {
|
||||
if (!(client.flags & ClientFlags::Used)) {
|
||||
continue;
|
||||
}
|
||||
auto bot = bots[client.ent];
|
||||
|
||||
// we're only intrested in bots here
|
||||
if (!bot) {
|
||||
continue;
|
||||
}
|
||||
int part = static_cast <int> (average.first * 0.2f);
|
||||
|
||||
int botPing = bot->m_basePing + rg.int_ (average.first - part, average.first + part) + rg.int_ (bot->m_difficulty / 2, bot->m_difficulty);
|
||||
int botLoss = rg.int_ (average.second / 2, average.second);
|
||||
|
||||
client.ping = getPingBitmask (client.ent, botLoss, botPing);
|
||||
client.pingUpdate = true; // force resend ping
|
||||
}
|
||||
}
|
||||
|
||||
void BotUtils::sendPings (edict_t *to) {
|
||||
MessageWriter msg;
|
||||
|
||||
// missing from sdk
|
||||
constexpr int kGamePingSVC = 17;
|
||||
|
||||
for (auto &client : m_clients) {
|
||||
if (!(client.flags & ClientFlags::Used)) {
|
||||
continue;
|
||||
}
|
||||
if (!client.pingUpdate) {
|
||||
continue;
|
||||
}
|
||||
client.pingUpdate = false;
|
||||
|
||||
// no ping, no fun
|
||||
if (!client.ping) {
|
||||
client.ping = getPingBitmask (client.ent, rg.int_ (5, 10), rg.int_ (15, 40));
|
||||
}
|
||||
|
||||
msg.start (MSG_ONE_UNRELIABLE, kGamePingSVC, nullvec, to)
|
||||
.writeLong (client.ping)
|
||||
.end ();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int BotUtils::buildNumber () {
|
||||
// this function generates build number from the compiler date macros
|
||||
|
||||
static int buildNumber = 0;
|
||||
|
|
@ -624,7 +607,7 @@ int BotUtils::buildNumber (void) {
|
|||
int i = 0;
|
||||
|
||||
// go through all months, and calculate, days since year start
|
||||
for (i = 0; i < 11; i++) {
|
||||
for (i = 0; i < 11; ++i) {
|
||||
if (strncmp (&date[0], months[i], 3) == 0) {
|
||||
break; // found current month break
|
||||
}
|
||||
|
|
@ -655,38 +638,38 @@ int BotUtils::getWeaponAlias (bool needString, const char *weaponAlias, int weap
|
|||
|
||||
// weapon enumeration
|
||||
WeaponTab_t weaponTab[] = {
|
||||
{WEAPON_USP, "usp"}, // HK USP .45 Tactical
|
||||
{WEAPON_GLOCK, "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
|
||||
{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
|
||||
|
|
|
|||
2928
source/waypoint.cpp
2928
source/waypoint.cpp
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue