Compare commits

...

21 commits

Author SHA1 Message Date
Azrub
39ca3d919b Release: v1.7.1.0
Finally self-hosted! Migrated from GitHub to my own Forgejo instance here. Full development history, all commits and tags are intact — nothing lost. Future updates will be distributed from here. Welcome to the new home of GolemHelper!
2026-04-15 01:09:51 +02:00
Azrub
d035d14587 Release v1.7.0.0
New Features:

- Added Coordinate Calibration - manually calibrate click positions for unsupported resolutions, UI scales, or custom Windows DPI settings via addon options
- Calibration values are saved persistently and applied globally to all click sequences

UI Improvements:

- Moved "Current template" indicator inside the Templates tab - also resolves window stretching on certain resolutions
- Added hint below delay settings to suggest calibration if clicks miss

Technical Changes:

- Fixed implicit size_t to int conversion warning in template list rendering
2026-04-02 00:53:28 +02:00
Azrub
a334cadd83 Release v1.6.0.0
New Features:

- Added "Remove and Respawn" button
- Added "Respawn" and "Remove and Respawn" buttons to Templates tab for quick access
- Added "Always Load Last Settings" option - automatically saves and restores your last used settings on startup

UI Improvements:

- Improved button spacing and layout consistency
2025-10-29 21:10:18 +01:00
Azrub
0faba02a60 Release v1.5.3.0
Added support for 3840x2160 monitor
2025-08-24 15:29:44 +02:00
Azrub
f6055f946c Release v1.5.2.0
Added Respawn Golem button
2025-08-12 12:13:11 +02:00
Azrub
98c51aa098 Release v1.5.1.0
New Features:

- Auto Show/Hide UI: New setting that automatically shows/hides the UI when entering/exiting Training Area

Technical Changes:

Architecture refactor; replaced coordinate arrays and magic numbers with enum-based system:

- NEW: MenuSequences.h - Centralized sequence definitions with clean logic
- REFACTORED: Types.h - Semantic enum structure mapping GW2 interface 1:1 (BOON_ALACRITY vs stepIndex == 13)
- REFACTORED: AutomationLogic.cpp - Eliminated all magic numbers, unified healer logic
- Improved maintainability
- Enhanced readability: Self-documenting code with meaningful names like GOLEM_SLOW instead of array indices
2025-08-08 03:56:11 +02:00
Azrub
54233f6ac1 Hotfix: restored deleted coordinate
Restored deleted coordinate
2025-08-06 05:41:08 +02:00
Azrub
ccead0d29b Release v1.5.0.0
New features:

- Skip Confusion
- Add Immobilize
- Add Blind

Templates Improvements:

- Templates tab redesign with improved layout and organization
- Apply Boons and Spawn Golem buttons added to Templates tab for instant access to templates sequences
- Template name truncation for the "Current" template indicator to prevent UI stretching with long names

Other Improvements/changes:

- Training Area safety check - Apply buttons only function when inside Training Area
- Auto-stop sequences when game loses focus (Alt+Tab, Windows key, etc.)
- Cleaned up golem sequence by removing redundant coordinate that was causing vulnerability to be clicked twice
- Cleaner console output with reduced debug logging
2025-08-06 04:00:04 +02:00
Azrub
cc5bcb3c9c Release v1.4.1.0
Added Skip Aegis option
2025-08-04 06:11:51 +02:00
Azrub
60bdded498 Removed PCH remnants and standardized C++17 across all configurations
- Removed obsolete files: framework.h, pch.h, pch.cpp
- Cleaned all PrecompiledHeader references from project settings
- Set C++17 standard for all platforms (Win32 + x64) and configurations (Debug + Release)
- Removed .vcxproj.user from tracking (personal settings)
- Updated .gitignore
2025-08-03 03:16:27 +02:00
Azrub
366f3f4918 Release v1.4.0.0
Template system, advanced boon settings, and icon visibility control

- Save/load/delete custom templates with boon, golem, and condition settings (saved to addons/GolemHelper/templates.cfg) and real-time current template display
- QuickLoad buttons: DPS, Quick DPS, Alac DPS, qHeal, aHeal for instant switching
- Advanced boon settings: Add Resistance/Stability options (now all boons are covered; disabled in healer mode)
- Always Hide Icon setting to permanently hide QuickAccess icon
- Removed redundant checkboxes
2025-08-03 01:45:01 +02:00
Azrub
47839c1915 Release v1.3.0.0
- GolemHelper icon now appears only in Training Area and automatically hides in all other maps.
2025-07-31 19:47:32 +02:00
Azrub
80c2157f24 Merge branch 'main' of https://github.com/Azrub/GolemHelper 2025-07-31 18:46:51 +02:00
Azrub
291c4aa939 Release v1.2.6.0
- Removed use custom delay tick option (addon will automatically use the values of the sliders for delays)
- Cleaned up the custom delays section (removed collapsible background)
2025-07-31 18:46:21 +02:00
Azrub
e369025a59
Update README.md 2025-07-21 18:22:15 +02:00
Azrub
f3f326266c Release v1.2.5.0
Added support for 3440x1440 monitor
2025-07-20 16:34:58 +02:00
Azrub
ad0d3f3641 Release v1.2.4.0
Added support for 5120x1440 monitor
2025-07-19 23:01:14 +02:00
Azrub
995dc8b505 Release v1.2.3.0
Dual delay system with collapsible UI

- Added separate Initial Delay and Step Delay sliders for better timing control
- Fixed custom delay bug where 290ms custom was failing vs 290ms default
- Implemented collapsible "Set Custom Delays" section for cleaner UI
- Added internal "Use Custom Delays" checkbox for easy on/off control
- Users can now configure delays, enable them, and collapse section to save space
- Updated config system to save/load both delay values
2025-07-19 19:54:41 +02:00
Azrub
4adbe16698 Refactor: Split dllmain.cpp into organized modules
- Split 1000+ line dllmain.cpp into clean, modular structure
- Organized code into Common/, Utils/, Config/, Automation/, UI/, Input/ modules
- Removed precompiled headers to simplify build configuration
- Improved maintainability and code organization
- No functional changes, identical addon behavior
2025-07-17 13:28:31 +02:00
Azrub
f41ab40356 Release 1.2.2.0
- Added embedded icons support with Windows resources
- Added icon extraction from embedded DLL resources
- Include PNG icons as embedded resources
- Updated gitignore for build artifacts
- Icons are automatically extracted to addons/GolemHelper/icons/
2025-07-16 18:57:20 +02:00
Azrub
8684c75f21 Release v1.2.1.0
Fixed slider width to prevent UI expansion when custom step delay is enabled
2025-07-16 12:44:16 +02:00
35 changed files with 2884 additions and 968 deletions

56
.gitignore vendored
View file

@ -1,34 +1,43 @@
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Linker files
*.ilk
# Debugger Files
*.pdb
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# debug information files
# Debug information files
*.dwo
# Visual Studio specific files
@ -45,6 +54,15 @@
*.svclog
*.scc
# Visual Studio additional files
*.vcxproj.user
*.sdf
*.opensdf
*.db
*.opendb
*.idb
*.exp
# Build folders
[Dd]ebug/
[Dd]ebugPublic/
@ -67,4 +85,38 @@ bld/
*.command.*
*.read.*
*.write.*
link-*
link-*
# Backup files
*.bak
*~
# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Temporary files
*.tmp
*.temp
# IDE files
*.swp
*.swo
# Package files (vcpkg, NuGet)
packages/
vcpkg_installed/
# Visual Studio Code
.vscode/
# JetBrains IDEs
.idea/
# Resource compiled files
*.aps

View file

@ -0,0 +1,427 @@
#include <Windows.h>
#include <string>
#include "AutomationLogic.h"
#include "../Common/Globals.h"
#include "../Common/MenuSequences.h"
#include "CoordinateUtils.h"
bool AutomationLogic::ShouldSkipBoonStep(int stepIndex) {
MenuOption step = MenuSequences::BOON_SEQUENCE[stepIndex];
if (g_state.isQuickDps && step == BOON_QUICKNESS) {
return true;
}
if (g_state.isAlacDps && step == BOON_ALACRITY) {
return true;
}
if (g_state.showBoonAdvanced && g_state.skipAegis && step == BOON_AEGIS) {
return true;
}
return false;
}
bool AutomationLogic::ShouldSkipGolemStep(int stepIndex) {
if (!g_state.showAdvanced) {
return false;
}
MenuOption step = MenuSequences::GOLEM_SEQUENCE[stepIndex];
if (g_state.skipBurning && step == GOLEM_BURNING) {
return true;
}
if (g_state.skipConfusion && step == GOLEM_CONFUSION) {
return true;
}
if (g_state.skipSlow && step == GOLEM_SLOW) {
return true;
}
return false;
}
void AutomationLogic::ApplyHealerBoons() {
if (!g_api || !g_state.enabled) return;
bool uiWasVisible = g_state.showUI;
if (uiWasVisible) {
g_state.showUI = false;
}
std::string mode = "Healer Bench - ";
if (g_state.isQuickDps) {
mode += "Quick DPS";
}
else if (g_state.isAlacDps) {
mode += "Alac DPS";
}
mode += " + Environment ";
switch (g_state.envDamageLevel) {
case ENV_MILD: mode += "Mild"; break;
case ENV_MODERATE: mode += "Moderate"; break;
case ENV_EXTREME: mode += "Extreme"; break;
}
char startBuffer[400];
sprintf_s(startBuffer, "Starting healer boon sequence - Mode: %s", mode.c_str());
g_api->Log(ELogLevel_INFO, "GolemHelper", startBuffer);
try {
g_api->GameBinds.InvokeAsync(EGameBinds_MiscInteract, 50);
Sleep(g_state.initialDelay);
bool alacrityCounted = false;
for (int i = 0; i < MenuSequences::HEALER_QUICK_LENGTH; i++) {
MenuOption step = MenuSequences::HEALER_QUICK_SEQUENCE[i];
if (g_state.isAlacDps && step == BOON_ALACRITY) {
if (!alacrityCounted) {
auto quicknessCoord = g_coords.coords.find(BOON_QUICKNESS);
if (quicknessCoord != g_coords.coords.end()) {
CoordinateUtils::ClickAtScaled(
quicknessCoord->second.first,
quicknessCoord->second.second,
g_state.stepDelay
);
}
alacrityCounted = true;
}
continue;
}
auto coordIt = g_coords.coords.find(step);
if (coordIt != g_coords.coords.end()) {
CoordinateUtils::ClickAtScaled(
coordIt->second.first,
coordIt->second.second,
g_state.stepDelay
);
}
}
MenuOption envDamageOption;
switch (g_state.envDamageLevel) {
case ENV_MILD: envDamageOption = BOON_ENV_MILD; break;
case ENV_MODERATE: envDamageOption = BOON_ENV_MODERATE; break;
case ENV_EXTREME: envDamageOption = BOON_ENV_EXTREME; break;
default: envDamageOption = BOON_ENV_MILD; break;
}
auto envCoord = g_coords.coords.find(envDamageOption);
if (envCoord != g_coords.coords.end()) {
CoordinateUtils::ClickAtScaled(envCoord->second.first, envCoord->second.second, 50);
}
}
catch (...) {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Exception during healer boon sequence");
}
if (uiWasVisible) {
g_state.showUI = true;
}
g_api->Log(ELogLevel_INFO, "GolemHelper", "Healer boon sequence completed!");
}
void AutomationLogic::ApplyBoons() {
if (!g_api || !g_state.enabled) return;
if (g_state.environmentDamage) {
ApplyHealerBoons();
return;
}
bool uiWasVisible = g_state.showUI;
if (uiWasVisible) {
g_state.showUI = false;
}
std::string mode = "Normal";
if (g_state.isQuickDps) {
mode = "Quick DPS";
}
else if (g_state.isAlacDps) {
mode = "Alac DPS";
}
std::string advancedBoons = "";
if (g_state.showBoonAdvanced && (g_state.addResistance || g_state.addStability || g_state.skipAegis)) {
advancedBoons = " + ";
if (g_state.addResistance) advancedBoons += "Resistance ";
if (g_state.addStability) advancedBoons += "Stability ";
if (g_state.skipAegis) advancedBoons += "Skip Aegis ";
advancedBoons.pop_back();
}
char startBuffer[300];
sprintf_s(startBuffer, "Starting boon sequence (20 steps) - Mode: %s%s", mode.c_str(), advancedBoons.c_str());
g_api->Log(ELogLevel_INFO, "GolemHelper", startBuffer);
try {
g_api->GameBinds.InvokeAsync(EGameBinds_MiscInteract, 50);
Sleep(g_state.initialDelay);
for (int i = 0; i < MenuSequences::BOON_LENGTH; i++) {
int stepIndex = i;
MenuOption step = MenuSequences::BOON_SEQUENCE[i];
auto coordIt = g_coords.coords.find(step);
if (coordIt == g_coords.coords.end() ||
(coordIt->second.first == 0 && coordIt->second.second == 0)) {
continue;
}
if (ShouldSkipBoonStep(stepIndex)) {
continue;
}
if (step == BOON_RESOLUTION) {
CoordinateUtils::ClickAtScaled(
coordIt->second.first,
coordIt->second.second,
g_state.stepDelay
);
if (g_state.showBoonAdvanced && g_state.addResistance) {
auto resistanceCoord = g_coords.coords.find(BOON_RESISTANCE);
if (resistanceCoord != g_coords.coords.end()) {
CoordinateUtils::ClickAtScaled(
resistanceCoord->second.first,
resistanceCoord->second.second,
g_state.stepDelay
);
}
}
if (g_state.showBoonAdvanced && g_state.addStability) {
auto stabilityCoord = g_coords.coords.find(BOON_STABILITY);
if (stabilityCoord != g_coords.coords.end()) {
CoordinateUtils::ClickAtScaled(
stabilityCoord->second.first,
stabilityCoord->second.second,
g_state.stepDelay
);
}
}
continue;
}
int delay = (i == MenuSequences::BOON_LENGTH - 1) ? 50 : g_state.stepDelay;
CoordinateUtils::ClickAtScaled(coordIt->second.first, coordIt->second.second, delay);
}
}
catch (...) {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Exception during boon sequence");
}
if (uiWasVisible) {
g_state.showUI = true;
}
g_api->Log(ELogLevel_INFO, "GolemHelper", "Boon sequence completed!");
}
void AutomationLogic::SpawnGolem() {
if (!g_api || !g_state.enabled) return;
bool uiWasVisible = g_state.showUI;
if (uiWasVisible) {
g_state.showUI = false;
}
const char* hitbox = g_state.hitboxType == HITBOX_SMALL ? "Small Hitbox" :
g_state.hitboxType == HITBOX_MEDIUM ? "Medium Hitbox" : "Large Hitbox";
std::string modifiers = "Normal";
if (g_state.showAdvanced && (g_state.skipBurning || g_state.skipConfusion || g_state.skipSlow ||
g_state.addImmobilize || g_state.addBlind || g_state.fiveBleedingStacks)) {
modifiers = "";
if (g_state.skipBurning) modifiers += "Skip Burning ";
if (g_state.skipConfusion) modifiers += "Skip Confusion ";
if (g_state.skipSlow) modifiers += "Skip Slow ";
if (g_state.addImmobilize) modifiers += "Add Immobilize ";
if (g_state.addBlind) modifiers += "Add Blind ";
if (g_state.fiveBleedingStacks) modifiers += "5 Bleeding ";
if (!modifiers.empty()) modifiers.pop_back();
}
char startBuffer[400];
sprintf_s(startBuffer, "Starting golem settings sequence (25 steps) - Modifiers: %s, Hitbox: %s", modifiers.c_str(), hitbox);
g_api->Log(ELogLevel_INFO, "GolemHelper", startBuffer);
try {
g_api->GameBinds.InvokeAsync(EGameBinds_MiscInteract, 50);
Sleep(g_state.initialDelay);
for (int i = 0; i < MenuSequences::GOLEM_LENGTH; i++) {
int stepIndex = i;
MenuOption step = MenuSequences::GOLEM_SEQUENCE[i];
auto coordIt = g_coords.coords.find(step);
if (coordIt == g_coords.coords.end() ||
(coordIt->second.first == 0 && coordIt->second.second == 0)) {
continue;
}
if (ShouldSkipGolemStep(stepIndex)) {
continue;
}
int currentX = coordIt->second.first;
int currentY = coordIt->second.second;
if (step == GOLEM_HITBOX_SMALL) {
MenuOption hitboxOption;
switch (g_state.hitboxType) {
case HITBOX_SMALL: hitboxOption = GOLEM_HITBOX_SMALL; break;
case HITBOX_MEDIUM: hitboxOption = GOLEM_HITBOX_MEDIUM; break;
case HITBOX_LARGE: hitboxOption = GOLEM_HITBOX_LARGE; break;
default: hitboxOption = GOLEM_HITBOX_SMALL; break;
}
auto hitboxCoord = g_coords.coords.find(hitboxOption);
if (hitboxCoord != g_coords.coords.end()) {
currentX = hitboxCoord->second.first;
currentY = hitboxCoord->second.second;
}
}
int delay = (i == MenuSequences::GOLEM_LENGTH - 1) ? 50 : g_state.stepDelay;
if (step == GOLEM_CRIPPLE) {
CoordinateUtils::ClickAtScaled(currentX, currentY, delay);
if (g_state.showAdvanced && g_state.addImmobilize) {
auto immobilizeCoord = g_coords.coords.find(GOLEM_IMMOBILIZE);
if (immobilizeCoord != g_coords.coords.end()) {
CoordinateUtils::ClickAtScaled(
immobilizeCoord->second.first,
immobilizeCoord->second.second,
g_state.stepDelay
);
}
}
continue;
}
if (step == GOLEM_COMBATAFFECTINGCONDITIONS) {
CoordinateUtils::ClickAtScaled(currentX, currentY, delay);
if (g_state.showAdvanced && g_state.addBlind) {
auto blindCoord = g_coords.coords.find(GOLEM_BLIND);
if (blindCoord != g_coords.coords.end()) {
CoordinateUtils::ClickAtScaled(
blindCoord->second.first,
blindCoord->second.second,
g_state.stepDelay
);
}
}
continue;
}
CoordinateUtils::ClickAtScaled(currentX, currentY, delay);
if (g_state.showAdvanced && g_state.fiveBleedingStacks && step == GOLEM_BLEEDING) {
for (int repeat = 0; repeat < 4; repeat++) {
CoordinateUtils::ClickAtScaled(currentX, currentY, g_state.stepDelay);
}
}
}
}
catch (...) {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Exception during golem settings sequence");
}
if (uiWasVisible) {
g_state.showUI = true;
}
g_api->Log(ELogLevel_INFO, "GolemHelper", "Golem settings sequence completed (25 steps)!");
}
void AutomationLogic::RespawnGolem() {
if (!g_api || !g_state.enabled) return;
bool uiWasVisible = g_state.showUI;
if (uiWasVisible) {
g_state.showUI = false;
}
g_api->Log(ELogLevel_INFO, "GolemHelper", "Starting golem respawn sequence (2 steps)");
try {
g_api->GameBinds.InvokeAsync(EGameBinds_MiscInteract, 50);
Sleep(g_state.initialDelay);
for (int i = 0; i < MenuSequences::GOLEM_RESPAWN_LENGTH; i++) {
MenuOption step = MenuSequences::GOLEM_RESPAWN[i];
auto coordIt = g_coords.coords.find(step);
if (coordIt == g_coords.coords.end() ||
(coordIt->second.first == 0 && coordIt->second.second == 0)) {
continue;
}
int delay = (i == MenuSequences::GOLEM_RESPAWN_LENGTH - 1) ? 50 : g_state.stepDelay;
CoordinateUtils::ClickAtScaled(coordIt->second.first, coordIt->second.second, delay);
}
}
catch (...) {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Exception during golem respawn sequence");
}
if (uiWasVisible) {
g_state.showUI = true;
}
g_api->Log(ELogLevel_INFO, "GolemHelper", "Golem respawn sequence completed!");
}
void AutomationLogic::RemoveAndRespawnGolem()
{
if (!g_api || !g_state.enabled) return;
bool uiWasVisible = g_state.showUI;
if (uiWasVisible) {
g_state.showUI = false;
}
g_api->Log(ELogLevel_INFO, "GolemHelper", "Starting golem remove and respawn sequence (3 steps)");
try {
g_api->GameBinds.InvokeAsync(EGameBinds_MiscInteract, 50);
Sleep(g_state.initialDelay);
for (int i = 0; i < MenuSequences::GOLEM_REMOVE_AND_RESPAWN_LENGTH; i++) {
MenuOption step = MenuSequences::GOLEM_REMOVE_AND_RESPAWN[i];
auto coordIt = g_coords.coords.find(step);
if (coordIt == g_coords.coords.end() ||
(coordIt->second.first == 0 && coordIt->second.second == 0)) {
continue;
}
int delay = (i == MenuSequences::GOLEM_REMOVE_AND_RESPAWN_LENGTH - 1) ? 50 : g_state.stepDelay;
CoordinateUtils::ClickAtScaled(coordIt->second.first, coordIt->second.second, delay);
}
}
catch (...) {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Exception during golem remove and respawn sequence");
}
if (uiWasVisible) {
g_state.showUI = true;
}
g_api->Log(ELogLevel_INFO, "GolemHelper", "Golem remove and respawn sequence completed!");
}

View file

@ -0,0 +1,12 @@
#pragma once
class AutomationLogic {
public:
static bool ShouldSkipBoonStep(int stepIndex);
static bool ShouldSkipGolemStep(int stepIndex);
static void ApplyBoons();
static void ApplyHealerBoons();
static void SpawnGolem();
static void RespawnGolem();
static void RemoveAndRespawnGolem();
};

View file

@ -0,0 +1,253 @@
#include <Windows.h>
#include <string>
#include "CoordinateUtils.h"
#include "../Common/Globals.h"
#include "../Config/ConfigManager.h"
void CoordinateUtils::GetScaledCoordinates(int baseX, int baseY, int* scaledX, int* scaledY) {
if (!g_api) return;
if (g_state.hasCalibration) {
*scaledX = (int)(baseX * g_state.calibratedScaleX);
*scaledY = (int)(baseY * g_state.calibratedScaleY);
return;
}
if (g_nexusLink && g_nexusLink->Width > 0 && g_nexusLink->Height > 0) {
float uiScale = g_nexusLink->Scaling;
float dpiScaleX, dpiScaleY;
// Ultrawide 5120x1440
if (g_nexusLink->Width == 5120 && g_nexusLink->Height == 1440) {
if (uiScale >= 0.89f && uiScale <= 0.91f) {
dpiScaleX = 2.814f;
dpiScaleY = 0.888f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "ULTRAWIDE 5120x1440: APPLIED SMALL UI OFFSET");
}
else if (uiScale >= 1.09f && uiScale <= 1.15f) {
dpiScaleX = 2.746f;
dpiScaleY = 1.104f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "ULTRAWIDE 5120x1440: APPLIED LARGE UI OFFSET");
}
else if (uiScale >= 1.21f && uiScale <= 1.25f) {
dpiScaleX = 2.713f;
dpiScaleY = 1.208f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "ULTRAWIDE 5120x1440: APPLIED LARGER UI OFFSET");
}
else {
dpiScaleX = 2.779f;
dpiScaleY = 1.000f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "ULTRAWIDE 5120x1440: APPLIED NORMAL UI OFFSET");
}
}
// Ultrawide 3440x1440
else if (g_nexusLink->Width == 3440 && g_nexusLink->Height == 1440) {
if (uiScale >= 0.89f && uiScale <= 0.91f) {
dpiScaleX = 1.810f;
dpiScaleY = 0.892f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "ULTRAWIDE 3440x1440: APPLIED SMALL UI OFFSET");
}
else if (uiScale >= 1.09f && uiScale <= 1.15f) {
dpiScaleX = 1.741f;
dpiScaleY = 1.104f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "ULTRAWIDE 3440x1440: APPLIED LARGE UI OFFSET");
}
else if (uiScale >= 1.21f && uiScale <= 1.25f) {
dpiScaleX = 1.708f;
dpiScaleY = 1.212f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "ULTRAWIDE 3440x1440: APPLIED LARGER UI OFFSET");
}
else {
dpiScaleX = 1.773f;
dpiScaleY = 0.992f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "ULTRAWIDE 3440x1440: APPLIED NORMAL UI OFFSET");
}
}
else if (g_nexusLink->Width == 3840 && g_nexusLink->Height == 2160) {
if (uiScale >= 0.89f && uiScale <= 0.91f) {
dpiScaleX = 2.052f;
dpiScaleY = 0.908f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "4K 3840x2160: APPLIED SMALL UI OFFSET");
}
else if (uiScale >= 1.09f && uiScale <= 1.15f) {
dpiScaleX = 1.985f;
dpiScaleY = 1.130f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "4K 3840x2160: APPLIED LARGE UI OFFSET");
}
else if (uiScale >= 1.21f && uiScale <= 1.25f) {
dpiScaleX = 1.952f;
dpiScaleY = 1.233f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "4K 3840x2160: APPLIED LARGER UI OFFSET");
}
else {
dpiScaleX = 2.0f;
dpiScaleY = 1.0f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "4K 3840x2160: APPLIED NORMAL UI OFFSET");
}
}
else {
dpiScaleX = (float)g_nexusLink->Width / 1920.0f;
dpiScaleY = 1.0f;
char normalBuffer[150];
sprintf_s(normalBuffer, "NORMAL MONITOR: Width=%d, Height=%d, scaleX=%.3f",
g_nexusLink->Width, g_nexusLink->Height, dpiScaleX);
g_api->Log(ELogLevel_INFO, "GolemHelper", normalBuffer);
}
int scaledForResolutionX = (int)(baseX * dpiScaleX);
int scaledForResolutionY = (int)(baseY * dpiScaleY);
int finalX = scaledForResolutionX;
int finalY = scaledForResolutionY;
if (!(g_nexusLink->Width == 5120 && g_nexusLink->Height == 1440) &&
!(g_nexusLink->Width == 3440 && g_nexusLink->Height == 1440) &&
!(g_nexusLink->Width == 3840 && g_nexusLink->Height == 2160)) {
if (uiScale >= 0.89f && uiScale <= 0.91f) {
finalX = scaledForResolutionX - (int)(scaledForResolutionX * 0.029f);
finalY = scaledForResolutionY - (int)(scaledForResolutionY * 0.103f);
g_api->Log(ELogLevel_INFO, "GolemHelper", "APPLIED SMALL UI OFFSET");
}
else if (uiScale >= 1.09f && uiScale <= 1.15f) {
finalX = scaledForResolutionX - (int)(scaledForResolutionX * 0.053f);
finalY = scaledForResolutionY + (int)(scaledForResolutionY * 0.095f);
g_api->Log(ELogLevel_INFO, "GolemHelper", "APPLIED LARGE UI OFFSET");
}
else if (uiScale >= 1.21f && uiScale <= 1.25f) {
finalX = scaledForResolutionX - (int)(scaledForResolutionX * 0.097f);
finalY = scaledForResolutionY + (int)(scaledForResolutionY * 0.206f);
}
}
*scaledX = finalX;
*scaledY = finalY;
}
else {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "GetScaledCoordinates - Nexus data not available");
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
float dpiScale = (float)screenWidth / 1920.0f;
*scaledX = (int)(baseX * dpiScale);
*scaledY = baseY;
}
}
void CoordinateUtils::DebugMousePosition() {
if (!g_api) return;
POINT mousePos;
GetCursorPos(&mousePos);
if (g_nexusLink && g_nexusLink->Width > 0 && g_nexusLink->Height > 0) {
float uiScale = g_nexusLink->Scaling;
float dpiScale = (float)g_nexusLink->Width / 1920.0f;
float finalScaleX = uiScale * dpiScale;
int baseX = (int)(mousePos.x / finalScaleX);
int baseY = mousePos.y;
g_state.debugCounter++;
char buffer[450];
sprintf_s(buffer, "=== DEBUG #%d === Resolution: %dx%d | Mouse: %d,%d | Base coords: %d,%d | Interface Size: %.2f | DPI Scale: %.3f | Final ScaleX: %.3f",
g_state.debugCounter, g_nexusLink->Width, g_nexusLink->Height,
mousePos.x, mousePos.y, baseX, baseY, uiScale, dpiScale, finalScaleX);
g_api->Log(ELogLevel_INFO, "GolemHelper", buffer);
}
else {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Cannot debug - Nexus data not available");
}
}
void CoordinateUtils::ClickAtScaled(int baseX, int baseY, int delay) {
if (g_mumbleData && !g_mumbleData->Context.IsGameFocused) {
if (g_api) {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Sequence stopped - Game lost focus");
}
return;
}
HWND gameWindow = GetForegroundWindow();
if (!gameWindow) return;
int scaledX, scaledY;
GetScaledCoordinates(baseX, baseY, &scaledX, &scaledY);
LPARAM lParam = MAKELPARAM(scaledX, scaledY);
SendMessage(gameWindow, WM_LBUTTONDOWN, MK_LBUTTON, lParam);
Sleep(10);
SendMessage(gameWindow, WM_LBUTTONUP, 0, lParam);
Sleep(delay);
}
void CoordinateUtils::StartCalibration() {
g_state.calibrationMode = true;
g_state.showUI = false;
if (g_api) {
g_api->Log(ELogLevel_INFO, "GolemHelper",
"Calibration started - interact with the Boon Console and click 'Adjust Self'");
}
}
void CoordinateUtils::CaptureCalibrationPoint() {
POINT mousePos;
GetCursorPos(&mousePos);
const float REF_BASE_X = 830.0f;
const float REF_BASE_Y = 262.0f;
g_state.calibratedScaleX = mousePos.x / REF_BASE_X;
g_state.calibratedScaleY = mousePos.y / REF_BASE_Y;
g_state.hasCalibration = true;
g_state.calibrationMode = false;
ConfigManager::SaveCustomDelaySettings();
if (g_api) {
char buffer[256];
sprintf_s(buffer,
"Calibration saved: click=(%ld, %ld) scaleX=%.4f scaleY=%.4f",
mousePos.x, mousePos.y,
g_state.calibratedScaleX, g_state.calibratedScaleY);
g_api->Log(ELogLevel_INFO, "GolemHelper", buffer);
g_api->UI.SendAlert("Calibration saved!");
}
}
void CoordinateUtils::ResetCalibration() {
g_state.hasCalibration = false;
g_state.calibrationMode = false;
g_state.calibratedScaleX = 1.0f;
g_state.calibratedScaleY = 1.0f;
ConfigManager::SaveCustomDelaySettings();
if (g_api) {
g_api->Log(ELogLevel_INFO, "GolemHelper", "Calibration reset - back to auto-scaling");
g_api->UI.SendAlert("Calibration reset to default");
}
}
void CoordinateUtils::UpdateCalibrationCapture() {
if (!g_state.calibrationMode) return;
if (GetAsyncKeyState(VK_ESCAPE) & 0x8000) {
g_state.calibrationMode = false;
if (g_api) g_api->UI.SendAlert("Calibration cancelled");
return;
}
static bool s_wasPressed = false;
bool isPressed = (GetAsyncKeyState(VK_LBUTTON) & 0x8000) != 0;
if (isPressed && !s_wasPressed) {
if (g_mumbleData && g_mumbleData->Context.IsGameFocused) {
CaptureCalibrationPoint();
}
}
s_wasPressed = isPressed;
}

View file

@ -0,0 +1,13 @@
#pragma once
class CoordinateUtils {
public:
static void GetScaledCoordinates(int baseX, int baseY, int* scaledX, int* scaledY);
static void DebugMousePosition();
static void ClickAtScaled(int baseX, int baseY, int delay = 25);
static void StartCalibration();
static void CaptureCalibrationPoint();
static void ResetCalibration();
static void UpdateCalibrationCapture();
};

View file

@ -0,0 +1,10 @@
#include <Windows.h>
#include <vector>
#include <string>
#include "Globals.h"
AddonAPI* g_api = nullptr;
NexusLinkData* g_nexusLink = nullptr;
Mumble::Data* g_mumbleData = nullptr;
GolemHelperState g_state;
MenuCoordinates g_coords;

View file

@ -0,0 +1,10 @@
#pragma once
#include "Types.h"
#include "../Dependencies/nexus/Nexus.h"
#include "../Dependencies/mumble/mumble.h"
extern AddonAPI* g_api;
extern NexusLinkData* g_nexusLink;
extern Mumble::Data* g_mumbleData;
extern GolemHelperState g_state;
extern MenuCoordinates g_coords;

View file

@ -0,0 +1,86 @@
#pragma once
#include "Types.h"
class MenuSequences {
public:
static constexpr MenuOption BOON_SEQUENCE[20] = {
BOON_ADJUSTSELF,
BOON_ADDBOONS,
BOON_OFFENSIVE,
BOON_MIGHT,
BOON_25MIGHT,
BOON_FURY,
BOON_RETURN1,
BOON_DEFENSIVE,
BOON_PROTECTION,
BOON_RESOLUTION,
BOON_AEGIS,
BOON_RETURN2,
BOON_UTILITY,
BOON_ALACRITY,
BOON_QUICKNESS,
BOON_REGENERATION,
BOON_SWIFTNESS,
BOON_VIGOR,
BOON_ALACRITY,
BOON_EXIT
};
static constexpr MenuOption HEALER_QUICK_SEQUENCE[10] = {
BOON_ADJUSTSELF,
BOON_ADDBOONS,
BOON_UTILITY,
BOON_ALACRITY,
BOON_ALACRITY,
BOON_RETURN3,
BOON_RETURN4,
BOON_GOBACK,
BOON_ADJUSTENVIRONMENT,
BOON_TOGGLEPULSINGARENADAMAGEON
};
static constexpr MenuOption GOLEM_SEQUENCE[25] = {
GOLEM_SPAWNAGOLEM,
GOLEM_HITBOX_SMALL,
GOLEM_AVERAGEENEMY,
GOLEM_ADDITIONALOPTIONS,
GOLEM_ADDCONDITIONS,
GOLEM_DAMAGEOVERTIMECONDITIONS,
GOLEM_BLEEDING,
GOLEM_BURNING,
GOLEM_CONFUSION,
GOLEM_POISON,
GOLEM_TORMENT,
GOLEM_GOBACK1,
GOLEM_MOBILITYAFFECTINGCONDITIONS,
GOLEM_CHILL,
GOLEM_CRIPPLE,
GOLEM_GOBACK2,
GOLEM_COMBATAFFECTINGCONDITIONS,
GOLEM_SLOW,
GOLEM_VULNERABILITY,
GOLEM_25VULNERABILITY,
GOLEM_GOBACK3,
GOLEM_WEAKNESS,
GOLEM_GOBACK4,
GOLEM_GOBACK5,
GOLEM_PLEASESPAWNMYGOLEM
};
static constexpr MenuOption GOLEM_RESPAWN[2] = {
GOLEM_RESPAWNMYPREVIOUSGOLEMINCARNATION,
GOLEM_EXIT
};
static constexpr MenuOption GOLEM_REMOVE_AND_RESPAWN[3] = {
GOLEM_REMOVEGOLEM,
GOLEM_RESPAWNMYPREVIOUSGOLEMINCARNATION,
GOLEM_EXIT
};
static constexpr int BOON_LENGTH = 20;
static constexpr int HEALER_QUICK_LENGTH = 10;
static constexpr int GOLEM_LENGTH = 25;
static constexpr int GOLEM_RESPAWN_LENGTH = 2;
static constexpr int GOLEM_REMOVE_AND_RESPAWN_LENGTH = 3;
};

239
GolemHelper/Common/Types.h Normal file
View file

@ -0,0 +1,239 @@
#pragma once
#include "../Dependencies/mumble/mumble.h"
#include <vector>
#include <string>
#include <map>
enum HitboxType {
HITBOX_SMALL = 0,
HITBOX_MEDIUM = 1,
HITBOX_LARGE = 2
};
enum EnvironmentDamageLevel {
ENV_MILD = 0,
ENV_MODERATE = 1,
ENV_EXTREME = 2
};
enum MenuOption {
// === BOON MENU ===
BOON_ADJUSTSELF,
BOON_ADDBOONS,
BOON_OFFENSIVE,
BOON_MIGHT,
BOON_25MIGHT,
BOON_FURY,
BOON_RETURN1,
BOON_DEFENSIVE,
BOON_PROTECTION,
BOON_RESOLUTION,
BOON_RESISTANCE,
BOON_STABILITY,
BOON_AEGIS,
BOON_RETURN2,
BOON_UTILITY,
BOON_ALACRITY,
BOON_QUICKNESS,
BOON_REGENERATION,
BOON_SWIFTNESS,
BOON_VIGOR,
BOON_EXIT,
// === HEALER EXTENSIONS ===
BOON_RETURN3,
BOON_RETURN4,
BOON_GOBACK,
BOON_ADJUSTENVIRONMENT,
BOON_TOGGLEPULSINGARENADAMAGEON,
BOON_ENV_MILD,
BOON_ENV_MODERATE,
BOON_ENV_EXTREME,
// === GOLEM MENU ===
GOLEM_RESPAWNMYPREVIOUSGOLEMINCARNATION,
GOLEM_REMOVEGOLEM,
GOLEM_SPAWNAGOLEM,
GOLEM_HITBOX_SMALL,
GOLEM_HITBOX_MEDIUM,
GOLEM_HITBOX_LARGE,
GOLEM_AVERAGEENEMY,
GOLEM_ADDITIONALOPTIONS,
GOLEM_ADDCONDITIONS,
GOLEM_DAMAGEOVERTIMECONDITIONS,
GOLEM_BLEEDING,
GOLEM_BURNING,
GOLEM_CONFUSION,
GOLEM_POISON,
GOLEM_TORMENT,
GOLEM_GOBACK1,
GOLEM_MOBILITYAFFECTINGCONDITIONS,
GOLEM_CHILL,
GOLEM_CRIPPLE,
GOLEM_IMMOBILIZE,
GOLEM_GOBACK2,
GOLEM_COMBATAFFECTINGCONDITIONS,
GOLEM_BLIND,
GOLEM_SLOW,
GOLEM_VULNERABILITY,
GOLEM_25VULNERABILITY,
GOLEM_GOBACK3,
GOLEM_WEAKNESS,
GOLEM_GOBACK4,
GOLEM_GOBACK5,
GOLEM_PLEASESPAWNMYGOLEM,
GOLEM_EXIT
};
struct GolemTemplate {
std::string name;
bool isQuickDps;
bool isAlacDps;
bool environmentDamage;
EnvironmentDamageLevel envDamageLevel;
bool skipBurning;
bool skipConfusion;
bool skipSlow;
bool addImmobilize;
bool addBlind;
bool fiveBleedingStacks;
HitboxType hitboxType;
bool isDefaultTemplate;
bool addResistance;
bool addStability;
bool skipAegis;
GolemTemplate() :
name("Unnamed Template"),
isQuickDps(false),
isAlacDps(false),
environmentDamage(false),
envDamageLevel(ENV_MILD),
skipBurning(false),
skipConfusion(false),
skipSlow(false),
addImmobilize(false),
addBlind(false),
fiveBleedingStacks(false),
hitboxType(HITBOX_SMALL),
isDefaultTemplate(false),
addResistance(false),
addStability(false),
skipAegis(false) {
}
};
struct GolemHelperState {
bool enabled = false;
bool isQuickDps = false;
bool isAlacDps = false;
bool environmentDamage = false;
EnvironmentDamageLevel envDamageLevel = ENV_MILD;
bool skipBurning = false;
bool skipConfusion = false;
bool skipSlow = false;
bool addImmobilize = false;
bool addBlind = false;
bool fiveBleedingStacks = false;
HitboxType hitboxType = HITBOX_SMALL;
bool debugMode = false;
bool showUI = false;
bool showAdvanced = false;
bool showTimingSettings = false;
bool showBoonAdvanced = false;
bool addResistance = false;
bool addStability = false;
bool skipAegis = false;
bool alwaysHideIcon = false;
bool autoShowHideUI = false;
bool alwaysLoadLastSettings = false;
int debugCounter = 0;
int initialDelay = 390;
int stepDelay = 290;
bool quickAccessVisible = false;
unsigned int lastMapID = 0;
// Calibration
bool calibrationMode = false;
bool hasCalibration = false;
float calibratedScaleX = 1.0f;
float calibratedScaleY = 1.0f;
std::vector<GolemTemplate> templates;
int selectedTemplateIndex = -1;
int lastUserTemplateIndex = -1;
char newTemplateName[64] = "";
};
struct MenuCoordinates {
std::map<MenuOption, std::pair<int, int>> coords = {
// === BOON MENU ===
{BOON_ADJUSTSELF, {830, 262}},
{BOON_ADDBOONS, {830, 354}},
{BOON_OFFENSIVE, {830, 262}},
{BOON_MIGHT, {830, 262}},
{BOON_25MIGHT, {830, 400}},
{BOON_FURY, {830, 305}},
{BOON_RETURN1, {830, 354}},
{BOON_DEFENSIVE, {830, 305}},
{BOON_PROTECTION, {830, 262}},
{BOON_RESOLUTION, {830, 305}},
{BOON_RESISTANCE, {830, 354}},
{BOON_STABILITY, {830, 400}},
{BOON_AEGIS, {830, 450}},
{BOON_RETURN2, {830, 500}},
{BOON_UTILITY, {830, 354}},
{BOON_ALACRITY, {830, 262}},
{BOON_QUICKNESS, {830, 305}},
{BOON_REGENERATION, {830, 354}},
{BOON_SWIFTNESS, {830, 400}},
{BOON_VIGOR, {830, 450}},
{BOON_EXIT, {830, 550}},
// === HEALER EXTENSIONS ===
{BOON_RETURN3, {830, 500}},
{BOON_RETURN4, {830, 450}},
{BOON_GOBACK, {830, 450}},
{BOON_ADJUSTENVIRONMENT, {830, 305}},
{BOON_TOGGLEPULSINGARENADAMAGEON, {830, 262}},
{BOON_ENV_MILD, {830, 352}},
{BOON_ENV_MODERATE, {830, 305}},
{BOON_ENV_EXTREME, {830, 262}},
// === GOLEM MENU ===
{GOLEM_RESPAWNMYPREVIOUSGOLEMINCARNATION, {830, 352}},
{GOLEM_REMOVEGOLEM, {830, 306}},
{GOLEM_SPAWNAGOLEM, {830, 260}},
{GOLEM_HITBOX_SMALL, {830, 260}},
{GOLEM_HITBOX_MEDIUM, {830, 305}},
{GOLEM_HITBOX_LARGE, {830, 352}},
{GOLEM_AVERAGEENEMY, {830, 306}},
{GOLEM_ADDITIONALOPTIONS, {830, 257}},
{GOLEM_ADDCONDITIONS, {830, 257}},
{GOLEM_DAMAGEOVERTIMECONDITIONS, {830, 306}},
{GOLEM_BLEEDING, {830, 257}},
{GOLEM_BURNING, {830, 306}},
{GOLEM_CONFUSION, {830, 352}},
{GOLEM_POISON, {830, 400}},
{GOLEM_TORMENT, {830, 454}},
{GOLEM_GOBACK1, {830, 508}},
{GOLEM_MOBILITYAFFECTINGCONDITIONS, {830, 352}},
{GOLEM_CHILL, {830, 257}},
{GOLEM_CRIPPLE, {830, 306}},
{GOLEM_IMMOBILIZE, {830, 400}},
{GOLEM_GOBACK2, {830, 454}},
{GOLEM_COMBATAFFECTINGCONDITIONS, {830, 400}},
{GOLEM_BLIND, {830, 260}},
{GOLEM_SLOW, {830, 306}},
{GOLEM_VULNERABILITY, {830, 352}},
{GOLEM_25VULNERABILITY, {830, 400}},
{GOLEM_GOBACK3, {830, 454}},
{GOLEM_WEAKNESS, {830, 400}},
{GOLEM_GOBACK4, {830, 454}},
{GOLEM_GOBACK5, {830, 454}},
{GOLEM_PLEASESPAWNMYGOLEM, {830, 548}},
{GOLEM_EXIT, {830, 400}},
};
};

View file

@ -0,0 +1,213 @@
#include <Windows.h>
#include <string>
#include <fstream>
#include <sstream>
#include "ConfigManager.h"
#include "../Common/Globals.h"
#include "../Utils/FileUtils.h"
void ConfigManager::SaveCustomDelaySettings() {
if (!g_api) return;
std::string configPath = FileUtils::GetConfigFilePath();
try {
std::ofstream configFile(configPath);
if (!configFile.is_open()) {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Could not create config file");
return;
}
configFile << "[GolemHelper]" << std::endl;
configFile << "initialDelay=" << g_state.initialDelay << std::endl;
configFile << "stepDelay=" << g_state.stepDelay << std::endl;
configFile << "alwaysHideIcon=" << (g_state.alwaysHideIcon ? "1" : "0") << std::endl;
configFile << "autoShowHideUI=" << (g_state.autoShowHideUI ? "1" : "0") << std::endl;
configFile << "alwaysLoadLastSettings=" << (g_state.alwaysLoadLastSettings ? "1" : "0") << std::endl;
configFile << "hasCalibration=" << (g_state.hasCalibration ? "1" : "0") << std::endl;
configFile << "calibratedScaleX=" << g_state.calibratedScaleX << std::endl;
configFile << "calibratedScaleY=" << g_state.calibratedScaleY << std::endl;
configFile.close();
char logBuffer[512];
sprintf_s(logBuffer, "Settings saved: initialDelay=%dms, stepDelay=%dms, alwaysHideIcon=%s, autoShowHideUI=%s, alwaysLoadLastSettings=%s",
g_state.initialDelay, g_state.stepDelay,
g_state.alwaysHideIcon ? "true" : "false",
g_state.autoShowHideUI ? "true" : "false",
g_state.alwaysLoadLastSettings ? "true" : "false");
g_api->Log(ELogLevel_INFO, "GolemHelper", logBuffer);
}
catch (...) {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Failed to save config file");
}
}
void ConfigManager::LoadCustomDelaySettings() {
if (!g_api) return;
std::string configPath = FileUtils::GetConfigFilePath();
try {
std::ifstream configFile(configPath);
if (!configFile.is_open()) {
g_api->Log(ELogLevel_INFO, "GolemHelper", "No config file found, using defaults");
return;
}
std::string line;
while (std::getline(configFile, line)) {
if (line.empty() || line[0] == '[') continue;
size_t equalPos = line.find('=');
if (equalPos == std::string::npos) continue;
std::string key = line.substr(0, equalPos);
std::string value = line.substr(equalPos + 1);
if (key == "initialDelay") {
int delay = std::stoi(value);
if (delay >= 100 && delay <= 1000) {
g_state.initialDelay = delay;
}
}
else if (key == "stepDelay") {
int delay = std::stoi(value);
if (delay >= 100 && delay <= 1000) {
g_state.stepDelay = delay;
}
}
else if (key == "alwaysHideIcon") {
g_state.alwaysHideIcon = (value == "1");
}
else if (key == "autoShowHideUI") {
g_state.autoShowHideUI = (value == "1");
}
else if (key == "alwaysLoadLastSettings") {
g_state.alwaysLoadLastSettings = (value == "1");
}
else if (key == "hasCalibration") {
g_state.hasCalibration = (value == "1");
}
else if (key == "calibratedScaleX") {
try {
float v = std::stof(value);
if (v > 0.1f && v < 10.0f) g_state.calibratedScaleX = v;
}
catch (...) {}
}
else if (key == "calibratedScaleY") {
try {
float v = std::stof(value);
if (v > 0.1f && v < 10.0f) g_state.calibratedScaleY = v;
}
catch (...) {}
}
}
configFile.close();
char logBuffer[512];
sprintf_s(logBuffer, "Settings loaded: initialDelay=%dms, stepDelay=%dms, alwaysHideIcon=%s, autoShowHideUI=%s, alwaysLoadLastSettings=%s",
g_state.initialDelay, g_state.stepDelay,
g_state.alwaysHideIcon ? "true" : "false",
g_state.autoShowHideUI ? "true" : "false",
g_state.alwaysLoadLastSettings ? "true" : "false");
g_api->Log(ELogLevel_INFO, "GolemHelper", logBuffer);
}
catch (...) {
g_api->Log(ELogLevel_INFO, "GolemHelper", "Could not load config file, using defaults");
}
}
void ConfigManager::SaveLastUsedSettings() {
if (!g_api) return;
std::string addonPath = g_api->Paths.GetAddonDirectory("GolemHelper");
std::string settingsPath = addonPath + "\\last_settings.ini";
try {
std::ofstream settingsFile(settingsPath);
if (!settingsFile.is_open()) {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Could not create last settings file");
return;
}
settingsFile << "[LastUsedSettings]" << std::endl;
settingsFile << "isQuickDps=" << (g_state.isQuickDps ? "1" : "0") << std::endl;
settingsFile << "isAlacDps=" << (g_state.isAlacDps ? "1" : "0") << std::endl;
settingsFile << "showBoonAdvanced=" << (g_state.showBoonAdvanced ? "1" : "0") << std::endl;
settingsFile << "environmentDamage=" << (g_state.environmentDamage ? "1" : "0") << std::endl;
settingsFile << "envDamageLevel=" << static_cast<int>(g_state.envDamageLevel) << std::endl;
settingsFile << "skipBurning=" << (g_state.skipBurning ? "1" : "0") << std::endl;
settingsFile << "showAdvanced=" << (g_state.showAdvanced ? "1" : "0") << std::endl;
settingsFile << "skipConfusion=" << (g_state.skipConfusion ? "1" : "0") << std::endl;
settingsFile << "skipSlow=" << (g_state.skipSlow ? "1" : "0") << std::endl;
settingsFile << "addImmobilize=" << (g_state.addImmobilize ? "1" : "0") << std::endl;
settingsFile << "addBlind=" << (g_state.addBlind ? "1" : "0") << std::endl;
settingsFile << "fiveBleedingStacks=" << (g_state.fiveBleedingStacks ? "1" : "0") << std::endl;
settingsFile << "hitboxType=" << static_cast<int>(g_state.hitboxType) << std::endl;
settingsFile << "addResistance=" << (g_state.addResistance ? "1" : "0") << std::endl;
settingsFile << "addStability=" << (g_state.addStability ? "1" : "0") << std::endl;
settingsFile << "skipAegis=" << (g_state.skipAegis ? "1" : "0") << std::endl;
settingsFile.close();
g_api->Log(ELogLevel_INFO, "GolemHelper", "Last used settings saved");
}
catch (...) {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Failed to save last settings file");
}
}
void ConfigManager::LoadLastUsedSettings() {
if (!g_api) return;
std::string addonPath = g_api->Paths.GetAddonDirectory("GolemHelper");
std::string settingsPath = addonPath + "\\last_settings.ini";
try {
std::ifstream settingsFile(settingsPath);
if (!settingsFile.is_open()) {
g_api->Log(ELogLevel_INFO, "GolemHelper", "No last settings file found");
return;
}
std::string line;
while (std::getline(settingsFile, line)) {
if (line.empty() || line[0] == '[') continue;
size_t equalPos = line.find('=');
if (equalPos == std::string::npos) continue;
std::string key = line.substr(0, equalPos);
std::string value = line.substr(equalPos + 1);
if (key == "isQuickDps") g_state.isQuickDps = (value == "1");
else if (key == "isAlacDps") g_state.isAlacDps = (value == "1");
else if (key == "showBoonAdvanced") g_state.showBoonAdvanced = (value == "1");
else if (key == "environmentDamage") g_state.environmentDamage = (value == "1");
else if (key == "envDamageLevel") g_state.envDamageLevel = static_cast<EnvironmentDamageLevel>(std::stoi(value));
else if (key == "showAdvanced") g_state.showAdvanced = (value == "1");
else if (key == "skipBurning") g_state.skipBurning = (value == "1");
else if (key == "skipConfusion") g_state.skipConfusion = (value == "1");
else if (key == "skipSlow") g_state.skipSlow = (value == "1");
else if (key == "addImmobilize") g_state.addImmobilize = (value == "1");
else if (key == "addBlind") g_state.addBlind = (value == "1");
else if (key == "fiveBleedingStacks") g_state.fiveBleedingStacks = (value == "1");
else if (key == "hitboxType") g_state.hitboxType = static_cast<HitboxType>(std::stoi(value));
else if (key == "addResistance") g_state.addResistance = (value == "1");
else if (key == "addStability") g_state.addStability = (value == "1");
else if (key == "skipAegis") g_state.skipAegis = (value == "1");
}
settingsFile.close();
g_api->Log(ELogLevel_INFO, "GolemHelper", "Last used settings loaded");
}
catch (...) {
g_api->Log(ELogLevel_INFO, "GolemHelper", "Could not load last settings file");
}
}

View file

@ -0,0 +1,9 @@
#pragma once
class ConfigManager {
public:
static void SaveCustomDelaySettings();
static void LoadCustomDelaySettings();
static void SaveLastUsedSettings();
static void LoadLastUsedSettings();
};

View file

@ -0,0 +1,319 @@
#include <Windows.h>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include "TemplateManager.h"
#include "../Common/Globals.h"
#include "../Utils/FileUtils.h"
void TemplateManager::LoadTemplates() {
if (!g_api) return;
CreateDefaultTemplates();
std::string templatePath = FileUtils::GetAddonPath() + "\\templates.cfg";
try {
std::ifstream file(templatePath);
if (!file.is_open()) {
g_api->Log(ELogLevel_INFO, "GolemHelper", "No user templates file found");
SaveTemplates();
return;
}
std::string line;
GolemTemplate currentTemplate;
bool inTemplate = false;
while (std::getline(file, line)) {
if (line.empty() || line[0] == '#') continue;
if (line.find("[Template]") == 0) {
if (inTemplate && !currentTemplate.name.empty()) {
g_state.templates.push_back(currentTemplate);
}
currentTemplate = GolemTemplate();
inTemplate = true;
continue;
}
if (!inTemplate) continue;
size_t equalPos = line.find('=');
if (equalPos == std::string::npos) continue;
std::string key = line.substr(0, equalPos);
std::string value = line.substr(equalPos + 1);
if (key == "name") {
currentTemplate.name = value;
}
else if (key == "isQuickDps") {
currentTemplate.isQuickDps = (value == "1");
}
else if (key == "isAlacDps") {
currentTemplate.isAlacDps = (value == "1");
}
else if (key == "environmentDamage") {
currentTemplate.environmentDamage = (value == "1");
}
else if (key == "envDamageLevel") {
currentTemplate.envDamageLevel = (EnvironmentDamageLevel)std::stoi(value);
}
else if (key == "skipBurning") {
currentTemplate.skipBurning = (value == "1");
}
else if (key == "skipConfusion") {
currentTemplate.skipConfusion = (value == "1");
}
else if (key == "skipSlow") {
currentTemplate.skipSlow = (value == "1");
}
else if (key == "addImmobilize") {
currentTemplate.addImmobilize = (value == "1");
}
else if (key == "addBlind") {
currentTemplate.addBlind = (value == "1");
}
else if (key == "fiveBleedingStacks") {
currentTemplate.fiveBleedingStacks = (value == "1");
}
else if (key == "hitboxType") {
currentTemplate.hitboxType = (HitboxType)std::stoi(value);
}
else if (key == "addResistance") {
currentTemplate.addResistance = (value == "1");
}
else if (key == "addStability") {
currentTemplate.addStability = (value == "1");
}
else if (key == "skipAegis") {
currentTemplate.skipAegis = (value == "1");
}
}
if (inTemplate && !currentTemplate.name.empty()) {
g_state.templates.push_back(currentTemplate);
}
file.close();
int userTemplateCount = 0;
for (const auto& temp : g_state.templates) {
if (!temp.isDefaultTemplate) userTemplateCount++;
}
char logBuffer[150];
sprintf_s(logBuffer, "Loaded %d user templates", userTemplateCount);
g_api->Log(ELogLevel_INFO, "GolemHelper", logBuffer);
}
catch (...) {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Failed to load user templates");
}
}
void TemplateManager::SaveTemplates() {
if (!g_api) return;
std::string templatePath = FileUtils::GetAddonPath() + "\\templates.cfg";
try {
std::ofstream file(templatePath);
if (!file.is_open()) {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Could not create templates file");
return;
}
file << "# GolemHelper User Templates Configuration\n";
int savedCount = 0;
for (const auto& temp : g_state.templates) {
if (!temp.isDefaultTemplate) {
file << "[Template]\n";
file << "name=" << temp.name << "\n";
file << "isQuickDps=" << (temp.isQuickDps ? "1" : "0") << "\n";
file << "isAlacDps=" << (temp.isAlacDps ? "1" : "0") << "\n";
file << "environmentDamage=" << (temp.environmentDamage ? "1" : "0") << "\n";
file << "envDamageLevel=" << temp.envDamageLevel << "\n";
file << "skipBurning=" << (temp.skipBurning ? "1" : "0") << "\n";
file << "skipConfusion=" << (temp.skipConfusion ? "1" : "0") << "\n";
file << "skipSlow=" << (temp.skipSlow ? "1" : "0") << "\n";
file << "addImmobilize=" << (temp.addImmobilize ? "1" : "0") << "\n";
file << "addBlind=" << (temp.addBlind ? "1" : "0") << "\n";
file << "fiveBleedingStacks=" << (temp.fiveBleedingStacks ? "1" : "0") << "\n";
file << "hitboxType=" << temp.hitboxType << "\n";
file << "addResistance=" << (temp.addResistance ? "1" : "0") << "\n";
file << "addStability=" << (temp.addStability ? "1" : "0") << "\n";
file << "skipAegis=" << (temp.skipAegis ? "1" : "0") << "\n\n";
savedCount++;
}
}
file.close();
char logBuffer[150];
sprintf_s(logBuffer, "Saved %d user templates", savedCount);
g_api->Log(ELogLevel_INFO, "GolemHelper", logBuffer);
}
catch (...) {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Failed to save templates");
}
}
void TemplateManager::SaveCurrentAsTemplate(const std::string& name) {
GolemTemplate newTemplate = CreateTemplateFromCurrentSettings();
newTemplate.name = name;
g_state.templates.push_back(newTemplate);
SaveTemplates();
if (g_api) {
char logBuffer[200];
sprintf_s(logBuffer, "Template '%s' saved successfully", name.c_str());
g_api->Log(ELogLevel_INFO, "GolemHelper", logBuffer);
}
}
void TemplateManager::LoadTemplate(int index) {
if (index < 0 || index >= g_state.templates.size()) return;
ApplyTemplateToSettings(g_state.templates[index]);
if (!g_state.templates[index].isDefaultTemplate) {
g_state.selectedTemplateIndex = index;
g_state.lastUserTemplateIndex = index;
}
if (g_api) {
char logBuffer[200];
sprintf_s(logBuffer, "Template '%s' loaded", g_state.templates[index].name.c_str());
g_api->Log(ELogLevel_INFO, "GolemHelper", logBuffer);
}
}
void TemplateManager::DeleteTemplate(int index) {
if (index < 0 || index >= g_state.templates.size()) return;
std::string templateName = g_state.templates[index].name;
g_state.templates.erase(g_state.templates.begin() + index);
if (g_state.selectedTemplateIndex == index) {
g_state.selectedTemplateIndex = -1;
}
else if (g_state.selectedTemplateIndex > index) {
g_state.selectedTemplateIndex--;
}
SaveTemplates();
if (g_api) {
char logBuffer[200];
sprintf_s(logBuffer, "Template '%s' deleted", templateName.c_str());
g_api->Log(ELogLevel_INFO, "GolemHelper", logBuffer);
}
}
void TemplateManager::RenameTemplate(int index, const std::string& newName) {
if (index < 0 || index >= g_state.templates.size()) return;
std::string oldName = g_state.templates[index].name;
g_state.templates[index].name = newName;
SaveTemplates();
if (g_api) {
char logBuffer[300];
sprintf_s(logBuffer, "Template renamed from '%s' to '%s'", oldName.c_str(), newName.c_str());
g_api->Log(ELogLevel_INFO, "GolemHelper", logBuffer);
}
}
GolemTemplate TemplateManager::CreateTemplateFromCurrentSettings() {
GolemTemplate temp;
temp.isQuickDps = g_state.isQuickDps;
temp.isAlacDps = g_state.isAlacDps;
temp.environmentDamage = g_state.environmentDamage;
temp.envDamageLevel = g_state.envDamageLevel;
temp.skipBurning = g_state.skipBurning;
temp.skipConfusion = g_state.skipConfusion;
temp.skipSlow = g_state.skipSlow;
temp.addImmobilize = g_state.addImmobilize;
temp.addBlind = g_state.addBlind;
temp.fiveBleedingStacks = g_state.fiveBleedingStacks;
temp.hitboxType = g_state.hitboxType;
temp.addResistance = g_state.addResistance;
temp.addStability = g_state.addStability;
temp.skipAegis = g_state.skipAegis;
temp.isDefaultTemplate = false;
return temp;
}
void TemplateManager::ApplyTemplateToSettings(const GolemTemplate& temp) {
g_state.isQuickDps = temp.isQuickDps;
g_state.isAlacDps = temp.isAlacDps;
g_state.environmentDamage = temp.environmentDamage;
g_state.envDamageLevel = temp.envDamageLevel;
g_state.skipBurning = temp.skipBurning;
g_state.skipConfusion = temp.skipConfusion;
g_state.skipSlow = temp.skipSlow;
g_state.addImmobilize = temp.addImmobilize;
g_state.addBlind = temp.addBlind;
g_state.fiveBleedingStacks = temp.fiveBleedingStacks;
g_state.hitboxType = temp.hitboxType;
g_state.addResistance = temp.addResistance;
g_state.addStability = temp.addStability;
g_state.skipAegis = temp.skipAegis;
if (temp.isDefaultTemplate) {
g_state.showAdvanced = false;
g_state.showBoonAdvanced = false;
}
else {
if (temp.skipBurning || temp.skipConfusion || temp.skipSlow ||
temp.addImmobilize || temp.addBlind || temp.fiveBleedingStacks) {
g_state.showAdvanced = true;
}
if (temp.addResistance || temp.addStability || temp.skipAegis) {
g_state.showBoonAdvanced = true;
}
}
}
void TemplateManager::CreateDefaultTemplates() {
g_state.templates.clear();
GolemTemplate dps;
dps.name = "DPS";
dps.isDefaultTemplate = true;
g_state.templates.push_back(dps);
GolemTemplate quickDps;
quickDps.name = "Quick DPS";
quickDps.isQuickDps = true;
quickDps.isDefaultTemplate = true;
g_state.templates.push_back(quickDps);
GolemTemplate alacDps;
alacDps.name = "Alac DPS";
alacDps.isAlacDps = true;
alacDps.isDefaultTemplate = true;
g_state.templates.push_back(alacDps);
GolemTemplate qHeal;
qHeal.name = "qHeal";
qHeal.isQuickDps = true;
qHeal.environmentDamage = true;
qHeal.envDamageLevel = ENV_MILD;
qHeal.isDefaultTemplate = true;
g_state.templates.push_back(qHeal);
GolemTemplate aHeal;
aHeal.name = "aHeal";
aHeal.isAlacDps = true;
aHeal.environmentDamage = true;
aHeal.envDamageLevel = ENV_MILD;
aHeal.isDefaultTemplate = true;
g_state.templates.push_back(aHeal);
}

View file

@ -0,0 +1,15 @@
#pragma once
#include "../Common/Types.h"
class TemplateManager {
public:
static void LoadTemplates();
static void SaveTemplates();
static void SaveCurrentAsTemplate(const std::string& name);
static void LoadTemplate(int index);
static void DeleteTemplate(int index);
static void RenameTemplate(int index, const std::string& newName);
static GolemTemplate CreateTemplateFromCurrentSettings();
static void ApplyTemplateToSettings(const GolemTemplate& temp);
static void CreateDefaultTemplates();
};

View file

@ -0,0 +1,79 @@
#include <Windows.h>
#include <string>
#include "Common/Globals.h"
#include "Utils/FileUtils.h"
#include "Utils/MapUtils.h"
#include "Config/ConfigManager.h"
#include "Config/TemplateManager.h"
#include "UI/UIManager.h"
#include "Input/KeybindManager.h"
#include "Dependencies/imgui/imgui.h"
void Load(AddonAPI* aApi) {
g_api = aApi;
ImGui::SetCurrentContext((ImGuiContext*)g_api->ImguiContext);
ImGui::SetAllocatorFunctions((void* (*)(size_t, void*))g_api->ImguiMalloc, (void(*)(void*, void*))g_api->ImguiFree);
g_nexusLink = (NexusLinkData*)g_api->DataLink.Get("DL_NEXUS_LINK");
g_mumbleData = (Mumble::Data*)g_api->DataLink.Get("DL_MUMBLE_LINK");
g_state.enabled = true;
ConfigManager::LoadCustomDelaySettings();
TemplateManager::LoadTemplates();
if (g_state.alwaysLoadLastSettings) {
ConfigManager::LoadLastUsedSettings();
}
FileUtils::CopyResourceIcons();
g_api->Renderer.Register(ERenderType_Render, UIManager::RenderUI);
g_api->Renderer.Register(ERenderType_OptionsRender, UIManager::RenderOptions);
KeybindManager::RegisterKeybinds();
g_api->Textures.GetOrCreateFromFile("GOLEM_HELPER_ICON", "addons/GolemHelper/icons/GOLEM_HELPER_ICON.png");
g_api->Textures.GetOrCreateFromFile("GOLEM_HELPER_ICON_HOVER", "addons/GolemHelper/icons/GOLEM_HELPER_ICON_HOVER.png");
MapUtils::UpdateQuickAccessVisibility();
g_api->Log(ELogLevel_INFO, "GolemHelper", "=== GolemHelper v1.7.1.0 Loaded ===");
g_api->Log(ELogLevel_INFO, "GolemHelper", "<c=#00ff00>GolemHelper addon</c> loaded successfully!");
}
void Unload() {
if (g_api) {
if (g_state.quickAccessVisible) {
g_api->QuickAccess.Remove("GolemHelper.ToggleUI");
}
g_api->Renderer.Deregister(UIManager::RenderUI);
g_api->Renderer.Deregister(UIManager::RenderOptions);
KeybindManager::UnregisterKeybinds();
}
g_api->Log(ELogLevel_INFO, "GolemHelper", "<c=#ff0000>GolemHelper signing off</c>, it was an honor commander.");
g_api = nullptr;
g_mumbleData = nullptr;
g_state.enabled = false;
g_state.showUI = false;
g_state.quickAccessVisible = false;
}
extern "C" __declspec(dllexport) AddonDefinition* GetAddonDef() {
static AddonDefinition def;
def.Signature = -424248;
def.APIVersion = NEXUS_API_VERSION;
def.Name = "GolemHelper";
def.Version = { 1, 7, 1, 0 };
def.Author = "Azrub";
def.Description = "Automates the process of setting optimal boon and golem configurations in the training area";
def.Load = Load;
def.Unload = Unload;
def.Flags = EAddonFlags_None;
def.Provider = EUpdateProvider_Direct;
def.UpdateLink = "https://git.azrub.dev/Azrub/GolemHelper/releases/download/latest/GolemHelper.dll";
return &def;
}

View file

@ -0,0 +1,6 @@
#pragma once
#include "Dependencies/nexus/Nexus.h"
void Load(AddonAPI* aApi);
void Unload();
extern "C" __declspec(dllexport) AddonDefinition* GetAddonDef();

BIN
GolemHelper/GolemHelper.rc Normal file

Binary file not shown.

View file

@ -76,8 +76,11 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;GOLEMHELPER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>
<LanguageStandard>stdcpp17</LanguageStandard>
<PrecompiledHeaderOutputFile />
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -93,8 +96,11 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;GOLEMHELPER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>
<LanguageStandard>stdcpp17</LanguageStandard>
<PrecompiledHeaderOutputFile />
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -110,9 +116,11 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;GOLEMHELPER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>
<LanguageStandard>stdcpp17</LanguageStandard>
<PrecompiledHeaderOutputFile />
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -128,9 +136,11 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;GOLEMHELPER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>
<LanguageStandard>stdcpp17</LanguageStandard>
<PrecompiledHeaderOutputFile />
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -141,6 +151,13 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="Automation\AutomationLogic.h" />
<ClInclude Include="Automation\CoordinateUtils.h" />
<ClInclude Include="Common\Globals.h" />
<ClInclude Include="Common\MenuSequences.h" />
<ClInclude Include="Common\Types.h" />
<ClInclude Include="Config\ConfigManager.h" />
<ClInclude Include="Config\TemplateManager.h" />
<ClInclude Include="Dependencies\imgui\imconfig.h" />
<ClInclude Include="Dependencies\imgui\imgui.h" />
<ClInclude Include="Dependencies\imgui\imgui_internal.h" />
@ -149,10 +166,19 @@
<ClInclude Include="Dependencies\imgui\imstb_truetype.h" />
<ClInclude Include="Dependencies\mumble\Mumble.h" />
<ClInclude Include="Dependencies\nexus\Nexus.h" />
<ClInclude Include="framework.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="GolemHelper.h" />
<ClInclude Include="Input\KeybindManager.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="UI\UIManager.h" />
<ClInclude Include="Utils\FileUtils.h" />
<ClInclude Include="Utils\MapUtils.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Automation\AutomationLogic.cpp" />
<ClCompile Include="Automation\CoordinateUtils.cpp" />
<ClCompile Include="Common\Globals.cpp" />
<ClCompile Include="Config\ConfigManager.cpp" />
<ClCompile Include="Config\TemplateManager.cpp" />
<ClCompile Include="Dependencies\imgui\imgui.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
@ -189,12 +215,18 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="GolemHelper.cpp" />
<ClCompile Include="Input\KeybindManager.cpp" />
<ClCompile Include="UI\UIManager.cpp" />
<ClCompile Include="Utils\FileUtils.cpp" />
<ClCompile Include="Utils\MapUtils.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="GolemHelper.rc" />
</ItemGroup>
<ItemGroup>
<Image Include="Resources\GOLEM_HELPER_ICON.png" />
<Image Include="Resources\GOLEM_HELPER_ICON_HOVER.png" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View file

@ -25,14 +25,29 @@
<Filter Include="Dependencies\nexus">
<UniqueIdentifier>{9474c716-f028-4778-8cd0-b5d8292d1586}</UniqueIdentifier>
</Filter>
<Filter Include="Resources">
<UniqueIdentifier>{07fb10f3-1f9b-483c-8721-e22bfe687792}</UniqueIdentifier>
</Filter>
<Filter Include="Common">
<UniqueIdentifier>{b4daf0a2-ce7a-4961-b877-492964d4659a}</UniqueIdentifier>
</Filter>
<Filter Include="Utils">
<UniqueIdentifier>{2822a502-cacf-4886-9672-0fcc32ee7086}</UniqueIdentifier>
</Filter>
<Filter Include="Config">
<UniqueIdentifier>{b37262c0-bd49-4acd-8713-e2667f4bc9fe}</UniqueIdentifier>
</Filter>
<Filter Include="Automation">
<UniqueIdentifier>{a9946213-e275-4fc2-989d-aff381613895}</UniqueIdentifier>
</Filter>
<Filter Include="UI">
<UniqueIdentifier>{4bbec8bd-548f-4efa-969c-af01a3e7e43f}</UniqueIdentifier>
</Filter>
<Filter Include="Input">
<UniqueIdentifier>{f74436fc-a159-4a48-8ac8-f79f20fb657f}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h">
<Filter>File di intestazione</Filter>
</ClInclude>
<ClInclude Include="pch.h">
<Filter>File di intestazione</Filter>
</ClInclude>
<ClInclude Include="Dependencies\imgui\imconfig.h">
<Filter>Dependencies\imgui</Filter>
</ClInclude>
@ -57,14 +72,50 @@
<ClInclude Include="Dependencies\nexus\Nexus.h">
<Filter>Dependencies\nexus</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>File di intestazione</Filter>
</ClInclude>
<ClInclude Include="Common\Globals.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\Types.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Utils\FileUtils.h">
<Filter>Utils</Filter>
</ClInclude>
<ClInclude Include="Config\ConfigManager.h">
<Filter>Config</Filter>
</ClInclude>
<ClInclude Include="Automation\AutomationLogic.h">
<Filter>Automation</Filter>
</ClInclude>
<ClInclude Include="Automation\CoordinateUtils.h">
<Filter>Automation</Filter>
</ClInclude>
<ClInclude Include="UI\UIManager.h">
<Filter>UI</Filter>
</ClInclude>
<ClInclude Include="Input\KeybindManager.h">
<Filter>Input</Filter>
</ClInclude>
<ClInclude Include="GolemHelper.h">
<Filter>File di origine</Filter>
</ClInclude>
<ClInclude Include="Utils\MapUtils.h">
<Filter>Utils</Filter>
</ClInclude>
<ClInclude Include="Config\TemplateManager.h">
<Filter>Config</Filter>
</ClInclude>
<ClInclude Include="Common\MenuSequences.h">
<Filter>Common</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
<Filter>File di origine</Filter>
</ClCompile>
<ClCompile Include="pch.cpp">
<Filter>File di origine</Filter>
</ClCompile>
<ClCompile Include="Dependencies\imgui\imgui.cpp">
<Filter>Dependencies\imgui</Filter>
</ClCompile>
@ -80,5 +131,48 @@
<ClCompile Include="Dependencies\imgui\imgui_widgets.cpp">
<Filter>Dependencies\imgui</Filter>
</ClCompile>
<ClCompile Include="Common\Globals.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Utils\FileUtils.cpp">
<Filter>Utils</Filter>
</ClCompile>
<ClCompile Include="Config\ConfigManager.cpp">
<Filter>Config</Filter>
</ClCompile>
<ClCompile Include="Automation\AutomationLogic.cpp">
<Filter>Automation</Filter>
</ClCompile>
<ClCompile Include="Automation\CoordinateUtils.cpp">
<Filter>Automation</Filter>
</ClCompile>
<ClCompile Include="UI\UIManager.cpp">
<Filter>UI</Filter>
</ClCompile>
<ClCompile Include="Input\KeybindManager.cpp">
<Filter>Input</Filter>
</ClCompile>
<ClCompile Include="GolemHelper.cpp">
<Filter>File di origine</Filter>
</ClCompile>
<ClCompile Include="Utils\MapUtils.cpp">
<Filter>Utils</Filter>
</ClCompile>
<ClCompile Include="Config\TemplateManager.cpp">
<Filter>Config</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="GolemHelper.rc">
<Filter>File di risorse</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<Image Include="Resources\GOLEM_HELPER_ICON.png">
<Filter>File di risorse</Filter>
</Image>
<Image Include="Resources\GOLEM_HELPER_ICON_HOVER.png">
<Filter>File di risorse</Filter>
</Image>
</ItemGroup>
</Project>

View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

View file

@ -0,0 +1,98 @@
#include <Windows.h>
#include <string>
#include "KeybindManager.h"
#include "../Common/Globals.h"
#include "../Automation/AutomationLogic.h"
#include "../Automation/CoordinateUtils.h"
void KeybindManager::RegisterKeybinds() {
if (!g_api) return;
Keybind kb_empty = { 0, false, false, false };
g_api->InputBinds.RegisterWithStruct("GolemHelper.ApplyBoons", HandleBoonKeybind, kb_empty);
g_api->InputBinds.RegisterWithStruct("GolemHelper.SpawnGolem", HandleGolemKeybind, kb_empty);
g_api->InputBinds.RegisterWithStruct("GolemHelper.RespawnGolem", HandleRespawnGolemKeybind, kb_empty);
g_api->InputBinds.RegisterWithStruct("GolemHelper.RemoveAndRespawnGolem", HandleRemoveAndRespawnGolemKeybind, kb_empty);
g_api->InputBinds.RegisterWithStruct("GolemHelper.QuickDPS", HandleQuickDpsKeybind, kb_empty);
g_api->InputBinds.RegisterWithStruct("GolemHelper.AlacDPS", HandleAlacDpsKeybind, kb_empty);
g_api->InputBinds.RegisterWithStruct("GolemHelper.Toggle", HandleToggleKeybind, kb_empty);
g_api->InputBinds.RegisterWithStruct("GolemHelper.ToggleUI", HandleUIToggleKeybind, kb_empty);
g_api->InputBinds.RegisterWithStruct("GolemHelper.DebugMouse", HandleDebugKeybind, kb_empty);
}
void KeybindManager::UnregisterKeybinds() {
if (!g_api) return;
g_api->InputBinds.Deregister("GolemHelper.ApplyBoons");
g_api->InputBinds.Deregister("GolemHelper.SpawnGolem");
g_api->InputBinds.Deregister("GolemHelper.RespawnGolem");
g_api->InputBinds.Deregister("GolemHelper.RemoveAndRespawnGolem");
g_api->InputBinds.Deregister("GolemHelper.QuickDPS");
g_api->InputBinds.Deregister("GolemHelper.AlacDPS");
g_api->InputBinds.Deregister("GolemHelper.Toggle");
g_api->InputBinds.Deregister("GolemHelper.ToggleUI");
g_api->InputBinds.Deregister("GolemHelper.DebugMouse");
}
void KeybindManager::HandleBoonKeybind(const char* id, bool release) {
if (!release && g_state.enabled) {
AutomationLogic::ApplyBoons();
}
}
void KeybindManager::HandleGolemKeybind(const char* id, bool release) {
if (!release && g_state.enabled) {
AutomationLogic::SpawnGolem();
}
}
void KeybindManager::HandleRespawnGolemKeybind(const char* id, bool release) {
if (!release && g_state.enabled) {
AutomationLogic::RespawnGolem();
}
}
void KeybindManager::HandleRemoveAndRespawnGolemKeybind(const char* id, bool release) {
if (!release && g_state.enabled) {
AutomationLogic::RemoveAndRespawnGolem();
}
}
void KeybindManager::HandleToggleKeybind(const char* id, bool release) {
if (!release) {
g_state.enabled = !g_state.enabled;
g_api->UI.SendAlert(g_state.enabled ? "GolemHelper enabled" : "GolemHelper disabled");
}
}
void KeybindManager::HandleUIToggleKeybind(const char* id, bool release) {
if (!release) {
g_state.showUI = !g_state.showUI;
}
}
void KeybindManager::HandleDebugKeybind(const char* id, bool release) {
if (!release) {
CoordinateUtils::DebugMousePosition();
}
}
void KeybindManager::HandleQuickDpsKeybind(const char* id, bool release) {
if (!release) {
g_state.isQuickDps = !g_state.isQuickDps;
if (g_state.isQuickDps) {
g_state.isAlacDps = false;
}
g_api->UI.SendAlert(g_state.isQuickDps ? "Quick DPS mode enabled" : "Quick DPS mode disabled");
}
}
void KeybindManager::HandleAlacDpsKeybind(const char* id, bool release) {
if (!release) {
g_state.isAlacDps = !g_state.isAlacDps;
if (g_state.isAlacDps) {
g_state.isQuickDps = false;
}
g_api->UI.SendAlert(g_state.isAlacDps ? "Alac DPS mode enabled" : "Alac DPS mode disabled");
}
}

View file

@ -0,0 +1,17 @@
#pragma once
class KeybindManager {
public:
static void RegisterKeybinds();
static void UnregisterKeybinds();
static void HandleBoonKeybind(const char* id, bool release);
static void HandleGolemKeybind(const char* id, bool release);
static void HandleRespawnGolemKeybind(const char* id, bool release);
static void HandleRemoveAndRespawnGolemKeybind(const char* id, bool release);
static void HandleQuickDpsKeybind(const char* id, bool release);
static void HandleAlacDpsKeybind(const char* id, bool release);
static void HandleToggleKeybind(const char* id, bool release);
static void HandleUIToggleKeybind(const char* id, bool release);
static void HandleDebugKeybind(const char* id, bool release);
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -0,0 +1,640 @@
#include <Windows.h>
#include <string>
#include "UIManager.h"
#include "../Common/Globals.h"
#include "../Config/ConfigManager.h"
#include "../Utils/MapUtils.h"
#include "../Config/TemplateManager.h"
#include "../Automation/CoordinateUtils.h"
#include "../Dependencies/imgui/imgui.h"
void UIManager::RenderUI() {
MapUtils::UpdateQuickAccessVisibility();
CoordinateUtils::UpdateCalibrationCapture();
if (!g_state.showUI) return;
ImGui::SetNextWindowSize(ImVec2(450, 600), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowPos(ImVec2(50, 50), ImGuiCond_FirstUseEver);
if (ImGui::Begin("GolemHelper", &g_state.showUI, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::TextColored(ImVec4(0.2f, 0.8f, 1.0f, 1.0f), "GolemHelper v1.7.1.0");
ImGui::Separator();
if (ImGui::BeginTabBar("GolemHelperTabs", ImGuiTabBarFlags_None)) {
if (ImGui::BeginTabItem("Settings")) {
RenderSettingsTab();
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Templates")) {
RenderTemplatesTab();
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
}
ImGui::End();
}
void UIManager::RenderSettingsTab() {
ImGui::Text("Boon Configuration");
if (ImGui::Button("Apply Boons", ImVec2(130, 0))) {
if (g_state.enabled && MapUtils::IsInTrainingArea()) {
g_api->InputBinds.Invoke("GolemHelper.ApplyBoons", false);
}
}
ImGui::Text(g_state.environmentDamage ? "Healer Modes:" : "DPS Modes:");
if (g_state.environmentDamage) {
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.6f);
ImGui::RadioButton("Normal Mode", false);
ImGui::PopStyleVar();
}
else {
if (ImGui::RadioButton("Normal Mode", !g_state.isQuickDps && !g_state.isAlacDps)) {
g_state.isQuickDps = false;
g_state.isAlacDps = false;
}
}
if (ImGui::RadioButton(g_state.environmentDamage ? "qHeal (Skip Quickness)" : "Quick DPS (Skip Quickness)", g_state.isQuickDps)) {
g_state.isQuickDps = true;
g_state.isAlacDps = false;
}
if (ImGui::RadioButton(g_state.environmentDamage ? "aHeal (Skip Alacrity)" : "Alac DPS (Skip Alacrity)", g_state.isAlacDps)) {
g_state.isQuickDps = false;
g_state.isAlacDps = true;
}
ImGui::Spacing();
ImGui::Text("Advanced:");
if (g_state.environmentDamage) {
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.6f);
ImGui::Checkbox("Boon Settings", &g_state.showBoonAdvanced);
g_state.showBoonAdvanced = false;
ImGui::PopStyleVar();
}
else {
ImGui::Checkbox("Boon Settings", &g_state.showBoonAdvanced);
}
if (g_state.showBoonAdvanced && !g_state.environmentDamage) {
ImGui::Checkbox("Add Resistance", &g_state.addResistance);
ImGui::Checkbox("Add Stability", &g_state.addStability);
ImGui::Checkbox("Skip Aegis", &g_state.skipAegis);
}
ImGui::Spacing();
ImGui::Text("Healer Bench:");
bool wasEnvironmentDamage = g_state.environmentDamage;
ImGui::Checkbox("Environment Damage", &g_state.environmentDamage);
if (g_state.environmentDamage && !wasEnvironmentDamage) {
if (!g_state.isQuickDps && !g_state.isAlacDps) {
g_state.isQuickDps = true;
}
}
if (g_state.environmentDamage) {
if (ImGui::RadioButton("Mild", g_state.envDamageLevel == ENV_MILD)) {
g_state.envDamageLevel = ENV_MILD;
}
if (ImGui::RadioButton("Moderate", g_state.envDamageLevel == ENV_MODERATE)) {
g_state.envDamageLevel = ENV_MODERATE;
}
if (ImGui::RadioButton("Extreme", g_state.envDamageLevel == ENV_EXTREME)) {
g_state.envDamageLevel = ENV_EXTREME;
}
}
ImGui::Spacing();
ImGui::Separator();
ImGui::Text("Golem Configuration");
if (ImGui::Button("Spawn Golem", ImVec2(110, 0))) {
if (g_state.enabled && MapUtils::IsInTrainingArea()) {
g_api->InputBinds.Invoke("GolemHelper.SpawnGolem", false);
}
}
ImGui::SameLine(0, 5);
if (ImGui::Button("Respawn", ImVec2(80, 0))) {
if (g_state.enabled && MapUtils::IsInTrainingArea()) {
g_api->InputBinds.Invoke("GolemHelper.RespawnGolem", false);
}
}
ImGui::Spacing();
if (ImGui::Button("Remove and Respawn", ImVec2(150, 0))) {
if (g_state.enabled && MapUtils::IsInTrainingArea()) {
g_api->InputBinds.Invoke("GolemHelper.RemoveAndRespawnGolem", false);
}
}
ImGui::Text("Golem Hitbox:");
if (ImGui::RadioButton("Small (Benchmark Default)", g_state.hitboxType == HITBOX_SMALL)) {
g_state.hitboxType = HITBOX_SMALL;
}
if (ImGui::RadioButton("Medium", g_state.hitboxType == HITBOX_MEDIUM)) {
g_state.hitboxType = HITBOX_MEDIUM;
}
if (ImGui::RadioButton("Large", g_state.hitboxType == HITBOX_LARGE)) {
g_state.hitboxType = HITBOX_LARGE;
}
ImGui::Spacing();
ImGui::Text("Advanced:");
ImGui::Checkbox("Condition Settings", &g_state.showAdvanced);
if (g_state.showAdvanced) {
ImGui::Checkbox("Skip Burning", &g_state.skipBurning);
ImGui::Checkbox("Skip Confusion", &g_state.skipConfusion);
ImGui::Checkbox("Skip Slow", &g_state.skipSlow);
ImGui::Checkbox("Add Immobilize", &g_state.addImmobilize);
ImGui::Checkbox("Add Blind", &g_state.addBlind);
ImGui::Checkbox("5 Bleeding Stacks", &g_state.fiveBleedingStacks);
}
if (g_state.debugMode) {
ImGui::Spacing();
ImGui::Separator();
ImGui::Text("Display Info:");
if (g_nexusLink && g_nexusLink->Width > 0 && g_nexusLink->Height > 0) {
ImGui::Text("Resolution: %dx%d", g_nexusLink->Width, g_nexusLink->Height);
ImGui::Text("UI Scale: %.2f", g_nexusLink->Scaling);
float dpiScale = (float)g_nexusLink->Width / 1920.0f;
ImGui::Text("DPI Scale: %.3f", dpiScale);
ImGui::Text("Debug samples: %d", g_state.debugCounter);
}
ImGui::Spacing();
ImGui::Text("Map Info:");
unsigned int currentMapID = MapUtils::GetCurrentMapID();
ImGui::Text("Current MapID: %u", currentMapID);
ImGui::Text("Is Training Area: %s", MapUtils::IsInTrainingArea() ? "YES" : "NO");
ImGui::Text("QuickAccess Visible: %s", g_state.quickAccessVisible ? "YES" : "NO");
}
ImGui::Spacing();
ImGui::Separator();
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.3f, 0.5f, 0.7f, 0.8f));
if (ImGui::CollapsingHeader("Set Custom Delays")) {
int oldStepDelay = g_state.stepDelay;
int oldInitialDelay = g_state.initialDelay;
ImGui::Text("Initial Delay (after F key):");
ImGui::SetNextItemWidth(200);
ImGui::SliderInt("##initial", &g_state.initialDelay, 100, 1000, "%d ms");
ImGui::Text("Step Delay (between clicks):");
ImGui::SetNextItemWidth(200);
ImGui::SliderInt("##step", &g_state.stepDelay, 100, 1000, "%d ms");
ImGui::Spacing();
if (ImGui::Button("Reset to Default", ImVec2(117, 0))) {
g_state.stepDelay = 290;
g_state.initialDelay = 390;
ConfigManager::SaveCustomDelaySettings();
}
ImGui::SameLine(0, 5);
if (ImGui::Button("Slow Mode", ImVec2(78, 0))) {
g_state.stepDelay = 1000;
g_state.initialDelay = 600;
ConfigManager::SaveCustomDelaySettings();
}
ImGui::Spacing();
ImGui::TextColored(ImVec4(0.8f, 0.8f, 0.2f, 1.0f), "Increase delays if clicks fail");
ImGui::TextColored(ImVec4(0.8f, 0.8f, 0.2f, 1.0f), "or calibrate in Options");
if (oldStepDelay != g_state.stepDelay || oldInitialDelay != g_state.initialDelay) {
ConfigManager::SaveCustomDelaySettings();
}
}
ImGui::PopStyleColor(2);
if (g_state.alwaysLoadLastSettings) {
static bool lastIsQuickDps = g_state.isQuickDps;
static bool lastIsAlacDps = g_state.isAlacDps;
static bool lastEnvironmentDamage = g_state.environmentDamage;
static EnvironmentDamageLevel lastEnvDamageLevel = g_state.envDamageLevel;
static bool lastSkipBurning = g_state.skipBurning;
static bool lastSkipConfusion = g_state.skipConfusion;
static bool lastSkipSlow = g_state.skipSlow;
static bool lastAddImmobilize = g_state.addImmobilize;
static bool lastAddBlind = g_state.addBlind;
static bool lastFiveBleedingStacks = g_state.fiveBleedingStacks;
static HitboxType lastHitboxType = g_state.hitboxType;
static bool lastAddResistance = g_state.addResistance;
static bool lastAddStability = g_state.addStability;
static bool lastSkipAegis = g_state.skipAegis;
static bool lastShowBoonAdvanced = g_state.showBoonAdvanced;
static bool lastShowAdvanced = g_state.showAdvanced;
if (lastIsQuickDps != g_state.isQuickDps ||
lastIsAlacDps != g_state.isAlacDps ||
lastEnvironmentDamage != g_state.environmentDamage ||
lastEnvDamageLevel != g_state.envDamageLevel ||
lastSkipBurning != g_state.skipBurning ||
lastSkipConfusion != g_state.skipConfusion ||
lastSkipSlow != g_state.skipSlow ||
lastAddImmobilize != g_state.addImmobilize ||
lastAddBlind != g_state.addBlind ||
lastFiveBleedingStacks != g_state.fiveBleedingStacks ||
lastHitboxType != g_state.hitboxType ||
lastAddResistance != g_state.addResistance ||
lastAddStability != g_state.addStability ||
lastSkipAegis != g_state.skipAegis ||
lastShowBoonAdvanced != g_state.showBoonAdvanced ||
lastShowAdvanced != g_state.showAdvanced) {
ConfigManager::SaveLastUsedSettings();
lastIsQuickDps = g_state.isQuickDps;
lastIsAlacDps = g_state.isAlacDps;
lastEnvironmentDamage = g_state.environmentDamage;
lastEnvDamageLevel = g_state.envDamageLevel;
lastSkipBurning = g_state.skipBurning;
lastSkipConfusion = g_state.skipConfusion;
lastSkipSlow = g_state.skipSlow;
lastAddImmobilize = g_state.addImmobilize;
lastAddBlind = g_state.addBlind;
lastFiveBleedingStacks = g_state.fiveBleedingStacks;
lastHitboxType = g_state.hitboxType;
lastAddResistance = g_state.addResistance;
lastAddStability = g_state.addStability;
lastSkipAegis = g_state.skipAegis;
lastShowBoonAdvanced = g_state.showBoonAdvanced;
lastShowAdvanced = g_state.showAdvanced;
}
}
}
void UIManager::RenderTemplatesTab() {
std::string currentTemplateName = "None";
bool foundMatchingTemplate = false;
for (const auto& temp : g_state.templates) {
if (temp.isQuickDps == g_state.isQuickDps &&
temp.isAlacDps == g_state.isAlacDps &&
temp.environmentDamage == g_state.environmentDamage &&
temp.envDamageLevel == g_state.envDamageLevel &&
temp.skipBurning == g_state.skipBurning &&
temp.skipConfusion == g_state.skipConfusion &&
temp.skipSlow == g_state.skipSlow &&
temp.addImmobilize == g_state.addImmobilize &&
temp.addBlind == g_state.addBlind &&
temp.fiveBleedingStacks == g_state.fiveBleedingStacks &&
temp.hitboxType == g_state.hitboxType &&
temp.addResistance == g_state.addResistance &&
temp.addStability == g_state.addStability &&
temp.skipAegis == g_state.skipAegis) {
currentTemplateName = temp.name;
foundMatchingTemplate = true;
break;
}
}
ImGui::Spacing();
ImGui::Text("Current: ");
ImGui::SameLine();
if (foundMatchingTemplate) {
ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "%s", currentTemplateName.c_str());
}
else {
ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "None");
}
ImGui::Separator();
ImGui::Spacing();
if (ImGui::Button("Apply Boons", ImVec2(110, 0))) {
if (g_state.enabled && MapUtils::IsInTrainingArea()) {
g_api->InputBinds.Invoke("GolemHelper.ApplyBoons", false);
}
}
ImGui::SameLine(0, 5);
if (ImGui::Button("Spawn Golem", ImVec2(110, 0))) {
if (g_state.enabled && MapUtils::IsInTrainingArea()) {
g_api->InputBinds.Invoke("GolemHelper.SpawnGolem", false);
}
}
ImGui::Spacing();
if (ImGui::Button("Respawn", ImVec2(110, 0))) {
if (g_state.enabled && MapUtils::IsInTrainingArea()) {
g_api->InputBinds.Invoke("GolemHelper.RespawnGolem", false);
}
}
ImGui::SameLine(0, 5);
if (ImGui::Button("Remove and Respawn", ImVec2(150, 0))) {
if (g_state.enabled && MapUtils::IsInTrainingArea()) {
g_api->InputBinds.Invoke("GolemHelper.RemoveAndRespawnGolem", false);
}
}
ImGui::Spacing();
ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();
ImGui::Text("Template Management");
ImGui::Separator();
ImGui::Text("Save Current Settings:");
ImGui::SetNextItemWidth(170);
ImGui::InputText("##templateName", g_state.newTemplateName, sizeof(g_state.newTemplateName));
ImGui::SameLine(0, 5);
if (ImGui::Button("Save", ImVec2(50, 0))) {
if (strlen(g_state.newTemplateName) > 0) {
TemplateManager::SaveCurrentAsTemplate(std::string(g_state.newTemplateName));
memset(g_state.newTemplateName, 0, sizeof(g_state.newTemplateName));
}
}
ImGui::Spacing();
ImGui::Separator();
ImGui::Text("Available Templates:");
std::vector<int> userTemplateIndices;
std::vector<const char*> userTemplateNames;
for (int i = 0; i < g_state.templates.size(); i++) {
if (!g_state.templates[i].isDefaultTemplate) {
userTemplateIndices.push_back(i);
userTemplateNames.push_back(g_state.templates[i].name.c_str());
}
}
if (userTemplateNames.empty()) {
ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "No user templates saved");
}
else {
int currentUserIndex = -1;
if (g_state.lastUserTemplateIndex >= 0) {
for (int i = 0; i < userTemplateIndices.size(); i++) {
if (userTemplateIndices[i] == g_state.lastUserTemplateIndex) {
currentUserIndex = i;
break;
}
}
}
ImGui::SetNextItemWidth(170);
if (ImGui::Combo("##templateList", &currentUserIndex, userTemplateNames.data(), (int)userTemplateNames.size())) {
g_state.selectedTemplateIndex = userTemplateIndices[currentUserIndex];
g_state.lastUserTemplateIndex = userTemplateIndices[currentUserIndex];
}
ImGui::SameLine(0, 5);
if (ImGui::Button("Load", ImVec2(50, 0))) {
if (currentUserIndex >= 0 && currentUserIndex < userTemplateIndices.size()) {
TemplateManager::LoadTemplate(userTemplateIndices[currentUserIndex]);
}
}
ImGui::SameLine(0, 5);
if (ImGui::Button("Del", ImVec2(50, 0))) {
if (currentUserIndex >= 0 && currentUserIndex < userTemplateIndices.size()) {
TemplateManager::DeleteTemplate(userTemplateIndices[currentUserIndex]);
g_state.selectedTemplateIndex = -1;
}
}
if (g_state.lastUserTemplateIndex >= 0 &&
g_state.lastUserTemplateIndex < g_state.templates.size()) {
const auto& selectedTemplate = g_state.templates[g_state.lastUserTemplateIndex];
ImGui::Spacing();
ImGui::Separator();
std::string displayName = selectedTemplate.name;
if (displayName.length() > 20) {
displayName = displayName.substr(0, 17) + "...";
}
ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f), "%s", displayName.c_str());
std::string modeText = "Normal";
if (selectedTemplate.isQuickDps) modeText = "Quick DPS";
else if (selectedTemplate.isAlacDps) modeText = "Alac DPS";
if (selectedTemplate.environmentDamage) {
modeText += " + Env ";
switch (selectedTemplate.envDamageLevel) {
case ENV_MILD: modeText += "Mild"; break;
case ENV_MODERATE: modeText += "Moderate"; break;
case ENV_EXTREME: modeText += "Extreme"; break;
}
}
ImGui::Text("Mode: %s", modeText.c_str());
const char* hitboxName = selectedTemplate.hitboxType == HITBOX_SMALL ? "Small" :
selectedTemplate.hitboxType == HITBOX_MEDIUM ? "Medium" : "Large";
ImGui::Text("Hitbox: %s", hitboxName);
if (selectedTemplate.skipBurning || selectedTemplate.skipConfusion || selectedTemplate.skipSlow ||
selectedTemplate.addImmobilize || selectedTemplate.addBlind || selectedTemplate.fiveBleedingStacks) {
ImGui::Text("Conditions:");
ImGui::Indent(15.0f);
std::vector<std::string> conditions;
if (selectedTemplate.skipBurning) conditions.push_back("Skip Burning");
if (selectedTemplate.skipConfusion) conditions.push_back("Skip Confusion");
if (selectedTemplate.skipSlow) conditions.push_back("Skip Slow");
if (selectedTemplate.addImmobilize) conditions.push_back("Add Immobilize");
if (selectedTemplate.addBlind) conditions.push_back("Add Blind");
if (selectedTemplate.fiveBleedingStacks) conditions.push_back("5 Bleeding");
std::string conditionsText = "";
for (int i = 0; i < conditions.size(); i++) {
if (i > 0 && i % 2 != 0) conditionsText += ", ";
conditionsText += conditions[i];
if ((i + 1) % 2 == 0 || i == conditions.size() - 1) {
ImGui::TextUnformatted(conditionsText.c_str());
conditionsText = "";
}
}
ImGui::Unindent(15.0f);
}
if (selectedTemplate.addResistance || selectedTemplate.addStability || selectedTemplate.skipAegis) {
ImGui::Text("Boon Settings:");
ImGui::Indent(15.0f);
std::vector<std::string> boonSettings;
if (selectedTemplate.addResistance) boonSettings.push_back("Add Resistance");
if (selectedTemplate.addStability) boonSettings.push_back("Add Stability");
if (selectedTemplate.skipAegis) boonSettings.push_back("Skip Aegis");
std::string boonText = "";
for (int i = 0; i < boonSettings.size(); i++) {
if (i > 0 && i % 2 != 0) boonText += ", ";
boonText += boonSettings[i];
if ((i + 1) % 2 == 0 || i == boonSettings.size() - 1) {
ImGui::TextUnformatted(boonText.c_str());
boonText = "";
}
}
ImGui::Unindent(15.0f);
}
}
}
ImGui::Spacing();
ImGui::Separator();
ImGui::Text("Quick Load:");
std::vector<std::string> defaultNames = { "DPS", "Quick DPS", "Alac DPS", "qHeal", "aHeal" };
for (int i = 0; i < 3; i++) {
const std::string& name = defaultNames[i];
int templateIndex = -1;
for (int j = 0; j < g_state.templates.size(); j++) {
if (g_state.templates[j].name == name && g_state.templates[j].isDefaultTemplate) {
templateIndex = j;
break;
}
}
if (templateIndex >= 0) {
if (ImGui::Button(name.c_str(), ImVec2(80, 0))) {
TemplateManager::LoadTemplate(templateIndex);
g_state.selectedTemplateIndex = -1;
}
if (i < 2) ImGui::SameLine(0, 5);
}
}
ImGui::Spacing();
for (int i = 3; i < 5; i++) {
const std::string& name = defaultNames[i];
int templateIndex = -1;
for (int j = 0; j < g_state.templates.size(); j++) {
if (g_state.templates[j].name == name && g_state.templates[j].isDefaultTemplate) {
templateIndex = j;
break;
}
}
if (templateIndex >= 0) {
if (ImGui::Button(name.c_str(), ImVec2(80, 0))) {
TemplateManager::LoadTemplate(templateIndex);
g_state.selectedTemplateIndex = -1;
}
if (i == 3) ImGui::SameLine(0, 5);
}
}
}
void UIManager::RenderOptions() {
ImGui::Separator();
ImGui::Text("GolemHelper Settings");
bool oldAlwaysHideIcon = g_state.alwaysHideIcon;
ImGui::Checkbox("Always Hide Icon", &g_state.alwaysHideIcon);
if (oldAlwaysHideIcon != g_state.alwaysHideIcon) {
ConfigManager::SaveCustomDelaySettings();
MapUtils::UpdateQuickAccessVisibility();
}
bool oldAutoShowHideUI = g_state.autoShowHideUI;
ImGui::Checkbox("Auto Show/Hide UI", &g_state.autoShowHideUI);
if (oldAutoShowHideUI != g_state.autoShowHideUI) {
ConfigManager::SaveCustomDelaySettings();
}
bool oldAlwaysLoadLastSettings = g_state.alwaysLoadLastSettings;
ImGui::Checkbox("Always Load Last Settings", &g_state.alwaysLoadLastSettings);
if (oldAlwaysLoadLastSettings != g_state.alwaysLoadLastSettings) {
ConfigManager::SaveCustomDelaySettings();
}
ImGui::Checkbox("Enable debug mode", &g_state.debugMode);
ImGui::Spacing();
ImGui::Separator();
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.3f, 0.5f, 0.7f, 0.8f));
if (ImGui::CollapsingHeader("Coordinate Calibration")) {
ImGui::Spacing();
if (g_state.calibrationMode) {
ImGui::TextColored(ImVec4(1.0f, 0.85f, 0.0f, 1.0f), "! Calibration active !");
ImGui::Spacing();
ImGui::TextWrapped("1. Interact with the Boon Console (press F)");
ImGui::TextWrapped("2. Hover your mouse over the middle of \"Adjust Self\" and click.");
ImGui::Spacing();
ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "The addon window is hidden.");
ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "Press ESC to cancel.");
}
else {
if (g_state.hasCalibration) {
ImGui::TextColored(ImVec4(0.2f, 1.0f, 0.4f, 1.0f), "Status: Calibrated");
ImGui::Text("scaleX: %.4f scaleY: %.4f",
g_state.calibratedScaleX, g_state.calibratedScaleY);
}
else {
ImGui::TextColored(ImVec4(0.75f, 0.75f, 0.75f, 1.0f), "Status: Auto-scaling (default)");
}
ImGui::Spacing();
if (ImGui::Button("Calibrate", ImVec2(120, 0))) {
CoordinateUtils::StartCalibration();
}
if (g_state.hasCalibration) {
ImGui::SameLine(0, 6);
if (ImGui::Button("Reset to Default", ImVec2(120, 0))) {
CoordinateUtils::ResetCalibration();
}
}
ImGui::Spacing();
ImGui::TextDisabled("Interact with the Boon Console, then hover over");
ImGui::TextDisabled("the middle of \"Adjust Self\" and click.");
}
ImGui::Spacing();
}
ImGui::PopStyleColor(2);
}

View file

@ -0,0 +1,11 @@
#pragma once
class UIManager {
public:
static void RenderUI();
static void RenderOptions();
private:
static void RenderSettingsTab();
static void RenderTemplatesTab();
};

View file

@ -0,0 +1,98 @@
#include <Windows.h>
#include <vector>
#include <string>
#include <fstream>
#include "FileUtils.h"
#include "../Common/Globals.h"
#include "../resource.h"
std::string FileUtils::GetAddonPath() {
char gameDir[MAX_PATH];
GetModuleFileNameA(NULL, gameDir, MAX_PATH);
std::string gamePath = gameDir;
size_t lastSlash = gamePath.find_last_of("\\");
if (lastSlash != std::string::npos) {
gamePath = gamePath.substr(0, lastSlash);
}
std::string addonPath = gamePath + "\\addons\\GolemHelper";
CreateDirectoryA(addonPath.c_str(), NULL);
return addonPath;
}
std::string FileUtils::GetConfigFilePath() {
std::string configPath = GetAddonPath() + "\\config.ini";
if (g_api) {
char logBuffer[500];
sprintf_s(logBuffer, "Config file path: %s", configPath.c_str());
g_api->Log(ELogLevel_INFO, "GolemHelper", logBuffer);
}
return configPath;
}
bool FileUtils::ExtractResourceToFile(HMODULE hModule, int resourceID, const std::string& filePath) {
HRSRC hRes = FindResourceA(hModule, MAKEINTRESOURCEA(resourceID), "PNG");
if (!hRes) return false;
HGLOBAL hData = LoadResource(hModule, hRes);
if (!hData) return false;
LPVOID pData = LockResource(hData);
if (!pData) return false;
DWORD dataSize = SizeofResource(hModule, hRes);
if (!dataSize) return false;
std::ofstream file(filePath, std::ios::binary);
if (!file.is_open()) return false;
file.write(static_cast<const char*>(pData), dataSize);
file.close();
return true;
}
void FileUtils::CopyResourceIcons() {
if (!g_api) return;
std::string addonPath = GetAddonPath();
std::string iconsPath = addonPath + "\\icons";
CreateDirectoryA(iconsPath.c_str(), NULL);
std::string iconDestPath = iconsPath + "\\GOLEM_HELPER_ICON.png";
std::string iconHoverDestPath = iconsPath + "\\GOLEM_HELPER_ICON_HOVER.png";
if (GetFileAttributesA(iconDestPath.c_str()) != INVALID_FILE_ATTRIBUTES &&
GetFileAttributesA(iconHoverDestPath.c_str()) != INVALID_FILE_ATTRIBUTES) {
g_api->Log(ELogLevel_INFO, "GolemHelper", "Icons already exist, skipping unpack");
return;
}
HMODULE hModule = GetModuleHandleA("GolemHelper.dll");
if (!hModule) {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Failed to get module handle");
return;
}
if (ExtractResourceToFile(hModule, IDB_PNG1, iconDestPath)) {
char logBuffer[300];
sprintf_s(logBuffer, "Extracted icon from resources: %s", iconDestPath.c_str());
g_api->Log(ELogLevel_INFO, "GolemHelper", logBuffer);
}
else {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Failed to extract normal icon from resources");
}
if (ExtractResourceToFile(hModule, IDB_PNG2, iconHoverDestPath)) {
char logBuffer[300];
sprintf_s(logBuffer, "Extracted hover icon from resources: %s", iconHoverDestPath.c_str());
g_api->Log(ELogLevel_INFO, "GolemHelper", logBuffer);
}
else {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Failed to extract hover icon from resources");
}
}

View file

@ -0,0 +1,11 @@
#pragma once
#include <string>
#include <Windows.h>
class FileUtils {
public:
static std::string GetAddonPath();
static std::string GetConfigFilePath();
static bool ExtractResourceToFile(HMODULE hModule, int resourceID, const std::string& filePath);
static void CopyResourceIcons();
};

View file

@ -0,0 +1,68 @@
#include <Windows.h>
#include "MapUtils.h"
#include "../Common/Globals.h"
bool MapUtils::IsInTrainingArea() {
return GetCurrentMapID() == 1154;
}
unsigned int MapUtils::GetCurrentMapID() {
if (g_mumbleData && g_mumbleData->Context.MapID != 0) {
return g_mumbleData->Context.MapID;
}
return 0;
}
void MapUtils::UpdateQuickAccessVisibility() {
if (!g_api) return;
bool shouldBeVisible = IsInTrainingArea() && !g_state.alwaysHideIcon;
unsigned int currentMapID = GetCurrentMapID();
if (currentMapID != g_state.lastMapID || g_state.quickAccessVisible != shouldBeVisible) {
g_state.lastMapID = currentMapID;
if (shouldBeVisible && !g_state.quickAccessVisible) {
g_api->QuickAccess.Add(
"GolemHelper.ToggleUI",
"GOLEM_HELPER_ICON",
"GOLEM_HELPER_ICON_HOVER",
"GolemHelper.ToggleUI",
"GolemHelper UI"
);
g_state.quickAccessVisible = true;
if (g_state.debugMode) {
char buffer[150];
sprintf_s(buffer, sizeof(buffer), "QuickAccess icon ADDED - MapID: %u (Training Area)", currentMapID);
g_api->Log(ELogLevel_INFO, "GolemHelper", buffer);
}
}
else if ((!shouldBeVisible || g_state.alwaysHideIcon) && g_state.quickAccessVisible) {
g_api->QuickAccess.Remove("GolemHelper.ToggleUI");
g_state.quickAccessVisible = false;
if (g_state.debugMode) {
const char* reason = g_state.alwaysHideIcon ? "Always Hide Icon enabled" : "Not Training Area";
char buffer[200];
sprintf_s(buffer, sizeof(buffer), "QuickAccess icon REMOVED - MapID: %u (%s)", currentMapID, reason);
g_api->Log(ELogLevel_INFO, "GolemHelper", buffer);
}
}
}
if (g_state.autoShowHideUI) {
bool inTrainingArea = IsInTrainingArea();
static bool wasInTrainingArea = false;
if (inTrainingArea && !wasInTrainingArea) {
g_state.showUI = true;
}
else if (!inTrainingArea && wasInTrainingArea) {
g_state.showUI = false;
}
wasInTrainingArea = inTrainingArea;
}
}

View file

@ -0,0 +1,8 @@
#pragma once
class MapUtils {
public:
static bool IsInTrainingArea();
static void UpdateQuickAccessVisibility();
static unsigned int GetCurrentMapID();
};

View file

@ -1,894 +1,4 @@
#include "pch.h"
#include <Windows.h>
#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include "Dependencies/imgui/imgui.h"
#include "Dependencies/nexus/Nexus.h"
#include "Dependencies/mumble/Mumble.h"
AddonAPI* g_api = nullptr;
NexusLinkData* NexusLink = nullptr;
enum HitboxType {
HITBOX_SMALL = 0,
HITBOX_MEDIUM = 1,
HITBOX_LARGE = 2
};
enum EnvironmentDamageLevel {
ENV_MILD = 0,
ENV_MODERATE = 1,
ENV_EXTREME = 2
};
struct {
bool enabled = false;
bool boonsEnabled = true;
bool golemEnabled = true;
bool isQuickDps = false;
bool isAlacDps = false;
bool environmentDamage = false;
EnvironmentDamageLevel envDamageLevel = ENV_MILD;
bool skipSlow = false;
bool skipBurning = false;
bool fiveBleedingStacks = false;
HitboxType hitboxType = HITBOX_SMALL;
bool debugMode = false;
bool showUI = false;
bool useCustomDelays = false;
bool showAdvanced = false;
int debugCounter = 0;
int stepDelay = 290;
} g_state;
struct MenuCoordinates {
int golemStepX[25] = {
830, 830, 830, 830, 830, 830, 830, 830, 830, 830,
830, 830, 830, 830, 830, 830, 830, 830, 830, 830,
830, 830, 830, 830, 830
};
int golemStepY[25] = {
260, 260, 306, 257, 257, 306, 257, 306, 352, 400,
454, 508, 352, 257, 306, 454, 400, 306, 352, 400,
454, 400, 454, 454, 548
};
int boonStepX[20] = {
830, 830, 830, 830, 830, 830, 830, 830, 830, 830,
830, 830, 830, 830, 830, 830, 830, 830, 830, 830
};
int boonStepY[20] = {
262, 354, 262, 262, 400, 305, 354, 305, 262, 305,
450, 500, 354, 262, 305, 354, 400, 450, 262, 550
};
int healerStepX[10] = {
830, 830, 830, 830, 830, 830, 830, 830, 830, 830
};
int healerStepY[10] = {
262, 352, 352, 262, 262, 500, 450, 450, 305, 262
};
} g_coords;
void GetScaledCoordinates(int baseX, int baseY, int* scaledX, int* scaledY);
void DebugMousePosition();
void ApplyAllBoons();
void ApplyHealerBoons();
void ApplyGolemSettings();
void ClickAtScaled(int baseX, int baseY, int delay);
bool ShouldSkipBoonStep(int stepIndex);
bool ShouldSkipGolemStep(int stepIndex);
void HandleBoonKeybind(const char* id, bool release);
void HandleGolemKeybind(const char* id, bool release);
void HandleQuickDpsKeybind(const char* id, bool release);
void HandleAlacDpsKeybind(const char* id, bool release);
void HandleToggleKeybind(const char* id, bool release);
void HandleUIToggleKeybind(const char* id, bool release);
void HandleDebugKeybind(const char* id, bool release);
void SaveCustomDelaySettings();
void LoadCustomDelaySettings();
void Load(AddonAPI* aApi);
void Unload();
std::string GetConfigFilePath() {
char gameDir[MAX_PATH];
GetModuleFileNameA(NULL, gameDir, MAX_PATH);
std::string gamePath = gameDir;
size_t lastSlash = gamePath.find_last_of("\\");
if (lastSlash != std::string::npos) {
gamePath = gamePath.substr(0, lastSlash);
}
std::string addonPath = gamePath + "\\addons\\GolemHelper";
CreateDirectoryA(addonPath.c_str(), NULL);
std::string configPath = addonPath + "\\config.ini";
if (g_api) {
char logBuffer[500];
sprintf_s(logBuffer, "Config file path: %s", configPath.c_str());
g_api->Log(ELogLevel_INFO, "GolemHelper", logBuffer);
}
return configPath;
}
void SaveCustomDelaySettings() {
if (!g_api) return;
std::string configPath = GetConfigFilePath();
try {
std::ofstream configFile(configPath);
if (!configFile.is_open()) {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Could not create config file");
return;
}
configFile << "[GolemHelper]" << std::endl;
configFile << "useCustomDelays=" << (g_state.useCustomDelays ? "1" : "0") << std::endl;
configFile << "stepDelay=" << g_state.stepDelay << std::endl;
configFile.close();
char logBuffer[200];
sprintf_s(logBuffer, "Custom delay settings saved: enabled=%s, delay=%dms",
g_state.useCustomDelays ? "true" : "false", g_state.stepDelay);
g_api->Log(ELogLevel_INFO, "GolemHelper", logBuffer);
}
catch (...) {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Failed to save config file");
}
}
void LoadCustomDelaySettings() {
if (!g_api) return;
std::string configPath = GetConfigFilePath();
try {
std::ifstream configFile(configPath);
if (!configFile.is_open()) {
g_api->Log(ELogLevel_INFO, "GolemHelper", "No config file found, using defaults");
return;
}
std::string line;
while (std::getline(configFile, line)) {
if (line.empty() || line[0] == '[') continue;
size_t equalPos = line.find('=');
if (equalPos == std::string::npos) continue;
std::string key = line.substr(0, equalPos);
std::string value = line.substr(equalPos + 1);
if (key == "useCustomDelays") {
g_state.useCustomDelays = (value == "1");
}
else if (key == "stepDelay") {
int delay = std::stoi(value);
if (delay >= 100 && delay <= 1000) {
g_state.stepDelay = delay;
}
}
}
configFile.close();
char logBuffer[200];
sprintf_s(logBuffer, "Custom delay settings loaded: enabled=%s, delay=%dms",
g_state.useCustomDelays ? "true" : "false", g_state.stepDelay);
g_api->Log(ELogLevel_INFO, "GolemHelper", logBuffer);
}
catch (...) {
g_api->Log(ELogLevel_INFO, "GolemHelper", "Could not load config file, using defaults");
}
}
void RenderUI() {
if (!g_state.showUI) return;
ImGui::SetNextWindowSize(ImVec2(400, 500), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowPos(ImVec2(50, 50), ImGuiCond_FirstUseEver);
if (ImGui::Begin("GolemHelper", &g_state.showUI, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::TextColored(ImVec4(0.2f, 0.8f, 1.0f, 1.0f), "GolemHelper v1.2.0.0");
ImGui::Separator();
ImGui::Text("Status:");
ImGui::SameLine();
if (g_state.enabled) {
ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "ENABLED");
}
else {
ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "DISABLED");
}
if (ImGui::Button(g_state.enabled ? "Disable GolemHelper" : "Enable GolemHelper", ImVec2(200, 0))) {
g_state.enabled = !g_state.enabled;
}
ImGui::Spacing();
ImGui::Separator();
ImGui::Text("Boon Configuration");
ImGui::Checkbox("Enable Boons", &g_state.boonsEnabled);
if (ImGui::Button("Apply Boons", ImVec2(150, 0))) {
if (g_state.enabled) {
g_api->InputBinds.Invoke("GolemHelper.ApplyBoons", false);
}
}
ImGui::Text(g_state.environmentDamage ? "Healer Modes:" : "DPS Modes:");
if (g_state.environmentDamage) {
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.6f);
ImGui::RadioButton("Normal Mode", false);
ImGui::PopStyleVar();
}
else {
if (ImGui::RadioButton("Normal Mode", !g_state.isQuickDps && !g_state.isAlacDps)) {
g_state.isQuickDps = false;
g_state.isAlacDps = false;
}
}
if (ImGui::RadioButton(g_state.environmentDamage ? "qHeal (Skip Quickness)" : "Quick DPS (Skip Quickness)", g_state.isQuickDps)) {
g_state.isQuickDps = true;
g_state.isAlacDps = false;
}
if (ImGui::RadioButton(g_state.environmentDamage ? "aHeal (Skip Alacrity)" : "Alac DPS (Skip Alacrity)", g_state.isAlacDps)) {
g_state.isQuickDps = false;
g_state.isAlacDps = true;
}
ImGui::Spacing();
ImGui::Text("Healer Bench:");
bool wasEnvironmentDamage = g_state.environmentDamage;
ImGui::Checkbox("Environment Damage", &g_state.environmentDamage);
if (g_state.environmentDamage && !wasEnvironmentDamage) {
if (!g_state.isQuickDps && !g_state.isAlacDps) {
g_state.isQuickDps = true;
}
}
if (g_state.environmentDamage) {
if (ImGui::RadioButton("Mild", g_state.envDamageLevel == ENV_MILD)) {
g_state.envDamageLevel = ENV_MILD;
}
if (ImGui::RadioButton("Moderate", g_state.envDamageLevel == ENV_MODERATE)) {
g_state.envDamageLevel = ENV_MODERATE;
}
if (ImGui::RadioButton("Extreme", g_state.envDamageLevel == ENV_EXTREME)) {
g_state.envDamageLevel = ENV_EXTREME;
}
}
ImGui::Spacing();
ImGui::Separator();
ImGui::Text("Golem Configuration");
ImGui::Checkbox("Enable Golem Settings", &g_state.golemEnabled);
if (ImGui::Button("Apply Golem Settings", ImVec2(150, 0))) {
if (g_state.enabled) {
g_api->InputBinds.Invoke("GolemHelper.ApplyGolem", false);
}
}
ImGui::Text("Golem Hitbox:");
if (ImGui::RadioButton("Small (Benchmark Default)", g_state.hitboxType == HITBOX_SMALL)) {
g_state.hitboxType = HITBOX_SMALL;
}
if (ImGui::RadioButton("Medium", g_state.hitboxType == HITBOX_MEDIUM)) {
g_state.hitboxType = HITBOX_MEDIUM;
}
if (ImGui::RadioButton("Large", g_state.hitboxType == HITBOX_LARGE)) {
g_state.hitboxType = HITBOX_LARGE;
}
ImGui::Spacing();
ImGui::Text("Advanced:");
ImGui::Checkbox("Condition Settings", &g_state.showAdvanced);
if (g_state.showAdvanced) {
ImGui::Checkbox("Skip Slow", &g_state.skipSlow);
ImGui::Checkbox("Skip Burning", &g_state.skipBurning);
ImGui::Checkbox("5 Bleeding Stacks", &g_state.fiveBleedingStacks);
}
if (g_state.debugMode) {
ImGui::Spacing();
ImGui::Separator();
ImGui::Text("Display Info:");
if (NexusLink && NexusLink->Width > 0 && NexusLink->Height > 0) {
ImGui::Text("Resolution: %dx%d", NexusLink->Width, NexusLink->Height);
ImGui::Text("UI Scale: %.2f", NexusLink->Scaling);
float dpiScale = (float)NexusLink->Width / 1920.0f;
ImGui::Text("DPI Scale: %.3f", dpiScale);
ImGui::Text("Debug samples: %d", g_state.debugCounter);
}
}
ImGui::Spacing();
ImGui::Separator();
ImGui::Text("Timing Settings");
bool oldUseCustomDelays = g_state.useCustomDelays;
int oldStepDelay = g_state.stepDelay;
ImGui::Checkbox("Use Custom Step Delay", &g_state.useCustomDelays);
if (g_state.useCustomDelays) {
ImGui::SliderInt("", &g_state.stepDelay, 100, 1000, "%d ms");
ImGui::Spacing();
if (ImGui::Button("Reset to Default", ImVec2(120, 0))) {
g_state.stepDelay = 290;
SaveCustomDelaySettings();
}
ImGui::SameLine();
if (ImGui::Button("Slow Mode", ImVec2(80, 0))) {
g_state.stepDelay = 1000;
SaveCustomDelaySettings();
}
ImGui::Spacing();
ImGui::TextColored(ImVec4(0.8f, 0.8f, 0.2f, 1.0f), "Increase delay if clicks fail");
}
if (oldUseCustomDelays != g_state.useCustomDelays || oldStepDelay != g_state.stepDelay) {
SaveCustomDelaySettings();
}
}
ImGui::End();
}
void RenderOptions() {
ImGui::Separator();
ImGui::Text("GolemHelper Settings");
ImGui::Checkbox("Show UI by default", &g_state.showUI);
ImGui::Checkbox("Enable debug mode", &g_state.debugMode);
if (ImGui::Button("Reset all settings")) {
g_state.isQuickDps = false;
g_state.isAlacDps = false;
g_state.environmentDamage = false;
g_state.envDamageLevel = ENV_MILD;
g_state.skipSlow = false;
g_state.skipBurning = false;
g_state.fiveBleedingStacks = false;
g_state.hitboxType = HITBOX_SMALL;
g_state.useCustomDelays = false;
g_state.showAdvanced = false;
g_state.stepDelay = 290;
g_state.boonsEnabled = true;
g_state.golemEnabled = true;
SaveCustomDelaySettings();
}
ImGui::Spacing();
ImGui::Text("Current Modes:");
std::string boonMode = "Normal";
if (g_state.isQuickDps) {
boonMode = "Quick DPS";
}
else if (g_state.isAlacDps) {
boonMode = "Alac DPS";
}
if (g_state.environmentDamage) {
boonMode += " + Env ";
switch (g_state.envDamageLevel) {
case ENV_MILD: boonMode += "Mild"; break;
case ENV_MODERATE: boonMode += "Moderate"; break;
case ENV_EXTREME: boonMode += "Extreme"; break;
}
}
ImGui::Text("- Boons: %s", boonMode.c_str());
std::string golemMods = "Normal";
if (g_state.showAdvanced && (g_state.skipSlow || g_state.skipBurning || g_state.fiveBleedingStacks)) {
golemMods = "";
if (g_state.skipSlow) golemMods += "Skip Slow ";
if (g_state.skipBurning) golemMods += "Skip Burning ";
if (g_state.fiveBleedingStacks) golemMods += "5 Bleeding ";
if (!golemMods.empty()) golemMods.pop_back();
}
ImGui::Text("- Golem: %s", golemMods.c_str());
const char* hitboxName = g_state.hitboxType == HITBOX_SMALL ? "Small" :
g_state.hitboxType == HITBOX_MEDIUM ? "Medium" : "Large";
ImGui::Text("- Hitbox: %s", hitboxName);
ImGui::Text("- Timing: %s", g_state.useCustomDelays ? "Custom" : "Default");
if (g_state.useCustomDelays) {
ImGui::Text("- Custom Delay: %d ms", g_state.stepDelay);
}
}
void GetScaledCoordinates(int baseX, int baseY, int* scaledX, int* scaledY) {
g_api->Log(ELogLevel_INFO, "GolemHelper", "GetScaledCoordinates CHIAMATA");
if (NexusLink && NexusLink->Width > 0 && NexusLink->Height > 0) {
float uiScale = NexusLink->Scaling;
float dpiScale = (float)NexusLink->Width / 1920.0f;
char valuesBuffer[200];
sprintf_s(valuesBuffer, "GetScaled INPUT: uiScale=%.3f, base=%d,%d", uiScale, baseX, baseY);
g_api->Log(ELogLevel_INFO, "GolemHelper", valuesBuffer);
int scaledForResolutionX = (int)(baseX * dpiScale);
int scaledForResolutionY = baseY;
int finalX = scaledForResolutionX;
int finalY = scaledForResolutionY;
if (uiScale >= 0.89f && uiScale <= 0.91f) {
finalX = scaledForResolutionX - (int)(scaledForResolutionX * 0.029f);
finalY = scaledForResolutionY - (int)(scaledForResolutionY * 0.103f);
g_api->Log(ELogLevel_INFO, "GolemHelper", "APPLIED SMALL OFFSET");
}
else if (uiScale >= 1.09f && uiScale <= 1.15f) {
finalX = scaledForResolutionX - (int)(scaledForResolutionX * 0.053f);
finalY = scaledForResolutionY + (int)(scaledForResolutionY * 0.095f);
g_api->Log(ELogLevel_INFO, "GolemHelper", "APPLIED LARGE OFFSET");
}
else if (uiScale >= 1.21f && uiScale <= 1.25f) {
finalX = scaledForResolutionX - (int)(scaledForResolutionX * 0.097f);
finalY = scaledForResolutionY + (int)(scaledForResolutionY * 0.206f);
g_api->Log(ELogLevel_INFO, "GolemHelper", "APPLIED LARGER OFFSET");
}
else {
char buffer[100];
sprintf_s(buffer, "NO OFFSET - uiScale %.3f", uiScale);
g_api->Log(ELogLevel_INFO, "GolemHelper", buffer);
}
*scaledX = finalX;
*scaledY = finalY;
char resultBuffer[200];
sprintf_s(resultBuffer, "GetScaled RESULT: %d,%d -> %d,%d", scaledForResolutionX, scaledForResolutionY, finalX, finalY);
g_api->Log(ELogLevel_INFO, "GolemHelper", resultBuffer);
}
else {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "GetScaledCoordinates - Nexus data not available");
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
float dpiScale = (float)screenWidth / 1920.0f;
*scaledX = (int)(baseX * dpiScale);
*scaledY = baseY;
}
}
void DebugMousePosition() {
if (!g_api) return;
POINT mousePos;
GetCursorPos(&mousePos);
if (NexusLink && NexusLink->Width > 0 && NexusLink->Height > 0) {
float uiScale = NexusLink->Scaling;
float dpiScale = (float)NexusLink->Width / 1920.0f;
float finalScaleX = uiScale * dpiScale;
int baseX = (int)(mousePos.x / finalScaleX);
int baseY = mousePos.y;
g_state.debugCounter++;
char buffer[450];
sprintf_s(buffer, "=== DEBUG #%d === Resolution: %dx%d | Mouse: %d,%d | Base coords: %d,%d | Interface Size: %.2f | DPI Scale: %.3f | Final ScaleX: %.3f",
g_state.debugCounter, NexusLink->Width, NexusLink->Height,
mousePos.x, mousePos.y, baseX, baseY, uiScale, dpiScale, finalScaleX);
g_api->Log(ELogLevel_INFO, "GolemHelper", buffer);
}
else {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Cannot debug - Nexus data not available");
}
if (g_state.debugCounter == 1) {
}
}
void ClickAtScaled(int baseX, int baseY, int delay = 25) {
HWND gameWindow = GetForegroundWindow();
if (!gameWindow) return;
int scaledX, scaledY;
GetScaledCoordinates(baseX, baseY, &scaledX, &scaledY);
LPARAM lParam = MAKELPARAM(scaledX, scaledY);
SendMessage(gameWindow, WM_LBUTTONDOWN, MK_LBUTTON, lParam);
Sleep(10);
SendMessage(gameWindow, WM_LBUTTONUP, 0, lParam);
Sleep(delay);
}
bool ShouldSkipBoonStep(int stepIndex) {
if (g_state.isQuickDps && stepIndex == 14) {
return true;
}
if (g_state.isAlacDps && (stepIndex == 13 || stepIndex == 18)) {
return true;
}
return false;
}
bool ShouldSkipGolemStep(int stepIndex) {
if (!g_state.showAdvanced) {
return false;
}
if (g_state.skipSlow && stepIndex == 17) {
return true;
}
if (g_state.skipBurning && stepIndex == 7) {
return true;
}
return false;
}
void ApplyHealerBoons() {
if (!g_api || !g_state.boonsEnabled || !g_state.enabled) return;
bool uiWasVisible = g_state.showUI;
if (uiWasVisible) {
g_state.showUI = false;
}
std::string mode = "Healer Bench - ";
if (g_state.isQuickDps) {
mode += "Quick DPS (Healer provides Alacrity)";
}
else if (g_state.isAlacDps) {
mode += "Alac DPS (Healer provides Quickness)";
}
mode += " + Environment ";
switch (g_state.envDamageLevel) {
case ENV_MILD: mode += "Mild"; break;
case ENV_MODERATE: mode += "Moderate"; break;
case ENV_EXTREME: mode += "Extreme"; break;
}
char startBuffer[400];
sprintf_s(startBuffer, "Starting healer boon sequence - Mode: %s", mode.c_str());
g_api->Log(ELogLevel_INFO, "GolemHelper", startBuffer);
try {
g_api->GameBinds.InvokeAsync(EGameBinds_MiscInteract, 50);
int initialDelay = g_state.useCustomDelays ? g_state.stepDelay : 390;
Sleep(initialDelay);
int delay = g_state.useCustomDelays ? g_state.stepDelay : 290;
if (g_state.isQuickDps) {
for (int i = 0; i < 10; i++) {
ClickAtScaled(g_coords.healerStepX[i], g_coords.healerStepY[i], delay);
}
}
else if (g_state.isAlacDps) {
int alacStepY[9] = { 262, 352, 352, 305, 500, 450, 450, 305, 262 };
for (int i = 0; i < 9; i++) {
ClickAtScaled(830, alacStepY[i], delay);
}
}
g_api->Log(ELogLevel_INFO, "GolemHelper", "Applying Environment Damage final click");
int finalY;
switch (g_state.envDamageLevel) {
case ENV_MILD: finalY = 352; break;
case ENV_MODERATE: finalY = 305; break;
case ENV_EXTREME: finalY = 262; break;
default: finalY = 352; break;
}
ClickAtScaled(830, finalY, 50);
}
catch (...) {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Exception during healer boon sequence");
}
if (uiWasVisible) {
g_state.showUI = true;
}
g_api->Log(ELogLevel_INFO, "GolemHelper", "Healer boon sequence completed!");
}
void ApplyAllBoons() {
if (!g_api || !g_state.boonsEnabled || !g_state.enabled) return;
if (g_state.environmentDamage) {
ApplyHealerBoons();
return;
}
bool uiWasVisible = g_state.showUI;
if (uiWasVisible) {
g_state.showUI = false;
}
std::string mode = "Normal";
if (g_state.isQuickDps) {
mode = "Quick DPS";
}
else if (g_state.isAlacDps) {
mode = "Alac DPS";
}
char startBuffer[300];
sprintf_s(startBuffer, "Starting boon sequence (20 steps) - Mode: %s", mode.c_str());
g_api->Log(ELogLevel_INFO, "GolemHelper", startBuffer);
try {
g_api->GameBinds.InvokeAsync(EGameBinds_MiscInteract, 50);
int initialDelay = g_state.useCustomDelays ? g_state.stepDelay : 390;
Sleep(initialDelay);
for (int i = 0; i < 20; i++) {
if (g_coords.boonStepX[i] == 0 && g_coords.boonStepY[i] == 0) {
continue;
}
if (ShouldSkipBoonStep(i)) {
continue;
}
int delay = (i == 19) ? 50 : (g_state.useCustomDelays ? g_state.stepDelay : 290);
ClickAtScaled(g_coords.boonStepX[i], g_coords.boonStepY[i], delay);
}
}
catch (...) {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Exception during boon sequence");
}
if (uiWasVisible) {
g_state.showUI = true;
}
g_api->Log(ELogLevel_INFO, "GolemHelper", "Boon sequence completed!");
}
void ApplyGolemSettings() {
if (!g_api || !g_state.golemEnabled || !g_state.enabled) return;
bool uiWasVisible = g_state.showUI;
if (uiWasVisible) {
g_state.showUI = false;
}
const char* hitbox = g_state.hitboxType == HITBOX_SMALL ? "Small Hitbox" :
g_state.hitboxType == HITBOX_MEDIUM ? "Medium Hitbox" : "Large Hitbox";
std::string modifiers = "Normal";
if (g_state.showAdvanced && (g_state.skipSlow || g_state.skipBurning || g_state.fiveBleedingStacks)) {
modifiers = "";
if (g_state.skipSlow) modifiers += "Skip Slow ";
if (g_state.skipBurning) modifiers += "Skip Burning ";
if (g_state.fiveBleedingStacks) modifiers += "5 Bleeding ";
if (!modifiers.empty()) modifiers.pop_back();
}
char startBuffer[400];
sprintf_s(startBuffer, "Starting golem settings sequence (25 steps) - Modifiers: %s, Hitbox: %s", modifiers.c_str(), hitbox);
g_api->Log(ELogLevel_INFO, "GolemHelper", startBuffer);
try {
g_api->GameBinds.InvokeAsync(EGameBinds_MiscInteract, 50);
int initialDelay = g_state.useCustomDelays ? g_state.stepDelay : 390;
Sleep(initialDelay);
for (int i = 0; i < 25; i++) {
if (g_coords.golemStepX[i] == 0 && g_coords.golemStepY[i] == 0) {
continue;
}
if (ShouldSkipGolemStep(i)) {
continue;
}
int currentX = g_coords.golemStepX[i];
int currentY = g_coords.golemStepY[i];
if (i == 1) {
switch (g_state.hitboxType) {
case HITBOX_SMALL:
currentY = 260;
break;
case HITBOX_MEDIUM:
currentY = 305;
break;
case HITBOX_LARGE:
currentY = 352;
break;
}
}
int delay = (i == 24) ? 50 : (g_state.useCustomDelays ? g_state.stepDelay : 290);
ClickAtScaled(currentX, currentY, delay);
if (g_state.showAdvanced && g_state.fiveBleedingStacks && i == 6) {
g_api->Log(ELogLevel_INFO, "GolemHelper", "5 Bleeding Stacks - repeating 7th step 4 more times");
for (int repeat = 0; repeat < 4; repeat++) {
int repeatDelay = g_state.useCustomDelays ? g_state.stepDelay : 290;
ClickAtScaled(currentX, currentY, repeatDelay);
}
}
}
}
catch (...) {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Exception during golem settings sequence");
}
if (uiWasVisible) {
g_state.showUI = true;
}
g_api->Log(ELogLevel_INFO, "GolemHelper", "Golem settings sequence completed (25 steps)!");
}
void HandleBoonKeybind(const char* id, bool release) {
if (!release && g_state.enabled) {
ApplyAllBoons();
}
}
void HandleGolemKeybind(const char* id, bool release) {
if (!release && g_state.enabled) {
ApplyGolemSettings();
}
}
void HandleToggleKeybind(const char* id, bool release) {
if (!release) {
g_state.enabled = !g_state.enabled;
g_api->UI.SendAlert(g_state.enabled ? "GolemHelper enabled" : "GolemHelper disabled");
}
}
void HandleUIToggleKeybind(const char* id, bool release) {
if (!release) {
g_state.showUI = !g_state.showUI;
}
}
void HandleDebugKeybind(const char* id, bool release) {
if (!release) DebugMousePosition();
}
void HandleQuickDpsKeybind(const char* id, bool release) {
if (!release) {
g_state.isQuickDps = !g_state.isQuickDps;
if (g_state.isQuickDps) {
g_state.isAlacDps = false;
}
g_api->UI.SendAlert(g_state.isQuickDps ? "Quick DPS mode enabled" : "Quick DPS mode disabled");
}
}
void HandleAlacDpsKeybind(const char* id, bool release) {
if (!release) {
g_state.isAlacDps = !g_state.isAlacDps;
if (g_state.isAlacDps) {
g_state.isQuickDps = false;
}
g_api->UI.SendAlert(g_state.isAlacDps ? "Alac DPS mode enabled" : "Alac DPS mode disabled");
}
}
void Load(AddonAPI* aApi) {
g_api = aApi;
ImGui::SetCurrentContext((ImGuiContext*)g_api->ImguiContext);
ImGui::SetAllocatorFunctions((void* (*)(size_t, void*))g_api->ImguiMalloc, (void(*)(void*, void*))g_api->ImguiFree);
NexusLink = (NexusLinkData*)g_api->DataLink.Get("DL_NEXUS_LINK");
g_state.enabled = true;
LoadCustomDelaySettings();
g_api->Renderer.Register(ERenderType_Render, RenderUI);
g_api->Renderer.Register(ERenderType_OptionsRender, RenderOptions);
Keybind kb_empty = { 0, false, false, false };
g_api->InputBinds.RegisterWithStruct("GolemHelper.ApplyBoons", HandleBoonKeybind, kb_empty);
g_api->InputBinds.RegisterWithStruct("GolemHelper.ApplyGolem", HandleGolemKeybind, kb_empty);
g_api->InputBinds.RegisterWithStruct("GolemHelper.QuickDPS", HandleQuickDpsKeybind, kb_empty);
g_api->InputBinds.RegisterWithStruct("GolemHelper.AlacDPS", HandleAlacDpsKeybind, kb_empty);
g_api->InputBinds.RegisterWithStruct("GolemHelper.Toggle", HandleToggleKeybind, kb_empty);
g_api->InputBinds.RegisterWithStruct("GolemHelper.ToggleUI", HandleUIToggleKeybind, kb_empty);
g_api->InputBinds.RegisterWithStruct("GolemHelper.DebugMouse", HandleDebugKeybind, kb_empty);
/* COMMENTO IN ATTESA DI CUSTOM ICON
g_api->Textures.GetOrCreateFromFile("GOLEM_HELPER_ICON", "addons/GolemHelper/GOLEM_HELPER_ICON.png");
g_api->Textures.GetOrCreateFromFile("GOLEM_HELPER_ICON_HOVER", "addons/GolemHelper/GOLEM_HELPER_ICON_HOVER.png");
*/
g_api->QuickAccess.Add(
"GolemHelper.ToggleUI",
"GOLEM_HELPER_ICON",
"GOLEM_HELPER_ICON_HOVER",
"GolemHelper.ToggleUI",
"Toggle GolemHelper UI"
);
g_api->Log(ELogLevel_INFO, "GolemHelper", "=== GolemHelper v1.2.0.0 Loaded ===");
g_api->Log(ELogLevel_INFO, "GolemHelper", "<c=#00ff00>GolemHelper addon</c> loaded successfully!");
}
void Unload() {
if (g_api) {
g_api->QuickAccess.Remove("GolemHelper.ToggleUI");
g_api->Renderer.Deregister(RenderUI);
g_api->Renderer.Deregister(RenderOptions);
g_api->InputBinds.Deregister("GolemHelper.ApplyBoons");
g_api->InputBinds.Deregister("GolemHelper.ApplyGolem");
g_api->InputBinds.Deregister("GolemHelper.QuickDPS");
g_api->InputBinds.Deregister("GolemHelper.AlacDPS");
g_api->InputBinds.Deregister("GolemHelper.Toggle");
g_api->InputBinds.Deregister("GolemHelper.ToggleUI");
g_api->InputBinds.Deregister("GolemHelper.DebugMouse");
}
g_api->Log(ELogLevel_INFO, "GolemHelper", "<c=#ff0000>GolemHelper signing off</c>, it was an honor commander.");
g_api = nullptr;
g_state.enabled = false;
g_state.showUI = false;
}
extern "C" __declspec(dllexport) AddonDefinition* GetAddonDef() {
static AddonDefinition def;
def.Signature = -424248;
def.APIVersion = NEXUS_API_VERSION;
def.Name = "GolemHelper";
def.Version = { 1, 2, 0, 0 };
def.Author = "Azrub";
def.Description = "Automates the process of setting optimal boon and golem configurations in the training area";
def.Load = Load;
def.Unload = Unload;
def.Flags = EAddonFlags_None;
def.Provider = EUpdateProvider_GitHub;
def.UpdateLink = "https://github.com/Azrub/GolemHelper";
return &def;
}
#include <Windows.h>
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
return TRUE;

View file

@ -1,5 +0,0 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Escludere gli elementi usati raramente dalle intestazioni di Windows
// File di intestazione di Windows
#include <windows.h>

View file

@ -1,5 +0,0 @@
// pch.cpp: file di origine corrispondente all'intestazione precompilata
#include "pch.h"
// Quando si usano intestazioni precompilate, questo file è necessario per la riuscita della compilazione.

View file

@ -1,13 +0,0 @@
// pch.h: questo è un file di intestazione precompilata.
// I file elencati di seguito vengono compilati una sola volta, in modo da migliorare le prestazioni per le compilazioni successive.
// Questa impostazione influisce anche sulle prestazioni di IntelliSense, incluso il completamento codice e molte altre funzionalità di esplorazione del codice.
// I file elencati qui vengono però TUTTI ricompilati se uno di essi viene aggiornato da una compilazione all'altra.
// Non aggiungere qui file soggetti a frequenti aggiornamenti; in caso contrario si perderanno i vantaggi offerti in termini di prestazioni.
#ifndef PCH_H
#define PCH_H
// aggiungere qui le intestazioni da precompilare
#include "framework.h"
#endif //PCH_H

17
GolemHelper/resource.h Normal file
View file

@ -0,0 +1,17 @@
//{{NO_DEPENDENCIES}}
// File di inclusione generato con Microsoft Visual C++.
// Utilizzato da GolemHelper.rc
//
#define IDB_PNG1 104
#define IDB_PNG2 105
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 106
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View file

@ -1,33 +1,29 @@
# GolemHelper BETA
# GolemHelper
A Guild Wars 2 addon for [Nexus](https://github.com/RaidcoreGG/Nexus) that that automates boon application and golem configuration in the Special Forces Training Area with support for different DPS role modes.
## Description
GolemHelper eliminates the tedious manual clicking required to set up optimal training conditions. With a single keypress, you can apply all necessary boons or configure golem settings.
The addon automatically scales coordinates for different resolutions and UI sizes.
Particularly useful for players who:
- Regularly practice rotations on training golems
- Test different build configurations
- Play multiple DPS roles (Quickness DPS, Alacrity DPS, Chronomancer DT+DR)
- Want to minimize setup time and focus on actual gameplay practice
A Guild Wars 2 addon for [Nexus](https://github.com/RaidcoreGG/Nexus) that automates optimal boon and golem configurations in the Special Forces Training Area.
## Features
- Automated Boon Application: Apply boon configuration based on dps mode.
- Automated Golem Configuration: Apply SnowCrows benchmark settings on golem with one keypress.
DPS Benchmarking:
DPS Modes:
- Quick DPS Mode: Automatically skips Quickness boon
- Alac DPS Mode: Automatically skips Alacrity boon
- Chronomancer Mode: Automatically skips Slow debuff on golem
- hi dps
- Quick DPS
- Alac DPS
## Planned Features (No ETA)
Healer Support:
- ImGui Interface: Visual interface for easier mode switching and configuration (coming in v1.0.0 final)
- Additional DPS Modes: More specialized role configurations based on community feedback
- Custom Presets: User-defined boon and golem configurations
- Environment Damage with Mild/Moderate/Extreme settings
- Specialized healer boon sequences (qHeal/aHeal modes)
Golem Customization:
- Hitbox selection: Small/Medium/Large (Small is benchmark default)
- Advanced condition modifiers: Skip Slow, Skip Burning, 5 Bleeding Stacks
Tips:
- If the sequence is too fast and missing clicks, increase Custom Delays in the UI
- You can move your mouse during the sequence, just don't hover over UIs or click
## Installation