Skip to content

Lua API Reference

Complete reference for all functions available in Wand Lua scripts.


Player

get_player()

Returns the local player's current state.

local p = get_player()
log_info("Level " .. p.level .. " at (" .. p.x .. ", " .. p.y .. ")")

Fields:

Field Type Description
x, y int Map position
vx, vy float Velocity
hp, mp int Current HP/MP
maxHp, maxMp int Max HP/MP
exp int Current EXP
expPer float EXP percentage (0-100)
mesos int Mesos
level int Character level
job int Job ID
attackCount int Combo attack count
breath int Swim breath
animation int Current animation state
comboCount int Combo counter
faceDir int Facing direction
uid int Character unique ID
channel int Current channel
total_channel int Total channels
isOnRope bool On a ladder/rope
isInAir bool In the air (jumping/falling)
isFaceDown bool Facing downward

Nested — p.basic:

Field Type
str, dex, int, luk int

Nested — p.secondary:

Field Type
attack, defense int
magic, magicDef int
accuracy, avoid int
hands, speed, jump int

Mobs, NPCs & Players

get_mobs()

Returns all mobs on the current map.

local mobs = get_mobs()
for _, mob in ipairs(mobs) do
    log_info(mob.name .. " HP:" .. mob.HPP .. "% at (" .. mob.x .. "," .. mob.y .. ")")
end
Field Type Description
id int Mob template ID
x, y int Position
name string Mob name
HPP int Current HP
maxHP int Maximum HP
platform int Platform ID the mob is on

get_npcs()

Returns all NPCs on the current map.

Field Type Description
id int NPC ID
x, y int Position
xp, yp int Previous position
name string NPC name

get_other_players()

Returns other players visible on the map.

Field Type Description
id int Character ID
job int Job ID
x, y int Position
name string Player name
jobName string Job name string
party bool Is in your party

get_pets()

Returns your active pets.

Field Type Description
id int Pet slot index (0/1/2)
name string Pet name
fullness int Fullness (0-100)

Drops & Items

get_drops()

Returns all items/mesos on the ground.

local drops = get_drops()
for _, d in ipairs(drops) do
    if d.isMeso then
        log_info("Meso drop at (" .. d.x .. "," .. d.y .. ")")
    else
        log_info(d.name .. " at (" .. d.x .. "," .. d.y .. ")")
    end
end
Field Type Description
uid int Unique drop ID
ownerId int Owner character ID
sourceId int Source mob/NPC ID
ownType int Ownership type
isMeso bool True if meso drop
id int Item ID (or meso amount)
x, y int Position
name string Item name
type int Item type

get_item_count(itemId)

Returns the total count of an item across all inventory tabs.

local potions = get_item_count(2000000)  -- white potion
log_info("Potions: " .. potions)

get_item_slot(itemId)

Returns the first inventory slot containing the item. Returns 0 if not found.

get_item_key(itemId)

Returns the virtual key code mapped to the item. Returns 0 if no key is mapped.

use_item(itemId)

Uses a consumable item from the Use tab (IDs starting with 2xxxxxx). Returns true on success.


Inventory

get_inventory()

Returns all 5 inventory tabs.

local inv = get_inventory()
for _, item in ipairs(inv.use.items) do
    log_info("Slot " .. item.slot .. ": " .. item.name .. " x" .. item.quantity)
end

Tab fields: equip, use, setup, etc, cash

Each tab has:

Field Type Description
type int Tab type (1-5)
typeName string Tab name
items array Items in this tab
slotCount int Total slots

get_inventory_tab(tabType)

Returns a single tab. tabType: 1=Equip, 2=Use, 3=Setup, 4=Etc, 5=Cash.

Item Fields

Field Type Description
id int Item ID
quantity int Stack count
slot int Slot number
type int Item type
name string Item name
desc string Item description
stats EquipStats Equipment stats (equip tab only)

EquipStats Fields

Field Type
str, dex, int, luk int
maxHp, maxMp int
attack, magic int
defense, magicDef int
accuracy, avoid int
hands, speed, jump int
slots int

Map Data

get_physical_space()

Returns the geometry of the current map.

local map = get_physical_space()
log_info("Map: " .. map.mapName .. " (" .. map.mapId .. ")")
log_info("Bounds: " .. map.left .. "," .. map.top .. " to " .. map.right .. "," .. map.bottom)

Fields:

Field Type Description
mapId int Map ID
streetName string Area name
mapName string Map name
left, right, top, bottom int Map boundaries
footholds array Walkable segments
ropes array Ladders and ropes
portals array Map portals
platforms array Platform groups

Foothold: x1, y1, x2, y2, id, prev, next, layer, platform

Rope: id, isLadder, fromUpper, x, y1, y2, platform

Portal: x, y, id, type, toMapId, name, toName

Platform: id, leftX, rightX, centerX, size, isRope


Buffs & Status

get_buffs()

Returns active buffs.

Field Type Description
type int Buff type
id int Buff/skill ID
subId int Sub-identifier
tLeft int Time remaining (ms)
vKey int Virtual key

get_debuffs()

Returns a string describing current debuffs.


Input & Keyboard

Key Press Functions

press_key(0x25)       -- hold left arrow
sleep(500)
release_key(0x25)     -- release left arrow

hit_key(0x51)         -- quick tap Q key (20ms press)

send_key(0x51, 3)     -- send Q key 3 times
Function Description
press_key(vk) Hold a key down
release_key(vk) Release a held key
hit_key(vk) Simulates a real key press and release (~20ms hold)
send_key(vk, repeat) Sends a key message event. repeat defaults to 1
stop_move() Release all movement keys

hit_key vs send_key

hit_key simulates a physical key press — it calls press_key then release_key with a short delay. This is how a real keyboard input works and is required for arrow keys and movement. Use press_key/release_key/hit_key for movement controls.

send_key sends a window message event directly. It works well for most skill and item keys, but because it doesn't simulate a real press-release cycle, some skills may behave differently — for example, a skill that has a charge/hold mechanic may trigger a prolonged hold when using send_key.

If a key isn't responding as expected, try switching between the two.

Mouse Functions

Function Returns Description
click(x, y) bool Click at screen coordinates
double_click(x, y) bool Double-click at screen coordinates

Common Virtual Key Codes

Key Code Key Code
Left Arrow 0x25 A 0x41
Up Arrow 0x26 Z 0x5A
Right Arrow 0x27 0-9 0x30-0x39
Down Arrow 0x28 F1-F12 0x70-0x7B
Space 0x20 Ctrl 0x11
Enter 0x0D Shift 0x10
Escape 0x1B Alt 0x12
Insert 0x2D Delete 0x2E

Arrow Key States

local left, up, right, down = get_arrow_key_states()
if left then log_info("Moving left") end

Skills & Key Mapping

get_skill_key(skillId)

Returns the virtual key mapped to a skill. Returns 0 if unmapped.

local key = get_skill_key(2001002)  -- Magic Guard
if key ~= 0 then hit_key(key) end

get_virtual_key(type, data)

General key lookup. Types: 1 = skill, 2 = item, 4, 5, 6 = UI and other functional actions.

Tip

Run dump_key_map() in an empty script to print the full key map to the log. This shows every bound key with its type and data values — useful for finding the right parameters.

get_item_key(itemId)

Shortcut for get_virtual_key(2, itemId).

set_key_mapping(vk, type, data)

Remap a key binding. Automatically closes any open dialogs first.

dump_key_map()

Prints all key mappings to the log, including the type and data for each bound key.


Movement & Pathfinding

move_to(x, y) / move_to(mob) / move_to(drop) / move_to(portal)

Compute a path and move there. When possible, pass the object directly (mob, drop, or portal) rather than raw coordinates — this allows Wand to apply object-specific handling during movement. Use move_to(x, y) only when you need to move to a fixed location.

-- Move to coordinates
move_to(100, -200)

-- Move to nearest mob
local mobs = get_mobs()
if #mobs > 0 then move_to(mobs[1]) end

-- Move to a drop
local drops = get_drops()
if #drops > 0 then move_to(drops[1]) end

Returns true if movement completed successfully.

find_path(x, y)

Compute a path without moving. Returns a PathReturn enum.

local result = find_path(500, -100)
if result == PathReturn.Found then
    move_to(500, -100)
end
Value Meaning
PathReturn.Found Path exists
PathReturn.NotFound No route available
PathReturn.Float Character is airborne
PathReturn.NoTarget Invalid target position
PathReturn.Error Internal error

get_travel_portal(toMapId)

For inter-map travel. Returns the status and portal to take for the next step toward toMapId.

local status, portal = get_travel_portal(100000000)  -- Henesys
if portal then
    move_to(portal)
    sleep(500)
end

Chat & Dialog

send_chat(type, message, target)

Send an in-game chat message.

send_chat("all", "Hello world!")
send_chat("party", "Need heal!")
send_chat("whisper", "Hey there", "PlayerName")
Type Description
"all" Normal chat
"party" Party chat
"guild" Guild chat
"alliance" Alliance chat
"spouse" Spouse chat
"whisper" Whisper (requires target)

get_chatlog()

Returns recent chat messages.

Field Type Description
index int Message index
type int Message type
content string Message text

get_dialog_text()

Returns NPC dialog options when a dialog is open.

Field Type Description
type int Entry type
select int Selection index
text string Option text

do_dialog_selection(selection)

Click a dialog option by index. Returns true on success.


Shopping

open_shop()

Open the NPC shop dialog (must be near a shop NPC). Returns true on success.

buy_item(itemId, quantity)

Buy an item from the currently open shop.

open_shop()
sleep(500)
buy_item(2000000, 100)  -- buy 100 white potions

sell_item(tab, index)

Sell a single item. tab: 1-5, index: slot number.

sell_all_item(tab, excludeIds)

Sell all items in a tab except those in the exclude list.

sell_all_item(4, {4000000, 4000001})  -- sell all Etc except these two

Networking

send_packet(hexString)

Send a raw packet to the server. The hex string represents the packet bytes.

send_packet("1A 00 FF 00")

Warning

Sending invalid packets can disconnect you or trigger server-side detection. Use with caution.

recv_packet(hexString)

Inject a fake server packet into the client. The client will process it as if it came from the server.

-- Example: inject a Ping packet (opcode 0x11)
recv_packet("11 00")
Return Description
bool true if the packet was queued successfully

Warning

The client will handle this packet as a real server message. Injecting malformed packets may crash the client.

change_channel(channel)

Change to a specific channel number.

change_channel(3)  -- switch to channel 3
sleep(5000)        -- wait for channel change

Stats & Skills

add_ap(stat)

Click the AP (Ability Point) button for a stat.

add_ap("str")   -- add 1 AP to STR
add_ap("luk")   -- add 1 AP to LUK

Valid stats: "hp", "mp", "str", "dex", "int", "luk"

add_sp(skillId)

Click the SP (Skill Point) button for a skill.

add_sp(2001002)  -- add 1 SP to Magic Guard

Alerts & Audio

play_alert() / play_alert(message)

Play an alert sound. If a message is provided and the Discord bot is connected, also sends a red alert embed to Discord.

play_alert()                -- sound only
play_alert("Low HP!")       -- sound + Discord alert

play_notify() / play_notify(message)

Play a notification sound. If a message is provided and the Discord bot is connected, also sends a blue notification embed to Discord.

play_notify()                    -- sound only
play_notify("Script finished")   -- sound + Discord notification

Image Matching

find_image(path)

Search for a template image inside the game window. Returns the center coordinates of the best match, or nil if no match is found within the configured threshold.

local result = find_image("potion.bmp")
if result then
    log_info("Found at (" .. result.x .. ", " .. result.y .. ") confidence: " .. result.confidence)
    click(result.x, result.y)
end

Returns: table or nil

Field Type Description
x int Center X of the matched region (game window client coordinates)
y int Center Y of the matched region (game window client coordinates)
confidence float Match quality — 0.0 = perfect match, higher = worse

Preparing a template:

  1. Take a screenshot using the game's built-in screenshot function
  2. Open the screenshot and crop the section you want to locate (e.g., an item icon, a UI element)
  3. Save as 24-bit BMP — this is the only supported format

The path can be absolute or relative to the exe folder.

Tip

The match threshold is configurable in the Settings tab under Image Matching. Default is 5. Lower values require a closer pixel match; higher values are more lenient but may cause false positives.


UI Windows

get_fade_wnd_types()

Returns a table of type IDs for all active CUIFadeYesNo windows (pop-up notifications). Returns an empty table if none are active.

local types = get_fade_wnd_types()
for i, t in ipairs(types) do
    log_info("Fade window " .. i .. " type: " .. t)
end

Type values:

Type Description
0 An invitation
1 Buddy request
2 Trade request
3 Cash Trade invite
4 (image only)
5 Party invite
6 Guild Alliance invite
7 New Quest / Quest Complete / Got a title
8 Guild invite
9 Buddy logged in / Same channel
10 Quick Delivery package
11 Party Quest
12 Family invitation
13 New Year Card arrived

Memory Read/Write

Direct memory access to the game process. Read functions return nil on failure. Write functions return true/false.

rpm_int(address)

Read a 4-byte signed integer.

local val = rpm_int(0x00BE7918)
if val then log_info("Value: " .. val) end

rpm_short(address)

Read a 2-byte signed short.

rpm_byte(address)

Read a 1-byte unsigned value (returned as integer 0–255).

rpm_float(address)

Read a 4-byte float.

wpm_int(address, value)

Write a 4-byte signed integer. Returns true on success.

if wpm_int(addr, 100) then log_info("Written") end

wpm_short(address, value)

Write a 2-byte short.

wpm_byte(address, value)

Write a 1-byte value.

wpm_float(address, value)

Write a 4-byte float.

Example: Reading drops with rpm

This example shows how to traverse the CDropPool ZList using raw memory reads — the same thing get_drops() does internally.

-- Drop pool offsets
local CDropPool_ptr   = 0x00BED6AC  -- pointer to CDropPool singleton
local CDropPoolList   = 0x2C        -- ZList head offset on CDropPool
local OFF_ID          = 0x34        -- item ID (or meso amount)
local OFF_Gr2DLayer   = 0x38        -- pointer to IWzGr2DLayer
local OFF_X           = 0x5C        -- x on Gr2DLayer
local OFF_Y           = 0x60        -- y on Gr2DLayer

-- ZList node layout:
--   node + 4        = object pointer
--   node - 16 + 4   = next link pointer (add +16 for next node)

function read_drops()
    local drops = {}

    local pool = rpm_int(CDropPool_ptr)
    if not pool or pool == 0 then return drops end

    local pos = rpm_int(pool + CDropPoolList)
    if not pos or pos == 0 then return drops end

    for i = 1, 500 do  -- safety limit
        if not pos or pos == 0 then break end

        local dropAddr = rpm_int(pos + 4)
        if dropAddr and dropAddr ~= 0 then
            local id = rpm_int(dropAddr + OFF_ID)
            local gr = rpm_int(dropAddr + OFF_Gr2DLayer)
            local x, y
            if gr and gr ~= 0 then
                x = rpm_int(gr + OFF_X)
                y = rpm_int(gr + OFF_Y)
            end
            if id then
                table.insert(drops, { id = id, x = x or 0, y = y or 0 })
            end
        end

        -- advance to next ZList node
        local link = rpm_int(pos - 16 + 4)
        if not link or link == 0 then break end
        pos = link + 16
    end

    return drops
end

-- Usage:
local drops = read_drops()
for _, d in ipairs(drops) do
    log_info(string.format("Drop id=%d at (%d, %d)", d.id, d.x, d.y))
end

Utility

sleep(ms)

Pause script execution for the given number of milliseconds. Supports early cancellation — if the script is stopped while sleeping, it will exit promptly.

sleep(1000)  -- wait 1 second

is_input_allowed()

Returns false if player controls are blocked by other UIs (e.g. input box active, dialog UIs).

reset_focus()

Force the game focus on the main window so player controls are not blocked.

revive_dead()

Check if player is dead, and revive the dead player. Returns true on success.