mirror of
https://github.com/Mr-X-GTA/YimMenu.git
synced 2025-06-18 07:07:32 +08:00
349 lines
12 KiB
C++
349 lines
12 KiB
C++
![]() |
#include "services/gta_data/gta_data_service.hpp"
|
||
|
#include "services/squad_spawner/squad_spawner.hpp"
|
||
|
#include "misc/cpp/imgui_stdlib.h"
|
||
|
#include "views/view.hpp"
|
||
|
|
||
|
namespace big
|
||
|
{
|
||
|
|
||
|
void view::squad_spawner()
|
||
|
{
|
||
|
const char* const spawn_distance_modes[5]{"Custom", "On target", "Closeby", "Moderately distanced", "Far away"};
|
||
|
const char* const combat_ability_levels[3]{"Poor", "Average", "Professional"};
|
||
|
|
||
|
static squad new_template{};
|
||
|
static player_ptr victim = g_player_service->get_selected();
|
||
|
|
||
|
ImGui::Text("Victim");
|
||
|
ImGui::SetNextItemWidth(200);
|
||
|
if (ImGui::BeginCombo("##victim", victim->get_name()))
|
||
|
{
|
||
|
auto self = g_player_service->get_self();
|
||
|
if (ImGui::Selectable(self->get_name(), self->id() == victim->id()))
|
||
|
victim = self;
|
||
|
for (auto p : g_player_service->players() | std::ranges::views::values)
|
||
|
{
|
||
|
if (ImGui::Selectable(p->get_name(), p->id() == victim->id()))
|
||
|
{
|
||
|
victim = p;
|
||
|
if (g.player.spectating)
|
||
|
g_player_service->set_selected(victim);
|
||
|
}
|
||
|
}
|
||
|
ImGui::EndCombo();
|
||
|
}
|
||
|
|
||
|
ImGui::SameLine();
|
||
|
|
||
|
if (ImGui::Checkbox("SPECTATE"_T.data(), &g.player.spectating))
|
||
|
{
|
||
|
g_player_service->set_selected(victim);
|
||
|
};
|
||
|
|
||
|
if (victim->id() != g_player_service->get_selected()->id() && victim->is_valid())
|
||
|
{
|
||
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.5f, 0.3f, 1.0f));
|
||
|
ImGui::Text("Warning: Victim and selected player are not the same");
|
||
|
ImGui::PopStyleColor();
|
||
|
}
|
||
|
|
||
|
ImGui::Separator();
|
||
|
|
||
|
static squad deletion_squad;
|
||
|
|
||
|
if (!std::string(deletion_squad.m_name).empty())
|
||
|
ImGui::OpenPopup("##deletesquad");
|
||
|
|
||
|
if (ImGui::BeginPopupModal("##deletesquad"))
|
||
|
{
|
||
|
ImGui::Text("Are you sure you want to delete %s?", deletion_squad.m_name);
|
||
|
|
||
|
if (ImGui::Button("Yes"))
|
||
|
{
|
||
|
g_squad_spawner_service.delete_squad(deletion_squad);
|
||
|
deletion_squad.m_name = "";
|
||
|
ImGui::CloseCurrentPopup();
|
||
|
}
|
||
|
ImGui::SameLine();
|
||
|
if (ImGui::Button("No"))
|
||
|
{
|
||
|
deletion_squad.m_name = "";
|
||
|
ImGui::CloseCurrentPopup();
|
||
|
}
|
||
|
|
||
|
ImGui::EndPopup();
|
||
|
}
|
||
|
|
||
|
|
||
|
ImGui::SetNextItemWidth(200);
|
||
|
if (ImGui::BeginCombo("Choose From Templates", "Templates"))
|
||
|
{
|
||
|
components::button("Fetch Custom Squads", [] {
|
||
|
g_squad_spawner_service.fetch_squads();
|
||
|
});
|
||
|
|
||
|
for (auto& temp : g_squad_spawner_service.m_templates)
|
||
|
{
|
||
|
if (ImGui::Selectable(temp.m_name.data()))
|
||
|
{
|
||
|
if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
|
||
|
{
|
||
|
deletion_squad = temp;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
new_template = temp;
|
||
|
}
|
||
|
}
|
||
|
if (ImGui::IsItemHovered() && temp.does_squad_have_description())
|
||
|
ImGui::SetTooltip(temp.m_description.data());
|
||
|
}
|
||
|
ImGui::EndCombo();
|
||
|
}
|
||
|
|
||
|
ImGui::Separator();
|
||
|
|
||
|
ImGui::BeginGroup(); //Main variables
|
||
|
|
||
|
ImGui::Text("Squad Details");
|
||
|
ImGui::Spacing();
|
||
|
|
||
|
ImGui::PushItemWidth(250);
|
||
|
|
||
|
components::input_text_with_hint("##name", "Name", &new_template.m_name);
|
||
|
components::input_text_with_hint("##pedmodel", "Ped model", &new_template.m_ped_model);
|
||
|
|
||
|
auto ped_found = std::find_if(g_gta_data_service->peds().begin(), g_gta_data_service->peds().end(), [=](const auto& pair) {
|
||
|
return pair.second.m_name == new_template.m_ped_model;
|
||
|
});
|
||
|
|
||
|
if (!std::string(new_template.m_ped_model).empty() && ped_found == g_gta_data_service->peds().end())
|
||
|
{
|
||
|
if (ImGui::ListBoxHeader("##pedlist", ImVec2(250, 200)))
|
||
|
{
|
||
|
for (auto& p : g_gta_data_service->peds() | std::ranges::views::values)
|
||
|
{
|
||
|
std::string p_model = p.m_name;
|
||
|
std::string filter = new_template.m_ped_model;
|
||
|
std::transform(p_model.begin(), p_model.end(), p_model.begin(), ::tolower);
|
||
|
std::transform(filter.begin(), filter.end(), filter.begin(), ::tolower);
|
||
|
if (p_model.find(filter) != std::string::npos && ImGui::Selectable(p.m_name))
|
||
|
{
|
||
|
new_template.m_ped_model = p.m_name;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ImGui::ListBoxFooter();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
components::input_text_with_hint("##vehmodel",
|
||
|
"Vehicle model",
|
||
|
&new_template.m_vehicle_model);
|
||
|
if (ImGui::IsItemHovered())
|
||
|
ImGui::SetTooltip("Leave empty to spawn on foot");
|
||
|
|
||
|
auto veh_found = std::find_if(g_gta_data_service->vehicles().begin(), g_gta_data_service->vehicles().end(), [=](const auto& pair) {
|
||
|
return pair.second.m_name == new_template.m_vehicle_model;
|
||
|
});
|
||
|
|
||
|
if (!new_template.m_vehicle_model.empty() && veh_found == g_gta_data_service->vehicles().end())
|
||
|
{
|
||
|
if (ImGui::ListBoxHeader("##vehlist", ImVec2(250, 200)))
|
||
|
{
|
||
|
for (auto& p : g_gta_data_service->vehicles() | std::ranges::views::values)
|
||
|
{
|
||
|
std::string p_model = p.m_name;
|
||
|
std::string filter = new_template.m_vehicle_model;
|
||
|
std::transform(p_model.begin(), p_model.end(), p_model.begin(), ::tolower);
|
||
|
std::transform(filter.begin(), filter.end(), filter.begin(), ::tolower);
|
||
|
if (p_model.find(filter) != std::string::npos && ImGui::Selectable(p.m_name))
|
||
|
{
|
||
|
new_template.m_vehicle_model = p.m_name;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ImGui::ListBoxFooter();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
components::input_text_with_hint("##weapmodel",
|
||
|
"Weapon model",
|
||
|
&new_template.m_weapon_model);
|
||
|
if (ImGui::IsItemHovered())
|
||
|
ImGui::SetTooltip("Leave empty to spawn unarmed, beware that a player can only attain 3 melee attackers at a time");
|
||
|
|
||
|
auto weap_found = std::find_if(g_gta_data_service->weapons().begin(), g_gta_data_service->weapons().end(), [=](const auto& pair) {
|
||
|
return pair.second.m_name == new_template.m_weapon_model;
|
||
|
});
|
||
|
|
||
|
if (!std::string(new_template.m_weapon_model).empty() && weap_found == g_gta_data_service->weapons().end())
|
||
|
{
|
||
|
if (ImGui::ListBoxHeader("##weaplist", ImVec2(250, 200)))
|
||
|
{
|
||
|
for (auto& p : g_gta_data_service->weapons() | std::ranges::views::values)
|
||
|
{
|
||
|
std::string p_model = p.m_name;
|
||
|
std::string filter = new_template.m_weapon_model;
|
||
|
std::transform(p_model.begin(), p_model.end(), p_model.begin(), ::tolower);
|
||
|
std::transform(filter.begin(), filter.end(), filter.begin(), ::tolower);
|
||
|
if (p_model.find(filter) != std::string::npos && ImGui::Selectable(p.m_name))
|
||
|
{
|
||
|
new_template.m_weapon_model = p.m_name;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ImGui::ListBoxFooter();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ImGui::Spacing();
|
||
|
ImGui::Text("Spawn Distance");
|
||
|
if (ImGui::BeginCombo("##spawndistance", spawn_distance_modes[(int)new_template.m_spawn_distance_mode]))
|
||
|
{
|
||
|
for (int i = 0; i < 5; i++)
|
||
|
{
|
||
|
if (ImGui::Selectable(spawn_distance_modes[i], (int)new_template.m_spawn_distance_mode == i))
|
||
|
new_template.m_spawn_distance_mode = (eSquadSpawnDistance)i;
|
||
|
}
|
||
|
ImGui::EndCombo();
|
||
|
}
|
||
|
ImGui::Text("Squad Size");
|
||
|
ImGui::SliderInt("##squadsize", &new_template.m_squad_size, 1, 8);
|
||
|
ImGui::PopItemWidth();
|
||
|
|
||
|
ImGui::EndGroup();
|
||
|
ImGui::SameLine();
|
||
|
ImGui::BeginGroup(); //General actions
|
||
|
|
||
|
ImGui::Text("Actions");
|
||
|
ImGui::Spacing();
|
||
|
components::button(std::string("Terminate " + std::to_string(g_squad_spawner_service.m_active_squads.size()) + " squads"), [] {
|
||
|
g_squad_spawner_service.terminate_squads();
|
||
|
});
|
||
|
|
||
|
components::button("Reset Fields", [] {
|
||
|
new_template.m_spawn_distance_mode = (eSquadSpawnDistance)1;
|
||
|
new_template.m_combat_ability_level = (eCombatAbilityLevel)2;
|
||
|
new_template.m_name[0] = '\0';
|
||
|
new_template.m_description[0] = '\0';
|
||
|
new_template.m_ped_model[0] = '\0';
|
||
|
new_template.m_vehicle_model[0] = '\0';
|
||
|
new_template.m_weapon_model[0] = '\0';
|
||
|
new_template.m_squad_size = 0;
|
||
|
new_template.m_ped_invincibility = 0;
|
||
|
new_template.m_veh_invincibility = 0;
|
||
|
new_template.m_ped_health = 0;
|
||
|
new_template.m_ped_armor = 0;
|
||
|
new_template.m_ped_accuracy = 0;
|
||
|
new_template.m_spawn_distance = 0;
|
||
|
for (int i = 0; i < sizeof(new_template.m_ped_proofs) / sizeof(new_template.m_ped_proofs[0]); i++)
|
||
|
new_template.m_ped_proofs[i] = false;
|
||
|
new_template.m_stay_in_veh = 0;
|
||
|
new_template.m_spawn_behind_same_velocity = 0;
|
||
|
new_template.m_disperse = 0;
|
||
|
});
|
||
|
|
||
|
ImGui::EndGroup();
|
||
|
ImGui::Spacing();
|
||
|
if (ImGui::TreeNode("Advanced Options"))
|
||
|
{
|
||
|
ImGui::BeginGroup(); //Toggleables
|
||
|
|
||
|
ImGui::Checkbox("Disperse", &new_template.m_disperse);
|
||
|
if (ImGui::IsItemHovered())
|
||
|
ImGui::SetTooltip("If the squad is on foot, will scatter units within the spawn distance");
|
||
|
ImGui::Checkbox("Vehicle catch up", &new_template.m_spawn_behind_same_velocity);
|
||
|
if (ImGui::IsItemHovered())
|
||
|
ImGui::SetTooltip("Will spawn the mobile squad behind the target with identical velocity if applicable.\nOnly for squads with a vehicle.");
|
||
|
ImGui::Checkbox("Stay In Vehicle", &new_template.m_stay_in_veh);
|
||
|
ImGui::Checkbox("Ped God Mode", &new_template.m_ped_invincibility);
|
||
|
ImGui::Checkbox("Vehicle God Mode", &new_template.m_veh_invincibility);
|
||
|
ImGui::Checkbox("Headshot Proof", &new_template.m_ped_proofs[0]);
|
||
|
ImGui::Checkbox("Bullet Proof", &new_template.m_ped_proofs[1]);
|
||
|
ImGui::Checkbox("Flame Proof", &new_template.m_ped_proofs[2]);
|
||
|
ImGui::Checkbox("Melee Proof", &new_template.m_ped_proofs[3]);
|
||
|
ImGui::Checkbox("Explosion Proof", &new_template.m_ped_proofs[4]);
|
||
|
|
||
|
ImGui::EndGroup();
|
||
|
ImGui::SameLine();
|
||
|
ImGui::BeginGroup(); //Slideables
|
||
|
ImGui::PushItemWidth(200);
|
||
|
ImGui::Text("Ped Health");
|
||
|
ImGui::SliderFloat("##pedhealth", &new_template.m_ped_health, 100, 2000);
|
||
|
ImGui::Text("Ped Armor");
|
||
|
ImGui::SliderFloat("##pedarmor", &new_template.m_ped_armor, 0, 2000);
|
||
|
ImGui::Text("Ped Accuracy");
|
||
|
ImGui::SliderFloat("##pedaccuracy", &new_template.m_ped_accuracy, 0, 100);
|
||
|
ImGui::Text("Custom Spawn Distance");
|
||
|
ImGui::SliderFloat("##customspawndistance", &new_template.m_spawn_distance, 10, 500);
|
||
|
ImGui::EndGroup();
|
||
|
if (ImGui::IsItemHovered())
|
||
|
ImGui::SetTooltip("Leave these values at 0 to default, except for accuracy.");
|
||
|
|
||
|
ImGui::SameLine();
|
||
|
ImGui::BeginGroup(); //Chooseables
|
||
|
ImGui::Text("Combat Ability");
|
||
|
if (ImGui::BeginCombo("##combatability", combat_ability_levels[(int)new_template.m_combat_ability_level]))
|
||
|
{
|
||
|
for (int i = 0; i < 3; i++)
|
||
|
{
|
||
|
if (ImGui::Selectable(combat_ability_levels[i], (int)new_template.m_combat_ability_level == i))
|
||
|
new_template.m_combat_ability_level = (eCombatAbilityLevel)i;
|
||
|
}
|
||
|
ImGui::EndCombo();
|
||
|
}
|
||
|
ImGui::PopItemWidth();
|
||
|
ImGui::EndGroup();
|
||
|
|
||
|
components::input_text_with_hint("##new_template.m_description",
|
||
|
"Squad new_template.m_description",
|
||
|
&new_template.m_description);
|
||
|
|
||
|
ImGui::TreePop();
|
||
|
}
|
||
|
|
||
|
static auto check_validity = [=](bool save) -> bool {
|
||
|
if (!victim->is_valid() && !save)
|
||
|
{
|
||
|
g_notification_service->push_error("Squad spawner", "Choose a victim first");
|
||
|
return false;
|
||
|
}
|
||
|
if (std::string(new_template.m_ped_model).empty())
|
||
|
{
|
||
|
g_notification_service->push_error("Squad spawner", "A ped model is required");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
};
|
||
|
|
||
|
static auto check_if_exists = [=](std::string squad_name) -> bool {
|
||
|
bool exists = false;
|
||
|
|
||
|
for (auto& s : g_squad_spawner_service.m_templates)
|
||
|
{
|
||
|
if (s.m_name.compare(squad_name) == 0)
|
||
|
{
|
||
|
exists = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return exists;
|
||
|
};
|
||
|
|
||
|
components::button("Spawn Squad", [] {
|
||
|
if (check_validity(false))
|
||
|
g_squad_spawner_service.spawn_squad({new_template.m_name, new_template.m_ped_model, new_template.m_weapon_model, new_template.m_vehicle_model, new_template.m_squad_size, new_template.m_ped_invincibility, new_template.m_veh_invincibility, new_template.m_ped_proofs, new_template.m_ped_health, new_template.m_ped_armor, new_template.m_spawn_distance, new_template.m_ped_accuracy, new_template.m_spawn_distance_mode, new_template.m_combat_ability_level, new_template.m_stay_in_veh, new_template.m_spawn_behind_same_velocity, new_template.m_description, new_template.m_disperse},
|
||
|
victim,
|
||
|
false,
|
||
|
{});
|
||
|
});
|
||
|
ImGui::SameLine();
|
||
|
components::button("Save", [] {
|
||
|
if (check_validity(true) && !check_if_exists(new_template.m_name))
|
||
|
g_squad_spawner_service.save_squad(new_template);
|
||
|
});
|
||
|
}
|
||
|
}
|