Link Skills
On this page
The core.link_skills module lets scripts inspect the character's three Link Skill presets, assign or unassign one skill on the active preset, and activate another preset.
Return conventions
Read functions return their value directly. When Link Skills are unavailable or an argument is invalid, they return nil, error_message.
local preset, err = core.link_skills.get_active_preset()
if preset == nil then
core.log("Unable to read Link Skills: " .. err)
return
endActions return true when the request is sent, or false, error_message when it cannot be sent safely.
local ok, err = core.link_skills.assign(
core.link_skills.skills.WILD_RAGE
)
if not ok then
core.log("Unable to assign Link Skill: " .. err)
endAssigning, unassigning, and activating a preset are real actions. A true result means the client sent the request, not that the server accepted it. Send one mutation at a time and confirm it by reading the state on a later on_tick; an immediate read may still show the previous state.
The server can reject a skill the account does not own or a change disallowed by the current game state.
Presets and slots
Preset indices use the game's zero-based values:
| Lua preset | In-game label |
|---|---|
0 | Preset 1 |
1 | Preset 2 |
2 | Preset 3 |
Use preset + 1 when displaying an in-game preset number. Each preset holds at most 12 skills. Arrays returned by get_assigned() are ordinary sequential Lua arrays, so their slot indices begin at 1.
Skill constants
The canonical assignable IDs are available as a convenience catalog under core.link_skills.skills. Prefer these constants over numeric literals. The table is not an enforced whitelist: assign() and unassign() accept any positive signed 32-bit ID, while the server remains authoritative about whether an ID is a valid, owned Link Skill.
| Constant | Skill ID | Display name |
|---|---|---|
FURY_UNLEASHED | 80000001 | Fury Unleashed |
PHANTOM_INSTINCT | 80000002 | Phantom Instinct |
MOONLIT_BLADE_LEARNINGS | 80000003 | Moonlit Blade Learnings |
ELEMENTALISM | 80000004 | Elementalism |
LIGHT_WASH | 80000005 | Light Wash |
IRON_WILL | 80000006 | Iron Will |
HYBRID_LOGIC | 80000047 | Hybrid Logic |
WILD_RAGE | 80000050 | Wild Rage |
CYGNUS_BLESSING | 80000055 | Cygnus Blessing |
RHINNES_BLESSING | 80000110 | Rhinne's Blessing |
CLOSE_CALL | 80000169 | Close Call |
JUDGMENT | 80000188 | Judgment |
UNFAIR_ADVANTAGE | 80000261 | Unfair Advantage |
TIDE_OF_BATTLE | 80000268 | Tide of Battle |
SPIRIT_OF_FREEDOM | 80000329 | Spirit of Freedom |
RUNE_PERSISTENCE | 80000369 | Rune Persistence |
COMBO_KILL_BLESSING | 80000370 | Combo Kill Blessing |
SOLUS | 80000514 | Solus |
BRAVADO | 80000609 | Bravado |
ELVEN_BLESSING | 80001040 | Elven Blessing |
KNIGHTS_WATCH | 80001140 | Knight's Watch |
TERMS_AND_CONDITIONS | 80001155 | Terms and Conditions |
INVINCIBLE_BELIEF | 80002758 | Invincible Belief |
EMPIRICAL_KNOWLEDGE | 80002762 | Empirical Knowledge |
ADVENTURERS_CURIOSITY | 80002766 | Adventurer's Curiosity |
THIEFS_CUNNING | 80002770 | Thief's Cunning |
PIRATE_BLESSING | 80002774 | Pirate Blessing |
NOBLESSE | 80002857 | Noblesse |
TIME_TO_PREPARE | 80003015 | Time to Prepare |
NATURES_FRIEND | 80003058 | Nature's Friend |
INNATE_GIFT | 80003224 | Innate Gift |
GROUNDED_BODY | 80003877 | Grounded Body |
FOCUS_SPIRIT | 80010006 | Focus Spirit |
GUIDING_STARS | 80010486 | Guiding Stars |
QI_CULTIVATION | 80011964 | Qi Cultivation |
Sia's source skill 80010343 and Erel's source skill 80010473 are normalized by the supported client build to the shared assignable GUIDING_STARS ID 80010486.
Reading Link Skill state
core.link_skills.get_active_preset() -> number | nil, string?
Returns the active zero-based preset index (0, 1, or 2).
local preset, err = core.link_skills.get_active_preset()
if preset ~= nil then
core.log("Active Link Skill preset: " .. (preset + 1))
else
core.log(err)
endcore.link_skills.get_assigned(preset?: number) -> table<number> | nil, string?
Returns a sequential array of the skill IDs assigned to preset. Omit preset, or pass nil, to read the active preset. An empty preset returns an empty table.
local assigned, err = core.link_skills.get_assigned()
if not assigned then
core.log(err)
return
end
for slot, skill_id in ipairs(assigned) do
core.log(string.format("Link slot %d: %d", slot, skill_id))
endTo inspect every preset without activating it:
for preset = 0, 2 do
local assigned = core.link_skills.get_assigned(preset)
if assigned then
core.log(string.format(
"Preset %d has %d assigned Link Skills",
preset + 1,
#assigned
))
end
endChanging Link Skills
Mutations always target the active preset. To edit another preset, call activate_preset() first, then wait until get_active_preset() reports the requested preset before assigning or unassigning a skill. An immediate mutation can still target the old preset.
core.link_skills.assign(skill_id: number) -> boolean, string?
Requests assignment of one skill to the active preset. According to the client snapshot at call time, the request is rejected before sending when the skill is already assigned or the preset already contains 12 skills.
local ok, err = core.link_skills.assign(
core.link_skills.skills.ELVEN_BLESSING
)
if not ok then core.log(err) endcore.link_skills.unassign(skill_id: number) -> boolean, string?
Requests removal of one skill from the active preset. According to the client snapshot at call time, the request is rejected before sending when that skill is not assigned.
local ok, err = core.link_skills.unassign(
core.link_skills.skills.ELVEN_BLESSING
)
if not ok then core.log(err) endcore.link_skills.activate_preset(preset: number) -> boolean, string?
Requests activation of preset 0, 1, or 2. Requesting the already-active preset returns false, error_message without sending another request.
local ok, err = core.link_skills.activate_preset(1) -- in-game Preset 2
if not ok then core.log(err) endSetting one skill to a desired state
There is no separate enable/disable flag. A skill is enabled for the active preset when its ID appears in get_assigned(). Use assign() to enable it and unassign() to disable it.
local links = core.link_skills
local function is_assigned(skill_id)
local assigned, err = links.get_assigned()
if not assigned then
return nil, err
end
for _, assigned_id in ipairs(assigned) do
if assigned_id == skill_id then
return true
end
end
return false
end
local function set_enabled(skill_id, enabled)
local assigned, err = is_assigned(skill_id)
if assigned == nil then
return false, err
end
if assigned == enabled then
return true
end
if enabled then
return links.assign(skill_id)
end
return links.unassign(skill_id)
end
local ok, err = set_enabled(links.skills.WILD_RAGE, true)
if not ok then core.log(err) endAfter a successful mutation, wait for a later on_tick and confirm the expected state before calling the helper again. Back-to-back requests can otherwise validate against stale character data.