-
Notifications
You must be signed in to change notification settings - Fork 177
Lich Triggers
The concept of triggers is that Lich will respond automatically to certain game output without the need to run a separate script. Historically, the ability to set triggers is a function of the Front End being used. Lich-based triggers are front-end agnostic and built within Lich itself. Thus, they can be used across and between front ends. Simple triggers have a fairly low barrier to entry for users, and more advanced uses can allow some complex handling without writing a dedicated script. Further, triggers can supplement the use of curated or custom Lich scripts. At some point, though, the complexity of an action calls for writing a dedicated script.
Lich's triggers are defined by the user in a yaml file along with the desired trigger responses. Triggers are then monitored for and acted upon with a persistent companion script called trigger-watcher
. Fundamentally, Lich's triggers use class Flags
which is defined in the events
script and at a basic level monitor for user-defined game output. In order for Lich triggers to work, triggers must be defined properly in the yaml, and both the events
and trigger-watcher
script must stay running.
The structure of each trigger is as follows:
- The top level heading of
lich_triggers
(required) - Beneath that and indented, the name of this specific trigger. This is arbitrary -- name it what you want.
- Beneath that and indented, a section called
triggers:
. This represents the game output you want the trigger to look for and then take action. - Beneath that and indented, a section called
responses:
. When Lich sees the output you defined in thetriggers
section, it will process these trigger responses. - Optionally, a section called
use_with_scripts:
that specifies that the trigger should only fire when one or more of those scripts are running.
Let's look at an extremely simple trigger.
# LICH TRIGGERS
# Yaml for Lich-based triggers
lich_triggers:
wave_hello:
triggers:
- Bobafett just arrived
responses:
- wave Bobafett
This trigger recognizes when a character named Bobafett enters the room, and it waves to them. What's happening behind the scenes is that Lich is watching all game output lines for Bobafett just arrived
. When it sees that, it takes the action you've defined in responses
and it will send wave Bobafett
as a game input command.
Only two things are necessary to be up and running with triggers:
- Define your triggers in a
lich_triggers:
section in yourCharname-setup.yaml
or set them up in a separate file namedCharname-triggers.yaml
. Both ways are supported. - Run the
trigger-watcher
script. It's recommended to add this to your autostarts.
Within a single trigger name, you can specify multiple triggers and multiple responses. Here are some simple examples:
# LICH TRIGGERS
# Yaml for Lich-based triggers
lich_triggers:
wave_hello:
triggers:
- Bobafett just arrived
- Hansolo just arrived
responses:
- wave
Here we've specified two different triggers, and modified our response slightly. If Lich sees game output of either Bobafett just arrived
OR Hansolo just arrived
, it will trigger a response of game input wave
.
# LICH TRIGGERS
# Yaml for Lich-based triggers
lich_triggers:
wave_hello:
triggers:
- Bobafett just arrived
responses:
- wave Bobafett
- kick Bobafett
Here we've specified a single trigger but two responses. If Lich sees Bobafett enter the room, it will send the two responses as game commands one right after the other: wave Bobafett
and kick Bobafett
.
A set of trigger commands is provided for use by the user. These commands tell Lich to treat trigger responses in various ways. Commands are always preceded by the =
sign, which tells Lich to run it as a trigger command. Trigger response lines must begin with these commands to be properly parsed. With the exception of the elsif/else
parts of if
functionality, trigger commands cannot be embedded. However, since multiple trigger response lines are supported, just add additional response lines if you want to use additional trigger commands. NOTE: Enclose all trigger command responses in curly braces.
Trigger Command | Description | Example | Notes |
---|---|---|---|
=exec |
Execute a script. | =exec {<script> [arguments]} |
|
=execw |
Execute a script and wait to complete the script before moving on. | =execw {<script> [arguments]} |
|
=eval |
Evaluate as Lich/Ruby code. | =eval {DRC.message("hello")} |
|
=uvar |
Set or delete a Lich User Variable. |
=uvar set MyUserVariable 22 =uvar delete MyUserVariable
|
You can reference a stored user variable in your triggers via $UserVarName . Can embed simple Lich/Ruby code, enclosed in curly braces to be evaluated. |
=logf |
Log to a file. | =logf {<filename> <text to log>} |
Creates the file if it doesn't exist. Appends the data if it does. Includes a timestamp. Can embed simple Lich/Ruby code, enclosed in curly braces, to be evaluated before logging. |
=logw |
Log to a window. | =logw {<windowname> <text to log>} |
Creates the window if it doesn't exist. Includes a timestamp. Can embed simple Lich/Ruby code, enclosed in curly braces, to be evaluated before logging. |
=pause |
Pause a specified amount of seconds. | =pause {10} |
|
=if =elsif =else
|
Allow if, elsif, else functionality. | =if {3 > 2} {DRC.message("true")} =else {DRC.message("else")} |
Can have multiple actions for each if/elsif/else . Can have multiple elsif 's. Nesting of these commands not currently supported, but valid Ruby works within them. Note the use of curly brackets, which are required. |
=reload |
Reloads yaml trigger settings without killing the script. | =reload |
Takes no arguments. An easy way to use this is to set up a trigger that uses this command when it sees a known phrase. Then type in game echo <the phrase to trigger> . Set it to an alias for even easier use. |
Triggers support regex and trigger responses support regex substitutions and Lich UserVar substitutions.
To use regex substitutions, use capture groups in your trigger and reference them via $1
through $9
. You are limited to 9 regex substitutions. Named capture groups are not currently supported.
lich_triggers:
regex_sub_test:
triggers:
- You are (.*) years old
responses:
- say I am $1
>age
You are one hundred twenty-seven years old.
Among Elves, you are considered an adult.
To the other races, you appear to be young.
You are aging at a normal rate for an Elf.
[Type AGE HELP for more options.]
>
[trigger-watcher]>say I am one hundred twenty-seven
You say, "I am one hundred twenty-seven."
NOTE: If you're using regex substitution, use only a single trigger response.
To use UserVar substitutions, use the same $
character and reference the UserVar by its name. The first character in a UserVar cannot be a number. Otherwise, no limitations on the name.
lich_triggers:
uservar_test:
triggers:
- What are your friend's names?
responses:
- say My friends are $friends # friends is a UserVar
Dilbert asks, "What are your friend's names?"
>
[trigger-watcher]>say My friends are ["Bob", "Bill", "Bernie", "Beatrice"]
You say, "My friends are ["Bob", "Bill", "Bernie", "Beatrice"]."
With use of the =eval
trigger command, as well as embedded code evaluation in trigger responses, you can structure advanced triggers. If desired, you can also specify each individual trigger to only fire if one of a list of specified scripts is running by way of a use_with_scripts
section in the trigger, or to NOT fire if one of a list of specified no_use_scripts
is running. Triggers will always favor a decision based on no_use_scripts
, meaning if any of the no_use_scripts
are running, the trigger will not fire even if one of the use_with_scripts
is running.
With advanced trigger responses, you will need to wrap the entire response line in quotes and then be careful about nested quotes. The use of Visual Studio code is recommended here, as it will visually color the line to let you know whether it's accepting it as a single trigger response string.
The following advanced trigger example tries to teach anyone who enters the room, but only if script afk
is running, and only if their name is included in your UserVars.friends
user variable, and only if you're currently in room 1234.
teach_friends:
use_with_scripts:
- afk
triggers:
- 'Also here: (\w+)'
responses:
- '=eval {UserVars.RoomOccupants.each {|name| fput("teach #{name}") if UserVars.friends.include?(name) && Room.current.id == 1234}}'