Lua scripting

Agenda

Plans with people at a place and a time, shared by every mod: checked for clashes, kept in the save, reserved in the NPCs' routines, shown in the agenda.

A mod that makes plans (an outing, a meeting, a class, a club night) books them into the shared agenda rather than keeping its own diary. Every mod then sees the same day: the player cannot be booked into two places at once, a contact into two outings, or a coffee at a cafe that is closed. The player sees them all behind the calendar on the map's rail, with where, with whom, how far and when.

lualocal M = "ynl_Nightlife"

local r = Agenda:propose(M, "dinner_" .. person:id(), {
	title = "Dinner with " .. person:name(),
	people = { person },          -- Actors, People references or ids
	inHours = 24,                 -- or at = an absolute time (Events:now() counts the same hours)
	duration = 2,
	tags = { "restaurant" },      -- any venue of these types...
	-- building = id, or here = true: ...or this exact building
	accepted = true,              -- false (the default): an invitation waiting for Agenda:respond
})
if not r.ok then
	Game:Narrate(r.reason)        -- "Noor is at work then.", "That overlaps "Coffee with Lena"."...
end

Checks

Agenda:propose refuses, with a reason to show, when:

  • the player has another plan at that time (any mod's);
  • someone in people is no longer a contact (blocked or deleted), already has plans then, or is at work then (their routine; pass ignoreRoutine = true if your story gave them the time off);
  • none of the tags is open at that hour (opening hours from Map/amenities.json);
  • the building is in another city, or the player could not get there in time from where they are.

Agenda:check(options) answers the same question without booking: nil, or the reason.

Life of a plan

State Meaning
invited Proposed, waiting for Agenda:respond(mod, key, accept [, reason]). Unanswered when its window opens, it is declined ("no answer").
accepted On. From early hours before the start (default 1) to late hours after it (default 3) is its window.
completed You called Agenda:complete(mod, key), typically in the scene where it happens.
missed The window closed while it was still accepted.
cancelled You called Agenda:cancel(mod, key, reason), or someone in it was blocked or deleted ("unavailable").
declined Refused through respond, or never answered.
  • While the window is open, each person in the plan is reserved at the venue in the NPC routines: that is where the game places them, instead of their schedule. Completing, cancelling or missing the plan, or turning your mod off, releases them.
  • One hour before, the player gets a reminder notification, and one when it is missed, both linking to the agenda. Pass notify = false if your mod sends its own (ul_Phone does).
  • Agenda:isHere(mod, key) is true when the player is at the place (the building, or a venue of one of the tags) inside the window: check it before running the meeting.
  • Every change is an agendaChanged event: Events:on(M, "agendaChanged", function(mod, key, state) ... end).
  • A suggestion in dialogue is not a plan: only what is in the agenda reserves anyone.

Moving your own saved plans in

A mod that kept plans in its own variables migrates them once, with migrate = true: the plan goes in as it was agreed, without the checks (it was valid when it was made), and the person is not asked again. Look it up with Agenda:get first so migrating twice does nothing. See ul_Phone's P.migrate for a complete example.

Method Does
Agenda:propose(mod, key, options) Books; { ok, id } or { ok = false, reason }.
Agenda:check(options) nil, or why it would be refused.
Agenda:respond(mod, key, accept [, reason]) Answers an invitation.
Agenda:cancel(mod, key [, reason]) Cancels an invited or accepted plan.
Agenda:complete(mod, key) Marks an accepted plan done.
Agenda:get(mod, key) The plan as a table (title, state, at, duration, people, tags, building, place, reason, here), or nil.
Agenda:list([mod]) Active plans soonest first, then ended ones.
Agenda:isHere(mod, key) The player is there, in the window.
Agenda:here() { id, name, tag } of the building the player is in, nil outdoors.
Agenda:version() The API version, 1.