Scheduled Events
Moongate supports Lua-first scheduled events for shard-wide timed behavior.
This system is separate from NPC brain loops and separate from combat or dialogue events.
Use it for things like:
- town crier announcements
- daily or weekly world reminders
- holiday triggers
- scripted world-state changes
Overview
Scheduled events are authored as Lua files under:
moongate_data/scripts/events/**
Each script registers a single event definition through:
local scheduled_events = require("common.scheduled_events")
At runtime, the server:
- loads the Lua definitions
- validates recurrence and schedule fields
- arms one-shot timers on top of
ITimerService - publishes
ScheduledEventTriggeredEvent - forwards the event to global Lua as:
function on_scheduled_event(event)
end
Example
local scheduled_events = require("common.scheduled_events")
return scheduled_events.event("town_crier_morning", {
trigger_name = "town_crier_announcement",
recurrence = "daily",
time = "09:00",
time_zone = "Europe/Rome",
payload = {
message = "Hear ye! The bank is now open."
}
})
Supported Recurrence Types
Current v1 support:
oncedailyweeklymonthly
Once
return scheduled_events.event("server_launch", {
trigger_name = "launch_announcement",
recurrence = "once",
start_at = "2026-03-20T18:00:00Z"
})
Daily
return scheduled_events.event("daily_noon", {
trigger_name = "daily_ping",
recurrence = "daily",
time = "12:00"
})
Weekly
return scheduled_events.event("market_days", {
trigger_name = "market_open",
recurrence = "weekly",
time = "09:00",
days_of_week = { "monday", "wednesday", "friday" }
})
Monthly
return scheduled_events.event("rent_due", {
trigger_name = "rent_due_notice",
recurrence = "monthly",
time = "08:00",
day_of_month = 1
})
Definition Fields
trigger_name- stable logical trigger identifier delivered in the fired event
recurrence- one of
once,daily,weekly,monthly
- one of
enabled- optional, defaults to
true
- optional, defaults to
time- required for
daily,weekly,monthly - format
HH:mm
- required for
time_zone- optional
- defaults to UTC
start_at- required for
once - ISO UTC timestamp recommended
- required for
days_of_week- required for
weekly - lowercase English names like
monday
- required for
day_of_month- required for
monthly - value
1..31
- required for
payload- optional Lua table carried with the fired event
Global Lua Callback
When a scheduled event fires, the global script bridge calls:
function on_scheduled_event(event)
if event.trigger_name == "town_crier_announcement" then
log.info("Scheduled event fired: " .. event.event_id)
end
end
Available event fields:
event.event_idevent.trigger_nameevent.scheduled_at_utcevent.fired_at_utcevent.recurrence_typeevent.payload
Notes
- This is a shard-level global event system, not a brain-local NPC timer system.
enabled = falseprevents the event from being armed.time_zoneis applied when calculating recurring events.- Recurring events reschedule themselves after firing.