> For the complete documentation index, see [llms.txt](https://axiomemu.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://axiomemu.gitbook.io/docs/data/monster/monsterairule.md).

# MonsterAIRule

Defines conditional rules that temporarily override a monster class's active AI Unit based on calendar date and time. While a rule is active, every live monster of the target class switches from its `BasicAI` to the rule's `Unit` until the rule expires.

## File Location

`Data/Monster/MonsterAIRule.xml`

## Dependencies

| Depends On                                                 | Purpose                                                |
| ---------------------------------------------------------- | ------------------------------------------------------ |
| [MonsterAIUnit.xml](/docs/data/monster/monsteraiunit.md)   | Supplies the replacement AI personality                |
| [MonsterAIGroup.xml](/docs/data/monster/monsteraigroup.md) | Assigns each monster's `BasicAI` (the rule's fallback) |
| [Monster.xml](/docs/data/monster/monster.md)               | Defines the monster classes referenced by `Class`      |

| Used By               | Purpose                                                    |
| --------------------- | ---------------------------------------------------------- |
| Monster AI dispatcher | Evaluates every rule on each AI tick and applies overrides |

## How It Works

1. The AI dispatcher walks the rule list on every AI tick.
2. Each rule is tested against the current server clock (and, when relevant, server events).
3. If a rule is valid and past its `WaitTime` but still inside `WaitTime + ContinuanceTime`, the target class is tagged with the rule's `Unit`.
4. On the next AI update, every live monster of that class has its `CurrentAI` switched to that `Unit`; its `BasicAI` is preserved untouched.
5. When no rule is active for the class, monsters fall back to `BasicAI` from [MonsterAIGroup.xml](/docs/data/monster/monsteraigroup.md).

{% hint style="info" %}
This is an AI Unit override, not a stat modifier. The Automata, Element bindings, and `DelayTime` of the new Unit completely replace the monster's behaviour for the duration of the rule.
{% endhint %}

## Current Status

{% hint style="warning" %}
The shipped configuration file is empty. The loader and dispatcher are fully wired; add `<Rule>` entries to activate the system.
{% endhint %}

```xml
<?xml version="1.0" ?>
<MonsterAIRule/>
```

## Configuration Structure

### Rule Attributes

| Attribute         | Type       | Required    | Description                                                                                                                      |
| ----------------- | ---------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `Number`          | int        | Yes         | Rule identifier (informational)                                                                                                  |
| `Class`           | int        | Yes         | Target monster class (from [Monster.xml](/docs/data/monster/monster.md)). All live monsters of this class are affected           |
| `Description`     | string     | No          | Human-readable label, up to 99 characters                                                                                        |
| `Unit`            | int        | Yes         | AI Unit that replaces `BasicAI` while the rule is active. Must exist in [MonsterAIUnit.xml](/docs/data/monster/monsteraiunit.md) |
| `Condition`       | int        | Yes         | Condition type. See below. Only `1` is functional                                                                                |
| `WaitTime`        | int        | Yes         | Seconds to wait after the condition first becomes true before the override starts                                                |
| `ContinuanceTime` | int        | Yes         | Seconds the override remains active after `WaitTime` elapses                                                                     |
| `Month`           | int/string | Conditional | Month 1-12, or `*` for any                                                                                                       |
| `Day`             | int/string | Conditional | Day of month 1-31, or `*` for any                                                                                                |
| `WeekDay`         | int/string | Conditional | Day of week 1-7 where 1 = Sunday and 7 = Saturday, or `*` for any                                                                |
| `Hour`            | int/string | Conditional | Hour 0-23, or `*` for any                                                                                                        |
| `Minute`          | int/string | Conditional | Minute 0-59, or `*` for any                                                                                                      |

{% hint style="info" %}
The wildcard `*` on any date or time attribute skips that field during matching. Numeric `0` does not mean wildcard - use `*` explicitly.
{% endhint %}

### Condition Types

| Condition | Description                 | Date/Time Fields Used                       |
| --------- | --------------------------- | ------------------------------------------- |
| `1`       | Specific calendar date/time | `Month`, `Day`, `WeekDay`, `Hour`, `Minute` |
| `71`      | Crywolf event start         | Hard-coded to always return false           |
| `72`      | Crywolf event end           | Hard-coded to always return false           |

{% hint style="warning" %}
Conditions `71` and `72` are stubs; they never activate regardless of Crywolf state. Use `Condition="1"` for any functional rule.
{% endhint %}

## Important Behavior

### Timing Logic

```
condition first TRUE -> wait [WaitTime]s -> override ACTIVE for [ContinuanceTime]s -> override EXPIRES
```

Example with `WaitTime="10"` and `ContinuanceTime="3600"`:

* 00:00:00 - condition becomes true
* 00:00:10 - override activates (10 s wait elapsed)
* 01:00:10 - override expires (3600 s duration elapsed)

Both `WaitTime` and `ContinuanceTime` are in seconds. `ContinuanceTime="60"` means one minute, not one hour.

### Date/Time Matching

* All non-wildcard fields must match simultaneously for the condition to be true.
* `WeekDay` is tested first. A mismatch short-circuits the rule as invalid for the current tick.
* `Month`, `Day`, `Hour`, `Minute` each build a "valid from" timestamp when their field differs from the current clock. The rule stays valid from that timestamp through `WaitTime + ContinuanceTime` past it.
* Matching is minute-precision. Firing resolution is the AI dispatcher tick (sub-second).

### Multiple Rules Per Class

Rules are evaluated in file order and all write to the same per-class override slot:

* The last rule in the file that touches a given `Class` determines the outcome for that class.
* If the last-listed rule for a class is valid, its `Unit` is applied.
* If the last-listed rule for a class is invalid (its condition is false or outside the timing window), the override slot is cleared even if an earlier rule for the same class was valid.

Order rules for the same class so the one you actually want to win is listed last, or keep one rule per class to avoid the overwrite.

### Fallback to BasicAI

When no active rule targets a monster's class, that monster uses its `BasicAI` assigned by [MonsterAIGroup.xml](/docs/data/monster/monsteraigroup.md). The override never modifies `BasicAI` itself; it only swaps the runtime `CurrentAI` pointer.

### Performance

Every rule is checked against the clock on every AI tick, and every live monster of an overridden class has its `CurrentAI` pointer rewritten on every AI tick. Keep the rule list small. The loader caps it at 200 entries.

## Examples

{% tabs %}
{% tab title="Halloween Day" %}
Golden Goblins (class 8) switch to an aggressive Unit for all of October 31:

```xml
<MonsterAIRule>
  <Rule
    Number="1"
    Class="8"
    Description="Halloween aggressive Golden Goblin"
    Unit="101"
    Condition="1"
    WaitTime="0"
    ContinuanceTime="86400"
    Month="10"
    Day="31"
    WeekDay="*"
    Hour="*"
    Minute="*"
  />
</MonsterAIRule>
```

* Activates at October 31 00:00 server time.
* Runs for 86400 s (24 h).
* Every Golden Goblin on the server swaps to Unit 101.
  {% endtab %}

{% tab title="Saturday Night" %}
White Wizards (class 20) use an event Unit every Saturday from 20:00 for four hours:

```xml
<MonsterAIRule>
  <Rule
    Number="2"
    Class="20"
    Description="Saturday night White Wizard event"
    Unit="205"
    Condition="1"
    WaitTime="0"
    ContinuanceTime="14400"
    Month="*"
    Day="*"
    WeekDay="7"
    Hour="20"
    Minute="0"
  />
</MonsterAIRule>
```

* `WeekDay="7"` = Saturday (1 = Sunday, 7 = Saturday).
* Runs Saturdays 20:00 to 24:00.
  {% endtab %}

{% tab title="Daily Peak Hours" %}
Budge Dragons (class 3) become more aggressive every evening:

```xml
<MonsterAIRule>
  <Rule
    Number="3"
    Class="3"
    Description="Evening peak aggression"
    Unit="150"
    Condition="1"
    WaitTime="0"
    ContinuanceTime="14400"
    Month="*"
    Day="*"
    WeekDay="*"
    Hour="18"
    Minute="0"
  />
</MonsterAIRule>
```

* Fires every day at 18:00 and runs four hours.
  {% endtab %}

{% tab title="Delayed Start" %}
Christmas event with a one-hour warmup after midnight:

```xml
<MonsterAIRule>
  <Rule
    Number="4"
    Class="50"
    Description="Christmas Elf event (delayed start)"
    Unit="300"
    Condition="1"
    WaitTime="3600"
    ContinuanceTime="82800"
    Month="12"
    Day="25"
    WeekDay="*"
    Hour="0"
    Minute="0"
  />
</MonsterAIRule>
```

* Condition first true at Dec 25 00:00.
* Override starts at 01:00 (after 3600 s wait) and expires at 24:00.
  {% endtab %}
  {% endtabs %}

## Common Issues

{% hint style="danger" %}
Rule not activating - check each of:

* `Unit` exists in [MonsterAIUnit.xml](/docs/data/monster/monsteraiunit.md)
* `Class` is a class actually used by [Monster.xml](/docs/data/monster/monster.md) / [MonsterAIGroup.xml](/docs/data/monster/monsteraigroup.md)
* `WeekDay` uses 1-7 (Sunday = 1, Saturday = 7), not 0-6
* `Condition="1"` - 71 and 72 never fire
  {% endhint %}

{% hint style="warning" %}
Rule expires too quickly - `ContinuanceTime` is seconds. 60 = one minute, 3600 = one hour, 86400 = one day.
{% endhint %}

{% hint style="warning" %}
Server time zone - all matching uses the server's local system clock. Verify system time and timezone before debugging rules.
{% endhint %}

{% hint style="warning" %}
Two rules on the same class - the last rule in the file wins, including when that last rule is currently invalid (it zeros the override). Keep one rule per class where possible.
{% endhint %}

## Use Cases

### Time-Based Events

* Night aggression: lower `DelayTime` Unit during dark hours
* Weekend bosses: swap to boss-behaviour Units on Saturday/Sunday
* Hourly rotations: multiple classes each with their own schedule

### Seasonal Events

* Halloween behaviour on October 31
* December festive patterns
* Anniversary overrides

### Dynamic Difficulty

* Peak-hour challenge: harder Units during prime-time
* Off-peak: easier Units overnight

## When NOT to Use MonsterAIRule

| Need                       | Better Solution                                                                    |
| -------------------------- | ---------------------------------------------------------------------------------- |
| Permanent behaviour change | Edit [MonsterAIGroup.xml](/docs/data/monster/monsteraigroup.md) `StartAI` directly |
| HP-based skill triggers    | Use `MonsterSkill.xml`                                                             |
| Timed spawn/despawn        | Use event spawn types in `MonsterSetBase/` per-map XML                             |
| Event-only monsters        | Add dedicated monster classes                                                      |
| Stat tweaks                | Edit [Monster.xml](/docs/data/monster/monster.md)                                  |

## Related Systems

* [MonsterAIUnit.xml](/docs/data/monster/monsteraiunit.md) - AI Unit definitions that rules override to
* [MonsterAIAutomata.xml](/docs/data/monster/monsteraiautomata.md) - state machine rules used by each Unit
* [MonsterAIElement.xml](/docs/data/monster/monsteraielement.md) - per-state actions used by each Unit
* [MonsterAIGroup.xml](/docs/data/monster/monsteraigroup.md) - default AI Unit assignments (BasicAI)
* [Monster.xml](/docs/data/monster/monster.md) - stats, aggression (`ViewRange`), movement patterns
* [MonsterSkill.xml](/docs/data/monster/monsterskill.md) - HP-gated skill triggers
* [MonsterSetBase](/docs/data/monster/monstersetbase.md) - spawn timing and locations
