veratown-prototype

Location Entry Messages

The location-messages plug-in sends a configured private Whisper when a player enters an enabled map location. Messages are configured per location in the location’s data.entryMessage field; the feature does not require a global configuration or a new collection.

Configuration

Set the location’s data field to an object like this:

{
    "entryMessage": {
        "enabled": true,
        "timeZone": "America/New_York",
        "template": "Welcome to {locationName}, {playerName}!",
        "variants": [
            {
                "when": [
                    {
                        "variable": "occupantCount",
                        "operator": "at_least",
                        "value": 5
                    }
                ],
                "template": "Welcome, {playerName}! There are {occupantCount} people here."
            },
            {
                "when": {
                    "mode": "any",
                    "conditions": [
                        {
                            "variable": "occupantCount",
                            "operator": "at_least",
                            "value": 5
                        },
                        {
                            "variable": "wears:ItemArms:HeavyYoke",
                            "operator": "equals",
                            "value": true
                        }
                    ]
                },
                "template": "Welcome, {playerName}. Your arm restraints are noted."
            }
        ]
    }
}

Use the guided Location entry message section in the stored location editor; map-analysis candidate drafts open in this same editor. The JSON can also be edited directly in the location’s data field in the configuration administration workspace. The same location metadata editor also supports an optional delayed appearance-set trigger. entryMessage is strict: unknown keys or malformed conditions are rejected. enabled is required. template is the fallback; variants are checked in order, and the first matching variant is rendered. A new condition group uses mode: "all" (AND) or "any" (OR), with 1–16 conditions and no nested groups. Legacy when arrays remain readable and mean AND; the guided editor saves groups. Up to 16 ordered variants are supported. Conditions support equals, at_least, and at_most; the latter two require numeric values.

Available condition facts are the template values listed below, including activePose:<PoseName>, arousalProgress, hasOwner, hasLover, and credits, playerTitle, reputation:<Type>, and item-scoped expression, lock-presence, and removal-time facts. Unknown facts do not match; an any group can still match another known fact. If no variant matches, the default template is used. The admin workspace provides controls to add, remove, and reorder rules and conditions, choose AND/OR, and preview sample values. Preview is local only and is not live BC evidence. Templates and rendered messages are limited to 1,800 characters. See the shared condition facts and rules reference for the complete location/door fact inventory and evidence boundaries.

timeZone is optional and defaults to UTC. It must be a valid IANA time-zone identifier. The hour, weekday, and time-of-day values use this zone.

Template values

Placeholders use {name} syntax. Available values are:

Placeholder Meaning
{playerName} Observed character name
{playerNickname} Observed nickname, or an empty string
{playerTitle} BC-observed title, or an empty string
{memberNumber} Observed BC member number
{locationName} Configured location name
{locationKey} Stable location key
{locationType} Configured location type
{occupantCount} Current observed characters inside the location, excluding the bot
{hour} Local hour from 0 to 23 in the configured time zone
{dayOfWeek} Local weekday name
{timeOfDay} night, morning, afternoon, or evening
{wears:Group:Name} Whether the entrant’s observed appearance includes that item
{hasAppearanceGroup:Group} Whether the entrant has any observed item in that group
{reputation:Type} Observed BC reputation value for that type
{activePose:PoseName} Whether the entrant’s latest BC-observed active-pose list includes it
{itemExpression:Group:Name} Expression on the exact worn item, or none
{itemLocked:Group:Name} Whether BC lock metadata is present on the exact worn item
{itemRemovalTimeRemainingMs:Group:Name} Milliseconds until its BC removal timer; zero means elapsed
{arousalProgress} Latest BC-observed arousal progress from 0 to 100
{hasOwner} Whether valid modern ownership metadata is present
{hasLover} Whether the BC room snapshot includes at least one lovership
{credits} Current available Veratown credits, excluding credits reserved elsewhere
{featureAvailable:id} available, unavailable, or unknown from the wired feature resolver

Feature availability currently recognizes casino and shop; other IDs resolve to unknown. Availability means the feature’s relevant configuration is enabled/valid, not that this player is authorized to use it. Appearance values come from the synchronized character snapshot, not client-side mod state. Reputation is unknown when that type is absent from the latest full character sync. Item-state variables are scoped to one exact worn item; itemLocked does not expose lock identity. Removal time uses BC’s absolute epoch-millisecond timer and does not prove that the item was removed when it reaches zero. Owner/lovership placeholders expose only booleans. Credits come from the Veratown economy service, not BC Money; failed reads are unknown. Unknown placeholders fail visibly rather than being silently removed.

Event and delivery behavior

The map runtime distinguishes position_update, member_join, initial_sync, and configuration_change entry causes. The feature handles a member join or a subsequent position transition, but ignores initial occupancy and entries created only by configuration reloads. Entry processing rechecks current room membership and the entrant’s observed coordinates against the current enabled location geometry before selecting a message.

Delivery is always a private, journaled Whisper through the existing communication action path. The feature does not send room-wide Chat or Emote, does not call helper bots, and does not retry an ambiguous delivery. The generic core location-entry handler owns subscription lifecycle, concurrent per-member/location de-duplication, error reporting, and draining in-flight work on plug-in stop; it does not promise exactly-once delivery across restarts.