Vehicle Abilities (#2474)

Co-authored-by: Yimura <24669514+Yimura@users.noreply.github.com>
This commit is contained in:
thehorizon84 2023-12-05 11:35:05 +01:00 committed by GitHub
parent d2a7ff8ba4
commit a3be8d9c03
6 changed files with 224 additions and 18 deletions

View File

@ -3,7 +3,7 @@ include(FetchContent)
FetchContent_Declare(
gtav_classes
GIT_REPOSITORY https://github.com/Yimura/GTAV-Classes.git
GIT_TAG 9e76175d28b3de21c24a69e71bee779d704d8304
GIT_TAG b93fcb4848c935b6b11ce9d5e82fb38aba3a59f4
GIT_PROGRESS TRUE
CONFIGURE_COMMAND ""
BUILD_COMMAND ""

View File

@ -0,0 +1,175 @@
#include "backend/looped_command.hpp"
#include "gta/enums.hpp"
#include "util/misc.hpp"
#include "util/vehicle.hpp"
#include <vehicle/CVehicleModelInfo.hpp>
namespace big
{
class vehicle_ability : looped_command
{
using looped_command::looped_command;
class vehicle_ability_helper
{
private:
static constexpr std::array<eVehicleAbilities, 4> m_abilities = {
eVehicleAbilities::JUMP,
eVehicleAbilities::ROCKET,
eVehicleAbilities::PARACHUTE,
eVehicleAbilities::RAMP_BUGGY,
};
private:
std::unordered_set<eVehicleAbilities> m_stock_abilities;
CVehicle* m_vehicle = nullptr;
uint16_t m_original_abilities;
public:
vehicle_ability_helper() = default;
vehicle_ability_helper(CVehicle* vehicle)
{
if (vehicle == nullptr || vehicle->m_model_info == nullptr)
return;
m_vehicle = vehicle;
const auto model_info = reinterpret_cast<CVehicleModelInfo*>(vehicle->m_model_info);
m_original_abilities = model_info->m_ability_flag;
for (const auto ability : m_abilities)
{
if (m_original_abilities >> (uint16_t)ability & 1)
{
m_stock_abilities.insert(ability);
}
}
}
/**
* @brief Gets the initial ability value of the vehicle.
*
* @param ability
* @return true
* @return false
*/
bool get_ability_default(eVehicleAbilities ability)
{
return m_stock_abilities.contains(ability);
}
/**
* @brief Checks if the currently bound CVehicle ptr has the flag enabled.
*
* @param ability
* @return true
* @return false
*/
bool has_ability(eVehicleAbilities ability)
{
return m_vehicle && m_vehicle->m_model_info && reinterpret_cast<CVehicleModelInfo*>(m_vehicle->m_model_info)->m_ability_flag >> (uint16_t)ability & 1;
}
/**
* @brief Resets the vehicle to its defaults safely!
*/
void reset_defaults()
{
if (m_vehicle && m_vehicle->m_model_info)
{
const auto model_info = reinterpret_cast<CVehicleModelInfo*>(m_vehicle->m_model_info);
model_info->m_ability_flag = m_original_abilities;
}
}
/**
* @brief Safely set the ability state of a vehicle.
*
* @param ability
* @param toggle
*/
void toggle_ability(eVehicleAbilities ability, bool toggle)
{
if (m_vehicle && m_vehicle->m_model_info)
{
const auto model_info = reinterpret_cast<CVehicleModelInfo*>(m_vehicle->m_model_info);
if (toggle)
misc::set_bits(&model_info->m_ability_flag, (uint16_t)ability);
else
misc::clear_bits(&model_info->m_ability_flag, (uint16_t)ability);
}
}
bool operator ==(const CVehicle* vehicle) const
{
return m_vehicle == vehicle;
}
} m_vehicle_ability_helper {};
virtual void on_enable() override
{
reset(g_local_player->m_vehicle);
}
virtual void on_tick() override
{
const auto curr_veh = g_local_player->m_vehicle;
if (curr_veh && !(g_local_player->m_ped_task_flag & (int)ePedTask::TASK_DRIVING))
{
m_vehicle_ability_helper.reset_defaults();
return;
}
if (m_vehicle_ability_helper != curr_veh)
{
reset(curr_veh);
}
m_vehicle_ability_helper.toggle_ability(eVehicleAbilities::JUMP, g.vehicle.abilities.jump);
m_vehicle_ability_helper.toggle_ability(eVehicleAbilities::ROCKET, g.vehicle.abilities.rocket);
m_vehicle_ability_helper.toggle_ability(eVehicleAbilities::PARACHUTE, g.vehicle.abilities.parachute);
m_vehicle_ability_helper.toggle_ability(eVehicleAbilities::RAMP_BUGGY, g.vehicle.abilities.ramp);
}
virtual void on_disable() override
{
reset(nullptr);
}
void reset(CVehicle* vehicle)
{
if (vehicle == nullptr)
{
m_vehicle_ability_helper = {};
g.vehicle.abilities = {};
return;
}
m_vehicle_ability_helper.reset_defaults();
m_vehicle_ability_helper = { vehicle };
// currently I'd keep overwriting the display values for what is default for the current vehicle
// should we always persist the user's choice onto the vehicle? or only the ones that are enabled?
// doesn't sound like too great of an idea for vehicles that have abilities by default and then suddenly they're disabled
g.vehicle.abilities.jump = m_vehicle_ability_helper.get_ability_default(eVehicleAbilities::JUMP);
g.vehicle.abilities.rocket = m_vehicle_ability_helper.get_ability_default(eVehicleAbilities::ROCKET);
g.vehicle.abilities.parachute = m_vehicle_ability_helper.get_ability_default(eVehicleAbilities::PARACHUTE);
g.vehicle.abilities.ramp = m_vehicle_ability_helper.get_ability_default(eVehicleAbilities::RAMP_BUGGY);
}
};
vehicle_ability
g_vehicle_ability("modifyvehicleability", "MODIFY_VEHICLE_ABILITY", "MODIFY_VEHICLE_ABILITY_DESC", g.vehicle.abilities.enabled);
bool_command g_jump_ability("jumpability", "BACKEND_LOOPED_VEHICLE_ABILITY_JUMP", "BACKEND_LOOPED_VEHICLE_ABILITY_JUMP_DESC",
g.vehicle.abilities.jump);
bool_command g_rocket_ability("rocketability", "BACKEND_LOOPED_VEHICLE_ABILITY_ROCKET", "BACKEND_LOOPED_VEHICLE_ABILITY_ROCKET_DESC",
g.vehicle.abilities.rocket);
bool_command g_parachute_ability("parachuteability", "BACKEND_LOOPED_VEHICLE_ABILITY_PARACHUTE", "BACKEND_LOOPED_VEHICLE_ABILITY_PARACHUTE_DESC",
g.vehicle.abilities.parachute);
bool_command g_ramp_ability("rampability", "BACKEND_LOOPED_VEHICLE_ABILITY_RAMP", "BACKEND_LOOPED_VEHICLE_ABILITY_RAMP_DESC",
g.vehicle.abilities.ramp);
}

View File

@ -9,8 +9,8 @@
#include <bitset>
#include <rage/rlSessionInfo.hpp>
#include <weapon/CAmmoInfo.hpp>
#include <weapon/CWeaponInfo.hpp>
#include <weapon/CAmmoRocketInfo.hpp>
#include <weapon/CWeaponInfo.hpp>
#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui.h>
@ -451,7 +451,7 @@ namespace big
struct hotkeys
{
bool editing_menu_toggle = false;
bool editing_menu_toggle = false;
std::atomic<bool> is_mp_chat_active;
int menu_toggle = VK_INSERT;
int teleport_waypoint = 0;
@ -554,9 +554,9 @@ namespace big
struct ocean
{
bool modify_ocean = false;
bool disable_ocean = false;
int ocean_opacity = 100;
bool modify_ocean = false;
bool disable_ocean = false;
int ocean_opacity = 100;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(ocean, modify_ocean, disable_ocean, ocean_opacity)
} ocean{};
@ -764,6 +764,17 @@ namespace big
bool siren_mute = false;
bool all_vehs_in_heists = false;
struct abilities
{
bool enabled = false;
bool jump = false;
bool rocket = false;
bool parachute = false;
bool ramp = false;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(abilities, enabled)
} abilities{};
struct vehicle_ammo_special
{
bool enabled = false;
@ -787,7 +798,7 @@ namespace big
NLOHMANN_DEFINE_TYPE_INTRUSIVE(vehicle_ammo_special, enabled, type, explosion_tag, speed, time_between_shots, alternate_wait_time, weapon_range, rocket_time_between_shots, rocket_alternate_wait_time, rocket_lock_on_range, rocket_range, rocket_reload_time, rocket_explosion_tag, rocket_lifetime, rocket_launch_speed, rocket_time_before_homing, rocket_improve_tracking)
} vehicle_ammo_special{};
NLOHMANN_DEFINE_TYPE_INTRUSIVE(vehicle, speedo_meter, fly, rainbow_paint, speed_unit, god_mode, proof_bullet, proof_fire, proof_collision, proof_melee, proof_explosion, proof_steam, proof_water, proof_mask, auto_drive_destination, auto_drive_style, auto_drive_speed, auto_turn_signals, boost_behavior, drive_on_water, horn_boost, instant_brake, block_homing, seatbelt, turn_signals, vehicle_jump, keep_vehicle_repaired, no_water_collision, disable_engine_auto_start, change_engine_state_immediately, keep_engine_running, keep_vehicle_clean, vehinvisibility, localveh_visibility, keep_on_ground, no_collision, unlimited_weapons, siren_mute, all_vehs_in_heists, vehicle_ammo_special)
NLOHMANN_DEFINE_TYPE_INTRUSIVE(vehicle, speedo_meter, fly, rainbow_paint, speed_unit, god_mode, proof_bullet, proof_fire, proof_collision, proof_melee, proof_explosion, proof_steam, proof_water, proof_mask, auto_drive_destination, auto_drive_style, auto_drive_speed, auto_turn_signals, boost_behavior, drive_on_water, horn_boost, instant_brake, block_homing, seatbelt, turn_signals, vehicle_jump, keep_vehicle_repaired, no_water_collision, disable_engine_auto_start, change_engine_state_immediately, keep_engine_running, keep_vehicle_clean, vehinvisibility, localveh_visibility, keep_on_ground, no_collision, unlimited_weapons, siren_mute, all_vehs_in_heists, abilities, vehicle_ammo_special)
} vehicle{};
struct weapons

View File

@ -2004,6 +2004,14 @@ enum class eVehicleSeats
OUTSIDE_RIGHT,
};
enum class eVehicleAbilities : uint16_t
{
JUMP = 1 << 5,
ROCKET = 1 << 6,
PARACHUTE = 1 << 8,
RAMP_BUGGY = 1 << 9
};
enum class eKnockOffVehicle
{
KNOCKOFFVEHICLE_DEFAULT,

View File

@ -2,17 +2,20 @@
namespace big::misc
{
inline void clear_bit(int* address, int pos)
template<typename T>
inline void clear_bit(T* address, int pos)
{
*address &= ~(1 << pos);
}
inline void clear_bits(int* address, int bits)
template<typename T>
inline void clear_bits(T* address, int bits)
{
*address &= ~(bits);
}
inline bool has_bit_set(int* address, int pos)
template<typename T>
inline bool has_bit_set(T* address, int pos)
{
return *address & 1 << pos;
}
@ -23,17 +26,14 @@ namespace big::misc
return (*address & bits) == bits;
}
inline bool has_bits_set(int* address, int bits)
{
return (*address & bits) == bits;
}
inline void set_bit(int* address, int pos)
template<typename T>
inline void set_bit(T* address, int pos)
{
*address |= 1 << pos;
}
inline void set_bits(int* address, int bits)
template<typename T>
inline void set_bits(T* address, int bits)
{
*address |= bits;
}

View File

@ -220,6 +220,18 @@ namespace big
ImGui::EndCombo();
}
ImGui::SeparatorText("VEHICLE_ABILITIES"_T.data());
{
components::command_checkbox<"modifyvehicleability">();
if (g.vehicle.abilities.enabled)
{
components::command_checkbox<"rocketability">();
components::command_checkbox<"jumpability">();
components::command_checkbox<"parachuteability">();
components::command_checkbox<"rampability">();
}
}
ImGui::SeparatorText("VEHICLE_FLY"_T.data());
{
ImGui::BeginGroup();