2023-12-05 11:35:05 +01:00
|
|
|
#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:
|
2023-12-14 00:54:59 +01:00
|
|
|
static constexpr std::array<CVehicleModelInfoFlags, 5> m_abilities = {
|
2023-12-12 15:46:59 +01:00
|
|
|
CVehicleModelInfoFlags::JUMPING_CAR,
|
|
|
|
CVehicleModelInfoFlags::HAS_ROCKET_BOOST,
|
|
|
|
CVehicleModelInfoFlags::HAS_PARACHUTE,
|
|
|
|
CVehicleModelInfoFlags::RAMP,
|
2023-12-14 00:54:59 +01:00
|
|
|
CVehicleModelInfoFlags::HAS_GLIDER
|
2023-12-05 11:35:05 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
private:
|
2023-12-12 15:46:59 +01:00
|
|
|
std::unordered_set<CVehicleModelInfoFlags> m_stock_abilities;
|
2023-12-05 11:35:05 +01:00
|
|
|
CVehicle* m_vehicle = nullptr;
|
2023-12-14 00:54:59 +01:00
|
|
|
bool m_original_abilities[5] = {};
|
2023-12-05 11:35:05 +01:00
|
|
|
|
|
|
|
public:
|
|
|
|
vehicle_ability_helper() = default;
|
|
|
|
vehicle_ability_helper(CVehicle* vehicle)
|
|
|
|
{
|
|
|
|
if (vehicle == nullptr || vehicle->m_model_info == nullptr)
|
|
|
|
return;
|
|
|
|
m_vehicle = vehicle;
|
|
|
|
|
2023-12-14 00:54:59 +01:00
|
|
|
for (int i = 0; i < 5; i++)
|
2023-12-12 15:46:59 +01:00
|
|
|
m_original_abilities[i] = has_ability(m_abilities.at(i));
|
2023-12-05 11:35:05 +01:00
|
|
|
|
|
|
|
for (const auto ability : m_abilities)
|
|
|
|
{
|
2023-12-12 15:46:59 +01:00
|
|
|
if (has_ability(ability))
|
2023-12-05 11:35:05 +01:00
|
|
|
{
|
|
|
|
m_stock_abilities.insert(ability);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Gets the initial ability value of the vehicle.
|
|
|
|
*
|
|
|
|
* @param ability
|
|
|
|
* @return true
|
|
|
|
* @return false
|
|
|
|
*/
|
2023-12-12 15:46:59 +01:00
|
|
|
bool get_ability_default(CVehicleModelInfoFlags ability)
|
2023-12-05 11:35:05 +01:00
|
|
|
{
|
|
|
|
return m_stock_abilities.contains(ability);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Checks if the currently bound CVehicle ptr has the flag enabled.
|
|
|
|
*
|
|
|
|
* @param ability
|
|
|
|
* @return true
|
|
|
|
* @return false
|
|
|
|
*/
|
2023-12-12 15:46:59 +01:00
|
|
|
bool has_ability(CVehicleModelInfoFlags ability)
|
2023-12-05 11:35:05 +01:00
|
|
|
{
|
2023-12-12 15:46:59 +01:00
|
|
|
return m_vehicle && m_vehicle->m_model_info && reinterpret_cast<CVehicleModelInfo*>(m_vehicle->m_model_info)->get_vehicle_model_flag(ability);
|
2023-12-05 11:35:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Resets the vehicle to its defaults safely!
|
|
|
|
*/
|
|
|
|
void reset_defaults()
|
|
|
|
{
|
|
|
|
if (m_vehicle && m_vehicle->m_model_info)
|
|
|
|
{
|
2023-12-14 00:54:59 +01:00
|
|
|
for (int i = 0; i < 5; i++)
|
2023-12-12 15:46:59 +01:00
|
|
|
toggle_ability(m_abilities.at(i), m_original_abilities[i]);
|
2023-12-05 11:35:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Safely set the ability state of a vehicle.
|
|
|
|
*
|
|
|
|
* @param ability
|
|
|
|
* @param toggle
|
|
|
|
*/
|
2023-12-12 15:46:59 +01:00
|
|
|
void toggle_ability(CVehicleModelInfoFlags ability, bool toggle)
|
2023-12-05 11:35:05 +01:00
|
|
|
{
|
|
|
|
if (m_vehicle && m_vehicle->m_model_info)
|
|
|
|
{
|
|
|
|
const auto model_info = reinterpret_cast<CVehicleModelInfo*>(m_vehicle->m_model_info);
|
2023-12-12 15:46:59 +01:00
|
|
|
|
|
|
|
model_info->set_vehicle_model_flag(ability, toggle);
|
2023-12-05 11:35:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2023-12-12 15:46:59 +01:00
|
|
|
m_vehicle_ability_helper.toggle_ability(CVehicleModelInfoFlags::JUMPING_CAR, g.vehicle.abilities.jump);
|
|
|
|
m_vehicle_ability_helper.toggle_ability(CVehicleModelInfoFlags::HAS_ROCKET_BOOST, g.vehicle.abilities.rocket);
|
|
|
|
m_vehicle_ability_helper.toggle_ability(CVehicleModelInfoFlags::HAS_PARACHUTE, g.vehicle.abilities.parachute);
|
|
|
|
m_vehicle_ability_helper.toggle_ability(CVehicleModelInfoFlags::RAMP, g.vehicle.abilities.ramp);
|
2023-12-14 00:54:59 +01:00
|
|
|
if (VEHICLE::GET_VEHICLE_CLASS(self::veh) == 8 || VEHICLE::GET_VEHICLE_CLASS(self::veh) == 13 /*Motorcycles & Bikes*/)
|
|
|
|
m_vehicle_ability_helper.toggle_ability(CVehicleModelInfoFlags::HAS_GLIDER, g.vehicle.abilities.glider);
|
2023-12-05 11:35:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2023-12-12 15:46:59 +01:00
|
|
|
g.vehicle.abilities.jump = m_vehicle_ability_helper.get_ability_default(CVehicleModelInfoFlags::JUMPING_CAR);
|
|
|
|
g.vehicle.abilities.rocket = m_vehicle_ability_helper.get_ability_default(CVehicleModelInfoFlags::HAS_ROCKET_BOOST);
|
|
|
|
g.vehicle.abilities.parachute = m_vehicle_ability_helper.get_ability_default(CVehicleModelInfoFlags::HAS_PARACHUTE);
|
|
|
|
g.vehicle.abilities.ramp = m_vehicle_ability_helper.get_ability_default(CVehicleModelInfoFlags::RAMP);
|
2023-12-14 00:54:59 +01:00
|
|
|
g.vehicle.abilities.glider = m_vehicle_ability_helper.get_ability_default(CVehicleModelInfoFlags::HAS_GLIDER);
|
2023-12-05 11:35:05 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-12-12 15:46:59 +01:00
|
|
|
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);
|
2023-12-14 00:54:59 +01:00
|
|
|
bool_command g_glider_ability("gliderability", "BACKEND_LOOPED_VEHICLE_ABILITY_GLIDER", "BACKEND_LOOPED_VEHICLE_ABILITY_GLIDER_DESC", g.vehicle.abilities.glider);
|
2023-12-05 11:35:05 +01:00
|
|
|
}
|