Address more
This commit is contained in:
parent
cfc540991c
commit
d7a2b1aae7
@ -3,8 +3,9 @@
|
|||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
std::vector<std::string> Bots::BotNames;
|
std::vector<std::string> Bots::BotNames;
|
||||||
|
Game::dvar_t* Bots::SVBotWarfare;
|
||||||
|
|
||||||
struct BotMovementInfo_t
|
struct BotMovementInfo
|
||||||
{
|
{
|
||||||
int buttons; // Actions
|
int buttons; // Actions
|
||||||
int8_t forward;
|
int8_t forward;
|
||||||
@ -12,7 +13,7 @@ namespace Components
|
|||||||
uint16_t weapon;
|
uint16_t weapon;
|
||||||
};
|
};
|
||||||
|
|
||||||
static BotMovementInfo_t g_botai[18];
|
static BotMovementInfo g_botai[18];
|
||||||
|
|
||||||
struct BotAction
|
struct BotAction
|
||||||
{
|
{
|
||||||
@ -187,7 +188,7 @@ namespace Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto weapId = Game::G_GetWeaponIndexForName(weapon);
|
const auto weapId = Game::G_GetWeaponIndexForName(weapon);
|
||||||
g_botai[entref.entnum].weapon = static_cast<unsigned short>(weapId);
|
g_botai[entref.entnum].weapon = static_cast<uint16_t>(weapId);
|
||||||
});
|
});
|
||||||
|
|
||||||
Script::AddFunction("BotAction", [](Game::scr_entref_t entref) // Usage: <bot> BotAction(<str action>);
|
Script::AddFunction("BotAction", [](Game::scr_entref_t entref) // Usage: <bot> BotAction(<str action>);
|
||||||
@ -253,6 +254,57 @@ namespace Components
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Bots::BotAiAction()
|
||||||
|
{
|
||||||
|
for (auto i = 0; i < *Game::svs_numclients; ++i)
|
||||||
|
{
|
||||||
|
auto* client = &Game::svs_clients[i];
|
||||||
|
|
||||||
|
if (client->state < Game::CS_CONNECTED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!client->isBot)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Game::usercmd_s ucmd = {0};
|
||||||
|
|
||||||
|
ucmd.serverTime = *Game::svs_time;
|
||||||
|
|
||||||
|
ucmd.buttons = g_botai[i].buttons;
|
||||||
|
ucmd.forwardmove = g_botai[i].forward;
|
||||||
|
ucmd.rightmove = g_botai[i].right;
|
||||||
|
ucmd.weapon = g_botai[i].weapon;
|
||||||
|
|
||||||
|
client->deltaMessage = client->netchan.outgoingSequence - 1;
|
||||||
|
|
||||||
|
Game::SV_ClientThink(client, &ucmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto SV_UpdateBots = 0x626E50;
|
||||||
|
__declspec(naked) void Bots::SV_UpdateBots_Hk()
|
||||||
|
{
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
pushad
|
||||||
|
|
||||||
|
call SV_UpdateBots
|
||||||
|
|
||||||
|
// If bot warfare isn't being used let's keep
|
||||||
|
// test clients normal functionality
|
||||||
|
mov eax, Bots::SVBotWarfare
|
||||||
|
cmp byte ptr [eax + 0x10], 0;
|
||||||
|
|
||||||
|
jz skip
|
||||||
|
|
||||||
|
call Bots::BotAiAction
|
||||||
|
|
||||||
|
skip:
|
||||||
|
popad
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Bots::Bots()
|
Bots::Bots()
|
||||||
{
|
{
|
||||||
// Replace connect string
|
// Replace connect string
|
||||||
@ -261,48 +313,19 @@ namespace Components
|
|||||||
// Intercept sprintf for the connect string
|
// Intercept sprintf for the connect string
|
||||||
Utils::Hook(0x48ADAB, Bots::BuildConnectString, HOOK_CALL).install()->quick();
|
Utils::Hook(0x48ADAB, Bots::BuildConnectString, HOOK_CALL).install()->quick();
|
||||||
|
|
||||||
// Stop default behavour of bots spinning and shooting
|
Bots::SVBotWarfare = Game::Dvar_RegisterBool("sv_botWarfare", false,
|
||||||
Utils::Hook(0x627021, 0x4BB9B0, HOOK_CALL).install()->quick();
|
Game::DVAR_FLAG_NONE, "Allow bot warfare mod to override default bot behaviour");
|
||||||
Utils::Hook(0x627241, 0x4BB9B0, HOOK_CALL).install()->quick();
|
|
||||||
|
Utils::Hook(0x627021, SV_UpdateBots_Hk, HOOK_CALL).install()->quick();
|
||||||
|
Utils::Hook(0x627241, SV_UpdateBots_Hk, HOOK_CALL).install()->quick();
|
||||||
|
|
||||||
// Zero the bot command array
|
// Zero the bot command array
|
||||||
for (auto i = 0u; i < std::extent_v<decltype(g_botai)>; i++)
|
for (auto i = 0u; i < std::extent_v<decltype(g_botai)>; i++)
|
||||||
{
|
{
|
||||||
g_botai[i] = {0};
|
g_botai[i] = {0};
|
||||||
g_botai[i].weapon = 1; // Prevent the bots from defaulting to the 'none' weapon
|
g_botai[i].weapon = 1; // Prevent the bots from defaulting to the 'none' weapon
|
||||||
}
|
}
|
||||||
|
|
||||||
// Have the bots perform the command every server frame
|
|
||||||
Scheduler::OnFrame([]()
|
|
||||||
{
|
|
||||||
if (!Game::SV_Loaded())
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (auto i = 0; i < *Game::svs_numclients; ++i)
|
|
||||||
{
|
|
||||||
auto* client = &Game::svs_clients[i];
|
|
||||||
|
|
||||||
if (client->state < Game::CS_CONNECTED)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!client->isBot)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Game::usercmd_s ucmd = {0};
|
|
||||||
|
|
||||||
ucmd.serverTime = *Game::svs_time;
|
|
||||||
|
|
||||||
ucmd.buttons = g_botai[i].buttons;
|
|
||||||
ucmd.forwardmove = g_botai[i].forward;
|
|
||||||
ucmd.rightmove = g_botai[i].right;
|
|
||||||
ucmd.weapon = g_botai[i].weapon;
|
|
||||||
|
|
||||||
client->deltaMessage = client->netchan.outgoingSequence - 1;
|
|
||||||
|
|
||||||
Game::SV_ClientThink(client, &ucmd);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Command::Add("spawnBot", [](Command::Params* params)
|
Command::Add("spawnBot", [](Command::Params* params)
|
||||||
{
|
{
|
||||||
auto count = 1u;
|
auto count = 1u;
|
||||||
|
@ -37,16 +37,20 @@ namespace Components
|
|||||||
NUM_8 = 0x1000000,
|
NUM_8 = 0x1000000,
|
||||||
NUM_9 = 0x2000000,
|
NUM_9 = 0x2000000,
|
||||||
|
|
||||||
USE = 0x28,
|
USE = NUM_0 | NUM_1
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::vector<std::string> BotNames;
|
static std::vector<std::string> BotNames;
|
||||||
|
static Game::dvar_t* SVBotWarfare;
|
||||||
|
|
||||||
static void BuildConnectString(char* buffer, const char* connectString, int num, int, int protocol, int checksum, int statVer, int statStuff, int port);
|
static void BuildConnectString(char* buffer, const char* connectString, int num, int, int protocol, int checksum, int statVer, int statStuff, int port);
|
||||||
|
|
||||||
static void Spawn(unsigned int count);
|
static void Spawn(unsigned int count);
|
||||||
|
|
||||||
static void AddMethods();
|
static void AddMethods();
|
||||||
|
|
||||||
|
static void BotAiAction();
|
||||||
|
static void SV_UpdateBots_Hk();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -433,6 +433,30 @@ namespace Components
|
|||||||
return Game::Scr_GetNumParam();
|
return Game::Scr_GetNumParam();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allow printing to the console even when developer is 0
|
||||||
|
void Script::PrintStub()
|
||||||
|
{
|
||||||
|
const auto g_no_script_spam = Dvar::Var("g_no_script_spam").get<bool>();
|
||||||
|
|
||||||
|
if (!g_no_script_spam)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto developer = Dvar::Var("developer").get<int>();
|
||||||
|
|
||||||
|
for (auto i = 0u; i < Game::Scr_GetNumParam(); i++)
|
||||||
|
{
|
||||||
|
const auto str = (developer) ? Game::Scr_GetDebugString(i) : Game::Scr_GetString(i);
|
||||||
|
|
||||||
|
if (str == nullptr)
|
||||||
|
{
|
||||||
|
Game::Scr_ParamError(i, "^1PrintConsole: Illegal parameters!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::Print(*Game::level_scriptPrintChannel, "%s", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const char* Script::GetCodePosForParam(int index)
|
const char* Script::GetCodePosForParam(int index)
|
||||||
{
|
{
|
||||||
if (static_cast<unsigned int>(index) >= Game::scrVmPub->outparamcount)
|
if (static_cast<unsigned int>(index) >= Game::scrVmPub->outparamcount)
|
||||||
@ -582,20 +606,6 @@ namespace Components
|
|||||||
Game::Scr_AddInt(time.wMilliseconds);
|
Game::Scr_AddInt(time.wMilliseconds);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Print to console, even without being in 'developer 1'.
|
|
||||||
Script::AddFunction("PrintConsole", [](Game::scr_entref_t) // gsc: PrintConsole(<string>)
|
|
||||||
{
|
|
||||||
const auto* str = Game::Scr_GetString(0);
|
|
||||||
|
|
||||||
if (str == nullptr)
|
|
||||||
{
|
|
||||||
Game::Scr_ParamError(0, "^1PrintConsole: Illegal parameters!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger::Print(0, "%s", str);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Executes command to the console
|
// Executes command to the console
|
||||||
Script::AddFunction("Exec", [](Game::scr_entref_t) // gsc: Exec(<string>)
|
Script::AddFunction("Exec", [](Game::scr_entref_t) // gsc: Exec(<string>)
|
||||||
{
|
{
|
||||||
@ -610,7 +620,6 @@ namespace Components
|
|||||||
Command::Execute(str, false);
|
Command::Execute(str, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Script Storage Funcs
|
// Script Storage Funcs
|
||||||
Script::AddFunction("StorageSet", [](Game::scr_entref_t) // gsc: StorageSet(<str key>, <str data>);
|
Script::AddFunction("StorageSet", [](Game::scr_entref_t) // gsc: StorageSet(<str key>, <str data>);
|
||||||
{
|
{
|
||||||
|
@ -73,6 +73,8 @@ namespace Components
|
|||||||
|
|
||||||
static unsigned int SetExpFogStub();
|
static unsigned int SetExpFogStub();
|
||||||
|
|
||||||
|
static void PrintStub();
|
||||||
|
|
||||||
static const char* GetCodePosForParam(int index);
|
static const char* GetCodePosForParam(int index);
|
||||||
static void GetReplacedPos(const char* pos);
|
static void GetReplacedPos(const char* pos);
|
||||||
static void SetReplacedPos(const char* what, const char* with);
|
static void SetReplacedPos(const char* what, const char* with);
|
||||||
|
@ -259,6 +259,7 @@ namespace Game
|
|||||||
Scr_GetFunctionHandle_t Scr_GetFunctionHandle = Scr_GetFunctionHandle_t(0x4234F0);
|
Scr_GetFunctionHandle_t Scr_GetFunctionHandle = Scr_GetFunctionHandle_t(0x4234F0);
|
||||||
|
|
||||||
Scr_GetString_t Scr_GetString = Scr_GetString_t(0x425900);
|
Scr_GetString_t Scr_GetString = Scr_GetString_t(0x425900);
|
||||||
|
Scr_GetDebugString_t Scr_GetDebugString = Scr_GetDebugString_t(0x4EBF50);
|
||||||
Scr_GetFloat_t Scr_GetFloat = Scr_GetFloat_t(0x443140);
|
Scr_GetFloat_t Scr_GetFloat = Scr_GetFloat_t(0x443140);
|
||||||
Scr_GetInt_t Scr_GetInt = Scr_GetInt_t(0x4F31D0);
|
Scr_GetInt_t Scr_GetInt = Scr_GetInt_t(0x4F31D0);
|
||||||
Scr_GetObject_t Scr_GetObject = Scr_GetObject_t(0x462100);
|
Scr_GetObject_t Scr_GetObject = Scr_GetObject_t(0x462100);
|
||||||
@ -431,6 +432,8 @@ namespace Game
|
|||||||
|
|
||||||
gentity_t* g_entities = reinterpret_cast<gentity_t*>(0x18835D8);
|
gentity_t* g_entities = reinterpret_cast<gentity_t*>(0x18835D8);
|
||||||
|
|
||||||
|
int* level_scriptPrintChannel = reinterpret_cast<int*>(0x1A860FC);
|
||||||
|
|
||||||
netadr_t* connectedHost = reinterpret_cast<netadr_t*>(0xA1E888);
|
netadr_t* connectedHost = reinterpret_cast<netadr_t*>(0xA1E888);
|
||||||
|
|
||||||
SOCKET* ip_socket = reinterpret_cast<SOCKET*>(0x64A3008);
|
SOCKET* ip_socket = reinterpret_cast<SOCKET*>(0x64A3008);
|
||||||
|
@ -663,6 +663,9 @@ namespace Game
|
|||||||
typedef const char*(__cdecl * Scr_GetString_t)(unsigned int);
|
typedef const char*(__cdecl * Scr_GetString_t)(unsigned int);
|
||||||
extern Scr_GetString_t Scr_GetString;
|
extern Scr_GetString_t Scr_GetString;
|
||||||
|
|
||||||
|
typedef const char*(__cdecl * Scr_GetDebugString_t)(unsigned int index);
|
||||||
|
extern Scr_GetDebugString_t Scr_GetDebugString;
|
||||||
|
|
||||||
typedef float(__cdecl * Scr_GetFloat_t)(unsigned int);
|
typedef float(__cdecl * Scr_GetFloat_t)(unsigned int);
|
||||||
extern Scr_GetFloat_t Scr_GetFloat;
|
extern Scr_GetFloat_t Scr_GetFloat;
|
||||||
|
|
||||||
@ -955,6 +958,8 @@ namespace Game
|
|||||||
constexpr auto MAX_GENTITIES = 2048u;
|
constexpr auto MAX_GENTITIES = 2048u;
|
||||||
extern gentity_t* g_entities;
|
extern gentity_t* g_entities;
|
||||||
|
|
||||||
|
extern int* level_scriptPrintChannel;
|
||||||
|
|
||||||
extern netadr_t* connectedHost;
|
extern netadr_t* connectedHost;
|
||||||
extern SOCKET* ip_socket;
|
extern SOCKET* ip_socket;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user