From cf07cfec04ad4752dce33ad3aa369e8d6512c049 Mon Sep 17 00:00:00 2001 From: gir489 <100792176+gir489returns@users.noreply.github.com> Date: Thu, 31 Aug 2023 09:43:55 -0400 Subject: [PATCH] Redesigned Vehicle Spawn menus to have consistent features. (#2063) Closes #2053 --- src/backend/commands/spawn/spawn_vehicle.cpp | 4 +- .../looped/player/remote_control_vehicle.cpp | 2 +- .../vehicle/allow_all_vehicles_in_heists.cpp | 40 +- src/core/settings.hpp | 17 +- src/gta/vehicle_values.hpp | 4 +- src/hooks/protections/can_apply_data.cpp | 2 - .../model_preview/model_preview_service.cpp | 34 +- .../model_preview/model_preview_service.hpp | 4 + src/services/vehicle/persist_car_service.cpp | 27 +- src/services/vehicle/persist_car_service.hpp | 8 +- src/util/entity.cpp | 31 +- src/util/entity.hpp | 2 +- src/util/vehicle.cpp | 794 +++++++++++++++++ src/util/vehicle.hpp | 804 +----------------- src/views/vehicle/spawn/view_persist_car.cpp | 76 +- src/views/vehicle/spawn/view_pv.cpp | 69 +- src/views/vehicle/view_lsc.cpp | 2 +- src/views/vehicle/view_spawn_vehicle.cpp | 143 ++-- src/views/world/view_spawn_ped.cpp | 2 + 19 files changed, 1115 insertions(+), 950 deletions(-) create mode 100644 src/util/vehicle.cpp diff --git a/src/backend/commands/spawn/spawn_vehicle.cpp b/src/backend/commands/spawn/spawn_vehicle.cpp index e190ec22..167869d9 100644 --- a/src/backend/commands/spawn/spawn_vehicle.cpp +++ b/src/backend/commands/spawn/spawn_vehicle.cpp @@ -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); } diff --git a/src/backend/looped/player/remote_control_vehicle.cpp b/src/backend/looped/player/remote_control_vehicle.cpp index 8ac8d9ef..27dd7b02 100644 --- a/src/backend/looped/player/remote_control_vehicle.cpp +++ b/src/backend/looped/player/remote_control_vehicle.cpp @@ -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); diff --git a/src/backend/looped/vehicle/allow_all_vehicles_in_heists.cpp b/src/backend/looped/vehicle/allow_all_vehicles_in_heists.cpp index 5f69edb8..c4a0960a 100644 --- a/src/backend/looped/vehicle/allow_all_vehicles_in_heists.cpp +++ b/src/backend/looped/vehicle/allow_all_vehicles_in_heists.cpp @@ -6,9 +6,7 @@ namespace big { - static bool initalized_backup = false; - static std::map 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(tunable_hash)) { - for (Hash tunable_hash : list_of_hashes) + if (*tunable_ptr != FALSE) { - if (auto tunable_ptr = g_tunables_service->get_tunable(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(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(tunable_hash)) //Sanity check in case of tunables_service failure. - { - *tunable_ptr = backup_map[tunable_hash]; + *tunable_ptr = FALSE; } } } diff --git a/src/core/settings.hpp b/src/core/settings.hpp index 8e4def13..95b4d401 100644 --- a/src/core/settings.hpp +++ b/src/core/settings.hpp @@ -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(); diff --git a/src/gta/vehicle_values.hpp b/src/gta/vehicle_values.hpp index d5729038..8579f1a1 100644 --- a/src/gta/vehicle_values.hpp +++ b/src/gta/vehicle_values.hpp @@ -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 }; diff --git a/src/hooks/protections/can_apply_data.cpp b/src/hooks/protections/can_apply_data.cpp index 91c21436..e843daff 100644 --- a/src/hooks/protections/can_apply_data.cpp +++ b/src/hooks/protections/can_apply_data.cpp @@ -1518,8 +1518,6 @@ namespace big } } } - - return true; } break; diff --git a/src/services/model_preview/model_preview_service.cpp b/src/services/model_preview/model_preview_service.cpp index 2745dd8c..32e06d25 100644 --- a/src/services/model_preview/model_preview_service.cpp +++ b/src/services/model_preview/model_preview_service.cpp @@ -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; }); diff --git a/src/services/model_preview/model_preview_service.hpp b/src/services/model_preview/model_preview_service.hpp index deedc5e1..2571f917 100644 --- a/src/services/model_preview/model_preview_service.hpp +++ b/src/services/model_preview/model_preview_service.hpp @@ -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& owned_mods, bool spawn_max); + void show_vehicle_persisted(std::string vehicle_name); + void show_vehicle(Vehicle veh); void preview_loop(); void stop_preview(); diff --git a/src/services/vehicle/persist_car_service.cpp b/src/services/vehicle/persist_car_service.cpp index de0f88cf..083fbaf0 100644 --- a/src/services/vehicle/persist_car_service.cpp +++ b/src/services/vehicle/persist_car_service.cpp @@ -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& 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 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& 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& spawn_coords) { - const auto vehicle = spawn_vehicle_json(vehicle_json, ped); + const auto vehicle = spawn_vehicle_json(vehicle_json, ped, spawn_coords); std::vector 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& 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); diff --git a/src/services/vehicle/persist_car_service.hpp b/src/services/vehicle/persist_car_service.hpp index c82dad2c..0b267c1c 100644 --- a/src/services/vehicle/persist_car_service.hpp +++ b/src/services/vehicle/persist_car_service.hpp @@ -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& = 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& spawn_coords = std::nullopt); + static Vehicle spawn_vehicle(nlohmann::json vehicle_json, Ped ped, const std::optional& spawn_coords); + static Vehicle spawn_vehicle_json(nlohmann::json vehicle_json, Ped ped, const std::optional& spawn_coords = std::nullopt); static nlohmann::json get_full_vehicle_json(Vehicle vehicle); diff --git a/src/util/entity.cpp b/src/util/entity.cpp index 2616b39c..2fe2899c 100644 --- a/src/util/entity.cpp +++ b/src/util/entity.cpp @@ -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)) diff --git a/src/util/entity.hpp b/src/util/entity.hpp index 0d993b52..42279cd5 100644 --- a/src/util/entity.hpp +++ b/src/util/entity.hpp @@ -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); diff --git a/src/util/vehicle.cpp b/src/util/vehicle.cpp new file mode 100644 index 00000000..729b56bc --- /dev/null +++ b/src/util/vehicle.cpp @@ -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& 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() = val; + } + } + + // permission fix + *scr_globals::spawn_global.at(27).at(1).as() = 0; + + // personal car flag + *scr_globals::spawn_global.at(27).at(94).as() = 14; + *scr_globals::spawn_global.at(27).at(95).as() = 2; + + // mmi + *scr_globals::spawn_global.at(27).at(103).as() = 0; + + // spawn location + *scr_globals::spawn_global.at(7).at(0).as() = tmpLocation.x; + *scr_globals::spawn_global.at(7).at(1).as() = tmpLocation.y; + *scr_globals::spawn_global.at(7).at(2).as() = tmpLocation.z; + + // spawn non pegasus + *scr_globals::spawn_global.at(3).as() = 0; + + // spawn signal + int* spawn_signal = scr_globals::spawn_global.at(2).as(); + *scr_globals::spawn_global.at(5).as() = 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 get_owned_mods_from_vehicle_idx(script_global vehicle_idx) + { + std::map 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 val_77 = *vehicle_idx.at(77).as(); + int32_t val_102 = *vehicle_idx.at(102).as(); + int32_t val_103 = *vehicle_idx.at(103).as(); + + owned_mods[MOD_MODEL_HASH] = *vehicle_idx.at(66).as(); + + owned_mods[MOD_PLATE_STYLE] = *vehicle_idx.at(0).as(); + owned_mods[MOD_WINDOW_TINT] = *vehicle_idx.at(65).as(); + owned_mods[MOD_WHEEL_TYPE] = *vehicle_idx.at(69).as(); + + + owned_mods[MOD_PRIMARY_COL] = *vehicle_idx.at(5).as(); + owned_mods[MOD_SECONDARY_COL] = *vehicle_idx.at(6).as(); + owned_mods[MOD_PEARLESCENT_COL] = *vehicle_idx.at(7).as(); + owned_mods[MOD_WHEEL_COL] = *vehicle_idx.at(8).as(); + owned_mods[MOD_INTERIOR_COL] = *vehicle_idx.at(97).as(); + owned_mods[MOD_DASHBOARD_COL] = *vehicle_idx.at(99).as(); + + + //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(); + owned_mods[MOD_PRIMARY_COL_G] = *vehicle_idx.at(72).as(); + owned_mods[MOD_PRIMARY_COL_B] = *vehicle_idx.at(73).as(); + } + + + //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(); + owned_mods[MOD_SECONDARY_COL_G] = *vehicle_idx.at(72).as(); + owned_mods[MOD_SECONDARY_COL_B] = *vehicle_idx.at(73).as(); + } + + + // TIRE SMOKE + owned_mods[MOD_TIRESMOKE_COL_R] = *vehicle_idx.at(62).as(); + owned_mods[MOD_TIRESMOKE_COL_G] = *vehicle_idx.at(63).as(); + owned_mods[MOD_TIRESMOKE_COL_B] = *vehicle_idx.at(64).as(); + 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(); + owned_mods[MOD_NEON_COL_G] = *vehicle_idx.at(75).as(); + owned_mods[MOD_NEON_COL_B] = *vehicle_idx.at(76).as(); + + // 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() != 0; + + owned_mods[MOD_FRONTWHEEL_VAR] = *vehicle_idx.at(60).as() != 0; + owned_mods[MOD_REARWHEEL_VAR] = *vehicle_idx.at(61).as() != 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() - 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 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 get_owned_mods_from_vehicle(Vehicle vehicle) + { + std::map 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; + } +} diff --git a/src/util/vehicle.hpp b/src/util/vehicle.hpp index cab2ce82..008c308b 100644 --- a/src/util/vehicle.hpp +++ b/src/util/vehicle.hpp @@ -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& 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() = val; - } - } - - // permission fix - *scr_globals::spawn_global.at(27).at(1).as() = 0; - - // personal car flag - *scr_globals::spawn_global.at(27).at(94).as() = 14; - *scr_globals::spawn_global.at(27).at(95).as() = 2; - - // mmi - *scr_globals::spawn_global.at(27).at(103).as() = 0; - - // spawn location - *scr_globals::spawn_global.at(7).at(0).as() = tmpLocation.x; - *scr_globals::spawn_global.at(7).at(1).as() = tmpLocation.y; - *scr_globals::spawn_global.at(7).at(2).as() = tmpLocation.z; - - // spawn non pegasus - *scr_globals::spawn_global.at(3).as() = 0; - - // spawn signal - int* spawn_signal = scr_globals::spawn_global.at(2).as(); - *scr_globals::spawn_global.at(5).as() = 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 get_vehicle_data_from_vehicle_idx(script_global vehicle_idx) - { - std::map veh_data; - - for (int i = 0; i < 142; i++) - { - veh_data[i] = *vehicle_idx.at(i).as(); - } - - veh_data.erase(1); - veh_data.erase(94); - veh_data.erase(95); - veh_data.erase(103); - - return veh_data; - } - - inline std::map get_owned_mods_from_vehicle_idx(script_global vehicle_idx) - { - std::map 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 val_77 = *vehicle_idx.at(77).as(); - int32_t val_102 = *vehicle_idx.at(102).as(); - - - owned_mods[MOD_MODEL_HASH] = *vehicle_idx.at(66).as(); - - owned_mods[MOD_PLATE_STYLE] = *vehicle_idx.at(0).as(); - owned_mods[MOD_WINDOW_TINT] = *vehicle_idx.at(65).as(); - owned_mods[MOD_WHEEL_TYPE] = *vehicle_idx.at(69).as(); - - - owned_mods[MOD_PRIMARY_COL] = *vehicle_idx.at(5).as(); - owned_mods[MOD_SECONDARY_COL] = *vehicle_idx.at(6).as(); - owned_mods[MOD_PEARLESCENT_COL] = *vehicle_idx.at(7).as(); - owned_mods[MOD_WHEEL_COL] = *vehicle_idx.at(8).as(); - owned_mods[MOD_INTERIOR_COL] = *vehicle_idx.at(97).as(); - owned_mods[MOD_DASHBOARD_COL] = *vehicle_idx.at(99).as(); - - - //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(); - owned_mods[MOD_PRIMARY_COL_G] = *vehicle_idx.at(72).as(); - owned_mods[MOD_PRIMARY_COL_B] = *vehicle_idx.at(73).as(); - } - - - //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(); - owned_mods[MOD_SECONDARY_COL_G] = *vehicle_idx.at(72).as(); - owned_mods[MOD_SECONDARY_COL_B] = *vehicle_idx.at(73).as(); - } - - - // TIRE SMOKE - owned_mods[MOD_TIRESMOKE_COL_R] = *vehicle_idx.at(62).as(); - owned_mods[MOD_TIRESMOKE_COL_G] = *vehicle_idx.at(63).as(); - owned_mods[MOD_TIRESMOKE_COL_B] = *vehicle_idx.at(64).as(); - 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(); - owned_mods[MOD_NEON_COL_G] = *vehicle_idx.at(75).as(); - owned_mods[MOD_NEON_COL_B] = *vehicle_idx.at(76).as(); - - // 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() != 0; - - owned_mods[MOD_FRONTWHEEL_VAR] = *vehicle_idx.at(60).as() != 0; - owned_mods[MOD_REARWHEEL_VAR] = *vehicle_idx.at(61).as() != 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() - 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 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 get_owned_mods_from_vehicle(Vehicle vehicle) - { - std::map 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& data, Vector3 location, float heading); + std::map get_owned_mods_from_vehicle_idx(script_global vehicle_idx); + Vehicle clone_from_owned_mods(std::map owned_mods, Vector3 location, float heading, bool is_networked = true); + std::map 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); } diff --git a/src/views/vehicle/spawn/view_persist_car.cpp b/src/views/vehicle/spawn/view_persist_car.cpp index 7c777812..9da2e85b 100644 --- a/src/views/vehicle/spawn/view_persist_car.cpp +++ b/src/views/vehicle/spawn/view_persist_car.cpp @@ -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) diff --git a/src/views/vehicle/spawn/view_pv.cpp b/src/views/vehicle/spawn/view_pv.cpp index 88ec6ac1..251ec148 100644 --- a/src/views/vehicle/spawn/view_pv.cpp +++ b/src/views/vehicle/spawn/view_pv.cpp @@ -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(*g_pointers->m_gta.m_resolution_y - 188 - 38 * num_of_rows)})) + + auto num_of_rows = 0; + + std::set 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) diff --git a/src/views/vehicle/view_lsc.cpp b/src/views/vehicle/view_lsc.cpp index e877984b..3ef6f81e 100644 --- a/src/views/vehicle/view_lsc.cpp +++ b/src/views/vehicle/view_lsc.cpp @@ -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]); diff --git a/src/views/vehicle/view_spawn_vehicle.cpp b/src/views/vehicle/view_spawn_vehicle.cpp index ca6ee10f..8975735b 100644 --- a/src/views/vehicle/view_spawn_vehicle.cpp +++ b/src/views/vehicle/view_spawn_vehicle.cpp @@ -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(*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; diff --git a/src/views/world/view_spawn_ped.cpp b/src/views/world/view_spawn_ped.cpp index 62510f00..aed30272 100644 --- a/src/views/world/view_spawn_ped.cpp +++ b/src/views/world/view_spawn_ped.cpp @@ -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);