Files
sacred_k/src/mods/skillkeys.cpp
T
khallaandClaude Opus 5.5 1fd89524d3 Skills, auto-attack, aura and chain lightning rework, Esc, cache fix
- Skill bar: no art selection; slot 0 is the right-click art, keys 0-6 cast
  slots directly; cooldown labels in exact seconds; slot 0 set apart.
- Arts regenerate on their own (casting no longer refills the group).
- Auto-attack after targeting or casting at a hostile creature, at the speed
  of a held button.
- Auras can be recast while active (renew, no second visual).
- Blicke wie Klingen hits every enemy in range, physical, with life leech.
- Blitzschlag steers the game's own chain: 3 + level/5 hits, 1 + level/10
  chains, re-hits a lone enemy.
- Weapon sets: click selects, drag only from the selected set; the leftmost
  set is clickable (signed hit tests).
- Esc closes open windows before opening the game menu.
- HUD: standalone buttons and texts are centred.
- Record cache sized for widened views (town lag while walking).
- Shared game code: orders, fx events, text drawing, cooldowns, effects.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-16 00:11:38 +02:00

89 lines
2.5 KiB
C++

// Skill keys cast their combat-art slot.
//
// The game casts one art with the right mouse button: the one in the
// "selected" art slot, which is always slot 0 now (src/mods/skillbar.cpp).
// Slot 0's key presses the right mouse button; the keys of slots 1-6 first
// make their slot the selected one. The button is pressed by posting
// WM_RBUTTONDOWN to the game window, so the game handles it exactly like a
// real right-click at the cursor (UI hit tests, target under the cursor,
// cEvent_creature 0x105), and released with the key: holding the key is
// holding the button. While no skill key is held, slot 0 is selected again
// (checked every engine tick, which also covers saves loaded with another
// selection).
#include "mods/skillkeys.h"
#include <atomic>
#include <windows.h>
#include "game/engine/events.h"
#include "mods/skillbar.h"
namespace mods::skillkeys {
namespace {
// The game window, if it has the focus (it does while a skill key is used).
HWND GameWindow() {
HWND window = GetForegroundWindow();
DWORD process = 0;
if (!window || !GetWindowThreadProcessId(window, &process) || process != GetCurrentProcessId()) {
return nullptr;
}
return window;
}
LPARAM CursorClientPos(HWND window) {
POINT cursor = {};
GetCursorPos(&cursor);
ScreenToClient(window, &cursor);
return MAKELPARAM(cursor.x, cursor.y);
}
// The key holding the right mouse button down, and the window it was pressed
// in. Set on the window thread, read by the engine tick.
std::atomic<int> g_heldKey{0};
HWND g_window = nullptr;
void OnTick(uint8_t*) {
if (!g_heldKey.load() && mods::skillbar::SelectedSkillSlot() != 0) {
mods::skillbar::SelectSkillSlot(0);
}
}
struct Registration {
Registration() { game::OnEngineTick(&OnTick); }
} g_registration;
} // namespace
void KeyPressed(unsigned slot, int vk) {
if (g_heldKey.load() || !mods::skillbar::SkillSlotHasArt(slot)) {
return;
}
HWND window = GameWindow();
if (!window) {
return;
}
g_window = window;
g_heldKey = vk; // before selecting: the tick leaves the selection alone
if (slot != 0) {
mods::skillbar::SelectSkillSlot(slot);
}
PostMessageW(window, WM_RBUTTONDOWN, MK_RBUTTON, CursorClientPos(window));
}
bool KeyHeld() {
return g_heldKey.load() != 0;
}
void KeyReleased(int vk) {
if (g_heldKey.load() != vk) {
return;
}
PostMessageW(g_window, WM_RBUTTONUP, 0, CursorClientPos(g_window));
g_heldKey = 0;
}
} // namespace mods::skillkeys