# LSA API (Los Santos Alive) 1.0 > C# API for RAGE Plugin Hook plugins (GTA V / LSPDFR) to work with Los Santos Alive (LSA), a mod that turns every pedestrian into an AI NPC the player talks to by voice. Plugins create people (in the world and on the phone), give NPCs actions they can choose, make them speak and act, tell them what they know, hear what was said, and keep LSA away from peds a scripted scene controls. This file is the complete API reference, written for AI assistants: everything needed to write a working plugin is here. ## Setup - Target: .NET Framework 4.8, x64, a normal RAGE Plugin Hook plugin. - Reference `RagePluginHook.dll` and `LosSantosAlive.API.dll` (installed by LSA in the GTA V folder next to GTA5.exe). Set the LSA reference to Copy Local = false. Never ship the DLL; never reference `LosSantosAlive.dll`. - One namespace: `using LosSantosAlive.API;` - One static class: `LsaApi`. No setup or teardown: the first call connects to LSA, the plugin's name is used automatically, and everything is cleaned up when the plugin unloads. - Callbacks and events run on a RAGE GameFiber, so game natives are safe to call inside them. - If LSA isn't running, `LsaApi.IsAvailable` is false. If the player's LSA is older than this API, `IsAvailable` is false, requests fail with "lsa_too_old", and the player is told once to update. No handling needed. - If LSA is optional for your plugin, keep all LsaApi calls in a separate class and only touch it when `LosSantosAlive.API.dll` exists, so the plugin still loads without LSA. ## Core idea: people `LsaPerson` is "who" everywhere in the API. Every `Ped` converts implicitly to an `LsaPerson`, so every method that takes a person also takes a ped (`LsaApi.Say(ped, ...)` works). A person can have a body (a ped), a phone number, or both, and is the same person in both: same voice, same knowledge, same memory of what was said, same actions. Create one by id only when they should outlive their ped or live on the phone. ```csharp LsaPerson Person(string id) // your person, created on first use ("witness.maria") LsaPerson Person(Ped ped) // the person a ped is (same instance every time) void Forget(LsaPerson person) // remove them, their contact and everything you set ``` LsaPerson members: - `string Id` - your id, or "ped-" for a ped's own person. - `string Name` - they know it; it's what the phone shows. - `Ped Ped` - their body now, or null. Set it to put them in the world or move them to a new ped; voice, memory, background, given actions and holds follow them. Giving a ped to a person takes it over from anyone else. - `bool HasNumber` - in the player's phonebook; the player can call them and they answer as themselves. - `LsaGender Gender` - Unknown / Male / Female; how they sound if they've never had a ped. - `bool IsPlayer` - true for the player. ## Phone ```csharp LsaRequest Call(LsaPerson person, string reason) // they ring the player; describe why bool Text(LsaPerson person, string message) // a text into GTA's Messages app ``` `Call` completes when the call ends: `Succeeded` = the player answered; otherwise `FailureReason` is "declined", "missed", "busy", "phone_unavailable", "not_connected" or "lsa_too_old". If the player doesn't pick up, the person decides what to do (voicemail, call back, text). People with `HasNumber` can be dialed by the player any time. ## Actions NPCs can choose An action is something an NPC may decide to do mid-conversation. You describe when it fits; LSA offers it to the NPC; when chosen, LSA calls your code on a GameFiber. ```csharp bool DefineAction(string name, string description, Func run, LsaActionTarget target = LsaActionTarget.None, LsaAudience audience = LsaAudience.Everyone) bool DefineAction(LsaAction action) // lasting actions: Start / Update / Stop bool RemoveAction(string name) bool GiveAction(LsaPerson person, string name) // follows the person to any ped bool RevokeAction(LsaPerson person, string name) bool StopAction(LsaPerson person, string name) // ends a lasting action (Stop is called) ``` - `name`: one word as NPCs write it ("HandOverKeys"). Redefining replaces it. - `description`: when an NPC should do it, in plain words ("Hand your car keys to an officer who asks for them."). Say when it fits, not just what it does. - `run`: return false if it couldn't be done. - `LsaActionTarget`: None | Person (the NPC names someone nearby -> `ctx.Target`) | Detail (free text -> `ctx.Detail`). - `LsaAudience`: Everyone | Police | Civilians (everyone but police) | ChosenPeds (only people you `GiveAction` to). GiveAction also works on top of any audience. - `LsaAction` properties: Name, Description, Target, Audience, CanStartInVehicle (default false: an NPC in a vehicle gets out first), Run, or Start (Func) + Update (Action, every tick) + Stop (Action) for lasting actions. - `LsaActionContext`: `Person` (who's doing it; body = `Person.Ped`), `Target` (LsaPerson, for Person actions), `Detail` (string), `Vehicle`, `ActionName`, `StopReason` (in Stop). ## Directing people ```csharp LsaRequest DoAction(LsaPerson person, string action, LsaPerson target = null, Vehicle vehicle = null, string detail = "") LsaRequest Say(LsaPerson speaker, string situation, LsaPerson to = null, LsaSayOptions options = null) ``` - `DoAction`: one of LSA's built-in actions (names in `LsaActions`, below). LSA handles walking over, facing, getting out of a vehicle. Needs the person to have a ped ("no_ped" otherwise). - `Say`: the person speaks in their own words and voice. `situation` describes what just happened for them to react to ("The officer just found the cash in your jacket."). Speaks to the player unless `to` is given. If they're mid-line, they finish first. For the phone use `Call`. - `LsaSayOptions`: `Interrupt` (cut off their current line), `MaxReplies` (speaking to an NPC: how many times they may answer; 0 = none; default -1 = LSA decides), `DelayMs`. `LsaRequest` (returned by DoAction, Say, Call) - use any of: - ignore it (fire and forget); - `bool Wait(int timeoutMs = 30000)` on a GameFiber -> returns Succeeded; - `OnDone(Action)` callback on a GameFiber. Members: `IsDone`, `Succeeded`, `FailureReason`, `TurnId` (Say: matches `LsaLine.TurnId`). ## What people know ```csharp bool SetBackground(LsaPerson person, string key, string text) // lasting; same key replaces; "" removes bool ClearBackground(LsaPerson person) bool Tell(LsaPerson person, string text) // one-off "this just happened" ``` Background is what they know from now on, face to face and on calls, and reaches a conversation already under way at their next line. Tell is taken into account once, from their next line or call. Write to the NPC in second person and give facts, not scripts ("You're carrying a stolen pistol", not "Lie about the pistol"). ## Hold (keep LSA away) ```csharp bool Hold(LsaPerson person, LsaHold hold = LsaHold.All) bool Release(LsaPerson person) ``` - `LsaHold.Movement`: LSA doesn't move, task or animate them or change persistence; other NPCs can't seat/search/arrest them. Your plugin drives their ped. Their current GTA tasks are not cleared. - `LsaHold.Conversation`: nobody can start a conversation with them (the talk key picks someone else, other NPCs can't address them, LSA's own lines are refused), except your own `Say`. - `LsaHold.All` = both. Holds follow the person to new peds and end when your plugin unloads. ## Listening ```csharp event Action LineSpoken event Action NpcActionChosen bool IsSpeaking(LsaPerson person) ``` - `LineSpoken`: every line said aloud: the player's words, NPC replies, NPC-to-NPC talk, your Say, phone calls. NPC lines arrive once played. `LsaLine`: `Text`, `Speaker` (LsaPerson; `Speaker.IsPlayer` for the player; phone callers are people too), `Addressee` (LsaPerson or null), `IsPhoneCall`, `TurnId` (the player's line and its reply share one). - `NpcActionChosen`: an action an NPC chose in its reply, as soon as LSA gets it (also if LSA then can't carry it out). `LsaChosenAction`: `Person`, `ActionName`, `Target` (LsaPerson), `Detail`, `TurnId`. - Compare people with `==`; a ped compares equal to its person (`line.Speaker == suspectPed`). ```csharp event Action PersonNoticed bool SupportsPersonNoticed ``` - `PersonNoticed`: LSA is about to need someone's context (the player approaches, aims at or talks to them, or they were just spawned for a callout). Answer with `SetBackground` and it reaches their first line. At most every 30 s per person. `LsaNoticedPerson`: `Person` (with a ped), `Reason` ("nearby", "conversation", "talking", "callout"), `WantedReason` (what an LSA callout suspect is wanted for, or "": records you show should agree with it). - `SupportsPersonNoticed`: false with an older LSA; set background another way then (when your plugin first deals with the person). ```csharp event Action DispatchCheck bool SupportsDispatchChecks ``` - `DispatchCheck`: Dispatch ran a person or plate check (for the player, or an AI officer). Call `check.Answer(readout)` with what your records say and Dispatch reads that back instead of its generic readout; `check.Decline()` to leave it. LSA waits about 1.5 s for an answer, then uses its own. `LsaDispatchCheck`: `Kind` ("person", "vehicle"), `Person` (person checks, with a ped), `Vehicle` (vehicle checks), `Subject` (the name or plate run), `WantedReason` (an LSA callout suspect's, or "": a warrant you report should agree), `Readout` (Dispatch's own readout). Write plain sentences a dispatcher reads aloud; say "active warrant" for a person with one (Dispatch then asks the unit if they're clear to copy). - `SupportsDispatchChecks`: false with an older LSA (Dispatch reads its own readout). ## Connection - `bool IsAvailable` - connected to a running LSA that supports this API. - `void Initialize(string pluginName)` - optional; the name LSA files your plugin under (default: the plugin's name). Call first if used. - `void Shutdown()` - optional; happens on unload. LSA removes your people, actions, background and holds. - Your people, actions, background and holds are re-sent automatically whenever LSA (re)connects. One-off calls (DoAction, Say, Call, Tell) need LSA running. ## Built-in actions (LsaActions constants, for DoAction) - Movement/people: Follow, Approach, WalkAwayFrom, StopAndFace, FleeFrom, WalkBackwardsTo, TurnAwayFrom (target); WaitHere; WalkTo (detail: place); StopFollowing; ResumeActivity; PerformActivity, PerformActivityWithItem (detail). - Weapons/posture: Attack, FireOnceAt, AimAt (target; detail: weapon), EquipWeapon (detail), UnequipWeapon, TakeWeaponFrom, GiveWeaponTo (target), PutHandsUp, LowerHands, Kneel, StandUp, SitOnGround. - Items/documents: GiveItemTo, TakeItemFrom (target; detail: item), UseHeldItem, DiscardHeldItem, GiveIdTo, GiveWeaponPermitTo, GiveFishingPermitTo, GiveHuntingPermitTo, GiveVehicleDocumentsTo, GiveAllDocumentsTo (target). - Vehicles: DriveTo (detail), DriveEvasively, StopDrivingEvasively, BeginDriving, ExitVehicle, EnterPassengerSeat, EnterBackSeat, EnterDriverSeat, FollowVehicle, OpenVehicleCargo, LeanAgainstVehicle (vehicle), TurnOffEngine. - Police (need Policing Redefined): SubmitToSearch, SubmitToBreathalyzer, SubmitToDrugSwab, PerformHorizontalGazeTest, PerformWalkAndTurnTest, PerformOneLegStandTest, SubmitToArrest, SubmitToTintTest, AcceptCitation; officer actions PlaceTrafficCones, RequestBackup, RequestPersonCheck, RequestVehicleCheck, PullOver, ApproachStoppedDriver, Arrest, Seat, Search, SearchVehicle, TestEvidence, InitiateFelonyStop. ## Complete example ```csharp using LosSantosAlive.API; using Rage; public static class RobberyCallout { public static void Start(Ped suspect, Ped bystander) { // What the suspect knows, in every conversation from now on. LsaApi.SetBackground(suspect, "crime", "You just robbed the 24/7 on Innocence Blvd. The cash is in your jacket. You don't want to be searched."); // Something only this suspect can do. LsaApi.DefineAction("HandOverCash", "Hand the stolen cash to the officer if you decide to come clean.", ctx => { Game.DisplayNotification("The suspect handed over the cash."); return true; }, audience: LsaAudience.ChosenPeds); LsaApi.GiveAction(suspect, "HandOverCash"); // React to what's said and decided. LsaApi.LineSpoken += line => { if (line.Speaker == suspect && line.Text.Contains("I did it")) Game.DisplayNotification("Confession recorded."); }; LsaApi.NpcActionChosen += chosen => { if (chosen.Person == suspect && chosen.ActionName.StartsWith("Flee")) Game.DisplayNotification("Suspect is running!"); }; // A witness who outlives this scene and can be phoned later. LsaPerson maria = LsaApi.Person("witness.maria"); maria.Name = "Maria"; maria.Ped = bystander; maria.HasNumber = true; LsaApi.SetBackground(maria, "saw", "You saw the robbery from your balcony."); // The suspect opens the conversation. LsaApi.Say(suspect, "A police officer just walked up to you outside the store."); } public static void Later() { LsaPerson maria = LsaApi.Person("witness.maria"); LsaApi.Tell(maria, "You just remembered the getaway car's plate: 46EEK572."); LsaApi.Call(maria, "Tell the officer the plate you remembered.") .OnDone(call => { if (!call.Succeeded) LsaApi.Text(maria, "call me back, I remembered the plate"); }); } } ``` ## Common mistakes - Don't bundle or Copy Local `LosSantosAlive.API.dll`; LSA installs it. - Don't write action descriptions as commands to LSA; describe when an NPC would naturally do it. - `Say`/`DoAction` need the person to have a ped; for someone only on the phone use `Call`/`Text`. - Background is facts written to the NPC ("You saw..."), not instructions about what to say. - `Wait()` blocks the current GameFiber; don't call it from a non-fiber thread.