Merge branch 'develop' into branding

This commit is contained in:
Edo 2022-05-07 10:00:09 -04:00 committed by GitHub
commit a455143785
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 231 additions and 118 deletions

View File

@ -20,7 +20,9 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.
### Changed
- Test clients' native functionality has been restored by default (#162)
- Renamed GSC method `isBot` to `IsTestClient` (#162)
- Custom GSC functions can be called correctly from a game script (#216)
- GSC functions `HttpCancel` and `HttpCancel` require the game to be launched with the command line argument `scriptablehttp` (#162)
- Master server list will be used instead of the node system (load server list faster) (#234)
### Fixed

View File

@ -108,8 +108,17 @@ namespace Components
}
}
void Bots::GScr_isTestClient(Game::scr_entref_t entref)
{
const auto* ent = Game::GetPlayerEntity(entref);
Game::Scr_AddBool(Game::SV_IsTestClient(ent->s.number) != 0);
}
void Bots::AddMethods()
{
Script::AddMethod("IsBot", Bots::GScr_isTestClient); // Usage: self IsBot();
Script::AddMethod("IsTestClient", Bots::GScr_isTestClient); // Usage: self IsTestClient();
Script::AddMethod("SetPing", [](Game::scr_entref_t entref) // gsc: self SetPing(<int>)
{
auto ping = Game::Scr_GetInt(0);
@ -119,7 +128,7 @@ namespace Components
const auto* ent = Game::GetPlayerEntity(entref);
auto* client = Script::GetClient(ent);
if (!client->bIsTestClient)
if (Game::SV_IsTestClient(ent->s.number) == 0)
{
Game::Scr_Error("^1SetPing: Can only call on a bot!\n");
return;
@ -128,20 +137,11 @@ namespace Components
client->ping = static_cast<int16_t>(ping);
});
Script::AddMethod("IsTestClient", [](Game::scr_entref_t entref) // Usage: <bot> IsTestClient();
{
const auto* gentity = Game::GetPlayerEntity(entref);
const auto* client = Script::GetClient(gentity);
Game::Scr_AddBool(client->bIsTestClient == 1);
});
Script::AddMethod("BotStop", [](Game::scr_entref_t entref) // Usage: <bot> BotStop();
{
const auto* ent = Game::GetPlayerEntity(entref);
const auto* client = Script::GetClient(ent);
if (!client->bIsTestClient)
if (Game::SV_IsTestClient(ent->s.number) == 0)
{
Game::Scr_Error("^1BotStop: Can only call on a bot!\n");
return;
@ -154,17 +154,16 @@ namespace Components
Script::AddMethod("BotWeapon", [](Game::scr_entref_t entref) // Usage: <bot> BotWeapon(<str>);
{
const auto* weapon = Game::Scr_GetString(0);
const auto* ent = Game::GetPlayerEntity(entref);
const auto* client = Script::GetClient(ent);
if (!client->bIsTestClient)
if (Game::SV_IsTestClient(ent->s.number) == 0)
{
Game::Scr_Error("^1BotWeapon: Can only call on a bot!\n");
return;
}
const auto* weapon = Game::Scr_GetString(0);
if (weapon == nullptr || weapon[0] == '\0')
{
g_botai[entref.entnum].weapon = 1;
@ -178,6 +177,14 @@ namespace Components
Script::AddMethod("BotAction", [](Game::scr_entref_t entref) // Usage: <bot> BotAction(<str action>);
{
const auto* ent = Game::GetPlayerEntity(entref);
if (Game::SV_IsTestClient(ent->s.number) == 0)
{
Game::Scr_Error("^1BotAction: Can only call on a bot!\n");
return;
}
const auto* action = Game::Scr_GetString(0);
if (action == nullptr)
@ -186,15 +193,6 @@ namespace Components
return;
}
const auto* ent = Game::GetPlayerEntity(entref);
const auto* client = Script::GetClient(ent);
if (!client->bIsTestClient)
{
Game::Scr_Error("^1BotAction: Can only call on a bot!\n");
return;
}
if (action[0] != '+' && action[0] != '-')
{
Game::Scr_ParamError(0, "^1BotAction: Sign for action must be '+' or '-'.\n");
@ -220,20 +218,16 @@ namespace Components
Script::AddMethod("BotMovement", [](Game::scr_entref_t entref) // Usage: <bot> BotMovement(<int>, <int>);
{
auto forwardInt = Game::Scr_GetInt(0);
auto rightInt = Game::Scr_GetInt(1);
const auto* ent = Game::GetPlayerEntity(entref);
const auto* client = Script::GetClient(ent);
if (!client->bIsTestClient)
if (Game::SV_IsTestClient(ent->s.number) == 0)
{
Game::Scr_Error("^1BotMovement: Can only call on a bot!\n");
return;
}
forwardInt = std::clamp<int>(forwardInt, std::numeric_limits<char>::min(), std::numeric_limits<char>::max());
rightInt = std::clamp<int>(rightInt, std::numeric_limits<char>::min(), std::numeric_limits<char>::max());
const auto forwardInt = std::clamp<int>(Game::Scr_GetInt(0), std::numeric_limits<char>::min(), std::numeric_limits<char>::max());
const auto rightInt = std::clamp<int>(Game::Scr_GetInt(1), std::numeric_limits<char>::min(), std::numeric_limits<char>::max());
g_botai[entref.entnum].forward = static_cast<int8_t>(forwardInt);
g_botai[entref.entnum].right = static_cast<int8_t>(rightInt);
@ -327,6 +321,8 @@ namespace Components
Bots::Bots()
{
AssertOffset(Game::client_s, bIsTestClient, 0x41AF0);
// Replace connect string
Utils::Hook::Set<const char*>(0x48ADA6, "connect bot%d \"\\cg_predictItems\\1\\cl_anonymous\\0\\color\\4\\head\\default\\model\\multi\\snaps\\20\\rate\\5000\\name\\%s\\protocol\\%d\\checksum\\%d\\statver\\%d %u\\qport\\%d\"");

View File

@ -14,6 +14,7 @@ namespace Components
static void Spawn(unsigned int count);
static void GScr_isTestClient(Game::scr_entref_t entref);
static void AddMethods();
static void BotAiAction(Game::client_t* cl);

View File

@ -354,7 +354,7 @@ namespace Components
}
});
Script::AddFunction("DropAllBots", []() // gsc: DropAllBots();
Script::AddFunction("DropAllBots", [] // gsc: DropAllBots();
{
Game::SV_DropAllBots();
});

View File

@ -964,7 +964,7 @@ namespace Components
Download::ScriptDownloads.clear();
});
Script::AddFunction("HttpGet", []()
Script::AddFunction("HttpGet", []
{
if (!Flags::HasFlag("scriptablehttp"))
return;
@ -985,7 +985,7 @@ namespace Components
Game::RemoveRefToObject(object);
});
Script::AddFunction("HttpCancel", []()
Script::AddFunction("HttpCancel", []
{
if (!Flags::HasFlag("scriptablehttp"))
return;

View File

@ -16,9 +16,9 @@ namespace Components
const auto elevatorSetting = Elevators::BG_Elevators.get<int>();
while (true)
{
point[0] = ps->origin[0] + Game::CorrectSolidDeltas[i][0];
point[1] = ps->origin[1] + Game::CorrectSolidDeltas[i][1];
point[2] = ps->origin[2] + Game::CorrectSolidDeltas[i][2];
point[0] = ps->origin[0] + (*Game::CorrectSolidDeltas)[i][0];
point[1] = ps->origin[1] + (*Game::CorrectSolidDeltas)[i][1];
point[2] = ps->origin[2] + (*Game::CorrectSolidDeltas)[i][2];
Game::PM_playerTrace(pm, trace, point, point, &pm->bounds, ps->clientNum, pm->tracemask);
@ -40,8 +40,8 @@ namespace Components
}
}
i += 1;
if (i >= 26)
++i;
if (i >= 26) // CorrectSolidDeltas count
{
ps->groundEntityNum = Game::ENTITYNUM_NONE;
pml->groundPlane = 0;
@ -62,15 +62,15 @@ namespace Components
return 1;
}
void Elevators::PM_Trace_Hk(Game::pmove_s* pm, Game::trace_t* trace, const float* f3,
const float* f4, const Game::Bounds* bounds, int a6, int a7)
void Elevators::PM_Trace_Hk(Game::pmove_s* pm, Game::trace_t* results, const float* start,
const float* end, const Game::Bounds* bounds, int passEntityNum, int contentMask)
{
Game::PM_Trace(pm, trace, f3, f4, bounds, a6, a7);
Game::PM_Trace(pm, results, start, end, bounds, passEntityNum, contentMask);
// Allow the player to stand even when there is no headroom
if (Elevators::BG_Elevators.get<int>() == Elevators::EASY)
{
trace->allsolid = false;
results->allsolid = false;
}
}
@ -111,8 +111,7 @@ namespace Components
Elevators::ENABLED, Game::DVAR_CODINFO, "Elevators glitch settings");
});
//Replace PM_CorrectAllSolid
Utils::Hook(0x57369E, Elevators::PM_CorrectAllSolidStub, HOOK_CALL).install()->quick();
Utils::Hook(0x57369E, Elevators::PM_CorrectAllSolidStub, HOOK_CALL).install()->quick(); // PM_GroundTrace
// Place hooks in PM_CheckDuck. If the elevators dvar is set to easy the
// flags for duck/prone will always be removed from the player state

View File

@ -661,7 +661,8 @@ namespace Components
Game::AimAssist_UpdateAdsLerp(input);
AimAssist_ApplyTurnRates(input, output);
Game::AimAssist_ApplyAutoMelee(input, output);
// Automelee has already been done by keyboard so don't do it again
AimAssist_ApplyLockOn(input, output);
}
@ -886,8 +887,6 @@ namespace Components
AimAssist_UpdateGamePadInput(&aimInput, &aimOutput);
clientActive.clViewangles[0] = aimOutput.pitch;
clientActive.clViewangles[1] = aimOutput.yaw;
cmd->meleeChargeDist = aimOutput.meleeChargeDist;
cmd->meleeChargeYaw = aimOutput.meleeChargeYaw;
}
}
@ -1033,6 +1032,13 @@ namespace Components
void Gamepad::UI_GamepadKeyEvent(const int gamePadIndex, const int key, const bool down)
{
// If we are currently capturing a key for menu bind inputs then do not map keys and pass to game
if (*Game::g_waitingForKey)
{
Game::UI_KeyEvent(gamePadIndex, key, down);
return;
}
for (const auto& mapping : controllerMenuKeyMappings)
{
if (mapping.controllerKey == key)
@ -1711,8 +1717,8 @@ namespace Components
{
gpad_enabled = Dvar::Register<bool>("gpad_enabled", false, Game::DVAR_ARCHIVE, "Game pad enabled");
gpad_debug = Dvar::Register<bool>("gpad_debug", false, Game::DVAR_NONE, "Game pad debugging");
gpad_present = Dvar::Register<bool>("gpad_present", false, Game::DVAR_NONE, "Game pad present");
gpad_in_use = Dvar::Register<bool>("gpad_in_use", false, Game::DVAR_NONE, "A game pad is in use");
gpad_present = Dvar::Register<bool>("gpad_present", false, Game::DVAR_READONLY, "Game pad present");
gpad_in_use = Dvar::Register<bool>("gpad_in_use", false, Game::DVAR_READONLY, "A game pad is in use");
gpad_style = Dvar::Register<bool>("gpad_style", false, Game::DVAR_ARCHIVE, "Switch between Xbox and PS HUD");
gpad_sticksConfig = Dvar::Register<const char*>("gpad_sticksConfig", "", Game::DVAR_ARCHIVE, "Game pad stick configuration");
gpad_buttonConfig = Dvar::Register<const char*>("gpad_buttonConfig", "", Game::DVAR_ARCHIVE, "Game pad button configuration");
@ -1720,15 +1726,15 @@ namespace Components
gpad_menu_scroll_delay_rest = Dvar::Register<int>("gpad_menu_scroll_delay_rest", 210, 0, 1000, Game::DVAR_ARCHIVE,
"Menu scroll key-repeat delay, for repeats after the first, in milliseconds");
gpad_rumble = Dvar::Register<bool>("gpad_rumble", true, Game::DVAR_ARCHIVE, "Enable game pad rumble");
gpad_stick_pressed_hysteresis = Dvar::Register<float>("gpad_stick_pressed_hysteresis", 0.1f, 0.0f, 1.0f, Game::DVAR_NONE,
gpad_stick_pressed_hysteresis = Dvar::Register<float>("gpad_stick_pressed_hysteresis", 0.1f, 0.0f, 1.0f, Game::DVAR_ARCHIVE,
"Game pad stick pressed no-change-zone around gpad_stick_pressed to prevent bouncing");
gpad_stick_pressed = Dvar::Register<float>("gpad_stick_pressed", 0.4f, 0.0, 1.0, Game::DVAR_NONE, "Game pad stick pressed threshhold");
gpad_stick_deadzone_max = Dvar::Register<float>("gpad_stick_deadzone_max", 0.01f, 0.0f, 1.0f, Game::DVAR_NONE, "Game pad maximum stick deadzone");
gpad_stick_deadzone_min = Dvar::Register<float>("gpad_stick_deadzone_min", 0.2f, 0.0f, 1.0f, Game::DVAR_NONE, "Game pad minimum stick deadzone");
gpad_button_deadzone = Dvar::Register<float>("gpad_button_deadzone", 0.13f, 0.0f, 1.0f, Game::DVAR_NONE, "Game pad button deadzone threshhold");
gpad_button_lstick_deflect_max = Dvar::Register<float>("gpad_button_lstick_deflect_max", 1.0f, 0.0f, 1.0f, Game::DVAR_NONE, "Game pad maximum pad stick pressed value");
gpad_button_rstick_deflect_max = Dvar::Register<float>("gpad_button_rstick_deflect_max", 1.0f, 0.0f, 1.0f, Game::DVAR_NONE, "Game pad maximum pad stick pressed value");
gpad_use_hold_time = Dvar::Register<int>("gpad_use_hold_time", 250, 0, std::numeric_limits<int>::max(), Game::DVAR_NONE, "Time to hold the 'use' button on gamepads to activate use");
gpad_stick_pressed = Dvar::Register<float>("gpad_stick_pressed", 0.4f, 0.0, 1.0, Game::DVAR_ARCHIVE, "Game pad stick pressed threshhold");
gpad_stick_deadzone_max = Dvar::Register<float>("gpad_stick_deadzone_max", 0.01f, 0.0f, 1.0f, Game::DVAR_ARCHIVE, "Game pad maximum stick deadzone");
gpad_stick_deadzone_min = Dvar::Register<float>("gpad_stick_deadzone_min", 0.2f, 0.0f, 1.0f, Game::DVAR_ARCHIVE, "Game pad minimum stick deadzone");
gpad_button_deadzone = Dvar::Register<float>("gpad_button_deadzone", 0.13f, 0.0f, 1.0f, Game::DVAR_ARCHIVE, "Game pad button deadzone threshhold");
gpad_button_lstick_deflect_max = Dvar::Register<float>("gpad_button_lstick_deflect_max", 1.0f, 0.0f, 1.0f, Game::DVAR_ARCHIVE, "Game pad maximum pad stick pressed value");
gpad_button_rstick_deflect_max = Dvar::Register<float>("gpad_button_rstick_deflect_max", 1.0f, 0.0f, 1.0f, Game::DVAR_ARCHIVE, "Game pad maximum pad stick pressed value");
gpad_use_hold_time = Dvar::Register<int>("gpad_use_hold_time", 250, 0, std::numeric_limits<int>::max(), Game::DVAR_ARCHIVE, "Time to hold the 'use' button on gamepads to activate use");
gpad_lockon_enabled = Dvar::Register<bool>("gpad_lockon_enabled", true, Game::DVAR_ARCHIVE, "Game pad lockon aim assist enabled");
gpad_slowdown_enabled = Dvar::Register<bool>("gpad_slowdown_enabled", true, Game::DVAR_ARCHIVE, "Game pad slowdown aim assist enabled");
@ -1777,19 +1783,19 @@ namespace Components
return command;
}
int Gamepad::Key_GetCommandAssignmentInternal_Hk(const char* cmd, int (*keys)[2])
int Gamepad::Key_GetCommandAssignmentInternal([[maybe_unused]] int localClientNum, const char* cmd, int (*keys)[2])
{
auto keyCount = 0;
if (gamePads[0].inUse)
{
cmd = GetGamePadCommand(cmd);
const auto gamePadCmd = GetGamePadCommand(cmd);
for (auto keyNum = 0; keyNum < Game::K_LAST_KEY; keyNum++)
{
if (!Key_IsValidGamePadChar(keyNum))
continue;
if (Game::playerKeys[0].keys[keyNum].binding && strcmp(Game::playerKeys[0].keys[keyNum].binding, cmd) == 0)
if (Game::playerKeys[0].keys[keyNum].binding && strcmp(Game::playerKeys[0].keys[keyNum].binding, gamePadCmd) == 0)
{
(*keys)[keyCount++] = keyNum;
@ -1818,6 +1824,35 @@ namespace Components
return keyCount;
}
void __declspec(naked) Gamepad::Key_GetCommandAssignmentInternal_Stub()
{
__asm
{
push eax
pushad
push [esp + 0x20 + 0x4 + 0x8] // keyNums
push [esp + 0x20 + 0x4 + 0x8] // command
push eax // localClientNum
call Key_GetCommandAssignmentInternal
add esp, 0xC
mov[esp + 0x20], eax
popad
pop eax
ret
}
}
void Gamepad::Key_SetBinding_Hk(const int localClientNum, const int keyNum, const char* binding)
{
if(Key_IsValidGamePadChar(keyNum))
gpad_buttonConfig.set("custom");
Game::Key_SetBinding(localClientNum, keyNum, binding);
}
void Gamepad::CL_KeyEvent_Hk(const int localClientNum, const int key, const int down, const unsigned time)
{
// A keyboard key has been pressed. Mark controller as unused.
@ -1833,13 +1868,18 @@ namespace Components
return gamePads[0].inUse;
}
int Gamepad::CL_MouseEvent_Hk(const int x, const int y, const int dx, const int dy)
void Gamepad::OnMouseMove([[maybe_unused]] const int x, [[maybe_unused]] const int y, const int dx, const int dy)
{
if (dx != 0 || dy != 0)
{
gamePads[0].inUse = false;
gpad_in_use.setRaw(false);
}
}
int Gamepad::CL_MouseEvent_Hk(const int x, const int y, const int dx, const int dy)
{
OnMouseMove(x, y, dx, dy);
// Call original function
return Utils::Hook::Call<int(int, int, int, int)>(0x4D7C50)(x, y, dx, dy);
@ -1949,7 +1989,12 @@ namespace Components
Utils::Hook(0x48E527, UI_RefreshViewport_Hk, HOOK_CALL).install()->quick();
// Only return gamepad keys when gamepad enabled and only non gamepad keys when not
Utils::Hook(0x5A7A23, Key_GetCommandAssignmentInternal_Hk, HOOK_CALL).install()->quick();
Utils::Hook(0x5A7890, Key_GetCommandAssignmentInternal_Stub, HOOK_JUMP).install()->quick();
// Whenever a key binding for a gamepad key is replaced update the button config
Utils::Hook(0x47D473, Key_SetBinding_Hk, HOOK_CALL).install()->quick();
Utils::Hook(0x47D485, Key_SetBinding_Hk, HOOK_CALL).install()->quick();
Utils::Hook(0x47D49D, Key_SetBinding_Hk, HOOK_CALL).install()->quick();
// Add gamepad inputs to remote control (eg predator) handling
Utils::Hook(0x5A6D4E, CL_RemoteControlMove_Stub, HOOK_CALL).install()->quick();

View File

@ -41,6 +41,8 @@ namespace Components
public:
Gamepad();
static void OnMouseMove(int x, int y, int dx, int dy);
private:
static Game::ButtonToCodeMap_t buttonList[];
static Game::StickToCodeMap_t analogStickList[4];
@ -190,7 +192,9 @@ namespace Components
static void CG_RegisterDvars_Hk();
static const char* GetGamePadCommand(const char* command);
static int Key_GetCommandAssignmentInternal_Hk(const char* cmd, int(*keys)[2]);
static int Key_GetCommandAssignmentInternal(int localClientNum, const char* cmd, int (*keys)[2]);
static void Key_GetCommandAssignmentInternal_Stub();
static void Key_SetBinding_Hk(int localClientNum, int keyNum, const char* binding);
static bool IsGamePadInUse();
static void CL_KeyEvent_Hk(int localClientNum, int key, int down, unsigned int time);
static int CL_MouseEvent_Hk(int x, int y, int dx, int dy);

View File

@ -97,6 +97,7 @@ namespace Components
Game::s_wmv->oldPos = curPos;
ScreenToClient(Window::GetWindow(), &curPos);
Gamepad::OnMouseMove(curPos.x, curPos.y, dx, dy);
auto recenterMouse = Game::CL_MouseEvent(curPos.x, curPos.y, dx, dy);
if (recenterMouse)

View File

@ -431,7 +431,7 @@ namespace Components
{
std::memmove(&Game::scrVmPub->top[-4], &Game::scrVmPub->top[-5], sizeof(Game::VariableValue) * 6);
Game::scrVmPub->top += 1;
Game::scrVmPub->top[-6].type = Game::VAR_FLOAT;
Game::scrVmPub->top[-6].type = Game::scrParamType_t::VAR_FLOAT;
Game::scrVmPub->top[-6].u.floatValue = 0.0f;
++Game::scrVmPub->outparamcount;
@ -450,7 +450,7 @@ namespace Components
const auto value = &Game::scrVmPub->top[-index];
if (value->type != Game::VAR_FUNCTION)
if (value->type != Game::scrParamType_t::VAR_FUNCTION)
{
Game::Scr_ParamError(static_cast<unsigned int>(index), "^1GetCodePosForParam: Expects a function as parameter!\n");
return "";
@ -549,7 +549,7 @@ namespace Components
void Script::AddFunctions()
{
Script::AddFunction("ReplaceFunc", []() // gsc: ReplaceFunc(<function>, <function>)
Script::AddFunction("ReplaceFunc", [] // gsc: ReplaceFunc(<function>, <function>)
{
if (Game::Scr_GetNumParam() != 2u)
{
@ -564,15 +564,7 @@ namespace Components
});
// System time
Script::AddFunction("GetSystemTime", []() // gsc: GetSystemTime()
{
SYSTEMTIME time;
GetSystemTime(&time);
Game::Scr_AddInt(time.wSecond);
});
Script::AddFunction("GetSystemMilliseconds", []() // gsc: GetSystemMilliseconds()
Script::AddFunction("GetSystemMilliseconds", [] // gsc: GetSystemMilliseconds()
{
SYSTEMTIME time;
GetSystemTime(&time);
@ -581,7 +573,7 @@ namespace Components
});
// Executes command to the console
Script::AddFunction("Exec", []() // gsc: Exec(<string>)
Script::AddFunction("Exec", [] // gsc: Exec(<string>)
{
const auto str = Game::Scr_GetString(0);
@ -595,7 +587,7 @@ namespace Components
});
// Allow printing to the console even when developer is 0
Script::AddFunction("PrintConsole", []() // gsc: PrintConsole(<string>)
Script::AddFunction("PrintConsole", [] // gsc: PrintConsole(<string>)
{
for (auto i = 0u; i < Game::Scr_GetNumParam(); i++)
{
@ -612,7 +604,7 @@ namespace Components
});
// Script Storage Functions
Script::AddFunction("StorageSet", []() // gsc: StorageSet(<str key>, <str data>);
Script::AddFunction("StorageSet", [] // gsc: StorageSet(<str key>, <str data>);
{
const auto* key = Game::Scr_GetString(0);
const auto* value = Game::Scr_GetString(1);
@ -626,7 +618,7 @@ namespace Components
Script::ScriptStorage.insert_or_assign(key, value);
});
Script::AddFunction("StorageRemove", []() // gsc: StorageRemove(<str key>);
Script::AddFunction("StorageRemove", [] // gsc: StorageRemove(<str key>);
{
const auto* key = Game::Scr_GetString(0);
@ -645,7 +637,7 @@ namespace Components
Script::ScriptStorage.erase(key);
});
Script::AddFunction("StorageGet", []() // gsc: StorageGet(<str key>);
Script::AddFunction("StorageGet", [] // gsc: StorageGet(<str key>);
{
const auto* key = Game::Scr_GetString(0);
@ -665,7 +657,7 @@ namespace Components
Game::Scr_AddString(data.data());
});
Script::AddFunction("StorageHas", []() // gsc: StorageHas(<str key>);
Script::AddFunction("StorageHas", [] // gsc: StorageHas(<str key>);
{
const auto* key = Game::Scr_GetString(0);
@ -678,7 +670,7 @@ namespace Components
Game::Scr_AddBool(static_cast<int>(Script::ScriptStorage.count(key))); // Until C++17
});
Script::AddFunction("StorageClear", []() // gsc: StorageClear();
Script::AddFunction("StorageClear", [] // gsc: StorageClear();
{
Script::ScriptStorage.clear();
});
@ -746,7 +738,7 @@ namespace Components
});
#ifdef _DEBUG
Script::AddFunction("DebugBox", []()
Script::AddFunction("DebugBox", []
{
const auto* message = Game::Scr_GetString(0);

View File

@ -116,7 +116,7 @@ namespace Components
void ScriptExtension::AddFunctions()
{
// File functions
Script::AddFunction("FileWrite", []() // gsc: FileWrite(<filepath>, <string>, <mode>)
Script::AddFunction("FileWrite", [] // gsc: FileWrite(<filepath>, <string>, <mode>)
{
const auto* path = Game::Scr_GetString(0);
auto* text = Game::Scr_GetString(1);
@ -159,7 +159,7 @@ namespace Components
}
});
Script::AddFunction("FileRead", []() // gsc: FileRead(<filepath>)
Script::AddFunction("FileRead", [] // gsc: FileRead(<filepath>)
{
const auto* path = Game::Scr_GetString(0);
@ -187,7 +187,7 @@ namespace Components
Game::Scr_AddString(FileSystem::FileReader(path).getBuffer().data());
});
Script::AddFunction("FileExists", []() // gsc: FileExists(<filepath>)
Script::AddFunction("FileExists", [] // gsc: FileExists(<filepath>)
{
const auto* path = Game::Scr_GetString(0);
@ -209,7 +209,7 @@ namespace Components
Game::Scr_AddInt(FileSystem::FileReader(path).exists());
});
Script::AddFunction("FileRemove", []() // gsc: FileRemove(<filepath>)
Script::AddFunction("FileRemove", [] // gsc: FileRemove(<filepath>)
{
const auto* path = Game::Scr_GetString(0);
@ -235,7 +235,7 @@ namespace Components
});
// Misc functions
Script::AddFunction("ToUpper", []() // gsc: ToUpper(<string>)
Script::AddFunction("ToUpper", [] // gsc: ToUpper(<string>)
{
const auto scriptValue = Game::Scr_GetConstString(0);
const auto* string = Game::SL_ConvertToString(scriptValue);
@ -280,7 +280,7 @@ namespace Components
});
// Func present on IW5
Script::AddFunction("StrICmp", []() // gsc: StrICmp(<string>, <string>)
Script::AddFunction("StrICmp", [] // gsc: StrICmp(<string>, <string>)
{
const auto value1 = Game::Scr_GetConstString(0);
const auto value2 = Game::Scr_GetConstString(1);
@ -292,7 +292,7 @@ namespace Components
});
// Func present on IW5
Script::AddFunction("IsEndStr", []() // gsc: IsEndStr(<string>, <string>)
Script::AddFunction("IsEndStr", [] // gsc: IsEndStr(<string>, <string>)
{
const auto* s1 = Game::Scr_GetString(0);
const auto* s2 = Game::Scr_GetString(1);
@ -305,6 +305,26 @@ namespace Components
Game::Scr_AddBool(Utils::String::EndsWith(s1, s2));
});
Script::AddFunction("IsArray", [] // gsc: IsArray(<object>)
{
const auto type = Game::Scr_GetType(0);
bool result;
if (type == Game::scrParamType_t::VAR_POINTER)
{
const auto ptr_type = Game::Scr_GetPointerType(0);
assert(ptr_type >= Game::FIRST_OBJECT);
result = (ptr_type == Game::scrParamType_t::VAR_ARRAY);
}
else
{
assert(type < Game::FIRST_OBJECT);
result = false;
}
Game::Scr_AddBool(result);
});
}
void ScriptExtension::AddMethods()

View File

@ -171,6 +171,7 @@ namespace Game
Key_SetCatcher_t Key_SetCatcher = Key_SetCatcher_t(0x43BD00);
Key_RemoveCatcher_t Key_RemoveCatcher = Key_RemoveCatcher_t(0x408260);
Key_IsKeyCatcherActive_t Key_IsKeyCatcherActive = Key_IsKeyCatcherActive_t(0x4DA010);
Key_SetBinding_t Key_SetBinding = Key_SetBinding_t(0x494C90);
LargeLocalInit_t LargeLocalInit = LargeLocalInit_t(0x4A62A0);
@ -293,6 +294,7 @@ namespace Game
Scr_ParamError_t Scr_ParamError = Scr_ParamError_t(0x4FBC70);
Scr_GetType_t Scr_GetType = Scr_GetType_t(0x422900);
Scr_GetPointerType_t Scr_GetPointerType = Scr_GetPointerType_t(0x4828E0);
Scr_ClearOutParams_t Scr_ClearOutParams = Scr_ClearOutParams_t(0x4386E0);
@ -545,12 +547,12 @@ namespace Game
XModel** cached_models = reinterpret_cast<XModel**>(0x1AA20C8);
vec3_t* CorrectSolidDeltas = reinterpret_cast<vec3_t*>(0x739BB8); // Count 26
FastCriticalSection* db_hashCritSect = reinterpret_cast<FastCriticalSection*>(0x16B8A54);
ScreenPlacement* scrPlaceFullUnsafe = reinterpret_cast<ScreenPlacement*>(0x1084460);
float (*CorrectSolidDeltas)[26][3] = reinterpret_cast<float(*)[26][3]>(0x739BB8); // Count 26
level_locals_t* level = reinterpret_cast<level_locals_t*>(0x1A831A8);
float (*penetrationDepthTable)[PENETRATE_TYPE_COUNT][SURF_TYPE_COUNT] = reinterpret_cast<float(*)[PENETRATE_TYPE_COUNT][SURF_TYPE_COUNT]>(0x7C4878);
@ -560,6 +562,8 @@ namespace Game
int* window_center_x = reinterpret_cast<int*>(0x649D638);
int* window_center_y = reinterpret_cast<int*>(0x649D630);
int* g_waitingForKey = reinterpret_cast<int*>(0x63A50FC);
void Sys_LockRead(FastCriticalSection* critSect)
{
InterlockedIncrement(&critSect->readCount);

View File

@ -420,6 +420,9 @@ namespace Game
typedef bool(__cdecl * Key_IsKeyCatcherActive_t)(int localClientNum, int catcher);
extern Key_IsKeyCatcherActive_t Key_IsKeyCatcherActive;
typedef void(__cdecl * Key_SetBinding_t)(int localClientNum, int keyNum, const char* binding);
extern Key_SetBinding_t Key_SetBinding;
typedef void(__cdecl * LargeLocalInit_t)();
extern LargeLocalInit_t LargeLocalInit;
@ -735,9 +738,12 @@ namespace Game
typedef bool(__cdecl * Scr_IsSystemActive_t)();
extern Scr_IsSystemActive_t Scr_IsSystemActive;
typedef int(__cdecl * Scr_GetType_t)(unsigned int);
typedef int(__cdecl * Scr_GetType_t)(unsigned int index);
extern Scr_GetType_t Scr_GetType;
typedef int(__cdecl * Scr_GetPointerType_t)(unsigned int index);
extern Scr_GetPointerType_t Scr_GetPointerType;
typedef void(__cdecl * Scr_Error_t)(const char*);
extern Scr_Error_t Scr_Error;
@ -999,10 +1005,10 @@ namespace Game
typedef void(__cdecl * Jump_ClearState_t)(playerState_s* ps);
extern Jump_ClearState_t Jump_ClearState;
typedef void(__cdecl * PM_playerTrace_t)(pmove_s*, trace_t*, const float*, const float*, const Bounds*, int, int);
typedef void(__cdecl * PM_playerTrace_t)(pmove_s* pm, trace_t* results, const float* start, const float* end, const Bounds* bounds, int passEntityNum, int contentMask);
extern PM_playerTrace_t PM_playerTrace;
typedef void(__cdecl * PM_Trace_t)(pmove_s*, trace_t*, const float*, const float*, const Bounds*, int, int);
typedef void(__cdecl * PM_Trace_t)(pmove_s* pm, trace_t* results, const float* start, const float* end, const Bounds* bounds, int passEntityNum, int contentMask);
extern PM_Trace_t PM_Trace;
typedef EffectiveStance(__cdecl * PM_GetEffectiveStance_t)(const playerState_s* ps);
@ -1145,7 +1151,7 @@ namespace Game
constexpr auto MAX_MODELS = 512;
extern XModel** cached_models;
extern vec3_t* CorrectSolidDeltas;
extern float (*CorrectSolidDeltas)[26][3];
extern FastCriticalSection* db_hashCritSect;
@ -1160,6 +1166,8 @@ namespace Game
extern int* window_center_x;
extern int* window_center_y;
extern int* g_waitingForKey;
void Sys_LockRead(FastCriticalSection* critSect);
void Sys_UnlockRead(FastCriticalSection* critSect);

View File

@ -234,7 +234,7 @@ namespace Game
CS_ACTIVE = 0x5,
} clientstate_t;
typedef enum
enum errorParm_t
{
ERR_FATAL = 0x0,
ERR_DROP = 0x1,
@ -244,7 +244,39 @@ namespace Game
ERR_SCRIPT_DROP = 0x5,
ERR_LOCALIZATION = 0x6,
ERR_MAPLOADERRORSUMMARY = 0x7
} errorParm_t;
};
enum conChannel_t
{
CON_CHANNEL_DONT_FILTER,
CON_CHANNEL_ERROR,
CON_CHANNEL_GAMENOTIFY,
CON_CHANNEL_BOLDGAME,
CON_CHANNEL_SUBTITLE,
CON_CHANNEL_OBITUARY,
CON_CHANNEL_LOGFILEONLY,
CON_CHANNEL_CONSOLEONLY,
CON_CHANNEL_GFX,
CON_CHANNEL_SOUND,
CON_CHANNEL_FILES,
CON_CHANNEL_DEVGUI,
CON_CHANNEL_PROFILE,
CON_CHANNEL_UI,
CON_CHANNEL_CLIENT,
CON_CHANNEL_SERVER,
CON_CHANNEL_SYSTEM,
CON_CHANNEL_PLAYERWEAP,
CON_CHANNEL_AI,
CON_CHANNEL_ANIM,
CON_CHANNEL_PHYS,
CON_CHANNEL_FX,
CON_CHANNEL_LEADERBOARDS,
CON_CHANNEL_PARSERSCRIPT,
CON_CHANNEL_SCRIPT,
CON_CHANNEL_NETWORK,
CON_BUILTIN_CHANNEL_COUNT,
};
enum entityFlag
{
@ -5096,7 +5128,7 @@ namespace Game
char buf[1];
};
enum VariableType
enum scrParamType_t
{
VAR_UNDEFINED = 0x0,
VAR_BEGIN_REF = 0x1,
@ -5114,21 +5146,30 @@ namespace Game
VAR_BUILTIN_METHOD = 0xB,
VAR_STACK = 0xC,
VAR_ANIMATION = 0xD,
VAR_PRE_ANIMATION = 0xE,
VAR_THREAD = 0xF,
VAR_NOTIFY_THREAD = 0x10,
VAR_TIME_THREAD = 0x11,
VAR_CHILD_THREAD = 0x12,
VAR_OBJECT = 0x13,
VAR_DEAD_ENTITY = 0x14,
VAR_ENTITY = 0x15,
VAR_ARRAY = 0x16,
VAR_DEAD_THREAD = 0x17,
VAR_COUNT = 0x18,
VAR_FREE = 0x18,
VAR_THREAD_LIST = 0x19,
VAR_ENDON_LIST = 0x1A,
VAR_TOTAL_COUNT = 0x1B,
VAR_DEVELOPER_CODEPOS = 0xE,
VAR_PRE_ANIMATION = 0xF,
VAR_THREAD = 0x10,
VAR_NOTIFY_THREAD = 0x11,
VAR_TIME_THREAD = 0x12,
VAR_CHILD_THREAD = 0x13,
VAR_OBJECT = 0x14,
VAR_DEAD_ENTITY = 0x15,
VAR_ENTITY = 0x16,
VAR_ARRAY = 0x17,
VAR_DEAD_THREAD = 0x18,
VAR_COUNT = 0x19,
VAR_THREAD_LIST = 0x1A,
VAR_ENDON_LIST = 0x1B,
};
enum $2441F0C7E439C64E6C27842ECB570A7C
{
FIRST_OBJECT = 0x10,
FIRST_CLEARABLE_OBJECT = 0x14,
LAST_NONENTITY_OBJECT = 0x14,
FIRST_ENTITY_OBJECT = 0x16,
FIRST_NONFIELD_OBJECT = 0x17,
FIRST_DEAD_OBJECT = 0x18,
};
union VariableUnion
@ -5147,7 +5188,7 @@ namespace Game
struct VariableValue
{
VariableUnion u;
VariableType type;
scrParamType_t type;
};
struct function_stack_t