Getting started
1. Install the runtime
Install the Tempest.Scripting runtime through the launcher like any other mod, then launch the game. A console window opens next to it, and the same lines go to %TEMP%\tempest-scripting.log. A healthy start looks like this:
[resolve] GNames/GObjects live
[hook] ProcessEvent detour live at 0x...
[resolve] GEngine live; objects=139788 names=139379
[hook] ProcessInternal detour live at 0x...
[loader] 1 mod(s): ...
[boot] readyAny NOTE: or ... not found line means something did not resolve; see troubleshooting.
2. Write a mod
A mod is a folder, anywhere on disk, with a manifest.toml and a scripts/ directory:
my-first-mod/
manifest.toml
scripts/
main.lua[mod]
id = "my-first-mod"
name = "My First Mod"
version = "0.1.0"
authors = ["you"]-- scripts/main.lua
print("[" .. MOD .. "] loaded")
-- Runs after the game's PostLogin: greet the joining player.
tempest.on("TgGame.TgGame.PostLogin", function(game, params)
local pc = params.NewPlayer
pc:ClientMessage("welcome, " .. tostring(pc.PlayerReplicationInfo.PlayerName))
end)
-- A console command: type `hello Tom` in the game console.
tempest.command("hello", function(pc, rest, argv)
pc:ClientMessage("hello " .. (argv[1] or "world"))
end, "hello [name]")Scripts in a mod run alphabetically. Everything printed with print lands in the log and the console window, prefixed with the mod id.
3. Pack and install
Pack the folder with the Tempest CLI:
tempest mod pack my-first-mod my-first-mod.tempestThen install the .tempest file in the launcher: drag it onto the launcher, double-click it, or pick it from the mods screen. Launch the game and look for [my-first-mod] loaded in the log.
To update a mod, pack and install it again; the launcher replaces the previous version.
4. Iterate while the game runs
Scripts reload in place, so a script change does not need a game restart. From the game console (F2 when the console mod is enabled):
tempest_reload reload every mod
tempest_reload my-first-mod reload one mod (its hooks, commands and keys are dropped first)
lua print(tempest.mods()) run Lua from the game console
lua =tempest.local_player() print an expressionThe runtime's own console window is a Lua REPL as well: type tempest.reload() or =tempest.status().notes there. Lines run on the game thread.
A new version of the runtime DLL does need a game restart.
5. Editor completion
types/tempest.d.lua in the Tempest.Scripting repository describes the whole API for the Lua Language Server. Copy it into your mod next to a .luarc.json:
{
"runtime.version": "Lua 5.4",
"workspace.library": ["types"],
"diagnostics.globals": ["MOD", "shared"]
}Open the mod folder in VS Code with the Lua extension and tempest.*, memory.*, objects, arrays and maps complete.
For the game's own classes, run tempest.dump_sdk("C:/path/to/my-first-mod/types/sdk") once from the console (or bind it to a key with tempest.on_key). It writes one <Package>.lua per package, generated from live reflection: every class with its fields and functions, typed. tempest.local_player() is then an Engine.PlayerController, and pc.Pawn.Location completes.
Hook handlers receive the generic Object, so tell the language server what it is:
tempest.on("PostRender", function(this, params)
---@cast this Engine.HUD
local pc = this.PlayerOwner -- completes as Engine.PlayerController
end)6. Explore
tempest.trace("PostRender", 5) logs the first five firings of an event with the object and its parameters, which is the quickest way to find out what fires and with what. obj:prop("Name") describes a property, obj.Func:params() lists a function's parameters, and tempest.status() reports what resolved.
