Violet

Navigation

On this page

Moves the character to a point on the current map by itself. It plans a route over the map's platforms, ladders, ropes and portals using the moves your character has (flash jump, up jump, teleport, rope lift), plays it with human-like timing, and replans when the character is pushed off the route.

Info

Navigation works within the current map. To travel to another map, use Rusher.

Functions

core.nav.path_to(x: number, y: number, opts?: table) -> boolean, string?

Starts travelling to the map coordinate (x, y) and returns at once; follow the trip with status(). The point can also be passed as a table: core.nav.path_to({x = 1200, y = -85}, opts).

The target is matched to the platform just below the point, or the nearest platform a short way from it, so y can be approximate. Calling path_to() during a trip replaces it.

OptionTypeDescription
seednumberPassing the same seed again repeats the same route choices between the same two points. Leave it out for a varied route each time

Returns true when travel started, or false and a reason when it did not:

ReasonMeaning
stand on a platform before navigatingThe character is in the air, on a ladder or rope, or not on a platform
no platform near the targetThere is no platform at or near the point
no jump key is boundBind Jump to a key first
map geometry unavailableThe map has not finished loading
Rotation Builder owns the inputThe Rotation Builder is recording or playing

A trip ends when the character arrives, when no route can be found, and when you call stop(). Changing map or channel, logging out and Panic Mode stop it too. When the character is knocked or falls off the route, navigation plans again from where it lands, up to 4 times per trip; after that the trip fails with too many replans: ... in status().message.


core.nav.stop()

Stops the current trip and lets go of the movement keys.


core.nav.is_active() -> boolean

Returns true from a successful path_to() until the trip arrives, fails or is stopped.


core.nav.status() -> table

Returns what the current or last trip is doing.

FieldTypeDescription
statestringidle, planning, running, replanning, arrived or failed (see below)
messagestringWhy the trip failed, when state is failed; otherwise usually empty
stepnumberThe route step being played, out of steps
stepsnumberSteps in the route
replansnumberTimes this trip has planned again, up to 4
target_xnumberx given to path_to()
target_ynumbery given to path_to()
stateMeaning
idleNo trip, including right after stop()
planningWorking out the route
runningMoving along the route
replanningThe character left the route; a new route is on its way
arrivedReached the target
failedGave up; message says why

A finished trip keeps its arrived or failed status until the next path_to().


core.nav.plan(x: number, y: number, seed?: number) -> table?, string?

Works out the route to (x, y) without moving, and returns it as a list of steps with a total_seconds field. Returns nil and a reason when there is no route; the reasons are the same as for path_to(), with stand on a platform before planning when the character is not on a platform. The call waits for the route, so on a large map it can take a moment.

Step fieldTypeDescription
kindstringwalk, jump, drop, teleport, climb, portal or rope
dirnumber-1 left, 1 right, 0 neither
runbooleantrue when the move is taken with a running start
from_x, from_ynumberWhere the step starts
to_x, to_ynumberWhere the step ends
secondsnumberExpected duration of the step
actionstableThe inputs in the step, each {at, kind}: at is seconds after the step starts, kind is one of hold_dir, release_dir, jump, flash_jump, up_jump, down_jump, teleport, teleport_up, teleport_down, climb, portal, walk, rope_lift

core.nav.get_capabilities() -> table

Returns the movement model routes are planned with. Violet fills it in from the character's job and skills the first time it plans a route.

FieldTypeDescription
flash_jump, up_jump, up_jump_airborne, teleport, down_jump, portals, rope_liftbooleanWhich moves the route may use
flash_jump_maxnumberFlash jumps in one jump
teleport_skill, rope_lift_skillnumberSkill IDs used for teleport and rope lift; 0 when none
walk_speed, climb_speed, rope_speednumberPixels per second
walk_jump, gravity, flash_jump_vx, flash_jump_vy, up_jump_vynumberJump and fall speeds, in pixels per second (gravity in pixels per second squared)
teleport_range_x, teleport_range_y, rope_range, ladder_attach_tolerancenumberDistances in pixels
flash_jump_min_delay, teleport_delay, rope_delaynumberSeconds

core.nav.set_capabilities(caps: table) -> boolean

Changes the movement model. Only the fields you pass change; the rest keep their values. From then on your values are used in place of the ones Violet fills in. Returns true.


core.nav.get_persona() -> table

Returns the style routes are chosen with. Each time Violet loads it picks a random style, so different characters take slightly different routes.

FieldTypeDescription
alternativesnumberHow many candidate routes are compared
betanumberHow strongly the fastest candidate is preferred; higher picks the fastest almost every time
cost_noisenumberRandom variation added to each move's cost; 0 for none
flash_jump_weight, ladder_weight, teleport_weight, portal_weight, drop_weightnumberCost multipliers per kind of move (teleport_weight covers rope lift too): above 1 uses that move less, below 1 more
fall_damage_penaltynumberSeconds added to a drop long enough to cause fall damage

core.nav.set_persona(persona: table) -> boolean

Changes the route style. Only the fields you pass change. Returns true.


core.nav.refresh() -> boolean

Reads the current map's platforms again. Returns true when it succeeded. Navigation reads them by itself the first time it plans on a map, so this is rarely needed.

Example

lua
-- Walk to a spot, and report how the trip ended
local ok, reason = core.nav.path_to(1200, -85)
if not ok then
    core.log("Can't go there: " .. reason)
end

local reported = false
function on_tick(stage)
    local status = core.nav.status()
    if reported or core.nav.is_active() then return end
    if status.state == "arrived" then
        core.log("Arrived")
    elseif status.state == "failed" then
        core.log("Navigation failed: " .. status.message)
    end
    reported = true
end
lua
-- Preview a route before taking it
local route, reason = core.nav.plan(1200, -85)
if route then
    core.log(string.format("%d steps, about %.1f s", #route, route.total_seconds))
    for i, step in ipairs(route) do
        core.log(string.format("%d. %s to (%.0f, %.0f)", i, step.kind, step.to_x, step.to_y))
    end
else
    core.log("No route: " .. reason)
end