mirror of
https://github.com/tbamud/tbamud.git
synced 2026-04-03 02:47:19 +02:00
Remove DG scripts in favor of Python scripting
This commit is contained in:
parent
5273201d1b
commit
a1976f92dd
80 changed files with 4332 additions and 2430 deletions
162
lib/scripts/README.md
Normal file
162
lib/scripts/README.md
Normal 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.
|
||||
14
lib/scripts/sample_echo.py
Normal file
14
lib/scripts/sample_echo.py
Normal 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)
|
||||
26
lib/scripts/sample_fountain.py
Normal file
26
lib/scripts/sample_fountain.py
Normal 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)
|
||||
39
lib/scripts/sample_patrol.py
Normal file
39
lib/scripts/sample_patrol.py
Normal 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)
|
||||
Loading…
Add table
Add a link
Reference in a new issue