Remove DG scripts in favor of Python scripting

This commit is contained in:
kinther 2026-02-01 08:05:04 -08:00
parent 5273201d1b
commit a1976f92dd
80 changed files with 4332 additions and 2430 deletions

162
lib/scripts/README.md Normal file
View file

@ -0,0 +1,162 @@
Scripts In lib/scripts
======================
This directory contains Python and DSL-style scripts used by the game. Scripts
are attached to rooms, npc's, and objects via builder commands (e.g. `rset add script`,
`mset add script`, `oset add script`). The script file itself is the data format.
Two Script Styles
-----------------
1) DSL (no function definitions)
- If the file does NOT contain `def on_trigger`, it is treated as the DSL.
- The DSL supports Python-style `if/elif/else`, `for`, and `while` blocks.
- Actions are written as simple verbs or function-style calls:
- `move("n")` or `move("north")`
- `move(1200)` (room vnum path step, no closed doors)
- `emote("looks around warily")`
- `sleep(3)`
- `log("text with {npc.vnum}")`
- `do("say hello")`
- Command-style is also supported:
- `move "n"`
- `sleep 3`
- `log "hello {npc.vnum}"`
- NOTE: The DSL does not support custom variable assignments yet. Use the
full Python style if you need variables.
2) Full Python (with `def on_trigger(event):`)
- If the file contains `def on_trigger`, it runs as normal Python.
- Use `mud.sleep(seconds)` to pause and resume later.
- You can use local variables, helpers, and full Python expressions.
Event Context (Full Python)
---------------------------
`on_trigger(event)` receives a dict with:
- `event["self"]`: the entity this trigger is attached to (mob/object/room)
- `event["trigger"]`: info about the trigger (vnum, name, type, narg, etc.)
- `event["vars"]`: trigger variables (if any)
Entity Data Model (DSL and Python)
----------------------------------
Every entity has these common properties:
- `entity.kind` -> kind id (mob/obj/room)
- `entity.uid` -> unique runtime id
- `entity.vnum` -> vnum (mob/obj/room)
- `entity.name` -> name/short for display
Mob (NPC or PC) properties:
- `npc.health` / `npc.max_health`
- `npc.mana` / `npc.max_mana`
- `npc.stamina` / `npc.max_stamina`
- `npc.move` / `npc.max_move` (alias for stamina)
- `npc.class` / `npc.class_id`
- `npc.species` / `npc.species_id`
- `npc.is_pc` / `npc.is_npc`
- `npc.keyword` (NPC keywords; for PCs, name)
- `npc.room` -> room entity where the mob is located
- `npc.room.vnum` -> room vnum
- `npc.room.name` -> room name/short
Object properties:
- `object.keyword` -> object keywords
- `object.oval` -> list of object values (oval[0] .. oval[NUM_OBJ_VAL_POSITIONS-1])
- `object.room` -> room entity where the object is located
- `object.room.vnum` -> room vnum
- `object.room.name` -> room name/short
Room properties:
- `room.contents` -> list of objects in the room
- `room.people` -> list of characters in the room
- `room.vnum` -> room vnum
- `room.name` -> room name/short
Entity comparisons:
- `entity == "rat"` checks keyword match for mobs/objects.
- `entity == 123456` checks entity uid.
- `entity_a == entity_b` matches if kind+uid are equal.
Available Methods
-----------------
These are available in both DSL and Python (via the `mud` module).
Core methods:
- `mud.do(command, actor=None)`
Execute a game command. If `actor` is a mob, it runs as that mob. If `actor`
is a room, it runs in that room context.
- `mud.emote(message, actor=None)`
Emote as a mob (actor is optional if the trigger is on a mob).
- `mud.move(direction, actor=None)`
Move a mob in a direction (e.g. "n", "south", "ne").
You can also pass a room vnum to step toward a destination, but if it is blocked (eg. with a door), this will not work.
- `mud.sleep(seconds)`
Pause the script and resume later.
- `mud.roll("1d6")`
Roll dice. Supported: d4/d6/d8/d10/d12/d20/d100.
- `mud.log(message)`
Write to `log/script.log`.
- `mud.echo_room(room, message)`
Echo a message to a specific room.
- `mud.send_char(character, message)`
Send a message to a character.
- `mud.call_later(seconds, func, *args, **kwargs)`
Call a function later (Python scripts only).
Convenience names in full Python scripts:
- `log("...")` is available as a shortcut for `mud.log(...)`.
- Direction strings are available as `mud.n`, `mud.s`, `mud.e`, `mud.w`, etc.
Formatting / Expressions
------------------------
DSL supports Python-style blocks:
```
while True:
if npc.stamina < 20:
rest
else:
stand
```
DSL logging supports f-string style with braces:
```
log "rat {npc.vnum} in room {npc.room.vnum}"
```
In full Python scripts, use normal f-strings:
```
log(f"rat {event['self'].vnum} in room {event['self'].room.vnum}")
```
Variables (Full Python)
-----------------------
Use normal Python variables:
```
def on_trigger(event):
room = event["self"]
count = 0
while True:
count += 1
mud.echo_room(room, f"tick {count}")
mud.sleep(30)
```
The DSL currently does not support custom variable assignment. If you need
variables, use full Python with `def on_trigger(event):`.
Best Practices
--------------
- Keep scripts small and focused.
- Use `log(...)` during development and remove or reduce noise later.
- Avoid infinite tight loops without `sleep`.
- Use comments generously (`# ...`).
- Prefer readable direction strings: `"north"`, `"west"`, etc.
Sample: Room Echo Script
------------------------
See `sample_echo.py` in this directory for a ready-to-attach room script.

View file

@ -0,0 +1,14 @@
# Room echo script example (attach to a room trigger)
def on_trigger(event):
# Room entity the script is attached to.
room = event["self"]
while True:
# Pick between two messages using a dice roll.
if mud.roll("1d2") == 1:
mud.echo_room(room, "someone spills a drink at the bar")
else:
mud.echo_room(room, "a game of cards gets rowdy as a dwarf slams a fist on a table")
# Wait before the next echo.
mud.sleep(60)

View file

@ -0,0 +1,26 @@
# Fountain refill script example (attach to an object trigger)
def on_trigger(event):
# Object entity the script is attached to.
fountain = event["self"]
# Minimum refill amount per tick.
refill_amount = 1
while True:
# Ensure the fountain has object values to read.
if fountain and fountain.oval:
# oval[0] is capacity, oval[1] is current contents.
capacity = fountain.oval[0]
contains = fountain.oval[1]
if capacity > 0 and contains < capacity:
# Calculate the new fill amount without exceeding capacity.
new_amount = contains + refill_amount
if new_amount > capacity:
new_amount = capacity
# Update the fountain contents via osetval.
mud.do(f"osetval 1 {new_amount}", actor=fountain)
# Echo a drip message to the room when refilling.
if fountain.room:
mud.echo_room(fountain.room, f"water drips from the ceiling into {fountain.name}")
# Wait before attempting another refill.
mud.sleep(300)

View file

@ -0,0 +1,39 @@
# NPC patrol script example (attach to a mob trigger)
# Track per-NPC patrol state by uid.
patrol_state = {}
# Ordered list of target room vnums for the patrol route.
patrol_route = [103, 105, 153, 149, 100]
def on_trigger(event):
# The mob this trigger is attached to.
npc = event["self"]
# Unique runtime id used to track this NPC's state.
uid = npc.uid
# Lookup or create state for this NPC.
state = patrol_state.get(uid)
if state is None:
# Start at the first patrol target.
state = {"target": 0}
patrol_state[uid] = state
# Current target room vnum.
target = patrol_route[state["target"]]
# If already at target, advance to the next.
if npc.room.vnum == target:
state["target"] = (state["target"] + 1) % len(patrol_route)
target = patrol_route[state["target"]]
# Move one step toward the target room vnum.
if not mud.move(target, actor=npc):
mud.log(f"sample_patrol: no path to {target}", actor=npc)
# Optional flavor emotes at specific rooms.
if npc.room.vnum == 153:
mud.emote("looks around carefully", actor=npc)
elif npc.room.vnum == 149:
mud.emote("sniffs the air", actor=npc)
# Sleep to schedule the next patrol tick.
mud.sleep(3)