4f5df4d1c9
The web radar component is undergoing refactoring and is non-functional. Core memory reading and overlay systems remain operational.
684 lines
25 KiB
C++
684 lines
25 KiB
C++
#include "headers/includes.h"
|
|
|
|
#include <Windows.h>
|
|
#include <array>
|
|
#include <cstdlib>
|
|
#include <string>
|
|
|
|
#include "Overlay/MenuBridge.h" // project header (src/ is on the include path)
|
|
|
|
// -------------------------------------------------------------------------
|
|
// DayZ overlay integration
|
|
//
|
|
// This is the original Lumin demo `gui.cpp`, stripped of the login screen and
|
|
// the placeholder "visual" feature panels. The window/sidebar/feature
|
|
// scaffolding is preserved verbatim; only the tab list and per-tab content
|
|
// were swapped to drive this project's real ESP state via `g_menu`
|
|
// (see src/Overlay/MenuBridge.h). https://discord.gg/jxqVWub6Dk
|
|
// -------------------------------------------------------------------------
|
|
|
|
static void sync_layout_preferences()
|
|
{
|
|
elements->padding = var->gui.compact_layout ? c_vec2(8, 8) : c_vec2(10, 10);
|
|
elements->window.rounding = var->gui.window_rounding;
|
|
}
|
|
|
|
static constexpr float visual_window_width = 900.f;
|
|
static constexpr float visual_window_height = 527.f;
|
|
static constexpr float visual_sidebar_width = 162.5f;
|
|
static constexpr float visual_outer_padding = 10.f;
|
|
static constexpr float visual_column_gap = 14.f;
|
|
static constexpr float visual_panel_scale = 1.0f;
|
|
static constexpr float visual_section_width_scale = 0.98f;
|
|
static constexpr float visual_feature_padding_x = 0.f;
|
|
static constexpr float visual_feature_padding_y = 0.f;
|
|
|
|
struct visual_panel_density_state
|
|
{
|
|
float dpi;
|
|
float font_scale;
|
|
};
|
|
|
|
static float unscale_visual(float value)
|
|
{
|
|
return value / ImMax(var->gui.dpi, 0.01f);
|
|
}
|
|
|
|
static float visual_section_height(int section_count)
|
|
{
|
|
const float content_height = unscale_visual(gui->content_avail().y);
|
|
const float gaps = visual_column_gap * static_cast<float>(ImMax(section_count - 1, 0));
|
|
return ImMax(220.f, (content_height - gaps) / static_cast<float>(ImMax(section_count, 1)));
|
|
}
|
|
|
|
extern c_vec4 g_pill_selected_rect;
|
|
extern c_vec4 g_sidebar_selected_rect;
|
|
|
|
static int g_panel_number = 0;
|
|
|
|
// ---- search filtering -----------------------------------------------------
|
|
|
|
static char visual_search_lower(char value)
|
|
{
|
|
return value >= 'A' && value <= 'Z' ? static_cast<char>(value - 'A' + 'a') : value;
|
|
}
|
|
|
|
static std::string visual_search_query()
|
|
{
|
|
std::string query = var->gui.feature_search;
|
|
size_t first = 0;
|
|
while (first < query.size() && (query[first] == ' ' || query[first] == '\t'))
|
|
first++;
|
|
|
|
size_t last = query.size();
|
|
while (last > first && (query[last - 1] == ' ' || query[last - 1] == '\t'))
|
|
last--;
|
|
|
|
return query.substr(first, last - first);
|
|
}
|
|
|
|
static bool visual_contains_ci(std::string_view text, std::string_view query)
|
|
{
|
|
if (query.empty())
|
|
return true;
|
|
|
|
if (query.size() > text.size())
|
|
return false;
|
|
|
|
for (size_t i = 0; i <= text.size() - query.size(); i++)
|
|
{
|
|
size_t j = 0;
|
|
while (j < query.size() && visual_search_lower(text[i + j]) == visual_search_lower(query[j]))
|
|
j++;
|
|
|
|
if (j == query.size())
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool visual_search_matches(std::string_view name, std::string_view description = {})
|
|
{
|
|
const std::string query = visual_search_query();
|
|
if (query.empty())
|
|
return true;
|
|
|
|
return visual_contains_ci(name, query) || visual_contains_ci(description, query);
|
|
}
|
|
|
|
struct visual_widget_filter
|
|
{
|
|
bool checkbox(std::string name, std::string description, bool* callback, title_status_icon status = title_status_none) const
|
|
{
|
|
if (!visual_search_matches(name, description))
|
|
return false;
|
|
|
|
return ::widgets->checkbox(name, description, callback, status);
|
|
}
|
|
|
|
bool slider(std::string name, std::string description, float* callback, float vmin, float vmax, std::string format = "%.1f") const
|
|
{
|
|
if (!visual_search_matches(name, description))
|
|
return false;
|
|
|
|
return ::widgets->slider(name, description, callback, vmin, vmax, format);
|
|
}
|
|
};
|
|
|
|
// ---- section helpers ------------------------------------------------------
|
|
|
|
static void begin_visual_section(std::string_view name, float height)
|
|
{
|
|
const int panel_number = g_panel_number + 1;
|
|
const float section_width = elements->child_width * visual_section_width_scale;
|
|
const float content_padding_x = ImMax(0.f, section_width * 0.05f);
|
|
gui->begin_content(name, c_vec2(section_width, s_(height)), c_vec2(content_padding_x, s_(5)), s_(0, 0), window_flags_no_move | window_flags_no_scrollbar, child_flags_none);
|
|
c_window* window = gui->get_window();
|
|
draw->rect_filled(window->DrawList, window->Rect().Min, window->Rect().Max, draw->get_clr(clr->child), s_(14));
|
|
|
|
g_panel_number = panel_number;
|
|
}
|
|
|
|
static void end_visual_section()
|
|
{
|
|
gui->end_content();
|
|
}
|
|
|
|
static visual_panel_density_state begin_visual_panel_density()
|
|
{
|
|
c_window* window = gui->get_window();
|
|
visual_panel_density_state state{ var->gui.dpi, window->FontWindowScale };
|
|
|
|
var->gui.dpi = ImMax(0.01f, state.dpi * visual_panel_scale);
|
|
ImGui::SetWindowFontScale(state.font_scale * visual_panel_scale);
|
|
return state;
|
|
}
|
|
|
|
static void end_visual_panel_density(visual_panel_density_state state)
|
|
{
|
|
ImGui::SetWindowFontScale(state.font_scale);
|
|
var->gui.dpi = state.dpi;
|
|
}
|
|
|
|
static void draw_visual_sidebar_glass(const c_rect& rect)
|
|
{
|
|
ImDrawList* draw_list = gui->get_window()->DrawList;
|
|
const float rounding = s_(14);
|
|
draw->rect_filled(draw_list, rect.Min, rect.Max, draw->get_clr(clr->child), rounding);
|
|
}
|
|
|
|
// Full-width single-column panel (used by Info / Radar / Settings).
|
|
static void begin_full_section(std::string_view name, float height, bool scroll = false)
|
|
{
|
|
const float section_width = gui->content_avail().x;
|
|
const float content_padding_x = ImMax(0.f, section_width * 0.035f);
|
|
const window_flags flags = window_flags_no_move | (scroll ? 0 : window_flags_no_scrollbar);
|
|
gui->begin_content(name, c_vec2(section_width, s_(height)), c_vec2(content_padding_x, s_(10)), s_(0, 6), flags, child_flags_none);
|
|
c_window* window = gui->get_window();
|
|
draw->rect_filled(window->DrawList, window->Rect().Min, window->Rect().Max, draw->get_clr(clr->child), s_(14));
|
|
}
|
|
|
|
// Accent section heading.
|
|
static void lumin_heading(const char* text)
|
|
{
|
|
c_window* w = gui->get_window();
|
|
const c_vec2 pos = w->DC.CursorPos;
|
|
const c_vec2 size = c_vec2(gui->content_avail().x, s_(22));
|
|
const c_rect rect(pos, pos + size);
|
|
gui->item_size(rect);
|
|
if (!gui->item_add(rect, w->GetID(text)))
|
|
return;
|
|
draw->text_clipped(w->DrawList, font->get(inter_semibold, 13), rect.Min, rect.Max, draw->get_clr(clr->accent), text, 0, 0, { 0.f, 0.5f });
|
|
}
|
|
|
|
// Muted single-line note.
|
|
static void lumin_note(const char* text)
|
|
{
|
|
c_window* w = gui->get_window();
|
|
const c_vec2 pos = w->DC.CursorPos;
|
|
const c_vec2 size = c_vec2(gui->content_avail().x, s_(16));
|
|
const c_rect rect(pos, pos + size);
|
|
gui->item_size(rect);
|
|
if (!gui->item_add(rect, w->GetID(text)))
|
|
return;
|
|
draw->text_clipped(w->DrawList, font->get(inter_medium, 11), rect.Min, rect.Max, draw->get_clr(clr->text), text, 0, 0, { 0.f, 0.5f });
|
|
}
|
|
|
|
// Read-only "label .... value" row on a rounded widget background.
|
|
static void lumin_kv(const char* label, const std::string& value, const c_vec4& value_clr)
|
|
{
|
|
c_window* w = gui->get_window();
|
|
const c_vec2 pos = w->DC.CursorPos;
|
|
const c_vec2 size = c_vec2(gui->content_avail().x, s_(34));
|
|
const c_rect rect(pos, pos + size);
|
|
gui->item_size(rect);
|
|
if (!gui->item_add(rect, w->GetID(label)))
|
|
return;
|
|
draw->rect_filled(w->DrawList, rect.Min, rect.Max, draw->get_clr(clr->widget), s_(8));
|
|
draw->text_clipped(w->DrawList, font->get(inter_semibold, 12), rect.Min + s_(12, 0), rect.Max, draw->get_clr(clr->white), label, 0, 0, { 0.f, 0.5f });
|
|
draw->text_clipped(w->DrawList, font->get(inter_medium, 11), rect.Min, rect.Max - s_(12, 0), draw->get_clr(value_clr), value.data(), 0, 0, { 1.f, 0.5f });
|
|
}
|
|
|
|
// ---- Tab content ----------------------------------------------------------
|
|
|
|
static void render_aim_tab(const visual_widget_filter& w, float section_height)
|
|
{
|
|
if (!g_menu || !g_menu->cfg)
|
|
return;
|
|
|
|
begin_full_section("Aim Assistance", section_height);
|
|
{
|
|
lumin_heading("Combat Mode");
|
|
w.checkbox("Combat Mode", "Hides loot and animals; shortens bullet trail fade for cleaner combat view", &g_menu->cfg->combatMode);
|
|
gui->dummy(c_vec2(0, s_(6)));
|
|
lumin_heading("Prediction");
|
|
w.checkbox("Ballistic Dot", "Cyan dot showing where to aim to hit centre mass (accounts for gravity + drag)", &g_menu->cfg->showBallisticDot);
|
|
gui->dummy(c_vec2(0, s_(6)));
|
|
lumin_heading("Trails");
|
|
w.checkbox("Bullet Trails", "Draw flight path of each bullet from origin to impact or despawn", &g_menu->cfg->showBulletTrails);
|
|
}
|
|
end_visual_section();
|
|
}
|
|
|
|
static void render_visuals_tab(const visual_widget_filter& w, float section_height)
|
|
{
|
|
if (!g_menu || !g_menu->cfg)
|
|
return;
|
|
|
|
if (var->gui.sub_tab_stored == 1)
|
|
{
|
|
// ---- Players sub-tab ----
|
|
gui->begin_group();
|
|
{
|
|
begin_visual_section("Players", section_height);
|
|
w.checkbox("Show Players", "Show player ESP", &g_menu->cfg->showPlayers);
|
|
w.checkbox("Bounding Box", "Draw entity box", &g_menu->cfg->showBox);
|
|
w.checkbox("Skeleton", "Draw bone skeleton", &g_menu->cfg->showSkeleton);
|
|
w.checkbox("Head Circle", "Draw head highlight", &g_menu->cfg->showHeadDot);
|
|
w.checkbox("Weapon In Hand", "Show held weapon name", &g_menu->cfg->showWeapon);
|
|
w.checkbox("Health Bar", "Draw player health bar", &g_menu->cfg->showHealthBar);
|
|
w.checkbox("Health Number", "Draw numeric health", &g_menu->cfg->showHealthNumber);
|
|
w.checkbox("Corpses", "Show dead bodies", &g_menu->cfg->showCorpses);
|
|
w.checkbox("Skeleton Debug", "Label every named bone", g_menu->debugSkeleton);
|
|
end_visual_section();
|
|
}
|
|
gui->end_group();
|
|
|
|
gui->sameline();
|
|
|
|
gui->begin_group();
|
|
{
|
|
begin_visual_section("Draw Distance", section_height);
|
|
w.slider("Players", "Max player draw distance", &g_menu->cfg->playerMaxDist, 50.f, 1000.f, "%.0f m");
|
|
end_visual_section();
|
|
}
|
|
gui->end_group();
|
|
}
|
|
else
|
|
{
|
|
// ---- World sub-tab ----
|
|
gui->begin_group();
|
|
{
|
|
begin_visual_section("Entities", section_height);
|
|
// Animals and Items are suppressed in combat mode; grey them out.
|
|
ImGui::BeginDisabled(g_menu->cfg->combatMode);
|
|
w.checkbox("Animals", "Show animal ESP", &g_menu->cfg->showAnimals);
|
|
ImGui::EndDisabled();
|
|
w.checkbox("Zombies", "Show infected ESP", &g_menu->cfg->showZombies);
|
|
ImGui::BeginDisabled(g_menu->cfg->combatMode);
|
|
w.checkbox("Items", "Show loot ESP", &g_menu->cfg->showItems);
|
|
ImGui::EndDisabled();
|
|
end_visual_section();
|
|
}
|
|
gui->end_group();
|
|
|
|
gui->sameline();
|
|
|
|
gui->begin_group();
|
|
{
|
|
begin_visual_section("Draw Distance", section_height);
|
|
ImGui::BeginDisabled(g_menu->cfg->combatMode);
|
|
w.slider("Animals", "Max animal draw distance", &g_menu->cfg->animalMaxDist, 50.f, 1000.f, "%.0f m");
|
|
ImGui::EndDisabled();
|
|
w.slider("Zombies", "Max zombie draw distance", &g_menu->cfg->zombieMaxDist, 50.f, 500.f, "%.0f m");
|
|
ImGui::BeginDisabled(g_menu->cfg->combatMode);
|
|
w.slider("Items", "Max loot draw distance", &g_menu->cfg->itemMaxDist, 20.f, 200.f, "%.0f m");
|
|
ImGui::EndDisabled();
|
|
end_visual_section();
|
|
}
|
|
gui->end_group();
|
|
}
|
|
}
|
|
|
|
static void render_loot_tab(const visual_widget_filter& w, float section_height)
|
|
{
|
|
if (!g_menu || !g_menu->cfg)
|
|
return;
|
|
|
|
struct cat_t { const char* key; const char* label; };
|
|
static const std::array<cat_t, 17> kCats = { {
|
|
{ "isWeapon", "Weapons" },
|
|
{ "isAmmo", "Ammo" },
|
|
{ "isMelee", "Melee" },
|
|
{ "isExplosives", "Explosives" },
|
|
{ "isMedical", "Medical" },
|
|
{ "isFood", "Food" },
|
|
{ "isConsumables", "Consumables" },
|
|
{ "isClothing", "Clothing" },
|
|
{ "isBackpack", "Backpacks" },
|
|
{ "isOptics", "Optics" },
|
|
{ "isWeaponAttachments", "Weapon Attachments" },
|
|
{ "isTool", "Tools" },
|
|
{ "isCrafting", "Crafting" },
|
|
{ "isVehiclePart", "Vehicle Parts" },
|
|
{ "isForBuilding", "Building" },
|
|
{ "isHouse", "House / Terrain" },
|
|
{ "isOtherLoot", "Other" },
|
|
} };
|
|
|
|
// Loot categories are irrelevant when combat mode suppresses all loot.
|
|
ImGui::BeginDisabled(g_menu->cfg->combatMode);
|
|
auto& cats = g_menu->cfg->itemCategories;
|
|
|
|
auto draw_category = [&](const cat_t& c)
|
|
{
|
|
// Missing key defaults to enabled; widget mutates the map slot directly.
|
|
auto it = cats.find(c.key);
|
|
if (it == cats.end())
|
|
it = cats.emplace(c.key, true).first;
|
|
w.checkbox(c.label, "Toggle loot category", &it->second);
|
|
};
|
|
|
|
const size_t split = (kCats.size() + 1) / 2;
|
|
|
|
gui->begin_group();
|
|
{
|
|
begin_visual_section("Loot Categories", section_height);
|
|
for (size_t i = 0; i < split; i++)
|
|
draw_category(kCats[i]);
|
|
end_visual_section();
|
|
}
|
|
gui->end_group();
|
|
|
|
gui->sameline();
|
|
|
|
gui->begin_group();
|
|
{
|
|
begin_visual_section("Loot Categories##2", section_height);
|
|
for (size_t i = split; i < kCats.size(); i++)
|
|
draw_category(kCats[i]);
|
|
end_visual_section();
|
|
}
|
|
gui->end_group();
|
|
|
|
ImGui::EndDisabled();
|
|
}
|
|
|
|
static constexpr const char* kRadarDomain = "radar.charliecharliekirky.christmas";
|
|
|
|
static void render_info_tab(float section_height)
|
|
{
|
|
const c_vec4 green = c_col(75, 225, 145).Value;
|
|
const c_vec4 orange = c_col(255, 175, 75).Value;
|
|
const c_vec4 red = c_col(225, 70, 70).Value;
|
|
|
|
begin_full_section("Info", section_height, true);
|
|
{
|
|
// ---- Server ----
|
|
lumin_heading("Server");
|
|
if (g_menu && g_menu->connected)
|
|
{
|
|
lumin_kv("Status", "Connected", green);
|
|
if (!g_menu->serverName.empty()) lumin_kv("Server", g_menu->serverName, clr->white.Value);
|
|
if (!g_menu->mapName.empty()) lumin_kv("Map", g_menu->mapName, clr->white.Value);
|
|
if (g_menu->hasPos)
|
|
{
|
|
char pos[64];
|
|
ImFormatString(pos, IM_ARRAYSIZE(pos), "%.1f / %.1f / %.1f", g_menu->px, g_menu->py, g_menu->pz);
|
|
lumin_kv("Position", pos, clr->accent.Value);
|
|
}
|
|
|
|
gui->dummy(c_vec2(0, s_(6)));
|
|
lumin_heading("Entity Counts");
|
|
lumin_kv("Players", std::to_string(g_menu->nPlayers), clr->accent.Value);
|
|
lumin_kv("Animals", std::to_string(g_menu->nAnimals), clr->accent.Value);
|
|
lumin_kv("Zombies", std::to_string(g_menu->nZombies), clr->accent.Value);
|
|
lumin_kv("Vehicles", std::to_string(g_menu->nVehicles), clr->accent.Value);
|
|
lumin_kv("Items", std::to_string(g_menu->nItems), clr->accent.Value);
|
|
lumin_kv("Bullets", std::to_string(g_menu->nBullets), clr->accent.Value);
|
|
}
|
|
else
|
|
{
|
|
lumin_kv("Status", (g_menu && !g_menu->status.empty()) ? g_menu->status : "Offline", orange);
|
|
}
|
|
|
|
// ---- DMA Handle ----
|
|
gui->dummy(c_vec2(0, s_(6)));
|
|
lumin_heading("DMA Handle");
|
|
if (g_menu)
|
|
{
|
|
lumin_kv("Handle", g_menu->dmaAttached ? "Attached" : "Detached",
|
|
g_menu->dmaAttached ? green : red);
|
|
|
|
char buf[64];
|
|
ImFormatString(buf, IM_ARRAYSIZE(buf), "%.2f MB/s", g_menu->dmaReadMBps);
|
|
lumin_kv("Read Speed", buf, clr->accent.Value);
|
|
|
|
ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f /s", g_menu->dmaScatterOps);
|
|
lumin_kv("Scatter Calls", buf, clr->accent.Value);
|
|
|
|
ImFormatString(buf, IM_ARRAYSIZE(buf), "%.3f GB", g_menu->dmaTotalGB);
|
|
lumin_kv("Total Read", buf, clr->text.Value);
|
|
|
|
ImFormatString(buf, IM_ARRAYSIZE(buf), "%llu", static_cast<unsigned long long>(g_menu->dmaTotalOps));
|
|
lumin_kv("Total Ops", buf, clr->text.Value);
|
|
}
|
|
|
|
// ---- Web Radar ----
|
|
gui->dummy(c_vec2(0, s_(6)));
|
|
lumin_heading("Web Radar");
|
|
lumin_note("Open this address in a browser:");
|
|
gui->dummy(c_vec2(0, s_(4)));
|
|
if (widgets->action_button(kRadarDomain, "copy"))
|
|
ImGui::SetClipboardText(kRadarDomain);
|
|
if (g_menu)
|
|
{
|
|
gui->dummy(c_vec2(0, s_(4)));
|
|
lumin_kv("Port", std::to_string(g_menu->webPort), clr->accent.Value);
|
|
lumin_kv("Password", "Set in config.cfg", clr->text.Value);
|
|
}
|
|
}
|
|
end_visual_section();
|
|
}
|
|
|
|
static void render_config_tab(float section_height)
|
|
{
|
|
if (!g_menu || !g_menu->cfg)
|
|
return;
|
|
|
|
// Persistent text buffers backing the four resolution fields. Seeded once
|
|
// from the live cfg values; parsed back into cfg every frame so Apply picks
|
|
// up whatever the user typed.
|
|
static char ovr_w[8], ovr_h[8], rnd_w[8], rnd_h[8];
|
|
static bool buffers_ready = false;
|
|
if (!buffers_ready)
|
|
{
|
|
ImFormatString(ovr_w, IM_ARRAYSIZE(ovr_w), "%d", g_menu->cfg->overlayWidth);
|
|
ImFormatString(ovr_h, IM_ARRAYSIZE(ovr_h), "%d", g_menu->cfg->overlayHeight);
|
|
ImFormatString(rnd_w, IM_ARRAYSIZE(rnd_w), "%d", g_menu->cfg->renderWidth);
|
|
ImFormatString(rnd_h, IM_ARRAYSIZE(rnd_h), "%d", g_menu->cfg->renderHeight);
|
|
buffers_ready = true;
|
|
}
|
|
|
|
begin_full_section("Config", section_height, true);
|
|
{
|
|
lumin_heading("Overlay (Monitor) Resolution");
|
|
lumin_note("Set to your MONITOR size. 0 x 0 = auto-detect.");
|
|
gui->push_id("ovr_res");
|
|
widgets->text_field("Width", ovr_w, IM_ARRAYSIZE(ovr_w));
|
|
widgets->text_field("Height", ovr_h, IM_ARRAYSIZE(ovr_h));
|
|
gui->pop_id();
|
|
g_menu->cfg->overlayWidth = ImMax(0, atoi(ovr_w));
|
|
g_menu->cfg->overlayHeight = ImMax(0, atoi(ovr_h));
|
|
if (widgets->primary_button("Apply Monitor Resolution") && g_menu->onApplyDisplayRes)
|
|
g_menu->onApplyDisplayRes();
|
|
|
|
gui->dummy(c_vec2(0, s_(8)));
|
|
lumin_heading("Game Render Resolution");
|
|
lumin_note("Set to the in-game resolution when it differs from the");
|
|
lumin_note("monitor. 0 x 0 = no stretched-res correction.");
|
|
gui->push_id("rnd_res");
|
|
widgets->text_field("Width", rnd_w, IM_ARRAYSIZE(rnd_w));
|
|
widgets->text_field("Height", rnd_h, IM_ARRAYSIZE(rnd_h));
|
|
gui->pop_id();
|
|
g_menu->cfg->renderWidth = ImMax(0, atoi(rnd_w));
|
|
g_menu->cfg->renderHeight = ImMax(0, atoi(rnd_h));
|
|
widgets->checkbox("Stretch to fill", "GPU stretches game to fill the monitor", &g_menu->cfg->stretchToFill);
|
|
if (widgets->primary_button("Apply Render Resolution") && g_menu->onApplyRenderRes)
|
|
g_menu->onApplyRenderRes();
|
|
|
|
gui->dummy(c_vec2(0, s_(10)));
|
|
lumin_heading("General");
|
|
lumin_note("Press INSERT to toggle this menu.");
|
|
gui->dummy(c_vec2(0, s_(4)));
|
|
if (widgets->primary_button("Save Config", "active") && g_menu->onSaveConfig)
|
|
g_menu->onSaveConfig();
|
|
|
|
gui->dummy(c_vec2(0, s_(10)));
|
|
lumin_heading("Exit");
|
|
lumin_note("This will close the overlay and exit the program.");
|
|
gui->dummy(c_vec2(0, s_(4)));
|
|
const c_col saved_accent = clr->accent;
|
|
clr->accent = c_col(225, 70, 70);
|
|
if (widgets->primary_button("Exit", "back") && g_menu->onExit)
|
|
g_menu->onExit();
|
|
clr->accent = saved_accent;
|
|
}
|
|
end_visual_section();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void c_gui::render()
|
|
{
|
|
gui->initialize();
|
|
sync_layout_preferences();
|
|
|
|
gui->easing(var->gui.tab_alpha, var->gui.tab != var->gui.tab_stored ? 0.f : 1.f, 7.f, static_easing);
|
|
if (var->gui.tab_alpha == 0)
|
|
var->gui.tab = var->gui.tab_stored;
|
|
|
|
const c_vec2 target(s_(visual_window_width), s_(visual_window_height));
|
|
gui->easing(elements->window.size.x, target.x, 24.f, dynamic_easing);
|
|
gui->easing(elements->window.size.y, target.y, 24.f, dynamic_easing);
|
|
|
|
const ImVec2 disp = ImGui::GetIO().DisplaySize;
|
|
gui->set_next_window_size(elements->window.size);
|
|
gui->set_next_window_pos(c_vec2(ImMax(0.f, (disp.x - elements->window.size.x) * 0.5f),
|
|
ImMax(0.f, (disp.y - elements->window.size.y) * 0.5f)));
|
|
|
|
gui->begin(elements->window.name, nullptr, window_flags_no_scrollbar | window_flags_no_scroll_with_mouse | window_flags_no_bring_to_front_on_focus | window_flags_no_focus_on_appearing | window_flags_no_background | window_flags_no_decoration | window_flags_no_move);
|
|
{
|
|
gui->set_style();
|
|
gui->draw_decorations();
|
|
|
|
const float top_row_y = visual_outer_padding;
|
|
const float top_row_height = 50.f;
|
|
const float top_row_gap = 2.f;
|
|
const float bottom_row_y = top_row_y + top_row_height + top_row_gap;
|
|
const float bottom_row_height = visual_window_height - bottom_row_y - visual_outer_padding;
|
|
const float sidebar_tabs_y = top_row_y + top_row_height;
|
|
const float sidebar_tabs_height = visual_window_height - sidebar_tabs_y - visual_outer_padding;
|
|
|
|
draw_visual_sidebar_glass(c_rect(c_vec2(s_(visual_outer_padding), s_(top_row_y)), c_vec2(s_(visual_outer_padding + visual_sidebar_width), s_(visual_window_height - visual_outer_padding))));
|
|
|
|
gui->set_pos(c_vec2(s_(visual_outer_padding), s_(top_row_y)), pos_all);
|
|
gui->begin_content("TopBrand", c_vec2(s_(visual_sidebar_width), s_(top_row_height)), s_(0, 0), s_(0, 0), window_flags_no_scrollbar | window_flags_no_background, child_flags_none);
|
|
{
|
|
widgets->brand_header("DayZ DMA", var->gui.profile_name[0] != '\0' ? var->gui.profile_name : "DayZ Overlay");
|
|
}
|
|
gui->end_content();
|
|
|
|
gui->set_pos(c_vec2(s_(visual_outer_padding), s_(sidebar_tabs_y)), pos_all);
|
|
gui->begin_content("Tabs", c_vec2(s_(visual_sidebar_width), s_(sidebar_tabs_height)), s_(10, 10), s_(0, 4), window_flags_no_scrollbar | window_flags_no_background, child_flags_none);
|
|
{
|
|
var->gui.sidebar_glass = true;
|
|
|
|
{
|
|
c_window* tabs_inner_bg = gui->get_window();
|
|
static c_vec4 sidebar_overlay = c_vec4(0, 0, 0, 0);
|
|
gui->easing(sidebar_overlay, g_sidebar_selected_rect, 18.f, dynamic_easing);
|
|
if (sidebar_overlay.z > sidebar_overlay.x + 1.f)
|
|
{
|
|
draw->rect_filled(tabs_inner_bg->DrawList,
|
|
c_vec2(sidebar_overlay.x, sidebar_overlay.y), c_vec2(sidebar_overlay.z, sidebar_overlay.w),
|
|
draw->get_clr(clr->widget), s_(9.1f));
|
|
}
|
|
}
|
|
|
|
widgets->tab_button("Aim", "aim", 1);
|
|
widgets->tab_button("Visuals", "visuals", 2);
|
|
widgets->tab_button("Loot", "loot", 3);
|
|
widgets->tab_button("Info", "stats", 4);
|
|
widgets->tab_button("Config", "polish", 5);
|
|
|
|
{
|
|
static c_vec4 sidebar_indicator = c_vec4(0, 0, 0, 0);
|
|
gui->easing(sidebar_indicator, g_sidebar_selected_rect, 18.f, dynamic_easing);
|
|
if (sidebar_indicator.w > sidebar_indicator.y + 1.f)
|
|
{
|
|
c_window* tabs_inner = gui->get_window();
|
|
const float bar_w = s_(2);
|
|
const float bar_inset_y = s_(6);
|
|
const float bar_x = sidebar_indicator.x + s_(2);
|
|
const c_vec2 bar_min = c_vec2(bar_x, sidebar_indicator.y + bar_inset_y);
|
|
const c_vec2 bar_max = c_vec2(bar_x + bar_w, sidebar_indicator.w - bar_inset_y);
|
|
draw->rect_filled(tabs_inner->DrawList, bar_min, bar_max,
|
|
draw->get_clr(clr->accent), bar_w * 0.5f);
|
|
}
|
|
}
|
|
|
|
gui->easing(elements->tab_window_width, gui->get_window()->Size.x, 24.f, dynamic_easing);
|
|
var->gui.sidebar_glass = false;
|
|
}
|
|
gui->end_content();
|
|
|
|
gui->push_var(style_var_alpha, var->gui.tab_alpha);
|
|
|
|
const float feature_x = visual_outer_padding + visual_sidebar_width + visual_outer_padding;
|
|
const float feature_width = visual_window_width - feature_x - visual_outer_padding;
|
|
const float feature_header_height = top_row_height * 0.8f;
|
|
const float feature_header_y = top_row_y;
|
|
|
|
gui->set_pos(c_vec2(s_(feature_x), s_(feature_header_y) + s_(10) * (1.f - var->gui.tab_alpha)), pos_all);
|
|
{
|
|
const c_vec2 pill_pos = gui->get_window()->DC.CursorPos;
|
|
draw->rect_filled(gui->get_window()->DrawList, pill_pos, pill_pos + c_vec2(s_(feature_width), s_(feature_header_height)), draw->get_clr(clr->child), s_(14));
|
|
|
|
gui->begin_content("FeatureHeader", c_vec2(s_(feature_width), s_(feature_header_height)), s_(8, 4), s_(8, 0), window_flags_no_scrollbar | window_flags_no_background, child_flags_none);
|
|
{
|
|
const float search_width = s_(178.f);
|
|
|
|
if (var->gui.tab == 2) // Visuals — show sub-tab row
|
|
{
|
|
// Animated pill highlight behind the selected sub_tab_button.
|
|
static c_vec4 pill_anim = c_vec4(0, 0, 0, 0);
|
|
c_window* pill_win = gui->get_window();
|
|
gui->easing(pill_anim, g_pill_selected_rect, 18.f, dynamic_easing);
|
|
if (pill_anim.z > pill_anim.x + 1.f)
|
|
draw->rect_filled(pill_win->DrawList,
|
|
c_vec2(pill_anim.x, pill_anim.y), c_vec2(pill_anim.z, pill_anim.w),
|
|
draw->get_clr(clr->widget), s_(9.1f));
|
|
|
|
widgets->sub_tab_button("Players", "player", 1);
|
|
gui->sameline(0.f, s_(4.f));
|
|
widgets->sub_tab_button("World", "world", 2);
|
|
// Keep on the same row; jump cursor to right edge for search.
|
|
ImGui::SameLine(ImGui::GetContentRegionMax().x - search_width);
|
|
}
|
|
else
|
|
{
|
|
ImGui::SetCursorPosX(ImGui::GetContentRegionMax().x - search_width);
|
|
}
|
|
|
|
widgets->search_field("Search", var->gui.feature_search, IM_ARRAYSIZE(var->gui.feature_search), c_vec2(search_width, s_(32.f)));
|
|
}
|
|
gui->end_content();
|
|
}
|
|
|
|
gui->set_pos(c_vec2(s_(feature_x), s_(bottom_row_y) + s_(10) * (1.f - var->gui.tab_alpha)), pos_all);
|
|
gui->begin_content("Features", c_vec2(s_(feature_width), s_(bottom_row_height)), s_(visual_feature_padding_x, visual_feature_padding_y), c_vec2(s_(visual_column_gap), 0.f), window_flags_no_scrollbar);
|
|
{
|
|
const visual_panel_density_state density_state = begin_visual_panel_density();
|
|
|
|
g_panel_number = 3;
|
|
gui->easing(elements->child_width, (gui->content_avail().x - s_(visual_column_gap)) / 2, 24.f, dynamic_easing);
|
|
const float section_height = visual_section_height(1);
|
|
const visual_widget_filter visual_widgets;
|
|
|
|
switch (var->gui.tab)
|
|
{
|
|
case 1: render_aim_tab(visual_widgets, section_height); break;
|
|
case 2: render_visuals_tab(visual_widgets, section_height); break;
|
|
case 3: render_loot_tab(visual_widgets, section_height); break;
|
|
case 4: render_info_tab(section_height); break;
|
|
case 5: render_config_tab(section_height); break;
|
|
default: break;
|
|
}
|
|
|
|
end_visual_panel_density(density_state);
|
|
}
|
|
gui->end_content();
|
|
|
|
gui->pop_var();
|
|
}
|
|
gui->end();
|
|
}
|
|
|
|
// Shim called by GameOverlay (declared in src/Overlay/MenuBridge.h).
|
|
void RenderLuminMenu()
|
|
{
|
|
gui->render();
|
|
}
|