Make a fight profile react to the fight with rules: a condition such as low life or an enemy nearby, and an action such as retreating, healing, focusing a target or ending the turn, with every subject, test, action and target.
Rules make a profile react to what happens in the fight: retreat when the character's life runs low, heal an ally in trouble, hit a given monster first while it's there, keep away when enemies crowd in. Each rule is a condition and one action, and the Rules section of the editor lists them in order.
"rules": [
{ "when": { "self.life": { "below": "30%" } }, "do": { "retreat": { "to": "outOfReach" } } },
{ "when": { "ally.life": { "below": "40%" } }, "do": { "heal": { "target": "lowestLifeAlly" } } }
]
How rules apply
Before each action of the character's turn, the module checks every rule's condition against the fight as it is at that moment, so a rule can start or stop applying in the middle of a turn. A rule without a condition applies all the time.
Rules apply in the turns of a summon the character controls too, the summon being the one who acts. There, the Character subjects read the summon, and Self names it: Pass every turn passes its turns as well.
Rules come in two kinds.
Modifiers change how the module scores a turn, and add up:
- every Focus and Avoid whose condition holds applies;
- of the movement rules, Retreat, Approach and Keep distance, only the first one whose condition holds applies.
Forcing actions tell the character what to do next: Cast, Attack, Heal, Buff and End the turn. The opening's spells come first, then these rules, in their order. The first one that can be played right now becomes the character's next action, and the module plays the rest of the turn freely. One that can't be played, for lack of AP, of a target in range or of the target itself, is passed over.
So order matters for forcing actions: put the most urgent first. A rule like "heal when an ally is low" placed above "attack the lowest life enemy" heals first whenever both apply.
Actions
| Action | JSON | Settings | What it does |
|---|---|---|---|
| Cast | cast |
spell: a spell, or "weapon" (Weapon or bare hands in the editor), required. target: optional. |
Casts this spell first, on the target when one is set, otherwise wherever it does the most. |
| Attack | attack |
target: optional |
Attacks first, with its best damaging spell or the weapon, on the target when one is set. |
| Heal | heal |
target: optional |
Heals first, the target when one is set. |
| Buff | buff |
target: optional |
Casts a buff first, on the target when one is set. |
| Retreat | retreat |
to: Cover (cover) or Out of reach (outOfReach) |
Ends its turns away from danger: Cover, out of every enemy's sight when it can, as Hide positioning does; Out of reach, where the danger is least, as Kite does. |
| Approach | approach |
target: optional |
Ends its turns close to the target, or to the nearest enemy when none is set. |
| Keep distance | keepDistance |
min and max: cells |
Ends its turns between min and max cells from the nearest enemy. max 0 means no upper limit. |
| Focus | focus |
target |
Hitting the target scores twice as much. |
| Avoid | avoid |
spell: a spell, or "weapon" (Weapon or bare hands in the editor). target: optional. |
Doesn't cast that spell, and hitting the target counts nothing, while the rule applies. |
| End the turn | endTurn |
after: seconds, default 0 |
Ends the turn without acting, once that many seconds have passed since it began. |
End the turn is a forcing action like the others: when it's the first one that can be played, the character does nothing else in that turn. Its delay never costs the turn: the module ends it at least 2 seconds before the turn's time runs out, whatever after says. A rule with no condition that ends the turn is what Pass every turn after (seconds) writes in Play.
Targets
A rule's target names one fighter, worked out again at each decision.
| Target | JSON | The fighter |
|---|---|---|
| Anyone | Left out | No one in particular: the module chooses. |
| Self | "self" |
The character. |
| Lowest life enemy | "lowestLifeEnemy" |
The enemy with the least life left. |
| Lowest life ally | "lowestLifeAlly" |
The ally with the least life left, the character not counted. |
| Closest enemy | "closestEnemy" |
The enemy nearest the character. |
| Most dangerous enemy | "mostDangerousEnemy" |
The enemy that could deal the character the most where it stands. |
| A monster | { "monster": 4109 } |
An enemy of that monster. |
| A race | { "race": 137 } |
An enemy of that monster race. |
{ "fighter": -2 } |
Only in the JSON: one fighter of the fight, by the id the game gives it. Mostly for scripts. |
When two fighters tie, the one with the lowest id is taken. A target that isn't in the fight, such as a monster that isn't there or that died, makes a forcing rule pass over itself.
Conditions
A condition holds when every test in it holds. In the editor, Only when opens the condition, Test adds a test, and All of, Any of and Not add a group.
Subjects
Each test reads one subject of the fight. The editor names it as whose and what, such as Character · HP.
| Subject | JSON | Tests | Reads |
|---|---|---|---|
| Character · HP | self.life |
below, above |
The character's life, as a number or a percent of its maximum. |
| Character · Shield | self.shield |
below, above |
Its shield points, as a number or a percent of its maximum life. |
| Character · AP | self.ap |
below, above |
Its AP left. |
| Character · MP | self.mp |
below, above |
Its MP left. |
| Character · States | self.state |
is |
Whether it is in that state. |
| Enemies · States | enemy.state |
is |
Whether an enemy is in that state. |
| Allies · States | ally.state |
is |
Whether an ally is in that state, the character not counted. |
| Allies · HP | ally.life |
below, above |
Whether an ally's life is in that range, the character not counted. |
| Enemies · Number | enemies.count |
is, atLeast, atMost |
How many enemies are alive, summons included. |
| Allies · Number | allies.count |
is, atLeast, atMost |
How many allies are alive, summons included, the character not counted. |
| Enemies · Nearby | enemies.within |
cells, then atLeast, atMost |
How many enemies stand within cells cells of the character. |
| Allies · Nearby | allies.within |
cells, then atLeast, atMost |
How many allies stand within cells cells of the character. |
| Enemies · Monster | enemy.monster |
is |
Whether that monster is among the living enemies. |
| Enemies · Race | enemy.race |
is |
Whether a monster of that race is among the living enemies. |
| Fight · Round | fight.round |
is, atLeast, atMost |
The fight's round. |
| Fight · Turns | fight.turn |
is, atLeast, atMost |
How many turns the character, or the summon whose turn it is, has played in this fight, the current one included. |
| Target · HP | target.life |
below, above |
In a spell's condition only: the life of the fighter the spell is cast on. |
| Target · Distance | target.distance |
below, above |
In a spell's condition only: how many cells away that fighter is. |
Each subject takes only the tests of its row. A test it doesn't take, such as below on Enemies · Count, a percent on Character · AP, Character · MP or Target · Distance, or Nearby without Within (cells), is refused when you save, naming it.
A subject this Asterobot doesn't know never holds, and the profile shows a warning for it. So do the Target subjects outside a spell's condition.
Tests
| Test | JSON | Holds when |
|---|---|---|
| Below | below |
The value is strictly less. A number, or a percent written as text, such as "30%". |
| Above | above |
The value is strictly more. A number or a percent. |
| Is | is |
The value is exactly this, or for states, monsters and races, this one is there. |
| At least | atLeast |
The count is this or more. |
| At most | atMost |
The count is this or less. |
| Within (cells) | cells |
For Nearby: the distance counted, in cells. |
A test with several bounds needs all of them: { "below": "60%", "above": "20%" } holds between a fifth and three fifths of the character's life.
Groups
| Group | JSON | Holds when |
|---|---|---|
| All of these | all |
Every condition in its list holds. |
| Any of these | any |
At least one condition in its list holds. |
| Not this | not |
Its condition doesn't hold. |
Groups go inside a condition and can hold groups of their own. This condition holds in the first two rounds, or when an enemy is in the Weakened state (a state's id, picked by name in the editor), as long as fewer than 3 enemies stand within 2 cells:
"when": {
"any": [
{ "fight.round": { "atMost": 2 } },
{ "enemy.state": { "is": 42 } }
],
"not": { "enemies.within": { "cells": 2, "atLeast": 3 } }
}
Examples
End the turns where the danger is least while the character's life is below 30%:
{ "when": { "self.life": { "below": "30%" } }, "do": { "retreat": { "to": "outOfReach" } } }
Keep a healer's allies alive first:
{ "when": { "ally.life": { "below": "40%" } }, "do": { "heal": { "target": "lowestLifeAlly" } } }
Don't let enemies surround the character:
{ "when": { "enemies.within": { "cells": 1, "atLeast": 2 } }, "do": { "keepDistance": { "min": 2 } } }
Hit the L'il Gloot first while it's in the fight:
{ "when": { "enemy.monster": { "is": 4109 } }, "do": { "focus": { "target": { "monster": 4109 } } } }
Keep the weapon for the end of the turn: no weapon hit while the character still has more than 4 AP:
{ "when": { "self.ap": { "above": 4 } }, "do": { "avoid": { "spell": "weapon" } } }
Wait 10 seconds and pass from round 30 on, to let a long fight run out:
{ "when": { "fight.round": { "atLeast": 30 } }, "do": { "endTurn": { "after": 10 } } }
Profile examples puts rules together with the other settings in whole profiles.