2022-02-03 14:05:24 -05:00
|
|
|
#include <std_include.hpp>
|
|
|
|
#include "loader/component_loader.hpp"
|
|
|
|
#include "command.hpp"
|
|
|
|
#include "console.hpp"
|
|
|
|
#include "game_console.hpp"
|
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
#include "game/game.hpp"
|
2022-02-03 14:05:24 -05:00
|
|
|
|
|
|
|
#include <utils/hook.hpp>
|
|
|
|
#include <utils/string.hpp>
|
|
|
|
#include <utils/memory.hpp>
|
|
|
|
#include "utils/io.hpp"
|
2022-02-17 00:11:35 -05:00
|
|
|
#include <game/dvars.hpp>
|
2022-02-03 14:05:24 -05:00
|
|
|
|
|
|
|
namespace command
|
|
|
|
{
|
|
|
|
namespace
|
|
|
|
{
|
2022-02-04 16:17:56 -05:00
|
|
|
utils::hook::detour client_command_hook;
|
2022-02-03 14:05:24 -05:00
|
|
|
|
|
|
|
std::unordered_map<std::string, std::function<void(params&)>> handlers;
|
|
|
|
std::unordered_map<std::string, std::function<void(int, params_sv&)>> handlers_sv;
|
|
|
|
|
|
|
|
void main_handler()
|
|
|
|
{
|
|
|
|
params params = {};
|
|
|
|
|
|
|
|
const auto command = utils::string::to_lower(params[0]);
|
|
|
|
if (handlers.find(command) != handlers.end())
|
|
|
|
{
|
|
|
|
handlers[command](params);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void client_command(const int client_num, void* a2)
|
|
|
|
{
|
|
|
|
params_sv params = {};
|
|
|
|
|
|
|
|
const auto command = utils::string::to_lower(params[0]);
|
|
|
|
if (handlers_sv.find(command) != handlers_sv.end())
|
|
|
|
{
|
|
|
|
handlers_sv[command](client_num, params);
|
|
|
|
}
|
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
client_command_hook.invoke<void>(client_num, a2);
|
2022-02-03 14:05:24 -05:00
|
|
|
}
|
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
// Shamelessly stolen from Quake3
|
|
|
|
// https://github.com/id-Software/Quake-III-Arena/blob/dbe4ddb10315479fc00086f08e25d968b4b43c49/code/qcommon/common.c#L364
|
|
|
|
void parse_command_line()
|
2022-02-03 14:05:24 -05:00
|
|
|
{
|
2022-02-04 16:17:56 -05:00
|
|
|
static auto parsed = false;
|
|
|
|
if (parsed)
|
2022-02-03 14:05:24 -05:00
|
|
|
{
|
2022-02-04 16:17:56 -05:00
|
|
|
return;
|
2022-02-03 14:05:24 -05:00
|
|
|
}
|
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
static std::string comand_line_buffer = GetCommandLineA();
|
|
|
|
auto* command_line = comand_line_buffer.data();
|
|
|
|
|
|
|
|
auto& com_num_console_lines = *reinterpret_cast<int*>(0x142623FB4); //H1(1.4)
|
|
|
|
auto* com_console_lines = reinterpret_cast<char**>(0x142623FC0); //H1(1.4)
|
|
|
|
|
|
|
|
auto inq = false;
|
|
|
|
com_console_lines[0] = command_line;
|
|
|
|
com_num_console_lines = 0;
|
2022-02-03 14:05:24 -05:00
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
while (*command_line)
|
2022-02-03 14:05:24 -05:00
|
|
|
{
|
2022-02-04 16:17:56 -05:00
|
|
|
if (*command_line == '"')
|
2022-02-03 14:05:24 -05:00
|
|
|
{
|
2022-02-04 16:17:56 -05:00
|
|
|
inq = !inq;
|
|
|
|
}
|
|
|
|
// look for a + separating character
|
|
|
|
// if commandLine came from a file, we might have real line seperators
|
|
|
|
if ((*command_line == '+' && !inq) || *command_line == '\n' || *command_line == '\r')
|
|
|
|
{
|
|
|
|
if (com_num_console_lines == 0x20) // MAX_CONSOLE_LINES
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
com_console_lines[com_num_console_lines] = command_line + 1;
|
|
|
|
com_num_console_lines++;
|
|
|
|
*command_line = '\0';
|
|
|
|
}
|
|
|
|
command_line++;
|
|
|
|
}
|
|
|
|
parsed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void parse_commandline_stub()
|
|
|
|
{
|
|
|
|
parse_command_line();
|
|
|
|
reinterpret_cast<void(*)()>(0x1400D8210)(); // mwr: test
|
|
|
|
}
|
2022-02-26 15:36:29 -05:00
|
|
|
|
|
|
|
game::dvar_t* dvar_command_stub()
|
|
|
|
{
|
|
|
|
const params args;
|
|
|
|
|
|
|
|
if (args.size() <= 0)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto dvar = game::Dvar_FindVar(args[0]);
|
|
|
|
|
|
|
|
if (dvar)
|
|
|
|
{
|
|
|
|
if (args.size() == 1)
|
|
|
|
{
|
|
|
|
const auto current = game::Dvar_ValueToString(dvar, dvar->current);
|
|
|
|
const auto reset = game::Dvar_ValueToString(dvar, dvar->reset);
|
|
|
|
|
|
|
|
console::info("\"%s\" is: \"%s\" default: \"%s\" hash: 0x%08lX",
|
|
|
|
args[0], current, reset, dvar->hash);
|
|
|
|
|
|
|
|
console::info(" %s\n", dvars::dvar_get_domain(dvar->type, dvar->domain).data());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char command[0x1000] = { 0 };
|
|
|
|
game::Dvar_GetCombinedString(command, 1);
|
|
|
|
game::Dvar_SetCommand(dvar->hash, "", command);
|
|
|
|
}
|
|
|
|
|
|
|
|
return dvar;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2022-02-04 16:17:56 -05:00
|
|
|
}
|
2022-02-03 14:05:24 -05:00
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
void read_startup_variable(const std::string& dvar)
|
|
|
|
{
|
|
|
|
// parse the commandline if it's not parsed
|
|
|
|
parse_command_line();
|
2022-02-03 14:05:24 -05:00
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
auto& com_num_console_lines = *reinterpret_cast<int*>(0x142623FB4); //H1(1.4)
|
|
|
|
auto* com_console_lines = reinterpret_cast<char**>(0x142623FC0); //H1(1.4)
|
|
|
|
|
|
|
|
for (int i = 0; i < com_num_console_lines; i++)
|
|
|
|
{
|
|
|
|
game::Cmd_TokenizeString(com_console_lines[i]);
|
|
|
|
|
|
|
|
// only +set dvar value
|
|
|
|
if (game::Cmd_Argc() >= 3 && game::Cmd_Argv(0) == "set"s && game::Cmd_Argv(1) == dvar)
|
|
|
|
{
|
2022-02-26 15:36:29 -05:00
|
|
|
game::Dvar_SetCommand(game::generateHashValue(game::Cmd_Argv(1)), "", game::Cmd_Argv(2));
|
2022-02-03 14:05:24 -05:00
|
|
|
}
|
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
game::Cmd_EndTokenizeString();
|
2022-02-03 14:05:24 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
params::params()
|
|
|
|
: nesting_(game::cmd_args->nesting)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
int params::size() const
|
|
|
|
{
|
|
|
|
return game::cmd_args->argc[this->nesting_];
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* params::get(const int index) const
|
|
|
|
{
|
|
|
|
if (index >= this->size())
|
|
|
|
{
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
return game::cmd_args->argv[this->nesting_][index];
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string params::join(const int index) const
|
|
|
|
{
|
|
|
|
std::string result = {};
|
|
|
|
|
|
|
|
for (auto i = index; i < this->size(); i++)
|
|
|
|
{
|
|
|
|
if (i > index) result.append(" ");
|
|
|
|
result.append(this->get(i));
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
params_sv::params_sv()
|
|
|
|
: nesting_(game::sv_cmd_args->nesting)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
int params_sv::size() const
|
|
|
|
{
|
|
|
|
return game::sv_cmd_args->argc[this->nesting_];
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* params_sv::get(const int index) const
|
|
|
|
{
|
|
|
|
if (index >= this->size())
|
|
|
|
{
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
return game::sv_cmd_args->argv[this->nesting_][index];
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string params_sv::join(const int index) const
|
|
|
|
{
|
|
|
|
std::string result = {};
|
|
|
|
|
|
|
|
for (auto i = index; i < this->size(); i++)
|
|
|
|
{
|
|
|
|
if (i > index) result.append(" ");
|
|
|
|
result.append(this->get(i));
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void add_raw(const char* name, void (*callback)())
|
|
|
|
{
|
|
|
|
game::Cmd_AddCommandInternal(name, callback, utils::memory::get_allocator()->allocate<game::cmd_function_s>());
|
|
|
|
}
|
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
void add_test(const char* name, void (*callback)())
|
|
|
|
{
|
|
|
|
static game::cmd_function_s cmd_test;
|
|
|
|
return game::Cmd_AddCommandInternal(name, callback, &cmd_test);
|
|
|
|
}
|
|
|
|
|
2022-02-03 14:05:24 -05:00
|
|
|
void add(const char* name, const std::function<void(const params&)>& callback)
|
|
|
|
{
|
2022-02-04 16:17:56 -05:00
|
|
|
static game::cmd_function_s cmd_test;
|
|
|
|
|
2022-02-03 14:05:24 -05:00
|
|
|
const auto command = utils::string::to_lower(name);
|
|
|
|
|
|
|
|
if (handlers.find(command) == handlers.end())
|
|
|
|
add_raw(name, main_handler);
|
|
|
|
|
|
|
|
handlers[command] = callback;
|
|
|
|
}
|
|
|
|
|
|
|
|
void add(const char* name, const std::function<void()>& callback)
|
|
|
|
{
|
|
|
|
add(name, [callback](const params&)
|
|
|
|
{
|
|
|
|
callback();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void add_sv(const char* name, std::function<void(int, const params_sv&)> callback)
|
|
|
|
{
|
|
|
|
// doing this so the sv command would show up in the console
|
|
|
|
add_raw(name, nullptr);
|
|
|
|
|
|
|
|
const auto command = utils::string::to_lower(name);
|
|
|
|
|
|
|
|
if (handlers_sv.find(command) == handlers_sv.end())
|
|
|
|
handlers_sv[command] = std::move(callback);
|
|
|
|
}
|
|
|
|
|
|
|
|
void execute(std::string command, const bool sync)
|
|
|
|
{
|
|
|
|
command += "\n";
|
|
|
|
|
|
|
|
if (sync)
|
|
|
|
{
|
|
|
|
game::Cmd_ExecuteSingleCommand(0, 0, command.data());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game::Cbuf_AddText(0, command.data());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
class component final : public component_interface
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
void post_unpack() override
|
2022-02-03 14:05:24 -05:00
|
|
|
{
|
2022-02-04 16:17:56 -05:00
|
|
|
if (game::environment::is_sp())
|
2022-02-03 14:05:24 -05:00
|
|
|
{
|
2022-02-04 16:17:56 -05:00
|
|
|
add_commands_sp();
|
2022-02-03 14:05:24 -05:00
|
|
|
}
|
2022-02-04 16:17:56 -05:00
|
|
|
else
|
2022-02-03 14:05:24 -05:00
|
|
|
{
|
2022-02-04 16:17:56 -05:00
|
|
|
utils::hook::call(0x1400D728F, &parse_commandline_stub); // MWR TEST
|
2022-02-26 15:36:29 -05:00
|
|
|
utils::hook::jump(0x14041D750, dvar_command_stub);
|
2022-02-04 16:17:56 -05:00
|
|
|
|
|
|
|
add_commands_mp();
|
2022-02-03 14:05:24 -05:00
|
|
|
}
|
2022-02-23 15:23:00 -05:00
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
add_commands_generic();
|
2022-02-03 14:05:24 -05:00
|
|
|
}
|
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
private:
|
|
|
|
static void add_commands_generic()
|
|
|
|
{
|
2022-02-26 16:09:23 -05:00
|
|
|
add("quit", game::Quit);
|
2022-02-11 22:21:53 -05:00
|
|
|
//add("quit_hard", utils::nt::raise_hard_exception); /* this command delivers you to a windows blue screen, its quit hard from windows xD */
|
2022-02-04 16:17:56 -05:00
|
|
|
add("crash", []()
|
2022-02-23 15:23:00 -05:00
|
|
|
{
|
|
|
|
*reinterpret_cast<int*>(1) = 0;
|
|
|
|
});
|
2022-02-03 14:05:24 -05:00
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
/*add("consoleList", [](const params& params)
|
|
|
|
{
|
|
|
|
const std::string input = params.get(1);
|
2022-02-03 14:05:24 -05:00
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
std::vector<std::string> matches;
|
|
|
|
game_console::find_matches(input, matches, false);
|
2022-02-03 14:05:24 -05:00
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
for (auto& match : matches)
|
|
|
|
{
|
|
|
|
auto* dvar = game::Dvar_FindVar(match.c_str());
|
|
|
|
if (!dvar)
|
|
|
|
{
|
|
|
|
console::info("[CMD]\t %s\n", match.c_str());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
console::info("[DVAR]\t%s \"%s\"\n", match.c_str(), game::Dvar_ValueToString(dvar, dvar->current, 0));
|
|
|
|
}
|
|
|
|
}
|
2022-02-03 14:05:24 -05:00
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
console::info("Total %i matches\n", matches.size());
|
2022-02-11 22:21:53 -05:00
|
|
|
});*/
|
2022-02-03 14:05:24 -05:00
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
add("commandDump", [](const params& argument)
|
2022-02-23 15:23:00 -05:00
|
|
|
{
|
|
|
|
console::info("================================ COMMAND DUMP =====================================\n");
|
|
|
|
game::cmd_function_s* cmd = (*game::cmd_functions);
|
|
|
|
std::string filename;
|
|
|
|
if (argument.size() == 2)
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
2022-02-23 15:23:00 -05:00
|
|
|
filename = "h1-mod/";
|
|
|
|
filename.append(argument[1]);
|
|
|
|
if (!filename.ends_with(".txt"))
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
2022-02-23 15:23:00 -05:00
|
|
|
filename.append(".txt");
|
2022-02-04 16:17:56 -05:00
|
|
|
}
|
2022-02-23 15:23:00 -05:00
|
|
|
}
|
|
|
|
int i = 0;
|
|
|
|
while (cmd)
|
|
|
|
{
|
|
|
|
if (cmd->name)
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
2022-02-23 15:23:00 -05:00
|
|
|
if (!filename.empty())
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
2022-02-23 15:23:00 -05:00
|
|
|
const auto line = std::format("{}\r\n", cmd->name);
|
|
|
|
utils::io::write_file(filename, line, i != 0);
|
2022-02-04 16:17:56 -05:00
|
|
|
}
|
2022-02-23 15:23:00 -05:00
|
|
|
console::info("%s\n", cmd->name);
|
|
|
|
i++;
|
2022-02-04 16:17:56 -05:00
|
|
|
}
|
2022-02-23 15:23:00 -05:00
|
|
|
cmd = cmd->next;
|
|
|
|
}
|
|
|
|
console::info("\n%i commands\n", i);
|
|
|
|
console::info("================================ END COMMAND DUMP =================================\n");
|
|
|
|
});
|
2022-02-17 00:11:35 -05:00
|
|
|
|
2022-02-23 15:23:00 -05:00
|
|
|
/*add("listassetpool", [](const params& params)
|
|
|
|
{
|
|
|
|
if (params.size() < 2)
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
2022-02-23 15:23:00 -05:00
|
|
|
console::info("listassetpool <poolnumber> [filter]: list all the assets in the specified pool\n");
|
|
|
|
|
|
|
|
for (auto i = 0; i < game::XAssetType::ASSET_TYPE_COUNT; i++)
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
2022-02-23 15:23:00 -05:00
|
|
|
console::info("%d %s\n", i, game::g_assetNames[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const auto type = static_cast<game::XAssetType>(atoi(params.get(1)));
|
2022-02-04 16:17:56 -05:00
|
|
|
|
2022-02-23 15:23:00 -05:00
|
|
|
if (type < 0 || type >= game::XAssetType::ASSET_TYPE_COUNT)
|
|
|
|
{
|
|
|
|
console::error("Invalid pool passed must be between [%d, %d]\n", 0, game::XAssetType::ASSET_TYPE_COUNT - 1);
|
|
|
|
return;
|
2022-02-04 16:17:56 -05:00
|
|
|
}
|
2022-02-23 15:23:00 -05:00
|
|
|
|
|
|
|
console::info("Listing assets in pool %s\n", game::g_assetNames[type]);
|
|
|
|
|
|
|
|
const std::string filter = params.get(2);
|
|
|
|
enum_assets(type, [type, filter](const game::XAssetHeader header)
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
2022-02-23 15:23:00 -05:00
|
|
|
const auto asset = game::XAsset{type, header};
|
|
|
|
const auto* const asset_name = game::DB_GetXAssetName(&asset);
|
|
|
|
//const auto entry = game::DB_FindXAssetEntry(type, asset_name);
|
|
|
|
//TODO: display which zone the asset is from
|
2022-02-04 16:17:56 -05:00
|
|
|
|
2022-02-23 15:23:00 -05:00
|
|
|
if (!filter.empty() && !game_console::match_compare(filter, asset_name, false))
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-02-23 15:23:00 -05:00
|
|
|
console::info("%s\n", asset_name);
|
|
|
|
}, true);
|
|
|
|
}
|
|
|
|
});
|
2022-02-04 16:17:56 -05:00
|
|
|
|
|
|
|
add("vstr", [](const params& params)
|
2022-02-23 15:23:00 -05:00
|
|
|
{
|
|
|
|
if (params.size() < 2)
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
2022-02-23 15:23:00 -05:00
|
|
|
console::info("vstr <variablename> : execute a variable command\n");
|
|
|
|
return;
|
|
|
|
}
|
2022-02-04 16:17:56 -05:00
|
|
|
|
2022-02-23 15:23:00 -05:00
|
|
|
const auto* dvarName = params.get(1);
|
|
|
|
const auto* dvar = game::Dvar_FindVar(dvarName);
|
2022-02-04 16:17:56 -05:00
|
|
|
|
2022-02-23 15:23:00 -05:00
|
|
|
if (dvar == nullptr)
|
|
|
|
{
|
|
|
|
console::info("%s doesn't exist\n", dvarName);
|
|
|
|
return;
|
|
|
|
}
|
2022-02-04 16:17:56 -05:00
|
|
|
|
2022-02-23 15:23:00 -05:00
|
|
|
if (dvar->type != game::dvar_type::string
|
|
|
|
&& dvar->type != game::dvar_type::enumeration)
|
|
|
|
{
|
|
|
|
console::info("%s is not a string-based dvar\n", dvar->hash);
|
|
|
|
return;
|
|
|
|
}
|
2022-02-04 16:17:56 -05:00
|
|
|
|
2022-02-23 15:23:00 -05:00
|
|
|
execute(dvar->current.string);
|
|
|
|
});*/
|
2022-02-03 14:05:24 -05:00
|
|
|
}
|
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
static void add_commands_sp()
|
2022-02-03 14:05:24 -05:00
|
|
|
{
|
2022-02-04 16:17:56 -05:00
|
|
|
add("god", []()
|
2022-02-23 15:23:00 -05:00
|
|
|
{
|
|
|
|
if (!game::SV_Loaded())
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
2022-02-23 15:23:00 -05:00
|
|
|
return;
|
|
|
|
}
|
2022-02-03 14:05:24 -05:00
|
|
|
|
2022-02-23 15:23:00 -05:00
|
|
|
game::sp::g_entities[0].flags ^= 1;
|
|
|
|
game::CG_GameMessage(0, utils::string::va("godmode %s",
|
|
|
|
game::sp::g_entities[0].flags & 1
|
|
|
|
? "^2on"
|
|
|
|
: "^1off"));
|
|
|
|
});
|
2022-02-03 14:05:24 -05:00
|
|
|
|
2022-02-11 22:21:53 -05:00
|
|
|
add("demigod", []()
|
2022-02-23 15:23:00 -05:00
|
|
|
{
|
|
|
|
if (!game::SV_Loaded())
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
2022-02-23 15:23:00 -05:00
|
|
|
return;
|
|
|
|
}
|
2022-02-03 14:05:24 -05:00
|
|
|
|
2022-02-23 15:23:00 -05:00
|
|
|
game::sp::g_entities[0].flags ^= 2;
|
|
|
|
game::CG_GameMessage(0, utils::string::va("demigod mode %s",
|
|
|
|
game::sp::g_entities[0].flags & 2
|
|
|
|
? "^2on"
|
|
|
|
: "^1off"));
|
|
|
|
});
|
2022-02-03 14:05:24 -05:00
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
add("notarget", []()
|
2022-02-23 15:23:00 -05:00
|
|
|
{
|
|
|
|
if (!game::SV_Loaded())
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
2022-02-23 15:23:00 -05:00
|
|
|
return;
|
|
|
|
}
|
2022-02-03 14:05:24 -05:00
|
|
|
|
2022-02-23 15:23:00 -05:00
|
|
|
game::sp::g_entities[0].flags ^= 4;
|
|
|
|
game::CG_GameMessage(0, utils::string::va("notarget %s",
|
|
|
|
game::sp::g_entities[0].flags & 4
|
|
|
|
? "^2on"
|
|
|
|
: "^1off"));
|
|
|
|
});
|
2022-02-03 14:05:24 -05:00
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
add("noclip", []()
|
2022-02-23 15:23:00 -05:00
|
|
|
{
|
|
|
|
if (!game::SV_Loaded())
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
2022-02-23 15:23:00 -05:00
|
|
|
return;
|
|
|
|
}
|
2022-02-03 14:05:24 -05:00
|
|
|
|
2022-02-23 15:23:00 -05:00
|
|
|
game::sp::g_entities[0].client->flags ^= 1;
|
|
|
|
game::CG_GameMessage(0, utils::string::va("noclip %s",
|
|
|
|
game::sp::g_entities[0].client->flags & 1
|
|
|
|
? "^2on"
|
|
|
|
: "^1off"));
|
|
|
|
});
|
2022-02-03 14:05:24 -05:00
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
add("ufo", []()
|
2022-02-23 15:23:00 -05:00
|
|
|
{
|
|
|
|
if (!game::SV_Loaded())
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
2022-02-23 15:23:00 -05:00
|
|
|
return;
|
|
|
|
}
|
2022-02-04 16:17:56 -05:00
|
|
|
|
2022-02-26 20:16:38 -05:00
|
|
|
game::sp::g_entities[0].client->flags ^= 2;
|
|
|
|
game::CG_GameMessage(0, utils::string::va("ufo %s",
|
|
|
|
game::sp::g_entities[0].client->flags & 2
|
|
|
|
? "^2on"
|
|
|
|
: "^1off"));
|
2022-02-23 15:23:00 -05:00
|
|
|
});
|
2022-02-04 16:17:56 -05:00
|
|
|
}
|
2022-02-03 14:05:24 -05:00
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
static void add_commands_mp()
|
|
|
|
{
|
|
|
|
//client_command_hook.create(0x1402E98F0, &client_command);
|
2022-02-03 14:05:24 -05:00
|
|
|
|
2022-02-04 16:17:56 -05:00
|
|
|
/*add_sv("god", [](const int client_num, const params_sv&)
|
2022-02-23 15:23:00 -05:00
|
|
|
{
|
|
|
|
if (!game::Dvar_FindVar("sv_cheats")->current.enabled)
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
|
|
|
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
2022-02-23 15:23:00 -05:00
|
|
|
"f \"Cheats are not enabled on this server\"");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
game::mp::g_entities[client_num].flags ^= 1;
|
|
|
|
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
|
|
|
utils::string::va("f \"godmode %s\"",
|
|
|
|
game::mp::g_entities[client_num].flags & 1
|
|
|
|
? "^2on"
|
|
|
|
: "^1off"));
|
|
|
|
});
|
2022-02-04 16:17:56 -05:00
|
|
|
|
|
|
|
add_sv("demigod", [](const int client_num, const params_sv&)
|
2022-02-23 15:23:00 -05:00
|
|
|
{
|
|
|
|
if (!game::Dvar_FindVar("sv_cheats")->current.enabled)
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
|
|
|
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
2022-02-23 15:23:00 -05:00
|
|
|
"f \"Cheats are not enabled on this server\"");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
game::mp::g_entities[client_num].flags ^= 2;
|
|
|
|
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
|
|
|
utils::string::va("f \"demigod mode %s\"",
|
|
|
|
game::mp::g_entities[client_num].flags & 2
|
|
|
|
? "^2on"
|
|
|
|
: "^1off"));
|
|
|
|
});
|
2022-02-04 16:17:56 -05:00
|
|
|
|
|
|
|
add_sv("notarget", [](const int client_num, const params_sv&)
|
2022-02-23 15:23:00 -05:00
|
|
|
{
|
|
|
|
if (!game::Dvar_FindVar("sv_cheats")->current.enabled)
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
|
|
|
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
2022-02-23 15:23:00 -05:00
|
|
|
"f \"Cheats are not enabled on this server\"");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
game::mp::g_entities[client_num].flags ^= 4;
|
|
|
|
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
|
|
|
utils::string::va("f \"notarget %s\"",
|
|
|
|
game::mp::g_entities[client_num].flags & 4
|
|
|
|
? "^2on"
|
|
|
|
: "^1off"));
|
|
|
|
});
|
2022-02-04 16:17:56 -05:00
|
|
|
|
|
|
|
add_sv("noclip", [](const int client_num, const params_sv&)
|
2022-02-23 15:23:00 -05:00
|
|
|
{
|
|
|
|
if (!game::Dvar_FindVar("sv_cheats")->current.enabled)
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
|
|
|
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
2022-02-23 15:23:00 -05:00
|
|
|
"f \"Cheats are not enabled on this server\"");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
game::mp::g_entities[client_num].client->flags ^= 1;
|
|
|
|
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
|
|
|
utils::string::va("f \"noclip %s\"",
|
|
|
|
game::mp::g_entities[client_num].client->flags & 1
|
|
|
|
? "^2on"
|
|
|
|
: "^1off"));
|
|
|
|
});
|
2022-02-04 16:17:56 -05:00
|
|
|
|
|
|
|
add_sv("ufo", [](const int client_num, const params_sv&)
|
2022-02-23 15:23:00 -05:00
|
|
|
{
|
|
|
|
if (!game::Dvar_FindVar("sv_cheats")->current.enabled)
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
|
|
|
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
2022-02-23 15:23:00 -05:00
|
|
|
"f \"Cheats are not enabled on this server\"");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
game::mp::g_entities[client_num].client->flags ^= 2;
|
|
|
|
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
|
|
|
utils::string::va("f \"ufo %s\"",
|
|
|
|
game::mp::g_entities[client_num].client->flags & 2
|
|
|
|
? "^2on"
|
|
|
|
: "^1off"));
|
|
|
|
});
|
2022-02-04 16:17:56 -05:00
|
|
|
|
|
|
|
add_sv("give", [](const int client_num, const params_sv& params)
|
2022-02-23 15:23:00 -05:00
|
|
|
{
|
|
|
|
if (!game::Dvar_FindVar("sv_cheats")->current.enabled)
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
2022-02-23 15:23:00 -05:00
|
|
|
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
|
|
|
"f \"Cheats are not enabled on this server\"");
|
|
|
|
return;
|
|
|
|
}
|
2022-02-04 16:17:56 -05:00
|
|
|
|
2022-02-23 15:23:00 -05:00
|
|
|
if (params.size() < 2)
|
|
|
|
{
|
|
|
|
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
|
|
|
"f \"You did not specify a weapon name\"");
|
|
|
|
return;
|
|
|
|
}
|
2022-02-04 16:17:56 -05:00
|
|
|
|
2022-02-23 15:23:00 -05:00
|
|
|
auto ps = game::SV_GetPlayerstateForClientNum(client_num);
|
|
|
|
const auto wp = game::G_GetWeaponForName(params.get(1));
|
|
|
|
if (wp)
|
|
|
|
{
|
|
|
|
if (game::G_GivePlayerWeapon(ps, wp, 0, 0, 0, 0, 0, 0))
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
2022-02-23 15:23:00 -05:00
|
|
|
game::G_InitializeAmmo(ps, wp, 0);
|
|
|
|
game::G_SelectWeapon(client_num, wp);
|
2022-02-04 16:17:56 -05:00
|
|
|
}
|
2022-02-23 15:23:00 -05:00
|
|
|
}
|
|
|
|
});
|
2022-02-04 16:17:56 -05:00
|
|
|
|
|
|
|
add_sv("take", [](const int client_num, const params_sv& params)
|
2022-02-23 15:23:00 -05:00
|
|
|
{
|
|
|
|
if (!game::Dvar_FindVar("sv_cheats")->current.enabled)
|
2022-02-04 16:17:56 -05:00
|
|
|
{
|
2022-02-23 15:23:00 -05:00
|
|
|
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
|
|
|
"f \"Cheats are not enabled on this server\"");
|
|
|
|
return;
|
|
|
|
}
|
2022-02-04 16:17:56 -05:00
|
|
|
|
2022-02-23 15:23:00 -05:00
|
|
|
if (params.size() < 2)
|
|
|
|
{
|
|
|
|
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
|
|
|
"f \"You did not specify a weapon name\"");
|
|
|
|
return;
|
|
|
|
}
|
2022-02-04 16:17:56 -05:00
|
|
|
|
2022-02-23 15:23:00 -05:00
|
|
|
auto ps = game::SV_GetPlayerstateForClientNum(client_num);
|
|
|
|
const auto wp = game::G_GetWeaponForName(params.get(1));
|
|
|
|
if (wp)
|
|
|
|
{
|
|
|
|
game::G_TakePlayerWeapon(ps, wp);
|
|
|
|
}
|
|
|
|
});*/
|
2022-02-03 14:05:24 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-02-23 15:23:00 -05:00
|
|
|
REGISTER_COMPONENT(command::component)
|