Kartik Scripts

Custom Callouts

You can add your own callouts in client/open/custom_callouts.lua. It runs on the client of the unit who accepted the callout.

Step 1: add it to the list

In shared/config_callouts.lua, add an entry to Config.Callouts.list:

{ id = 'loitering', service = 'police', label = 'Loitering', code = '10-37', priority = 3, weight = 5,
  description = 'Group loitering outside a store.' },

Step 2: register the scenario

In client/open/custom_callouts.lua, register a scenario with the same id:

RegisterCallout('loitering', {
    tasks = {
        { id = 'talk', label = 'task_check_id' },
        { id = 'resolve', label = 'task_arrest_or_release', final = true },
    },
    setup = function(ctx)
        local pos = FindPedSpot(ctx.coords, 15.0)
        for i = 1, 2 do
            local ped = ctx:SpawnPed(RandomFrom(Config.CalloutPeds.suspects), pos + vec3(i, 0.0, 0.0), 0.0)
            TaskStartScenarioInPlace(ped, 'WORLD_HUMAN_SMOKING', 0, true)
            ctx:AddSuspect(ped, { compliant = true })
        end
    end,
    update = function(ctx)
        ctx:Task('talk', ctx:AnySuspect(function(_, s) return s.idChecked end))
        ctx:Task('resolve', ctx:SuspectsHandled())
    end,
})

Restart kartik-ers and the callout is offered like any other.

The scenario

FieldWhen it runs
tasksThe HUD checklist. { id, label, optional = true, final = true }
pending(ctx)Every 500 ms until the scene spawns (e.g. dispatch updates on the way)
setup(ctx)Once, when the unit gets close. Spawn everything here
onArrive(ctx)Once, when the unit is on scene
update(ctx)Every tick after the scene spawns. Return 'completed' or 'failed' to finish
cleanup(ctx)When the callout ends, however it ends
assistFor joint callouts: tasks for assisting services (see below)

The callout completes on its own once every required task is ticked. Task labels are locale keys: add your own to locales/en.json.

The ctx API

Location

MethodReturns
ctx.coords, ctx.headingThe road node the callout was placed on
ctx:RoadSide(offset)A point at the side of the road
FindPedSpot(coords, radius)A pavement spot for a ped
ctx.stateA free table for your own data

Spawning

Method
ctx:SpawnPed(model, coords, heading)A ped, cleaned up when the callout ends
ctx:SpawnVehicle(model, coords, heading)A vehicle
ctx:SpawnPedInVehicle(vehicle, model, seat)A ped in a seat
ctx:SpawnObject(model, coords, heading)A prop
ctx:SpawnPatient(coords, model, conditionId)A patient on the ground, for the medical system

People and vehicles

Method
ctx:AddSuspect(ped, overrides)Registers a suspect
ctx:AddVictim(ped, overrides)Registers a victim (or a patient with condition)
ctx:AddCivilian(ped, overrides)Registers a witness or bystander
ctx:FlagVehicle(vehicle, { stolen = true })Flags a vehicle on its record
ctx:SetTarget(entity, label)Routes the unit to a moving entity

overrides shape the person's record and behaviour:

{
    flags = { wanted = true, armed = true },
    bac = 0.12, drugs = true,
    weapon = true, weaponLabel = 'Knife',
    items = { 'Stolen watch' },
    flee = true, hostile = true, compliant = true,
    condition = 'fracture',            -- for patients (config_medical.lua)
    description = 'a man in a red cap', -- answer to "Can you describe the suspect?"
}

Tasks and checks

Method
ctx:Task(id, condition)Ticks a task when condition is true
ctx:CompleteTask(id)Ticks a task now
ctx:IsTaskDone(id) / ctx:AllTasksDone()
ctx:SetTaskOptional(id, optional)Makes a task optional or required
ctx:SuspectsHandled()Every suspect arrested, released or gone
ctx:VictimsHandled()Every victim dealt with
ctx:VictimsCaredFor()Every patient treated, transported or handed to EMS
ctx:AnySuspect(fn) / ctx:AnyVictim(fn) / ctx:AllVictims(fn)fn(ped, state) checks, e.g. state.idChecked, state.cuffed, state.treated
ctx:SceneResolved()Nothing left to do on scene
ctx:Elapsed()Seconds since the callout was accepted

Scene actions

-- "press E here" with a progress bar
ctx:AddAction('valve', { at = coords, label = 'action_shut_gas', time = 6000, run = function(ctx) end })
ctx:IsActionDone('valve')

-- a choice menu instead of a progress bar
ctx:AddAction('agent', { at = coords, label = 'action_mitigate',
    choices = function(ctx) return { ... } end,
    choose = function(ctx, id) return 'done' end }) -- nil | 'done' | 'close'

Investigations

Method
ctx:AddLead(id, text) / ctx:HasLead(id) / ctx:LeadCount()Leads listed on the HUD
ctx:AddSearchArea(center, radius)A yellow search circle (never centred exactly on the target)
ctx:StartTracker(entity, { interval, min, max, label }) / ctx:StopTracker()GPS or phone pings
AddTalkDown(ctx, id, { at = ped, profile = Config.Negotiation.barricade, onSuccess = fn, onFail = fn })A negotiation with a trust meter

Fires and patients

Method
ctx:AddFire(coords, children)A fire with spread points
ctx:FiresOut(radius)True when every fire in range is out
ctx:SetPatientCondition(ped, conditionId)The patient deteriorates (assisting EMS sees it too)

HUD

Method
ctx:SetLabel(text)Renames the call, e.g. when it escalates
ctx:SetObjective(text)The objective line
ctx:AddBlip(entity, sprite, colour, label, scale)A blip, removed when the callout ends

Fixed locations

By default a callout is placed on a road 350 to 1100 m from the unit. To use fixed spots instead, add locations to the list entry:

{ id = 'bank_alarm', service = 'police', ..., locations = { vec4(150.2, -1040.3, 29.4, 340.0), vec4(-1212.9, -330.6, 37.8, 25.0) } },

Or name a Config table, like the gas station fire does: locations = 'FuelStations'.

Joint callouts

Add assist = { 'ambulance', 'tow' } to the list entry. Assisting units get the default tasks for their service. To give them your own:

RegisterCallout('my_scene', {
    -- ...
    assist = {
        ambulance = {
            tasks = { { id = 'treat', label = 'task_stabilise_all', final = true } },
            update = function(ctx) ctx:Task('treat', ctx:VictimsCaredFor()) end,
        },
        police = 'cordon', -- police only close the road
    },
})

Everything you register with AddSuspect, AddVictim, AddCivilian and FlagVehicle is shared with assisting units, and the approached, idChecked, treated, arrested, released and delivered flags are synced.

The built-in scenarios in client/callouts/ are escrowed, but custom_callouts.lua has the full list of helpers in its header comment.

On this page