Notifications & Text — Notifier, Palette, Captions
Three surfaces for talking to the player, each with a distinct job:
| Surface | Where | Use for |
|---|---|---|
Notifier toasts | top-right feed | Events: dispatches, arrivals, status changes |
Notifier live status | top-left HUD line | A persistent, update-in-place incident status |
Captions | bottom-centre subtitle | Spoken dialogue and narration |
Notifier — rate-limited toasts + live status
Why it exists
Two failure modes are engineered out:
- Feed flooding. A wave dispatch plus five arrivals in two seconds unreadably floods
the notification feed. Queued toasts drain on a fiber with a minimum gap (default
1200 ms, tune via
MinGapMs). - Flickering status. Feed toasts auto-fade; updating one means remove + re-add, which
flashes. The live-status line is instead drawn every frame via
Game.FrameRender, so it updates in place without flicker.
Usage
var notifier = new Notifier(log);
notifier.Start(fibers, flag); // starts the queue drain fiber; once per duty session
// Queued (rate-limited) toasts:
notifier.Show(Palette.Dispatch("unit en route to " + Palette.Key(areaName)));
notifier.ShowBranded("~b~MyPlugin", "~s~subtitle", "body text");
// Immediate variants — for moments that must not wait (must be called from a GameFiber):
notifier.ShowNow("text");
notifier.ShowBrandedNow("~b~MyPlugin", "~s~subtitle", "body");
// Persistent live status (top-left; call as often as you like, it never flashes):
notifier.SetLiveStatus("~b~PANIC ACTIVE", "", "3 units responding");
notifier.ClearLiveStatus();
// Teardown — once per session:
notifier.Clear(); // drop anything still queued
notifier.Stop(); // clears status AND detaches the frame-render hook
Behavior notes
Enabled = falseis a master switch: all toasts drop silently (logging stays).- The queue is bounded (16 entries) so a stuck drain fiber can't grow it unbounded.
- Branded toasts use the
web_lossantospolicedepttexture by default; override withTextureDictionary/TextureName. - Color/style markup (
~b~,~r~, …) is stripped from the live-status line — it is drawn text, not a game notification, so tokens would render literally. - The live-status overlay disables itself for the session if drawing ever throws (a throwing render handler would fire every frame), and the failure is logged once.
- Call
Stop()at session teardown. The frame-render hook must not outlive the notifier across duty toggles.
Palette — the community color standard
Implements the lcpdfr.com "standardisation of API plugin colors" convention. Color the
key words, not whole sentences; always reset with ~s~.
| Constant / helper | Token | Meaning |
|---|---|---|
Palette.Red, Danger(text) | ~r~ | Danger, suspects, critical alerts |
Palette.Blue, Police(text) | ~b~ | Police, dispatch, plugin branding |
Palette.Yellow, Key(text) | ~y~ | Keybinds, objectives, routes |
Palette.Orange, Warn(text) | ~o~ | Warnings, cooldowns |
Palette.Green, Success(text) | ~g~ | Success, Code 4 |
Palette.White | ~w~ | White |
Palette.Reset | ~s~ | Reset to default style |
Palette.NewLine | ~n~ | Line break inside a notification |
Dispatch(text) | — | ~b~Dispatch:~s~ text — a dispatch-voiced line |
notifier.Show(Palette.Dispatch("respond " + Palette.Danger("Code 3") +
" to " + Palette.Key("Mission Row")));
Captions — movie-style dialogue subtitles
Rendered on GTA's own subtitle line (bottom-centre) with a colored speaker label — the right surface for speech, where help text and notifications read as UI.
// Duration derived from text length (reading pace, clamped 1.8–7 s), returned in ms
// so you can pace the next line:
int ms = Captions.Speak("Auditor", "You can't stop me filming.");
GameFiber.Sleep(ms + 300);
Captions.Speak("Officer", "Sir, step back behind the tape.");
// Plain narration (no speaker label):
Captions.Narrate("The crowd is getting restless.");
// Explicit duration:
Captions.Show("Dispatch", "Units be advised...", 4000);
Pacing constants: 45 ms per character, minimum 1800 ms, maximum 7000 ms. Captions are cosmetic — failures are swallowed, never disturbing the scene.