Extract shared lua.zig and add DLL-side marker permission check
Move Lua C API wrappers from main.zig's lua struct into src/lua.zig so both main.zig and markers.zig import from the same source. Remove duplicate lapi struct from markers.zig. Add DLL-side permission gating on WorldMarker/ClearWorldMarker: calls WoW's IsPartyLeader (0x4e9130) and IsRaidOfficer (0x4bb910) C functions directly. Requires party leader, raid leader, or raid assist to place or clear markers. SetMarkerDef/ClearMarkerDef remain ungated (addon validates sender before calling).
This commit is contained in:
+155
@@ -0,0 +1,155 @@
|
||||
//! WoW 1.12.1 Lua C API wrappers (all __fastcall, L in ECX)
|
||||
|
||||
const std = @import("std");
|
||||
const fc: std.builtin.CallingConvention = .{ .x86_fastcall = .{} };
|
||||
|
||||
pub const State = *anyopaque;
|
||||
|
||||
pub fn getContext() State {
|
||||
const f: *const fn () callconv(fc) State = @ptrFromInt(0x7040D0);
|
||||
return f();
|
||||
}
|
||||
|
||||
pub fn gettop(L: State) i32 {
|
||||
const f: *const fn (State) callconv(fc) i32 = @ptrFromInt(0x6F3070);
|
||||
return f(L);
|
||||
}
|
||||
|
||||
pub fn settop(L: State, index: i32) void {
|
||||
const f: *const fn (State, i32) callconv(fc) void = @ptrFromInt(0x6F3080);
|
||||
f(L, index);
|
||||
}
|
||||
|
||||
pub fn pop(L: State, n: i32) void {
|
||||
settop(L, -n - 1);
|
||||
}
|
||||
|
||||
pub fn pushvalue(L: State, index: i32) void {
|
||||
const f: *const fn (State, i32) callconv(fc) void = @ptrFromInt(0x6F3350);
|
||||
f(L, index);
|
||||
}
|
||||
|
||||
pub fn remove(L: State, index: i32) void {
|
||||
const f: *const fn (State, i32) callconv(fc) void = @ptrFromInt(0x6F30D0);
|
||||
f(L, index);
|
||||
}
|
||||
|
||||
pub fn insert(L: State, index: i32) void {
|
||||
const f: *const fn (State, i32) callconv(fc) void = @ptrFromInt(0x6F31A0);
|
||||
f(L, index);
|
||||
}
|
||||
|
||||
pub fn typeOf(L: State, index: i32) i32 {
|
||||
const f: *const fn (State, i32) callconv(fc) i32 = @ptrFromInt(0x6F3400);
|
||||
return f(L, index);
|
||||
}
|
||||
|
||||
pub fn typeName(L: State, tp: i32) [*:0]const u8 {
|
||||
const f: *const fn (State, i32) callconv(fc) [*:0]const u8 = @ptrFromInt(0x6F3480);
|
||||
return f(L, tp);
|
||||
}
|
||||
|
||||
pub fn isnumber(L: State, index: i32) bool {
|
||||
const f: *const fn (State, i32) callconv(fc) u32 = @ptrFromInt(0x6F34D0);
|
||||
return f(L, index) != 0;
|
||||
}
|
||||
|
||||
pub fn isstring(L: State, index: i32) bool {
|
||||
const f: *const fn (State, i32) callconv(fc) u32 = @ptrFromInt(0x6F3510);
|
||||
return f(L, index) != 0;
|
||||
}
|
||||
|
||||
pub fn pushnil(L: State) void {
|
||||
const f: *const fn (State) callconv(fc) void = @ptrFromInt(0x6F37F0);
|
||||
f(L);
|
||||
}
|
||||
|
||||
pub fn pushnumber(L: State, n: f64) void {
|
||||
// __thiscall: ECX=L, f64 on stack [EBP+8]/[EBP+0xc], ret 8.
|
||||
const f: *const fn (State, f64) callconv(.{ .x86_thiscall = .{} }) void = @ptrFromInt(0x6F3810);
|
||||
f(L, n);
|
||||
}
|
||||
|
||||
pub fn pushstring(L: State, s: [*:0]const u8) void {
|
||||
const f: *const fn (State, [*:0]const u8) callconv(fc) void = @ptrFromInt(0x6F3890);
|
||||
f(L, s);
|
||||
}
|
||||
|
||||
pub fn pushboolean(L: State, b: i32) void {
|
||||
const f: *const fn (State, i32) callconv(fc) void = @ptrFromInt(0x6F39F0);
|
||||
f(L, b);
|
||||
}
|
||||
|
||||
pub fn pushcclosure(L: State, func: usize, n: i32) void {
|
||||
const f: *const fn (State, usize, i32) callconv(fc) void = @ptrFromInt(0x6F3920);
|
||||
f(L, func, n);
|
||||
}
|
||||
|
||||
pub fn tonumber(L: State, index: i32) f64 {
|
||||
const f: *const fn (State, i32) callconv(fc) f64 = @ptrFromInt(0x6F3620);
|
||||
return f(L, index);
|
||||
}
|
||||
|
||||
pub fn tostring(L: State, index: i32) ?[*:0]const u8 {
|
||||
const f: *const fn (State, i32) callconv(fc) ?[*:0]const u8 = @ptrFromInt(0x6F3690);
|
||||
return f(L, index);
|
||||
}
|
||||
|
||||
pub fn toboolean(L: State, index: i32) i32 {
|
||||
const f: *const fn (State, i32) callconv(fc) i32 = @ptrFromInt(0x6F3660);
|
||||
return f(L, index);
|
||||
}
|
||||
|
||||
pub fn newtable(L: State) void {
|
||||
const f: *const fn (State) callconv(fc) void = @ptrFromInt(0x6F3C90);
|
||||
f(L);
|
||||
}
|
||||
|
||||
pub fn settable(L: State, index: i32) void {
|
||||
const f: *const fn (State, i32) callconv(fc) void = @ptrFromInt(0x6F3E20);
|
||||
f(L, index);
|
||||
}
|
||||
|
||||
pub fn gettable(L: State, index: i32) void {
|
||||
const f: *const fn (State, i32) callconv(fc) void = @ptrFromInt(0x6F3A40);
|
||||
f(L, index);
|
||||
}
|
||||
|
||||
pub fn next(L: State, index: i32) i32 {
|
||||
const f: *const fn (State, i32) callconv(fc) i32 = @ptrFromInt(0x6F4450);
|
||||
return f(L, index);
|
||||
}
|
||||
|
||||
pub fn pcall(L: State, nargs: i32, nresults: i32, errfunc: i32) i32 {
|
||||
const f: *const fn (State, i32, i32, i32) callconv(fc) i32 = @ptrFromInt(0x6F41A0);
|
||||
return f(L, nargs, nresults, errfunc);
|
||||
}
|
||||
|
||||
pub fn luaError(L: State, msg: [*:0]const u8) void {
|
||||
asm volatile (
|
||||
\\push %[msg]
|
||||
\\push %[L]
|
||||
\\call *%[func]
|
||||
\\add $8, %%esp
|
||||
:
|
||||
: [L] "r" (@intFromPtr(L)),
|
||||
[msg] "r" (@intFromPtr(msg)),
|
||||
[func] "r" (@as(u32, 0x6F4940)),
|
||||
: .{ .eax = true, .ecx = true, .edx = true, .memory = true, .cc = true }
|
||||
);
|
||||
}
|
||||
|
||||
pub const LuaReg = extern struct {
|
||||
name: ?[*:0]const u8,
|
||||
func: usize,
|
||||
};
|
||||
|
||||
pub fn openlib(L: State, libname: ?[*:0]const u8, funcs: [*]const LuaReg, nup: i32) void {
|
||||
const f: *const fn (State, ?[*:0]const u8, [*]const LuaReg, i32) callconv(fc) void = @ptrFromInt(0x6F4DC0);
|
||||
f(L, libname, funcs, nup);
|
||||
}
|
||||
|
||||
pub fn checknumber(L: State, index: i32) f64 {
|
||||
const f: *const fn (State, i32) callconv(fc) f64 = @ptrFromInt(0x6F4C80);
|
||||
return f(L, index);
|
||||
}
|
||||
+1
-152
@@ -44,158 +44,7 @@ fn luaProtectionDetour() callconv(sc) void {}
|
||||
// Lua C API wrappers (WoW 1.12.1 — all __fastcall, L in ECX)
|
||||
// =============================================================================
|
||||
|
||||
pub const lua = struct {
|
||||
pub const State = *anyopaque;
|
||||
|
||||
pub fn getContext() State {
|
||||
const f: *const fn () callconv(fc) State = @ptrFromInt(0x7040D0);
|
||||
return f();
|
||||
}
|
||||
|
||||
pub fn gettop(L: State) i32 {
|
||||
const f: *const fn (State) callconv(fc) i32 = @ptrFromInt(0x6F3070);
|
||||
return f(L);
|
||||
}
|
||||
|
||||
pub fn settop(L: State, index: i32) void {
|
||||
const f: *const fn (State, i32) callconv(fc) void = @ptrFromInt(0x6F3080);
|
||||
f(L, index);
|
||||
}
|
||||
|
||||
pub fn pop(L: State, n: i32) void {
|
||||
settop(L, -n - 1);
|
||||
}
|
||||
|
||||
pub fn pushvalue(L: State, index: i32) void {
|
||||
const f: *const fn (State, i32) callconv(fc) void = @ptrFromInt(0x6F3350);
|
||||
f(L, index);
|
||||
}
|
||||
|
||||
pub fn remove(L: State, index: i32) void {
|
||||
const f: *const fn (State, i32) callconv(fc) void = @ptrFromInt(0x6F30D0);
|
||||
f(L, index);
|
||||
}
|
||||
|
||||
pub fn insert(L: State, index: i32) void {
|
||||
const f: *const fn (State, i32) callconv(fc) void = @ptrFromInt(0x6F31A0);
|
||||
f(L, index);
|
||||
}
|
||||
|
||||
pub fn typeOf(L: State, index: i32) i32 {
|
||||
const f: *const fn (State, i32) callconv(fc) i32 = @ptrFromInt(0x6F3400);
|
||||
return f(L, index);
|
||||
}
|
||||
|
||||
pub fn typeName(L: State, tp: i32) [*:0]const u8 {
|
||||
const f: *const fn (State, i32) callconv(fc) [*:0]const u8 = @ptrFromInt(0x6F3480);
|
||||
return f(L, tp);
|
||||
}
|
||||
|
||||
pub fn isnumber(L: State, index: i32) bool {
|
||||
const f: *const fn (State, i32) callconv(fc) u32 = @ptrFromInt(0x6F34D0);
|
||||
return f(L, index) != 0;
|
||||
}
|
||||
|
||||
pub fn isstring(L: State, index: i32) bool {
|
||||
const f: *const fn (State, i32) callconv(fc) u32 = @ptrFromInt(0x6F3510);
|
||||
return f(L, index) != 0;
|
||||
}
|
||||
|
||||
pub fn pushnil(L: State) void {
|
||||
const f: *const fn (State) callconv(fc) void = @ptrFromInt(0x6F37F0);
|
||||
f(L);
|
||||
}
|
||||
|
||||
pub fn pushnumber(L: State, n: f64) void {
|
||||
// __thiscall: ECX=L, f64 on stack [EBP+8]/[EBP+0xc], ret 8.
|
||||
const f: *const fn (State, f64) callconv(.{ .x86_thiscall = .{} }) void = @ptrFromInt(0x6F3810);
|
||||
f(L, n);
|
||||
}
|
||||
|
||||
pub fn pushstring(L: State, s: [*:0]const u8) void {
|
||||
const f: *const fn (State, [*:0]const u8) callconv(fc) void = @ptrFromInt(0x6F3890);
|
||||
f(L, s);
|
||||
}
|
||||
|
||||
pub fn pushboolean(L: State, b: i32) void {
|
||||
const f: *const fn (State, i32) callconv(fc) void = @ptrFromInt(0x6F39F0);
|
||||
f(L, b);
|
||||
}
|
||||
|
||||
pub fn pushcclosure(L: State, func: usize, n: i32) void {
|
||||
const f: *const fn (State, usize, i32) callconv(fc) void = @ptrFromInt(0x6F3920);
|
||||
f(L, func, n);
|
||||
}
|
||||
|
||||
pub fn tonumber(L: State, index: i32) f64 {
|
||||
const f: *const fn (State, i32) callconv(fc) f64 = @ptrFromInt(0x6F3620);
|
||||
return f(L, index);
|
||||
}
|
||||
|
||||
pub fn tostring(L: State, index: i32) ?[*:0]const u8 {
|
||||
const f: *const fn (State, i32) callconv(fc) ?[*:0]const u8 = @ptrFromInt(0x6F3690);
|
||||
return f(L, index);
|
||||
}
|
||||
|
||||
pub fn toboolean(L: State, index: i32) i32 {
|
||||
const f: *const fn (State, i32) callconv(fc) i32 = @ptrFromInt(0x6F3660);
|
||||
return f(L, index);
|
||||
}
|
||||
|
||||
pub fn newtable(L: State) void {
|
||||
const f: *const fn (State) callconv(fc) void = @ptrFromInt(0x6F3C90);
|
||||
f(L);
|
||||
}
|
||||
|
||||
pub fn settable(L: State, index: i32) void {
|
||||
const f: *const fn (State, i32) callconv(fc) void = @ptrFromInt(0x6F3E20);
|
||||
f(L, index);
|
||||
}
|
||||
|
||||
pub fn gettable(L: State, index: i32) void {
|
||||
const f: *const fn (State, i32) callconv(fc) void = @ptrFromInt(0x6F3A40);
|
||||
f(L, index);
|
||||
}
|
||||
|
||||
pub fn next(L: State, index: i32) i32 {
|
||||
const f: *const fn (State, i32) callconv(fc) i32 = @ptrFromInt(0x6F4450);
|
||||
return f(L, index);
|
||||
}
|
||||
|
||||
pub fn pcall(L: State, nargs: i32, nresults: i32, errfunc: i32) i32 {
|
||||
const f: *const fn (State, i32, i32, i32) callconv(fc) i32 = @ptrFromInt(0x6F41A0);
|
||||
return f(L, nargs, nresults, errfunc);
|
||||
}
|
||||
|
||||
pub fn luaError(L: State, msg: [*:0]const u8) void {
|
||||
asm volatile (
|
||||
\\push %[msg]
|
||||
\\push %[L]
|
||||
\\call *%[func]
|
||||
\\add $8, %%esp
|
||||
:
|
||||
: [L] "r" (@intFromPtr(L)),
|
||||
[msg] "r" (@intFromPtr(msg)),
|
||||
[func] "r" (@as(u32, 0x6F4940)),
|
||||
: .{ .eax = true, .ecx = true, .edx = true, .memory = true, .cc = true }
|
||||
);
|
||||
}
|
||||
|
||||
pub const LuaReg = extern struct {
|
||||
name: ?[*:0]const u8,
|
||||
func: usize,
|
||||
};
|
||||
|
||||
pub fn openlib(L: State, libname: ?[*:0]const u8, funcs: [*]const LuaReg, nup: i32) void {
|
||||
const f: *const fn (State, ?[*:0]const u8, [*]const LuaReg, i32) callconv(fc) void = @ptrFromInt(0x6F4DC0);
|
||||
f(L, libname, funcs, nup);
|
||||
}
|
||||
|
||||
pub fn checknumber(L: State, index: i32) f64 {
|
||||
const f: *const fn (State, i32) callconv(fc) f64 = @ptrFromInt(0x6F4C80);
|
||||
return f(L, index);
|
||||
}
|
||||
};
|
||||
pub const lua = @import("lua.zig");
|
||||
|
||||
// =============================================================================
|
||||
// Game function wrappers
|
||||
|
||||
+79
-85
@@ -17,6 +17,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
const hook = @import("zhook");
|
||||
const lua = @import("../lua.zig");
|
||||
const o = @import("offsets.zig");
|
||||
const wow = @import("../outline/wow.zig");
|
||||
const con = @import("../console.zig");
|
||||
@@ -107,52 +108,35 @@ const DespawningEntity = struct {
|
||||
};
|
||||
var despawning: [MAX_DESPAWNING]?DespawningEntity = .{null} ** MAX_DESPAWNING;
|
||||
|
||||
// =============================================================================
|
||||
// Lua C API (WoW 1.12.1 — all __fastcall, L in ECX)
|
||||
// =============================================================================
|
||||
|
||||
const fc = std.builtin.CallingConvention{ .x86_fastcall = .{} };
|
||||
const sc = std.builtin.CallingConvention{ .x86_stdcall = .{} };
|
||||
|
||||
const lapi = struct {
|
||||
fn gettop(L: u32) i32 {
|
||||
const f: *const fn (u32) callconv(fc) i32 = @ptrFromInt(0x6F3070);
|
||||
return f(L);
|
||||
}
|
||||
// =============================================================================
|
||||
// Permission check — leader or raid officer required
|
||||
// =============================================================================
|
||||
|
||||
fn isnumber(L: u32, index: i32) bool {
|
||||
const f: *const fn (u32, i32) callconv(fc) u32 = @ptrFromInt(0x6F34D0);
|
||||
return f(L, index) != 0;
|
||||
}
|
||||
/// WoW Lua C functions: ECX=L, return count of pushed values.
|
||||
const LuaCFn = *const fn (lua.State) callconv(.c) u32;
|
||||
const FN_IS_PARTY_LEADER: LuaCFn = @ptrFromInt(0x004e9130);
|
||||
const FN_IS_RAID_OFFICER: LuaCFn = @ptrFromInt(0x004bb910);
|
||||
|
||||
fn isstring(L: u32, index: i32) bool {
|
||||
const f: *const fn (u32, i32) callconv(fc) u32 = @ptrFromInt(0x6F3510);
|
||||
return f(L, index) != 0;
|
||||
}
|
||||
/// Call a WoW Lua C function that pushes 1 value, check if it pushed
|
||||
/// a truthy value (non-nil), then pop the result.
|
||||
fn luaBoolCheck(L: lua.State, func: LuaCFn) bool {
|
||||
const before = lua.gettop(L);
|
||||
_ = func(L);
|
||||
const after = lua.gettop(L);
|
||||
if (after <= before) return false;
|
||||
const is_nil = lua.typeOf(L, -1) == 0;
|
||||
lua.settop(L, before);
|
||||
return !is_nil;
|
||||
}
|
||||
|
||||
fn tonumber(L: u32, index: i32) f64 {
|
||||
const f: *const fn (u32, i32) callconv(fc) f64 = @ptrFromInt(0x6F3620);
|
||||
return f(L, index);
|
||||
}
|
||||
|
||||
fn tostring(L: u32, index: i32) ?[*:0]const u8 {
|
||||
const f: *const fn (u32, i32) callconv(fc) ?[*:0]const u8 = @ptrFromInt(0x6F3690);
|
||||
return f(L, index);
|
||||
}
|
||||
|
||||
fn pushstring(L: u32, s: [*:0]const u8) void {
|
||||
const f: *const fn (u32, [*:0]const u8) callconv(fc) void = @ptrFromInt(0x6F3890);
|
||||
f(L, s);
|
||||
}
|
||||
|
||||
fn pushnumber(L: u32, n: f64) void {
|
||||
// Ghidra confirms: __thiscall(ECX=L), double on stack as [EBP+8]/[EBP+0xc], ret 8.
|
||||
// Can't use fastcall — our patched inreg would shove the f64's low dword into EDX.
|
||||
const tc = std.builtin.CallingConvention{ .x86_thiscall = .{} };
|
||||
const f: *const fn (u32, f64) callconv(tc) void = @ptrFromInt(0x6F3810);
|
||||
f(L, n);
|
||||
}
|
||||
};
|
||||
/// Check if the local player has permission to place/clear markers.
|
||||
/// Requires: party leader, raid leader, or raid officer (assist).
|
||||
fn canSetMarkers(L: lua.State) bool {
|
||||
return luaBoolCheck(L, FN_IS_PARTY_LEADER) or luaBoolCheck(L, FN_IS_RAID_OFFICER);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Position helpers
|
||||
@@ -414,30 +398,35 @@ fn clearAllMarkers() void {
|
||||
/// WorldMarker(1, x, y, z) — place at coordinates
|
||||
/// WorldMarker(1, "target") — place at unit's current position
|
||||
/// WorldMarker(1) — place at cursor terrain position
|
||||
pub fn luaWorldMarker(L: u32) callconv(.c) u32 {
|
||||
const nargs = lapi.gettop(L);
|
||||
pub fn luaWorldMarker(L: lua.State) callconv(.c) u32 {
|
||||
if (!canSetMarkers(L)) {
|
||||
con.print("[markers] WorldMarker: no permission (need leader/assist)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nargs < 1 or !lapi.isnumber(L, 1)) {
|
||||
const nargs = lua.gettop(L);
|
||||
|
||||
if (nargs < 1 or !lua.isnumber(L, 1)) {
|
||||
con.print("[markers] WorldMarker: expected index (1-5)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const raw_index = @as(i32, @intFromFloat(lapi.tonumber(L, 1)));
|
||||
const raw_index = @as(i32, @intFromFloat(lua.tonumber(L, 1)));
|
||||
if (raw_index < 1 or raw_index > NUM_MARKERS) {
|
||||
con.print("[markers] WorldMarker: index must be 1-5\n");
|
||||
return 0;
|
||||
}
|
||||
const index: usize = @intCast(raw_index - 1);
|
||||
|
||||
if (nargs >= 4 and lapi.isnumber(L, 2)) {
|
||||
if (nargs >= 4 and lua.isnumber(L, 2)) {
|
||||
// WorldMarker(index, x, y, z)
|
||||
const x: f32 = @floatCast(lapi.tonumber(L, 2));
|
||||
const y: f32 = @floatCast(lapi.tonumber(L, 3));
|
||||
const z: f32 = @floatCast(lapi.tonumber(L, 4));
|
||||
const x: f32 = @floatCast(lua.tonumber(L, 2));
|
||||
const y: f32 = @floatCast(lua.tonumber(L, 3));
|
||||
const z: f32 = @floatCast(lua.tonumber(L, 4));
|
||||
_ = placeMarker(index, .{ .x = x, .y = y, .z = z });
|
||||
} else if (nargs >= 2 and lapi.isstring(L, 2)) {
|
||||
} else if (nargs >= 2 and lua.isstring(L, 2)) {
|
||||
// WorldMarker(index, "unitId")
|
||||
const unit_id = lapi.tostring(L, 2) orelse {
|
||||
const unit_id = lua.tostring(L, 2) orelse {
|
||||
con.print("[markers] WorldMarker: invalid unit string\n");
|
||||
return 0;
|
||||
};
|
||||
@@ -461,20 +450,25 @@ pub fn luaWorldMarker(L: u32) callconv(.c) u32 {
|
||||
/// Lua: ClearWorldMarker([index])
|
||||
/// ClearWorldMarker(1) — remove marker 1
|
||||
/// ClearWorldMarker() — remove all markers
|
||||
pub fn luaClearWorldMarker(L: u32) callconv(.c) u32 {
|
||||
const nargs = lapi.gettop(L);
|
||||
pub fn luaClearWorldMarker(L: lua.State) callconv(.c) u32 {
|
||||
if (!canSetMarkers(L)) {
|
||||
con.print("[markers] ClearWorldMarker: no permission (need leader/assist)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const nargs = lua.gettop(L);
|
||||
|
||||
if (nargs == 0) {
|
||||
clearAllMarkers();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lapi.isnumber(L, 1)) {
|
||||
if (!lua.isnumber(L, 1)) {
|
||||
con.print("[markers] ClearWorldMarker: expected index (1-5) or no args\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const raw_index = @as(i32, @intFromFloat(lapi.tonumber(L, 1)));
|
||||
const raw_index = @as(i32, @intFromFloat(lua.tonumber(L, 1)));
|
||||
if (raw_index < 1 or raw_index > NUM_MARKERS) {
|
||||
con.print("[markers] ClearWorldMarker: index must be 1-5\n");
|
||||
return 0;
|
||||
@@ -557,25 +551,25 @@ fn tickAnimations() void {
|
||||
}
|
||||
|
||||
/// Lua: local x, y, z = GetPlayerPosition()
|
||||
pub fn luaGetPlayerPosition(L: u32) callconv(.c) u32 {
|
||||
pub fn luaGetPlayerPosition(L: lua.State) callconv(.c) u32 {
|
||||
const player = wow.getLocalPlayer();
|
||||
if (player == 0) return 0;
|
||||
|
||||
const pos = getUnitPosition(player);
|
||||
lapi.pushnumber(L, @floatCast(pos.x));
|
||||
lapi.pushnumber(L, @floatCast(pos.y));
|
||||
lapi.pushnumber(L, @floatCast(pos.z));
|
||||
lua.pushnumber(L, @floatCast(pos.x));
|
||||
lua.pushnumber(L, @floatCast(pos.y));
|
||||
lua.pushnumber(L, @floatCast(pos.z));
|
||||
return 3;
|
||||
}
|
||||
|
||||
/// Lua: local dist = DistanceToMark(index)
|
||||
/// Returns distance in yards from player to the stored marker position,
|
||||
/// or nil if the marker doesn't exist or there's no player.
|
||||
pub fn luaDistanceToMark(L: u32) callconv(.c) u32 {
|
||||
const nargs = lapi.gettop(L);
|
||||
if (nargs < 1 or !lapi.isnumber(L, 1)) return 0;
|
||||
pub fn luaDistanceToMark(L: lua.State) callconv(.c) u32 {
|
||||
const nargs = lua.gettop(L);
|
||||
if (nargs < 1 or !lua.isnumber(L, 1)) return 0;
|
||||
|
||||
const raw_index = @as(i32, @intFromFloat(lapi.tonumber(L, 1)));
|
||||
const raw_index = @as(i32, @intFromFloat(lua.tonumber(L, 1)));
|
||||
if (raw_index < 1 or raw_index > NUM_MARKERS) return 0;
|
||||
const index: usize = @intCast(raw_index - 1);
|
||||
|
||||
@@ -592,26 +586,26 @@ pub fn luaDistanceToMark(L: u32) callconv(.c) u32 {
|
||||
const dz = player_pos.z - mark_pos.z;
|
||||
const dist = @sqrt(dx * dx + dy * dy + dz * dz);
|
||||
|
||||
lapi.pushnumber(L, @floatCast(dist));
|
||||
lua.pushnumber(L, @floatCast(dist));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// Lua: SetMarkerDef(index, x, y, z, areaId)
|
||||
/// Store a marker definition without immediately spawning. Used by the addon
|
||||
/// when receiving remote marker data — proximity respawn handles entity creation.
|
||||
pub fn luaSetMarkerDef(L: u32) callconv(.c) u32 {
|
||||
const nargs = lapi.gettop(L);
|
||||
pub fn luaSetMarkerDef(L: lua.State) callconv(.c) u32 {
|
||||
const nargs = lua.gettop(L);
|
||||
if (nargs < 5) return 0;
|
||||
if (!lapi.isnumber(L, 1) or !lapi.isnumber(L, 2) or !lapi.isnumber(L, 3) or !lapi.isnumber(L, 4) or !lapi.isnumber(L, 5)) return 0;
|
||||
if (!lua.isnumber(L, 1) or !lua.isnumber(L, 2) or !lua.isnumber(L, 3) or !lua.isnumber(L, 4) or !lua.isnumber(L, 5)) return 0;
|
||||
|
||||
const raw_index = @as(i32, @intFromFloat(lapi.tonumber(L, 1)));
|
||||
const raw_index = @as(i32, @intFromFloat(lua.tonumber(L, 1)));
|
||||
if (raw_index < 1 or raw_index > NUM_MARKERS) return 0;
|
||||
const index: usize = @intCast(raw_index - 1);
|
||||
|
||||
const x: f32 = @floatCast(lapi.tonumber(L, 2));
|
||||
const y: f32 = @floatCast(lapi.tonumber(L, 3));
|
||||
const z: f32 = @floatCast(lapi.tonumber(L, 4));
|
||||
const area_id: u32 = @intFromFloat(lapi.tonumber(L, 5));
|
||||
const x: f32 = @floatCast(lua.tonumber(L, 2));
|
||||
const y: f32 = @floatCast(lua.tonumber(L, 3));
|
||||
const z: f32 = @floatCast(lua.tonumber(L, 4));
|
||||
const area_id: u32 = @intFromFloat(lua.tonumber(L, 5));
|
||||
|
||||
// Clear existing entity if any (will be respawned by proximity check)
|
||||
clearEntity(index);
|
||||
@@ -628,15 +622,15 @@ pub fn luaSetMarkerDef(L: u32) callconv(.c) u32 {
|
||||
|
||||
/// Lua: ClearMarkerDef([index])
|
||||
/// Clear a definition (and its entity if alive). No args = clear all.
|
||||
pub fn luaClearMarkerDef(L: u32) callconv(.c) u32 {
|
||||
const nargs = lapi.gettop(L);
|
||||
pub fn luaClearMarkerDef(L: lua.State) callconv(.c) u32 {
|
||||
const nargs = lua.gettop(L);
|
||||
if (nargs == 0) {
|
||||
clearAllMarkers();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lapi.isnumber(L, 1)) return 0;
|
||||
const raw_index = @as(i32, @intFromFloat(lapi.tonumber(L, 1)));
|
||||
if (!lua.isnumber(L, 1)) return 0;
|
||||
const raw_index = @as(i32, @intFromFloat(lua.tonumber(L, 1)));
|
||||
if (raw_index < 1 or raw_index > NUM_MARKERS) return 0;
|
||||
|
||||
clearMarker(@intCast(raw_index - 1));
|
||||
@@ -645,28 +639,28 @@ pub fn luaClearMarkerDef(L: u32) callconv(.c) u32 {
|
||||
|
||||
/// Lua: local x, y, z, areaId = GetMarkerDef(index)
|
||||
/// Returns position and area ID for an active marker def, or nil if inactive.
|
||||
pub fn luaGetMarkerDef(L: u32) callconv(.c) u32 {
|
||||
const nargs = lapi.gettop(L);
|
||||
if (nargs < 1 or !lapi.isnumber(L, 1)) return 0;
|
||||
pub fn luaGetMarkerDef(L: lua.State) callconv(.c) u32 {
|
||||
const nargs = lua.gettop(L);
|
||||
if (nargs < 1 or !lua.isnumber(L, 1)) return 0;
|
||||
|
||||
const raw_index = @as(i32, @intFromFloat(lapi.tonumber(L, 1)));
|
||||
const raw_index = @as(i32, @intFromFloat(lua.tonumber(L, 1)));
|
||||
if (raw_index < 1 or raw_index > NUM_MARKERS) return 0;
|
||||
const index: usize = @intCast(raw_index - 1);
|
||||
|
||||
if (!marker_defs[index].active) return 0;
|
||||
|
||||
lapi.pushnumber(L, @floatCast(marker_defs[index].pos.x));
|
||||
lapi.pushnumber(L, @floatCast(marker_defs[index].pos.y));
|
||||
lapi.pushnumber(L, @floatCast(marker_defs[index].pos.z));
|
||||
lapi.pushnumber(L, @floatCast(@as(f64, @floatFromInt(marker_defs[index].area_id))));
|
||||
lua.pushnumber(L, @floatCast(marker_defs[index].pos.x));
|
||||
lua.pushnumber(L, @floatCast(marker_defs[index].pos.y));
|
||||
lua.pushnumber(L, @floatCast(marker_defs[index].pos.z));
|
||||
lua.pushnumber(L, @floatCast(@as(f64, @floatFromInt(marker_defs[index].area_id))));
|
||||
return 4;
|
||||
}
|
||||
|
||||
/// Lua: local areaId = GetCurrentAreaId()
|
||||
/// Returns the current zone area ID from the game global.
|
||||
pub fn luaGetCurrentAreaId(L: u32) callconv(.c) u32 {
|
||||
pub fn luaGetCurrentAreaId(L: lua.State) callconv(.c) u32 {
|
||||
const area_id = hook.readMem(u32, o.ZONE_AREA_ID);
|
||||
lapi.pushnumber(L, @floatCast(@as(f64, @floatFromInt(area_id))));
|
||||
lua.pushnumber(L, @floatCast(@as(f64, @floatFromInt(area_id))));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user