Merge branch 'develop' of https://github.com/h1-mod/h1-mod into develop
This commit is contained in:
commit
825da4ee94
27
data/cdata/scripts/mp/team_balance.gsc
Normal file
27
data/cdata/scripts/mp/team_balance.gsc
Normal file
@ -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();
|
||||||
|
}
|
@ -33,11 +33,6 @@ namespace gsc
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
struct gsc_error : public std::runtime_error
|
|
||||||
{
|
|
||||||
using std::runtime_error::runtime_error;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unordered_map<std::uint32_t, script_function> functions;
|
std::unordered_map<std::uint32_t, script_function> functions;
|
||||||
std::unordered_map<std::uint32_t, script_method> methods;
|
std::unordered_map<std::uint32_t, script_method> methods;
|
||||||
|
|
||||||
@ -134,9 +129,8 @@ namespace gsc
|
|||||||
void vm_call_builtin_function_stub(builtin_function function)
|
void vm_call_builtin_function_stub(builtin_function function)
|
||||||
{
|
{
|
||||||
const auto function_id = get_function_id();
|
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();
|
function();
|
||||||
}
|
}
|
||||||
@ -156,9 +150,8 @@ namespace gsc
|
|||||||
void vm_call_builtin_method_stub(builtin_method method)
|
void vm_call_builtin_method_stub(builtin_method method)
|
||||||
{
|
{
|
||||||
const auto function_id = get_function_id();
|
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);
|
method(saved_ent_ref);
|
||||||
}
|
}
|
||||||
@ -266,6 +259,11 @@ namespace gsc
|
|||||||
}
|
}
|
||||||
console::info("%s\n", buffer.data());
|
console::info("%s\n", buffer.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scripting::script_value typeof(const function_args& args)
|
||||||
|
{
|
||||||
|
return args[0].type_name();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace function
|
namespace function
|
||||||
@ -367,6 +365,15 @@ namespace gsc
|
|||||||
|
|
||||||
utils::hook::call(SELECT_VALUE(0x3CC9F3_b, 0x513A53_b), vm_error_stub);
|
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)
|
function::add("print", [](const function_args& args)
|
||||||
{
|
{
|
||||||
print(args);
|
print(args);
|
||||||
@ -402,17 +409,17 @@ namespace gsc
|
|||||||
return scripting::script_value{};
|
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<std::string>();
|
const auto filename = args[0].as<std::string>();
|
||||||
const auto function = args[1].as<std::string>();
|
const auto function = args[1].as<std::string>();
|
||||||
|
|
||||||
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)
|
function::add("replacefunc", [](const function_args& args)
|
||||||
@ -459,12 +466,6 @@ namespace gsc
|
|||||||
return scripting::script_value{};
|
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)
|
function::add("say", [](const function_args& args)
|
||||||
{
|
{
|
||||||
const auto message = args[0].as<std::string>();
|
const auto message = args[0].as<std::string>();
|
||||||
@ -473,6 +474,9 @@ namespace gsc
|
|||||||
return scripting::script_value{};
|
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)
|
method::add("tell", [](const game::scr_entref_t ent, const function_args& args)
|
||||||
{
|
{
|
||||||
if (ent.classnum != 0)
|
if (ent.classnum != 0)
|
||||||
|
@ -88,28 +88,29 @@ namespace gsc
|
|||||||
return itr->second;
|
return itr->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
std::string source_buffer;
|
||||||
without this check, gsc rawfiles that a map contains will be compiled. however, these aren't the correct files.
|
const auto rawfile_gsc_exists = read_script_file(real_name + ".gsc", &source_buffer);
|
||||||
each rawfile has a scriptfile counterpart in asset pool that is meant to be used instead.
|
if (!rawfile_gsc_exists || source_buffer.empty())
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
return nullptr;
|
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<std::uint8_t> data;
|
std::vector<std::uint8_t> data;
|
||||||
data.assign(source_buffer.begin(), source_buffer.end());
|
data.assign(source_buffer.begin(), source_buffer.end());
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ namespace io
|
|||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
bool use_root_folder = false;
|
bool allow_root_io = false;
|
||||||
|
|
||||||
void check_path(const std::filesystem::path& path)
|
void check_path(const std::filesystem::path& path)
|
||||||
{
|
{
|
||||||
@ -34,7 +34,7 @@ namespace io
|
|||||||
{
|
{
|
||||||
check_path(path);
|
check_path(path);
|
||||||
|
|
||||||
if (use_root_folder)
|
if (allow_root_io)
|
||||||
{
|
{
|
||||||
static const auto fs_base_game = game::Dvar_FindVar("fs_basepath");
|
static const auto fs_base_game = game::Dvar_FindVar("fs_basepath");
|
||||||
const std::filesystem::path fs_base_game_path(fs_base_game->current.string);
|
const std::filesystem::path fs_base_game_path(fs_base_game->current.string);
|
||||||
@ -69,10 +69,10 @@ namespace io
|
|||||||
public:
|
public:
|
||||||
void post_unpack() override
|
void post_unpack() override
|
||||||
{
|
{
|
||||||
use_root_folder = utils::flags::has_flag("io_game_dir");
|
allow_root_io = utils::flags::has_flag("allow_root_io");
|
||||||
if (use_root_folder)
|
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)
|
gsc::function::add("fileexists", [](const gsc::function_args& args)
|
||||||
|
@ -94,7 +94,7 @@ namespace json
|
|||||||
case (game::SCRIPT_FUNCTION):
|
case (game::SCRIPT_FUNCTION):
|
||||||
return _value.as<scripting::function>().get_name();
|
return _value.as<scripting::function>().get_name();
|
||||||
default:
|
default:
|
||||||
return "[unknown type]";
|
return utils::string::va("[%s]", _value.type_name().data());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,6 @@ namespace logfile
|
|||||||
utils::hook::detour scr_player_damage_hook;
|
utils::hook::detour scr_player_damage_hook;
|
||||||
|
|
||||||
utils::hook::detour client_command_hook;
|
utils::hook::detour client_command_hook;
|
||||||
utils::hook::detour g_shutdown_game_hook;
|
|
||||||
|
|
||||||
utils::hook::detour g_log_printf_hook;
|
utils::hook::detour g_log_printf_hook;
|
||||||
|
|
||||||
@ -328,8 +327,8 @@ namespace logfile
|
|||||||
const scripting::entity level{*game::levelEntityId};
|
const scripting::entity level{*game::levelEntityId};
|
||||||
const scripting::entity player{game::Scr_GetEntityId(self->s.number, 0)};
|
const scripting::entity player{game::Scr_GetEntityId(self->s.number, 0)};
|
||||||
|
|
||||||
scripting::notify(level, cmd, {player, message, hidden});
|
notify(level, cmd, {player, message, hidden});
|
||||||
scripting::notify(player, cmd, {message, hidden});
|
notify(player, cmd, {message, hidden});
|
||||||
|
|
||||||
game::G_LogPrintf("%s;%s;%i;%s;%s\n",
|
game::G_LogPrintf("%s;%s;%i;%s;%s\n",
|
||||||
cmd,
|
cmd,
|
||||||
|
@ -30,20 +30,19 @@ namespace scripting
|
|||||||
{11, "builtin method"},
|
{11, "builtin method"},
|
||||||
{12, "stack"},
|
{12, "stack"},
|
||||||
{13, "animation"},
|
{13, "animation"},
|
||||||
{14, "developer codepos"}, // this exists on H1 but not IW6
|
{14, "pre animation"},
|
||||||
{15, "pre animation"},
|
{15, "thread"},
|
||||||
{16, "thread"},
|
{16, "notify thread"},
|
||||||
{17, "notify thread"},
|
{17, "time thread"},
|
||||||
{18, "time thread"},
|
{18, "child thread"},
|
||||||
{19, "child thread"},
|
{19, "struct"},
|
||||||
{20, "struct"},
|
{20, "removed entity"},
|
||||||
{21, "removed entity"},
|
{21, "entity"},
|
||||||
{22, "entity"},
|
{22, "array"},
|
||||||
{23, "array"},
|
{23, "removed thread"},
|
||||||
{24, "removed thread"},
|
{24, "<free>"},
|
||||||
{25, "<free>"}, // VAR_COUNT is 25 on H1, but 24 on IW6
|
{25, "thread list"},
|
||||||
{26, "thread list"},
|
{26, "endon list"},
|
||||||
{27, "endon list"},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string get_typename(const game::VariableValue& value)
|
std::string get_typename(const game::VariableValue& value)
|
||||||
|
@ -56,22 +56,21 @@ namespace game
|
|||||||
VAR_BUILTIN_METHOD = 0xB,
|
VAR_BUILTIN_METHOD = 0xB,
|
||||||
VAR_STACK = 0xC,
|
VAR_STACK = 0xC,
|
||||||
VAR_ANIMATION = 0xD,
|
VAR_ANIMATION = 0xD,
|
||||||
VAR_DEVELOPER_CODEPOS = 0xE,
|
VAR_PRE_ANIMATION = 0xE,
|
||||||
VAR_PRE_ANIMATION = 0xF,
|
VAR_THREAD = 0xF,
|
||||||
VAR_THREAD = 0x10,
|
VAR_NOTIFY_THREAD = 0x10,
|
||||||
VAR_NOTIFY_THREAD = 0x11,
|
VAR_TIME_THREAD = 0x11,
|
||||||
VAR_TIME_THREAD = 0x12,
|
VAR_CHILD_THREAD = 0x12,
|
||||||
VAR_CHILD_THREAD = 0x13,
|
VAR_OBJECT = 0x13,
|
||||||
VAR_OBJECT = 0x14,
|
VAR_DEAD_ENTITY = 0x14,
|
||||||
VAR_DEAD_ENTITY = 0x15,
|
VAR_ENTITY = 0x15,
|
||||||
VAR_ENTITY = 0x16,
|
VAR_ARRAY = 0x16,
|
||||||
VAR_ARRAY = 0x17,
|
VAR_DEAD_THREAD = 0x17,
|
||||||
VAR_DEAD_THREAD = 0x18,
|
VAR_COUNT = 0x18,
|
||||||
VAR_COUNT = 0x19,
|
VAR_FREE = 0x18,
|
||||||
VAR_FREE = 0x19,
|
VAR_THREAD_LIST = 0x19,
|
||||||
VAR_THREAD_LIST = 0x1A,
|
VAR_ENDON_LIST = 0x1A,
|
||||||
VAR_ENDON_LIST = 0x1B,
|
VAR_TOTAL_COUNT = 0x1B,
|
||||||
VAR_TOTAL_COUNT = 0x1C,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VariableStackBuffer
|
struct VariableStackBuffer
|
||||||
|
Loading…
Reference in New Issue
Block a user