Repository navigation
Fenia Scripts
TL;DR: A Fenia script is a code source stored in the Fenia database. You load it from the web editor, from a file with
cs load, or witheval. Loading runs the file once, and the assignments in it bind triggers and helpers. Nothing re-reads the files at boot. Use when: you add, replace, load or remove Fenia scripts, name a script file, or wonder what survives a reboot. Source of truth:dreamland_code/plug-ins/feniaroot/ccodesource.cpp(cs),ceval.cpp(eval),codesourcerepo.cpp(file layout),cfindref.cpp,src/fenia/codesource.cpp,closure.cppVerified: 2026-11-02 against dreamland_code a7c4fd10, dreamland_world a35c62ce, dreamland_fenia_public c28874b. Private script repositories were read for behaviour only.
For the language see Fenia-Language. For which events a script can bind to see Fenia-Triggers.
A code source has an id, a name (the "subject"), an author, the source text, and a list of functions compiled from it. Loading a code source evaluates the text once. The text is one expression, normally .apply(function() { ... }), and the assignments inside it bind functions to places:
.apply(function() {
.get_mob_index(3090).onSpec = function(mob) {
if (.chance(5))
mob.interpret("emote purrs.");
};
})After the load, the function lives in the field onSpec of the prototype of mob 3090. The code source stays registered as long as some function from it is still referenced.
eval, cs, findrefs and the fenia command need Fenia security 110. The engine grants it when one of these holds:
- the character's trust is 110 or higher
- the server runs in buildplot mode and the character has a
feniasecurityattribute of 110 or more - the character wrapper has a numeric
feniaSecurityfield of 110 or more
The subcommands cs load, cs save, cs del and cs gc are further limited to coders.
| Way | What it does |
|---|---|
eval <expression> |
Evaluates one expression. this is the acting character. ptc(x) prints a string. Creates a throwaway code source named <eval command>. |
cs web [id or name] |
Opens the script editor in the web client with a new or an existing script. Run in the editor evaluates the text and saves it under its subject. |
cs post |
Evaluates the script in your edit buffer (filled by cs paste) and clears the buffer. |
cs load <file> |
Coders only. Reads a file from the Fenia script directory and evaluates it. |
cs load all [folder] |
Coders only. Loads every file under the script directory, or under one folder of it, that matches a known layout pattern. |
fenia <trigger> inside medit, oedit, redit, bedit, skedit
|
Opens the web editor with a template for that trigger and the right subject. See OLC-Other-Editors. |
Reposting a file with the same subject replaces the stored source in place. It no longer creates a second copy.
The Fenia script directory is set by feniaScriptDir in the server config. The stock template points it at share/DL/fenia (the CI build config still says share/DL/fenia.local). A server that carries the public Fenia repository uses share/DL/fenia and mounts that repository at share/DL/fenia/public (see Repositories). The loader treats a leading public/ in a subject as that folder. The directory is read only by cs load and by the server's HTTP eval interface. Nothing reads it at boot or on a plugin reload. The Fenia database is the source of truth for what runs.
Two consequences:
- A file that is correct on disk but was never loaded is not running.
- A script that names a skill or an affect at its top level (
.AffectHandler("x").onRefresh = ...,.SkillCommand("x").run = ...) needs that skill to be loaded first. If it is not, the load fails with "skill does not exist", the file is not bound, and nobody reloads it later. Load the world data first, then the script.
From the command help in ccodesource.cpp.
| Subcommand | Use |
|---|---|
cs list [text] |
List code sources, all or with the text in the name. |
cs read <id or name> |
Print a script. |
cs copy <id or name> |
Copy a script into your edit buffer. |
cs search <text> |
Find every script whose source contains the text. |
cs dups |
Names that have more than one code source. |
cs orphans |
Counts of unreferenced code sources, objects and functions. Read-only, like the boot check. |
cs gc |
Coders only. Dry run of the duplicate collapse done at boot. Read-only. |
cs web [id or name] |
Web editor. |
cs paste, cs show, cs clear
|
Work with the edit buffer. |
cs post |
Evaluate the buffer. |
cs load <file>, cs load all [folder]
|
Coders. Load from disk. |
cs save <id or name> |
Coders. Write one script to share/DL/fenia.local/<name>.f++, the fenia.local folder under tablePath. This path ignores feniaScriptDir. |
cs save all |
Coders. Write every script to the script directory using the layout below. |
cs del <id> force |
Coders. Break the cycles of a code source and let the collector take it. |
findrefs <id> |
A separate command. Lists what refers to a code source. Zero lines means nothing refers to it. |
rtapi() on a wrapper prints the fields that scripts set on it at runtime, for example eval ptc(.get_mob_index(3090).rtapi()). Use it to see which triggers a prototype has.
CodeSourceRepo maps a subject to a file path. The patterns, in the order the engine tries them:
| Subject pattern | Holds |
|---|---|
spell/<spell name>/run<Target> |
Spell run hooks (runVict, runObj, ...) |
affect/<skill name>/<Trigger> |
Affect handler triggers |
skillcommand/<skill name>/<method> |
Skill command methods (run, preRun, apply) |
command/<command name>/<method> |
Command overrides (runFunc) |
areas/<area file>.are/<mob|obj|room>/<vnum>[ label] or <vnum>.<trigger>
|
Triggers on one prototype |
areas/<area file>.are/<name> |
Shared code for one area |
<folder>/<name> and <folder>/<sub>/<name>
|
Everything else, for example utils/<topic> helper files |
A leading public/ marks a script that belongs to the public repository. Names may contain spaces and, in helper files, a literal colon and space (utils/object: dimensions). Quote such paths in a shell. In game, cs load takes the rest of the line as the name, so type it without quotes.
Several helper files can fill one .tmp.<namespace>. A single trigger file can also arm more than one method on the same prototype, so read a whole file before saying a prototype has "only" one trigger.
- Code sources, functions,
.tmpand every field set on a character, item, room or prototype live in the Fenia database and come back after a reboot. Fenia fields on a character are not in the player file. - Players have a second store: typed attributes, saved in the player file.
ch.attribute("name", value)creates one,ch.attribute("name")reads it,ch.hasAttribute(name),ch.eraseAttribute(name). The setter throws if the attribute already exists, so update with erase then set. It works for online players only. For a player who is offline use.Player(name), which hasattribute(name),hasAttribute(name),eraseAttribute(name)andsetAttribute(name, value[, save]). The last one writes a string attribute, overwrites an existing one, and saves the profile unlesssaveis false. -
ch.attribute("name")returns a copy. Writing into the returned value changes nothing. OnlyeraseAttributeremoves a whole attribute. - A number attribute is dropped at remort. A string attribute survives. Store anything permanent as a string and convert on read.
-
.Map()keys that are not legal XML names break the object at the next boot, see Fenia-Language.
There is no cs delete. A code source disappears when its last function is no longer referenced. The collector counts references, so:
-
Annul before you delete. Set every binding the script made to
nullfirst (.get_mob_index(3090).onSpec = null;,.tmp.topic = null;), then remove the file. If you delete the code first, the old binding stays in the database and the next script of the same name can end up duplicated. - Deleting the file does not unregister the script.
cs load allre-evaluates whatever is on disk andcs save allwrites every registered script back out. - A script whose objects point at each other (a parent object and children registered in a shared map) is a reference cycle. Annulling the bindings does not free it. Use
findrefs <id>andcs orphansto see it, andcs del <id> forceto break the cycle. - Reposting a body that no longer makes an assignment does not unbind what the old body bound. Annul the bindings instead.
- Annul every debug probe you bound while testing:
.tmp.test.x = null, temporaryonSpechandlers on a prototype. They persist in the database and fire forever. - After you edit a script,
cs search <text>finds orphans of the old name.
- Posting a caller before its helper, or the reverse. Fenia arity is strict, so changing a helper's parameter list breaks every caller that still passes the old count until it is posted too. Post the helper and every caller together, or add the parameter under a new helper name.
-
A command override is bound by load order.
.FeniaCommand("x").runFunc = ...binds only if the command registered after the Fenia database was recovered. A command registered earlier by a plugin that loads before the Fenia plugin serves its C++ body after every boot. Reposting such an override each boot piles up orphaned wrappers. Declare the command in the world data instead(measured live). -
A skill command
runtakes over at once. Postingrunfor a skill that has a C++ body replaces the body immediately, even if the skill's world data still describes the old argument type. With noargtype,victis null and onlyargOne/argAllare set, so the script must find its own target. - Affect handlers and skills referenced at the top of a file need the world data first, see above.
- A script that parses but throws while running shows nothing to the player. Check the server log for lines containing
Exception calling Fenia prog.
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