124 lines
3.2 KiB
C++
124 lines
3.2 KiB
C++
|
#include <std_include.hpp>
|
||
|
#include "loader/component_loader.hpp"
|
||
|
|
||
|
#include "game/game.hpp"
|
||
|
|
||
|
#include "console.hpp"
|
||
|
#include "command.hpp"
|
||
|
#include "fastfiles.hpp"
|
||
|
|
||
|
#include "utils/hook.hpp"
|
||
|
|
||
|
namespace weapon
|
||
|
{
|
||
|
namespace
|
||
|
{
|
||
|
utils::hook::detour g_setup_level_weapon_def_hook;
|
||
|
void g_setup_level_weapon_def_stub()
|
||
|
{
|
||
|
// precache level weapons first
|
||
|
g_setup_level_weapon_def_hook.invoke<void>();
|
||
|
|
||
|
std::vector<game::WeaponDef*> weapons;
|
||
|
|
||
|
// find all weapons in asset pools
|
||
|
fastfiles::enum_assets(game::ASSET_TYPE_WEAPON, [&weapons](game::XAssetHeader header)
|
||
|
{
|
||
|
weapons.push_back(header.weapon);
|
||
|
}, false);
|
||
|
|
||
|
// sort weapons
|
||
|
std::sort(weapons.begin(), weapons.end(), [](game::WeaponDef* weapon1, game::WeaponDef* weapon2)
|
||
|
{
|
||
|
return std::string_view(weapon1->name) <
|
||
|
std::string_view(weapon2->name);
|
||
|
});
|
||
|
|
||
|
// precache items
|
||
|
for (std::size_t i = 0; i < weapons.size(); i++)
|
||
|
{
|
||
|
console::debug("precaching weapon \"%s\"\n", weapons[i]->name);
|
||
|
game::G_GetWeaponForName(weapons[i]->name);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template <typename T>
|
||
|
void set_weapon_field(const std::string& weapon_name, unsigned int field, T value)
|
||
|
{
|
||
|
auto weapon = game::DB_FindXAssetHeader(game::ASSET_TYPE_WEAPON, weapon_name.data(), false).data;
|
||
|
if (weapon)
|
||
|
{
|
||
|
if (field && field < (0xE20 + sizeof(T)))
|
||
|
{
|
||
|
*reinterpret_cast<T*>(reinterpret_cast<std::uintptr_t>(weapon) + field) = value;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
console::warn("weapon field: %d is higher than the size of weapon struct!\n", field);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
console::warn("weapon %s not found!\n", weapon_name.data());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void set_weapon_field_float(const std::string& weapon_name, unsigned int field, float value)
|
||
|
{
|
||
|
set_weapon_field<float>(weapon_name, field, value);
|
||
|
}
|
||
|
|
||
|
void set_weapon_field_int(const std::string& weapon_name, unsigned int field, int value)
|
||
|
{
|
||
|
set_weapon_field<int>(weapon_name, field, value);
|
||
|
}
|
||
|
|
||
|
void set_weapon_field_bool(const std::string& weapon_name, unsigned int field, bool value)
|
||
|
{
|
||
|
set_weapon_field<bool>(weapon_name, field, value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class component final : public component_interface
|
||
|
{
|
||
|
public:
|
||
|
void post_unpack() override
|
||
|
{
|
||
|
g_setup_level_weapon_def_hook.create(0x462630_b, g_setup_level_weapon_def_stub);
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
command::add("setWeaponFieldFloat", [](const command::params& params)
|
||
|
{
|
||
|
if (params.size() <= 3)
|
||
|
{
|
||
|
console::info("usage: setWeaponFieldInt <weapon> <field> <value>\n");
|
||
|
return;
|
||
|
}
|
||
|
set_weapon_field_float(params.get(1), atoi(params.get(2)), static_cast<float>(atof(params.get(3))));
|
||
|
});
|
||
|
|
||
|
command::add("setWeaponFieldInt", [](const command::params& params)
|
||
|
{
|
||
|
if (params.size() <= 3)
|
||
|
{
|
||
|
console::info("usage: setWeaponFieldInt <weapon> <field> <value>\n");
|
||
|
return;
|
||
|
}
|
||
|
set_weapon_field_int(params.get(1), atoi(params.get(2)), static_cast<int>(atoi(params.get(3))));
|
||
|
});
|
||
|
|
||
|
command::add("setWeaponFieldBool", [](const command::params& params)
|
||
|
{
|
||
|
if (params.size() <= 3)
|
||
|
{
|
||
|
console::info("usage: setWeaponFieldBool <weapon> <field> <value>\n");
|
||
|
return;
|
||
|
}
|
||
|
set_weapon_field_bool(params.get(1), atoi(params.get(2)), static_cast<bool>(atoi(params.get(3))));
|
||
|
});
|
||
|
#endif
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
REGISTER_COMPONENT(weapon::component)
|