From 91b754bfb0f4f23dfef2dd4e0c1df218374abbe2 Mon Sep 17 00:00:00 2001 From: AyeZeeBB Date: Tue, 20 Oct 2026 01:46:18 -0500 Subject: [PATCH] Docs: the throwdown kit for Lua, and Board Break and Road Rash as plugins inside their packs contrib/throwdown-kit.md is the reference for making a throwdown mode in Lua: registering modes, the documents (setup page, waiting card, HUD, match panel, flags, match), the throwdown_ui events, the native flag, and the services a mode uses. Board Break's doc says how the deck is chosen now (the pack's decks as variants, reskate.package.choose, reskate.board.fit); Road Rash's that it ships inside its item pack. The plugin list and the README name the throwdown plugins. --- README.md | 7 +- contrib/board-break.md | 121 ++++++++++----------- contrib/plugins/README.md | 11 ++ contrib/road-rash.md | 5 +- contrib/throwdown-kit.md | 223 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 297 insertions(+), 70 deletions(-) create mode 100644 contrib/throwdown-kit.md diff --git a/README.md b/README.md index 170152b3..57e1593c 100644 --- a/README.md +++ b/README.md @@ -15,15 +15,16 @@ the launcher, the runtime that loads into the game, and the dedicated server. - Join dedicated servers from the in-game server browser. - Proximity voice chat, and text chat with emotes and an optional bad-word filter. - Parties in lobbies and on dedicated servers: invite, join, leave, promote. - - Throwdowns with other players (Jam, Spot Battle and S.K.A.T.E.), and co-op challenges. + - Throwdowns with other players (Jam, Spot Battle and S.K.A.T.E.), and co-op challenges. Plugins add + throwdown modes of their own to the Throwdowns page ([contrib/throwdown-kit.md](contrib/throwdown-kit.md)). - **In-game menu and console.** - Map and fast travel. - World: time of day, population, district levels, rotating parks. - The **Park Editor**: place, move and save objects with freecam, snapping and undo. Save a selection as a set and place it again anywhere, on any map. - Skater options: first person, movement, boosts, noclip. - - Hall of Meat and grind exit triggers are plugin mods now - ([contrib/plugins/hall-of-meat](contrib/plugins/hall-of-meat), [contrib/plugins/grind-exits](contrib/plugins/grind-exits)). + - Hall of Meat, grind exit triggers, Board Break, Road Rash and the FPV drone are plugin mods now + ([contrib/plugins](contrib/plugins)). Board Break and Road Rash ship inside their asset mods. - Progression, controls, graphics and multiplayer settings. - **Mods.** - Drop a mod in `Mods/` and it is merged into the game at launch. Mods can add custom maps, loading diff --git a/contrib/board-break.md b/contrib/board-break.md index e5024d5d..58b005eb 100644 --- a/contrib/board-break.md +++ b/contrib/board-break.md @@ -4,8 +4,8 @@ A hard slam can break the local skater's board: at the nose, in the middle or at time the grip tape holds the pieces together and the board folds or an end hangs; otherwise a piece comes off, flies and lies where it lands, truck and wheels with it. The board is whole again once the skater has picked it up, rides again or respawns. A plugin, [board-break](plugins/board-break) -(it was built into ReSkate until 2026-10); the broken pieces themselves come from a content mod -with the deck shapes in it. +(it was built into ReSkate until 2026-10), that ships inside the Board Break deck pack: the broken +pieces themselves are the pack's deck models. Boards also wear: every hard landing, rail hit, grind and slam takes something out of the board of the deck in the game, and a worn board steers lazier, wobbles, breaks from less and in the end can @@ -13,14 +13,12 @@ give way under the rider. A boardslide or darkslide that comes down too hard ont the board and throw the rider. A break cracks (and sounds like metal when it happened on metal), and the body's hits in a bail are heard where and as hard as they land. The player sets all of it. -Code: the plugin's Lua in [plugins/board-break/plugin](plugins/board-break/plugin) (the break, -wear, rail snaps, sounds, its console command and menu), drawn through reskate.board -([board_pose.cpp](../Extension/Skater/board_pose.cpp)). What every board needs while a deck pack -is in the game stays in core whichever plugins run: -[breakable_deck.cpp](../Extension/Skater/breakable_deck.cpp) (which deck, its name and wheel -spacing, the `boarddeck` command), board_pose.cpp (the deck's stretches kept out of sight, the -baseplates on the deck, the wheels at the deck's spacing, on every board), and the deck's place in -the mod list in [mod_catalog.cpp](../Engine/Vfs/mod_catalog.cpp). +Code: the plugin's Lua in [plugins/board-break/plugin](plugins/board-break/plugin): the break, +wear, rail snaps, sounds, the deck, its console command and its page. It draws through +`reskate.board` (set, hide, park and toss the board's bones; `fit` every board for the deck in +the game), and picks the deck with `reskate.package.variants` and `reskate.package.choose`: the +pack's decks are variants of its mod, which its `reskate-plugin.json` declares. Nothing in ReSkate +knows Board Break. ## What the player gets @@ -28,10 +26,9 @@ the mod list in [mod_catalog.cpp](../Engine/Vfs/mod_catalog.cpp). in between (the force is the bail cause's that led to the wipeout). Now and then a board gives way while it is ridden: the nose goes. - `boardbreak 0|1`, `boardbreak snap [nose|mid|tail]` to look at a break (that one stays until - `boardbreak mend` or a respawn), from the plugin; its settings are on its page in the overlay's PLUGINS - section. `boarddeck [name|number|next]` (core) and the overlay's BREAKABLE DECK card on the - Mods page pick the deck: a press asks for that deck, the mods are applied and the level loads - again with it. + `boardbreak mend` or a respawn). Its settings are on its page in the overlay's PLUGINS section. + `boardbreak deck [name|number|next]` and the DECK card on that page pick the deck: a press asks + for that deck, the mods are applied and the level loads again with it. - A break plays back in the replay editor as it happened. - **Wear and tear.** Each deck's board wears from 0% (new) to 100% (worn out): a landing coming down faster than 3.5 m/s, a hit onto a rail or ledge (harder on a slide than on the trucks), every second @@ -46,14 +43,12 @@ the mod list in [mod_catalog.cpp](../Engine/Vfs/mod_catalog.cpp). rider goes down with it. Grinds on the trucks never do. - **Sounds.** A crack by the size of the break, a metal one on top when the board broke on metal, and the body's hits in a bail, louder the harder they land. -- **Settings**, on the overlay's Skater page in a card BOARD BREAK SETTINGS (with how worn the board - is): always break (for replay clips), rail snaps, wear and tear, break sounds, body hit sounds, - break sensitivity (10% to 400%), how many breaks the grip tape holds (0% to 100%), wear speed (0% - to 500%), and New board. Always break and wear and tear are also rows in the game's Mod Options. - The console has them all: `boardbreak always|sensitivity|joined|rails|wear|wearrate|cracks|bodysounds - [value]`, `boardbreak worn [percent]`, `boardbreak status`, and for metal `boardbreak metal - mark|unmark|clear|list` and `boardbreak materials`. They are kept, with each deck's wear and the - materials marked as metal, in `%LOCALAPPDATA%\ReSkate\BoardBreak.settings`. +- **Settings**, on the plugin's page in the overlay's PLUGINS section (with how worn the board is): + always break (for replay clips), rail snaps, wear and tear, break sounds, body hit sounds, break + sensitivity, how many breaks the grip tape holds, wear speed, and New board. The console has them + all: `boardbreak always|sensitivity|joined|rails|wear|wearrate|cracks|bodysounds [value]`, + `boardbreak worn [percent]`, `boardbreak status`. They are kept, with the board's wear, in the + plugin's storage. - Without a deck pack installed nothing breaks and nothing is changed. ## How it works @@ -82,18 +77,15 @@ the mod list in [mod_catalog.cpp](../Engine/Vfs/mod_catalog.cpp). that passes the hook (the local one, other players'), the stretches of a whole board are moved away like a broken board's deck. The call into Board Break is the last thing the hook does, after another player's pose has been written, so that pose's bones do not bring them back. -- **Which deck is in the game** is a question for the mod list, because any mod that reshapes the - deck replaces the same mesh and the one higher in the order has it. When the mods are put - together, the Board Break deck the player chose goes first, and what would fight it is set - aside for the run: the other Board Break decks, and other mods whose bundle lists name the - deck's bundle. Those are left out whole (with the breakable deck in place of its own, a wide-deck - mod has its trucks and wheels on a deck they were not made for). mods.json is not changed; the - mod list shows them as SET ASIDE. -- **Another deck without a restart.** The deck mesh is in the items superbundle, which a live apply - of the mods already refreshes, and the game reads the mesh when a level loads. Choosing a deck - saves the choice, applies the mods and loads the level again (live_mods.h). -- **The choice** is a line in `%LOCALAPPDATA%\ReSkate\BoardBreak.deck`, not a profile preference: - the mods are put together before the profile is there. +- **Which deck is in the game.** Any mod that reshapes the deck replaces the same mesh, so the + pack's decks are variants of its mod: one is in the game at a time, the one the player chose + (else the first of the manifest's `order`). The manifest names the deck's bundle in `displaces`, + so any other mod that brings a deck model is set aside while a deck is in the game (with the + breakable deck in place of its own, a wide-deck mod has its trucks and wheels on a deck they + were not made for). The mod list shows those as SET ASIDE. +- **Another deck without a restart.** `reskate.package.choose(deck)` keeps the choice, applies the + mods and loads the level again: the deck mesh is in the items superbundle, which a live apply + refreshes, and the game reads it when a level loads. - **The sound** is a wave file from the `sounds` folder of an installed deck pack (subfolders `light`, `medium`, `heavy`, by the size of the break), played straight to the speakers. - **The slam's force** comes through No Bail's existing hooks: the cause it records for the watched @@ -139,35 +131,35 @@ the mod list in [mod_catalog.cpp](../Engine/Vfs/mod_catalog.cpp). - **The sounds** play through XAudio2 on a thread of their own, several at once and each at its own loudness; 16-bit and 32-bit float wave files both play. - **Wider decks, wider trucks.** The game puts each wheel on its truck's bone along the axle, about - 0.0876 m out. A deck that says so (deck.ini `axle`) has its wheels set further apart, or closer, - by the render pose hook: set, not scaled, so a pose that comes by twice is not moved twice, and - only what is drawn changes. The deck's own truck model is made to match. -- Off, the board holds. Without a deck pack in the game the hook returns at once. + 0.0876 m out. A deck that says so (deck.ini `axle`) has its wheels set further apart, or closer: + the plugin reads it and asks `reskate.board.fit{plates = true, axle = ...}`, which sets them in + the render pose hook (set, not scaled, so a pose that comes by twice is not moved twice, and only + what is drawn changes) and holds the baseplates on the deck, on every board. The deck's own truck + model is made to match. +- Off, the board holds. With no deck in the game the plugin fits nothing. -## The deck packs +## The deck pack -A deck is a content mod's copy of the deck model (no code), and comes in one of two ways: +A deck is a copy of the deck model (no code). The Board Break deck pack holds a deck in each +`decks//`, laid out like a mod folder (`layout.toc`, `Win32/...`), and the plugin beside +them (`reskate-plugin.json`, `plugin/`). The plugin's manifest declares the decks: -- a mod folder named `Board_Break_` holds the deck ``; -- a deck pack, a mod folder of any name, holds a deck in each `decks//`, laid out like a mod - folder (`layout.toc`, `Win32/...`). The launcher installs one mod folder per package, so this is - how one package brings every deck. When the mods are put together each deck inside becomes a mod - of its own for the run, listed as `#`: it is chosen, set aside and switched like a - deck in a folder of its own (its archives are placed like a disabled mod's). mods.json and the - mod list only know the pack, which counts as loaded when one of its decks is. The launcher takes - a folder for a mod only when it has a `layout.toc` of its own. That layout is not one of the - pack's decks, whatever the folder is named, and is set aside like any other deck model; it is - what an older ReSkate loads from the pack. ReSkate 2.0.6 knows a deck by its folder's name only, - so a pack in a folder named `Board_Break_` (the package `Board_Break_Pack`, installed as - `Team-Board_Break_Pack`) with a breakable deck as its own layout breaks boards there with that - one deck, and brings all its decks from this version on. The truck model with the baseplates on - the effectors belongs in the decks inside the pack only: a ReSkate that does not place those - bones would draw the baseplates turning with the hangers, and such a version reads the pack's - own layout, never `decks/`. +```json +"variants": { + "folder": "decks", + "order": ["standard", "wide", "concave", "powell", "slim", "egg", "square", "shaped", "oldschool", "pig"], + "displaces": ["deck_gen_popsicle_cas_main_bundlereftable"] +} +``` -The name is what the deck goes by. The ten the feature was made with are standard, wide, -concave, powell, slim, egg, square, shaped, oldschool and pig, and the console also knows those by -number. Any other deck that follows the recipe works, with no change to ReSkate: +The pack's own `layout.toc` is set aside while one of its decks is in the game; it is what an older +ReSkate loads from the pack. The truck model with the baseplates on the effectors belongs in the +decks inside the pack only: a ReSkate that does not place those bones would draw the baseplates +turning with the hangers, and such a version reads the pack's own layout, never `decks/`. + +The name is what the deck goes by (its folder's name: letters, digits, `_` and `-`). The ten the +feature was made with are in the manifest's `order`, which is also how the console numbers them. +Any other deck folder that follows the recipe works, with no change to ReSkate or the plugin: - Start from the deck mesh as ReSkate Studio exports it (three parts on the bone Deck: the grip sheet, the wood, and a plain copy of the whole deck). Studio only takes back a mesh whose @@ -186,10 +178,9 @@ number. Any other deck that follows the recipe works, with no change to ReSkate: - The sounds are `sounds/light|medium|heavy|metal|body/*.wav` in the folder of any mod that brings a deck (a crack size without sounds of its own takes the nearest that has some), and `sounds/metal/materials.txt` may list the level's materials that are metal, by number. -- A deck may say something of itself in a `deck.ini` in its folder (a pack's `decks//`, or the - `Board_Break_` folder): `label = Old School`, its name in the menus, and `axle = 1.17`, how - far apart its wheels sit against a standard board's (0.8 to 1.6), for a deck wider or narrower - than the standard one. +- A deck may say something of itself in a `deck.ini` in its folder (`decks//deck.ini`): + `label = Old School`, its name in the menus, and `axle = 1.17`, how far apart its wheels sit + against a standard board's (0.8 to 1.6), for a deck wider or narrower than the standard one. ## Seen working in game @@ -232,8 +223,8 @@ too fast (the rates are a third of that now). - The online route: all of the above ran on the offline profile. - The replay editor on this branch (the replay was checked on the older build the feature was developed on). -- The deck card with a deck that is not one of the eight, and with none installed (it draws - nothing then). +- The plugin's DECK card and `boardbreak deck` (2026-10-20, built and tested without the game): + choosing a deck, a deck that is not one of the ten, and a pack with no decks. - A board that does not pass the render pose hook, with the truck model from a pack: its baseplates would follow the hangers. - A mod that brings a truck model of its own beside a deck pack: the pack's is the one that loads. diff --git a/contrib/plugins/README.md b/contrib/plugins/README.md index a1635704..58013c29 100644 --- a/contrib/plugins/README.md +++ b/contrib/plugins/README.md @@ -33,3 +33,14 @@ test`) that `dingosdk_plugin_tests` runs too, and its own page in the ReSkate me pictures (`d:game_image`). `hallofmeat 0|1`. - **grind-exits**: LT / RT in a grind pick the side of the pop (`reskate.skater.grind_exit`, `reskate.input.hide`). `grindexit status`. + +## Throwdown modes + +Throwdown modes made in Lua with the throwdown kit ([throwdown-kit.md](../throwdown-kit.md)): the +plugin registers its modes and publishes what the player should see; ReSkate shows it with skate.'s +native Throwdowns page, setup page, flag, HUD and match panel. + +- **throwdown-modes-test**: two modes through the whole native flow (card, setup page, flag, + waiting card) and no match. The smallest example of the kit. +- **SmokeyDawg58-ReSkate_Throwdown**: SmokeyDawg58's ten modes, with their rules, HUDs, gates and + route editor, all in Lua, inside his asset mod. `tdm help`. diff --git a/contrib/road-rash.md b/contrib/road-rash.md index cbc20ff5..95ca511b 100644 --- a/contrib/road-rash.md +++ b/contrib/road-rash.md @@ -2,8 +2,9 @@ Bails leave marks on the local skater that build up over a session: road dust and a graze first, then scrapes and bruises, then raw wounds, a bruised face and (if the player leaves it on) blood. -A plugin, [road-rash](plugins/road-rash); the pictures themselves come from a content mod. It was -built into ReSkate until 2026-10; what follows is how that worked, and how the plugin still works. +A plugin, [road-rash](plugins/road-rash), that ships inside the Road Rash item pack: the pictures +themselves are the pack's skin items. It was built into ReSkate until 2026-10; what follows is how +that worked, and how the plugin still works. Code: the plugin's Lua in [plugins/road-rash/plugin](plugins/road-rash/plugin), and the core service it wears its marks through, reskate.outfit: diff --git a/contrib/throwdown-kit.md b/contrib/throwdown-kit.md new file mode 100644 index 00000000..e0ba9eaa --- /dev/null +++ b/contrib/throwdown-kit.md @@ -0,0 +1,223 @@ +# The throwdown kit: throwdown modes in Lua + +A throwdown mode is a plugin. ReSkate knows no particular mode: a plugin registers its modes, +publishes documents that say what the player should see, and hears what the player does as +events. ReSkate shows the documents with skate.'s own native widgets: the Throwdowns page, the +setup page, the start flag, the waiting card, the in-game HUD and the match panel. A new mode needs +no change to ReSkate. + +Two plugins use it: + +- [throwdown-modes-test](plugins/throwdown-modes-test): two modes through the whole native flow + (card, setup page, flag, waiting card) and no match. The smallest example. +- [SmokeyDawg58-ReSkate_Throwdown](plugins/SmokeyDawg58-ReSkate_Throwdown): SmokeyDawg58's ten + modes (Deathrace, 1-UP, Spot Jam and the rest), with their rules, HUDs and route editor, all in + Lua. The full example. + +Everything below needs the `throwdowns` permission in `reskate-plugin.json`. A plugin's documents +only drive its own modes, and its events only reach it. + +## 1. Registering a mode + +```lua +reskate.throwdowns.mode{ + id = "duel", -- unique in the plugin, 1 to 32 characters, no "/" + name = "Duel", + description = "Beat the last total. Three misses and you're out.", + art = "UI/MyMod/Throwdowns/img_duel", -- the card's logo: a texture or image asset path + color = 0xff3434ff, -- the card's tint, 0xAABBGGRR (optional) + card = "spot", -- the stock card it is drawn like: "skate", "spot" or "jam" + replaces = "skate", -- optional: takes that stock card's place on the page + order = 10, -- its place among the plugins' modes + flag = "World/MyMod/Flags/duel_Placement", -- optional: the flag's placement preview prefab + cursor_height = 4, -- optional: metres the placement cursor may rise onto things + players = {min = 1, max = 6, default = 2}, +} +``` + +Calling it again with the same id updates the mode; `reskate.throwdowns.remove_mode(id)` takes it +off the page. The page shows the stock S.K.A.T.E. (unless a mode replaces it), Spot Battle and +Skate Jam, then every plugin mode by `order`. Clicking a card sends the `open` event. + +## 2. Documents + +```lua +reskate.throwdowns.ui{setup = ..., waiting = ..., hud = ..., panel = ..., flags = ..., match = ...} +``` + +Publish whenever something changes; every tick is fine, since an unchanged document costs only a +comparison. Any part left out shows nothing. In documents, `mode` is the plugin's own id ("duel"). +Colours are 0xAABBGGRR, times are milliseconds, positions are vectors in world metres, and Steam +IDs are strings. Texts may also be numbers. + +### setup: the setup page + +The stock Spot Battle setup page, relabelled. It shows while the player is on it after `open`. + +```lua +setup = { + mode = "duel", title = "DUEL", art = "UI/...", description = "...", back = "BACK", + players = {caption = "Players", min = 1, max = 6, step = 1, value = 2}, + timer = {caption = "Turn", min = 10, max = 120, step = 10, value = 20}, -- nil: no timer row + rows = { -- at most 12 + {id = "laps", kind = "choice", caption = "Laps", options = {"1", "2", "3"}, value = 1}, -- value from 1 + {id = "boost", kind = "slider", caption = "Boost", min = 0, max = 5, step = 1, value = 2}, + {id = "route", kind = "button", caption = "Route", label = "Place gates"}, + {id = "note", kind = "info", caption = "Area", label = "Anywhere"}, + }, + hide_native = {"rounds"}, -- stock rows taken off (the default) +} +``` + +Moving a slider or a choice sends `setup_row`; pressing a button row sends `setup_button`. Confirm +places the start flag (section 4). + +### waiting: the waiting card + +Shown while the flag is down and the match has not started. + +```lua +waiting = {mode = "duel", title = "DUEL", art = "UI/...", status = "Enrolled skaters | Host starts", + enrolled = 1, capacity = 6, can_start = true, + countdown = {remaining_ms = 5000, total_ms = 10000}} -- optional +``` + +Start sends `start`, Leave sends `leave`. + +### hud: the in-game HUD + +Slots of the native HUD, drawn with the widget family `theme` names (`HUD__Title_..._Widget` +and so on; a mod brings its own in its assets). Every slot is optional. + +```lua +hud = { + active = true, theme = "race", + header = {title, art, status, offset = {x, y}, icon_size = 96, frame_width = 704}, -- 0: the theme's + layout = "side", -- where the board sits: "side" (right edge) or "bottom" + counters = {"LEADER 1,200", "SCORE 900"}, score_width = 480, score_art = "", + clock = Clock, -- the match clock + board = {title = "LEADERBOARD", columns = {"POS", "NAME", "SCORE"}, + variant = "", -- "stamps": a stamp per mark instead of joined letters + style = "outlined", -- or "plain" + heading = "list", -- or "shared" + name_art = "", out_art = "", rank_art = "", value_art = "", value_width = 0, reserve = "", + rows = {BoardRow, ...}}, + results = {title, notice, caption, heading_art = "", title_width = 0, style = "outlined", rows = {BoardRow, ...}}, + intro = {title, art_key, rules, until_ms}, + countdown = Clock, -- 3-2-1-GO + banner = {title, subtitle, art, serial, ms}, -- a new serial shows it again + callout = {text, style, serial, ms}, + warning = {text, art, serial, ms}, + card = {caption, title, image}, -- a trick card; image is a texture path + list = {caption, items = {"KICKFLIP", ...}}, + position = {place = 1, medal = "gold", art = ""}, -- "gold" | "silver" | "bronze" | "white" + timers = {{caption, text = "0:12.40" or Clock}, ...}, timer_art = "", + compass = {at = vector, art = "UI/..."}, + markers = {{at = vector, text = "GATE 3", distance = true}, ...}, -- distance from the skater + blackout = {text}, + editor = {title, variant = "builder", -- or "compact" + prompts = {{inputs = {"UI_DpadLeft"}, caption = "Move", glyph = "", hold = 0.5}, ...}, + info = {title, rows = {{caption, value}, ...}}, + toast = {text, alpha}, + modal = {text, actions = {{input, caption}, ...}}}, +} +-- BoardRow: {rank, name, value, color, self = bool, out = bool, +-- marks = {{text = "S", on = true}, ...}, clock = Clock} +-- Clock: {remaining_ms, total_ms, sampled_ms, ticking = true, up = false}, or a stopwatch +-- {base_ms, sampled_ms, running, cap_ms}. The HUD ticks a clock itself between documents; +-- sampled_ms is reskate.time.now() when the numbers were true. +``` + +### panel: the match panel + +The native details page the pause menu opens during a match. + +```lua +panel = {title, description, art, score_caption = "SCORE", quit = "Quit", + settings = {{icon = "players", caption = "Players", value = "4"}, ...}, -- at most 3; + -- icon "players" | "timer" | "rounds" | a texture + prompts = {{input = "UI_ShoulderL", caption = "Spectate", command = "spectate"}, ...}, + players = {{id = "7656...", name, value, rank, outcome, portrait = "steam", self = true}, ...}} +``` + +Opening it sends `panel_open`; a prompt's button sends `panel_command` with its command. + +### flags: flags for other players + +```lua +flags = {{id = "f1", mode = "duel", leader = "7656...", game = 123, at = vector, yaw = 0, + players = 1, capacity = 6, open = true, + stats = {{title = "LAPS", value = "3"}, ...}}} -- at most 3 +``` + +Each shows on other players' games as a native flag (map point, bubble, map card, Enroll card). +Their Join reaches this plugin on their game as `join`. + +### match: what a running match asks of the game + +```lua +match = {markers = true, -- session markers and Return are blocked; the pause menu's Quit is the plugin's + input_lock = true, -- no skating input (a countdown) + offboard = true, -- the skater is kept off the board + hidden = {"7656..."},-- players whose skater, nametag, map dot and chat bubble are hidden + teleports = true, -- the plugin may teleport the skater even where noclip is off + in_activity = true} -- the game treats the player as in an activity +``` + +## 3. Events + +```lua +reskate.on("throwdown_ui", function(e) -- e = {action, mode, args}: args are strings +end) +``` + +| action | args | +| --- | --- | +| `open` | game: a card was clicked, and the flag registration began (section 4) | +| `setup_row` | row id ("players" and "timer" for those), value (a choice's from 0) | +| `setup_button` | row id | +| `setup_back` | game | +| `setup_confirm` | players, timer seconds | +| `flag_placed` | game, x, y, z, yaw | +| `flag_left` | game | +| `start` | game | +| `leave` | game | +| `quit` | (the pause menu's or the panel's Quit) | +| `join` | flag id, leader, game | +| `panel_open` | | +| `panel_command` | command | +| `dialog` | dialog id, button, text, row, file text (section 5) | + +## 4. The native flag + +One native flag registration exists at a time. Clicking a mode's card begins it at once, with the +mode's players and the setup page, and then sends `open {game}`. Confirm on the setup page goes on +to native flag placement (`setup_confirm`, then `flag_placed`), then to the waiting card, until the +plugin starts the match or the owner leaves. + +```lua +reskate.throwdowns.flag.begin(mode, game, {players, seconds, setup_page = true, cursor_height}) +-- false while another registration is busy; setup_page = false goes straight to placement +reskate.throwdowns.flag.state() +-- {owned, waiting, placing, busy, mine, mode, game}: mode and game only when it is one of the plugin's +reskate.throwdowns.flag.leave() -- refused, finished or cancelled: the registration goes +``` + +## 5. Services a mode uses + +None of these knows a throwdown mode; any plugin may use them under its permission. + +| Call | Permission | What it does | +| --- | --- | --- | +| `reskate.files.list/read/write/remove(path)` | files | the plugin's own data folder, for saved routes and the like: 1 MB a file, 1000 files, 64 calls a second | +| `reskate.ui.dialog(id, {title, message, field, list, buttons, file})`, `reskate.ui.close_dialog(id)` | ui.screen and throwdowns | an overlay dialog: a text field, a list with buttons on each row, up to 4 buttons, a file to open; answers come as `dialog` events, Esc answers "cancel" | +| `reskate.skater.push(velocity)`, `push_wait()`, `push_reset()` | skater.control | the skater's velocity once it is back on its board | +| `reskate.skater.hold(on)` | skater.control | the skater held where it is | +| `reskate.physics.competition(on)`, `stock_ready()`, `prepare()` | skater.control | the game's stock physics while the player competes | +| `reskate.skater.telemetry()`, `reskate.skater.goofy()` | skater.read | speed, air time, the last jump, the physics state | +| `reskate.skater.bone_cam(word, ...)` | camera | the Bone Cam | +| `reskate.camera.free(...)`, `reskate.camera.pad_flight(on)` | camera | the free camera, flown from the pad while placing things from the air | +| `reskate.session.world()`, `reskate.session.spectate(...)` | session.read | the session's world id and map; spectating a player | +| `reskate.tricks.feed(on)`, `reskate.tricks.gesture(name)` | events.tricks | skate.'s trick list as `trick_notes` events; a flip trick's flick diagram | +| `reskate.input.pad_bits/key/wheel/game_buttons/allowed/focus` | input | the pad, keys and wheel, and game buttons kept from the game | +| `reskate.entities.set(id, blueprint, transform, hidden?)`, `remove`, `clear`, `ready`, `status` | world.entities | world objects of the plugin's own (gates, arrows, flags) |