diff --git a/data/cdata/scripts/mp/team_balance.gsc b/data/cdata/scripts/mp/team_balance.gsc new file mode 100644 index 00000000..759aceb2 --- /dev/null +++ b/data/cdata/scripts/mp/team_balance.gsc @@ -0,0 +1,27 @@ +init() +{ + // define the auto balance string in the game array (referenced in gsc dump, but not defined past IW6?) + precachestring(&"MP_AUTOBALANCE_NOW"); + game["strings"]["autobalance"] = &"MP_AUTOBALANCE_NOW"; + + // define onteamselection callback function used in balanceteams() + level.onteamselection = ::set_team; +} + +set_team(team) +{ + if (team != self.pers["team"]) + { + self.switching_teams = true; + self.joining_team = team; + self.leaving_team = self.pers["team"]; + } + + if (self.sessionstate == "playing") + { + self suicide(); + } + + maps\mp\gametypes\_menus::addtoteam(team); + maps\mp\gametypes\_menus::endrespawnnotify(); +} diff --git a/src/client/component/gsc/script_extension.cpp b/src/client/component/gsc/script_extension.cpp index cb164a72..56682adf 100644 --- a/src/client/component/gsc/script_extension.cpp +++ b/src/client/component/gsc/script_extension.cpp @@ -33,11 +33,6 @@ namespace gsc namespace { - struct gsc_error : public std::runtime_error - { - using std::runtime_error::runtime_error; - }; - std::unordered_map functions; std::unordered_map methods; @@ -134,9 +129,8 @@ namespace gsc void vm_call_builtin_function_stub(builtin_function function) { const auto function_id = get_function_id(); - const auto is_custom_function = functions.find(function_id) != functions.end(); - if (!is_custom_function) + if (!functions.contains(function_id)) { function(); } @@ -156,9 +150,8 @@ namespace gsc void vm_call_builtin_method_stub(builtin_method method) { const auto function_id = get_function_id(); - const auto is_custom_function = methods.find(function_id) != methods.end(); - if (!is_custom_function) + if (!methods.contains(function_id)) { method(saved_ent_ref); } @@ -266,6 +259,11 @@ namespace gsc } console::info("%s\n", buffer.data()); } + + scripting::script_value typeof(const function_args& args) + { + return args[0].type_name(); + } } namespace function @@ -367,6 +365,15 @@ namespace gsc utils::hook::call(SELECT_VALUE(0x3CC9F3_b, 0x513A53_b), vm_error_stub); + if (game::environment::is_dedi()) + { + function::add("isusingmatchrulesdata", [](const function_args& args) + { + // return 0 so the game doesn't override the cfg + return 0; + }); + } + function::add("print", [](const function_args& args) { print(args); @@ -402,17 +409,17 @@ namespace gsc return scripting::script_value{}; }); - function::add("getfunction", [](const function_args& args) -> scripting::script_value + function::add("getfunction", [](const function_args& args) { const auto filename = args[0].as(); const auto function = args[1].as(); - if (scripting::script_function_table[filename].find(function) != scripting::script_function_table[filename].end()) + if (!scripting::script_function_table[filename].contains(function)) { - return scripting::function{scripting::script_function_table[filename][function]}; + throw std::runtime_error("function not found"); } - return {}; + return scripting::function{scripting::script_function_table[filename][function]}; }); function::add("replacefunc", [](const function_args& args) @@ -459,12 +466,6 @@ namespace gsc return scripting::script_value{}; }); - function::add("isusingmatchrulesdata", [](const function_args& args) - { - // return 0 so the game doesn't override the cfg - return 0; - }); - function::add("say", [](const function_args& args) { const auto message = args[0].as(); @@ -473,6 +474,9 @@ namespace gsc return scripting::script_value{}; }); + function::add("typeof", typeof); + function::add("type", typeof); + method::add("tell", [](const game::scr_entref_t ent, const function_args& args) { if (ent.classnum != 0) diff --git a/src/client/component/gsc/script_loading.cpp b/src/client/component/gsc/script_loading.cpp index 7761b337..e5232396 100644 --- a/src/client/component/gsc/script_loading.cpp +++ b/src/client/component/gsc/script_loading.cpp @@ -88,28 +88,29 @@ namespace gsc return itr->second; } - /* - without this check, gsc rawfiles that a map contains will be compiled. however, these aren't the correct files. - each rawfile has a scriptfile counterpart in asset pool that is meant to be used instead. - the gsc rawfiles are just leftover from creating the maps. - - (if you are creating a custom map, you can safely have gsc rawfiles without having scriptfile counterparts) - */ - if (real_name.starts_with("maps/createfx") || real_name.starts_with("maps/createart") - || (real_name.starts_with("maps/mp") && real_name.ends_with("_fx.gsc"))) - { - if (game::DB_XAssetExists(game::ASSET_TYPE_SCRIPTFILE, real_name.data())) - { - return game::DB_FindXAssetHeader(game::ASSET_TYPE_SCRIPTFILE, real_name.data(), false).scriptfile; - } - } - - std::string source_buffer{}; - if (!read_script_file(real_name + ".gsc", &source_buffer)) + std::string source_buffer; + const auto rawfile_gsc_exists = read_script_file(real_name + ".gsc", &source_buffer); + if (!rawfile_gsc_exists || source_buffer.empty()) { return nullptr; } + if (game::DB_XAssetExists(game::ASSET_TYPE_SCRIPTFILE, file_name) && + !game::DB_IsXAssetDefault(game::ASSET_TYPE_SCRIPTFILE, file_name)) + { + // filter out developer rawfiles that won't compile + if ((real_name.starts_with("maps/createfx") || real_name.starts_with("maps/createart") || real_name.starts_with("maps/mp")) + && (real_name.ends_with("_fx") || real_name.ends_with("_fog") || real_name.ends_with("_hdr"))) + { + return game::DB_FindXAssetHeader(game::ASSET_TYPE_SCRIPTFILE, file_name, false).scriptfile; + } + + if (!rawfile_gsc_exists) + { + return game::DB_FindXAssetHeader(game::ASSET_TYPE_SCRIPTFILE, file_name, false).scriptfile; + } + } + std::vector data; data.assign(source_buffer.begin(), source_buffer.end()); diff --git a/src/client/component/io.cpp b/src/client/component/io.cpp index b1ca0882..64373558 100644 --- a/src/client/component/io.cpp +++ b/src/client/component/io.cpp @@ -20,7 +20,7 @@ namespace io { namespace { - bool use_root_folder = false; + bool allow_root_io = false; void check_path(const std::filesystem::path& path) { @@ -34,7 +34,7 @@ namespace io { check_path(path); - if (use_root_folder) + if (allow_root_io) { static const auto fs_base_game = game::Dvar_FindVar("fs_basepath"); const std::filesystem::path fs_base_game_path(fs_base_game->current.string); @@ -69,10 +69,10 @@ namespace io public: void post_unpack() override { - use_root_folder = utils::flags::has_flag("io_game_dir"); - if (use_root_folder) + allow_root_io = utils::flags::has_flag("allow_root_io"); + if (allow_root_io) { - console::warn("GSC has access to your game folder. To prevent possible malicious code, remove the '-io_game_dir' launch flag."); + console::warn("GSC has access to your game folder. Remove the '-allow_root_io' launch parameter to disable this feature."); } gsc::function::add("fileexists", [](const gsc::function_args& args) diff --git a/src/client/component/json.cpp b/src/client/component/json.cpp index 3a879694..8ff70958 100644 --- a/src/client/component/json.cpp +++ b/src/client/component/json.cpp @@ -94,7 +94,7 @@ namespace json case (game::SCRIPT_FUNCTION): return _value.as().get_name(); default: - return "[unknown type]"; + return utils::string::va("[%s]", _value.type_name().data()); }; } diff --git a/src/client/component/logfile.cpp b/src/client/component/logfile.cpp index abce3289..ddf5b5b5 100644 --- a/src/client/component/logfile.cpp +++ b/src/client/component/logfile.cpp @@ -29,7 +29,6 @@ namespace logfile utils::hook::detour scr_player_damage_hook; utils::hook::detour client_command_hook; - utils::hook::detour g_shutdown_game_hook; utils::hook::detour g_log_printf_hook; @@ -328,8 +327,8 @@ namespace logfile const scripting::entity level{*game::levelEntityId}; const scripting::entity player{game::Scr_GetEntityId(self->s.number, 0)}; - scripting::notify(level, cmd, {player, message, hidden}); - scripting::notify(player, cmd, {message, hidden}); + notify(level, cmd, {player, message, hidden}); + notify(player, cmd, {message, hidden}); game::G_LogPrintf("%s;%s;%i;%s;%s\n", cmd, diff --git a/src/client/game/scripting/script_value.hpp b/src/client/game/scripting/script_value.hpp index 7c519828..ee703e09 100644 --- a/src/client/game/scripting/script_value.hpp +++ b/src/client/game/scripting/script_value.hpp @@ -30,20 +30,19 @@ namespace scripting {11, "builtin method"}, {12, "stack"}, {13, "animation"}, - {14, "developer codepos"}, // this exists on H1 but not IW6 - {15, "pre animation"}, - {16, "thread"}, - {17, "notify thread"}, - {18, "time thread"}, - {19, "child thread"}, - {20, "struct"}, - {21, "removed entity"}, - {22, "entity"}, - {23, "array"}, - {24, "removed thread"}, - {25, ""}, // VAR_COUNT is 25 on H1, but 24 on IW6 - {26, "thread list"}, - {27, "endon list"}, + {14, "pre animation"}, + {15, "thread"}, + {16, "notify thread"}, + {17, "time thread"}, + {18, "child thread"}, + {19, "struct"}, + {20, "removed entity"}, + {21, "entity"}, + {22, "array"}, + {23, "removed thread"}, + {24, ""}, + {25, "thread list"}, + {26, "endon list"}, }; std::string get_typename(const game::VariableValue& value) diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index 155c7b5e..67bb8fe7 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -56,22 +56,21 @@ namespace game VAR_BUILTIN_METHOD = 0xB, VAR_STACK = 0xC, VAR_ANIMATION = 0xD, - 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_FREE = 0x19, - VAR_THREAD_LIST = 0x1A, - VAR_ENDON_LIST = 0x1B, - VAR_TOTAL_COUNT = 0x1C, + 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, }; struct VariableStackBuffer