Address more

This commit is contained in:
FutureRave 2022-01-24 02:00:30 +00:00
parent cfc540991c
commit d7a2b1aae7
No known key found for this signature in database
GPG Key ID: E883E2BC9657D955
6 changed files with 100 additions and 54 deletions

View File

@ -3,8 +3,9 @@
namespace Components
{
std::vector<std::string> Bots::BotNames;
Game::dvar_t* Bots::SVBotWarfare;
struct BotMovementInfo_t
struct BotMovementInfo
{
int buttons; // Actions
int8_t forward;
@ -12,7 +13,7 @@ namespace Components
uint16_t weapon;
};
static BotMovementInfo_t g_botai[18];
static BotMovementInfo g_botai[18];
struct BotAction
{
@ -187,7 +188,7 @@ namespace Components
}
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>);
@ -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()
{
// Replace connect string
@ -261,48 +313,19 @@ namespace Components
// Intercept sprintf for the connect string
Utils::Hook(0x48ADAB, Bots::BuildConnectString, HOOK_CALL).install()->quick();
// Stop default behavour of bots spinning and shooting
Utils::Hook(0x627021, 0x4BB9B0, HOOK_CALL).install()->quick();
Utils::Hook(0x627241, 0x4BB9B0, HOOK_CALL).install()->quick();
Bots::SVBotWarfare = Game::Dvar_RegisterBool("sv_botWarfare", false,
Game::DVAR_FLAG_NONE, "Allow bot warfare mod to override default bot behaviour");
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
for (auto i = 0u; i < std::extent_v<decltype(g_botai)>; i++)
{
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)
{
auto count = 1u;

View File

@ -37,16 +37,20 @@ namespace Components
NUM_8 = 0x1000000,
NUM_9 = 0x2000000,
USE = 0x28,
USE = NUM_0 | NUM_1
};
private:
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 Spawn(unsigned int count);
static void AddMethods();
static void BotAiAction();
static void SV_UpdateBots_Hk();
};
}

View File

@ -433,6 +433,30 @@ namespace Components
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)
{
if (static_cast<unsigned int>(index) >= Game::scrVmPub->outparamcount)
@ -582,20 +606,6 @@ namespace Components
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
Script::AddFunction("Exec", [](Game::scr_entref_t) // gsc: Exec(<string>)
{
@ -610,7 +620,6 @@ namespace Components
Command::Execute(str, false);
});
// Script Storage Funcs
Script::AddFunction("StorageSet", [](Game::scr_entref_t) // gsc: StorageSet(<str key>, <str data>);
{

View File

@ -73,6 +73,8 @@ namespace Components
static unsigned int SetExpFogStub();
static void PrintStub();
static const char* GetCodePosForParam(int index);
static void GetReplacedPos(const char* pos);
static void SetReplacedPos(const char* what, const char* with);

View File

@ -259,6 +259,7 @@ namespace Game
Scr_GetFunctionHandle_t Scr_GetFunctionHandle = Scr_GetFunctionHandle_t(0x4234F0);
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_GetInt_t Scr_GetInt = Scr_GetInt_t(0x4F31D0);
Scr_GetObject_t Scr_GetObject = Scr_GetObject_t(0x462100);
@ -431,6 +432,8 @@ namespace Game
gentity_t* g_entities = reinterpret_cast<gentity_t*>(0x18835D8);
int* level_scriptPrintChannel = reinterpret_cast<int*>(0x1A860FC);
netadr_t* connectedHost = reinterpret_cast<netadr_t*>(0xA1E888);
SOCKET* ip_socket = reinterpret_cast<SOCKET*>(0x64A3008);

View File

@ -663,6 +663,9 @@ namespace Game
typedef const char*(__cdecl * Scr_GetString_t)(unsigned int);
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);
extern Scr_GetFloat_t Scr_GetFloat;
@ -955,6 +958,8 @@ namespace Game
constexpr auto MAX_GENTITIES = 2048u;
extern gentity_t* g_entities;
extern int* level_scriptPrintChannel;
extern netadr_t* connectedHost;
extern SOCKET* ip_socket;