Write conditions
An automation has no separate condition form: the condition is an ordinary if in run(ctx). A module that reaches no action simply does nothing for that event.
If you write no condition, the automation acts on every occurrence of its trigger.
Skip with an early return
Section titled “Skip with an early return”- Read what you need from the run context:
ctx.eventfor the event that started the run,ctx.playerfor the subject player,ctx.inputfor button inputs,ctx.serverfor the server. - Compare it with
if, andreturnwhen the run should not act.
async run(ctx) { if (ctx.event.channel !== 'ChatTeam') return if (!ctx.event.message.includes('!voteban')) return
await ctx.note('Asked for a voteban')}The fields available on ctx.event depend on the event in the trigger; see Squad events.
Combining conditions
Section titled “Combining conditions”Use && when all of several conditions must hold and || when any one is enough. For example, a message that contains !ban or !voteban, sent on the team channel:
const asksForBan = ctx.event.message.includes('!ban') || ctx.event.message.includes('!voteban')
if (ctx.event.channel === 'ChatTeam' && asksForBan) { await ctx.note('Asked for a ban')}Branching between actions
Section titled “Branching between actions”Because the condition is code, one run can take different actions on different branches, which a single filter could not express: warn below a limit and ban at it, as in the counter example below.
Fields that cost a query
Section titled “Fields that cost a query”Some player facts are not part of the event; they are read on demand, with a call: await ctx.player.bansCount(), await ctx.player.country(). A read makes one query the first time it is awaited and is cached until the module performs an action, so a module that never calls it pays nothing. All values come back as strings: convert with Number(...) before comparing. The full list is in the Run context reference.
Counting with counter.<name>
Section titled “Counting with counter.<name>”A counter is how you write “the N-th time in a window”. Declare it in the header counters — a name, an event to count and a window — and read it in run as ctx.counter.<name>:
counters: { tk: { event: 'teamkill', per: 'actor', window: '1h' } },async run(ctx) { if (ctx.counter.tk < 7) { await ctx.rcon('AdminWarn "..." Stop teamkilling.') return }
await ctx.ban({ for: '1h', reason: 'Teamkilling', servers: 'all' })},The comparison is numeric, so <, <=, > and >= are the operators that make sense on a counter.
A counter keeps no state of its own — the number is recomputed from event history before the run — so it survives a restart, and no reset step exists or is needed. Declaring one is walked through step by step in Create an event automation.
Using regex
Section titled “Using regex”Use a JavaScript RegExp: /^!(ban|kick)\b/i.test(ctx.event.message). Matching flags, including case-insensitivity, are whatever you write in the literal; heliana does not rewrite the pattern. A run that takes too long is stopped by the limits, so keep patterns simple.