diff --git a/src/backend/looped/self/super_hero_fly.cpp b/src/backend/looped/self/super_hero_fly.cpp new file mode 100644 index 00000000..e13a21a8 --- /dev/null +++ b/src/backend/looped/self/super_hero_fly.cpp @@ -0,0 +1,411 @@ +#include "backend/looped_command.hpp" +#include "backend/bool_command.hpp" +#include "backend/float_command.hpp" +#include "gta/enums.hpp" +#include "natives.hpp" +#include "util/entity.hpp" +#include "util/math.hpp" +#include "util/notify.hpp" +#include "util/ped.hpp" +#include "util/vehicle.hpp" + +namespace big +{ + class super_hero_fly : looped_command + { + using looped_command::looped_command; + + bool m_flying = false; + bool m_landing = false; + bool m_launching = false; + bool m_anims_are_playing = false; + + bool m_timer = false; + std::chrono::system_clock::time_point m_time_stamp; + std::chrono::milliseconds m_duration; + + bool m_charging = false; + double m_charge_intensity = 1; + int m_charge_ptfx = 0; + float m_explosion_intensity = 0; + + Vehicle m_veh_handle{}; + Vector3 m_land_coords{}; + Vector3 m_fly_motion{}; + + void reset() + { + m_flying = false; + m_landing = false; + m_launching = false; + m_timer = false; + m_charging = false; + m_charge_intensity = 0; + m_charge_ptfx = 0; + m_explosion_intensity = 0; + TASK::CLEAR_PED_TASKS(self::ped); + m_time_stamp = std::chrono::system_clock::now(); + PED::SET_PED_CAN_RAGDOLL(self::ped, true); + detach_delete_vehicle(); + if (STREAMING::HAS_NAMED_PTFX_ASSET_LOADED("scr_rcbarry1")) + STREAMING::REMOVE_NAMED_PTFX_ASSET("scr_rcbarry1"); + } + + void apply_fly_animations(bool apply_lower_body, bool apply_uppder_body) + { + //A mix of two animations with their flags specifically tailored to mimic a sort of superman stance + + if (apply_lower_body) + ped::ped_play_animation(self::ped, "skydive@parachute@first_person", "chute_idle_alt_lookright", 4, 1, -1, 1 | 1048576); + + if (apply_uppder_body) + ped::ped_play_animation(self::ped, "missfam5_yoga", "c8_to_start", 4, 1, -1, 2 | 16 | 32 | 131072 | 1048576); + } + + void apply_explosion() + { + if (g.self.super_hero_fly.explosions) + FIRE::ADD_EXPLOSION(self::pos.x, self::pos.y, self::pos.z, eExplosionTag::TANKSHELL, 0, true, true, 1, true); + } + + void detach_delete_vehicle() + { + ENTITY::DETACH_ENTITY(m_veh_handle, false, false); + ENTITY::DETACH_ENTITY(self::ped, true, true); + ENTITY::SET_ENTITY_COLLISION(m_veh_handle, false, false); + script::get_current()->yield(50ms); + + if (ENTITY::DOES_ENTITY_EXIST(m_veh_handle)) + { + if (entity::take_control_of(m_veh_handle)) + { + ENTITY::DETACH_ENTITY(m_veh_handle, false, false); + + entity::delete_entity(m_veh_handle); + } + } + } + + void create_psuedo_vehicle() + { + detach_delete_vehicle(); + m_veh_handle = vehicle::spawn(0xEEF345EC, ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(self::ped, 0.0, 0.0, 5.f), ENTITY::GET_ENTITY_HEADING(self::ped), true, false); + VEHICLE::SET_VEHICLE_GRAVITY(m_veh_handle, false); + ENTITY::SET_ENTITY_INVINCIBLE(m_veh_handle, true); + ENTITY::SET_ENTITY_VISIBLE(m_veh_handle, false, 0); + } + + void attach_to_psuedo_vehicle() + { + if (ENTITY::DOES_ENTITY_EXIST(m_veh_handle)) + { + ENTITY::ATTACH_ENTITY_TO_ENTITY(self::ped, m_veh_handle, 0, 0, 0, 0, 0, 0, 0, true, false, false, false, 0, true, false); + } + } + + void gravitate(Entity ent, Vector3 coord, float speed) + { + ENTITY::SET_ENTITY_VELOCITY(ent, + (coord.x - self::pos.x) * speed, + (coord.y - self::pos.y) * speed, + (coord.z - self::pos.z) * speed); + } + + /* + This method is called in conjunction with a pressed key, so it can be considered a loop. + Consider all its content to have a lifetime similar to a while loop. + */ + void charge_launch() + { + if (ENTITY::IS_ENTITY_IN_AIR(self::ped) || ENTITY::GET_ENTITY_HEIGHT_ABOVE_GROUND(self::ped) > 5 || m_duration.count() < 0.2) + return; + + if (!ENTITY::IS_ENTITY_PLAYING_ANIM(self::ped, "anim@amb@inspect@crouch@male_a@base", "base", 3)) + ped::ped_play_animation(self::ped, "anim@amb@inspect@crouch@male_a@base", "base", 4, 1, -1, 1 | 131072 | 262144 | 1048576 | 33554432); + + m_charge_intensity = m_duration.count(); + + if (m_charge_intensity > 5) + m_charge_intensity = 5; + if (m_explosion_intensity > 10) + m_explosion_intensity = 10; + + if (g.self.super_hero_fly.ptfx && m_charge_intensity > 0.4) + { + STREAMING::REQUEST_NAMED_PTFX_ASSET("scr_rcbarry1"); + GRAPHICS::USE_PARTICLE_FX_ASSET("scr_rcbarry1"); + m_charge_ptfx = GRAPHICS::START_NETWORKED_PARTICLE_FX_NON_LOOPED_AT_COORD("scr_alien_disintegrate", + self::pos.x, + self::pos.y, + self::pos.z - 1, + 0, + 0, + 0, + m_charge_intensity / 10, + 0, + 0, + 0, + 0); + + if ((((int)(std::round(m_charge_intensity * 10)) % 5)) == 1) + { + for (int i = 0; i < m_explosion_intensity; i++) + { + FIRE::ADD_EXPLOSION(self::pos.x, self::pos.y, self::pos.z + i, eExplosionTag::EXP_TAG_TORPEDO_UNDERWATER, 0, true, true, m_charge_intensity / 10, true); + } + m_explosion_intensity += 0.5; + } + } + + m_charging = true; + } + + /* + Unlike the method name, this method is responsible for both initiating the flight and landing once in air. + */ + void launch() + { + if (!m_flying) + { + m_launching = true; + m_landing = false; + m_fly_motion = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(self::ped, 0.0, 0.0, 5.f); + TASK::CLEAR_PED_TASKS_IMMEDIATELY(self::ped); + + apply_fly_animations(true, true); + + //Avoid gravity related game mechanics to interupt any of our operations + ENTITY::SET_ENTITY_VELOCITY(self::ped, 0, 0, 1); + //Since flight is tightly connected to the animations, flying is only true if and when the animations are playing. + m_flying = true; + + create_psuedo_vehicle(); + attach_to_psuedo_vehicle(); + + //Special effect if player is on ground + if (!ENTITY::IS_ENTITY_IN_AIR(m_veh_handle) && ENTITY::GET_ENTITY_HEIGHT_ABOVE_GROUND(m_veh_handle) < 10) + { + m_fly_motion = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(self::ped, + 0.0, + 0.0, + g.self.super_hero_fly.charge ? m_charge_intensity * 50 : g.self.super_hero_fly.initial_launch); + + apply_explosion(); + } + + m_charge_intensity = 0; + m_timer = false; + GRAPHICS::STOP_PARTICLE_FX_LOOPED(m_charge_ptfx, false); + STREAMING::REMOVE_NAMED_PTFX_ASSET("scr_rcbarry1"); + m_charge_ptfx = 0; + m_explosion_intensity = 0; + m_launching = false; + + //Relying on a script yield, we return since flying wasn't true. Anything beyond this point would initiate landing. + return; + } + + land(); + } + + void land() + { + if (!m_landing && m_flying) + { + //Negative Z velocity results in gravity assuming we are falling, hence the removal of the parachute. + constexpr auto parachute_hash = RAGE_JOAAT("GADGET_PARACHUTE"); + WEAPON::REMOVE_WEAPON_FROM_PED(self::ped, parachute_hash); + detach_delete_vehicle(); + TASK::CLEAR_PED_TASKS_IMMEDIATELY(self::ped); + m_flying = false; + m_landing = true; + + //Using raycast probe to determine where the player camera is looking at. + m_land_coords = math::raycast_coords(CAM::GET_GAMEPLAY_CAM_COORD(), CAM::GET_GAMEPLAY_CAM_ROT(2), self::ped); + + //If the determined land_coords are further than 500, we change our landing coord to the ground beneath. + if (math::distance_between_vectors(self::pos, m_land_coords) > 500) + { + m_land_coords = self::pos; + MISC::GET_GROUND_Z_FOR_3D_COORD(self::pos.x, self::pos.y, self::pos.z, &m_land_coords.z, true, 0); + } + + PED::SET_PED_CAN_RAGDOLL(self::ped, false); + + //Use gravitate singularly to swing the player ped to the determined land_coords. Roughly innacurate since velocity is physics based. + gravitate(self::ped, m_land_coords, 40); + } + } + + virtual void on_tick() override + { + //Both anims are required in order to consider the player ped flying. + m_anims_are_playing = ENTITY::IS_ENTITY_PLAYING_ANIM(self::ped, "missfam5_yoga", "c8_to_start", 3) && ENTITY::IS_ENTITY_PLAYING_ANIM(self::ped, "skydive@parachute@first_person", "chute_idle_alt_lookright", 3); + + //Check whether animations are compromised which would mean our flight is interrupted. Reset to avoid unwanted behaviour. + if (!m_anims_are_playing && !m_launching && m_flying) + reset(); + + PAD::DISABLE_CONTROL_ACTION(0, (int)ControllerInputs::INPUT_COVER, false); + + if (m_timer) + m_duration = std::chrono::duration_cast (std::chrono::system_clock::now() - m_time_stamp); + + //Timer is used for both the reset and the charged launch + if (PAD::IS_DISABLED_CONTROL_JUST_RELEASED(0, (int)ControllerInputs::INPUT_COVER)) + { + m_timer = false; + m_charging = false; + + //Check whether the button was released quickly to reset instead of initiate landing + if (m_flying && m_duration.count() <= 0.2) + { + reset(); + } + else + { + launch(); + + script::get_current()->yield(10ms); + } + + m_duration = std::chrono::milliseconds::zero(); + } + + //Timer is started once the button is pressed and a marker is drawn if player is flying to visualize landing coords. + if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_COVER)) + { + if (!m_timer) + { + m_time_stamp = std::chrono::system_clock::now(); + m_timer = true; + } + + if (m_flying) + { + auto probable_land_coords = math::raycast_coords(CAM::GET_GAMEPLAY_CAM_COORD(), CAM::GET_GAMEPLAY_CAM_ROT(2), self::ped); + GRAPHICS::DRAW_MARKER(25, probable_land_coords.x, probable_land_coords.y, probable_land_coords.z + 0.1f, 0.f, 0.f, 0.f, 0, 0, 0, 5.f, 5.f, 5.f, 255, 255, 255, 100, 0, 0, 0, 0, 0, 0, 0); + } + } + + if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_COVER) && !m_flying + && g.self.super_hero_fly.charge) + { + charge_launch(); + } + + if (m_flying) + { + if (g.self.super_hero_fly.fly_speed > 20) + g.self.super_hero_fly.fly_speed = 20; + if (g.self.super_hero_fly.fly_speed < 1) + g.self.super_hero_fly.fly_speed = 1; + + Vector3 rot = CAM::GET_GAMEPLAY_CAM_ROT(2); + + if (!NETWORK::NETWORK_HAS_CONTROL_OF_ENTITY(m_veh_handle)) + entity::take_control_of(m_veh_handle); + + ENTITY::SET_ENTITY_ROTATION(m_veh_handle, rot.x, rot.y, rot.z, 2, 0); + + //Gravitate is called as long as flying is true to move our player ped to the desired coords with velocity. + gravitate(m_veh_handle, m_fly_motion, g.self.super_hero_fly.fly_speed); + + if (ENTITY::GET_ENTITY_HEIGHT_ABOVE_GROUND(m_veh_handle) < 1 && g.self.super_hero_fly.auto_land) + launch(); + + //Fly motion nav + Vector3 fly_nav{}; + bool moved = false; + if (PAD::IS_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_MOVE_UP_ONLY)) + { + fly_nav = + ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(m_veh_handle, 0.0, (1.0 * g.self.super_hero_fly.fly_speed), 0.f); + moved = true; + } + if (PAD::IS_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_MOVE_LEFT_ONLY)) + { + fly_nav = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(m_veh_handle, (-1.0 * g.self.super_hero_fly.fly_speed), 0.0, 0.f); + moved = true; + } + if (PAD::IS_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_MOVE_RIGHT_ONLY)) + { + fly_nav = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(m_veh_handle, (1.0 * g.self.super_hero_fly.fly_speed), 0.0, 0.f); + moved = true; + } + if (PAD::IS_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_MOVE_DOWN_ONLY)) + { + fly_nav = + ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(m_veh_handle, 0.0, (-1.0 * g.self.super_hero_fly.fly_speed), 0.f); + moved = true; + } + if (PAD::IS_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_SPRINT)) + { + Vector3 above = {self::pos.x, self::pos.y, self::pos.z + (float)(1.0 * g.self.super_hero_fly.fly_speed)}; + fly_nav = above; + moved = true; + } + if (PAD::IS_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_DUCK)) + { + Vector3 below = {self::pos.x, self::pos.y, self::pos.z - (float)(1.0 * g.self.super_hero_fly.fly_speed)}; + fly_nav = below; + moved = true; + } + + if (moved) + { + //Gradual smoothes the flight by incrementing speed as long as we are moving + if (g.self.super_hero_fly.gradual) + { + g.self.super_hero_fly.fly_speed += 0.1f; + } + m_fly_motion = fly_nav; + moved = false; + } + else + { + //Reset the speed for gradual movement + if (g.self.super_hero_fly.gradual) + { + g.self.super_hero_fly.fly_speed = 1.f; + } + } + } + + if (m_landing) + { + if (ENTITY::GET_ENTITY_HEIGHT_ABOVE_GROUND(self::ped) < 2 || !ENTITY::IS_ENTITY_IN_AIR(self::ped)) + { + detach_delete_vehicle(); + + ENTITY::SET_ENTITY_VELOCITY(self::ped, 0, 0, 0); + TASK::CLEAR_PED_TASKS(self::ped); + m_landing = false; + ENTITY::SET_ENTITY_VELOCITY(m_veh_handle, 0, 0, 0); + ped::ped_play_animation(self::ped, "move_fall@beastjump", "high_land_stand", 4, -4, 2000, 0 | 4); + apply_explosion(); + reset(); + } + } + } + + virtual void on_enable() override + { + g_notification_service->push("SUPER_HERO_FLY"_T.data(), "SUPER_HERO_FLY_ENABLE_NOTIFICATION"_T.data()); + } + + virtual void on_disable() override + { + reset(); + } + }; + + super_hero_fly g_super_hero_fly("superherofly", "SUPER_HERO_FLY", "SUPER_HERO_FLY_DESC", g.self.super_hero_fly.enabled); + bool_command gradual_speed("superheroflygradualspeed", "SUPER_HERO_FLY_GRADUAL_SPEED", "SUPER_HERO_FLY_GRADUAL_SPEED_DESC", g.self.super_hero_fly.gradual); + bool_command explosions("superheroflyexplosions", "SUPER_HERO_FLY_EXPLOSIONS", "SUPER_HERO_FLY_EXPLOSIONS_DESC", g.self.super_hero_fly.explosions); + bool_command auto_land("superheroflyautoland", "SUPER_HERO_FLY_AUTO_LAND", "SUPER_HERO_FLY_AUTO_LAND_DESC", g.self.super_hero_fly.auto_land); + bool_command charge_launch("superheroflychargelaunch", "SUPER_HERO_FLY_CHARGE_LAUNCH", "SUPER_HERO_FLY_CHARGE_LAUNCH_DESC", g.self.super_hero_fly.charge); + bool_command charge_ptfx("superheroflychargeptfx", "SUPER_HERO_FLY_CHARGE_PTFX", "SUPER_HERO_FLY_CHARGE_PTFX_DESC", g.self.super_hero_fly.ptfx); + float_command speed("superheroflyspeed", "SUPER_HERO_FLY_SPEED", "SUPER_HERO_FLY_SPEED_DESC", g.self.super_hero_fly.fly_speed, 1.f, 50.f); + float_command initial_launch("superheroflyinitiallaunch", "SUPER_HERO_FLY_INITIAL_LAUNCH", "SUPER_HERO_FLY_INITIAL_LAUNCH_DESC", g.self.super_hero_fly.initial_launch, 1.f, 50.f); +} \ No newline at end of file diff --git a/src/backend/looped/self/superman.cpp b/src/backend/looped/self/superman.cpp deleted file mode 100644 index cd2229e0..00000000 --- a/src/backend/looped/self/superman.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "backend/looped_command.hpp" -#include "gta/enums.hpp" -#include "natives.hpp" -namespace big -{ - class superman : looped_command - { - using looped_command::looped_command; - - void apply_force(float x, float y, float z) - { - ENTITY::APPLY_FORCE_TO_ENTITY(self::ped, 1, x, y, z, 0, 0, 0, 0, true, true, true, false, true); - } - - virtual void on_tick() override - { - if (PAD::IS_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_JUMP)) - apply_force(0, 0, 10); - - WEAPON::GIVE_DELAYED_WEAPON_TO_PED(self::ped, rage::joaat("GADGET_PARACHUTE"), 1, 1); - if (!ENTITY::IS_ENTITY_IN_AIR(self::ped) || PED::IS_PED_RAGDOLL(self::ped)) - return; - - if (PAD::IS_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_MOVE_UP_ONLY)) - apply_force(3, 0, 0); - - if (PAD::IS_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_MOVE_DOWN_ONLY)) - apply_force(3, 6, 0); - - if (PAD::IS_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_SPRINT)) - apply_force(6, 0, 0); - } - - virtual void on_enable() override - { - g_notification_service->push("Superman Controls", "Use the following keys to control the Superman mode:\n'W' / 'S' / 'SPACE' / 'SHIFT'."); - } - }; - - superman g_superman("superman", "SUPERMAN", "SUPERMAN_DESC", g.self.superman); -} diff --git a/src/core/settings.hpp b/src/core/settings.hpp index 9ef5e21f..74e65a23 100644 --- a/src/core/settings.hpp +++ b/src/core/settings.hpp @@ -367,7 +367,21 @@ namespace big // do not save below entries bool dance_mode = false; - NLOHMANN_DEFINE_TYPE_INTRUSIVE(self, ipls, ptfx_effects, clean_player, force_wanted_level, passive, free_cam, invisibility, local_visibility, never_wanted, no_ragdoll, noclip, noclip_aim_speed_multiplier, noclip_speed_multiplier, off_radar, super_run, no_collision, unlimited_oxygen, no_water_collision, wanted_level, god_mode, part_water, proof_bullet, proof_fire, proof_collision, proof_melee, proof_explosion, proof_steam, proof_drown, proof_water, proof_mask, mobile_radio, fast_respawn, auto_tp, super_jump, beast_jump, healthregen, healthregenrate, hud, superman, custom_weapon_stop, prompt_ambient_animations, persist_outfit, persist_outfits_mis) + struct super_hero_fly + { + bool enabled = false; + bool gradual = true; + bool explosions = true; + bool auto_land = false; + bool charge = true; + bool ptfx = true; + float fly_speed = 15.f; + float initial_launch = 15.f; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(super_hero_fly, gradual, explosions, auto_land, charge, ptfx, fly_speed, initial_launch) + } super_hero_fly{}; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(self, ipls, ptfx_effects, clean_player, force_wanted_level, passive, free_cam, invisibility, local_visibility, never_wanted, no_ragdoll, noclip, noclip_aim_speed_multiplier, noclip_speed_multiplier, off_radar, super_run, no_collision, unlimited_oxygen, no_water_collision, wanted_level, god_mode, part_water, proof_bullet, proof_fire, proof_collision, proof_melee, proof_explosion, proof_steam, proof_drown, proof_water, proof_mask, mobile_radio, fast_respawn, auto_tp, super_jump, beast_jump, healthregen, healthregenrate, hud, superman, custom_weapon_stop, prompt_ambient_animations, persist_outfit, persist_outfits_mis, super_hero_fly) } self{}; struct session diff --git a/src/gui/components/components.hpp b/src/gui/components/components.hpp index 94918613..bfb224dc 100644 --- a/src/gui/components/components.hpp +++ b/src/gui/components/components.hpp @@ -35,7 +35,7 @@ namespace big static bool script_patch_checkbox(const std::string_view text, bool* option, const std::string_view tooltip = ""); - static void options_modal(std::string element_name, std::function render_elements, bool sameline = true, std::string custom_button_name = "Options"); + static void options_modal(const std::string_view element_name, std::function render_elements, bool sameline = true, std::string custom_button_name = "Options"); template static void command_button(const std::vector args = {}, std::optional label_override = std::nullopt) @@ -117,6 +117,22 @@ namespace big ImGui::SetTooltip(command->get_description().c_str()); } + template + static void command_float_input(std::optional label_override = std::nullopt) + { + static float_command* command = (float_command*)command::get(rage::consteval_joaat(cmd_str.value)); + if (command == nullptr) + return ImGui::Text("INVALID COMMAND"); + + ImGui::InputFloat(label_override.value_or(command->get_label()).data(), + &command->get_value(), + command->get_lower_bound(), + command->get_upper_bound()); + + if (ImGui::IsItemHovered()) + ImGui::SetTooltip(command->get_description().c_str()); + } + template static bool button(const std::string_view text) { diff --git a/src/gui/components/options_modal.cpp b/src/gui/components/options_modal.cpp index 096cd81b..7dfa73b5 100644 --- a/src/gui/components/options_modal.cpp +++ b/src/gui/components/options_modal.cpp @@ -5,12 +5,13 @@ namespace big /* Will provide an options button next to the previous element that opens up a popup to run the content of 'render_elements' */ - void components::options_modal(std::string element_name, std::function render_elements, bool sameline, std::string custom_button_name) + void components::options_modal(const std::string_view element_name, std::function render_elements, bool sameline, std::string custom_button_name) { if (sameline) ImGui::SameLine(); - if (ImGui::Button(std::string(custom_button_name + "##" + element_name).data())) + ImGui::PushID(element_name.data()); + if (ImGui::Button(custom_button_name.c_str())) ImGui::OpenPopup(element_name.data()); ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x * 0.5f, ImGui::GetIO().DisplaySize.y * 0.5f), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); @@ -18,10 +19,11 @@ namespace big { render_elements(); ImGui::Spacing(); - if (ImGui::Button(std::format("{}##{}", "CLOSE"_T, element_name).c_str()) || ((!ImGui::IsWindowHovered() && !ImGui::IsAnyItemHovered()) && ImGui::IsMouseClicked(ImGuiMouseButton_Left))) + if (components::button("CLOSE"_T) || ((!ImGui::IsWindowHovered() && !ImGui::IsAnyItemHovered()) && ImGui::IsMouseClicked(ImGuiMouseButton_Left))) ImGui::CloseCurrentPopup(); ImGui::EndPopup(); } + ImGui::PopID(); } } \ No newline at end of file diff --git a/src/util/math.hpp b/src/util/math.hpp index f7c7ac95..749eabc2 100644 --- a/src/util/math.hpp +++ b/src/util/math.hpp @@ -1,5 +1,6 @@ #pragma once #include "pointers.hpp" +#include "natives.hpp" namespace big::math { @@ -36,4 +37,30 @@ namespace big::math return (float)distance_between_vectors(plyr_coords, cam_coords); } + + inline Vector3 raycast_coords(Vector3 coord, Vector3 rot, Entity ignore) + { + BOOL hit; + Vector3 end_coords; + Vector3 surface_normal; + Entity hit_entity; + Vector3 dir = math::rotation_to_direction(rot); + Vector3 far_coords; + + far_coords.x = coord.x + dir.x * 1000; + far_coords.y = coord.y + dir.y * 1000; + far_coords.z = coord.z + dir.z * 1000; + + int ray = SHAPETEST::START_EXPENSIVE_SYNCHRONOUS_SHAPE_TEST_LOS_PROBE(coord.x, + coord.y, + coord.z, + far_coords.x, + far_coords.y, + far_coords.z, + -1, + ignore, + 7); + SHAPETEST::GET_SHAPE_TEST_RESULT(ray, &hit, &end_coords, &surface_normal, &hit_entity); + return end_coords; + } } diff --git a/src/views/self/view_self.cpp b/src/views/self/view_self.cpp index 6bb7c875..1baae19d 100644 --- a/src/views/self/view_self.cpp +++ b/src/views/self/view_self.cpp @@ -55,7 +55,7 @@ namespace big ImGui::BeginGroup(); components::command_checkbox<"noclip">(); - components::options_modal("Noclip", [] { + components::options_modal("NO_CLIP"_T, [] { ImGui::Separator(); ImGui::BeginGroup(); @@ -82,7 +82,25 @@ namespace big components::command_checkbox<"cleanloop">(); components::command_checkbox<"mobileradio">(); - components::command_checkbox<"superman">(); + components::command_checkbox<"superherofly">(); + components::options_modal("SUPER_HERO_FLY_OPTION_MODAL"_T, [] { + ImGui::Text("SUPER_HERO_FLY_OPTION_MODAL_DETAILED_DESC"_T.data()); + ImGui::Separator(); + + components::command_checkbox<"superheroflygradualspeed">(); + components::disable_unless([] { return !g.self.super_hero_fly.gradual; }, []{ + ImGui::SetNextItemWidth(150); + components::command_float_input<"superheroflyspeed">(); + }); + components::command_checkbox<"superheroflyexplosions">(); + components::command_checkbox<"superheroflyautoland">(); + components::command_checkbox<"superheroflychargelaunch">(); + components::disable_unless([] { return g.self.super_hero_fly.charge; }, []{ + components::command_checkbox<"superheroflychargeptfx">(); + }); + ImGui::SetNextItemWidth(150); + components::command_float_input<"superheroflyinitiallaunch">(); + }); ImGui::Checkbox("DANCE_MODE"_T.data(), &g.self.dance_mode);