Repository navigation
Fenia Behaviors
TL;DR: A behavior is a named bundle of Fenia triggers, default properties and a help article. You create it once with
bedit, write its trigger files, and attach it to any number of mobs, items or rooms. Only some triggers reach behaviors. The table below is built from the C++ dispatch sites. Use when: you share one scenario between many prototypes, attach or detach a behavior, or need to know whether a given trigger works on a behavior. Source of truth:dreamland_code/plug-ins/loadsave/behavior_utils.cpp(behavior_trigger),plug-ins/feniaroot/behaviorwrapper.cpp,plug-ins/olc/bedit.cpp,plug-ins/olc/olcstate.cpp(editBehaviors),dreamland_world/behaviors/*.xml,dreamland_world/fenia.examples/behavior/Verified: 2026-11-02 against dreamland_code a7c4fd10, dreamland_world a35c62ce. Private script repositories were read for behaviour only.
Triggers and their arguments are on Fenia-Triggers. This page covers what is specific to behaviors.
A behavior has two halves that must agree:
-
A definition in the world data:
dreamland_world/behaviors/<name>.xml. -
Trigger functions in the Fenia database, one script per trigger, each assigning to
.Behavior("<name>").on<Event>.
The behavior does nothing until it is attached to a prototype and both halves are loaded.
<?xml version="1.0" encoding="UTF-8"?>
<behavior type="DefaultBehavior">
<cmd></cmd>
<description></description>
<help id="257" level="-1" type="BehaviorHelp">
<extra l="en">adept acolyte healer buffs newbie</extra>
<text l="en">An adept looks after the young and after its own ...</text>
</help>
<id>30</id>
<nameRus>адепт</nameRus>
<nameUa>адепт</nameUa>
<props>null</props>
<target>mob</target>
</behavior>| Field | Meaning |
|---|---|
id |
Numeric id, allocated by bedit create. |
target |
mob, obj or room. The kind of prototype the behavior can attach to. |
nameRus, nameUa, description
|
Names and text shown in editors and help. English uses the file name. |
cmd |
Alternative sub-command names for use <item> <subcommand>. Usually empty. |
props |
Default properties as JSON, or null. Copied to a prototype when the behavior is attached. |
help |
The help article for the behavior. bedit create allocates its id. |
A behavior name is lower-case and may contain spaces, for example master samurai. Two-word names are quoted in a script: .Behavior("master samurai").
bedit create <new name>
bedit list
bedit <name>
-
bedit createrefuses a name that collides with an existing behavior keyword. It registers the behavior in the Fenia database, allocates a help id and opens the editor. -
.Behavior("name")throwsname: behavior not founduntil the behavior has been created. The registry persists in the database across reboots. -
bedit listshows every mob, item and room that uses the behavior. - Editor sub-commands:
nameRus,nameUa,description,target,props,subcommands,help,affect,fenia <trigger>,list,show,commands,done.fenia <trigger>opens the web editor with a template taken fromfenia.examples/behavior. The templates exist for these triggers:
| Target | Templated triggers |
|---|---|
| mob |
onArea, onBribe, onCantTeach, onCantTrain, onFight, onGive, onGreet, onSpec, onSpeech, onTeach, onTrain, postSpeech, postTeach, postTrain
|
| item |
onArea, onCantFetch, onCantPut, onDrop, onEquip, onFetch, onFight, onLook, onPut, onRemove, onSpec, onUse, postUse
|
| room |
onDive, onDiveUpdate, onReset, onShowEnd, onSpec
|
A template exists to help you start. A trigger without a template can still work if the engine dispatches it (see below).
-
affectcreates or edits an affect handler tied to the behavior, so one behavior can also act as a persistent affect. - The
propseditor sets the default properties. A script can read them with.Behavior("name").props. - The definition file lives in
dreamland_world/behaviors. Commit it with the rest of the world data. Do not hand-write a second definition with a different id for a namebeditalready created. - A help id collision crashes the next plugin reload. Pick help ids from the live maximum, see Help-Articles.
One file per trigger, named behaviors/<name>/<trigger>. The body is a single assignment. The first argument of every behavior trigger is the entity the behavior sits on:
.Behavior("fido").onGreet = function(mob, ch) {
if (ch.is_npc())
return false;
mob.interpret("emote wags its tail.");
return false;
}A file with more than one top-level assignment must be wrapped in .apply(function() { ... }), with a ; after each assignment inside. A shared engine file of helper methods is written that way: .Behavior("name").helper = function(...) { ... };.
Area files list behaviors on each prototype as a space-separated registry list:
<behaviors registry="behavior">fido thief</behaviors>A prototype can carry several Fenia behaviors and also a C++ behavior class at the same time. The C++ class is written as <behavior type="ShopTrader">...</behavior> and is a different mechanism.
In OLC, behaviors inside medit, oedit and redit edits the list. Adding a behavior copies its default props into the prototype's own props[<behavior name>]. Removing it deletes that key.
From a script you can set the list on a prototype. A string of names or a list replaces the whole set, null clears it, and an unknown name throws:
.get_mob_index(3090).behaviors = "fido";To check from a script: mob.hasBehavior("fido"), obj.hasBehavior("name"), room.hasBehavior("name"). The check reads the prototype's list and throws if the behavior name does not exist. mob.clearBehavior() resets the mob's C++ behavior class (it does not touch Fenia behaviors).
Dispatch is per event, not universal. A behavior method fires only where the C++ code for that command calls behavior_trigger. This table is built from the call sites.
| Entity | Triggers a behavior can define | Arguments (entity first) |
|---|---|---|
| mob | onSpec |
mob. Skipped in an area marked empty. |
| mob | onArea |
mob. Once per tick. |
| mob | onGreet |
mob, walker |
| mob | onSpeech |
mob, talker, msg. Fires for say in the room and for a tell to the mob. |
| mob | onBribe |
mob, giver, gold, silver |
| mob | onGive |
mob, ch, obj |
| mob | onFight |
mob, victim |
| mob | onShow |
mob, ch. Returns a string tag added to the mob line in room lists and matched by where. |
| mob | onDescr |
mob, ch. Returns a hint line shown under the mob description on look. |
| mob | any name fired by a Fenia command script with mob.trigger("Name", ...)
|
arguments as that script passes them |
| item |
onSpec, onArea
|
obj |
| item | onGet |
obj, ch. The item entered ch's inventory: get from the floor or a corpse, give and request with ch the receiver, obj.trigger("Get"). Return true to stop the rest of the get chain. |
| item | onDrop |
obj, ch |
| item | onLook |
obj, ch, keyword. After the text was shown, append only. |
| item | onUse |
obj, ch, argument |
| item |
onPut, onCantPut
|
container, ch, obj and container, ch, obj, pocket, verbose
|
| item |
onFetch, onCantFetch
|
container, ch, obj and container, ch, obj, pocket
|
| item |
onEquip, onRemove
|
obj, ch |
| item | onWear |
obj, ch. ch put the item on through the wear path: the wear command, a mob arming itself, a reset re-equipping a mob. Login and obj.equip fire only onEquip. Hang affects in onEquip. |
| item | onPourOn |
item, ch, out, liqname, amount |
| item | onPourGround |
out, ch, liqname, amount |
| item | onFight |
obj, ch |
| room |
onReset, onSpec, onDiveUpdate
|
room |
| room | onDive |
room, walker, danger |
| room | onEntryNear |
room, walker, movetype |
| room | onShowEnd |
room, ch, looker. Returns a string. |
Things that do not reach a behavior:
-
onDeath,onKill,onCantLeave,onCommand,onTell,onSafe,onSocial,onEmote,onExamine. -
onTellas a separate trigger: a behavioronTellloads and never fires. UseonSpeechon the behavior, or keeponTellas a prototype trigger. -
onExamine.examinecalls only the C++ behavior class, so a FeniaonExamineon a behavior never runs.onLookdoes fire, but only after the main text. - Anything not in the table. Before you rely on a trigger, search the C++ for
behavior_trigger(with its name.
Two practical rules follow:
- A migration from prototype triggers to a behavior can end up hybrid:
onGreetandonSpecon the behavior,onTellandonSafestill on the prototype. Check each trigger with a real action in the game.hasBehaviorreturning true proves nothing about dispatch. - For generated text that must answer
lookorread(a book that lists its pages, a board), use a prototypeonExtraDescroronExamine, not a behavior. Answer only your own keywords.
Behavior triggers also come in post form. A post trigger runs after the command in its own thread. A behavior with only a post<Event> and no on<Event> cannot suppress the underlying C++ command, whatever it returns.
Properties are a JSON object per behavior. The behavior definition holds the defaults. Each prototype holds its own copy, under the behavior's name:
var proto; proto = .get_obj_index(obj.vnum);
if (proto != null && proto.props != null && proto.props["random weapon"] != null)
...- Read per-prototype settings through the prototype (
obj_index.props,mob_index.props,room.props). The key is the behavior name, quoted with["..."]when it has a space. A missing key givesNONE. -
obj.propson an instance is that instance's own properties. It isnullunless a script gave the instance some. Do not expect the prototype's properties there. -
obj_index.property(name, default)andsetProperty(key, subkey, value)read and write a prototype property.obj.property(name, default)andobj.setProperty(name, value)do the same on an instance.
When you replace a prototype-level scenario with a behavior, annul the old bindings so nothing fires twice:
- Stand up and load the new behavior. Check that every trigger fires once.
- Set every trigger the old script attached to the prototypes to
null, including helper functions it hung on them:.get_obj_index(v).onUse = null;. Trigger names are mandatory here. Otherwise both the prototype and the behavior fire. - Set the old shared namespace to
null(.tmp.OldEngine = null;). - Delete the old files, and for a C++ migration remove the
<spec>tag from the area nodes. - Look for leftovers with
cs search <old name>.
Start here
Get running
Contribute
- Contribute
- Contributing Workflow
- Code Style
- Accessibility
- Writing Player Text
- Game Design Principles
Build areas
- Building
- OLC
- OLC Rooms
- OLC Mobiles
- OLC Objects
- OLC Resets
- OLC Line Editor
- OLC Other Editors
- Area Format
- Area Quests
- Mob Forms and Parts
Fenia
- Fenia
- Fenia Language
- Fenia Triggers
- Fenia Gotchas
- Fenia API
- Fenia Scripts
- Fenia Behaviors
- Fenia Skills and Spells
- Fenia Cookbook
- Fenia Grammar
Engine
- Engine Architecture
- Engine Time and Pulses
- Output Format
- Mechanics Combat
- Mechanics World
- Data Configs
- Item Power
Localization
Clients
More