veratown-prototype

Trick-or-Treat

Trick-or-Treat is a disabled-by-default, room-scoped Halloween route game. It uses existing enabled veratownLocations records; it never creates map locations or changes the live BC map.

On shutdown the plug-in removes BC and location listeners, drains accepted event work, and then stops the game service. Partial startup rolls back registrations and preserves the original failure if cleanup also fails.

Configure the route

In Admin Web, open the Trick-or-Treat shortcut under Games. Add checkpoint rows by selecting enabled map locations from the location dropdown. A checkpoint may have an optional display label such as “Pumpkin Patch”; otherwise the location key is shown. Set the number of stops to draw for each round, a round duration from 5 minutes to 2 hours, and the player cap (2–12). Enable Solo play to allow one current room member to start a route; it is disabled by default. Cooperative treats and friendly duels can be disabled independently.

The route pool must contain at least as many unique enabled locations as the configured stops. The server validates every location reference on save, and the runtime checks enabled locations again when the admin starts a game. A lobby snapshots its settings, so later configuration edits affect new lobbies only. The startup seed creates a disabled configuration with no locations; operators must choose the map locations that fit their event.

Admins may also select enabled doors in Emote unlock door keys. During an active round, a joined participant’s exact TRICK OR TREAT emote opens those doors through the ordinary journaled map action and each door’s configured unlock duration. The emote is ignored in the lobby, outside the roster, and when no doors are selected.

Optional loss consequences are disabled by default. To configure them, enable Loss consequences and add up to five stages in order. Each stage names an enabled appearance itemset, a participant-facing description, and a timer from 1 to 240 minutes; durations cannot decrease at later stages. Every applied piece in a stage itemset must use TimerPasswordPadlock with Remove item on expiry enabled. Stages may also strip catalog groups classified as restraint items; clothing and cosplay groups are rejected. The itemset’s allowNonOwnerLockRemoval option can request removal of supported non-owner locks from those stripped items, but does not bypass BC permissions or remove owner/relationship locks. The admin validates itemsets against the pinned appearance catalog when saving, and runtime checks the same restrictions before application. Give each stage an accurate description: that description and timer are shown privately before participants choose whether to opt in. Configure only restraint itemsets appropriate for the event and the room’s permissions. The saved game configuration pins each stage to the itemset revision used for validation. If an itemset is edited afterward, the old game configuration will not apply the new definition; save the game settings again before using that revision in a new lobby.

Optionally select a Costume itemset to enable the Halloween costume bonus. The itemset must be enabled, contain only unlocked clothing/cosplay pieces, and is pinned to its validated revision when the game configuration is saved. Costume itemsets cannot contain conditional variants; the same pinned pieces are checked for every participant. Participants put on the configured pieces themselves; the bot does not change their appearance. All configured pieces must be present in BC-observed appearance for candy rewards to double, including checkpoint treats/tricks, shared treats, and duel rewards. If an opted-in participant removes any piece during an active round, the first configured consequence stage is applied once on the observed removal. Opting out avoids that removal consequence, but does not disable the costume reward bonus. Changing the itemset requires saving the game configuration again before it will count.

Play

Use /bot tt or !tt for a private, themed introduction with command examples. The long-form equivalent is /bot trick-or-treat, and /bot trick-or-treat intro (or /bot tt intro) shows the guide again. Global and scoped help list Trick-or-Treat commands only while the room’s enabled setting is true. Disabling the game hides both command aliases from help without removing their command-time checks.

  1. Players in the room use /bot trick-or-treat join (or !trick-or-treat join) to join the lobby. The short command prefix /bot tt and !tt works as an alias. When loss consequences are enabled, the first join request privately shows the rules and stages and does not join. The player must then choose /bot tt join opt-in or join opt-out; either choice allows participation. A participant may later use /bot tt consent opt-in|opt-out; opting out is immediate, while opting in requires a fresh display of the rules and a second confirmation.
  2. In a multiplayer lobby, every joined participant must run /bot tt ready (use /bot tt ready no to withdraw readiness). Once at least two players have joined and everyone is ready, the route starts automatically. A room admin may also use /bot tt start, but cannot bypass readiness. In a configured solo game, the sole player may start directly with /bot tt start; no room-admin permission or separate readiness step is required. The game privately sends each participant the randomly drawn checkpoints; players can visit them in any order.
  3. Only a post-start location entry caused by a real position_update offers a checkpoint choice. Initial sync, member join, map configuration changes, and merely standing in a location do not award progress. Route and checkpoint messages use lantern, ghost, and scarecrow narration around the configured location labels; these are flavor only and do not change map locations.
  4. At a checkpoint choose /bot tt treat for one guaranteed candy or /bot tt trick for zero or two candy. Ghosts and scarecrows narrate the outcome; scores are game points, not spendable economy credits. If configured costume pieces are observed on you, the candy reward is doubled. Emote TRICK OR TREAT during the active round to open the configured event doors.
  5. Players can use /bot tt team <member> to invite a co-located participant to share a treat. The target must accept; both earn one candy at most once per checkpoint, doubled individually while their configured costume is worn.
  6. /bot tt challenge <member> starts an optional friendly rock-paper-scissors duel after mutual acceptance. Each player submits /bot tt duel <member> <rock|paper|scissors> privately. A winner earns two candy and a tie gives each one, doubled individually while the costume is worn; nobody loses candy. A pair may duel only once per round.

Optional loss consequences

Only a fully completed multiplayer round can produce a loss. The unique lowest-candy scorer is the loser; a tie for lowest is a tie, not a loss. Solo rounds, cancelled games, and rounds ending with any unfinished participant do not apply consequences. Only a player who explicitly opted in for that game is affected. The game result is privately reported before any appearance action.

An opted-in unique loser advances one stage for each consecutive eligible loss, capped at the last configured stage. A completed eligible round without an opted-in unique loser resets participants’ streaks. The streak is scoped to the room/member and expires after 30 days without a completed eligible round. Failed or unobserved appearance changes do not advance the streak and are never automatically retried. The existing journaled appearance action must observe the requested BC appearance before reporting success; dispatch alone is not confirmation. Existing locks, BC permissions, disconnects, or item-specific BC rules may prevent an application, and the game will not replace another lock. Generated lock credentials are ephemeral and are not stored in the game session, logs, or action journal.

The same disclosed opt-in also covers the costume-removal trigger when a costume itemset is configured. Removal applies the first stage once; it does not change the participant’s loss streak.

Replies, checkpoint choices, invitations, and duel choices are sent privately. status privately shows the route, progress, readiness, and scores. A round ends when all participants finish or its timer expires; an idle lobby is cancelled after 30 minutes. An admin can cancel with /bot tt cancel.

Runtime ownership and retention

TrickOrTreatPlugin subscribes to the shared MapLocationEventBus, BC emote and appearance observations, room membership, and transport-state events. It clears in-memory positions and costume evidence on reconnect before fresh sync repopulates observations. TrickOrTreatService owns game rules, bounded in-memory position tracking, lobby/round timers, and private invitations; it never optimistically treats a dispatch as observed location evidence. MongoTrickOrTreatRepository validates persisted documents and uses revision compare-and-set transitions. The room-scoped config shares prototypePartyGameConfigs; sessions are stored in prototypeTrickOrTreatSessions. Active sessions are durable and bounded to 12 players, 32 route locations, and 512 interaction records. Terminal sessions expire after 30 days. Per-member consequence streaks live in prototypeTrickOrTreatProgress and expire after 30 days.

The runtime reports the saved configuration as adopted when it starts a round, not when an admin merely saves settings. See feature configuration and bot runtime architecture.