TmpMenu/src/views/world/view_squad_spawner.cpp
tupoy-ya e0bd043588 feat(Outfit Editor): Add [+] & [-] buttons (#1441)
* And other general UI improvements
2023-06-23 10:44:06 +02:00

404 lines
14 KiB
C++

#include "misc/cpp/imgui_stdlib.h"
#include "services/gta_data/gta_data_service.hpp"
#include "services/orbital_drone/orbital_drone.hpp"
#include "services/squad_spawner/squad_spawner.hpp"
#include "services/vehicle/persist_car_service.hpp"
#include "views/view.hpp"
namespace big
{
void view::squad_spawner()
{
const char* const spawn_distance_modes[5]{"Custom", "On target", "Nearby", "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 (!new_template.m_ped_model.empty() && ped_found == g_gta_data_service->peds().end())
{
if (ImGui::BeginListBox("##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::EndListBox();
}
}
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::BeginListBox("##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::EndListBox();
}
}
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 (!new_template.m_weapon_model.empty() && weap_found == g_gta_data_service->weapons().end())
{
if (ImGui::BeginListBox("##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::EndListBox();
}
}
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::CLOSEBY;
new_template.m_combat_ability_level = eCombatAbilityLevel::AVERAGE;
new_template.m_name.clear();
new_template.m_description.clear();
new_template.m_ped_model.clear();
new_template.m_vehicle_model.clear();
new_template.m_weapon_model.clear();
new_template.m_persistent_vehicle = "None";
new_template.m_squad_size = 1;
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 = 50;
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;
new_template.m_spawn_ahead = 0;
new_template.m_favour_roads = 0;
new_template.m_max_vehicle = 0;
});
ImGui::EndGroup();
ImGui::Spacing();
if (ImGui::TreeNode("Advanced Options"))
{
ImGui::BeginGroup(); //Toggleables
ImGui::Checkbox("Spawn Ahead", &new_template.m_spawn_ahead);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Will use the distance specified and apply it in a forward direction to find a position ahead of the target");
ImGui::Checkbox("Favour Roads", &new_template.m_favour_roads);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Will try and find a road first");
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("Vehicle Mods Maxed", &new_template.m_max_vehicle);
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
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, 0, 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, 0, 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::Text("Persistent Vehicle");
if (ImGui::BeginCombo("##persistent_vehicle", new_template.m_persistent_vehicle.data()))
{
if (ImGui::Selectable("None", new_template.m_persistent_vehicle == "None"))
new_template.m_persistent_vehicle = "None";
for (auto& p : persist_car_service::list_files())
{
if (ImGui::Selectable(p.data(), p == new_template.m_persistent_vehicle))
new_template.m_persistent_vehicle = p;
}
ImGui::EndCombo();
}
ImGui::PopItemWidth();
ImGui::EndGroup();
components::input_text_with_hint("##new_template.m_description", "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", [] {
try
{
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,
new_template.m_spawn_ahead,
new_template.m_favour_roads,
new_template.m_max_vehicle,
new_template.m_persistent_vehicle},
victim,
new_template.m_spawn_distance_mode == eSquadSpawnDistance::CUSTOM,
g_orbital_drone_service.m_ground_pos);
}
catch (std::exception e)
{
LOG(WARNING) << "Exception while spawning squad " << e.what();
}
});
ImGui::SameLine();
components::button("Save", [] {
if (check_validity(true) && !check_if_exists(new_template.m_name))
g_squad_spawner_service.save_squad(new_template);
});
}
}