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>
This commit is contained in:
1 parent
f721d2a486
commit
1fd89524d3
41 files changed
+2347
-214
No files matched your search
+15
-40
@@ -22,34 +22,16 @@
|
||||
|
||||
#include "game/engine/events.h"
|
||||
#include "game/engine/objects.h"
|
||||
#include "game/engine/orders.h"
|
||||
#include "mods/input.h"
|
||||
#include "re/hook.h"
|
||||
|
||||
namespace mods::wasd {
|
||||
namespace {
|
||||
|
||||
// --- sacred.exe ---------------------------------------------------------------
|
||||
constexpr uint32_t kEventCreatureVtable = 0x0088e95c;
|
||||
|
||||
using SendOrderFn = void(__fastcall*)(void* engine, void* edx, void* creature, void* event);
|
||||
const auto SendOrder = reinterpret_cast<SendOrderFn>(0x006170d0); // adjusts ground targets, then vf18
|
||||
|
||||
// cEngine fields.
|
||||
constexpr size_t kEngineFlags = 0x54; // 0x10 mouse button held (hold-to-move), 0x4000 input blocked
|
||||
constexpr size_t kEngineControlledId = 0x13c; // object id of the controlled creature
|
||||
|
||||
// cEvent_creature, command 4 = walk.
|
||||
struct CreatureEvent {
|
||||
uint32_t vtable;
|
||||
uint32_t command;
|
||||
uint32_t unknown08[3];
|
||||
uint32_t groundTarget; // 2: x, y are a point on the ground
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
uint32_t held; // 1: re-aim while a mouse button is held (cEngine::Tick)
|
||||
uint32_t unknown24[8];
|
||||
};
|
||||
static_assert(sizeof(CreatureEvent) == 0x44);
|
||||
using game::ControlledCreature;
|
||||
using game::CreatureOrder;
|
||||
using game::kEngineFlags;
|
||||
|
||||
// Walk orders aim this far (world units) from the creature, about where the
|
||||
// cursor would be.
|
||||
@@ -59,27 +41,21 @@ bool KeyDown(int key) {
|
||||
return (GetAsyncKeyState(key) & 0x8000) != 0;
|
||||
}
|
||||
|
||||
void* ControlledCreature(uint8_t* engine) {
|
||||
return game::GetCreature(*reinterpret_cast<uint32_t*>(engine + kEngineControlledId));
|
||||
}
|
||||
|
||||
void SendWalk(uint8_t* engine, void* creature, int x, int y) {
|
||||
CreatureEvent event = {};
|
||||
event.vtable = kEventCreatureVtable;
|
||||
event.command = 4;
|
||||
event.groundTarget = 2;
|
||||
event.x = x;
|
||||
event.y = y;
|
||||
SendOrder(engine, nullptr, creature, &event);
|
||||
CreatureOrder order;
|
||||
order.command = game::kOrderWalk;
|
||||
order.groundTarget = 2;
|
||||
order.a = x;
|
||||
order.b = y;
|
||||
game::SendCreatureOrder(engine, creature, order);
|
||||
}
|
||||
|
||||
// A walk order without a target stops the creature where it is (what
|
||||
// releasing a held mouse button sends, cEngine::HandleMouseButton).
|
||||
void SendStop(uint8_t* engine, void* creature) {
|
||||
CreatureEvent event = {};
|
||||
event.vtable = kEventCreatureVtable;
|
||||
event.command = 4;
|
||||
SendOrder(engine, nullptr, creature, &event);
|
||||
CreatureOrder order;
|
||||
order.command = game::kOrderWalk;
|
||||
game::SendCreatureOrder(engine, creature, order);
|
||||
}
|
||||
|
||||
struct MoveState {
|
||||
@@ -119,10 +95,9 @@ void Update(uint8_t* engine) {
|
||||
if (!creature) {
|
||||
return;
|
||||
}
|
||||
const auto* c = static_cast<const uint8_t*>(creature);
|
||||
const double length = std::sqrt(static_cast<double>(dx * dx + dy * dy));
|
||||
const int x = *reinterpret_cast<const int32_t*>(c + 0x1c) + static_cast<int>(dx / length * kTargetDistance);
|
||||
const int y = *reinterpret_cast<const int32_t*>(c + 0x20) + static_cast<int>(dy / length * kTargetDistance);
|
||||
const int x = game::CreatureField(creature, game::kCreatureX) + static_cast<int>(dx / length * kTargetDistance);
|
||||
const int y = game::CreatureField(creature, game::kCreatureY) + static_cast<int>(dy / length * kTargetDistance);
|
||||
SendWalk(engine, creature, x, y);
|
||||
g_move.moving = true;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user