openrac.game
Since 1.1openrac.game: stringopenrac.game, .version, .platform, .api: "rac1", "pal" or "ntsc", "macos-arm64" ..., the game's interface version ("1.1")
Reference · SDK 1.11.0
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: stringopenrac.game, .version, .platform, .api: "rac1", "pal" or "ntsc", "macos-arm64" ..., the game's interface version ("1.1")
openrac.version: "pal" | "ntsc"openrac.game, .version, .platform, .api: "rac1", "pal" or "ntsc", "macos-arm64" ..., the game's interface version ("1.1")
openrac.platform: stringopenrac.game, .version, .platform, .api: "rac1", "pal" or "ntsc", "macos-arm64" ..., the game's interface version ("1.1")
openrac.api: stringopenrac.game, .version, .platform, .api: "rac1", "pal" or "ntsc", "macos-arm64" ..., the game's interface version ("1.1")
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)
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)-- 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: (...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: (key: string) -> anyopenrac.setting(key): one of your settings
--!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)local every = openrac.setting("every") :: number -- the manifest's setting, as the launcher set it
local ticks = 0openrac.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
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)-- 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: (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: (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.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: (fn: () -> ()) -> ()openrac.on_frame(fn): fn() after each game tick
--!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)-- 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: (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
--!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)-- Each pad report, before the game reads it: `report` is a buffer the script may change (openrac-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: (kind: MemoryType, address: number) -> numberopenrac.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: (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: Fieldsopenrac.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: (bind: string) -> booleanopenrac.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: (bind: string) -> booleanopenrac.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: () -> (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: () -> (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.pointer: () -> (number, number, boolean)openrac.pointer() (1.3): x, y, inside: the cursor over the game's picture, 0..1 each way (x * 512, y * 416 is the game's 2D pixel), and whether it is over it
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: (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: (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: (name: string) -> anyrequire(name): another .luau file of your mod's own folder: require("util"), require("lib/util")
type MemoryType = "u8" | "i8" | "u16" | "i16" | "u32" | "i32" | "f32"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.
}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.
type Pad_ProcessReportFn = (pad: number, report: number, size: number) -> ()rac1.player.update_motion_input (Hero_UpdateMotionInput) void(): The stick read into the hero, early in his update each tick.
type Hero_UpdateMotionInputFn = () -> ()rac1.player.turn_to_heading (Hero_TurnToHeading) void(i32,f32,f32,f32): Eases the hero's facing toward his move yaw.
type Hero_TurnToHeadingFn = (mode: number, accel: number, damping: number, limit: number) -> ()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.
type Hero_SetPlanarVelocityFn = (angle: number) -> ()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.
type FollowCamera_ApplyOverridesFn = (camera: number) -> ()rac1.player.advance_animation (Hero_AdvanceAnimation) void(): Ratchet's animation moved on by his animation speed, once a tick after his state's update.
type Hero_AdvanceAnimationFn = () -> ()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.
type Item_GiveFn = (id: number, equip: number) -> ()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.
type Planet_UnlockFn = (planet: number) -> ()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.
type Vendor_InitLevelStockFn = () -> ()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).
type Vendor_BuildItemListFn = (skip_unflagged: number) -> ()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.
type GoldBolts_CountCollectedFn = () -> numberrac1.player.take_damage (Hero_TakeDamage) void(i32): Takes hit points off the hero's health (Hero_TakeDamage): at most one a call, none for 0, then the HUD's health bank. Every hit the hero takes goes through it but the instant kills (falls, crushers), which set his health to 0.
type Hero_TakeDamageFn = (amount: number) -> ()rac1.combat.get_hit (Moby_GetHitMessage) u32(u32,i32,i32): The hit pending on moby (MobyGetHitMessage): the record of the last hit posted to it (+0x20 the attacker, +0x24 the flags, +0x2C the damage, an f32) when its flags match mask, else 0, dropping the hit unless keep. How the hero and every enemy read the hits they take, each tick, so a hit may be read more than once.
type Moby_GetHitMessageFn = (moby: number, mask: number, keep: number) -> numberrac1.weapon.take_ammo (Weapon_TakeAmmo) i32(i32,i32): Takes amount of ammo from item for a shot (TakeAmmo; -1 is the item in hand): 1 when taken, 0 when there is too little. An item with no ammo limit takes none and gives 1.
type Weapon_TakeAmmoFn = (item: number, amount: number) -> numberrac1.moby.record_death (Moby_RecordDeath) void(u32,i32,i32): Records a placed moby's death or a crate's break (SetDeathBits): its save id's killed bits (none for a save id below 0), its mission, then drops its bolts: about the s16 at +0xB4 (or what a tallied source has left of +0xB6), which it then clears.
type Moby_RecordDeathFn = (moby: number, flags: number, index: number) -> ()rac1.level.load_gameplay (Level_LoadGameplay) u32(i32): Loads a level's gameplay file into the level heap (LoadLevelGameplay), once per level start: the settings, the placed mobys and their pvars, the spare moby pool, the paths and the rest; returns the heap cursor. After it, every placed moby exists and none has run.
type Level_LoadGameplayFn = (full: number) -> numberrac1.player.approach_speed (Hero_ApproachSpeed) void(f32,f32): Eases the hero's ground speed (+0x194, the speed Hero_SetPlanarVelocity moves him at) toward his target speed (+0x190) by up when below it and by down when above, each tick he moves on foot, in every level.
type Hero_ApproachSpeedFn = (up: number, down: number) -> ()rac1.ship.travel_to (Ship_TravelTo) void(i32): The ship's travel from the planet select (ShipTravelTo), once its menu closes: to the planet it is on (dest the level now), the landing again, as backing out of the select does; to another, the game saved to the card and the ship's flight out of the level, whose loop then ends and flies to dest. After the take-off; a level's only way to another planet by ship.
type Ship_TravelToFn = (dest: number) -> ()rac1.moby.collect_bolt (Moby_CollectBolt) void(u32): Collects a bolt (collect_bolt), called by the bolt update (classes 13 to 16) once the bolt reaches the hero: adds its value (1, or 5 / 20 / 50 for classes 14 / 15 / 16) to the bolt count, the level's total and its source's stats, shows the bolt counter and makes two sparkles at it. The bolt update then deletes the bolt (a placed one marked taken) whether or not this ran.
type Moby_CollectBoltFn = (bolt: number) -> ()rac1.menu.item_grid.update (Menu_ItemGrid_Update) i32(u32): Moves the pause menu item grid's focus and takes its selection (update_menu_grid_selection), each tick the grid is open. Returns the menu's action.
type Menu_ItemGrid_UpdateFn = (grid: number) -> numberrac1.menu.item_grid.draw (Menu_ItemGrid_Draw) i32(u32): Draws the pause menu item grid (draw_menu_item_grid). Returns the render-pass flags the menu passes on.
type Menu_ItemGrid_DrawFn = (grid: number) -> numberrac1.menu.item_slots.update (Menu_ItemSlots_Update) i32(u32): Puts the highlighted item in one of the quick select's eight slots (update_menu_item_slots), in the pause menu's quick select editor.
type Menu_ItemSlots_UpdateFn = (list: number) -> numberrac1.menu.quick_select.draw (Menu_QuickSelect_Draw) i32(u32): Draws the pause menu's quick select ring (draw_pause_ring). Returns the render-pass flags.
type Menu_QuickSelect_DrawFn = (screen: number) -> numberrac1.menu.quick_select.load (Menu_QuickSelect_Load) i32(u32): Copies the eight saved quick select items into the pause menu's editor (load_selection_list).
type Menu_QuickSelect_LoadFn = (list: number) -> numberrac1.menu.quick_select.store (Menu_QuickSelect_Store) i32(u32): Copies the editor's eight quick select items (+0x30 of screen) back to the saved quick select (pause_stage_sprite_lists).
type Menu_QuickSelect_StoreFn = (screen: number) -> numberrac1.menu.item_text.draw (Menu_ItemText_Draw) i32(u32): Draws a menu text label from its configuration (render_configured_text_label): the selected item's name and description among others.
type Menu_ItemText_DrawFn = (label: number) -> numberrac1.menu.item_ammo.draw (Menu_ItemAmmo_Draw) i32(i32): Draws the selected item's ammo panel in the pause menu (draw_selected_item_ammo).
type Menu_ItemAmmo_DrawFn = (screen: number) -> numberrac1.menu.preview.bind (Menu_Preview_Bind) i32(u32): Binds the selected item, and what it carries, to the pause menu's preview (update_item_preview_binding).
type Menu_Preview_BindFn = (preview: number) -> numberrac1.menu.preview.update (Menu_Preview_Update) i32(u32): Makes or replaces the moby of the pause menu's item preview (update_item_preview_moby).
type Menu_Preview_UpdateFn = (screen: number) -> numberrac1.menu.preview.draw_available (Menu_Preview_DrawAvailable) i32(u32): Draws the preview mobys of the owned, selected item (draw_available_item_preview_mobys). Returns the render-pass flags.
type Menu_Preview_DrawAvailableFn = (screen: number) -> numberrac1.menu.preview.draw_selected (Menu_Preview_DrawSelected) i32(u32): Draws the selected item's preview, or the message for an item not owned (draw_item_preview_screen).
type Menu_Preview_DrawSelectedFn = (screen: number) -> numberrac1.menu.equipped_preview.update (Menu_EquippedPreview_Update) i32(u32): Loads the preview of the gadget or weapon in hand (LoadHandGadget).
type Menu_EquippedPreview_UpdateFn = (hand: number) -> numberrac1.menu.equipped_preview.draw (Menu_EquippedPreview_Draw) i32(u32): Draws the pause menu's preview of the hero and what he holds (draw_menu_preview_objects).
type Menu_EquippedPreview_DrawFn = (screen: number) -> numberrac1.hud.quick_select.init (Hud_QuickSelect_Init) void(u32): Sets up the quick select's eight-slot selector in play (initialize_eight_slot_hud_selector).
type Hud_QuickSelect_InitFn = (selector: number) -> ()rac1.hud.quick_select.update (Hud_QuickSelect_Update) void(u32): The quick select in play, each tick (update_hud_item_selector_selection_and_visibility): its focus, whether it shows, and the item chosen.
type Hud_QuickSelect_UpdateFn = (selector: number) -> ()rac1.hud.quick_select.draw (Hud_QuickSelect_Draw) i32(u32): Draws the quick select's item icons in play (draw_hud_item_selector_panel).
type Hud_QuickSelect_DrawFn = (panel: number) -> numberrac1.vendor.menu_update (Vendor_MenuUpdate) void(): The vendor's purchase menu, each tick it is open (update_vendor_purchase): buying items and ammo.
type Vendor_MenuUpdateFn = () -> ()rac1.vendor.initialize_selected (Vendor_InitializeSelected) void(): Sets up the mobys and text of the vendor's selected row (initialize_vendor_selected_item_mobys).
type Vendor_InitializeSelectedFn = () -> ()rac1.ammo.choose_drop (Ammo_ChooseDrop) i32(u32,u32): Chooses the ammo a dying moby or a broken crate drops (ChooseDropItem): writes the item to out_item and returns how many pickups.
type Ammo_ChooseDropFn = (moby: number, out_item: number) -> numberrac1.ammo.spawn_drop (Ammo_SpawnDrop) u32(u32,i32,i32,i32): Makes an ammo pickup moby of item at pos (spawn_on_path); amount -1 takes the item's own. Returns the moby, or 0.
type Ammo_SpawnDropFn = (pos: number, item: number, amount: number, flags: number) -> numberrac1.save.prepare (Save_Prepare) void(i32,i32): Writes the game's state into a save and starts a full memory card write (prepare_save_game).
type Save_PrepareFn = (buffer: number, slot: number) -> ()rac1.save.request_autosave (Save_RequestAutosave) i32(i32,i32): Writes the save's packets and asks for their memory card update (memcard_Save), as an autosave does.
type Save_RequestAutosaveFn = (slot: number, flags: number) -> numberrac1.save.restore (Save_Restore) void(u32): Restores a whole save from memory (memcard_RestoreGame); a new game's default state goes through it too. The port keeps the player's options around it (rac1/host/options.c).
type Save_RestoreFn = (save: number) -> ()rac1.save.restore_data (Save_RestoreData) i32(u32,i32,u32): Restores one checked save packet (memcard_RestoreData); loading a file calls it directly. Returns non-zero when it took the packet.
type Save_RestoreDataFn = (src: number, slot: number, table: number) -> numberrac1.save.new_game (Save_NewGame) void(): A new game (NewGameInit): the disc's default state, and level 0. The port's --level N runs around it (rac1/host/boot.c).
type Save_NewGameFn = () -> ()rac1.save.new_game_plus (Save_NewGamePlus) void(i32): Challenge mode's start (load_level_zero_preserving_progress): the game reset to level 0 with the progress it carries kept.
type Save_NewGamePlusFn = (slot: number) -> ()rac1.save.serialize (Save_Serialize) void(u32): Writes the whole save into out (memcard_MakeWholeSave), with no memory card access.
type Save_SerializeFn = (out: number) -> ()rac1.save.update_state (Save_UpdateState) void(): The memory card's state machine, each tick (memcard_update_state): saves and loads go through it.
type Save_UpdateStateFn = () -> ()rac1.moby.<class>.update (experimental): (moby: number) -> (), or () -> () where it gets no moby.
type MobyUpdateFn = (moby: number) -> ()Generated from sdk/types/rac1.d.luau at sdk-v1.11.0. Edit this page or report a problem.