Docs menu · Luau API+

    You are reading the docs of SDK 1.2.0, an older release. See the latest (1.11.0).

    Reference · SDK 1.2.0

    The Luau API

    What a script mod can use: the openrac table. Scripts run in a sandbox with a 2 ms budget per call

    The openrac table

    A script mod sees one global, openrac, and the safe parts of Luau's library. For autocomplete, point your editor's Luau language server at the SDK's types/rac1.d.luau.

    openrac.game

    Since 1.1
    Type
    openrac.game: string

    openrac.game, .version, .platform, .api: "rac1", "pal" or "ntsc", "macos-arm64" ..., the game's interface version ("1.1")

    openrac.version

    Since 1.1
    Type
    openrac.version: "pal" | "ntsc"

    openrac.game, .version, .platform, .api: "rac1", "pal" or "ntsc", "macos-arm64" ..., the game's interface version ("1.1")

    openrac.platform

    Since 1.1
    Type
    openrac.platform: string

    openrac.game, .version, .platform, .api: "rac1", "pal" or "ntsc", "macos-arm64" ..., the game's interface version ("1.1")

    openrac.api

    Since 1.1
    Type
    openrac.api: string

    openrac.game, .version, .platform, .api: "rac1", "pal" or "ntsc", "macos-arm64" ..., the game's interface version ("1.1")

    openrac.log()

    Since 1.1
    Type
    openrac.log: (...any) -> ()

    openrac.log(...), openrac.warn(...): a line in the game's log, after your mod's id (print does the same as log)

    From the guide “Hooks”
    openrac.hook("rac1.player.set_planar_velocity", function(original, angle)
        original(angle)   -- the game's own, or the mod before yours
        openrac.log(`moving along {angle}`)
    end)
    
    openrac.after("rac1.player.advance_animation", function()
        -- runs after the game has moved the animation on
    end)
    +Example (1)
    From sdk/template-script/main.luau
    -- After each game tick (50 a second on PAL, 60 on NTSC-U).
    openrac.on_frame(function()
    	ticks += 1
    	if ticks % (every * 50) == 0 then
    		openrac.log(`still here after {ticks} ticks`)
    	end
    end)

    openrac.warn()

    Since 1.1
    Type
    openrac.warn: (...any) -> ()

    openrac.log(...), openrac.warn(...): a line in the game's log, after your mod's id (print does the same as log)

    openrac.setting()

    Since 1.1
    Type
    openrac.setting: (key: string) -> any

    openrac.setting(key): one of your settings

    From the guide “Script mods (Luau)”
    --!strict
    local swap = openrac.setting("pair") :: string
    
    openrac.on_pad(function(port: number, report: buffer)
        local buttons = buffer.readu16(report, 0)   -- a bit is clear while its button is held
        -- ... change buttons ...
        buffer.writeu16(report, 0, buttons)
    end)
    
    openrac.on_frame(function()
        -- after each game tick: 50 a second on PAL, 60 on NTSC-U
    end)
    +Example (1)
    From sdk/template-script/main.luau
    local every = openrac.setting("every") :: number -- the manifest's setting, as the launcher set it
    local ticks = 0

    openrac.hook()

    Since 1.1
    Type
    openrac.hook: (name: HookPoint, fn: (original: (...number) -> ...number, ...number) -> ...number) -> ()

    openrac.hook(id, fn): wrap or replace a hook point: fn(original, ...) gets its arguments; original(...) goes on down the chain and returns its result; original() with no arguments passes the call's own; return nothing to keep the original's result

    From the guide “Hooks”
    openrac.hook("rac1.player.set_planar_velocity", function(original, angle)
        original(angle)   -- the game's own, or the mod before yours
        openrac.log(`moving along {angle}`)
    end)
    
    openrac.after("rac1.player.advance_animation", function()
        -- runs after the game has moved the animation on
    end)
    +Example (1)
    From sdk/template-script/main.luau
    -- A hook point by name, wrapped: the game's own call goes on through `original`.
    -- openrac.hook("Hero_SetPlanarVelocity", function(original, angle: number)
    -- 	original(angle)
    -- end)

    openrac.before()

    Since 1.1
    Type
    openrac.before: (name: HookPoint, fn: (...number) -> ()) -> ()

    openrac.before(id, fn), openrac.after(id, fn): fn(...) before or after the rest of the chain, which runs whatever fn does

    openrac.after()

    Since 1.1
    Type
    openrac.after: (name: HookPoint, fn: (...number) -> ()) -> ()

    openrac.before(id, fn), openrac.after(id, fn): fn(...) before or after the rest of the chain, which runs whatever fn does

    From the guide “Hooks”
    openrac.hook("rac1.player.set_planar_velocity", function(original, angle)
        original(angle)   -- the game's own, or the mod before yours
        openrac.log(`moving along {angle}`)
    end)
    
    openrac.after("rac1.player.advance_animation", function()
        -- runs after the game has moved the animation on
    end)

    openrac.on_frame()

    Since 1.1
    Type
    openrac.on_frame: (fn: () -> ()) -> ()

    openrac.on_frame(fn): fn() after each game tick

    From the guide “Script mods (Luau)”
    --!strict
    local swap = openrac.setting("pair") :: string
    
    openrac.on_pad(function(port: number, report: buffer)
        local buttons = buffer.readu16(report, 0)   -- a bit is clear while its button is held
        -- ... change buttons ...
        buffer.writeu16(report, 0, buttons)
    end)
    
    openrac.on_frame(function()
        -- after each game tick: 50 a second on PAL, 60 on NTSC-U
    end)
    +Example (1)
    From sdk/template-script/main.luau
    -- After each game tick (50 a second on PAL, 60 on NTSC-U).
    openrac.on_frame(function()
    	ticks += 1
    	if ticks % (every * 50) == 0 then
    		openrac.log(`still here after {ticks} ticks`)
    	end
    end)

    openrac.on_pad()

    Since 1.1
    Type
    openrac.on_pad: (fn: (port: number, report: buffer) -> ()) -> ()

    openrac.on_pad(fn): fn(port, report) for each pad report before the game reads it; report is a buffer you may change

    From the guide “Script mods (Luau)”
    --!strict
    local swap = openrac.setting("pair") :: string
    
    openrac.on_pad(function(port: number, report: buffer)
        local buttons = buffer.readu16(report, 0)   -- a bit is clear while its button is held
        -- ... change buttons ...
        buffer.writeu16(report, 0, buttons)
    end)
    
    openrac.on_frame(function()
        -- after each game tick: 50 a second on PAL, 60 on NTSC-U
    end)
    +Example (1)
    From sdk/template-script/main.luau
    -- Each pad report, before the game reads it: `report` is a buffer the script may change (rac1-mods'
    -- button-swap shows its layout). Uncomment to see the buttons.
    -- openrac.on_pad(function(port: number, report: buffer)
    -- 	openrac.log(`port {port}: buttons {buffer.readu16(report, 0)}`) -- a bit clear for a button held
    -- end)

    openrac.read()

    Since 1.1
    Type
    openrac.read: (kind: MemoryType, address: number) -> number

    openrac.read(type, address), openrac.write(type, address, value): game memory; type is u8 i8 u16 i16 u32 i32 f32; addresses in game RAM only (below 32 MB)

    openrac.write()

    Since 1.1
    Type
    openrac.write: (kind: MemoryType, address: number, value: number) -> ()

    openrac.read(type, address), openrac.write(type, address, value): game memory; type is u8 i8 u16 i16 u32 i32 f32; addresses in game RAM only (below 32 MB)

    openrac.fields

    Since 1.1Experimental
    Type
    openrac.fields: Fields

    openrac.fields: game state by name, read and written as plain values: openrac.fields.bolts, openrac.fields.hero.position.x (experimental: see the reference)

    openrac.key()

    New 1.2
    Type
    openrac.key: (bind: string) -> boolean

    openrac.key(bind), openrac.pressed(bind) (1.2): whether a key, mouse button or wheel direction is held, or went down since the last tick, by its name: openrac.key("KeyW"), openrac.pressed("MouseLeft"), openrac.pressed("WheelUp") (settings)

    openrac.pressed()

    New 1.2
    Type
    openrac.pressed: (bind: string) -> boolean

    openrac.key(bind), openrac.pressed(bind) (1.2): whether a key, mouse button or wheel direction is held, or went down since the last tick, by its name: openrac.key("KeyW"), openrac.pressed("MouseLeft"), openrac.pressed("WheelUp") (settings)

    openrac.mouse()

    New 1.2
    Type
    openrac.mouse: () -> (number, number, number, number)

    openrac.mouse() (1.2): dx, dy, wheel_x, wheel_y: the mouse's motion since the last tick and its wheel in notches

    openrac.window()

    New 1.2
    Type
    openrac.window: () -> (boolean, boolean, boolean)

    openrac.window() (1.2): focused, captured, overlay: the window has the keyboard; the cursor is captured; OpenRAC's overlay has the input

    openrac.take_input()

    New 1.2
    Type
    openrac.take_input: (...("keyboard" | "mouse")) -> ()

    openrac.take_input("keyboard") (1.2): while your scripts first run: the port's own keyboard table stops pressing pad 0's buttons, so your on_pad presses them

    openrac.capture_mouse()

    New 1.2
    Type
    openrac.capture_mouse: (capture: boolean) -> ()

    openrac.capture_mouse(on) (1.2): hide the cursor and keep it in the window (relative motion), or let it go

    openrac.pvars()

    Since 1.1Experimental
    Type
    openrac.pvars: (moby: number) -> { [string]: number }?

    openrac.pvars(moby): with the behaviour catalogue: the per-class variables of the moby at that address, by name (experimental)

    require()

    Since 1.1
    Type
    require: (name: string) -> any

    require(name): another .luau file of your mod's own folder: require("util"), require("lib/util")

    Types

    MemoryType

    Luau
    type MemoryType = "u8" | "i8" | "u16" | "i16" | "u32" | "i32" | "f32"

    Fields

    Luau
    type Fields = {
        hero: {
            position: {
                x: number, -- Where the hero is (gHeroPos).
                y: number,
                z: number,
            },
            facing: number, -- The way he faces (rot.z), in radians.
            move_yaw: number, -- Where the stick moves him: the stick's angle plus the camera's yaw.
            state: number, -- read-only; His state: 0 standing, 2 running, 7 jumping, ...
        },
        bolts: number, -- The player's bolts.
    }

    Pad_ProcessReportFn

    rac1.pad.process_report (Pad_ProcessReport) void(u32,u32,i32): One pad report into the pad's state (PadState, at pad), each poll, before the tick reads it.

    Luau
    type Pad_ProcessReportFn = (pad: number, report: number, size: number) -> ()

    Hero_UpdateMotionInputFn

    rac1.player.update_motion_input (Hero_UpdateMotionInput) void(): The stick read into the hero, early in his update each tick.

    Luau
    type Hero_UpdateMotionInputFn = () -> ()

    Hero_TurnToHeadingFn

    rac1.player.turn_to_heading (Hero_TurnToHeading) void(i32,f32,f32,f32): Eases the hero's facing toward his move yaw.

    Luau
    type Hero_TurnToHeadingFn = (mode: number, accel: number, damping: number, limit: number) -> ()

    Hero_SetPlanarVelocityFn

    rac1.player.set_planar_velocity (Hero_SetPlanarVelocity) void(f32): The hero's velocity at his ground speed along an angle; an angle above pi means his facing.

    Luau
    type Hero_SetPlanarVelocityFn = (angle: number) -> ()

    FollowCamera_ApplyOverridesFn

    rac1.camera.follow.apply_overrides (FollowCamera_ApplyOverrides) void(u32): The follow camera's per-tick requests from the hero's state; the camera moby's update calls it before it places the eye.

    Luau
    type FollowCamera_ApplyOverridesFn = (camera: number) -> ()

    Hero_AdvanceAnimationFn

    rac1.player.advance_animation (Hero_AdvanceAnimation) void(): Ratchet's animation moved on by his animation speed, once a tick after his state's update.

    Luau
    type Hero_AdvanceAnimationFn = () -> ()

    Item_GiveFn

    rac1.item.give (Item_Give) void(i32,i32): Gives the player item id (GiveItem): sets its owned and obtained bytes, shows its banner, gives its starting ammo, marks it bought in the vendor's stock and adds it to the quick select; equip non-zero also puts it in hand. Every item the game gives goes through it but the Persuader's.

    Luau
    type Item_GiveFn = (id: number, equip: number) -> ()

    Planet_UnlockFn

    rac1.planet.unlock (Planet_Unlock) void(i32): Unlocks a planet's coordinates (UnlockPlanet): its flag (one byte per level), the galaxy list, and its banner unless it is the planet the player is on.

    Luau
    type Planet_UnlockFn = (planet: number) -> ()

    Vendor_InitLevelStockFn

    rac1.vendor.init_level_stock (Vendor_InitLevelStock) void(): The vendor's stock at each level start (VendorStockLevelInit): gives the Bomb Glove while the player has none, keeps the stock's known items and adds the level's new weapon.

    Luau
    type Vendor_InitLevelStockFn = () -> ()

    Vendor_BuildItemListFn

    rac1.vendor.build_item_list (Vendor_BuildItemList) void(i32): The vendor menu's list (VendorBuildItemList), from the stock and the items owned: each time the menu opens and after each purchase. skip_unflagged leaves out what is for sale (the menu opened from the pause screen).

    Luau
    type Vendor_BuildItemListFn = (skip_unflagged: number) -> ()

    GoldBolts_CountCollectedFn

    rac1.gold_bolt.count_collected (GoldBolts_CountCollected) i32(): The gold bolts collected, at most 40 (count_nonzero_entries_up_to_40): what the pause screen shows; the unspent ones are this less 4 per gold weapon.

    Luau
    type GoldBolts_CountCollectedFn = () -> number

    MobyUpdateFn

    rac1.moby.<class>.update (experimental): (moby: number) -> (), or () -> () where it gets no moby.

    Luau
    type MobyUpdateFn = (moby: number) -> ()

    Generated from sdk/types/rac1.d.luau at sdk-v1.2.0. Edit this page or report a problem.