Skip to content

Mechanics World

Kit Oliynyk edited this page Nov 2, 2026 · 1 revision

TL;DR: Rules of the world outside the fight itself: light and darkness, charmed followers and orders, permanent affects, what the server saves to disk and when, limited items, corpses, aggression, religion defaults. Use when: you build or script anything that touches visibility, followers, persistence of mobs and items, scarce items, deaths, or a permanent buff. Source of truth: src/core/room.cpp (Room::isDark), plug-ins/loadsave/character.cpp (eyes_darkened), plug-ins/comm/corder.cpp, plug-ins/command/command.cpp (properOrder), plug-ins/loadsave/save_drop.cpp, plug-ins/updates/update.cpp, plug-ins/updates/update_areas.cpp, plug-ins/fight/fight_death.cpp, plug-ins/ai/aggression.cpp. Verified: 2026-11-02 against dreamland_code 88da8302, dreamland_world 43880467, dreamland_fenia_public c28874b. Charm limits were read from the private script that implements them and are described by behaviour.

Darkness

Room::isDark() is true when all of these hold:

  1. No light source is present. light is the count of lit sources carried by everyone in the room.
  2. The room has the dark flag, or else it is outdoors at night. A room of sector inside or city is never dark by time of day. Any other sector is dark unless the sun is rising or up.

eyes_darkened(ch) is the question "is it too dark for this character". It is true when the room is dark, the character does not have the holylight config, and seesInDark() is false. seesInDark() is true for an infrared affect, a ghost, or a character in the death-time window.

What reads them:

Check Effect
can_see of a character or object in a dark room, a viewer who cannot see in the dark sees nothing. Pass ignoreDark to ask "would they see this if the room were lit"
eyes_darkened in look a room look shows "too dark" and only what glows or carries a light, then the people. Looking at anything else in the dark fails
eyes_darkened in where the zone name and neighbours are hidden
eyes_darkened in movement the arrival banner of a new zone is skipped
isDark in exits for a viewer who cannot see in the dark and has no holylight, a dark destination room is shown as "the road leads into darkness" instead of its name
isDark in look an unseen creature with infrared and eyes in a dark room shows up to others as a pair of burning red eyes. An invisible or hidden one stays unseen
web location panel not shown while it is too dark

Charmed followers

How many

The limit is computed by a script, not by C++. By behaviour:

  • A base number by profession. Druid, necromancer, witch and warlock get 4. Anti-paladin, ranger and vampire get 3. Everyone else gets 2.
  • +1 if the higher of intelligence and wisdom is above 25.
  • -1 if charisma is below 25, and -2 if it is below 18.
  • +1 for a newbie.
  • If the result is 0 or less the character cannot control anyone.
  • Followers that count are the character's current followers, except one "free" follower that a skill may grant on top of the cap (only for the character who summoned it).

The check runs from the charm-type spells, from animate dead, and from a number of summon skills. Summons that do not call it are not limited. A script turns the older formula on or off with one switch (newcharm). The older formula was max(int, wis) / 4 + level / 30 - (25 - min(charisma, 25)).

Orders

order <follower> <command> works on:

  • a charmed follower of the character,
  • a player in manacles, when the giver is a ruler and the command is marked allow_ruler.

Charmed characters cannot give orders. order all is refused. The follower must be in the same room.

Each command declares which orders it accepts in .tables.order_flags on the command definition (command show <name> prints them to mortals):

Flag Meaning
allow_ruler may be ordered to a player in manacles by a ruler
fight_only an NPC follower accepts it only while fighting
player_only never ordered to a mob. For players it is allowed
thief_only only a mob with the thief act flag accepts it
never nobody can be ordered to do it
except_pk not ordered to a charmed player, only to mobs

Immortals and commands above mortal level are never orderable. A player's own aliases are not expanded.

After the flags, the follower's state is checked as for any command (stunned, asleep, sitting, ghost, away, punished). The master gets a message that explains the failure. Fenia can veto an order with onCantOrder and observe it with onOrder on the follower. The master's input is marked ordering while the command runs, so echoMaster can relay the follower's refusal messages.

Experience

When a group kills a mob, every NPC member of the group that is in the room (charmed followers count) removes 5% from each player's share. Leader skill and player count adjust it further.

Permanent affects

An affect with duration -1 is permanent. -2 is permanent and cannot be dispelled or cancelled: savesDispel always saves it, the dispel and cancel scripts skip it, and remove curse leaves it alone. Negative durations never tick down. Race traits use -1 and heal themselves when stripped. Everything meant to stay as long as its source (set bonuses, item grants, passive-skill grants) uses -2.

Three shipped mechanisms:

  • Race and prototype affects. char_update compares the character's affected_by bits with the race mask and calls the affect's onRefresh for each missing trait. It runs on every tick for players and mobs.
  • Passive skills. A skill XML can name affects in <grants registry="skill">. Once the skill is learned above 1% and usable, the grant is installed by the affect's onRefresh at -2. If no source grants it any more (remort, class change, deleted skill), only the permanent copy is removed and a spell-laid copy with a positive duration is left. Reconciled each tick and at login.
  • Items. An item affect can carry a skill type (<affect> in area XML). On equip, the types of worn items are collected into the wearer's eqAffects cache. isAffected(skill) is true if the affect is in the list or in eqAffects. Nothing is copied into the character's affect list or the player file, so unequipping or destroying the item removes it. Code that reads the level or modifier of the found affect does not see item grants. Bare stealth bits (sneak, hide, fade, invisibility) on worn items are also kept as real affects so they come back after combat strips them.

Item sets are scripted: counting worn members and adding a -2 affect named after the set when it completes (unverified for the current script layout, data-driven sets are not built).

What the server saves

Thing Where When
Players one flat profile plus an XML attribute file per character autosave of everyone once a minute, and on events
Items on room floors, and items inside containers on the floor per-room file under the saved directory (savedDir in the main config), grouped by vnum % 16 when an item moves (obj_to_room, obj_from_room, obj_to_obj, obj_from_obj), and at the 5 second room-saving sweep for rooms marked dirty
Mobs standing in rooms per-room file under mobiles in the same directory same sweep, uncharmed mobs only. Doppelgangers are skipped
Charmed summons per-creature file under charmed, written whenever the owner is saved owner save
Pets in the owner's profile owner save

Rules that follow from this:

  • Saving mobs and items is controlled by the save_objs and save_mobs server options. Both are switched off while a corpse is being built and restored after.
  • An item is written only when it moves. Changing an object in place (swapping its behavior, editing a saved field) writes nothing until it moves again. After such a change call the save helper for the holder (save_items_at_holder in C++, room.saveItems and room.saveMobs in Fenia).
  • A saved mob comes back from its file at boot, not from the area reset. Removing the <mob> reset from an area does not remove a mob that was saved. Purge the instance and delete its entry from the room file. The same holds for a new <give> on a saved shopkeeper: its stock is restored from the file and the reset does not fire again.
  • A saved mob keeps its own keyword set per language, so a keyword added to the area later does not reach the saved copy for display. Matching a name still uses the prototype keywords too.
  • Saved mobs and pets keep their saved numbers only while the stored BodyVer equals the prototype's body stamp (level, tier, race, size, body bits, wear locations). A change to tiers or body bits re-stamps many prototypes, and affected saved mobs reload at prototype numbers. Summons are rebuilt from their stored call level on owner login by a script.
  • A saved mob's worn gear is reloaded without applying its bits again. Item bits are removed from the base bits at load, which prevents "orphan" resist or blind bits after an item is gone (applies from the boot after the fix).
  • A room save file that names a deleted vnum stops the boot with "vnum N not found". See Troubleshooting.

Limited items

limit on an object prototype is the global cap on live copies. -1 means unlimited. Above zero it is a scarcity flag, and these are among the best items.

  • A limited item is stamped with an expiry two weeks after it first reaches a player's hands (or a charmed follower's). It then loses a whole day per minute while it lies on the ground, while a mob carries it, or while a player holds it in a safe room (clan flowers lose an hour per minute instead). Items on their original reset place, inside corpses and on auction are left alone. A purge task runs every minute and removes expired copies, with a message to the holder.
  • The engine counts copies in the world and in offline player profiles. Boot counting includes a profile copy only while its stamp has not expired. An item without a stamp is counted with a warning.
  • A reset places a limited item only while count < limit. In an area with players in it a limited reset never fires. In an empty area it fires with a 10% chance per pass. Unlimited items use the reset's own maximum, and reset at 25% once the world already holds that many.
  • count is not presence. It includes copies held by offline players. For "is one physically in the world" use the list of live instances.
  • A reset with limit and maxHere fields controls spawning of that reset line. That is a different thing from the prototype limit.
  • An owned item on a room floor with no timer is swept to the lost and found room by the hourly task, unless the room is a mansion or the item has the keepHere property.
  • Items on the floor of a mansion room that are limited are swept by the housekeeper at the next tick.

Death and corpses

  • On death a player always moves to the altar of their hometown. The corpse goes there only below level 15.
  • The corpse stores the vnum of the hometown pit room at the time of death. If the player later changes hometown, the old corpse still decays into the old pit.
  • A player's corpse keeps all its contents. When it decays the contents are moved to the pit container in the stored room, or to the floor of the corpse's room if there is none. The corpse itself is never swept to lost and found.
  • Mortals cannot get all from a pit, only item by item. Items from a pit cannot be sold. Immortals bypass both.
  • The corpse is built by a Fenia hook. If the hook does not handle it, the C++ legacy path builds the corpse. A mob of an instant-decay form leaves no corpse.
  • While a corpse is built the character is flagged dying: item and affect removal triggers still run but print nothing.

Aggression

An aggressive mob attacks a player unless one of these holds:

  • the mob's level is more than 5 below the player's,
  • the player is a vampire,
  • both are good,
  • the recall room of the player's hometown lies inside the vnum range of the mob's area. This is the only "own people" rule in the engine. Race is never consulted.

Only mobs in areas with a recent player visit are driven by aggr_update, so aggression stops in an empty zone.

Falling objects

Once per tick, a takeable object lying on the floor of an air room falls through the room's down exit if that exit exists, leads to another room and is not closed. It falls one room per tick, so a column of air rooms drains to solid ground. Carried objects, objects in containers, objects with the hover flag and anything in a mansion room stay. A line is echoed in both rooms.

Objects that land in a water room are handled by the water sweep. See Engine-Time-and-Pulses.

Religion and mobs

  • A character with no religion resolves to the none religion. Everyone starts as an atheist. A prayer cast by an atheist takes a level penalty and the character is pointed to the religion help.
  • A mob of a flying race (a bird, or any race whose form has wings) is flying for good. Race affects, the body parts and the can_fly race fallback all give it. A prototype aff del cannot ground it.
  • A mob that teaches, sells or serves needs a form with sentient or magical. A golem or beast without it is silently skipped by the service scripts.
  • A mob's hit points, damage and armor in the area file are ignored. They are derived at boot from level, tier, race and form. Tier 10 is the training dummy. See OLC-Mobiles.

See also

Clone this wiki locally