Redesigned Vehicle Spawn menus to have consistent features. (#2063)
Closes #2053
This commit is contained in:
parent
4c6226d022
commit
cf07cfec04
@ -61,8 +61,8 @@ namespace big
|
||||
};
|
||||
|
||||
spawn_vehicle g_spawn_vehicle("spawn", "Spawn Vehicle", "Spawn a vehicle with the specified model", 1);
|
||||
bool_command g_spawn_maxed("spawnmaxed", "Spawn Maxed", "Controls whether the vehicle spawned will have its mods maxed out",
|
||||
bool_command g_spawn_maxed("spawnmaxed", "SPAWN_MAXED", "SPAWN_MAXED_DESC",
|
||||
g.spawn_vehicle.spawn_maxed);
|
||||
bool_command g_spawn_inside("spawnin", "Spawn Inside", "Controls whether the player should be set inside the vehicle after it spawns",
|
||||
bool_command g_spawn_inside("spawnin", "SPAWN_IN", "SPAWN_IN_DESC",
|
||||
g.spawn_vehicle.spawn_inside);
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ namespace big
|
||||
{
|
||||
auto controlled = g.m_remote_controlled_vehicle;
|
||||
auto controller = g.m_remote_controller_vehicle;
|
||||
g_fiber_pool->queue_job([controlled, controller] {
|
||||
g_fiber_pool->queue_job([controlled, &controller] {
|
||||
if (entity::take_control_of(controlled))
|
||||
{
|
||||
ENTITY::SET_ENTITY_COLLISION(g.m_remote_controlled_vehicle, TRUE, TRUE);
|
||||
|
@ -6,9 +6,7 @@
|
||||
|
||||
namespace big
|
||||
{
|
||||
static bool initalized_backup = false;
|
||||
static std::map<Hash, BOOL> backup_map{};
|
||||
static constexpr auto list_of_hashes = {RAGE_JOAAT("GR_BLOCK_APC_IN_HEISTS"), RAGE_JOAAT("GR_BLOCK_ARDENT_IN_HEISTS"), RAGE_JOAAT("GR_BLOCK_NIGHTSHARK_IN_HEISTS"), RAGE_JOAAT("GR_BLOCK_INSURGENT3_IN_HEISTS"), RAGE_JOAAT("GR_BLOCK_TECHNICAL3_IN_HEISTS"), RAGE_JOAAT("GR_BLOCK_HALFTRACK_IN_HEISTS"), RAGE_JOAAT("GR_BLOCK_TRAILERSMALL_IN_HEISTS"), RAGE_JOAAT("GR_BLOCK_TAMPA3_IN_HEISTS"), RAGE_JOAAT("GR_BLOCK_DUNE3_IN_HEISTS"), RAGE_JOAAT("GR_BLOCK_OPPRESSOR_IN_HEISTS"), RAGE_JOAAT("SMUG_BLOCK_VIGILANTE_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_THRUSTER_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_DELUXO_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_STROMBERG_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_RCV_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_CHERNOBOG_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_BARRAGE_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_KHANJALI_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_SAFARI_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_SAVESTRA_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_AVENGER_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_VOLATOL_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_AKULA_IN_HEISTS"), RAGE_JOAAT("BB_BLOCK_OPPRESSOR2_IN_HEISTS"), RAGE_JOAAT("BB_BLOCK_SCRAMJET_IN_HEISTS"), RAGE_JOAAT("BLOCK_HYDRA_IN_HEISTS"), RAGE_JOAAT("BLOCK_TOREADOR_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_VISERIS_IN_HEISTS")};
|
||||
constexpr auto list_of_hashes = {RAGE_JOAAT("GR_BLOCK_APC_IN_HEISTS"), RAGE_JOAAT("GR_BLOCK_ARDENT_IN_HEISTS"), RAGE_JOAAT("GR_BLOCK_NIGHTSHARK_IN_HEISTS"), RAGE_JOAAT("GR_BLOCK_INSURGENT3_IN_HEISTS"), RAGE_JOAAT("GR_BLOCK_TECHNICAL3_IN_HEISTS"), RAGE_JOAAT("GR_BLOCK_HALFTRACK_IN_HEISTS"), RAGE_JOAAT("GR_BLOCK_TRAILERSMALL_IN_HEISTS"), RAGE_JOAAT("GR_BLOCK_TAMPA3_IN_HEISTS"), RAGE_JOAAT("GR_BLOCK_DUNE3_IN_HEISTS"), RAGE_JOAAT("GR_BLOCK_OPPRESSOR_IN_HEISTS"), RAGE_JOAAT("SMUG_BLOCK_VIGILANTE_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_THRUSTER_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_DELUXO_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_STROMBERG_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_RCV_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_CHERNOBOG_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_BARRAGE_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_KHANJALI_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_SAFARI_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_SAVESTRA_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_AVENGER_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_VOLATOL_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_AKULA_IN_HEISTS"), RAGE_JOAAT("BB_BLOCK_OPPRESSOR2_IN_HEISTS"), RAGE_JOAAT("BB_BLOCK_SCRAMJET_IN_HEISTS"), RAGE_JOAAT("BLOCK_HYDRA_IN_HEISTS"), RAGE_JOAAT("BLOCK_TOREADOR_IN_HEISTS"), RAGE_JOAAT("H2_BLOCK_VISERIS_IN_HEISTS")};
|
||||
|
||||
class allvehsinheists : looped_command
|
||||
{
|
||||
@ -16,41 +14,13 @@ namespace big
|
||||
|
||||
virtual void on_tick() override
|
||||
{
|
||||
if (*g_pointers->m_gta.m_is_session_started)
|
||||
for (Hash tunable_hash : list_of_hashes)
|
||||
{
|
||||
if (initalized_backup == false)
|
||||
if (auto tunable_ptr = g_tunables_service->get_tunable<PBOOL>(tunable_hash))
|
||||
{
|
||||
for (Hash tunable_hash : list_of_hashes)
|
||||
if (*tunable_ptr != FALSE)
|
||||
{
|
||||
if (auto tunable_ptr = g_tunables_service->get_tunable<PBOOL>(tunable_hash))
|
||||
{
|
||||
backup_map[tunable_hash] = *tunable_ptr;
|
||||
initalized_backup = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Hash tunable_hash : list_of_hashes)
|
||||
{
|
||||
if (auto tunable_ptr = g_tunables_service->get_tunable<PBOOL>(tunable_hash))
|
||||
{
|
||||
*tunable_ptr = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void on_disable() override
|
||||
{
|
||||
if (*g_pointers->m_gta.m_is_session_started && initalized_backup)
|
||||
{
|
||||
for (Hash tunable_hash : list_of_hashes)
|
||||
{
|
||||
if (auto tunable_ptr = g_tunables_service->get_tunable<PBOOL>(tunable_hash)) //Sanity check in case of tunables_service failure.
|
||||
{
|
||||
*tunable_ptr = backup_map[tunable_hash];
|
||||
*tunable_ptr = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -474,8 +474,9 @@ namespace big
|
||||
bool spawn_inside = false;
|
||||
bool spawn_maxed = false;
|
||||
std::string plate = "";
|
||||
int spawn_type = 0;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(spawn_vehicle, preview_vehicle, spawn_inside, spawn_maxed, plate)
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(spawn_vehicle, preview_vehicle, spawn_inside, spawn_maxed, plate, spawn_type)
|
||||
} spawn_vehicle{};
|
||||
|
||||
struct clone_pv
|
||||
@ -490,6 +491,15 @@ namespace big
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(clone_pv, preview_vehicle, spawn_inside, spawn_clone, spawn_maxed, clone_plate, plate)
|
||||
} clone_pv{};
|
||||
|
||||
struct persist_car
|
||||
{
|
||||
bool preview_vehicle = false;
|
||||
bool spawn_inside = false;
|
||||
std::string persist_vehicle_sub_folder = "";
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(persist_car, preview_vehicle, spawn_inside, persist_vehicle_sub_folder)
|
||||
} persist_car{};
|
||||
|
||||
struct world
|
||||
{
|
||||
struct orbital_drone
|
||||
@ -706,9 +716,8 @@ namespace big
|
||||
bool unlimited_weapons = false;
|
||||
bool siren_mute = false;
|
||||
bool all_vehs_in_heists = false;
|
||||
std::string persist_vehicle_sub_folder = "";
|
||||
|
||||
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, persist_vehicle_sub_folder)
|
||||
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{};
|
||||
|
||||
struct weapons
|
||||
@ -993,7 +1002,7 @@ namespace big
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(vfx, enable_custom_sky_color, azimuth_east, azimuth_west, azimuth_transition, zenith, stars_intensity)
|
||||
} vfx{};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(menu_settings, debug, tunables, notifications, player, player_db, protections, self, session, settings, spawn_vehicle, clone_pv, spoofing, vehicle, weapons, window, context_menu, esp, session_browser, ugc, reactions, world, stat_editor, lua, persist_weapons, vfx)
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(menu_settings, debug, tunables, notifications, player, player_db, protections, self, session, settings, spawn_vehicle, clone_pv, persist_car, spoofing, vehicle, weapons, window, context_menu, esp, session_browser, ugc, reactions, world, stat_editor, lua, persist_weapons, vfx)
|
||||
};
|
||||
|
||||
inline auto g = menu_settings();
|
||||
|
@ -444,7 +444,9 @@ enum CustomVehicleModType
|
||||
MOD_EXTRA_11 = -211,
|
||||
MOD_EXTRA_12 = -212,
|
||||
MOD_EXTRA_13 = -213,
|
||||
MOD_EXTRA_14 = -214
|
||||
MOD_EXTRA_14 = -214,
|
||||
|
||||
MOD_HAS_CLAN_LOGO = -215
|
||||
};
|
||||
|
||||
|
||||
|
@ -1518,8 +1518,6 @@ namespace big
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include "util/ped.hpp"
|
||||
#include "util/vehicle.hpp"
|
||||
|
||||
#include "services/vehicle/persist_car_service.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
model_preview_service::model_preview_service()
|
||||
@ -65,6 +67,7 @@ namespace big
|
||||
if (m_veh_model_hash != hash || m_veh_spawn_max != spawn_max)
|
||||
{
|
||||
m_veh_model_hash = hash;
|
||||
m_current_persisted_vehicle_name.clear();
|
||||
|
||||
if (m_veh_model_hash != 0)
|
||||
{
|
||||
@ -80,6 +83,7 @@ namespace big
|
||||
{
|
||||
m_ped_model_hash = 0;
|
||||
m_ped_clone = 0;
|
||||
m_current_persisted_vehicle_name.clear();
|
||||
|
||||
if (m_veh_spawn_max != spawn_max || m_veh_owned_mods.size() != owned_mods.size()
|
||||
|| !std::equal(m_veh_owned_mods.begin(), m_veh_owned_mods.end(), owned_mods.begin()))
|
||||
@ -101,6 +105,21 @@ namespace big
|
||||
}
|
||||
}
|
||||
|
||||
void model_preview_service::show_vehicle_persisted(std::string vehicle_name)
|
||||
{
|
||||
m_ped_model_hash = 0;
|
||||
m_ped_clone = 0;
|
||||
m_veh_model_hash = 0;
|
||||
|
||||
if (m_current_persisted_vehicle_name != vehicle_name)
|
||||
{
|
||||
m_current_persisted_vehicle_name = vehicle_name;
|
||||
m_new_model = true;
|
||||
|
||||
preview_loop();
|
||||
}
|
||||
}
|
||||
|
||||
void model_preview_service::preview_loop()
|
||||
{
|
||||
if (m_running || m_loop_running)
|
||||
@ -113,7 +132,7 @@ namespace big
|
||||
g_fiber_pool->queue_job([this] {
|
||||
m_loop_running = true;
|
||||
|
||||
while (g_running && m_running && g_gui->is_open() && (m_ped_model_hash || m_veh_model_hash))
|
||||
while (g_running && m_running && g_gui->is_open() && (m_ped_model_hash || m_veh_model_hash || !m_current_persisted_vehicle_name.empty()))
|
||||
{
|
||||
Vector3 location;
|
||||
|
||||
@ -121,7 +140,7 @@ namespace big
|
||||
{
|
||||
location = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(self::ped, 0.f, 5.f, -.5f);
|
||||
}
|
||||
else if (m_veh_model_hash)
|
||||
else if (m_veh_model_hash || !m_current_persisted_vehicle_name.empty())
|
||||
{
|
||||
location = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(self::ped, 0.f, 10.f, .5f);
|
||||
}
|
||||
@ -151,6 +170,10 @@ namespace big
|
||||
m_current_ent = vehicle::clone_from_owned_mods(m_veh_owned_mods, location, 0.f, false);
|
||||
}
|
||||
}
|
||||
else if (!m_current_persisted_vehicle_name.empty())
|
||||
{
|
||||
m_current_ent = persist_car_service::load_vehicle(m_current_persisted_vehicle_name, g.persist_car.persist_vehicle_sub_folder, Vector3());
|
||||
}
|
||||
|
||||
if (m_current_ent)
|
||||
{
|
||||
@ -168,8 +191,7 @@ namespace big
|
||||
}
|
||||
else if (m_new_model)
|
||||
{
|
||||
ENTITY::DETACH_ENTITY(m_current_ent, 1, 1);
|
||||
ENTITY::DELETE_ENTITY(&m_current_ent);
|
||||
entity::delete_entity(m_current_ent, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -190,13 +212,13 @@ namespace big
|
||||
script::get_current()->yield(15ms);
|
||||
}
|
||||
|
||||
ENTITY::DETACH_ENTITY(m_current_ent, 1, 1);
|
||||
ENTITY::DELETE_ENTITY(&m_current_ent);
|
||||
entity::delete_entity(m_current_ent, true);
|
||||
|
||||
m_current_ent = 0;
|
||||
m_ped_model_hash = 0;
|
||||
m_veh_model_hash = 0;
|
||||
m_veh_owned_mods.clear();
|
||||
m_current_persisted_vehicle_name.clear();
|
||||
m_running = false;
|
||||
m_loop_running = false;
|
||||
});
|
||||
|
@ -22,6 +22,8 @@ namespace big
|
||||
bool m_loop_running = false;
|
||||
bool m_running = false;
|
||||
|
||||
std::string m_current_persisted_vehicle_name;
|
||||
|
||||
public:
|
||||
model_preview_service();
|
||||
~model_preview_service();
|
||||
@ -31,6 +33,8 @@ namespace big
|
||||
|
||||
void show_vehicle(Hash hash, bool spawn_max);
|
||||
void show_vehicle(const std::map<int, int32_t>& owned_mods, bool spawn_max);
|
||||
void show_vehicle_persisted(std::string vehicle_name);
|
||||
void show_vehicle(Vehicle veh);
|
||||
|
||||
void preview_loop();
|
||||
void stop_preview();
|
||||
|
@ -27,7 +27,7 @@ namespace big
|
||||
file_stream.close();
|
||||
}
|
||||
|
||||
Vehicle persist_car_service::load_vehicle(std::string_view file_name, std::string folder_name)
|
||||
Vehicle persist_car_service::load_vehicle(std::string_view file_name, std::string folder_name, const std::optional<Vector3>& spawn_coords)
|
||||
{
|
||||
const auto file = check_vehicle_folder(folder_name).get_file(file_name);
|
||||
|
||||
@ -46,7 +46,7 @@ namespace big
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return spawn_vehicle_full(vehicle_json, self::ped);
|
||||
return spawn_vehicle_full(vehicle_json, self::ped, spawn_coords);
|
||||
}
|
||||
|
||||
std::vector<std::string> persist_car_service::list_files(std::string folder_name)
|
||||
@ -80,13 +80,13 @@ namespace big
|
||||
return spawn_vehicle_full(get_full_vehicle_json(vehicle), ped);
|
||||
}
|
||||
|
||||
Vehicle persist_car_service::spawn_vehicle_full(nlohmann::json vehicle_json, Ped ped)
|
||||
Vehicle persist_car_service::spawn_vehicle_full(nlohmann::json vehicle_json, Ped ped, const std::optional<Vector3>& spawn_coords)
|
||||
{
|
||||
const auto vehicle = spawn_vehicle(vehicle_json, ped);
|
||||
const auto vehicle = spawn_vehicle(vehicle_json, ped, spawn_coords);
|
||||
|
||||
if (!vehicle_json[tow_key].is_null())
|
||||
{
|
||||
const auto tow = spawn_vehicle(vehicle_json[tow_key], ped);
|
||||
const auto tow = spawn_vehicle(vehicle_json[tow_key], ped, spawn_coords);
|
||||
|
||||
auto pos = ENTITY::GET_ENTITY_COORDS(tow, true);
|
||||
pos.x -= 10;
|
||||
@ -101,7 +101,7 @@ namespace big
|
||||
}
|
||||
else if (!vehicle_json[trailer_key].is_null())
|
||||
{
|
||||
const auto trailer = spawn_vehicle(vehicle_json[trailer_key], ped);
|
||||
const auto trailer = spawn_vehicle(vehicle_json[trailer_key], ped, spawn_coords);
|
||||
VEHICLE::ATTACH_VEHICLE_TO_TRAILER(vehicle, trailer, 1.0f);
|
||||
|
||||
const auto rotation = ENTITY::GET_ENTITY_ROTATION(trailer, 2);
|
||||
@ -114,9 +114,9 @@ namespace big
|
||||
return vehicle;
|
||||
}
|
||||
|
||||
Vehicle persist_car_service::spawn_vehicle(nlohmann::json vehicle_json, Ped ped)
|
||||
Vehicle persist_car_service::spawn_vehicle(nlohmann::json vehicle_json, Ped ped, const std::optional<Vector3>& spawn_coords)
|
||||
{
|
||||
const auto vehicle = spawn_vehicle_json(vehicle_json, ped);
|
||||
const auto vehicle = spawn_vehicle_json(vehicle_json, ped, spawn_coords);
|
||||
|
||||
std::vector<nlohmann::json> model_attachments = vehicle_json[model_attachments_key];
|
||||
for (const auto& j : model_attachments)
|
||||
@ -180,15 +180,16 @@ namespace big
|
||||
return vehicle;
|
||||
}
|
||||
|
||||
Vehicle persist_car_service::spawn_vehicle_json(nlohmann::json vehicle_json, Ped ped)
|
||||
Vehicle persist_car_service::spawn_vehicle_json(nlohmann::json vehicle_json, Ped ped, const std::optional<Vector3>& spawn_coords)
|
||||
{
|
||||
const Hash vehicle_hash = vehicle_json[vehicle_model_hash_key];
|
||||
Vector3 spawn_location = spawn_coords.has_value() ? spawn_coords.value() : vehicle::get_spawn_location(g.persist_car.spawn_inside, vehicle_hash);
|
||||
const float spawn_heading = ENTITY::GET_ENTITY_HEADING(self::ped);
|
||||
|
||||
const auto pos = ENTITY::GET_ENTITY_COORDS(self::ped, true);
|
||||
const auto vehicle = big::vehicle::spawn(vehicle_hash, spawn_location, spawn_heading);
|
||||
|
||||
const auto vehicle = big::vehicle::spawn(vehicle_hash, pos, ENTITY::GET_ENTITY_HEADING(ped));
|
||||
|
||||
script::get_current()->yield(); //This is needed to wait for the engine to instantiate things like the radio station so it won't overwrite it on the next frame.
|
||||
if (spawn_location.x + spawn_location.y + spawn_location.z != 0)
|
||||
script::get_current()->yield(); //This is needed to wait for the engine to instantiate things like the radio station so it won't overwrite it on the next frame.
|
||||
|
||||
VEHICLE::SET_VEHICLE_DIRT_LEVEL(vehicle, 0.0f);
|
||||
VEHICLE::SET_VEHICLE_MOD_KIT(vehicle, 0);
|
||||
|
@ -12,7 +12,7 @@ namespace big
|
||||
|
||||
static Vehicle clone_ped_car(Ped ped, Vehicle vehicle);
|
||||
static void save_vehicle(Vehicle vehicle, std::string_view file_name, std::string folder_name);
|
||||
static Vehicle load_vehicle(std::string_view file_name, std::string folder_name = "");
|
||||
static Vehicle load_vehicle(std::string_view file_name, std::string folder_name = "", const std::optional<Vector3>& = std::nullopt);
|
||||
|
||||
private:
|
||||
static constexpr auto model_attachment_key = "model_attachment";
|
||||
@ -64,9 +64,9 @@ namespace big
|
||||
static constexpr auto clan_logo_key = "clan_logo";
|
||||
|
||||
|
||||
static Vehicle spawn_vehicle_full(nlohmann::json vehicle_json, Ped ped);
|
||||
static Vehicle spawn_vehicle(nlohmann::json vehicle_json, Ped ped);
|
||||
static Vehicle spawn_vehicle_json(nlohmann::json vehicle_json, Ped ped);
|
||||
static Vehicle spawn_vehicle_full(nlohmann::json vehicle_json, Ped ped, const std::optional<Vector3>& spawn_coords = std::nullopt);
|
||||
static Vehicle spawn_vehicle(nlohmann::json vehicle_json, Ped ped, const std::optional<Vector3>& spawn_coords);
|
||||
static Vehicle spawn_vehicle_json(nlohmann::json vehicle_json, Ped ped, const std::optional<Vector3>& spawn_coords = std::nullopt);
|
||||
|
||||
static nlohmann::json get_full_vehicle_json(Vehicle vehicle);
|
||||
|
||||
|
@ -20,16 +20,43 @@ namespace big::entity
|
||||
PED::RESET_PED_VISIBLE_DAMAGE(player_ped);
|
||||
}
|
||||
|
||||
void delete_entity(Entity ent)
|
||||
void delete_entity(Entity& ent, bool force)
|
||||
{
|
||||
if (!ENTITY::DOES_ENTITY_EXIST(ent))
|
||||
return;
|
||||
if (!take_control_of(ent))
|
||||
if (!force && !take_control_of(ent))
|
||||
{
|
||||
LOG(VERBOSE) << "Failed to take control of entity before deleting";
|
||||
return;
|
||||
}
|
||||
|
||||
if (ENTITY::IS_ENTITY_A_VEHICLE(ent))
|
||||
{
|
||||
for (auto obj : pools::get_all_props())
|
||||
{
|
||||
auto object = g_pointers->m_gta.m_ptr_to_handle(obj);
|
||||
if (!object)
|
||||
break;
|
||||
|
||||
if (!ENTITY::IS_ENTITY_ATTACHED_TO_ENTITY(ent, object))
|
||||
continue;
|
||||
|
||||
ENTITY::DELETE_ENTITY(&object);
|
||||
}
|
||||
|
||||
for (auto veh : pools::get_all_vehicles())
|
||||
{
|
||||
auto vehicle = g_pointers->m_gta.m_ptr_to_handle(veh);
|
||||
if (!vehicle)
|
||||
break;
|
||||
|
||||
if (ent == vehicle || !ENTITY::IS_ENTITY_ATTACHED_TO_ENTITY(ent, vehicle))
|
||||
continue;
|
||||
|
||||
ENTITY::DELETE_ENTITY(&vehicle);
|
||||
}
|
||||
}
|
||||
|
||||
ENTITY::DETACH_ENTITY(ent, 1, 1);
|
||||
ENTITY::SET_ENTITY_COORDS_NO_OFFSET(ent, 7000.f, 7000.f, 15.f, 0, 0, 0);
|
||||
if (!ENTITY::IS_ENTITY_A_MISSION_ENTITY(ent))
|
||||
|
@ -12,7 +12,7 @@ namespace big::entity
|
||||
void cage_ped(Ped ped);
|
||||
void clean_ped(Ped ped);
|
||||
bool take_control_of(Entity ent, int timeout = 300);
|
||||
void delete_entity(Entity ent);
|
||||
void delete_entity(Entity& ent, bool force = false);
|
||||
bool raycast(Entity* ent);
|
||||
bool raycast(Vector3* endcoor);
|
||||
bool network_has_control_of_entity(rage::netObject* net_object);
|
||||
|
794
src/util/vehicle.cpp
Normal file
794
src/util/vehicle.cpp
Normal file
@ -0,0 +1,794 @@
|
||||
#include "vehicle.hpp"
|
||||
|
||||
namespace big::vehicle
|
||||
{
|
||||
float mps_to_speed(float mps, SpeedUnit speed_unit)
|
||||
{
|
||||
switch (speed_unit)
|
||||
{
|
||||
case SpeedUnit::KMPH: return mps * 3.6f; break;
|
||||
case SpeedUnit::MIPH: return mps * 2.2369f; break;
|
||||
}
|
||||
|
||||
return mps;
|
||||
}
|
||||
|
||||
float speed_to_mps(float speed, SpeedUnit speed_unit)
|
||||
{
|
||||
switch (speed_unit)
|
||||
{
|
||||
case SpeedUnit::KMPH: return speed / 3.6f; break;
|
||||
case SpeedUnit::MIPH: return speed / 2.2369f; break;
|
||||
}
|
||||
|
||||
return speed;
|
||||
}
|
||||
|
||||
Vector3 get_spawn_location(bool spawn_inside, Hash hash, Ped ped)
|
||||
{
|
||||
float y_offset = 0;
|
||||
|
||||
if (self::veh != 0)
|
||||
{
|
||||
Vector3 min, max, result;
|
||||
MISC::GET_MODEL_DIMENSIONS(hash, &min, &max);
|
||||
result = max - min;
|
||||
y_offset = result.y;
|
||||
}
|
||||
else if (!spawn_inside)
|
||||
{
|
||||
y_offset = 5.f;
|
||||
}
|
||||
|
||||
return ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(ped, 0.f, y_offset, 0.f);
|
||||
}
|
||||
|
||||
void set_mp_bitset(Vehicle veh)
|
||||
{
|
||||
DECORATOR::DECOR_SET_INT(veh, "MPBitset", 0);
|
||||
DECORATOR::DECOR_SET_INT(veh, "RandomId", g_local_player->m_net_object->m_object_id);
|
||||
auto networkId = NETWORK::VEH_TO_NET(veh);
|
||||
if (NETWORK::NETWORK_GET_ENTITY_IS_NETWORKED(veh))
|
||||
NETWORK::SET_NETWORK_ID_EXISTS_ON_ALL_MACHINES(networkId, true);
|
||||
VEHICLE::SET_VEHICLE_IS_STOLEN(veh, FALSE);
|
||||
}
|
||||
|
||||
void bring(Vehicle veh, Vector3 location, bool put_in, int seatIdx)
|
||||
{
|
||||
if (!ENTITY::IS_ENTITY_A_VEHICLE(veh))
|
||||
return g_notification_service->push_error("VEHICLE"_T.data(), "VEHICLE_INVALID"_T.data());
|
||||
|
||||
auto vecVehicleLocation = ENTITY::GET_ENTITY_COORDS(veh, true);
|
||||
entity::load_ground_at_3dcoord(vecVehicleLocation);
|
||||
|
||||
if (!entity::take_control_of(veh))
|
||||
return g_notification_service->push_warning("VEHICLE"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
|
||||
auto ped = self::ped;
|
||||
|
||||
ENTITY::SET_ENTITY_COORDS(veh, location.x, location.y, location.z + 1.f, 0, 0, 0, 0);
|
||||
ENTITY::SET_ENTITY_HEADING(veh, ENTITY::GET_ENTITY_HEADING(ped));
|
||||
|
||||
if (put_in)
|
||||
{
|
||||
for (size_t i = 0; i < 100 && math::distance_between_vectors(location, ENTITY::GET_ENTITY_COORDS(veh, true)) > 10; i++)
|
||||
script::get_current()->yield();
|
||||
|
||||
auto driver_ped = VEHICLE::GET_PED_IN_VEHICLE_SEAT(veh, -1, false);
|
||||
|
||||
if (driver_ped != 0)
|
||||
{
|
||||
if (PED::GET_PED_TYPE(driver_ped) == ePedType::PED_TYPE_NETWORK_PLAYER)
|
||||
{
|
||||
TASK::CLEAR_PED_TASKS_IMMEDIATELY(driver_ped);
|
||||
}
|
||||
else
|
||||
{
|
||||
entity::delete_entity(driver_ped);
|
||||
}
|
||||
}
|
||||
|
||||
PED::SET_PED_INTO_VEHICLE(ped, veh, seatIdx);
|
||||
}
|
||||
}
|
||||
|
||||
Vehicle get_closest_to_location(Vector3 location, float range)
|
||||
{
|
||||
float min_dist = FLT_MAX;
|
||||
int32_t m_handle = 0;
|
||||
|
||||
for (const auto veh_entity : pools::get_all_vehicles())
|
||||
{
|
||||
const auto veh_ptr = veh_entity;
|
||||
if (!veh_ptr || !veh_ptr->m_navigation)
|
||||
continue;
|
||||
|
||||
auto veh_pos_arr = *veh_ptr->m_navigation->get_position();
|
||||
Vector3 veh_pos(veh_pos_arr.x, veh_pos_arr.y, veh_pos_arr.z);
|
||||
|
||||
float dist = math::distance_between_vectors(veh_pos, location);
|
||||
|
||||
if (dist < min_dist)
|
||||
{
|
||||
int32_t tmp_handle = g_pointers->m_gta.m_ptr_to_handle(veh_ptr);
|
||||
|
||||
if (entity::take_control_of(tmp_handle))
|
||||
{
|
||||
min_dist = dist;
|
||||
m_handle = tmp_handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
bool set_plate(Vehicle veh, const char* plate)
|
||||
{
|
||||
if (!ENTITY::IS_ENTITY_A_VEHICLE(veh) || !entity::take_control_of(veh))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (plate != nullptr && plate[0] != 0)
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_NUMBER_PLATE_TEXT(veh, plate);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool repair(Vehicle veh)
|
||||
{
|
||||
if (!ENTITY::IS_ENTITY_A_VEHICLE(veh) || !entity::take_control_of(veh, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
VEHICLE::SET_VEHICLE_FIXED(veh);
|
||||
VEHICLE::SET_VEHICLE_DIRT_LEVEL(veh, 0.f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Vehicle spawn(Hash hash, Vector3 location, float heading, bool is_networked, bool script_veh)
|
||||
{
|
||||
for (int i = 0; !STREAMING::HAS_MODEL_LOADED(hash) && i < 100; i++)
|
||||
{
|
||||
STREAMING::REQUEST_MODEL(hash);
|
||||
script::get_current()->yield();
|
||||
}
|
||||
|
||||
if (!STREAMING::HAS_MODEL_LOADED(hash))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto veh = VEHICLE::CREATE_VEHICLE(hash, location.x, location.y, location.z, heading, is_networked, script_veh, false);
|
||||
|
||||
STREAMING::SET_MODEL_AS_NO_LONGER_NEEDED(hash);
|
||||
|
||||
if (*g_pointers->m_gta.m_is_session_started)
|
||||
{
|
||||
set_mp_bitset(veh);
|
||||
}
|
||||
|
||||
return veh;
|
||||
}
|
||||
|
||||
Vehicle clone_from_vehicle_data(std::map<int, int32_t>& data, Vector3 location, float heading)
|
||||
{
|
||||
Vector3 tmpLocation = {location.x, location.y, 1200.0f};
|
||||
if (location.z > 1000.0f && location.z < 1400.0)
|
||||
{
|
||||
tmpLocation.z = 800.0f;
|
||||
}
|
||||
|
||||
// vehicle data
|
||||
for (const auto& [idx, val] : data)
|
||||
{
|
||||
if (idx >= 0 && idx < 142)
|
||||
{
|
||||
*scr_globals::spawn_global.at(27).at(idx).as<int32_t*>() = val;
|
||||
}
|
||||
}
|
||||
|
||||
// permission fix
|
||||
*scr_globals::spawn_global.at(27).at(1).as<int32_t*>() = 0;
|
||||
|
||||
// personal car flag
|
||||
*scr_globals::spawn_global.at(27).at(94).as<int32_t*>() = 14;
|
||||
*scr_globals::spawn_global.at(27).at(95).as<int32_t*>() = 2;
|
||||
|
||||
// mmi
|
||||
*scr_globals::spawn_global.at(27).at(103).as<int32_t*>() = 0;
|
||||
|
||||
// spawn location
|
||||
*scr_globals::spawn_global.at(7).at(0).as<float*>() = tmpLocation.x;
|
||||
*scr_globals::spawn_global.at(7).at(1).as<float*>() = tmpLocation.y;
|
||||
*scr_globals::spawn_global.at(7).at(2).as<float*>() = tmpLocation.z;
|
||||
|
||||
// spawn non pegasus
|
||||
*scr_globals::spawn_global.at(3).as<int*>() = 0;
|
||||
|
||||
// spawn signal
|
||||
int* spawn_signal = scr_globals::spawn_global.at(2).as<int32_t*>();
|
||||
*scr_globals::spawn_global.at(5).as<int32_t*>() = 1;
|
||||
*spawn_signal = 1;
|
||||
|
||||
// wait until the vehicle is spawned
|
||||
for (size_t retry = 0; *spawn_signal != 0 && retry < 200; retry++)
|
||||
{
|
||||
script::get_current()->yield(10ms);
|
||||
}
|
||||
|
||||
if (*spawn_signal == 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto veh = vehicle::get_closest_to_location(tmpLocation, 200);
|
||||
if (veh == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ENTITY::SET_ENTITY_COORDS(veh, location.x, location.y, location.z + 1.f, 0, 0, 0, 0);
|
||||
ENTITY::SET_ENTITY_HEADING(veh, heading);
|
||||
|
||||
return veh;
|
||||
}
|
||||
|
||||
std::map<int, int32_t> get_owned_mods_from_vehicle_idx(script_global vehicle_idx)
|
||||
{
|
||||
std::map<int, int32_t> owned_mods;
|
||||
|
||||
for (int i = MOD_SECONDARY_CUSTOM; i <= MOD_MODEL_HASH; i++)
|
||||
{
|
||||
owned_mods[i] = 0;
|
||||
}
|
||||
|
||||
int32_t val_32 = *vehicle_idx.at(32).as<int32_t*>();
|
||||
int32_t val_77 = *vehicle_idx.at(77).as<int32_t*>();
|
||||
int32_t val_102 = *vehicle_idx.at(102).as<int32_t*>();
|
||||
int32_t val_103 = *vehicle_idx.at(103).as<int32_t*>();
|
||||
|
||||
owned_mods[MOD_MODEL_HASH] = *vehicle_idx.at(66).as<int32_t*>();
|
||||
|
||||
owned_mods[MOD_PLATE_STYLE] = *vehicle_idx.at(0).as<int32_t*>();
|
||||
owned_mods[MOD_WINDOW_TINT] = *vehicle_idx.at(65).as<int32_t*>();
|
||||
owned_mods[MOD_WHEEL_TYPE] = *vehicle_idx.at(69).as<int32_t*>();
|
||||
|
||||
|
||||
owned_mods[MOD_PRIMARY_COL] = *vehicle_idx.at(5).as<int32_t*>();
|
||||
owned_mods[MOD_SECONDARY_COL] = *vehicle_idx.at(6).as<int32_t*>();
|
||||
owned_mods[MOD_PEARLESCENT_COL] = *vehicle_idx.at(7).as<int32_t*>();
|
||||
owned_mods[MOD_WHEEL_COL] = *vehicle_idx.at(8).as<int32_t*>();
|
||||
owned_mods[MOD_INTERIOR_COL] = *vehicle_idx.at(97).as<int32_t*>();
|
||||
owned_mods[MOD_DASHBOARD_COL] = *vehicle_idx.at(99).as<int32_t*>();
|
||||
|
||||
|
||||
//CUSTOM PRIMARY
|
||||
owned_mods[MOD_PRIMARY_CUSTOM] = (val_77 & (1 << 13)) != 0;
|
||||
if (owned_mods[MOD_PRIMARY_CUSTOM])
|
||||
{
|
||||
owned_mods[MOD_PRIMARY_COL_R] = *vehicle_idx.at(71).as<int32_t*>();
|
||||
owned_mods[MOD_PRIMARY_COL_G] = *vehicle_idx.at(72).as<int32_t*>();
|
||||
owned_mods[MOD_PRIMARY_COL_B] = *vehicle_idx.at(73).as<int32_t*>();
|
||||
}
|
||||
|
||||
|
||||
//CUSTOM SECONDARY
|
||||
owned_mods[MOD_SECONDARY_CUSTOM] = (val_77 & (1 << 12)) != 0;
|
||||
if (owned_mods[MOD_SECONDARY_CUSTOM])
|
||||
{
|
||||
owned_mods[MOD_SECONDARY_COL_R] = *vehicle_idx.at(71).as<int32_t*>();
|
||||
owned_mods[MOD_SECONDARY_COL_G] = *vehicle_idx.at(72).as<int32_t*>();
|
||||
owned_mods[MOD_SECONDARY_COL_B] = *vehicle_idx.at(73).as<int32_t*>();
|
||||
}
|
||||
|
||||
|
||||
// TIRE SMOKE
|
||||
owned_mods[MOD_TIRESMOKE_COL_R] = *vehicle_idx.at(62).as<int32_t*>();
|
||||
owned_mods[MOD_TIRESMOKE_COL_G] = *vehicle_idx.at(63).as<int32_t*>();
|
||||
owned_mods[MOD_TIRESMOKE_COL_B] = *vehicle_idx.at(64).as<int32_t*>();
|
||||
owned_mods[MOD_TYRE_SMOKE] = !(owned_mods[MOD_TIRESMOKE_COL_R] == 255 && owned_mods[MOD_TIRESMOKE_COL_G] == 255 && owned_mods[MOD_TIRESMOKE_COL_B] == 255);
|
||||
|
||||
|
||||
// XENON
|
||||
if (val_32 > 0)
|
||||
{
|
||||
owned_mods[MOD_XENON_LIGHTS] = 1;
|
||||
owned_mods[MOD_XENON_COL] = val_32 - 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
owned_mods[MOD_XENON_LIGHTS] = 0;
|
||||
}
|
||||
|
||||
|
||||
// NEON
|
||||
owned_mods[MOD_NEON_LEFT_ON] = (val_77 & (1 << 30)) != 0;
|
||||
owned_mods[MOD_NEON_RIGHT_ON] = (val_77 & (1 << 31)) != 0;
|
||||
owned_mods[MOD_NEON_FRONT_ON] = (val_77 & (1 << 28)) != 0;
|
||||
owned_mods[MOD_NEON_BACK_ON] = (val_77 & (1 << 29)) != 0;
|
||||
owned_mods[MOD_NEON_COL_R] = *vehicle_idx.at(74).as<int32_t*>();
|
||||
owned_mods[MOD_NEON_COL_G] = *vehicle_idx.at(75).as<int32_t*>();
|
||||
owned_mods[MOD_NEON_COL_B] = *vehicle_idx.at(76).as<int32_t*>();
|
||||
|
||||
// TIRE OPTIONS
|
||||
if (val_102 != 0) //Hal's Tyres
|
||||
{
|
||||
owned_mods[MOD_TIRE_CAN_BURST] = val_102 > 1;
|
||||
owned_mods[MOD_DRIFT_TIRE] = val_102 == 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
owned_mods[MOD_TIRE_CAN_BURST] = (val_77 & (1 << 9)) == 0;
|
||||
}
|
||||
|
||||
|
||||
owned_mods[MOD_TURBO] = *vehicle_idx.at(28).as<int32_t*>() != 0;
|
||||
|
||||
owned_mods[MOD_FRONTWHEEL_VAR] = *vehicle_idx.at(60).as<int32_t*>() != 0;
|
||||
owned_mods[MOD_REARWHEEL_VAR] = *vehicle_idx.at(61).as<int32_t*>() != 0;
|
||||
|
||||
|
||||
// OTHER MODS
|
||||
for (int slot = MOD_SPOILERS; slot <= MOD_LIGHTBAR; slot++)
|
||||
{
|
||||
if (slot == MOD_TURBO || slot == MOD_TYRE_SMOKE || slot == MOD_XENON_LIGHTS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int32_t val = *vehicle_idx.at(10 + slot).as<int32_t*>() - 1;
|
||||
if (val != -1)
|
||||
{
|
||||
owned_mods[slot] = val;
|
||||
}
|
||||
}
|
||||
|
||||
// EXTRA
|
||||
for (int extra = MOD_EXTRA_11; extra <= MOD_EXTRA_0; extra++)
|
||||
{
|
||||
int gta_extra_id = (extra - MOD_EXTRA_0) * -1;
|
||||
owned_mods[extra] = val_77 >> (gta_extra_id - 1) & 1;
|
||||
}
|
||||
|
||||
owned_mods[MOD_HAS_CLAN_LOGO] = (val_103 & (1 << 8)) != 0;
|
||||
|
||||
return owned_mods;
|
||||
}
|
||||
|
||||
|
||||
Vehicle clone_from_owned_mods(std::map<int, int32_t> owned_mods, Vector3 location, float heading, bool is_networked)
|
||||
{
|
||||
auto vehicle = spawn(owned_mods[MOD_MODEL_HASH], location, heading, is_networked);
|
||||
if (vehicle == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i = MOD_NEON_COL_B; i <= MOD_MODEL_HASH; i++)
|
||||
{
|
||||
if (owned_mods.count(i) == 0)
|
||||
{
|
||||
owned_mods[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
VEHICLE::SET_VEHICLE_MOD_KIT(vehicle, 0);
|
||||
script::get_current()->yield(10ms);
|
||||
|
||||
VEHICLE::SET_VEHICLE_NUMBER_PLATE_TEXT_INDEX(vehicle, owned_mods[MOD_PLATE_STYLE]);
|
||||
VEHICLE::SET_VEHICLE_WINDOW_TINT(vehicle, owned_mods[MOD_WINDOW_TINT]);
|
||||
VEHICLE::SET_VEHICLE_WHEEL_TYPE(vehicle, owned_mods[MOD_WHEEL_TYPE]);
|
||||
script::get_current()->yield(10ms);
|
||||
|
||||
VEHICLE::SET_VEHICLE_COLOURS(vehicle, owned_mods[MOD_PRIMARY_COL], owned_mods[MOD_SECONDARY_COL]);
|
||||
VEHICLE::SET_VEHICLE_EXTRA_COLOURS(vehicle, owned_mods[MOD_PEARLESCENT_COL], owned_mods[MOD_WHEEL_COL]);
|
||||
VEHICLE::SET_VEHICLE_EXTRA_COLOUR_5(vehicle, owned_mods[MOD_INTERIOR_COL]);
|
||||
VEHICLE::SET_VEHICLE_EXTRA_COLOUR_6(vehicle, owned_mods[MOD_DASHBOARD_COL]);
|
||||
|
||||
if (owned_mods[MOD_PRIMARY_CUSTOM])
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_CUSTOM_PRIMARY_COLOUR(vehicle, owned_mods[MOD_PRIMARY_COL_R], owned_mods[MOD_PRIMARY_COL_G], owned_mods[MOD_PRIMARY_COL_B]);
|
||||
}
|
||||
|
||||
if (owned_mods[MOD_SECONDARY_CUSTOM])
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_CUSTOM_SECONDARY_COLOUR(vehicle, owned_mods[MOD_SECONDARY_COL_R], owned_mods[MOD_SECONDARY_COL_G], owned_mods[MOD_SECONDARY_COL_B]);
|
||||
}
|
||||
|
||||
if (owned_mods[MOD_TYRE_SMOKE])
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_TYRE_SMOKE_COLOR(vehicle, owned_mods[MOD_TIRESMOKE_COL_R], owned_mods[MOD_TIRESMOKE_COL_G], owned_mods[MOD_TIRESMOKE_COL_B]);
|
||||
VEHICLE::TOGGLE_VEHICLE_MOD(vehicle, MOD_TYRE_SMOKE, owned_mods[MOD_TYRE_SMOKE]);
|
||||
}
|
||||
|
||||
if (owned_mods[MOD_XENON_LIGHTS])
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_XENON_LIGHT_COLOR_INDEX(vehicle, owned_mods[MOD_XENON_COL]);
|
||||
VEHICLE::TOGGLE_VEHICLE_MOD(vehicle, MOD_XENON_LIGHTS, owned_mods[MOD_XENON_LIGHTS]);
|
||||
}
|
||||
|
||||
VEHICLE::SET_VEHICLE_NEON_COLOUR(vehicle, owned_mods[MOD_NEON_COL_R], owned_mods[MOD_NEON_COL_G], owned_mods[MOD_NEON_COL_B]);
|
||||
VEHICLE::SET_VEHICLE_NEON_ENABLED(vehicle, NEON_LEFT, owned_mods[MOD_NEON_LEFT_ON]);
|
||||
VEHICLE::SET_VEHICLE_NEON_ENABLED(vehicle, NEON_RIGHT, owned_mods[MOD_NEON_RIGHT_ON]);
|
||||
VEHICLE::SET_VEHICLE_NEON_ENABLED(vehicle, NEON_FRONT, owned_mods[MOD_NEON_FRONT_ON]);
|
||||
VEHICLE::SET_VEHICLE_NEON_ENABLED(vehicle, NEON_BACK, owned_mods[MOD_NEON_BACK_ON]);
|
||||
|
||||
|
||||
VEHICLE::SET_VEHICLE_TYRES_CAN_BURST(vehicle, owned_mods[MOD_TIRE_CAN_BURST]);
|
||||
VEHICLE::SET_DRIFT_TYRES(vehicle, owned_mods[MOD_DRIFT_TIRE]);
|
||||
VEHICLE::TOGGLE_VEHICLE_MOD(vehicle, MOD_TURBO, owned_mods[MOD_TURBO]);
|
||||
|
||||
for (int slot = MOD_SPOILERS; slot <= MOD_LIGHTBAR; slot++)
|
||||
{
|
||||
if (owned_mods.count(slot) && owned_mods[slot] != -1)
|
||||
{
|
||||
bool custom_tire = false;
|
||||
|
||||
if (slot == MOD_FRONTWHEEL)
|
||||
{
|
||||
custom_tire = owned_mods[MOD_FRONTWHEEL_VAR];
|
||||
}
|
||||
else if (slot == MOD_REARWHEEL)
|
||||
{
|
||||
custom_tire = owned_mods[MOD_REARWHEEL_VAR];
|
||||
}
|
||||
|
||||
VEHICLE::SET_VEHICLE_MOD(vehicle, slot, owned_mods[slot], custom_tire);
|
||||
}
|
||||
}
|
||||
|
||||
for (int extra = MOD_EXTRA_11; extra <= MOD_EXTRA_0; extra++)
|
||||
{
|
||||
int gta_extra_id = (extra - MOD_EXTRA_0) * -1;
|
||||
if (owned_mods.count(extra) && VEHICLE::DOES_EXTRA_EXIST(vehicle, gta_extra_id))
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_EXTRA(vehicle, gta_extra_id, owned_mods[extra] == 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (owned_mods[MOD_HAS_CLAN_LOGO] != 0)
|
||||
{
|
||||
vehicle_helper::add_clan_logo_to_vehicle(vehicle, self::ped);
|
||||
}
|
||||
|
||||
return vehicle;
|
||||
}
|
||||
|
||||
std::map<int, int32_t> get_owned_mods_from_vehicle(Vehicle vehicle)
|
||||
{
|
||||
std::map<int, int32_t> owned_mods;
|
||||
|
||||
for (int i = MOD_SECONDARY_CUSTOM; i <= MOD_MODEL_HASH; i++)
|
||||
{
|
||||
owned_mods[i] = 0;
|
||||
}
|
||||
|
||||
owned_mods[MOD_MODEL_HASH] = ENTITY::GET_ENTITY_MODEL(vehicle);
|
||||
|
||||
owned_mods[MOD_PLATE_STYLE] = VEHICLE::GET_VEHICLE_NUMBER_PLATE_TEXT_INDEX(vehicle);
|
||||
owned_mods[MOD_WINDOW_TINT] = VEHICLE::GET_VEHICLE_WINDOW_TINT(vehicle);
|
||||
owned_mods[MOD_WHEEL_TYPE] = VEHICLE::GET_VEHICLE_WHEEL_TYPE(vehicle);
|
||||
|
||||
VEHICLE::GET_VEHICLE_COLOURS(vehicle, &owned_mods[MOD_PRIMARY_COL], &owned_mods[MOD_SECONDARY_COL]);
|
||||
VEHICLE::GET_VEHICLE_EXTRA_COLOURS(vehicle, &owned_mods[MOD_PEARLESCENT_COL], &owned_mods[MOD_WHEEL_COL]);
|
||||
VEHICLE::GET_VEHICLE_EXTRA_COLOUR_5(vehicle, &owned_mods[MOD_INTERIOR_COL]);
|
||||
VEHICLE::GET_VEHICLE_EXTRA_COLOUR_6(vehicle, &owned_mods[MOD_DASHBOARD_COL]);
|
||||
|
||||
owned_mods[MOD_PRIMARY_CUSTOM] = VEHICLE::GET_IS_VEHICLE_PRIMARY_COLOUR_CUSTOM(vehicle);
|
||||
if (owned_mods[MOD_PRIMARY_CUSTOM])
|
||||
{
|
||||
VEHICLE::GET_VEHICLE_CUSTOM_PRIMARY_COLOUR(vehicle, &owned_mods[MOD_PRIMARY_COL_R], &owned_mods[MOD_PRIMARY_COL_G], &owned_mods[MOD_PRIMARY_COL_B]);
|
||||
}
|
||||
|
||||
owned_mods[MOD_SECONDARY_CUSTOM] = VEHICLE::GET_IS_VEHICLE_SECONDARY_COLOUR_CUSTOM(vehicle);
|
||||
if (owned_mods[MOD_SECONDARY_CUSTOM])
|
||||
{
|
||||
VEHICLE::GET_VEHICLE_CUSTOM_SECONDARY_COLOUR(vehicle, &owned_mods[MOD_SECONDARY_COL_R], &owned_mods[MOD_SECONDARY_COL_G], &owned_mods[MOD_SECONDARY_COL_B]);
|
||||
}
|
||||
|
||||
owned_mods[MOD_TYRE_SMOKE] = VEHICLE::IS_TOGGLE_MOD_ON(vehicle, MOD_TYRE_SMOKE);
|
||||
if (owned_mods[MOD_TYRE_SMOKE])
|
||||
{
|
||||
VEHICLE::GET_VEHICLE_TYRE_SMOKE_COLOR(vehicle, &owned_mods[MOD_TIRESMOKE_COL_R], &owned_mods[MOD_TIRESMOKE_COL_G], &owned_mods[MOD_TIRESMOKE_COL_B]);
|
||||
}
|
||||
|
||||
owned_mods[MOD_XENON_LIGHTS] = VEHICLE::IS_TOGGLE_MOD_ON(vehicle, MOD_XENON_LIGHTS);
|
||||
if (owned_mods[MOD_XENON_LIGHTS])
|
||||
{
|
||||
owned_mods[MOD_XENON_COL] = (int8_t)VEHICLE::GET_VEHICLE_XENON_LIGHT_COLOR_INDEX(vehicle);
|
||||
}
|
||||
|
||||
owned_mods[MOD_NEON_LEFT_ON] = VEHICLE::GET_VEHICLE_NEON_ENABLED(vehicle, NEON_LEFT);
|
||||
owned_mods[MOD_NEON_RIGHT_ON] = VEHICLE::GET_VEHICLE_NEON_ENABLED(vehicle, NEON_RIGHT);
|
||||
owned_mods[MOD_NEON_FRONT_ON] = VEHICLE::GET_VEHICLE_NEON_ENABLED(vehicle, NEON_FRONT);
|
||||
owned_mods[MOD_NEON_BACK_ON] = VEHICLE::GET_VEHICLE_NEON_ENABLED(vehicle, NEON_BACK);
|
||||
VEHICLE::GET_VEHICLE_NEON_COLOUR(vehicle, &owned_mods[MOD_NEON_COL_R], &owned_mods[MOD_NEON_COL_G], &owned_mods[MOD_NEON_COL_B]);
|
||||
|
||||
owned_mods[MOD_TIRE_CAN_BURST] = VEHICLE::GET_VEHICLE_TYRES_CAN_BURST(vehicle);
|
||||
owned_mods[MOD_DRIFT_TIRE] = VEHICLE::GET_DRIFT_TYRES_SET(vehicle);
|
||||
owned_mods[MOD_TURBO] = VEHICLE::IS_TOGGLE_MOD_ON(vehicle, MOD_TURBO);
|
||||
|
||||
owned_mods[MOD_FRONTWHEEL_VAR] = VEHICLE::GET_VEHICLE_MOD_VARIATION(vehicle, MOD_FRONTWHEEL);
|
||||
owned_mods[MOD_REARWHEEL_VAR] = VEHICLE::GET_VEHICLE_MOD_VARIATION(vehicle, MOD_REARWHEEL);
|
||||
|
||||
for (int slot = MOD_SPOILERS; slot <= MOD_LIGHTBAR; slot++)
|
||||
{
|
||||
int count = VEHICLE::GET_NUM_VEHICLE_MODS(vehicle, slot);
|
||||
if (count > 0)
|
||||
{
|
||||
int32_t val = VEHICLE::GET_VEHICLE_MOD(vehicle, slot);
|
||||
|
||||
if (val != -1)
|
||||
{
|
||||
owned_mods[slot] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int extra = MOD_EXTRA_11; extra <= MOD_EXTRA_0; extra++)
|
||||
{
|
||||
int gta_extra_id = (extra - MOD_EXTRA_0) * -1;
|
||||
if (VEHICLE::DOES_EXTRA_EXIST(vehicle, gta_extra_id))
|
||||
{
|
||||
owned_mods[extra] = VEHICLE::IS_VEHICLE_EXTRA_TURNED_ON(vehicle, gta_extra_id);
|
||||
}
|
||||
}
|
||||
|
||||
owned_mods[MOD_HAS_CLAN_LOGO] = GRAPHICS::DOES_VEHICLE_HAVE_CREW_EMBLEM(vehicle, 0);
|
||||
|
||||
return owned_mods;
|
||||
}
|
||||
|
||||
void teleport_into_vehicle(Vehicle veh)
|
||||
{
|
||||
PED::SET_PED_INTO_VEHICLE(self::ped, veh, -1);
|
||||
}
|
||||
|
||||
void max_vehicle(Vehicle veh)
|
||||
{
|
||||
Hash model = ENTITY::GET_ENTITY_MODEL(veh);
|
||||
|
||||
VEHICLE::SET_VEHICLE_MOD_KIT(veh, 0);
|
||||
|
||||
VEHICLE::TOGGLE_VEHICLE_MOD(veh, MOD_TURBO, TRUE);
|
||||
VEHICLE::TOGGLE_VEHICLE_MOD(veh, MOD_TYRE_SMOKE, TRUE);
|
||||
VEHICLE::TOGGLE_VEHICLE_MOD(veh, MOD_XENON_LIGHTS, TRUE);
|
||||
VEHICLE::SET_VEHICLE_WINDOW_TINT(veh, 1);
|
||||
VEHICLE::SET_VEHICLE_TYRES_CAN_BURST(veh, false);
|
||||
|
||||
for (int slot = MOD_SPOILERS; slot <= MOD_LIGHTBAR; slot++)
|
||||
{
|
||||
if (slot == MOD_LIVERY)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int count = VEHICLE::GET_NUM_VEHICLE_MODS(veh, slot);
|
||||
if (count > 0)
|
||||
{
|
||||
int selected_mod = -1;
|
||||
|
||||
for (int mod = count - 1; mod >= -1; mod--)
|
||||
{
|
||||
if (VEHICLE::IS_VEHICLE_MOD_GEN9_EXCLUSIVE(veh, slot, mod))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
selected_mod = mod;
|
||||
break;
|
||||
}
|
||||
|
||||
if (selected_mod != -1)
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_MOD(veh, slot, selected_mod, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void max_vehicle_performance(Vehicle veh)
|
||||
{
|
||||
if (entity::take_control_of(veh))
|
||||
{
|
||||
VehicleModType perfomance_mods[] = {MOD_ENGINE, MOD_BRAKES, MOD_TRANSMISSION, MOD_SUSPENSION, MOD_ARMOR, MOD_NITROUS, MOD_TURBO};
|
||||
VEHICLE::SET_VEHICLE_MOD_KIT(veh, 0);
|
||||
|
||||
for (auto mod_slot : perfomance_mods)
|
||||
{
|
||||
if (mod_slot != MOD_NITROUS && mod_slot != MOD_TURBO)
|
||||
VEHICLE::SET_VEHICLE_MOD(veh, mod_slot, VEHICLE::GET_NUM_VEHICLE_MODS(veh, mod_slot) - 1, true);
|
||||
else
|
||||
VEHICLE::TOGGLE_VEHICLE_MOD(veh, mod_slot, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_engine_state(Vehicle current_vehicle, bool state, bool immediately, bool disable_auto_start)
|
||||
{
|
||||
if (current_vehicle)
|
||||
VEHICLE::SET_VEHICLE_ENGINE_ON(current_vehicle, state, immediately, disable_auto_start);
|
||||
else
|
||||
return g_notification_service->push_warning("VEHICLE"_T.data(), "PLEASE_ENTER_VEHICLE"_T.data());
|
||||
}
|
||||
|
||||
void downgrade(Vehicle vehicle)
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_MOD_KIT(vehicle, 0);
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
VEHICLE::REMOVE_VEHICLE_MOD(vehicle, i);
|
||||
}
|
||||
}
|
||||
|
||||
bool remote_control_vehicle(Vehicle veh)
|
||||
{
|
||||
if (!entity::take_control_of(veh, 4000))
|
||||
{
|
||||
g_notification_service->push_warning("REMOTE_CONTROL"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (g.m_remote_controlled_vehicle == veh)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Hash model = ENTITY::GET_ENTITY_MODEL(veh);
|
||||
Vehicle spawned = vehicle::spawn(model, self::pos, 0.0f);
|
||||
|
||||
ENTITY::SET_ENTITY_ALPHA(spawned, 0, FALSE);
|
||||
if (!VEHICLE::IS_THIS_MODEL_A_BIKE(model))
|
||||
ENTITY::SET_ENTITY_VISIBLE(spawned, FALSE, FALSE);
|
||||
ENTITY::SET_ENTITY_INVINCIBLE(spawned, TRUE);
|
||||
|
||||
float heading = ENTITY::GET_ENTITY_HEADING(veh);
|
||||
Vector3 rotation = ENTITY::GET_ENTITY_ROTATION(veh, 2);
|
||||
Vector3 coords = ENTITY::GET_ENTITY_COORDS(veh, FALSE);
|
||||
Vector3 velocity = ENTITY::GET_ENTITY_VELOCITY(veh);
|
||||
|
||||
ENTITY::SET_ENTITY_COORDS_NO_OFFSET(spawned, coords.x, coords.y, coords.z, FALSE, FALSE, FALSE);
|
||||
ENTITY::SET_ENTITY_HEADING(spawned, heading);
|
||||
ENTITY::SET_ENTITY_ROTATION(spawned, rotation.x, rotation.y, rotation.z, 2, TRUE);
|
||||
|
||||
ENTITY::SET_ENTITY_VISIBLE(veh, TRUE, FALSE);
|
||||
|
||||
ENTITY::SET_ENTITY_COLLISION(veh, FALSE, FALSE);
|
||||
ENTITY::SET_ENTITY_INVINCIBLE(veh, TRUE);
|
||||
VEHICLE::SET_VEHICLE_DOORS_LOCKED(veh, 4);
|
||||
VEHICLE::SET_VEHICLE_MAX_SPEED(veh, 0.0001f);
|
||||
ENTITY::ATTACH_ENTITY_TO_ENTITY(veh, spawned, 0, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, FALSE, FALSE, FALSE, FALSE, 0, TRUE, FALSE);
|
||||
PED::SET_PED_INTO_VEHICLE(PLAYER::PLAYER_PED_ID(), spawned, -1);
|
||||
|
||||
VEHICLE::SET_VEHICLE_ENGINE_ON(spawned, TRUE, TRUE, FALSE);
|
||||
ENTITY::SET_ENTITY_VELOCITY(spawned, velocity.x, velocity.y, velocity.z);
|
||||
VEHICLE::COPY_VEHICLE_DAMAGES(veh, spawned);
|
||||
|
||||
g.m_remote_controller_vehicle = spawned;
|
||||
g.m_remote_controlled_vehicle = veh;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Set doorId to eDoorId::VEH_EXT_DOOR_INVALID_ID or simply -1 to apply to all vehicle doors.
|
||||
*/
|
||||
bool change_vehicle_door_lock_state(Vehicle veh, eDoorId doorId, eVehicleLockState state)
|
||||
{
|
||||
if (ENTITY::DOES_ENTITY_EXIST(veh))
|
||||
{
|
||||
if (doorId == eDoorId::VEH_EXT_DOOR_INVALID_ID)
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_DOORS_LOCKED(veh, (int)state);
|
||||
for (int i = 0; i < 6; i++)
|
||||
VEHICLE::SET_VEHICLE_INDIVIDUAL_DOORS_LOCKED(veh, i, (int)state);
|
||||
return VEHICLE::GET_VEHICLE_DOOR_LOCK_STATUS(veh) == (int)state;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (VEHICLE::GET_IS_DOOR_VALID(veh, (int)doorId))
|
||||
VEHICLE::SET_VEHICLE_INDIVIDUAL_DOORS_LOCKED(veh, (int)doorId, (int)state);
|
||||
|
||||
return VEHICLE::GET_VEHICLE_INDIVIDUAL_DOOR_LOCK_STATUS(veh, (int)doorId) == (int)state;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set 'open' to false to close the door.
|
||||
* Set doorId to eDoorId::VEH_EXT_DOOR_INVALID_ID or simply -1 to apply to all doors.
|
||||
*/
|
||||
bool operate_vehicle_door(Vehicle veh, eDoorId doorId, bool open)
|
||||
{
|
||||
bool success = false;
|
||||
if (ENTITY::DOES_ENTITY_EXIST(veh))
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
if (doorId == eDoorId::VEH_EXT_DOOR_INVALID_ID || (int)doorId == i)
|
||||
{
|
||||
if (VEHICLE::GET_IS_DOOR_VALID(veh, i))
|
||||
{
|
||||
if (open)
|
||||
VEHICLE::SET_VEHICLE_DOOR_OPEN(veh, i, false, false);
|
||||
else
|
||||
VEHICLE::SET_VEHICLE_DOOR_SHUT(veh, i, false);
|
||||
}
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool operate_vehicle_window(Vehicle veh, eWindowId windowId, bool open)
|
||||
{
|
||||
bool success = false;
|
||||
if (ENTITY::DOES_ENTITY_EXIST(veh))
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (windowId == eWindowId::WINDOW_INVALID_ID)
|
||||
{
|
||||
if (open)
|
||||
VEHICLE::ROLL_DOWN_WINDOWS(veh);
|
||||
else
|
||||
VEHICLE::ROLL_UP_WINDOW(veh, i);
|
||||
}
|
||||
|
||||
if ((int)windowId == i)
|
||||
{
|
||||
if (open)
|
||||
VEHICLE::ROLL_DOWN_WINDOW(veh, i);
|
||||
else
|
||||
VEHICLE::ROLL_UP_WINDOW(veh, i);
|
||||
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool operate_vehicle_headlights(Vehicle veh, bool lights, bool highbeams)
|
||||
{
|
||||
if (ENTITY::DOES_ENTITY_EXIST(veh))
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_FULLBEAM(veh, highbeams);
|
||||
VEHICLE::SET_VEHICLE_LIGHTS(veh, lights ? 3 : 4);
|
||||
int regular, highbeam;
|
||||
VEHICLE::GET_VEHICLE_LIGHTS_STATE(veh, ®ular, &highbeam);
|
||||
return regular == (int)lights && (int)highbeams == highbeam;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Input index -1 to apply to all neons.
|
||||
*/
|
||||
bool operate_vehicle_neons(Vehicle veh, int index, bool toggle)
|
||||
{
|
||||
bool success = false;
|
||||
if (ENTITY::DOES_ENTITY_EXIST(veh))
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_MOD_KIT(veh, 0);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (index == -1 || index == i)
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_NEON_ENABLED(veh, index, toggle);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
@ -18,796 +18,42 @@ namespace big::vehicle
|
||||
inline static memory::byte_patch* m_patch;
|
||||
};
|
||||
|
||||
inline float mps_to_speed(float mps, SpeedUnit speed_unit)
|
||||
{
|
||||
switch (speed_unit)
|
||||
{
|
||||
case SpeedUnit::KMPH: return mps * 3.6f; break;
|
||||
case SpeedUnit::MIPH: return mps * 2.2369f; break;
|
||||
}
|
||||
|
||||
return mps;
|
||||
}
|
||||
|
||||
inline float speed_to_mps(float speed, SpeedUnit speed_unit)
|
||||
{
|
||||
switch (speed_unit)
|
||||
{
|
||||
case SpeedUnit::KMPH: return speed / 3.6f; break;
|
||||
case SpeedUnit::MIPH: return speed / 2.2369f; break;
|
||||
}
|
||||
|
||||
return speed;
|
||||
}
|
||||
|
||||
inline Vector3 get_spawn_location(bool spawn_inside, Hash hash, Ped ped = self::ped)
|
||||
{
|
||||
float y_offset = 0;
|
||||
|
||||
if (self::veh != 0)
|
||||
{
|
||||
Vector3 min, max, result;
|
||||
MISC::GET_MODEL_DIMENSIONS(hash, &min, &max);
|
||||
result = max - min;
|
||||
y_offset = result.y;
|
||||
}
|
||||
else if (!spawn_inside)
|
||||
{
|
||||
y_offset = 5.f;
|
||||
}
|
||||
|
||||
return ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(ped, 0.f, y_offset, 0.f);
|
||||
}
|
||||
|
||||
inline void set_mp_bitset(Vehicle veh)
|
||||
{
|
||||
DECORATOR::DECOR_SET_INT(veh, "MPBitset", 0);
|
||||
DECORATOR::DECOR_SET_INT(veh, "RandomId", g_local_player->m_net_object->m_object_id);
|
||||
auto networkId = NETWORK::VEH_TO_NET(veh);
|
||||
if (NETWORK::NETWORK_GET_ENTITY_IS_NETWORKED(veh))
|
||||
NETWORK::SET_NETWORK_ID_EXISTS_ON_ALL_MACHINES(networkId, true);
|
||||
VEHICLE::SET_VEHICLE_IS_STOLEN(veh, FALSE);
|
||||
}
|
||||
|
||||
inline void bring(Vehicle veh, Vector3 location, bool put_in = true, int seatIdx = -1)
|
||||
{
|
||||
if (!ENTITY::IS_ENTITY_A_VEHICLE(veh))
|
||||
return g_notification_service->push_error("VEHICLE"_T.data(), "VEHICLE_INVALID"_T.data());
|
||||
|
||||
auto vecVehicleLocation = ENTITY::GET_ENTITY_COORDS(veh, true);
|
||||
entity::load_ground_at_3dcoord(vecVehicleLocation);
|
||||
|
||||
if (!entity::take_control_of(veh))
|
||||
return g_notification_service->push_warning("VEHICLE"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
|
||||
auto ped = self::ped;
|
||||
|
||||
ENTITY::SET_ENTITY_COORDS(veh, location.x, location.y, location.z + 1.f, 0, 0, 0, 0);
|
||||
ENTITY::SET_ENTITY_HEADING(veh, ENTITY::GET_ENTITY_HEADING(ped));
|
||||
|
||||
if (put_in)
|
||||
{
|
||||
for (size_t i = 0; i < 100 && math::distance_between_vectors(location, ENTITY::GET_ENTITY_COORDS(veh, true)) > 10; i++)
|
||||
script::get_current()->yield();
|
||||
|
||||
auto driver_ped = VEHICLE::GET_PED_IN_VEHICLE_SEAT(veh, -1, false);
|
||||
|
||||
if (driver_ped != 0)
|
||||
{
|
||||
if (PED::GET_PED_TYPE(driver_ped) == ePedType::PED_TYPE_NETWORK_PLAYER)
|
||||
{
|
||||
TASK::CLEAR_PED_TASKS_IMMEDIATELY(driver_ped);
|
||||
}
|
||||
else
|
||||
{
|
||||
entity::delete_entity(driver_ped);
|
||||
}
|
||||
}
|
||||
|
||||
PED::SET_PED_INTO_VEHICLE(ped, veh, seatIdx);
|
||||
}
|
||||
}
|
||||
|
||||
inline Vehicle get_closest_to_location(Vector3 location, float range)
|
||||
{
|
||||
float min_dist = FLT_MAX;
|
||||
int32_t m_handle = 0;
|
||||
|
||||
for (const auto veh_entity : pools::get_all_vehicles())
|
||||
{
|
||||
const auto veh_ptr = veh_entity;
|
||||
if (!veh_ptr || !veh_ptr->m_navigation)
|
||||
continue;
|
||||
|
||||
auto veh_pos_arr = *veh_ptr->m_navigation->get_position();
|
||||
Vector3 veh_pos(veh_pos_arr.x, veh_pos_arr.y, veh_pos_arr.z);
|
||||
|
||||
float dist = math::distance_between_vectors(veh_pos, location);
|
||||
|
||||
if (dist < min_dist)
|
||||
{
|
||||
int32_t tmp_handle = g_pointers->m_gta.m_ptr_to_handle(veh_ptr);
|
||||
|
||||
if (entity::take_control_of(tmp_handle))
|
||||
{
|
||||
min_dist = dist;
|
||||
m_handle = tmp_handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
inline bool set_plate(Vehicle veh, const char* plate)
|
||||
{
|
||||
if (!ENTITY::IS_ENTITY_A_VEHICLE(veh) || !entity::take_control_of(veh))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (plate != nullptr && plate[0] != 0)
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_NUMBER_PLATE_TEXT(veh, plate);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool repair(Vehicle veh)
|
||||
{
|
||||
if (!ENTITY::IS_ENTITY_A_VEHICLE(veh) || !entity::take_control_of(veh, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
VEHICLE::SET_VEHICLE_FIXED(veh);
|
||||
VEHICLE::SET_VEHICLE_DIRT_LEVEL(veh, 0.f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline Vehicle spawn(Hash hash, Vector3 location, float heading, bool is_networked = true, bool script_veh = false)
|
||||
{
|
||||
for (int i = 0; !STREAMING::HAS_MODEL_LOADED(hash) && i < 100; i++)
|
||||
{
|
||||
STREAMING::REQUEST_MODEL(hash);
|
||||
script::get_current()->yield();
|
||||
}
|
||||
|
||||
if (!STREAMING::HAS_MODEL_LOADED(hash))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto veh = VEHICLE::CREATE_VEHICLE(hash, location.x, location.y, location.z, heading, is_networked, script_veh, false);
|
||||
|
||||
STREAMING::SET_MODEL_AS_NO_LONGER_NEEDED(hash);
|
||||
|
||||
if (*g_pointers->m_gta.m_is_session_started)
|
||||
{
|
||||
set_mp_bitset(veh);
|
||||
}
|
||||
|
||||
return veh;
|
||||
}
|
||||
|
||||
inline Vehicle clone_from_vehicle_data(std::map<int, int32_t>& data, Vector3 location, float heading)
|
||||
{
|
||||
Vector3 tmpLocation = {location.x, location.y, 1200.0f};
|
||||
if (location.z > 1000.0f && location.z < 1400.0)
|
||||
{
|
||||
tmpLocation.z = 800.0f;
|
||||
}
|
||||
|
||||
// vehicle data
|
||||
for (const auto& [idx, val] : data)
|
||||
{
|
||||
if (idx >= 0 && idx < 142)
|
||||
{
|
||||
*scr_globals::spawn_global.at(27).at(idx).as<int32_t*>() = val;
|
||||
}
|
||||
}
|
||||
|
||||
// permission fix
|
||||
*scr_globals::spawn_global.at(27).at(1).as<int32_t*>() = 0;
|
||||
|
||||
// personal car flag
|
||||
*scr_globals::spawn_global.at(27).at(94).as<int32_t*>() = 14;
|
||||
*scr_globals::spawn_global.at(27).at(95).as<int32_t*>() = 2;
|
||||
|
||||
// mmi
|
||||
*scr_globals::spawn_global.at(27).at(103).as<int32_t*>() = 0;
|
||||
|
||||
// spawn location
|
||||
*scr_globals::spawn_global.at(7).at(0).as<float*>() = tmpLocation.x;
|
||||
*scr_globals::spawn_global.at(7).at(1).as<float*>() = tmpLocation.y;
|
||||
*scr_globals::spawn_global.at(7).at(2).as<float*>() = tmpLocation.z;
|
||||
|
||||
// spawn non pegasus
|
||||
*scr_globals::spawn_global.at(3).as<int*>() = 0;
|
||||
|
||||
// spawn signal
|
||||
int* spawn_signal = scr_globals::spawn_global.at(2).as<int32_t*>();
|
||||
*scr_globals::spawn_global.at(5).as<int32_t*>() = 1;
|
||||
*spawn_signal = 1;
|
||||
|
||||
// wait until the vehicle is spawned
|
||||
for (size_t retry = 0; *spawn_signal != 0 && retry < 200; retry++)
|
||||
{
|
||||
script::get_current()->yield(10ms);
|
||||
}
|
||||
|
||||
if (*spawn_signal == 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto veh = vehicle::get_closest_to_location(tmpLocation, 200);
|
||||
if (veh == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ENTITY::SET_ENTITY_COORDS(veh, location.x, location.y, location.z + 1.f, 0, 0, 0, 0);
|
||||
ENTITY::SET_ENTITY_HEADING(veh, heading);
|
||||
|
||||
return veh;
|
||||
}
|
||||
|
||||
inline std::map<int, int32_t> get_vehicle_data_from_vehicle_idx(script_global vehicle_idx)
|
||||
{
|
||||
std::map<int, int32_t> veh_data;
|
||||
|
||||
for (int i = 0; i < 142; i++)
|
||||
{
|
||||
veh_data[i] = *vehicle_idx.at(i).as<int32_t*>();
|
||||
}
|
||||
|
||||
veh_data.erase(1);
|
||||
veh_data.erase(94);
|
||||
veh_data.erase(95);
|
||||
veh_data.erase(103);
|
||||
|
||||
return veh_data;
|
||||
}
|
||||
|
||||
inline std::map<int, int32_t> get_owned_mods_from_vehicle_idx(script_global vehicle_idx)
|
||||
{
|
||||
std::map<int, int32_t> owned_mods;
|
||||
|
||||
for (int i = MOD_SECONDARY_CUSTOM; i <= MOD_MODEL_HASH; i++)
|
||||
{
|
||||
owned_mods[i] = 0;
|
||||
}
|
||||
|
||||
int32_t val_32 = *vehicle_idx.at(32).as<int32_t*>();
|
||||
int32_t val_77 = *vehicle_idx.at(77).as<int32_t*>();
|
||||
int32_t val_102 = *vehicle_idx.at(102).as<int32_t*>();
|
||||
|
||||
|
||||
owned_mods[MOD_MODEL_HASH] = *vehicle_idx.at(66).as<int32_t*>();
|
||||
|
||||
owned_mods[MOD_PLATE_STYLE] = *vehicle_idx.at(0).as<int32_t*>();
|
||||
owned_mods[MOD_WINDOW_TINT] = *vehicle_idx.at(65).as<int32_t*>();
|
||||
owned_mods[MOD_WHEEL_TYPE] = *vehicle_idx.at(69).as<int32_t*>();
|
||||
|
||||
|
||||
owned_mods[MOD_PRIMARY_COL] = *vehicle_idx.at(5).as<int32_t*>();
|
||||
owned_mods[MOD_SECONDARY_COL] = *vehicle_idx.at(6).as<int32_t*>();
|
||||
owned_mods[MOD_PEARLESCENT_COL] = *vehicle_idx.at(7).as<int32_t*>();
|
||||
owned_mods[MOD_WHEEL_COL] = *vehicle_idx.at(8).as<int32_t*>();
|
||||
owned_mods[MOD_INTERIOR_COL] = *vehicle_idx.at(97).as<int32_t*>();
|
||||
owned_mods[MOD_DASHBOARD_COL] = *vehicle_idx.at(99).as<int32_t*>();
|
||||
|
||||
|
||||
//CUSTOM PRIMARY
|
||||
owned_mods[MOD_PRIMARY_CUSTOM] = (val_77 & (1 << 13)) != 0;
|
||||
if (owned_mods[MOD_PRIMARY_CUSTOM])
|
||||
{
|
||||
owned_mods[MOD_PRIMARY_COL_R] = *vehicle_idx.at(71).as<int32_t*>();
|
||||
owned_mods[MOD_PRIMARY_COL_G] = *vehicle_idx.at(72).as<int32_t*>();
|
||||
owned_mods[MOD_PRIMARY_COL_B] = *vehicle_idx.at(73).as<int32_t*>();
|
||||
}
|
||||
|
||||
|
||||
//CUSTOM SECONDARY
|
||||
owned_mods[MOD_SECONDARY_CUSTOM] = (val_77 & (1 << 12)) != 0;
|
||||
if (owned_mods[MOD_SECONDARY_CUSTOM])
|
||||
{
|
||||
owned_mods[MOD_SECONDARY_COL_R] = *vehicle_idx.at(71).as<int32_t*>();
|
||||
owned_mods[MOD_SECONDARY_COL_G] = *vehicle_idx.at(72).as<int32_t*>();
|
||||
owned_mods[MOD_SECONDARY_COL_B] = *vehicle_idx.at(73).as<int32_t*>();
|
||||
}
|
||||
|
||||
|
||||
// TIRE SMOKE
|
||||
owned_mods[MOD_TIRESMOKE_COL_R] = *vehicle_idx.at(62).as<int32_t*>();
|
||||
owned_mods[MOD_TIRESMOKE_COL_G] = *vehicle_idx.at(63).as<int32_t*>();
|
||||
owned_mods[MOD_TIRESMOKE_COL_B] = *vehicle_idx.at(64).as<int32_t*>();
|
||||
owned_mods[MOD_TYRE_SMOKE] = !(owned_mods[MOD_TIRESMOKE_COL_R] == 255 && owned_mods[MOD_TIRESMOKE_COL_G] == 255 && owned_mods[MOD_TIRESMOKE_COL_B] == 255);
|
||||
|
||||
|
||||
// XENON
|
||||
if (val_32 > 0)
|
||||
{
|
||||
owned_mods[MOD_XENON_LIGHTS] = 1;
|
||||
owned_mods[MOD_XENON_COL] = val_32 - 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
owned_mods[MOD_XENON_LIGHTS] = 0;
|
||||
}
|
||||
|
||||
|
||||
// NEON
|
||||
owned_mods[MOD_NEON_LEFT_ON] = (val_77 & (1 << 30)) != 0;
|
||||
owned_mods[MOD_NEON_RIGHT_ON] = (val_77 & (1 << 31)) != 0;
|
||||
owned_mods[MOD_NEON_FRONT_ON] = (val_77 & (1 << 28)) != 0;
|
||||
owned_mods[MOD_NEON_BACK_ON] = (val_77 & (1 << 29)) != 0;
|
||||
owned_mods[MOD_NEON_COL_R] = *vehicle_idx.at(74).as<int32_t*>();
|
||||
owned_mods[MOD_NEON_COL_G] = *vehicle_idx.at(75).as<int32_t*>();
|
||||
owned_mods[MOD_NEON_COL_B] = *vehicle_idx.at(76).as<int32_t*>();
|
||||
|
||||
// TIRE OPTIONS
|
||||
owned_mods[MOD_TIRE_CAN_BURST] = (val_77 & (1 << 9)) == 0;
|
||||
if ((val_102 & 0b11) == 0b11)
|
||||
{
|
||||
owned_mods[MOD_DRIFT_TIRE] = 1;
|
||||
}
|
||||
|
||||
owned_mods[MOD_TURBO] = *vehicle_idx.at(28).as<int32_t*>() != 0;
|
||||
|
||||
owned_mods[MOD_FRONTWHEEL_VAR] = *vehicle_idx.at(60).as<int32_t*>() != 0;
|
||||
owned_mods[MOD_REARWHEEL_VAR] = *vehicle_idx.at(61).as<int32_t*>() != 0;
|
||||
|
||||
|
||||
// OTHER MODS
|
||||
for (int slot = MOD_SPOILERS; slot <= MOD_LIGHTBAR; slot++)
|
||||
{
|
||||
if (slot == MOD_TURBO || slot == MOD_TYRE_SMOKE || slot == MOD_XENON_LIGHTS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int32_t val = *vehicle_idx.at(10 + slot).as<int32_t*>() - 1;
|
||||
if (val != -1)
|
||||
{
|
||||
owned_mods[slot] = val;
|
||||
}
|
||||
}
|
||||
|
||||
// EXTRA
|
||||
for (int extra = MOD_EXTRA_9; extra <= MOD_EXTRA_1; extra++)
|
||||
{
|
||||
int gta_extra_id = (extra - MOD_EXTRA_0) * -1;
|
||||
owned_mods[extra] = val_77 >> (gta_extra_id - 1) & 1;
|
||||
}
|
||||
|
||||
return owned_mods;
|
||||
}
|
||||
|
||||
|
||||
inline Vehicle clone_from_owned_mods(std::map<int, int32_t> owned_mods, Vector3 location, float heading, bool is_networked = true)
|
||||
{
|
||||
auto vehicle = spawn(owned_mods[MOD_MODEL_HASH], location, heading, is_networked);
|
||||
if (vehicle == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i = MOD_NEON_COL_B; i <= MOD_MODEL_HASH; i++)
|
||||
{
|
||||
if (owned_mods.count(i) == 0)
|
||||
{
|
||||
owned_mods[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
VEHICLE::SET_VEHICLE_MOD_KIT(vehicle, 0);
|
||||
script::get_current()->yield(10ms);
|
||||
|
||||
VEHICLE::SET_VEHICLE_NUMBER_PLATE_TEXT_INDEX(vehicle, owned_mods[MOD_PLATE_STYLE]);
|
||||
VEHICLE::SET_VEHICLE_WINDOW_TINT(vehicle, owned_mods[MOD_WINDOW_TINT]);
|
||||
VEHICLE::SET_VEHICLE_WHEEL_TYPE(vehicle, owned_mods[MOD_WHEEL_TYPE]);
|
||||
script::get_current()->yield(10ms);
|
||||
|
||||
VEHICLE::SET_VEHICLE_COLOURS(vehicle, owned_mods[MOD_PRIMARY_COL], owned_mods[MOD_SECONDARY_COL]);
|
||||
VEHICLE::SET_VEHICLE_EXTRA_COLOURS(vehicle, owned_mods[MOD_PEARLESCENT_COL], owned_mods[MOD_WHEEL_COL]);
|
||||
VEHICLE::SET_VEHICLE_EXTRA_COLOUR_5(vehicle, owned_mods[MOD_INTERIOR_COL]);
|
||||
VEHICLE::SET_VEHICLE_EXTRA_COLOUR_6(vehicle, owned_mods[MOD_DASHBOARD_COL]);
|
||||
|
||||
if (owned_mods[MOD_PRIMARY_CUSTOM])
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_CUSTOM_PRIMARY_COLOUR(vehicle, owned_mods[MOD_PRIMARY_COL_R], owned_mods[MOD_PRIMARY_COL_G], owned_mods[MOD_PRIMARY_COL_B]);
|
||||
}
|
||||
|
||||
if (owned_mods[MOD_SECONDARY_CUSTOM])
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_CUSTOM_SECONDARY_COLOUR(vehicle, owned_mods[MOD_SECONDARY_COL_R], owned_mods[MOD_SECONDARY_COL_G], owned_mods[MOD_SECONDARY_COL_B]);
|
||||
}
|
||||
|
||||
if (owned_mods[MOD_TYRE_SMOKE])
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_TYRE_SMOKE_COLOR(vehicle, owned_mods[MOD_TIRESMOKE_COL_R], owned_mods[MOD_TIRESMOKE_COL_G], owned_mods[MOD_TIRESMOKE_COL_B]);
|
||||
VEHICLE::TOGGLE_VEHICLE_MOD(vehicle, MOD_TYRE_SMOKE, owned_mods[MOD_TYRE_SMOKE]);
|
||||
}
|
||||
|
||||
if (owned_mods[MOD_XENON_LIGHTS])
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_XENON_LIGHT_COLOR_INDEX(vehicle, owned_mods[MOD_XENON_COL]);
|
||||
VEHICLE::TOGGLE_VEHICLE_MOD(vehicle, MOD_XENON_LIGHTS, owned_mods[MOD_XENON_LIGHTS]);
|
||||
}
|
||||
|
||||
VEHICLE::SET_VEHICLE_NEON_COLOUR(vehicle, owned_mods[MOD_NEON_COL_R], owned_mods[MOD_NEON_COL_G], owned_mods[MOD_NEON_COL_B]);
|
||||
VEHICLE::SET_VEHICLE_NEON_ENABLED(vehicle, NEON_LEFT, owned_mods[MOD_NEON_LEFT_ON]);
|
||||
VEHICLE::SET_VEHICLE_NEON_ENABLED(vehicle, NEON_RIGHT, owned_mods[MOD_NEON_RIGHT_ON]);
|
||||
VEHICLE::SET_VEHICLE_NEON_ENABLED(vehicle, NEON_FRONT, owned_mods[MOD_NEON_FRONT_ON]);
|
||||
VEHICLE::SET_VEHICLE_NEON_ENABLED(vehicle, NEON_BACK, owned_mods[MOD_NEON_BACK_ON]);
|
||||
|
||||
|
||||
VEHICLE::SET_VEHICLE_TYRES_CAN_BURST(vehicle, owned_mods[MOD_TIRE_CAN_BURST]);
|
||||
VEHICLE::SET_DRIFT_TYRES(vehicle, owned_mods[MOD_DRIFT_TIRE]);
|
||||
VEHICLE::TOGGLE_VEHICLE_MOD(vehicle, MOD_TURBO, owned_mods[MOD_TURBO]);
|
||||
|
||||
for (int slot = MOD_SPOILERS; slot <= MOD_LIGHTBAR; slot++)
|
||||
{
|
||||
if (owned_mods.count(slot) && owned_mods[slot] != -1)
|
||||
{
|
||||
bool custom_tire = false;
|
||||
|
||||
if (slot == MOD_FRONTWHEEL)
|
||||
{
|
||||
custom_tire = owned_mods[MOD_FRONTWHEEL_VAR];
|
||||
}
|
||||
else if (slot == MOD_REARWHEEL)
|
||||
{
|
||||
custom_tire = owned_mods[MOD_REARWHEEL_VAR];
|
||||
}
|
||||
|
||||
VEHICLE::SET_VEHICLE_MOD(vehicle, slot, owned_mods[slot], custom_tire);
|
||||
}
|
||||
}
|
||||
|
||||
for (int extra = MOD_EXTRA_14; extra <= MOD_EXTRA_1; extra++)
|
||||
{
|
||||
int gta_extra_id = (extra - MOD_EXTRA_0) * -1;
|
||||
if (owned_mods.count(extra) && VEHICLE::DOES_EXTRA_EXIST(vehicle, gta_extra_id))
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_EXTRA(vehicle, gta_extra_id, owned_mods[extra] == 0);
|
||||
}
|
||||
}
|
||||
|
||||
return vehicle;
|
||||
}
|
||||
|
||||
inline std::map<int, int32_t> get_owned_mods_from_vehicle(Vehicle vehicle)
|
||||
{
|
||||
std::map<int, int32_t> owned_mods;
|
||||
|
||||
for (int i = MOD_SECONDARY_CUSTOM; i <= MOD_MODEL_HASH; i++)
|
||||
{
|
||||
owned_mods[i] = 0;
|
||||
}
|
||||
|
||||
owned_mods[MOD_MODEL_HASH] = ENTITY::GET_ENTITY_MODEL(vehicle);
|
||||
|
||||
owned_mods[MOD_PLATE_STYLE] = VEHICLE::GET_VEHICLE_NUMBER_PLATE_TEXT_INDEX(vehicle);
|
||||
owned_mods[MOD_WINDOW_TINT] = VEHICLE::GET_VEHICLE_WINDOW_TINT(vehicle);
|
||||
owned_mods[MOD_WHEEL_TYPE] = VEHICLE::GET_VEHICLE_WHEEL_TYPE(vehicle);
|
||||
|
||||
VEHICLE::GET_VEHICLE_COLOURS(vehicle, &owned_mods[MOD_PRIMARY_COL], &owned_mods[MOD_SECONDARY_COL]);
|
||||
VEHICLE::GET_VEHICLE_EXTRA_COLOURS(vehicle, &owned_mods[MOD_PEARLESCENT_COL], &owned_mods[MOD_WHEEL_COL]);
|
||||
VEHICLE::GET_VEHICLE_EXTRA_COLOUR_5(vehicle, &owned_mods[MOD_INTERIOR_COL]);
|
||||
VEHICLE::GET_VEHICLE_EXTRA_COLOUR_6(vehicle, &owned_mods[MOD_DASHBOARD_COL]);
|
||||
|
||||
owned_mods[MOD_PRIMARY_CUSTOM] = VEHICLE::GET_IS_VEHICLE_PRIMARY_COLOUR_CUSTOM(vehicle);
|
||||
if (owned_mods[MOD_PRIMARY_CUSTOM])
|
||||
{
|
||||
VEHICLE::GET_VEHICLE_CUSTOM_PRIMARY_COLOUR(vehicle, &owned_mods[MOD_PRIMARY_COL_R], &owned_mods[MOD_PRIMARY_COL_G], &owned_mods[MOD_PRIMARY_COL_B]);
|
||||
}
|
||||
|
||||
owned_mods[MOD_SECONDARY_CUSTOM] = VEHICLE::GET_IS_VEHICLE_SECONDARY_COLOUR_CUSTOM(vehicle);
|
||||
if (owned_mods[MOD_SECONDARY_CUSTOM])
|
||||
{
|
||||
VEHICLE::GET_VEHICLE_CUSTOM_SECONDARY_COLOUR(vehicle, &owned_mods[MOD_SECONDARY_COL_R], &owned_mods[MOD_SECONDARY_COL_G], &owned_mods[MOD_SECONDARY_COL_B]);
|
||||
}
|
||||
|
||||
owned_mods[MOD_TYRE_SMOKE] = VEHICLE::IS_TOGGLE_MOD_ON(vehicle, MOD_TYRE_SMOKE);
|
||||
if (owned_mods[MOD_TYRE_SMOKE])
|
||||
{
|
||||
VEHICLE::GET_VEHICLE_TYRE_SMOKE_COLOR(vehicle, &owned_mods[MOD_TIRESMOKE_COL_R], &owned_mods[MOD_TIRESMOKE_COL_G], &owned_mods[MOD_TIRESMOKE_COL_B]);
|
||||
}
|
||||
|
||||
owned_mods[MOD_XENON_LIGHTS] = VEHICLE::IS_TOGGLE_MOD_ON(vehicle, MOD_XENON_LIGHTS);
|
||||
if (owned_mods[MOD_XENON_LIGHTS])
|
||||
{
|
||||
owned_mods[MOD_XENON_COL] = (int8_t)VEHICLE::GET_VEHICLE_XENON_LIGHT_COLOR_INDEX(vehicle);
|
||||
}
|
||||
|
||||
owned_mods[MOD_NEON_LEFT_ON] = VEHICLE::GET_VEHICLE_NEON_ENABLED(vehicle, NEON_LEFT);
|
||||
owned_mods[MOD_NEON_RIGHT_ON] = VEHICLE::GET_VEHICLE_NEON_ENABLED(vehicle, NEON_RIGHT);
|
||||
owned_mods[MOD_NEON_FRONT_ON] = VEHICLE::GET_VEHICLE_NEON_ENABLED(vehicle, NEON_FRONT);
|
||||
owned_mods[MOD_NEON_BACK_ON] = VEHICLE::GET_VEHICLE_NEON_ENABLED(vehicle, NEON_BACK);
|
||||
VEHICLE::GET_VEHICLE_NEON_COLOUR(vehicle, &owned_mods[MOD_NEON_COL_R], &owned_mods[MOD_NEON_COL_G], &owned_mods[MOD_NEON_COL_B]);
|
||||
|
||||
owned_mods[MOD_TIRE_CAN_BURST] = VEHICLE::GET_VEHICLE_TYRES_CAN_BURST(vehicle);
|
||||
owned_mods[MOD_DRIFT_TIRE] = VEHICLE::GET_DRIFT_TYRES_SET(vehicle);
|
||||
owned_mods[MOD_TURBO] = VEHICLE::IS_TOGGLE_MOD_ON(vehicle, MOD_TURBO);
|
||||
|
||||
owned_mods[MOD_FRONTWHEEL_VAR] = VEHICLE::GET_VEHICLE_MOD_VARIATION(vehicle, MOD_FRONTWHEEL);
|
||||
owned_mods[MOD_REARWHEEL_VAR] = VEHICLE::GET_VEHICLE_MOD_VARIATION(vehicle, MOD_REARWHEEL);
|
||||
|
||||
for (int slot = MOD_SPOILERS; slot <= MOD_LIGHTBAR; slot++)
|
||||
{
|
||||
int count = VEHICLE::GET_NUM_VEHICLE_MODS(vehicle, slot);
|
||||
if (count > 0)
|
||||
{
|
||||
int32_t val = VEHICLE::GET_VEHICLE_MOD(vehicle, slot);
|
||||
|
||||
if (val != -1)
|
||||
{
|
||||
owned_mods[slot] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int extra = MOD_EXTRA_14; extra <= MOD_EXTRA_1; extra++)
|
||||
{
|
||||
int gta_extra_id = (extra - MOD_EXTRA_0) * -1;
|
||||
if (VEHICLE::DOES_EXTRA_EXIST(vehicle, gta_extra_id))
|
||||
{
|
||||
owned_mods[extra] = VEHICLE::IS_VEHICLE_EXTRA_TURNED_ON(vehicle, gta_extra_id);
|
||||
}
|
||||
}
|
||||
|
||||
return owned_mods;
|
||||
}
|
||||
|
||||
inline void teleport_into_vehicle(Vehicle veh)
|
||||
{
|
||||
PED::SET_PED_INTO_VEHICLE(self::ped, veh, -1);
|
||||
}
|
||||
|
||||
inline void max_vehicle(Vehicle veh)
|
||||
{
|
||||
Hash model = ENTITY::GET_ENTITY_MODEL(veh);
|
||||
|
||||
VEHICLE::SET_VEHICLE_MOD_KIT(veh, 0);
|
||||
|
||||
VEHICLE::TOGGLE_VEHICLE_MOD(veh, MOD_TURBO, TRUE);
|
||||
VEHICLE::TOGGLE_VEHICLE_MOD(veh, MOD_TYRE_SMOKE, TRUE);
|
||||
VEHICLE::TOGGLE_VEHICLE_MOD(veh, MOD_XENON_LIGHTS, TRUE);
|
||||
VEHICLE::SET_VEHICLE_WINDOW_TINT(veh, 1);
|
||||
VEHICLE::SET_VEHICLE_TYRES_CAN_BURST(veh, false);
|
||||
|
||||
for (int slot = MOD_SPOILERS; slot <= MOD_LIGHTBAR; slot++)
|
||||
{
|
||||
if (slot == MOD_LIVERY)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int count = VEHICLE::GET_NUM_VEHICLE_MODS(veh, slot);
|
||||
if (count > 0)
|
||||
{
|
||||
int selected_mod = -1;
|
||||
|
||||
for (int mod = count - 1; mod >= -1; mod--)
|
||||
{
|
||||
if (VEHICLE::IS_VEHICLE_MOD_GEN9_EXCLUSIVE(veh, slot, mod))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
selected_mod = mod;
|
||||
break;
|
||||
}
|
||||
|
||||
if (selected_mod != -1)
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_MOD(veh, slot, selected_mod, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void max_vehicle_performance(Vehicle veh)
|
||||
{
|
||||
if (entity::take_control_of(veh))
|
||||
{
|
||||
VehicleModType perfomance_mods[] = {MOD_ENGINE, MOD_BRAKES, MOD_TRANSMISSION, MOD_SUSPENSION, MOD_ARMOR, MOD_NITROUS, MOD_TURBO};
|
||||
VEHICLE::SET_VEHICLE_MOD_KIT(veh, 0);
|
||||
|
||||
for (auto mod_slot : perfomance_mods)
|
||||
{
|
||||
if (mod_slot != MOD_NITROUS && mod_slot != MOD_TURBO)
|
||||
VEHICLE::SET_VEHICLE_MOD(veh, mod_slot, VEHICLE::GET_NUM_VEHICLE_MODS(veh, mod_slot) - 1, true);
|
||||
else
|
||||
VEHICLE::TOGGLE_VEHICLE_MOD(veh, mod_slot, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void set_engine_state(Vehicle current_vehicle, bool state, bool immediately, bool disable_auto_start)
|
||||
{
|
||||
if (current_vehicle)
|
||||
VEHICLE::SET_VEHICLE_ENGINE_ON(current_vehicle, state, immediately, disable_auto_start);
|
||||
else
|
||||
return g_notification_service->push_warning("VEHICLE"_T.data(), "PLEASE_ENTER_VEHICLE"_T.data());
|
||||
}
|
||||
|
||||
inline void downgrade(Vehicle vehicle)
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_MOD_KIT(vehicle, 0);
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
VEHICLE::REMOVE_VEHICLE_MOD(vehicle, i);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool remote_control_vehicle(Vehicle veh)
|
||||
{
|
||||
if (!entity::take_control_of(veh, 4000))
|
||||
{
|
||||
g_notification_service->push_warning("REMOTE_CONTROL"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (g.m_remote_controlled_vehicle == veh)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Hash model = ENTITY::GET_ENTITY_MODEL(veh);
|
||||
Vehicle spawned = vehicle::spawn(model, self::pos, 0.0f);
|
||||
|
||||
ENTITY::SET_ENTITY_ALPHA(spawned, 0, FALSE);
|
||||
if (!VEHICLE::IS_THIS_MODEL_A_BIKE(model))
|
||||
ENTITY::SET_ENTITY_VISIBLE(spawned, FALSE, FALSE);
|
||||
ENTITY::SET_ENTITY_INVINCIBLE(spawned, TRUE);
|
||||
|
||||
float heading = ENTITY::GET_ENTITY_HEADING(veh);
|
||||
Vector3 rotation = ENTITY::GET_ENTITY_ROTATION(veh, 2);
|
||||
Vector3 coords = ENTITY::GET_ENTITY_COORDS(veh, FALSE);
|
||||
Vector3 velocity = ENTITY::GET_ENTITY_VELOCITY(veh);
|
||||
|
||||
ENTITY::SET_ENTITY_COORDS_NO_OFFSET(spawned, coords.x, coords.y, coords.z, FALSE, FALSE, FALSE);
|
||||
ENTITY::SET_ENTITY_HEADING(spawned, heading);
|
||||
ENTITY::SET_ENTITY_ROTATION(spawned, rotation.x, rotation.y, rotation.z, 2, TRUE);
|
||||
|
||||
ENTITY::SET_ENTITY_VISIBLE(veh, TRUE, FALSE);
|
||||
|
||||
ENTITY::SET_ENTITY_COLLISION(veh, FALSE, FALSE);
|
||||
ENTITY::SET_ENTITY_INVINCIBLE(veh, TRUE);
|
||||
VEHICLE::SET_VEHICLE_DOORS_LOCKED(veh, 4);
|
||||
VEHICLE::SET_VEHICLE_MAX_SPEED(veh, 0.0001f);
|
||||
ENTITY::ATTACH_ENTITY_TO_ENTITY(veh, spawned, 0, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, FALSE, FALSE, FALSE, FALSE, 0, TRUE, FALSE);
|
||||
PED::SET_PED_INTO_VEHICLE(PLAYER::PLAYER_PED_ID(), spawned, -1);
|
||||
|
||||
VEHICLE::SET_VEHICLE_ENGINE_ON(spawned, TRUE, TRUE, FALSE);
|
||||
ENTITY::SET_ENTITY_VELOCITY(spawned, velocity.x, velocity.y, velocity.z);
|
||||
VEHICLE::COPY_VEHICLE_DAMAGES(veh, spawned);
|
||||
|
||||
g.m_remote_controller_vehicle = spawned;
|
||||
g.m_remote_controlled_vehicle = veh;
|
||||
return true;
|
||||
}
|
||||
|
||||
float mps_to_speed(float mps, SpeedUnit speed_unit);
|
||||
float speed_to_mps(float speed, SpeedUnit speed_unit);
|
||||
Vector3 get_spawn_location(bool spawn_inside, Hash hash, Ped ped = self::ped);
|
||||
void set_mp_bitset(Vehicle veh);
|
||||
void bring(Vehicle veh, Vector3 location, bool put_in = true, int seatIdx = -1);
|
||||
Vehicle get_closest_to_location(Vector3 location, float range);
|
||||
bool set_plate(Vehicle veh, const char* plate);
|
||||
bool repair(Vehicle veh);
|
||||
Vehicle spawn(Hash hash, Vector3 location, float heading, bool is_networked = true, bool script_veh = false);
|
||||
Vehicle clone_from_vehicle_data(std::map<int, int32_t>& data, Vector3 location, float heading);
|
||||
std::map<int, int32_t> get_owned_mods_from_vehicle_idx(script_global vehicle_idx);
|
||||
Vehicle clone_from_owned_mods(std::map<int, int32_t> owned_mods, Vector3 location, float heading, bool is_networked = true);
|
||||
std::map<int, int32_t> get_owned_mods_from_vehicle(Vehicle vehicle);
|
||||
void teleport_into_vehicle(Vehicle veh);
|
||||
void max_vehicle(Vehicle veh);
|
||||
void max_vehicle_performance(Vehicle veh);
|
||||
void set_engine_state(Vehicle current_vehicle, bool state, bool immediately, bool disable_auto_start);
|
||||
void downgrade(Vehicle vehicle);
|
||||
bool remote_control_vehicle(Vehicle veh);
|
||||
|
||||
/*
|
||||
Set doorId to eDoorId::VEH_EXT_DOOR_INVALID_ID or simply -1 to apply to all vehicle doors.
|
||||
*/
|
||||
inline bool change_vehicle_door_lock_state(Vehicle veh, eDoorId doorId, eVehicleLockState state)
|
||||
{
|
||||
if (ENTITY::DOES_ENTITY_EXIST(veh))
|
||||
{
|
||||
if (doorId == eDoorId::VEH_EXT_DOOR_INVALID_ID)
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_DOORS_LOCKED(veh, (int)state);
|
||||
for (int i = 0; i < 6; i++)
|
||||
VEHICLE::SET_VEHICLE_INDIVIDUAL_DOORS_LOCKED(veh, i, (int)state);
|
||||
return VEHICLE::GET_VEHICLE_DOOR_LOCK_STATUS(veh) == (int)state;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (VEHICLE::GET_IS_DOOR_VALID(veh, (int)doorId))
|
||||
VEHICLE::SET_VEHICLE_INDIVIDUAL_DOORS_LOCKED(veh, (int)doorId, (int)state);
|
||||
|
||||
return VEHICLE::GET_VEHICLE_INDIVIDUAL_DOOR_LOCK_STATUS(veh, (int)doorId) == (int)state;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
bool change_vehicle_door_lock_state(Vehicle veh, eDoorId doorId, eVehicleLockState state);
|
||||
|
||||
/*
|
||||
* Set 'open' to false to close the door.
|
||||
* Set doorId to eDoorId::VEH_EXT_DOOR_INVALID_ID or simply -1 to apply to all doors.
|
||||
*/
|
||||
inline bool operate_vehicle_door(Vehicle veh, eDoorId doorId, bool open)
|
||||
{
|
||||
bool success = false;
|
||||
if (ENTITY::DOES_ENTITY_EXIST(veh))
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
if (doorId == eDoorId::VEH_EXT_DOOR_INVALID_ID || (int)doorId == i)
|
||||
{
|
||||
if (VEHICLE::GET_IS_DOOR_VALID(veh, i))
|
||||
{
|
||||
if (open)
|
||||
VEHICLE::SET_VEHICLE_DOOR_OPEN(veh, i, false, false);
|
||||
else
|
||||
VEHICLE::SET_VEHICLE_DOOR_SHUT(veh, i, false);
|
||||
}
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
bool operate_vehicle_door(Vehicle veh, eDoorId doorId, bool open);
|
||||
bool operate_vehicle_window(Vehicle veh, eWindowId windowId, bool open);
|
||||
|
||||
inline bool operate_vehicle_window(Vehicle veh, eWindowId windowId, bool open)
|
||||
{
|
||||
bool success = false;
|
||||
if (ENTITY::DOES_ENTITY_EXIST(veh))
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (windowId == eWindowId::WINDOW_INVALID_ID)
|
||||
{
|
||||
if (open)
|
||||
VEHICLE::ROLL_DOWN_WINDOWS(veh);
|
||||
else
|
||||
VEHICLE::ROLL_UP_WINDOW(veh, i);
|
||||
}
|
||||
|
||||
if ((int)windowId == i)
|
||||
{
|
||||
if (open)
|
||||
VEHICLE::ROLL_DOWN_WINDOW(veh, i);
|
||||
else
|
||||
VEHICLE::ROLL_UP_WINDOW(veh, i);
|
||||
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
inline bool operate_vehicle_headlights(Vehicle veh, bool lights, bool highbeams)
|
||||
{
|
||||
if (ENTITY::DOES_ENTITY_EXIST(veh))
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_FULLBEAM(veh, highbeams);
|
||||
VEHICLE::SET_VEHICLE_LIGHTS(veh, lights ? 3 : 4);
|
||||
int regular, highbeam;
|
||||
VEHICLE::GET_VEHICLE_LIGHTS_STATE(veh, ®ular, &highbeam);
|
||||
return regular == (int)lights && (int)highbeams == highbeam;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
bool operate_vehicle_headlights(Vehicle veh, bool lights, bool highbeams);
|
||||
|
||||
/*
|
||||
* Input index -1 to apply to all neons.
|
||||
*/
|
||||
inline bool operate_vehicle_neons(Vehicle veh, int index, bool toggle)
|
||||
{
|
||||
bool success = false;
|
||||
if (ENTITY::DOES_ENTITY_EXIST(veh))
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_MOD_KIT(veh, 0);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (index == -1 || index == i)
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_NEON_ENABLED(veh, index, toggle);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
bool operate_vehicle_neons(Vehicle veh, int index, bool toggle);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "fiber_pool.hpp"
|
||||
#include "script.hpp"
|
||||
#include "services/vehicle/persist_car_service.hpp"
|
||||
#include "services/model_preview/model_preview_service.hpp"
|
||||
#include "util/mobile.hpp"
|
||||
#include "util/teleport.hpp"
|
||||
#include "views/view.hpp"
|
||||
@ -22,13 +23,15 @@ namespace big
|
||||
{
|
||||
if (!selected_vehicle_file.empty())
|
||||
{
|
||||
const auto vehicle = persist_car_service::load_vehicle(selected_vehicle_file, g.vehicle.persist_vehicle_sub_folder);
|
||||
const auto vehicle = persist_car_service::load_vehicle(selected_vehicle_file, g.persist_car.persist_vehicle_sub_folder);
|
||||
if (!vehicle)
|
||||
{
|
||||
g_notification_service->push_warning("PERSIST_CAR"_T.data(), "PERSIST_CAR_TO_MANY_SPAWNED"_T.data());
|
||||
}
|
||||
else if (g.spawn_vehicle.spawn_inside)
|
||||
else if (g.persist_car.spawn_inside)
|
||||
{
|
||||
teleport::into_vehicle(vehicle);
|
||||
}
|
||||
|
||||
selected_vehicle_file.clear();
|
||||
}
|
||||
@ -43,25 +46,47 @@ namespace big
|
||||
static std::string selected_vehicle_file;
|
||||
|
||||
const auto vehicle_folders = persist_car_service::list_sub_folders();
|
||||
const auto vehicle_files = persist_car_service::list_files(g.vehicle.persist_vehicle_sub_folder);
|
||||
const auto vehicle_files = persist_car_service::list_files(g.persist_car.persist_vehicle_sub_folder);
|
||||
|
||||
if (ImGui::Checkbox("PREVIEW"_T.data(), &g.persist_car.preview_vehicle))
|
||||
{
|
||||
if (!g.persist_car.preview_vehicle)
|
||||
{
|
||||
g_model_preview_service->stop_preview();
|
||||
}
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("PREVIEW_DESC"_T.data());
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("SPAWN_IN"_T.data(), &g.persist_car.spawn_inside);
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("SPAWN_IN_DESC"_T.data());
|
||||
|
||||
auto folder_display = g.vehicle.persist_vehicle_sub_folder.empty() ? "ROOT"_T.data() : g.vehicle.persist_vehicle_sub_folder.c_str();
|
||||
ImGui::SetNextItemWidth(300.f);
|
||||
auto folder_display = g.persist_car.persist_vehicle_sub_folder.empty() ?
|
||||
"ROOT"_T.data() :
|
||||
g.persist_car.persist_vehicle_sub_folder.c_str();
|
||||
if (ImGui::BeginCombo("FOLDER"_T.data(), folder_display))
|
||||
{
|
||||
if (ImGui::Selectable("ROOT"_T.data(), g.vehicle.persist_vehicle_sub_folder == ""))
|
||||
g.vehicle.persist_vehicle_sub_folder = "";
|
||||
if (ImGui::Selectable("ROOT"_T.data(), g.persist_car.persist_vehicle_sub_folder == ""))
|
||||
g.persist_car.persist_vehicle_sub_folder.clear();
|
||||
|
||||
for (std::string folder_name : vehicle_folders)
|
||||
{
|
||||
if (ImGui::Selectable(folder_name.c_str(), g.vehicle.persist_vehicle_sub_folder == folder_name))
|
||||
g.vehicle.persist_vehicle_sub_folder = folder_name;
|
||||
if (ImGui::Selectable(folder_name.c_str(), g.persist_car.persist_vehicle_sub_folder == folder_name))
|
||||
g.persist_car.persist_vehicle_sub_folder = folder_name;
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
ImGui::PushItemWidth(250);
|
||||
static char search[64];
|
||||
ImGui::SetNextItemWidth(300.f);
|
||||
components::input_text_with_hint("FILE_NAME"_T, "SEARCH"_T, search, sizeof(search), ImGuiInputTextFlags_None);
|
||||
std::string lower_search = search;
|
||||
std::transform(lower_search.begin(), lower_search.end(), lower_search.begin(), tolower);
|
||||
|
||||
ImGui::SetNextItemWidth(250);
|
||||
ImGui::Text("SAVED_VEHICLES"_T.data());
|
||||
|
||||
static const auto over_30 = (30 * ImGui::GetTextLineHeightWithSpacing() + 2);
|
||||
@ -70,12 +95,29 @@ namespace big
|
||||
{
|
||||
for (const auto& pair : vehicle_files)
|
||||
{
|
||||
if (ImGui::Selectable(pair.c_str(), selected_vehicle_file == pair))
|
||||
std::string pair_lower = pair;
|
||||
std::transform(pair_lower.begin(), pair_lower.end(), pair_lower.begin(), tolower);
|
||||
if (pair_lower.contains(lower_search))
|
||||
{
|
||||
selected_vehicle_file = pair;
|
||||
g_fiber_pool->queue_job([] {
|
||||
load_vehicle(selected_vehicle_file);
|
||||
});
|
||||
if (ImGui::Selectable(pair.c_str(), selected_vehicle_file == pair))
|
||||
{
|
||||
selected_vehicle_file = pair;
|
||||
g_fiber_pool->queue_job([] {
|
||||
load_vehicle(selected_vehicle_file);
|
||||
g_model_preview_service->stop_preview();
|
||||
});
|
||||
}
|
||||
|
||||
if (!g.persist_car.preview_vehicle || (g.persist_car.preview_vehicle && !ImGui::IsAnyItemHovered()))
|
||||
{
|
||||
g_model_preview_service->stop_preview();
|
||||
}
|
||||
else if (ImGui::IsItemHovered())
|
||||
{
|
||||
g_fiber_pool->queue_job([pair] {
|
||||
g_model_preview_service->show_vehicle_persisted(pair);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,19 +130,17 @@ namespace big
|
||||
static char vehicle_file_name_input[50]{};
|
||||
|
||||
components::small_text("VEHICLE_FILE_NAME"_T);
|
||||
ImGui::PushItemWidth(250);
|
||||
ImGui::SetNextItemWidth(250);
|
||||
ImGui::InputText("##vehiclefilename", vehicle_file_name_input, IM_ARRAYSIZE(vehicle_file_name_input));
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("VEHICLE_FILE_NAME_EXAMPLE"_T.data());
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
static char save_folder[50]{};
|
||||
components::small_text("VEHICLE_FOLDER_NAME"_T);
|
||||
ImGui::PushItemWidth(250);
|
||||
ImGui::SetNextItemWidth(250);
|
||||
ImGui::InputText("##foldername", save_folder, IM_ARRAYSIZE(save_folder));
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("VEHICLE_FOLDER_NAME_EXAMPLE"_T.data());
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
components::button("SAVE_VEHICLE"_T, [] {
|
||||
if (!self::veh)
|
||||
|
@ -19,27 +19,28 @@ namespace big
|
||||
g_model_preview_service->stop_preview();
|
||||
}
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("PREVIEW_DESC"_T.data());
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("SPAWN_IN"_T.data(), &g.clone_pv.spawn_inside);
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("SPAWN_IN_DESC"_T.data());
|
||||
ImGui::SameLine();
|
||||
|
||||
static char plate_buf[9] = {0};
|
||||
int num_of_rows = 3;
|
||||
|
||||
ImGui::Checkbox("SPAWN_CLONE"_T.data(), &g.clone_pv.spawn_clone);
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("SPAWN_CLONE_DESC"_T.data());
|
||||
if (g.clone_pv.spawn_clone)
|
||||
{
|
||||
num_of_rows = 5;
|
||||
|
||||
ImGui::Checkbox("SPAWN_MAXED"_T.data(), &g.clone_pv.spawn_maxed);
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("SPAWN_MAXED_DESC"_T.data());
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("CLONE_PV_PLATE"_T.data(), &g.clone_pv.clone_plate);
|
||||
if (g.clone_pv.clone_plate)
|
||||
{
|
||||
num_of_rows = 4;
|
||||
}
|
||||
else
|
||||
if (!g.clone_pv.clone_plate)
|
||||
{
|
||||
ImGui::SetNextItemWidth(300.f);
|
||||
|
||||
@ -86,7 +87,44 @@ namespace big
|
||||
components::input_text_with_hint("MODEL_NAME"_T, "SEARCH"_T, search, sizeof(search), ImGuiInputTextFlags_None);
|
||||
|
||||
g_mobile_service->refresh_personal_vehicles();
|
||||
if (ImGui::BeginListBox("###personal_veh_list", {300, static_cast<float>(*g_pointers->m_gta.m_resolution_y - 188 - 38 * num_of_rows)}))
|
||||
|
||||
auto num_of_rows = 0;
|
||||
|
||||
std::set<int> indexes_to_use;
|
||||
|
||||
if (!g_mobile_service->personal_vehicles().empty())
|
||||
{
|
||||
std::string lower_search = search;
|
||||
std::transform(lower_search.begin(), lower_search.end(), lower_search.begin(), tolower);
|
||||
|
||||
for (const auto& it : g_mobile_service->personal_vehicles())
|
||||
{
|
||||
const auto& label = it.first;
|
||||
const auto& personal_veh = it.second;
|
||||
const auto& item = g_gta_data_service->vehicle_by_hash(personal_veh->get_hash());
|
||||
|
||||
std::string vehicle_class = item.m_vehicle_class;
|
||||
std::string display_name = label;
|
||||
std::string display_manufacturer = item.m_display_manufacturer;
|
||||
std::transform(display_name.begin(), display_name.end(), display_name.begin(), ::tolower);
|
||||
std::transform(display_manufacturer.begin(), display_manufacturer.end(), display_manufacturer.begin(), ::tolower);
|
||||
|
||||
if ((selected_class == -1 || class_arr[selected_class] == vehicle_class)
|
||||
&& (display_name.find(lower_search) != std::string::npos || display_manufacturer.find(lower_search) != std::string::npos))
|
||||
{
|
||||
indexes_to_use.insert(personal_veh->get_id());
|
||||
}
|
||||
}
|
||||
num_of_rows = indexes_to_use.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
num_of_rows = 2;
|
||||
}
|
||||
|
||||
static const auto over_30 = (30 * ImGui::GetTextLineHeightWithSpacing() + 2);
|
||||
const auto box_height = num_of_rows <= 30 ? (num_of_rows * ImGui::GetTextLineHeightWithSpacing() + 2) : over_30;
|
||||
if (ImGui::BeginListBox("###personal_veh_list", {300, box_height}))
|
||||
{
|
||||
if (g_mobile_service->personal_vehicles().empty())
|
||||
{
|
||||
@ -99,19 +137,12 @@ namespace big
|
||||
|
||||
for (const auto& it : g_mobile_service->personal_vehicles())
|
||||
{
|
||||
const auto& label = it.first;
|
||||
const auto& personal_veh = it.second;
|
||||
const auto& item = g_gta_data_service->vehicle_by_hash(personal_veh->get_hash());
|
||||
|
||||
std::string vehicle_class = item.m_vehicle_class;
|
||||
std::string display_name = label;
|
||||
std::string display_manufacturer = item.m_display_manufacturer;
|
||||
std::transform(display_name.begin(), display_name.end(), display_name.begin(), ::tolower);
|
||||
std::transform(display_manufacturer.begin(), display_manufacturer.end(), display_manufacturer.begin(), ::tolower);
|
||||
|
||||
if ((selected_class == -1 || class_arr[selected_class] == vehicle_class)
|
||||
&& (display_name.find(lower_search) != std::string::npos || display_manufacturer.find(lower_search) != std::string::npos))
|
||||
if (indexes_to_use.contains(personal_veh->get_id()))
|
||||
{
|
||||
const auto& label = it.first;
|
||||
|
||||
ImGui::PushID('v' << 24 & personal_veh->get_id());
|
||||
components::selectable(label, false, [&personal_veh] {
|
||||
if (g.clone_pv.spawn_clone)
|
||||
|
@ -257,7 +257,7 @@ namespace big
|
||||
});
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Checkbox("TIRESMOKE"_T.data(), (bool*)&owned_mods[MOD_TYRE_SMOKE]))
|
||||
if (ImGui::Checkbox("TIRE_SMOKE"_T.data(), (bool*)&owned_mods[MOD_TYRE_SMOKE]))
|
||||
{
|
||||
g_fiber_pool->queue_job([] {
|
||||
VEHICLE::TOGGLE_VEHICLE_MOD(player_vehicle, MOD_TYRE_SMOKE, owned_mods[MOD_TYRE_SMOKE]);
|
||||
|
@ -9,8 +9,6 @@ namespace big
|
||||
{
|
||||
void render_spawn_new_vehicle()
|
||||
{
|
||||
ImGui::SetWindowSize({0.f, (float)*g_pointers->m_gta.m_resolution_y}, ImGuiCond_Always);
|
||||
|
||||
if (ImGui::Checkbox("PREVIEW"_T.data(), &g.spawn_vehicle.preview_vehicle))
|
||||
{
|
||||
if (!g.spawn_vehicle.preview_vehicle)
|
||||
@ -18,6 +16,8 @@ namespace big
|
||||
g_model_preview_service->stop_preview();
|
||||
}
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("PREVIEW_DESC"_T.data());
|
||||
ImGui::SameLine();
|
||||
components::command_checkbox<"spawnin">();
|
||||
ImGui::SameLine();
|
||||
@ -64,7 +64,43 @@ namespace big
|
||||
ImGui::SetNextItemWidth(300.f);
|
||||
components::input_text_with_hint("MODEL_NAME"_T, "SEARCH"_T, search, sizeof(search), ImGuiInputTextFlags_None);
|
||||
|
||||
if (ImGui::BeginListBox("###vehicles", {300, static_cast<float>(*g_pointers->m_gta.m_resolution_y - 188 - 38 * 4)}))
|
||||
vehicle_map calculated_map{};
|
||||
|
||||
if (g_gta_data_service->vehicles().size() > 0)
|
||||
{
|
||||
for (auto& item : g_gta_data_service->vehicles())
|
||||
{
|
||||
const auto& vehicle = item.second;
|
||||
|
||||
std::string display_name = vehicle.m_display_name;
|
||||
std::string display_manufacturer = vehicle.m_display_manufacturer;
|
||||
std::string clazz = vehicle.m_vehicle_class;
|
||||
|
||||
std::transform(display_name.begin(), display_name.end(), display_name.begin(), ::tolower);
|
||||
std::transform(display_manufacturer.begin(), display_manufacturer.end(), display_manufacturer.begin(), ::tolower);
|
||||
|
||||
std::string lower_search = search;
|
||||
std::transform(lower_search.begin(), lower_search.end(), lower_search.begin(), tolower);
|
||||
|
||||
if ((selected_class == -1 || class_arr[selected_class] == clazz) && (display_name.find(lower_search) != std::string::npos || display_manufacturer.find(lower_search) != std::string::npos))
|
||||
{
|
||||
calculated_map.emplace(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const auto over_30 = (30 * ImGui::GetTextLineHeightWithSpacing() + 2);
|
||||
auto calculated_size = calculated_map.size();
|
||||
if (calculated_map.size() == 0)
|
||||
{
|
||||
calculated_size++;
|
||||
}
|
||||
if (self::veh)
|
||||
{
|
||||
calculated_size++;
|
||||
}
|
||||
const auto box_height = calculated_size <= 30 ? (calculated_size * ImGui::GetTextLineHeightWithSpacing() + 2) : over_30;
|
||||
if (ImGui::BeginListBox("###vehicles", {300, box_height}))
|
||||
{
|
||||
if (self::veh)
|
||||
{
|
||||
@ -125,66 +161,50 @@ namespace big
|
||||
}
|
||||
}
|
||||
|
||||
const auto& item_arr = g_gta_data_service->vehicles();
|
||||
if (item_arr.size() > 0)
|
||||
if (calculated_map.size() > 0)
|
||||
{
|
||||
std::string lower_search = search;
|
||||
std::transform(lower_search.begin(), lower_search.end(), lower_search.begin(), tolower);
|
||||
|
||||
for (auto& item : item_arr)
|
||||
for (auto& item : calculated_map)
|
||||
{
|
||||
const auto& vehicle = item.second;
|
||||
ImGui::PushID(vehicle.m_hash);
|
||||
components::selectable(vehicle.m_display_name, false, [&vehicle] {
|
||||
const auto spawn_location =
|
||||
vehicle::get_spawn_location(g.spawn_vehicle.spawn_inside, vehicle.m_hash);
|
||||
const auto spawn_heading = ENTITY::GET_ENTITY_HEADING(self::ped);
|
||||
|
||||
std::string display_name = vehicle.m_display_name;
|
||||
std::string display_manufacturer = vehicle.m_display_manufacturer;
|
||||
std::string clazz = vehicle.m_vehicle_class;
|
||||
auto veh = vehicle::spawn(vehicle.m_hash, spawn_location, spawn_heading);
|
||||
|
||||
std::transform(display_name.begin(), display_name.end(), display_name.begin(), ::tolower);
|
||||
std::transform(display_manufacturer.begin(), display_manufacturer.end(), display_manufacturer.begin(), ::tolower);
|
||||
if (veh == 0)
|
||||
{
|
||||
g_notification_service->push_error("VEHICLE"_T.data(), "UNABLE_TO_SPAWN_VEHICLE"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g.spawn_vehicle.spawn_maxed)
|
||||
{
|
||||
vehicle::max_vehicle(veh);
|
||||
}
|
||||
|
||||
if ((selected_class == -1 || class_arr[selected_class] == clazz)
|
||||
&& (display_name.find(lower_search) != std::string::npos || display_manufacturer.find(lower_search) != std::string::npos))
|
||||
vehicle::set_plate(veh, plate_buf);
|
||||
|
||||
if (g.spawn_vehicle.spawn_inside)
|
||||
{
|
||||
vehicle::teleport_into_vehicle(veh);
|
||||
}
|
||||
}
|
||||
|
||||
g_model_preview_service->stop_preview();
|
||||
ENTITY::SET_ENTITY_AS_NO_LONGER_NEEDED(&veh);
|
||||
});
|
||||
ImGui::PopID();
|
||||
|
||||
if (!g.spawn_vehicle.preview_vehicle || (g.spawn_vehicle.preview_vehicle && !ImGui::IsAnyItemHovered()))
|
||||
{
|
||||
ImGui::PushID(vehicle.m_hash);
|
||||
components::selectable(vehicle.m_display_name, false, [&vehicle] {
|
||||
const auto spawn_location =
|
||||
vehicle::get_spawn_location(g.spawn_vehicle.spawn_inside, vehicle.m_hash);
|
||||
const auto spawn_heading = ENTITY::GET_ENTITY_HEADING(self::ped);
|
||||
|
||||
auto veh = vehicle::spawn(vehicle.m_hash, spawn_location, spawn_heading);
|
||||
|
||||
if (veh == 0)
|
||||
{
|
||||
g_notification_service->push_error("VEHICLE"_T.data(), "UNABLE_TO_SPAWN_VEHICLE"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g.spawn_vehicle.spawn_maxed)
|
||||
{
|
||||
vehicle::max_vehicle(veh);
|
||||
}
|
||||
|
||||
vehicle::set_plate(veh, plate_buf);
|
||||
|
||||
if (g.spawn_vehicle.spawn_inside)
|
||||
{
|
||||
vehicle::teleport_into_vehicle(veh);
|
||||
}
|
||||
}
|
||||
|
||||
g_model_preview_service->stop_preview();
|
||||
ENTITY::SET_ENTITY_AS_NO_LONGER_NEEDED(&veh);
|
||||
});
|
||||
ImGui::PopID();
|
||||
|
||||
if (!g.spawn_vehicle.preview_vehicle || (g.spawn_vehicle.preview_vehicle && !ImGui::IsAnyItemHovered()))
|
||||
{
|
||||
g_model_preview_service->stop_preview();
|
||||
}
|
||||
else if (ImGui::IsItemHovered())
|
||||
{
|
||||
g_model_preview_service->show_vehicle(vehicle.m_hash, g.spawn_vehicle.spawn_maxed);
|
||||
}
|
||||
g_model_preview_service->stop_preview();
|
||||
}
|
||||
else if (ImGui::IsItemHovered())
|
||||
{
|
||||
g_model_preview_service->show_vehicle(vehicle.m_hash, g.spawn_vehicle.spawn_maxed);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -198,16 +218,15 @@ namespace big
|
||||
|
||||
void view::spawn_vehicle()
|
||||
{
|
||||
static int spawn_type = 0;
|
||||
ImGui::RadioButton("New", &spawn_type, 0);
|
||||
ImGui::RadioButton("New", &g.spawn_vehicle.spawn_type, 0);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Personal", &spawn_type, 1);
|
||||
ImGui::RadioButton("Personal", &g.spawn_vehicle.spawn_type, 1);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Persistent", &spawn_type, 2);
|
||||
ImGui::RadioButton("Persistent", &g.spawn_vehicle.spawn_type, 2);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Xml", &spawn_type, 3);
|
||||
ImGui::RadioButton("Xml", &g.spawn_vehicle.spawn_type, 3);
|
||||
|
||||
switch (spawn_type)
|
||||
switch (g.spawn_vehicle.spawn_type)
|
||||
{
|
||||
case 0: render_spawn_new_vehicle(); break;
|
||||
case 1: view::pv(); break;
|
||||
|
@ -594,6 +594,8 @@ namespace big
|
||||
g_model_preview_service->stop_preview();
|
||||
}
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("PREVIEW_DESC"_T.data());
|
||||
|
||||
ImGui::Checkbox("Invincible", &g.world.spawn_ped.spawn_invincible);
|
||||
ImGui::Checkbox("Invisible", &g.world.spawn_ped.spawn_invisible);
|
||||
|
Reference in New Issue
Block a user