Skip to content

Smart AI

Smart AI is the declarative scripting path. Authors describe NPC behaviour as a list of event → action → target rules; the runtime under splintertree-world/src/systems/scripting/smart_ai.rs evaluates them. The on-disk format is fully compatible with AzerothCore's world.smart_scripts table — every existing AC row ports across unchanged.

When it fits

Smart AI is the right tool when the behaviour is a small handful of "on event X, do action Y, targeting Z" rules. Typical cases:

  • "Cast spell N on aggro."
  • "Flee at 30 % HP."
  • "Summon adds at 50 % HP, once per encounter."
  • "Open this gameobject when the party stands on the trigger."

Anything that needs branching beyond the event flags, custom RNG, or its own DB state belongs in Python instead.

YAML manifest

Authoring scripts as raw world.smart_scripts rows means looking up every event / action / target id in SmartScriptMgr.h. The stctl smart build DSL takes a YAML manifest with named enums and produces JSON files that drop straight into a .rcmod bundle's smart_scripts/ directory.

# smart-manifest.yaml
scripts:
  - entry: 257
    source: creature
    comment: "Forest Boar"
    rules:
      - id: 0
        event: aggro
        event_chance: 100
        action: cast
        action_params: [12345]   # Charge spell
        target: victim
        comment: "Charge on aggro"

      - id: 1
        event: health_pct
        event_params: [30, 100, 0, 0]   # below 30% HP
        action: flee_for_assist
        target: self
        comment: "Flee at 30% HP"

Build:

stctl smart build smart-manifest.yaml --out mods/my_mod/

The tool emits smart_scripts/<entry>.json, one file per script source, with the rules array inside. The applier upserts these into world.smart_scripts keyed by entryorguid on mod activation.

Row shape

Each Smart AI rule maps one-to-one to an AC world.smart_scripts row:

entryorguid | source_type | id | link
event_type  | event_phase_mask | event_chance | event_flags
            | event_param1..4
action_type | action_param1..6
target_type | target_param1..3 | target_x | target_y | target_z | target_o
comment

The DSL accepts either the integer or the snake_case name for every typed column (source_type, event_type, action_type, target_type, event_flags). Unknown numeric ids fall through unchanged so AC rows that the named-enum table does not yet cover still build.

Source types

Name id
creature 0
gameobject (go) 1
area_trigger (areatrigger) 2
event 3
gossip 4
quest 5
spell 6
transport 7
instance 8
timed_actionlist (actionlist) 9
scene 10

The full event / action / target tables track AC's SmartScriptMgr.h — both Rust runtime and stctl DSL stay in sync. See splintertree-ctl/src/smart_enums.rs for the canonical lookup.

Worked example — multi-phase boss skeleton

scripts:
  - entry: 4500          # boss creature_template entry
    source: creature
    comment: "Stitches"
    rules:
      - id: 0
        event: aggro
        action: talk
        action_params: [0]          # broadcast_text id 0 from creature_text
        target: self

      - id: 1
        event: aggro
        action: cast
        action_params: [11538]      # Frost Nova (initial)
        target: victim

      - id: 2
        event: health_pct
        event_params: [50, 100, 0, 0]
        action: cast
        action_params: [29371]      # Enrage
        target: self
        event_flags: [not_repeatable]

      - id: 3
        event: health_pct
        event_params: [30, 100, 0, 0]
        action: summon_creature
        action_params: [4501, 1, 30000]   # adds entry 4501, summon type, 30s
        target: position
        target_x: -10412.5
        target_y: -1187.4
        target_z: 35.7

      - id: 4
        event: just_died
        action: talk
        action_params: [1]
        target: self

The same manifest, expanded in AC's wiki form, would be five rows of integer columns. Splintertree keeps the rows around — they are the storage format — but mods author against the YAML.

Mixing with Python

Smart AI and Python coexist on the same creature. A practical split:

  • Smart AI handles the deterministic combat skeleton (cast on aggro, flee at low HP, despawn on evade).
  • Python CreatureScript handles the bespoke phase transitions, AIO push to nearby players, custom RNG decisions, or anything that needs to read mod-defined DB state.

The Python script's hooks fire alongside the Smart AI rules. Use event_flags: [not_repeatable] and the Python state to keep the two in sync where they overlap.

Hot reload

.script reload smart

Re-reads world.smart_scripts and re-arms every loaded source. Useful while iterating on a manifest — combine with stctl smart build and a fast \copy into the dev DB.

Tooling reference

Command Output Notes
stctl smart build smart_scripts/<entry>.json Builds a manifest into AC-compatible rows ready for a .rcmod bundle.
stctl smart validate (exit code) Same checks the activator runs at load time.

The full stctl surface lives on Modding › Tooling.

Further reading

  • AzerothCore Smart Scripts wiki — every event, action, and target with parameter semantics. www.azerothcore.org/wiki/smart_scripts
  • Source of truth (Rust runtime): splintertree-world/src/systems/scripting/smart_ai.rs.
  • Source of truth (DSL): splintertree-ctl/src/smart_scripts.rs and splintertree-ctl/src/smart_enums.rs.